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:
@@ -33,6 +33,7 @@ import { AddSectionDialog, type SectionLayout } from './AddSectionDialog';
|
||||
import { FreeTextEditor } from './FreeTextEditor';
|
||||
import { SpacingEditor, type Padding } from './SpacingEditor';
|
||||
import { BandSettings } from './BandSettings';
|
||||
import { BlockSettings } from './BlockSettings';
|
||||
import { useEditorSlot } from '../useEditorSlot';
|
||||
import { AddComponentDialog, type ComponentKind } from './AddComponentDialog';
|
||||
import { MediaPicker } from '../MediaPicker';
|
||||
@@ -462,7 +463,14 @@ export const PageBuilderPanel = () => {
|
||||
if (!node) return;
|
||||
|
||||
const tools = node.querySelector('[data-fofos-admin-canvas="component-tools"]');
|
||||
node.innerHTML = editing.html;
|
||||
/*
|
||||
The BLOCK inside, when the component has a heading.
|
||||
|
||||
A titled component renders as a wrapper — heading, then `[data-block]` — and writing into the
|
||||
wrapper would replace the heading with the paragraph as somebody typed. Untitled ones are not
|
||||
wrapped, so the node itself is the block.
|
||||
*/
|
||||
(node.querySelector<HTMLElement>('[data-block]') ?? node).innerHTML = editing.html;
|
||||
if (tools) node.append(tools);
|
||||
}, [editing?.id, editing?.html]);
|
||||
|
||||
@@ -577,6 +585,42 @@ export const PageBuilderPanel = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
The selected block's heading, above whatever editor its kind has.
|
||||
|
||||
Announced together, because they are one selection: the heading belongs to the block and the
|
||||
editor is what is inside it. A block with no editor gets the heading alone, which is why every
|
||||
block is selectable now.
|
||||
*/
|
||||
const owner = piece ? sections.find((one) => one.components.some((c) => String(c.id) === piece)) : null;
|
||||
const block = owner?.components.find((c) => String(c.id) === piece);
|
||||
|
||||
if (block && owner && page) {
|
||||
setEditorRef.current(
|
||||
<div className="flex flex-col gap-4">
|
||||
<BlockSettings
|
||||
pageId={page.id}
|
||||
sectionId={owner.id}
|
||||
block={block}
|
||||
onSaved={() => setRendered((n) => n + 1)}
|
||||
/>
|
||||
{editing && (
|
||||
<FreeTextEditor
|
||||
html={editing.html}
|
||||
busy={creating}
|
||||
onChange={(html) => setEditing((was) => (was ? { ...was, html } : was))}
|
||||
onCancel={() => {
|
||||
setEditing(null);
|
||||
setRendered((n) => n + 1);
|
||||
}}
|
||||
onSave={() => void saveTextRef.current()}
|
||||
/>
|
||||
)}
|
||||
</div>,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (editing) {
|
||||
setEditorRef.current(
|
||||
<FreeTextEditor
|
||||
|
||||
Reference in New Issue
Block a user