@@ -22,10 +22,12 @@ import { useEffect, useRef, useState } from 'react';
2222// See: https://github.com/software-mansion/react-native-enriched/issues/229
2323// const ANDROID_EXPERIMENTAL_SYNCHRONOUS_EVENTS = false;
2424
25+ type Selection = { start : number ; end : number } ;
26+
2527export default function App ( ) {
2628 const inputRef = useRef < TypeRichTextInputRef > ( null ) ;
27- const textRef = useRef ( 'hello world' ) ;
28- const selectionRef = useRef < { start : number ; end : number } > ( {
29+ const textRef = useRef < string > ( 'hello world' ) ;
30+ const selectionRef = useRef < Selection > ( {
2931 start : 0 ,
3032 end : 0 ,
3133 } ) ;
@@ -143,7 +145,7 @@ export default function App() {
143145 < TypeRichTextInput
144146 ref = { inputRef }
145147 // value={value}
146- defaultValue = { textRef . current }
148+ // defaultValue={textRef.current}
147149 style = { styles . editorInput }
148150 placeholder = "custom textinput"
149151 placeholderTextColor = "rgb(0, 26, 114)"
@@ -153,7 +155,7 @@ export default function App() {
153155 autoFocus
154156 onChangeText = { ( text : string ) => {
155157 console . log ( 'text changed ========' , text ) ;
156- console . log ( 'value ========' , value ) ;
158+ // console.log('value ========', value);
157159 textRef . current = text ;
158160 // setValue(text); // controlled by value
159161 inputRef . current ?. setText ( text ) ; // controlled by command
@@ -223,6 +225,7 @@ export default function App() {
223225 </ View >
224226 < View style = { styles . buttonStack } >
225227 < Pressable
228+ disabled
226229 onPress = { ( ) => {
227230 console . log ( 'setvalue' ) ;
228231 console . log ( value ) ;
@@ -247,36 +250,20 @@ export default function App() {
247250 style = { styles . button }
248251 onPress = { ( ) => {
249252 const text = textRef . current ;
250- const start = 6 ; // before "world"
251- const end = 11 ;
252-
253- const next =
254- text . slice ( 0 , start ) +
255- '*' +
256- text . slice ( start , end ) +
257- '*' +
258- text . slice ( end ) ;
259-
260- // this MUST preserve cursor after native fix
261- inputRef . current ?. setText ( next ) ;
262- let { start : selStart , end : selEnd } = selectionRef . current ;
263-
264- if ( selStart <= start ) {
265- // before wrap → no change
266- } else if ( selStart < end ) {
267- // inside wrapped range → +1
268- selStart += 1 ;
269- selEnd += 1 ;
270- } else {
271- // at or after end → +2
272- selStart += 2 ;
273- selEnd += 2 ;
274- }
275-
276- inputRef . current ?. setSelection ( selStart , selEnd ) ;
253+ const selection = selectionRef . current ;
254+
255+ const result = wrapWithMarkdown ( text , selection , '**' ) ;
256+
257+ textRef . current = result . text ;
258+
259+ inputRef . current ?. setText ( result . text ) ;
260+ inputRef . current ?. setSelection (
261+ result . selection . start ,
262+ result . selection . end
263+ ) ;
277264 } }
278265 >
279- < Text style = { styles . label2 } > Wrap middle with * *</ Text >
266+ < Text style = { styles . label2 } > Wrap selection with * *</ Text >
280267 </ Pressable >
281268 < Pressable
282269 style = { styles . button }
@@ -295,6 +282,48 @@ export default function App() {
295282 ) ;
296283}
297284
285+ export function wrapWithMarkdown (
286+ text : string ,
287+ selection : Selection ,
288+ markdownChar = '*'
289+ ) : {
290+ text : string ;
291+ selection : Selection ;
292+ } {
293+ let { start, end } = selection ;
294+
295+ const before = text . slice ( 0 , start ) ;
296+ const selected = text . slice ( start , end ) ;
297+ const after = text . slice ( end ) ;
298+
299+ const hasLeading = before . endsWith ( '*' ) ;
300+ const hasTrailing = after . startsWith ( '*' ) ;
301+
302+ // 🔁 TOGGLE OFF
303+ if ( hasLeading && hasTrailing ) {
304+ const newText = before . slice ( 0 , - 2 ) + selected + after . slice ( 2 ) ;
305+
306+ return {
307+ text : newText ,
308+ selection : {
309+ start : start - 2 ,
310+ end : end - 2 ,
311+ } ,
312+ } ;
313+ }
314+
315+ // ➕ WRAP
316+ const newText = `${ before } ${ markdownChar } ${ selected } ${ markdownChar } ${ after } ` ;
317+
318+ return {
319+ text : newText ,
320+ selection : {
321+ start : start + markdownChar . length ,
322+ end : end + markdownChar . length ,
323+ } ,
324+ } ;
325+ }
326+
298327const ImageInfo = ( { image } : { image : onPasteImageEventData } ) => {
299328 function formatFileSize ( bytes : number ) : string {
300329 if ( bytes <= 0 ) return '0 KB' ;
0 commit comments