selecting a block shows its settings, not a modal

editComponent means "edit what is IN this block", and for media and galleries
that is a dialog over the whole screen. Firing it on selection threw one at you
before you had asked for it — those kinds get a button in the settings instead.

Free text keeps opening inline, because its editor is in the same column and
opening it IS showing the settings.

The text editor now only renders when it belongs to the selected block. A stale
one showed the previous block's words under the new block's title.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-01 19:55:05 +01:00
co-authored by Claude Opus 5
parent 1ec361d006
commit 9c97773cf7
+36 -2
View File
@@ -1,5 +1,6 @@
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { Button } from '@/components/ui/button';
import { href, useNav } from '../routes'; import { href, useNav } from '../routes';
import { useClient } from 'hooks/useClient'; import { useClient } from 'hooks/useClient';
import { readableError } from '../errors'; import { readableError } from '../errors';
@@ -189,7 +190,21 @@ export const PageBuilderPanel = () => {
return; return;
} }
const found = sections.flatMap((section) => section.components).find((one) => String(one.id) === piece); const found = sections.flatMap((section) => section.components).find((one) => String(one.id) === piece);
if (found) editComponentRef.current(found); if (!found) return;
/*
Selecting a block shows its settings. It does not open a picker.
`editComponent` means "edit what is IN this block", and for media and galleries that is a modal
over the whole screen. Firing it on mere selection meant clicking a row in the nav threw a dialog
at you before you had said you wanted one — those kinds get a button in the settings instead.
Free text is different: its editor is inline in the same column, so opening it on selection is
the same act as showing the settings.
*/
if (found.kind === 'free-text') editComponentRef.current(found);
// Whatever was open belonged to the block that was selected before this one.
else setEditing(null);
}, [piece, sections]); }, [piece, sections]);
/* /*
@@ -605,7 +620,9 @@ export const PageBuilderPanel = () => {
steps={steps} steps={steps}
onSaved={() => setRendered((n) => n + 1)} onSaved={() => setRendered((n) => n + 1)}
/> />
{editing && ( {/* Only when it belongs to THIS block. A stale one showed the previous block's words under
the new block's title. */}
{editing?.id === block.id && (
<FreeTextEditor <FreeTextEditor
html={editing.html} html={editing.html}
busy={creating} busy={creating}
@@ -617,6 +634,23 @@ export const PageBuilderPanel = () => {
onSave={() => void saveTextRef.current()} onSave={() => void saveTextRef.current()}
/> />
)} )}
{/*
The kinds whose contents are chosen rather than typed.
A button rather than the modal opening itself, so picking the block and changing what is in
it are two acts — see the note in the selection effect.
*/}
{(block.kind === 'media' || block.kind === 'video' || block.kind === 'gallery') && (
<Button
size="sm"
variant="outline"
className="h-8 self-start text-xs"
onClick={() => handlersRef.current.editComponent(block)}
>
{block.kind === 'gallery' ? 'Choose gallery…' : 'Choose media…'}
</Button>
)}
</div>, </div>,
); );
return; return;