react-native-enriched-markdown-scaffold 0.7.4-scaffold.1 → 0.7.4-scaffold.10

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.
Files changed (103) hide show
  1. package/android/build.gradle +5 -0
  2. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +3 -0
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +1 -0
  4. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +5 -0
  5. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +49 -0
  6. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +6 -4
  7. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +20 -0
  8. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +55 -9
  9. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockSyntaxSentinel.kt +69 -0
  10. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +71 -12
  11. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputLayoutManager.kt +30 -2
  12. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +7 -2
  13. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +3 -0
  14. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +1 -0
  15. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +8 -1
  16. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -1
  17. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +5 -1
  18. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathFontWeight.kt +25 -0
  19. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +12 -1
  20. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +7 -7
  21. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +10 -0
  22. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/SpannableExtensions.kt +12 -4
  23. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +1 -1
  24. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +2 -0
  25. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
  26. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlinePlaceholderSpan.kt +7 -3
  27. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +8 -5
  28. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathTypeface.kt +30 -0
  29. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +3 -1
  30. package/docs/API_REFERENCE.md +9 -0
  31. package/docs/INPUT.md +48 -0
  32. package/docs/LATEX_MATH.md +62 -0
  33. package/docs/STYLES.md +3 -0
  34. package/ios/EnrichedMarkdown.mm +44 -12
  35. package/ios/EnrichedMarkdownText.mm +47 -11
  36. package/ios/attachments/ENRMMathInlineAttachment+macOS.m +5 -1
  37. package/ios/attachments/ENRMMathInlineAttachment.h +3 -0
  38. package/ios/attachments/ENRMMathInlineAttachment.m +2 -1
  39. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +5 -0
  40. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +49 -0
  41. package/ios/input/ENRMBlockSyntaxSentinel.h +25 -0
  42. package/ios/input/ENRMBlockSyntaxSentinel.mm +80 -0
  43. package/ios/input/ENRMInputFormatter.h +4 -0
  44. package/ios/input/ENRMInputFormatter.mm +2 -0
  45. package/ios/input/ENRMInputParser.h +5 -0
  46. package/ios/input/ENRMInputParser.mm +79 -6
  47. package/ios/input/EnrichedMarkdownTextInput.mm +55 -22
  48. package/ios/input/InputStylePropsUtils.h +13 -0
  49. package/ios/internals/MeasurementCache.h +1 -0
  50. package/ios/math/ENRMRaTeXBridge.swift +52 -3
  51. package/ios/parser/ENRMMarkdownParser.h +8 -0
  52. package/ios/parser/ENRMMarkdownParser.mm +11 -0
  53. package/ios/renderer/ENRMMathInlineRenderer.m +3 -0
  54. package/ios/renderer/ListItemRenderer.m +8 -5
  55. package/ios/styles/StyleConfig.h +6 -0
  56. package/ios/styles/StyleConfig.mm +36 -0
  57. package/ios/utils/ENRMMathFontWeight.h +18 -0
  58. package/ios/utils/StylePropsUtils.h +21 -0
  59. package/ios/views/ENRMMathContainerView.m +3 -1
  60. package/lib/module/EnrichedMarkdownNativeComponent.ts +3 -0
  61. package/lib/module/EnrichedMarkdownTextInput.js +2 -0
  62. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  63. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +12 -0
  64. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +3 -0
  65. package/lib/module/normalizeMarkdownStyle.js +5 -2
  66. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  67. package/lib/module/normalizeMarkdownStyle.web.js +5 -2
  68. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  69. package/lib/module/normalizeMarkdownTextInputStyle.js +7 -3
  70. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  71. package/lib/module/web/globalStyles.js +8 -1
  72. package/lib/module/web/globalStyles.js.map +1 -1
  73. package/lib/module/web/styles.js +3 -1
  74. package/lib/module/web/styles.js.map +1 -1
  75. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +3 -0
  76. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  77. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +3 -1
  78. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  79. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +12 -0
  80. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  81. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +3 -0
  82. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  83. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  84. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  85. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +1 -0
  86. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  87. package/lib/typescript/src/types/MarkdownStyle.d.ts +32 -0
  88. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  89. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +3 -0
  90. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  91. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  92. package/package.json +1 -1
  93. package/src/EnrichedMarkdownNativeComponent.ts +3 -0
  94. package/src/EnrichedMarkdownTextInput.tsx +4 -0
  95. package/src/EnrichedMarkdownTextInputNativeComponent.ts +12 -0
  96. package/src/EnrichedMarkdownTextNativeComponent.ts +3 -0
  97. package/src/normalizeMarkdownStyle.ts +6 -1
  98. package/src/normalizeMarkdownStyle.web.ts +6 -1
  99. package/src/normalizeMarkdownTextInputStyle.ts +5 -0
  100. package/src/types/MarkdownStyle.ts +32 -0
  101. package/src/types/MarkdownStyleInternal.ts +3 -0
  102. package/src/web/globalStyles.ts +7 -0
  103. package/src/web/styles.ts +5 -1
@@ -123,6 +123,45 @@ static char kENRMSegmentFadeAnimatorKey;
123
123
  return concreteComponentDescriptorProvider<EnrichedMarkdownComponentDescriptor>();
124
124
  }
125
125
 
126
+ /// Clears every piece of state that `updateProps` derives from props, back to the
127
+ /// values the default-constructed `EnrichedMarkdownProps` describes.
128
+ ///
129
+ /// `updateProps` applies most props as a per-field diff against `_props`, so this
130
+ /// state is only correct while it stays in phase with the `_props` baseline it was
131
+ /// diffed from. `prepareForRecycle` resets `_props`, so it must reset this too —
132
+ /// otherwise every field the next consumer leaves at its default silently inherits
133
+ /// the previous consumer's value. Called from `initWithFrame:` as well, so the two
134
+ /// baselines cannot drift apart.
135
+ ///
136
+ /// Requires `_fontScaleObserver` to already exist.
137
+ - (void)resetPropDerivedState
138
+ {
139
+ // Discarded rather than cleared field-by-field: the style diff can only clear a
140
+ // field when new and old differ, which never holds against a reset baseline.
141
+ _config = nil;
142
+
143
+ _md4cFlags = [ENRMMd4cFlags propsDefaultFlags];
144
+ _maxFontSizeMultiplier = 0;
145
+ _allowTrailingMargin = NO;
146
+ _fontScaleObserver.allowFontScaling = YES;
147
+ _streamingAnimation = NO;
148
+ _tableStreamingMode = ENRMTableStreamingModeProgressive;
149
+ _spoilerOverlay = ENRMSpoilerOverlayParticles;
150
+ _lineBreakStrategy = NSLineBreakStrategyNone;
151
+ _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
152
+ _contextMenuItemTexts = nil;
153
+ _contextMenuItemIcons = nil;
154
+ _accessibilityLabels = nil;
155
+
156
+ // Written only once a render completes, so stale until the next one lands.
157
+ _renderedStyleFingerprint = 0;
158
+ _pendingStyleFingerprint = 0;
159
+
160
+ _dirtyFlags = ENRMDirtyNone;
161
+ _heightUpdateCounter = 0;
162
+ _state = nullptr;
163
+ }
164
+
126
165
  - (instancetype)initWithFrame:(CGRect)frame
127
166
  {
128
167
  if (self = [super initWithFrame:frame]) {
@@ -131,28 +170,22 @@ static char kENRMSegmentFadeAnimatorKey;
131
170
 
132
171
  self.backgroundColor = [RCTUIColor clearColor];
133
172
  _parser = [[ENRMMarkdownParser alloc] init];
134
- _md4cFlags = [ENRMMd4cFlags defaultFlags];
135
173
  _segmentViews = [NSMutableArray array];
136
174
  _segmentSignatures = [NSMutableArray array];
137
- _dirtyFlags = ENRMDirtyNone;
138
175
  [self configureSegmentViewRegistry];
139
176
 
140
177
  _renderCoordinator =
141
178
  [[ENRMAsyncRenderCoordinator alloc] initWithQueueLabel:"com.swmansion.enriched.markdown.container.render"];
142
179
 
143
- _maxFontSizeMultiplier = 0;
144
- _allowTrailingMargin = NO;
145
180
  _selectable = YES;
146
181
  _enableLinkPreview = YES;
147
- _streamingAnimation = NO;
148
- _tableStreamingMode = ENRMTableStreamingModeProgressive;
149
182
  _selectionMenuConfig = (ENRMSelectionMenuConfig){.copyAsMarkdown = YES, .copyImageURL = YES};
150
- _lineBreakStrategy = NSLineBreakStrategyNone;
151
- _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
152
183
  _resolvedLayoutDirection =
153
184
  [[RCTI18nUtil sharedInstance] isRTL] ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
154
185
 
155
186
  _fontScaleObserver = [[FontScaleObserver alloc] init];
187
+ [self resetPropDerivedState];
188
+
156
189
  __weak EnrichedMarkdown *weakSelf = self;
157
190
  _fontScaleObserver.onChange = ^{
158
191
  EnrichedMarkdown *strongSelf = weakSelf;
@@ -624,7 +657,7 @@ static char kENRMSegmentFadeAnimatorKey;
624
657
  selectionEnd:selectionEnd];
625
658
  });
626
659
  return buildEditMenuForSelection(textView.textStorage, textView.selectedRange, segmentMarkdown, strongSelf->_config,
627
- @[ baseMenu ], customItems, strongSelf -> _selectionMenuConfig);
660
+ @[ baseMenu ], customItems, strongSelf->_selectionMenuConfig);
628
661
  }];
629
662
  #endif
630
663
 
@@ -949,9 +982,8 @@ static char kENRMSegmentFadeAnimatorKey;
949
982
 
950
983
  _cachedMarkdown = nil;
951
984
  _renderedMarkdown = nil;
952
- _streamingAnimation = NO;
953
- _tableStreamingMode = ENRMTableStreamingModeProgressive;
954
- _dirtyFlags = ENRMDirtyNone;
985
+
986
+ [self resetPropDerivedState];
955
987
 
956
988
  [super prepareForRecycle];
957
989
  }
@@ -46,6 +46,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
46
46
  };
47
47
 
48
48
  @interface EnrichedMarkdownText () <RCTEnrichedMarkdownTextViewProtocol, UITextViewDelegate>
49
+ - (void)resetPropDerivedState;
49
50
  - (void)setupTextView;
50
51
  - (void)renderMarkdownContent:(NSString *)markdownString;
51
52
  - (void)applyRenderedText:(NSMutableAttributedString *)attributedText;
@@ -177,6 +178,46 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
177
178
  ENRMRequestHeightUpdate<EnrichedMarkdownTextState>(_state, _heightUpdateCounter, self);
178
179
  }
179
180
 
181
+ /// Clears every piece of state that `updateProps` derives from props, back to the
182
+ /// values the default-constructed `EnrichedMarkdownTextProps` describes.
183
+ ///
184
+ /// `updateProps` applies most props as a per-field diff against `_props`, so this
185
+ /// state is only correct while it stays in phase with the `_props` baseline it was
186
+ /// diffed from. `prepareForRecycle` resets `_props`, so it must reset this too —
187
+ /// otherwise every field the next consumer leaves at its default silently inherits
188
+ /// the previous consumer's value. Called from `initWithFrame:` as well, so the two
189
+ /// baselines cannot drift apart.
190
+ ///
191
+ /// Requires `_fontScaleObserver` to already exist.
192
+ - (void)resetPropDerivedState
193
+ {
194
+ // Discarded rather than cleared field-by-field: the style diff can only clear a
195
+ // field when new and old differ, which never holds against a reset baseline.
196
+ _config = nil;
197
+ _spoilerManager = nil;
198
+
199
+ _md4cFlags = [ENRMMd4cFlags propsDefaultFlags];
200
+ _maxFontSizeMultiplier = 0;
201
+ _allowTrailingMargin = NO;
202
+ _fontScaleObserver.allowFontScaling = YES;
203
+ _streamingAnimation = NO;
204
+ _lineBreakStrategy = NSLineBreakStrategyNone;
205
+ _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
206
+ _contextMenuItemTexts = nil;
207
+ _contextMenuItemIcons = nil;
208
+ _accessibilityLabels = nil;
209
+
210
+ // Written only once a render completes, so stale until the next one lands.
211
+ _renderedStyleFingerprint = 0;
212
+ _pendingStyleFingerprint = 0;
213
+ _lastElementMarginBottom = 0;
214
+
215
+ _dirtyFlags = ENRMDirtyNone;
216
+ _forceHeightUpdateOnNextRender = NO;
217
+ _heightUpdateCounter = 0;
218
+ _state = nullptr;
219
+ }
220
+
180
221
  - (instancetype)initWithFrame:(CGRect)frame
181
222
  {
182
223
  if (self = [super initWithFrame:frame]) {
@@ -185,23 +226,18 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
185
226
 
186
227
  self.backgroundColor = [RCTUIColor clearColor];
187
228
  _parser = [[ENRMMarkdownParser alloc] init];
188
- _md4cFlags = [ENRMMd4cFlags defaultFlags];
189
229
 
190
230
  _renderCoordinator =
191
231
  [[ENRMAsyncRenderCoordinator alloc] initWithQueueLabel:"com.swmansion.enriched.markdown.render"];
192
232
 
193
- _maxFontSizeMultiplier = 0;
194
- _allowTrailingMargin = NO;
195
233
  _enableLinkPreview = YES;
196
- _forceHeightUpdateOnNextRender = NO;
197
234
  _selectionMenuConfig = (ENRMSelectionMenuConfig){.copyAsMarkdown = YES, .copyImageURL = YES};
198
- _lineBreakStrategy = NSLineBreakStrategyNone;
199
- _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
200
235
  _resolvedLayoutDirection =
201
236
  [[RCTI18nUtil sharedInstance] isRTL] ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
202
- _dirtyFlags = ENRMDirtyNone;
203
237
 
204
238
  _fontScaleObserver = [[FontScaleObserver alloc] init];
239
+ [self resetPropDerivedState];
240
+
205
241
  __weak EnrichedMarkdownText *weakSelf = self;
206
242
  _fontScaleObserver.onChange = ^{
207
243
  EnrichedMarkdownText *strongSelf = weakSelf;
@@ -253,8 +289,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
253
289
  selectionEnd:selectionEnd];
254
290
  });
255
291
  return buildEditMenuForSelection(textView.textStorage, textView.selectedRange, strongSelf->_cachedMarkdown,
256
- strongSelf->_config, @[ baseMenu ], customItems,
257
- strongSelf -> _selectionMenuConfig);
292
+ strongSelf->_config, @[ baseMenu ], customItems, strongSelf->_selectionMenuConfig);
258
293
  };
259
294
  #endif
260
295
 
@@ -636,14 +671,15 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
636
671
  [_fadeAnimator cancel];
637
672
  _fadeAnimator = nil;
638
673
  _previousTextLength = 0;
639
- _streamingAnimation = NO;
640
- _forceHeightUpdateOnNextRender = NO;
641
674
  _cachedMarkdown = nil;
642
675
  _renderedMarkdown = nil;
643
676
  _accessibilityElements = nil;
644
677
  _accessibilityInfo = nil;
645
678
  _accessibilityNeedsRebuild = NO;
646
679
  [_spoilerManager removeAllOverlays];
680
+
681
+ [self resetPropDerivedState];
682
+
647
683
  if (_textView != nil) {
648
684
  ENRMSetAttributedText(_textView, [[NSAttributedString alloc] initWithString:@""]);
649
685
  _textView.hidden = YES;
@@ -25,7 +25,11 @@
25
25
  - (void)renderForMacOS
26
26
  {
27
27
  RCTUIColor *color = self.mathTextColor ?: [RCTUIColor blackColor];
28
- ENRMRaTeXRenderResult *result = [ENRMRaTeXBridge parse:self.latex displayMode:NO fontSize:self.fontSize color:color];
28
+ ENRMRaTeXRenderResult *result = [ENRMRaTeXBridge parse:self.latex
29
+ displayMode:NO
30
+ fontSize:self.fontSize
31
+ color:color
32
+ bold:self.bold];
29
33
  if (!result)
30
34
  return;
31
35
 
@@ -9,6 +9,9 @@ NS_ASSUME_NONNULL_BEGIN
9
9
  @property (nonatomic, assign) CGFloat fontSize;
10
10
  @property (nonatomic, strong, nullable) RCTUIColor *mathTextColor;
11
11
 
12
+ /// Typeset the glyphs at bold weight (synthetic — see ENRMRaTeXBridge).
13
+ @property (nonatomic, assign) BOOL bold;
14
+
12
15
  /// YES if block math (`$$...$$`), NO for inline (`$...$`).
13
16
  @property (nonatomic, assign) BOOL displayMode;
14
17
 
@@ -21,7 +21,8 @@
21
21
  ENRMRaTeXRenderResult *result = [ENRMRaTeXBridge parse:self.latex
22
22
  displayMode:self.displayMode
23
23
  fontSize:self.fontSize
24
- color:color];
24
+ color:color
25
+ bold:self.bold];
25
26
  if (!result)
26
27
  return;
27
28
 
@@ -144,6 +144,7 @@ EnrichedMarkdownTextInputProps::EnrichedMarkdownTextInputProps(
144
144
  editable(convertRawProp(context, rawProps, "editable", sourceProps.editable, {false})),
145
145
  autoFocus(convertRawProp(context, rawProps, "autoFocus", sourceProps.autoFocus, {false})),
146
146
  scrollEnabled(convertRawProp(context, rawProps, "scrollEnabled", sourceProps.scrollEnabled, {false})),
147
+ blockSyntax(convertRawProp(context, rawProps, "blockSyntax", sourceProps.blockSyntax, {false})),
147
148
  autoCapitalize(convertRawProp(context, rawProps, "autoCapitalize", sourceProps.autoCapitalize, {})),
148
149
  multiline(convertRawProp(context, rawProps, "multiline", sourceProps.multiline, {false})),
149
150
  cursorColor(convertRawProp(context, rawProps, "cursorColor", sourceProps.cursorColor, {})),
@@ -202,6 +203,10 @@ folly::dynamic EnrichedMarkdownTextInputProps::getDiffProps(
202
203
  result["scrollEnabled"] = scrollEnabled;
203
204
  }
204
205
 
206
+ if (blockSyntax != oldProps->blockSyntax) {
207
+ result["blockSyntax"] = blockSyntax;
208
+ }
209
+
205
210
  if (autoCapitalize != oldProps->autoCapitalize) {
206
211
  result["autoCapitalize"] = autoCapitalize;
207
212
  }
@@ -1534,6 +1534,7 @@ struct EnrichedMarkdownMarkdownStyleMathStruct {
1534
1534
  Float marginTop{0.0};
1535
1535
  Float marginBottom{0.0};
1536
1536
  std::string textAlign{};
1537
+ std::string fontWeight{};
1537
1538
 
1538
1539
 
1539
1540
  #ifdef RN_SERIALIZABLE_STATE
@@ -1548,6 +1549,7 @@ struct EnrichedMarkdownMarkdownStyleMathStruct {
1548
1549
  result["marginTop"] = marginTop;
1549
1550
  result["marginBottom"] = marginBottom;
1550
1551
  result["textAlign"] = textAlign;
1552
+ result["fontWeight"] = fontWeight;
1551
1553
  return result;
1552
1554
  }
1553
1555
  #endif
@@ -1584,6 +1586,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
1584
1586
  if (tmp_textAlign != map.end()) {
1585
1587
  fromRawValue(context, tmp_textAlign->second, result.textAlign);
1586
1588
  }
1589
+ auto tmp_fontWeight = map.find("fontWeight");
1590
+ if (tmp_fontWeight != map.end()) {
1591
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
1592
+ }
1587
1593
  }
1588
1594
 
1589
1595
  static inline std::string toString(const EnrichedMarkdownMarkdownStyleMathStruct &value) {
@@ -1598,6 +1604,8 @@ static inline folly::dynamic toDynamic(const EnrichedMarkdownMarkdownStyleMathSt
1598
1604
 
1599
1605
  struct EnrichedMarkdownMarkdownStyleInlineMathStruct {
1600
1606
  SharedColor color{};
1607
+ Float paddingVertical{0.0};
1608
+ std::string fontWeight{};
1601
1609
 
1602
1610
 
1603
1611
  #ifdef RN_SERIALIZABLE_STATE
@@ -1606,6 +1614,8 @@ struct EnrichedMarkdownMarkdownStyleInlineMathStruct {
1606
1614
  folly::dynamic toDynamic() const {
1607
1615
  folly::dynamic result = folly::dynamic::object();
1608
1616
  result["color"] = ::facebook::react::toDynamic(color);
1617
+ result["paddingVertical"] = paddingVertical;
1618
+ result["fontWeight"] = fontWeight;
1609
1619
  return result;
1610
1620
  }
1611
1621
  #endif
@@ -1618,6 +1628,14 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
1618
1628
  if (tmp_color != map.end()) {
1619
1629
  fromRawValue(context, tmp_color->second, result.color);
1620
1630
  }
1631
+ auto tmp_paddingVertical = map.find("paddingVertical");
1632
+ if (tmp_paddingVertical != map.end()) {
1633
+ fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical);
1634
+ }
1635
+ auto tmp_fontWeight = map.find("fontWeight");
1636
+ if (tmp_fontWeight != map.end()) {
1637
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
1638
+ }
1621
1639
  }
1622
1640
 
1623
1641
  static inline std::string toString(const EnrichedMarkdownMarkdownStyleInlineMathStruct &value) {
@@ -2804,6 +2822,7 @@ struct EnrichedMarkdownTextInputMarkdownStyleMathStruct {
2804
2822
  Float paddingVertical{0.0};
2805
2823
  SharedColor selectedBackgroundColor{};
2806
2824
  SharedColor selectedBorderColor{};
2825
+ std::string fontWeight{};
2807
2826
 
2808
2827
 
2809
2828
  #ifdef RN_SERIALIZABLE_STATE
@@ -2821,6 +2840,7 @@ struct EnrichedMarkdownTextInputMarkdownStyleMathStruct {
2821
2840
  result["paddingVertical"] = paddingVertical;
2822
2841
  result["selectedBackgroundColor"] = ::facebook::react::toDynamic(selectedBackgroundColor);
2823
2842
  result["selectedBorderColor"] = ::facebook::react::toDynamic(selectedBorderColor);
2843
+ result["fontWeight"] = fontWeight;
2824
2844
  return result;
2825
2845
  }
2826
2846
  #endif
@@ -2869,6 +2889,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
2869
2889
  if (tmp_selectedBorderColor != map.end()) {
2870
2890
  fromRawValue(context, tmp_selectedBorderColor->second, result.selectedBorderColor);
2871
2891
  }
2892
+ auto tmp_fontWeight = map.find("fontWeight");
2893
+ if (tmp_fontWeight != map.end()) {
2894
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
2895
+ }
2872
2896
  }
2873
2897
 
2874
2898
  static inline std::string toString(const EnrichedMarkdownTextInputMarkdownStyleMathStruct &value) {
@@ -2892,6 +2916,7 @@ struct EnrichedMarkdownTextInputMarkdownStyleMathBlockStruct {
2892
2916
  Float paddingVertical{0.0};
2893
2917
  SharedColor selectedBackgroundColor{};
2894
2918
  SharedColor selectedBorderColor{};
2919
+ std::string fontWeight{};
2895
2920
  Float marginTop{0.0};
2896
2921
  Float marginBottom{0.0};
2897
2922
  std::string alignment{};
@@ -2912,6 +2937,7 @@ struct EnrichedMarkdownTextInputMarkdownStyleMathBlockStruct {
2912
2937
  result["paddingVertical"] = paddingVertical;
2913
2938
  result["selectedBackgroundColor"] = ::facebook::react::toDynamic(selectedBackgroundColor);
2914
2939
  result["selectedBorderColor"] = ::facebook::react::toDynamic(selectedBorderColor);
2940
+ result["fontWeight"] = fontWeight;
2915
2941
  result["marginTop"] = marginTop;
2916
2942
  result["marginBottom"] = marginBottom;
2917
2943
  result["alignment"] = alignment;
@@ -2963,6 +2989,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
2963
2989
  if (tmp_selectedBorderColor != map.end()) {
2964
2990
  fromRawValue(context, tmp_selectedBorderColor->second, result.selectedBorderColor);
2965
2991
  }
2992
+ auto tmp_fontWeight = map.find("fontWeight");
2993
+ if (tmp_fontWeight != map.end()) {
2994
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
2995
+ }
2966
2996
  auto tmp_marginTop = map.find("marginTop");
2967
2997
  if (tmp_marginTop != map.end()) {
2968
2998
  fromRawValue(context, tmp_marginTop->second, result.marginTop);
@@ -3329,6 +3359,7 @@ class EnrichedMarkdownTextInputProps final : public ViewProps {
3329
3359
  bool editable{false};
3330
3360
  bool autoFocus{false};
3331
3361
  bool scrollEnabled{false};
3362
+ bool blockSyntax{false};
3332
3363
  std::string autoCapitalize{};
3333
3364
  bool multiline{false};
3334
3365
  SharedColor cursorColor{};
@@ -4872,6 +4903,7 @@ struct EnrichedMarkdownTextMarkdownStyleMathStruct {
4872
4903
  Float marginTop{0.0};
4873
4904
  Float marginBottom{0.0};
4874
4905
  std::string textAlign{};
4906
+ std::string fontWeight{};
4875
4907
 
4876
4908
 
4877
4909
  #ifdef RN_SERIALIZABLE_STATE
@@ -4886,6 +4918,7 @@ struct EnrichedMarkdownTextMarkdownStyleMathStruct {
4886
4918
  result["marginTop"] = marginTop;
4887
4919
  result["marginBottom"] = marginBottom;
4888
4920
  result["textAlign"] = textAlign;
4921
+ result["fontWeight"] = fontWeight;
4889
4922
  return result;
4890
4923
  }
4891
4924
  #endif
@@ -4922,6 +4955,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
4922
4955
  if (tmp_textAlign != map.end()) {
4923
4956
  fromRawValue(context, tmp_textAlign->second, result.textAlign);
4924
4957
  }
4958
+ auto tmp_fontWeight = map.find("fontWeight");
4959
+ if (tmp_fontWeight != map.end()) {
4960
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
4961
+ }
4925
4962
  }
4926
4963
 
4927
4964
  static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleMathStruct &value) {
@@ -4936,6 +4973,8 @@ static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleMa
4936
4973
 
4937
4974
  struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct {
4938
4975
  SharedColor color{};
4976
+ Float paddingVertical{0.0};
4977
+ std::string fontWeight{};
4939
4978
 
4940
4979
 
4941
4980
  #ifdef RN_SERIALIZABLE_STATE
@@ -4944,6 +4983,8 @@ struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct {
4944
4983
  folly::dynamic toDynamic() const {
4945
4984
  folly::dynamic result = folly::dynamic::object();
4946
4985
  result["color"] = ::facebook::react::toDynamic(color);
4986
+ result["paddingVertical"] = paddingVertical;
4987
+ result["fontWeight"] = fontWeight;
4947
4988
  return result;
4948
4989
  }
4949
4990
  #endif
@@ -4956,6 +4997,14 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
4956
4997
  if (tmp_color != map.end()) {
4957
4998
  fromRawValue(context, tmp_color->second, result.color);
4958
4999
  }
5000
+ auto tmp_paddingVertical = map.find("paddingVertical");
5001
+ if (tmp_paddingVertical != map.end()) {
5002
+ fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical);
5003
+ }
5004
+ auto tmp_fontWeight = map.find("fontWeight");
5005
+ if (tmp_fontWeight != map.end()) {
5006
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
5007
+ }
4959
5008
  }
4960
5009
 
4961
5010
  static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct &value) {
@@ -0,0 +1,25 @@
1
+ #pragma once
2
+
3
+ #import <Foundation/Foundation.h>
4
+
5
+ NS_ASSUME_NONNULL_BEGIN
6
+
7
+ /// Vertical tab. md4c treats it as ordinary whitespace, never as a line break.
8
+ extern const unichar ENRMBlockSyntaxSentinelChar;
9
+
10
+ /// Collapses `\r\n` / `\r` to `\n` and drops any `0x0B` already in the input.
11
+ /// Dropping is deliberate: a pre-existing `0x0B` would come back out of
12
+ /// `ENRMBlockSyntaxDecode` as a newline and silently corrupt the text.
13
+ NSString *ENRMBlockSyntaxCanonicalize(NSString *markdown);
14
+
15
+ /// Prepends one sentinel and replaces every `\n` with one. Grows the string by
16
+ /// exactly one character and one UTF-8 byte, which is what keeps the parser's
17
+ /// byte-to-UTF16 map valid and the offset correction a flat -1.
18
+ NSString *ENRMBlockSyntaxEncode(NSString *canonical);
19
+
20
+ /// Reverses `ENRMBlockSyntaxEncode`. Returns nil when the leading sentinel is
21
+ /// missing, so the caller can fall back instead of shifting offsets that no
22
+ /// longer hold.
23
+ NSString *_Nullable ENRMBlockSyntaxDecode(NSString *plainText);
24
+
25
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,80 @@
1
+ #import "ENRMBlockSyntaxSentinel.h"
2
+
3
+ #import <vector>
4
+
5
+ const unichar ENRMBlockSyntaxSentinelChar = 0x000B;
6
+
7
+ NSString *ENRMBlockSyntaxCanonicalize(NSString *markdown)
8
+ {
9
+ NSUInteger length = markdown.length;
10
+ if (length == 0) {
11
+ return @"";
12
+ }
13
+
14
+ std::vector<unichar> source(length);
15
+ [markdown getCharacters:source.data() range:NSMakeRange(0, length)];
16
+
17
+ std::vector<unichar> out;
18
+ out.reserve(length);
19
+
20
+ for (NSUInteger i = 0; i < length; i++) {
21
+ unichar c = source[i];
22
+ if (c == '\r') {
23
+ out.push_back('\n');
24
+ if (i + 1 < length && source[i + 1] == '\n') {
25
+ i++;
26
+ }
27
+ } else if (c != ENRMBlockSyntaxSentinelChar) {
28
+ out.push_back(c);
29
+ }
30
+ }
31
+
32
+ // `out.data()` on an empty vector may be null, which -stringWithCharacters: rejects.
33
+ if (out.empty()) {
34
+ return @"";
35
+ }
36
+
37
+ return [NSString stringWithCharacters:out.data() length:out.size()];
38
+ }
39
+
40
+ NSString *ENRMBlockSyntaxEncode(NSString *canonical)
41
+ {
42
+ NSUInteger length = canonical.length;
43
+
44
+ std::vector<unichar> out;
45
+ out.reserve(length + 1);
46
+ out.push_back(ENRMBlockSyntaxSentinelChar);
47
+
48
+ if (length > 0) {
49
+ std::vector<unichar> source(length);
50
+ [canonical getCharacters:source.data() range:NSMakeRange(0, length)];
51
+ for (NSUInteger i = 0; i < length; i++) {
52
+ out.push_back(source[i] == '\n' ? ENRMBlockSyntaxSentinelChar : source[i]);
53
+ }
54
+ }
55
+
56
+ return [NSString stringWithCharacters:out.data() length:out.size()];
57
+ }
58
+
59
+ NSString *ENRMBlockSyntaxDecode(NSString *plainText)
60
+ {
61
+ NSUInteger length = plainText.length;
62
+ if (length == 0 || [plainText characterAtIndex:0] != ENRMBlockSyntaxSentinelChar) {
63
+ return nil;
64
+ }
65
+
66
+ std::vector<unichar> source(length);
67
+ [plainText getCharacters:source.data() range:NSMakeRange(0, length)];
68
+
69
+ std::vector<unichar> out;
70
+ out.reserve(length - 1);
71
+ for (NSUInteger i = 1; i < length; i++) {
72
+ out.push_back(source[i] == ENRMBlockSyntaxSentinelChar ? '\n' : source[i]);
73
+ }
74
+
75
+ if (out.empty()) {
76
+ return @"";
77
+ }
78
+
79
+ return [NSString stringWithCharacters:out.data() length:out.size()];
80
+ }
@@ -50,6 +50,8 @@ NS_ASSUME_NONNULL_BEGIN
50
50
  @property (nonatomic, assign) CGFloat mathPaddingVertical;
51
51
  @property (nonatomic, strong, nullable) RCTUIColor *mathSelectedBackgroundColor;
52
52
  @property (nonatomic, strong, nullable) RCTUIColor *mathSelectedBorderColor;
53
+ /// Raw `fontWeight` string; narrowed at the draw site (see ENRMMathFontWeight.h).
54
+ @property (nonatomic, copy, nullable) NSString *mathFontWeight;
53
55
 
54
56
  /// Math block (`$$...$$`)
55
57
  @property (nonatomic, strong, nullable) RCTUIColor *mathBlockColor;
@@ -65,6 +67,8 @@ NS_ASSUME_NONNULL_BEGIN
65
67
  @property (nonatomic, assign) CGFloat mathBlockMarginTop;
66
68
  @property (nonatomic, assign) CGFloat mathBlockMarginBottom;
67
69
  @property (nonatomic, assign) NSTextAlignment mathBlockAlignment;
70
+ /// Raw `fontWeight` string; narrowed at the draw site (see ENRMMathFontWeight.h).
71
+ @property (nonatomic, copy, nullable) NSString *mathBlockFontWeight;
68
72
 
69
73
  - (UIFont *)fontForTraits:(UIFontDescriptorSymbolicTraits)traits;
70
74
  - (void)invalidateFontCache;
@@ -56,6 +56,7 @@
56
56
  copy.mathPaddingVertical = _mathPaddingVertical;
57
57
  copy.mathSelectedBackgroundColor = _mathSelectedBackgroundColor;
58
58
  copy.mathSelectedBorderColor = _mathSelectedBorderColor;
59
+ copy.mathFontWeight = _mathFontWeight;
59
60
  copy.mathBlockColor = _mathBlockColor;
60
61
  copy.mathBlockFontSize = _mathBlockFontSize;
61
62
  copy.mathBlockBackgroundColor = _mathBlockBackgroundColor;
@@ -69,6 +70,7 @@
69
70
  copy.mathBlockMarginTop = _mathBlockMarginTop;
70
71
  copy.mathBlockMarginBottom = _mathBlockMarginBottom;
71
72
  copy.mathBlockAlignment = _mathBlockAlignment;
73
+ copy.mathBlockFontWeight = _mathBlockFontWeight;
72
74
  return copy;
73
75
  }
74
76
 
@@ -22,6 +22,11 @@ NS_ASSUME_NONNULL_BEGIN
22
22
 
23
23
  - (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown;
24
24
 
25
+ /// `blockSyntax = NO` hides block structure from md4c (see ENRMBlockSyntaxSentinel)
26
+ /// and skips `ENRMInputRemendComplete`, so list markers, headings and blockquotes
27
+ /// survive as text and the markdown round-trips byte-for-byte.
28
+ - (ENRMParseResult *)parseToPlainTextAndRanges:(NSString *)markdown blockSyntax:(BOOL)blockSyntax;
29
+
25
30
  @end
26
31
 
27
32
  NS_ASSUME_NONNULL_END