Skip to content

Commit 571fa10

Browse files
feat: add support for codeblock on iOS (#253)
1 parent c560531 commit 571fa10

27 files changed

+678
-92
lines changed

ios/EnrichedTextInputView.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ NS_ASSUME_NONNULL_BEGIN
1818
@public InputParser *parser;
1919
@public NSMutableDictionary<NSAttributedStringKey, id> *defaultTypingAttributes;
2020
@public NSDictionary<NSNumber *, id<BaseStyleProtocol>> *stylesDict;
21+
NSDictionary<NSNumber *, NSArray<NSNumber *> *> *conflictingStyles;
22+
NSDictionary<NSNumber *, NSArray<NSNumber *> *> *blockingStyles;
2123
@public BOOL blockEmitting;
2224
}
2325
- (CGSize)measureSize:(CGFloat)maxWidth;
2426
- (void)emitOnLinkDetectedEvent:(NSString *)text url:(NSString *)url range:(NSRange)range;
2527
- (void)emitOnMentionEvent:(NSString *)indicator text:(nullable NSString *)text;
2628
- (void)anyTextMayHaveBeenModified;
2729
- (BOOL)handleStyleBlocksAndConflicts:(StyleType)type range:(NSRange)range;
30+
- (NSArray<NSNumber *> *)getPresentStyleTypesFrom:(NSArray<NSNumber *> *)types range:(NSRange)range;
2831
@end
2932

3033
NS_ASSUME_NONNULL_END

ios/EnrichedTextInputView.mm

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ @implementation EnrichedTextInputView {
2626
EnrichedTextInputViewShadowNode::ConcreteState::Shared _state;
2727
int _componentViewHeightUpdateCounter;
2828
NSMutableSet<NSNumber *> *_activeStyles;
29-
NSDictionary<NSNumber *, NSArray<NSNumber *> *> *_conflictingStyles;
30-
NSDictionary<NSNumber *, NSArray<NSNumber *> *> *_blockingStyles;
3129
LinkData *_recentlyActiveLinkData;
3230
NSRange _recentlyActiveLinkRange;
3331
NSString *_recentlyEmittedString;
@@ -95,39 +93,43 @@ - (void)setDefaults {
9593
@([H3Style getStyleType]): [[H3Style alloc] initWithInput:self],
9694
@([UnorderedListStyle getStyleType]): [[UnorderedListStyle alloc] initWithInput:self],
9795
@([OrderedListStyle getStyleType]): [[OrderedListStyle alloc] initWithInput:self],
98-
@([BlockQuoteStyle getStyleType]): [[BlockQuoteStyle alloc] initWithInput:self]
96+
@([BlockQuoteStyle getStyleType]): [[BlockQuoteStyle alloc] initWithInput:self],
97+
@([CodeBlockStyle getStyleType]): [[CodeBlockStyle alloc] initWithInput:self]
9998
};
10099

101-
_conflictingStyles = @{
100+
conflictingStyles = @{
102101
@([BoldStyle getStyleType]) : @[],
103102
@([ItalicStyle getStyleType]) : @[],
104103
@([UnderlineStyle getStyleType]) : @[],
105104
@([StrikethroughStyle getStyleType]) : @[],
106105
@([InlineCodeStyle getStyleType]) : @[@([LinkStyle getStyleType]), @([MentionStyle getStyleType])],
107106
@([LinkStyle getStyleType]): @[@([InlineCodeStyle getStyleType]), @([LinkStyle getStyleType]), @([MentionStyle getStyleType])],
108107
@([MentionStyle getStyleType]): @[@([InlineCodeStyle getStyleType]), @([LinkStyle getStyleType])],
109-
@([H1Style getStyleType]): @[@([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType])],
110-
@([H2Style getStyleType]): @[@([H1Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType])],
111-
@([H3Style getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType])],
112-
@([UnorderedListStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType])],
113-
@([OrderedListStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType])],
114-
@([BlockQuoteStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType])]
108+
@([H1Style getStyleType]): @[@([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])],
109+
@([H2Style getStyleType]): @[@([H1Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])],
110+
@([H3Style getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])],
111+
@([UnorderedListStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])],
112+
@([OrderedListStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])],
113+
@([BlockQuoteStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([CodeBlockStyle getStyleType])],
114+
@([CodeBlockStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]),
115+
@([BoldStyle getStyleType]), @([ItalicStyle getStyleType]), @([UnderlineStyle getStyleType]), @([StrikethroughStyle getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([InlineCodeStyle getStyleType]), @([MentionStyle getStyleType]), @([LinkStyle getStyleType])]
115116
};
116117

117-
_blockingStyles = @{
118-
@([BoldStyle getStyleType]) : @[],
119-
@([ItalicStyle getStyleType]) : @[],
120-
@([UnderlineStyle getStyleType]) : @[],
121-
@([StrikethroughStyle getStyleType]) : @[],
122-
@([InlineCodeStyle getStyleType]) : @[],
123-
@([LinkStyle getStyleType]): @[],
124-
@([MentionStyle getStyleType]): @[],
118+
blockingStyles = @{
119+
@([BoldStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
120+
@([ItalicStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
121+
@([UnderlineStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
122+
@([StrikethroughStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
123+
@([InlineCodeStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
124+
@([LinkStyle getStyleType]): @[@([CodeBlockStyle getStyleType])],
125+
@([MentionStyle getStyleType]): @[@([CodeBlockStyle getStyleType])],
125126
@([H1Style getStyleType]): @[],
126127
@([H2Style getStyleType]): @[],
127128
@([H3Style getStyleType]): @[],
128129
@([UnorderedListStyle getStyleType]): @[],
129130
@([OrderedListStyle getStyleType]): @[],
130131
@([BlockQuoteStyle getStyleType]): @[],
132+
@([CodeBlockStyle getStyleType]): @[],
131133
};
132134

133135
parser = [[InputParser alloc] initWithInput:self];
@@ -347,6 +349,25 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
347349
}
348350
}
349351

352+
if(newViewProps.htmlStyle.codeblock.color != oldViewProps.htmlStyle.codeblock.color) {
353+
if(isColorMeaningful(newViewProps.htmlStyle.codeblock.color)) {
354+
[newConfig setCodeBlockFgColor:RCTUIColorFromSharedColor(newViewProps.htmlStyle.codeblock.color)];
355+
stylePropChanged = YES;
356+
}
357+
}
358+
359+
if(newViewProps.htmlStyle.codeblock.backgroundColor != oldViewProps.htmlStyle.codeblock.backgroundColor) {
360+
if(isColorMeaningful(newViewProps.htmlStyle.codeblock.backgroundColor)) {
361+
[newConfig setCodeBlockBgColor:RCTUIColorFromSharedColor(newViewProps.htmlStyle.codeblock.backgroundColor)];
362+
stylePropChanged = YES;
363+
}
364+
}
365+
366+
if(newViewProps.htmlStyle.codeblock.borderRadius != oldViewProps.htmlStyle.codeblock.borderRadius) {
367+
[newConfig setCodeBlockBorderRadius:newViewProps.htmlStyle.codeblock.borderRadius];
368+
stylePropChanged = YES;
369+
}
370+
350371
if(newViewProps.htmlStyle.a.textDecorationLine != oldViewProps.htmlStyle.a.textDecorationLine) {
351372
NSString *objcString = [NSString fromCppString:newViewProps.htmlStyle.a.textDecorationLine];
352373
if([objcString isEqualToString:DecorationUnderline]) {
@@ -512,9 +533,8 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
512533
_emitHtml = newViewProps.isOnChangeHtmlSet;
513534

514535
[super updateProps:props oldProps:oldProps];
515-
// mandatory text and height checks
536+
// run the changes callback
516537
[self anyTextMayHaveBeenModified];
517-
[self tryUpdatingHeight];
518538

519539
// autofocus - needs to be done at the very end
520540
if(isFirstMount && newViewProps.autoFocus) {
@@ -702,7 +722,7 @@ - (void)tryUpdatingActiveStyles {
702722
.isUnorderedList = [_activeStyles containsObject: @([UnorderedListStyle getStyleType])],
703723
.isOrderedList = [_activeStyles containsObject: @([OrderedListStyle getStyleType])],
704724
.isBlockQuote = [_activeStyles containsObject: @([BlockQuoteStyle getStyleType])],
705-
.isCodeBlock = NO, // [_activeStyles containsObject: @([CodeBlockStyle getStyleType])],
725+
.isCodeBlock = [_activeStyles containsObject: @([CodeBlockStyle getStyleType])],
706726
.isImage = NO // [_activeStyles containsObject: @([ImageStyle getStyleType]])],
707727
});
708728
}
@@ -771,6 +791,8 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
771791
[self toggleParagraphStyle:[OrderedListStyle getStyleType]];
772792
} else if([commandName isEqualToString:@"toggleBlockQuote"]) {
773793
[self toggleParagraphStyle:[BlockQuoteStyle getStyleType]];
794+
} else if([commandName isEqualToString:@"toggleCodeBlock"]) {
795+
[self toggleParagraphStyle:[CodeBlockStyle getStyleType]];
774796
}
775797
}
776798

@@ -930,13 +952,13 @@ - (void)startMentionWithIndicator:(NSString *)indicator {
930952
// returns false when style shouldn't be applied and true when it can be
931953
- (BOOL)handleStyleBlocksAndConflicts:(StyleType)type range:(NSRange)range {
932954
// handle blocking styles: if any is present we do not apply the toggled style
933-
NSArray<NSNumber *> *blocking = [self getPresentStyleTypesFrom: _blockingStyles[@(type)] range:range];
955+
NSArray<NSNumber *> *blocking = [self getPresentStyleTypesFrom: blockingStyles[@(type)] range:range];
934956
if(blocking.count != 0) {
935957
return NO;
936958
}
937959

938960
// handle conflicting styles: all of their occurences have to be removed
939-
NSArray<NSNumber *> *conflicting = [self getPresentStyleTypesFrom: _conflictingStyles[@(type)] range:range];
961+
NSArray<NSNumber *> *conflicting = [self getPresentStyleTypesFrom: conflictingStyles[@(type)] range:range];
940962
if(conflicting.count != 0) {
941963
for(NSNumber *style in conflicting) {
942964
id<BaseStyleProtocol> styleClass = stylesDict[style];
@@ -1012,6 +1034,7 @@ - (void)manageSelectionBasedChanges {
10121034
- (void)handleWordModificationBasedChanges:(NSString*)word inRange:(NSRange)range {
10131035
// manual links refreshing and automatic links detection handling
10141036
LinkStyle* linkStyle = [stylesDict objectForKey:@([LinkStyle getStyleType])];
1037+
10151038
if(linkStyle != nullptr) {
10161039
// manual links need to be handled first because they can block automatic links after being refreshed
10171040
[linkStyle handleManualLinks:word inRange:range];
@@ -1046,6 +1069,12 @@ - (void)anyTextMayHaveBeenModified {
10461069
[bqStyle manageBlockquoteColor];
10471070
}
10481071

1072+
// codeblock font and color management
1073+
CodeBlockStyle *codeBlockStyle = stylesDict[@([CodeBlockStyle getStyleType])];
1074+
if(codeBlockStyle != nullptr) {
1075+
[codeBlockStyle manageCodeBlockFontAndColor];
1076+
}
1077+
10491078
// improper headings fix
10501079
H1Style *h1Style = stylesDict[@([H1Style getStyleType])];
10511080
H2Style *h2Style = stylesDict[@([H2Style getStyleType])];
@@ -1171,6 +1200,7 @@ - (bool)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range r
11711200
UnorderedListStyle *uStyle = stylesDict[@([UnorderedListStyle getStyleType])];
11721201
OrderedListStyle *oStyle = stylesDict[@([OrderedListStyle getStyleType])];
11731202
BlockQuoteStyle *bqStyle = stylesDict[@([BlockQuoteStyle getStyleType])];
1203+
CodeBlockStyle *cbStyle = stylesDict[@([CodeBlockStyle getStyleType])];
11741204
LinkStyle *linkStyle = stylesDict[@([LinkStyle getStyleType])];
11751205
MentionStyle *mentionStyle = stylesDict[@([MentionStyle getStyleType])];
11761206
H1Style *h1Style = stylesDict[@([H1Style getStyleType])];
@@ -1186,13 +1216,19 @@ - (bool)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range r
11861216
[oStyle handleBackspaceInRange:range replacementText:text] ||
11871217
[oStyle tryHandlingListShorcutInRange:range replacementText:text] ||
11881218
[bqStyle handleBackspaceInRange:range replacementText:text] ||
1219+
[cbStyle handleBackspaceInRange:range replacementText:text] ||
11891220
[linkStyle handleLeadingLinkReplacement:range replacementText:text] ||
11901221
[mentionStyle handleLeadingMentionReplacement:range replacementText:text] ||
11911222
[h1Style handleNewlinesInRange:range replacementText:text] ||
11921223
[h2Style handleNewlinesInRange:range replacementText:text] ||
11931224
[h3Style handleNewlinesInRange:range replacementText:text] ||
11941225
[ZeroWidthSpaceUtils handleBackspaceInRange:range replacementText:text input:self] ||
1195-
[ParagraphAttributesUtils handleBackspaceInRange:range replacementText:text input:self]
1226+
[ParagraphAttributesUtils handleBackspaceInRange:range replacementText:text input:self] ||
1227+
// CRITICAL: This callback HAS TO be always evaluated last.
1228+
//
1229+
// This function is the "Generic Fallback": if no specific style claims the backspace action
1230+
// to change its state, only then do we proceed to physically delete the newline and merge paragraphs.
1231+
[ParagraphAttributesUtils handleNewlineBackspaceInRange:range replacementText:text input:self]
11961232
) {
11971233
[self anyTextMayHaveBeenModified];
11981234
return NO;

ios/config/InputConfig.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,10 @@
6464
- (void)setLinkDecorationLine:(TextDecorationLineEnum)newValue;
6565
- (void)setMentionStyleProps:(NSDictionary *)newValue;
6666
- (MentionStyleProps *)mentionStylePropsForIndicator:(NSString *)indicator;
67+
- (UIColor *)codeBlockFgColor;
68+
- (void)setCodeBlockFgColor:(UIColor *)newValue;
69+
- (UIColor *)codeBlockBgColor;
70+
- (void)setCodeBlockBgColor:(UIColor *)newValue;
71+
- (CGFloat)codeBlockBorderRadius;
72+
- (void)setCodeBlockBorderRadius:(CGFloat)newValue;
6773
@end

ios/config/InputConfig.mm

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ @implementation InputConfig {
3636
UIColor *_linkColor;
3737
TextDecorationLineEnum _linkDecorationLine;
3838
NSDictionary *_mentionProperties;
39+
UIColor *_codeBlockFgColor;
40+
CGFloat _codeBlockBorderRadius;
41+
UIColor *_codeBlockBgColor;
3942
}
4043

4144
- (instancetype) init {
@@ -79,6 +82,9 @@ - (id)copyWithZone:(NSZone *)zone {
7982
copy->_linkColor = [_linkColor copy];
8083
copy->_linkDecorationLine = [_linkDecorationLine copy];
8184
copy->_mentionProperties = [_mentionProperties mutableCopy];
85+
copy->_codeBlockFgColor = [_codeBlockFgColor copy];
86+
copy->_codeBlockBgColor = [_codeBlockBgColor copy];
87+
copy->_codeBlockBorderRadius = _codeBlockBorderRadius;
8288
return copy;
8389
}
8490

@@ -379,4 +385,28 @@ - (MentionStyleProps *)mentionStylePropsForIndicator:(NSString *)indicator {
379385
return fallbackProps;
380386
}
381387

388+
- (UIColor *)codeBlockFgColor {
389+
return _codeBlockFgColor;
390+
}
391+
392+
- (void)setCodeBlockFgColor:(UIColor *)newValue {
393+
_codeBlockFgColor = newValue;
394+
}
395+
396+
- (UIColor *)codeBlockBgColor {
397+
return _codeBlockBgColor;
398+
}
399+
400+
- (void)setCodeBlockBgColor:(UIColor *)newValue {
401+
_codeBlockBgColor = newValue;
402+
}
403+
404+
- (CGFloat)codeBlockBorderRadius {
405+
return _codeBlockBorderRadius;
406+
}
407+
408+
- (void)setCodeBlockBorderRadius:(CGFloat)newValue {
409+
_codeBlockBorderRadius = newValue;
410+
}
411+
382412
@end

0 commit comments

Comments
 (0)