Fix content editable onKeyDown
This commit is contained in:
parent
2a711a6dea
commit
20485ba551
|
|
@ -27,7 +27,8 @@ function setCaretOffset(el: HTMLElement, offset: number) {
|
||||||
|
|
||||||
function traverse(node: Node): boolean {
|
function traverse(node: Node): boolean {
|
||||||
if (node.nodeType === Node.TEXT_NODE) {
|
if (node.nodeType === Node.TEXT_NODE) {
|
||||||
const len = node.textContent?.length ?? 0;
|
const text = node.textContent || ''
|
||||||
|
const len = text.length;
|
||||||
if (remaining <= len) {
|
if (remaining <= len) {
|
||||||
range.setStart(node, remaining);
|
range.setStart(node, remaining);
|
||||||
range.collapse(true);
|
range.collapse(true);
|
||||||
|
|
@ -56,7 +57,7 @@ function resizeToContent(el: HTMLElement) {
|
||||||
el.style.height = el.scrollHeight + 'px';
|
el.style.height = el.scrollHeight + 'px';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ContentEditable = ({ value, placeholder, autoLines, onInput, class: externalClass, ...props }: Props) => {
|
export const ContentEditable = ({ value, placeholder, autoLines, onInput, onKeyDown, class: externalClass, ...props }: Props) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -70,7 +71,10 @@ export const ContentEditable = ({ value, placeholder, autoLines, onInput, class:
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
const handleKeyDown: JSX.KeyboardEventHandler<HTMLDivElement> = (e) => {
|
const handleKeyDown: JSX.KeyboardEventHandler<HTMLDivElement> = (e) => {
|
||||||
if (e.key !== 'Enter' || !ref.current) return;
|
if (e.key !== 'Enter' || !ref.current) {
|
||||||
|
onKeyDown?.(e);
|
||||||
|
return;
|
||||||
|
};
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const sel = window.getSelection();
|
const sel = window.getSelection();
|
||||||
|
|
@ -79,8 +83,8 @@ export const ContentEditable = ({ value, placeholder, autoLines, onInput, class:
|
||||||
const range = sel.getRangeAt(0);
|
const range = sel.getRangeAt(0);
|
||||||
range.deleteContents();
|
range.deleteContents();
|
||||||
|
|
||||||
const endsWithNewline = ref.current.textContent?.endsWith('\n');
|
const endsWithNewline = ref.current.innerText?.endsWith('\n');
|
||||||
const caretAtEnd = getCaretOffset(ref.current) === (ref.current.textContent?.length ?? 0);
|
const caretAtEnd = getCaretOffset(ref.current) === (ref.current.innerText?.length ?? 0);
|
||||||
|
|
||||||
const newline = document.createTextNode('\n'.repeat((endsWithNewline || !caretAtEnd) ? 1 : 2));
|
const newline = document.createTextNode('\n'.repeat((endsWithNewline || !caretAtEnd) ? 1 : 2));
|
||||||
range.insertNode(newline);
|
range.insertNode(newline);
|
||||||
|
|
@ -90,14 +94,15 @@ export const ContentEditable = ({ value, placeholder, autoLines, onInput, class:
|
||||||
sel.removeAllRanges();
|
sel.removeAllRanges();
|
||||||
sel.addRange(range);
|
sel.addRange(range);
|
||||||
|
|
||||||
(ref.current as any).value = ref.current.textContent;
|
(ref.current as any).value = ref.current.innerText;
|
||||||
ref.current?.dispatchEvent(new InputEvent('input', { bubbles: true }));
|
ref.current?.dispatchEvent(new InputEvent('input', { bubbles: true }));
|
||||||
|
onKeyDown?.(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleInput: JSX.EventHandler<JSX.TargetedInputEvent<HTMLDivElement>> = (e) => {
|
const handleInput: JSX.EventHandler<JSX.TargetedInputEvent<HTMLDivElement>> = (e) => {
|
||||||
if (autoLines && ref.current) resizeToContent(ref.current);
|
if (autoLines && ref.current) resizeToContent(ref.current);
|
||||||
if (ref.current) {
|
if (ref.current) {
|
||||||
(ref.current as any).value = ref.current.textContent;
|
(ref.current as any).value = ref.current.innerText;
|
||||||
}
|
}
|
||||||
onInput?.(e);
|
onInput?.(e);
|
||||||
};
|
};
|
||||||
|
|
@ -105,12 +110,12 @@ export const ContentEditable = ({ value, placeholder, autoLines, onInput, class:
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
{...props}
|
||||||
contentEditable
|
contentEditable
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
onInput={handleInput}
|
|
||||||
data-placeholder={value.replaceAll('\n', '').length ? undefined : placeholder}
|
data-placeholder={value.replaceAll('\n', '').length ? undefined : placeholder}
|
||||||
class={clsx(styles.root, autoLines && styles.autoLines, externalClass)}
|
class={clsx(styles.root, autoLines && styles.autoLines, externalClass)}
|
||||||
{...props}
|
onKeyDown={handleKeyDown}
|
||||||
|
onInput={handleInput}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue