react-native-enriched-markdown-scaffold 0.6.0-scaffold.8 → 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 (213) hide show
  1. package/ReactNativeEnrichedMarkdown.podspec +62 -11
  2. package/android/build.gradle +5 -0
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +3 -0
  4. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +1 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +12 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +4 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +3 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +1 -0
  9. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +25 -0
  10. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +793 -0
  11. package/android/src/main/baseline-prof.txt +75 -2
  12. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +62 -0
  13. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +10 -2
  14. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +10 -0
  15. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +9 -2
  16. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +10 -0
  17. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +6 -4
  18. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/AccessibilityLabels.kt +15 -0
  19. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +44 -7
  20. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +72 -0
  21. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +110 -12
  22. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockSyntaxSentinel.kt +69 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +19 -0
  24. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +84 -6
  25. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputRemend.kt +1 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputLayoutManager.kt +30 -2
  27. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +13 -2
  28. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +3 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +54 -13
  30. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +17 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +1 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +4 -4
  33. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +8 -1
  34. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -1
  35. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +5 -1
  36. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathFontWeight.kt +25 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +12 -1
  38. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +37 -7
  39. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +10 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/SpannableExtensions.kt +12 -4
  41. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt +22 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +36 -7
  43. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +74 -4
  44. package/android/src/main/jni/CMakeLists.txt +15 -1
  45. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +2 -0
  46. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
  47. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlinePlaceholderSpan.kt +7 -3
  48. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +8 -5
  49. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathTypeface.kt +30 -0
  50. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +27 -3
  51. package/app.plugin.js +2 -1
  52. package/cpp/parser/MD4CParser.cpp +1 -1
  53. package/cpp/wasm/build.sh +9 -9
  54. package/docs/ACCESSIBILITY.md +172 -0
  55. package/docs/API_REFERENCE.md +957 -0
  56. package/docs/COPY_OPTIONS.md +127 -0
  57. package/docs/ELEMENTS_STRUCTURE.md +112 -0
  58. package/docs/IMAGE_CACHING.md +25 -0
  59. package/docs/INPUT.md +281 -0
  60. package/docs/LATEX_MATH.md +198 -0
  61. package/docs/MACOS.md +19 -0
  62. package/docs/MARKDOWN_STREAMING.md +36 -0
  63. package/docs/MENTIONS.md +97 -0
  64. package/docs/RTL.md +82 -0
  65. package/docs/STYLES.md +522 -0
  66. package/docs/TEXT.md +110 -0
  67. package/docs/WEB.md +49 -0
  68. package/ios/EnrichedMarkdown.mm +126 -37
  69. package/ios/EnrichedMarkdownText.mm +84 -16
  70. package/ios/attachments/ENRMMathInlineAttachment+macOS.m +5 -1
  71. package/ios/attachments/ENRMMathInlineAttachment.h +3 -0
  72. package/ios/attachments/ENRMMathInlineAttachment.m +2 -1
  73. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +25 -0
  74. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +793 -0
  75. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +15 -0
  76. package/ios/input/ENRMBlockSyntaxSentinel.h +25 -0
  77. package/ios/input/ENRMBlockSyntaxSentinel.mm +80 -0
  78. package/ios/input/ENRMFormattingStore.h +5 -0
  79. package/ios/input/ENRMFormattingStore.mm +34 -0
  80. package/ios/input/ENRMInputFormatter.h +4 -0
  81. package/ios/input/ENRMInputFormatter.mm +2 -0
  82. package/ios/input/ENRMInputParser.h +5 -0
  83. package/ios/input/ENRMInputParser.mm +79 -6
  84. package/ios/input/ENRMInputTextView.h +2 -0
  85. package/ios/input/ENRMInputTextView.mm +8 -17
  86. package/ios/input/ENRMMarkdownSerializer.mm +1 -1
  87. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +71 -53
  88. package/ios/input/EnrichedMarkdownTextInput+Internal.h +26 -0
  89. package/ios/input/EnrichedMarkdownTextInput.h +1 -0
  90. package/ios/input/EnrichedMarkdownTextInput.mm +249 -31
  91. package/ios/input/InputStylePropsUtils.h +13 -0
  92. package/ios/input/styles/ENRMBoldStyleHandler.mm +3 -2
  93. package/ios/input/styles/ENRMItalicStyleHandler.mm +3 -2
  94. package/ios/internals/MeasurementCache.h +1 -0
  95. package/ios/math/ENRMRaTeXBridge.swift +52 -3
  96. package/ios/parser/ENRMMarkdownParser.h +8 -0
  97. package/ios/parser/ENRMMarkdownParser.mm +11 -0
  98. package/ios/renderer/AttributedRenderer.m +51 -6
  99. package/ios/renderer/ENRMMathInlineRenderer.m +8 -1
  100. package/ios/renderer/ListItemRenderer.m +8 -5
  101. package/ios/styles/ENRMFontSlot.h +1 -1
  102. package/ios/styles/StyleConfig.h +6 -0
  103. package/ios/styles/StyleConfig.mm +36 -0
  104. package/ios/utils/ENRMAccessibilityLabels.h +36 -0
  105. package/ios/utils/ENRMAccessibilityLabels.m +5 -0
  106. package/ios/utils/ENRMMathFontWeight.h +18 -0
  107. package/ios/utils/EditMenuUtils+macOS.m +4 -5
  108. package/ios/utils/EditMenuUtils.h +70 -0
  109. package/ios/utils/EditMenuUtils.m +14 -11
  110. package/ios/utils/LastElementUtils.h +39 -2
  111. package/ios/utils/MarkdownAccessibilityElementBuilder.h +18 -16
  112. package/ios/utils/MarkdownAccessibilityElementBuilder.m +64 -32
  113. package/ios/utils/ParagraphStyleUtils.m +21 -2
  114. package/ios/utils/StylePropsUtils.h +21 -0
  115. package/ios/views/ENRMMathContainerView.h +8 -0
  116. package/ios/views/ENRMMathContainerView.m +10 -6
  117. package/ios/views/ENRMTableIOSGridView.h +40 -0
  118. package/ios/views/ENRMTableIOSGridView.m +216 -0
  119. package/ios/views/EnrichedMarkdownInternalText.h +2 -0
  120. package/ios/views/EnrichedMarkdownInternalText.m +2 -0
  121. package/ios/views/TableContainerView.h +8 -0
  122. package/ios/views/TableContainerView.m +72 -128
  123. package/lib/module/EnrichedMarkdownNativeComponent.ts +40 -0
  124. package/lib/module/EnrichedMarkdownTextInput.js +50 -1
  125. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  126. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +47 -0
  127. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +40 -0
  128. package/lib/module/accessibilityLabelDefaults.js +64 -0
  129. package/lib/module/accessibilityLabelDefaults.js.map +1 -0
  130. package/lib/module/index.js +1 -0
  131. package/lib/module/index.js.map +1 -1
  132. package/lib/module/native/EnrichedMarkdownText.js +72 -4
  133. package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
  134. package/lib/module/normalizeMarkdownStyle.js +5 -2
  135. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  136. package/lib/module/normalizeMarkdownStyle.web.js +5 -2
  137. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  138. package/lib/module/normalizeMarkdownTextInputStyle.js +7 -3
  139. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  140. package/lib/module/normalizeMenuItem.js +38 -0
  141. package/lib/module/normalizeMenuItem.js.map +1 -0
  142. package/lib/module/types/AccessibilityLabels.js +2 -0
  143. package/lib/module/types/AccessibilityLabels.js.map +1 -0
  144. package/lib/module/web/globalStyles.js +8 -1
  145. package/lib/module/web/globalStyles.js.map +1 -1
  146. package/lib/module/web/styles.js +3 -1
  147. package/lib/module/web/styles.js.map +1 -1
  148. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +37 -0
  149. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  150. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +57 -1
  151. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  152. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +42 -0
  153. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  154. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +37 -0
  155. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  156. package/lib/typescript/src/accessibilityLabelDefaults.d.ts +16 -0
  157. package/lib/typescript/src/accessibilityLabelDefaults.d.ts.map +1 -0
  158. package/lib/typescript/src/index.d.ts +4 -2
  159. package/lib/typescript/src/index.d.ts.map +1 -1
  160. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
  161. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
  162. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  163. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  164. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +1 -0
  165. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  166. package/lib/typescript/src/normalizeMenuItem.d.ts +7 -0
  167. package/lib/typescript/src/normalizeMenuItem.d.ts.map +1 -0
  168. package/lib/typescript/src/types/AccessibilityLabels.d.ts +114 -0
  169. package/lib/typescript/src/types/AccessibilityLabels.d.ts.map +1 -0
  170. package/lib/typescript/src/types/MarkdownStyle.d.ts +32 -0
  171. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  172. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +3 -0
  173. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  174. package/lib/typescript/src/types/MarkdownTextProps.d.ts +78 -9
  175. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
  176. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  177. package/package.json +4 -2
  178. package/plugin/build/withAndroidMath.js +19 -0
  179. package/plugin/build/withIosMath.js +28 -0
  180. package/plugin/build/withReactNativeEnrichedMarkdown.js +11 -0
  181. package/plugin/tsconfig.build.json +16 -0
  182. package/src/EnrichedMarkdownNativeComponent.ts +40 -0
  183. package/src/EnrichedMarkdownTextInput.tsx +121 -1
  184. package/src/EnrichedMarkdownTextInputNativeComponent.ts +47 -0
  185. package/src/EnrichedMarkdownTextNativeComponent.ts +40 -0
  186. package/src/accessibilityLabelDefaults.ts +83 -0
  187. package/src/index.tsx +11 -0
  188. package/src/native/EnrichedMarkdownText.tsx +120 -6
  189. package/src/normalizeMarkdownStyle.ts +6 -1
  190. package/src/normalizeMarkdownStyle.web.ts +6 -1
  191. package/src/normalizeMarkdownTextInputStyle.ts +5 -0
  192. package/src/normalizeMenuItem.ts +52 -0
  193. package/src/types/AccessibilityLabels.ts +118 -0
  194. package/src/types/MarkdownStyle.ts +32 -0
  195. package/src/types/MarkdownStyleInternal.ts +3 -0
  196. package/src/types/MarkdownTextProps.ts +74 -9
  197. package/src/web/globalStyles.ts +7 -0
  198. package/src/web/styles.ts +5 -1
  199. package/lib/module/plugin/withAndroidMath.js +0 -20
  200. package/lib/module/plugin/withAndroidMath.js.map +0 -1
  201. package/lib/module/plugin/withIosMath.js +0 -23
  202. package/lib/module/plugin/withIosMath.js.map +0 -1
  203. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js +0 -16
  204. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map +0 -1
  205. package/lib/typescript/src/plugin/withAndroidMath.d.ts +0 -5
  206. package/lib/typescript/src/plugin/withAndroidMath.d.ts.map +0 -1
  207. package/lib/typescript/src/plugin/withIosMath.d.ts +0 -5
  208. package/lib/typescript/src/plugin/withIosMath.d.ts.map +0 -1
  209. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts +0 -6
  210. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts.map +0 -1
  211. /package/{src/plugin → plugin/src}/withAndroidMath.ts +0 -0
  212. /package/{src/plugin → plugin/src}/withIosMath.ts +0 -0
  213. /package/{src/plugin → plugin/src}/withReactNativeEnrichedMarkdown.ts +0 -0
@@ -26,6 +26,7 @@ interface MathStyleInternal {
26
26
  paddingVertical: number;
27
27
  selectedBackgroundColor: ColorValue;
28
28
  selectedBorderColor: ColorValue;
29
+ fontWeight: string;
29
30
  }
30
31
 
31
32
  interface MathBlockStyleInternal extends MathStyleInternal {
@@ -76,6 +77,7 @@ const defaultMathInternal: MathStyleInternal = Object.freeze({
76
77
  paddingVertical: 0,
77
78
  selectedBackgroundColor: TRANSPARENT,
78
79
  selectedBorderColor: TRANSPARENT,
80
+ fontWeight: 'normal',
79
81
  });
80
82
 
81
83
  const defaultMathBlockInternal: MathBlockStyleInternal = Object.freeze({
@@ -89,6 +91,7 @@ const defaultMathBlockInternal: MathBlockStyleInternal = Object.freeze({
89
91
  paddingVertical: 8,
90
92
  selectedBackgroundColor: TRANSPARENT,
91
93
  selectedBorderColor: TRANSPARENT,
94
+ fontWeight: 'normal',
92
95
  marginTop: 8,
93
96
  marginBottom: 8,
94
97
  alignment: 'center',
@@ -152,6 +155,7 @@ function normalizeMathStyle(
152
155
  normalizeColor(style?.selectedBackgroundColor) ?? backgroundColor,
153
156
  selectedBorderColor:
154
157
  normalizeColor(style?.selectedBorderColor) ?? borderColor,
158
+ fontWeight: style?.fontWeight ?? fallback.fontWeight,
155
159
  };
156
160
  }
157
161
 
@@ -171,6 +175,7 @@ function normalizeMathBlockStyle(
171
175
  paddingVertical: fallback.paddingVertical,
172
176
  selectedBackgroundColor: baseInline.selectedBackgroundColor,
173
177
  selectedBorderColor: baseInline.selectedBorderColor,
178
+ fontWeight: baseInline.fontWeight,
174
179
  };
175
180
  const inheritedInline = normalizeMathStyle(style, merged);
176
181
  let alignment: 'left' | 'center' | 'right' = fallback.alignment;
@@ -0,0 +1,52 @@
1
+ // Not __DEV__-gated on purpose: deprecation warnings need to surface in
2
+ // staging/TestFlight/CI prod builds too.
3
+ const warned = new Set<string>();
4
+
5
+ const warnOnce = (key: string, msg: string) => {
6
+ if (warned.has(key)) return;
7
+ warned.add(key);
8
+ console.warn(msg);
9
+ };
10
+
11
+ export type NormalizedMenuItem = { enabled: boolean; label: string };
12
+
13
+ // TODO: revisit grouping cross-cutting utilities (this, styleUtils, linkVariantUtils,
14
+ // normalizeMarkdownStyle, etc.) into a shared module once the set grows further.
15
+ export const normalizeMenuItem = (
16
+ raw: unknown,
17
+ defaultEnabled: boolean,
18
+ defaultLabel: string
19
+ ): NormalizedMenuItem => {
20
+ if (raw === undefined)
21
+ return { enabled: defaultEnabled, label: defaultLabel };
22
+ // Validate per leaf so an empty string stays an empty string (an emoji-only
23
+ // item is a legitimate use case), while null / non-object / wrong-typed
24
+ // fields fall back to defaults — `getBoolean` on the Android side throws on
25
+ // non-booleans, and a null root would crash JS on property access.
26
+ const obj =
27
+ typeof raw === 'object' && raw !== null
28
+ ? (raw as { enabled?: unknown; label?: unknown })
29
+ : {};
30
+ return {
31
+ enabled: typeof obj.enabled === 'boolean' ? obj.enabled : defaultEnabled,
32
+ label: typeof obj.label === 'string' ? obj.label : defaultLabel,
33
+ };
34
+ };
35
+
36
+ export const normalizeLegacyBooleanMenuItem = (
37
+ raw: unknown,
38
+ parentProp: string,
39
+ field: string,
40
+ defaultEnabled: boolean,
41
+ defaultLabel: string
42
+ ): NormalizedMenuItem => {
43
+ if (typeof raw === 'boolean') {
44
+ warnOnce(
45
+ `${parentProp}.${field}`,
46
+ `[react-native-enriched-markdown] ${parentProp}.${field} as a boolean is ` +
47
+ `deprecated; use { enabled: ${raw} }. The boolean form will be removed in 0.8.`
48
+ );
49
+ return { enabled: raw, label: defaultLabel };
50
+ }
51
+ return normalizeMenuItem(raw, defaultEnabled, defaultLabel);
52
+ };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Strings spoken by VoiceOver (iOS) / TalkBack (Android) when navigating
3
+ * the rendered markdown.
4
+ *
5
+ * Every key is optional — when omitted, defaults from
6
+ * `accessibilityLabelDefaults.ts` are applied on the JS side before being
7
+ * forwarded to native. Native code can rely on every field being a concrete
8
+ * string at the point it is consumed.
9
+ *
10
+ * **Placeholder syntax.** Where a label has dynamic content, the default uses
11
+ * `{n}` (count / index, 1-based), `{content}` (resolved cell text or similar),
12
+ * or `{latex}` (math source). Translations must preserve the placeholder names
13
+ * exactly — native code substitutes them at speak time.
14
+ *
15
+ * **No plurals.** Defaults intentionally use the cardinal form (`"Row 2"`,
16
+ * `"List item 2"`) instead of ordinals or count-aware variants. Screen readers
17
+ * already announce numbers locale-appropriately, and a single template avoids
18
+ * the per-language plural rules (en `1/2+`, pl `1/2-4/5+`, ar `0/1/2/3-10/11-99/100+`, …).
19
+ *
20
+ * The shape is split into logical sub-groups so that consumers can override
21
+ * just the announcements that matter to them without re-declaring the rest.
22
+ */
23
+ export interface AccessibilityLabels {
24
+ /** Labels spoken for list items. iOS + Android. */
25
+ list?: {
26
+ /** @default 'Bullet point' */
27
+ bulletPoint?: string;
28
+ /**
29
+ * Spoken when the bullet is inside another list.
30
+ * @default 'Nested bullet point'
31
+ */
32
+ nestedBulletPoint?: string;
33
+ /**
34
+ * `{n}` → 1-based item number.
35
+ * @default 'List item {n}'
36
+ */
37
+ orderedItem?: string;
38
+ /**
39
+ * `{n}` → 1-based item number.
40
+ * @default 'Nested list item {n}'
41
+ */
42
+ nestedOrderedItem?: string;
43
+ };
44
+
45
+ /** Labels appended for content inside a blockquote. iOS + Android. */
46
+ blockquote?: {
47
+ /**
48
+ * Spoken for top-level blockquote content.
49
+ * @default 'Blockquote'
50
+ */
51
+ quote?: string;
52
+ /**
53
+ * Spoken for content nested inside another blockquote.
54
+ * @default 'Nested blockquote'
55
+ */
56
+ nestedQuote?: string;
57
+ };
58
+
59
+ /** Labels spoken for tables. iOS + Android. */
60
+ table?: {
61
+ /**
62
+ * `{n}` → 1-based row index, `{content}` → comma-joined cell texts.
63
+ * @default 'Row {n}: {content}'
64
+ */
65
+ row?: string;
66
+ };
67
+
68
+ /** Labels spoken for math equations. iOS + Android. */
69
+ math?: {
70
+ /**
71
+ * `{latex}` → equation source.
72
+ * @default 'Math: {latex}'
73
+ */
74
+ equation?: string;
75
+ };
76
+
77
+ /**
78
+ * Labels for the VoiceOver rotor (the secondary jump-by-type navigator on iOS).
79
+ * iOS only — Android has no rotor concept.
80
+ */
81
+ rotor?: {
82
+ /** @default 'Headings' */
83
+ headings?: string;
84
+ /** @default 'Links' */
85
+ links?: string;
86
+ /** @default 'Images' */
87
+ images?: string;
88
+ };
89
+ }
90
+
91
+ /**
92
+ * Fully-populated counterpart of `AccessibilityLabels` — every leaf field is a
93
+ * concrete string. Produced by `resolveAccessibilityLabels()` and what native
94
+ * code should be wired to consume.
95
+ */
96
+ export interface ResolvedAccessibilityLabels {
97
+ list: {
98
+ bulletPoint: string;
99
+ nestedBulletPoint: string;
100
+ orderedItem: string;
101
+ nestedOrderedItem: string;
102
+ };
103
+ blockquote: {
104
+ quote: string;
105
+ nestedQuote: string;
106
+ };
107
+ table: {
108
+ row: string;
109
+ };
110
+ math: {
111
+ equation: string;
112
+ };
113
+ rotor: {
114
+ headings: string;
115
+ links: string;
116
+ images: string;
117
+ };
118
+ }
@@ -155,10 +155,42 @@ interface MathStyle {
155
155
  marginTop?: number;
156
156
  marginBottom?: number;
157
157
  textAlign?: 'left' | 'center' | 'right';
158
+ /**
159
+ * Typeset the formula at bold weight.
160
+ *
161
+ * The native engine has no weight parameter and its glyph positions are
162
+ * already laid out when this applies, so `'bold'` is a SYNTHETIC embolden
163
+ * (a stroke on iOS, the platform's fake-bold on Android) rather than a
164
+ * switch to the bundled bold faces. That is deliberate: KaTeX's bold faces
165
+ * are up to 15% wider than the regular advances the layout reserved, so
166
+ * swapping them in would make glyphs collide.
167
+ * @default 'normal'
168
+ */
169
+ fontWeight?: 'bold' | 'normal';
158
170
  }
159
171
 
160
172
  interface InlineMathStyle {
161
173
  color?: string;
174
+ /**
175
+ * Empty space added above and below the formula box, in points.
176
+ * Inline formulas report their own metrics, so a fraction can be taller
177
+ * than the paragraph's `lineHeight` — which is expand-only and therefore
178
+ * cannot loosen those lines. This is the knob that does.
179
+ * @default 4
180
+ */
181
+ paddingVertical?: number;
182
+ /**
183
+ * Typeset the formula at bold weight.
184
+ *
185
+ * The native engine has no weight parameter and its glyph positions are
186
+ * already laid out when this applies, so `'bold'` is a SYNTHETIC embolden
187
+ * (a stroke on iOS, the platform's fake-bold on Android) rather than a
188
+ * switch to the bundled bold faces. That is deliberate: KaTeX's bold faces
189
+ * are up to 15% wider than the regular advances the layout reserved, so
190
+ * swapping them in would make glyphs collide.
191
+ * @default 'normal'
192
+ */
193
+ fontWeight?: 'bold' | 'normal';
162
194
  }
163
195
 
164
196
  interface SpoilerParticlesStyle {
@@ -140,10 +140,13 @@ interface MathStyleInternal {
140
140
  marginTop: number;
141
141
  marginBottom: number;
142
142
  textAlign: BlockTextAlign;
143
+ fontWeight: string;
143
144
  }
144
145
 
145
146
  interface InlineMathStyleInternal {
146
147
  color: string;
148
+ paddingVertical: number;
149
+ fontWeight: string;
147
150
  }
148
151
 
149
152
  interface SpoilerParticlesStyleInternal {
@@ -1,5 +1,6 @@
1
1
  import type { ColorValue, ViewProps, ViewStyle, TextStyle } from 'react-native';
2
2
  import type { MarkdownStyle, Md4cFlags } from './MarkdownStyle';
3
+ import type { AccessibilityLabels } from './AccessibilityLabels';
3
4
  import type {
4
5
  LinkPressEvent,
5
6
  LinkLongPressEvent,
@@ -20,17 +21,71 @@ export interface ContextMenuItem {
20
21
  visible?: boolean;
21
22
  }
22
23
 
24
+ /**
25
+ * Plural forms for the "Copy Image URL(s)" action, keyed by CLDR plural
26
+ * category. The right form is chosen at runtime from the number of selected
27
+ * images using `Intl.PluralRules` (resolved against the app's default locale).
28
+ *
29
+ * Each value is a template where the `{count}` token is replaced with the
30
+ * number of selected images. Only `other` is required by CLDR; any category
31
+ * left `undefined` falls back to `other`.
32
+ *
33
+ * @example
34
+ * // Polish: one / few / many / other
35
+ * pluralLabels: {
36
+ * one: 'Kopiuj adres URL obrazu',
37
+ * few: 'Kopiuj adresy URL {count} obrazów',
38
+ * many: 'Kopiuj adresy URL {count} obrazów',
39
+ * other: 'Kopiuj adresy URL {count} obrazu',
40
+ * }
41
+ */
42
+ export interface SelectionMenuPluralLabels {
43
+ /**
44
+ * Required base form. Any category left `undefined` falls back to `other`,
45
+ * so the menu never shows the English default once `pluralLabels` is set.
46
+ */
47
+ other: string;
48
+ zero?: string;
49
+ one?: string;
50
+ two?: string;
51
+ few?: string;
52
+ many?: string;
53
+ }
54
+
55
+ /**
56
+ * Controls the built-in items added to the native text selection menu and
57
+ * lets you localize their labels.
58
+ *
59
+ * Each item accepts an object: `{ enabled }` toggles visibility (the system
60
+ * `copy` item can't be hidden — only relabeled) and `label` overrides the
61
+ * English default. Wire `label` to your i18n library to match the rest of your
62
+ * app's UI. Labels apply to the main text selection menu as well as the table
63
+ * and math block copy menus.
64
+ *
65
+ * @platform ios, android, macos
66
+ */
23
67
  export interface SelectionMenuConfig {
24
68
  /**
25
- * Shows the built-in "Copy as Markdown" action for text selections.
26
- * @default true
69
+ * The system "Copy" item. It can't be hidden — only its label is configurable.
70
+ * @default { label: "Copy" }
27
71
  */
28
- copyAsMarkdown?: boolean;
72
+ copy?: { label?: string };
29
73
  /**
30
- * Shows the built-in "Copy Image URL" action when selected content contains images.
31
- * @default true
74
+ * The built-in "Copy as Markdown" action for text selections.
75
+ * @default { enabled: true, label: "Copy as Markdown" }
76
+ */
77
+ copyAsMarkdown?: { enabled?: boolean; label?: string };
78
+ /**
79
+ * The built-in "Copy Image URL" action, shown when the selection contains
80
+ * images. `label` is used for a single image; `pluralLabels` provides the
81
+ * forms for multiple images.
82
+ * @default { enabled: true, label: "Copy Image URL" }
32
83
  */
33
- copyImageUrl?: boolean;
84
+ copyImageUrl?: {
85
+ enabled?: boolean;
86
+ label?: string;
87
+ pluralLabels?: SelectionMenuPluralLabels;
88
+ };
34
89
  }
35
90
 
36
91
  export interface StreamingConfig {
@@ -200,12 +255,22 @@ export interface EnrichedMarkdownTextProps extends Omit<ViewProps, 'style'> {
200
255
  */
201
256
  contextMenuItems?: ContextMenuItem[];
202
257
  /**
203
- * Controls built-in items added to the native text selection menu.
204
- * Custom app-provided actions are controlled separately with `contextMenuItems`.
205
- * @default { copyAsMarkdown: true, copyImageUrl: true }
258
+ * Controls the built-in items added to the native text selection menu and
259
+ * lets you localize their labels. Custom app-provided actions are controlled
260
+ * separately with `contextMenuItems`.
261
+ * @default { copyAsMarkdown: { enabled: true }, copyImageUrl: { enabled: true } }
206
262
  * @platform ios, android, macos
207
263
  */
208
264
  selectionMenuConfig?: SelectionMenuConfig;
265
+ /**
266
+ * Translations for VoiceOver / TalkBack announcements (list items, table
267
+ * rows, math, and the iOS rotor). All keys are optional and fall back to
268
+ * the English defaults from `accessibilityLabelDefaults.ts` — see
269
+ * `AccessibilityLabels` for the placeholder syntax and the no-plural
270
+ * rationale.
271
+ * @platform ios, android
272
+ */
273
+ accessibilityLabels?: AccessibilityLabels;
209
274
  /**
210
275
  * Sets the text direction on the root container.
211
276
  * Useful for RTL languages — CSS logical properties in the renderers
@@ -8,6 +8,13 @@ const RULES: ReadonlyArray<readonly [id: string, css: string]> = [
8
8
  'enrm-selection-style',
9
9
  `.${ENRM_TEXT_CLASS} ::selection { background-color: var(${ENRM_SELECTION_BG_VAR}); }`,
10
10
  ],
11
+ // `fontWeight` for math is set on the span wrapping KaTeX's output, so the
12
+ // formula only picks it up by inheritance. `katex.css` opens `.katex` with
13
+ // the `font` shorthand, which resets `font-weight` — and a rule matching the
14
+ // element itself always beats a value inherited from an ancestor, inline
15
+ // style included. We do not load `katex.css` (MathML output needs no CSS),
16
+ // but a consumer may, so opt `.katex` back into inheriting.
17
+ ['enrm-katex-font-weight', '.katex { font-weight: inherit; }'],
11
18
  ];
12
19
 
13
20
  for (const [id, css] of RULES) {
package/src/web/styles.ts CHANGED
@@ -333,7 +333,10 @@ function highlightStyle(style: MarkdownStyleInternal): CSSProperties {
333
333
  }
334
334
 
335
335
  function mathInlineStyle(style: MarkdownStyleInternal): CSSProperties {
336
- return { color: style.inlineMath.color };
336
+ return {
337
+ color: style.inlineMath.color,
338
+ fontWeight: normalizeFontWeight(style.inlineMath.fontWeight),
339
+ };
337
340
  }
338
341
 
339
342
  function mathDisplayStyle(style: MarkdownStyleInternal): CSSProperties {
@@ -341,6 +344,7 @@ function mathDisplayStyle(style: MarkdownStyleInternal): CSSProperties {
341
344
  return {
342
345
  fontSize: math.fontSize,
343
346
  color: math.color,
347
+ fontWeight: normalizeFontWeight(math.fontWeight),
344
348
  backgroundColor: math.backgroundColor,
345
349
  padding: math.padding,
346
350
  marginTop: math.marginTop,
@@ -1,20 +0,0 @@
1
- "use strict";
2
-
3
- import { withGradleProperties } from '@expo/config-plugins';
4
- export const withAndroidMath = (config, {
5
- enableMath = true
6
- }) => {
7
- if (enableMath) {
8
- return config;
9
- }
10
- return withGradleProperties(config, gradleConfig => {
11
- gradleConfig.modResults = gradleConfig.modResults.filter(prop => prop.type !== 'property' || prop.key !== 'enrichedMarkdown.enableMath');
12
- gradleConfig.modResults.push({
13
- type: 'property',
14
- key: 'enrichedMarkdown.enableMath',
15
- value: 'false'
16
- });
17
- return gradleConfig;
18
- });
19
- };
20
- //# sourceMappingURL=withAndroidMath.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["withGradleProperties","withAndroidMath","config","enableMath","gradleConfig","modResults","filter","prop","type","key","push","value"],"sourceRoot":"../../../src","sources":["plugin/withAndroidMath.ts"],"mappings":";;AAAA,SAASA,oBAAoB,QAA2B,sBAAsB;AAE9E,OAAO,MAAMC,eAAuD,GAAGA,CACrEC,MAAM,EACN;EAAEC,UAAU,GAAG;AAAK,CAAC,KAClB;EACH,IAAIA,UAAU,EAAE;IACd,OAAOD,MAAM;EACf;EACA,OAAOF,oBAAoB,CAACE,MAAM,EAAGE,YAAY,IAAK;IACpDA,YAAY,CAACC,UAAU,GAAGD,YAAY,CAACC,UAAU,CAACC,MAAM,CACrDC,IAAI,IACHA,IAAI,CAACC,IAAI,KAAK,UAAU,IAAID,IAAI,CAACE,GAAG,KAAK,6BAC7C,CAAC;IAEDL,YAAY,CAACC,UAAU,CAACK,IAAI,CAAC;MAC3BF,IAAI,EAAE,UAAU;MAChBC,GAAG,EAAE,6BAA6B;MAClCE,KAAK,EAAE;IACT,CAAC,CAAC;IAEF,OAAOP,YAAY;EACrB,CAAC,CAAC;AACJ,CAAC","ignoreList":[]}
@@ -1,23 +0,0 @@
1
- "use strict";
2
-
3
- import { withDangerousMod } from '@expo/config-plugins';
4
- import fs from 'fs';
5
- import path from 'path';
6
- const IOS_MATH_OPTION = "ENV['ENRICHED_MARKDOWN_ENABLE_MATH'] = '0'";
7
- export const withIosMath = (config, {
8
- enableMath = true
9
- }) => {
10
- if (enableMath) {
11
- return config;
12
- }
13
- return withDangerousMod(config, ['ios', async modConfig => {
14
- const file = path.join(modConfig.modRequest.platformProjectRoot, 'Podfile');
15
- const contents = fs.readFileSync(file, 'utf8');
16
- const lines = contents.split('\n');
17
- const filteredLines = lines.filter(line => !line.includes('ENRICHED_MARKDOWN_ENABLE_MATH'));
18
- filteredLines.unshift(IOS_MATH_OPTION);
19
- fs.writeFileSync(file, filteredLines.join('\n'));
20
- return modConfig;
21
- }]);
22
- };
23
- //# sourceMappingURL=withIosMath.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["withDangerousMod","fs","path","IOS_MATH_OPTION","withIosMath","config","enableMath","modConfig","file","join","modRequest","platformProjectRoot","contents","readFileSync","lines","split","filteredLines","filter","line","includes","unshift","writeFileSync"],"sourceRoot":"../../../src","sources":["plugin/withIosMath.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAA2B,sBAAsB;AAC1E,OAAOC,EAAE,MAAM,IAAI;AACnB,OAAOC,IAAI,MAAM,MAAM;AAEvB,MAAMC,eAAe,GAAG,4CAA4C;AAEpE,OAAO,MAAMC,WAAmD,GAAGA,CACjEC,MAAM,EACN;EAAEC,UAAU,GAAG;AAAK,CAAC,KAClB;EACH,IAAIA,UAAU,EAAE;IACd,OAAOD,MAAM;EACf;EACA,OAAOL,gBAAgB,CAACK,MAAM,EAAE,CAC9B,KAAK,EACL,MAAOE,SAAS,IAAK;IACnB,MAAMC,IAAI,GAAGN,IAAI,CAACO,IAAI,CACpBF,SAAS,CAACG,UAAU,CAACC,mBAAmB,EACxC,SACF,CAAC;IACD,MAAMC,QAAQ,GAAGX,EAAE,CAACY,YAAY,CAACL,IAAI,EAAE,MAAM,CAAC;IAE9C,MAAMM,KAAK,GAAGF,QAAQ,CAACG,KAAK,CAAC,IAAI,CAAC;IAClC,MAAMC,aAAa,GAAGF,KAAK,CAACG,MAAM,CAC/BC,IAAY,IAAK,CAACA,IAAI,CAACC,QAAQ,CAAC,+BAA+B,CAClE,CAAC;IAEDH,aAAa,CAACI,OAAO,CAACjB,eAAe,CAAC;IAEtCF,EAAE,CAACoB,aAAa,CAACb,IAAI,EAAEQ,aAAa,CAACP,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhD,OAAOF,SAAS;EAClB,CAAC,CACF,CAAC;AACJ,CAAC","ignoreList":[]}
@@ -1,16 +0,0 @@
1
- "use strict";
2
-
3
- import { withIosMath } from "./withIosMath.js";
4
- import { withAndroidMath } from "./withAndroidMath.js";
5
- const withEnrichedMarkdown = (config, props) => {
6
- const enableMath = props?.enableMath !== false;
7
- config = withAndroidMath(config, {
8
- enableMath
9
- });
10
- config = withIosMath(config, {
11
- enableMath
12
- });
13
- return config;
14
- };
15
- export default withEnrichedMarkdown;
16
- //# sourceMappingURL=withReactNativeEnrichedMarkdown.js.map
@@ -1 +0,0 @@
1
- {"version":3,"names":["withIosMath","withAndroidMath","withEnrichedMarkdown","config","props","enableMath"],"sourceRoot":"../../../src","sources":["plugin/withReactNativeEnrichedMarkdown.ts"],"mappings":";;AACA,SAASA,WAAW,QAAQ,kBAAe;AAC3C,SAASC,eAAe,QAAQ,sBAAmB;AAEnD,MAAMC,oBAAmE,GAAGA,CAC1EC,MAAM,EACNC,KAAK,KACF;EACH,MAAMC,UAAU,GAAGD,KAAK,EAAEC,UAAU,KAAK,KAAK;EAE9CF,MAAM,GAAGF,eAAe,CAACE,MAAM,EAAE;IAAEE;EAAW,CAAC,CAAC;EAChDF,MAAM,GAAGH,WAAW,CAACG,MAAM,EAAE;IAAEE;EAAW,CAAC,CAAC;EAE5C,OAAOF,MAAM;AACf,CAAC;AAED,eAAeD,oBAAoB","ignoreList":[]}
@@ -1,5 +0,0 @@
1
- import { type ConfigPlugin } from '@expo/config-plugins';
2
- export declare const withAndroidMath: ConfigPlugin<{
3
- enableMath?: boolean;
4
- }>;
5
- //# sourceMappingURL=withAndroidMath.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withAndroidMath.d.ts","sourceRoot":"","sources":["../../../../src/plugin/withAndroidMath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE/E,eAAO,MAAM,eAAe,EAAE,YAAY,CAAC;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,CAqBlE,CAAC"}
@@ -1,5 +0,0 @@
1
- import { type ConfigPlugin } from '@expo/config-plugins';
2
- export declare const withIosMath: ConfigPlugin<{
3
- enableMath?: boolean;
4
- }>;
5
- //# sourceMappingURL=withIosMath.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withIosMath.d.ts","sourceRoot":"","sources":["../../../../src/plugin/withIosMath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAM3E,eAAO,MAAM,WAAW,EAAE,YAAY,CAAC;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,CA4B9D,CAAC"}
@@ -1,6 +0,0 @@
1
- import { type ConfigPlugin } from '@expo/config-plugins';
2
- declare const withEnrichedMarkdown: ConfigPlugin<{
3
- enableMath?: boolean;
4
- } | void>;
5
- export default withEnrichedMarkdown;
6
- //# sourceMappingURL=withReactNativeEnrichedMarkdown.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withReactNativeEnrichedMarkdown.d.ts","sourceRoot":"","sources":["../../../../src/plugin/withReactNativeEnrichedMarkdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,QAAA,MAAM,oBAAoB,EAAE,YAAY,CAAC;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAUvE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
File without changes
File without changes