@chaitrabhairappa/react-native-rich-text-editor 1.0.7 → 2.0.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 CHANGED
@@ -27,6 +27,37 @@ Unlike other rich text editor packages that rely on HTML and WebView, this libra
27
27
  - Floating toolbar with customizable options
28
28
  - Two variants: outlined and flat
29
29
  - Auto-growing height
30
+ - **Delta-based content updates** for optimized performance
31
+ - **Synchronous style detection** via `onActiveStylesChange`
32
+
33
+ ## Why Delta-Based Updates?
34
+
35
+ Unlike other editors that send the **entire document** on every keystroke, this library includes **delta information** — only what changed.
36
+
37
+ ```typescript
38
+ onContentChange={(event) => {
39
+ // Full content (for saving)
40
+ console.log(event.nativeEvent.text);
41
+ console.log(event.nativeEvent.blocks);
42
+
43
+ // Delta (for optimized processing)
44
+ console.log(event.nativeEvent.delta);
45
+ // { type: "insert", position: 50, text: "a" }
46
+ }}
47
+ ```
48
+
49
+ | Delta Type | When | Data |
50
+ |------------|------|------|
51
+ | `insert` | User types | `position`, `text` |
52
+ | `delete` | User deletes | `position`, `length` |
53
+ | `replace` | Selection replaced | `position`, `length`, `text` |
54
+ | `format` | Style applied | `position`, `length`, `style` |
55
+
56
+ **Benefits:**
57
+ - **Server sync** — Send only deltas instead of full document
58
+ - **Collaborative editing** — Apply remote changes efficiently
59
+ - **Analytics** — Track exactly what users type/delete
60
+ - **Performance** — Process small changes without parsing entire content
30
61
 
31
62
  ## Installation
32
63
 
@@ -12,22 +12,23 @@ buildscript {
12
12
  }
13
13
  }
14
14
 
15
- def isNewArchitectureEnabled() {
16
- return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
17
- }
18
-
19
15
  apply plugin: 'com.android.library'
20
16
  apply plugin: 'kotlin-android'
17
+ apply plugin: 'com.facebook.react'
21
18
 
22
19
  android {
23
20
  namespace "com.richtext.editor"
24
21
  compileSdkVersion safeExtGet('compileSdkVersion', 34)
25
22
 
26
23
  defaultConfig {
27
- minSdkVersion safeExtGet('minSdkVersion', 21)
24
+ minSdkVersion safeExtGet('minSdkVersion', 23)
28
25
  targetSdkVersion safeExtGet('targetSdkVersion', 34)
29
26
  }
30
27
 
28
+ buildFeatures {
29
+ buildConfig true
30
+ }
31
+
31
32
  buildTypes {
32
33
  release {
33
34
  minifyEnabled false
@@ -56,6 +57,12 @@ repositories {
56
57
  }
57
58
 
58
59
  dependencies {
59
- implementation "com.facebook.react:react-native:+"
60
+ implementation "com.facebook.react:react-android:+"
60
61
  implementation "org.jetbrains.kotlin:kotlin-stdlib:${safeExtGet('kotlinVersion', '1.8.0')}"
61
62
  }
63
+
64
+ react {
65
+ jsRootDir = file("../src/")
66
+ libraryName = "RichTextEditorSpec"
67
+ codegenJavaPackageName = "com.richtext.editor"
68
+ }
@@ -113,12 +113,12 @@ class FloatingToolbar(context: Context) : LinearLayout(context) {
113
113
  private fun createArrowButton(text: String): TextView {
114
114
  return TextView(context).apply {
115
115
  this.text = text
116
- textSize = 24f
116
+ textSize = 20f
117
117
  setTextColor(Color.parseColor("#FFFFFF"))
118
118
  gravity = Gravity.CENTER
119
119
  isClickable = true
120
120
  isFocusable = true
121
- val params = LayoutParams((32 * density).toInt(), ViewGroup.LayoutParams.MATCH_PARENT)
121
+ val params = LayoutParams((16 * density).toInt(), ViewGroup.LayoutParams.MATCH_PARENT)
122
122
  layoutParams = params
123
123
  // Add touch feedback
124
124
  val bg = GradientDrawable().apply {
@@ -190,7 +190,7 @@ class FloatingToolbar(context: Context) : LinearLayout(context) {
190
190
  }
191
191
 
192
192
  private val iconSize = (20 * density).toInt()
193
- private val iconPadding = (8 * density).toInt()
193
+ private val iconPadding = (10 * density).toInt()
194
194
 
195
195
  private fun createButton(option: String): ImageView? {
196
196
  val drawableResId = getDrawableResId(option)
@@ -290,7 +290,7 @@ class FloatingToolbar(context: Context) : LinearLayout(context) {
290
290
  val screenWidth = context.resources.displayMetrics.widthPixels
291
291
  val maxWidth = (screenWidth * 0.9).toInt()
292
292
  val buttonCount = enabledOptions.size
293
- val calculatedWidth = (buttonCount * buttonSize) + ((buttonCount - 1) * buttonSpacing) + (56 * density).toInt()
293
+ val calculatedWidth = (buttonCount * buttonSize) + ((buttonCount - 1) * buttonSpacing) + (48 * density).toInt()
294
294
  return minOf(calculatedWidth, maxWidth)
295
295
  }
296
296
 
@@ -1,13 +1,21 @@
1
1
  package com.richtext.editor
2
2
 
3
- import com.facebook.react.ReactPackage
3
+ import com.facebook.react.TurboReactPackage
4
4
  import com.facebook.react.bridge.NativeModule
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.model.ReactModuleInfo
7
+ import com.facebook.react.module.model.ReactModuleInfoProvider
6
8
  import com.facebook.react.uimanager.ViewManager
7
9
 
8
- class RichTextEditorPackage : ReactPackage {
9
- override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
- return emptyList()
10
+ class RichTextEditorPackage : TurboReactPackage() {
11
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
12
+ return null
13
+ }
14
+
15
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
16
+ return ReactModuleInfoProvider {
17
+ mapOf()
18
+ }
11
19
  }
12
20
 
13
21
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
@@ -45,6 +45,9 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
45
45
  private var minHeightPx: Float = 0f
46
46
  private var isInitialized = false
47
47
 
48
+ private var previousText: String = ""
49
+ private var pendingDelta: Map<String, Any>? = null
50
+
48
51
  // For flat variant bottom border
49
52
  private val bottomBorderPaint = Paint().apply {
50
53
  color = Color.parseColor("#E0E0E0")
@@ -112,13 +115,57 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
112
115
  setupToolbar()
113
116
 
114
117
  addTextChangedListener(object : TextWatcher {
115
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
116
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
118
+ private var changeStart = 0
119
+ private var removedCount = 0
120
+ private var addedCount = 0
121
+
122
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
123
+ changeStart = start
124
+ removedCount = count
125
+ addedCount = after
126
+ }
127
+
128
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
129
+ // Capture delta information
130
+ if (!isInternalChange && s != null) {
131
+ val newText = s.toString()
132
+ val deltaMap = mutableMapOf<String, Any>()
133
+
134
+ when {
135
+ removedCount == 0 && addedCount > 0 -> {
136
+ // Insert
137
+ deltaMap["type"] = "insert"
138
+ deltaMap["position"] = changeStart
139
+ deltaMap["text"] = newText.substring(start, start + count)
140
+ }
141
+ removedCount > 0 && addedCount == 0 -> {
142
+ // Delete
143
+ deltaMap["type"] = "delete"
144
+ deltaMap["position"] = changeStart
145
+ deltaMap["length"] = removedCount
146
+ }
147
+ removedCount > 0 && addedCount > 0 -> {
148
+ // Replace
149
+ deltaMap["type"] = "replace"
150
+ deltaMap["position"] = changeStart
151
+ deltaMap["length"] = removedCount
152
+ deltaMap["text"] = newText.substring(start, start + count)
153
+ }
154
+ }
155
+
156
+ if (deltaMap.isNotEmpty()) {
157
+ pendingDelta = deltaMap
158
+ }
159
+ }
160
+ }
161
+
117
162
  override fun afterTextChanged(s: Editable?) {
118
163
  if (!isInternalChange) {
119
- sendContentChange()
164
+ sendContentChangeWithDelta()
120
165
  saveToUndoStack()
166
+ pendingDelta = null
121
167
  }
168
+ previousText = s?.toString() ?: ""
122
169
  post { updateContentSize() }
123
170
  }
124
171
  })
@@ -213,6 +260,9 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
213
260
  map.putInt("end", selEnd)
214
261
  sendEvent("onSelectionChange", map)
215
262
 
263
+ // Emit active styles synchronously for instant toolbar updates
264
+ emitActiveStyles()
265
+
216
266
  // Show/hide toolbar based on selection
217
267
  if (selStart != selEnd && showToolbar && hasFocus()) {
218
268
  android.util.Log.d("RichTextEditor", "Should show toolbar - selection exists")
@@ -231,6 +281,78 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
231
281
  }
232
282
  }
233
283
 
284
+ // Synchronous style detection - emits current active styles to JS
285
+ private fun emitActiveStyles() {
286
+ val start = selectionStart
287
+ val end = selectionEnd
288
+ val spannable = text as? Spanned
289
+
290
+ var hasBold = false
291
+ var hasItalic = false
292
+ var hasUnderline = false
293
+ var hasStrikethrough = false
294
+ var hasCode = false
295
+ var hasHighlight = false
296
+ var blockType = "paragraph"
297
+ var alignment = "left"
298
+
299
+ if (spannable != null && start <= end) {
300
+ // Check for style spans
301
+ spannable.getSpans(start, end.coerceAtLeast(start + 1), StyleSpan::class.java).forEach { span ->
302
+ when (span.style) {
303
+ Typeface.BOLD -> hasBold = true
304
+ Typeface.ITALIC -> hasItalic = true
305
+ Typeface.BOLD_ITALIC -> {
306
+ hasBold = true
307
+ hasItalic = true
308
+ }
309
+ }
310
+ }
311
+
312
+ hasUnderline = spannable.getSpans(start, end.coerceAtLeast(start + 1), UnderlineSpan::class.java).isNotEmpty()
313
+ hasStrikethrough = spannable.getSpans(start, end.coerceAtLeast(start + 1), StrikethroughSpan::class.java).isNotEmpty()
314
+ hasCode = spannable.getSpans(start, end.coerceAtLeast(start + 1), TypefaceSpan::class.java).any { it.family == "monospace" }
315
+
316
+ // Check highlight (but not code background)
317
+ val bgSpans = spannable.getSpans(start, end.coerceAtLeast(start + 1), BackgroundColorSpan::class.java)
318
+ hasHighlight = bgSpans.any {
319
+ val color = it.backgroundColor
320
+ color == Color.parseColor("#80FFFF00") || color == Color.YELLOW
321
+ }
322
+
323
+ // Check block type from line content
324
+ val lineText = getCurrentLineText()
325
+ blockType = when {
326
+ lineText.startsWith("• ") -> "bullet"
327
+ lineText.matches(Regex("^\\d+\\.\\s.*")) -> "numbered"
328
+ lineText.startsWith("☐ ") || lineText.startsWith("☑ ") -> "checklist"
329
+ lineText.startsWith("\"") && lineText.endsWith("\"") -> "quote"
330
+ spannable.getSpans(start, end.coerceAtLeast(start + 1), RelativeSizeSpan::class.java).any { it.sizeChange > 1.2f } -> "heading"
331
+ else -> "paragraph"
332
+ }
333
+
334
+ // Check alignment
335
+ spannable.getSpans(start, end.coerceAtLeast(start + 1), AlignmentSpan.Standard::class.java).firstOrNull()?.let { span ->
336
+ alignment = when (span.alignment) {
337
+ Layout.Alignment.ALIGN_CENTER -> "center"
338
+ Layout.Alignment.ALIGN_OPPOSITE -> "right"
339
+ else -> "left"
340
+ }
341
+ }
342
+ }
343
+
344
+ val map = Arguments.createMap()
345
+ map.putBoolean("bold", hasBold)
346
+ map.putBoolean("italic", hasItalic)
347
+ map.putBoolean("underline", hasUnderline)
348
+ map.putBoolean("strikethrough", hasStrikethrough)
349
+ map.putBoolean("code", hasCode)
350
+ map.putBoolean("highlight", hasHighlight)
351
+ map.putString("blockType", blockType)
352
+ map.putString("alignment", alignment)
353
+ sendEvent("onActiveStylesChange", map)
354
+ }
355
+
234
356
  private val hideToolbarRunnable = Runnable {
235
357
  android.util.Log.d("RichTextEditor", "hideToolbarRunnable: selectionStart=$selectionStart, selectionEnd=$selectionEnd")
236
358
  if (selectionStart == selectionEnd) {
@@ -583,16 +705,44 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
583
705
  }
584
706
 
585
707
  private fun sendContentChange() {
708
+ sendContentChangeWithDelta(null)
709
+ }
710
+
711
+ private fun sendContentChangeWithDelta(delta: Map<String, Any>? = pendingDelta) {
586
712
  try {
587
713
  val map = Arguments.createMap()
588
714
  map.putString("text", text?.toString() ?: "")
589
- map.putArray("blocks", getBlocksArray())
715
+ // Serialize blocks to JSON string (codegen doesn't support nested arrays)
716
+ map.putString("blocksJson", getBlocksJsonString())
717
+
718
+ // Include delta information if available
719
+ if (delta != null) {
720
+ val deltaMap = Arguments.createMap()
721
+ delta["type"]?.let { deltaMap.putString("type", it as String) }
722
+ delta["position"]?.let { deltaMap.putInt("position", it as Int) }
723
+ delta["length"]?.let { deltaMap.putInt("length", it as Int) }
724
+ delta["text"]?.let { deltaMap.putString("text", it as String) }
725
+ delta["style"]?.let { deltaMap.putString("style", it as String) }
726
+ map.putMap("delta", deltaMap)
727
+ }
728
+
590
729
  sendEvent("onContentChange", map)
591
730
  } catch (e: Exception) {
592
731
  e.printStackTrace()
593
732
  }
594
733
  }
595
734
 
735
+ // Send format delta when applying styles
736
+ private fun sendFormatDelta(style: String, start: Int, end: Int) {
737
+ val delta = mapOf(
738
+ "type" to "format",
739
+ "position" to start,
740
+ "length" to (end - start),
741
+ "style" to style
742
+ )
743
+ sendContentChangeWithDelta(delta)
744
+ }
745
+
596
746
  private fun saveToUndoStack() {
597
747
  val currentText = text?.toString() ?: ""
598
748
  if (currentText != lastSavedText) {
@@ -717,6 +867,19 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
717
867
 
718
868
  fun getTextContent(): String = text.toString()
719
869
 
870
+ // Fabric command response methods
871
+ fun emitGetTextResponse() {
872
+ val map = Arguments.createMap()
873
+ map.putString("text", text?.toString() ?: "")
874
+ sendEvent("onGetTextResponse", map)
875
+ }
876
+
877
+ fun emitGetBlocksResponse() {
878
+ val map = Arguments.createMap()
879
+ map.putArray("blocks", getBlocksArray())
880
+ sendEvent("onGetBlocksResponse", map)
881
+ }
882
+
720
883
  fun getBlocksArray(): WritableArray {
721
884
  val blocks = Arguments.createArray()
722
885
  val textContent = text?.toString() ?: ""
@@ -734,6 +897,23 @@ class RichTextEditorView(context: Context) : androidx.appcompat.widget.AppCompat
734
897
  return blocks
735
898
  }
736
899
 
900
+ fun getBlocksJsonString(): String {
901
+ val textContent = text?.toString() ?: ""
902
+ if (textContent.isEmpty()) {
903
+ return "[]"
904
+ }
905
+ val jsonArray = org.json.JSONArray()
906
+ val lines = textContent.split("\n")
907
+ lines.forEach { line ->
908
+ val block = org.json.JSONObject()
909
+ block.put("type", "paragraph")
910
+ block.put("text", line)
911
+ block.put("styles", org.json.JSONArray())
912
+ jsonArray.put(block)
913
+ }
914
+ return jsonArray.toString()
915
+ }
916
+
737
917
  fun clearContent() {
738
918
  isInternalChange = true
739
919
  text?.clear()
@@ -1,14 +1,19 @@
1
1
  package com.richtext.editor
2
2
 
3
3
  import com.facebook.react.bridge.ReadableArray
4
- import com.facebook.react.common.MapBuilder
4
+ import com.facebook.react.module.annotations.ReactModule
5
5
  import com.facebook.react.uimanager.SimpleViewManager
6
6
  import com.facebook.react.uimanager.ThemedReactContext
7
7
  import com.facebook.react.uimanager.annotations.ReactProp
8
8
 
9
+ @ReactModule(name = RichTextEditorViewManager.NAME)
9
10
  class RichTextEditorViewManager : SimpleViewManager<RichTextEditorView>() {
10
11
 
11
- override fun getName(): String = "RichTextEditorView"
12
+ companion object {
13
+ const val NAME = "RichTextEditorView"
14
+ }
15
+
16
+ override fun getName(): String = NAME
12
17
 
13
18
  override fun createViewInstance(reactContext: ThemedReactContext): RichTextEditorView {
14
19
  return RichTextEditorView(reactContext)
@@ -33,9 +38,9 @@ class RichTextEditorViewManager : SimpleViewManager<RichTextEditorView>() {
33
38
  }
34
39
 
35
40
  @ReactProp(name = "maxHeight")
36
- fun setMaxHeight(view: RichTextEditorView, maxHeight: Int) {
41
+ fun setMaxHeight(view: RichTextEditorView, maxHeight: Double) {
37
42
  try {
38
- view.setMaxHeightValue(maxHeight)
43
+ view.setMaxHeightValue(maxHeight.toInt())
39
44
  } catch (e: Exception) {
40
45
  e.printStackTrace()
41
46
  }
@@ -76,36 +81,34 @@ class RichTextEditorViewManager : SimpleViewManager<RichTextEditorView>() {
76
81
  }
77
82
  }
78
83
 
79
- @ReactProp(name = "initialContent")
80
- fun setInitialContent(view: RichTextEditorView, initialContent: ReadableArray?) {
81
- if (initialContent == null || initialContent.size() == 0) return
84
+ @ReactProp(name = "initialContentJson")
85
+ fun setInitialContentJson(view: RichTextEditorView, initialContentJson: String?) {
86
+ if (initialContentJson.isNullOrEmpty()) return
82
87
 
83
88
  try {
89
+ val json = org.json.JSONArray(initialContentJson)
84
90
  val blocksList = mutableListOf<Map<String, Any>>()
85
- for (i in 0 until initialContent.size()) {
86
- val block = initialContent.getMap(i) ?: continue
91
+ for (i in 0 until json.length()) {
92
+ val block = json.getJSONObject(i)
87
93
  val blockMap = mutableMapOf<String, Any>()
88
- blockMap["text"] = block.getString("text") ?: ""
89
- blockMap["type"] = block.getString("type") ?: "paragraph"
94
+ blockMap["text"] = block.optString("text", "")
95
+ blockMap["type"] = block.optString("type", "paragraph")
90
96
 
91
97
  val stylesList = mutableListOf<Map<String, Any>>()
92
- if (block.hasKey("styles")) {
93
- val styles = block.getArray("styles")
94
- if (styles != null) {
95
- for (j in 0 until styles.size()) {
96
- val style = styles.getMap(j) ?: continue
97
- val styleMap = mutableMapOf<String, Any>()
98
- styleMap["style"] = style.getString("style") ?: ""
99
- styleMap["start"] = if (style.hasKey("start")) style.getInt("start") else 0
100
- styleMap["end"] = if (style.hasKey("end")) style.getInt("end") else 0
101
- stylesList.add(styleMap)
102
- }
98
+ val styles = block.optJSONArray("styles")
99
+ if (styles != null) {
100
+ for (j in 0 until styles.length()) {
101
+ val style = styles.getJSONObject(j)
102
+ val styleMap = mutableMapOf<String, Any>()
103
+ styleMap["style"] = style.optString("style", "")
104
+ styleMap["start"] = style.optInt("start", 0)
105
+ styleMap["end"] = style.optInt("end", 0)
106
+ stylesList.add(styleMap)
103
107
  }
104
108
  }
105
109
  blockMap["styles"] = stylesList
106
110
  blocksList.add(blockMap)
107
111
  }
108
- // Delay setting content until view is ready
109
112
  view.post {
110
113
  view.setContent(blocksList)
111
114
  }
@@ -114,123 +117,14 @@ class RichTextEditorViewManager : SimpleViewManager<RichTextEditorView>() {
114
117
  }
115
118
  }
116
119
 
117
- override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
118
- return MapBuilder.builder<String, Any>()
119
- .put("onContentChange", MapBuilder.of("registrationName", "onContentChange"))
120
- .put("onSelectionChange", MapBuilder.of("registrationName", "onSelectionChange"))
121
- .put("onEditorFocus", MapBuilder.of("registrationName", "onEditorFocus"))
122
- .put("onEditorBlur", MapBuilder.of("registrationName", "onEditorBlur"))
123
- .put("onSizeChange", MapBuilder.of("registrationName", "onSizeChange"))
124
- .build()
125
- }
126
-
127
- override fun getCommandsMap(): Map<String, Int>? {
128
- return MapBuilder.builder<String, Int>()
129
- // Content management
130
- .put("setContent", 1)
131
- .put("getText", 2)
132
- .put("getBlocks", 3)
133
- .put("clear", 4)
134
- // Focus management
135
- .put("focus", 5)
136
- .put("blur", 6)
137
- // Text styles
138
- .put("toggleBold", 10)
139
- .put("toggleItalic", 11)
140
- .put("toggleUnderline", 12)
141
- .put("toggleStrikethrough", 13)
142
- .put("toggleCode", 14)
143
- .put("toggleHighlight", 15)
144
- // Block types
145
- .put("setHeading", 16)
146
- .put("setBulletList", 17)
147
- .put("setNumberedList", 18)
148
- .put("setQuote", 19)
149
- .put("setChecklist", 20)
150
- .put("setParagraph", 21)
151
- // Actions
152
- .put("insertLink", 7)
153
- .put("undo", 8)
154
- .put("redo", 9)
155
- .put("clearFormatting", 22)
156
- // Indentation
157
- .put("indent", 23)
158
- .put("outdent", 24)
159
- // Alignment
160
- .put("setAlignment", 25)
161
- // Checklist
162
- .put("toggleChecklistItem", 26)
163
- .build()
164
- }
165
-
166
- override fun receiveCommand(view: RichTextEditorView, commandId: Int, args: ReadableArray?) {
167
- when (commandId) {
168
- 1 -> {
169
- val blocks = args?.getArray(0)
170
- if (blocks != null) {
171
- val blocksList = mutableListOf<Map<String, Any>>()
172
- for (i in 0 until blocks.size()) {
173
- val block = blocks.getMap(i)
174
- val blockMap = mutableMapOf<String, Any>()
175
- blockMap["text"] = block?.getString("text") ?: ""
176
- blockMap["type"] = block?.getString("type") ?: "paragraph"
177
-
178
- val styles = block?.getArray("styles")
179
- if (styles != null) {
180
- val stylesList = mutableListOf<Map<String, Any>>()
181
- for (j in 0 until styles.size()) {
182
- val style = styles.getMap(j)
183
- val styleMap = mutableMapOf<String, Any>()
184
- styleMap["style"] = style?.getString("style") ?: ""
185
- styleMap["start"] = style?.getInt("start") ?: 0
186
- styleMap["end"] = style?.getInt("end") ?: 0
187
- stylesList.add(styleMap)
188
- }
189
- blockMap["styles"] = stylesList
190
- }
191
- blocksList.add(blockMap)
192
- }
193
- view.setContent(blocksList)
194
- }
195
- }
196
- 4 -> view.clearContent()
197
- 5 -> view.focusEditor()
198
- 6 -> view.blurEditor()
199
- 7 -> {
200
- val url = args?.getString(0) ?: ""
201
- val text = args?.getString(1) ?: ""
202
- view.insertLink(url, text)
203
- }
204
- 8 -> view.undo()
205
- 9 -> view.redo()
206
- 10 -> view.toggleBold()
207
- 11 -> view.toggleItalic()
208
- 12 -> view.toggleUnderline()
209
- 13 -> view.toggleStrikethrough()
210
- 14 -> view.toggleCode()
211
- 15 -> {
212
- val color = args?.getString(0)
213
- view.toggleHighlight(color)
214
- }
215
- 16 -> view.setHeading()
216
- 17 -> view.toggleBulletList()
217
- 18 -> view.toggleNumberedList()
218
- 19 -> view.setQuote()
219
- 20 -> view.setChecklist()
220
- 21 -> view.setParagraph()
221
- 22 -> view.clearFormatting()
222
- 23 -> view.indent()
223
- 24 -> view.outdent()
224
- 25 -> {
225
- val alignment = args?.getString(0) ?: "left"
226
- val layoutAlignment = when (alignment) {
227
- "center" -> android.text.Layout.Alignment.ALIGN_CENTER
228
- "right" -> android.text.Layout.Alignment.ALIGN_OPPOSITE
229
- else -> android.text.Layout.Alignment.ALIGN_NORMAL
230
- }
231
- view.setAlignment(layoutAlignment)
232
- }
233
- 26 -> view.toggleChecklistItem()
234
- }
120
+ override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
121
+ val events = mutableMapOf<String, Any>()
122
+ events["onContentChange"] = mapOf("registrationName" to "onContentChange")
123
+ events["onSelectionChange"] = mapOf("registrationName" to "onSelectionChange")
124
+ events["onEditorFocus"] = mapOf("registrationName" to "onEditorFocus")
125
+ events["onEditorBlur"] = mapOf("registrationName" to "onEditorBlur")
126
+ events["onSizeChange"] = mapOf("registrationName" to "onSizeChange")
127
+ events["onActiveStylesChange"] = mapOf("registrationName" to "onActiveStylesChange")
128
+ return events
235
129
  }
236
130
  }