Skip to content

Commit e860f2d

Browse files
committed
feat(rich-text): add convertion to html
1 parent e5d8b3b commit e860f2d

8 files changed

Lines changed: 45 additions & 27 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ const handleChange = (event: RichTextChangeEvent) => {
7575
2. Select a portion of text and add different styles (bold, italic, underline, strikethrough) (iOS, Android)
7676
3. Add native context menu for formatting (iOS)
7777
4. Add onChange prop (iOS, Android)
78-
5. Return text without markdown (iOS)
79-
6. Add method that returns rich text in RTF (iOS)
78+
5. Return text without markdown (iOS, Android)
79+
6. Add method that returns rich text in HTML (iOS, Android)
8080
8181
# TODO
8282
8383
1. Ability to enable certain format and apply it without selecting a portion of text
8484
2. Returning active formats for a selection
85-
3. Returning text with markdown (not sure about this for now)
85+
3. Add convertation to markdown (not sure about this for now)
8686
4. Add method to set default text
8787
8888
## Contributing

android/src/main/java/com/richtextinput/RichTextInputPackage.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import com.facebook.react.uimanager.ViewManager
77

88

99
class RichTextInputPackage : ReactPackage {
10+
val richTextInputViewManager = RichTextInputViewManager()
11+
1012
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11-
return emptyList()
13+
return listOf(richTextInputViewManager).toMutableList()
1214
}
1315

1416
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15-
return listOf(RichTextInputViewManager())
17+
return listOf(richTextInputViewManager)
1618
}
1719
}

android/src/main/java/com/richtextinput/RichTextInputViewManager.kt

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,20 @@ import android.text.style.StrikethroughSpan
66
import android.text.style.StyleSpan
77
import android.text.style.UnderlineSpan
88
import android.widget.EditText
9+
import androidx.core.text.toHtml
910
import androidx.core.widget.doOnTextChanged
1011
import com.facebook.infer.annotation.Assertions
1112
import com.facebook.react.bridge.Arguments
13+
import com.facebook.react.bridge.ReactMethod
1214
import com.facebook.react.bridge.ReadableArray
1315
import com.facebook.react.uimanager.SimpleViewManager
1416
import com.facebook.react.uimanager.ThemedReactContext
1517
import com.facebook.react.uimanager.annotations.ReactProp
1618
import com.facebook.react.uimanager.events.RCTEventEmitter
1719

1820
class RichTextInputViewManager : SimpleViewManager<EditText>() {
21+
var editText: EditText? = null
22+
1923
override fun getName() = "RichTextInputView"
2024

2125
override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
@@ -29,25 +33,34 @@ class RichTextInputViewManager : SimpleViewManager<EditText>() {
2933
}
3034

3135
override fun createViewInstance(reactContext: ThemedReactContext): EditText {
32-
val editText = EditText(reactContext)
36+
editText = EditText(reactContext)
3337

34-
editText.doOnTextChanged { text, start, before, count ->
38+
editText!!.doOnTextChanged { text, start, before, count ->
3539
val event = Arguments.createMap().apply {
3640
putString("text", text.toString())
3741
}
3842
reactContext
3943
.getJSModule(RCTEventEmitter::class.java)
40-
.receiveEvent(editText.id, "topChange", event)
44+
.receiveEvent(editText!!.id, "topChange", event)
4145
}
4246

43-
return editText
47+
return editText as EditText
4448
}
4549

4650
@ReactProp(name = "placeholder")
4751
fun setPlaceholder(view: EditText, placeholder: String) {
4852
view.hint = placeholder
4953
}
5054

55+
@ReactMethod(isBlockingSynchronousMethod = true)
56+
fun getHTML(): String {
57+
if (editText != null) {
58+
return editText!!.text.toHtml()
59+
}
60+
61+
return "ERROR: richTextView IS NOT INITIALIZED"
62+
}
63+
5164
override fun receiveCommand(root: EditText, commandId: String?, args: ReadableArray?) {
5265
Assertions.assertNotNull(root)
5366

example/src/App.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ function App(): React.JSX.Element {
3131
ref.current?.toggleItalic();
3232
};
3333

34-
const handleGetMarkdown = async () => {
35-
console.log(ref.current?.getRTF());
34+
const handleGetHTML = async () => {
35+
console.log(ref.current?.getHTML());
3636
};
3737

3838
const handleChange = (event: RichTextChangeEvent) => {
@@ -51,7 +51,7 @@ function App(): React.JSX.Element {
5151
<Button title="Bold" onPress={handleBoldPress} />
5252
<Button title="Strike" onPress={handleStrikePress} />
5353
<Button title="Italic" onPress={handleItalicPress} />
54-
<Button title="Get markdown" onPress={handleGetMarkdown} />
54+
<Button title="Get HTML" onPress={handleGetHTML} />
5555
</SafeAreaView>
5656
);
5757
}

ios/RichTextInput.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ class RichTextInput: UITextView, UIEditMenuInteractionDelegate {
125125

126126
// TODO: does it have to be so complicated?
127127
// NOTE: semaphors are needed cause textstorage requires to work on main thread
128-
func getRTF() -> String {
128+
func getHTML() -> String {
129129
var value: String = ""
130130

131131
let semaphore = DispatchSemaphore(value: 0)
132132

133133
DispatchQueue.main.async {
134-
value = self.attributedText.toRTF() ?? ""
134+
value = self.attributedText.toHTML() ?? ""
135135
semaphore.signal()
136136
}
137137

@@ -142,16 +142,16 @@ class RichTextInput: UITextView, UIEditMenuInteractionDelegate {
142142
}
143143

144144
extension NSAttributedString {
145-
func toRTF() -> String? {
146-
let documentAttributes = [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.rtf]
145+
func toHTML() -> String? {
146+
let documentAttributes = [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.html]
147147
do {
148-
let rtfData = try self.data(from: NSMakeRange(0, self.length), documentAttributes:documentAttributes)
149-
if let rtfString = String(data:rtfData, encoding:String.Encoding.utf8) {
150-
return rtfString
148+
let htmlData = try self.data(from: NSMakeRange(0, self.length), documentAttributes:documentAttributes)
149+
if let htmlString = String(data:htmlData, encoding:String.Encoding.utf8) {
150+
return htmlString
151151
}
152152
}
153153
catch {
154-
print("error creating RTF from Attributed String")
154+
print("error creating HTML from Attributed String")
155155
}
156156
return nil
157157
}

ios/RichTextInputViewManager.m

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ @interface RCT_EXTERN_MODULE(RichTextInputViewManager, RCTViewManager)
1717

1818
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
1919

20-
// NOTE: work in progress
21-
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(getRTF);
20+
RCT_EXTERN__BLOCKING_SYNCHRONOUS_METHOD(getHTML);
2221

2322
@end

ios/RichTextInputViewManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ public class RichTextInputViewManager: RCTViewManager, UITextViewDelegate {
7171
}
7272

7373
@objc
74-
func getRTF() -> String {
75-
return richTextView?.getRTF() ?? "ERROR: richTextView IS NOT INITIALIZED"
74+
func getHTML() -> String {
75+
return richTextView?.getHTML() ?? "ERROR: richTextView IS NOT INITIALIZED"
7676
}
7777

7878
// Helpers

src/index.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export interface RichTextRef {
3535
toggleItalic: Function;
3636
toggleStrike: Function;
3737
toggleUnderline: Function;
38-
getRTF: () => Promise<string>;
38+
getHTML: () => Promise<string>;
3939
}
4040

4141
const ComponentName = 'RichTextInputView';
@@ -92,8 +92,12 @@ const RichTextInput = forwardRef<RichTextRef, RichTextProps>(
9292
[]
9393
);
9494
},
95-
getRTF: () => {
96-
return NativeModules.RichTextInputViewManager.getRTF();
95+
getHTML: () => {
96+
// NOTE: maybe I should address this issue... just maybe...
97+
if (Platform.OS === 'android') {
98+
return NativeModules.RichTextInputView.getHTML();
99+
}
100+
return NativeModules.RichTextInputViewManager.getHTML();
97101
},
98102
};
99103
}, []);

0 commit comments

Comments
 (0)