Skip to content

Commit

Permalink
Fix cursor selection event on the web (#459)
Browse files Browse the repository at this point in the history
  • Loading branch information
Skalakid authored Aug 27, 2024
1 parent c9d6205 commit 7640090
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 18 deletions.
8 changes: 7 additions & 1 deletion WebExample/__tests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ const setupInput = async (page: Page, action?: 'clear' | 'reset') => {
};

const getCursorPosition = async (elementHandle: Locator) => {
const inputSelectionHandle = await elementHandle.evaluateHandle((div: HTMLInputElement) => ({start: div.selectionStart, end: div.selectionEnd}));
const inputSelectionHandle = await elementHandle.evaluateHandle(
(
div: HTMLInputElement & {
selection: {start: number; end: number};
},
) => div.selection,
);
const selection = await inputSelectionHandle.jsonValue();
return selection;
};
Expand Down
29 changes: 12 additions & 17 deletions src/MarkdownTextInput.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ let focusTimeout: NodeJS.Timeout | null = null;
type MarkdownTextInputElement = HTMLDivElement &
HTMLInputElement & {
tree: TreeNode;
selection: Selection;
};

type HTMLMarkdownElement = HTMLElement & {
Expand Down Expand Up @@ -233,14 +234,15 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
);

const updateRefSelectionVariables = useCallback((newSelection: Selection) => {
if (!divRef.current) {
return;
}
const {start, end} = newSelection;
const markdownHTMLInput = divRef.current as HTMLInputElement;
markdownHTMLInput.selectionStart = start;
markdownHTMLInput.selectionEnd = end;
divRef.current.selection = {start, end};
}, []);

const updateSelection = useCallback(
(e: SyntheticEvent<HTMLDivElement> | null = null, predefinedSelection: Selection | null = null) => {
(e: SyntheticEvent<HTMLDivElement>, predefinedSelection: Selection | null = null) => {
if (!divRef.current) {
return;
}
Expand All @@ -250,9 +252,7 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
updateRefSelectionVariables(newSelection);
contentSelection.current = newSelection;

if (e) {
handleSelectionChange(e);
}
handleSelectionChange(e);
}
},
[handleSelectionChange, updateRefSelectionVariables],
Expand Down Expand Up @@ -382,9 +382,8 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
(e.nativeEvent as MarkdownNativeEvent).inputType = 'pasteText';

handleOnChangeText(e);
updateSelection(e);
},
[handleOnChangeText, updateSelection],
[handleOnChangeText],
);

const handleKeyPress = useCallback(
Expand Down Expand Up @@ -421,8 +420,6 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
onKeyPress(event);
}

updateSelection(event as unknown as SyntheticEvent<HTMLDivElement, Event>);

if (
e.key === 'Enter' &&
// Do not call submit if composition is occuring.
Expand All @@ -443,7 +440,7 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
}
}
},
[multiline, blurOnSubmit, setEventProps, onKeyPress, updateSelection, handleOnChangeText, onSubmitEditing, insertText],
[multiline, blurOnSubmit, setEventProps, onKeyPress, handleOnChangeText, onSubmitEditing, insertText],
);

const handleFocus: FocusEventHandler<HTMLDivElement> = useCallback(
Expand All @@ -459,7 +456,6 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
const valueLength = value ? value.length : divRef.current.value.length;
setCursorPosition(divRef.current, valueLength, null);
}
updateSelection(event, contentSelection.current);
}

if (onFocus) {
Expand All @@ -485,7 +481,7 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
}
}
},
[clearTextOnFocus, onFocus, selectTextOnFocus, setEventProps, updateSelection, value],
[clearTextOnFocus, onFocus, selectTextOnFocus, setEventProps, value],
);

const handleBlur: FocusEventHandler<HTMLDivElement> = useCallback(
Expand All @@ -503,14 +499,13 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(

const handleClick = useCallback(
(e: MouseEvent<HTMLDivElement, globalThis.MouseEvent>) => {
updateSelection(e);
if (!onClick || !divRef.current) {
return;
}
(e.target as HTMLInputElement).value = divRef.current.value;
onClick(e);
},
[onClick, updateSelection],
[onClick],
);

const handleCopy: ClipboardEventHandler<HTMLDivElement> = useCallback((e) => {
Expand Down Expand Up @@ -660,7 +655,6 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
onKeyDown={handleKeyPress}
onCompositionStart={startComposition}
onCompositionEnd={endComposition}
onKeyUp={updateSelection}
onInput={handleOnChangeText}
onClick={handleClick}
onFocus={handleFocus}
Expand All @@ -672,6 +666,7 @@ const MarkdownTextInput = React.forwardRef<TextInput, MarkdownTextInputProps>(
spellCheck={spellCheck}
dir={dir}
inputMode={inputMode}
onSelect={updateSelection}

This comment has been minimized.

Copy link
@tomekzaw

tomekzaw Aug 30, 2024

Collaborator

This event prop could be defined directly below other event props.

/>
);
},
Expand Down
4 changes: 4 additions & 0 deletions src/web/utils/cursorUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ function setCursorPosition(target: MarkdownTextInputElement, startIndex: number,
selection.setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
}

// Update the focused elements zIndex to make sure they are on top and the cursor is beeing set correctly

This comment has been minimized.

Copy link
@tomekzaw

tomekzaw Aug 30, 2024

Collaborator

beeing → being

startTreeNode.element.style.zIndex = '1';
endTreeNode.element.style.zIndex = '1';

scrollIntoView(startTreeNode);
}

Expand Down

0 comments on commit 7640090

Please sign in to comment.