@chaitrabhairappa/react-native-rich-text-editor 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Chaitra Bhairappa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # react-native-richtext-editor
2
+
3
+ A powerful native rich text editor for React Native with support for text formatting, lists, and more. Works on both iOS and Android.
4
+
5
+ ## Features
6
+
7
+ - Bold, Italic, Underline, Strikethrough
8
+ - Code and Highlight formatting
9
+ - Bullet lists and Numbered lists
10
+ - Headings
11
+ - Quotes and Checklists
12
+ - Link insertion
13
+ - Undo/Redo
14
+ - Text alignment (left, center, right)
15
+ - Indent/Outdent
16
+ - Floating toolbar with customizable options
17
+ - Two variants: outlined and flat
18
+ - Auto-growing height
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install react-native-richtext-editor
24
+ # or
25
+ yarn add react-native-richtext-editor
26
+ ```
27
+
28
+ ### iOS
29
+
30
+ ```bash
31
+ cd ios && pod install
32
+ ```
33
+
34
+ ### Android
35
+
36
+ No additional setup required.
37
+
38
+ ## Usage
39
+
40
+ ```tsx
41
+ import React, { useRef } from 'react';
42
+ import { View } from 'react-native';
43
+ import RichTextEditor, {
44
+ RichTextEditorRef,
45
+ Block,
46
+ ContentChangeEvent
47
+ } from 'react-native-richtext-editor';
48
+
49
+ const App = () => {
50
+ const editorRef = useRef<RichTextEditorRef>(null);
51
+
52
+ const handleContentChange = (event: ContentChangeEvent) => {
53
+ console.log('Content changed:', event.nativeEvent.blocks);
54
+ };
55
+
56
+ const initialContent: Block[] = [
57
+ {
58
+ type: 'paragraph',
59
+ text: 'Hello World',
60
+ styles: [{ style: 'bold', start: 0, end: 5 }],
61
+ },
62
+ {
63
+ type: 'bullet',
64
+ text: 'First item',
65
+ styles: [],
66
+ },
67
+ {
68
+ type: 'bullet',
69
+ text: 'Second item',
70
+ styles: [{ style: 'italic', start: 0, end: 6 }],
71
+ },
72
+ ];
73
+
74
+ return (
75
+ <View style={{ flex: 1, padding: 16 }}>
76
+ <RichTextEditor
77
+ ref={editorRef}
78
+ placeholder="Enter text..."
79
+ initialContent={initialContent}
80
+ onContentChange={handleContentChange}
81
+ maxHeight={300}
82
+ variant="outlined"
83
+ />
84
+ </View>
85
+ );
86
+ };
87
+
88
+ export default App;
89
+ ```
90
+
91
+ ## Props
92
+
93
+ | Prop | Type | Default | Description |
94
+ |------|------|---------|-------------|
95
+ | `placeholder` | `string` | `""` | Placeholder text |
96
+ | `initialContent` | `Block[]` | `[]` | Initial content blocks |
97
+ | `readOnly` | `boolean` | `false` | Make editor read-only |
98
+ | `maxHeight` | `number` | `undefined` | Maximum height before scrolling |
99
+ | `showToolbar` | `boolean` | `true` | Show/hide floating toolbar |
100
+ | `toolbarOptions` | `ToolbarOption[]` | All options | Customize toolbar buttons |
101
+ | `variant` | `'outlined' \| 'flat'` | `'outlined'` | Editor style variant |
102
+ | `onContentChange` | `(event: ContentChangeEvent) => void` | `undefined` | Called when content changes |
103
+ | `onSelectionChange` | `(event: SelectionChangeEvent) => void` | `undefined` | Called when selection changes |
104
+ | `onFocus` | `() => void` | `undefined` | Called when editor gains focus |
105
+ | `onBlur` | `() => void` | `undefined` | Called when editor loses focus |
106
+
107
+ ## Ref Methods
108
+
109
+ ```tsx
110
+ const editorRef = useRef<RichTextEditorRef>(null);
111
+
112
+ // Content management
113
+ editorRef.current?.setContent(blocks);
114
+ editorRef.current?.clear();
115
+ const text = await editorRef.current?.getText();
116
+ const blocks = await editorRef.current?.getBlocks();
117
+
118
+ // Focus management
119
+ editorRef.current?.focus();
120
+ editorRef.current?.blur();
121
+
122
+ // Text styles
123
+ editorRef.current?.toggleBold();
124
+ editorRef.current?.toggleItalic();
125
+ editorRef.current?.toggleUnderline();
126
+ editorRef.current?.toggleStrikethrough();
127
+ editorRef.current?.toggleCode();
128
+ editorRef.current?.toggleHighlight();
129
+
130
+ // Block types
131
+ editorRef.current?.setHeading();
132
+ editorRef.current?.setBulletList();
133
+ editorRef.current?.setNumberedList();
134
+ editorRef.current?.setQuote();
135
+ editorRef.current?.setChecklist();
136
+ editorRef.current?.setParagraph();
137
+
138
+ // Actions
139
+ editorRef.current?.insertLink(url, text);
140
+ editorRef.current?.undo();
141
+ editorRef.current?.redo();
142
+ editorRef.current?.clearFormatting();
143
+
144
+ // Indentation
145
+ editorRef.current?.indent();
146
+ editorRef.current?.outdent();
147
+
148
+ // Alignment
149
+ editorRef.current?.setAlignment('left' | 'center' | 'right');
150
+ ```
151
+
152
+ ## Types
153
+
154
+ ```typescript
155
+ interface Block {
156
+ type: BlockType;
157
+ text: string;
158
+ styles: StyleRange[];
159
+ alignment?: TextAlignment;
160
+ checked?: boolean;
161
+ indentLevel?: number;
162
+ }
163
+
164
+ type BlockType = 'paragraph' | 'bullet' | 'numbered' | 'heading' | 'quote' | 'checklist';
165
+ type TextAlignment = 'left' | 'center' | 'right';
166
+
167
+ interface StyleRange {
168
+ style: 'bold' | 'italic' | 'underline' | 'strikethrough' | 'link' | 'code' | 'highlight';
169
+ start: number;
170
+ end: number;
171
+ url?: string;
172
+ highlightColor?: string;
173
+ }
174
+
175
+ type ToolbarOption =
176
+ | 'bold' | 'italic' | 'strikethrough' | 'underline' | 'code' | 'highlight'
177
+ | 'heading' | 'bullet' | 'numbered' | 'quote' | 'checklist'
178
+ | 'link' | 'undo' | 'redo' | 'clearFormatting'
179
+ | 'indent' | 'outdent'
180
+ | 'alignLeft' | 'alignCenter' | 'alignRight';
181
+ ```
182
+
183
+ ## Customizing Toolbar
184
+
185
+ ```tsx
186
+ import RichTextEditor, { ToolbarOption } from 'react-native-richtext-editor';
187
+
188
+ const toolbarOptions: ToolbarOption[] = [
189
+ 'bold',
190
+ 'italic',
191
+ 'underline',
192
+ 'bullet',
193
+ 'numbered',
194
+ ];
195
+
196
+ <RichTextEditor
197
+ toolbarOptions={toolbarOptions}
198
+ // ...
199
+ />
200
+ ```
201
+
202
+ ## Android Setup
203
+
204
+ Add the package to your `MainApplication.java` or `MainApplication.kt`:
205
+
206
+ ```java
207
+ // MainApplication.java
208
+ import com.richtext.editor.RichTextEditorPackage;
209
+
210
+ @Override
211
+ protected List<ReactPackage> getPackages() {
212
+ List<ReactPackage> packages = new PackageList(this).getPackages();
213
+ packages.add(new RichTextEditorPackage());
214
+ return packages;
215
+ }
216
+ ```
217
+
218
+ ## License
219
+
220
+ MIT
@@ -0,0 +1,61 @@
1
+ buildscript {
2
+ ext.safeExtGet = {prop, fallback ->
3
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4
+ }
5
+ repositories {
6
+ google()
7
+ mavenCentral()
8
+ }
9
+ dependencies {
10
+ classpath("com.android.tools.build:gradle:7.4.2")
11
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${safeExtGet('kotlinVersion', '1.8.0')}")
12
+ }
13
+ }
14
+
15
+ def isNewArchitectureEnabled() {
16
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
17
+ }
18
+
19
+ apply plugin: 'com.android.library'
20
+ apply plugin: 'kotlin-android'
21
+
22
+ android {
23
+ namespace "com.richtext.editor"
24
+ compileSdkVersion safeExtGet('compileSdkVersion', 34)
25
+
26
+ defaultConfig {
27
+ minSdkVersion safeExtGet('minSdkVersion', 21)
28
+ targetSdkVersion safeExtGet('targetSdkVersion', 34)
29
+ }
30
+
31
+ buildTypes {
32
+ release {
33
+ minifyEnabled false
34
+ }
35
+ }
36
+
37
+ compileOptions {
38
+ sourceCompatibility JavaVersion.VERSION_17
39
+ targetCompatibility JavaVersion.VERSION_17
40
+ }
41
+
42
+ kotlinOptions {
43
+ jvmTarget = '17'
44
+ }
45
+
46
+ sourceSets {
47
+ main {
48
+ java.srcDirs = ['src/main/java']
49
+ }
50
+ }
51
+ }
52
+
53
+ repositories {
54
+ google()
55
+ mavenCentral()
56
+ }
57
+
58
+ dependencies {
59
+ implementation "com.facebook.react:react-native:+"
60
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:${safeExtGet('kotlinVersion', '1.8.0')}"
61
+ }
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.richtext.editor">
3
+ </manifest>
@@ -0,0 +1,350 @@
1
+ package com.richtext.editor
2
+
3
+ import android.content.Context
4
+ import android.graphics.Color
5
+ import android.graphics.drawable.GradientDrawable
6
+ import android.view.Gravity
7
+ import android.view.View
8
+ import android.view.ViewGroup
9
+ import android.widget.HorizontalScrollView
10
+ import android.widget.LinearLayout
11
+ import android.widget.TextView
12
+ import android.graphics.Typeface
13
+ import android.text.SpannableString
14
+ import android.text.Spanned
15
+ import android.text.style.StrikethroughSpan
16
+ import android.text.style.UnderlineSpan
17
+ import android.text.style.BackgroundColorSpan
18
+
19
+ class FloatingToolbar(context: Context) : LinearLayout(context) {
20
+
21
+ interface ToolbarActionListener {
22
+ fun onBoldClick()
23
+ fun onItalicClick()
24
+ fun onUnderlineClick()
25
+ fun onStrikethroughClick()
26
+ fun onCodeClick()
27
+ fun onHighlightClick()
28
+ fun onHeadingClick()
29
+ fun onBulletListClick()
30
+ fun onNumberedListClick()
31
+ fun onQuoteClick()
32
+ fun onChecklistClick()
33
+ fun onLinkClick()
34
+ fun onUndoClick()
35
+ fun onRedoClick()
36
+ fun onClearFormattingClick()
37
+ fun onIndentClick()
38
+ fun onOutdentClick()
39
+ fun onAlignLeftClick()
40
+ fun onAlignCenterClick()
41
+ fun onAlignRightClick()
42
+ }
43
+
44
+ var listener: ToolbarActionListener? = null
45
+
46
+ private val density = context.resources.displayMetrics.density
47
+ private val buttonSize = (36 * density).toInt()
48
+ private val toolbarHeight = (52 * density).toInt()
49
+ private val buttonSpacing = (8 * density).toInt()
50
+
51
+ private val toolbarBackgroundColor = Color.parseColor("#2D2D2D")
52
+ private val activeColor = Color.parseColor("#5082C8")
53
+ private val inactiveColor = Color.WHITE
54
+
55
+ private val buttons = mutableMapOf<String, TextView>()
56
+ private val buttonContainer: LinearLayout
57
+ private val scrollView: HorizontalScrollView
58
+
59
+ private var enabledOptions: List<String> = listOf(
60
+ "bold", "italic", "underline", "strikethrough", "code", "highlight",
61
+ "heading", "bullet", "numbered", "quote", "checklist",
62
+ "link", "undo", "redo", "clearFormatting",
63
+ "indent", "outdent",
64
+ "alignLeft", "alignCenter", "alignRight"
65
+ )
66
+
67
+ init {
68
+ orientation = HORIZONTAL
69
+ gravity = Gravity.CENTER_VERTICAL
70
+ setPadding((8 * density).toInt(), (8 * density).toInt(), (8 * density).toInt(), (8 * density).toInt())
71
+
72
+ // Set background with rounded corners and shadow
73
+ val bg = GradientDrawable().apply {
74
+ setColor(toolbarBackgroundColor)
75
+ cornerRadius = 10 * density
76
+ }
77
+ background = bg
78
+ elevation = 6 * density
79
+
80
+ // Left arrow
81
+ val leftArrow = createArrowButton("‹").apply {
82
+ setOnClickListener { scrollLeft() }
83
+ }
84
+ addView(leftArrow)
85
+
86
+ // Scroll view for buttons
87
+ scrollView = HorizontalScrollView(context).apply {
88
+ isHorizontalScrollBarEnabled = false
89
+ layoutParams = LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f)
90
+ }
91
+
92
+ buttonContainer = LinearLayout(context).apply {
93
+ orientation = HORIZONTAL
94
+ gravity = Gravity.CENTER_VERTICAL
95
+ }
96
+
97
+ scrollView.addView(buttonContainer)
98
+ addView(scrollView)
99
+
100
+ // Right arrow
101
+ val rightArrow = createArrowButton("›").apply {
102
+ setOnClickListener { scrollRight() }
103
+ }
104
+ addView(rightArrow)
105
+
106
+ buildButtons()
107
+ }
108
+
109
+ private fun createArrowButton(text: String): TextView {
110
+ return TextView(context).apply {
111
+ this.text = text
112
+ textSize = 24f
113
+ setTextColor(Color.parseColor("#FFFFFF"))
114
+ gravity = Gravity.CENTER
115
+ isClickable = true
116
+ isFocusable = true
117
+ val params = LayoutParams((32 * density).toInt(), ViewGroup.LayoutParams.MATCH_PARENT)
118
+ layoutParams = params
119
+ // Add touch feedback
120
+ val bg = GradientDrawable().apply {
121
+ cornerRadius = 4 * density
122
+ setColor(Color.TRANSPARENT)
123
+ }
124
+ background = bg
125
+ }
126
+ }
127
+
128
+ private fun scrollLeft() {
129
+ val scrollAmount = (150 * density).toInt()
130
+ scrollView.smoothScrollBy(-scrollAmount, 0)
131
+ }
132
+
133
+ private fun scrollRight() {
134
+ val scrollAmount = (150 * density).toInt()
135
+ scrollView.smoothScrollBy(scrollAmount, 0)
136
+ }
137
+
138
+ fun setToolbarOptions(options: List<String>?) {
139
+ enabledOptions = options ?: listOf(
140
+ "bold", "italic", "underline", "strikethrough", "code", "highlight",
141
+ "heading", "bullet", "numbered", "quote", "checklist",
142
+ "link", "undo", "redo", "clearFormatting",
143
+ "indent", "outdent",
144
+ "alignLeft", "alignCenter", "alignRight"
145
+ )
146
+ buildButtons()
147
+ }
148
+
149
+ private fun buildButtons() {
150
+ buttonContainer.removeAllViews()
151
+ buttons.clear()
152
+
153
+ for (option in enabledOptions) {
154
+ val button = createButton(option)
155
+ if (button != null) {
156
+ buttons[option] = button
157
+ buttonContainer.addView(button)
158
+ }
159
+ }
160
+ }
161
+
162
+ private fun createButton(option: String): TextView? {
163
+ val button = TextView(context).apply {
164
+ gravity = Gravity.CENTER
165
+ setTextColor(inactiveColor)
166
+
167
+ val bg = GradientDrawable().apply {
168
+ cornerRadius = 6 * density
169
+ setColor(Color.TRANSPARENT)
170
+ }
171
+ background = bg
172
+
173
+ val params = LayoutParams(buttonSize, buttonSize)
174
+ params.marginEnd = buttonSpacing
175
+ layoutParams = params
176
+ }
177
+
178
+ when (option) {
179
+ "bold" -> {
180
+ button.text = "B"
181
+ button.textSize = 18f
182
+ button.setTypeface(null, Typeface.BOLD)
183
+ button.setOnClickListener { listener?.onBoldClick() }
184
+ }
185
+ "italic" -> {
186
+ button.text = "I"
187
+ button.textSize = 18f
188
+ button.setTypeface(null, Typeface.ITALIC)
189
+ button.setOnClickListener { listener?.onItalicClick() }
190
+ }
191
+ "underline" -> {
192
+ val spannable = SpannableString("U")
193
+ spannable.setSpan(UnderlineSpan(), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
194
+ button.text = spannable
195
+ button.textSize = 18f
196
+ button.setOnClickListener { listener?.onUnderlineClick() }
197
+ }
198
+ "strikethrough" -> {
199
+ val spannable = SpannableString("S")
200
+ spannable.setSpan(StrikethroughSpan(), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
201
+ button.text = spannable
202
+ button.textSize = 18f
203
+ button.setOnClickListener { listener?.onStrikethroughClick() }
204
+ }
205
+ "code" -> {
206
+ button.text = "</>"
207
+ button.textSize = 12f
208
+ button.setTypeface(Typeface.MONOSPACE, Typeface.NORMAL)
209
+ button.setOnClickListener { listener?.onCodeClick() }
210
+ }
211
+ "highlight" -> {
212
+ // Use marker/highlighter icon representation
213
+ button.text = "✎"
214
+ button.textSize = 18f
215
+ button.setOnClickListener { listener?.onHighlightClick() }
216
+ }
217
+ "heading" -> {
218
+ button.text = "H1"
219
+ button.textSize = 14f
220
+ button.setTypeface(null, Typeface.BOLD)
221
+ button.setOnClickListener { listener?.onHeadingClick() }
222
+ }
223
+ "bullet" -> {
224
+ button.text = "•≡"
225
+ button.textSize = 14f
226
+ button.setOnClickListener { listener?.onBulletListClick() }
227
+ }
228
+ "numbered" -> {
229
+ button.text = "1."
230
+ button.textSize = 14f
231
+ button.setOnClickListener { listener?.onNumberedListClick() }
232
+ }
233
+ "quote" -> {
234
+ button.text = "❞"
235
+ button.textSize = 18f
236
+ button.setOnClickListener { listener?.onQuoteClick() }
237
+ }
238
+ "checklist" -> {
239
+ button.text = "☑"
240
+ button.textSize = 18f
241
+ button.setOnClickListener { listener?.onChecklistClick() }
242
+ }
243
+ "link" -> {
244
+ button.text = "🔗"
245
+ button.textSize = 14f
246
+ button.setOnClickListener { listener?.onLinkClick() }
247
+ }
248
+ "undo" -> {
249
+ button.text = "↩"
250
+ button.textSize = 18f
251
+ button.setOnClickListener { listener?.onUndoClick() }
252
+ }
253
+ "redo" -> {
254
+ button.text = "↪"
255
+ button.textSize = 18f
256
+ button.setOnClickListener { listener?.onRedoClick() }
257
+ }
258
+ "clearFormatting" -> {
259
+ val spannable = SpannableString("Tx")
260
+ spannable.setSpan(StrikethroughSpan(), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
261
+ button.text = spannable
262
+ button.textSize = 14f
263
+ button.setOnClickListener { listener?.onClearFormattingClick() }
264
+ }
265
+ "indent" -> {
266
+ button.text = "→⊢"
267
+ button.textSize = 12f
268
+ button.setOnClickListener { listener?.onIndentClick() }
269
+ }
270
+ "outdent" -> {
271
+ button.text = "⊣←"
272
+ button.textSize = 12f
273
+ button.setOnClickListener { listener?.onOutdentClick() }
274
+ }
275
+ "alignLeft" -> {
276
+ button.text = "≡"
277
+ button.textSize = 18f
278
+ button.gravity = Gravity.START or Gravity.CENTER_VERTICAL
279
+ button.setOnClickListener { listener?.onAlignLeftClick() }
280
+ }
281
+ "alignCenter" -> {
282
+ button.text = "≡"
283
+ button.textSize = 18f
284
+ button.gravity = Gravity.CENTER
285
+ button.setOnClickListener { listener?.onAlignCenterClick() }
286
+ }
287
+ "alignRight" -> {
288
+ button.text = "≡"
289
+ button.textSize = 18f
290
+ button.gravity = Gravity.END or Gravity.CENTER_VERTICAL
291
+ button.setOnClickListener { listener?.onAlignRightClick() }
292
+ }
293
+ else -> return null
294
+ }
295
+
296
+ return button
297
+ }
298
+
299
+ fun updateButtonStates(
300
+ bold: Boolean = false,
301
+ italic: Boolean = false,
302
+ underline: Boolean = false,
303
+ strikethrough: Boolean = false,
304
+ code: Boolean = false,
305
+ highlight: Boolean = false,
306
+ heading: Boolean = false,
307
+ bullet: Boolean = false,
308
+ numbered: Boolean = false,
309
+ quote: Boolean = false,
310
+ checklist: Boolean = false,
311
+ alignLeft: Boolean = true,
312
+ alignCenter: Boolean = false,
313
+ alignRight: Boolean = false
314
+ ) {
315
+ val states = mapOf(
316
+ "bold" to bold,
317
+ "italic" to italic,
318
+ "underline" to underline,
319
+ "strikethrough" to strikethrough,
320
+ "code" to code,
321
+ "highlight" to highlight,
322
+ "heading" to heading,
323
+ "bullet" to bullet,
324
+ "numbered" to numbered,
325
+ "quote" to quote,
326
+ "checklist" to checklist,
327
+ "alignLeft" to alignLeft,
328
+ "alignCenter" to alignCenter,
329
+ "alignRight" to alignRight
330
+ )
331
+
332
+ for ((option, button) in buttons) {
333
+ val isActive = states[option] ?: false
334
+ button.setTextColor(if (isActive) activeColor else inactiveColor)
335
+ (button.background as? GradientDrawable)?.setColor(
336
+ if (isActive) Color.parseColor("#40FFFFFF") else Color.TRANSPARENT
337
+ )
338
+ }
339
+ }
340
+
341
+ fun getToolbarWidth(): Int {
342
+ val screenWidth = context.resources.displayMetrics.widthPixels
343
+ val maxWidth = (screenWidth * 0.9).toInt()
344
+ val buttonCount = enabledOptions.size
345
+ val calculatedWidth = (buttonCount * buttonSize) + ((buttonCount - 1) * buttonSpacing) + (56 * density).toInt()
346
+ return minOf(calculatedWidth, maxWidth)
347
+ }
348
+
349
+ fun getToolbarHeight(): Int = toolbarHeight
350
+ }
@@ -0,0 +1,16 @@
1
+ package com.richtext.editor
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ class RichTextEditorPackage : ReactPackage {
9
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
10
+ return emptyList()
11
+ }
12
+
13
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
14
+ return listOf(RichTextEditorViewManager())
15
+ }
16
+ }