@expensify/react-native-live-markdown 0.1.189 → 0.1.191

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ package com.expensify.livemarkdown;
2
+
3
+ public class MarkdownRange {
4
+ private final String mType;
5
+ private final int mStart;
6
+ private final int mLength;
7
+ private final int mDepth;
8
+
9
+ public MarkdownRange(String type, int start, int length, int depth) {
10
+ mType = type;
11
+ mStart = start;
12
+ mLength = length;
13
+ mDepth = depth;
14
+ }
15
+
16
+ public String getType() {
17
+ return mType;
18
+ }
19
+
20
+ public int getStart() {
21
+ return mStart;
22
+ }
23
+
24
+ public int getLength() {
25
+ return mLength;
26
+ }
27
+
28
+ public int getDepth() {
29
+ return mDepth;
30
+ }
31
+ }
@@ -16,6 +16,8 @@ import org.json.JSONArray;
16
16
  import org.json.JSONException;
17
17
  import org.json.JSONObject;
18
18
 
19
+ import java.util.LinkedList;
20
+ import java.util.List;
19
21
  import java.util.Objects;
20
22
 
21
23
  public class MarkdownUtils {
@@ -68,6 +70,7 @@ public class MarkdownUtils {
68
70
  mPrevParserId = mParserId;
69
71
  }
70
72
 
73
+ List<MarkdownRange> markdownRanges = new LinkedList<>();
71
74
  try {
72
75
  JSONArray ranges = new JSONArray(output);
73
76
  for (int i = 0; i < ranges.length(); i++) {
@@ -80,14 +83,21 @@ public class MarkdownUtils {
80
83
  if (length == 0 || end > input.length()) {
81
84
  continue;
82
85
  }
83
- applyRange(ssb, type, start, end, depth);
86
+ markdownRanges.add(new MarkdownRange(type, start, length, depth));
84
87
  }
85
88
  } catch (JSONException e) {
86
89
  RNLog.w(mReactContext, "[react-native-live-markdown] Incorrect schema of worklet parser output: " + e.getMessage());
87
90
  }
91
+
92
+ for (MarkdownRange markdownRange : markdownRanges) {
93
+ applyRange(ssb, markdownRange);
94
+ }
88
95
  }
89
96
 
90
- private void applyRange(SpannableStringBuilder ssb, String type, int start, int end, int depth) {
97
+ private void applyRange(SpannableStringBuilder ssb, MarkdownRange markdownRange) {
98
+ String type = markdownRange.getType();
99
+ int start = markdownRange.getStart();
100
+ int end = start + markdownRange.getLength();
91
101
  switch (type) {
92
102
  case "bold":
93
103
  setSpan(ssb, new MarkdownBoldSpan(), start, end);
@@ -149,7 +159,7 @@ public class MarkdownUtils {
149
159
  mMarkdownStyle.getBlockquoteBorderWidth(),
150
160
  mMarkdownStyle.getBlockquoteMarginLeft(),
151
161
  mMarkdownStyle.getBlockquotePaddingLeft(),
152
- depth);
162
+ markdownRange.getDepth());
153
163
  setSpan(ssb, span, start, end);
154
164
  break;
155
165
  }
@@ -0,0 +1,15 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @interface MarkdownRange : NSObject
6
+
7
+ @property (nonatomic, strong) NSString *type;
8
+ @property (nonatomic) NSRange range;
9
+ @property (nonatomic) NSUInteger depth;
10
+
11
+ - (instancetype)initWithType:(NSString *)type range:(NSRange)range depth:(NSUInteger)depth;
12
+
13
+ NS_ASSUME_NONNULL_END
14
+
15
+ @end
@@ -0,0 +1,15 @@
1
+ #import "MarkdownRange.h"
2
+
3
+ @implementation MarkdownRange
4
+
5
+ - (instancetype)initWithType:(NSString *)type range:(NSRange)range depth:(NSUInteger)depth {
6
+ self = [super init];
7
+ if (self) {
8
+ _type = type;
9
+ _range = range;
10
+ _depth = depth;
11
+ }
12
+ return self;
13
+ }
14
+
15
+ @end
@@ -1,5 +1,6 @@
1
1
  #import <RNLiveMarkdown/RCTMarkdownUtils.h>
2
2
  #import <RNLiveMarkdown/MarkdownGlobal.h>
3
+ #import <RNLiveMarkdown/MarkdownRange.h>
3
4
  #import "react_native_assert.h"
4
5
  #import <React/RCTAssert.h>
5
6
  #import <React/RCTFont.h>
@@ -32,22 +33,14 @@
32
33
  jsi::Runtime &rt = markdownRuntime->getJSIRuntime();
33
34
 
34
35
  auto markdownWorklet = expensify::livemarkdown::getMarkdownWorklet([_parserId intValue]);
36
+
37
+ NSMutableArray *markdownRanges = [[NSMutableArray alloc] init];
35
38
 
36
39
  try {
37
40
  const auto &text = jsi::String::createFromUtf8(rt, [inputString UTF8String]);
38
41
  const auto &output = markdownRuntime->runGuarded(markdownWorklet, text);
39
42
  const auto &ranges = output.asObject(rt).asArray(rt);
40
43
 
41
- NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:attributes];
42
- [attributedString beginEditing];
43
-
44
- // If the attributed string ends with underlined text, blurring the single-line input imprints the underline style across the whole string.
45
- // It looks like a bug in iOS, as there is no underline style to be found in the attributed string, especially after formatting.
46
- // This is a workaround that applies the NSUnderlineStyleNone to the string before iterating over ranges which resolves this problem.
47
- [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleNone] range:NSMakeRange(0, attributedString.length)];
48
-
49
- _blockquoteRangesAndLevels = [NSMutableArray new];
50
-
51
44
  for (size_t i = 0, n = ranges.size(rt); i < n; ++i) {
52
45
  const auto &item = ranges.getValueAtIndex(rt, i).asObject(rt);
53
46
  const auto &type = item.getProperty(rt, "type").asString(rt).utf8(rt);
@@ -55,20 +48,10 @@
55
48
  const auto &length = static_cast<int>(item.getProperty(rt, "length").asNumber());
56
49
  const auto &depth = item.hasProperty(rt, "depth") ? static_cast<int>(item.getProperty(rt, "depth").asNumber()) : 1;
57
50
 
58
- [self applyRangeToAttributedString:attributedString type:type start:start length:length depth:depth];
51
+ NSRange range = NSMakeRange(start, length);
52
+ MarkdownRange *markdownRange = [[MarkdownRange alloc] initWithType:@(type.c_str()) range:range depth:depth];
53
+ [markdownRanges addObject:markdownRange];
59
54
  }
60
-
61
- RCTApplyBaselineOffset(attributedString);
62
-
63
- [attributedString endEditing];
64
-
65
- _prevInputString = inputString;
66
- _prevAttributedString = attributedString;
67
- _prevTextAttributes = attributes;
68
- _prevMarkdownStyle = _markdownStyle;
69
- _prevParserId = _parserId;
70
-
71
- return attributedString;
72
55
  } catch (const jsi::JSError &error) {
73
56
  RCTLogWarn(@"[react-native-live-markdown] Incorrect schema of worklet parser output: %s", error.getMessage().c_str());
74
57
  NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:inputString attributes:attributes];
@@ -79,18 +62,45 @@
79
62
  _prevParserId = _parserId;
80
63
  return attributedString;
81
64
  }
65
+
66
+ NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:attributes];
67
+ [attributedString beginEditing];
68
+
69
+ // If the attributed string ends with underlined text, blurring the single-line input imprints the underline style across the whole string.
70
+ // It looks like a bug in iOS, as there is no underline style to be found in the attributed string, especially after formatting.
71
+ // This is a workaround that applies the NSUnderlineStyleNone to the string before iterating over ranges which resolves this problem.
72
+ [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleNone] range:NSMakeRange(0, attributedString.length)];
73
+
74
+ _blockquoteRangesAndLevels = [NSMutableArray new];
75
+
76
+ for (MarkdownRange *markdownRange in markdownRanges) {
77
+ [self applyRangeToAttributedString:attributedString
78
+ type:std::string([markdownRange.type UTF8String])
79
+ range:markdownRange.range
80
+ depth:markdownRange.depth];
81
+ }
82
+
83
+ RCTApplyBaselineOffset(attributedString);
84
+
85
+ [attributedString endEditing];
86
+
87
+ _prevInputString = inputString;
88
+ _prevAttributedString = attributedString;
89
+ _prevTextAttributes = attributes;
90
+ _prevMarkdownStyle = _markdownStyle;
91
+ _prevParserId = _parserId;
92
+
93
+ return attributedString;
82
94
  }
83
95
  }
84
96
 
85
- - (void)applyRangeToAttributedString:(NSMutableAttributedString *)attributedString type:(const std::string)type start:(const int)start length:(const int)length depth:(const int)depth {
86
- if (length == 0 || start + length > attributedString.length) {
97
+ - (void)applyRangeToAttributedString:(NSMutableAttributedString *)attributedString type:(const std::string)type range:(NSRange)range depth:(const int)depth {
98
+ if (range.length == 0 || range.location + range.length > attributedString.length) {
87
99
  return;
88
100
  }
89
101
 
90
- NSRange range = NSMakeRange(start, length);
91
-
92
102
  if (type == "bold" || type == "italic" || type == "code" || type == "pre" || type == "h1" || type == "emoji") {
93
- UIFont *font = [attributedString attribute:NSFontAttributeName atIndex:start effectiveRange:NULL];
103
+ UIFont *font = [attributedString attribute:NSFontAttributeName atIndex:range.location effectiveRange:NULL];
94
104
  if (type == "bold") {
95
105
  font = [RCTFont updateFont:font withWeight:@"bold"];
96
106
  } else if (type == "italic") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expensify/react-native-live-markdown",
3
- "version": "0.1.189",
3
+ "version": "0.1.191",
4
4
  "description": "Drop-in replacement for React Native's TextInput component with Markdown formatting.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",