diff --git a/web/package.json b/web/package.json index ac80eb8a..29fadb88 100644 --- a/web/package.json +++ b/web/package.json @@ -21,8 +21,8 @@ "@codemirror/commands": "^6.10.4", "@codemirror/lang-markdown": "^6.5.0", "@codemirror/language": "^6.12.4", - "@codemirror/state": "^6.7.0", - "@codemirror/view": "^6.43.3", + "@codemirror/state": "^6.7.1", + "@codemirror/view": "^6.43.6", "@connectrpc/connect": "^2.1.1", "@connectrpc/connect-web": "^2.1.1", "@github/relative-time-element": "^5.0.0", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index fdd9e4c9..f1b4e2e6 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -21,11 +21,11 @@ importers: specifier: ^6.12.4 version: 6.12.4 '@codemirror/state': - specifier: ^6.7.0 - version: 6.7.0 + specifier: ^6.7.1 + version: 6.7.1 '@codemirror/view': - specifier: ^6.43.3 - version: 6.43.3 + specifier: ^6.43.6 + version: 6.43.6 '@connectrpc/connect': specifier: ^2.1.1 version: 2.1.1(@bufbuild/protobuf@2.12.0) @@ -498,11 +498,11 @@ packages: '@codemirror/lint@6.9.7': resolution: {integrity: sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg==} - '@codemirror/state@6.7.0': - resolution: {integrity: sha512-Zbl9NyscLMZkfXPQnNAIIAFftidrA1UbcJEIMp24C0Bukc2I5T8wJS0wsXYsnDOqCFJUeJ1BITGNs5CqPDSmSg==} + '@codemirror/state@6.7.1': + resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} - '@codemirror/view@6.43.3': - resolution: {integrity: sha512-MwEwCAr/o0agJefhC2+reBv5kfOQpMcDRUNQrRYZgWlhH8IwQcerMZrpqWyUFSyO0ebgN2cnh/w87F7G4BGSng==} + '@codemirror/view@6.43.6': + resolution: {integrity: sha512-EVunGSYN1wz1p75WY1s3Xg7t3i8Yol0kGZGizNdX9BUFgMFILYVe8/u6EVpo7Ff5PwbZuILb4QAq7IZoKzIEQA==} '@connectrpc/connect-web@2.1.1': resolution: {integrity: sha512-J8317Q2MaFRCT1jzVR1o06bZhDIBmU0UAzWx6xOIXzOq8+k71/+k7MUF7AwcBUX+34WIvbm5syRgC5HXQA8fOg==} @@ -633,8 +633,8 @@ packages: '@lezer/markdown@1.6.4': resolution: {integrity: sha512-N0SxazMj4k65DBfaf1azqtMZd6u7MqluP84/NZnB/io8Td9aleFmAhz9hcbvSfsxT5tdYlJ5qgv5aMJGY4zEtA==} - '@marijn/find-cluster-break@1.0.2': - resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@marijn/find-cluster-break@1.0.3': + resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==} '@mermaid-js/parser@1.1.0': resolution: {integrity: sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==} @@ -1828,6 +1828,9 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} + css-tree@3.2.1: resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -3360,22 +3363,22 @@ snapshots: '@codemirror/autocomplete@6.20.3': dependencies: '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@codemirror/commands@6.10.4': dependencies: '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@codemirror/lang-css@6.3.1': dependencies: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 + '@codemirror/state': 6.7.1 '@lezer/common': 1.5.2 '@lezer/css': 1.3.3 @@ -3385,8 +3388,8 @@ snapshots: '@codemirror/lang-css': 6.3.1 '@codemirror/lang-javascript': 6.2.5 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/css': 1.3.3 '@lezer/html': 1.3.13 @@ -3396,8 +3399,8 @@ snapshots: '@codemirror/autocomplete': 6.20.3 '@codemirror/language': 6.12.4 '@codemirror/lint': 6.9.7 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/javascript': 1.5.4 @@ -3406,15 +3409,15 @@ snapshots: '@codemirror/autocomplete': 6.20.3 '@codemirror/lang-html': 6.4.11 '@codemirror/language': 6.12.4 - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/markdown': 1.6.4 '@codemirror/language@6.12.4': dependencies: - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.10 @@ -3422,18 +3425,18 @@ snapshots: '@codemirror/lint@6.9.7': dependencies: - '@codemirror/state': 6.7.0 - '@codemirror/view': 6.43.3 + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.6 crelt: 1.0.6 - '@codemirror/state@6.7.0': + '@codemirror/state@6.7.1': dependencies: - '@marijn/find-cluster-break': 1.0.2 + '@marijn/find-cluster-break': 1.0.3 - '@codemirror/view@6.43.3': + '@codemirror/view@6.43.6': dependencies: - '@codemirror/state': 6.7.0 - crelt: 1.0.6 + '@codemirror/state': 6.7.1 + crelt: 1.0.7 style-mod: 4.1.3 w3c-keyname: 2.2.8 @@ -3572,7 +3575,7 @@ snapshots: '@lezer/common': 1.5.2 '@lezer/highlight': 1.2.3 - '@marijn/find-cluster-break@1.0.2': {} + '@marijn/find-cluster-break@1.0.3': {} '@mermaid-js/parser@1.1.0': dependencies: @@ -4657,6 +4660,8 @@ snapshots: crelt@1.0.6: {} + crelt@1.0.7: {} + css-tree@3.2.1: dependencies: mdn-data: 2.27.1 diff --git a/web/src/components/MemoEditor/Editor/editor.css b/web/src/components/MemoEditor/Editor/editor.css index 45a534bc..2e741703 100644 --- a/web/src/components/MemoEditor/Editor/editor.css +++ b/web/src/components/MemoEditor/Editor/editor.css @@ -12,14 +12,11 @@ & .cm-editor { background: transparent; font-size: 1rem; - /* Fill the host so the whole visible editor area belongs to CodeMirror. - Without this the editor only grows to its content height, and any empty - space below the text (notably in focus mode, where the host is tall) is - bare host markup — clicking it can't focus the editor or place the caret, - so the caret appears to vanish in "empty" space (#6076). height:100% - collapses to auto when the host is auto-height (normal mode), so this - only fills when the host has a definite height. */ + max-height: 50vh; + } + &[data-focus-mode] .cm-editor { height: 100%; + max-height: none; } & .cm-editor.cm-focused { outline: none; @@ -27,7 +24,6 @@ & .cm-content { font-family: inherit; padding: 0; - caret-color: var(--foreground); } & .cm-line { padding: 0; @@ -35,6 +31,7 @@ & .cm-scroller { font-family: inherit; line-height: 1.5; + overflow: auto; } & .cm-placeholder { color: var(--muted-foreground); diff --git a/web/src/components/MemoEditor/Editor/extensions.ts b/web/src/components/MemoEditor/Editor/extensions.ts index 5d86cb1d..514cf04a 100644 --- a/web/src/components/MemoEditor/Editor/extensions.ts +++ b/web/src/components/MemoEditor/Editor/extensions.ts @@ -1,7 +1,7 @@ import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands"; import { markdown } from "@codemirror/lang-markdown"; import { indentUnit } from "@codemirror/language"; -import { EditorState, type Extension } from "@codemirror/state"; +import type { Extension } from "@codemirror/state"; import { placeholder as cmPlaceholder, drawSelection, dropCursor, EditorView, type KeyBinding, keymap } from "@codemirror/view"; import { GFM } from "@lezer/markdown"; import { headingDecorations } from "./headingDecorations"; @@ -50,15 +50,11 @@ export function buildEditorExtensions({ placeholder, onChange, onUpdate, onSubmi ]; return [ - // Core editing behavior. Without these the editor relies on raw - // contenteditable: typing works but there is no visible caret on focus - // (drawSelection), no undo/redo (history), and Enter/selection/word-motion - // keys are unwired (defaultKeymap). They are NOT part of CodeMirror's - // minimal core — basicSetup bundles them, and we assemble them here. + // Core editing behavior. These are the pieces from CM6 setup that this memo + // editor uses, without enabling multi-cursor selection. history(), drawSelection(), dropCursor(), - EditorState.allowMultipleSelections.of(true), // Indent with spaces (markdown), matching the 2-space bullet nesting. indentUnit.of(" "), markdown({ extensions: [GFM] }), diff --git a/web/src/components/MemoEditor/Editor/index.tsx b/web/src/components/MemoEditor/Editor/index.tsx index a3f9b501..d560dfd2 100644 --- a/web/src/components/MemoEditor/Editor/index.tsx +++ b/web/src/components/MemoEditor/Editor/index.tsx @@ -3,7 +3,6 @@ import { EditorView } from "@codemirror/view"; import { forwardRef, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef } from "react"; import { useTagCounts } from "@/hooks/useUserQueries"; import { cn } from "@/lib/utils"; -import { EDITOR_HEIGHT } from "../constants"; import type { EditorController } from "../types/editorController"; import { createController } from "./controller"; import "./editor.css"; @@ -78,13 +77,10 @@ const Editor = forwardRef(function Editor(props: EditorProps, ref: React.Forward return (