diff --git a/example/src/App.tsx b/example/src/App.tsx index 034c1a563..ebde39b41 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -99,9 +99,7 @@ export default function App() { ref={ref} markdownStyle={markdownStyle} placeholder="Type here..." - onSelectionChange={(e) => { - setSelection(e.nativeEvent.selection); - }} + onSelectionChange={(e) => setSelection(e.nativeEvent.selection)} selection={selection} /> {/* TextInput singleline diff --git a/src/MarkdownTextInput.web.tsx b/src/MarkdownTextInput.web.tsx index f2fe9a2b2..cc7ad33b7 100644 --- a/src/MarkdownTextInput.web.tsx +++ b/src/MarkdownTextInput.web.tsx @@ -160,7 +160,7 @@ const MarkdownTextInput = React.forwardRef( const divRef = useRef(null); const currentlyFocusedField = useRef(null); const valueLength = value ? value.length : 0; - const contentSelection = useRef({start: valueLength, end: valueLength}); + const currentSelection = useRef({start: valueLength, end: valueLength}); const className = `react-native-live-markdown-input-${multiline ? 'multiline' : 'singleline'}`; const history = useRef(); if (!history.current) { @@ -175,7 +175,7 @@ const MarkdownTextInput = React.forwardRef( const setEventProps = useCallback((e: NativeSyntheticEvent) => { if (divRef.current) { const text = normalizeValue(divRef.current.innerText || ''); - if (e.target && typeof e.target !== 'number') { + if (e.target) { // TODO: change the logic here so every event have value property (e.target as unknown as HTMLInputElement).value = text; } @@ -292,15 +292,16 @@ const MarkdownTextInput = React.forwardRef( (event) => { const e = event as unknown as NativeSyntheticEvent; setEventProps(e); - if (onSelectionChange && contentSelection.current) { - e.nativeEvent.selection = contentSelection.current; + if (onSelectionChange && currentSelection.current) { + e.nativeEvent.selection = currentSelection.current; onSelectionChange(e); } }, [onSelectionChange, setEventProps], ); - const updateRefSelectionVariables = useCallback((start: number, end: number) => { + const updateRefSelectionVariables = useCallback((newSelection: Selection) => { + const {start, end} = newSelection; const markdownHTMLInput = divRef.current as HTMLInputElement; markdownHTMLInput.selectionStart = start; markdownHTMLInput.selectionEnd = end; @@ -310,12 +311,12 @@ const MarkdownTextInput = React.forwardRef( if (!divRef.current) { return; } - const currentSelection = CursorUtils.getCurrentCursorPosition(divRef.current); + const newSelection = CursorUtils.getCurrentCursorPosition(divRef.current); - if (currentSelection && (contentSelection.current.start !== currentSelection.start || contentSelection.current.end !== currentSelection.end)) { - if (contentSelection.current.start >= 0 && contentSelection.current.end >= 0) { - updateRefSelectionVariables(contentSelection.current.start, contentSelection.current.end); - contentSelection.current = currentSelection; + if (newSelection && (currentSelection.current.start !== newSelection.start || currentSelection.current.end !== newSelection.end)) { + if (currentSelection.current.start >= 0 && currentSelection.current.end >= 0) { + updateRefSelectionVariables(currentSelection.current); + currentSelection.current = newSelection; } if (e) { handleSelectionChange(e); @@ -393,8 +394,8 @@ const MarkdownTextInput = React.forwardRef( const hostNode = e.target as unknown as HTMLDivElement; currentlyFocusedField.current = hostNode; setEventProps(e); - if (divRef.current && contentSelection.current) { - CursorUtils.setCursorPosition(divRef.current, contentSelection.current.end || contentSelection.current.start); + if (divRef.current && currentSelection.current) { + CursorUtils.setCursorPosition(divRef.current, currentSelection.current.end || currentSelection.current.start); } if (onFocus) { @@ -530,11 +531,11 @@ const MarkdownTextInput = React.forwardRef( if (autoFocus) { divRef.current.focus(); } - updateRefSelectionVariables(contentSelection.current.start, contentSelection.current.end); + updateRefSelectionVariables(currentSelection.current); }, []); useEffect(() => { - if (!divRef.current || !selection || !(selection.start !== contentSelection.current.start || selection.end !== contentSelection.current.end)) { + if (!divRef.current || !selection || !(selection.start === currentSelection.current.start && selection.end === currentSelection.current.end)) { return; } CursorUtils.setCursorPosition(divRef.current, selection.start, selection.end); @@ -578,8 +579,8 @@ const styles = StyleSheet.create({ // @ts-expect-error it works on web boxSizing: 'border-box', whiteSpace: 'pre-wrap', - overflowY: 'scroll', - overflowX: 'scroll', + overflowY: 'auto', + overflowX: 'auto', overflowWrap: 'break-word', }, disabledInputStyles: { diff --git a/src/web/cursorUtils.ts b/src/web/cursorUtils.ts index 3522c79c6..bf12c8e69 100644 --- a/src/web/cursorUtils.ts +++ b/src/web/cursorUtils.ts @@ -1,8 +1,8 @@ function findTextNodes(textNodes: Text[], node: ChildNode) { - if (node.nodeType === 3) { + if (node.nodeType === Node.TEXT_NODE) { textNodes.push(node as Text); } else { - for (let i = 0, len = node.childNodes.length; i < len; ++i) { + for (let i = 0, length = node.childNodes.length; i < length; ++i) { const childNode = node.childNodes[i]; if (childNode) { findTextNodes(textNodes, childNode); @@ -66,16 +66,16 @@ function moveCursorToEnd(target: HTMLElement) { function getCurrentCursorPosition(target: HTMLElement) { const selection = window.getSelection(); - if (selection && selection.rangeCount > 0) { - const range = selection.getRangeAt(0); - const preSelectionRange = range.cloneRange(); - preSelectionRange.selectNodeContents(target); - preSelectionRange.setEnd(range.startContainer, range.startOffset); - const start = preSelectionRange.toString().length; - const end = start + range.toString().length; - return {start, end}; + if (!selection || (selection && selection.rangeCount === 0)) { + return null; } - return null; + const range = selection.getRangeAt(0); + const preSelectionRange = range.cloneRange(); + preSelectionRange.selectNodeContents(target); + preSelectionRange.setEnd(range.startContainer, range.startOffset); + const start = preSelectionRange.toString().length; + const end = start + range.toString().length; + return {start, end}; } function removeSelection() {