Skip to content

Commit 60eeba1

Browse files
feat: improved markdown wrapping example logic
1 parent e68626f commit 60eeba1

File tree

1 file changed

+61
-32
lines changed

1 file changed

+61
-32
lines changed

example/src/App.tsx

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
2527
export 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+
298327
const ImageInfo = ({ image }: { image: onPasteImageEventData }) => {
299328
function formatFileSize(bytes: number): string {
300329
if (bytes <= 0) return '0 KB';

0 commit comments

Comments
 (0)