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.
- package/ReactNativeEnrichedMarkdown.podspec +62 -11
- package/android/build.gradle +5 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +1 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +12 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +4 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +3 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +1 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +25 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +793 -0
- package/android/src/main/baseline-prof.txt +75 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +62 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +10 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +9 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +6 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/AccessibilityLabels.kt +15 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +44 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +72 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +110 -12
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockSyntaxSentinel.kt +69 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +19 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +84 -6
- package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputRemend.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputLayoutManager.kt +30 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +13 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +54 -13
- package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +17 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +1 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +4 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +8 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +5 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathFontWeight.kt +25 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +12 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +37 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +10 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/SpannableExtensions.kt +12 -4
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt +22 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +36 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +74 -4
- package/android/src/main/jni/CMakeLists.txt +15 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +2 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlinePlaceholderSpan.kt +7 -3
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +8 -5
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathTypeface.kt +30 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +27 -3
- package/app.plugin.js +2 -1
- package/cpp/parser/MD4CParser.cpp +1 -1
- package/cpp/wasm/build.sh +9 -9
- package/docs/ACCESSIBILITY.md +172 -0
- package/docs/API_REFERENCE.md +957 -0
- package/docs/COPY_OPTIONS.md +127 -0
- package/docs/ELEMENTS_STRUCTURE.md +112 -0
- package/docs/IMAGE_CACHING.md +25 -0
- package/docs/INPUT.md +281 -0
- package/docs/LATEX_MATH.md +198 -0
- package/docs/MACOS.md +19 -0
- package/docs/MARKDOWN_STREAMING.md +36 -0
- package/docs/MENTIONS.md +97 -0
- package/docs/RTL.md +82 -0
- package/docs/STYLES.md +522 -0
- package/docs/TEXT.md +110 -0
- package/docs/WEB.md +49 -0
- package/ios/EnrichedMarkdown.mm +126 -37
- package/ios/EnrichedMarkdownText.mm +84 -16
- package/ios/attachments/ENRMMathInlineAttachment+macOS.m +5 -1
- package/ios/attachments/ENRMMathInlineAttachment.h +3 -0
- package/ios/attachments/ENRMMathInlineAttachment.m +2 -1
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +25 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +793 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +15 -0
- package/ios/input/ENRMBlockSyntaxSentinel.h +25 -0
- package/ios/input/ENRMBlockSyntaxSentinel.mm +80 -0
- package/ios/input/ENRMFormattingStore.h +5 -0
- package/ios/input/ENRMFormattingStore.mm +34 -0
- package/ios/input/ENRMInputFormatter.h +4 -0
- package/ios/input/ENRMInputFormatter.mm +2 -0
- package/ios/input/ENRMInputParser.h +5 -0
- package/ios/input/ENRMInputParser.mm +79 -6
- package/ios/input/ENRMInputTextView.h +2 -0
- package/ios/input/ENRMInputTextView.mm +8 -17
- package/ios/input/ENRMMarkdownSerializer.mm +1 -1
- package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +71 -53
- package/ios/input/EnrichedMarkdownTextInput+Internal.h +26 -0
- package/ios/input/EnrichedMarkdownTextInput.h +1 -0
- package/ios/input/EnrichedMarkdownTextInput.mm +249 -31
- package/ios/input/InputStylePropsUtils.h +13 -0
- package/ios/input/styles/ENRMBoldStyleHandler.mm +3 -2
- package/ios/input/styles/ENRMItalicStyleHandler.mm +3 -2
- package/ios/internals/MeasurementCache.h +1 -0
- package/ios/math/ENRMRaTeXBridge.swift +52 -3
- package/ios/parser/ENRMMarkdownParser.h +8 -0
- package/ios/parser/ENRMMarkdownParser.mm +11 -0
- package/ios/renderer/AttributedRenderer.m +51 -6
- package/ios/renderer/ENRMMathInlineRenderer.m +8 -1
- package/ios/renderer/ListItemRenderer.m +8 -5
- package/ios/styles/ENRMFontSlot.h +1 -1
- package/ios/styles/StyleConfig.h +6 -0
- package/ios/styles/StyleConfig.mm +36 -0
- package/ios/utils/ENRMAccessibilityLabels.h +36 -0
- package/ios/utils/ENRMAccessibilityLabels.m +5 -0
- package/ios/utils/ENRMMathFontWeight.h +18 -0
- package/ios/utils/EditMenuUtils+macOS.m +4 -5
- package/ios/utils/EditMenuUtils.h +70 -0
- package/ios/utils/EditMenuUtils.m +14 -11
- package/ios/utils/LastElementUtils.h +39 -2
- package/ios/utils/MarkdownAccessibilityElementBuilder.h +18 -16
- package/ios/utils/MarkdownAccessibilityElementBuilder.m +64 -32
- package/ios/utils/ParagraphStyleUtils.m +21 -2
- package/ios/utils/StylePropsUtils.h +21 -0
- package/ios/views/ENRMMathContainerView.h +8 -0
- package/ios/views/ENRMMathContainerView.m +10 -6
- package/ios/views/ENRMTableIOSGridView.h +40 -0
- package/ios/views/ENRMTableIOSGridView.m +216 -0
- package/ios/views/EnrichedMarkdownInternalText.h +2 -0
- package/ios/views/EnrichedMarkdownInternalText.m +2 -0
- package/ios/views/TableContainerView.h +8 -0
- package/ios/views/TableContainerView.m +72 -128
- package/lib/module/EnrichedMarkdownNativeComponent.ts +40 -0
- package/lib/module/EnrichedMarkdownTextInput.js +50 -1
- package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
- package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +47 -0
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +40 -0
- package/lib/module/accessibilityLabelDefaults.js +64 -0
- package/lib/module/accessibilityLabelDefaults.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/native/EnrichedMarkdownText.js +72 -4
- package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.js +5 -2
- package/lib/module/normalizeMarkdownStyle.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.web.js +5 -2
- package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
- package/lib/module/normalizeMarkdownTextInputStyle.js +7 -3
- package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
- package/lib/module/normalizeMenuItem.js +38 -0
- package/lib/module/normalizeMenuItem.js.map +1 -0
- package/lib/module/types/AccessibilityLabels.js +2 -0
- package/lib/module/types/AccessibilityLabels.js.map +1 -0
- package/lib/module/web/globalStyles.js +8 -1
- package/lib/module/web/globalStyles.js.map +1 -1
- package/lib/module/web/styles.js +3 -1
- package/lib/module/web/styles.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +37 -0
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +57 -1
- package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +42 -0
- package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +37 -0
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/accessibilityLabelDefaults.d.ts +16 -0
- package/lib/typescript/src/accessibilityLabelDefaults.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +4 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +1 -0
- package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
- package/lib/typescript/src/normalizeMenuItem.d.ts +7 -0
- package/lib/typescript/src/normalizeMenuItem.d.ts.map +1 -0
- package/lib/typescript/src/types/AccessibilityLabels.d.ts +114 -0
- package/lib/typescript/src/types/AccessibilityLabels.d.ts.map +1 -0
- package/lib/typescript/src/types/MarkdownStyle.d.ts +32 -0
- package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +3 -0
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.d.ts +78 -9
- package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
- package/lib/typescript/src/web/styles.d.ts.map +1 -1
- package/package.json +4 -2
- package/plugin/build/withAndroidMath.js +19 -0
- package/plugin/build/withIosMath.js +28 -0
- package/plugin/build/withReactNativeEnrichedMarkdown.js +11 -0
- package/plugin/tsconfig.build.json +16 -0
- package/src/EnrichedMarkdownNativeComponent.ts +40 -0
- package/src/EnrichedMarkdownTextInput.tsx +121 -1
- package/src/EnrichedMarkdownTextInputNativeComponent.ts +47 -0
- package/src/EnrichedMarkdownTextNativeComponent.ts +40 -0
- package/src/accessibilityLabelDefaults.ts +83 -0
- package/src/index.tsx +11 -0
- package/src/native/EnrichedMarkdownText.tsx +120 -6
- package/src/normalizeMarkdownStyle.ts +6 -1
- package/src/normalizeMarkdownStyle.web.ts +6 -1
- package/src/normalizeMarkdownTextInputStyle.ts +5 -0
- package/src/normalizeMenuItem.ts +52 -0
- package/src/types/AccessibilityLabels.ts +118 -0
- package/src/types/MarkdownStyle.ts +32 -0
- package/src/types/MarkdownStyleInternal.ts +3 -0
- package/src/types/MarkdownTextProps.ts +74 -9
- package/src/web/globalStyles.ts +7 -0
- package/src/web/styles.ts +5 -1
- package/lib/module/plugin/withAndroidMath.js +0 -20
- package/lib/module/plugin/withAndroidMath.js.map +0 -1
- package/lib/module/plugin/withIosMath.js +0 -23
- package/lib/module/plugin/withIosMath.js.map +0 -1
- package/lib/module/plugin/withReactNativeEnrichedMarkdown.js +0 -16
- package/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map +0 -1
- package/lib/typescript/src/plugin/withAndroidMath.d.ts +0 -5
- package/lib/typescript/src/plugin/withAndroidMath.d.ts.map +0 -1
- package/lib/typescript/src/plugin/withIosMath.d.ts +0 -5
- package/lib/typescript/src/plugin/withIosMath.d.ts.map +0 -1
- package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts +0 -6
- package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts.map +0 -1
- /package/{src/plugin → plugin/src}/withAndroidMath.ts +0 -0
- /package/{src/plugin → plugin/src}/withIosMath.ts +0 -0
- /package/{src/plugin → plugin/src}/withReactNativeEnrichedMarkdown.ts +0 -0
|
@@ -38,6 +38,7 @@ import type {
|
|
|
38
38
|
ColorValue,
|
|
39
39
|
} from 'react-native';
|
|
40
40
|
import { normalizeMarkdownTextInputStyle } from './normalizeMarkdownTextInputStyle';
|
|
41
|
+
import { normalizeMenuItem } from './normalizeMenuItem';
|
|
41
42
|
import { toNativeRegexConfig } from './utils/regexParser';
|
|
42
43
|
import type { RefObject } from 'react';
|
|
43
44
|
|
|
@@ -60,6 +61,7 @@ export interface MathStyle {
|
|
|
60
61
|
paddingVertical?: number;
|
|
61
62
|
selectedBackgroundColor?: string;
|
|
62
63
|
selectedBorderColor?: string;
|
|
64
|
+
fontWeight?: 'bold' | 'normal';
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
export interface MathBlockStyle extends MathStyle {
|
|
@@ -149,10 +151,48 @@ export interface EnrichedMarkdownTextInputInstance {
|
|
|
149
151
|
options?: InsertMathOptions
|
|
150
152
|
) => void;
|
|
151
153
|
removeMath: (start: number) => void;
|
|
154
|
+
copyToClipboard: () => void;
|
|
152
155
|
getMarkdown: () => Promise<string>;
|
|
153
156
|
getCaretRect: () => Promise<CaretRect>;
|
|
154
157
|
}
|
|
155
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Per-item shape: `{ enabled }` toggles visibility, `label` overrides the
|
|
161
|
+
* English default. Wire `label` to your i18n library to localize the menu.
|
|
162
|
+
*/
|
|
163
|
+
type MenuItem = { enabled?: boolean; label?: string };
|
|
164
|
+
|
|
165
|
+
export interface InputSelectionMenuConfig {
|
|
166
|
+
/**
|
|
167
|
+
* The built-in "Format" submenu (Bold, Italic, Underline, etc.) in the
|
|
168
|
+
* text selection context menu. `label` overrides the submenu title.
|
|
169
|
+
* @default { enabled: true, label: "Format" }
|
|
170
|
+
*/
|
|
171
|
+
format?: MenuItem;
|
|
172
|
+
/**
|
|
173
|
+
* The built-in "Copy as Markdown" action in the text selection context
|
|
174
|
+
* menu. `label` overrides the action title.
|
|
175
|
+
* @default { enabled: true, label: "Copy as Markdown" }
|
|
176
|
+
*/
|
|
177
|
+
copyAsMarkdown?: MenuItem;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Controls the individual items inside the Format submenu. */
|
|
181
|
+
export interface FormatMenuConfig {
|
|
182
|
+
/** @default { enabled: true, label: "Bold" } */
|
|
183
|
+
bold?: MenuItem;
|
|
184
|
+
/** @default { enabled: true, label: "Italic" } */
|
|
185
|
+
italic?: MenuItem;
|
|
186
|
+
/** @default { enabled: true, label: "Underline" } */
|
|
187
|
+
underline?: MenuItem;
|
|
188
|
+
/** @default { enabled: true, label: "Strikethrough" } */
|
|
189
|
+
strikethrough?: MenuItem;
|
|
190
|
+
/** @default { enabled: true, label: "Spoiler" } */
|
|
191
|
+
spoiler?: MenuItem;
|
|
192
|
+
/** @default { enabled: true, label: "Link" } */
|
|
193
|
+
link?: MenuItem;
|
|
194
|
+
}
|
|
195
|
+
|
|
156
196
|
export interface EnrichedMarkdownTextInputProps extends Omit<
|
|
157
197
|
ViewProps,
|
|
158
198
|
'style' | 'children'
|
|
@@ -164,6 +204,7 @@ export interface EnrichedMarkdownTextInputProps extends Omit<
|
|
|
164
204
|
editable?: boolean;
|
|
165
205
|
autoFocus?: boolean;
|
|
166
206
|
scrollEnabled?: boolean;
|
|
207
|
+
blockSyntax?: boolean;
|
|
167
208
|
autoCapitalize?: string;
|
|
168
209
|
multiline?: boolean;
|
|
169
210
|
cursorColor?: ColorValue;
|
|
@@ -184,6 +225,22 @@ export interface EnrichedMarkdownTextInputProps extends Omit<
|
|
|
184
225
|
onFocus?: () => void;
|
|
185
226
|
onBlur?: () => void;
|
|
186
227
|
contextMenuItems?: ContextMenuItem[];
|
|
228
|
+
/**
|
|
229
|
+
* Controls built-in items in the text selection context menu.
|
|
230
|
+
* Omitting the prop or any field reproduces today's exact menu.
|
|
231
|
+
* Custom app-provided actions are controlled separately via `contextMenuItems`.
|
|
232
|
+
* @default { format: true, copyAsMarkdown: true }
|
|
233
|
+
* @platform ios, android, macos
|
|
234
|
+
*/
|
|
235
|
+
selectionMenuConfig?: InputSelectionMenuConfig;
|
|
236
|
+
/**
|
|
237
|
+
* Controls which items appear inside the Format submenu.
|
|
238
|
+
* Only effective when `selectionMenuConfig.format` is `true` (the default).
|
|
239
|
+
* Omitting the prop or any field shows all items.
|
|
240
|
+
* @default { bold: true, italic: true, underline: true, strikethrough: true, spoiler: true, link: true }
|
|
241
|
+
* @platform ios, android, macos
|
|
242
|
+
*/
|
|
243
|
+
formatMenuConfig?: FormatMenuConfig;
|
|
187
244
|
linkRegex?: RegExp | null;
|
|
188
245
|
/**
|
|
189
246
|
* Paragraph writing direction.
|
|
@@ -228,6 +285,7 @@ export const EnrichedMarkdownTextInput = ({
|
|
|
228
285
|
editable = true,
|
|
229
286
|
autoFocus = false,
|
|
230
287
|
scrollEnabled = true,
|
|
288
|
+
blockSyntax = true,
|
|
231
289
|
autoCapitalize = 'sentences',
|
|
232
290
|
multiline = true,
|
|
233
291
|
cursorColor,
|
|
@@ -246,11 +304,15 @@ export const EnrichedMarkdownTextInput = ({
|
|
|
246
304
|
onFocus,
|
|
247
305
|
onBlur,
|
|
248
306
|
contextMenuItems,
|
|
307
|
+
selectionMenuConfig,
|
|
308
|
+
formatMenuConfig,
|
|
249
309
|
linkRegex: _linkRegex,
|
|
250
310
|
writingDirection = 'first-strong',
|
|
251
311
|
...rest
|
|
252
312
|
}: EnrichedMarkdownTextInputProps) => {
|
|
253
313
|
const nativeRef = useRef<NativeRef | null>(null);
|
|
314
|
+
// Freeze `defaultValue` at mount (RN TextInput semantics): post-mount changes are ignored.
|
|
315
|
+
const initialDefaultValue = useRef(defaultValue).current;
|
|
254
316
|
|
|
255
317
|
const nextRequestId = useRef(1);
|
|
256
318
|
const pendingRequests = useRef(new Map<number, PendingRequest<string>>());
|
|
@@ -294,6 +356,60 @@ export const EnrichedMarkdownTextInput = ({
|
|
|
294
356
|
|
|
295
357
|
const normalizedStyle = normalizeMarkdownTextInputStyle(markdownStyle);
|
|
296
358
|
|
|
359
|
+
const normalizedSelectionMenuConfig = useMemo(() => {
|
|
360
|
+
const format = normalizeMenuItem(
|
|
361
|
+
selectionMenuConfig?.format,
|
|
362
|
+
true,
|
|
363
|
+
'Format'
|
|
364
|
+
);
|
|
365
|
+
const copyAsMarkdown = normalizeMenuItem(
|
|
366
|
+
selectionMenuConfig?.copyAsMarkdown,
|
|
367
|
+
true,
|
|
368
|
+
'Copy as Markdown'
|
|
369
|
+
);
|
|
370
|
+
return {
|
|
371
|
+
format: format.enabled,
|
|
372
|
+
formatLabel: format.label,
|
|
373
|
+
copyAsMarkdown: copyAsMarkdown.enabled,
|
|
374
|
+
copyAsMarkdownLabel: copyAsMarkdown.label,
|
|
375
|
+
};
|
|
376
|
+
}, [selectionMenuConfig]);
|
|
377
|
+
|
|
378
|
+
const normalizedFormatMenuConfig = useMemo(() => {
|
|
379
|
+
const bold = normalizeMenuItem(formatMenuConfig?.bold, true, 'Bold');
|
|
380
|
+
const italic = normalizeMenuItem(formatMenuConfig?.italic, true, 'Italic');
|
|
381
|
+
const underline = normalizeMenuItem(
|
|
382
|
+
formatMenuConfig?.underline,
|
|
383
|
+
true,
|
|
384
|
+
'Underline'
|
|
385
|
+
);
|
|
386
|
+
const strikethrough = normalizeMenuItem(
|
|
387
|
+
formatMenuConfig?.strikethrough,
|
|
388
|
+
true,
|
|
389
|
+
'Strikethrough'
|
|
390
|
+
);
|
|
391
|
+
const spoiler = normalizeMenuItem(
|
|
392
|
+
formatMenuConfig?.spoiler,
|
|
393
|
+
true,
|
|
394
|
+
'Spoiler'
|
|
395
|
+
);
|
|
396
|
+
const link = normalizeMenuItem(formatMenuConfig?.link, true, 'Link');
|
|
397
|
+
return {
|
|
398
|
+
bold: bold.enabled,
|
|
399
|
+
boldLabel: bold.label,
|
|
400
|
+
italic: italic.enabled,
|
|
401
|
+
italicLabel: italic.label,
|
|
402
|
+
underline: underline.enabled,
|
|
403
|
+
underlineLabel: underline.label,
|
|
404
|
+
strikethrough: strikethrough.enabled,
|
|
405
|
+
strikethroughLabel: strikethrough.label,
|
|
406
|
+
spoiler: spoiler.enabled,
|
|
407
|
+
spoilerLabel: spoiler.label,
|
|
408
|
+
link: link.enabled,
|
|
409
|
+
linkLabel: link.label,
|
|
410
|
+
};
|
|
411
|
+
}, [formatMenuConfig]);
|
|
412
|
+
|
|
297
413
|
const linkRegex = useMemo(
|
|
298
414
|
() => toNativeRegexConfig(_linkRegex),
|
|
299
415
|
[_linkRegex]
|
|
@@ -476,6 +592,7 @@ export const EnrichedMarkdownTextInput = ({
|
|
|
476
592
|
options?.display ?? false
|
|
477
593
|
),
|
|
478
594
|
removeMath: (start) => Commands.removeMath(commandRef, start),
|
|
595
|
+
copyToClipboard: () => Commands.copyToClipboard(commandRef),
|
|
479
596
|
getMarkdown: () =>
|
|
480
597
|
new Promise<string>((resolve, reject) => {
|
|
481
598
|
const requestId = nextRequestId.current++;
|
|
@@ -499,12 +616,13 @@ export const EnrichedMarkdownTextInput = ({
|
|
|
499
616
|
ref={nativeRef}
|
|
500
617
|
style={style}
|
|
501
618
|
markdownStyle={normalizedStyle}
|
|
502
|
-
defaultValue={
|
|
619
|
+
defaultValue={initialDefaultValue}
|
|
503
620
|
placeholder={placeholder}
|
|
504
621
|
placeholderTextColor={placeholderTextColor}
|
|
505
622
|
editable={editable}
|
|
506
623
|
autoFocus={autoFocus}
|
|
507
624
|
scrollEnabled={scrollEnabled}
|
|
625
|
+
blockSyntax={blockSyntax}
|
|
508
626
|
autoCapitalize={autoCapitalize}
|
|
509
627
|
multiline={multiline}
|
|
510
628
|
cursorColor={cursorColor}
|
|
@@ -530,6 +648,8 @@ export const EnrichedMarkdownTextInput = ({
|
|
|
530
648
|
handleCaretRectChange as NativeProps['onCaretRectChange']
|
|
531
649
|
}
|
|
532
650
|
contextMenuItems={nativeContextMenuItems}
|
|
651
|
+
selectionMenuConfig={normalizedSelectionMenuConfig}
|
|
652
|
+
formatMenuConfig={normalizedFormatMenuConfig}
|
|
533
653
|
mentionIndicators={mentionIndicators}
|
|
534
654
|
onContextMenuItemPress={
|
|
535
655
|
handleContextMenuItemPress as NativeProps['onContextMenuItemPress']
|
|
@@ -19,6 +19,7 @@ interface MathStyleInternal {
|
|
|
19
19
|
paddingVertical: CodegenTypes.Float;
|
|
20
20
|
selectedBackgroundColor: ColorValue;
|
|
21
21
|
selectedBorderColor: ColorValue;
|
|
22
|
+
fontWeight: string;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
interface MathBlockStyleInternal extends MathStyleInternal {
|
|
@@ -145,6 +146,28 @@ export interface ContextMenuItemConfig {
|
|
|
145
146
|
icon?: string;
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
export interface InputSelectionMenuConfigInternal {
|
|
150
|
+
format: boolean;
|
|
151
|
+
formatLabel: string;
|
|
152
|
+
copyAsMarkdown: boolean;
|
|
153
|
+
copyAsMarkdownLabel: string;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface FormatMenuConfigInternal {
|
|
157
|
+
bold: boolean;
|
|
158
|
+
boldLabel: string;
|
|
159
|
+
italic: boolean;
|
|
160
|
+
italicLabel: string;
|
|
161
|
+
underline: boolean;
|
|
162
|
+
underlineLabel: string;
|
|
163
|
+
strikethrough: boolean;
|
|
164
|
+
strikethroughLabel: string;
|
|
165
|
+
spoiler: boolean;
|
|
166
|
+
spoilerLabel: string;
|
|
167
|
+
link: boolean;
|
|
168
|
+
linkLabel: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
148
171
|
export interface OnContextMenuItemPressEvent {
|
|
149
172
|
itemText: string;
|
|
150
173
|
selectedText: string;
|
|
@@ -188,6 +211,17 @@ export interface NativeProps extends ViewProps {
|
|
|
188
211
|
* @default true
|
|
189
212
|
*/
|
|
190
213
|
scrollEnabled?: boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Whether block-level markdown syntax is interpreted.
|
|
216
|
+
*
|
|
217
|
+
* When `false`, list markers, headings, blockquotes, tables, code blocks and
|
|
218
|
+
* thematic breaks stay in the text verbatim instead of being consumed as
|
|
219
|
+
* structure, so the markdown round-trips byte-for-byte. Inline syntax
|
|
220
|
+
* (`**bold**`, links, `$math$`) still applies. `\r\n` is normalized to `\n`
|
|
221
|
+
* and `U+000B` is stripped from the input.
|
|
222
|
+
* @default true
|
|
223
|
+
*/
|
|
224
|
+
blockSyntax?: boolean;
|
|
191
225
|
/**
|
|
192
226
|
* Auto-capitalization behavior.
|
|
193
227
|
*/
|
|
@@ -230,6 +264,17 @@ export interface NativeProps extends ViewProps {
|
|
|
230
264
|
*/
|
|
231
265
|
contextMenuItems?: ReadonlyArray<Readonly<ContextMenuItemConfig>>;
|
|
232
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Controls built-in items in the text selection context menu.
|
|
269
|
+
* `format` toggles the Format submenu; `copyAsMarkdown` toggles the Copy as Markdown action.
|
|
270
|
+
*/
|
|
271
|
+
selectionMenuConfig: Readonly<InputSelectionMenuConfigInternal>;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Controls which items appear inside the Format submenu.
|
|
275
|
+
*/
|
|
276
|
+
formatMenuConfig: Readonly<FormatMenuConfigInternal>;
|
|
277
|
+
|
|
233
278
|
/**
|
|
234
279
|
* Regex configuration for automatic link detection.
|
|
235
280
|
* Omit or pass undefined to use platform defaults.
|
|
@@ -322,6 +367,7 @@ interface NativeCommands {
|
|
|
322
367
|
viewRef: React.ElementRef<ComponentType>,
|
|
323
368
|
start: CodegenTypes.Int32
|
|
324
369
|
) => void;
|
|
370
|
+
copyToClipboard: (viewRef: React.ElementRef<ComponentType>) => void;
|
|
325
371
|
requestMarkdown: (
|
|
326
372
|
viewRef: React.ElementRef<ComponentType>,
|
|
327
373
|
requestId: CodegenTypes.Int32
|
|
@@ -351,6 +397,7 @@ export const Commands: NativeCommands = codegenNativeCommands<NativeCommands>({
|
|
|
351
397
|
'insertMath',
|
|
352
398
|
'updateMath',
|
|
353
399
|
'removeMath',
|
|
400
|
+
'copyToClipboard',
|
|
354
401
|
'requestMarkdown',
|
|
355
402
|
'requestCaretRect',
|
|
356
403
|
],
|
|
@@ -141,10 +141,13 @@ interface MathStyleInternal {
|
|
|
141
141
|
marginTop: CodegenTypes.Float;
|
|
142
142
|
marginBottom: CodegenTypes.Float;
|
|
143
143
|
textAlign: string;
|
|
144
|
+
fontWeight: string;
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
interface InlineMathStyleInternal {
|
|
147
148
|
color: ColorValue;
|
|
149
|
+
paddingVertical: CodegenTypes.Float;
|
|
150
|
+
fontWeight: string;
|
|
148
151
|
}
|
|
149
152
|
|
|
150
153
|
interface SpoilerParticlesStyleInternal {
|
|
@@ -230,6 +233,13 @@ export interface ContextMenuItemConfig {
|
|
|
230
233
|
export interface SelectionMenuConfig {
|
|
231
234
|
copyAsMarkdown: boolean;
|
|
232
235
|
copyImageUrl: boolean;
|
|
236
|
+
copyLabel: string;
|
|
237
|
+
copyAsMarkdownLabel: string;
|
|
238
|
+
copyImageUrlLabel: string;
|
|
239
|
+
copyImageUrlsLabel: string;
|
|
240
|
+
// Precomputed plural templates indexed by image count (0..100). Empty when no
|
|
241
|
+
// pluralLabels are set; native then uses copyImageUrlLabel/copyImageUrlsLabel.
|
|
242
|
+
copyImageUrlPluralTemplates: ReadonlyArray<string>;
|
|
233
243
|
}
|
|
234
244
|
|
|
235
245
|
export interface OnContextMenuItemPressEvent {
|
|
@@ -239,6 +249,35 @@ export interface OnContextMenuItemPressEvent {
|
|
|
239
249
|
selectionEnd: CodegenTypes.Int32;
|
|
240
250
|
}
|
|
241
251
|
|
|
252
|
+
export interface AccessibilityLabelsListProps {
|
|
253
|
+
bulletPoint: string;
|
|
254
|
+
nestedBulletPoint: string;
|
|
255
|
+
orderedItem: string;
|
|
256
|
+
nestedOrderedItem: string;
|
|
257
|
+
}
|
|
258
|
+
export interface AccessibilityLabelsBlockquoteProps {
|
|
259
|
+
quote: string;
|
|
260
|
+
nestedQuote: string;
|
|
261
|
+
}
|
|
262
|
+
export interface AccessibilityLabelsTableProps {
|
|
263
|
+
row: string;
|
|
264
|
+
}
|
|
265
|
+
export interface AccessibilityLabelsMathProps {
|
|
266
|
+
equation: string;
|
|
267
|
+
}
|
|
268
|
+
export interface AccessibilityLabelsRotorProps {
|
|
269
|
+
headings: string;
|
|
270
|
+
links: string;
|
|
271
|
+
images: string;
|
|
272
|
+
}
|
|
273
|
+
export interface AccessibilityLabelsProps {
|
|
274
|
+
list: Readonly<AccessibilityLabelsListProps>;
|
|
275
|
+
blockquote: Readonly<AccessibilityLabelsBlockquoteProps>;
|
|
276
|
+
table: Readonly<AccessibilityLabelsTableProps>;
|
|
277
|
+
math: Readonly<AccessibilityLabelsMathProps>;
|
|
278
|
+
rotor: Readonly<AccessibilityLabelsRotorProps>;
|
|
279
|
+
}
|
|
280
|
+
|
|
242
281
|
/**
|
|
243
282
|
* MD4C parser flags configuration.
|
|
244
283
|
* Controls how the markdown parser interprets certain syntax.
|
|
@@ -393,6 +432,7 @@ export interface NativeProps extends ViewProps {
|
|
|
393
432
|
* Built-in items to show in the text selection context menu.
|
|
394
433
|
*/
|
|
395
434
|
selectionMenuConfig: Readonly<SelectionMenuConfig>;
|
|
435
|
+
accessibilityLabels: Readonly<AccessibilityLabelsProps>;
|
|
396
436
|
/**
|
|
397
437
|
* Fired when a custom context menu item is pressed.
|
|
398
438
|
* Receives the item label, the currently selected text, and the selection range.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AccessibilityLabels,
|
|
3
|
+
ResolvedAccessibilityLabels,
|
|
4
|
+
} from './types/AccessibilityLabels';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Default strings spoken by VoiceOver / TalkBack when the consumer does not
|
|
8
|
+
* provide an override. See `AccessibilityLabels` for the placeholder syntax
|
|
9
|
+
* and the rationale for the no-plural cardinal form.
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_ACCESSIBILITY_LABELS: ResolvedAccessibilityLabels = {
|
|
12
|
+
list: {
|
|
13
|
+
bulletPoint: 'Bullet point',
|
|
14
|
+
nestedBulletPoint: 'Nested bullet point',
|
|
15
|
+
orderedItem: 'List item {n}',
|
|
16
|
+
nestedOrderedItem: 'Nested list item {n}',
|
|
17
|
+
},
|
|
18
|
+
blockquote: {
|
|
19
|
+
quote: 'Blockquote',
|
|
20
|
+
nestedQuote: 'Nested blockquote',
|
|
21
|
+
},
|
|
22
|
+
table: {
|
|
23
|
+
row: 'Row {n}: {content}',
|
|
24
|
+
},
|
|
25
|
+
math: {
|
|
26
|
+
equation: 'Math: {latex}',
|
|
27
|
+
},
|
|
28
|
+
rotor: {
|
|
29
|
+
headings: 'Headings',
|
|
30
|
+
links: 'Links',
|
|
31
|
+
images: 'Images',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Resolves a partial `AccessibilityLabels` against `DEFAULT_ACCESSIBILITY_LABELS`,
|
|
37
|
+
* returning a fully-populated struct that native code can consume without any
|
|
38
|
+
* null checks. Override resolution is shallow per sub-group: if a consumer
|
|
39
|
+
* passes `{ list: { bulletPoint: 'Punkt' } }`, only that one field changes and
|
|
40
|
+
* the other list entries fall back to the defaults.
|
|
41
|
+
*/
|
|
42
|
+
export function resolveAccessibilityLabels(
|
|
43
|
+
labels: AccessibilityLabels | undefined
|
|
44
|
+
): ResolvedAccessibilityLabels {
|
|
45
|
+
return {
|
|
46
|
+
list: {
|
|
47
|
+
bulletPoint:
|
|
48
|
+
labels?.list?.bulletPoint ??
|
|
49
|
+
DEFAULT_ACCESSIBILITY_LABELS.list.bulletPoint,
|
|
50
|
+
nestedBulletPoint:
|
|
51
|
+
labels?.list?.nestedBulletPoint ??
|
|
52
|
+
DEFAULT_ACCESSIBILITY_LABELS.list.nestedBulletPoint,
|
|
53
|
+
orderedItem:
|
|
54
|
+
labels?.list?.orderedItem ??
|
|
55
|
+
DEFAULT_ACCESSIBILITY_LABELS.list.orderedItem,
|
|
56
|
+
nestedOrderedItem:
|
|
57
|
+
labels?.list?.nestedOrderedItem ??
|
|
58
|
+
DEFAULT_ACCESSIBILITY_LABELS.list.nestedOrderedItem,
|
|
59
|
+
},
|
|
60
|
+
blockquote: {
|
|
61
|
+
quote:
|
|
62
|
+
labels?.blockquote?.quote ??
|
|
63
|
+
DEFAULT_ACCESSIBILITY_LABELS.blockquote.quote,
|
|
64
|
+
nestedQuote:
|
|
65
|
+
labels?.blockquote?.nestedQuote ??
|
|
66
|
+
DEFAULT_ACCESSIBILITY_LABELS.blockquote.nestedQuote,
|
|
67
|
+
},
|
|
68
|
+
table: {
|
|
69
|
+
row: labels?.table?.row ?? DEFAULT_ACCESSIBILITY_LABELS.table.row,
|
|
70
|
+
},
|
|
71
|
+
math: {
|
|
72
|
+
equation:
|
|
73
|
+
labels?.math?.equation ?? DEFAULT_ACCESSIBILITY_LABELS.math.equation,
|
|
74
|
+
},
|
|
75
|
+
rotor: {
|
|
76
|
+
headings:
|
|
77
|
+
labels?.rotor?.headings ?? DEFAULT_ACCESSIBILITY_LABELS.rotor.headings,
|
|
78
|
+
links: labels?.rotor?.links ?? DEFAULT_ACCESSIBILITY_LABELS.rotor.links,
|
|
79
|
+
images:
|
|
80
|
+
labels?.rotor?.images ?? DEFAULT_ACCESSIBILITY_LABELS.rotor.images,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -6,12 +6,21 @@ export type {
|
|
|
6
6
|
Md4cFlags,
|
|
7
7
|
ContextMenuItem as TextContextMenuItem,
|
|
8
8
|
SelectionMenuConfig as TextSelectionMenuConfig,
|
|
9
|
+
SelectionMenuPluralLabels as TextSelectionMenuPluralLabels,
|
|
9
10
|
} from './native/EnrichedMarkdownText';
|
|
10
11
|
export type {
|
|
11
12
|
LinkPressEvent,
|
|
12
13
|
LinkLongPressEvent,
|
|
13
14
|
TaskListItemPressEvent,
|
|
14
15
|
} from './types/events';
|
|
16
|
+
export type {
|
|
17
|
+
AccessibilityLabels,
|
|
18
|
+
ResolvedAccessibilityLabels,
|
|
19
|
+
} from './types/AccessibilityLabels';
|
|
20
|
+
export {
|
|
21
|
+
DEFAULT_ACCESSIBILITY_LABELS,
|
|
22
|
+
resolveAccessibilityLabels,
|
|
23
|
+
} from './accessibilityLabelDefaults';
|
|
15
24
|
|
|
16
25
|
export { EnrichedMarkdownTextInput } from './EnrichedMarkdownTextInput';
|
|
17
26
|
export type {
|
|
@@ -20,6 +29,8 @@ export type {
|
|
|
20
29
|
MarkdownTextInputStyle,
|
|
21
30
|
StyleState,
|
|
22
31
|
ContextMenuItem,
|
|
32
|
+
InputSelectionMenuConfig,
|
|
33
|
+
FormatMenuConfig,
|
|
23
34
|
OnLinkDetected,
|
|
24
35
|
OnStartMentionEvent,
|
|
25
36
|
OnChangeMentionEvent,
|
|
@@ -3,6 +3,11 @@ import EnrichedMarkdownTextNativeComponent from '../EnrichedMarkdownTextNativeCo
|
|
|
3
3
|
import type { MarkdownStyleInternal } from '../EnrichedMarkdownTextNativeComponent';
|
|
4
4
|
import EnrichedMarkdownNativeComponent from '../EnrichedMarkdownNativeComponent';
|
|
5
5
|
import { normalizeMarkdownStyle } from '../normalizeMarkdownStyle';
|
|
6
|
+
import { resolveAccessibilityLabels } from '../accessibilityLabelDefaults';
|
|
7
|
+
import {
|
|
8
|
+
normalizeMenuItem,
|
|
9
|
+
normalizeLegacyBooleanMenuItem,
|
|
10
|
+
} from '../normalizeMenuItem';
|
|
6
11
|
import type { NativeSyntheticEvent } from 'react-native';
|
|
7
12
|
import type { MarkdownStyle, Md4cFlags } from '../types/MarkdownStyle';
|
|
8
13
|
import type {
|
|
@@ -10,6 +15,7 @@ import type {
|
|
|
10
15
|
StreamingConfig,
|
|
11
16
|
ContextMenuItem,
|
|
12
17
|
SelectionMenuConfig,
|
|
18
|
+
SelectionMenuPluralLabels,
|
|
13
19
|
} from '../types/MarkdownTextProps';
|
|
14
20
|
import type {
|
|
15
21
|
LinkPressEvent,
|
|
@@ -24,9 +30,71 @@ export type {
|
|
|
24
30
|
StreamingConfig,
|
|
25
31
|
ContextMenuItem,
|
|
26
32
|
SelectionMenuConfig,
|
|
33
|
+
SelectionMenuPluralLabels,
|
|
27
34
|
};
|
|
28
35
|
export type { LinkPressEvent, LinkLongPressEvent, TaskListItemPressEvent };
|
|
29
36
|
|
|
37
|
+
// Default English labels for the built-in selection menu actions. Defaults are
|
|
38
|
+
// resolved here (JS-side) so the native code always receives a concrete string.
|
|
39
|
+
const DEFAULT_COPY_LABEL = 'Copy';
|
|
40
|
+
const DEFAULT_COPY_AS_MARKDOWN_LABEL = 'Copy as Markdown';
|
|
41
|
+
const DEFAULT_COPY_IMAGE_URL_LABEL = 'Copy Image URL';
|
|
42
|
+
const DEFAULT_COPY_IMAGE_URLS_LABEL = 'Copy {count} Image URLs';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolves `pluralLabels` into a per-count template table (index = image count,
|
|
46
|
+
* 0..100) the native side can index without any locale logic. `Intl.PluralRules`
|
|
47
|
+
* selects the CLDR category for each count; missing categories fall back to the
|
|
48
|
+
* required `other`. Index 1 uses the singular `label` (the single-image case).
|
|
49
|
+
* Native uses `other` (copyImageUrlsLabel) for counts > 100, and falls back to
|
|
50
|
+
* the singular/`{count}` templates entirely when this returns an empty array
|
|
51
|
+
* (no plural labels set, or `Intl.PluralRules` unavailable).
|
|
52
|
+
*/
|
|
53
|
+
const buildPluralTemplates = (
|
|
54
|
+
pluralLabels: SelectionMenuPluralLabels | undefined,
|
|
55
|
+
singularLabel: string
|
|
56
|
+
): string[] => {
|
|
57
|
+
if (!pluralLabels) return [];
|
|
58
|
+
|
|
59
|
+
const IntlRef = Intl as unknown as {
|
|
60
|
+
PluralRules?: new (locales?: string | string[]) => {
|
|
61
|
+
select(n: number): string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
if (typeof IntlRef.PluralRules !== 'function') return [];
|
|
65
|
+
|
|
66
|
+
let pluralRules: { select(n: number): string };
|
|
67
|
+
try {
|
|
68
|
+
// TODO: expose `copyImageUrl.pluralLocale?: string` so i18n apps can force
|
|
69
|
+
// a locale independent of the device. Today this resolves to the JS
|
|
70
|
+
// runtime's default locale, so on an English device only `one` and `other`
|
|
71
|
+
// ever fire even when richer plural labels are configured.
|
|
72
|
+
pluralRules = new IntlRef.PluralRules();
|
|
73
|
+
} catch {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { other } = pluralLabels;
|
|
78
|
+
const byCategory: Record<string, string> = {
|
|
79
|
+
zero: pluralLabels.zero ?? other,
|
|
80
|
+
one: pluralLabels.one ?? other,
|
|
81
|
+
two: pluralLabels.two ?? other,
|
|
82
|
+
few: pluralLabels.few ?? other,
|
|
83
|
+
many: pluralLabels.many ?? other,
|
|
84
|
+
other,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const templates: string[] = [];
|
|
88
|
+
for (let n = 0; n <= 100; n++) {
|
|
89
|
+
// The literal single-image case uses the (non-plural) singular label; every
|
|
90
|
+
// other count uses its CLDR category form.
|
|
91
|
+
templates.push(
|
|
92
|
+
n === 1 ? singularLabel : (byCategory[pluralRules.select(n)] ?? other)
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return templates;
|
|
96
|
+
};
|
|
97
|
+
|
|
30
98
|
const defaultMd4cFlags: Md4cFlags = {
|
|
31
99
|
underline: false,
|
|
32
100
|
superscript: false,
|
|
@@ -54,6 +122,7 @@ export const EnrichedMarkdownText = ({
|
|
|
54
122
|
spoilerOverlay = 'particles',
|
|
55
123
|
contextMenuItems,
|
|
56
124
|
selectionMenuConfig,
|
|
125
|
+
accessibilityLabels,
|
|
57
126
|
selectionColor,
|
|
58
127
|
selectionHandleColor,
|
|
59
128
|
textBreakStrategy,
|
|
@@ -142,12 +211,56 @@ export const EnrichedMarkdownText = ({
|
|
|
142
211
|
|
|
143
212
|
const tableMode = streamingConfig?.tableMode ?? 'progressive';
|
|
144
213
|
const normalizedStreamingConfig = useMemo(() => ({ tableMode }), [tableMode]);
|
|
145
|
-
const normalizedSelectionMenuConfig = useMemo(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
214
|
+
const normalizedSelectionMenuConfig = useMemo(() => {
|
|
215
|
+
// The boolean acceptance is confined to this wrapper boundary via a single
|
|
216
|
+
// `as unknown` cast; the public type only exposes the object shape.
|
|
217
|
+
const config = selectionMenuConfig as
|
|
218
|
+
| {
|
|
219
|
+
copy?: unknown;
|
|
220
|
+
copyAsMarkdown?: unknown;
|
|
221
|
+
copyImageUrl?: unknown;
|
|
222
|
+
}
|
|
223
|
+
| undefined;
|
|
224
|
+
|
|
225
|
+
const copy = normalizeMenuItem(config?.copy, true, DEFAULT_COPY_LABEL);
|
|
226
|
+
const copyAsMarkdown = normalizeLegacyBooleanMenuItem(
|
|
227
|
+
config?.copyAsMarkdown,
|
|
228
|
+
'selectionMenuConfig',
|
|
229
|
+
'copyAsMarkdown',
|
|
230
|
+
true,
|
|
231
|
+
DEFAULT_COPY_AS_MARKDOWN_LABEL
|
|
232
|
+
);
|
|
233
|
+
const copyImageUrl = normalizeLegacyBooleanMenuItem(
|
|
234
|
+
config?.copyImageUrl,
|
|
235
|
+
'selectionMenuConfig',
|
|
236
|
+
'copyImageUrl',
|
|
237
|
+
true,
|
|
238
|
+
DEFAULT_COPY_IMAGE_URL_LABEL
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const pluralLabels = (
|
|
242
|
+
config?.copyImageUrl as
|
|
243
|
+
| { pluralLabels?: SelectionMenuPluralLabels }
|
|
244
|
+
| undefined
|
|
245
|
+
)?.pluralLabels;
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
copyAsMarkdown: copyAsMarkdown.enabled,
|
|
249
|
+
copyImageUrl: copyImageUrl.enabled,
|
|
250
|
+
copyLabel: copy.label,
|
|
251
|
+
copyAsMarkdownLabel: copyAsMarkdown.label,
|
|
252
|
+
copyImageUrlLabel: copyImageUrl.label,
|
|
253
|
+
copyImageUrlsLabel: pluralLabels?.other ?? DEFAULT_COPY_IMAGE_URLS_LABEL,
|
|
254
|
+
copyImageUrlPluralTemplates: buildPluralTemplates(
|
|
255
|
+
pluralLabels,
|
|
256
|
+
copyImageUrl.label
|
|
257
|
+
),
|
|
258
|
+
};
|
|
259
|
+
}, [selectionMenuConfig]);
|
|
260
|
+
|
|
261
|
+
const resolvedAccessibilityLabels = useMemo(
|
|
262
|
+
() => resolveAccessibilityLabels(accessibilityLabels),
|
|
263
|
+
[accessibilityLabels]
|
|
151
264
|
);
|
|
152
265
|
|
|
153
266
|
const sharedProps = {
|
|
@@ -168,6 +281,7 @@ export const EnrichedMarkdownText = ({
|
|
|
168
281
|
style: containerStyle,
|
|
169
282
|
contextMenuItems: nativeContextMenuItems,
|
|
170
283
|
selectionMenuConfig: normalizedSelectionMenuConfig,
|
|
284
|
+
accessibilityLabels: resolvedAccessibilityLabels,
|
|
171
285
|
onContextMenuItemPress: handleContextMenuItemPress,
|
|
172
286
|
selectionColor,
|
|
173
287
|
selectionHandleColor,
|
|
@@ -193,8 +193,13 @@ const DEFAULT_NORMALIZED_STYLE = Object.freeze({
|
|
|
193
193
|
marginTop: 0,
|
|
194
194
|
marginBottom: 16,
|
|
195
195
|
textAlign: 'center' as BlockTextAlign,
|
|
196
|
+
fontWeight: 'normal',
|
|
197
|
+
},
|
|
198
|
+
inlineMath: {
|
|
199
|
+
color: defaultTextColor,
|
|
200
|
+
paddingVertical: 4,
|
|
201
|
+
fontWeight: 'normal',
|
|
196
202
|
},
|
|
197
|
-
inlineMath: { color: defaultTextColor },
|
|
198
203
|
taskList: {
|
|
199
204
|
checkedColor: Platform.select({
|
|
200
205
|
ios: normalizeColor('#007AFF')!,
|
|
@@ -177,8 +177,13 @@ const DEFAULT_NORMALIZED_STYLE: MarkdownStyleInternal = Object.freeze({
|
|
|
177
177
|
marginTop: 0,
|
|
178
178
|
marginBottom: 16,
|
|
179
179
|
textAlign: 'center' as BlockTextAlign,
|
|
180
|
+
fontWeight: 'normal',
|
|
181
|
+
},
|
|
182
|
+
inlineMath: {
|
|
183
|
+
color: defaultTextColor,
|
|
184
|
+
paddingVertical: 4,
|
|
185
|
+
fontWeight: 'normal',
|
|
180
186
|
},
|
|
181
|
-
inlineMath: { color: defaultTextColor },
|
|
182
187
|
taskList: {
|
|
183
188
|
checkedColor: '#007AFF',
|
|
184
189
|
borderColor: '#9E9E9E',
|