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

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 (120) hide show
  1. package/android/build.gradle +5 -0
  2. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +9 -0
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +3 -0
  4. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +10 -0
  5. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +7 -0
  6. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +10 -0
  7. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +50 -0
  8. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +6 -4
  9. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +38 -0
  10. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +174 -9
  11. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
  12. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockSyntaxSentinel.kt +69 -0
  13. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +71 -12
  14. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +8 -0
  15. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputLayoutManager.kt +30 -2
  16. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +7 -2
  17. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +3 -0
  18. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +1 -0
  19. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +8 -1
  20. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -1
  21. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +5 -1
  22. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathFontWeight.kt +25 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +12 -1
  24. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +7 -7
  25. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +10 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/SpannableExtensions.kt +12 -4
  28. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +1 -1
  29. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +2 -0
  30. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
  31. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlinePlaceholderSpan.kt +7 -3
  32. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +8 -5
  33. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathTypeface.kt +30 -0
  34. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +3 -1
  35. package/docs/API_REFERENCE.md +43 -0
  36. package/docs/INPUT.md +87 -0
  37. package/docs/LATEX_MATH.md +62 -0
  38. package/docs/STYLES.md +3 -0
  39. package/ios/EnrichedMarkdown.mm +44 -12
  40. package/ios/EnrichedMarkdownText.mm +47 -11
  41. package/ios/attachments/ENRMMathInlineAttachment+macOS.m +5 -1
  42. package/ios/attachments/ENRMMathInlineAttachment.h +3 -0
  43. package/ios/attachments/ENRMMathInlineAttachment.m +2 -1
  44. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +10 -0
  45. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +7 -0
  46. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +10 -0
  47. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +50 -0
  48. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +29 -0
  49. package/ios/input/ENRMBlockSyntaxSentinel.h +25 -0
  50. package/ios/input/ENRMBlockSyntaxSentinel.mm +80 -0
  51. package/ios/input/ENRMInputFormatter.h +4 -0
  52. package/ios/input/ENRMInputFormatter.mm +2 -0
  53. package/ios/input/ENRMInputParser.h +5 -0
  54. package/ios/input/ENRMInputParser.mm +79 -6
  55. package/ios/input/ENRMInputTextView.mm +11 -1
  56. package/ios/input/EnrichedMarkdownTextInput.h +5 -0
  57. package/ios/input/EnrichedMarkdownTextInput.mm +88 -22
  58. package/ios/input/InputStylePropsUtils.h +13 -0
  59. package/ios/internals/MeasurementCache.h +1 -0
  60. package/ios/math/ENRMRaTeXBridge.swift +52 -3
  61. package/ios/parser/ENRMMarkdownParser.h +8 -0
  62. package/ios/parser/ENRMMarkdownParser.mm +11 -0
  63. package/ios/renderer/ENRMMathInlineRenderer.m +3 -0
  64. package/ios/renderer/ListItemRenderer.m +8 -5
  65. package/ios/styles/StyleConfig.h +6 -0
  66. package/ios/styles/StyleConfig.mm +36 -0
  67. package/ios/utils/ENRMMathFontWeight.h +18 -0
  68. package/ios/utils/StylePropsUtils.h +21 -0
  69. package/ios/views/ENRMMathContainerView.m +3 -1
  70. package/lib/module/EnrichedMarkdownNativeComponent.ts +3 -0
  71. package/lib/module/EnrichedMarkdownTextInput.js +17 -0
  72. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  73. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +34 -0
  74. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +3 -0
  75. package/lib/module/index.js.map +1 -1
  76. package/lib/module/normalizeMarkdownStyle.js +5 -2
  77. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  78. package/lib/module/normalizeMarkdownStyle.web.js +5 -2
  79. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  80. package/lib/module/normalizeMarkdownTextInputStyle.js +7 -3
  81. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  82. package/lib/module/web/globalStyles.js +8 -1
  83. package/lib/module/web/globalStyles.js.map +1 -1
  84. package/lib/module/web/styles.js +3 -1
  85. package/lib/module/web/styles.js.map +1 -1
  86. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +3 -0
  87. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  88. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +26 -1
  89. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  90. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +28 -0
  91. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  92. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +3 -0
  93. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  94. package/lib/typescript/src/index.d.ts +1 -1
  95. package/lib/typescript/src/index.d.ts.map +1 -1
  96. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  97. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  98. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +1 -0
  99. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  100. package/lib/typescript/src/types/MarkdownStyle.d.ts +32 -0
  101. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  102. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +3 -0
  103. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  104. package/lib/typescript/src/types/events.d.ts +15 -0
  105. package/lib/typescript/src/types/events.d.ts.map +1 -1
  106. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  107. package/package.json +1 -1
  108. package/src/EnrichedMarkdownNativeComponent.ts +3 -0
  109. package/src/EnrichedMarkdownTextInput.tsx +41 -0
  110. package/src/EnrichedMarkdownTextInputNativeComponent.ts +34 -0
  111. package/src/EnrichedMarkdownTextNativeComponent.ts +3 -0
  112. package/src/index.tsx +1 -0
  113. package/src/normalizeMarkdownStyle.ts +6 -1
  114. package/src/normalizeMarkdownStyle.web.ts +6 -1
  115. package/src/normalizeMarkdownTextInputStyle.ts +5 -0
  116. package/src/types/MarkdownStyle.ts +32 -0
  117. package/src/types/MarkdownStyleInternal.ts +3 -0
  118. package/src/types/events.ts +16 -0
  119. package/src/web/globalStyles.ts +7 -0
  120. package/src/web/styles.ts +5 -1
package/docs/STYLES.md CHANGED
@@ -179,9 +179,12 @@ The library provides sensible default styles for all Markdown elements out of th
179
179
  padding: 12,
180
180
  marginBottom: 16,
181
181
  textAlign: 'center',
182
+ fontWeight: 'normal',
182
183
  },
183
184
  inlineMath: {
184
185
  color: '#1F2937',
186
+ paddingVertical: 4,
187
+ fontWeight: 'normal',
185
188
  },
186
189
  spoiler: {
187
190
  color: '#6B7280',
@@ -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
 
@@ -247,6 +247,16 @@ payload.setProperty(runtime, "height", event.height);
247
247
  }
248
248
 
249
249
 
250
+ void EnrichedMarkdownTextInputEventEmitter::onPaste(OnPaste event) const {
251
+ dispatchEvent("paste", [event=std::move(event)](jsi::Runtime &runtime) {
252
+ auto payload = jsi::Object(runtime);
253
+ payload.setProperty(runtime, "text", event.text);
254
+ payload.setProperty(runtime, "markdown", event.markdown);
255
+ return payload;
256
+ });
257
+ }
258
+
259
+
250
260
  void EnrichedMarkdownTextInputEventEmitter::onStartMention(OnStartMention event) const {
251
261
  dispatchEvent("startMention", [event=std::move(event)](jsi::Runtime &runtime) {
252
262
  auto payload = jsi::Object(runtime);
@@ -182,6 +182,11 @@ class EnrichedMarkdownTextInputEventEmitter : public ViewEventEmitter {
182
182
  double height;
183
183
  };
184
184
 
185
+ struct OnPaste {
186
+ std::string text;
187
+ std::string markdown;
188
+ };
189
+
185
190
  struct OnStartMention {
186
191
  std::string indicator;
187
192
  };
@@ -218,6 +223,8 @@ class EnrichedMarkdownTextInputEventEmitter : public ViewEventEmitter {
218
223
 
219
224
  void onMathPress(OnMathPress value) const;
220
225
 
226
+ void onPaste(OnPaste value) const;
227
+
221
228
  void onStartMention(OnStartMention value) const;
222
229
 
223
230
  void onChangeMention(OnChangeMention value) const;
@@ -144,7 +144,9 @@ 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, {})),
149
+ interceptPaste(convertRawProp(context, rawProps, "interceptPaste", sourceProps.interceptPaste, {false})),
148
150
  multiline(convertRawProp(context, rawProps, "multiline", sourceProps.multiline, {false})),
149
151
  cursorColor(convertRawProp(context, rawProps, "cursorColor", sourceProps.cursorColor, {})),
150
152
  selectionColor(convertRawProp(context, rawProps, "selectionColor", sourceProps.selectionColor, {})),
@@ -202,10 +204,18 @@ folly::dynamic EnrichedMarkdownTextInputProps::getDiffProps(
202
204
  result["scrollEnabled"] = scrollEnabled;
203
205
  }
204
206
 
207
+ if (blockSyntax != oldProps->blockSyntax) {
208
+ result["blockSyntax"] = blockSyntax;
209
+ }
210
+
205
211
  if (autoCapitalize != oldProps->autoCapitalize) {
206
212
  result["autoCapitalize"] = autoCapitalize;
207
213
  }
208
214
 
215
+ if (interceptPaste != oldProps->interceptPaste) {
216
+ result["interceptPaste"] = interceptPaste;
217
+ }
218
+
209
219
  if (multiline != oldProps->multiline) {
210
220
  result["multiline"] = multiline;
211
221
  }
@@ -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,7 +3359,9 @@ 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{};
3364
+ bool interceptPaste{false};
3333
3365
  bool multiline{false};
3334
3366
  SharedColor cursorColor{};
3335
3367
  SharedColor selectionColor{};
@@ -4872,6 +4904,7 @@ struct EnrichedMarkdownTextMarkdownStyleMathStruct {
4872
4904
  Float marginTop{0.0};
4873
4905
  Float marginBottom{0.0};
4874
4906
  std::string textAlign{};
4907
+ std::string fontWeight{};
4875
4908
 
4876
4909
 
4877
4910
  #ifdef RN_SERIALIZABLE_STATE
@@ -4886,6 +4919,7 @@ struct EnrichedMarkdownTextMarkdownStyleMathStruct {
4886
4919
  result["marginTop"] = marginTop;
4887
4920
  result["marginBottom"] = marginBottom;
4888
4921
  result["textAlign"] = textAlign;
4922
+ result["fontWeight"] = fontWeight;
4889
4923
  return result;
4890
4924
  }
4891
4925
  #endif
@@ -4922,6 +4956,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
4922
4956
  if (tmp_textAlign != map.end()) {
4923
4957
  fromRawValue(context, tmp_textAlign->second, result.textAlign);
4924
4958
  }
4959
+ auto tmp_fontWeight = map.find("fontWeight");
4960
+ if (tmp_fontWeight != map.end()) {
4961
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
4962
+ }
4925
4963
  }
4926
4964
 
4927
4965
  static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleMathStruct &value) {
@@ -4936,6 +4974,8 @@ static inline folly::dynamic toDynamic(const EnrichedMarkdownTextMarkdownStyleMa
4936
4974
 
4937
4975
  struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct {
4938
4976
  SharedColor color{};
4977
+ Float paddingVertical{0.0};
4978
+ std::string fontWeight{};
4939
4979
 
4940
4980
 
4941
4981
  #ifdef RN_SERIALIZABLE_STATE
@@ -4944,6 +4984,8 @@ struct EnrichedMarkdownTextMarkdownStyleInlineMathStruct {
4944
4984
  folly::dynamic toDynamic() const {
4945
4985
  folly::dynamic result = folly::dynamic::object();
4946
4986
  result["color"] = ::facebook::react::toDynamic(color);
4987
+ result["paddingVertical"] = paddingVertical;
4988
+ result["fontWeight"] = fontWeight;
4947
4989
  return result;
4948
4990
  }
4949
4991
  #endif
@@ -4956,6 +4998,14 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
4956
4998
  if (tmp_color != map.end()) {
4957
4999
  fromRawValue(context, tmp_color->second, result.color);
4958
5000
  }
5001
+ auto tmp_paddingVertical = map.find("paddingVertical");
5002
+ if (tmp_paddingVertical != map.end()) {
5003
+ fromRawValue(context, tmp_paddingVertical->second, result.paddingVertical);
5004
+ }
5005
+ auto tmp_fontWeight = map.find("fontWeight");
5006
+ if (tmp_fontWeight != map.end()) {
5007
+ fromRawValue(context, tmp_fontWeight->second, result.fontWeight);
5008
+ }
4959
5009
  }
4960
5010
 
4961
5011
  static inline std::string toString(const EnrichedMarkdownTextMarkdownStyleInlineMathStruct &value) {
@@ -36,6 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
36
36
  - (void)updateMath:(NSInteger)start latex:(NSString *)latex displayMode:(BOOL)displayMode;
37
37
  - (void)removeMath:(NSInteger)start;
38
38
  - (void)copyToClipboard;
39
+ - (void)resolvePaste:(NSString *)text markdown:(NSString *)markdown;
39
40
  - (void)requestMarkdown:(NSInteger)requestId;
40
41
  - (void)requestCaretRect:(NSInteger)requestId;
41
42
  @end
@@ -399,6 +400,34 @@ if ([commandName isEqualToString:@"copyToClipboard"]) {
399
400
  return;
400
401
  }
401
402
 
403
+ if ([commandName isEqualToString:@"resolvePaste"]) {
404
+ #if RCT_DEBUG
405
+ if ([args count] != 2) {
406
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 2);
407
+ return;
408
+ }
409
+ #endif
410
+
411
+ NSObject *arg0 = args[0];
412
+ #if RCT_DEBUG
413
+ if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"1st")) {
414
+ return;
415
+ }
416
+ #endif
417
+ NSString * text = (NSString *)arg0;
418
+
419
+ NSObject *arg1 = args[1];
420
+ #if RCT_DEBUG
421
+ if (!RCTValidateTypeOfViewCommandArgument(arg1, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"2nd")) {
422
+ return;
423
+ }
424
+ #endif
425
+ NSString * markdown = (NSString *)arg1;
426
+
427
+ [componentView resolvePaste:text markdown:markdown];
428
+ return;
429
+ }
430
+
402
431
  if ([commandName isEqualToString:@"requestMarkdown"]) {
403
432
  #if RCT_DEBUG
404
433
  if ([args count] != 1) {
@@ -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;