Contenteditable fixes
This commit is contained in:
parent
4c57bef21e
commit
f5d1571e91
|
|
@ -59,10 +59,47 @@ export const ContentEditable = ({ value, onInput, ...props }: Props) => {
|
|||
if (offset !== null) setCaretOffset(el, offset);
|
||||
}, [value]);
|
||||
|
||||
const handleKeyDown: JSX.KeyboardEventHandler<HTMLDivElement> = (e) => {
|
||||
if (e.key !== 'Enter') return;
|
||||
const prevTextContent = (e.target as HTMLDivElement).textContent;
|
||||
e.preventDefault();
|
||||
|
||||
const sel = window.getSelection();
|
||||
if (!sel || sel.rangeCount === 0) return;
|
||||
|
||||
const range = sel.getRangeAt(0);
|
||||
range.deleteContents();
|
||||
|
||||
const newline = document.createTextNode('\n');
|
||||
range.insertNode(newline);
|
||||
range.setStartAfter(newline);
|
||||
range.collapse(true);
|
||||
|
||||
const nextTextContent = (e.target as HTMLDivElement).textContent;
|
||||
|
||||
// A trailing \n needs a following character to render in pre-line.
|
||||
// If nothing follows the inserted newline, add a sentinel \n so the
|
||||
// new line is visible, then place the caret before it.
|
||||
const atEnd = nextTextContent.startsWith(prevTextContent) && nextTextContent !== prevTextContent && nextTextContent.length === prevTextContent.length + 1 && nextTextContent.at(-1) === '\n';
|
||||
if (atEnd) {
|
||||
const sentinel = document.createTextNode('\n');
|
||||
range.insertNode(sentinel);
|
||||
range.setStartBefore(sentinel);
|
||||
range.collapse(true);
|
||||
}
|
||||
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
ref.current?.dispatchEvent(new InputEvent('input', { bubbles: true }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
contentEditable
|
||||
style="white-space: pre"
|
||||
onKeyDown={handleKeyDown}
|
||||
onInput={onInput}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue