@apollohg/react-native-prose-editor 0.5.10 → 0.5.12
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/EditorEditText.kt +14 -2
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +208 -27
- package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +4 -0
- package/android/src/main/java/com/apollohg/editor/NativeToolbar.kt +2 -1
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +10 -0
- package/dist/EditorToolbar.d.ts +18 -1
- package/dist/EditorToolbar.js +192 -4
- package/dist/NativeRichTextEditor.d.ts +16 -0
- package/dist/NativeRichTextEditor.js +89 -13
- package/dist/index.d.ts +1 -1
- 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/NativeEditorExpoView.swift +70 -8
- package/ios/NativeEditorModule.swift +3 -0
- package/ios/RichTextEditorView.swift +7 -0
- package/package.json +1 -1
- package/rust/android/arm64-v8a/libeditor_core.so +0 -0
- package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
- package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +1892 -1391
|
@@ -551,6 +551,18 @@ class EditorEditText @JvmOverloads constructor(
|
|
|
551
551
|
}
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
+
internal fun caretRect(): RectF? {
|
|
555
|
+
val textLayout = layout ?: return null
|
|
556
|
+
val selectionOffset = selectionEnd.takeIf { it >= 0 } ?: return null
|
|
557
|
+
val clampedOffset = selectionOffset.coerceIn(0, textLayout.text.length)
|
|
558
|
+
val line = textLayout.getLineForOffset(clampedOffset)
|
|
559
|
+
val caretLeft = textLayout.getPrimaryHorizontal(clampedOffset)
|
|
560
|
+
val left = totalPaddingLeft + caretLeft - scrollX
|
|
561
|
+
val top = totalPaddingTop + textLayout.getLineTop(line) - scrollY
|
|
562
|
+
val bottom = totalPaddingTop + textLayout.getLineBottom(line) - scrollY
|
|
563
|
+
return RectF(left, top.toFloat(), left + 1f, bottom.toFloat())
|
|
564
|
+
}
|
|
565
|
+
|
|
554
566
|
// ── Input Handling: Text Commit ─────────────────────────────────────
|
|
555
567
|
|
|
556
568
|
/**
|
|
@@ -657,7 +669,7 @@ class EditorEditText @JvmOverloads constructor(
|
|
|
657
669
|
cursor > 0 &&
|
|
658
670
|
currentText.getOrNull(cursor - 1) == EMPTY_BLOCK_PLACEHOLDER
|
|
659
671
|
) {
|
|
660
|
-
val scalarCursor = PositionBridge.utf16ToScalar(cursor
|
|
672
|
+
val scalarCursor = PositionBridge.utf16ToScalar(cursor, currentText)
|
|
661
673
|
deleteBackwardAtSelectionScalarInRust(scalarCursor, scalarCursor)
|
|
662
674
|
return
|
|
663
675
|
}
|
|
@@ -710,7 +722,7 @@ class EditorEditText @JvmOverloads constructor(
|
|
|
710
722
|
deleteRangeInRust(scalarStart, scalarEnd)
|
|
711
723
|
} else if (start > 0) {
|
|
712
724
|
if (currentText.getOrNull(start - 1) == EMPTY_BLOCK_PLACEHOLDER) {
|
|
713
|
-
val scalarCursor = PositionBridge.utf16ToScalar(start
|
|
725
|
+
val scalarCursor = PositionBridge.utf16ToScalar(start, currentText)
|
|
714
726
|
deleteBackwardAtSelectionScalarInRust(scalarCursor, scalarCursor)
|
|
715
727
|
return
|
|
716
728
|
}
|
|
@@ -5,6 +5,7 @@ import android.content.Context
|
|
|
5
5
|
import android.content.ContextWrapper
|
|
6
6
|
import android.graphics.Rect
|
|
7
7
|
import android.graphics.RectF
|
|
8
|
+
import android.os.SystemClock
|
|
8
9
|
import android.view.Gravity
|
|
9
10
|
import android.view.MotionEvent
|
|
10
11
|
import android.view.View
|
|
@@ -61,7 +62,10 @@ class NativeEditorExpoView(
|
|
|
61
62
|
private var lastEmittedContentHeight = 0
|
|
62
63
|
private var outsideTapWindowCallback: Window.Callback? = null
|
|
63
64
|
private var previousWindowCallback: Window.Callback? = null
|
|
64
|
-
private var
|
|
65
|
+
private var toolbarFramesInWindow: List<RectF> = emptyList()
|
|
66
|
+
private var lastToolbarTouchUptimeMs: Long? = null
|
|
67
|
+
private var pendingOutsideTapBlur: Runnable? = null
|
|
68
|
+
private var pendingKeyboardDismiss: Runnable? = null
|
|
65
69
|
private var addons = NativeEditorAddons(null)
|
|
66
70
|
private var mentionQueryState: MentionQueryState? = null
|
|
67
71
|
private var lastMentionEventJson: String? = null
|
|
@@ -91,7 +95,7 @@ class NativeEditorExpoView(
|
|
|
91
95
|
ViewCompat.setOnApplyWindowInsetsListener(keyboardToolbarView) { _, insets ->
|
|
92
96
|
currentImeBottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
|
|
93
97
|
updateKeyboardToolbarLayout()
|
|
94
|
-
|
|
98
|
+
updateAttachedKeyboardToolbarForInsets()
|
|
95
99
|
insets
|
|
96
100
|
}
|
|
97
101
|
|
|
@@ -101,6 +105,12 @@ class NativeEditorExpoView(
|
|
|
101
105
|
installOutsideTapBlurHandlerIfNeeded()
|
|
102
106
|
refreshMentionQuery()
|
|
103
107
|
} else {
|
|
108
|
+
if (shouldPreserveFocusAfterToolbarTouch()) {
|
|
109
|
+
richTextView.editorEditText.post {
|
|
110
|
+
focus()
|
|
111
|
+
}
|
|
112
|
+
return@setOnFocusChangeListener
|
|
113
|
+
}
|
|
104
114
|
uninstallOutsideTapBlurHandler()
|
|
105
115
|
clearMentionQueryState()
|
|
106
116
|
}
|
|
@@ -195,23 +205,52 @@ class NativeEditorExpoView(
|
|
|
195
205
|
if (lastToolbarFrameJson == toolbarFrameJson) return
|
|
196
206
|
lastToolbarFrameJson = toolbarFrameJson
|
|
197
207
|
if (toolbarFrameJson.isNullOrBlank()) {
|
|
198
|
-
|
|
208
|
+
toolbarFramesInWindow = emptyList()
|
|
199
209
|
return
|
|
200
210
|
}
|
|
201
211
|
|
|
202
|
-
|
|
212
|
+
toolbarFramesInWindow = try {
|
|
203
213
|
val json = JSONObject(toolbarFrameJson)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
val frames = json.optJSONArray("frames")
|
|
215
|
+
if (frames != null) {
|
|
216
|
+
buildList {
|
|
217
|
+
for (index in 0 until frames.length()) {
|
|
218
|
+
frames.optJSONObject(index)?.toToolbarFrame()?.let { add(it) }
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
listOfNotNull(json.toToolbarFrame())
|
|
223
|
+
}
|
|
210
224
|
} catch (_: Throwable) {
|
|
211
|
-
|
|
225
|
+
emptyList()
|
|
212
226
|
}
|
|
213
227
|
}
|
|
214
228
|
|
|
229
|
+
private fun JSONObject.toToolbarFrame(): RectF? {
|
|
230
|
+
val x = optDouble("x", Double.NaN)
|
|
231
|
+
val y = optDouble("y", Double.NaN)
|
|
232
|
+
val width = optDouble("width", Double.NaN)
|
|
233
|
+
val height = optDouble("height", Double.NaN)
|
|
234
|
+
if (
|
|
235
|
+
x.isNaN() || x.isInfinite() ||
|
|
236
|
+
y.isNaN() || y.isInfinite() ||
|
|
237
|
+
width.isNaN() || width.isInfinite() ||
|
|
238
|
+
height.isNaN() || height.isInfinite()
|
|
239
|
+
) {
|
|
240
|
+
return null
|
|
241
|
+
}
|
|
242
|
+
if (width <= 0.0 || height <= 0.0) {
|
|
243
|
+
return null
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return RectF(
|
|
247
|
+
x.toFloat(),
|
|
248
|
+
y.toFloat(),
|
|
249
|
+
(x + width).toFloat(),
|
|
250
|
+
(y + height).toFloat()
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
|
|
215
254
|
fun setPendingEditorUpdateJson(editorUpdateJson: String?) {
|
|
216
255
|
pendingEditorUpdateJson = editorUpdateJson
|
|
217
256
|
}
|
|
@@ -229,17 +268,83 @@ class NativeEditorExpoView(
|
|
|
229
268
|
}
|
|
230
269
|
|
|
231
270
|
fun focus() {
|
|
271
|
+
cancelPendingOutsideTapBlur()
|
|
272
|
+
cancelPendingKeyboardDismiss()
|
|
232
273
|
richTextView.editorEditText.requestFocus()
|
|
274
|
+
richTextView.editorEditText.post {
|
|
275
|
+
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
|
276
|
+
imm?.showSoftInput(richTextView.editorEditText, InputMethodManager.SHOW_IMPLICIT)
|
|
277
|
+
}
|
|
233
278
|
}
|
|
234
279
|
|
|
235
280
|
fun blur() {
|
|
281
|
+
cancelPendingOutsideTapBlur()
|
|
282
|
+
cancelPendingKeyboardDismiss()
|
|
283
|
+
clearRecentToolbarTouch()
|
|
236
284
|
richTextView.editorEditText.clearFocus()
|
|
237
285
|
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
|
238
286
|
imm?.hideSoftInputFromWindow(richTextView.editorEditText.windowToken, 0)
|
|
239
287
|
}
|
|
240
288
|
|
|
289
|
+
private fun blurWithDeferredKeyboardDismiss() {
|
|
290
|
+
cancelPendingKeyboardDismiss()
|
|
291
|
+
clearRecentToolbarTouch()
|
|
292
|
+
richTextView.editorEditText.clearFocus()
|
|
293
|
+
val dismiss = Runnable {
|
|
294
|
+
pendingKeyboardDismiss = null
|
|
295
|
+
if (!richTextView.editorEditText.hasFocus()) {
|
|
296
|
+
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
|
297
|
+
imm?.hideSoftInputFromWindow(richTextView.editorEditText.windowToken, 0)
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
pendingKeyboardDismiss = dismiss
|
|
301
|
+
richTextView.editorEditText.post(dismiss)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
private fun scheduleOutsideTapBlur() {
|
|
305
|
+
cancelPendingOutsideTapBlur()
|
|
306
|
+
val blur = Runnable {
|
|
307
|
+
pendingOutsideTapBlur = null
|
|
308
|
+
if (richTextView.editorEditText.hasFocus()) {
|
|
309
|
+
blurWithDeferredKeyboardDismiss()
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
pendingOutsideTapBlur = blur
|
|
313
|
+
richTextView.editorEditText.postDelayed(blur, OUTSIDE_TAP_BLUR_DELAY_MS)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private fun cancelPendingOutsideTapBlur() {
|
|
317
|
+
pendingOutsideTapBlur?.let {
|
|
318
|
+
richTextView.editorEditText.removeCallbacks(it)
|
|
319
|
+
pendingOutsideTapBlur = null
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private fun cancelPendingKeyboardDismiss() {
|
|
324
|
+
pendingKeyboardDismiss?.let {
|
|
325
|
+
richTextView.editorEditText.removeCallbacks(it)
|
|
326
|
+
pendingKeyboardDismiss = null
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
fun getCaretRectJson(): String? {
|
|
331
|
+
if (width <= 0 || height <= 0) return null
|
|
332
|
+
val rect = richTextView.caretRect() ?: return null
|
|
333
|
+
val density = resources.displayMetrics.density
|
|
334
|
+
return JSONObject()
|
|
335
|
+
.put("x", rect.left / density)
|
|
336
|
+
.put("y", rect.top / density)
|
|
337
|
+
.put("width", rect.width() / density)
|
|
338
|
+
.put("height", rect.height() / density)
|
|
339
|
+
.put("editorWidth", width / density)
|
|
340
|
+
.put("editorHeight", height / density)
|
|
341
|
+
.toString()
|
|
342
|
+
}
|
|
343
|
+
|
|
241
344
|
override fun onDetachedFromWindow() {
|
|
242
345
|
super.onDetachedFromWindow()
|
|
346
|
+
cancelPendingOutsideTapBlur()
|
|
347
|
+
cancelPendingKeyboardDismiss()
|
|
243
348
|
uninstallOutsideTapBlurHandler()
|
|
244
349
|
detachKeyboardToolbarIfNeeded()
|
|
245
350
|
}
|
|
@@ -374,14 +479,17 @@ class NativeEditorExpoView(
|
|
|
374
479
|
|
|
375
480
|
val wrappedCallback = object : Window.Callback by currentCallback {
|
|
376
481
|
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
377
|
-
|
|
482
|
+
val shouldBlur =
|
|
378
483
|
event.action == MotionEvent.ACTION_DOWN &&
|
|
379
484
|
richTextView.editorEditText.hasFocus() &&
|
|
380
485
|
isTouchOutsideEditor(event)
|
|
381
|
-
)
|
|
382
|
-
|
|
486
|
+
val result = currentCallback.dispatchTouchEvent(event)
|
|
487
|
+
if (shouldBlur) {
|
|
488
|
+
scheduleOutsideTapBlur()
|
|
489
|
+
} else if (event.action == MotionEvent.ACTION_DOWN) {
|
|
490
|
+
cancelPendingOutsideTapBlur()
|
|
383
491
|
}
|
|
384
|
-
return
|
|
492
|
+
return result
|
|
385
493
|
}
|
|
386
494
|
}
|
|
387
495
|
|
|
@@ -402,26 +510,88 @@ class NativeEditorExpoView(
|
|
|
402
510
|
|
|
403
511
|
private fun isTouchOutsideEditor(event: MotionEvent): Boolean {
|
|
404
512
|
if (isTouchInsideKeyboardToolbar(event)) {
|
|
513
|
+
markRecentToolbarTouch()
|
|
514
|
+
return false
|
|
515
|
+
}
|
|
516
|
+
if (isTouchInsideStandaloneToolbar(event)) {
|
|
517
|
+
markRecentToolbarTouch()
|
|
405
518
|
return false
|
|
406
519
|
}
|
|
407
|
-
val
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
520
|
+
val rect = Rect()
|
|
521
|
+
richTextView.editorEditText.getGlobalVisibleRect(rect)
|
|
522
|
+
return !rect.contains(event.rawX.toInt(), event.rawY.toInt())
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
private fun markRecentToolbarTouch() {
|
|
526
|
+
lastToolbarTouchUptimeMs = SystemClock.uptimeMillis()
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
private fun clearRecentToolbarTouch() {
|
|
530
|
+
lastToolbarTouchUptimeMs = null
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
private fun shouldPreserveFocusAfterToolbarTouch(): Boolean {
|
|
534
|
+
val lastToolbarTouch = lastToolbarTouchUptimeMs ?: return false
|
|
535
|
+
val elapsedMs = SystemClock.uptimeMillis() - lastToolbarTouch
|
|
536
|
+
return elapsedMs in 0L..TOOLBAR_FOCUS_PRESERVE_MS
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
internal fun markRecentToolbarTouchForTesting() {
|
|
540
|
+
markRecentToolbarTouch()
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
internal fun shouldPreserveFocusAfterToolbarTouchForTesting(): Boolean =
|
|
544
|
+
shouldPreserveFocusAfterToolbarTouch()
|
|
545
|
+
|
|
546
|
+
private fun isTouchInsideStandaloneToolbar(event: MotionEvent): Boolean {
|
|
547
|
+
val visibleWindowFrame = Rect()
|
|
548
|
+
getWindowVisibleDisplayFrame(visibleWindowFrame)
|
|
549
|
+
return isPointInsideStandaloneToolbar(event.rawX, event.rawY, visibleWindowFrame)
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
internal fun isPointInsideStandaloneToolbarForTesting(
|
|
553
|
+
rawX: Float,
|
|
554
|
+
rawY: Float,
|
|
555
|
+
visibleWindowFrame: Rect
|
|
556
|
+
): Boolean = isPointInsideStandaloneToolbar(rawX, rawY, visibleWindowFrame)
|
|
557
|
+
|
|
558
|
+
private fun isPointInsideStandaloneToolbar(
|
|
559
|
+
rawX: Float,
|
|
560
|
+
rawY: Float,
|
|
561
|
+
visibleWindowFrame: Rect
|
|
562
|
+
): Boolean {
|
|
563
|
+
if (toolbarFramesInWindow.isEmpty()) {
|
|
564
|
+
return false
|
|
565
|
+
}
|
|
566
|
+
// toolbarFrame is in DP from React Native's measureInWindow. On Android
|
|
567
|
+
// that is window-relative after visible-window insets are subtracted,
|
|
568
|
+
// while rawX/rawY are screen pixels. Fabric/newer implementations may
|
|
569
|
+
// differ here, so accept both window-relative and raw-screen comparisons.
|
|
570
|
+
val density = resources.displayMetrics.density
|
|
571
|
+
val hitSlopPx = TOOLBAR_HIT_SLOP_DP * density
|
|
572
|
+
val eventX = rawX - visibleWindowFrame.left
|
|
573
|
+
val eventY = rawY - visibleWindowFrame.top
|
|
574
|
+
for (toolbarFrame in toolbarFramesInWindow) {
|
|
575
|
+
val windowFrameInPx = RectF(
|
|
413
576
|
toolbarFrame.left * density,
|
|
414
577
|
toolbarFrame.top * density,
|
|
415
578
|
toolbarFrame.right * density,
|
|
416
579
|
toolbarFrame.bottom * density
|
|
417
|
-
)
|
|
418
|
-
|
|
419
|
-
|
|
580
|
+
).apply {
|
|
581
|
+
inset(-hitSlopPx, -hitSlopPx)
|
|
582
|
+
}
|
|
583
|
+
val screenFrameInPx = RectF(windowFrameInPx).apply {
|
|
584
|
+
offset(visibleWindowFrame.left.toFloat(), visibleWindowFrame.top.toFloat())
|
|
585
|
+
}
|
|
586
|
+
if (
|
|
587
|
+
windowFrameInPx.contains(rawX, rawY) ||
|
|
588
|
+
windowFrameInPx.contains(eventX, eventY) ||
|
|
589
|
+
screenFrameInPx.contains(rawX, rawY)
|
|
590
|
+
) {
|
|
591
|
+
return true
|
|
420
592
|
}
|
|
421
593
|
}
|
|
422
|
-
|
|
423
|
-
richTextView.editorEditText.getGlobalVisibleRect(rect)
|
|
424
|
-
return !rect.contains(event.rawX.toInt(), event.rawY.toInt())
|
|
594
|
+
return false
|
|
425
595
|
}
|
|
426
596
|
|
|
427
597
|
private fun isTouchInsideKeyboardToolbar(event: MotionEvent): Boolean {
|
|
@@ -433,6 +603,12 @@ class NativeEditorExpoView(
|
|
|
433
603
|
return rect.contains(event.rawX.toInt(), event.rawY.toInt())
|
|
434
604
|
}
|
|
435
605
|
|
|
606
|
+
private companion object {
|
|
607
|
+
private const val TOOLBAR_HIT_SLOP_DP = 8f
|
|
608
|
+
private const val TOOLBAR_FOCUS_PRESERVE_MS = 750L
|
|
609
|
+
private const val OUTSIDE_TAP_BLUR_DELAY_MS = 100L
|
|
610
|
+
}
|
|
611
|
+
|
|
436
612
|
private fun resolveActivity(context: Context): Activity? {
|
|
437
613
|
var current: Context? = context
|
|
438
614
|
while (current is ContextWrapper) {
|
|
@@ -658,6 +834,11 @@ class NativeEditorExpoView(
|
|
|
658
834
|
keyboardToolbarView.layoutParams = params
|
|
659
835
|
}
|
|
660
836
|
|
|
837
|
+
private fun updateAttachedKeyboardToolbarForInsets() {
|
|
838
|
+
keyboardToolbarView.visibility = if (currentImeBottom > 0) View.VISIBLE else View.INVISIBLE
|
|
839
|
+
updateEditorViewportInset()
|
|
840
|
+
}
|
|
841
|
+
|
|
661
842
|
private fun updateKeyboardToolbarVisibility() {
|
|
662
843
|
val shouldAttach =
|
|
663
844
|
showsToolbar &&
|
|
@@ -380,6 +380,10 @@ class NativeEditorModule : Module() {
|
|
|
380
380
|
view.blur()
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
AsyncFunction("getCaretRect") { view: NativeEditorExpoView ->
|
|
384
|
+
view.getCaretRectJson()
|
|
385
|
+
}
|
|
386
|
+
|
|
383
387
|
AsyncFunction("applyEditorUpdate") { view: NativeEditorExpoView, updateJson: String ->
|
|
384
388
|
view.applyEditorUpdate(updateJson)
|
|
385
389
|
}
|
|
@@ -11,6 +11,7 @@ import android.view.View
|
|
|
11
11
|
import android.view.ViewOutlineProvider
|
|
12
12
|
import android.widget.HorizontalScrollView
|
|
13
13
|
import android.widget.LinearLayout
|
|
14
|
+
import androidx.appcompat.R as AppCompatR
|
|
14
15
|
import androidx.appcompat.widget.AppCompatButton
|
|
15
16
|
import androidx.appcompat.widget.PopupMenu
|
|
16
17
|
import androidx.appcompat.widget.AppCompatTextView
|
|
@@ -834,7 +835,7 @@ internal class EditorKeyboardToolbarView(context: Context) : HorizontalScrollVie
|
|
|
834
835
|
0.38f
|
|
835
836
|
)
|
|
836
837
|
active -> theme?.buttonActiveColor ?: resolveColorAttr(
|
|
837
|
-
|
|
838
|
+
AppCompatR.attr.colorPrimary,
|
|
838
839
|
android.R.attr.textColorPrimary
|
|
839
840
|
)
|
|
840
841
|
else -> theme?.buttonColor ?: resolveColorAttr(
|
|
@@ -301,6 +301,16 @@ class RichTextEditorView @JvmOverloads constructor(
|
|
|
301
301
|
)
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
internal fun caretRect(): RectF? {
|
|
305
|
+
val rect = editorEditText.caretRect() ?: return null
|
|
306
|
+
return RectF(
|
|
307
|
+
editorViewport.left + editorScrollView.left + editorEditText.left + rect.left,
|
|
308
|
+
editorViewport.top + editorScrollView.top + editorEditText.top + rect.top - editorScrollView.scrollY,
|
|
309
|
+
editorViewport.left + editorScrollView.left + editorEditText.left + rect.right,
|
|
310
|
+
editorViewport.top + editorScrollView.top + editorEditText.top + rect.bottom - editorScrollView.scrollY
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
|
|
304
314
|
internal fun maximumImageWidthPx(): Float {
|
|
305
315
|
val availableWidth =
|
|
306
316
|
maxOf(editorEditText.width, editorEditText.measuredWidth) -
|
package/dist/EditorToolbar.d.ts
CHANGED
|
@@ -91,6 +91,18 @@ export type EditorToolbarItem = EditorToolbarLeafItem | EditorToolbarGroupItem |
|
|
|
91
91
|
type: 'separator';
|
|
92
92
|
key?: string;
|
|
93
93
|
};
|
|
94
|
+
export interface EditorToolbarFrame {
|
|
95
|
+
x: number;
|
|
96
|
+
y: number;
|
|
97
|
+
width: number;
|
|
98
|
+
height: number;
|
|
99
|
+
}
|
|
100
|
+
export declare function isEditorToolbarFocusPreservationActive(): boolean;
|
|
101
|
+
export declare function useEditorToolbarFrames(): readonly EditorToolbarFrame[];
|
|
102
|
+
export declare function _setEditorToolbarFrameForTests(id: number, frame: EditorToolbarFrame | null): void;
|
|
103
|
+
export declare function _resetEditorToolbarFrameRegistryForTests(): void;
|
|
104
|
+
export declare function _beginEditorToolbarInteractionForTests(): void;
|
|
105
|
+
export declare function _endEditorToolbarInteractionForTests(): void;
|
|
94
106
|
export declare const DEFAULT_EDITOR_TOOLBAR_ITEMS: readonly EditorToolbarItem[];
|
|
95
107
|
export interface EditorToolbarProps {
|
|
96
108
|
/** Currently active marks and nodes from the Rust engine. */
|
|
@@ -145,5 +157,10 @@ export interface EditorToolbarProps {
|
|
|
145
157
|
theme?: EditorToolbarTheme;
|
|
146
158
|
/** Whether to render the built-in top separator line. */
|
|
147
159
|
showTopBorder?: boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Keep NativeRichTextEditor focused when this toolbar is rendered outside
|
|
162
|
+
* the editor wrapper. Defaults to true.
|
|
163
|
+
*/
|
|
164
|
+
preserveEditorFocus?: boolean;
|
|
148
165
|
}
|
|
149
|
-
export declare 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, theme, showTopBorder, }: EditorToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
166
|
+
export declare 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, theme, showTopBorder, preserveEditorFocus, }: EditorToolbarProps): import("react/jsx-runtime").JSX.Element;
|