@apollohg/react-native-rich-text-editor 2.0.3 → 2.0.5
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/src/main/java/com/apollohg/editor/EditorCheckboxSpan.kt +8 -3
- package/android/src/main/java/com/apollohg/editor/EditorEditTextConfiguration.kt +5 -1
- package/android/src/main/java/com/apollohg/editor/EditorEditTextToolbar.kt +1 -1
- package/android/src/main/java/com/apollohg/editor/EditorMentionStyle.kt +3 -2
- package/android/src/main/java/com/apollohg/editor/EditorStyleSheet.kt +196 -8
- package/android/src/main/java/com/apollohg/editor/EditorV2Adapter.kt +7 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2Driver.kt +1 -0
- package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +48 -9
- package/android/src/main/java/com/apollohg/editor/RenderBridgeBlockStyles.kt +17 -4
- package/android/src/main/java/com/apollohg/editor/RenderBridgeElements.kt +83 -25
- package/android/src/main/java/com/apollohg/editor/RenderBridgeInlineAndAtoms.kt +28 -14
- package/android/src/main/java/com/apollohg/editor/RenderParagraphSpans.kt +5 -1
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +5 -1
- package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +141 -40
- package/dist/EditorStyleSheetNormalization.js +37 -0
- package/dist/EditorStyleSheetTypes.d.ts +22 -1
- package/dist/EditorTheme.js +4 -1
- package/dist/index.d.ts +1 -1
- package/dist/useRichTextEditorCommands.js +1 -6
- package/ios/EditorCore.xcframework/Info.plist +5 -5
- package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
- package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
- package/ios/EditorLayoutManager.swift +2 -4
- package/ios/EditorStyleSheet.swift +77 -11
- package/ios/EditorTextView+Commands.swift +1 -1
- package/ios/EditorTextView+Selection.swift +5 -2
- package/ios/EditorTextView.swift +5 -2
- package/ios/EditorTheme.swift +3 -1
- package/ios/EditorV2Adapter+Commands.swift +10 -0
- package/ios/EditorV2Shadow.swift +4 -0
- package/ios/RenderBridge+Atoms.swift +15 -6
- package/ios/RenderBridge+Style.swift +59 -17
- package/ios/RenderBridge.swift +19 -16
- package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +31 -13
- package/ios/Viewer/CoreTextProseLayoutEngine+Models.swift +17 -2
- package/ios/Viewer/CoreTextProseLayoutEngine.swift +39 -21
- package/package.json +3 -3
- package/rust/android/arm64-v8a/libeditor_core.so +0 -0
- package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
- package/rust/android/x86/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
- package/src/EditorStyleSheetNormalization.ts +50 -0
- package/src/EditorStyleSheetTypes.ts +51 -6
- package/src/EditorTheme.ts +5 -1
- package/src/index.ts +1 -0
- package/src/useRichTextEditorCommands.tsx +1 -7
|
@@ -101,14 +101,20 @@ internal fun RenderBridge.appendElements(
|
|
|
101
101
|
atomId != null,
|
|
102
102
|
state.blockStack.isEmpty(),
|
|
103
103
|
state.reusableImages,
|
|
104
|
-
state.blockStack.
|
|
104
|
+
state.blockStack.foldIndexed(EditorEdges()) { index, total, block ->
|
|
105
105
|
total +
|
|
106
106
|
(
|
|
107
|
-
theme?.styleSheet?.box(
|
|
107
|
+
theme?.styleSheet?.box(
|
|
108
|
+
block.nodeType,
|
|
109
|
+
state.blockStack.take(index).map {
|
|
110
|
+
it.nodeType
|
|
111
|
+
}
|
|
112
|
+
)?.outerInset?.scaled(density)
|
|
108
113
|
?: EditorEdges()
|
|
109
114
|
)
|
|
110
115
|
},
|
|
111
|
-
state.blockStack.size
|
|
116
|
+
state.blockStack.size,
|
|
117
|
+
state.blockStack.map { it.nodeType }
|
|
112
118
|
)
|
|
113
119
|
}
|
|
114
120
|
|
|
@@ -279,6 +285,12 @@ internal fun RenderBridge.appendElements(
|
|
|
279
285
|
}
|
|
280
286
|
|
|
281
287
|
if (markerListContext != null) {
|
|
288
|
+
val ownerIndex = state.blockStack.indexOfLast { it.listContext != null }
|
|
289
|
+
val markerAncestors = state.blockStack.take(ownerIndex + 1).map { it.nodeType }
|
|
290
|
+
val markerStyle = theme?.styleSheet?.resolveElement(
|
|
291
|
+
"listMarker",
|
|
292
|
+
markerAncestors
|
|
293
|
+
)
|
|
282
294
|
val ordered = markerListContext.optBoolean("ordered", false)
|
|
283
295
|
val isTask = markerListContext.optString("kind", "") == "task"
|
|
284
296
|
val visualListDepth = (
|
|
@@ -295,34 +307,62 @@ internal fun RenderBridge.appendElements(
|
|
|
295
307
|
OrderedListMarkerFormatter.label(
|
|
296
308
|
index,
|
|
297
309
|
visualListDepth,
|
|
298
|
-
theme?.list?.orderedMarker
|
|
310
|
+
markerStyle?.ordered ?: theme?.list?.orderedMarker
|
|
299
311
|
)
|
|
300
312
|
} else {
|
|
301
313
|
null
|
|
302
314
|
}
|
|
303
315
|
val marker = listMarkerString(markerListContext)
|
|
304
|
-
val
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
316
|
+
val markerInBlockquote = blockquoteDepth(state.blockStack) > 0
|
|
317
|
+
var markerTextStyle = theme?.styleSheet?.resolveBaseText(
|
|
318
|
+
nodeType,
|
|
319
|
+
if (markerInBlockquote) listOf("blockquote") else emptyList()
|
|
320
|
+
) ?: resolveTextStyle(
|
|
321
|
+
nodeType,
|
|
322
|
+
theme,
|
|
323
|
+
markerInBlockquote
|
|
324
|
+
)
|
|
325
|
+
theme?.styleSheet?.let { sheet ->
|
|
326
|
+
val ancestors = state.blockStack.dropLast(1).map { it.nodeType }
|
|
327
|
+
val resolved = sheet.resolveText(nodeType, ancestors)
|
|
328
|
+
markerTextStyle = markerTextStyle.copy(
|
|
329
|
+
fontSize = if (sheet.hasMatchingRuleProperty(
|
|
330
|
+
nodeType,
|
|
331
|
+
ancestors,
|
|
332
|
+
"fontSize"
|
|
333
|
+
)
|
|
334
|
+
) {
|
|
335
|
+
resolved.fontSize
|
|
336
|
+
} else {
|
|
337
|
+
markerTextStyle.fontSize
|
|
338
|
+
},
|
|
339
|
+
color = if (sheet.hasMatchingRuleProperty(
|
|
340
|
+
nodeType,
|
|
341
|
+
ancestors,
|
|
342
|
+
"color"
|
|
343
|
+
)
|
|
344
|
+
) {
|
|
345
|
+
resolved.color
|
|
346
|
+
} else {
|
|
347
|
+
markerTextStyle.color
|
|
348
|
+
}
|
|
349
|
+
)
|
|
350
|
+
}
|
|
351
|
+
val markerBaseSize = markerTextStyle.fontSize?.times(density) ?: baseFontSize
|
|
310
352
|
val resolvedMarkerBaseSize = if (isTask) {
|
|
311
353
|
markerBaseSize * LayoutConstants.TASK_LIST_MARKER_FONT_SCALE
|
|
312
354
|
} else {
|
|
313
355
|
markerBaseSize
|
|
314
356
|
}
|
|
315
|
-
val
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
blockquoteDepth(state.blockStack) > 0
|
|
319
|
-
)
|
|
357
|
+
val markerColor = markerStyle?.text?.color ?: theme?.list?.markerColor
|
|
358
|
+
?: markerTextStyle.color
|
|
359
|
+
?: textColor
|
|
320
360
|
appendStyledText(
|
|
321
361
|
state.result,
|
|
322
362
|
marker,
|
|
323
363
|
emptyList(),
|
|
324
364
|
resolvedMarkerBaseSize,
|
|
325
|
-
|
|
365
|
+
markerColor,
|
|
326
366
|
state.blockStack,
|
|
327
367
|
state.pendingLeadingMargins,
|
|
328
368
|
null,
|
|
@@ -348,7 +388,11 @@ internal fun RenderBridge.appendElements(
|
|
|
348
388
|
}
|
|
349
389
|
val checkbox = if (isTask) {
|
|
350
390
|
theme?.styleSheet?.let {
|
|
351
|
-
resolvedCheckboxStyle(
|
|
391
|
+
resolvedCheckboxStyle(
|
|
392
|
+
it,
|
|
393
|
+
markerListContext.optBoolean("checked"),
|
|
394
|
+
markerAncestors
|
|
395
|
+
)
|
|
352
396
|
}
|
|
353
397
|
} else {
|
|
354
398
|
null
|
|
@@ -367,7 +411,7 @@ internal fun RenderBridge.appendElements(
|
|
|
367
411
|
}
|
|
368
412
|
val markerGapPx =
|
|
369
413
|
(
|
|
370
|
-
checkbox?.gap ?: theme?.list?.markerGap
|
|
414
|
+
checkbox?.gap ?: markerStyle?.gap ?: theme?.list?.markerGap
|
|
371
415
|
?: LayoutConstants.LIST_MARKER_TEXT_GAP
|
|
372
416
|
) *
|
|
373
417
|
density
|
|
@@ -381,7 +425,7 @@ internal fun RenderBridge.appendElements(
|
|
|
381
425
|
}
|
|
382
426
|
if (ordered && !isTask && presentationLabel != null && marker.endsWith(' ')) {
|
|
383
427
|
state.result.setSpan(
|
|
384
|
-
OrderedListMarkerSpan(presentationLabel),
|
|
428
|
+
OrderedListMarkerSpan(presentationLabel, markerColor),
|
|
385
429
|
markerStart,
|
|
386
430
|
markerEnd - 1,
|
|
387
431
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
|
@@ -389,15 +433,19 @@ internal fun RenderBridge.appendElements(
|
|
|
389
433
|
}
|
|
390
434
|
if (!ordered && !isTask) {
|
|
391
435
|
val markerScale =
|
|
392
|
-
theme?.list?.markerScale
|
|
436
|
+
markerStyle?.scale ?: theme?.list?.markerScale
|
|
393
437
|
?: LayoutConstants.UNORDERED_LIST_MARKER_FONT_SCALE
|
|
394
|
-
val markerWidth = calculateMarkerWidth(density)
|
|
395
438
|
val bulletRadius = ((markerBaseSize * markerScale) * 0.16f).coerceAtLeast(
|
|
396
439
|
2f * density
|
|
397
440
|
)
|
|
441
|
+
val markerWidth = if (theme?.styleSheet != null) {
|
|
442
|
+
(bulletRadius * 2f) + markerGapPx
|
|
443
|
+
} else {
|
|
444
|
+
calculateMarkerWidth(density)
|
|
445
|
+
}
|
|
398
446
|
state.result.setSpan(
|
|
399
447
|
CenteredBulletSpan(
|
|
400
|
-
textColor =
|
|
448
|
+
textColor = markerColor,
|
|
401
449
|
markerWidthPx = markerWidth,
|
|
402
450
|
bulletRadiusPx = bulletRadius,
|
|
403
451
|
bodyFontSizePx = resolvedMarkerBaseSize,
|
|
@@ -420,6 +468,7 @@ internal fun RenderBridge.appendElements(
|
|
|
420
468
|
|
|
421
469
|
"blockEnd" -> {
|
|
422
470
|
if (state.blockStack.isNotEmpty()) {
|
|
471
|
+
val endedAncestors = state.blockStack.dropLast(1).map { it.nodeType }
|
|
423
472
|
val endedBlock = state.blockStack.removeAt(state.blockStack.lastIndex)
|
|
424
473
|
appendTrailingHardBreakPlaceholderIfNeeded(
|
|
425
474
|
builder = state.result,
|
|
@@ -434,9 +483,18 @@ internal fun RenderBridge.appendElements(
|
|
|
434
483
|
theme?.styleSheet?.let { sheet ->
|
|
435
484
|
val start = endedBlock.renderStart
|
|
436
485
|
if (start <= state.result.length) {
|
|
437
|
-
val ancestors = state.blockStack.
|
|
486
|
+
val ancestors = state.blockStack.foldIndexed(EditorEdges()) {
|
|
487
|
+
index,
|
|
488
|
+
total,
|
|
489
|
+
block
|
|
490
|
+
->
|
|
438
491
|
total +
|
|
439
|
-
sheet.box(
|
|
492
|
+
sheet.box(
|
|
493
|
+
block.nodeType,
|
|
494
|
+
state.blockStack.take(index).map {
|
|
495
|
+
it.nodeType
|
|
496
|
+
}
|
|
497
|
+
).outerInset.scaled(density)
|
|
440
498
|
}
|
|
441
499
|
val empty = start == state.result.length
|
|
442
500
|
val flags = if (empty) {
|
|
@@ -446,7 +504,7 @@ internal fun RenderBridge.appendElements(
|
|
|
446
504
|
}
|
|
447
505
|
state.result.setSpan(
|
|
448
506
|
EditorBlockBoxSpan(
|
|
449
|
-
sheet.box(endedBlock.nodeType).scaled(density),
|
|
507
|
+
sheet.box(endedBlock.nodeType, endedAncestors).scaled(density),
|
|
450
508
|
ancestors,
|
|
451
509
|
state.blockStack.size,
|
|
452
510
|
endedBlock.nodeType
|
|
@@ -317,7 +317,8 @@ internal fun RenderBridge.appendVoidBlock(
|
|
|
317
317
|
isDirectRootChild: Boolean,
|
|
318
318
|
reusableImages: MutableList<BlockImageSpan> = mutableListOf(),
|
|
319
319
|
ancestorBoxInset: EditorEdges = EditorEdges(),
|
|
320
|
-
containerDepth: Int = 0
|
|
320
|
+
containerDepth: Int = 0,
|
|
321
|
+
ancestors: List<String> = emptyList()
|
|
321
322
|
) {
|
|
322
323
|
if (docPos != null && atomConfiguration?.registeredNodeTypes?.contains(nodeType) == true) {
|
|
323
324
|
val start = builder.length
|
|
@@ -356,18 +357,21 @@ internal fun RenderBridge.appendVoidBlock(
|
|
|
356
357
|
val start = builder.length
|
|
357
358
|
builder.append(LayoutConstants.OBJECT_REPLACEMENT_CHARACTER)
|
|
358
359
|
val end = builder.length
|
|
359
|
-
val
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
Color.
|
|
363
|
-
|
|
364
|
-
|
|
360
|
+
val ruleStyle = theme?.styleSheet?.resolveElement("horizontalRule", ancestors)
|
|
361
|
+
val ruleBox = theme?.styleSheet?.box("horizontalRule", ancestors)
|
|
362
|
+
val ruleColor =
|
|
363
|
+
ruleStyle?.box?.backgroundColor ?: theme?.horizontalRule?.color ?: Color.argb(
|
|
364
|
+
(Color.alpha(textColor) * 0.3f).toInt(),
|
|
365
|
+
Color.red(textColor),
|
|
366
|
+
Color.green(textColor),
|
|
367
|
+
Color.blue(textColor)
|
|
368
|
+
)
|
|
365
369
|
builder.setSpan(
|
|
366
370
|
HorizontalRuleSpan(
|
|
367
371
|
lineColor = ruleColor,
|
|
368
372
|
lineHeight =
|
|
369
373
|
(
|
|
370
|
-
theme?.horizontalRule?.thickness
|
|
374
|
+
ruleStyle?.height ?: theme?.horizontalRule?.thickness
|
|
371
375
|
?: LayoutConstants.HORIZONTAL_RULE_HEIGHT
|
|
372
376
|
) *
|
|
373
377
|
density,
|
|
@@ -378,17 +382,17 @@ internal fun RenderBridge.appendVoidBlock(
|
|
|
378
382
|
) *
|
|
379
383
|
density,
|
|
380
384
|
boxInset =
|
|
381
|
-
|
|
385
|
+
ruleBox?.outerInset?.scaled(density)
|
|
382
386
|
?: EditorEdges()
|
|
383
387
|
),
|
|
384
388
|
start,
|
|
385
389
|
end,
|
|
386
390
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
|
387
391
|
)
|
|
388
|
-
|
|
392
|
+
ruleBox?.let { box ->
|
|
389
393
|
builder.setSpan(
|
|
390
394
|
EditorBlockBoxSpan(
|
|
391
|
-
|
|
395
|
+
box.scaled(density),
|
|
392
396
|
ancestorBoxInset,
|
|
393
397
|
containerDepth,
|
|
394
398
|
"horizontalRule"
|
|
@@ -417,8 +421,8 @@ internal fun RenderBridge.appendVoidBlock(
|
|
|
417
421
|
builder.append(LayoutConstants.OBJECT_REPLACEMENT_CHARACTER)
|
|
418
422
|
val end = builder.length
|
|
419
423
|
val imageStyle = theme?.styleSheet?.let {
|
|
420
|
-
it
|
|
421
|
-
?: EditorElementStyle(EditorTextStyle(), it.box("image"))
|
|
424
|
+
it.resolveElement("image", ancestors)
|
|
425
|
+
?: EditorElementStyle(EditorTextStyle(), it.box("image", ancestors))
|
|
422
426
|
}
|
|
423
427
|
val reused = reusableImages.firstOrNull {
|
|
424
428
|
it.matches(source, preferredWidthDp, preferredHeightDp)
|
|
@@ -494,7 +498,17 @@ internal fun RenderBridge.appendOpaqueInlineAtom(
|
|
|
494
498
|
)
|
|
495
499
|
)
|
|
496
500
|
builder.setSpan(
|
|
497
|
-
EditorMentionSpan(
|
|
501
|
+
EditorMentionSpan(
|
|
502
|
+
resolvedMentionStyle(
|
|
503
|
+
base,
|
|
504
|
+
theme,
|
|
505
|
+
mentionTheme,
|
|
506
|
+
blockStack.map {
|
|
507
|
+
it.nodeType
|
|
508
|
+
}
|
|
509
|
+
),
|
|
510
|
+
density
|
|
511
|
+
),
|
|
498
512
|
start,
|
|
499
513
|
end,
|
|
500
514
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
|
@@ -106,7 +106,8 @@ class MarkerGapSpan(private val widthPx: Float) : ReplacementSpan() {
|
|
|
106
106
|
) = Unit
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
internal class OrderedListMarkerSpan(internal val label: String
|
|
109
|
+
internal class OrderedListMarkerSpan(internal val label: String, private val textColor: Int) :
|
|
110
|
+
ReplacementSpan() {
|
|
110
111
|
override fun getSize(
|
|
111
112
|
paint: Paint,
|
|
112
113
|
text: CharSequence,
|
|
@@ -126,7 +127,10 @@ internal class OrderedListMarkerSpan(internal val label: String) : ReplacementSp
|
|
|
126
127
|
bottom: Int,
|
|
127
128
|
paint: Paint
|
|
128
129
|
) {
|
|
130
|
+
val previousColor = paint.color
|
|
131
|
+
paint.color = textColor
|
|
129
132
|
canvas.drawText(label, x, y.toFloat(), paint)
|
|
133
|
+
paint.color = previousColor
|
|
130
134
|
}
|
|
131
135
|
}
|
|
132
136
|
|
|
@@ -946,7 +946,11 @@ class RichTextEditorView @JvmOverloads constructor(
|
|
|
946
946
|
internal fun selectedImageSpanForResize(): BlockImageSpan? =
|
|
947
947
|
editorEditText.selectedImageSpanForResize()
|
|
948
948
|
|
|
949
|
-
internal fun previewImageResize(
|
|
949
|
+
internal fun previewImageResize(
|
|
950
|
+
span: BlockImageSpan,
|
|
951
|
+
widthPx: Float,
|
|
952
|
+
heightPx: Float
|
|
953
|
+
): Boolean {
|
|
950
954
|
if (!span.setTemporarySizePx(widthPx, heightPx)) return false
|
|
951
955
|
editorEditText.relayoutImageResizePreview(span)
|
|
952
956
|
return true
|