react-native-enriched-markdown-scaffold 1.0.2-scaffold.1 → 1.0.2-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/android/build.gradle +2 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +18 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +4 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +18 -0
- package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +4 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +148 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +120 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +30 -0
- package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +210 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +176 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +45 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +35 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +112 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +34 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +46 -8
- package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyRequestEvent.kt +28 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLayoutEvent.kt +36 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/events/SelectionChangeEvent.kt +43 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +25 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +7 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +37 -7
- package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +5 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +13 -99
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/InlineChipPainter.kt +140 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkChipSpans.kt +177 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +1 -6
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +16 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +36 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkVariantEntry.kt +7 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +3 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +51 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +34 -2
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/HTMLGenerator.kt +2 -1
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt +6 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/HeadlessActionMode.kt +88 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLayoutCollector.kt +100 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +53 -14
- package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionChangeReporter.kt +232 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +64 -0
- package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +29 -3
- package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +30 -7
- package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +1 -0
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +13 -6
- package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathMeasureHelper.kt +2 -1
- package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +25 -9
- package/docs/API_REFERENCE.md +183 -4
- package/docs/COPY_OPTIONS.md +40 -0
- package/docs/INPUT.md +3 -1
- package/docs/MENTIONS.md +8 -1
- package/docs/STYLES.md +27 -0
- package/docs/TEXT.md +2 -0
- package/docs/WEB.md +1 -0
- package/ios/EnrichedMarkdown.mm +321 -9
- package/ios/EnrichedMarkdownText.mm +203 -6
- package/ios/attachments/ENRMMathInlineAttachment+macOS.m +2 -1
- package/ios/attachments/ENRMMathInlineAttachment.h +3 -0
- package/ios/attachments/ENRMMathInlineAttachment.m +2 -1
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +148 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +120 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +30 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +210 -0
- package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +50 -2
- package/ios/internals/MeasurementCache.h +8 -2
- package/ios/math/ENRMRaTeXBridge.swift +23 -5
- package/ios/renderer/ENRMMathInlineRenderer.m +1 -0
- package/ios/renderer/LinkRenderer.m +47 -15
- package/ios/styles/StyleConfig.h +20 -0
- package/ios/styles/StyleConfig.mm +84 -0
- package/ios/utils/CodeBackground.m +3 -65
- package/ios/utils/ENRMBlockMenu.h +66 -0
- package/ios/utils/ENRMChipDrawing.h +24 -0
- package/ios/utils/ENRMChipDrawing.m +83 -0
- package/ios/utils/ENRMLinkChip.h +70 -0
- package/ios/utils/ENRMLinkChip.m +213 -0
- package/ios/utils/ENRMLinkLayout.h +50 -0
- package/ios/utils/ENRMLinkLayout.m +45 -0
- package/ios/utils/ENRMSelectionChange.h +120 -0
- package/ios/utils/ENRMSelectionChange.m +282 -0
- package/ios/utils/EditMenuUtils+macOS.m +4 -1
- package/ios/utils/EditMenuUtils.h +35 -6
- package/ios/utils/EditMenuUtils.m +171 -15
- package/ios/utils/HTMLGenerator.m +2 -1
- package/ios/utils/MarkdownAccessibilityElementBuilder.m +3 -1
- package/ios/utils/MarkdownExtractor.m +2 -1
- package/ios/utils/RTFExportUtils.m +2 -0
- package/ios/utils/StylePropsUtils.h +47 -1
- package/ios/utils/TextViewLayoutManager.mm +3 -0
- package/ios/views/ENRMCodeBlockContainerView.h +16 -2
- package/ios/views/ENRMCodeBlockContainerView.m +22 -19
- package/ios/views/ENRMMathContainerView.h +11 -0
- package/ios/views/ENRMMathContainerView.m +17 -20
- package/ios/views/TableContainerView.h +14 -0
- package/ios/views/TableContainerView.m +34 -18
- package/lib/module/EnrichedMarkdownNativeComponent.ts +138 -1
- package/lib/module/EnrichedMarkdownTextNativeComponent.ts +138 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/jest/index.js +14 -0
- package/lib/module/jest/index.js.map +1 -1
- package/lib/module/native/EnrichedMarkdownText.js +169 -11
- package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.js +17 -4
- package/lib/module/normalizeMarkdownStyle.js.map +1 -1
- package/lib/module/normalizeMarkdownStyle.web.js +17 -4
- package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
- package/lib/module/web/EnrichedMarkdownText.js +6 -3
- package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
- package/lib/module/web/renderers/InlineRenderers.js +96 -3
- package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
- package/lib/module/web/styles.js +18 -0
- package/lib/module/web/styles.js.map +1 -1
- package/lib/module/web/utils.js +13 -0
- package/lib/module/web/utils.js.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +123 -2
- package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +123 -2
- package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.web.d.ts +1 -1
- package/lib/typescript/src/index.web.d.ts.map +1 -1
- package/lib/typescript/src/jest/index.d.ts +1 -1
- package/lib/typescript/src/jest/index.d.ts.map +1 -1
- package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +5 -5
- 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/types/MarkdownStyle.d.ts +50 -5
- package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +12 -0
- package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.d.ts +144 -11
- package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
- package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +41 -1
- package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +66 -0
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
- package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
- package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
- package/lib/typescript/src/web/styles.d.ts.map +1 -1
- package/lib/typescript/src/web/types.d.ts +4 -0
- package/lib/typescript/src/web/types.d.ts.map +1 -1
- package/lib/typescript/src/web/utils.d.ts +4 -0
- package/lib/typescript/src/web/utils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/EnrichedMarkdownNativeComponent.ts +138 -1
- package/src/EnrichedMarkdownTextNativeComponent.ts +138 -1
- package/src/index.tsx +6 -0
- package/src/index.web.tsx +5 -1
- package/src/jest/index.tsx +22 -1
- package/src/native/EnrichedMarkdownText.tsx +220 -9
- package/src/normalizeMarkdownStyle.ts +15 -0
- package/src/normalizeMarkdownStyle.web.ts +13 -0
- package/src/types/MarkdownStyle.ts +51 -5
- package/src/types/MarkdownStyleInternal.ts +12 -0
- package/src/types/MarkdownTextProps.ts +151 -11
- package/src/types/MarkdownTextProps.web.ts +43 -1
- package/src/types/events.ts +69 -0
- package/src/web/EnrichedMarkdownText.tsx +10 -3
- package/src/web/renderers/InlineRenderers.tsx +111 -3
- package/src/web/styles.ts +25 -0
- package/src/web/types.ts +4 -0
- package/src/web/utils.ts +8 -0
|
@@ -1,43 +1,75 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
useMemo,
|
|
3
|
+
useCallback,
|
|
4
|
+
useRef,
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import EnrichedMarkdownTextNativeComponent, {
|
|
10
|
+
Commands as TextCommands,
|
|
11
|
+
} from '../EnrichedMarkdownTextNativeComponent';
|
|
12
|
+
import type {
|
|
13
|
+
LinkLayoutEvent,
|
|
14
|
+
MarkdownStyleInternal,
|
|
15
|
+
SelectionChangeEvent as NativeSelectionChangeEvent,
|
|
16
|
+
} from '../EnrichedMarkdownTextNativeComponent';
|
|
17
|
+
import EnrichedMarkdownNativeComponent, {
|
|
18
|
+
Commands as MarkdownCommands,
|
|
19
|
+
} from '../EnrichedMarkdownNativeComponent';
|
|
5
20
|
import { normalizeMarkdownStyle } from '../normalizeMarkdownStyle';
|
|
6
21
|
import { resolveAccessibilityLabels } from '../accessibilityLabelDefaults';
|
|
7
22
|
import {
|
|
8
23
|
normalizeMenuItem,
|
|
9
24
|
normalizeLegacyBooleanMenuItem,
|
|
10
25
|
} from '../normalizeMenuItem';
|
|
11
|
-
import
|
|
26
|
+
import { StyleSheet, View } from 'react-native';
|
|
27
|
+
import type {
|
|
28
|
+
HostInstance,
|
|
29
|
+
LayoutChangeEvent,
|
|
30
|
+
NativeSyntheticEvent,
|
|
31
|
+
} from 'react-native';
|
|
12
32
|
import type { MarkdownStyle, Md4cFlags } from '../types/MarkdownStyle';
|
|
13
33
|
import type {
|
|
14
34
|
EnrichedMarkdownTextProps,
|
|
35
|
+
EnrichedMarkdownTextInstance,
|
|
15
36
|
StreamingConfig,
|
|
16
37
|
ContextMenuItem,
|
|
17
38
|
SelectionMenuConfig,
|
|
18
39
|
SelectionMenuPluralLabels,
|
|
40
|
+
LinkDecorationInfo,
|
|
41
|
+
LinkRect,
|
|
19
42
|
} from '../types/MarkdownTextProps';
|
|
20
43
|
import type {
|
|
21
44
|
LinkPressEvent,
|
|
22
45
|
LinkLongPressEvent,
|
|
23
46
|
TaskListItemPressEvent,
|
|
24
47
|
CopyPressEvent,
|
|
48
|
+
CopyEvent,
|
|
25
49
|
OnContextMenuItemPressEvent,
|
|
50
|
+
SelectionChangeEvent,
|
|
51
|
+
SelectionRect,
|
|
26
52
|
} from '../types/events';
|
|
27
53
|
|
|
28
54
|
export type { MarkdownStyle, Md4cFlags };
|
|
29
55
|
export type {
|
|
30
56
|
EnrichedMarkdownTextProps,
|
|
57
|
+
EnrichedMarkdownTextInstance,
|
|
31
58
|
StreamingConfig,
|
|
32
59
|
ContextMenuItem,
|
|
33
60
|
SelectionMenuConfig,
|
|
34
61
|
SelectionMenuPluralLabels,
|
|
62
|
+
LinkDecorationInfo,
|
|
63
|
+
LinkRect,
|
|
35
64
|
};
|
|
36
65
|
export type {
|
|
37
66
|
LinkPressEvent,
|
|
38
67
|
LinkLongPressEvent,
|
|
39
68
|
TaskListItemPressEvent,
|
|
40
69
|
CopyPressEvent,
|
|
70
|
+
CopyEvent,
|
|
71
|
+
SelectionChangeEvent,
|
|
72
|
+
SelectionRect,
|
|
41
73
|
};
|
|
42
74
|
|
|
43
75
|
// Default English labels for the built-in selection menu actions. Defaults are
|
|
@@ -101,6 +133,34 @@ const buildPluralTemplates = (
|
|
|
101
133
|
return templates;
|
|
102
134
|
};
|
|
103
135
|
|
|
136
|
+
type LinkLayoutFragment = LinkLayoutEvent['fragments'][number];
|
|
137
|
+
|
|
138
|
+
/** Groups the flat per-line fragments native reports into one entry per link. */
|
|
139
|
+
const groupLinkFragments = (
|
|
140
|
+
fragments: ReadonlyArray<LinkLayoutFragment>
|
|
141
|
+
): LinkDecorationInfo[] => {
|
|
142
|
+
const byIndex = new Map<number, LinkDecorationInfo>();
|
|
143
|
+
for (const { linkIndex, url, text, x, y, width, height } of fragments) {
|
|
144
|
+
const rect: LinkRect = { x, y, width, height };
|
|
145
|
+
const info = byIndex.get(linkIndex);
|
|
146
|
+
if (info) {
|
|
147
|
+
info.rects.push(rect);
|
|
148
|
+
info.rect = rect;
|
|
149
|
+
} else {
|
|
150
|
+
byIndex.set(linkIndex, {
|
|
151
|
+
index: linkIndex,
|
|
152
|
+
url,
|
|
153
|
+
text,
|
|
154
|
+
rect,
|
|
155
|
+
rects: [rect],
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return [...byIndex.values()];
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const ZERO_OFFSET = { x: 0, y: 0 };
|
|
163
|
+
|
|
104
164
|
const defaultMd4cFlags: Md4cFlags = {
|
|
105
165
|
underline: false,
|
|
106
166
|
superscript: false,
|
|
@@ -111,6 +171,7 @@ const defaultMd4cFlags: Md4cFlags = {
|
|
|
111
171
|
};
|
|
112
172
|
|
|
113
173
|
export const EnrichedMarkdownText = ({
|
|
174
|
+
ref,
|
|
114
175
|
markdown,
|
|
115
176
|
markdownStyle = {},
|
|
116
177
|
containerStyle,
|
|
@@ -119,7 +180,10 @@ export const EnrichedMarkdownText = ({
|
|
|
119
180
|
onTaskListItemPress,
|
|
120
181
|
enableTaskListItemToggle = true,
|
|
121
182
|
onCopyPress,
|
|
183
|
+
onCopy,
|
|
184
|
+
onSelectionChange,
|
|
122
185
|
enableLinkPreview,
|
|
186
|
+
linkLongPressSelects = false,
|
|
123
187
|
selectable = true,
|
|
124
188
|
md4cFlags = defaultMd4cFlags,
|
|
125
189
|
allowFontScaling = true,
|
|
@@ -139,6 +203,8 @@ export const EnrichedMarkdownText = ({
|
|
|
139
203
|
textBreakStrategy,
|
|
140
204
|
lineBreakStrategyIOS,
|
|
141
205
|
writingDirection = 'first-strong',
|
|
206
|
+
renderLinkDecoration,
|
|
207
|
+
onLayout,
|
|
142
208
|
...rest
|
|
143
209
|
}: EnrichedMarkdownTextProps) => {
|
|
144
210
|
const normalizedStyleRef = useRef<MarkdownStyleInternal | null>(null);
|
|
@@ -239,6 +305,89 @@ export const EnrichedMarkdownText = ({
|
|
|
239
305
|
[onCopyPress]
|
|
240
306
|
);
|
|
241
307
|
|
|
308
|
+
const handleCopyRequest = useCallback(
|
|
309
|
+
// Codegen types `source` as a plain string; native only sends the four
|
|
310
|
+
// values of CopyEvent['source'].
|
|
311
|
+
(
|
|
312
|
+
e: NativeSyntheticEvent<Omit<CopyEvent, 'source'> & { source: string }>
|
|
313
|
+
) => {
|
|
314
|
+
const { source, markdown: copied, text, whole } = e.nativeEvent;
|
|
315
|
+
onCopy?.({
|
|
316
|
+
source: source as CopyEvent['source'],
|
|
317
|
+
markdown: copied,
|
|
318
|
+
text,
|
|
319
|
+
whole,
|
|
320
|
+
});
|
|
321
|
+
},
|
|
322
|
+
[onCopy]
|
|
323
|
+
);
|
|
324
|
+
const interceptCopy = onCopy != null;
|
|
325
|
+
|
|
326
|
+
const decorated = renderLinkDecoration != null;
|
|
327
|
+
const [linkLayout, setLinkLayout] = useState<LinkDecorationInfo[]>([]);
|
|
328
|
+
// Where the native view sits inside the wrapper (the wrapper's padding).
|
|
329
|
+
const [nativeOffset, setNativeOffset] = useState(ZERO_OFFSET);
|
|
330
|
+
|
|
331
|
+
const handleLinkLayout = useCallback(
|
|
332
|
+
(e: NativeSyntheticEvent<LinkLayoutEvent>) => {
|
|
333
|
+
setLinkLayout(groupLinkFragments(e.nativeEvent.fragments));
|
|
334
|
+
},
|
|
335
|
+
[]
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
const handleNativeLayout = useCallback((e: LayoutChangeEvent) => {
|
|
339
|
+
const { x, y } = e.nativeEvent.layout;
|
|
340
|
+
setNativeOffset((prev) => (prev.x === x && prev.y === y ? prev : { x, y }));
|
|
341
|
+
}, []);
|
|
342
|
+
|
|
343
|
+
// Rects stay relative to the native view — the view the ref's
|
|
344
|
+
// `measureInWindow` measures — even when decorations wrap it.
|
|
345
|
+
const handleSelectionChange = useCallback(
|
|
346
|
+
// Codegen types `source` as a plain string; native only sends the four
|
|
347
|
+
// values of SelectionChangeEvent['source'].
|
|
348
|
+
(e: NativeSyntheticEvent<NativeSelectionChangeEvent>) => {
|
|
349
|
+
const { source, ...payload } = e.nativeEvent;
|
|
350
|
+
onSelectionChange?.({
|
|
351
|
+
...payload,
|
|
352
|
+
source: source as SelectionChangeEvent['source'],
|
|
353
|
+
});
|
|
354
|
+
},
|
|
355
|
+
[onSelectionChange]
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
const nativeRef = useRef<HostInstance | null>(null);
|
|
359
|
+
const isGithubFlavor = flavor === 'github';
|
|
360
|
+
useImperativeHandle(
|
|
361
|
+
ref,
|
|
362
|
+
() => ({
|
|
363
|
+
clearSelection: () => {
|
|
364
|
+
const node = nativeRef.current;
|
|
365
|
+
if (node == null) return;
|
|
366
|
+
// Codegen's ViewRef resolves to `never` with RN 0.84's function-based
|
|
367
|
+
// HostComponent type — the cast is safe at runtime.
|
|
368
|
+
if (isGithubFlavor) {
|
|
369
|
+
MarkdownCommands.clearSelection(
|
|
370
|
+
node as Parameters<(typeof MarkdownCommands)['clearSelection']>[0]
|
|
371
|
+
);
|
|
372
|
+
} else {
|
|
373
|
+
TextCommands.clearSelection(
|
|
374
|
+
node as Parameters<(typeof TextCommands)['clearSelection']>[0]
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
measure: (callback) => nativeRef.current?.measure(callback),
|
|
379
|
+
measureInWindow: (callback) =>
|
|
380
|
+
nativeRef.current?.measureInWindow(callback),
|
|
381
|
+
measureLayout: (relativeToNativeNode, onSuccess, onFail) =>
|
|
382
|
+
nativeRef.current?.measureLayout(
|
|
383
|
+
relativeToNativeNode,
|
|
384
|
+
onSuccess,
|
|
385
|
+
onFail
|
|
386
|
+
),
|
|
387
|
+
}),
|
|
388
|
+
[isGithubFlavor]
|
|
389
|
+
);
|
|
390
|
+
|
|
242
391
|
const tableMode = streamingConfig?.tableMode ?? 'progressive';
|
|
243
392
|
const codeBlockMode = streamingConfig?.codeBlockMode ?? 'progressive';
|
|
244
393
|
const normalizedStreamingConfig = useMemo(
|
|
@@ -253,10 +402,19 @@ export const EnrichedMarkdownText = ({
|
|
|
253
402
|
copy?: unknown;
|
|
254
403
|
copyAsMarkdown?: unknown;
|
|
255
404
|
copyImageUrl?: unknown;
|
|
405
|
+
systemItems?: unknown;
|
|
406
|
+
codeBlockCopyButton?: unknown;
|
|
256
407
|
}
|
|
257
408
|
| undefined;
|
|
258
409
|
|
|
259
410
|
const copy = normalizeMenuItem(config?.copy, true, DEFAULT_COPY_LABEL);
|
|
411
|
+
const copyFormat = (config?.copy as { format?: unknown } | undefined)
|
|
412
|
+
?.format;
|
|
413
|
+
const codeBlockCopyButton = normalizeMenuItem(
|
|
414
|
+
config?.codeBlockCopyButton,
|
|
415
|
+
true,
|
|
416
|
+
''
|
|
417
|
+
);
|
|
260
418
|
const copyAsMarkdown = normalizeLegacyBooleanMenuItem(
|
|
261
419
|
config?.copyAsMarkdown,
|
|
262
420
|
'selectionMenuConfig',
|
|
@@ -289,8 +447,13 @@ export const EnrichedMarkdownText = ({
|
|
|
289
447
|
pluralLabels,
|
|
290
448
|
copyImageUrl.label
|
|
291
449
|
),
|
|
450
|
+
copyEnabled: copy.enabled,
|
|
451
|
+
copyFormatMarkdown: copyFormat === 'markdown',
|
|
452
|
+
systemItemsNone: config?.systemItems === 'none',
|
|
453
|
+
codeBlockCopyButton: codeBlockCopyButton.enabled,
|
|
454
|
+
interceptCopy,
|
|
292
455
|
};
|
|
293
|
-
}, [selectionMenuConfig]);
|
|
456
|
+
}, [selectionMenuConfig, interceptCopy]);
|
|
294
457
|
|
|
295
458
|
const resolvedAccessibilityLabels = useMemo(
|
|
296
459
|
() => resolveAccessibilityLabels(accessibilityLabels),
|
|
@@ -305,7 +468,11 @@ export const EnrichedMarkdownText = ({
|
|
|
305
468
|
onTaskListItemPress: handleTaskListItemPress,
|
|
306
469
|
enableTaskListItemToggle,
|
|
307
470
|
onCopyPress: handleCopyPress,
|
|
471
|
+
onCopyRequest: handleCopyRequest,
|
|
472
|
+
emitSelectionChange: onSelectionChange != null,
|
|
473
|
+
onSelectionChange: handleSelectionChange,
|
|
308
474
|
enableLinkPreview: onLinkLongPress == null && (enableLinkPreview ?? true),
|
|
475
|
+
linkLongPressSelects,
|
|
309
476
|
selectable,
|
|
310
477
|
md4cFlags: normalizedMd4cFlags,
|
|
311
478
|
allowFontScaling,
|
|
@@ -329,11 +496,55 @@ export const EnrichedMarkdownText = ({
|
|
|
329
496
|
...rest,
|
|
330
497
|
};
|
|
331
498
|
|
|
332
|
-
|
|
333
|
-
|
|
499
|
+
const NativeComponent = isGithubFlavor
|
|
500
|
+
? EnrichedMarkdownNativeComponent
|
|
501
|
+
: EnrichedMarkdownTextNativeComponent;
|
|
502
|
+
|
|
503
|
+
// Without decorations the native view is returned as-is (no wrapper, no
|
|
504
|
+
// layout events) so existing layouts are untouched.
|
|
505
|
+
if (!decorated) {
|
|
506
|
+
return (
|
|
507
|
+
<NativeComponent {...sharedProps} ref={nativeRef} onLayout={onLayout} />
|
|
508
|
+
);
|
|
334
509
|
}
|
|
335
510
|
|
|
336
|
-
return
|
|
511
|
+
return (
|
|
512
|
+
<View style={containerStyle} onLayout={onLayout}>
|
|
513
|
+
<NativeComponent
|
|
514
|
+
{...sharedProps}
|
|
515
|
+
ref={nativeRef}
|
|
516
|
+
style={undefined}
|
|
517
|
+
emitLinkLayout
|
|
518
|
+
onLinkLayout={handleLinkLayout}
|
|
519
|
+
onLayout={handleNativeLayout}
|
|
520
|
+
/>
|
|
521
|
+
{linkLayout.map((info) => {
|
|
522
|
+
const decoration = renderLinkDecoration(info);
|
|
523
|
+
if (decoration == null) return null;
|
|
524
|
+
return (
|
|
525
|
+
<View
|
|
526
|
+
key={info.index}
|
|
527
|
+
pointerEvents="box-none"
|
|
528
|
+
style={[
|
|
529
|
+
styles.decoration,
|
|
530
|
+
{
|
|
531
|
+
left: nativeOffset.x + info.rect.x,
|
|
532
|
+
top: nativeOffset.y + info.rect.y,
|
|
533
|
+
width: info.rect.width,
|
|
534
|
+
height: info.rect.height,
|
|
535
|
+
},
|
|
536
|
+
]}
|
|
537
|
+
>
|
|
538
|
+
{decoration}
|
|
539
|
+
</View>
|
|
540
|
+
);
|
|
541
|
+
})}
|
|
542
|
+
</View>
|
|
543
|
+
);
|
|
337
544
|
};
|
|
338
545
|
|
|
546
|
+
const styles = StyleSheet.create({
|
|
547
|
+
decoration: { position: 'absolute' },
|
|
548
|
+
});
|
|
549
|
+
|
|
339
550
|
export default EnrichedMarkdownText;
|
|
@@ -183,6 +183,11 @@ const DEFAULT_NORMALIZED_STYLE = Object.freeze({
|
|
|
183
183
|
color: normalizeColor('#2563EB')!,
|
|
184
184
|
underline: true,
|
|
185
185
|
backgroundColor: normalizeColor('transparent')!,
|
|
186
|
+
borderRadius: 0,
|
|
187
|
+
paddingHorizontal: 0,
|
|
188
|
+
paddingVertical: 0,
|
|
189
|
+
borderColor: normalizeColor('transparent')!,
|
|
190
|
+
borderWidth: 0,
|
|
186
191
|
},
|
|
187
192
|
linkVariants: [],
|
|
188
193
|
strong: { fontFamily: '', fontWeight: 'bold', color: undefined },
|
|
@@ -248,11 +253,13 @@ const DEFAULT_NORMALIZED_STYLE = Object.freeze({
|
|
|
248
253
|
marginBottom: 16,
|
|
249
254
|
textAlign: 'center' as BlockTextAlign,
|
|
250
255
|
fontWeight: 'normal',
|
|
256
|
+
glyphOverflow: 0,
|
|
251
257
|
},
|
|
252
258
|
inlineMath: {
|
|
253
259
|
color: defaultTextColor,
|
|
254
260
|
paddingVertical: 4,
|
|
255
261
|
fontWeight: 'normal',
|
|
262
|
+
glyphOverflow: 0,
|
|
256
263
|
},
|
|
257
264
|
taskList: {
|
|
258
265
|
checkedColor: Platform.select({
|
|
@@ -338,9 +345,17 @@ export const normalizeMarkdownStyle = (
|
|
|
338
345
|
color: ((override.color ? normalizeColor(override.color) : null) ??
|
|
339
346
|
linkBase.color) as string,
|
|
340
347
|
underline: override.underline ?? linkBase.underline,
|
|
348
|
+
// Chip ("box") properties never inherit from the base link style.
|
|
341
349
|
backgroundColor: (override.backgroundColor
|
|
342
350
|
? (normalizeColor(override.backgroundColor) ?? transparent)
|
|
343
351
|
: transparent) as string,
|
|
352
|
+
borderRadius: override.borderRadius ?? 0,
|
|
353
|
+
paddingHorizontal: override.paddingHorizontal ?? 0,
|
|
354
|
+
paddingVertical: override.paddingVertical ?? 0,
|
|
355
|
+
borderColor: (override.borderColor
|
|
356
|
+
? (normalizeColor(override.borderColor) ?? transparent)
|
|
357
|
+
: transparent) as string,
|
|
358
|
+
borderWidth: override.borderWidth ?? 0,
|
|
344
359
|
};
|
|
345
360
|
}
|
|
346
361
|
);
|
|
@@ -147,6 +147,11 @@ const DEFAULT_NORMALIZED_STYLE: MarkdownStyleInternal = Object.freeze({
|
|
|
147
147
|
color: '#2563EB',
|
|
148
148
|
underline: true,
|
|
149
149
|
backgroundColor: 'transparent',
|
|
150
|
+
borderRadius: 0,
|
|
151
|
+
paddingHorizontal: 0,
|
|
152
|
+
paddingVertical: 0,
|
|
153
|
+
borderColor: 'transparent',
|
|
154
|
+
borderWidth: 0,
|
|
150
155
|
},
|
|
151
156
|
linkVariants: [],
|
|
152
157
|
strong: { fontFamily: '', fontWeight: 'bold', color: undefined },
|
|
@@ -210,11 +215,13 @@ const DEFAULT_NORMALIZED_STYLE: MarkdownStyleInternal = Object.freeze({
|
|
|
210
215
|
marginBottom: 16,
|
|
211
216
|
textAlign: 'center' as BlockTextAlign,
|
|
212
217
|
fontWeight: 'normal',
|
|
218
|
+
glyphOverflow: 0,
|
|
213
219
|
},
|
|
214
220
|
inlineMath: {
|
|
215
221
|
color: defaultTextColor,
|
|
216
222
|
paddingVertical: 4,
|
|
217
223
|
fontWeight: 'normal',
|
|
224
|
+
glyphOverflow: 0,
|
|
218
225
|
},
|
|
219
226
|
taskList: {
|
|
220
227
|
checkedColor: '#007AFF',
|
|
@@ -289,7 +296,13 @@ export const normalizeMarkdownStyle = (
|
|
|
289
296
|
pattern,
|
|
290
297
|
color: override.color ?? linkBase.color,
|
|
291
298
|
underline: override.underline ?? linkBase.underline,
|
|
299
|
+
// Chip ("box") properties never inherit from the base link style.
|
|
292
300
|
backgroundColor: override.backgroundColor ?? 'transparent',
|
|
301
|
+
borderRadius: override.borderRadius ?? 0,
|
|
302
|
+
paddingHorizontal: override.paddingHorizontal ?? 0,
|
|
303
|
+
paddingVertical: override.paddingVertical ?? 0,
|
|
304
|
+
borderColor: override.borderColor ?? 'transparent',
|
|
305
|
+
borderWidth: override.borderWidth ?? 0,
|
|
293
306
|
};
|
|
294
307
|
}
|
|
295
308
|
);
|
|
@@ -84,17 +84,39 @@ interface CodeBlockStyle extends BaseBlockStyle {
|
|
|
84
84
|
syntaxColors?: CodeBlockSyntaxColors;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Chip ("box") properties shared by `link` and `linkVariants`. Unlike `color`
|
|
89
|
+
* and `underline`, these never inherit from the base `link` style: a variant
|
|
90
|
+
* that omits them renders without a chip (`0` / `transparent`).
|
|
91
|
+
*/
|
|
92
|
+
interface LinkChipStyle {
|
|
93
|
+
backgroundColor?: string;
|
|
94
|
+
/** Corner radius of the chip, in dp. */
|
|
95
|
+
borderRadius?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Horizontal padding, in dp. Reserves real space in the line on both outer
|
|
98
|
+
* edges of the link (affects measurement and wrapping).
|
|
99
|
+
*/
|
|
100
|
+
paddingHorizontal?: number;
|
|
101
|
+
/**
|
|
102
|
+
* Vertical padding, in dp. Only affects the drawn chip (it bleeds into the
|
|
103
|
+
* surrounding line spacing); the line box is unchanged.
|
|
104
|
+
*/
|
|
105
|
+
paddingVertical?: number;
|
|
106
|
+
borderColor?: string;
|
|
107
|
+
/** Border width, in dp. Drawn inset, within the chip bounds. */
|
|
108
|
+
borderWidth?: number;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface LinkStyle extends LinkChipStyle {
|
|
88
112
|
fontFamily?: string;
|
|
89
113
|
color?: string;
|
|
90
114
|
underline?: boolean;
|
|
91
|
-
backgroundColor?: string;
|
|
92
115
|
}
|
|
93
116
|
|
|
94
|
-
export interface LinkVariantStyle {
|
|
117
|
+
export interface LinkVariantStyle extends LinkChipStyle {
|
|
95
118
|
color?: string;
|
|
96
119
|
underline?: boolean;
|
|
97
|
-
backgroundColor?: string;
|
|
98
120
|
}
|
|
99
121
|
|
|
100
122
|
interface StrongStyle {
|
|
@@ -234,6 +256,17 @@ interface MathStyle {
|
|
|
234
256
|
* @default 'normal'
|
|
235
257
|
*/
|
|
236
258
|
fontWeight?: 'bold' | 'normal';
|
|
259
|
+
/**
|
|
260
|
+
* Headroom kept above and below the rendered formula, in points (dp on
|
|
261
|
+
* Android), inside the box the formula reports. The math engine sizes a
|
|
262
|
+
* formula by its TeX metric box, and digit and capital outlines — plus the
|
|
263
|
+
* synthetic-bold stroke — rise a little past it; without this headroom that
|
|
264
|
+
* ink is clipped at the top of the box. About `0.06 × fontSize` covers the
|
|
265
|
+
* KaTeX faces; add `0.02 × fontSize` when `fontWeight` is `'bold'`.
|
|
266
|
+
* Android rounds it up to whole pixels.
|
|
267
|
+
* @default 0
|
|
268
|
+
*/
|
|
269
|
+
glyphOverflow?: number;
|
|
237
270
|
}
|
|
238
271
|
|
|
239
272
|
interface InlineMathStyle {
|
|
@@ -258,6 +291,17 @@ interface InlineMathStyle {
|
|
|
258
291
|
* @default 'normal'
|
|
259
292
|
*/
|
|
260
293
|
fontWeight?: 'bold' | 'normal';
|
|
294
|
+
/**
|
|
295
|
+
* Headroom kept above and below the rendered formula, in points (dp on
|
|
296
|
+
* Android), inside the box the formula reports. The math engine sizes a
|
|
297
|
+
* formula by its TeX metric box, and digit and capital outlines — plus the
|
|
298
|
+
* synthetic-bold stroke — rise a little past it; without this headroom that
|
|
299
|
+
* ink is clipped at the top of the box. About `0.06 × fontSize` covers the
|
|
300
|
+
* KaTeX faces; add `0.02 × fontSize` when `fontWeight` is `'bold'`.
|
|
301
|
+
* Android rounds it up to whole pixels.
|
|
302
|
+
* @default 0
|
|
303
|
+
*/
|
|
304
|
+
glyphOverflow?: number;
|
|
261
305
|
}
|
|
262
306
|
|
|
263
307
|
interface SpoilerParticlesStyle {
|
|
@@ -350,7 +394,9 @@ export interface MarkdownStyle {
|
|
|
350
394
|
* specific patterns take precedence.
|
|
351
395
|
*
|
|
352
396
|
* `color` and `underline` inherit from the base `link` style when omitted.
|
|
353
|
-
* `backgroundColor`
|
|
397
|
+
* Chip properties (`backgroundColor`, `borderRadius`, `paddingHorizontal`,
|
|
398
|
+
* `paddingVertical`, `borderColor`, `borderWidth`) do not inherit: when
|
|
399
|
+
* omitted they default to `0` / `transparent`.
|
|
354
400
|
* `fontFamily` always follows the base `link` style and cannot be overridden per-variant.
|
|
355
401
|
*
|
|
356
402
|
* @example
|
|
@@ -88,6 +88,11 @@ interface LinkStyleInternal {
|
|
|
88
88
|
color: string;
|
|
89
89
|
underline: boolean;
|
|
90
90
|
backgroundColor: string;
|
|
91
|
+
borderRadius: number;
|
|
92
|
+
paddingHorizontal: number;
|
|
93
|
+
paddingVertical: number;
|
|
94
|
+
borderColor: string;
|
|
95
|
+
borderWidth: number;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
export interface LinkVariantEntryInternal {
|
|
@@ -95,6 +100,11 @@ export interface LinkVariantEntryInternal {
|
|
|
95
100
|
color: string;
|
|
96
101
|
underline: boolean;
|
|
97
102
|
backgroundColor: string;
|
|
103
|
+
borderRadius: number;
|
|
104
|
+
paddingHorizontal: number;
|
|
105
|
+
paddingVertical: number;
|
|
106
|
+
borderColor: string;
|
|
107
|
+
borderWidth: number;
|
|
98
108
|
}
|
|
99
109
|
|
|
100
110
|
interface StrongStyleInternal {
|
|
@@ -180,12 +190,14 @@ interface MathStyleInternal {
|
|
|
180
190
|
marginBottom: number;
|
|
181
191
|
textAlign: BlockTextAlign;
|
|
182
192
|
fontWeight: string;
|
|
193
|
+
glyphOverflow: number;
|
|
183
194
|
}
|
|
184
195
|
|
|
185
196
|
interface InlineMathStyleInternal {
|
|
186
197
|
color: string;
|
|
187
198
|
paddingVertical: number;
|
|
188
199
|
fontWeight: string;
|
|
200
|
+
glyphOverflow: number;
|
|
189
201
|
}
|
|
190
202
|
|
|
191
203
|
interface SpoilerParticlesStyleInternal {
|