react-native-enriched-markdown-scaffold 0.6.0-scaffold.6 → 0.7.4-scaffold.1

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 (190) hide show
  1. package/ReactNativeEnrichedMarkdown.podspec +62 -11
  2. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +3 -0
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +1 -0
  4. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +9 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +3 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +3 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +1 -0
  8. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +20 -0
  9. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +744 -36
  10. package/android/src/main/baseline-prof.txt +75 -2
  11. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +62 -0
  12. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +10 -2
  13. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +10 -0
  14. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +9 -2
  15. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +10 -0
  16. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +0 -1
  17. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/AccessibilityLabels.kt +15 -0
  18. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +44 -7
  19. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +52 -0
  20. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +55 -3
  21. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +19 -0
  22. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +22 -3
  23. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputRemend.kt +1 -0
  24. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +7 -1
  25. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +0 -3
  26. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +54 -13
  27. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +17 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +4 -4
  29. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MathModels.kt +0 -1
  30. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +1 -3
  31. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +1 -3
  32. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +30 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +0 -14
  34. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt +22 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +36 -7
  36. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +73 -3
  37. package/android/src/main/jni/CMakeLists.txt +15 -1
  38. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +0 -1
  39. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -2
  40. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +1 -3
  41. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathMeasureHelper.kt +1 -2
  42. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +25 -10
  43. package/app.plugin.js +2 -1
  44. package/cpp/parser/MD4CParser.cpp +1 -1
  45. package/cpp/wasm/build.sh +9 -9
  46. package/docs/ACCESSIBILITY.md +172 -0
  47. package/docs/API_REFERENCE.md +948 -0
  48. package/docs/COPY_OPTIONS.md +127 -0
  49. package/docs/ELEMENTS_STRUCTURE.md +112 -0
  50. package/docs/IMAGE_CACHING.md +25 -0
  51. package/docs/INPUT.md +233 -0
  52. package/docs/LATEX_MATH.md +136 -0
  53. package/docs/MACOS.md +19 -0
  54. package/docs/MARKDOWN_STREAMING.md +36 -0
  55. package/docs/MENTIONS.md +97 -0
  56. package/docs/RTL.md +82 -0
  57. package/docs/STYLES.md +519 -0
  58. package/docs/TEXT.md +110 -0
  59. package/docs/WEB.md +49 -0
  60. package/ios/EnrichedMarkdown.mm +82 -25
  61. package/ios/EnrichedMarkdownText.mm +37 -5
  62. package/ios/attachments/ENRMMathInlineAttachment+macOS.m +1 -5
  63. package/ios/attachments/ENRMMathInlineAttachment.h +0 -3
  64. package/ios/attachments/ENRMMathInlineAttachment.m +1 -2
  65. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +20 -0
  66. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +744 -36
  67. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +15 -0
  68. package/ios/input/ENRMFormattingStore.h +5 -0
  69. package/ios/input/ENRMFormattingStore.mm +34 -0
  70. package/ios/input/ENRMInputFormatter.h +0 -6
  71. package/ios/input/ENRMInputFormatter.mm +0 -2
  72. package/ios/input/ENRMInputTextView.h +2 -0
  73. package/ios/input/ENRMInputTextView.mm +8 -17
  74. package/ios/input/ENRMMarkdownSerializer.mm +1 -1
  75. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +71 -53
  76. package/ios/input/EnrichedMarkdownTextInput+Internal.h +26 -0
  77. package/ios/input/EnrichedMarkdownTextInput.h +1 -0
  78. package/ios/input/EnrichedMarkdownTextInput.mm +207 -12
  79. package/ios/input/InputStylePropsUtils.h +0 -8
  80. package/ios/input/styles/ENRMBoldStyleHandler.mm +3 -2
  81. package/ios/input/styles/ENRMItalicStyleHandler.mm +3 -2
  82. package/ios/math/ENRMRaTeXBridge.swift +2 -16
  83. package/ios/renderer/AttributedRenderer.m +51 -6
  84. package/ios/renderer/ENRMMathInlineRenderer.m +5 -2
  85. package/ios/styles/ENRMFontSlot.h +1 -1
  86. package/ios/styles/StyleConfig.h +0 -4
  87. package/ios/styles/StyleConfig.mm +0 -24
  88. package/ios/utils/ENRMAccessibilityLabels.h +36 -0
  89. package/ios/utils/ENRMAccessibilityLabels.m +5 -0
  90. package/ios/utils/EditMenuUtils+macOS.m +4 -5
  91. package/ios/utils/EditMenuUtils.h +70 -0
  92. package/ios/utils/EditMenuUtils.m +14 -11
  93. package/ios/utils/LastElementUtils.h +39 -2
  94. package/ios/utils/MarkdownAccessibilityElementBuilder.h +18 -16
  95. package/ios/utils/MarkdownAccessibilityElementBuilder.m +64 -32
  96. package/ios/utils/ParagraphStyleUtils.m +21 -2
  97. package/ios/utils/StylePropsUtils.h +0 -10
  98. package/ios/views/ENRMMathContainerView.h +8 -0
  99. package/ios/views/ENRMMathContainerView.m +8 -7
  100. package/ios/views/ENRMTableIOSGridView.h +40 -0
  101. package/ios/views/ENRMTableIOSGridView.m +216 -0
  102. package/ios/views/EnrichedMarkdownInternalText.h +2 -0
  103. package/ios/views/EnrichedMarkdownInternalText.m +2 -0
  104. package/ios/views/TableContainerView.h +8 -0
  105. package/ios/views/TableContainerView.m +72 -128
  106. package/lib/module/EnrichedMarkdownNativeComponent.ts +37 -2
  107. package/lib/module/EnrichedMarkdownTextInput.js +48 -1
  108. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  109. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +35 -1
  110. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +37 -2
  111. package/lib/module/accessibilityLabelDefaults.js +64 -0
  112. package/lib/module/accessibilityLabelDefaults.js.map +1 -0
  113. package/lib/module/index.js +1 -0
  114. package/lib/module/index.js.map +1 -1
  115. package/lib/module/native/EnrichedMarkdownText.js +72 -4
  116. package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
  117. package/lib/module/normalizeMarkdownStyle.js +2 -4
  118. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  119. package/lib/module/normalizeMarkdownStyle.web.js +2 -4
  120. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  121. package/lib/module/normalizeMarkdownTextInputStyle.js +3 -10
  122. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  123. package/lib/module/normalizeMenuItem.js +38 -0
  124. package/lib/module/normalizeMenuItem.js.map +1 -0
  125. package/lib/module/types/AccessibilityLabels.js +2 -0
  126. package/lib/module/types/AccessibilityLabels.js.map +1 -0
  127. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +34 -2
  128. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  129. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +55 -13
  130. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  131. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +30 -1
  132. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  133. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +34 -2
  134. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  135. package/lib/typescript/src/accessibilityLabelDefaults.d.ts +16 -0
  136. package/lib/typescript/src/accessibilityLabelDefaults.d.ts.map +1 -0
  137. package/lib/typescript/src/index.d.ts +4 -2
  138. package/lib/typescript/src/index.d.ts.map +1 -1
  139. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
  140. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
  141. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  142. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  143. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +0 -2
  144. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  145. package/lib/typescript/src/normalizeMenuItem.d.ts +7 -0
  146. package/lib/typescript/src/normalizeMenuItem.d.ts.map +1 -0
  147. package/lib/typescript/src/types/AccessibilityLabels.d.ts +114 -0
  148. package/lib/typescript/src/types/AccessibilityLabels.d.ts.map +1 -0
  149. package/lib/typescript/src/types/MarkdownStyle.d.ts +0 -14
  150. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  151. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +0 -3
  152. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  153. package/lib/typescript/src/types/MarkdownTextProps.d.ts +78 -9
  154. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
  155. package/package.json +4 -2
  156. package/plugin/build/withAndroidMath.js +19 -0
  157. package/plugin/build/withIosMath.js +28 -0
  158. package/plugin/build/withReactNativeEnrichedMarkdown.js +11 -0
  159. package/plugin/tsconfig.build.json +16 -0
  160. package/src/EnrichedMarkdownNativeComponent.ts +37 -2
  161. package/src/EnrichedMarkdownTextInput.tsx +117 -13
  162. package/src/EnrichedMarkdownTextInputNativeComponent.ts +35 -1
  163. package/src/EnrichedMarkdownTextNativeComponent.ts +37 -2
  164. package/src/accessibilityLabelDefaults.ts +83 -0
  165. package/src/index.tsx +11 -0
  166. package/src/native/EnrichedMarkdownText.tsx +120 -6
  167. package/src/normalizeMarkdownStyle.ts +1 -6
  168. package/src/normalizeMarkdownStyle.web.ts +1 -6
  169. package/src/normalizeMarkdownTextInputStyle.ts +0 -14
  170. package/src/normalizeMenuItem.ts +52 -0
  171. package/src/types/AccessibilityLabels.ts +118 -0
  172. package/src/types/MarkdownStyle.ts +0 -14
  173. package/src/types/MarkdownStyleInternal.ts +0 -4
  174. package/src/types/MarkdownTextProps.ts +74 -9
  175. package/android/src/math/java/com/swmansion/enriched/markdown/utils/math/LatexWeightWrapper.kt +0 -23
  176. package/lib/module/plugin/withAndroidMath.js +0 -20
  177. package/lib/module/plugin/withAndroidMath.js.map +0 -1
  178. package/lib/module/plugin/withIosMath.js +0 -23
  179. package/lib/module/plugin/withIosMath.js.map +0 -1
  180. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js +0 -16
  181. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map +0 -1
  182. package/lib/typescript/src/plugin/withAndroidMath.d.ts +0 -5
  183. package/lib/typescript/src/plugin/withAndroidMath.d.ts.map +0 -1
  184. package/lib/typescript/src/plugin/withIosMath.d.ts +0 -5
  185. package/lib/typescript/src/plugin/withIosMath.d.ts.map +0 -1
  186. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts +0 -6
  187. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts.map +0 -1
  188. /package/{src/plugin → plugin/src}/withAndroidMath.ts +0 -0
  189. /package/{src/plugin → plugin/src}/withIosMath.ts +0 -0
  190. /package/{src/plugin → plugin/src}/withReactNativeEnrichedMarkdown.ts +0 -0
@@ -20,9 +20,12 @@
20
20
  #import "ENRMStyleMergingConfig.h"
21
21
  #import "ENRMUIKit.h"
22
22
  #import "ENRMWordsUtils.h"
23
+ #import "EnrichedMarkdownTextInput+Internal.h"
23
24
  #import "InputStylePropsUtils.h"
24
25
  #import "ParagraphStyleUtils.h"
26
+ #import "PasteboardUtils.h"
25
27
  #import "SelectionColorUtils.h"
28
+ #import <QuartzCore/CABase.h>
26
29
  #import <React/RCTI18nUtil.h>
27
30
  #if TARGET_OS_OSX
28
31
  #import <React/RCTBackedTextInputDelegate.h>
@@ -41,7 +44,8 @@
41
44
  using namespace facebook::react;
42
45
 
43
46
  #if !TARGET_OS_OSX
44
- @interface EnrichedMarkdownTextInput () <RCTEnrichedMarkdownTextInputViewProtocol, UITextViewDelegate>
47
+ @interface EnrichedMarkdownTextInput () <RCTEnrichedMarkdownTextInputViewProtocol, UITextViewDelegate,
48
+ UIGestureRecognizerDelegate>
45
49
  #else
46
50
  @interface EnrichedMarkdownTextInput () <RCTEnrichedMarkdownTextInputViewProtocol, RCTBackedTextInputDelegate>
47
51
  #endif
@@ -64,6 +68,7 @@ using namespace facebook::react;
64
68
  BOOL _isApplyingFormatting;
65
69
  BOOL _isTextChanging;
66
70
  BOOL _emitMarkdown;
71
+ CFTimeInterval _lastTextChangeTime;
67
72
 
68
73
  ENRMPlaceholderLabel *_placeholderLabel;
69
74
 
@@ -101,6 +106,20 @@ using namespace facebook::react;
101
106
  BOOL _suppressMathChipClearOnce;
102
107
  /// Character index of the currently selected math chip, or NSNotFound.
103
108
  NSUInteger _activeMathChipIndex;
109
+
110
+ ENRMInputSelectionMenuConfig _inputSelectionMenuConfig;
111
+ ENRMFormatMenuConfig _formatMenuConfig;
112
+
113
+ // Strong owners for the strings the two config structs above reference via
114
+ // `__unsafe_unretained` pointers.
115
+ NSString *_inputSelectionMenuFormatLabel;
116
+ NSString *_inputSelectionMenuCopyAsMarkdownLabel;
117
+ NSString *_formatMenuBoldLabel;
118
+ NSString *_formatMenuItalicLabel;
119
+ NSString *_formatMenuUnderlineLabel;
120
+ NSString *_formatMenuStrikethroughLabel;
121
+ NSString *_formatMenuSpoilerLabel;
122
+ NSString *_formatMenuLinkLabel;
104
123
  }
105
124
 
106
125
  #pragma mark - Fabric lifecycle
@@ -138,6 +157,9 @@ using namespace facebook::react;
138
157
  _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
139
158
  _resolvedLayoutDirection =
140
159
  [[RCTI18nUtil sharedInstance] isRTL] ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
160
+ _inputSelectionMenuConfig = (ENRMInputSelectionMenuConfig){.format = YES, .copyAsMarkdown = YES};
161
+ _formatMenuConfig = (ENRMFormatMenuConfig){
162
+ .bold = YES, .italic = YES, .underline = YES, .strikethrough = YES, .spoiler = YES, .link = YES};
141
163
 
142
164
  _suppressMathChipClearOnce = NO;
143
165
  _activeMathChipIndex = NSNotFound;
@@ -222,6 +244,9 @@ using namespace facebook::react;
222
244
  UITapGestureRecognizer *mathTap = [[UITapGestureRecognizer alloc] initWithTarget:self
223
245
  action:@selector(handleTapForMathChip:)];
224
246
  mathTap.cancelsTouchesInView = NO;
247
+ mathTap.delaysTouchesBegan = NO;
248
+ mathTap.delaysTouchesEnded = NO;
249
+ mathTap.delegate = self;
225
250
  [_textView addGestureRecognizer:mathTap];
226
251
  #endif
227
252
  }
@@ -459,6 +484,44 @@ using namespace facebook::react;
459
484
  _contextMenuItemIcons = ENRMContextMenuIconsFromItems(newViewProps.contextMenuItems);
460
485
  }
461
486
 
487
+ // Coalesce against `initWithUTF8String:` returning nil on malformed UTF-8 —
488
+ // UIMenu / UIAction / NSMenuItem titles are _Nonnull and would crash.
489
+ _inputSelectionMenuFormatLabel =
490
+ [[NSString alloc] initWithUTF8String:newViewProps.selectionMenuConfig.formatLabel.c_str()] ?: @"";
491
+ _inputSelectionMenuCopyAsMarkdownLabel =
492
+ [[NSString alloc] initWithUTF8String:newViewProps.selectionMenuConfig.copyAsMarkdownLabel.c_str()] ?: @"";
493
+ _inputSelectionMenuConfig = (ENRMInputSelectionMenuConfig){
494
+ .format = newViewProps.selectionMenuConfig.format,
495
+ .formatLabel = _inputSelectionMenuFormatLabel,
496
+ .copyAsMarkdown = newViewProps.selectionMenuConfig.copyAsMarkdown,
497
+ .copyAsMarkdownLabel = _inputSelectionMenuCopyAsMarkdownLabel,
498
+ };
499
+
500
+ _formatMenuBoldLabel = [[NSString alloc] initWithUTF8String:newViewProps.formatMenuConfig.boldLabel.c_str()] ?: @"";
501
+ _formatMenuItalicLabel =
502
+ [[NSString alloc] initWithUTF8String:newViewProps.formatMenuConfig.italicLabel.c_str()] ?: @"";
503
+ _formatMenuUnderlineLabel =
504
+ [[NSString alloc] initWithUTF8String:newViewProps.formatMenuConfig.underlineLabel.c_str()] ?: @"";
505
+ _formatMenuStrikethroughLabel =
506
+ [[NSString alloc] initWithUTF8String:newViewProps.formatMenuConfig.strikethroughLabel.c_str()] ?: @"";
507
+ _formatMenuSpoilerLabel =
508
+ [[NSString alloc] initWithUTF8String:newViewProps.formatMenuConfig.spoilerLabel.c_str()] ?: @"";
509
+ _formatMenuLinkLabel = [[NSString alloc] initWithUTF8String:newViewProps.formatMenuConfig.linkLabel.c_str()] ?: @"";
510
+ _formatMenuConfig = (ENRMFormatMenuConfig){
511
+ .bold = newViewProps.formatMenuConfig.bold,
512
+ .boldLabel = _formatMenuBoldLabel,
513
+ .italic = newViewProps.formatMenuConfig.italic,
514
+ .italicLabel = _formatMenuItalicLabel,
515
+ .underline = newViewProps.formatMenuConfig.underline,
516
+ .underlineLabel = _formatMenuUnderlineLabel,
517
+ .strikethrough = newViewProps.formatMenuConfig.strikethrough,
518
+ .strikethroughLabel = _formatMenuStrikethroughLabel,
519
+ .spoiler = newViewProps.formatMenuConfig.spoiler,
520
+ .spoilerLabel = _formatMenuSpoilerLabel,
521
+ .link = newViewProps.formatMenuConfig.link,
522
+ .linkLabel = _formatMenuLinkLabel,
523
+ };
524
+
462
525
  if (newViewProps.mentionIndicators != oldViewProps.mentionIndicators) {
463
526
  NSMutableArray<NSString *> *indicators = [NSMutableArray array];
464
527
  for (const auto &indicator : newViewProps.mentionIndicators) {
@@ -592,6 +655,14 @@ using namespace facebook::react;
592
655
  [_textView mouseDown:event];
593
656
  }
594
657
 
658
+ #else // iOS
659
+
660
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
661
+ shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
662
+ {
663
+ return YES;
664
+ }
665
+
595
666
  #endif
596
667
 
597
668
  #if !TARGET_OS_OSX
@@ -683,7 +754,6 @@ using namespace facebook::react;
683
754
  att.blockAlignment = _formatterStyle.mathBlockAlignment;
684
755
  att.selectedBackgroundColor = _formatterStyle.mathBlockSelectedBackgroundColor;
685
756
  att.selectedBorderColor = _formatterStyle.mathBlockSelectedBorderColor;
686
- att.fontWeight = _formatterStyle.mathBlockFontWeight;
687
757
  } else {
688
758
  att.fontSize = _formatterStyle.mathFontSize > 0 ? _formatterStyle.mathFontSize : 16.0;
689
759
  att.mathTextColor = _formatterStyle.mathColor ?: _formatterStyle.baseTextColor;
@@ -698,7 +768,6 @@ using namespace facebook::react;
698
768
  att.blockAlignment = NSTextAlignmentNatural;
699
769
  att.selectedBackgroundColor = _formatterStyle.mathSelectedBackgroundColor;
700
770
  att.selectedBorderColor = _formatterStyle.mathSelectedBorderColor;
701
- att.fontWeight = _formatterStyle.mathFontWeight;
702
771
  }
703
772
  }
704
773
 
@@ -954,6 +1023,7 @@ using namespace facebook::react;
954
1023
  }
955
1024
 
956
1025
  [self applyFormatting];
1026
+ [self syncTypingAttributesWithPendingStyles];
957
1027
  [self emitFormattingChanged];
958
1028
  }
959
1029
 
@@ -1211,6 +1281,21 @@ using namespace facebook::react;
1211
1281
  return [ENRMMarkdownSerializer serializeAttributedString:selectedAttr ranges:clippedRanges];
1212
1282
  }
1213
1283
 
1284
+ - (void)copyToClipboard
1285
+ {
1286
+ NSString *plainText = ENRMGetPlainText(_textView);
1287
+ if (plainText.length == 0) {
1288
+ return;
1289
+ }
1290
+ NSString *markdown = [ENRMMarkdownSerializer serializePlainText:plainText ranges:[self allRangesIncludingTransient]];
1291
+ NSMutableDictionary *items = [NSMutableDictionary dictionary];
1292
+ items[kUTIPlainText] = plainText;
1293
+ if (markdown.length > 0) {
1294
+ items[kENRMMarkdownPasteboardType] = markdown;
1295
+ }
1296
+ copyItemsToPasteboard(items);
1297
+ }
1298
+
1214
1299
  - (void)requestMarkdown:(NSInteger)requestId
1215
1300
  {
1216
1301
  auto emitter = [self getEventEmitter];
@@ -1283,6 +1368,57 @@ using namespace facebook::react;
1283
1368
  return inRange;
1284
1369
  }
1285
1370
 
1371
+ - (void)syncTypingAttributesWithPendingStyles
1372
+ {
1373
+ UIFontDescriptorSymbolicTraits traits = 0;
1374
+ if ([_pendingStyles containsObject:@(ENRMInputStyleTypeStrong)]) {
1375
+ traits |= UIFontDescriptorTraitBold;
1376
+ }
1377
+ if ([_pendingStyles containsObject:@(ENRMInputStyleTypeEmphasis)]) {
1378
+ traits |= UIFontDescriptorTraitItalic;
1379
+ }
1380
+
1381
+ NSMutableDictionary *attrs = [_textView.typingAttributes mutableCopy];
1382
+ attrs[NSFontAttributeName] = [_formatterStyle fontForTraits:traits];
1383
+ _textView.typingAttributes = attrs;
1384
+ }
1385
+
1386
+ - (void)resetPendingStylesForSelectionChange
1387
+ {
1388
+ // Skip system-driven selection adjustments (e.g., predictive text) that fire
1389
+ // immediately after a text edit.
1390
+ static const CFTimeInterval kPostEditGracePeriod = 0.1;
1391
+ BOOL isPostEditAdjustment =
1392
+ (_lastTextChangeTime > 0 && (CACurrentMediaTime() - _lastTextChangeTime) < kPostEditGracePeriod);
1393
+ if (isPostEditAdjustment) {
1394
+ return;
1395
+ }
1396
+ [_pendingStyles removeAllObjects];
1397
+ [_pendingStyleRemovals removeAllObjects];
1398
+ [self rebuildPendingStylesFromContext];
1399
+ [self syncTypingAttributesWithPendingStyles];
1400
+ }
1401
+
1402
+ - (void)rebuildPendingStylesFromContext
1403
+ {
1404
+ NSUInteger cursor = _textView.selectedRange.location;
1405
+ if (_textView.selectedRange.length > 0 || cursor == 0) {
1406
+ return;
1407
+ }
1408
+
1409
+ static const ENRMInputStyleType inlineStyles[] = {
1410
+ ENRMInputStyleTypeStrong, ENRMInputStyleTypeEmphasis, ENRMInputStyleTypeUnderline,
1411
+ ENRMInputStyleTypeStrikethrough, ENRMInputStyleTypeSpoiler,
1412
+ };
1413
+
1414
+ for (NSUInteger i = 0; i < sizeof(inlineStyles) / sizeof(inlineStyles[0]); i++) {
1415
+ ENRMInputStyleType type = inlineStyles[i];
1416
+ if ([_formattingStore isStyleAdjacentBefore:type position:cursor]) {
1417
+ [_pendingStyles addObject:@(type)];
1418
+ }
1419
+ }
1420
+ }
1421
+
1286
1422
  #pragma mark - Event emitters
1287
1423
 
1288
1424
  - (void)emitFormattingChanged
@@ -1521,6 +1657,16 @@ using namespace facebook::react;
1521
1657
  return _contextMenuItemIcons ?: @[];
1522
1658
  }
1523
1659
 
1660
+ - (ENRMInputSelectionMenuConfig)inputSelectionMenuConfig
1661
+ {
1662
+ return _inputSelectionMenuConfig;
1663
+ }
1664
+
1665
+ - (ENRMFormatMenuConfig)formatMenuConfig
1666
+ {
1667
+ return _formatMenuConfig;
1668
+ }
1669
+
1524
1670
  - (void)emitContextMenuItemPress:(NSString *)itemText
1525
1671
  {
1526
1672
  auto eventEmitter = [self getEventEmitter];
@@ -1664,10 +1810,27 @@ using namespace facebook::react;
1664
1810
  if (insertedLength > 0) {
1665
1811
  NSRange insertedRange = NSMakeRange(editLocation, insertedLength);
1666
1812
 
1667
- for (NSNumber *styleNum in _pendingStyles) {
1668
- ENRMFormattingRange *newRange = [ENRMFormattingRange rangeWithType:(ENRMInputStyleType)styleNum.integerValue
1669
- range:insertedRange];
1670
- [_formattingStore addRange:newRange];
1813
+ // Skip applying pending styles when the insertion is only line breaks —
1814
+ // a phantom range over a bare newline corrupts isStyleActive() at the boundary.
1815
+ NSString *plainText = ENRMGetPlainText(_textView);
1816
+ NSUInteger insertedEnd = NSMaxRange(insertedRange);
1817
+ BOOL insertedHasGlyphContent = NO;
1818
+ if (insertedEnd <= plainText.length) {
1819
+ NSCharacterSet *newlines = [NSCharacterSet newlineCharacterSet];
1820
+ for (NSUInteger i = insertedRange.location; i < insertedEnd; i++) {
1821
+ if (![newlines characterIsMember:[plainText characterAtIndex:i]]) {
1822
+ insertedHasGlyphContent = YES;
1823
+ break;
1824
+ }
1825
+ }
1826
+ }
1827
+
1828
+ if (insertedHasGlyphContent) {
1829
+ for (NSNumber *styleNum in _pendingStyles) {
1830
+ ENRMFormattingRange *newRange = [ENRMFormattingRange rangeWithType:(ENRMInputStyleType)styleNum.integerValue
1831
+ range:insertedRange];
1832
+ [_formattingStore addRange:newRange];
1833
+ }
1671
1834
  }
1672
1835
 
1673
1836
  // adjustForEditAtLocation may have expanded an existing range to cover
@@ -1771,6 +1934,7 @@ using namespace facebook::react;
1771
1934
  }
1772
1935
  [self handleTextChanged];
1773
1936
  _isTextChanging = NO;
1937
+ _lastTextChangeTime = CACurrentMediaTime();
1774
1938
  _lastSelectedRange = textView.selectedRange;
1775
1939
  }
1776
1940
 
@@ -1788,6 +1952,15 @@ using namespace facebook::react;
1788
1952
  - (void)textViewDidChangeSelection:(UITextView *)textView
1789
1953
  {
1790
1954
  NSRange newSelection = textView.selectedRange;
1955
+ // Links (e.g. mentions) are atomic: snap a partial selection to the whole link, and a caret inside
1956
+ // a link to its end. Returning hands the adjusted selection to the recursive change (no double emit).
1957
+ if (!_isApplyingFormatting && !_isTextChanging && !ENRMHasMarkedText(_textView)) {
1958
+ NSRange adjusted = [_formattingStore selectionAdjustedForAtomicLinks:newSelection];
1959
+ if (!NSEqualRanges(adjusted, newSelection)) {
1960
+ _textView.selectedRange = adjusted;
1961
+ return;
1962
+ }
1963
+ }
1791
1964
  NSRange previousSelection = _lastSelectedRange;
1792
1965
  _lastSelectedRange = newSelection;
1793
1966
 
@@ -1795,6 +1968,10 @@ using namespace facebook::react;
1795
1968
  return;
1796
1969
  }
1797
1970
 
1971
+ if (ENRMHasMarkedText(_textView)) {
1972
+ return;
1973
+ }
1974
+
1798
1975
  #if ENRICHED_MARKDOWN_MATH
1799
1976
  if (_suppressMathChipClearOnce) {
1800
1977
  // Caret update was triggered by handleTapForMathChip — keep that chip
@@ -1810,8 +1987,7 @@ using namespace facebook::react;
1810
1987
  newSelection.location != previousSelection.location || newSelection.length != previousSelection.length;
1811
1988
 
1812
1989
  if (selectionMoved) {
1813
- [_pendingStyles removeAllObjects];
1814
- [_pendingStyleRemovals removeAllObjects];
1990
+ [self resetPendingStylesForSelectionChange];
1815
1991
  }
1816
1992
 
1817
1993
  [self manageSelectionBasedChanges];
@@ -1918,19 +2094,38 @@ using namespace facebook::react;
1918
2094
  }
1919
2095
  [self handleTextChanged];
1920
2096
  _isTextChanging = NO;
2097
+ _lastTextChangeTime = CACurrentMediaTime();
1921
2098
  _lastSelectedRange = _textView.selectedRange;
1922
2099
  }
1923
2100
 
1924
2101
  - (void)textInputDidChangeSelection
1925
2102
  {
1926
- _lastSelectedRange = _textView.selectedRange;
2103
+ NSRange newSelection = _textView.selectedRange;
2104
+ // Atomic link snapping — same logic as textViewDidChangeSelection: (iOS).
2105
+ if (!_isApplyingFormatting && !_isTextChanging && !ENRMHasMarkedText(_textView)) {
2106
+ NSRange adjusted = [_formattingStore selectionAdjustedForAtomicLinks:newSelection];
2107
+ if (!NSEqualRanges(adjusted, newSelection)) {
2108
+ _textView.selectedRange = adjusted;
2109
+ return;
2110
+ }
2111
+ }
2112
+ NSRange previousSelection = _lastSelectedRange;
2113
+ _lastSelectedRange = newSelection;
1927
2114
 
1928
2115
  if (_isApplyingFormatting || _isTextChanging) {
1929
2116
  return;
1930
2117
  }
1931
2118
 
1932
- [_pendingStyles removeAllObjects];
1933
- [_pendingStyleRemovals removeAllObjects];
2119
+ if (ENRMHasMarkedText(_textView)) {
2120
+ return;
2121
+ }
2122
+
2123
+ BOOL selectionMoved =
2124
+ newSelection.location != previousSelection.location || newSelection.length != previousSelection.length;
2125
+
2126
+ if (selectionMoved) {
2127
+ [self resetPendingStylesForSelectionChange];
2128
+ }
1934
2129
 
1935
2130
  [self emitOnChangeSelection];
1936
2131
  [self updateActiveMention];
@@ -187,10 +187,6 @@ BOOL applyInputStyleProps(ENRMInputFormatterStyle *style, const InputProps &newP
187
187
  style.mathSelectedBorderColor = (sbc && CGColorGetAlpha(sbc.CGColor) > 0) ? sbc : nil;
188
188
  changed = YES;
189
189
  }
190
- if (newProps.markdownStyle.math.fontWeight != oldProps.markdownStyle.math.fontWeight) {
191
- style.mathFontWeight = @(newProps.markdownStyle.math.fontWeight.c_str());
192
- changed = YES;
193
- }
194
190
 
195
191
  // Math block (`$$...$$`)
196
192
  if (newProps.markdownStyle.mathBlock.color != oldProps.markdownStyle.mathBlock.color) {
@@ -260,10 +256,6 @@ BOOL applyInputStyleProps(ENRMInputFormatterStyle *style, const InputProps &newP
260
256
  }
261
257
  changed = YES;
262
258
  }
263
- if (newProps.markdownStyle.mathBlock.fontWeight != oldProps.markdownStyle.mathBlock.fontWeight) {
264
- style.mathBlockFontWeight = @(newProps.markdownStyle.mathBlock.fontWeight.c_str());
265
- changed = YES;
266
- }
267
259
 
268
260
  return changed;
269
261
  }
@@ -22,8 +22,9 @@
22
22
  formattingRange:(ENRMFormattingRange *)formattingRange
23
23
  style:(ENRMInputFormatterStyle *)style
24
24
  {
25
- RCTUIColor *color = style.boldColor ?: style.baseTextColor;
26
- [storage addAttribute:NSForegroundColorAttributeName value:color range:range];
25
+ if (style.boldColor) {
26
+ [storage addAttribute:NSForegroundColorAttributeName value:style.boldColor range:range];
27
+ }
27
28
  }
28
29
 
29
30
  @end
@@ -22,8 +22,9 @@
22
22
  formattingRange:(ENRMFormattingRange *)formattingRange
23
23
  style:(ENRMInputFormatterStyle *)style
24
24
  {
25
- RCTUIColor *color = style.italicColor ?: style.baseTextColor;
26
- [storage addAttribute:NSForegroundColorAttributeName value:color range:range];
25
+ if (style.italicColor) {
26
+ [storage addAttribute:NSForegroundColorAttributeName value:style.italicColor range:range];
27
+ }
27
28
  }
28
29
 
29
30
  @end
@@ -39,29 +39,15 @@ public final class ENRMRaTeXBridge: NSObject {
39
39
  RaTeXFontLoader.ensureLoaded()
40
40
  }
41
41
 
42
- /// Wraps a raw LaTeX expression with the appropriate KaTeX bold command so
43
- /// RaTeX picks up the bold glyph variant (KaTeX_Main-Bold). Render-time only
44
- /// — callers keep the original `latex` on attachments so serialized markdown
45
- /// round-trips cleanly.
46
- ///
47
- /// Caveat: large operators (`\sum`, `\int`), AMS symbols and Script/Typewriter
48
- /// glyphs have no bold variant in the bundled KaTeX fonts and stay regular
49
- /// even when wrapped.
50
- private static func wrapWeight(_ latex: String, fontWeight: String?) -> String {
51
- return fontWeight == "bold" ? "\\mathbf{\(latex)}" : latex
52
- }
53
-
54
42
  @objc public static func parse(
55
43
  _ latex: String,
56
44
  displayMode: Bool,
57
45
  fontSize: CGFloat,
58
- color: UIColor,
59
- fontWeight: String?
46
+ color: UIColor
60
47
  ) -> ENRMRaTeXRenderResult? {
61
48
  RaTeXFontLoader.ensureLoaded()
62
49
  do {
63
- let wrapped = wrapWeight(latex, fontWeight: fontWeight)
64
- let displayList = try RaTeXEngine.shared.parse(wrapped, displayMode: displayMode, color: color)
50
+ let displayList = try RaTeXEngine.shared.parse(latex, displayMode: displayMode, color: color)
65
51
  let renderer = RaTeXRenderer(displayList: displayList, fontSize: fontSize)
66
52
  return ENRMRaTeXRenderResult(renderer: renderer)
67
53
  } catch {
@@ -3,6 +3,7 @@
3
3
  #import "LastElementUtils.h"
4
4
  #import "MarkdownASTNode.h"
5
5
  #import "NodeRenderer.h"
6
+ #import "ParagraphStyleUtils.h"
6
7
  #import "RenderContext.h"
7
8
  #import "RendererFactory.h"
8
9
  #import "StyleConfig.h"
@@ -58,7 +59,32 @@
58
59
  return output;
59
60
  }
60
61
 
61
- /// Removes trailing margin spacing while preserving code block padding
62
+ /**
63
+ * Trims trailing newlines after the last rendered block, with special handling for code blocks.
64
+ *
65
+ * For non-code-block tail elements: deletes all trailing newlines after the last non-newline
66
+ * character and zeroes the last element's paragraph spacing so it doesn't render a margin past
67
+ * the content.
68
+ *
69
+ * For code blocks (`isLastBlockACodeBlock` == YES): keeps the bottom padding spacer in place
70
+ * AND preserves a single trailing newline immediately after it (typically the
71
+ * codeBlockMarginBottom spacer that CodeBlockRenderer already appended; if none exists, one is
72
+ * synthesized here). That extra newline matters because of an iOS layout quirk:
73
+ *
74
+ * - iOS treats the trailing `\n` of the storage as a paragraph terminator and reports the
75
+ * line fragment for the paragraph after it via `extraLineFragmentRect`.
76
+ * - `boundingRectForGlyphRange:` excludes that extra line, and the graphics-context clip
77
+ * passed to `drawBackgroundForGlyphRange:` is tiled to the laid-out content area (rounded
78
+ * up to 128pt boundaries) which also excludes it.
79
+ * - If the bottom padding spacer were the trailing `\n`, its 16/19pt line fragment would
80
+ * fall into that excluded zone — the background rect would have to be manually extended
81
+ * past the clip and the bottom rounded corner would get sliced off at the tile boundary
82
+ * (the original visual bug in #354).
83
+ *
84
+ * By keeping a 1pt-tall tail newline beyond the bottom padding spacer, iOS lays the spacer
85
+ * out as a normal interior line fragment included in usedRect/boundingRect and inside the
86
+ * drawing tiles, so the corner renders intact and no rect extension is needed.
87
+ */
62
88
  - (void)removeTrailingSpacing:(NSMutableAttributedString *)output
63
89
  {
64
90
  if (output.length == 0)
@@ -83,17 +109,36 @@
83
109
 
84
110
  // 2. Trim trailing characters
85
111
  NSUInteger logicalEnd = NSMaxRange(lastContent);
86
- BOOL isCodeBlock = isLastElementCodeBlock(output);
112
+ BOOL isCodeBlock = isLastBlockACodeBlock(output);
113
+ NSRange codeRange = NSMakeRange(0, 0);
87
114
  if (isCodeBlock) {
88
- NSRange codeRange;
89
- [output attribute:CodeBlockAttributeName atIndex:lastContent.location effectiveRange:&codeRange];
90
- logicalEnd = NSMaxRange(codeRange);
115
+ [output attribute:CodeBlockAttributeName
116
+ atIndex:lastContent.location
117
+ longestEffectiveRange:&codeRange
118
+ inRange:NSMakeRange(0, output.length)];
119
+ NSUInteger codeEnd = NSMaxRange(codeRange);
120
+ if (codeEnd >= output.length) {
121
+ [output appendAttributedString:kNewlineAttributedString];
122
+ }
123
+ logicalEnd = codeEnd + 1;
91
124
  }
92
125
 
93
126
  if (logicalEnd < output.length) {
94
127
  [output deleteCharactersInRange:NSMakeRange(logicalEnd, output.length - logicalEnd)];
95
128
  }
96
129
 
130
+ if (isCodeBlock && NSMaxRange(codeRange) < output.length) {
131
+ NSUInteger tailIdx = NSMaxRange(codeRange);
132
+ [output removeAttribute:CodeBlockAttributeName range:NSMakeRange(tailIdx, 1)];
133
+ NSParagraphStyle *style = [output attribute:NSParagraphStyleAttributeName atIndex:tailIdx effectiveRange:NULL];
134
+ NSMutableParagraphStyle *mutableStyle = style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init];
135
+ mutableStyle.paragraphSpacing = 0;
136
+ mutableStyle.paragraphSpacingBefore = 0;
137
+ mutableStyle.minimumLineHeight = 1;
138
+ mutableStyle.maximumLineHeight = 1;
139
+ [output addAttribute:NSParagraphStyleAttributeName value:mutableStyle range:NSMakeRange(tailIdx, 1)];
140
+ }
141
+
97
142
  // 3. Zero out internal spacing for the last element (if not a code block)
98
143
  if (!isCodeBlock) {
99
144
  NSRange styleRange;
@@ -150,4 +195,4 @@
150
195
  }
151
196
  }
152
197
 
153
- @end
198
+ @end
@@ -25,7 +25,6 @@
25
25
  attachment.latex = latex;
26
26
  attachment.fontSize = currentFont ? currentFont.pointSize : [_config paragraphFontSize];
27
27
  attachment.mathTextColor = [_config inlineMathColor];
28
- attachment.fontWeight = [_config inlineMathFontWeight];
29
28
 
30
29
  #if TARGET_OS_OSX
31
30
  // On macOS, NSLayoutManager uses self.image/self.bounds rather than calling
@@ -33,7 +32,11 @@
33
32
  [attachment renderForMacOS];
34
33
  #endif
35
34
 
36
- NSAttributedString *attachmentString = [NSAttributedString attributedStringWithAttachment:attachment];
35
+ NSMutableAttributedString *attachmentString =
36
+ [[NSAttributedString attributedStringWithAttachment:attachment] mutableCopy];
37
+ if (currentFont) {
38
+ [attachmentString addAttribute:NSFontAttributeName value:currentFont range:NSMakeRange(0, attachmentString.length)];
39
+ }
37
40
  [output appendAttributedString:attachmentString];
38
41
  }
39
42
 
@@ -1,5 +1,5 @@
1
1
  #pragma once
2
- #import <UIKit/UIKit.h>
2
+ #import "ENRMUIKit.h"
3
3
 
4
4
  NS_ASSUME_NONNULL_BEGIN
5
5
 
@@ -378,14 +378,10 @@ NS_ASSUME_NONNULL_BEGIN
378
378
  - (void)setMathMarginBottom:(CGFloat)newValue;
379
379
  - (NSString *)mathTextAlign;
380
380
  - (void)setMathTextAlign:(NSString *)newValue;
381
- - (NSString *)mathFontWeight;
382
- - (void)setMathFontWeight:(NSString *)newValue;
383
381
 
384
382
  // Inline Math properties
385
383
  - (RCTUIColor *)inlineMathColor;
386
384
  - (void)setInlineMathColor:(RCTUIColor *)newValue;
387
- - (NSString *)inlineMathFontWeight;
388
- - (void)setInlineMathFontWeight:(NSString *)newValue;
389
385
  // Spoiler properties
390
386
  - (RCTUIColor *)spoilerColor;
391
387
  - (void)setSpoilerColor:(RCTUIColor *)newValue;
@@ -224,10 +224,8 @@ static inline NSString *normalizedFontWeight(NSString *fontWeight)
224
224
  CGFloat _mathMarginTop;
225
225
  CGFloat _mathMarginBottom;
226
226
  NSString *_mathTextAlign;
227
- NSString *_mathFontWeight;
228
227
  // Inline Math properties
229
228
  RCTUIColor *_inlineMathColor;
230
- NSString *_inlineMathFontWeight;
231
229
  // Spoiler properties
232
230
  RCTUIColor *_spoilerColor;
233
231
  CGFloat _spoilerParticleDensity;
@@ -484,9 +482,7 @@ static inline NSString *normalizedFontWeight(NSString *fontWeight)
484
482
  copy->_mathMarginTop = _mathMarginTop;
485
483
  copy->_mathMarginBottom = _mathMarginBottom;
486
484
  copy->_mathTextAlign = [_mathTextAlign copy];
487
- copy->_mathFontWeight = [_mathFontWeight copy];
488
485
  copy->_inlineMathColor = [_inlineMathColor copy];
489
- copy->_inlineMathFontWeight = [_inlineMathFontWeight copy];
490
486
  copy->_spoilerColor = [_spoilerColor copy];
491
487
  copy->_spoilerParticleDensity = _spoilerParticleDensity;
492
488
  copy->_spoilerParticleSpeed = _spoilerParticleSpeed;
@@ -2422,16 +2418,6 @@ static const CGFloat kDefaultMinGap = 4.0;
2422
2418
  _mathTextAlign = newValue;
2423
2419
  }
2424
2420
 
2425
- - (NSString *)mathFontWeight
2426
- {
2427
- return _mathFontWeight ?: @"normal";
2428
- }
2429
-
2430
- - (void)setMathFontWeight:(NSString *)newValue
2431
- {
2432
- _mathFontWeight = newValue;
2433
- }
2434
-
2435
2421
  // ── Inline Math ─────────────────────────────────────────────────────────────
2436
2422
 
2437
2423
  - (RCTUIColor *)inlineMathColor
@@ -2444,16 +2430,6 @@ static const CGFloat kDefaultMinGap = 4.0;
2444
2430
  _inlineMathColor = newValue;
2445
2431
  }
2446
2432
 
2447
- - (NSString *)inlineMathFontWeight
2448
- {
2449
- return _inlineMathFontWeight ?: @"normal";
2450
- }
2451
-
2452
- - (void)setInlineMathFontWeight:(NSString *)newValue
2453
- {
2454
- _inlineMathFontWeight = newValue;
2455
- }
2456
-
2457
2433
  // ── Spoiler ─────────────────────────────────────────────────────────────
2458
2434
 
2459
2435
  - (RCTUIColor *)spoilerColor
@@ -0,0 +1,36 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ NS_ASSUME_NONNULL_BEGIN
4
+
5
+ @interface ENRMAccessibilityLabels : NSObject
6
+
7
+ @property (nonatomic, copy) NSString *bulletPoint;
8
+ @property (nonatomic, copy) NSString *nestedBulletPoint;
9
+ @property (nonatomic, copy) NSString *orderedItem;
10
+ @property (nonatomic, copy) NSString *nestedOrderedItem;
11
+ @property (nonatomic, copy) NSString *blockquote;
12
+ @property (nonatomic, copy) NSString *nestedBlockquote;
13
+ @property (nonatomic, copy) NSString *tableRow;
14
+ @property (nonatomic, copy) NSString *mathEquation;
15
+ @property (nonatomic, copy) NSString *rotorHeadings;
16
+ @property (nonatomic, copy) NSString *rotorLinks;
17
+ @property (nonatomic, copy) NSString *rotorImages;
18
+
19
+ @end
20
+
21
+ NS_ASSUME_NONNULL_END
22
+
23
+ #ifdef __cplusplus
24
+ template <typename T> static bool ENRMAccessibilityLabelsChanged(const T &oldLabels, const T &newLabels)
25
+ {
26
+ return oldLabels.list.bulletPoint != newLabels.list.bulletPoint ||
27
+ oldLabels.list.nestedBulletPoint != newLabels.list.nestedBulletPoint ||
28
+ oldLabels.list.orderedItem != newLabels.list.orderedItem ||
29
+ oldLabels.list.nestedOrderedItem != newLabels.list.nestedOrderedItem ||
30
+ oldLabels.blockquote.quote != newLabels.blockquote.quote ||
31
+ oldLabels.blockquote.nestedQuote != newLabels.blockquote.nestedQuote ||
32
+ oldLabels.table.row != newLabels.table.row || oldLabels.math.equation != newLabels.math.equation ||
33
+ oldLabels.rotor.headings != newLabels.rotor.headings || oldLabels.rotor.links != newLabels.rotor.links ||
34
+ oldLabels.rotor.images != newLabels.rotor.images;
35
+ }
36
+ #endif
@@ -0,0 +1,5 @@
1
+ #import "ENRMAccessibilityLabels.h"
2
+
3
+ @implementation ENRMAccessibilityLabels
4
+
5
+ @end