Files
fofos-admin/web/useEditorSlot.ts
pastilhasandClaude Opus 5 9eb17c8d03 an editor opens beside the page, not under it
The spacing and free-text editors rendered below the preview, so they took their height from the thing
being edited: choosing a spacing shrank the page you were choosing it for, and on a laptop two
dropdowns cost a third of the frame.

They are a third panel now, to the right of the preview. The workspace already knows how to size and
move panels; a drawer was a second, worse layout system living inside one of them.

The panel holds nothing. Whichever panel owns a selection BUILDS the editor and announces it through a
`useGlobal` slot — the two are siblings and neither may own the other, and a provider around both would
mean something above them knowing they exist.

The slot carries the ELEMENT, not a description of one. A descriptor plus a switch would move every
editor's loading, saving and cancelling into a panel that would have to learn what a section is — a
second place that understands the page builder, kept in step by hand. SaveTarget makes the same trade
for the same reason.

The hazard is real and worth naming: an element captures the props it was built with, so the announcing
effect must depend on everything the editor DISPLAYS. The save handlers sit in refs so they cannot drag
that list wider — depending on them would re-announce on every keystroke, and omitting them without
refs would announce a stale one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-01 02:29:08 +01:00

33 lines
1.5 KiB
TypeScript

import type { ReactNode } from 'react';
import { useGlobal } from 'hooks/useGlobal';
/**
* What the editor panel is showing, announced by whichever panel owns it.
*
* ── Why the ELEMENT and not a descriptor ──
*
* The obvious shape is `{ kind: 'spacing', componentId: 12 }` and a switch in the panel. That means
* every editor's loading, saving and cancelling moves out of the panel that knows about sections and
* into one that would have to learn — a second place that understands what a component is, kept in
* step by hand.
*
* So the owner builds the editor and this carries it. The panel is a frame: it decides where the
* editor lives on screen and nothing about what it does. `SaveTarget` makes the same trade for the
* same reason — the section announces its own Save rather than DetailPanel learning to perform one.
*
* ── The hazard, which is real ──
*
* An element captures the props it was built with. Announce it once and the panel will happily show
* the values from that render forever. Whoever announces must do so in an effect that depends on
* everything the editor displays — the same rule `useSaveTarget` documents, and the same way to get it
* wrong.
*
* ── `useGlobal`, not a context ──
*
* The two panels are siblings; neither may own the other, and wrapping both in a provider would mean a
* component above them knowing they exist. A keyed slot is the house pattern for exactly this.
*/
const KEY = ['fofos-admin', 'editor'];
export const useEditorSlot = () => useGlobal<ReactNode>(KEY, null);