33 StyleSheet ,
44 Text ,
55 type NativeSyntheticEvent ,
6- TextInput ,
76 ScrollView ,
87} from 'react-native' ;
98import {
@@ -21,10 +20,12 @@ import { useRef, useState } from 'react';
2120import { Button } from './components/Button' ;
2221import { Toolbar } from './components/Toolbar' ;
2322import { LinkModal } from './components/LinkModal' ;
23+ import { ValueModal } from './components/ValueModal' ;
2424import { launchImageLibrary } from 'react-native-image-picker' ;
2525import { type MentionItem , MentionPopup } from './components/MentionPopup' ;
2626import { useUserMention } from './useUserMention' ;
2727import { useChannelMention } from './useChannelMention' ;
28+ import { HtmlSection } from './components/HtmlSection' ;
2829
2930type StylesState = OnChangeStateEvent ;
3031
@@ -71,10 +72,11 @@ export default function App() {
7172 const [ isChannelPopupOpen , setIsChannelPopupOpen ] = useState ( false ) ;
7273 const [ isUserPopupOpen , setIsUserPopupOpen ] = useState ( false ) ;
7374 const [ isLinkModalOpen , setIsLinkModalOpen ] = useState ( false ) ;
75+ const [ isValueModalOpen , setIsValueModalOpen ] = useState ( false ) ;
76+ const [ currentHtml , setCurrentHtml ] = useState ( '' ) ;
7477
7578 const [ selection , setSelection ] = useState < Selection > ( ) ;
7679 const [ stylesState , setStylesState ] = useState < StylesState > ( DEFAULT_STYLE ) ;
77- const [ defaultValue , setDefaultValue ] = useState ( '' ) ;
7880 const [ currentLink , setCurrentLink ] =
7981 useState < CurrentLinkState > ( DEFAULT_LINK_STATE ) ;
8082
@@ -83,12 +85,21 @@ export default function App() {
8385 const userMention = useUserMention ( ) ;
8486 const channelMention = useChannelMention ( ) ;
8587
88+ const insideCurrentLink =
89+ stylesState . isLink &&
90+ currentLink . url . length > 0 &&
91+ ( currentLink . start || currentLink . end ) &&
92+ selection &&
93+ selection . start >= currentLink . start &&
94+ selection . end <= currentLink . end ;
95+
8696 const handleChangeText = ( e : NativeSyntheticEvent < OnChangeTextEvent > ) => {
8797 console . log ( 'Text changed:' , e ?. nativeEvent . value ) ;
8898 } ;
8999
90100 const handleChangeHtml = ( e : NativeSyntheticEvent < OnChangeHtmlEvent > ) => {
91101 console . log ( 'HTML changed:' , e ?. nativeEvent . value ) ;
102+ setCurrentHtml ( e ?. nativeEvent . value ) ;
92103 } ;
93104
94105 const handleChangeState = ( e : NativeSyntheticEvent < OnChangeStateEvent > ) => {
@@ -103,10 +114,6 @@ export default function App() {
103114 ref . current ?. blur ( ) ;
104115 } ;
105116
106- const handleSetValue = ( ) => {
107- ref . current ?. setValue ( '<html><b>Hello</b> <i>world</i></html>' ) ;
108- } ;
109-
110117 const openLinkModal = ( ) => {
111118 setIsLinkModalOpen ( true ) ;
112119 } ;
@@ -133,6 +140,14 @@ export default function App() {
133140 channelMention . onMentionChange ( '' ) ;
134141 } ;
135142
143+ const openValueModal = ( ) => {
144+ setIsValueModalOpen ( true ) ;
145+ } ;
146+
147+ const closeValueModal = ( ) => {
148+ setIsValueModalOpen ( false ) ;
149+ } ;
150+
136151 const handleStartMention = ( indicator : string ) => {
137152 indicator === '@' ? openUserMentionPopup ( ) : openChannelMentionPopup ( ) ;
138153 } ;
@@ -151,12 +166,27 @@ export default function App() {
151166 } ;
152167
153168 const submitLink = ( text : string , url : string ) => {
154- if ( ! selection ) return ;
169+ if ( ! selection || url . length === 0 ) {
170+ closeLinkModal ( ) ;
171+ return ;
172+ }
173+
174+ const newText = text . length > 0 ? text : url ;
175+
176+ if ( insideCurrentLink ) {
177+ ref . current ?. setLink ( currentLink . start , currentLink . end , newText , url ) ;
178+ } else {
179+ ref . current ?. setLink ( selection . start , selection . end , newText , url ) ;
180+ }
155181
156- ref . current ?. setLink ( selection . start , selection . end , text , url ) ;
157182 closeLinkModal ( ) ;
158183 } ;
159184
185+ const submitSetValue = ( value : string ) => {
186+ ref . current ?. setValue ( value ) ;
187+ closeValueModal ( ) ;
188+ } ;
189+
160190 const selectImage = async ( ) => {
161191 const response = await launchImageLibrary ( {
162192 mediaType : 'photo' ,
@@ -219,7 +249,7 @@ export default function App() {
219249 style = { styles . container }
220250 contentContainerStyle = { styles . content }
221251 >
222- < Text style = { styles . label } > react-native-enriched </ Text >
252+ < Text style = { styles . label } > Enriched Text Input </ Text >
223253 < View style = { styles . editor } >
224254 < EnrichedTextInput
225255 autoFocus
@@ -232,7 +262,6 @@ export default function App() {
232262 selectionColor = "deepskyblue"
233263 cursorColor = "dodgerblue"
234264 autoCapitalize = "sentences"
235- defaultValue = { defaultValue }
236265 onChangeText = { handleChangeText }
237266 onChangeHtml = { handleChangeHtml }
238267 onChangeState = { handleChangeState }
@@ -255,22 +284,32 @@ export default function App() {
255284 onSelectImage = { selectImage }
256285 />
257286 </ View >
258- < TextInput
259- placeholder = "Default value"
260- style = { styles . defaultInput }
261- onChangeText = { setDefaultValue }
287+ < View style = { styles . buttonStack } >
288+ < Button title = "Focus" onPress = { handleFocus } style = { styles . button } />
289+ < Button title = "Blur" onPress = { handleBlur } style = { styles . button } />
290+ </ View >
291+ < Button
292+ title = "Set input's value"
293+ onPress = { openValueModal }
294+ style = { styles . valueButton }
262295 />
263- < Button title = "Focus" onPress = { handleFocus } />
264- < Button title = "Blur" onPress = { handleBlur } />
265- < Button title = "Set value" onPress = { handleSetValue } />
296+ < HtmlSection currentHtml = { currentHtml } />
266297 { DEBUG_SCROLLABLE && < View style = { styles . scrollPlaceholder } /> }
267298 </ ScrollView >
268299 < LinkModal
269- defaults = { currentLink }
270300 isOpen = { isLinkModalOpen }
301+ editedText = {
302+ insideCurrentLink ? currentLink . text : ( selection ?. text ?? '' )
303+ }
304+ editedUrl = { insideCurrentLink ? currentLink . url : '' }
271305 onSubmit = { submitLink }
272306 onClose = { closeLinkModal }
273307 />
308+ < ValueModal
309+ isOpen = { isValueModalOpen }
310+ onSubmit = { submitSetValue }
311+ onClose = { closeValueModal }
312+ />
274313 < MentionPopup
275314 variant = "user"
276315 data = { userMention . data }
@@ -368,23 +407,28 @@ const styles = StyleSheet.create({
368407 textAlign : 'center' ,
369408 color : 'rgb(0, 26, 114)' ,
370409 } ,
410+ buttonStack : {
411+ flexDirection : 'row' ,
412+ alignItems : 'center' ,
413+ justifyContent : 'space-between' ,
414+ width : '100%' ,
415+ } ,
416+ button : {
417+ width : '45%' ,
418+ } ,
419+ valueButton : {
420+ width : '100%' ,
421+ } ,
371422 editorInput : {
372423 marginTop : 24 ,
373424 width : '100%' ,
374- maxHeight : 240 ,
425+ maxHeight : 180 ,
375426 backgroundColor : 'gainsboro' ,
376427 fontSize : 18 ,
377428 fontFamily : 'Nunito-Regular' ,
378429 paddingVertical : 12 ,
379430 paddingHorizontal : 14 ,
380431 } ,
381- defaultInput : {
382- marginTop : 24 ,
383- width : '100%' ,
384- height : 40 ,
385- borderBottomWidth : 1 ,
386- borderBottomColor : 'grey' ,
387- } ,
388432 scrollPlaceholder : {
389433 marginTop : 24 ,
390434 width : '100%' ,
0 commit comments