@openeditor/react-native-prose-editor 0.0.2

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.
Files changed (91) hide show
  1. package/LICENSE +160 -0
  2. package/README.md +180 -0
  3. package/android/build.gradle +69 -0
  4. package/android/consumer-rules.pro +18 -0
  5. package/android/src/androidTest/AndroidManifest.xml +8 -0
  6. package/android/src/androidTest/java/com/apollohg/editor/MeasureHeightInstrumentedTest.kt +53 -0
  7. package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceCollaborationInitialSyncTest.kt +241 -0
  8. package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceImeRegressionTest.kt +338 -0
  9. package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceOutsideTapTest.kt +789 -0
  10. package/android/src/androidTest/java/com/apollohg/editor/NativeDevicePerformanceTest.kt +350 -0
  11. package/android/src/androidTest/java/com/apollohg/editor/NativeEditorOutsideTapActivity.kt +5 -0
  12. package/android/src/main/assets/editor-icons/MaterialIcons.json +2236 -0
  13. package/android/src/main/assets/editor-icons/MaterialIcons.ttf +0 -0
  14. package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +50 -0
  15. package/android/src/main/java/com/apollohg/editor/EditorAddons.kt +135 -0
  16. package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +4527 -0
  17. package/android/src/main/java/com/apollohg/editor/EditorHeightBehavior.kt +14 -0
  18. package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +999 -0
  19. package/android/src/main/java/com/apollohg/editor/EditorTheme.kt +474 -0
  20. package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +199 -0
  21. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +3137 -0
  22. package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +561 -0
  23. package/android/src/main/java/com/apollohg/editor/NativeProseViewerExpoView.kt +315 -0
  24. package/android/src/main/java/com/apollohg/editor/NativeToolbar.kt +1413 -0
  25. package/android/src/main/java/com/apollohg/editor/PositionBridge.kt +133 -0
  26. package/android/src/main/java/com/apollohg/editor/RemoteSelectionOverlayView.kt +315 -0
  27. package/android/src/main/java/com/apollohg/editor/RenderBridge.kt +2172 -0
  28. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +399 -0
  29. package/android/src/sharedTest/java/com/apollohg/editor/NativePerformanceSupport.kt +482 -0
  30. package/android/src/test/java/com/apollohg/editor/CaretGeometryTest.kt +137 -0
  31. package/android/src/test/java/com/apollohg/editor/EditorEditTextHardwareKeyTest.kt +321 -0
  32. package/android/src/test/java/com/apollohg/editor/EditorInputConnectionTest.kt +4202 -0
  33. package/android/src/test/java/com/apollohg/editor/NativeEditorExpoViewTest.kt +2581 -0
  34. package/android/src/test/java/com/apollohg/editor/NativeEditorModuleTest.kt +27 -0
  35. package/android/src/test/java/com/apollohg/editor/NativePerformanceTest.kt +197 -0
  36. package/android/src/test/java/com/apollohg/editor/NativeProseViewerExpoViewTest.kt +84 -0
  37. package/android/src/test/java/com/apollohg/editor/NativeToolbarTest.kt +544 -0
  38. package/android/src/test/java/com/apollohg/editor/PositionBridgeTest.kt +461 -0
  39. package/android/src/test/java/com/apollohg/editor/RenderBridgeTest.kt +2054 -0
  40. package/android/src/test/java/com/apollohg/editor/RichTextEditorViewTest.kt +1367 -0
  41. package/app.plugin.js +62 -0
  42. package/dist/EditorTheme.d.ts +113 -0
  43. package/dist/EditorTheme.js +29 -0
  44. package/dist/EditorToolbar.d.ts +191 -0
  45. package/dist/EditorToolbar.js +1095 -0
  46. package/dist/NativeEditorBridge.d.ts +325 -0
  47. package/dist/NativeEditorBridge.js +933 -0
  48. package/dist/NativeProseViewer.d.ts +53 -0
  49. package/dist/NativeProseViewer.js +480 -0
  50. package/dist/NativeRichTextEditor.d.ts +183 -0
  51. package/dist/NativeRichTextEditor.js +2574 -0
  52. package/dist/YjsCollaboration.d.ts +90 -0
  53. package/dist/YjsCollaboration.js +743 -0
  54. package/dist/addons.d.ts +100 -0
  55. package/dist/addons.js +82 -0
  56. package/dist/heightCache.d.ts +6 -0
  57. package/dist/heightCache.js +45 -0
  58. package/dist/index.d.ts +10 -0
  59. package/dist/index.js +30 -0
  60. package/dist/schemas.d.ts +37 -0
  61. package/dist/schemas.js +263 -0
  62. package/dist/useNativeEditor.d.ts +42 -0
  63. package/dist/useNativeEditor.js +124 -0
  64. package/expo-module.config.json +9 -0
  65. package/ios/EditorAddons.swift +327 -0
  66. package/ios/EditorCore.xcframework/Info.plist +44 -0
  67. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  68. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  69. package/ios/EditorLayoutManager.swift +774 -0
  70. package/ios/EditorTheme.swift +515 -0
  71. package/ios/Generated_editor_core.swift +1513 -0
  72. package/ios/NativeEditorExpoView.swift +3593 -0
  73. package/ios/NativeEditorModule.swift +624 -0
  74. package/ios/NativeProseViewerExpoView.swift +276 -0
  75. package/ios/PositionBridge.swift +558 -0
  76. package/ios/ReactNativeProseEditor.podspec +49 -0
  77. package/ios/RenderBridge.swift +1708 -0
  78. package/ios/RichTextEditorView.swift +6150 -0
  79. package/ios/Tests/NativePerformanceTests.swift +687 -0
  80. package/ios/Tests/PositionBridgeTests.swift +706 -0
  81. package/ios/Tests/RenderBridgeTests.swift +2236 -0
  82. package/ios/Tests/RichTextEditorViewTests.swift +6548 -0
  83. package/ios/editor_coreFFI/editor_coreFFI.h +1289 -0
  84. package/ios/editor_coreFFI/module.modulemap +7 -0
  85. package/ios/editor_coreFFI.h +904 -0
  86. package/ios/editor_coreFFI.modulemap +7 -0
  87. package/package.json +74 -0
  88. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  89. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  90. package/rust/android/x86_64/libeditor_core.so +0 -0
  91. package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +2563 -0
@@ -0,0 +1,321 @@
1
+ package com.openeditor.editor
2
+
3
+ import android.view.KeyEvent
4
+ import android.view.inputmethod.EditorInfo
5
+ import org.junit.Assert.assertEquals
6
+ import org.junit.Assert.assertNotNull
7
+ import org.junit.Assert.assertTrue
8
+ import org.junit.Test
9
+ import org.junit.runner.RunWith
10
+ import org.robolectric.RobolectricTestRunner
11
+ import org.robolectric.RuntimeEnvironment
12
+ import org.robolectric.annotation.Config
13
+
14
+ @RunWith(RobolectricTestRunner::class)
15
+ @Config(sdk = [34])
16
+ class EditorEditTextHardwareKeyTest {
17
+
18
+ @Test
19
+ fun `hardware backspace deletes on first key press in dev mode`() {
20
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
21
+ editText.setText("abc")
22
+ editText.setSelection(3)
23
+
24
+ val downEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)
25
+ val upEvent = KeyEvent(downEvent.downTime, downEvent.eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL, 0)
26
+
27
+ val handledDown = editText.dispatchKeyEvent(downEvent)
28
+ val handledUp = editText.dispatchKeyEvent(upEvent)
29
+
30
+ assertTrue(handledDown)
31
+ assertTrue(handledUp)
32
+ assertEquals("ab", editText.text?.toString())
33
+ assertEquals(2, editText.selectionStart)
34
+ assertEquals(2, editText.selectionEnd)
35
+ }
36
+
37
+ @Test
38
+ fun `duplicate hardware backspace from dispatch and input connection deletes once`() {
39
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
40
+ editText.setText("abc")
41
+ editText.setSelection(3)
42
+ val inputConnection = editText.onCreateInputConnection(EditorInfo())
43
+ assertNotNull(inputConnection)
44
+
45
+ val downEvent = KeyEvent(100L, 100L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
46
+
47
+ assertTrue(editText.dispatchKeyEvent(downEvent))
48
+ assertTrue(inputConnection!!.sendKeyEvent(downEvent))
49
+
50
+ assertEquals("ab", editText.text?.toString())
51
+ assertEquals(2, editText.selectionStart)
52
+ assertEquals(2, editText.selectionEnd)
53
+ }
54
+
55
+ @Test
56
+ fun `duplicate hardware backspace with rewrapped event time deletes once`() {
57
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
58
+ editText.setText("abc")
59
+ editText.setSelection(3)
60
+ val inputConnection = editText.onCreateInputConnection(EditorInfo())
61
+ assertNotNull(inputConnection)
62
+
63
+ val dispatchedEvent = KeyEvent(100L, 100L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
64
+ val rewrappedEvent = KeyEvent(100L, 101L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
65
+
66
+ assertTrue(editText.dispatchKeyEvent(dispatchedEvent))
67
+ assertTrue(inputConnection!!.sendKeyEvent(rewrappedEvent))
68
+
69
+ assertEquals("ab", editText.text?.toString())
70
+ assertEquals(2, editText.selectionStart)
71
+ assertEquals(2, editText.selectionEnd)
72
+ }
73
+
74
+ @Test
75
+ fun `late duplicate hardware backspace after key up deletes once`() {
76
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
77
+ editText.setText("abc")
78
+ editText.setSelection(3)
79
+ val inputConnection = editText.onCreateInputConnection(EditorInfo())
80
+ assertNotNull(inputConnection)
81
+
82
+ val downEvent = KeyEvent(100L, 100L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
83
+ val upEvent = KeyEvent(100L, 102L, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL, 0)
84
+ val lateDuplicateDown = KeyEvent(100L, 103L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
85
+
86
+ assertTrue(editText.dispatchKeyEvent(downEvent))
87
+ assertTrue(editText.dispatchKeyEvent(upEvent))
88
+ assertTrue(inputConnection!!.sendKeyEvent(lateDuplicateDown))
89
+
90
+ assertEquals("ab", editText.text?.toString())
91
+ assertEquals(2, editText.selectionStart)
92
+ assertEquals(2, editText.selectionEnd)
93
+ }
94
+
95
+ @Test
96
+ fun `duplicate printable hardware key from dispatch and input connection inserts once`() {
97
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
98
+ editText.setText("")
99
+ editText.setSelection(0)
100
+ val inputConnection = editText.onCreateInputConnection(EditorInfo())
101
+ assertNotNull(inputConnection)
102
+
103
+ val downEvent = KeyEvent(100L, 100L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A, 0)
104
+
105
+ assertTrue(editText.dispatchKeyEvent(downEvent))
106
+ assertTrue(inputConnection!!.sendKeyEvent(downEvent))
107
+
108
+ assertEquals("a", editText.text?.toString())
109
+ assertEquals(1, editText.selectionStart)
110
+ assertEquals(1, editText.selectionEnd)
111
+ }
112
+
113
+ @Test
114
+ fun `duplicate hardware forward delete from dispatch and input connection deletes once`() {
115
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
116
+ editText.setText("abc")
117
+ editText.setSelection(1)
118
+ val inputConnection = editText.onCreateInputConnection(EditorInfo())
119
+ assertNotNull(inputConnection)
120
+
121
+ val downEvent = KeyEvent(100L, 100L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FORWARD_DEL, 0)
122
+
123
+ assertTrue(editText.dispatchKeyEvent(downEvent))
124
+ assertTrue(inputConnection!!.sendKeyEvent(downEvent))
125
+
126
+ assertEquals("ac", editText.text?.toString())
127
+ assertEquals(1, editText.selectionStart)
128
+ assertEquals(1, editText.selectionEnd)
129
+ }
130
+
131
+ @Test
132
+ fun `bound duplicate hardware forward delete with rewrapped event time deletes once in rust`() {
133
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
134
+ editText.isApplyingRustState = true
135
+ editText.setText("abc")
136
+ editText.isApplyingRustState = false
137
+ editText.setSelection(1)
138
+ editText.editorId = 1
139
+ val inputConnection = editText.onCreateInputConnection(EditorInfo())
140
+ assertNotNull(inputConnection)
141
+
142
+ val dispatchedEvent = KeyEvent(
143
+ 100L,
144
+ 100L,
145
+ KeyEvent.ACTION_DOWN,
146
+ KeyEvent.KEYCODE_FORWARD_DEL,
147
+ 0
148
+ )
149
+ val rewrappedEvent = KeyEvent(
150
+ 100L,
151
+ 101L,
152
+ KeyEvent.ACTION_DOWN,
153
+ KeyEvent.KEYCODE_FORWARD_DEL,
154
+ 0
155
+ )
156
+ var deleteCount = 0
157
+ var deletedRange: Pair<Int, Int>? = null
158
+ editText.onDeleteRangeInRustForTesting = { scalarFrom, scalarTo ->
159
+ deleteCount += 1
160
+ deletedRange = scalarFrom to scalarTo
161
+ }
162
+
163
+ assertTrue(editText.dispatchKeyEvent(dispatchedEvent))
164
+ assertTrue(inputConnection!!.sendKeyEvent(rewrappedEvent))
165
+
166
+ assertEquals(1, deleteCount)
167
+ assertEquals(1 to 2, deletedRange)
168
+ }
169
+
170
+ @Test
171
+ fun `hardware forward delete routes scalar range through rust`() {
172
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
173
+ editText.isApplyingRustState = true
174
+ editText.setText("A😀B")
175
+ editText.isApplyingRustState = false
176
+ editText.setSelection(1)
177
+ editText.editorId = 1
178
+
179
+ var deletedRange: Pair<Int, Int>? = null
180
+ editText.onDeleteRangeInRustForTesting = { scalarFrom, scalarTo ->
181
+ deletedRange = scalarFrom to scalarTo
182
+ }
183
+
184
+ val downEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FORWARD_DEL)
185
+
186
+ assertTrue(editText.dispatchKeyEvent(downEvent))
187
+
188
+ assertEquals(1 to 2, deletedRange)
189
+ }
190
+
191
+ @Test
192
+ fun `hardware backspace repeat events continue deleting`() {
193
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
194
+ editText.setText("abc")
195
+ editText.setSelection(3)
196
+
197
+ val firstDown = KeyEvent(100L, 100L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0)
198
+ val repeatDown = KeyEvent(100L, 120L, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 1)
199
+
200
+ assertTrue(editText.dispatchKeyEvent(firstDown))
201
+ assertTrue(editText.dispatchKeyEvent(repeatDown))
202
+
203
+ assertEquals("a", editText.text?.toString())
204
+ assertEquals(1, editText.selectionStart)
205
+ assertEquals(1, editText.selectionEnd)
206
+ }
207
+
208
+ @Test
209
+ fun `read only hardware backspace is consumed without mutating text`() {
210
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
211
+ editText.setText("abc")
212
+ editText.setSelection(3)
213
+ editText.isEditable = false
214
+
215
+ val downEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)
216
+ val upEvent = KeyEvent(downEvent.downTime, downEvent.eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL, 0)
217
+
218
+ assertTrue(editText.dispatchKeyEvent(downEvent))
219
+ assertTrue(editText.dispatchKeyEvent(upEvent))
220
+ assertEquals("abc", editText.text?.toString())
221
+ assertEquals(3, editText.selectionStart)
222
+ assertEquals(3, editText.selectionEnd)
223
+ }
224
+
225
+ @Test
226
+ fun `read only printable hardware key is consumed without mutating text`() {
227
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
228
+ editText.setText("abc")
229
+ editText.setSelection(3)
230
+ editText.isEditable = false
231
+
232
+ val downEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)
233
+ val upEvent = KeyEvent(downEvent.downTime, downEvent.eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A, 0)
234
+
235
+ assertTrue(editText.dispatchKeyEvent(downEvent))
236
+ assertTrue(editText.dispatchKeyEvent(upEvent))
237
+ assertEquals("abc", editText.text?.toString())
238
+ assertEquals(3, editText.selectionStart)
239
+ assertEquals(3, editText.selectionEnd)
240
+ }
241
+
242
+ @Test
243
+ fun `read only forward delete hardware key is consumed without mutating text`() {
244
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
245
+ editText.setText("abc")
246
+ editText.setSelection(1)
247
+ editText.isEditable = false
248
+
249
+ val downEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FORWARD_DEL)
250
+ val upEvent = KeyEvent(
251
+ downEvent.downTime,
252
+ downEvent.eventTime,
253
+ KeyEvent.ACTION_UP,
254
+ KeyEvent.KEYCODE_FORWARD_DEL,
255
+ 0
256
+ )
257
+
258
+ assertTrue(editText.dispatchKeyEvent(downEvent))
259
+ assertTrue(editText.dispatchKeyEvent(upEvent))
260
+ assertEquals("abc", editText.text?.toString())
261
+ assertEquals(1, editText.selectionStart)
262
+ assertEquals(1, editText.selectionEnd)
263
+ }
264
+
265
+ @Test
266
+ fun `soft backspace over empty block placeholder routes caret scalar through fallback`() {
267
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
268
+ editText.editorId = 1
269
+ editText.isApplyingRustState = true
270
+ editText.setText("\u200B")
271
+ editText.isApplyingRustState = false
272
+ editText.setSelection(1)
273
+
274
+ var fallbackSelection: Pair<Int, Int>? = null
275
+ editText.onDeleteBackwardAtSelectionScalarInRustForTesting = { anchor, head ->
276
+ fallbackSelection = anchor to head
277
+ }
278
+
279
+ editText.handleDelete(1, 0)
280
+
281
+ assertEquals(1 to 1, fallbackSelection)
282
+ }
283
+
284
+ @Test
285
+ fun `soft backspace over escaped list placeholder routes caret scalar through fallback`() {
286
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
287
+ editText.editorId = 1
288
+ editText.isApplyingRustState = true
289
+ editText.setText("\u2022 A\n\u2022 B\n\u200B")
290
+ editText.isApplyingRustState = false
291
+ editText.setSelection(editText.text?.length ?: 0)
292
+
293
+ var fallbackSelection: Pair<Int, Int>? = null
294
+ editText.onDeleteBackwardAtSelectionScalarInRustForTesting = { anchor, head ->
295
+ fallbackSelection = anchor to head
296
+ }
297
+
298
+ editText.handleDelete(1, 0)
299
+
300
+ assertEquals(9 to 9, fallbackSelection)
301
+ }
302
+
303
+ @Test
304
+ fun `hardware backspace over escaped list placeholder routes caret scalar through fallback`() {
305
+ val editText = EditorEditText(RuntimeEnvironment.getApplication())
306
+ editText.editorId = 1
307
+ editText.isApplyingRustState = true
308
+ editText.setText("\u2022 A\n\u2022 B\n\u200B")
309
+ editText.isApplyingRustState = false
310
+ editText.setSelection(editText.text?.length ?: 0)
311
+
312
+ var fallbackSelection: Pair<Int, Int>? = null
313
+ editText.onDeleteBackwardAtSelectionScalarInRustForTesting = { anchor, head ->
314
+ fallbackSelection = anchor to head
315
+ }
316
+
317
+ editText.handleBackspace()
318
+
319
+ assertEquals(9 to 9, fallbackSelection)
320
+ }
321
+ }