Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
629270d
docs: add approved inline text editing design spec
DavidBabinec Jun 10, 2026
f975e9a
feat(module-engine): add inlineTextEdit contract, declare on text/but…
DavidBabinec Jun 10, 2026
a0a7f24
feat(editor-store): add inline text edit session slice with coalesced…
DavidBabinec Jun 10, 2026
6bfcbf6
feat(editor-store): force-close inline edit sessions on deletion and …
DavidBabinec Jun 11, 2026
20edb1d
feat(canvas): add inline-edit typography mirroring helpers
DavidBabinec Jun 11, 2026
6bad4b7
feat(canvas): add InlineTextEditOverlay, mounted per breakpoint frame
DavidBabinec Jun 11, 2026
ee59e9f
feat(canvas): wire double-click inline editing and hide doubled text
DavidBabinec Jun 11, 2026
41b2575
docs: document canvas inline text editing (parent-doc overlay)
DavidBabinec Jun 11, 2026
a617084
docs: fix remaining stale slice counts in editor.md (11 -> 12)
DavidBabinec Jun 11, 2026
83bf384
docs: fix stale slice count in adminUi header comment (11 -> 12)
DavidBabinec Jun 11, 2026
7447335
Merge origin/main into feat/inline-text-editing
DavidBabinec Jun 11, 2026
6cfeb1a
fix(canvas): render canvas + inline-edit field in the site's fonts, n…
DavidBabinec Jun 11, 2026
61b3457
fix(canvas): stop inline-edit field scroll-shifting multi-line text
DavidBabinec Jun 11, 2026
b7b265a
fix(canvas): remove inline-edit open flash by positioning in a layout…
DavidBabinec Jun 11, 2026
a23853d
feat(canvas): rewrite inline text editing to edit the real element in…
DavidBabinec Jun 11, 2026
84b59ea
fix(canvas): stop React clobbering the inline-edit caret every keystroke
DavidBabinec Jun 11, 2026
4fe6f20
fix(canvas): let the spacebar type a space during inline editing
DavidBabinec Jun 11, 2026
3486ff0
fix(canvas): finalize inline editing — keyboard-forward guard, select…
DavidBabinec Jun 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(canvas): let the spacebar type a space during inline editing
Pressing space mid-word did nothing. The edited element lives in a breakpoint
iframe, which forwards its keystrokes to the parent document as a clone
dispatched on `document` (so parent shortcuts like Cmd+K/Cmd+S work). The
space-to-pan handler (useCanvas) listens on that document and guards only
against `target.isContentEditable` — but the forwarded event's target IS the
document, not the iframe's editing element, so the guard missed it, the handler
called preventDefault(), and forwardKeyboard propagated that back to suppress
the original spacebar. Net effect: every space was eaten.

Guard the space-pan handler with the same activeInlineEdit check the other
canvas shortcut handler uses: while a session is active the spacebar (and every
non-Escape/Enter key) must reach the editing element untouched.

Verified in a real browser: a Space keydown on the editing element went from
defaultPrevented:true to defaultPrevented:false after the fix; contentEditable
inserts the space normally (execCommand path already confirmed spaces work).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
  • Loading branch information
DavidBabinec and claude committed Jun 11, 2026
commit 4fe6f20a2f4db34e74a831be600eaa2fb5d31ff9
9 changes: 9 additions & 0 deletions src/__tests__/canvas/inlineTextEditingWiring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { readFileSync } from 'fs'
const CANVAS_ROOT = new URL('../../admin/pages/site/canvas/CanvasRoot.tsx', import.meta.url)
const NODE_RENDERER = new URL('../../admin/pages/site/canvas/NodeRenderer.tsx', import.meta.url)
const KEYBOARD_SHORTCUTS = new URL('../../admin/pages/site/canvas/useCanvasKeyboardShortcuts.ts', import.meta.url)
const USE_CANVAS = new URL('../../admin/pages/site/hooks/useCanvas.ts', import.meta.url)
const BREAKPOINT_FRAME = new URL('../../admin/pages/site/canvas/BreakpointFrame.tsx', import.meta.url)
const CONTEXTS = new URL('../../admin/pages/site/canvas/CanvasContexts.ts', import.meta.url)

Expand Down Expand Up @@ -63,6 +64,14 @@ describe('inline text editing wiring (in-place contentEditable)', () => {
expect(src).toContain('if (useEditorStore.getState().activeInlineEdit) return')
})

it('space-to-pan bails while an inline edit is active so the spacebar types a space', () => {
// The edited element forwards its keystrokes to the parent document, where
// the space-pan handler would otherwise preventDefault the spacebar and the
// author could never type a space mid-word.
const src = readFileSync(USE_CANVAS, 'utf-8')
expect(src).toContain('if (useEditorStore.getState().activeInlineEdit) return')
})

it('BreakpointFrame no longer mounts an inline-edit overlay', () => {
const src = readFileSync(BREAKPOINT_FRAME, 'utf-8')
expect(src).not.toContain('InlineTextEditOverlay')
Expand Down
8 changes: 8 additions & 0 deletions src/admin/pages/site/hooks/useCanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,14 @@ export function useCanvas({ canvasRootRef, transformLayerRef, enabled }: UseCanv
useEffect(() => {
function onKeyDown(e: KeyboardEvent) {
if (e.code === 'Space' && !e.repeat) {
// Inline text editing owns the keyboard. The edited element lives in a
// breakpoint iframe and forwards its keystrokes here as a clone
// dispatched on `document`, so `e.target` is the document — the
// contentEditable check below can't see it. Without this guard the
// space-pan would preventDefault every spacebar press, so the author
// could never type a space. The editing element handles Escape/Enter
// itself; every other key (space included) must reach it untouched.
if (useEditorStore.getState().activeInlineEdit) return
const target = e.target as HTMLElement
// Don't intercept space in inputs/textareas
if (
Expand Down