1
0
Fork 0

Contenteditable fixes

This commit is contained in:
Pabloader 2026-03-19 15:39:23 +00:00
parent 4c57bef21e
commit f5d1571e91
1 changed files with 37 additions and 0 deletions

View File

@ -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}
/>