M7: editor keyboard + one-click card toolbars (live-pass fixes)
CI & Build / Python lint (push) Successful in 2s
CI & Build / TypeScript typecheck (push) Successful in 5s
CI & Build / Python tests (push) Successful in 9s
CI & Build / Build & push image (push) Successful in 30s

From the unified-editor live pass (task 1922):

- Esc now returns to the base Notes board from any view (AppShell); an open editor consumes Esc first (its handler stops propagation) so it closes before navigating.

- Ctrl/Cmd+Enter = finish & close in BOTH frames — it already closed the modal editor; now it also commits+collapses the board composer (matches the email/chat 'send' convention). Shift+Enter still saves & starts a new note.

- Fix: the inline composer committed on document mousedown, collapsing and shifting the board before a click landed — so clicking another card's pin/archive/trash took two clicks. Commit on click (bubble phase) instead; the target's action fires first, then the composer closes.

Pure frontend.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRgehjoz7Yv8LkUfADxACm
This commit is contained in:
2026-07-22 14:53:18 -04:00
co-authored by Claude Opus 4.8
parent 261d8fcac5
commit 47974f62ee
2 changed files with 18 additions and 7 deletions
+10 -5
View File
@@ -192,12 +192,17 @@ function onEsc(): void {
else void close();
}
function onMetaEnter(): void {
if (!props.inline) void close();
// Ctrl/Cmd+Enter = finish & close, in both frames (matches email/chat "send").
if (props.inline) void commitInline();
else void close();
}
function onBackdropMousedown(): void {
if (!props.inline) void close();
}
function onDocMousedown(e: MouseEvent): void {
function onDocClick(e: MouseEvent): void {
// Commit the inline composer on an OUTSIDE *click* (bubble phase, not mousedown):
// the clicked target's own handler fires first, so clicking another card's toolbar
// performs its action, THEN the composer collapses — no wasted first click.
if (props.inline && expanded.value && root.value && !root.value.contains(e.target as Node)) {
void commitInline();
}
@@ -230,14 +235,14 @@ onMounted(async () => {
void titles.load();
void loadBacklinks();
if (props.inline) {
document.addEventListener("mousedown", onDocMousedown);
document.addEventListener("click", onDocClick);
if (props.autofocus) void open();
} else {
await nextTick();
bodyInput.value?.focus();
}
});
onBeforeUnmount(() => document.removeEventListener("mousedown", onDocMousedown));
onBeforeUnmount(() => document.removeEventListener("click", onDocClick));
// ---- outgoing links (edit mode) ----
const outgoingLinks = computed(() => {
@@ -489,7 +494,7 @@ defineExpose({ open });
"
:role="inline ? undefined : 'dialog'"
:aria-modal="inline ? undefined : 'true'"
@keydown.esc="onEsc"
@keydown.esc.stop="onEsc"
@keydown.enter.meta.prevent="onMetaEnter"
@keydown.enter.ctrl.prevent="onMetaEnter"
@paste="onPaste"