@chaitrabhairappa/react-native-rich-text-editor 3.4.3 → 3.5.0
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/README.md +8 -14
- package/android/src/main/java/com/richtext/editor/MediaAttachmentSupport.kt +36 -5
- package/android/src/main/java/com/richtext/editor/RichTextEditorView.kt +151 -10
- package/android/src/main/java/com/richtext/editor/RichTextEditorViewManager.kt +3 -0
- package/ios/RichTextEditorView.swift +166 -3
- package/lib/commonjs/index.js +10 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +10 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +11 -2
package/README.md
CHANGED
|
@@ -21,14 +21,14 @@ Unlike other rich text editor packages that rely on HTML and WebView, this libra
|
|
|
21
21
|
- Headings
|
|
22
22
|
- Quotes and Checklists
|
|
23
23
|
- Media attachments (images)
|
|
24
|
-
- Link insertion
|
|
24
|
+
- Link insertion with clickable hyperlinks in readOnly mode
|
|
25
|
+
- Auto-detection of URLs (typed or pasted)
|
|
25
26
|
- Undo/Redo
|
|
26
27
|
- Text alignment (left, center, right)
|
|
27
28
|
- Indent/Outdent
|
|
28
29
|
- Floating toolbar with customizable options
|
|
29
30
|
- Three variants: outlined, flat, and plain
|
|
30
31
|
- Auto-growing height
|
|
31
|
-
- **`numberOfLines` support** — truncate text with ellipsis in readOnly mode
|
|
32
32
|
- **Delta-based content updates** for optimized performance
|
|
33
33
|
- **Synchronous style detection** via `onActiveStylesChange`
|
|
34
34
|
|
|
@@ -141,7 +141,6 @@ export default App;
|
|
|
141
141
|
| `initialContent` | `Block[]` | `[]` | Initial content blocks |
|
|
142
142
|
| `readOnly` | `boolean` | `false` | Make editor read-only |
|
|
143
143
|
| `selectable` | `boolean` | `true` | Enable/disable text selection |
|
|
144
|
-
| `numberOfLines` | `number` | `undefined` | Truncate text with ellipsis in readOnly mode |
|
|
145
144
|
| `maxHeight` | `number` | `undefined` | Maximum height before scrolling |
|
|
146
145
|
| `showToolbar` | `boolean` | `true` | Show/hide floating toolbar |
|
|
147
146
|
| `toolbarOptions` | `ToolbarOption[]` | All options | Customize toolbar buttons |
|
|
@@ -255,16 +254,6 @@ type ToolbarOption =
|
|
|
255
254
|
| 'alignRight';
|
|
256
255
|
```
|
|
257
256
|
|
|
258
|
-
## Read-Only with numberOfLines
|
|
259
|
-
|
|
260
|
-
Use the `numberOfLines` prop along with `readOnly` to truncate content with an ellipsis:
|
|
261
|
-
|
|
262
|
-
```tsx
|
|
263
|
-
<RichTextEditor readOnly numberOfLines={3} initialContent={initialContent} />
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
This works like React Native's `Text` component — content is truncated at the specified number of lines with a trailing ellipsis.
|
|
267
|
-
|
|
268
257
|
## Media Attachments
|
|
269
258
|
|
|
270
259
|
You can insert images into the editor using the `insertMediaAttachment` ref method. The toolbar also includes a `mediaAttachment` button that triggers the native media attachment flow.
|
|
@@ -315,6 +304,12 @@ const toolbarOptions: ToolbarOption[] = ['bold', 'italic', 'underline', 'bullet'
|
|
|
315
304
|
|
|
316
305
|
## Changelog
|
|
317
306
|
|
|
307
|
+
### 3.5.0
|
|
308
|
+
|
|
309
|
+
- Clickable hyperlinks in readOnly mode — links are highlighted in blue with underline and open in the browser on tap (iOS & Android)
|
|
310
|
+
- Auto-detection of URLs — typed or pasted URLs are automatically converted to clickable links after a space or newline
|
|
311
|
+
- Fix Android link URL not being parsed from initialContent
|
|
312
|
+
|
|
318
313
|
### 3.3.0
|
|
319
314
|
|
|
320
315
|
- Add `selectable` prop to enable/disable text selection (iOS & Android)
|
|
@@ -328,7 +323,6 @@ const toolbarOptions: ToolbarOption[] = ['bold', 'italic', 'underline', 'bullet'
|
|
|
328
323
|
|
|
329
324
|
### 2.1.2
|
|
330
325
|
|
|
331
|
-
- Add `numberOfLines` prop to truncate text with ellipsis in readOnly mode (iOS & Android)
|
|
332
326
|
- Fix Android `onContentChange` to correctly extract text styles (bold, italic, underline, strikethrough, code, highlight)
|
|
333
327
|
- Fix Android `onContentChange` to correctly detect block types (bullet, numbered, checklist, quote)
|
|
334
328
|
- Android: auto-scroll to cursor when content exceeds maxHeight
|
|
@@ -278,10 +278,33 @@ class MediaAttachmentSupport(
|
|
|
278
278
|
return Pair(scaled, targetHeightPx)
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
+
private fun hasExplicitDimensions(mediaData: MediaAttachmentData): Boolean {
|
|
282
|
+
return mediaData.widthDp > 0 && mediaData.heightDp > 0
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
private fun scaleToExplicitDimensions(bitmap: Bitmap, mediaData: MediaAttachmentData, targetWidthPx: Int): Pair<Bitmap, MediaAttachmentData> {
|
|
286
|
+
val explicitWidthPx = (mediaData.widthDp * density).toInt().coerceAtMost(targetWidthPx).coerceAtLeast(1)
|
|
287
|
+
val scale = explicitWidthPx.toFloat() / (mediaData.widthDp * density).coerceAtLeast(1f)
|
|
288
|
+
val explicitHeightPx = (mediaData.heightDp * density * scale).toInt().coerceAtLeast(1)
|
|
289
|
+
val scaled = if (bitmap.width == explicitWidthPx && bitmap.height == explicitHeightPx) {
|
|
290
|
+
bitmap
|
|
291
|
+
} else {
|
|
292
|
+
Bitmap.createScaledBitmap(bitmap, explicitWidthPx, explicitHeightPx, true)
|
|
293
|
+
}
|
|
294
|
+
val updatedData = mediaData.copy(
|
|
295
|
+
widthDp = (explicitWidthPx / density).toInt().coerceAtLeast(1),
|
|
296
|
+
heightDp = (explicitHeightPx / density).toInt().coerceAtLeast(1)
|
|
297
|
+
)
|
|
298
|
+
return Pair(scaled, updatedData)
|
|
299
|
+
}
|
|
300
|
+
|
|
281
301
|
private fun loadBitmapForMedia(mediaData: MediaAttachmentData, targetWidthPx: Int): Pair<Bitmap, MediaAttachmentData>? {
|
|
282
302
|
if (mediaData.uri.isBlank() || mediaData.uri == "red-box-placeholder") return null
|
|
283
303
|
|
|
284
304
|
mediaBitmapCache[mediaData.uri]?.let { cached ->
|
|
305
|
+
if (hasExplicitDimensions(mediaData)) {
|
|
306
|
+
return scaleToExplicitDimensions(cached, mediaData, targetWidthPx)
|
|
307
|
+
}
|
|
285
308
|
val (scaledBitmap, targetHeightPx) = buildScaledBitmapWithAspect(cached, targetWidthPx)
|
|
286
309
|
val updatedData = mediaData.copy(
|
|
287
310
|
widthDp = (targetWidthPx / density).toInt().coerceAtLeast(1),
|
|
@@ -303,6 +326,9 @@ class MediaAttachmentSupport(
|
|
|
303
326
|
BitmapFactory.decodeStream(inputStream)
|
|
304
327
|
}?.let { original ->
|
|
305
328
|
mediaBitmapCache[mediaData.uri] = original
|
|
329
|
+
if (hasExplicitDimensions(mediaData)) {
|
|
330
|
+
return scaleToExplicitDimensions(original, mediaData, targetWidthPx)
|
|
331
|
+
}
|
|
306
332
|
val (scaledBitmap, targetHeightPx) = buildScaledBitmapWithAspect(original, targetWidthPx)
|
|
307
333
|
val updatedData = mediaData.copy(
|
|
308
334
|
widthDp = (targetWidthPx / density).toInt().coerceAtLeast(1),
|
|
@@ -331,11 +357,16 @@ class MediaAttachmentSupport(
|
|
|
331
357
|
} ?: return@Thread
|
|
332
358
|
|
|
333
359
|
mediaBitmapCache[uriString] = loaded
|
|
334
|
-
val
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
360
|
+
val result = if (hasExplicitDimensions(mediaData)) {
|
|
361
|
+
scaleToExplicitDimensions(loaded, mediaData, targetWidthPx)
|
|
362
|
+
} else {
|
|
363
|
+
val (scaledBitmap, targetHeightPx) = buildScaledBitmapWithAspect(loaded, targetWidthPx)
|
|
364
|
+
Pair(scaledBitmap, mediaData.copy(
|
|
365
|
+
widthDp = (targetWidthPx / density).toInt().coerceAtLeast(1),
|
|
366
|
+
heightDp = (targetHeightPx / density).toInt().coerceAtLeast(1)
|
|
367
|
+
))
|
|
368
|
+
}
|
|
369
|
+
val (scaledBitmap, updatedData) = result
|
|
339
370
|
|
|
340
371
|
runOnUiThread {
|
|
341
372
|
synchronized(loadingRemoteUris) {
|
|
@@ -60,11 +60,13 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
60
60
|
private var customTypeface: Typeface? = null
|
|
61
61
|
private var density: Float = 1f
|
|
62
62
|
private var isInternalChange = false
|
|
63
|
+
private var isEditable = true
|
|
63
64
|
private var lastReportedHeight: Float = 0f
|
|
64
65
|
private var calculatedHeight: Float = 0f
|
|
65
66
|
private var minHeightPx: Float = 0f
|
|
66
67
|
private var isInitialized = false
|
|
67
68
|
|
|
69
|
+
private var longPressToolbarShowing = false
|
|
68
70
|
private var previousText: String = ""
|
|
69
71
|
private var pendingDelta: Map<String, Any>? = null
|
|
70
72
|
private var pendingPrefixDeletion: Pair<Int, Int>? = null // (lineStart, prefixLength) for backspace-in-prefix
|
|
@@ -117,7 +119,6 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
117
119
|
private var savedSelectionStart: Int = 0
|
|
118
120
|
private var savedSelectionEnd: Int = 0
|
|
119
121
|
|
|
120
|
-
// Gesture detector for double-tap word selection
|
|
121
122
|
private val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
|
|
122
123
|
override fun onDoubleTap(e: MotionEvent): Boolean {
|
|
123
124
|
selectWordAtPosition(e.x, e.y)
|
|
@@ -125,9 +126,17 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
override fun onSingleTapUp(e: MotionEvent): Boolean {
|
|
128
|
-
|
|
129
|
+
longPressToolbarShowing = false
|
|
129
130
|
return false
|
|
130
131
|
}
|
|
132
|
+
|
|
133
|
+
override fun onLongPress(e: MotionEvent) {
|
|
134
|
+
if (showToolbar && hasFocus() && selectionStart == selectionEnd) {
|
|
135
|
+
longPressToolbarShowing = true
|
|
136
|
+
removeCallbacks(hideToolbarRunnable)
|
|
137
|
+
postDelayed({ showToolbarAtCursor() }, 50)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
131
140
|
})
|
|
132
141
|
|
|
133
142
|
init {
|
|
@@ -159,6 +168,9 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
159
168
|
// Default outlined style
|
|
160
169
|
applyVariantStyle()
|
|
161
170
|
|
|
171
|
+
// Enable link clicks
|
|
172
|
+
movementMethod = android.text.method.LinkMovementMethod.getInstance()
|
|
173
|
+
|
|
162
174
|
// Setup toolbar
|
|
163
175
|
setupToolbar()
|
|
164
176
|
|
|
@@ -222,6 +234,7 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
222
234
|
renumberNumberedLists()
|
|
223
235
|
isInternalChange = false
|
|
224
236
|
}
|
|
237
|
+
autoDetectLinks(s)
|
|
225
238
|
sendContentChangeWithDelta()
|
|
226
239
|
saveToUndoStack()
|
|
227
240
|
pendingDelta = null
|
|
@@ -372,10 +385,11 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
372
385
|
// Show/hide toolbar based on selection
|
|
373
386
|
if (selStart != selEnd && showToolbar && hasFocus()) {
|
|
374
387
|
android.util.Log.d("RichTextEditor", "Should show toolbar - selection exists")
|
|
388
|
+
longPressToolbarShowing = false
|
|
375
389
|
removeCallbacks(hideToolbarRunnable)
|
|
376
390
|
// Use postDelayed to ensure layout is complete
|
|
377
391
|
postDelayed({ showToolbarAtSelection() }, 50)
|
|
378
|
-
} else {
|
|
392
|
+
} else if (!longPressToolbarShowing) {
|
|
379
393
|
// Delay hiding to prevent flicker during selection changes
|
|
380
394
|
android.util.Log.d("RichTextEditor", "Scheduling hide toolbar")
|
|
381
395
|
postDelayed(hideToolbarRunnable, 200)
|
|
@@ -535,7 +549,56 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
535
549
|
}
|
|
536
550
|
}
|
|
537
551
|
|
|
552
|
+
private fun showToolbarAtCursor() {
|
|
553
|
+
if (!showToolbar || toolbarPopup == null || floatingToolbar == null) return
|
|
554
|
+
if (!isAttachedToWindow) return
|
|
555
|
+
|
|
556
|
+
val cursorPos = selectionStart
|
|
557
|
+
if (cursorPos < 0) return
|
|
558
|
+
|
|
559
|
+
try {
|
|
560
|
+
val textLayout = layout ?: return
|
|
561
|
+
|
|
562
|
+
val cursorLine = textLayout.getLineForOffset(cursorPos)
|
|
563
|
+
val lineBottom = textLayout.getLineBottom(cursorLine)
|
|
564
|
+
val lineTop = textLayout.getLineTop(cursorLine)
|
|
565
|
+
|
|
566
|
+
val location = IntArray(2)
|
|
567
|
+
getLocationOnScreen(location)
|
|
568
|
+
|
|
569
|
+
val toolbarWidth = floatingToolbar?.getToolbarWidth() ?: (300 * density).toInt()
|
|
570
|
+
val toolbarHeight = floatingToolbar?.getToolbarHeight() ?: (52 * density).toInt()
|
|
571
|
+
|
|
572
|
+
val screenWidth = context.resources.displayMetrics.widthPixels
|
|
573
|
+
var x = (screenWidth - toolbarWidth) / 2
|
|
574
|
+
if (x < 0) x = 0
|
|
575
|
+
|
|
576
|
+
var y = location[1] + lineBottom + paddingTop + (8 * density).toInt()
|
|
577
|
+
|
|
578
|
+
val screenHeight = context.resources.displayMetrics.heightPixels
|
|
579
|
+
if (y + toolbarHeight > screenHeight - (100 * density).toInt()) {
|
|
580
|
+
y = location[1] + lineTop + paddingTop - toolbarHeight - (8 * density).toInt()
|
|
581
|
+
}
|
|
582
|
+
if (y < 0) y = (8 * density).toInt()
|
|
583
|
+
|
|
584
|
+
toolbarPopup?.width = toolbarWidth
|
|
585
|
+
toolbarPopup?.height = toolbarHeight
|
|
586
|
+
|
|
587
|
+
val token = windowToken ?: return
|
|
588
|
+
|
|
589
|
+
if (toolbarPopup?.isShowing == true) {
|
|
590
|
+
toolbarPopup?.update(x, y, toolbarWidth, toolbarHeight)
|
|
591
|
+
} else {
|
|
592
|
+
val decorView = (context as? android.app.Activity)?.window?.decorView ?: rootView
|
|
593
|
+
toolbarPopup?.showAtLocation(decorView, Gravity.NO_GRAVITY, x, y)
|
|
594
|
+
}
|
|
595
|
+
} catch (e: Exception) {
|
|
596
|
+
android.util.Log.e("RichTextEditor", "Error showing toolbar at cursor", e)
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
538
600
|
private fun hideToolbar() {
|
|
601
|
+
longPressToolbarShowing = false
|
|
539
602
|
try {
|
|
540
603
|
if (toolbarPopup?.isShowing == true) {
|
|
541
604
|
android.util.Log.d("RichTextEditor", "Hiding toolbar")
|
|
@@ -660,6 +723,33 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
660
723
|
return Pair(lineStart, lineEnd)
|
|
661
724
|
}
|
|
662
725
|
|
|
726
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
727
|
+
if (!isEditable && event.action == MotionEvent.ACTION_UP) {
|
|
728
|
+
val x = event.x.toInt() - totalPaddingLeft + scrollX
|
|
729
|
+
val y = event.y.toInt() - totalPaddingTop + scrollY
|
|
730
|
+
val textLayout = layout
|
|
731
|
+
if (textLayout != null) {
|
|
732
|
+
val line = textLayout.getLineForVertical(y)
|
|
733
|
+
val off = textLayout.getOffsetForHorizontal(line, x.toFloat())
|
|
734
|
+
val spannable = text as? Spanned
|
|
735
|
+
if (spannable != null) {
|
|
736
|
+
val urlSpans = spannable.getSpans(off, off, android.text.style.URLSpan::class.java)
|
|
737
|
+
if (urlSpans.isNotEmpty()) {
|
|
738
|
+
val url = urlSpans[0].url
|
|
739
|
+
try {
|
|
740
|
+
val intent = android.content.Intent(android.content.Intent.ACTION_VIEW, Uri.parse(url))
|
|
741
|
+
context.startActivity(intent)
|
|
742
|
+
} catch (e: Exception) {
|
|
743
|
+
android.util.Log.e("RichTextEditor", "Failed to open URL: $url", e)
|
|
744
|
+
}
|
|
745
|
+
return true
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
return super.dispatchTouchEvent(event)
|
|
751
|
+
}
|
|
752
|
+
|
|
663
753
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
664
754
|
gestureDetector.onTouchEvent(event)
|
|
665
755
|
return super.onTouchEvent(event)
|
|
@@ -786,7 +876,7 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
786
876
|
if (textLayout != null) {
|
|
787
877
|
val lineCount = textLayout.lineCount
|
|
788
878
|
if (lineCount > 0) {
|
|
789
|
-
val effectiveLineCount = if (numberOfLinesValue > 0 && !
|
|
879
|
+
val effectiveLineCount = if (numberOfLinesValue > 0 && !isEditable) {
|
|
790
880
|
minOf(numberOfLinesValue, lineCount)
|
|
791
881
|
} else {
|
|
792
882
|
lineCount
|
|
@@ -824,7 +914,7 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
824
914
|
val lineCount = textLayout.lineCount
|
|
825
915
|
if (lineCount == 0) return
|
|
826
916
|
|
|
827
|
-
val effectiveLineCount = if (numberOfLinesValue > 0 && !
|
|
917
|
+
val effectiveLineCount = if (numberOfLinesValue > 0 && !isEditable) {
|
|
828
918
|
minOf(numberOfLinesValue, lineCount)
|
|
829
919
|
} else {
|
|
830
920
|
lineCount
|
|
@@ -862,7 +952,7 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
862
952
|
}
|
|
863
953
|
}
|
|
864
954
|
|
|
865
|
-
if (maxHeightValue > 0 && textLayout.lineCount > 0 && !(numberOfLinesValue > 0 && !
|
|
955
|
+
if (maxHeightValue > 0 && textLayout.lineCount > 0 && !(numberOfLinesValue > 0 && !isEditable)) {
|
|
866
956
|
val cursorPos = selectionEnd.coerceAtLeast(0)
|
|
867
957
|
val cursorLine = textLayout.getLineForOffset(cursorPos)
|
|
868
958
|
val cursorBottom = textLayout.getLineBottom(cursorLine)
|
|
@@ -1000,7 +1090,18 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
1000
1090
|
}
|
|
1001
1091
|
|
|
1002
1092
|
fun setEditable(value: Boolean) {
|
|
1003
|
-
|
|
1093
|
+
isEditable = value
|
|
1094
|
+
if (value) {
|
|
1095
|
+
isEnabled = true
|
|
1096
|
+
isFocusable = true
|
|
1097
|
+
isFocusableInTouchMode = true
|
|
1098
|
+
isCursorVisible = true
|
|
1099
|
+
} else {
|
|
1100
|
+
isFocusable = false
|
|
1101
|
+
isFocusableInTouchMode = false
|
|
1102
|
+
isCursorVisible = false
|
|
1103
|
+
isEnabled = true // Keep enabled so touch events fire for link clicks
|
|
1104
|
+
}
|
|
1004
1105
|
if (numberOfLinesValue > 0) {
|
|
1005
1106
|
setNumberOfLinesValue(numberOfLinesValue)
|
|
1006
1107
|
}
|
|
@@ -1010,6 +1111,35 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
1010
1111
|
setTextIsSelectable(value)
|
|
1011
1112
|
}
|
|
1012
1113
|
|
|
1114
|
+
private fun autoDetectLinks(s: Editable?) {
|
|
1115
|
+
if (s == null || s.isEmpty()) return
|
|
1116
|
+
val text = s.toString()
|
|
1117
|
+
val cursorPos = selectionStart
|
|
1118
|
+
|
|
1119
|
+
// Only auto-detect when the character before cursor is a space or newline
|
|
1120
|
+
// (i.e., user finished typing the URL)
|
|
1121
|
+
if (cursorPos > 0 && cursorPos <= text.length) {
|
|
1122
|
+
val prevChar = text[cursorPos - 1]
|
|
1123
|
+
if (prevChar != ' ' && prevChar != '\n') return
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
val urlPattern = android.util.Patterns.WEB_URL
|
|
1127
|
+
val matcher = urlPattern.matcher(text)
|
|
1128
|
+
isInternalChange = true
|
|
1129
|
+
while (matcher.find()) {
|
|
1130
|
+
val start = matcher.start()
|
|
1131
|
+
val end = matcher.end()
|
|
1132
|
+
val existingSpans = s.getSpans(start, end, android.text.style.URLSpan::class.java)
|
|
1133
|
+
if (existingSpans.isNotEmpty()) continue
|
|
1134
|
+
val url = matcher.group() ?: continue
|
|
1135
|
+
val fullUrl = if (!url.startsWith("http://") && !url.startsWith("https://")) "https://$url" else url
|
|
1136
|
+
s.setSpan(android.text.style.URLSpan(fullUrl), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1137
|
+
s.setSpan(android.text.style.ForegroundColorSpan(Color.parseColor("#2196F3")), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1138
|
+
s.setSpan(UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1139
|
+
}
|
|
1140
|
+
isInternalChange = false
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1013
1143
|
fun setMaxHeightValue(value: Int) {
|
|
1014
1144
|
maxHeightValue = value
|
|
1015
1145
|
post { updateContentSize() }
|
|
@@ -1017,7 +1147,7 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
1017
1147
|
|
|
1018
1148
|
fun setNumberOfLinesValue(value: Int) {
|
|
1019
1149
|
numberOfLinesValue = if (value == 0) 0 else value
|
|
1020
|
-
if (numberOfLinesValue > 0 && !
|
|
1150
|
+
if (numberOfLinesValue > 0 && !isEditable) {
|
|
1021
1151
|
maxLines = numberOfLinesValue
|
|
1022
1152
|
ellipsize = android.text.TextUtils.TruncateAt.END
|
|
1023
1153
|
isVerticalScrollBarEnabled = false
|
|
@@ -1149,6 +1279,12 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
1149
1279
|
spannable.setSpan(BackgroundColorSpan(Color.parseColor("#F5F5F5")), absoluteStart, absoluteEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1150
1280
|
}
|
|
1151
1281
|
"highlight" -> spannable.setSpan(BackgroundColorSpan(Color.parseColor("#80FFFF00")), absoluteStart, absoluteEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1282
|
+
"link" -> {
|
|
1283
|
+
val url = styleInfo["url"] as? String ?: ""
|
|
1284
|
+
spannable.setSpan(android.text.style.URLSpan(url), absoluteStart, absoluteEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1285
|
+
spannable.setSpan(android.text.style.ForegroundColorSpan(Color.parseColor("#2196F3")), absoluteStart, absoluteEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1286
|
+
spannable.setSpan(UnderlineSpan(), absoluteStart, absoluteEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
1287
|
+
}
|
|
1152
1288
|
}
|
|
1153
1289
|
}
|
|
1154
1290
|
|
|
@@ -1160,17 +1296,22 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
|
|
|
1160
1296
|
|
|
1161
1297
|
isInternalChange = true
|
|
1162
1298
|
setText(spannable)
|
|
1163
|
-
if (numberOfLinesValue > 0 && !
|
|
1299
|
+
if (numberOfLinesValue > 0 && !isEditable) {
|
|
1164
1300
|
setSelection(0)
|
|
1165
1301
|
} else {
|
|
1166
1302
|
setSelection(spannable.length)
|
|
1167
1303
|
}
|
|
1168
1304
|
isInternalChange = false
|
|
1169
|
-
if (numberOfLinesValue > 0 && !
|
|
1305
|
+
if (numberOfLinesValue > 0 && !isEditable) {
|
|
1170
1306
|
scrollTo(0, 0)
|
|
1171
1307
|
applyEllipsisIfNeeded()
|
|
1172
1308
|
}
|
|
1173
1309
|
updateContentSize()
|
|
1310
|
+
|
|
1311
|
+
post {
|
|
1312
|
+
requestLayout()
|
|
1313
|
+
post { updateContentSize() }
|
|
1314
|
+
}
|
|
1174
1315
|
}
|
|
1175
1316
|
|
|
1176
1317
|
fun getTextContent(): String = text.toString()
|
|
@@ -164,6 +164,9 @@ class RichTextEditorViewManager : SimpleViewManager<RichTextEditorView>() {
|
|
|
164
164
|
styleMap["style"] = style.optString("style", "")
|
|
165
165
|
styleMap["start"] = style.optInt("start", 0)
|
|
166
166
|
styleMap["end"] = style.optInt("end", 0)
|
|
167
|
+
if (style.has("url")) {
|
|
168
|
+
styleMap["url"] = style.optString("url", "")
|
|
169
|
+
}
|
|
167
170
|
stylesList.add(styleMap)
|
|
168
171
|
}
|
|
169
172
|
}
|
|
@@ -492,7 +492,7 @@ class RichTextView: UITextView {
|
|
|
492
492
|
}
|
|
493
493
|
|
|
494
494
|
@objcMembers
|
|
495
|
-
class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
|
|
495
|
+
class RichTextEditorView: UIView, UITextViewDelegate, UIGestureRecognizerDelegate, PHPickerViewControllerDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
|
|
496
496
|
private static let defaultLineHeightMultiple: CGFloat = 1.3
|
|
497
497
|
private static let mediaPlaceholderCharacter: Character = "\u{FFFC}"
|
|
498
498
|
private static let mediaAttachmentAttributeKey = NSAttributedString.Key("richTextMediaAttachment")
|
|
@@ -512,6 +512,11 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
512
512
|
.paragraphStyle: paragraphStyle
|
|
513
513
|
]
|
|
514
514
|
|
|
515
|
+
tv.linkTextAttributes = [
|
|
516
|
+
.foregroundColor: UIColor.systemBlue,
|
|
517
|
+
.underlineStyle: NSUnderlineStyle.single.rawValue
|
|
518
|
+
]
|
|
519
|
+
|
|
515
520
|
return tv
|
|
516
521
|
}()
|
|
517
522
|
|
|
@@ -580,6 +585,8 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
580
585
|
}
|
|
581
586
|
|
|
582
587
|
@objc var showToolbar: Bool = true
|
|
588
|
+
private var longPressToolbarShowing: Bool = false
|
|
589
|
+
private var longPressToolbarJustShown: Bool = false
|
|
583
590
|
|
|
584
591
|
@objc var toolbarOptions: [String]? {
|
|
585
592
|
didSet {
|
|
@@ -733,11 +740,95 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
733
740
|
return false
|
|
734
741
|
}
|
|
735
742
|
|
|
743
|
+
let linkTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleLinkTap(_:)))
|
|
744
|
+
linkTapGesture.delegate = self
|
|
745
|
+
textView.addGestureRecognizer(linkTapGesture)
|
|
746
|
+
|
|
747
|
+
let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
|
|
748
|
+
longPressGesture.delegate = self
|
|
749
|
+
textView.addGestureRecognizer(longPressGesture)
|
|
750
|
+
|
|
736
751
|
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange), name: UITextView.textDidChangeNotification, object: textView)
|
|
737
752
|
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
|
|
738
753
|
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
|
|
739
754
|
}
|
|
740
755
|
|
|
756
|
+
@objc private func handleLinkTap(_ gesture: UITapGestureRecognizer) {
|
|
757
|
+
guard !editable else { return }
|
|
758
|
+
let location = gesture.location(in: textView)
|
|
759
|
+
guard let position = textView.closestPosition(to: location) else { return }
|
|
760
|
+
let charIndex = textView.offset(from: textView.beginningOfDocument, to: position)
|
|
761
|
+
let attrText = textView.attributedText ?? NSAttributedString()
|
|
762
|
+
guard charIndex >= 0 && charIndex < attrText.length else { return }
|
|
763
|
+
if let url = attrText.attribute(.link, at: charIndex, effectiveRange: nil) {
|
|
764
|
+
let linkURL: URL?
|
|
765
|
+
if let urlObj = url as? URL {
|
|
766
|
+
linkURL = urlObj
|
|
767
|
+
} else if let urlStr = url as? String {
|
|
768
|
+
linkURL = URL(string: urlStr)
|
|
769
|
+
} else {
|
|
770
|
+
linkURL = nil
|
|
771
|
+
}
|
|
772
|
+
if let linkURL = linkURL {
|
|
773
|
+
UIApplication.shared.open(linkURL)
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
@objc private func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
|
|
779
|
+
guard gesture.state == .began,
|
|
780
|
+
showToolbar,
|
|
781
|
+
editable,
|
|
782
|
+
textView.selectedRange.length == 0,
|
|
783
|
+
let window = window else { return }
|
|
784
|
+
|
|
785
|
+
longPressToolbarShowing = true
|
|
786
|
+
longPressToolbarJustShown = true
|
|
787
|
+
let cursorPosition: UITextPosition
|
|
788
|
+
if let selectedRange = textView.selectedTextRange {
|
|
789
|
+
cursorPosition = selectedRange.start
|
|
790
|
+
} else {
|
|
791
|
+
return
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
let caretRect = textView.caretRect(for: cursorPosition)
|
|
795
|
+
guard !caretRect.isNull && !caretRect.isInfinite else { return }
|
|
796
|
+
|
|
797
|
+
let convertedRect = textView.convert(caretRect, to: window)
|
|
798
|
+
guard convertedRect.maxY > 0 && convertedRect.minY < window.bounds.height else { return }
|
|
799
|
+
|
|
800
|
+
let toolbarWidth: CGFloat = floatingToolbar.getToolbarWidth()
|
|
801
|
+
let toolbarHeight: CGFloat = 52
|
|
802
|
+
|
|
803
|
+
let safeAreaTop = window.safeAreaInsets.top
|
|
804
|
+
let safeAreaBottom = window.safeAreaInsets.bottom
|
|
805
|
+
|
|
806
|
+
var toolbarX = (window.bounds.width - toolbarWidth) / 2
|
|
807
|
+
var toolbarY = convertedRect.maxY + 8
|
|
808
|
+
|
|
809
|
+
toolbarX = max(8, min(toolbarX, window.bounds.width - toolbarWidth - 8))
|
|
810
|
+
|
|
811
|
+
let maxY = window.bounds.height - safeAreaBottom - currentKeyboardHeight - toolbarHeight - 8
|
|
812
|
+
if toolbarY > maxY {
|
|
813
|
+
toolbarY = convertedRect.minY - toolbarHeight - 8
|
|
814
|
+
if toolbarY < safeAreaTop + 8 {
|
|
815
|
+
toolbarY = safeAreaTop + 8
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
toolbarBackdrop.frame = window.bounds
|
|
820
|
+
toolbarBackdrop.isHidden = false
|
|
821
|
+
window.bringSubviewToFront(toolbarBackdrop)
|
|
822
|
+
|
|
823
|
+
floatingToolbar.frame = CGRect(x: toolbarX, y: toolbarY, width: toolbarWidth, height: toolbarHeight)
|
|
824
|
+
floatingToolbar.isHidden = false
|
|
825
|
+
window.bringSubviewToFront(floatingToolbar)
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
829
|
+
return true
|
|
830
|
+
}
|
|
831
|
+
|
|
741
832
|
@objc private func keyboardWillShow(_ notification: Notification) {
|
|
742
833
|
if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
|
|
743
834
|
currentKeyboardHeight = keyboardFrame.height
|
|
@@ -754,6 +845,7 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
754
845
|
}
|
|
755
846
|
|
|
756
847
|
private func hideToolbar() {
|
|
848
|
+
longPressToolbarShowing = false
|
|
757
849
|
floatingToolbar.isHidden = true
|
|
758
850
|
toolbarBackdrop.isHidden = true
|
|
759
851
|
}
|
|
@@ -785,9 +877,12 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
785
877
|
!selectedRange.isEmpty,
|
|
786
878
|
showToolbar,
|
|
787
879
|
let window = window else {
|
|
788
|
-
|
|
880
|
+
if !longPressToolbarShowing {
|
|
881
|
+
hideToolbar()
|
|
882
|
+
}
|
|
789
883
|
return
|
|
790
884
|
}
|
|
885
|
+
longPressToolbarShowing = false
|
|
791
886
|
|
|
792
887
|
let endRect = textView.caretRect(for: selectedRange.end)
|
|
793
888
|
let startRect = textView.caretRect(for: selectedRange.start)
|
|
@@ -833,6 +928,13 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
833
928
|
window.bringSubviewToFront(floatingToolbar)
|
|
834
929
|
}
|
|
835
930
|
|
|
931
|
+
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
|
|
932
|
+
if !editable {
|
|
933
|
+
UIApplication.shared.open(URL)
|
|
934
|
+
}
|
|
935
|
+
return false
|
|
936
|
+
}
|
|
937
|
+
|
|
836
938
|
func textViewDidBeginEditing(_ textView: UITextView) {
|
|
837
939
|
onEditorFocus?([:])
|
|
838
940
|
}
|
|
@@ -848,6 +950,14 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
848
950
|
savedSelectionRange = range
|
|
849
951
|
}
|
|
850
952
|
|
|
953
|
+
if longPressToolbarShowing && range.length == 0 {
|
|
954
|
+
if longPressToolbarJustShown {
|
|
955
|
+
longPressToolbarJustShown = false
|
|
956
|
+
} else {
|
|
957
|
+
longPressToolbarShowing = false
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
|
|
851
961
|
updateToolbarPosition()
|
|
852
962
|
updateToolbarButtonStates()
|
|
853
963
|
|
|
@@ -1229,6 +1339,7 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
1229
1339
|
|
|
1230
1340
|
if !isInternalChange {
|
|
1231
1341
|
autoContinueListOnEnter()
|
|
1342
|
+
autoDetectLinks()
|
|
1232
1343
|
saveToUndoStack()
|
|
1233
1344
|
}
|
|
1234
1345
|
|
|
@@ -1238,6 +1349,44 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
1238
1349
|
sendContentChange()
|
|
1239
1350
|
}
|
|
1240
1351
|
|
|
1352
|
+
private func autoDetectLinks() {
|
|
1353
|
+
guard let text = textView.text, !text.isEmpty else { return }
|
|
1354
|
+
let cursorPos = textView.selectedRange.location
|
|
1355
|
+
|
|
1356
|
+
// Only auto-detect after space or newline (user finished typing the URL)
|
|
1357
|
+
if cursorPos > 0, cursorPos <= text.count {
|
|
1358
|
+
let nsText = text as NSString
|
|
1359
|
+
let prevChar = nsText.character(at: cursorPos - 1)
|
|
1360
|
+
// space = 32, newline = 10
|
|
1361
|
+
if prevChar != 32 && prevChar != 10 { return }
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
let nsText = text as NSString
|
|
1365
|
+
let fullRange = NSRange(location: 0, length: nsText.length)
|
|
1366
|
+
guard let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) else { return }
|
|
1367
|
+
let matches = detector.matches(in: text, range: fullRange)
|
|
1368
|
+
let mutable = NSMutableAttributedString(attributedString: textView.attributedText)
|
|
1369
|
+
var changed = false
|
|
1370
|
+
|
|
1371
|
+
for match in matches {
|
|
1372
|
+
guard let url = match.url else { continue }
|
|
1373
|
+
let existingLink = mutable.attribute(.link, at: match.range.location, effectiveRange: nil)
|
|
1374
|
+
if existingLink != nil { continue }
|
|
1375
|
+
mutable.addAttribute(.link, value: url.absoluteString, range: match.range)
|
|
1376
|
+
mutable.addAttribute(.foregroundColor, value: UIColor.systemBlue, range: match.range)
|
|
1377
|
+
mutable.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: match.range)
|
|
1378
|
+
changed = true
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
if changed {
|
|
1382
|
+
let savedSelection = textView.selectedRange
|
|
1383
|
+
isInternalChange = true
|
|
1384
|
+
textView.attributedText = mutable
|
|
1385
|
+
textView.selectedRange = savedSelection
|
|
1386
|
+
isInternalChange = false
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1241
1390
|
private func autoContinueListOnEnter() {
|
|
1242
1391
|
guard let text = textView.text, !text.isEmpty else { return }
|
|
1243
1392
|
let cursorPos = textView.selectedRange.location
|
|
@@ -2142,7 +2291,10 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
2142
2291
|
|
|
2143
2292
|
let sourceImage = image ?? loadImageFromUri(uri)
|
|
2144
2293
|
let normalizedHeight: CGFloat
|
|
2145
|
-
if let
|
|
2294
|
+
if let explicitW = widthFromPayload, let explicitH = heightFromPayload {
|
|
2295
|
+
// Respect explicit dimensions from the block data
|
|
2296
|
+
normalizedHeight = max(1, explicitH * (normalizedWidth / explicitW))
|
|
2297
|
+
} else if let sourceImage = sourceImage, sourceImage.size.width > 0 {
|
|
2146
2298
|
normalizedHeight = max(1, normalizedWidth * (sourceImage.size.height / sourceImage.size.width))
|
|
2147
2299
|
} else {
|
|
2148
2300
|
normalizedHeight = max(1, height ?? heightFromPayload ?? normalizedWidth)
|
|
@@ -2654,6 +2806,12 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
2654
2806
|
blockAttrString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
|
2655
2807
|
case "strikethrough":
|
|
2656
2808
|
blockAttrString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
|
2809
|
+
case "link":
|
|
2810
|
+
if let url = style["url"] as? String {
|
|
2811
|
+
blockAttrString.addAttribute(.link, value: url, range: range)
|
|
2812
|
+
blockAttrString.addAttribute(.foregroundColor, value: UIColor.systemBlue, range: range)
|
|
2813
|
+
blockAttrString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
|
2814
|
+
}
|
|
2657
2815
|
default:
|
|
2658
2816
|
break
|
|
2659
2817
|
}
|
|
@@ -2681,6 +2839,11 @@ class RichTextEditorView: UIView, UITextViewDelegate, PHPickerViewControllerDele
|
|
|
2681
2839
|
|
|
2682
2840
|
textView.scrollRangeToVisible(NSRange(location: endPosition, length: 0))
|
|
2683
2841
|
updateContentSize()
|
|
2842
|
+
|
|
2843
|
+
DispatchQueue.main.async { [weak self] in
|
|
2844
|
+
self?.textView.layoutIfNeeded()
|
|
2845
|
+
self?.updateContentSize()
|
|
2846
|
+
}
|
|
2684
2847
|
}
|
|
2685
2848
|
|
|
2686
2849
|
func getText() -> String {
|
package/lib/commonjs/index.js
CHANGED
|
@@ -17,7 +17,13 @@ var _types = require("./types");
|
|
|
17
17
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
18
|
const RichTextEditor = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
|
|
19
19
|
const nativeRef = _react.default.useRef(null);
|
|
20
|
-
const
|
|
20
|
+
const [nativeHeight, setNativeHeight] = _react.default.useState(undefined);
|
|
21
|
+
const handleSizeChange = _react.default.useCallback(event => {
|
|
22
|
+
const h = event.nativeEvent.height;
|
|
23
|
+
if (h > 0) {
|
|
24
|
+
setNativeHeight(h);
|
|
25
|
+
}
|
|
26
|
+
}, []);
|
|
21
27
|
const dispatchAndroidCommand = _react.default.useCallback((commandName, args = []) => {
|
|
22
28
|
if (_reactNative.Platform.OS !== 'android') return;
|
|
23
29
|
const nativeTag = (0, _reactNative.findNodeHandle)(nativeRef.current);
|
|
@@ -175,7 +181,9 @@ const RichTextEditor = /*#__PURE__*/_react.default.forwardRef((props, ref) => {
|
|
|
175
181
|
const handleActiveStylesChange = _react.default.useCallback(event => {
|
|
176
182
|
props.onActiveStylesChange?.(event.nativeEvent);
|
|
177
183
|
}, [props.onActiveStylesChange]);
|
|
178
|
-
const combinedStyle = props.style
|
|
184
|
+
const combinedStyle = _react.default.useMemo(() => [props.style, nativeHeight ? {
|
|
185
|
+
minHeight: nativeHeight
|
|
186
|
+
} : undefined], [props.style, nativeHeight]);
|
|
179
187
|
return /*#__PURE__*/_react.default.createElement(_RichTextEditorViewNativeComponent.default, {
|
|
180
188
|
ref: nativeRef,
|
|
181
189
|
style: combinedStyle,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_RichTextEditorViewNativeComponent","_types","e","__esModule","default","RichTextEditor","React","forwardRef","props","ref","nativeRef","useRef","handleSizeChange","useCallback","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_RichTextEditorViewNativeComponent","_types","e","__esModule","default","RichTextEditor","React","forwardRef","props","ref","nativeRef","useRef","nativeHeight","setNativeHeight","useState","undefined","handleSizeChange","useCallback","event","h","nativeEvent","height","dispatchAndroidCommand","commandName","args","Platform","OS","nativeTag","findNodeHandle","current","commandConfig","UIManager","getViewManagerConfig","Commands","commandId","dispatchViewManagerCommand","dispatchInsertMediaAttachment","mediaAttachment","uri","trim","length","normalizedMediaAttachment","sourceUri","JSON","stringify","manager","NativeModules","insertMediaAttachment","useImperativeHandle","setContent","_blocks","getText","getBlocks","clear","focus","blur","toggleBold","toggleItalic","toggleUnderline","toggleStrikethrough","toggleCode","toggleHighlight","_color","setHeading","setBulletList","setNumberedList","setQuote","setChecklist","setParagraph","insertLink","_url","_text","undo","redo","clearFormatting","indent","outdent","setAlignment","_alignment","toggleChecklistItem","handleContentChange","blocks","blocksJson","parse","contentEvent","text","delta","onContentChange","handleSelectionChange","selectionEvent","start","end","onSelectionChange","handleFocus","onFocus","handleBlur","onBlur","handleActiveStylesChange","onActiveStylesChange","combinedStyle","useMemo","style","minHeight","createElement","placeholder","initialContentJson","initialContent","editable","readOnly","selectable","maxHeight","numberOfLines","showToolbar","toolbarOptions","variant","fontFamily","fontSize","onEditorFocus","onEditorBlur","onSizeChange","displayName","_default","exports"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -3,7 +3,13 @@ import { findNodeHandle, NativeModules, Platform, UIManager } from 'react-native
|
|
|
3
3
|
import RichTextEditorViewNative from './RichTextEditorViewNativeComponent';
|
|
4
4
|
const RichTextEditor = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
5
5
|
const nativeRef = React.useRef(null);
|
|
6
|
-
const
|
|
6
|
+
const [nativeHeight, setNativeHeight] = React.useState(undefined);
|
|
7
|
+
const handleSizeChange = React.useCallback(event => {
|
|
8
|
+
const h = event.nativeEvent.height;
|
|
9
|
+
if (h > 0) {
|
|
10
|
+
setNativeHeight(h);
|
|
11
|
+
}
|
|
12
|
+
}, []);
|
|
7
13
|
const dispatchAndroidCommand = React.useCallback((commandName, args = []) => {
|
|
8
14
|
if (Platform.OS !== 'android') return;
|
|
9
15
|
const nativeTag = findNodeHandle(nativeRef.current);
|
|
@@ -161,7 +167,9 @@ const RichTextEditor = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
|
161
167
|
const handleActiveStylesChange = React.useCallback(event => {
|
|
162
168
|
props.onActiveStylesChange?.(event.nativeEvent);
|
|
163
169
|
}, [props.onActiveStylesChange]);
|
|
164
|
-
const combinedStyle = props.style
|
|
170
|
+
const combinedStyle = React.useMemo(() => [props.style, nativeHeight ? {
|
|
171
|
+
minHeight: nativeHeight
|
|
172
|
+
} : undefined], [props.style, nativeHeight]);
|
|
165
173
|
return /*#__PURE__*/React.createElement(RichTextEditorViewNative, {
|
|
166
174
|
ref: nativeRef,
|
|
167
175
|
style: combinedStyle,
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","findNodeHandle","NativeModules","Platform","UIManager","RichTextEditorViewNative","RichTextEditor","forwardRef","props","ref","nativeRef","useRef","handleSizeChange","useCallback","
|
|
1
|
+
{"version":3,"names":["React","findNodeHandle","NativeModules","Platform","UIManager","RichTextEditorViewNative","RichTextEditor","forwardRef","props","ref","nativeRef","useRef","nativeHeight","setNativeHeight","useState","undefined","handleSizeChange","useCallback","event","h","nativeEvent","height","dispatchAndroidCommand","commandName","args","OS","nativeTag","current","commandConfig","getViewManagerConfig","Commands","commandId","dispatchViewManagerCommand","dispatchInsertMediaAttachment","mediaAttachment","uri","trim","length","normalizedMediaAttachment","sourceUri","JSON","stringify","manager","insertMediaAttachment","useImperativeHandle","setContent","_blocks","getText","getBlocks","clear","focus","blur","toggleBold","toggleItalic","toggleUnderline","toggleStrikethrough","toggleCode","toggleHighlight","_color","setHeading","setBulletList","setNumberedList","setQuote","setChecklist","setParagraph","insertLink","_url","_text","undo","redo","clearFormatting","indent","outdent","setAlignment","_alignment","toggleChecklistItem","handleContentChange","blocks","blocksJson","parse","contentEvent","text","delta","onContentChange","handleSelectionChange","selectionEvent","start","end","onSelectionChange","handleFocus","onFocus","handleBlur","onBlur","handleActiveStylesChange","onActiveStylesChange","combinedStyle","useMemo","style","minHeight","createElement","placeholder","initialContentJson","initialContent","editable","readOnly","selectable","maxHeight","numberOfLines","showToolbar","toolbarOptions","variant","fontFamily","fontSize","onEditorFocus","onEditorBlur","onSizeChange","displayName","DEFAULT_TOOLBAR_OPTIONS"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAMV,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AASjB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,WAAW,2BAA4B,SAAQ,mBAAmB;IACtE,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC5D;AAED,QAAA,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAMV,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AASjB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,WAAW,2BAA4B,SAAQ,mBAAmB;IACtE,oBAAoB,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC5D;AAED,QAAA,MAAM,cAAc,uGAwPnB,CAAC;AAIF,eAAe,cAAc,CAAC;AAC9B,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,YAAY,EACV,KAAK,EACL,SAAS,EACT,UAAU,EACV,SAAS,EACT,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,YAAY,EACZ,SAAS,GACV,MAAM,SAAS,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaitrabhairappa/react-native-rich-text-editor",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.5.0",
|
|
4
4
|
"description": "A high-performance native rich text editor for React Native (New Architecture / Fabric only)",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
package/src/index.tsx
CHANGED
|
@@ -39,7 +39,13 @@ export interface RichTextEditorPropsExtended extends RichTextEditorProps {
|
|
|
39
39
|
const RichTextEditor = React.forwardRef<RichTextEditorRef, RichTextEditorPropsExtended>(
|
|
40
40
|
(props, ref) => {
|
|
41
41
|
const nativeRef = React.useRef<React.ElementRef<typeof RichTextEditorViewNative>>(null);
|
|
42
|
-
const
|
|
42
|
+
const [nativeHeight, setNativeHeight] = React.useState<number | undefined>(undefined);
|
|
43
|
+
const handleSizeChange = React.useCallback((event: SizeChangeEvent) => {
|
|
44
|
+
const h = event.nativeEvent.height;
|
|
45
|
+
if (h > 0) {
|
|
46
|
+
setNativeHeight(h);
|
|
47
|
+
}
|
|
48
|
+
}, []);
|
|
43
49
|
|
|
44
50
|
const dispatchAndroidCommand = React.useCallback(
|
|
45
51
|
(commandName: string, args: (string | number | boolean)[] = []) => {
|
|
@@ -249,7 +255,10 @@ const RichTextEditor = React.forwardRef<RichTextEditorRef, RichTextEditorPropsEx
|
|
|
249
255
|
[props.onActiveStylesChange],
|
|
250
256
|
);
|
|
251
257
|
|
|
252
|
-
const combinedStyle =
|
|
258
|
+
const combinedStyle = React.useMemo(
|
|
259
|
+
() => [props.style, nativeHeight ? { minHeight: nativeHeight } : undefined],
|
|
260
|
+
[props.style, nativeHeight],
|
|
261
|
+
);
|
|
253
262
|
|
|
254
263
|
return (
|
|
255
264
|
<RichTextEditorViewNative
|