diff --git a/apple/MarkdownTextInputDecoratorView.mm b/apple/MarkdownTextInputDecoratorView.mm index d24a116e..6ec1a93a 100644 --- a/apple/MarkdownTextInputDecoratorView.mm +++ b/apple/MarkdownTextInputDecoratorView.mm @@ -22,7 +22,7 @@ @implementation MarkdownTextInputDecoratorView { #else __weak RCTBaseTextInputView *_textInput; #endif /* RCT_NEW_ARCH_ENABLED */ - __weak UIView *_backedTextInputView; + __weak RCTUIView *_backedTextInputView; __weak RCTBackedTextFieldDelegateAdapter *_adapter; __weak RCTUITextView *_textView; } @@ -78,11 +78,11 @@ - (void)didMoveToWindow { CGSize contentSize = _textView.contentSize; CGRect textBounds = [layoutManager usedRectForTextContainer:_textView.textContainer]; contentSize.height = textBounds.size.height + _textView.textContainerInset.top + _textView.textContainerInset.bottom; - [_textView setContentSize:contentSize]; + // [_textView setContentSize:contentSize]; - layoutManager.allowsNonContiguousLayout = NO; // workaround for onScroll issue - object_setClass(layoutManager, [MarkdownLayoutManager class]); - objc_setAssociatedObject(layoutManager, @selector(markdownUtils), _markdownUtils, OBJC_ASSOCIATION_RETAIN); +// layoutManager.allowsNonContiguousLayout = NO; // workaround for onScroll issue +// object_setClass(layoutManager, [MarkdownLayoutManager class]); +// objc_setAssociatedObject(layoutManager, @selector(markdownUtils), _markdownUtils, OBJC_ASSOCIATION_RETAIN); } else { react_native_assert(false && "Cannot enable Markdown for this type of TextInput."); } @@ -99,10 +99,10 @@ - (void)willMoveToWindow:(NSWindow *)newWindow if (_textView != nil) { [_textView setMarkdownUtils:nil]; NSLayoutManager *layoutManager = _textView.layoutManager; - if (layoutManager != nil && [object_getClass(layoutManager) isEqual:[MarkdownLayoutManager class]]) { - objc_setAssociatedObject(layoutManager, @selector(markdownUtils), nil, OBJC_ASSOCIATION_RETAIN); - object_setClass(layoutManager, [NSLayoutManager class]); - } +// if (layoutManager != nil && [object_getClass(layoutManager) isEqual:[MarkdownLayoutManager class]]) { +// objc_setAssociatedObject(layoutManager, @selector(markdownUtils), nil, OBJC_ASSOCIATION_RETAIN); +// object_setClass(layoutManager, [NSLayoutManager class]); +// } } } diff --git a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m index f0f0bfed..b22706e6 100644 --- a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m +++ b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m @@ -18,13 +18,8 @@ - (void)markdown_textFieldDidChange RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { RCTUITextField *backedTextInputView = [self valueForKey:@"_backedTextInputView"]; -<<<<<<<< HEAD:apple/RCTBackedTextFieldDelegateAdapter+Markdown.m NSRange range = backedTextInputView.selectedRange; - backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText]; -======== - UITextRange *range = backedTextInputView.selectedTextRange; backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText withAttributes:backedTextInputView.defaultTextAttributes]; ->>>>>>>> main:apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm [backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; } diff --git a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm index f0f0bfed..b22706e6 100644 --- a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm +++ b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm @@ -18,13 +18,8 @@ - (void)markdown_textFieldDidChange RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { RCTUITextField *backedTextInputView = [self valueForKey:@"_backedTextInputView"]; -<<<<<<<< HEAD:apple/RCTBackedTextFieldDelegateAdapter+Markdown.m NSRange range = backedTextInputView.selectedRange; - backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText]; -======== - UITextRange *range = backedTextInputView.selectedTextRange; backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText withAttributes:backedTextInputView.defaultTextAttributes]; ->>>>>>>> main:apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm [backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; } diff --git a/apple/RCTBaseTextInputView+Markdown.m b/apple/RCTBaseTextInputView+Markdown.m index dd5b9da0..a0800a1b 100644 --- a/apple/RCTBaseTextInputView+Markdown.m +++ b/apple/RCTBaseTextInputView+Markdown.m @@ -1,5 +1,5 @@ -#import -#import +#import +#import #import @implementation RCTBaseTextInputView (Markdown) @@ -16,21 +16,47 @@ - (void)markdown_setAttributedText:(NSAttributedString *)attributedText { RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { - attributedText = [markdownUtils parseMarkdown:attributedText]; + attributedText = [markdownUtils parseMarkdown:attributedText withAttributes:self.backedTextInputView.defaultTextAttributes]; } // Call the original method [self markdown_setAttributedText:attributedText]; } +- (BOOL)markdown_textOf:(NSAttributedString *)newText equals:(NSAttributedString *)oldText +{ + RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; + if (markdownUtils != nil) { + // Emoji characters are automatically assigned an AppleColorEmoji NSFont and the original font is moved to NSOriginalFont + // We need to remove these attributes before comparison + NSMutableAttributedString *newTextCopy = [newText mutableCopy]; + NSMutableAttributedString *oldTextCopy = [oldText mutableCopy]; + [newTextCopy removeAttribute:@"NSFont" range:NSMakeRange(0, newTextCopy.length)]; + [oldTextCopy removeAttribute:@"NSFont" range:NSMakeRange(0, oldTextCopy.length)]; + [oldTextCopy removeAttribute:@"NSOriginalFont" range:NSMakeRange(0, oldTextCopy.length)]; + return [newTextCopy isEqualToAttributedString:oldTextCopy]; + } + + return [self markdown_textOf:newText equals:oldText]; +} + - (void)markdown_updateLocalData { RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { - NSRange range = self.backedTextInputView.selectedRange; - NSAttributedString *attributedText = [markdownUtils parseMarkdown:self.backedTextInputView.attributedText]; - [self.backedTextInputView setAttributedText:attributedText]; - [self.backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; + id backedTextInputView = self.backedTextInputView; + NSAttributedString *oldAttributedText = backedTextInputView.attributedText; + NSAttributedString *newAttributedText = [markdownUtils parseMarkdown:oldAttributedText withAttributes:backedTextInputView.defaultTextAttributes]; + NSRange range = backedTextInputView.selectedTextRange; + + // update attributed text without emitting onSelectionChange event + id delegate = backedTextInputView.textInputDelegate; + backedTextInputView.textInputDelegate = nil; + [backedTextInputView setAttributedText:newAttributedText]; + backedTextInputView.textInputDelegate = delegate; + + // restore original selection and emit onSelectionChange event + [backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; } // Call the original method @@ -58,7 +84,16 @@ + (void)load SEL swizzledSelector = @selector(markdown_updateLocalData); Method originalMethod = class_getInstanceMethod(cls, originalSelector); Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); - // method_exchangeImplementations(originalMethod, swizzledMethod); + method_exchangeImplementations(originalMethod, swizzledMethod); + } + + { + // swizzle textOf + SEL originalSelector = @selector(textOf:equals:); + SEL swizzledSelector = @selector(markdown_textOf:equals:); + Method originalMethod = class_getInstanceMethod(cls, originalSelector); + Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); + method_exchangeImplementations(originalMethod, swizzledMethod); } }); } diff --git a/apple/RCTBaseTextInputView+Markdown.mm b/apple/RCTBaseTextInputView+Markdown.mm index 7662d545..a0800a1b 100644 --- a/apple/RCTBaseTextInputView+Markdown.mm +++ b/apple/RCTBaseTextInputView+Markdown.mm @@ -47,7 +47,7 @@ - (void)markdown_updateLocalData id backedTextInputView = self.backedTextInputView; NSAttributedString *oldAttributedText = backedTextInputView.attributedText; NSAttributedString *newAttributedText = [markdownUtils parseMarkdown:oldAttributedText withAttributes:backedTextInputView.defaultTextAttributes]; - UITextRange *range = backedTextInputView.selectedTextRange; + NSRange range = backedTextInputView.selectedTextRange; // update attributed text without emitting onSelectionChange event id delegate = backedTextInputView.textInputDelegate; diff --git a/apple/RCTMarkdownUtils.h b/apple/RCTMarkdownUtils.h index c6f0f9f7..4d080bb8 100644 --- a/apple/RCTMarkdownUtils.h +++ b/apple/RCTMarkdownUtils.h @@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN @interface RCTMarkdownUtils : NSObject @property (nonatomic) RCTMarkdownStyle *markdownStyle; -@property (nonatomic) NSMutableArray *blockquoteRangesAndLevels; +@property (nonatomic) NSMutableArray *blockquoteRangesAndLevels; - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withAttributes:(nullable NSDictionary*)attributes; diff --git a/apple/RCTMarkdownUtils.mm b/apple/RCTMarkdownUtils.mm index c22a8784..43d027d2 100644 --- a/apple/RCTMarkdownUtils.mm +++ b/apple/RCTMarkdownUtils.mm @@ -197,7 +197,7 @@ static void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText) return; } - maximumFontLineHeight = MAX(font.lineHeight, maximumFontLineHeight); + maximumFontLineHeight = MAX(UIFontLineHeight(font), maximumFontLineHeight); // [macOS] }]; if (maximumLineHeight < maximumFontLineHeight) {