diff --git a/src/client/PageDocument.tsx b/src/client/PageDocument.tsx
index 164b3bf..da3e104 100644
--- a/src/client/PageDocument.tsx
+++ b/src/client/PageDocument.tsx
@@ -19,6 +19,7 @@ import { api } from './api';
import { usePageAutosave } from './editor/use-page-autosave';
import { inspectMarkdown } from './editor/markdown';
import { DocumentMenu } from './editor/DocumentMenu';
+import { PageTitleField } from './editor/PageTitleField';
import { PageConversation } from './PageConversation';
const RichEditor = lazy(() => import('./editor/RichEditor'));
export function PageDocument({
@@ -260,15 +261,9 @@ export function PageDocument({
)}
-
- controller.edit({ title: event.target.value })
- }
+ onChange={(title) => controller.edit({ title })}
/>
{sourceMode ? (
<>
diff --git a/src/client/editor.css b/src/client/editor.css
index 9c9c91a..1c63014 100644
--- a/src/client/editor.css
+++ b/src/client/editor.css
@@ -397,6 +397,11 @@
margin-bottom: 24px;
outline: none;
border-radius: 0;
+ display: block;
+ resize: none;
+ overflow: hidden;
+ font-family: inherit;
+ overflow-wrap: anywhere;
}
.document-title::placeholder {
color: #747c70;
diff --git a/src/client/editor/PageTitleField.tsx b/src/client/editor/PageTitleField.tsx
new file mode 100644
index 0000000..e840cc1
--- /dev/null
+++ b/src/client/editor/PageTitleField.tsx
@@ -0,0 +1,36 @@
+import { useLayoutEffect, useRef } from 'react';
+
+export function singleLineTitle(value: string): string {
+ return value.replace(/[\r\n]+/g, ' ');
+}
+
+export function PageTitleField({
+ value,
+ onChange,
+}: {
+ value: string;
+ onChange: (title: string) => void;
+}) {
+ const ref = useRef(null);
+ useLayoutEffect(() => {
+ const el = ref.current;
+ if (!el) return;
+ el.style.height = 'auto';
+ el.style.height = `${el.scrollHeight}px`;
+ }, [value]);
+ return (
+