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
|
@@ -16,6 +16,7 @@ class MathInlineSpan(
|
|
|
16
16
|
private val textColor: Int,
|
|
17
17
|
private val paddingVertical: Float,
|
|
18
18
|
private val fontWeight: String = "normal",
|
|
19
|
+
private val glyphOverflow: Float = 0f,
|
|
19
20
|
) : ReplacementSpan() {
|
|
20
21
|
private var cachedBitmap: Bitmap? = null
|
|
21
22
|
private var cachedWidth = 0
|
|
@@ -31,18 +32,24 @@ class MathInlineSpan(
|
|
|
31
32
|
val displayList = RaTeXEngine.parseBlocking(latex, displayMode = false, color = textColor)
|
|
32
33
|
val renderer = RaTeXRenderer(displayList, fontSize, ratexTypefaceLoader(fontWeight))
|
|
33
34
|
|
|
34
|
-
cachedWidth = renderer.widthPx.toInt().coerceAtLeast(1)
|
|
35
|
+
cachedWidth = ceil(renderer.widthPx).toInt().coerceAtLeast(1)
|
|
35
36
|
mathAscent = renderer.heightPx
|
|
36
37
|
mathDescent = renderer.depthPx
|
|
37
38
|
|
|
39
|
+
// RaTeX reports TeX metric boxes, which digit and capital outlines (and the
|
|
40
|
+
// fake-bold stroke) overshoot; the bitmap keeps glyphOverflow px of headroom
|
|
41
|
+
// on both sides so that ink is not cut off.
|
|
42
|
+
val overflowPx = glyphOverflow.toInt()
|
|
38
43
|
val bitmap =
|
|
39
44
|
Bitmap.createBitmap(
|
|
40
45
|
cachedWidth,
|
|
41
|
-
ceil(renderer.totalHeightPx).toInt().coerceAtLeast(1),
|
|
46
|
+
ceil(renderer.totalHeightPx).toInt().coerceAtLeast(1) + overflowPx * 2,
|
|
42
47
|
Bitmap.Config.ARGB_8888,
|
|
43
48
|
)
|
|
44
49
|
|
|
45
|
-
|
|
50
|
+
val canvas = Canvas(bitmap)
|
|
51
|
+
canvas.translate(0f, overflowPx.toFloat())
|
|
52
|
+
renderer.draw(canvas)
|
|
46
53
|
cachedBitmap = bitmap
|
|
47
54
|
} catch (_: Exception) {
|
|
48
55
|
renderFailed = true
|
|
@@ -66,9 +73,9 @@ class MathInlineSpan(
|
|
|
66
73
|
// Must stay identical to MathInlinePlaceholderSpan.getSize: that span measures
|
|
67
74
|
// this one off the main thread, and a box that disagrees by even a pixel either
|
|
68
75
|
// clips the formula or eats the padding this field is here to add.
|
|
69
|
-
ascent = -ceil(mathAscent + paddingVertical).toInt()
|
|
76
|
+
ascent = -ceil(mathAscent + (paddingVertical + glyphOverflow)).toInt()
|
|
70
77
|
top = ascent
|
|
71
|
-
descent = ceil(mathDescent + paddingVertical).toInt()
|
|
78
|
+
descent = ceil(mathDescent + (paddingVertical + glyphOverflow)).toInt()
|
|
72
79
|
bottom = descent
|
|
73
80
|
}
|
|
74
81
|
|
|
@@ -88,7 +95,7 @@ class MathInlineSpan(
|
|
|
88
95
|
) {
|
|
89
96
|
prepareResources()
|
|
90
97
|
cachedBitmap?.let {
|
|
91
|
-
val bitmapY = y - ceil(mathAscent)
|
|
98
|
+
val bitmapY = y - ceil(mathAscent) - glyphOverflow
|
|
92
99
|
canvas.drawBitmap(it, x, bitmapY, paint)
|
|
93
100
|
}
|
|
94
101
|
}
|
|
@@ -5,6 +5,7 @@ import android.util.Log
|
|
|
5
5
|
import io.ratex.RaTeXEngine
|
|
6
6
|
import io.ratex.RaTeXFontLoader
|
|
7
7
|
import io.ratex.RaTeXRenderer
|
|
8
|
+
import kotlin.math.ceil
|
|
8
9
|
|
|
9
10
|
object MathMeasureHelper {
|
|
10
11
|
@JvmStatic
|
|
@@ -37,7 +38,7 @@ object MathMeasureHelper {
|
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
return MathMetrics(
|
|
40
|
-
renderer.widthPx.toInt(),
|
|
41
|
+
ceil(renderer.widthPx).toInt().coerceAtLeast(1),
|
|
41
42
|
renderer.heightPx,
|
|
42
43
|
renderer.depthPx,
|
|
43
44
|
)
|
|
@@ -42,6 +42,11 @@ class MathContainerView(
|
|
|
42
42
|
var copyLabel: String = ""
|
|
43
43
|
var copyAsMarkdownLabel: String = ""
|
|
44
44
|
var contextMenuHidden: Boolean = false
|
|
45
|
+
var menuOptions: BlockMenuOptions = BlockMenuOptions()
|
|
46
|
+
|
|
47
|
+
// Called instead of the menu on long press while contextMenuHidden is on, so
|
|
48
|
+
// the owner can report the block (onSelectionChange) and show its own UI.
|
|
49
|
+
var onMenuSuppressed: ((markdown: String, text: String) -> Unit)? = null
|
|
45
50
|
|
|
46
51
|
override val segmentMarginTop: Int get() = mathStyle.marginTop.toInt()
|
|
47
52
|
override val segmentMarginBottom: Int get() = mathStyle.marginBottom.toInt()
|
|
@@ -53,7 +58,7 @@ class MathContainerView(
|
|
|
53
58
|
else -> Gravity.CENTER_HORIZONTAL
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
private val mathView = RaTeXCanvasView(context)
|
|
61
|
+
private val mathView = RaTeXCanvasView(context, mathStyle.glyphOverflow)
|
|
57
62
|
|
|
58
63
|
init {
|
|
59
64
|
setBackgroundColor(mathStyle.backgroundColor)
|
|
@@ -118,20 +123,27 @@ class MathContainerView(
|
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
private fun showContextMenu(anchor: View) {
|
|
121
|
-
if (contextMenuHidden)
|
|
126
|
+
if (contextMenuHidden) {
|
|
127
|
+
onMenuSuppressed?.invoke("$$\n$cachedLatex\n$$", cachedLatex)
|
|
128
|
+
return
|
|
129
|
+
}
|
|
122
130
|
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
|
123
131
|
ContextMenuPopup.show(anchor, this) {
|
|
124
|
-
|
|
132
|
+
blockCopyItems(menuOptions, copyLabel, copyAsMarkdownLabel, markdown = {
|
|
133
|
+
"$$\n$cachedLatex\n$$"
|
|
134
|
+
}, rawText = { cachedLatex }, copyRaw = {
|
|
125
135
|
clipboard.setPrimaryClip(ClipData.newPlainText("Math", cachedLatex))
|
|
126
|
-
}
|
|
127
|
-
item(ContextMenuPopup.Icon.DOCUMENT, copyAsMarkdownLabel) {
|
|
136
|
+
}, copyMarkdown = {
|
|
128
137
|
clipboard.setPrimaryClip(ClipData.newPlainText("Math", "$$\n$cachedLatex\n$$"))
|
|
129
|
-
}
|
|
138
|
+
})
|
|
130
139
|
}
|
|
131
140
|
}
|
|
132
141
|
|
|
142
|
+
// glyphOverflow px of headroom above and below the RaTeX box: digit and capital
|
|
143
|
+
// outlines (and the fake-bold stroke) overshoot it, and this view clips to its size.
|
|
133
144
|
private class RaTeXCanvasView(
|
|
134
145
|
context: Context,
|
|
146
|
+
private val glyphOverflow: Float,
|
|
135
147
|
) : View(context) {
|
|
136
148
|
var renderer: RaTeXRenderer? = null
|
|
137
149
|
|
|
@@ -144,12 +156,16 @@ class MathContainerView(
|
|
|
144
156
|
?: return setMeasuredDimension(0, 0)
|
|
145
157
|
setMeasuredDimension(
|
|
146
158
|
ceil(currentRenderer.widthPx).toInt().coerceAtLeast(1),
|
|
147
|
-
ceil(currentRenderer.totalHeightPx).toInt().coerceAtLeast(1),
|
|
159
|
+
ceil(currentRenderer.totalHeightPx).toInt().coerceAtLeast(1) + (glyphOverflow * 2).toInt(),
|
|
148
160
|
)
|
|
149
161
|
}
|
|
150
162
|
|
|
151
163
|
override fun onDraw(canvas: Canvas) {
|
|
152
|
-
renderer
|
|
164
|
+
val currentRenderer = renderer ?: return
|
|
165
|
+
canvas.save()
|
|
166
|
+
canvas.translate(0f, glyphOverflow)
|
|
167
|
+
currentRenderer.draw(canvas)
|
|
168
|
+
canvas.restore()
|
|
153
169
|
}
|
|
154
170
|
}
|
|
155
171
|
|
|
@@ -166,7 +182,7 @@ class MathContainerView(
|
|
|
166
182
|
mode = MathRenderMode.Display,
|
|
167
183
|
)
|
|
168
184
|
val metrics = MathMeasureHelper.measure(context, listOf(request)).first()
|
|
169
|
-
return ceil(metrics.ascent + metrics.descent).toInt() + (mathStyle.padding * 2)
|
|
185
|
+
return ceil(metrics.ascent + metrics.descent).toInt() + (mathStyle.padding * 2) + (mathStyle.glyphOverflow * 2)
|
|
170
186
|
}
|
|
171
187
|
|
|
172
188
|
private const val TAG = "MathContainerView"
|
package/docs/API_REFERENCE.md
CHANGED
|
@@ -69,6 +69,59 @@ Callback when a link is long pressed. Access URL via `event.url`. On iOS, automa
|
|
|
69
69
|
/>
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
### `renderLinkDecoration`
|
|
73
|
+
|
|
74
|
+
Renders a React Native view on top of each link — for example a badge or sparkle on a [link chip](STYLES.md#link-chips). Return `null` to leave a link undecorated.
|
|
75
|
+
|
|
76
|
+
| Type | Default Value | Platform |
|
|
77
|
+
| ------------------------------------------------------ | ------------- | -------- |
|
|
78
|
+
| `(info: LinkDecorationInfo) => ReactNode \| null` | - | Both |
|
|
79
|
+
|
|
80
|
+
`LinkDecorationInfo`:
|
|
81
|
+
|
|
82
|
+
| Field | Type | Description |
|
|
83
|
+
| ------- | ------------ | ----------- |
|
|
84
|
+
| `index` | `number` | Position of the link in the document (0-based). Stable key for the link |
|
|
85
|
+
| `url` | `string` | Link URL |
|
|
86
|
+
| `text` | `string` | Visible link text |
|
|
87
|
+
| `rect` | `LinkRect` | Anchor rect: the drawn chip (glyphs + horizontal/vertical padding) of the link's **last** line fragment |
|
|
88
|
+
| `rects` | `LinkRect[]` | Every line fragment, in order (several when the link wraps) |
|
|
89
|
+
|
|
90
|
+
`LinkRect` is `{ x, y, width, height }` in dp, relative to the component's content box (inside `containerStyle` padding).
|
|
91
|
+
|
|
92
|
+
The returned node is placed inside an absolutely positioned box matching `rect`, with `pointerEvents="box-none"`, so position it relative to that box. Negative offsets let it overflow the chip:
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<EnrichedMarkdownText
|
|
96
|
+
markdown="Read the [guide](https://example.com/guide) first."
|
|
97
|
+
markdownStyle={{
|
|
98
|
+
link: {
|
|
99
|
+
backgroundColor: '#DCE2FF',
|
|
100
|
+
borderRadius: 5,
|
|
101
|
+
paddingHorizontal: 7,
|
|
102
|
+
underline: false,
|
|
103
|
+
},
|
|
104
|
+
}}
|
|
105
|
+
renderLinkDecoration={({ url }) =>
|
|
106
|
+
url.startsWith('https://') ? (
|
|
107
|
+
<View style={{ position: 'absolute', top: -8, right: -8 }}>
|
|
108
|
+
<SparkleIcon />
|
|
109
|
+
</View>
|
|
110
|
+
) : null
|
|
111
|
+
}
|
|
112
|
+
/>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Notes and limitations:
|
|
116
|
+
|
|
117
|
+
- When this prop is not set the component renders exactly as before: no wrapper view and no layout events.
|
|
118
|
+
- Setting it wraps the native view in a `View` (which takes `containerStyle`). Switching between set and unset remounts the native view.
|
|
119
|
+
- Rects are measured natively after layout and sent to JS, so decorations appear one frame after the text. Updates are deduplicated — streaming does not re-render decorations unless a link actually moves.
|
|
120
|
+
- Links inside tables (`flavor="github"`) are not reported.
|
|
121
|
+
- On Android, parts of a decoration that overflow the component's bounds do not receive touches.
|
|
122
|
+
- Web: `rect` is the link's whole inline box and `rects` is `[rect]`; for a wrapping link the decoration anchors to that box rather than the last line.
|
|
123
|
+
- Not supported by `EnrichedMarkdownTextInput`.
|
|
124
|
+
|
|
72
125
|
### `onTaskListItemPress`
|
|
73
126
|
|
|
74
127
|
Callback when a task list checkbox is tapped. Receives `index` (0-based), `checked` (new state after toggling), and `text` (item text).
|
|
@@ -122,6 +175,112 @@ Only fires when `flavor="github"` — the copy button is part of the GitHub flav
|
|
|
122
175
|
/>
|
|
123
176
|
```
|
|
124
177
|
|
|
178
|
+
### `onCopy`
|
|
179
|
+
|
|
180
|
+
Takes over the **Copy** item of the text selection menu and of the table, math and code block menus. When set, native does **not** write the clipboard: it calls `onCopy` with the copied content and your handler writes whatever it wants — for example with [`expo-clipboard`](https://docs.expo.dev/versions/latest/sdk/clipboard/). Use it to post-process what users copy (strip formatting, drop link targets…) without a native change.
|
|
181
|
+
|
|
182
|
+
| Type | Default Value | Platform |
|
|
183
|
+
| ----------------------------- | ------------- | -------- |
|
|
184
|
+
| `(event: CopyEvent) => void` | - | Both |
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
interface CopyEvent {
|
|
188
|
+
/** Which menu the Copy item belongs to. */
|
|
189
|
+
source: 'selection' | 'math' | 'table' | 'code';
|
|
190
|
+
/** What `copy.format: 'markdown'` would write. */
|
|
191
|
+
markdown: string;
|
|
192
|
+
/** Rendered text of the selection, or the block's raw content. */
|
|
193
|
+
text: string;
|
|
194
|
+
/** The selection spans the whole component (`markdown` is the source). Always true for blocks. */
|
|
195
|
+
whole: boolean;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
| `source` | `markdown` | `text` |
|
|
200
|
+
| ----------- | -------------------------------------------------------------------------- | ----------------------------- |
|
|
201
|
+
| `selection` | Original source when `whole`, otherwise rebuilt from the rendered styles | Selected text as rendered |
|
|
202
|
+
| `math` | `$$…$$` | LaTeX |
|
|
203
|
+
| `table` | The table as Markdown | Tab-separated cells |
|
|
204
|
+
| `code` | Fenced code block | Raw code |
|
|
205
|
+
|
|
206
|
+
- `onCopy` overrides `selectionMenuConfig.copy.format`; `copy.enabled: false` still hides the item, so no event fires.
|
|
207
|
+
- **Copy as Markdown**, the code block header copy button and the VoiceOver copy action are unaffected. `onCopyPress` does not fire for an intercepted Copy.
|
|
208
|
+
- With `flavor="github"` the text is split into segments around blocks, so a selection is `whole` only when the markdown renders as a single text segment.
|
|
209
|
+
- A rebuilt `markdown` wraps each styled run separately (`**a *****b***** c**`) and does not escape literal `*` / `_`.
|
|
210
|
+
- Copying with a hardware keyboard (Cmd+C / Ctrl+C) does not go through the menu and is not intercepted.
|
|
211
|
+
- Ignored on macOS. On web the prop is not this API: it reaches the container `div` as the DOM `onCopy` clipboard event.
|
|
212
|
+
|
|
213
|
+
**Example:**
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import * as Clipboard from 'expo-clipboard';
|
|
217
|
+
|
|
218
|
+
<EnrichedMarkdownText
|
|
219
|
+
markdown={content}
|
|
220
|
+
onCopy={({ source, markdown }) => {
|
|
221
|
+
Clipboard.setStringAsync(source === 'selection' ? stripFormatting(markdown) : markdown);
|
|
222
|
+
}}
|
|
223
|
+
/>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### `onSelectionChange`
|
|
227
|
+
|
|
228
|
+
Reports the text selection so the app can draw its own selection menu. Pair it with [`contextMenuHidden`](#contextmenuhidden) to replace the native menu entirely.
|
|
229
|
+
|
|
230
|
+
| Type | Default Value | Platform |
|
|
231
|
+
| ---------------------------------------- | ------------- | -------- |
|
|
232
|
+
| `(event: SelectionChangeEvent) => void` | - | Both |
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
interface SelectionRect { x: number; y: number; width: number; height: number }
|
|
236
|
+
|
|
237
|
+
interface SelectionChangeEvent {
|
|
238
|
+
/** `false` once the selection is gone; every other field is then empty / zero. */
|
|
239
|
+
active: boolean;
|
|
240
|
+
/** `'selection'` for text, or the kind of a long-pressed block. */
|
|
241
|
+
source: 'selection' | 'math' | 'table' | 'code';
|
|
242
|
+
/** Same as `CopyEvent.text` / `CopyEvent.markdown` / `CopyEvent.whole`. */
|
|
243
|
+
text: string;
|
|
244
|
+
markdown: string;
|
|
245
|
+
whole: boolean;
|
|
246
|
+
/** Bounding box (full content width when it spans several lines). */
|
|
247
|
+
rect: SelectionRect;
|
|
248
|
+
/** Selected part of the first / last line — anchor a menu above the start or below the end. */
|
|
249
|
+
startRect: SelectionRect;
|
|
250
|
+
endRect: SelectionRect;
|
|
251
|
+
/** `true` while a selection handle is dragged (iOS; always `false` on Android). */
|
|
252
|
+
adjusting: boolean;
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
- Fires at most once per frame while the selection changes (payloads are deduplicated), and with `active: false` right away once it is gone — including when new `markdown` replaces the text.
|
|
257
|
+
- Rects are in dp, relative to the component's native view: add the origin from `ref.current.measureInWindow` to get window coordinates. Re-measure after scrolling instead of waiting for a new event.
|
|
258
|
+
- With `contextMenuHidden`, a long press on a table, math or code block (`flavor="github"`) fires the event with `source` set to the block kind, `whole: true` and every rect set to the block's frame. These blocks have no text selection, so without this they would offer no way to copy. Without `contextMenuHidden` the block menu shows as usual and no event fires.
|
|
259
|
+
- On iOS the selection isn't reported while a handle is dragged: the event fires with `adjusting: true` (and the selection as it was) when the drag begins, and with `adjusting: false` and the new selection when the finger lifts. Hide your menu while `adjusting` is `true`. Android has no such flag (`adjusting` is always `false`) but reports every step of the drag, so debounce before showing the menu there too.
|
|
260
|
+
- Within one component only one part holds a selection at a time: selecting in another text segment clears the previous one. To keep a single selection across several components, call `clearSelection()` on the previous one.
|
|
261
|
+
- Ignored on macOS and web.
|
|
262
|
+
|
|
263
|
+
**Imperative handle.** `ref` exposes `clearSelection()`, which clears the selection (and any long-pressed block) and fires `active: false`. It also forwards `measure`, `measureInWindow` and `measureLayout`.
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
const ref = useRef<EnrichedMarkdownTextInstance>(null);
|
|
267
|
+
|
|
268
|
+
<EnrichedMarkdownText
|
|
269
|
+
ref={ref}
|
|
270
|
+
markdown={content}
|
|
271
|
+
contextMenuHidden
|
|
272
|
+
onSelectionChange={(e) => {
|
|
273
|
+
if (!e.active || e.adjusting) return hideMenu();
|
|
274
|
+
ref.current?.measureInWindow((x, y) =>
|
|
275
|
+
showMenuDebounced({ x: x + e.startRect.x, y: y + e.startRect.y }, e.markdown)
|
|
276
|
+
);
|
|
277
|
+
}}
|
|
278
|
+
/>;
|
|
279
|
+
|
|
280
|
+
// After the menu action:
|
|
281
|
+
ref.current?.clearSelection();
|
|
282
|
+
```
|
|
283
|
+
|
|
125
284
|
### `enableLinkPreview`
|
|
126
285
|
|
|
127
286
|
Controls the native link preview on long press (iOS only). Automatically set to `false` when `onLinkLongPress` is provided.
|
|
@@ -142,6 +301,16 @@ You can also control this behavior explicitly without providing a handler:
|
|
|
142
301
|
/>
|
|
143
302
|
```
|
|
144
303
|
|
|
304
|
+
### `linkLongPressSelects`
|
|
305
|
+
|
|
306
|
+
Long-pressing a link selects its label and shows the selection edit menu (the same one a manual selection gets), instead of the system link preview (iOS only). Takes precedence over `enableLinkPreview` and `onLinkLongPress`.
|
|
307
|
+
|
|
308
|
+
| Type | Default Value | Platform |
|
|
309
|
+
| --------- | ------------- | -------- |
|
|
310
|
+
| `boolean` | `false` | iOS |
|
|
311
|
+
|
|
312
|
+
Only the link label is selected, not the chip padding; the selection handles can be dragged to extend it. Long-pressing inline math always behaves this way, without the prop.
|
|
313
|
+
|
|
145
314
|
### `selectable`
|
|
146
315
|
|
|
147
316
|
Whether text can be selected.
|
|
@@ -180,6 +349,8 @@ Notes:
|
|
|
180
349
|
prop suppresses it the same way.
|
|
181
350
|
- Applies to `EnrichedMarkdownText` only — it does not affect
|
|
182
351
|
`EnrichedMarkdownTextInput`.
|
|
352
|
+
- To show your own menu instead, use [`onSelectionChange`](#onselectionchange);
|
|
353
|
+
with this prop on, block long-presses are reported through it as well.
|
|
183
354
|
|
|
184
355
|
### `selectionColor`
|
|
185
356
|
|
|
@@ -469,7 +640,7 @@ Controls built-in actions added to the native text selection menu. Custom app-pr
|
|
|
469
640
|
| -------------------- | ---------------------------------------------- | -------- |
|
|
470
641
|
| `SelectionMenuConfig` | `{}` (see shape below for per-field defaults) | iOS, Android, macOS |
|
|
471
642
|
|
|
472
|
-
Each item takes an object: `{ enabled }` toggles visibility
|
|
643
|
+
Each item takes an object: `{ enabled }` toggles visibility and `label` overrides the English default. Items and labels apply to the main text selection menu as well as the table, math and code block copy menus. `copy.enabled`, `copy.format` and `systemItems` are ignored on macOS.
|
|
473
644
|
|
|
474
645
|
> **Deprecation:** the previous boolean shape (`copyAsMarkdown: false`) is still accepted at runtime for backward compatibility but logs a one-time warning. It will be removed in 0.8 — migrate to `{ enabled: false }`.
|
|
475
646
|
|
|
@@ -477,9 +648,13 @@ Each item takes an object: `{ enabled }` toggles visibility (the system `copy` i
|
|
|
477
648
|
|
|
478
649
|
```ts
|
|
479
650
|
interface SelectionMenuConfig {
|
|
480
|
-
/**
|
|
481
|
-
|
|
482
|
-
|
|
651
|
+
/**
|
|
652
|
+
* "Copy" item. `format: 'markdown'` copies Markdown as plain text instead of
|
|
653
|
+
* rich text (text selections) or the raw content (blocks).
|
|
654
|
+
* @default { enabled: true, label: "Copy", format: "rich" }
|
|
655
|
+
*/
|
|
656
|
+
copy?: { enabled?: boolean; label?: string; format?: 'rich' | 'markdown' };
|
|
657
|
+
/** "Copy as Markdown" action, in the text and block menus. @default { enabled: true, label: "Copy as Markdown" } */
|
|
483
658
|
copyAsMarkdown?: { enabled?: boolean; label?: string };
|
|
484
659
|
/** "Copy Image URL" action, shown when the selection contains images. */
|
|
485
660
|
copyImageUrl?: {
|
|
@@ -489,6 +664,10 @@ interface SelectionMenuConfig {
|
|
|
489
664
|
/** Forms for multiple images, chosen with Intl.PluralRules. @default { other: "Copy {count} Image URLs" } */
|
|
490
665
|
pluralLabels?: SelectionMenuPluralLabels;
|
|
491
666
|
};
|
|
667
|
+
/** `'none'` drops every system item (Select All, Look Up, Share, Translate…). @default 'default' */
|
|
668
|
+
systemItems?: 'default' | 'none';
|
|
669
|
+
/** Copy button in the code block header. @default { enabled: true } */
|
|
670
|
+
codeBlockCopyButton?: { enabled?: boolean };
|
|
492
671
|
}
|
|
493
672
|
|
|
494
673
|
interface SelectionMenuPluralLabels {
|
package/docs/COPY_OPTIONS.md
CHANGED
|
@@ -44,6 +44,46 @@ Use `selectionMenuConfig` to hide built-in selection menu actions while keeping
|
|
|
44
44
|
/>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
### Copy as Markdown only, no system items
|
|
48
|
+
|
|
49
|
+
`copy` can also be hidden (`{ enabled: false }`) or switched to Markdown with
|
|
50
|
+
`format: 'markdown'`, and `systemItems: 'none'` drops everything the OS adds
|
|
51
|
+
(Select All, Look Up, Share, Translate, app text actions…):
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<EnrichedMarkdownText
|
|
55
|
+
markdown={content}
|
|
56
|
+
selectionMenuConfig={{
|
|
57
|
+
copy: { format: 'markdown' }, // inline math → $…$, plain text only
|
|
58
|
+
copyAsMarkdown: { enabled: false },
|
|
59
|
+
systemItems: 'none',
|
|
60
|
+
codeBlockCopyButton: { enabled: false },
|
|
61
|
+
}}
|
|
62
|
+
/>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The same `copy` and `copyAsMarkdown` settings drive the long-press menus on
|
|
66
|
+
table, math and code blocks: with `format: 'markdown'` their Copy item writes
|
|
67
|
+
the block's Markdown (`$$…$$`, a fenced code block, a Markdown table). On code
|
|
68
|
+
blocks, the header copy button and the VoiceOver copy action always copy the raw
|
|
69
|
+
code and fire `onCopyPress`; `codeBlockCopyButton: { enabled: false }` hides the
|
|
70
|
+
button, and `copy: { enabled: false }` also removes the VoiceOver action.
|
|
71
|
+
`copy.enabled`, `copy.format` and `systemItems` are ignored on macOS.
|
|
72
|
+
|
|
73
|
+
### Handling Copy in JS
|
|
74
|
+
|
|
75
|
+
To decide in JS what lands on the clipboard, pass `onCopy`. The Copy item
|
|
76
|
+
(text selection and block menus) then writes nothing itself and hands you the
|
|
77
|
+
content — `markdown`, `text`, `source` and `whole` — to write with your
|
|
78
|
+
clipboard library. See [`onCopy`](API_REFERENCE.md#oncopy).
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<EnrichedMarkdownText
|
|
82
|
+
markdown={content}
|
|
83
|
+
onCopy={({ markdown }) => Clipboard.setStringAsync(markdown)}
|
|
84
|
+
/>
|
|
85
|
+
```
|
|
86
|
+
|
|
47
87
|
To turn the menu off entirely rather than item by item, use `contextMenuHidden`:
|
|
48
88
|
|
|
49
89
|
```tsx
|
package/docs/INPUT.md
CHANGED
|
@@ -283,11 +283,13 @@ Because nothing is written until you resolve, an async decision is safe: the sel
|
|
|
283
283
|
| | Behavior |
|
|
284
284
|
| --- | --- |
|
|
285
285
|
| **iOS** | Context menu and hardware ⌘V. `markdown` is set when the copy source was an `EnrichedMarkdownTextInput`. |
|
|
286
|
-
| **Android** | Context menu, hardware Ctrl+V
|
|
286
|
+
| **Android** | Context menu, hardware Ctrl+V, `KEYCODE_PASTE`, and a keyboard clipboard chip (Gboard, Samsung Keyboard) — see below. `markdown` is always `''`, and `resolvePaste` inserts `text` verbatim — so an intercepted copy-then-paste inside the app lands as plain text, even though the un-intercepted paste restores the formatting. |
|
|
287
287
|
| **macOS** | `interceptPaste` is ignored, `onPaste` never fires, and pastes insert inline as usual. |
|
|
288
288
|
|
|
289
289
|
Only clipboard content is intercepted. Drag-and-drop, autofill and IME content insertion bypass `onPaste` on both platforms and insert normally — on Android they are filtered out explicitly, so an autofill never arrives looking like a paste.
|
|
290
290
|
|
|
291
|
+
On Android a keyboard clipboard chip does not paste through the menu: the keyboard types the text in through the input connection. The input reports it as a paste when the committed text is exactly the current clipboard text and is at least 16 characters long or spans more than one line. Shorter single-line chip pastes, entries from the keyboard's clipboard history other than the current clip, and text the keyboard changes on the way insert inline without `onPaste`.
|
|
292
|
+
|
|
291
293
|
## Style Detection
|
|
292
294
|
|
|
293
295
|
All of the above styles can be detected with the use of [onChangeState](API_REFERENCE.md#onchangestate) callback payload.
|
package/docs/MENTIONS.md
CHANGED
|
@@ -69,7 +69,14 @@ linkVariants: {
|
|
|
69
69
|
}
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
Each key is a regex tested against the link URL. First match wins.
|
|
72
|
+
Each key is a regex tested against the link URL. First match wins. Patterns are auto-sorted longest-first.
|
|
73
|
+
|
|
74
|
+
Inheritance from the base `link` style is split in two groups:
|
|
75
|
+
|
|
76
|
+
- **Text** (`color`, `underline`): unspecified properties inherit from `link`.
|
|
77
|
+
- **Box** (`backgroundColor`, `borderRadius`, `paddingHorizontal`, `paddingVertical`, `borderColor`, `borderWidth`): never inherited. A variant that sets none of them renders without a chip, even when `link` is a chip.
|
|
78
|
+
|
|
79
|
+
`fontFamily` is only configurable on `link` and applies to every variant. See [Link chips](STYLES.md#link-chips) for the box properties.
|
|
73
80
|
|
|
74
81
|
## Positioning the Suggestion List
|
|
75
82
|
|
package/docs/STYLES.md
CHANGED
|
@@ -368,6 +368,33 @@ Per-token foreground colors for syntax highlighting, keyed on the highlight toke
|
|
|
368
368
|
| `fontFamily` | `string` | Font family for links. Overrides the parent block's font family when set |
|
|
369
369
|
| `color` | `string` | Link text color |
|
|
370
370
|
| `underline` | `boolean` | Show underline |
|
|
371
|
+
| `backgroundColor` | `string` | Chip background, drawn behind the link's glyphs (ascender to descender) plus padding |
|
|
372
|
+
| `borderRadius` | `number` | Chip corner radius |
|
|
373
|
+
| `paddingHorizontal` | `number` | Space added before and after the link text. It takes real room in the line, so it affects wrapping and measured size |
|
|
374
|
+
| `paddingVertical` | `number` | Extends the chip above and below the text. Drawn only: it does not change the line height, so it can overlap neighbouring lines (or be clipped at the component's top/bottom edge) if the line height is too small |
|
|
375
|
+
| `borderColor` | `string` | Chip border color |
|
|
376
|
+
| `borderWidth` | `number` | Chip border width, drawn inset (does not grow the chip) |
|
|
377
|
+
|
|
378
|
+
#### Link chips
|
|
379
|
+
|
|
380
|
+
Setting `backgroundColor`, `borderRadius`, padding or a border turns a link into a chip. When a link wraps, each line gets its own piece of the chip; only the outer ends are rounded and the border is left open where the link breaks.
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
link: {
|
|
384
|
+
color: '#3346C8',
|
|
385
|
+
underline: false,
|
|
386
|
+
backgroundColor: '#DCE2FF',
|
|
387
|
+
borderRadius: 5,
|
|
388
|
+
paddingHorizontal: 7,
|
|
389
|
+
paddingVertical: 4,
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Horizontal padding is reserved with an invisible non-breaking spacer at each end of the link, so the padding always stays attached to the text on wrap. The spacer is removed from copied text (plain, HTML, RTF, Markdown and `onCopy`) and is part of the link's tap area.
|
|
394
|
+
|
|
395
|
+
On iOS (and in RTF copies), links inside table cells fall back to a plain text background: `backgroundColor` and `paddingHorizontal` are kept (the background covers the horizontal padding), but `borderRadius`, `paddingVertical` and the border are not drawn.
|
|
396
|
+
|
|
397
|
+
Use [`renderLinkDecoration`](API_REFERENCE.md#renderlinkdecoration) to draw a React Native view on top of a chip (e.g. a badge or icon).
|
|
371
398
|
|
|
372
399
|
### Strong-specific
|
|
373
400
|
|
package/docs/TEXT.md
CHANGED
|
@@ -95,6 +95,8 @@ Links in Markdown are interactive and can be handled with the `onLinkPress` and
|
|
|
95
95
|
|
|
96
96
|
See the [API Reference](API_REFERENCE.md#onlinkpress) for detailed examples and usage.
|
|
97
97
|
|
|
98
|
+
Links can be styled as chips (background, radius, padding, border — see [Link chips](STYLES.md#link-chips)) and decorated with your own views via [`renderLinkDecoration`](API_REFERENCE.md#renderlinkdecoration).
|
|
99
|
+
|
|
98
100
|
## Supported Markdown Elements
|
|
99
101
|
|
|
100
102
|
`react-native-enriched-markdown-scaffold` supports a comprehensive set of Markdown elements. See [Element Structure](ELEMENTS_STRUCTURE.md) for a detailed overview of all supported elements, their syntax, block vs inline categorization, nesting behavior, and how elements inherit typography from their parent blocks.
|
package/docs/WEB.md
CHANGED
|
@@ -37,6 +37,7 @@ The web implementation also exports `WebMarkdownTextProps` which extends `Enrich
|
|
|
37
37
|
|---|---|
|
|
38
38
|
| `flavor` | The web renderer always uses full GFM capabilities. On native, `flavor` controls whether a single `TextView` (CommonMark) or container-based renderer (GitHub) is used; the DOM has no such constraint. |
|
|
39
39
|
| `enableLinkPreview` | iOS-only feature (native link preview on long press). |
|
|
40
|
+
| `linkLongPressSelects` | iOS-only feature (selects a link on long press instead of the link preview). |
|
|
40
41
|
| `allowFontScaling` / `maxFontSizeMultiplier` | React Native text scaling props. Browsers handle font scaling natively via OS accessibility settings. |
|
|
41
42
|
| `streamingAnimation` | Native-only tail fade-in animation. Not yet implemented on web. |
|
|
42
43
|
| `streamingConfig` | Native-only streaming table configuration. Not yet implemented on web. |
|