Skip to content
7 changes: 6 additions & 1 deletion example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Text,
type NativeSyntheticEvent,
ScrollView,
Platform,
} from 'react-native';
import {
EnrichedTextInput,
Expand Down Expand Up @@ -202,7 +203,11 @@ export default function App() {
selectionLimit: 1,
});

const imageUri = response.assets?.[0]?.originalPath;
const imageUri =
Platform.OS === 'android'
? response.assets?.[0]?.originalPath
: response.assets?.[0]?.uri;

if (!imageUri) return;

ref.current?.setImage(imageUri);
Expand Down
39 changes: 33 additions & 6 deletions ios/EnrichedTextInputView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ - (void)setDefaults {
@([UnorderedListStyle getStyleType]): [[UnorderedListStyle alloc] initWithInput:self],
@([OrderedListStyle getStyleType]): [[OrderedListStyle alloc] initWithInput:self],
@([BlockQuoteStyle getStyleType]): [[BlockQuoteStyle alloc] initWithInput:self],
@([CodeBlockStyle getStyleType]): [[CodeBlockStyle alloc] initWithInput:self]
@([CodeBlockStyle getStyleType]): [[CodeBlockStyle alloc] initWithInput:self],
@([ImageStyle getStyleType]): [[ImageStyle alloc] initWithInput:self]
};

conflictingStyles = @{
Expand All @@ -112,24 +113,26 @@ - (void)setDefaults {
@([OrderedListStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])],
@([BlockQuoteStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([CodeBlockStyle getStyleType])],
@([CodeBlockStyle getStyleType]): @[@([H1Style getStyleType]), @([H2Style getStyleType]), @([H3Style getStyleType]),
@([BoldStyle getStyleType]), @([ItalicStyle getStyleType]), @([UnderlineStyle getStyleType]), @([StrikethroughStyle getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([InlineCodeStyle getStyleType]), @([MentionStyle getStyleType]), @([LinkStyle getStyleType])]
@([BoldStyle getStyleType]), @([ItalicStyle getStyleType]), @([UnderlineStyle getStyleType]), @([StrikethroughStyle getStyleType]), @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]), @([InlineCodeStyle getStyleType]), @([MentionStyle getStyleType]), @([LinkStyle getStyleType])],
@([ImageStyle getStyleType]) : @[@([LinkStyle getStyleType]), @([MentionStyle getStyleType])]
};

blockingStyles = @{
@([BoldStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
@([ItalicStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
@([UnderlineStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
@([StrikethroughStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
@([InlineCodeStyle getStyleType]) : @[@([CodeBlockStyle getStyleType])],
@([LinkStyle getStyleType]): @[@([CodeBlockStyle getStyleType])],
@([MentionStyle getStyleType]): @[@([CodeBlockStyle getStyleType])],
@([InlineCodeStyle getStyleType]) : @[@([CodeBlockStyle getStyleType]), @([ImageStyle getStyleType])],
@([LinkStyle getStyleType]): @[@([CodeBlockStyle getStyleType]), @([ImageStyle getStyleType])],
@([MentionStyle getStyleType]): @[@([CodeBlockStyle getStyleType]), @([ImageStyle getStyleType])],
@([H1Style getStyleType]): @[],
@([H2Style getStyleType]): @[],
@([H3Style getStyleType]): @[],
@([UnorderedListStyle getStyleType]): @[],
@([OrderedListStyle getStyleType]): @[],
@([BlockQuoteStyle getStyleType]): @[],
@([CodeBlockStyle getStyleType]): @[],
@([ImageStyle getStyleType]) : @[@([InlineCodeStyle getStyleType])]
};

parser = [[InputParser alloc] initWithInput:self];
Expand Down Expand Up @@ -368,6 +371,16 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &
stylePropChanged = YES;
}

if(newViewProps.htmlStyle.img.width != oldViewProps.htmlStyle.img.width) {
[newConfig setImageWidth:newViewProps.htmlStyle.img.width];
stylePropChanged = YES;
}

if(newViewProps.htmlStyle.img.height != oldViewProps.htmlStyle.img.height) {
[newConfig setImageHeight:newViewProps.htmlStyle.img.height];
stylePropChanged = YES;
}

if(newViewProps.htmlStyle.a.textDecorationLine != oldViewProps.htmlStyle.a.textDecorationLine) {
NSString *objcString = [NSString fromCppString:newViewProps.htmlStyle.a.textDecorationLine];
if([objcString isEqualToString:DecorationUnderline]) {
Expand Down Expand Up @@ -723,7 +736,7 @@ - (void)tryUpdatingActiveStyles {
.isOrderedList = [_activeStyles containsObject: @([OrderedListStyle getStyleType])],
.isBlockQuote = [_activeStyles containsObject: @([BlockQuoteStyle getStyleType])],
.isCodeBlock = [_activeStyles containsObject: @([CodeBlockStyle getStyleType])],
.isImage = NO // [_activeStyles containsObject: @([ImageStyle getStyleType]])],
.isImage = [_activeStyles containsObject: @([ImageStyle getStyleType])],
});
}
}
Expand Down Expand Up @@ -793,6 +806,9 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
[self toggleParagraphStyle:[BlockQuoteStyle getStyleType]];
} else if([commandName isEqualToString:@"toggleCodeBlock"]) {
[self toggleParagraphStyle:[CodeBlockStyle getStyleType]];
} else if([commandName isEqualToString:@"addImage"]) {
NSString *uri = (NSString *)args[0];
[self addImage:uri];
}
}

Expand Down Expand Up @@ -939,6 +955,17 @@ - (void)addMention:(NSString *)indicator text:(NSString *)text attributes:(NSStr
}
}

- (void)addImage:(NSString *)uri
{
ImageStyle *imageStyleClass = (ImageStyle *)stylesDict[@([ImageStyle getStyleType])];
if(imageStyleClass == nullptr) { return; }

if([self handleStyleBlocksAndConflicts:[ImageStyle getStyleType] range:textView.selectedRange]) {
[imageStyleClass addImage:uri];
[self anyTextMayHaveBeenModified];
}
}

- (void)startMentionWithIndicator:(NSString *)indicator {
MentionStyle *mentionStyleClass = (MentionStyle *)stylesDict[@([MentionStyle getStyleType])];
if(mentionStyleClass == nullptr) { return; }
Expand Down
4 changes: 4 additions & 0 deletions ios/config/InputConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,8 @@
- (void)setCodeBlockBgColor:(UIColor *)newValue;
- (CGFloat)codeBlockBorderRadius;
- (void)setCodeBlockBorderRadius:(CGFloat)newValue;
- (void)setImageWidth:(CGFloat)newValue;
- (CGFloat)imageWidth;
- (void)setImageHeight:(CGFloat)newValue;
- (CGFloat)imageHeight;
@end
20 changes: 20 additions & 0 deletions ios/config/InputConfig.mm
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ @implementation InputConfig {
UIColor *_codeBlockFgColor;
CGFloat _codeBlockBorderRadius;
UIColor *_codeBlockBgColor;
CGFloat _imageWidth;
CGFloat _imageHeight;
}

- (instancetype) init {
Expand Down Expand Up @@ -85,6 +87,8 @@ - (id)copyWithZone:(NSZone *)zone {
copy->_codeBlockFgColor = [_codeBlockFgColor copy];
copy->_codeBlockBgColor = [_codeBlockBgColor copy];
copy->_codeBlockBorderRadius = _codeBlockBorderRadius;
copy->_imageWidth = _imageWidth;
copy->_imageHeight = _imageHeight;
return copy;
}

Expand Down Expand Up @@ -409,4 +413,20 @@ - (void)setCodeBlockBorderRadius:(CGFloat)newValue {
_codeBlockBorderRadius = newValue;
}

- (CGFloat)imageWidth {
return _imageWidth;
}

- (void)setImageWidth:(CGFloat)newValue {
_imageWidth = newValue;
}

- (CGFloat)imageHeight {
return _imageHeight;
}

- (void)setImageHeight:(CGFloat)newValue {
_imageHeight = newValue;
}

@end
47 changes: 46 additions & 1 deletion ios/inputParser/InputParser.mm
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ - (NSString *)parseToHtmlFromRange:(NSRange)range {

// append closing tags
for(NSNumber *style in sortedEndedStyles) {
if ([style isEqualToNumber: @([ImageStyle getStyleType])]) {
continue;
}
NSString *tagContent = [self tagContentForStyle:style openingTag:NO location:currentRange.location];
[result appendString: [NSString stringWithFormat:@"</%@>", tagContent]];
}
Expand Down Expand Up @@ -221,6 +224,9 @@ - (NSString *)parseToHtmlFromRange:(NSRange)range {

// append closing tags
for(NSNumber *style in sortedEndedStyles) {
if ([style isEqualToNumber: @([ImageStyle getStyleType])]) {
continue;
}
NSString *tagContent = [self tagContentForStyle:style openingTag:NO location:currentRange.location];
[result appendString: [NSString stringWithFormat:@"</%@>", tagContent]];
}
Expand All @@ -233,7 +239,11 @@ - (NSString *)parseToHtmlFromRange:(NSRange)range {
// append opening tags
for(NSNumber *style in sortedNewStyles) {
NSString *tagContent = [self tagContentForStyle:style openingTag:YES location:currentRange.location];
[result appendString: [NSString stringWithFormat:@"<%@>", tagContent]];
if ([style isEqualToNumber: @([ImageStyle getStyleType])]) {
[result appendString: [NSString stringWithFormat:@"<%@/>", tagContent]];
} else {
[result appendString: [NSString stringWithFormat:@"<%@>", tagContent]];
}
}

// append the letter and escape it if needed
Expand All @@ -254,6 +264,9 @@ - (NSString *)parseToHtmlFromRange:(NSRange)range {

// append closing tags
for(NSNumber *style in sortedEndedStyles) {
if ([style isEqualToNumber: @([ImageStyle getStyleType])]) {
continue;
}
NSString *tagContent = [self tagContentForStyle:style openingTag:NO location:_input->textView.textStorage.string.length - 1];
[result appendString: [NSString stringWithFormat:@"</%@>", tagContent]];
}
Expand Down Expand Up @@ -310,6 +323,19 @@ - (NSString *)tagContentForStyle:(NSNumber *)style openingTag:(BOOL)openingTag l
return @"b";
} else if([style isEqualToNumber: @([ItalicStyle getStyleType])]) {
return @"i";
} else if ([style isEqualToNumber: @([ImageStyle getStyleType])]) {
if(openingTag) {
ImageStyle *imageStyle = (ImageStyle *)_input->stylesDict[@([ImageStyle getStyleType])];
if(imageStyle != nullptr) {
ImageData *data = [imageStyle getImageDataAt:location];
if(data != nullptr && data.uri != nullptr) {
return [NSString stringWithFormat:@"img src=\"%@\"", data.uri];
}
}
return @"img";
} else {
return @"";
}
} else if([style isEqualToNumber: @([UnderlineStyle getStyleType])]) {
return @"u";
} else if([style isEqualToNumber: @([StrikethroughStyle getStyleType])]) {
Expand Down Expand Up @@ -642,6 +668,25 @@ - (NSArray *)getTextAndStylesFromHtml:(NSString *)fixedHtml {
[styleArr addObject:@([BoldStyle getStyleType])];
} else if([tagName isEqualToString:@"i"]) {
[styleArr addObject:@([ItalicStyle getStyleType])];
} else if([tagName isEqualToString:@"img"]) {
NSRegularExpression *srcRegex = [NSRegularExpression regularExpressionWithPattern:@"src=\".+\""
options:0
error:nullptr
];
NSTextCheckingResult* match = [srcRegex firstMatchInString:params options:0 range: NSMakeRange(0, params.length)];

if(match == nullptr) {
continue;
}

NSRange srcRange = match.range;
[styleArr addObject:@([ImageStyle getStyleType])];
// cut only the uri from the src="..." string
NSString *uri = [params substringWithRange:NSMakeRange(srcRange.location + 5, srcRange.length - 6)];
ImageData *imageData = [[ImageData alloc] init];
imageData.uri = uri;

stylePair.styleValue = imageData;
} else if([tagName isEqualToString:@"u"]) {
[styleArr addObject:@([UnderlineStyle getStyleType])];
} else if([tagName isEqualToString:@"s"]) {
Expand Down
Loading
Loading