@apollohg/react-native-prose-editor 0.5.2 → 0.5.4

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.
@@ -77,6 +77,11 @@ class EditorEditText @JvmOverloads constructor(
77
77
  val label: String
78
78
  )
79
79
 
80
+ data class LinkHit(
81
+ val href: String,
82
+ val text: String
83
+ )
84
+
80
85
  private data class ParsedRenderPatch(
81
86
  val startIndex: Int,
82
87
  val deleteCount: Int,
@@ -1583,7 +1588,7 @@ class EditorEditText @JvmOverloads constructor(
1583
1588
  }
1584
1589
  }
1585
1590
 
1586
- fun mentionHitAt(x: Float, y: Float): MentionHit? {
1591
+ private fun textOffsetHitAt(x: Float, y: Float): Pair<Spanned, Int>? {
1587
1592
  val spannable = text as? Spanned ?: return null
1588
1593
  val layout = layout ?: return null
1589
1594
  if (spannable.isEmpty()) return null
@@ -1603,6 +1608,11 @@ class EditorEditText @JvmOverloads constructor(
1603
1608
 
1604
1609
  val offset = layout.getOffsetForHorizontal(line, localX)
1605
1610
  .coerceIn(0, maxOf(spannable.length - 1, 0))
1611
+ return spannable to offset
1612
+ }
1613
+
1614
+ fun mentionHitAt(x: Float, y: Float): MentionHit? {
1615
+ val (spannable, offset) = textOffsetHitAt(x, y) ?: return null
1606
1616
  val annotations = spannable.getSpans(
1607
1617
  offset,
1608
1618
  (offset + 1).coerceAtMost(spannable.length),
@@ -1626,6 +1636,28 @@ class EditorEditText @JvmOverloads constructor(
1626
1636
  )
1627
1637
  }
1628
1638
 
1639
+ fun linkHitAt(x: Float, y: Float): LinkHit? {
1640
+ val (spannable, offset) = textOffsetHitAt(x, y) ?: return null
1641
+ val annotations = spannable.getSpans(
1642
+ offset,
1643
+ (offset + 1).coerceAtMost(spannable.length),
1644
+ Annotation::class.java
1645
+ )
1646
+ val linkAnnotation = annotations.firstOrNull {
1647
+ it.key == RenderBridge.NATIVE_LINK_HREF_ANNOTATION && it.value.isNotBlank()
1648
+ } ?: return null
1649
+ val start = spannable.getSpanStart(linkAnnotation)
1650
+ val end = spannable.getSpanEnd(linkAnnotation)
1651
+ if (start < 0 || end <= start) {
1652
+ return null
1653
+ }
1654
+
1655
+ return LinkHit(
1656
+ href = linkAnnotation.value,
1657
+ text = spannable.subSequence(start, end).toString()
1658
+ )
1659
+ }
1660
+
1629
1661
  private fun handleImageTap(event: MotionEvent): Boolean {
1630
1662
  if (!imageResizingEnabled) {
1631
1663
  return false
@@ -55,6 +55,7 @@ data class EditorTextStyle(
55
55
 
56
56
  data class EditorListTheme(
57
57
  val indent: Float? = null,
58
+ val baseIndentMultiplier: Float? = null,
58
59
  val itemSpacing: Float? = null,
59
60
  val markerColor: Int? = null,
60
61
  val markerScale: Float? = null
@@ -64,6 +65,7 @@ data class EditorListTheme(
64
65
  json ?: return null
65
66
  return EditorListTheme(
66
67
  indent = json.optNullableFloat("indent"),
68
+ baseIndentMultiplier = json.optNullableFloat("baseIndentMultiplier"),
67
69
  itemSpacing = json.optNullableFloat("itemSpacing"),
68
70
  markerColor = parseColor(json.optNullableString("markerColor")),
69
71
  markerScale = json.optNullableFloat("markerScale")
@@ -194,6 +196,8 @@ data class EditorToolbarTheme(
194
196
  val borderColor: Int? = null,
195
197
  val borderWidth: Float? = null,
196
198
  val borderRadius: Float? = null,
199
+ val marginTop: Float? = null,
200
+ val showTopBorder: Boolean? = null,
197
201
  val keyboardOffset: Float? = null,
198
202
  val horizontalInset: Float? = null,
199
203
  val separatorColor: Int? = null,
@@ -222,6 +226,8 @@ data class EditorToolbarTheme(
222
226
  borderColor = parseColor(json.optNullableString("borderColor")),
223
227
  borderWidth = json.optNullableFloat("borderWidth"),
224
228
  borderRadius = json.optNullableFloat("borderRadius"),
229
+ marginTop = json.optNullableFloat("marginTop"),
230
+ showTopBorder = if (json.has("showTopBorder")) json.optBoolean("showTopBorder") else null,
225
231
  keyboardOffset = json.optNullableFloat("keyboardOffset"),
226
232
  horizontalInset = json.optNullableFloat("horizontalInset"),
227
233
  separatorColor = parseColor(json.optNullableString("separatorColor")),
@@ -295,6 +295,14 @@ class NativeEditorModule : Module() {
295
295
  editorDestroy(editorId)
296
296
  }
297
297
  }
298
+ Function("renderDocumentHtml") { configJson: String, html: String ->
299
+ val editorId = editorCreate(configJson)
300
+ try {
301
+ editorSetHtml(editorId, html)
302
+ } finally {
303
+ editorDestroy(editorId)
304
+ }
305
+ }
298
306
 
299
307
  View(NativeEditorExpoView::class) {
300
308
  Events(
@@ -370,7 +378,7 @@ class NativeEditorModule : Module() {
370
378
 
371
379
  View(NativeProseViewerExpoView::class) {
372
380
  Name("NativeProseViewer")
373
- Events("onContentHeightChange", "onPressMention")
381
+ Events("onContentHeightChange", "onPressLink", "onPressMention")
374
382
 
375
383
  Prop("renderJson") { view: NativeProseViewerExpoView, renderJson: String? ->
376
384
  view.setRenderJson(renderJson)
@@ -378,6 +386,17 @@ class NativeEditorModule : Module() {
378
386
  Prop("themeJson") { view: NativeProseViewerExpoView, themeJson: String? ->
379
387
  view.setThemeJson(themeJson)
380
388
  }
389
+ Prop("collapsesWhenEmpty") {
390
+ view: NativeProseViewerExpoView,
391
+ collapsesWhenEmpty: Boolean? ->
392
+ view.setCollapsesWhenEmpty(collapsesWhenEmpty)
393
+ }
394
+ Prop("enableLinkTaps") { view: NativeProseViewerExpoView, enableLinkTaps: Boolean? ->
395
+ view.setEnableLinkTaps(enableLinkTaps)
396
+ }
397
+ Prop("interceptLinkTaps") { view: NativeProseViewerExpoView, interceptLinkTaps: Boolean? ->
398
+ view.setInterceptLinkTaps(interceptLinkTaps)
399
+ }
381
400
  }
382
401
  }
383
402
  }
@@ -1,13 +1,16 @@
1
1
  package com.apollohg.editor
2
2
 
3
+ import android.content.Intent
3
4
  import android.content.Context
4
5
  import android.graphics.Color
6
+ import android.net.Uri
5
7
  import android.view.MotionEvent
6
8
  import android.view.View
7
9
  import android.view.ViewGroup
8
10
  import expo.modules.kotlin.AppContext
9
11
  import expo.modules.kotlin.viewevent.EventDispatcher
10
12
  import expo.modules.kotlin.views.ExpoView
13
+ import org.json.JSONArray
11
14
 
12
15
  class NativeProseViewerExpoView(
13
16
  context: Context,
@@ -17,11 +20,17 @@ class NativeProseViewerExpoView(
17
20
  private val proseView = EditorEditText(context)
18
21
  private val onContentHeightChange by EventDispatcher<Map<String, Any>>()
19
22
  @Suppress("unused")
23
+ private val onPressLink by EventDispatcher<Map<String, Any>>()
24
+ @Suppress("unused")
20
25
  private val onPressMention by EventDispatcher<Map<String, Any>>()
21
26
 
22
27
  private var lastRenderJson: String? = null
23
28
  private var lastThemeJson: String? = null
24
29
  private var lastEmittedContentHeight = 0
30
+ private var collapsesWhenEmpty = true
31
+ private var isCollapsedEmptyContent = false
32
+ private var enableLinkTaps = true
33
+ private var interceptLinkTaps = false
25
34
 
26
35
  init {
27
36
  proseView.setBaseStyle(
@@ -43,14 +52,27 @@ class NativeProseViewerExpoView(
43
52
  return@setOnTouchListener false
44
53
  }
45
54
 
46
- val mention = proseView.mentionHitAt(event.x, event.y) ?: return@setOnTouchListener false
47
- onPressMention(
48
- mapOf(
49
- "docPos" to mention.docPos,
50
- "label" to mention.label
55
+ proseView.mentionHitAt(event.x, event.y)?.let { mention ->
56
+ onPressMention(mapOf("docPos" to mention.docPos, "label" to mention.label))
57
+ return@setOnTouchListener true
58
+ }
59
+
60
+ if (!enableLinkTaps) {
61
+ return@setOnTouchListener false
62
+ }
63
+
64
+ val link = proseView.linkHitAt(event.x, event.y) ?: return@setOnTouchListener false
65
+ if (interceptLinkTaps) {
66
+ onPressLink(
67
+ mapOf(
68
+ "href" to link.href,
69
+ "text" to link.text
70
+ )
51
71
  )
52
- )
53
- true
72
+ return@setOnTouchListener true
73
+ }
74
+
75
+ return@setOnTouchListener openLink(link.href)
54
76
  }
55
77
 
56
78
  addView(
@@ -65,7 +87,7 @@ class NativeProseViewerExpoView(
65
87
  fun setRenderJson(renderJson: String?) {
66
88
  if (lastRenderJson == renderJson) return
67
89
  lastRenderJson = renderJson
68
- proseView.applyRenderJSON(renderJson ?: "[]")
90
+ applyRenderJson()
69
91
  post {
70
92
  requestLayout()
71
93
  emitContentHeightIfNeeded(force = true)
@@ -76,14 +98,36 @@ class NativeProseViewerExpoView(
76
98
  if (lastThemeJson == themeJson) return
77
99
  lastThemeJson = themeJson
78
100
  proseView.applyTheme(EditorTheme.fromJson(themeJson))
79
- proseView.applyRenderJSON(lastRenderJson ?: "[]")
101
+ applyRenderJson()
80
102
  post {
81
103
  requestLayout()
82
104
  emitContentHeightIfNeeded(force = true)
83
105
  }
84
106
  }
85
107
 
108
+ fun setCollapsesWhenEmpty(collapsesWhenEmpty: Boolean?) {
109
+ val nextValue = collapsesWhenEmpty ?: true
110
+ if (this.collapsesWhenEmpty == nextValue) return
111
+ this.collapsesWhenEmpty = nextValue
112
+ updateCollapsedEmptyState()
113
+ requestLayout()
114
+ emitContentHeightIfNeeded(force = true)
115
+ }
116
+
117
+ fun setEnableLinkTaps(enableLinkTaps: Boolean?) {
118
+ this.enableLinkTaps = enableLinkTaps ?: true
119
+ }
120
+
121
+ fun setInterceptLinkTaps(interceptLinkTaps: Boolean?) {
122
+ this.interceptLinkTaps = interceptLinkTaps ?: false
123
+ }
124
+
86
125
  override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
126
+ if (isCollapsedEmptyContent) {
127
+ setMeasuredDimension(resolveSize(0, widthMeasureSpec), 0)
128
+ return
129
+ }
130
+
87
131
  val childWidthSpec = getChildMeasureSpec(
88
132
  widthMeasureSpec,
89
133
  paddingLeft + paddingRight,
@@ -104,6 +148,12 @@ class NativeProseViewerExpoView(
104
148
  }
105
149
 
106
150
  override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
151
+ if (isCollapsedEmptyContent) {
152
+ proseView.layout(paddingLeft, paddingTop, right - left - paddingRight, paddingTop)
153
+ emitContentHeightIfNeeded()
154
+ return
155
+ }
156
+
107
157
  val childLeft = paddingLeft
108
158
  val childTop = paddingTop
109
159
  proseView.layout(
@@ -115,10 +165,25 @@ class NativeProseViewerExpoView(
115
165
  emitContentHeightIfNeeded()
116
166
  }
117
167
 
168
+ private fun applyRenderJson() {
169
+ updateCollapsedEmptyState()
170
+ proseView.applyRenderJSON(lastRenderJson ?: "[]")
171
+ proseView.visibility = if (isCollapsedEmptyContent) View.GONE else View.VISIBLE
172
+ }
173
+
174
+ private fun updateCollapsedEmptyState() {
175
+ isCollapsedEmptyContent = collapsesWhenEmpty &&
176
+ renderJsonContainsOnlyEmptyParagraphs(lastRenderJson ?: "[]")
177
+ proseView.visibility = if (isCollapsedEmptyContent) View.GONE else View.VISIBLE
178
+ }
179
+
118
180
  private fun emitContentHeightIfNeeded(force: Boolean = false) {
119
- val contentHeight = (measureContentHeightPx() + paddingTop + paddingBottom)
120
- .coerceAtLeast(0)
121
- if (contentHeight <= 0) {
181
+ val contentHeight = if (isCollapsedEmptyContent) {
182
+ 0
183
+ } else {
184
+ (measureContentHeightPx() + paddingTop + paddingBottom).coerceAtLeast(0)
185
+ }
186
+ if (contentHeight <= 0 && !isCollapsedEmptyContent) {
122
187
  return
123
188
  }
124
189
  if (!force && contentHeight == lastEmittedContentHeight) {
@@ -129,6 +194,10 @@ class NativeProseViewerExpoView(
129
194
  }
130
195
 
131
196
  private fun measureContentHeightPx(): Int {
197
+ if (isCollapsedEmptyContent) {
198
+ return 0
199
+ }
200
+
132
201
  val currentMeasuredHeight = proseView.measuredHeight
133
202
  if (currentMeasuredHeight > 0 && proseView.layout != null) {
134
203
  return currentMeasuredHeight
@@ -154,4 +223,71 @@ class NativeProseViewerExpoView(
154
223
 
155
224
  return (resources.displayMetrics.widthPixels - paddingLeft - paddingRight).coerceAtLeast(1)
156
225
  }
226
+
227
+ private fun openLink(href: String): Boolean {
228
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(href)).apply {
229
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
230
+ }
231
+ return runCatching {
232
+ context.startActivity(intent)
233
+ true
234
+ }.getOrDefault(false)
235
+ }
236
+
237
+ companion object {
238
+ private const val EMPTY_TEXT_BLOCK_PLACEHOLDER = '\u200B'
239
+
240
+ internal fun renderJsonContainsOnlyEmptyParagraphs(renderJson: String): Boolean {
241
+ val elements = try {
242
+ JSONArray(renderJson)
243
+ } catch (_: Exception) {
244
+ return false
245
+ }
246
+
247
+ if (elements.length() == 0) {
248
+ return true
249
+ }
250
+
251
+ var hasParagraph = false
252
+ var paragraphIsOpen = false
253
+
254
+ for (index in 0 until elements.length()) {
255
+ val element = elements.optJSONObject(index) ?: return false
256
+ when (element.optString("type", "")) {
257
+ "blockStart" -> {
258
+ if (
259
+ paragraphIsOpen ||
260
+ element.optString("nodeType", "") != "paragraph" ||
261
+ element.optInt("depth", 0) != 0
262
+ ) {
263
+ return false
264
+ }
265
+ paragraphIsOpen = true
266
+ hasParagraph = true
267
+ }
268
+
269
+ "textRun" -> {
270
+ val text = element.optString("text", "")
271
+ if (
272
+ !paragraphIsOpen ||
273
+ !text.all { it == EMPTY_TEXT_BLOCK_PLACEHOLDER }
274
+ ) {
275
+ return false
276
+ }
277
+ }
278
+
279
+ "blockEnd" -> {
280
+ if (!paragraphIsOpen) {
281
+ return false
282
+ }
283
+ paragraphIsOpen = false
284
+ }
285
+
286
+ else -> return false
287
+ }
288
+ }
289
+
290
+ return hasParagraph && !paragraphIsOpen
291
+ }
292
+ }
157
293
  }
@@ -752,6 +752,7 @@ class CenteredBulletSpan(
752
752
  object RenderBridge {
753
753
  internal const val NATIVE_BLOCKQUOTE_ANNOTATION = "nativeBlockquote"
754
754
  internal const val NATIVE_TOP_LEVEL_CHILD_INDEX_ANNOTATION = "nativeTopLevelChildIndex"
755
+ internal const val NATIVE_LINK_HREF_ANNOTATION = "nativeLinkHref"
755
756
  private const val NATIVE_SYNTHETIC_PLACEHOLDER_ANNOTATION = "nativeSyntheticPlaceholder"
756
757
 
757
758
  private data class RenderBuildState(
@@ -1174,6 +1175,15 @@ object RenderBridge {
1174
1175
  end,
1175
1176
  Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
1176
1177
  )
1178
+ val href = mark.optString("href", "")
1179
+ if (href.isNotBlank()) {
1180
+ builder.setSpan(
1181
+ Annotation(NATIVE_LINK_HREF_ANNOTATION, href),
1182
+ start,
1183
+ end,
1184
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
1185
+ )
1186
+ }
1177
1187
  }
1178
1188
  }
1179
1189
  }
@@ -1455,6 +1465,9 @@ object RenderBridge {
1455
1465
  val indent = calculateIndent(currentBlock, blockStack, theme, density)
1456
1466
  val markerWidth = calculateMarkerWidth(density)
1457
1467
  val quoteDepth = blockquoteDepth(blockStack)
1468
+ val indentPerDepth = (theme?.list?.indent ?: LayoutConstants.INDENT_PER_DEPTH) * density
1469
+ val listBaseIndentAdjustment =
1470
+ calculateListBaseIndentAdjustment(currentBlock, theme, density)
1458
1471
  val quoteStripeColor = if (quoteDepth > 0) {
1459
1472
  theme?.blockquote?.borderColor ?: Color.argb(
1460
1473
  (Color.alpha(resolveInlineTextColor(blockStack, Color.BLACK, theme)) * 0.3f).toInt(),
@@ -1476,8 +1489,9 @@ object RenderBridge {
1476
1489
  ) * density
1477
1490
  val blockquoteIndentPx = (quoteDepth * quoteIndent).toInt()
1478
1491
  val quoteBaseIndent = if (quoteDepth > 0) {
1479
- ((currentBlock.depth * ((theme?.list?.indent ?: LayoutConstants.INDENT_PER_DEPTH) * density))
1480
- - (quoteDepth * ((theme?.list?.indent ?: LayoutConstants.INDENT_PER_DEPTH) * density))
1492
+ ((currentBlock.depth * indentPerDepth)
1493
+ - (quoteDepth * indentPerDepth)
1494
+ + listBaseIndentAdjustment
1481
1495
  + ((quoteDepth - 1f) * quoteIndent)).toInt()
1482
1496
  } else {
1483
1497
  0
@@ -1656,7 +1670,25 @@ object RenderBridge {
1656
1670
  (theme?.blockquote?.markerGap ?: LayoutConstants.BLOCKQUOTE_MARKER_GAP) +
1657
1671
  (theme?.blockquote?.borderWidth ?: LayoutConstants.BLOCKQUOTE_BORDER_WIDTH)
1658
1672
  ) * density
1659
- return (context.depth * indentPerDepth) - (quoteDepth * indentPerDepth) + (quoteDepth * quoteIndent)
1673
+ val listBaseIndentAdjustment = calculateListBaseIndentAdjustment(context, theme, density)
1674
+ return (context.depth * indentPerDepth) -
1675
+ (quoteDepth * indentPerDepth) +
1676
+ listBaseIndentAdjustment +
1677
+ (quoteDepth * quoteIndent)
1678
+ }
1679
+
1680
+ private fun calculateListBaseIndentAdjustment(
1681
+ context: BlockContext,
1682
+ theme: EditorTheme?,
1683
+ density: Float
1684
+ ): Float {
1685
+ if (context.listContext == null) {
1686
+ return 0f
1687
+ }
1688
+
1689
+ val indentPerDepth = (theme?.list?.indent ?: LayoutConstants.INDENT_PER_DEPTH) * density
1690
+ val listBaseIndentMultiplier = maxOf(theme?.list?.baseIndentMultiplier ?: 1f, 0f)
1691
+ return (listBaseIndentMultiplier - 1f) * indentPerDepth
1660
1692
  }
1661
1693
 
1662
1694
  private fun effectiveBlockContext(blockStack: List<BlockContext>): BlockContext? {
@@ -36,6 +36,7 @@ export interface EditorHeadingTheme {
36
36
  }
37
37
  export interface EditorListTheme {
38
38
  indent?: number;
39
+ baseIndentMultiplier?: number;
39
40
  itemSpacing?: number;
40
41
  markerColor?: string;
41
42
  markerScale?: number;
@@ -59,6 +60,8 @@ export interface EditorToolbarTheme {
59
60
  borderColor?: string;
60
61
  borderWidth?: number;
61
62
  borderRadius?: number;
63
+ marginTop?: number;
64
+ showTopBorder?: boolean;
62
65
  keyboardOffset?: number;
63
66
  horizontalInset?: number;
64
67
  separatorColor?: string;
@@ -109,7 +109,7 @@ const DEFAULT_MATERIAL_ICONS = {
109
109
  undo: 'undo',
110
110
  redo: 'redo',
111
111
  };
112
- function EditorToolbar({ activeState, historyState, onToggleBold, onToggleItalic, onToggleUnderline, onToggleStrike, onToggleBulletList, onToggleHeading, onToggleBlockquote, onToggleOrderedList, onIndentList, onOutdentList, onInsertHorizontalRule, onInsertLineBreak, onUndo, onRedo, onToggleMark, onToggleListType, onInsertNodeType, onRunCommand, onToolbarAction, onRequestLink, onRequestImage, toolbarItems = exports.DEFAULT_EDITOR_TOOLBAR_ITEMS, theme, showTopBorder = true, }) {
112
+ function EditorToolbar({ activeState, historyState, onToggleBold, onToggleItalic, onToggleUnderline, onToggleStrike, onToggleBulletList, onToggleHeading, onToggleBlockquote, onToggleOrderedList, onIndentList, onOutdentList, onInsertHorizontalRule, onInsertLineBreak, onUndo, onRedo, onToggleMark, onToggleListType, onInsertNodeType, onRunCommand, onToolbarAction, onRequestLink, onRequestImage, toolbarItems = exports.DEFAULT_EDITOR_TOOLBAR_ITEMS, theme, showTopBorder, }) {
113
113
  const marks = activeState.marks ?? {};
114
114
  const nodes = activeState.nodes ?? {};
115
115
  const commands = activeState.commands ?? {};
@@ -371,6 +371,7 @@ function EditorToolbar({ activeState, historyState, onToggleBold, onToggleItalic
371
371
  groupsByKey: nextGroups,
372
372
  };
373
373
  }, [expandedGroupKey, menuState?.groupKey, resolveButton, toolbarItems]);
374
+ const resolvedShowTopBorder = showTopBorder ?? theme?.showTopBorder ?? true;
374
375
  (0, react_1.useEffect)(() => {
375
376
  if (expandedGroupKey != null && !groupsByKey.has(expandedGroupKey)) {
376
377
  setExpandedGroupKey(null);
@@ -414,7 +415,7 @@ function EditorToolbar({ activeState, historyState, onToggleBold, onToggleItalic
414
415
  });
415
416
  });
416
417
  }, []);
417
- const menuGroup = menuState != null ? groupsByKey.get(menuState.groupKey) ?? null : null;
418
+ const menuGroup = menuState != null ? (groupsByKey.get(menuState.groupKey) ?? null) : null;
418
419
  const menuHeight = menuGroup ? menuGroup.children.length * 40 + 16 : 0;
419
420
  const menuTop = menuState == null
420
421
  ? 0
@@ -426,7 +427,11 @@ function EditorToolbar({ activeState, historyState, onToggleBold, onToggleItalic
426
427
  const activeColor = theme?.buttonActiveColor ?? ACTIVE_COLOR;
427
428
  const defaultColor = theme?.buttonColor ?? DEFAULT_COLOR;
428
429
  const disabledColor = theme?.buttonDisabledColor ?? DISABLED_COLOR;
429
- const color = button.isActive ? activeColor : button.isDisabled ? disabledColor : defaultColor;
430
+ const color = button.isActive
431
+ ? activeColor
432
+ : button.isDisabled
433
+ ? disabledColor
434
+ : defaultColor;
430
435
  const anchorGroupKey = options?.anchorGroupKey;
431
436
  return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { ref: anchorGroupKey == null
432
437
  ? undefined
@@ -457,15 +462,15 @@ function EditorToolbar({ activeState, historyState, onToggleBold, onToggleItalic
457
462
  ] }, key));
458
463
  return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
459
464
  styles.container,
460
- !showTopBorder && styles.containerWithoutTopBorder,
465
+ !resolvedShowTopBorder && styles.containerWithoutTopBorder,
461
466
  theme?.backgroundColor != null ? { backgroundColor: theme.backgroundColor } : null,
462
467
  theme?.borderColor != null
463
- ? showTopBorder
468
+ ? resolvedShowTopBorder
464
469
  ? { borderTopColor: theme.borderColor }
465
470
  : null
466
471
  : null,
467
472
  theme?.borderWidth != null
468
- ? showTopBorder
473
+ ? resolvedShowTopBorder
469
474
  ? { borderTopWidth: theme.borderWidth }
470
475
  : null
471
476
  : null,
@@ -9,17 +9,33 @@ export interface NativeProseViewerMentionRenderContext {
9
9
  }
10
10
  export interface NativeProseViewerMentionPressEvent extends NativeProseViewerMentionRenderContext {
11
11
  }
12
+ export interface NativeProseViewerLinkPressEvent {
13
+ href: string;
14
+ text: string;
15
+ }
12
16
  type NativeProseViewerContent = DocumentJSON | string;
13
- export interface NativeProseViewerProps {
14
- contentJSON: NativeProseViewerContent;
17
+ interface NativeProseViewerBaseProps {
18
+ contentRevision?: string | number;
15
19
  contentJSONRevision?: string | number;
16
20
  schema?: SchemaDefinition;
17
21
  theme?: EditorTheme;
18
22
  style?: StyleProp<ViewStyle>;
19
23
  allowBase64Images?: boolean;
24
+ collapseTrailingEmptyParagraphs?: boolean;
25
+ enableLinkTaps?: boolean;
20
26
  mentionPrefix?: string | ((mention: NativeProseViewerMentionRenderContext) => string | null | undefined);
21
27
  resolveMentionTheme?: (mention: NativeProseViewerMentionRenderContext) => EditorMentionTheme | null | undefined;
28
+ onPressLink?: (event: NativeProseViewerLinkPressEvent) => void;
22
29
  onPressMention?: (event: NativeProseViewerMentionPressEvent) => void;
23
30
  }
24
- export declare function NativeProseViewer({ contentJSON, contentJSONRevision, schema, theme, style, allowBase64Images, mentionPrefix, resolveMentionTheme, onPressMention, }: NativeProseViewerProps): import("react/jsx-runtime").JSX.Element;
31
+ interface NativeProseViewerJsonProps extends NativeProseViewerBaseProps {
32
+ contentJSON: NativeProseViewerContent;
33
+ contentHTML?: never;
34
+ }
35
+ interface NativeProseViewerHtmlProps extends NativeProseViewerBaseProps {
36
+ contentHTML: string;
37
+ contentJSON?: never;
38
+ }
39
+ export type NativeProseViewerProps = NativeProseViewerJsonProps | NativeProseViewerHtmlProps;
40
+ export declare function NativeProseViewer({ ...props }: NativeProseViewerProps): import("react/jsx-runtime").JSX.Element;
25
41
  export {};