Reusable building blocks for editor chrome. Lives in packages/sdk/src/chrome/primitives/ (and packages/sdk/src/chrome/floating/ for window-style panels).
Reusable building blocks for editor chrome. Lives in packages/sdk/src/chrome/primitives/ (and packages/sdk/src/chrome/floating/ for window-style panels).
When you need a popover, floating panel, scrollable list, or sidebar surface, reach for one of these before writing a new one. Hand-rolled absolute + outside-click hacks are not allowed — see editor-popover-pattern.md.
Every "label-on-the-left + control-on-the-right" row in the editor sidebar is a Chip. Reach for it before hand-rolling <div flex> + label spans or <div className="input-wrapper ..."> wrappers. See chip.md for the full pattern doc.
mode="input" (default) — children plug in as the inline control (text input, segmented control, swatch button, etc.). frame="bordered" (default) gives the canonical h-8 input-wrapper; frame="bare" drops the border for self-bordered controls. grow swaps h-8 for min-h-8 (textarea). variant="swatch" for full-bleed leading controls (color picker).mode="popover" — chip is a click-to-open trigger. Owns leading icon + summary text + clear × (session-aware). variant="preview" for full-bleed preview swatch (gradient/image).label and the gutter renders with truncation-aware tooltip + click-forward to the row's primary control. Pass propKey + propType (when class-typed) and the breakpoint-pill indicator renders next to the label automatically. passthrough is the escape hatch when the row is being rendered inside a parent that already provides the frame.size-5 rounded icon button. Variants: ghost (default — no hover bg, used inside chip trailing slots) and subtle (hover:bg-neutral ramp, used standalone).× button. Default mode composes from ToolbarIconButton; floating variant overlays a media tile. Chip mode="popover" adds one of these automatically; manual placement is for input-mode chips that want a clear affordance in the trailing slot.open. Composes from ToolbarIconButton.swatch (h-6 w-12) and video (aspect-video w-full). Used by PatternsDialogInput swatch, MediaInput preview, MediaTab selected-media preview. Not a button — wrap in one if you need click semantics.<label> [+ Add...] empty-state row. Thin shell over Chip; used by ActionInput / HandlersInput empty states inside list-item detail panels so the three rows (Action / Handlers / Icon) all read as one consistent labeled-chip pattern instead of full-width dashed CTAs.Historical note:
ToolbarRowFrame,PopoverChip,BgWrap,Wrap,Labler,MobileDesktopLabelsare deleted. Anything that still references them is stale — replace withChip.
Suspense for childless-container empty state (import from selectors). Implementation: EditorEmptyLeafHintView.tsx.PAGEHUB_RTT_GLOBAL_ID + REACT_TOOLTIP_SURFACE_CLASSComposition: <AnchoredPopover> for positioning + outside-click + ESC + fade, plus Headless UI <Combobox> for search input, filtering, keyboard nav.
Use this for any "click trigger → search → pick one" UX. Items shape:
type SearchableMenuItem = {
id: string;
label: string;
hint?: string; // right-aligned secondary
help?: string; // tooltip
keywords?: string[]; // extra filter terms
data?: unknown; // passed back to onSelect
};
Anchor positions: "bottom start" | "bottom end" | "top start" | "top end".
For window-style draggable, resizable panels (settings windows, large dialogs, popover-mode property editors). Backed by:
useDraggableWindow (drag from header)useResizable (per-edge resize, persisted via storageKey)useFocusTrap (a11y)Supports backdrop, dock-to-edge, focus trap, ESC. NOT for anchored popovers — use AnchoredPopover.
scrollable + bodyClassName propsDefault scrollable={false} — children render bare (preserves behavior for non-popover callers like ModifiersModal, SettingsShell, IconPickerPanel).
Pass scrollable and FloatingPanel wraps children in <AutoHideScrollbar className="flex-1"><div className={bodyClassName}>...</div></AutoHideScrollbar> for you. Default bodyClassName="text-base-content flex flex-col gap-2 p-3 text-xs" matches the popover-mode property convention. Override with a custom string, or pass bodyClassName={null} to skip the inner padded wrapper (rare — when scrollable is true but children manage their own padding).
<FloatingPanel ... scrollable>
<SomeBody />
</FloatingPanel>
This is the canonical structure for popover-mode property panels (Action, Animations, Conditions per-chip editor, Data Attributes, Bundle, Gradient, Pattern). Do not hand-roll <div className="...overflow-y-auto p-3..."> wrappers inside <FloatingPanel> — that produces an ugly native browser scrollbar instead of the auto-hiding one. See editor-popover-pattern.md authoring checklist.
Exponential-ramp progress bar. Ramps toward ~92% while active, snaps to 100% when done. Sizes: default, sm. Optional overlay mode for blur-overlay use. Honors prefers-reduced-motion.
The SDK mounts a single <ReactTooltip id={PAGEHUB_RTT_GLOBAL_ID}> in core/context.tsx. All chrome tooltips must wire to it via data-attrs — never title="". See .claude/rules/tooltips.md.
<button
data-tooltip-id={PAGEHUB_RTT_GLOBAL_ID}
data-tooltip-content="Drag to move"
data-tooltip-place="bottom"
/>