Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/**/*
Expand Down
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
3 changes: 0 additions & 3 deletions ios/MarkdownLayoutManager.h → apple/MarkdownLayoutManager.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
#import <UIKit/UIKit.h>
#import <react-native-live-markdown/RCTMarkdownUtils.h>

NS_ASSUME_NONNULL_BEGIN

@interface MarkdownLayoutManager : NSLayoutManager

@property(nonatomic) RCTMarkdownUtils *markdownUtils;

@end

NS_ASSUME_NONNULL_END
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#import <objc/runtime.h>
#import <react-native-live-markdown/MarkdownLayoutManager.h>

@implementation MarkdownLayoutManager
Expand All @@ -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;
Expand All @@ -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);
}
}];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
#import <UIKit/UIKit.h>
#import <react-native-live-markdown/RCTMarkdownStyle.h>

NS_ASSUME_NONNULL_BEGIN

@interface MarkdownTextInputDecoratorView : UIView
@interface MarkdownTextInputDecoratorView : RCTUIView

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand All @@ -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<RCTBackedTextInputViewProtocol> *backedTextInputView = _textInput.backedTextInputView;
RCTUIView<RCTBackedTextInputViewProtocol> *backedTextInputView = _textInput.backedTextInputView;
#endif /* RCT_NEW_ARCH_ENABLED */

_markdownUtils = [[RCTMarkdownUtils alloc] initWithBackedTextInputView:backedTextInputView];
Expand All @@ -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];
Expand All @@ -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]);
}
}
}
Expand Down
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
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.selectedRange;
backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText];
[backedTextInputView setSelectedTextRange:range notifyDelegate:YES];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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);
}
});
}
Expand Down
24 changes: 13 additions & 11 deletions ios/RCTMarkdownStyle.h → apple/RCTMarkdownStyle.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#import <React/RCTUIKit.h> // [macOS]

#ifdef RCT_NEW_ARCH_ENABLED
#import <react/renderer/components/RNLiveMarkdownSpec/Props.h>
#endif /* RCT_NEW_ARCH_ENABLED */
Expand All @@ -6,23 +8,23 @@ NS_ASSUME_NONNULL_BEGIN

@interface RCTMarkdownStyle : NSObject

@property (nonatomic) UIColor *syntaxColor;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think React Native macOS #defines UIColor to NSColor if that helps?

@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;
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions ios/RCTMarkdownUtils.h → apple/RCTMarkdownUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ NS_ASSUME_NONNULL_BEGIN

@property (nonatomic) RCTMarkdownStyle *markdownStyle;
@property (nonatomic) NSMutableArray<NSValue *> *blockquoteRanges;
@property (weak, nonatomic) UIView<RCTBackedTextInputViewProtocol> *backedTextInputView;
@property (weak, nonatomic) RCTUIView<RCTBackedTextInputViewProtocol> *backedTextInputView;

- (instancetype)initWithBackedTextInputView:(UIView<RCTBackedTextInputViewProtocol> *)backedTextInputView;
- (instancetype)initWithBackedTextInputView:(RCTUIView<RCTBackedTextInputViewProtocol> *)backedTextInputView;

- (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input;

Expand Down
2 changes: 1 addition & 1 deletion ios/RCTMarkdownUtils.mm → apple/RCTMarkdownUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ @implementation RCTMarkdownUtils {
__weak RCTMarkdownStyle *_prevMarkdownStyle;
}

- (instancetype)initWithBackedTextInputView:(UIView<RCTBackedTextInputViewProtocol> *)backedTextInputView
- (instancetype)initWithBackedTextInputView:(RCTUIView<RCTBackedTextInputViewProtocol> *)backedTextInputView
{
if (self = [super init]) {
_backedTextInputView = backedTextInputView;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#import <UIKit/UIKit.h>
#import <React/RCTUITextView.h>
#import <react-native-live-markdown/RCTMarkdownUtils.h>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

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

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions react-native-live-markdown.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
1 change: 1 addition & 0 deletions src/MarkdownTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type MarkdownStyle = MarkdownTextInputDecoractorView.MarkdownStyle;

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

Expand Down
2 changes: 1 addition & 1 deletion turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": []
}
}
Expand Down