Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add macOS support #149

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion RNLiveMarkdown.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
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}"
Expand Down
1 change: 0 additions & 1 deletion apple/MarkdownLayoutManager.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#import <UIKit/UIKit.h>
#import <RNLiveMarkdown/RCTMarkdownUtils.h>

NS_ASSUME_NONNULL_BEGIN
Expand Down
5 changes: 3 additions & 2 deletions apple/MarkdownLayoutManager.mm
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#import <RNLiveMarkdown/MarkdownLayoutManager.h>
#import <objc/runtime.h>

@implementation MarkdownLayoutManager

Expand All @@ -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];
Expand All @@ -31,7 +32,7 @@ - (void)drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origi
CGFloat x = paddingLeft + (level * shift) + markdownUtils.markdownStyle.blockquoteMarginLeft;
CGRect lineRect = CGRectMake(x, y, width, height);
[markdownUtils.markdownStyle.blockquoteBorderColor setFill];
UIRectFill(lineRect);
NSRectFill(lineRect);
}
}
}];
Expand Down
3 changes: 1 addition & 2 deletions apple/MarkdownTextInputDecoratorView.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#import <UIKit/UIKit.h>
#import <RNLiveMarkdown/RCTMarkdownStyle.h>

NS_ASSUME_NONNULL_BEGIN

@interface MarkdownTextInputDecoratorView : UIView
@interface MarkdownTextInputDecoratorView : RCTUIView

- (void)setMarkdownStyle:(RCTMarkdownStyle *)markdownStyle;

Expand Down
17 changes: 9 additions & 8 deletions apple/MarkdownTextInputDecoratorView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ @implementation MarkdownTextInputDecoratorView {
#else
__weak RCTBaseTextInputView *_textInput;
#endif /* RCT_NEW_ARCH_ENABLED */
__weak UIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
__weak RCTUIView<RCTBackedTextInputViewProtocol> *_backedTextInputView;
__weak RCTBackedTextFieldDelegateAdapter *_adapter;
__weak RCTUITextView *_textView;
}
Expand All @@ -47,7 +47,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.");
Expand Down Expand Up @@ -78,17 +78,17 @@ - (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]);
[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:(RCTUIWindow *)newWindow
{
if (_textInput != nil) {
[_textInput setMarkdownUtils:nil];
Expand All @@ -98,9 +98,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]);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion apple/MarkdownTextInputDecoratorViewManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ @implementation MarkdownTextInputDecoratorViewManager

RCT_EXPORT_MODULE(MarkdownTextInputDecoratorView)

- (UIView *)view
- (RCTUIView *)view
{
return [[MarkdownTextInputDecoratorView alloc] init];
}
Expand Down
2 changes: 1 addition & 1 deletion apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm
Original file line number Diff line number Diff line change
Expand Up @@ -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 selectedTextRange];
backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText withAttributes:backedTextInputView.defaultTextAttributes];
[backedTextInputView setSelectedTextRange:range notifyDelegate:YES];
}
Expand Down
4 changes: 2 additions & 2 deletions apple/RCTBaseTextInputView+Markdown.mm
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ - (void)markdown_updateLocalData
id<RCTBackedTextInputViewProtocol> 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<RCTBackedTextInputDelegate> delegate = backedTextInputView.textInputDelegate;
Expand Down Expand Up @@ -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);
}

{
Expand Down
28 changes: 14 additions & 14 deletions apple/RCTMarkdownStyle.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#import <UIKit/UIKit.h>
#import <React/RCTUIKit.h>

Check failure on line 1 in apple/RCTMarkdownStyle.h

View workflow job for this annotation

GitHub Actions / build (Fabric)

'React/RCTUIKit.h' file not found

Check failure on line 1 in apple/RCTMarkdownStyle.h

View workflow job for this annotation

GitHub Actions / build (Fabric)

'React/RCTUIKit.h' file not found

Check failure on line 1 in apple/RCTMarkdownStyle.h

View workflow job for this annotation

GitHub Actions / build (Fabric)

'React/RCTUIKit.h' file not found

Check failure on line 1 in apple/RCTMarkdownStyle.h

View workflow job for this annotation

GitHub Actions / build (Paper)

'React/RCTUIKit.h' file not found

Check failure on line 1 in apple/RCTMarkdownStyle.h

View workflow job for this annotation

GitHub Actions / build (Paper)

'React/RCTUIKit.h' file not found

Check failure on line 1 in apple/RCTMarkdownStyle.h

View workflow job for this annotation

GitHub Actions / build (Paper)

'React/RCTUIKit.h' file not found

#ifdef RCT_NEW_ARCH_ENABLED
#import <react/renderer/components/RNLiveMarkdownSpec/Props.h>
Expand All @@ -8,28 +8,28 @@

@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) CGFloat emojiFontSize;
@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) CGFloat codeFontSize;
@property (nonatomic) UIColor *codeColor;
@property (nonatomic) UIColor *codeBackgroundColor;
@property (nonatomic) RCTUIColor *codeColor;
@property (nonatomic) RCTUIColor *codeBackgroundColor;
@property (nonatomic) NSString *preFontFamily;
@property (nonatomic) CGFloat preFontSize;
@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) UIColor *mentionReportColor;
@property (nonatomic) UIColor *mentionReportBackgroundColor;
@property (nonatomic) RCTUIColor *preColor;
@property (nonatomic) RCTUIColor *preBackgroundColor;
@property (nonatomic) RCTUIColor *mentionHereColor;
@property (nonatomic) RCTUIColor *mentionHereBackgroundColor;
@property (nonatomic) RCTUIColor *mentionUserColor;
@property (nonatomic) RCTUIColor *mentionUserBackgroundColor;
@property (nonatomic) RCTUIColor *mentionReportColor;
@property (nonatomic) RCTUIColor *mentionReportBackgroundColor;

#ifdef RCT_NEW_ARCH_ENABLED
- (instancetype)initWithStruct:(const facebook::react::MarkdownTextInputDecoratorViewMarkdownStyleStruct &)style;
Expand Down
2 changes: 1 addition & 1 deletion apple/RCTMarkdownUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ static void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText)
return;
}

maximumFontLineHeight = MAX(font.lineHeight, maximumFontLineHeight);
maximumFontLineHeight = MAX(UIFontLineHeight(font), maximumFontLineHeight); // [macOS]
}];

if (maximumLineHeight < maximumFontLineHeight) {
Expand Down
1 change: 0 additions & 1 deletion apple/RCTUITextView+Markdown.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#import <UIKit/UIKit.h>
#import <React/RCTUITextView.h>
#import <RNLiveMarkdown/RCTMarkdownUtils.h>

Expand Down
9 changes: 5 additions & 4 deletions apple/RCTUITextView+Markdown.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ - (void)markdown_textDidChange
{
RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils];
if (markdownUtils != nil) {
UITextRange *range = self.selectedTextRange;
super.attributedText = [markdownUtils parseMarkdown:self.attributedText withAttributes:self.defaultTextAttributes];
[super setSelectedTextRange:range]; // prevents cursor from jumping at the end when typing in the middle of the text
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
}

Expand All @@ -35,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);
});
}

Expand Down
1 change: 1 addition & 0 deletions src/styleUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type PartialMarkdownStyle = Partial<{

const FONT_FAMILY_MONOSPACE = Platform.select({
ios: 'Courier',
macos: 'Menlo',
default: 'monospace',
});

Expand Down
Loading