Skip to content

Commit

Permalink
Merge branch 'main' into @tomekzaw/blockquote-text-layout-fragment
Browse files Browse the repository at this point in the history
  • Loading branch information
tomekzaw committed Jan 10, 2025
2 parents bd5e3b3 + 76258f1 commit 0778469
Show file tree
Hide file tree
Showing 37 changed files with 2,380 additions and 898 deletions.
9 changes: 0 additions & 9 deletions .yarn/patches/html-entities-npm-2.5.2-0b6113e376.patch

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ npm install @expensify/react-native-live-markdown react-native-reanimated expens
npx expo install @expensify/react-native-live-markdown react-native-reanimated expensify-common
```

React Native Live Markdown requires [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) 3.16.3 or newer and [expensify-common](https://github.com/Expensify/expensify-common) 2.0.108 or newer.
React Native Live Markdown requires [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) 3.16.4 or newer and [expensify-common](https://github.com/Expensify/expensify-common) 2.0.108 or newer.

Then, install the iOS dependencies with CocoaPods:

Expand Down
11 changes: 10 additions & 1 deletion RNLiveMarkdown.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ react_native_node_modules_dir = ENV['REACT_NATIVE_NODE_MODULES_DIR'] || File.joi
react_native_json = JSON.parse(File.read(File.join(react_native_node_modules_dir, 'react-native/package.json')))
react_native_minor_version = react_native_json['version'].split('.')[1].to_i

pods_root = Pod::Config.instance.project_pods_root
react_native_reanimated_node_modules_dir = ENV['REACT_NATIVE_REANIMATED_NODE_MODULES_DIR'] || File.dirname(`cd "#{Pod::Config.instance.installation_root.to_s}" && node --print "require.resolve('react-native-reanimated/package.json')"`)
react_native_reanimated_node_modules_dir_from_pods_root = Pathname.new(react_native_reanimated_node_modules_dir).relative_path_from(pods_root).to_s

package = JSON.parse(File.read(File.join(__dir__, "package.json")))
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'

Expand All @@ -23,7 +27,11 @@ Pod::Spec.new do |s|
s.dependency "RNReanimated/worklets"

s.xcconfig = {
"OTHER_CFLAGS" => "$(inherited) -DREACT_NATIVE_MINOR_VERSION=#{react_native_minor_version}"
"OTHER_CFLAGS" => "$(inherited) -DREACT_NATIVE_MINOR_VERSION=#{react_native_minor_version}",
"HEADER_SEARCH_PATHS" => [
"\"$(PODS_ROOT)/#{react_native_reanimated_node_modules_dir_from_pods_root}/apple\"",
"\"$(PODS_ROOT)/#{react_native_reanimated_node_modules_dir_from_pods_root}/Common/cpp\"",
].join(' '),
}

install_modules_dependencies(s)
Expand All @@ -33,6 +41,7 @@ Pod::Spec.new do |s|
"react/renderer/textlayoutmanager/platform/ios",
"react/renderer/components/textinput/platform/ios",
])
add_dependency(s, "React-rendererconsistency")
end

if ENV['RCT_NEW_ARCH_ENABLED'] == '1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ protected void onAttachedToWindow() {
mReactEditText = (ReactEditText) previousSibling;
mTextWatcher = new MarkdownTextWatcher(mMarkdownUtils);
mReactEditText.addTextChangedListener(mTextWatcher);
applyNewStyles();
}
}

Expand Down
4 changes: 2 additions & 2 deletions apple/MarkdownCommitHook.mm
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@

// apply markdown
auto newString = [usedUtils parseMarkdown:nsAttributedString
withAttributes:defaultNSTextAttributes];
withDefaultTextAttributes:defaultNSTextAttributes];

// create a clone of the old TextInputState and update the
// attributed string box to point to the string with markdown
Expand Down Expand Up @@ -247,7 +247,7 @@

// apply markdown
auto newString = [usedUtils parseMarkdown:nsAttributedString
withAttributes:defaultNSTextAttributes];
withDefaultTextAttributes:defaultNSTextAttributes];

// create a clone of the old TextInputState and update the
// attributed string box to point to the string with markdown
Expand Down
2 changes: 1 addition & 1 deletion apple/MarkdownFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const NSAttributedStringKey RCTLiveMarkdownBlockquoteDepthAttributeName = @"RCTL
@interface MarkdownFormatter : NSObject

- (nonnull NSAttributedString *)format:(nonnull NSString *)text
withAttributes:(nullable NSDictionary<NSAttributedStringKey, id>*)attributes
withDefaultTextAttributes:(nonnull NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
withMarkdownRanges:(nonnull NSArray<MarkdownRange *> *)markdownRanges
withMarkdownStyle:(nonnull RCTMarkdownStyle *)markdownStyle;

Expand Down
28 changes: 18 additions & 10 deletions apple/MarkdownFormatter.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
@implementation MarkdownFormatter

- (nonnull NSAttributedString *)format:(nonnull NSString *)text
withAttributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attributes
withDefaultTextAttributes:(nonnull NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
withMarkdownRanges:(nonnull NSArray<MarkdownRange *> *)markdownRanges
withMarkdownStyle:(nonnull RCTMarkdownStyle *)markdownStyle
{
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:defaultTextAttributes];

[attributedString beginEditing];

Expand All @@ -24,10 +24,15 @@ - (nonnull NSAttributedString *)format:(nonnull NSString *)text
type:std::string([markdownRange.type UTF8String])
range:markdownRange.range
depth:markdownRange.depth
markdownStyle:markdownStyle];
markdownStyle:markdownStyle
defaultTextAttributes:defaultTextAttributes];
}

RCTApplyBaselineOffset(attributedString);
[attributedString.string enumerateSubstringsInRange:NSMakeRange(0, attributedString.length)
options:NSStringEnumerationByLines | NSStringEnumerationSubstringNotRequired
usingBlock:^(NSString * _Nullable substring, NSRange substringRange, NSRange enclosingRange, BOOL * _Nonnull stop) {
RCTApplyBaselineOffset(attributedString, enclosingRange);
}];

[attributedString endEditing];

Expand All @@ -38,7 +43,9 @@ - (void)applyRangeToAttributedString:(NSMutableAttributedString *)attributedStri
type:(const std::string)type
range:(const NSRange)range
depth:(const int)depth
markdownStyle:(nonnull RCTMarkdownStyle *)markdownStyle {
markdownStyle:(nonnull RCTMarkdownStyle *)markdownStyle
defaultTextAttributes:(nonnull NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
{
if (type == "bold" || type == "italic" || type == "code" || type == "pre" || type == "h1" || type == "emoji") {
UIFont *font = [attributedString attribute:NSFontAttributeName atIndex:range.location effectiveRange:NULL];
if (type == "bold") {
Expand Down Expand Up @@ -99,7 +106,8 @@ - (void)applyRangeToAttributedString:(NSMutableAttributedString *)attributedStri
[attributedString addAttribute:NSForegroundColorAttributeName value:markdownStyle.linkColor range:range];
} else if (type == "blockquote") {
CGFloat indent = (markdownStyle.blockquoteMarginLeft + markdownStyle.blockquoteBorderWidth + markdownStyle.blockquotePaddingLeft) * depth;
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
NSParagraphStyle *defaultParagraphStyle = defaultTextAttributes[NSParagraphStyleAttributeName];
NSMutableParagraphStyle *paragraphStyle = defaultParagraphStyle != nil ? [defaultParagraphStyle mutableCopy] : [NSMutableParagraphStyle new];
paragraphStyle.firstLineHeadIndent = indent;
paragraphStyle.headIndent = indent;
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range];
Expand All @@ -112,12 +120,12 @@ - (void)applyRangeToAttributedString:(NSMutableAttributedString *)attributedStri
}
}

static void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText)
static void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText, NSRange attributedTextRange)
{
__block CGFloat maximumLineHeight = 0;

[attributedText enumerateAttribute:NSParagraphStyleAttributeName
inRange:NSMakeRange(0, attributedText.length)
inRange:attributedTextRange
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange range, __unused BOOL *stop) {
if (!paragraphStyle) {
Expand All @@ -135,7 +143,7 @@ static void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText)
__block CGFloat maximumFontLineHeight = 0;

[attributedText enumerateAttribute:NSFontAttributeName
inRange:NSMakeRange(0, attributedText.length)
inRange:attributedTextRange
options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
usingBlock:^(UIFont *font, NSRange range, __unused BOOL *stop) {
if (!font) {
Expand All @@ -152,7 +160,7 @@ static void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText)
CGFloat baseLineOffset = (maximumLineHeight - maximumFontLineHeight) / 2.0;
[attributedText addAttribute:NSBaselineOffsetAttributeName
value:@(baseLineOffset)
range:NSMakeRange(0, attributedText.length)];
range:attributedTextRange];
}

@end
3 changes: 2 additions & 1 deletion apple/MarkdownParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ NS_ASSUME_NONNULL_BEGIN

@interface MarkdownParser : NSObject

- (NSArray<MarkdownRange *> *)parse:(NSString *)text withParserId:(NSNumber *)parserId;
- (NSArray<MarkdownRange *> *)parse:(nonnull NSString *)text
withParserId:(nonnull NSNumber *)parserId;

NS_ASSUME_NONNULL_END

Expand Down
4 changes: 3 additions & 1 deletion apple/MarkdownParser.mm
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ @implementation MarkdownParser {
NSArray<MarkdownRange *> *_prevMarkdownRanges;
}

- (NSArray<MarkdownRange *> *)parse:(NSString *)text withParserId:(nonnull NSNumber *)parserId {
- (NSArray<MarkdownRange *> *)parse:(nonnull NSString *)text
withParserId:(nonnull NSNumber *)parserId
{
@synchronized (self) {
if ([text isEqualToString:_prevText] && [parserId isEqualToNumber:_prevParserId]) {
return _prevMarkdownRanges;
Expand Down
2 changes: 1 addition & 1 deletion apple/RCTBackedTextFieldDelegateAdapter+Markdown.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ - (void)markdown_textFieldDidChange
if (markdownUtils != nil) {
RCTUITextField *backedTextInputView = [self valueForKey:@"_backedTextInputView"];
UITextRange *range = backedTextInputView.selectedTextRange;
backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText withAttributes:backedTextInputView.defaultTextAttributes];
backedTextInputView.attributedText = [markdownUtils parseMarkdown:backedTextInputView.attributedText withDefaultTextAttributes: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 @@ -16,7 +16,7 @@ - (void)markdown_setAttributedText:(NSAttributedString *)attributedText
{
RCTMarkdownUtils *markdownUtils = [self getMarkdownUtils];
if (markdownUtils != nil) {
attributedText = [markdownUtils parseMarkdown:attributedText withAttributes:self.backedTextInputView.defaultTextAttributes];
attributedText = [markdownUtils parseMarkdown:attributedText withDefaultTextAttributes:self.backedTextInputView.defaultTextAttributes];
}

// Call the original method
Expand Down Expand Up @@ -46,7 +46,7 @@ - (void)markdown_updateLocalData
if (markdownUtils != nil) {
id<RCTBackedTextInputViewProtocol> backedTextInputView = self.backedTextInputView;
NSAttributedString *oldAttributedText = backedTextInputView.attributedText;
NSAttributedString *newAttributedText = [markdownUtils parseMarkdown:oldAttributedText withAttributes:backedTextInputView.defaultTextAttributes];
NSAttributedString *newAttributedText = [markdownUtils parseMarkdown:oldAttributedText withDefaultTextAttributes:backedTextInputView.defaultTextAttributes];
UITextRange *range = backedTextInputView.selectedTextRange;

// update attributed text without emitting onSelectionChange event
Expand Down
3 changes: 2 additions & 1 deletion apple/RCTMarkdownUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) RCTMarkdownStyle *markdownStyle;
@property (nonatomic) NSNumber *parserId;

- (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withAttributes:(nullable NSDictionary<NSAttributedStringKey, id>*)attributes;
- (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input
withDefaultTextAttributes:(nonnull NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes;

@end

Expand Down
11 changes: 6 additions & 5 deletions apple/RCTMarkdownUtils.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ @implementation RCTMarkdownUtils {
MarkdownFormatter *_markdownFormatter;
NSString *_prevInputString;
NSAttributedString *_prevAttributedString;
NSDictionary<NSAttributedStringKey, id> *_prevTextAttributes;
NSDictionary<NSAttributedStringKey, id> *_prevDefaultTextAttributes;
__weak RCTMarkdownStyle *_prevMarkdownStyle;
__weak NSNumber *_prevParserId;
}
Expand All @@ -22,27 +22,28 @@ - (instancetype)init
return self;
}

- (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input withAttributes:(nullable NSDictionary<NSAttributedStringKey,id> *)attributes
- (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input
withDefaultTextAttributes:(nonnull NSDictionary<NSAttributedStringKey, id> *)defaultTextAttributes
{
@synchronized (self) {
if (input == nil) {
return nil;
}

NSString *inputString = [input string];
if ([inputString isEqualToString:_prevInputString] && [attributes isEqualToDictionary:_prevTextAttributes] && [_markdownStyle isEqual:_prevMarkdownStyle] && [_parserId isEqualToNumber:_prevParserId]) {
if ([inputString isEqualToString:_prevInputString] && [defaultTextAttributes isEqualToDictionary:_prevDefaultTextAttributes] && [_markdownStyle isEqual:_prevMarkdownStyle] && [_parserId isEqualToNumber:_prevParserId]) {
return _prevAttributedString;
}

NSArray<MarkdownRange *> *markdownRanges = [_markdownParser parse:inputString withParserId:_parserId];

NSAttributedString *attributedString = [_markdownFormatter format:inputString
withAttributes:attributes
withDefaultTextAttributes:defaultTextAttributes
withMarkdownRanges:markdownRanges
withMarkdownStyle:_markdownStyle];
_prevInputString = inputString;
_prevAttributedString = attributedString;
_prevTextAttributes = attributes;
_prevDefaultTextAttributes = defaultTextAttributes;
_prevMarkdownStyle = _markdownStyle;
_prevParserId = _parserId;

Expand Down
Loading

0 comments on commit 0778469

Please sign in to comment.