every block is selectable, and has a Title

canEditComponent answers "is there content to type", and a heading is not
content — so the blocks with no editor of their own are now selectable too, and
get the heading alone.

The live draft writes into [data-block] when there is one. A titled component
renders as a wrapper, and writing into the wrapper would replace the heading with
the paragraph as somebody typed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-01 19:46:59 +01:00
co-authored by Claude Opus 5
parent aaf767087e
commit 361684b8c5
3 changed files with 123 additions and 5 deletions
+7 -4
View File
@@ -53,6 +53,8 @@ export type CanvasComponent = {
id: number;
column: number;
kind: string;
/** The heading the page draws above the block, or null. Every kind may have one. */
title?: string | null;
/*
One optional field per kind that the panel reads back. Not `Record<string, unknown>`: every reader
would then need a cast, and the point of naming them is that the compiler knows `free-text` holds
@@ -128,6 +130,11 @@ const style = (element: HTMLElement, rules: string[]) => {
* So this draws nothing at all: no elements, no stylesheet, no outlines. A click selects a block, and
* its editor opens in the panel beside the preview — where every other control now lives.
*
* ── Every block is selectable ──
*
* Including the ones with no editor of their own. `canEditComponent` answers "is there content to
* type", and since every block now has an optional heading, there is always something to open.
*
* ── The marker stays ──
*
* `data-fofos-component` is how the panel finds the block being edited so it can write a draft into it
@@ -158,10 +165,6 @@ export function paintSelection(document: Document, canvas: Canvas): () => void {
node.setAttribute('data-fofos-component', String(component.id));
undo.push(() => node.removeAttribute('data-fofos-component'));
// A block the panel has no editor for is left alone: a click that opens nothing reads as a
// failure, which is worse than a click that does nothing. See canEditComponent.
if (canvas.canEditComponent && !canvas.canEditComponent(component)) continue;
const open = (event: MouseEvent) => {
// The page is real, so a block can hold a link and following it would leave the editor.
event.preventDefault();