1
0
Fork 0

Fix newlines in the contenteditable

This commit is contained in:
Pabloader 2026-03-25 14:51:02 +00:00
parent a605c95890
commit 360bb1d714
4 changed files with 23 additions and 14 deletions

View File

@ -2,6 +2,14 @@
overflow: hidden;
}
.root {
white-space: pre-wrap;
outline: none;
word-wrap: break-word;
overflow-wrap: break-word;
border: none;
}
.root:empty::before {
content: attr(data-placeholder);
color: var(--text-muted);

View File

@ -70,7 +70,7 @@ export const ContentEditable = ({ value, placeholder, autoLines, onInput, class:
}, [value]);
const handleKeyDown: JSX.KeyboardEventHandler<HTMLDivElement> = (e) => {
if (e.key !== 'Enter') return;
if (e.key !== 'Enter' || !ref.current) return;
e.preventDefault();
const sel = window.getSelection();
@ -79,7 +79,10 @@ export const ContentEditable = ({ value, placeholder, autoLines, onInput, class:
const range = sel.getRangeAt(0);
range.deleteContents();
const newline = document.createTextNode('\n');
const endsWithNewline = ref.current.textContent?.endsWith('\n');
const caretAtEnd = getCaretOffset(ref.current) === ref.current.textContent.length;
const newline = document.createTextNode('\n'.repeat((endsWithNewline || !caretAtEnd) ? 1 : 2));
range.insertNode(newline);
range.setStartAfter(newline);
range.collapse(true);
@ -87,11 +90,15 @@ export const ContentEditable = ({ value, placeholder, autoLines, onInput, class:
sel.removeAllRanges();
sel.addRange(range);
(ref.current as any).value = ref.current.textContent;
ref.current?.dispatchEvent(new InputEvent('input', { bubbles: true }));
};
const handleInput: JSX.EventHandler<JSX.TargetedInputEvent<HTMLDivElement>> = (e) => {
if (autoLines && ref.current) resizeToContent(ref.current);
if (ref.current) {
(ref.current as any).value = ref.current.textContent;
}
onInput?.(e);
};

View File

@ -33,12 +33,7 @@
line-height: 1.9;
color: var(--textColor);
background: transparent;
border: none;
outline: none;
box-sizing: border-box;
white-space: pre-wrap;
word-wrap: break-word;
overflow-wrap: break-word;
&::placeholder {
color: var(--text-muted);

View File

@ -7,6 +7,7 @@ import clsx from "clsx";
import { CharacterEditor } from "./character-editor";
import { LocationEditor } from "./location-editor";
import { ChaptersEditor } from "./chapters-editor";
import { useInputCallback } from "@common/hooks/useInputCallback";
const TABS: { id: Tab; label: string }[] = [
{ id: "story", label: "Story" },
@ -23,23 +24,21 @@ export const Editor = () => {
return <div class={styles.editor} />;
}
const handleInput = (e: Event) => {
const text = (e.target as HTMLElement).textContent || '';
const handleInput = useInputCallback((text: string) => {
dispatch({
type: 'EDIT_STORY',
id: currentStory.id,
text,
});
};
}, []);
const handleLoreInput = (e: Event) => {
const lore = (e.target as HTMLElement).textContent || '';
const handleLoreInput = useInputCallback((lore: string) => {
dispatch({
type: 'EDIT_LORE',
id: currentStory.id,
lore,
});
};
}, []);
const handleTabChange = (tab: Tab) => {
dispatch({