From 6ae56bd56f37ad198cddd5ffba31be7aad7d14d1 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Fri, 2 Feb 2024 22:32:00 +0100 Subject: [PATCH 01/17] Update podspec and rename `ios` directory to `apple` --- .eslintignore | 2 +- {ios => apple}/MarkdownLayoutManager.h | 0 {ios => apple}/MarkdownLayoutManager.mm | 0 {ios => apple}/MarkdownTextInputDecoratorComponentView.h | 0 {ios => apple}/MarkdownTextInputDecoratorComponentView.mm | 0 {ios => apple}/MarkdownTextInputDecoratorView.h | 0 {ios => apple}/MarkdownTextInputDecoratorView.mm | 0 {ios => apple}/MarkdownTextInputDecoratorViewManager.h | 0 {ios => apple}/MarkdownTextInputDecoratorViewManager.mm | 0 {ios => apple}/RCTBackedTextFieldDelegateAdapter+Markdown.h | 0 {ios => apple}/RCTBackedTextFieldDelegateAdapter+Markdown.m | 0 {ios => apple}/RCTBaseTextInputView+Markdown.h | 0 {ios => apple}/RCTBaseTextInputView+Markdown.m | 0 {ios => apple}/RCTMarkdownStyle.h | 0 {ios => apple}/RCTMarkdownStyle.mm | 0 {ios => apple}/RCTMarkdownUtils.h | 0 {ios => apple}/RCTMarkdownUtils.mm | 0 {ios => apple}/RCTTextInputComponentView+Markdown.h | 0 {ios => apple}/RCTTextInputComponentView+Markdown.mm | 0 {ios => apple}/RCTUITextView+Markdown.h | 0 {ios => apple}/RCTUITextView+Markdown.mm | 0 package.json | 4 ++-- react-native-live-markdown.podspec | 4 ++-- turbo.json | 2 +- 24 files changed, 6 insertions(+), 6 deletions(-) rename {ios => apple}/MarkdownLayoutManager.h (100%) rename {ios => apple}/MarkdownLayoutManager.mm (100%) rename {ios => apple}/MarkdownTextInputDecoratorComponentView.h (100%) rename {ios => apple}/MarkdownTextInputDecoratorComponentView.mm (100%) rename {ios => apple}/MarkdownTextInputDecoratorView.h (100%) rename {ios => apple}/MarkdownTextInputDecoratorView.mm (100%) rename {ios => apple}/MarkdownTextInputDecoratorViewManager.h (100%) rename {ios => apple}/MarkdownTextInputDecoratorViewManager.mm (100%) rename {ios => apple}/RCTBackedTextFieldDelegateAdapter+Markdown.h (100%) rename {ios => apple}/RCTBackedTextFieldDelegateAdapter+Markdown.m (100%) rename {ios => apple}/RCTBaseTextInputView+Markdown.h (100%) rename {ios => apple}/RCTBaseTextInputView+Markdown.m (100%) rename {ios => apple}/RCTMarkdownStyle.h (100%) rename {ios => apple}/RCTMarkdownStyle.mm (100%) rename {ios => apple}/RCTMarkdownUtils.h (100%) rename {ios => apple}/RCTMarkdownUtils.mm (100%) rename {ios => apple}/RCTTextInputComponentView+Markdown.h (100%) rename {ios => apple}/RCTTextInputComponentView+Markdown.mm (100%) rename {ios => apple}/RCTUITextView+Markdown.h (100%) rename {ios => apple}/RCTUITextView+Markdown.mm (100%) diff --git a/.eslintignore b/.eslintignore index f868bfeb..45ef798e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,7 +3,7 @@ parser/react-native-live-markdown-parser.js # any js file inside android and ios folders **/android/**/*.js -**/ios/**/*.js +**/apple/**/*.js # Output of the build process & scripts lib/**/* diff --git a/ios/MarkdownLayoutManager.h b/apple/MarkdownLayoutManager.h similarity index 100% rename from ios/MarkdownLayoutManager.h rename to apple/MarkdownLayoutManager.h diff --git a/ios/MarkdownLayoutManager.mm b/apple/MarkdownLayoutManager.mm similarity index 100% rename from ios/MarkdownLayoutManager.mm rename to apple/MarkdownLayoutManager.mm diff --git a/ios/MarkdownTextInputDecoratorComponentView.h b/apple/MarkdownTextInputDecoratorComponentView.h similarity index 100% rename from ios/MarkdownTextInputDecoratorComponentView.h rename to apple/MarkdownTextInputDecoratorComponentView.h diff --git a/ios/MarkdownTextInputDecoratorComponentView.mm b/apple/MarkdownTextInputDecoratorComponentView.mm similarity index 100% rename from ios/MarkdownTextInputDecoratorComponentView.mm rename to apple/MarkdownTextInputDecoratorComponentView.mm diff --git a/ios/MarkdownTextInputDecoratorView.h b/apple/MarkdownTextInputDecoratorView.h similarity index 100% rename from ios/MarkdownTextInputDecoratorView.h rename to apple/MarkdownTextInputDecoratorView.h diff --git a/ios/MarkdownTextInputDecoratorView.mm b/apple/MarkdownTextInputDecoratorView.mm similarity index 100% rename from ios/MarkdownTextInputDecoratorView.mm rename to apple/MarkdownTextInputDecoratorView.mm diff --git a/ios/MarkdownTextInputDecoratorViewManager.h b/apple/MarkdownTextInputDecoratorViewManager.h similarity index 100% rename from ios/MarkdownTextInputDecoratorViewManager.h rename to apple/MarkdownTextInputDecoratorViewManager.h diff --git a/ios/MarkdownTextInputDecoratorViewManager.mm b/apple/MarkdownTextInputDecoratorViewManager.mm similarity index 100% rename from ios/MarkdownTextInputDecoratorViewManager.mm rename to apple/MarkdownTextInputDecoratorViewManager.mm diff --git a/ios/RCTBackedTextFieldDelegateAdapter+Markdown.h b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.h similarity index 100% rename from ios/RCTBackedTextFieldDelegateAdapter+Markdown.h rename to apple/RCTBackedTextFieldDelegateAdapter+Markdown.h diff --git a/ios/RCTBackedTextFieldDelegateAdapter+Markdown.m b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m similarity index 100% rename from ios/RCTBackedTextFieldDelegateAdapter+Markdown.m rename to apple/RCTBackedTextFieldDelegateAdapter+Markdown.m diff --git a/ios/RCTBaseTextInputView+Markdown.h b/apple/RCTBaseTextInputView+Markdown.h similarity index 100% rename from ios/RCTBaseTextInputView+Markdown.h rename to apple/RCTBaseTextInputView+Markdown.h diff --git a/ios/RCTBaseTextInputView+Markdown.m b/apple/RCTBaseTextInputView+Markdown.m similarity index 100% rename from ios/RCTBaseTextInputView+Markdown.m rename to apple/RCTBaseTextInputView+Markdown.m diff --git a/ios/RCTMarkdownStyle.h b/apple/RCTMarkdownStyle.h similarity index 100% rename from ios/RCTMarkdownStyle.h rename to apple/RCTMarkdownStyle.h diff --git a/ios/RCTMarkdownStyle.mm b/apple/RCTMarkdownStyle.mm similarity index 100% rename from ios/RCTMarkdownStyle.mm rename to apple/RCTMarkdownStyle.mm diff --git a/ios/RCTMarkdownUtils.h b/apple/RCTMarkdownUtils.h similarity index 100% rename from ios/RCTMarkdownUtils.h rename to apple/RCTMarkdownUtils.h diff --git a/ios/RCTMarkdownUtils.mm b/apple/RCTMarkdownUtils.mm similarity index 100% rename from ios/RCTMarkdownUtils.mm rename to apple/RCTMarkdownUtils.mm diff --git a/ios/RCTTextInputComponentView+Markdown.h b/apple/RCTTextInputComponentView+Markdown.h similarity index 100% rename from ios/RCTTextInputComponentView+Markdown.h rename to apple/RCTTextInputComponentView+Markdown.h diff --git a/ios/RCTTextInputComponentView+Markdown.mm b/apple/RCTTextInputComponentView+Markdown.mm similarity index 100% rename from ios/RCTTextInputComponentView+Markdown.mm rename to apple/RCTTextInputComponentView+Markdown.mm diff --git a/ios/RCTUITextView+Markdown.h b/apple/RCTUITextView+Markdown.h similarity index 100% rename from ios/RCTUITextView+Markdown.h rename to apple/RCTUITextView+Markdown.h diff --git a/ios/RCTUITextView+Markdown.mm b/apple/RCTUITextView+Markdown.mm similarity index 100% rename from ios/RCTUITextView+Markdown.mm rename to apple/RCTUITextView+Markdown.mm diff --git a/package.json b/package.json index c9160512..866642e9 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,10 @@ "lib", "parser/react-native-live-markdown-parser.js", "android", - "ios", + "apple", "cpp", "*.podspec", - "!ios/build", + "!apple/build", "!android/build", "!android/gradle", "!android/gradlew", diff --git a/react-native-live-markdown.podspec b/react-native-live-markdown.podspec index ab67b029..6f0a0709 100644 --- a/react-native-live-markdown.podspec +++ b/react-native-live-markdown.podspec @@ -11,10 +11,10 @@ Pod::Spec.new do |s| s.license = package["license"] s.authors = package["author"] - s.platforms = { :ios => "11.0" } + s.platforms = { :ios => "11.0", osx: "10.15" } s.source = { :git => "https://github.com/expensify/react-native-live-markdown.git", :tag => "#{s.version}" } - s.source_files = "ios/**/*.{h,m,mm}" + s.source_files = "apple/**/*.{h,m,mm}" s.resources = "parser/react-native-live-markdown-parser.js" diff --git a/turbo.json b/turbo.json index ba8a8aa7..fae3b13c 100644 --- a/turbo.json +++ b/turbo.json @@ -17,7 +17,7 @@ "outputs": [] }, "build:ios": { - "inputs": ["package.json", "*.podspec", "ios", "src/*.ts", "src/*.tsx", "example/package.json", "example/ios", "!example/ios/build", "!example/ios/Pods"], + "inputs": ["package.json", "*.podspec", "apple", "src/*.ts", "src/*.tsx", "example/package.json", "example/ios", "!example/ios/build", "!example/ios/Pods"], "outputs": [] } } From aa8dad8928b1b677c25ab8fa43933e6aa17096fc Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Fri, 2 Feb 2024 22:35:15 +0100 Subject: [PATCH 02/17] Some more changes --- apple/MarkdownLayoutManager.h | 3 --- apple/MarkdownLayoutManager.mm | 5 ++-- apple/MarkdownTextInputDecoratorView.h | 3 +-- apple/MarkdownTextInputDecoratorView.mm | 15 ++++++------ .../MarkdownTextInputDecoratorViewManager.mm | 2 +- ...TBackedTextFieldDelegateAdapter+Markdown.m | 2 +- apple/RCTBaseTextInputView+Markdown.m | 2 +- apple/RCTMarkdownStyle.h | 24 ++++++++++--------- apple/RCTMarkdownUtils.h | 4 ++-- apple/RCTMarkdownUtils.mm | 2 +- apple/RCTUITextView+Markdown.h | 1 - apple/RCTUITextView+Markdown.mm | 8 ++++--- src/MarkdownTextInput.tsx | 1 + 13 files changed, 37 insertions(+), 35 deletions(-) diff --git a/apple/MarkdownLayoutManager.h b/apple/MarkdownLayoutManager.h index fa0e9e33..a3ec6cfc 100644 --- a/apple/MarkdownLayoutManager.h +++ b/apple/MarkdownLayoutManager.h @@ -1,12 +1,9 @@ -#import #import NS_ASSUME_NONNULL_BEGIN @interface MarkdownLayoutManager : NSLayoutManager -@property(nonatomic) RCTMarkdownUtils *markdownUtils; - @end NS_ASSUME_NONNULL_END diff --git a/apple/MarkdownLayoutManager.mm b/apple/MarkdownLayoutManager.mm index 17362823..0d8967b3 100644 --- a/apple/MarkdownLayoutManager.mm +++ b/apple/MarkdownLayoutManager.mm @@ -1,3 +1,4 @@ +#import #import @implementation MarkdownLayoutManager @@ -7,7 +8,7 @@ - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origi [self enumerateLineFragmentsForGlyphRange:glyphsToShow usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) { __block BOOL isBlockquote = NO; - RCTMarkdownUtils *markdownUtils = [self valueForKey:@"markdownUtils"]; + RCTMarkdownUtils *markdownUtils = objc_getAssociatedObject(self, @selector(markdownUtils)); [markdownUtils.blockquoteRanges enumerateObjectsUsingBlock:^(NSValue *item, NSUInteger idx, BOOL * _Nonnull stop) { NSRange range = [item rangeValue]; NSUInteger start = range.location; @@ -27,7 +28,7 @@ - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origi CGFloat height = rect.size.height; CGRect lineRect = CGRectMake(x, y, width, height); [markdownUtils.markdownStyle.blockquoteBorderColor setFill]; - UIRectFill(lineRect); + NSRectFill(lineRect); } }]; } diff --git a/apple/MarkdownTextInputDecoratorView.h b/apple/MarkdownTextInputDecoratorView.h index 7de9a1f4..99b6fbaa 100644 --- a/apple/MarkdownTextInputDecoratorView.h +++ b/apple/MarkdownTextInputDecoratorView.h @@ -1,9 +1,8 @@ -#import #import NS_ASSUME_NONNULL_BEGIN -@interface MarkdownTextInputDecoratorView : UIView +@interface MarkdownTextInputDecoratorView : RCTUIView - (void)setMarkdownStyle:(RCTMarkdownStyle *)markdownStyle; diff --git a/apple/MarkdownTextInputDecoratorView.mm b/apple/MarkdownTextInputDecoratorView.mm index af73a926..bb1ec185 100644 --- a/apple/MarkdownTextInputDecoratorView.mm +++ b/apple/MarkdownTextInputDecoratorView.mm @@ -46,7 +46,7 @@ - (void)didMoveToWindow { #endif /* RCT_NEW_ARCH_ENABLED */ react_native_assert(currentIndex != 0 && currentIndex != NSNotFound && "Error while finding current component."); - UIView *view = [viewsArray objectAtIndex:currentIndex - 1]; + RCTUIView *view = [viewsArray objectAtIndex:currentIndex - 1]; #ifdef RCT_NEW_ARCH_ENABLED react_native_assert([view isKindOfClass:[RCTTextInputComponentView class]] && "Previous sibling component is not an instance of RCTTextInputComponentView."); @@ -55,7 +55,7 @@ - (void)didMoveToWindow { #else react_native_assert([view isKindOfClass:[RCTBaseTextInputView class]] && "Previous sibling component is not an instance of RCTBaseTextInputView."); _textInput = (RCTBaseTextInputView *)view; - UIView *backedTextInputView = _textInput.backedTextInputView; + RCTUIView *backedTextInputView = _textInput.backedTextInputView; #endif /* RCT_NEW_ARCH_ENABLED */ _markdownUtils = [[RCTMarkdownUtils alloc] initWithBackedTextInputView:backedTextInputView]; @@ -73,13 +73,13 @@ - (void)didMoveToWindow { NSLayoutManager *layoutManager = _textView.layoutManager; // switching to TextKit 1 compatibility mode layoutManager.allowsNonContiguousLayout = NO; // workaround for onScroll issue object_setClass(layoutManager, [MarkdownLayoutManager class]); - [layoutManager setValue:_markdownUtils forKey:@"markdownUtils"]; + objc_setAssociatedObject(layoutManager, @selector(markdownUtils), _markdownUtils, OBJC_ASSOCIATION_RETAIN); } else { react_native_assert(false && "Cannot enable Markdown for this type of TextInput."); } } -- (void)willMoveToWindow:(UIWindow *)newWindow +- (void)willMoveToWindow:(NSWindow *)newWindow { if (_textInput != nil) { [_textInput setMarkdownUtils:nil]; @@ -89,9 +89,10 @@ - (void)willMoveToWindow:(UIWindow *)newWindow } if (_textView != nil) { [_textView setMarkdownUtils:nil]; - if (_textView.layoutManager != nil && [object_getClass(_textView.layoutManager) isEqual:[MarkdownLayoutManager class]]) { - [_textView.layoutManager setValue:nil forKey:@"markdownUtils"]; - object_setClass(_textView.layoutManager, [NSLayoutManager class]); + 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]); } } } diff --git a/apple/MarkdownTextInputDecoratorViewManager.mm b/apple/MarkdownTextInputDecoratorViewManager.mm index 8efb04f9..405fcb59 100644 --- a/apple/MarkdownTextInputDecoratorViewManager.mm +++ b/apple/MarkdownTextInputDecoratorViewManager.mm @@ -5,7 +5,7 @@ @implementation MarkdownTextInputDecoratorViewManager RCT_EXPORT_MODULE(MarkdownTextInputDecoratorView) -- (UIView *)view +- (RCTUIView *)view { return [[MarkdownTextInputDecoratorView alloc] init]; } diff --git a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m index 75d49585..1155388c 100644 --- a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m +++ b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m @@ -18,7 +18,7 @@ - (void)markdown_textFieldDidChange RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { RCTUITextField *backedTextInputView = [self valueForKey:@"_backedTextInputView"]; - UITextRange *range = backedTextInputView.selectedTextRange; + NSRange range = backedTextInputView.selectedRange; backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText]; [backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; } diff --git a/apple/RCTBaseTextInputView+Markdown.m b/apple/RCTBaseTextInputView+Markdown.m index fd5f22db..66c6d80d 100644 --- a/apple/RCTBaseTextInputView+Markdown.m +++ b/apple/RCTBaseTextInputView+Markdown.m @@ -27,7 +27,7 @@ - (void)markdown_updateLocalData { RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { - UITextRange *range = self.backedTextInputView.selectedTextRange; + NSRange range = self.backedTextInputView.selectedRange; NSAttributedString *attributedText = [markdownUtils parseMarkdown:self.backedTextInputView.attributedText]; [self.backedTextInputView setAttributedText:attributedText]; [self.backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; diff --git a/apple/RCTMarkdownStyle.h b/apple/RCTMarkdownStyle.h index a29a23a2..e7921df8 100644 --- a/apple/RCTMarkdownStyle.h +++ b/apple/RCTMarkdownStyle.h @@ -1,3 +1,5 @@ +#import // [macOS] + #ifdef RCT_NEW_ARCH_ENABLED #import #endif /* RCT_NEW_ARCH_ENABLED */ @@ -6,23 +8,23 @@ NS_ASSUME_NONNULL_BEGIN @interface RCTMarkdownStyle : NSObject -@property (nonatomic) UIColor *syntaxColor; -@property (nonatomic) UIColor *linkColor; +@property (nonatomic) RCTUIColor *syntaxColor; +@property (nonatomic) RCTUIColor *linkColor; @property (nonatomic) CGFloat h1FontSize; -@property (nonatomic) UIColor *blockquoteBorderColor; +@property (nonatomic) RCTUIColor *blockquoteBorderColor; @property (nonatomic) CGFloat blockquoteBorderWidth; @property (nonatomic) CGFloat blockquoteMarginLeft; @property (nonatomic) CGFloat blockquotePaddingLeft; @property (nonatomic) NSString *codeFontFamily; -@property (nonatomic) UIColor *codeColor; -@property (nonatomic) UIColor *codeBackgroundColor; +@property (nonatomic) RCTUIColor *codeColor; +@property (nonatomic) RCTUIColor *codeBackgroundColor; @property (nonatomic) NSString *preFontFamily; -@property (nonatomic) UIColor *preColor; -@property (nonatomic) UIColor *preBackgroundColor; -@property (nonatomic) UIColor *mentionHereColor; -@property (nonatomic) UIColor *mentionHereBackgroundColor; -@property (nonatomic) UIColor *mentionUserColor; -@property (nonatomic) UIColor *mentionUserBackgroundColor; +@property (nonatomic) RCTUIColor *preColor; +@property (nonatomic) RCTUIColor *preBackgroundColor; +@property (nonatomic) RCTUIColor *mentionHereColor; +@property (nonatomic) RCTUIColor *mentionHereBackgroundColor; +@property (nonatomic) RCTUIColor *mentionUserColor; +@property (nonatomic) RCTUIColor *mentionUserBackgroundColor; #ifdef RCT_NEW_ARCH_ENABLED - (instancetype)initWithStruct:(const facebook::react::MarkdownTextInputDecoratorViewMarkdownStyleStruct &)style; diff --git a/apple/RCTMarkdownUtils.h b/apple/RCTMarkdownUtils.h index 31257cbc..dcb70497 100644 --- a/apple/RCTMarkdownUtils.h +++ b/apple/RCTMarkdownUtils.h @@ -7,9 +7,9 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) RCTMarkdownStyle *markdownStyle; @property (nonatomic) NSMutableArray *blockquoteRanges; -@property (weak, nonatomic) UIView *backedTextInputView; +@property (weak, nonatomic) RCTUIView *backedTextInputView; -- (instancetype)initWithBackedTextInputView:(UIView *)backedTextInputView; +- (instancetype)initWithBackedTextInputView:(RCTUIView *)backedTextInputView; - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input; diff --git a/apple/RCTMarkdownUtils.mm b/apple/RCTMarkdownUtils.mm index ef71cbca..abe0bcd6 100644 --- a/apple/RCTMarkdownUtils.mm +++ b/apple/RCTMarkdownUtils.mm @@ -11,7 +11,7 @@ @implementation RCTMarkdownUtils { __weak RCTMarkdownStyle *_prevMarkdownStyle; } -- (instancetype)initWithBackedTextInputView:(UIView *)backedTextInputView +- (instancetype)initWithBackedTextInputView:(RCTUIView *)backedTextInputView { if (self = [super init]) { _backedTextInputView = backedTextInputView; diff --git a/apple/RCTUITextView+Markdown.h b/apple/RCTUITextView+Markdown.h index d036b0a6..b3d83b86 100644 --- a/apple/RCTUITextView+Markdown.h +++ b/apple/RCTUITextView+Markdown.h @@ -1,4 +1,3 @@ -#import #import #import diff --git a/apple/RCTUITextView+Markdown.mm b/apple/RCTUITextView+Markdown.mm index f2a9a5bb..d5cf4f37 100644 --- a/apple/RCTUITextView+Markdown.mm +++ b/apple/RCTUITextView+Markdown.mm @@ -16,9 +16,11 @@ - (void)markdown_textDidChange { RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { - UITextRange *range = self.selectedTextRange; - super.attributedText = [markdownUtils parseMarkdown:self.attributedText]; - [super setSelectedTextRange:range]; // prevents cursor from jumping at the end when typing in the middle of the text + NSRange range = self.selectedRange; + NSAttributedString *attributedText = [markdownUtils parseMarkdown:self.attributedText]; + [self breakUndoCoalescing]; + [self.textStorage setAttributedString:attributedText ?: [NSAttributedString new]]; + [super setSelectedRange:range]; // prevents cursor from jumping at the end when typing in the middle of the text self.typingAttributes = self.defaultTextAttributes; // removes indent in new line when typing after blockquote } diff --git a/src/MarkdownTextInput.tsx b/src/MarkdownTextInput.tsx index b2414d38..1967b9f0 100644 --- a/src/MarkdownTextInput.tsx +++ b/src/MarkdownTextInput.tsx @@ -9,6 +9,7 @@ type MarkdownStyle = MarkdownTextInputDecoractorView.MarkdownStyle; const FONT_FAMILY_MONOSPACE = Platform.select({ ios: 'Courier', + macos: 'Courier', default: 'monospace', }); From 5409a4bbdfb9866b094231ae2b82117306170eee Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Fri, 2 Feb 2024 22:35:37 +0100 Subject: [PATCH 03/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c6dec42..39532ac0 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ - ⌨️ Live synchronous formatting on every keystroke - ⚡ Fully native experience (selection, spellcheck, autocomplete) - 🎨 Customizable styles -- 🌐 Universal support (Android, iOS, web) +- 🌐 Universal support (Android, iOS, macOS, web) - 🏗️ Supports New Architecture ## Installation From b5c72bf2149b99d7bd00915a0eb8cb2a919f5a75 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Mon, 5 Feb 2024 11:11:52 +0100 Subject: [PATCH 04/17] Temporarily fix --- apple/RCTBaseTextInputView+Markdown.m | 2 +- apple/RCTUITextView+Markdown.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apple/RCTBaseTextInputView+Markdown.m b/apple/RCTBaseTextInputView+Markdown.m index 66c6d80d..dd5b9da0 100644 --- a/apple/RCTBaseTextInputView+Markdown.m +++ b/apple/RCTBaseTextInputView+Markdown.m @@ -58,7 +58,7 @@ + (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); } }); } diff --git a/apple/RCTUITextView+Markdown.mm b/apple/RCTUITextView+Markdown.mm index d5cf4f37..3ce3d631 100644 --- a/apple/RCTUITextView+Markdown.mm +++ b/apple/RCTUITextView+Markdown.mm @@ -37,7 +37,7 @@ + (void)load SEL swizzledSelector = @selector(markdown_textDidChange); Method originalMethod = class_getInstanceMethod(cls, originalSelector); Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); - method_exchangeImplementations(originalMethod, swizzledMethod); + // method_exchangeImplementations(originalMethod, swizzledMethod); }); } From 2427010f2ffe056dfcddd4df86f3051da6b03b0e Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 18:23:10 +0200 Subject: [PATCH 05/17] Update RNLiveMarkdown.podspec --- RNLiveMarkdown.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNLiveMarkdown.podspec b/RNLiveMarkdown.podspec index 7a85850f..90eea736 100644 --- a/RNLiveMarkdown.podspec +++ b/RNLiveMarkdown.podspec @@ -15,7 +15,7 @@ Pod::Spec.new do |s| s.license = package["license"] s.authors = package["author"] - s.platforms = { :ios => "11.0", :visionos => "1.0", osx: "10.15" } + s.platforms = { :ios => "11.0", :visionos => "1.0", :osx => "10.15" } s.source = { :git => "https://github.com/expensify/react-native-live-markdown.git", :tag => "#{s.version}" } s.source_files = "apple/**/*.{h,m,mm}" From 3f3411197d7e8e0f0567417e944983432a0088cd Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:10:11 +0200 Subject: [PATCH 06/17] Make it build --- apple/MarkdownTextInputDecoratorView.mm | 18 +++---- ...TBackedTextFieldDelegateAdapter+Markdown.m | 5 -- ...BackedTextFieldDelegateAdapter+Markdown.mm | 5 -- apple/RCTBaseTextInputView+Markdown.m | 51 ++++++++++++++++--- apple/RCTBaseTextInputView+Markdown.mm | 2 +- apple/RCTMarkdownUtils.h | 2 +- apple/RCTMarkdownUtils.mm | 2 +- 7 files changed, 55 insertions(+), 30 deletions(-) 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) { From d519f36e9d179164a288841feb7de5d8c1f1eb52 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:11:25 +0200 Subject: [PATCH 07/17] Remove unnecessary file --- ...TBackedTextFieldDelegateAdapter+Markdown.m | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 apple/RCTBackedTextFieldDelegateAdapter+Markdown.m diff --git a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m deleted file mode 100644 index b22706e6..00000000 --- a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.m +++ /dev/null @@ -1,43 +0,0 @@ -#import -#import -#import -#import - -@implementation RCTBackedTextFieldDelegateAdapter (Markdown) - -- (void)setMarkdownUtils:(RCTMarkdownUtils *)markdownUtils { - objc_setAssociatedObject(self, @selector(getMarkdownUtils), markdownUtils, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (RCTMarkdownUtils *)getMarkdownUtils { - return objc_getAssociatedObject(self, @selector(getMarkdownUtils)); -} - -- (void)markdown_textFieldDidChange -{ - RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; - if (markdownUtils != nil) { - RCTUITextField *backedTextInputView = [self valueForKey:@"_backedTextInputView"]; - NSRange range = backedTextInputView.selectedRange; - backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText withAttributes:backedTextInputView.defaultTextAttributes]; - [backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; - } - - // Call the original method - [self markdown_textFieldDidChange]; -} - -+ (void)load -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - Class cls = [self class]; - SEL originalSelector = @selector(textFieldDidChange); - SEL swizzledSelector = @selector(markdown_textFieldDidChange); - Method originalMethod = class_getInstanceMethod(cls, originalSelector); - Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); - method_exchangeImplementations(originalMethod, swizzledMethod); - }); -} - -@end From e8c71ac5f91f57a1095373c7eb60d8e7eb7510da Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:25:06 +0200 Subject: [PATCH 08/17] Fix formatting --- apple/RCTUITextView+Markdown.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apple/RCTUITextView+Markdown.mm b/apple/RCTUITextView+Markdown.mm index f0a75a1c..f0c789b6 100644 --- a/apple/RCTUITextView+Markdown.mm +++ b/apple/RCTUITextView+Markdown.mm @@ -37,7 +37,7 @@ + (void)load SEL swizzledSelector = @selector(markdown_textDidChange); Method originalMethod = class_getInstanceMethod(cls, originalSelector); Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); - // method_exchangeImplementations(originalMethod, swizzledMethod); + method_exchangeImplementations(originalMethod, swizzledMethod); }); } From 8404341d8df8cc5c1e1ac16f026f482ed24476da Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:26:43 +0200 Subject: [PATCH 09/17] Revert some changes --- apple/MarkdownLayoutManager.mm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apple/MarkdownLayoutManager.mm b/apple/MarkdownLayoutManager.mm index ea55aa1e..6da41584 100644 --- a/apple/MarkdownLayoutManager.mm +++ b/apple/MarkdownLayoutManager.mm @@ -1,4 +1,3 @@ -#import #import @implementation MarkdownLayoutManager @@ -9,7 +8,7 @@ - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origi [self enumerateLineFragmentsForGlyphRange:glyphsToShow usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) { __block BOOL isBlockquote = NO; __block int currentDepth = 0; - RCTMarkdownUtils *markdownUtils = objc_getAssociatedObject(self, @selector(markdownUtils)); + RCTMarkdownUtils *markdownUtils = [self valueForKey:@"markdownUtils"]; [markdownUtils.blockquoteRangesAndLevels enumerateObjectsUsingBlock:^(NSDictionary *item, NSUInteger idx, BOOL * _Nonnull stop) { NSRange range = [[item valueForKey:@"range"] rangeValue]; currentDepth = [[item valueForKey:@"depth"] unsignedIntegerValue]; From 80553cbaef2f0a41194f71c4f497885f23427201 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:27:35 +0200 Subject: [PATCH 10/17] Revert some changes --- apple/MarkdownLayoutManager.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apple/MarkdownLayoutManager.h b/apple/MarkdownLayoutManager.h index d23a69e5..fed54edc 100644 --- a/apple/MarkdownLayoutManager.h +++ b/apple/MarkdownLayoutManager.h @@ -4,6 +4,8 @@ NS_ASSUME_NONNULL_BEGIN @interface MarkdownLayoutManager : NSLayoutManager +@property(nonatomic) RCTMarkdownUtils *markdownUtils; + @end NS_ASSUME_NONNULL_END From 4bf29ad16f7465faba79c742ac32272a774b5110 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:34:54 +0200 Subject: [PATCH 11/17] Fix `MarkdownLayoutManager` --- apple/MarkdownLayoutManager.mm | 3 ++- apple/MarkdownTextInputDecoratorView.mm | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/apple/MarkdownLayoutManager.mm b/apple/MarkdownLayoutManager.mm index 6da41584..c60be01a 100644 --- a/apple/MarkdownLayoutManager.mm +++ b/apple/MarkdownLayoutManager.mm @@ -1,4 +1,5 @@ #import +#import @implementation MarkdownLayoutManager @@ -8,7 +9,7 @@ - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origi [self enumerateLineFragmentsForGlyphRange:glyphsToShow usingBlock:^(CGRect rect, CGRect usedRect, NSTextContainer * _Nonnull textContainer, NSRange glyphRange, BOOL * _Nonnull stop) { __block BOOL isBlockquote = NO; __block int currentDepth = 0; - RCTMarkdownUtils *markdownUtils = [self valueForKey:@"markdownUtils"]; + RCTMarkdownUtils *markdownUtils = objc_getAssociatedObject(self, @selector(markdownUtils)); [markdownUtils.blockquoteRangesAndLevels enumerateObjectsUsingBlock:^(NSDictionary *item, NSUInteger idx, BOOL * _Nonnull stop) { NSRange range = [[item valueForKey:@"range"] rangeValue]; currentDepth = [[item valueForKey:@"depth"] unsignedIntegerValue]; diff --git a/apple/MarkdownTextInputDecoratorView.mm b/apple/MarkdownTextInputDecoratorView.mm index 6ec1a93a..2027b3e9 100644 --- a/apple/MarkdownTextInputDecoratorView.mm +++ b/apple/MarkdownTextInputDecoratorView.mm @@ -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]; // TODO -// 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]); + } } } From d1a7f2c1882864558d65ca96276eba214f973c66 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:38:33 +0200 Subject: [PATCH 12/17] Use `RCTUIWindow` instead of `NSWindow` --- apple/MarkdownTextInputDecoratorView.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apple/MarkdownTextInputDecoratorView.mm b/apple/MarkdownTextInputDecoratorView.mm index 2027b3e9..a45a487c 100644 --- a/apple/MarkdownTextInputDecoratorView.mm +++ b/apple/MarkdownTextInputDecoratorView.mm @@ -88,7 +88,7 @@ - (void)didMoveToWindow { } } -- (void)willMoveToWindow:(NSWindow *)newWindow +- (void)willMoveToWindow:(RCTUIWindow *)newWindow { if (_textInput != nil) { [_textInput setMarkdownUtils:nil]; From 3de6fe0658c70afd56906579b216287c34368b2b Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:40:49 +0200 Subject: [PATCH 13/17] Use `selectedTextRange` --- apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm index b22706e6..a0337b56 100644 --- a/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm +++ b/apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm @@ -18,7 +18,7 @@ - (void)markdown_textFieldDidChange RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { RCTUITextField *backedTextInputView = [self valueForKey:@"_backedTextInputView"]; - NSRange range = backedTextInputView.selectedRange; + NSRange range = [backedTextInputView selectedTextRange]; backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText withAttributes:backedTextInputView.defaultTextAttributes]; [backedTextInputView setSelectedTextRange:range notifyDelegate:YES]; } From 3ccac83168d986ec18bf61e62c3d916bcb2802a0 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:40:55 +0200 Subject: [PATCH 14/17] Remove unused file --- apple/RCTBaseTextInputView+Markdown.m | 101 -------------------------- 1 file changed, 101 deletions(-) delete mode 100644 apple/RCTBaseTextInputView+Markdown.m diff --git a/apple/RCTBaseTextInputView+Markdown.m b/apple/RCTBaseTextInputView+Markdown.m deleted file mode 100644 index a0800a1b..00000000 --- a/apple/RCTBaseTextInputView+Markdown.m +++ /dev/null @@ -1,101 +0,0 @@ -#import -#import -#import - -@implementation RCTBaseTextInputView (Markdown) - -- (void)setMarkdownUtils:(RCTMarkdownUtils *)markdownUtils { - objc_setAssociatedObject(self, @selector(getMarkdownUtils), markdownUtils, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (RCTMarkdownUtils *)getMarkdownUtils { - return objc_getAssociatedObject(self, @selector(getMarkdownUtils)); -} - -- (void)markdown_setAttributedText:(NSAttributedString *)attributedText -{ - RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; - if (markdownUtils != nil) { - 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) { - 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 - [self markdown_updateLocalData]; -} - -+ (void)load -{ - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - Class cls = [self class]; - - { - // swizzle setAttributedText - SEL originalSelector = @selector(setAttributedText:); - SEL swizzledSelector = @selector(markdown_setAttributedText:); - Method originalMethod = class_getInstanceMethod(cls, originalSelector); - Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); - method_exchangeImplementations(originalMethod, swizzledMethod); - } - - { - // swizzle updateLocalData - SEL originalSelector = @selector(updateLocalData); - SEL swizzledSelector = @selector(markdown_updateLocalData); - Method originalMethod = class_getInstanceMethod(cls, originalSelector); - Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); - 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); - } - }); -} - -@end From a19a31a22f988ecbf31751e327e38c781ce1dac4 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:44:18 +0200 Subject: [PATCH 15/17] Update header --- apple/RCTMarkdownStyle.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apple/RCTMarkdownStyle.h b/apple/RCTMarkdownStyle.h index b1c4de87..98496cd0 100644 --- a/apple/RCTMarkdownStyle.h +++ b/apple/RCTMarkdownStyle.h @@ -1,4 +1,4 @@ -#import // [macOS] +#import #ifdef RCT_NEW_ARCH_ENABLED #import From ece355980461470b0e7802de089ae910231d6470 Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 19:50:54 +0200 Subject: [PATCH 16/17] So far so good --- apple/RCTUITextView+Markdown.mm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apple/RCTUITextView+Markdown.mm b/apple/RCTUITextView+Markdown.mm index f0c789b6..eaf0bbd9 100644 --- a/apple/RCTUITextView+Markdown.mm +++ b/apple/RCTUITextView+Markdown.mm @@ -16,10 +16,9 @@ - (void)markdown_textDidChange { RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils]; if (markdownUtils != nil) { - NSRange range = self.selectedRange; - NSAttributedString *attributedText = [markdownUtils parseMarkdown:self.attributedText withAttributes:self.defaultTextAttributes]; - [self breakUndoCoalescing]; - [self.textStorage setAttributedString:attributedText ?: [NSAttributedString new]]; + NSRange range = [self selectedTextRange]; + NSAttributedString *attributedString = [markdownUtils parseMarkdown:self.attributedText withAttributes:self.defaultTextAttributes]; + [self.textStorage setAttributedString:attributedString ?: [NSAttributedString new]]; [super setSelectedRange:range]; // prevents cursor from jumping at the end when typing in the middle of the text self.typingAttributes = self.defaultTextAttributes; // removes indent in new line when typing after blockquote } From 7026df149fbddd1c3620132922bd1489bc151d6c Mon Sep 17 00:00:00 2001 From: Tomek Zawadzki Date: Thu, 10 Oct 2024 20:08:54 +0200 Subject: [PATCH 17/17] Make it work --- apple/RCTBaseTextInputView+Markdown.mm | 2 +- apple/RCTUITextView+Markdown.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apple/RCTBaseTextInputView+Markdown.mm b/apple/RCTBaseTextInputView+Markdown.mm index a0800a1b..1358d50f 100644 --- a/apple/RCTBaseTextInputView+Markdown.mm +++ b/apple/RCTBaseTextInputView+Markdown.mm @@ -84,7 +84,7 @@ + (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); } { diff --git a/apple/RCTUITextView+Markdown.mm b/apple/RCTUITextView+Markdown.mm index eaf0bbd9..8b3f0f34 100644 --- a/apple/RCTUITextView+Markdown.mm +++ b/apple/RCTUITextView+Markdown.mm @@ -36,7 +36,7 @@ + (void)load SEL swizzledSelector = @selector(markdown_textDidChange); Method originalMethod = class_getInstanceMethod(cls, originalSelector); Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector); - method_exchangeImplementations(originalMethod, swizzledMethod); + // method_exchangeImplementations(originalMethod, swizzledMethod); }); }