@tangle-network/agent-app 0.23.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DesignCanvas-JTSAL6KX.js → DesignCanvas-MA5EH324.js} +2 -2
- package/dist/DesignCanvasEditor-YLCO7I5I.js +9 -0
- package/dist/{chunk-NSKJFV4Y.js → chunk-FSUR2752.js} +156 -22
- package/dist/chunk-FSUR2752.js.map +1 -0
- package/dist/{chunk-2W4YCAFH.js → chunk-LPAVBGVY.js} +485 -174
- package/dist/chunk-LPAVBGVY.js.map +1 -0
- package/dist/design-canvas-react/index.d.ts +42 -5
- package/dist/design-canvas-react/index.js +60 -124
- package/dist/design-canvas-react/index.js.map +1 -1
- package/package.json +1 -6
- package/dist/DesignCanvasEditor-YPVETLZG.js +0 -9
- package/dist/chunk-2W4YCAFH.js.map +0 -1
- package/dist/chunk-NSKJFV4Y.js.map +0 -1
- /package/dist/{DesignCanvas-JTSAL6KX.js.map → DesignCanvas-MA5EH324.js.map} +0 -0
- /package/dist/{DesignCanvasEditor-YPVETLZG.js.map → DesignCanvasEditor-YLCO7I5I.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/design-canvas-react/components/DesignCanvas.tsx","../src/design-canvas-react/engine/command-stack.ts","../src/design-canvas-react/engine/commands.ts","../src/design-canvas-react/components/ruler-math.ts","../src/design-canvas-react/components/BleedTrimOverlay.tsx","../src/design-canvas-react/components/PagesStrip.tsx","../src/design-canvas-react/components/glyphs.tsx","../src/design-canvas-react/components/Rulers.tsx","../src/design-canvas-react/components/Toolbar.tsx","../src/design-canvas-react/components/ZoomControls.tsx","../src/design-canvas-react/components/ExportControl.tsx"],"sourcesContent":["/**\n * Root editor shell. Products mount exactly this component. Layout mirrors\n * Polotno: optional left side panel | main column | optional right agent panel.\n *\n * Main column stacks top→bottom:\n * Toolbar (undo/redo, view toggles, selection attrs, page props)\n * Rulers + Workspace (the Workspace is injected by the integrator via the\n * `renderWorkspace` prop — it owns Konva and is Konva-\n * specific; this chrome stays canvas-free)\n * bottom row: PagesStrip + ZoomControls\n *\n * Command lifecycle:\n * - The command stack lives here; every panel receives callbacks, never the\n * stack itself.\n * - `onApplyOperations` is called optimistically after every command. If it\n * rejects, the command is rolled back locally. If it resolves with a fresh\n * `document`, the stack rebases via `stack.reset(document)` — this preserves\n * history while reconciling server-minted ids or normalised values.\n * - `setView` (zoom/pan/selection/toggles) never enters history.\n * - Keyboard: Mod+Z undo · Shift+Mod+Z / Mod+Y redo · Delete/Backspace deletes\n * the selection · F fits the page (forwarded to workspace via ref).\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'\nimport type { SceneDocument, SceneElement } from '../../design-canvas/model'\nimport { findElement, requirePage } from '../../design-canvas/model'\nimport type { SceneAttrsPatch, SceneOperation } from '../../design-canvas/operations'\nimport type { PageBleed } from '../../design-canvas/model'\nimport type { DesignCanvasProps, ExportTriggerOptions, SceneCommand } from '../contracts'\nimport { createSceneCommandStack } from '../engine/command-stack'\nimport {\n addPageCommand,\n bindSlotCommand,\n deleteElementCommand,\n deletePageCommand,\n duplicatePageCommand,\n groupElementsCommand,\n multiSetAttrsCommand,\n reorderElementCommand,\n reorderPageCommand,\n setAttrsCommand,\n setPageGuidesCommand,\n setPagePropsCommand,\n ungroupElementCommand,\n} from '../engine/commands'\nimport { clampIndex, indexBackward, indexForward, topIndex } from './ruler-math'\nimport { BleedTrimOverlay } from './BleedTrimOverlay'\nimport { LayersPanel } from './LayersPanel'\nimport { PagesStrip } from './PagesStrip'\nimport { Rulers } from './Rulers'\nimport { Toolbar } from './Toolbar'\nimport { ZoomControls } from './ZoomControls'\nimport { ExportControl } from './ExportControl'\n\n/** Callers inject a workspace renderer so this chrome stays Konva-free. The\n * workspace occupies the scrollable area between the rulers and the bottom bar. */\nexport interface DesignCanvasFullProps extends DesignCanvasProps {\n /**\n * Render the Konva canvas workspace into the slot this shell provides.\n * The shell passes viewport dimensions, view-state, and the shared command\n * stack so `WorkspaceView` can commit gestures through the same stack the\n * chrome uses for undo/redo and layers-panel selection.\n *\n * `onFitRef` is a ref the workspace fills with a fit-page callback; the\n * shell calls it when the user presses F or clicks the Fit button.\n */\n renderWorkspace(ctx: {\n document: SceneDocument\n activePageId: string\n selectedElementIds: string[]\n zoom: number\n panX: number\n panY: number\n gridEnabled: boolean\n gridSize: number\n snapEnabled: boolean\n showBleed: boolean\n canWrite: boolean\n /** The chrome's command stack. Pass to WorkspaceView so gestures, undo,\n * and layers-panel selection share a single state machine. */\n stack: ReturnType<typeof createSceneCommandStack>\n activePage: SceneDocument['pages'][number] | undefined\n onFitRef: React.MutableRefObject<(() => void) | null>\n /** A ref the workspace fills with an export callback. The chrome's Export\n * control calls it with the chosen format/scale; the workspace renders the\n * Konva stage to a data URL and forwards the result to `onExport`. Filled\n * only when `onExport` is wired (the workspace skips it otherwise). */\n onExportRef: React.MutableRefObject<((opts: ExportTriggerOptions) => void) | null>\n /** Forwarded from DesignCanvasProps. Default true: WorkspaceView fits the\n * active page to the viewport once, on the first non-zero measurement. */\n fitOnMount?: boolean\n /** Forwarded from DesignCanvasProps. Fires once after the first real\n * measurement, after the initial fit is applied (or skipped). */\n onReady?(): void\n onZoomChange(zoom: number): void\n onPanChange(panX: number, panY: number): void\n onSelectElements(ids: string[], additive: boolean): void\n }): React.ReactNode\n\n /**\n * Generates page thumbnails for the PagesStrip. Injected by the integrator\n * (who has Konva access) so the chrome doesn't import Konva directly.\n */\n renderThumbnail(page: SceneDocument['pages'][number]): Promise<string | null>\n}\n\nfunction mintId(): string {\n const uuid = globalThis.crypto && 'randomUUID' in globalThis.crypto\n ? globalThis.crypto.randomUUID()\n : null\n return `local-${uuid ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}`\n}\n\nfunction isTypingTarget(target: EventTarget | null): boolean {\n return (\n target instanceof Element &&\n target.closest('input, textarea, select, [contenteditable=\"true\"]') !== null\n )\n}\n\n/** Commit a command: execute optimistically, persist via `onApplyOperations`,\n * roll back locally on rejection. The command reference is captured at call\n * time so the rejection handler removes that specific command regardless of\n * how many further commands the user has executed while the save was pending. */\nfunction useCommitCommand(\n stack: ReturnType<typeof createSceneCommandStack>,\n onApplyOperations: DesignCanvasProps['onApplyOperations'],\n canWrite: boolean,\n setError: (msg: string | null) => void,\n) {\n return useCallback(\n (command: SceneCommand) => {\n if (!canWrite) return\n try {\n stack.execute(command)\n } catch (error) {\n setError(error instanceof Error ? error.message : String(error))\n return\n }\n const ops = command.operations()\n void onApplyOperations(ops)\n .then((result) => {\n if (result.document) {\n // Server re-minted ids or normalised the document: rebase without\n // clearing history. History holds transforms, not snapshots, so\n // rebasing cannot stale it; a later undo re-applies the inverse\n // transform to the current (rebased) document.\n stack.reset(result.document)\n }\n })\n .catch((error: unknown) => {\n // Roll back the specific command that failed. stack.rollback() splices\n // this command out of history and applies its inverse to the current\n // state — commands the user executed while this save was in-flight are\n // not disturbed (their undo entries are preserved). If the command is\n // no longer in the stack (double-fire or already reset), rollback is a\n // safe no-op.\n stack.rollback(command)\n setError(error instanceof Error ? error.message : String(error))\n })\n },\n [stack, onApplyOperations, canWrite, setError],\n )\n}\n\nexport function DesignCanvas({\n document: initialDocument,\n rev: initialRev,\n canWrite,\n onApplyOperations,\n onSelectionChange,\n renderAgentPanel,\n renderSidePanel,\n onExport,\n exportDefaults,\n className,\n fitOnMount,\n onReady,\n renderWorkspace,\n renderThumbnail,\n}: DesignCanvasFullProps) {\n // The command stack is created once from the initial document. Subsequent\n // server refreshes come in via the prop and are applied via reset().\n const stack = useMemo(\n () => createSceneCommandStack(initialDocument, initialDocument.pages[0]?.id ?? 'page-1'),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [],\n )\n\n const editorState = useSyncExternalStore(stack.subscribe, stack.getState, stack.getState)\n\n // Track the applied document prop to detect server refreshes.\n const appliedDocumentRef = useRef(initialDocument)\n useEffect(() => {\n if (appliedDocumentRef.current === initialDocument) return\n appliedDocumentRef.current = initialDocument\n stack.reset(initialDocument)\n }, [initialDocument, stack])\n\n const [commitError, setCommitError] = useState<string | null>(null)\n\n const commit = useCommitCommand(stack, onApplyOperations, canWrite, setCommitError)\n\n // Notify host when selection changes.\n const selectionChangeRef = useRef(onSelectionChange)\n selectionChangeRef.current = onSelectionChange\n useEffect(() => {\n const page = editorState.document.pages.find((p) => p.id === editorState.activePageId)\n if (!page) return\n const selected = editorState.selectedElementIds\n .map((id) => page.elements.find((el) => el.id === id))\n .filter((el): el is SceneElement => el !== undefined)\n selectionChangeRef.current?.(selected)\n }, [editorState.selectedElementIds, editorState.activePageId, editorState.document])\n\n // Workspace fit callback ref — the workspace fills this; the shell calls it.\n const fitRef = useRef<(() => void) | null>(null)\n\n // Workspace export callback ref — the workspace (Konva owner) fills this; the\n // chrome's Export control calls it with the chosen format/scale.\n const exportRef = useRef<((opts: ExportTriggerOptions) => void) | null>(null)\n\n // ---------------------------------------------------------------------------\n // View-state helpers (no history)\n // ---------------------------------------------------------------------------\n\n const setZoom = useCallback((zoom: number) => stack.setView({ zoom }), [stack])\n const setPan = useCallback((panX: number, panY: number) => stack.setView({ panX, panY }), [stack])\n const setActivePage = useCallback((activePageId: string) => stack.setView({ activePageId, selectedElementIds: [] }), [stack])\n\n const setSelectedElements = useCallback(\n (ids: string[], additive: boolean) => {\n if (!additive) {\n stack.setView({ selectedElementIds: ids })\n return\n }\n const current = new Set(editorState.selectedElementIds)\n for (const id of ids) {\n if (current.has(id)) current.delete(id)\n else current.add(id)\n }\n stack.setView({ selectedElementIds: [...current] })\n },\n [stack, editorState.selectedElementIds],\n )\n\n // ---------------------------------------------------------------------------\n // Element commands\n // ---------------------------------------------------------------------------\n\n const handleSetAttrs = useCallback(\n (elementId: string, attrs: SceneAttrsPatch) => {\n const page = requirePage(editorState.document, editorState.activePageId)\n // findElement searches group children; page.elements.find misses nested elements.\n const found = findElement(page, elementId)\n if (!found) return\n if (found.element.locked) return\n const priorAttrs: SceneAttrsPatch = Object.fromEntries(\n Object.keys(attrs).map((k) => [k, (found.element as unknown as Record<string, unknown>)[k]]),\n ) as SceneAttrsPatch\n commit(\n setAttrsCommand({\n pageId: editorState.activePageId,\n elementId,\n attrs,\n priorAttrs,\n }),\n )\n },\n [commit, editorState.activePageId, editorState.document],\n )\n\n const handleMultiSetAttrs = useCallback(\n (patches: Array<{ elementId: string; attrs: SceneAttrsPatch }>) => {\n const page = requirePage(editorState.document, editorState.activePageId)\n const entries = patches.flatMap(({ elementId, attrs }) => {\n const found = findElement(page, elementId)\n // Skip elements that are missing (concurrent delete) or locked.\n if (!found || found.element.locked) return []\n const priorAttrs = Object.fromEntries(\n Object.keys(attrs).map((k) => [k, (found.element as unknown as Record<string, unknown>)[k]]),\n ) as SceneAttrsPatch\n return [{ pageId: editorState.activePageId, elementId, attrs, priorAttrs }]\n })\n if (entries.length === 0) return\n commit(multiSetAttrsCommand(entries))\n },\n [commit, editorState.activePageId, editorState.document],\n )\n\n const handleReorder = useCallback(\n (elementId: string, toIndex: number, ownerLength: number, direction: 'front' | 'back' | 'forward' | 'backward') => {\n const page = requirePage(editorState.document, editorState.activePageId)\n // findElement searches group children so nested elements are reorderable.\n const found = findElement(page, elementId)\n if (!found) return\n const currentIndex = found.index\n const target =\n direction === 'front'\n ? topIndex(ownerLength)\n : direction === 'back'\n ? 0\n : direction === 'forward'\n ? indexForward(currentIndex, ownerLength)\n : indexBackward(currentIndex)\n const clamped = clampIndex(target, ownerLength)\n if (clamped === currentIndex) return\n commit(reorderElementCommand({ pageId: editorState.activePageId, elementId, toIndex: clamped }))\n },\n [commit, editorState.activePageId, editorState.document],\n )\n\n const handleDelete = useCallback(\n (elementIds: string[]) => {\n for (const elementId of elementIds) {\n commit(\n deleteElementCommand({\n document: editorState.document,\n pageId: editorState.activePageId,\n elementId,\n }),\n )\n }\n },\n [commit, editorState.document, editorState.activePageId],\n )\n\n const handleGroup = useCallback(\n (elementIds: string[]) => {\n commit(\n groupElementsCommand({\n document: editorState.document,\n pageId: editorState.activePageId,\n elementIds,\n groupId: mintId(),\n }),\n )\n },\n [commit, editorState.document, editorState.activePageId],\n )\n\n const handleUngroup = useCallback(\n (groupId: string) => {\n commit(ungroupElementCommand({ document: editorState.document, pageId: editorState.activePageId, groupId }))\n },\n [commit, editorState.document, editorState.activePageId],\n )\n\n const handleBindSlot = useCallback(\n (elementId: string, slot: string | null) => {\n commit(bindSlotCommand({ document: editorState.document, pageId: editorState.activePageId, elementId, slot }))\n },\n [commit, editorState.document, editorState.activePageId],\n )\n\n // ---------------------------------------------------------------------------\n // Page commands\n // ---------------------------------------------------------------------------\n\n const handleSetPageProps = useCallback(\n (props: { name?: string; width?: number; height?: number; background?: string; bleed?: PageBleed | null }) => {\n commit(setPagePropsCommand({ document: editorState.document, pageId: editorState.activePageId, props }))\n },\n [commit, editorState.document, editorState.activePageId],\n )\n\n const handleSetPageGuides = useCallback(\n (guides: { vertical: number[]; horizontal: number[] }) => {\n commit(setPageGuidesCommand({ document: editorState.document, pageId: editorState.activePageId, guides }))\n },\n [commit, editorState.document, editorState.activePageId],\n )\n\n const handleAddPage = useCallback(() => {\n const pageId = mintId()\n commit(addPageCommand({ pageId }))\n setActivePage(pageId)\n }, [commit, setActivePage])\n\n const handleDuplicatePage = useCallback(\n (sourcePageId: string) => {\n const pageId = mintId()\n commit(duplicatePageCommand({ document: editorState.document, sourcePageId, pageId }))\n setActivePage(pageId)\n },\n [commit, editorState.document, setActivePage],\n )\n\n const handleDeletePage = useCallback(\n (pageId: string) => {\n commit(deletePageCommand({ document: editorState.document, pageId }))\n },\n [commit, editorState.document],\n )\n\n const handleReorderPage = useCallback(\n (pageId: string, toIndex: number) => {\n commit(reorderPageCommand({ pageId, toIndex }))\n },\n [commit],\n )\n\n // ---------------------------------------------------------------------------\n // Undo / redo\n // ---------------------------------------------------------------------------\n\n const handleUndo = useCallback(() => {\n if (!canWrite || !stack.canUndo()) return\n let command\n try {\n command = stack.undo()\n } catch (error) {\n setCommitError(`Undo failed: ${error instanceof Error ? error.message : String(error)}`)\n return\n }\n // Persist the inverse so the server tracks the undo; on rejection re-execute\n // to re-apply the original forward state.\n void onApplyOperations(command.inverseOperations())\n .then((result) => {\n if (result.document) stack.reset(result.document)\n })\n .catch((error: unknown) => {\n if (stack.canRedo()) {\n try { stack.redo() } catch { /* concurrent edit; next reset reconciles */ }\n }\n setCommitError(error instanceof Error ? error.message : String(error))\n })\n }, [stack, canWrite, onApplyOperations])\n\n const handleRedo = useCallback(() => {\n if (!canWrite || !stack.canRedo()) return\n let command\n try {\n command = stack.redo()\n } catch (error) {\n setCommitError(`Redo failed: ${error instanceof Error ? error.message : String(error)}`)\n return\n }\n void onApplyOperations(command.operations())\n .then((result) => {\n if (result.document) stack.reset(result.document)\n })\n .catch((error: unknown) => {\n if (stack.canUndo()) {\n try { stack.undo() } catch { /* concurrent edit; next reset reconciles */ }\n }\n setCommitError(error instanceof Error ? error.message : String(error))\n })\n }, [stack, canWrite, onApplyOperations])\n\n // ---------------------------------------------------------------------------\n // Keyboard shortcuts\n // ---------------------------------------------------------------------------\n\n useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n const mod = event.metaKey || event.ctrlKey\n if (mod && !isTypingTarget(event.target)) {\n if (event.key.toLowerCase() === 'z') {\n event.preventDefault()\n if (event.shiftKey) handleRedo()\n else handleUndo()\n return\n }\n if (event.key.toLowerCase() === 'y') {\n event.preventDefault()\n handleRedo()\n return\n }\n }\n if ((event.key === 'Delete' || event.key === 'Backspace') && !isTypingTarget(event.target)) {\n if (!canWrite || editorState.selectedElementIds.length === 0) return\n event.preventDefault()\n handleDelete(editorState.selectedElementIds)\n return\n }\n if (event.key.toLowerCase() === 'f' && !isTypingTarget(event.target)) {\n event.preventDefault()\n fitRef.current?.()\n }\n }\n window.addEventListener('keydown', onKeyDown)\n return () => window.removeEventListener('keydown', onKeyDown)\n })\n\n // ---------------------------------------------------------------------------\n // Derived state for render\n // ---------------------------------------------------------------------------\n\n const activePage = useMemo(\n () => editorState.document.pages.find((p) => p.id === editorState.activePageId),\n [editorState.document, editorState.activePageId],\n )\n\n const selectedElements = useMemo(() => {\n if (!activePage) return []\n return editorState.selectedElementIds\n .map((id) => activePage.elements.find((el) => el.id === id))\n .filter((el): el is SceneElement => el !== undefined)\n }, [activePage, editorState.selectedElementIds])\n\n if (!activePage) {\n return (\n <div className={`flex h-full items-center justify-center bg-[var(--bg-input)] text-[var(--text-muted)] ${className ?? ''}`}>\n No pages in document\n </div>\n )\n }\n\n // Bleed extents in screen px for the overlay\n const bleedScreen = editorState.showBleed && activePage.bleed\n ? {\n top: activePage.bleed.top * editorState.zoom,\n right: activePage.bleed.right * editorState.zoom,\n bottom: activePage.bleed.bottom * editorState.zoom,\n left: activePage.bleed.left * editorState.zoom,\n }\n : null\n\n return (\n <div className={`flex h-full min-h-0 bg-[var(--bg-input)] text-[var(--text-primary)] ${className ?? ''}`}>\n {/* Optional left side panel (asset/template browser, etc.) */}\n {renderSidePanel ? (\n <aside className=\"flex w-64 shrink-0 flex-col overflow-hidden border-r border-[var(--border-default)]\">\n {renderSidePanel()}\n </aside>\n ) : null}\n\n {/* Main column */}\n <div className=\"flex min-w-0 flex-1 flex-col\">\n {/* Toolbar + chrome-right controls (Export). The Toolbar grows to fill;\n the Export control is pinned to the top-right of the chrome. */}\n <div className=\"flex shrink-0 items-stretch\">\n <div className=\"min-w-0 flex-1\">\n <Toolbar\n page={activePage}\n selectedElements={selectedElements}\n canWrite={canWrite}\n canUndo={stack.canUndo()}\n canRedo={stack.canRedo()}\n gridEnabled={editorState.gridEnabled}\n snapEnabled={editorState.snapEnabled}\n showRulers={editorState.showRulers}\n showBleed={editorState.showBleed}\n onUndo={handleUndo}\n onRedo={handleRedo}\n onToggleGrid={() => stack.setView({ gridEnabled: !editorState.gridEnabled })}\n onToggleSnap={() => stack.setView({ snapEnabled: !editorState.snapEnabled })}\n onToggleRulers={() => stack.setView({ showRulers: !editorState.showRulers })}\n onToggleBleed={() => stack.setView({ showBleed: !editorState.showBleed })}\n onSetAttrs={handleSetAttrs}\n onSetPageProps={handleSetPageProps}\n onSetPageGuides={handleSetPageGuides}\n onReorder={handleReorder}\n onGroup={handleGroup}\n onUngroup={handleUngroup}\n onDelete={handleDelete}\n onBindSlot={handleBindSlot}\n />\n </div>\n {onExport ? (\n <div className=\"flex shrink-0 items-center border-b border-l border-[var(--border-default)] bg-[var(--bg-input)] px-2\">\n <ExportControl\n defaults={exportDefaults}\n onExport={(opts) => exportRef.current?.(opts)}\n />\n </div>\n ) : null}\n </div>\n\n {/* Error bar */}\n {commitError ? (\n <div\n className=\"flex shrink-0 items-center justify-between gap-3 border-b border-rose-500/30 bg-rose-500/10 px-3 py-1.5 text-xs text-rose-300\"\n role=\"alert\"\n >\n <span className=\"min-w-0 truncate\">{commitError}</span>\n <button\n type=\"button\"\n onClick={() => setCommitError(null)}\n className=\"shrink-0 underline-offset-2 hover:underline\"\n >\n Dismiss\n </button>\n </div>\n ) : null}\n\n {/* Rulers + Workspace area */}\n <div className=\"relative min-h-0 flex-1\">\n {/* Rulers overlay inside the workspace container */}\n <Rulers\n pageWidth={activePage.width}\n pageHeight={activePage.height}\n zoom={editorState.zoom}\n scrollLeft={-editorState.panX / editorState.zoom}\n scrollTop={-editorState.panY / editorState.zoom}\n showRulers={editorState.showRulers}\n guides={activePage.guides}\n onGuidesChange={handleSetPageGuides}\n />\n\n {/* Bleed overlay — absolutely positioned over the workspace */}\n {bleedScreen && activePage.bleed ? (\n <div\n className=\"pointer-events-none absolute inset-0 z-10 overflow-hidden\"\n aria-hidden\n >\n <div\n style={{\n position: 'absolute',\n left: editorState.panX,\n top: editorState.panY,\n }}\n >\n <BleedTrimOverlay\n pageWidthPx={activePage.width * editorState.zoom}\n pageHeightPx={activePage.height * editorState.zoom}\n bleed={bleedScreen}\n />\n </div>\n </div>\n ) : null}\n\n {/* Workspace slot (Konva; injected by integrator) */}\n {renderWorkspace({\n document: editorState.document,\n activePageId: editorState.activePageId,\n selectedElementIds: editorState.selectedElementIds,\n zoom: editorState.zoom,\n panX: editorState.panX,\n panY: editorState.panY,\n gridEnabled: editorState.gridEnabled,\n gridSize: editorState.gridSize,\n snapEnabled: editorState.snapEnabled,\n showBleed: editorState.showBleed,\n canWrite,\n stack,\n activePage,\n onFitRef: fitRef,\n onExportRef: exportRef,\n fitOnMount,\n onReady,\n onZoomChange: setZoom,\n onPanChange: setPan,\n onSelectElements: setSelectedElements,\n })}\n </div>\n\n {/* Bottom row: PagesStrip + ZoomControls */}\n <div className=\"flex shrink-0 items-stretch border-t border-[var(--border-default)]\">\n <div className=\"min-w-0 flex-1 overflow-hidden\">\n <PagesStrip\n pages={editorState.document.pages}\n activePageId={editorState.activePageId}\n canWrite={canWrite}\n renderThumbnail={renderThumbnail}\n onSelectPage={setActivePage}\n onAddPage={handleAddPage}\n onDuplicatePage={handleDuplicatePage}\n onDeletePage={handleDeletePage}\n onReorderPage={handleReorderPage}\n />\n </div>\n <div className=\"flex shrink-0 items-center border-l border-[var(--border-default)]\">\n <ZoomControls\n zoom={editorState.zoom}\n onZoom={setZoom}\n onFit={() => fitRef.current?.()}\n />\n </div>\n </div>\n </div>\n\n {/* Optional right agent panel */}\n {renderAgentPanel ? (\n <aside className=\"flex w-80 shrink-0 flex-col overflow-hidden border-l border-[var(--border-default)]\">\n {renderAgentPanel({ selectedElements, activePageId: editorState.activePageId })}\n </aside>\n ) : null}\n\n {/* Layers panel lives in the left side panel slot by convention; products\n that want it standalone can render LayersPanel directly. */}\n </div>\n )\n}\n\nexport default DesignCanvas\n","/**\n * Undo/redo command stack over immutable `EditorSceneState`.\n *\n * History entries hold COMMANDS (state transforms + durable operations\n * captured at construction), never snapshots. Rebasing the document via\n * `reset()` therefore cannot stale the history: a later undo re-applies the\n * inverse transform to whatever document is current. If the rebase removed an\n * element a historical command targets, that transform throws (fail loud)\n * rather than silently editing the wrong element.\n *\n * `setView` updates volatile view state (zoom/pan/selection/toggles) without\n * touching history — view changes are never undo steps.\n */\n\nimport type { SceneDocument } from '../../design-canvas/model'\nimport type { EditorSceneState, SceneCommand, SceneCommandStack } from '../contracts'\n\n/** Oldest entries are dropped past this bound; redo stack is cleared on execute. */\nexport const SCENE_COMMAND_HISTORY_LIMIT = 200\n\nexport function createSceneCommandStack(document: SceneDocument, activePageId: string): SceneCommandStack {\n let state: EditorSceneState = {\n document,\n activePageId,\n selectedElementIds: [],\n zoom: 1,\n panX: 0,\n panY: 0,\n gridEnabled: false,\n gridSize: 10,\n snapEnabled: true,\n showRulers: true,\n showBleed: false,\n }\n\n const undoStack: SceneCommand[] = []\n const redoStack: SceneCommand[] = []\n const listeners = new Set<() => void>()\n\n const notify = (): void => {\n for (const listener of [...listeners]) listener()\n }\n\n return {\n execute(command: SceneCommand): void {\n state = command.execute(state)\n undoStack.push(command)\n if (undoStack.length > SCENE_COMMAND_HISTORY_LIMIT) {\n undoStack.splice(0, undoStack.length - SCENE_COMMAND_HISTORY_LIMIT)\n }\n redoStack.length = 0\n notify()\n },\n\n // Both transforms run BEFORE the stacks move: a throwing transform (e.g.\n // missing element after reset()) leaves history and state exactly as they\n // were. The entry is never silently destroyed — the caller can retry after\n // the next server refresh restores the target.\n undo(): SceneCommand {\n const command = undoStack[undoStack.length - 1]\n if (!command) throw new Error('nothing to undo — guard with canUndo() before calling undo()')\n state = command.undo(state)\n undoStack.pop()\n redoStack.push(command)\n notify()\n return command\n },\n\n redo(): SceneCommand {\n const command = redoStack[redoStack.length - 1]\n if (!command) throw new Error('nothing to redo — guard with canRedo() before calling redo()')\n state = command.execute(state)\n redoStack.pop()\n undoStack.push(command)\n notify()\n return command\n },\n\n canUndo(): boolean {\n return undoStack.length > 0\n },\n\n canRedo(): boolean {\n return redoStack.length > 0\n },\n\n subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n\n getState(): EditorSceneState {\n return state\n },\n\n setView(patch: Partial<Omit<EditorSceneState, 'document'>>): void {\n state = { ...state, ...patch }\n notify()\n },\n\n rollback(command: SceneCommand): void {\n const idx = undoStack.lastIndexOf(command)\n // Command not in history — stale or double-fire rejection handler; no-op.\n if (idx === -1) return\n\n // Apply the command's inverse against the current state. For non-overlapping\n // edits (different elements or different attributes) this is exact: the\n // inverse commutes freely past all subsequent commands. For overlapping edits\n // on the same attribute the result is defined but not semantically perfect;\n // the persistence layer should trigger an onResyncRequired refetch in that\n // case so the server document reconciles.\n state = command.undo(state)\n\n // Splice the target command out of the undo stack.\n undoStack.splice(idx, 1)\n\n // Clear the redo stack: its entries were computed relative to a history that\n // included this command, so they are now stale.\n redoStack.length = 0\n\n notify()\n },\n\n /** Rebase onto a server-refreshed document. History survives; selection\n * drops ids the refresh removed so view state never dangles. */\n reset(newDocument: SceneDocument): void {\n // Collect all live element ids across all pages for selection cleanup\n const liveElementIds = new Set<string>()\n for (const page of newDocument.pages) {\n collectElementIds(page.elements, liveElementIds)\n }\n // If the active page was removed, fall back to the first page\n const activePageExists = newDocument.pages.some((p) => p.id === state.activePageId)\n const activePageId = activePageExists ? state.activePageId : (newDocument.pages[0]?.id ?? state.activePageId)\n state = {\n ...state,\n document: newDocument,\n activePageId,\n selectedElementIds: state.selectedElementIds.filter((id) => liveElementIds.has(id)),\n }\n notify()\n },\n }\n}\n\nfunction collectElementIds(elements: ReturnType<typeof Array.prototype.slice>, ids: Set<string>): void {\n for (const el of elements as Array<{ id: string; kind: string; children?: unknown[] }>) {\n ids.add(el.id)\n if (el.kind === 'group' && Array.isArray(el.children)) {\n collectElementIds(el.children as Array<{ id: string; kind: string; children?: unknown[] }>, ids)\n }\n }\n}\n","/**\n * Concrete `SceneCommand` factories for the design-canvas editor. Every factory\n * captures the inverse from PRE-state at construction — undo is a value\n * computed once, never re-derived from current state later. Local execute/undo\n * update `EditorSceneState` immutably by routing through `applySceneOperation`\n * so optimistic state matches what the server-side dispatcher will persist.\n *\n * Drag gestures coalesce: pointer moves update volatile state, ONE command\n * executes on pointer release with (finalAttrs, priorAttrs). `setAttrsCommand`\n * is that gesture command — one undo step per drag/transform/toolbar change.\n * `multiSetAttrsCommand` collects N set_attrs ops into one undo step for\n * multi-select transforms.\n *\n * Group/ungroup route through `applySceneOperation` so the group-origin\n * rebasing in `apply.ts` is the single source of truth for both optimistic and\n * server state.\n */\n\nimport type { SceneDocument, SceneElement, ScenePage } from '../../design-canvas/model'\nimport { requireElement, requirePage } from '../../design-canvas/model'\nimport { applySceneOperation, applySceneOperations } from '../../design-canvas/apply'\nimport type {\n AddElementOperation,\n DeleteElementOperation,\n SceneAttrsPatch,\n SceneOperation,\n} from '../../design-canvas/operations'\nimport type { EditorSceneState, SceneCommand } from '../contracts'\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nfunction applyOps(state: EditorSceneState, ops: SceneOperation[]): EditorSceneState {\n return { ...state, document: applySceneOperations(state.document, ops) }\n}\n\nfunction applyOp(state: EditorSceneState, op: SceneOperation): EditorSceneState {\n return { ...state, document: applySceneOperation(state.document, op) }\n}\n\n// ---------------------------------------------------------------------------\n// add_element / inverse = delete_element\n// ---------------------------------------------------------------------------\n\nexport interface AddElementInput {\n pageId: string\n element: SceneElement\n /** Insertion z-index within owner; omitted → top. */\n index?: number\n /** Parent group id; omitted → page root. */\n parentGroupId?: string\n}\n\nexport function addElementCommand(input: AddElementInput): SceneCommand {\n const addOp: SceneOperation = {\n type: 'add_element',\n pageId: input.pageId,\n element: structuredClone(input.element),\n ...(input.index !== undefined ? { index: input.index } : {}),\n ...(input.parentGroupId !== undefined ? { parentGroupId: input.parentGroupId } : {}),\n }\n const deleteOp: SceneOperation = {\n type: 'delete_element',\n pageId: input.pageId,\n elementId: input.element.id,\n }\n\n return {\n label: `Add ${input.element.kind}`,\n execute: (state) => applyOp(state, addOp),\n undo: (state) => applyOp(state, deleteOp),\n operations: () => [structuredClone(addOp)],\n inverseOperations: () => [structuredClone(deleteOp)],\n }\n}\n\n// ---------------------------------------------------------------------------\n// set_attrs — THE gesture command (one undo step per drag/transform)\n// ---------------------------------------------------------------------------\n\nexport interface SetAttrsInput {\n pageId: string\n elementId: string\n /** Final attribute values after the gesture. */\n attrs: SceneAttrsPatch\n /** Attribute values BEFORE the gesture began — inverse is built from these. */\n priorAttrs: SceneAttrsPatch\n}\n\nexport function setAttrsCommand(input: SetAttrsInput): SceneCommand {\n const forwardOp: SceneOperation = {\n type: 'set_attrs',\n pageId: input.pageId,\n elementId: input.elementId,\n attrs: structuredClone(input.attrs),\n }\n const inverseOp: SceneOperation = {\n type: 'set_attrs',\n pageId: input.pageId,\n elementId: input.elementId,\n attrs: structuredClone(input.priorAttrs),\n }\n\n return {\n label: 'Edit element',\n execute: (state) => applyOp(state, forwardOp),\n undo: (state) => applyOp(state, inverseOp),\n operations: () => [structuredClone(forwardOp)],\n inverseOperations: () => [structuredClone(inverseOp)],\n }\n}\n\n// ---------------------------------------------------------------------------\n// multi-select set_attrs — N set_attrs ops, one undo step\n// ---------------------------------------------------------------------------\n\nexport interface MultiSetAttrsEntry {\n pageId: string\n elementId: string\n attrs: SceneAttrsPatch\n priorAttrs: SceneAttrsPatch\n}\n\nexport function multiSetAttrsCommand(entries: MultiSetAttrsEntry[]): SceneCommand {\n if (entries.length === 0) throw new Error('multiSetAttrsCommand: entries must not be empty')\n\n const forwardOps: SceneOperation[] = entries.map((e) => ({\n type: 'set_attrs' as const,\n pageId: e.pageId,\n elementId: e.elementId,\n attrs: structuredClone(e.attrs),\n }))\n const inverseOps: SceneOperation[] = entries.map((e) => ({\n type: 'set_attrs' as const,\n pageId: e.pageId,\n elementId: e.elementId,\n attrs: structuredClone(e.priorAttrs),\n }))\n\n return {\n label: `Edit ${entries.length} elements`,\n execute: (state) => applyOps(state, forwardOps),\n undo: (state) => applyOps(state, inverseOps),\n operations: () => structuredClone(forwardOps),\n inverseOperations: () => structuredClone(inverseOps),\n }\n}\n\n// ---------------------------------------------------------------------------\n// reorder_element\n// ---------------------------------------------------------------------------\n\nexport interface ReorderElementInput {\n pageId: string\n elementId: string\n toIndex: number\n}\n\nexport function reorderElementCommand(input: ReorderElementInput): SceneCommand {\n // Capture the element's current index at construction for the inverse\n let capturedFromIndex: number | null = null\n\n const forwardOp: SceneOperation = {\n type: 'reorder_element',\n pageId: input.pageId,\n elementId: input.elementId,\n toIndex: input.toIndex,\n }\n\n return {\n label: 'Reorder element',\n execute: (state) => {\n // Guard: on redo the element is already at toIndex, so we must not\n // overwrite the captured origin with the wrong position.\n if (capturedFromIndex === null) {\n const page = requirePage(state.document, input.pageId)\n const { index } = requireElement(page, input.elementId)\n capturedFromIndex = index\n }\n return applyOp(state, forwardOp)\n },\n undo: (state) => {\n if (capturedFromIndex === null) {\n throw new Error('reorderElementCommand: undo called before execute')\n }\n return applyOp(state, {\n type: 'reorder_element',\n pageId: input.pageId,\n elementId: input.elementId,\n toIndex: capturedFromIndex,\n })\n },\n operations: () => [structuredClone(forwardOp)],\n inverseOperations: () => {\n if (capturedFromIndex === null) {\n throw new Error('reorderElementCommand: inverseOperations called before execute')\n }\n return [{\n type: 'reorder_element' as const,\n pageId: input.pageId,\n elementId: input.elementId,\n toIndex: capturedFromIndex,\n }]\n },\n }\n}\n\n// ---------------------------------------------------------------------------\n// delete_element / inverse = add_element (full snapshot + index + parent)\n// ---------------------------------------------------------------------------\n\nexport interface DeleteElementInput {\n document: SceneDocument\n pageId: string\n elementId: string\n}\n\nexport function deleteElementCommand(input: DeleteElementInput): SceneCommand {\n const page = requirePage(input.document, input.pageId)\n const { element, owner, index } = requireElement(page, input.elementId)\n const snapshot = structuredClone(element)\n\n // Determine parentGroupId by finding which group owns this element\n const parentGroupId = findParentGroupId(page, owner)\n\n const deleteOp: DeleteElementOperation = {\n type: 'delete_element',\n pageId: input.pageId,\n elementId: input.elementId,\n }\n const addOp: AddElementOperation = {\n type: 'add_element',\n pageId: input.pageId,\n element: snapshot,\n index,\n ...(parentGroupId !== undefined ? { parentGroupId } : {}),\n }\n\n return {\n label: `Delete ${element.kind}`,\n execute: (state) => {\n const next = applyOp(state, deleteOp)\n return {\n ...next,\n selectedElementIds: next.selectedElementIds.filter((id) => id !== input.elementId),\n }\n },\n undo: (state) => applyOp(state, addOp),\n operations: () => [structuredClone(deleteOp)],\n inverseOperations: () => [structuredClone(addOp)],\n }\n}\n\nfunction findParentGroupId(page: ScenePage, owner: SceneElement[]): string | undefined {\n if (owner === page.elements) return undefined\n // Walk the element tree looking for a group whose children === owner\n return findGroupWithChildren(page.elements, owner)\n}\n\nfunction findGroupWithChildren(elements: SceneElement[], target: SceneElement[]): string | undefined {\n for (const el of elements) {\n if (el.kind === 'group') {\n if (el.children === target) return el.id\n const found = findGroupWithChildren(el.children, target)\n if (found !== undefined) return found\n }\n }\n return undefined\n}\n\n// ---------------------------------------------------------------------------\n// group_elements / inverse = ungroup_element\n// ---------------------------------------------------------------------------\n\nexport interface GroupElementsInput {\n document: SceneDocument\n pageId: string\n elementIds: string[]\n groupId: string\n name?: string\n}\n\nexport function groupElementsCommand(input: GroupElementsInput): SceneCommand {\n if (input.elementIds.length < 2) {\n throw new Error('groupElementsCommand: requires ≥ 2 elementIds')\n }\n\n const groupOp: SceneOperation = {\n type: 'group_elements',\n pageId: input.pageId,\n elementIds: input.elementIds.slice(),\n groupId: input.groupId,\n ...(input.name !== undefined ? { name: input.name } : {}),\n }\n const ungroupOp: SceneOperation = {\n type: 'ungroup_element',\n pageId: input.pageId,\n groupId: input.groupId,\n }\n\n return {\n label: `Group ${input.elementIds.length} elements`,\n execute: (state) => {\n const next = applyOp(state, groupOp)\n return {\n ...next,\n selectedElementIds: [input.groupId],\n }\n },\n undo: (state) => {\n const next = applyOp(state, ungroupOp)\n return { ...next, selectedElementIds: input.elementIds.slice() }\n },\n operations: () => [structuredClone(groupOp)],\n inverseOperations: () => [structuredClone(ungroupOp)],\n }\n}\n\n// ---------------------------------------------------------------------------\n// ungroup_element / inverse = group_elements (re-using original ids)\n// ---------------------------------------------------------------------------\n\nexport interface UngroupElementInput {\n document: SceneDocument\n pageId: string\n groupId: string\n}\n\nexport function ungroupElementCommand(input: UngroupElementInput): SceneCommand {\n const page = requirePage(input.document, input.pageId)\n const { element } = requireElement(page, input.groupId)\n if (element.kind !== 'group') {\n throw new Error(`ungroupElementCommand: element ${input.groupId} is kind ${element.kind}, not group`)\n }\n const childIds = element.children.map((c) => c.id)\n\n const ungroupOp: SceneOperation = {\n type: 'ungroup_element',\n pageId: input.pageId,\n groupId: input.groupId,\n }\n const regroupOp: SceneOperation = {\n type: 'group_elements',\n pageId: input.pageId,\n elementIds: childIds,\n groupId: input.groupId,\n name: element.name,\n }\n\n return {\n label: `Ungroup`,\n execute: (state) => {\n const next = applyOp(state, ungroupOp)\n return { ...next, selectedElementIds: childIds.slice() }\n },\n undo: (state) => {\n const next = applyOp(state, regroupOp)\n return { ...next, selectedElementIds: [input.groupId] }\n },\n operations: () => [structuredClone(ungroupOp)],\n inverseOperations: () => [structuredClone(regroupOp)],\n }\n}\n\n// ---------------------------------------------------------------------------\n// Page commands\n// ---------------------------------------------------------------------------\n\nexport interface AddPageInput {\n pageId: string\n options?: import('../../design-canvas/model').NewPageOptions\n index?: number\n}\n\nexport function addPageCommand(input: AddPageInput): SceneCommand {\n const addOp: SceneOperation = {\n type: 'add_page',\n pageId: input.pageId,\n ...(input.options !== undefined ? { options: input.options } : {}),\n ...(input.index !== undefined ? { index: input.index } : {}),\n }\n const deleteOp: SceneOperation = { type: 'delete_page', pageId: input.pageId }\n\n return {\n label: 'Add page',\n execute: (state) => {\n const next = applyOp(state, addOp)\n return { ...next, activePageId: input.pageId }\n },\n undo: (state) => {\n const next = applyOp(state, deleteOp)\n // Switch active page to first surviving page if we deleted the active one\n const activeExists = next.document.pages.some((p) => p.id === next.activePageId)\n return activeExists ? next : { ...next, activePageId: next.document.pages[0]!.id }\n },\n operations: () => [structuredClone(addOp)],\n inverseOperations: () => [structuredClone(deleteOp)],\n }\n}\n\nexport interface DuplicatePageInput {\n document: SceneDocument\n sourcePageId: string\n /** Caller-minted id for the copy. */\n pageId: string\n}\n\nexport function duplicatePageCommand(input: DuplicatePageInput): SceneCommand {\n requirePage(input.document, input.sourcePageId)\n\n const dupOp: SceneOperation = {\n type: 'duplicate_page',\n sourcePageId: input.sourcePageId,\n pageId: input.pageId,\n }\n const deleteOp: SceneOperation = { type: 'delete_page', pageId: input.pageId }\n\n return {\n label: 'Duplicate page',\n execute: (state) => {\n const next = applyOp(state, dupOp)\n return { ...next, activePageId: input.pageId }\n },\n undo: (state) => {\n const next = applyOp(state, deleteOp)\n const activeExists = next.document.pages.some((p) => p.id === next.activePageId)\n return activeExists ? next : { ...next, activePageId: input.sourcePageId }\n },\n operations: () => [structuredClone(dupOp)],\n inverseOperations: () => [structuredClone(deleteOp)],\n }\n}\n\nexport interface DeletePageInput {\n document: SceneDocument\n pageId: string\n}\n\nexport function deletePageCommand(input: DeletePageInput): SceneCommand {\n if (input.document.pages.length <= 1) {\n throw new Error('deletePageCommand: cannot delete the last page')\n }\n const page = requirePage(input.document, input.pageId)\n const currentIndex = input.document.pages.findIndex((p) => p.id === input.pageId)\n const snapshot = structuredClone(page)\n\n const deleteOp: SceneOperation = { type: 'delete_page', pageId: input.pageId }\n\n // Undo uses add_page + per-element add_element to restore the full snapshot.\n // The page shell is added first, then elements are inserted in z-order so\n // subsequent undo/redo round-trips see the correct stack. This also makes\n // inverseOperations() safe to emit server-side: the server will see the same\n // full restore instead of a bare shell.\n function buildRestoreOps(): SceneOperation[] {\n const ops: SceneOperation[] = [\n {\n type: 'add_page',\n pageId: snapshot.id,\n options: {\n name: snapshot.name,\n width: snapshot.width,\n height: snapshot.height,\n background: snapshot.background,\n },\n index: currentIndex,\n },\n ]\n if (snapshot.bleed) {\n ops.push({ type: 'set_page_props', pageId: snapshot.id, bleed: snapshot.bleed })\n }\n if (snapshot.guides.vertical.length > 0 || snapshot.guides.horizontal.length > 0) {\n ops.push({ type: 'set_page_guides', pageId: snapshot.id, guides: snapshot.guides })\n }\n for (let i = 0; i < snapshot.elements.length; i++) {\n ops.push({\n type: 'add_element',\n pageId: snapshot.id,\n element: structuredClone(snapshot.elements[i]!),\n index: i,\n })\n }\n return ops\n }\n\n return {\n label: 'Delete page',\n execute: (state) => {\n const next = applyOp(state, deleteOp)\n const activeExists = next.document.pages.some((p) => p.id === next.activePageId)\n if (activeExists) return next\n const fallbackIndex = Math.min(currentIndex, next.document.pages.length - 1)\n return { ...next, activePageId: next.document.pages[fallbackIndex]!.id }\n },\n undo: (state) => {\n const next = applyOps(state, buildRestoreOps())\n return { ...next, activePageId: input.pageId }\n },\n operations: () => [structuredClone(deleteOp)],\n inverseOperations: () => buildRestoreOps(),\n }\n}\n\nexport interface ReorderPageInput {\n pageId: string\n toIndex: number\n}\n\nexport function reorderPageCommand(input: ReorderPageInput): SceneCommand {\n let capturedFromIndex: number | null = null\n\n const forwardOp: SceneOperation = {\n type: 'reorder_page',\n pageId: input.pageId,\n toIndex: input.toIndex,\n }\n\n return {\n label: 'Reorder page',\n execute: (state) => {\n // Guard: on redo the page is already at toIndex; capture only on first execute.\n if (capturedFromIndex === null) {\n capturedFromIndex = state.document.pages.findIndex((p) => p.id === input.pageId)\n if (capturedFromIndex === -1) throw new Error(`reorderPageCommand: page ${input.pageId} not found`)\n }\n return applyOp(state, forwardOp)\n },\n undo: (state) => {\n if (capturedFromIndex === null) throw new Error('reorderPageCommand: undo called before execute')\n return applyOp(state, {\n type: 'reorder_page',\n pageId: input.pageId,\n toIndex: capturedFromIndex,\n })\n },\n operations: () => [structuredClone(forwardOp)],\n inverseOperations: () => {\n if (capturedFromIndex === null) throw new Error('reorderPageCommand: inverseOperations called before execute')\n return [{ type: 'reorder_page' as const, pageId: input.pageId, toIndex: capturedFromIndex }]\n },\n }\n}\n\nexport interface SetPagePropsInput {\n document: SceneDocument\n pageId: string\n props: {\n name?: string\n width?: number\n height?: number\n background?: string\n bleed?: import('../../design-canvas/model').PageBleed | null\n }\n}\n\nexport function setPagePropsCommand(input: SetPagePropsInput): SceneCommand {\n const page = requirePage(input.document, input.pageId)\n const prior: NonNullable<import('../../design-canvas/operations').SetPagePropsOperation> = {\n type: 'set_page_props',\n pageId: input.pageId,\n ...(input.props.name !== undefined ? { name: page.name } : {}),\n ...(input.props.width !== undefined ? { width: page.width } : {}),\n ...(input.props.height !== undefined ? { height: page.height } : {}),\n ...(input.props.background !== undefined ? { background: page.background } : {}),\n ...(input.props.bleed !== undefined ? { bleed: page.bleed } : {}),\n }\n\n const forwardOp: SceneOperation = {\n type: 'set_page_props',\n pageId: input.pageId,\n ...input.props,\n }\n\n return {\n label: 'Edit page',\n execute: (state) => applyOp(state, forwardOp),\n undo: (state) => applyOp(state, prior),\n operations: () => [structuredClone(forwardOp)],\n inverseOperations: () => [structuredClone(prior) as SceneOperation],\n }\n}\n\nexport interface SetPageGuidesInput {\n document: SceneDocument\n pageId: string\n guides: import('../../design-canvas/model').PageGuides\n}\n\nexport function setPageGuidesCommand(input: SetPageGuidesInput): SceneCommand {\n const page = requirePage(input.document, input.pageId)\n const priorGuides = structuredClone(page.guides)\n\n const forwardOp: SceneOperation = {\n type: 'set_page_guides',\n pageId: input.pageId,\n guides: structuredClone(input.guides),\n }\n const inverseOp: SceneOperation = {\n type: 'set_page_guides',\n pageId: input.pageId,\n guides: priorGuides,\n }\n\n return {\n label: 'Edit guides',\n execute: (state) => applyOp(state, forwardOp),\n undo: (state) => applyOp(state, inverseOp),\n operations: () => [structuredClone(forwardOp)],\n inverseOperations: () => [structuredClone(inverseOp)],\n }\n}\n\n// ---------------------------------------------------------------------------\n// bind_slot\n// ---------------------------------------------------------------------------\n\nexport interface BindSlotInput {\n document: SceneDocument\n pageId: string\n elementId: string\n slot: string | null\n}\n\nexport function bindSlotCommand(input: BindSlotInput): SceneCommand {\n const page = requirePage(input.document, input.pageId)\n const { element } = requireElement(page, input.elementId)\n const priorSlot = element.slot ?? null\n\n const forwardOp: SceneOperation = {\n type: 'bind_slot',\n pageId: input.pageId,\n elementId: input.elementId,\n slot: input.slot,\n }\n const inverseOp: SceneOperation = {\n type: 'bind_slot',\n pageId: input.pageId,\n elementId: input.elementId,\n slot: priorSlot,\n }\n\n return {\n label: input.slot === null ? 'Unbind slot' : `Bind slot \"${input.slot}\"`,\n execute: (state) => applyOp(state, forwardOp),\n undo: (state) => applyOp(state, inverseOp),\n operations: () => [structuredClone(forwardOp)],\n inverseOperations: () => [structuredClone(inverseOp)],\n }\n}\n\n// ---------------------------------------------------------------------------\n// set_document_title\n// ---------------------------------------------------------------------------\n\nexport interface SetDocumentTitleInput {\n document: SceneDocument\n title: string\n}\n\nexport function setDocumentTitleCommand(input: SetDocumentTitleInput): SceneCommand {\n const priorTitle = input.document.title\n\n const forwardOp: SceneOperation = { type: 'set_document_title', title: input.title }\n const inverseOp: SceneOperation = { type: 'set_document_title', title: priorTitle }\n\n return {\n label: `Rename document`,\n execute: (state) => applyOp(state, forwardOp),\n undo: (state) => applyOp(state, inverseOp),\n operations: () => [structuredClone(forwardOp)],\n inverseOperations: () => [structuredClone(inverseOp)],\n }\n}\n","/**\n * Pure ruler tick-step and label math for the canvas rulers. Nothing here\n * touches React or the DOM — all interaction geometry is extracted so it can\n * be unit-tested without a browser.\n *\n * Canvas rulers show document-coordinate values (CSS px). Tick density adapts\n * to the current zoom so major ticks never sit closer than `minMajorSpacingPx`\n * screen pixels apart. The step table covers typical design zoom ranges; beyond\n * the table the step grows by doubling the last candidate.\n */\n\n/** Ordered candidate major-tick steps in document px. Chosen so common design\n * values (10, 50, 100, 500…) are always available as label boundaries. */\nconst TICK_STEP_CANDIDATES_PX = [1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000] as const\n\nexport interface TickStep {\n /** Document-coordinate step between major ticks. */\n major: number\n /** Document-coordinate step between minor ticks (major / 5). */\n minor: number\n /** True when minor ticks should be drawn (they sit ≥ minMinorSpacingPx apart). */\n drawMinor: boolean\n}\n\n/**\n * Select the major tick step that keeps major ticks ≥ minMajorSpacingPx apart\n * at the given zoom. Minor ticks are rendered when they'd clear minMinorSpacingPx.\n *\n * Both spacing thresholds are SCREEN pixels — the caller provides `zoom` (screen\n * px per document px) so the result is zoom-independent.\n */\nexport function selectTickStep(input: {\n zoom: number\n minMajorSpacingPx?: number\n minMinorSpacingPx?: number\n}): TickStep {\n if (!Number.isFinite(input.zoom) || input.zoom <= 0) {\n throw new Error(`zoom must be a positive finite number, got ${input.zoom}`)\n }\n const minMajor = input.minMajorSpacingPx ?? 40\n const minMinor = input.minMinorSpacingPx ?? 8\n\n let major = TICK_STEP_CANDIDATES_PX[TICK_STEP_CANDIDATES_PX.length - 1]!\n for (const candidate of TICK_STEP_CANDIDATES_PX) {\n if (candidate * input.zoom >= minMajor) {\n major = candidate\n break\n }\n }\n // Beyond the table: double until the constraint is satisfied.\n while (major * input.zoom < minMajor) {\n major = major * 2\n }\n\n const minor = major / 5\n const drawMinor = minor * input.zoom >= minMinor\n\n return { major, minor, drawMinor }\n}\n\nexport interface RulerTick {\n /** Position in document coordinates. */\n position: number\n /** Label text, or null for a minor tick. */\n label: string | null\n}\n\n/**\n * Generate all ticks visible in a ruler of `documentLength` document-px,\n * given the current tick step. The caller clips to the viewport; this produces\n * all ticks for the full document extent so the ruler can be rendered\n * declaratively without a separate clipping pass.\n */\nexport function buildRulerTicks(input: {\n documentLength: number\n step: TickStep\n}): RulerTick[] {\n if (input.documentLength <= 0) return []\n\n const { major, minor, drawMinor } = input.step\n const ticks: RulerTick[] = []\n\n for (let pos = 0; pos <= input.documentLength; pos += major) {\n ticks.push({ position: pos, label: formatRulerLabel(pos) })\n if (!drawMinor) continue\n for (let m = 1; m < 5; m += 1) {\n const minorPos = pos + m * minor\n if (minorPos >= input.documentLength) break\n ticks.push({ position: minorPos, label: null })\n }\n }\n\n return ticks\n}\n\n/** Format a document-px position as a compact label: integers stay whole,\n * decimals are rounded to 1 place. Values ≥ 1000 are compacted to \"1k\" etc. */\nexport function formatRulerLabel(value: number): string {\n if (!Number.isFinite(value)) return ''\n if (Math.abs(value) >= 1000) {\n const k = value / 1000\n return `${Number.isInteger(k) ? k : k.toFixed(1)}k`\n }\n return Number.isInteger(value) ? String(value) : value.toFixed(1)\n}\n\n/**\n * Convert a screen-coordinate pointer position to a document-coordinate guide\n * drop position, given the ruler's scroll offset and zoom. Used by both the\n * horizontal and vertical ruler drag-guide creation paths.\n *\n * `scrollOffset` is how many document-px of the ruler are scrolled off-screen\n * to the left/top. `pointerScreenPx` is the cursor position in screen px\n * relative to the ruler element's origin.\n */\nexport function screenToDocumentPosition(input: {\n pointerScreenPx: number\n scrollOffset: number\n zoom: number\n}): number {\n if (!Number.isFinite(input.zoom) || input.zoom <= 0) {\n throw new Error(`zoom must be a positive finite number, got ${input.zoom}`)\n }\n return input.pointerScreenPx / input.zoom + input.scrollOffset\n}\n\n/** Snap a guide drop position to the nearest major tick if within\n * `snapThresholdPx` document px; otherwise returns the raw position. */\nexport function snapGuideToTick(position: number, step: TickStep, snapThresholdPx: number): number {\n const nearest = Math.round(position / step.major) * step.major\n return Math.abs(nearest - position) <= snapThresholdPx ? nearest : position\n}\n\n// ---------------------------------------------------------------------------\n// Z-order index math — extracted so Toolbar and LayersPanel agree\n// ---------------------------------------------------------------------------\n\n/** Index of the topmost element for a given owner length. */\nexport function topIndex(ownerLength: number): number {\n return ownerLength - 1\n}\n\n/** Move an element one step toward the top (higher index = above in z-order).\n * Returns the current index unchanged if already at the top. */\nexport function indexForward(current: number, ownerLength: number): number {\n return Math.min(current + 1, ownerLength - 1)\n}\n\n/** Move an element one step toward the bottom (lower index = below). Returns\n * the current index unchanged if already at the bottom. */\nexport function indexBackward(current: number): number {\n return Math.max(current - 1, 0)\n}\n\n/** Clamp an arbitrary target index to valid range. */\nexport function clampIndex(target: number, ownerLength: number): number {\n return Math.max(0, Math.min(target, ownerLength - 1))\n}\n","/**\n * Semi-transparent bleed tint drawn OUTSIDE the page bounds, with trim-mark\n * corner indicators. Renders as an absolutely-positioned div layered over the\n * workspace canvas; node name 'overlay:bleed' lets automated tests target it.\n *\n * Conditionally rendered: parent mounts this only when `showBleed && bleed`.\n * All dimensions are in SCREEN pixels (caller applies the zoom factor).\n */\n\nimport type { PageBleed } from '../../design-canvas/model'\n\nexport interface BleedTrimOverlayProps {\n /** Page dimensions in screen pixels (already multiplied by zoom). */\n pageWidthPx: number\n pageHeightPx: number\n /** Bleed extents in SCREEN pixels (caller multiplies doc-px by zoom). */\n bleed: {\n top: number\n right: number\n bottom: number\n left: number\n }\n}\n\n/** Length in screen pixels of each trim-mark arm. */\nconst TRIM_MARK_PX = 12\n\n/** How far trim marks sit from the page corner (in screen px). */\nconst TRIM_MARK_OFFSET_PX = 4\n\nexport function BleedTrimOverlay({ pageWidthPx, pageHeightPx, bleed }: BleedTrimOverlayProps) {\n const totalW = bleed.left + pageWidthPx + bleed.right\n const totalH = bleed.top + pageHeightPx + bleed.bottom\n\n return (\n <div\n data-node=\"overlay:bleed\"\n className=\"pointer-events-none absolute\"\n style={{\n top: -bleed.top,\n left: -bleed.left,\n width: totalW,\n height: totalH,\n }}\n aria-hidden\n >\n {/* Bleed tint strips — four sides */}\n {/* top */}\n <div\n className=\"absolute bg-rose-500/10\"\n style={{ top: 0, left: 0, width: totalW, height: bleed.top }}\n />\n {/* bottom */}\n <div\n className=\"absolute bg-rose-500/10\"\n style={{ bottom: 0, left: 0, width: totalW, height: bleed.bottom }}\n />\n {/* left */}\n <div\n className=\"absolute bg-rose-500/10\"\n style={{ top: bleed.top, left: 0, width: bleed.left, height: pageHeightPx }}\n />\n {/* right */}\n <div\n className=\"absolute bg-rose-500/10\"\n style={{ top: bleed.top, right: 0, width: bleed.right, height: pageHeightPx }}\n />\n\n {/* Trim marks — one per corner, two lines each */}\n <TrimMark corner=\"tl\" bleed={bleed} />\n <TrimMark corner=\"tr\" bleed={bleed} pageWidthPx={pageWidthPx} />\n <TrimMark corner=\"bl\" bleed={bleed} pageHeightPx={pageHeightPx} />\n <TrimMark corner=\"br\" bleed={bleed} pageWidthPx={pageWidthPx} pageHeightPx={pageHeightPx} />\n </div>\n )\n}\n\ntype Corner = 'tl' | 'tr' | 'bl' | 'br'\n\ninterface TrimMarkProps {\n corner: Corner\n bleed: BleedTrimOverlayProps['bleed']\n pageWidthPx?: number\n pageHeightPx?: number\n}\n\nfunction TrimMark({ corner, bleed, pageWidthPx = 0, pageHeightPx = 0 }: TrimMarkProps) {\n const isRight = corner === 'tr' || corner === 'br'\n const isBottom = corner === 'bl' || corner === 'br'\n\n const xBase = isRight ? bleed.left + pageWidthPx : bleed.left\n const yBase = isBottom ? bleed.top + pageHeightPx : bleed.top\n\n // Horizontal arm\n const hX = isRight ? xBase + TRIM_MARK_OFFSET_PX : xBase - TRIM_MARK_OFFSET_PX - TRIM_MARK_PX\n const hY = yBase - 0.5\n\n // Vertical arm\n const vX = xBase - 0.5\n const vY = isBottom ? yBase + TRIM_MARK_OFFSET_PX : yBase - TRIM_MARK_OFFSET_PX - TRIM_MARK_PX\n\n return (\n <>\n <div\n className=\"absolute bg-[var(--text-muted)]\"\n style={{ left: hX, top: hY, width: TRIM_MARK_PX, height: 1 }}\n />\n <div\n className=\"absolute bg-[var(--text-muted)]\"\n style={{ left: vX, top: vY, width: 1, height: TRIM_MARK_PX }}\n />\n </>\n )\n}\n","/**\n * Horizontal page-thumbnail strip shown at the bottom of the editor. The active\n * page is highlighted. Thumbnails are rendered externally (Konva; the host\n * injects `renderThumbnail` so this component stays canvas-free and testable).\n *\n * Actions: add page, duplicate active page, delete active page (disabled when\n * only one page remains), drag-reorder pages. The strip is read-only when\n * `canWrite` is false.\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { ScenePage } from '../../design-canvas/model'\nimport { DuplicateGlyph, PageGlyph, PlusGlyph, TrashGlyph } from './glyphs'\n\nexport interface PagesStripProps {\n pages: ScenePage[]\n activePageId: string\n canWrite: boolean\n /**\n * The host provides this to generate thumbnail data-URLs. The strip calls it\n * on mount and debounces re-calls on document changes. Returns null when the\n * thumbnail is not yet available (the strip renders a placeholder instead).\n */\n renderThumbnail(page: ScenePage): Promise<string | null>\n onSelectPage(pageId: string): void\n onAddPage(): void\n onDuplicatePage(pageId: string): void\n onDeletePage(pageId: string): void\n onReorderPage(pageId: string, toIndex: number): void\n}\n\nconst THUMBNAIL_W = 80\nconst THUMBNAIL_H = 56\n\nconst BTN =\n 'flex h-6 w-6 items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] disabled:cursor-default disabled:opacity-40'\n\nexport function PagesStrip({\n pages,\n activePageId,\n canWrite,\n renderThumbnail,\n onSelectPage,\n onAddPage,\n onDuplicatePage,\n onDeletePage,\n onReorderPage,\n}: PagesStripProps) {\n // Map from page id → data URL; null while loading.\n const [thumbnails, setThumbnails] = useState<Record<string, string | null>>({})\n const thumbnailVersionRef = useRef(0)\n\n useEffect(() => {\n // Debounce thumbnail regeneration: bump the version on every render cycle\n // and only apply results from the CURRENT version.\n const version = ++thumbnailVersionRef.current\n let cancelled = false\n\n async function generate() {\n const results: Record<string, string | null> = {}\n for (const page of pages) {\n if (cancelled) return\n try {\n results[page.id] = await renderThumbnail(page)\n } catch {\n results[page.id] = null\n }\n }\n if (!cancelled && thumbnailVersionRef.current === version) {\n setThumbnails(results)\n }\n }\n\n void generate()\n return () => {\n cancelled = true\n }\n // renderThumbnail is assumed stable (host memoizes it); pages is the dep.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [pages])\n\n // Drag-reorder\n const dragIndexRef = useRef<number | null>(null)\n const [dragOverIndex, setDragOverIndex] = useState<number | null>(null)\n\n return (\n <div\n className=\"flex h-[84px] shrink-0 items-center gap-2 overflow-x-auto border-t border-[var(--border-default)] bg-[var(--bg-input)] px-2\"\n aria-label=\"Pages\"\n >\n {pages.map((page, index) => {\n const isActive = page.id === activePageId\n const thumbUrl = thumbnails[page.id]\n\n return (\n <div\n key={page.id}\n role=\"button\"\n tabIndex={0}\n aria-label={`Page ${index + 1}: ${page.name}${isActive ? ' (active)' : ''}`}\n aria-pressed={isActive}\n draggable={canWrite}\n onDragStart={() => {\n dragIndexRef.current = index\n }}\n onDragOver={(event) => {\n if (dragIndexRef.current === null) return\n event.preventDefault()\n setDragOverIndex(index)\n }}\n onDragLeave={() => setDragOverIndex(null)}\n onDrop={() => {\n const from = dragIndexRef.current\n if (from !== null && from !== index) {\n onReorderPage(pages[from]!.id, index)\n }\n dragIndexRef.current = null\n setDragOverIndex(null)\n }}\n onDragEnd={() => {\n dragIndexRef.current = null\n setDragOverIndex(null)\n }}\n onClick={() => onSelectPage(page.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onSelectPage(page.id)\n }\n }}\n className={[\n 'group relative flex shrink-0 cursor-pointer flex-col items-center gap-1 rounded p-1 transition',\n isActive\n ? 'ring-2 ring-[var(--brand-primary)]'\n : 'hover:bg-[var(--border-default)]/40',\n dragOverIndex === index ? 'ring-1 ring-[var(--brand-primary)]/60' : '',\n ].join(' ')}\n >\n {/* Thumbnail or placeholder */}\n <div\n className=\"overflow-hidden rounded border border-[var(--border-default)] bg-white\"\n style={{ width: THUMBNAIL_W, height: THUMBNAIL_H }}\n >\n {thumbUrl ? (\n <img\n src={thumbUrl}\n alt={page.name}\n className=\"h-full w-full object-cover\"\n draggable={false}\n />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center\">\n <PageGlyph className=\"h-5 w-5 text-[var(--text-muted)]\" />\n </div>\n )}\n </div>\n\n {/* Page name */}\n <span className=\"max-w-[80px] truncate text-[10px] text-[var(--text-secondary)]\">\n {page.name}\n </span>\n\n {/* Per-page action buttons — visible on hover or when active */}\n {canWrite ? (\n <div className=\"pointer-events-none absolute -top-1 right-0 flex gap-0.5 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100\">\n <button\n type=\"button\"\n aria-label={`Duplicate page ${page.name}`}\n onClick={(event) => {\n event.stopPropagation()\n onDuplicatePage(page.id)\n }}\n className={BTN}\n >\n <DuplicateGlyph className=\"h-3 w-3\" />\n </button>\n <button\n type=\"button\"\n aria-label={`Delete page ${page.name}`}\n disabled={pages.length <= 1}\n onClick={(event) => {\n event.stopPropagation()\n if (pages.length > 1) onDeletePage(page.id)\n }}\n className={BTN}\n >\n <TrashGlyph className=\"h-3 w-3 text-rose-400\" />\n </button>\n </div>\n ) : null}\n </div>\n )\n })}\n\n {/* Add page button */}\n {canWrite ? (\n <button\n type=\"button\"\n aria-label=\"Add page\"\n onClick={onAddPage}\n className=\"flex h-[72px] w-[80px] shrink-0 flex-col items-center justify-center gap-1 rounded border border-dashed border-[var(--border-default)] text-[var(--text-muted)] transition hover:border-[var(--brand-primary)] hover:text-[var(--brand-primary)]\"\n >\n <PlusGlyph className=\"h-4 w-4\" />\n <span className=\"text-[10px]\">Add page</span>\n </button>\n ) : null}\n </div>\n )\n}\n","/**\n * Inline SVG glyphs for the design canvas editor. No external icon dependency —\n * same convention as sequences-react/components/glyphs.tsx.\n */\n\ninterface GlyphProps {\n className?: string\n}\n\nfunction glyph(paths: React.ReactNode) {\n return function Glyph({ className }: GlyphProps) {\n return (\n <svg\n className={className}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n {paths}\n </svg>\n )\n }\n}\n\nexport const UndoGlyph = glyph(<path d=\"M3 7v6h6M3 13a9 9 0 1 0 3-7.7\" />)\nexport const RedoGlyph = glyph(<path d=\"M21 7v6h-6M21 13a9 9 0 1 1-3-7.7\" />)\n\nexport const EyeGlyph = glyph(\n <>\n <path d=\"M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </>,\n)\n\nexport const EyeOffGlyph = glyph(\n <>\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n <path d=\"m1 1 22 22\" />\n </>,\n)\n\nexport const LockGlyph = glyph(\n <>\n <rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\" />\n <path d=\"M8 11V7a4 4 0 0 1 8 0v4\" />\n </>,\n)\n\nexport const UnlockGlyph = glyph(\n <>\n <rect x=\"5\" y=\"11\" width=\"14\" height=\"10\" rx=\"2\" />\n <path d=\"M8 11V7a4 4 0 1 1 8 0\" />\n </>,\n)\n\nexport const TrashGlyph = glyph(\n <>\n <path d=\"M3 6h18M19 6l-1 14H6L5 6M10 6V4h4v2\" />\n </>,\n)\n\nexport const GroupGlyph = glyph(\n <>\n <rect x=\"2\" y=\"2\" width=\"8\" height=\"8\" rx=\"1\" />\n <rect x=\"14\" y=\"2\" width=\"8\" height=\"8\" rx=\"1\" />\n <rect x=\"2\" y=\"14\" width=\"8\" height=\"8\" rx=\"1\" />\n <rect x=\"14\" y=\"14\" width=\"8\" height=\"8\" rx=\"1\" />\n </>,\n)\n\nexport const UngroupGlyph = glyph(\n <>\n <path d=\"M3 7V5a2 2 0 0 1 2-2h2M17 3h2a2 2 0 0 1 2 2v2M21 17v2a2 2 0 0 1-2 2h-2M7 21H5a2 2 0 0 1-2-2v-2\" />\n </>,\n)\n\nexport const BringFrontGlyph = glyph(\n <>\n <rect x=\"8\" y=\"8\" width=\"12\" height=\"12\" rx=\"1\" />\n <path d=\"M4 4h12v4H4z\" opacity=\".4\" />\n </>,\n)\n\nexport const SendBackGlyph = glyph(\n <>\n <rect x=\"4\" y=\"4\" width=\"12\" height=\"12\" rx=\"1\" opacity=\".4\" />\n <path d=\"M8 8h12v12H8z\" />\n </>,\n)\n\nexport const AlignLeftGlyph = glyph(\n <>\n <path d=\"M3 4v16M7 8h10M7 16h6\" />\n </>,\n)\nexport const AlignCenterGlyph = glyph(\n <>\n <path d=\"M12 4v16M7 8h10M9 16h6\" />\n </>,\n)\nexport const AlignRightGlyph = glyph(\n <>\n <path d=\"M21 4v16M7 8h10M11 16h6\" />\n </>,\n)\n\nexport const BoldGlyph = glyph(<path d=\"M6 4h8a4 4 0 0 1 0 8H6zM6 12h9a4 4 0 0 1 0 8H6z\" fill=\"currentColor\" stroke=\"none\" />)\nexport const ItalicGlyph = glyph(<path d=\"M11 4h6M7 20h6M14 4 8 20\" />)\n\nexport const PlusGlyph = glyph(<path d=\"M12 5v14M5 12h14\" />)\nexport const ChevronDownGlyph = glyph(<path d=\"m6 9 6 6 6-6\" />)\nexport const ChevronRightGlyph = glyph(<path d=\"m9 18 6-6-6-6\" />)\n\nexport const RectGlyph = glyph(<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />)\nexport const EllipseGlyph = glyph(<ellipse cx=\"12\" cy=\"12\" rx=\"10\" ry=\"7\" />)\nexport const LineGlyph = glyph(<path d=\"M5 19 19 5\" />)\nexport const TextGlyph = glyph(<path d=\"M4 7V4h16v3M9 20h6M12 4v16\" />)\nexport const ImageGlyph = glyph(\n <>\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" />\n <circle cx=\"9\" cy=\"9\" r=\"2\" />\n <path d=\"m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21\" />\n </>,\n)\nexport const VideoGlyph = glyph(\n <>\n <rect x=\"2\" y=\"3\" width=\"20\" height=\"18\" rx=\"2\" />\n <path d=\"m10 8 6 4-6 4z\" fill=\"currentColor\" stroke=\"none\" />\n </>,\n)\n\nexport const SlotGlyph = glyph(\n <>\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n <path d=\"M12 1v4M12 19v4M4.2 4.2l2.8 2.8M17 17l2.8 2.8M1 12h4M19 12h4M4.2 19.8l2.8-2.8M17 7 19.8 4.2\" />\n </>,\n)\n\nexport const FitGlyph = glyph(\n <>\n <path d=\"M3 3h4v4H3zM17 3h4v4h-4zM3 17h4v4H3zM17 17h4v4h-4z\" />\n <path d=\"M7 5h10M5 7v10M19 7v10M7 19h10\" />\n </>,\n)\n\nexport const PageGlyph = glyph(\n <>\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <polyline points=\"14 2 14 8 20 8\" />\n </>,\n)\n\nexport const GridGlyph = glyph(\n <>\n <path d=\"M3 3h18v18H3zM3 9h18M3 15h18M9 3v18M15 3v18\" />\n </>,\n)\n\nexport const RulerGlyph = glyph(\n <>\n <path d=\"M1 9v6l12 6V9L1 3z\" />\n <path d=\"m13 15 9-4.5V4.5L13 9\" />\n <path d=\"M5 12v3M8 13.5v2.5M11 15v3\" />\n </>,\n)\n\nexport const MagnetGlyph = glyph(\n <>\n <path d=\"m6 15-4-4 6.75-6.77a7.79 7.79 0 0 1 11 11L13 22l-4-4 6.39-6.36a2.14 2.14 0 0 0-3-3z\" />\n <path d=\"m5 8 4 4M12 15l4 4\" />\n </>,\n)\n\nexport const BleedGlyph = glyph(\n <>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" strokeDasharray=\"3 2\" />\n <rect x=\"7\" y=\"7\" width=\"10\" height=\"10\" />\n </>,\n)\n\nexport const DuplicateGlyph = glyph(\n <>\n <rect x=\"8\" y=\"8\" width=\"12\" height=\"12\" rx=\"2\" />\n <path d=\"M4 16V4a2 2 0 0 1 2-2h12\" />\n </>,\n)\n\nexport const ZoomFitGlyph = glyph(\n <>\n <path d=\"M15 3h6v6M14 10l6.1-6.1M9 21H3v-6M10 14l-6.1 6.1\" />\n </>,\n)\n\nexport const ExportGlyph = glyph(\n <>\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3\" />\n </>,\n)\n\nexport const ShapesGlyph = glyph(\n <>\n <rect x=\"3\" y=\"13\" width=\"8\" height=\"8\" rx=\"1\" />\n <circle cx=\"17\" cy=\"17\" r=\"4\" />\n <path d=\"M8.5 3 13 11H4z\" />\n </>,\n)\n","/**\n * Horizontal (top) and vertical (left) canvas rulers. Each ruler:\n * - Draws zoom-scaled tick marks via `buildRulerTicks` / `selectTickStep`.\n * - Shows a pointer-position indicator (a hairline that follows the cursor).\n * - Supports guide creation by dragging OUT of the ruler: a live preview line\n * appears while dragging; on drop a `set_page_guides` command is emitted.\n * - Existing guides that are dragged BACK into the ruler are deleted.\n *\n * All interaction math lives in ruler-math.ts and is testable without a DOM.\n * The rulers themselves are pure DOM (no Konva); they sit in a CSS grid slot\n * next to the workspace canvas.\n */\n\nimport { useCallback, useRef, useState } from 'react'\nimport type { PageGuides } from '../../design-canvas/model'\nimport { buildRulerTicks, screenToDocumentPosition, selectTickStep } from './ruler-math'\n\nconst RULER_SIZE_PX = 20\n\nexport interface RulersProps {\n /** Page width in document px. */\n pageWidth: number\n /** Page height in document px. */\n pageHeight: number\n zoom: number\n /** How many doc-px of the canvas are scrolled off-screen left/top. */\n scrollLeft: number\n scrollTop: number\n showRulers: boolean\n guides: PageGuides\n /** Emitted when the user drops a guide or deletes one back into the ruler. */\n onGuidesChange(guides: PageGuides): void\n}\n\n/** Minimum px from ruler edge before a guide drag counts as \"delete\". */\nconst DELETE_THRESHOLD_PX = RULER_SIZE_PX + 4\n\nexport function Rulers({ pageWidth, pageHeight, zoom, scrollLeft, scrollTop, showRulers, guides, onGuidesChange }: RulersProps) {\n if (!showRulers) return null\n\n return (\n <>\n {/* Corner filler */}\n <div\n className=\"absolute top-0 left-0 z-20 shrink-0 border-b border-r border-[var(--border-default)] bg-[var(--bg-input)]\"\n style={{ width: RULER_SIZE_PX, height: RULER_SIZE_PX }}\n />\n\n <HorizontalRuler\n pageWidth={pageWidth}\n zoom={zoom}\n scrollLeft={scrollLeft}\n guides={guides}\n onGuidesChange={onGuidesChange}\n />\n\n <VerticalRuler\n pageHeight={pageHeight}\n zoom={zoom}\n scrollTop={scrollTop}\n guides={guides}\n onGuidesChange={onGuidesChange}\n />\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Horizontal ruler\n// ---------------------------------------------------------------------------\n\ninterface HorizontalRulerProps {\n pageWidth: number\n zoom: number\n scrollLeft: number\n guides: PageGuides\n onGuidesChange(guides: PageGuides): void\n}\n\nfunction HorizontalRuler({ pageWidth, zoom, scrollLeft, guides, onGuidesChange }: HorizontalRulerProps) {\n const ref = useRef<HTMLDivElement>(null)\n const [pointerX, setPointerX] = useState<number | null>(null)\n const [dragGuideX, setDragGuideX] = useState<number | null>(null)\n const dragGuideIndexRef = useRef<number | null>(null)\n\n const step = selectTickStep({ zoom, minMajorSpacingPx: 40 })\n const ticks = buildRulerTicks({ documentLength: pageWidth, step })\n\n function screenXToDoc(clientX: number): number {\n if (!ref.current) return 0\n const rect = ref.current.getBoundingClientRect()\n return screenToDocumentPosition({ pointerScreenPx: clientX - rect.left, scrollOffset: scrollLeft, zoom })\n }\n\n function handlePointerDown(event: React.PointerEvent<HTMLDivElement>) {\n if (event.button !== 0) return\n event.preventDefault()\n event.currentTarget.setPointerCapture(event.pointerId)\n const docX = screenXToDoc(event.clientX)\n // Check if pointer is near an existing guide (within 4 screen px).\n const threshold = 4 / zoom\n const nearIdx = guides.vertical.findIndex((g) => Math.abs(g - docX) <= threshold)\n if (nearIdx >= 0) {\n dragGuideIndexRef.current = nearIdx\n } else {\n dragGuideIndexRef.current = null\n }\n setDragGuideX(docX)\n }\n\n function handlePointerMove(event: React.PointerEvent<HTMLDivElement>) {\n if (!ref.current) return\n const rect = ref.current.getBoundingClientRect()\n const localY = event.clientY - rect.top\n setPointerX(event.clientX - rect.left)\n if (!event.currentTarget.hasPointerCapture(event.pointerId)) return\n const docX = screenXToDoc(event.clientX)\n // If pointer moves BELOW the ruler, treat as \"dragging to canvas\" — show guide.\n if (localY > DELETE_THRESHOLD_PX) {\n setDragGuideX(docX)\n } else {\n // Dragged back into ruler — signal delete on release.\n setDragGuideX(null)\n }\n }\n\n function handlePointerUp(event: React.PointerEvent<HTMLDivElement>) {\n if (!event.currentTarget.hasPointerCapture(event.pointerId)) return\n event.currentTarget.releasePointerCapture(event.pointerId)\n\n const rect = ref.current?.getBoundingClientRect()\n const localY = rect ? event.clientY - rect.top : 0\n const deletingExisting = dragGuideIndexRef.current !== null\n const docX = screenXToDoc(event.clientX)\n\n const vertical = [...guides.vertical]\n\n if (localY <= DELETE_THRESHOLD_PX && deletingExisting) {\n // Dragged existing guide back into ruler — delete it.\n vertical.splice(dragGuideIndexRef.current!, 1)\n } else if (localY > DELETE_THRESHOLD_PX) {\n if (deletingExisting) {\n // Moved existing guide to new position.\n vertical[dragGuideIndexRef.current!] = docX\n } else {\n // New guide.\n vertical.push(docX)\n }\n }\n\n dragGuideIndexRef.current = null\n setDragGuideX(null)\n onGuidesChange({ ...guides, vertical })\n }\n\n function handlePointerLeave() {\n setPointerX(null)\n }\n\n return (\n <div\n ref={ref}\n className=\"absolute top-0 left-0 right-0 z-10 cursor-ew-resize select-none overflow-hidden border-b border-[var(--border-default)] bg-[var(--bg-input)]\"\n style={{ height: RULER_SIZE_PX, marginLeft: RULER_SIZE_PX }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerLeave={handlePointerLeave}\n >\n {ticks.map((tick) => {\n const screenX = tick.position * zoom - scrollLeft * zoom\n return (\n <div\n key={tick.position}\n className={`absolute bottom-0 w-px bg-[var(--border-default)] ${tick.label !== null ? 'top-1.5' : 'top-[14px]'}`}\n style={{ left: screenX }}\n >\n {tick.label !== null ? (\n <span className=\"absolute -top-1 left-0.5 whitespace-nowrap font-mono text-[9px] leading-none text-[var(--text-muted)]\">\n {tick.label}\n </span>\n ) : null}\n </div>\n )\n })}\n\n {/* Pointer indicator */}\n {pointerX !== null ? (\n <div className=\"pointer-events-none absolute top-0 bottom-0 w-px bg-[var(--brand-primary)]/60\" style={{ left: pointerX }} />\n ) : null}\n\n {/* Live drag-guide preview */}\n {dragGuideX !== null ? (\n <div\n className=\"pointer-events-none absolute top-0 bottom-0 w-px bg-[var(--brand-primary)]\"\n style={{ left: dragGuideX * zoom - scrollLeft * zoom }}\n />\n ) : null}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Vertical ruler\n// ---------------------------------------------------------------------------\n\ninterface VerticalRulerProps {\n pageHeight: number\n zoom: number\n scrollTop: number\n guides: PageGuides\n onGuidesChange(guides: PageGuides): void\n}\n\nfunction VerticalRuler({ pageHeight, zoom, scrollTop, guides, onGuidesChange }: VerticalRulerProps) {\n const ref = useRef<HTMLDivElement>(null)\n const [pointerY, setPointerY] = useState<number | null>(null)\n const [dragGuideY, setDragGuideY] = useState<number | null>(null)\n const dragGuideIndexRef = useRef<number | null>(null)\n\n const step = selectTickStep({ zoom, minMajorSpacingPx: 40 })\n const ticks = buildRulerTicks({ documentLength: pageHeight, step })\n\n function screenYToDoc(clientY: number): number {\n if (!ref.current) return 0\n const rect = ref.current.getBoundingClientRect()\n return screenToDocumentPosition({ pointerScreenPx: clientY - rect.top, scrollOffset: scrollTop, zoom })\n }\n\n function handlePointerDown(event: React.PointerEvent<HTMLDivElement>) {\n if (event.button !== 0) return\n event.preventDefault()\n event.currentTarget.setPointerCapture(event.pointerId)\n const docY = screenYToDoc(event.clientY)\n const threshold = 4 / zoom\n const nearIdx = guides.horizontal.findIndex((g) => Math.abs(g - docY) <= threshold)\n dragGuideIndexRef.current = nearIdx >= 0 ? nearIdx : null\n setDragGuideY(docY)\n }\n\n function handlePointerMove(event: React.PointerEvent<HTMLDivElement>) {\n if (!ref.current) return\n const rect = ref.current.getBoundingClientRect()\n const localX = event.clientX - rect.left\n setPointerY(event.clientY - rect.top)\n if (!event.currentTarget.hasPointerCapture(event.pointerId)) return\n const docY = screenYToDoc(event.clientY)\n if (localX > DELETE_THRESHOLD_PX) {\n setDragGuideY(docY)\n } else {\n setDragGuideY(null)\n }\n }\n\n function handlePointerUp(event: React.PointerEvent<HTMLDivElement>) {\n if (!event.currentTarget.hasPointerCapture(event.pointerId)) return\n event.currentTarget.releasePointerCapture(event.pointerId)\n\n const rect = ref.current?.getBoundingClientRect()\n const localX = rect ? event.clientX - rect.left : 0\n const deletingExisting = dragGuideIndexRef.current !== null\n const docY = screenYToDoc(event.clientY)\n\n const horizontal = [...guides.horizontal]\n\n if (localX <= DELETE_THRESHOLD_PX && deletingExisting) {\n horizontal.splice(dragGuideIndexRef.current!, 1)\n } else if (localX > DELETE_THRESHOLD_PX) {\n if (deletingExisting) {\n horizontal[dragGuideIndexRef.current!] = docY\n } else {\n horizontal.push(docY)\n }\n }\n\n dragGuideIndexRef.current = null\n setDragGuideY(null)\n onGuidesChange({ ...guides, horizontal })\n }\n\n function handlePointerLeave() {\n setPointerY(null)\n }\n\n return (\n <div\n ref={ref}\n className=\"absolute top-0 left-0 bottom-0 z-10 cursor-ns-resize select-none overflow-hidden border-r border-[var(--border-default)] bg-[var(--bg-input)]\"\n style={{ width: RULER_SIZE_PX, marginTop: RULER_SIZE_PX }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerLeave={handlePointerLeave}\n >\n {ticks.map((tick) => {\n const screenY = tick.position * zoom - scrollTop * zoom\n return (\n <div\n key={tick.position}\n className={`absolute right-0 h-px bg-[var(--border-default)] ${tick.label !== null ? 'left-1.5' : 'left-[14px]'}`}\n style={{ top: screenY }}\n >\n {tick.label !== null ? (\n <span\n className=\"absolute top-0.5 left-0 whitespace-nowrap font-mono text-[9px] leading-none text-[var(--text-muted)]\"\n style={{ transform: 'rotate(-90deg)', transformOrigin: '0 0', marginTop: 4 }}\n >\n {tick.label}\n </span>\n ) : null}\n </div>\n )\n })}\n\n {pointerY !== null ? (\n <div className=\"pointer-events-none absolute left-0 right-0 h-px bg-[var(--brand-primary)]/60\" style={{ top: pointerY }} />\n ) : null}\n\n {dragGuideY !== null ? (\n <div\n className=\"pointer-events-none absolute left-0 right-0 h-px bg-[var(--brand-primary)]\"\n style={{ top: dragGuideY * zoom - scrollTop * zoom }}\n />\n ) : null}\n </div>\n )\n}\n","/**\n * Selection-aware toolbar. When elements are selected it shows per-kind\n * attribute controls; when nothing is selected it shows page-props controls.\n * Every number input commits on blur or Enter as a single command (not\n * per-keystroke). The toolbar is stateless beyond transient input focus;\n * the caller owns the command stack.\n *\n * Layout: the root never scrolls horizontally. Global controls (undo/redo +\n * view toggles) are pinned left; the selection/page attribute group wraps so\n * the whole bar fits the editor's center column (viewport minus the w-64 side\n * panel and w-80 agent panel) at 1024–1280px with nothing clipped.\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { ReactNode } from 'react'\nimport type { SceneElement, ScenePage, TextElement, RectElement, EllipseElement, ImageElement } from '../../design-canvas/model'\nimport type { SceneAttrsPatch } from '../../design-canvas/operations'\nimport type { PageBleed } from '../../design-canvas/model'\nimport { matchPreset, SIZE_PRESETS } from '../../design-canvas/export-presets'\nimport {\n AlignCenterGlyph,\n AlignLeftGlyph,\n AlignRightGlyph,\n BleedGlyph,\n BoldGlyph,\n BringFrontGlyph,\n GridGlyph,\n GroupGlyph,\n ItalicGlyph,\n LockGlyph,\n MagnetGlyph,\n RedoGlyph,\n RulerGlyph,\n SendBackGlyph,\n SlotGlyph,\n TrashGlyph,\n UndoGlyph,\n UngroupGlyph,\n UnlockGlyph,\n} from './glyphs'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ToolbarProps {\n page: ScenePage\n selectedElements: SceneElement[]\n canWrite: boolean\n canUndo: boolean\n canRedo: boolean\n gridEnabled: boolean\n snapEnabled: boolean\n showRulers: boolean\n showBleed: boolean\n onUndo(): void\n onRedo(): void\n onToggleGrid(): void\n onToggleSnap(): void\n onToggleRulers(): void\n onToggleBleed(): void\n /** Emit attrs patch for each selected element. */\n onSetAttrs(elementId: string, attrs: SceneAttrsPatch): void\n onSetPageProps(props: { name?: string; width?: number; height?: number; background?: string; bleed?: PageBleed | null }): void\n onSetPageGuides(guides: { vertical: number[]; horizontal: number[] }): void\n onReorder(elementId: string, toIndex: number, ownerLength: number, direction: 'front' | 'back' | 'forward' | 'backward'): void\n onGroup(elementIds: string[]): void\n onUngroup(groupId: string): void\n onDelete(elementIds: string[]): void\n onBindSlot(elementId: string, slot: string | null): void\n}\n\n// ---------------------------------------------------------------------------\n// Font families offered by the font picker. The model's fontFamily is a free\n// string (agents/templates may set anything); the picker selects from this\n// curated list but always surfaces the element's current family even when it\n// is not a member, so a programmatically-set font is never silently dropped.\n// ---------------------------------------------------------------------------\n\nconst FONT_FAMILIES = [\n 'Inter',\n 'Arial',\n 'Helvetica',\n 'Verdana',\n 'Tahoma',\n 'Trebuchet MS',\n 'Times New Roman',\n 'Georgia',\n 'Garamond',\n 'Courier New',\n 'Brush Script MT',\n 'Impact',\n] as const\n\n// ---------------------------------------------------------------------------\n// Small helpers\n// ---------------------------------------------------------------------------\n\nconst BTN =\n 'flex h-7 w-7 items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] disabled:cursor-default disabled:opacity-40'\n\nconst BTN_ACTIVE = `${BTN} border-[var(--brand-primary)] text-[var(--brand-primary)] hover:text-[var(--brand-primary)]`\n\nconst SEP = <div className=\"mx-1 h-5 w-px shrink-0 bg-[var(--border-default)]\" />\n\nconst POPOVER_PANEL =\n 'absolute top-full left-0 z-50 mt-1 flex flex-col rounded border border-[var(--border-default)] bg-[var(--bg-input)] shadow-lg'\n\n/**\n * Click-outside / Escape-to-close popover anchored under its trigger. The\n * trigger renders inside the relative wrapper so the panel positions against\n * it. `open`/`onClose` are owned by the caller so the trigger can stay a\n * stateful glyph button when needed.\n */\nfunction Popover({\n open,\n onClose,\n trigger,\n children,\n}: {\n open: boolean\n onClose(): void\n trigger: ReactNode\n children: ReactNode\n}) {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (!open) return\n function onDocPointer(event: PointerEvent) {\n if (ref.current && !ref.current.contains(event.target as Node)) onClose()\n }\n function onKey(event: KeyboardEvent) {\n if (event.key === 'Escape') onClose()\n }\n document.addEventListener('pointerdown', onDocPointer)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('pointerdown', onDocPointer)\n document.removeEventListener('keydown', onKey)\n }\n }, [open, onClose])\n\n return (\n <div ref={ref} className=\"relative\">\n {trigger}\n {open ? children : null}\n </div>\n )\n}\n\nconst FIELD_LABEL = 'text-[9px] uppercase tracking-wide text-[var(--text-muted)]'\n\nfunction NumberInput({\n label,\n value,\n onCommit,\n min,\n step = 1,\n className = 'w-16',\n}: {\n label: string\n value: number\n onCommit(v: number): void\n min?: number\n step?: number\n className?: string\n}) {\n const [raw, setRaw] = useState<string | null>(null)\n\n function commit(v: string) {\n const n = parseFloat(v)\n if (Number.isFinite(n) && (min === undefined || n >= min)) onCommit(n)\n setRaw(null)\n }\n\n return (\n <label className=\"flex flex-col items-center gap-0.5\">\n <span className={FIELD_LABEL}>{label}</span>\n <input\n type=\"number\"\n value={raw ?? value}\n min={min}\n step={step}\n onChange={(event) => setRaw(event.target.value)}\n onBlur={(event) => commit(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit((event.target as HTMLInputElement).value)\n if (event.key === 'Escape') setRaw(null)\n }}\n className={`${className} rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-1 py-0.5 text-center text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]`}\n />\n </label>\n )\n}\n\n/**\n * Compact dropdown built on the popover pattern (replaces native <select>,\n * which the design system bans). Same value/onChange contract: `value` is the\n * current option id, `onChange` fires with the chosen id.\n */\nfunction SelectControl<T extends string>({\n label,\n value,\n options,\n disabled,\n onChange,\n buttonClassName = 'w-24',\n}: {\n label: string\n value: T\n options: ReadonlyArray<{ value: T; label: string }>\n disabled?: boolean\n onChange(value: T): void\n buttonClassName?: string\n}) {\n const [open, setOpen] = useState(false)\n const current = options.find((o) => o.value === value)\n\n return (\n <label className=\"flex flex-col items-center gap-0.5\">\n <span className={FIELD_LABEL}>{label}</span>\n <Popover\n open={open}\n onClose={() => setOpen(false)}\n trigger={\n <button\n type=\"button\"\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className={`${buttonClassName} flex items-center justify-between gap-1 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-0.5 text-left text-[12px] text-[var(--text-primary)] outline-none hover:border-[var(--brand-primary)] disabled:cursor-default disabled:opacity-40`}\n >\n <span className=\"truncate\">{current?.label ?? value}</span>\n <span className=\"text-[8px] text-[var(--text-muted)]\">▾</span>\n </button>\n }\n >\n <div role=\"listbox\" className={`${POPOVER_PANEL} max-h-64 w-44 overflow-y-auto py-1`}>\n {options.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n role=\"option\"\n aria-selected={opt.value === value}\n onClick={() => {\n onChange(opt.value)\n setOpen(false)\n }}\n className={`px-3 py-1 text-left text-[12px] hover:bg-[var(--brand-primary)]/10 ${\n opt.value === value ? 'text-[var(--brand-primary)]' : 'text-[var(--text-primary)]'\n }`}\n >\n {opt.label}\n </button>\n ))}\n </div>\n </Popover>\n </label>\n )\n}\n\n/**\n * Searchable font dropdown. Each option previews in its own family. The\n * element's current family is always present in the list (prepended when it\n * is not one of the curated families) so a typed/agent-set font is never lost.\n */\nfunction FontPicker({\n value,\n disabled,\n onChange,\n}: {\n value: string\n disabled?: boolean\n onChange(value: string): void\n}) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n\n const families: string[] = FONT_FAMILIES.includes(value as (typeof FONT_FAMILIES)[number])\n ? [...FONT_FAMILIES]\n : [value, ...FONT_FAMILIES]\n const filtered = families.filter((f) => f.toLowerCase().includes(query.trim().toLowerCase()))\n\n return (\n <label className=\"flex flex-col items-center gap-0.5\">\n <span className={FIELD_LABEL}>Font</span>\n <Popover\n open={open}\n onClose={() => {\n setOpen(false)\n setQuery('')\n }}\n trigger={\n <button\n type=\"button\"\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-label=\"Font family\"\n onClick={() => setOpen((v) => !v)}\n className=\"flex w-28 items-center justify-between gap-1 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-0.5 text-left text-[12px] text-[var(--text-primary)] outline-none hover:border-[var(--brand-primary)] disabled:cursor-default disabled:opacity-40\"\n style={{ fontFamily: value }}\n >\n <span className=\"truncate\">{value}</span>\n <span className=\"text-[8px] text-[var(--text-muted)]\">▾</span>\n </button>\n }\n >\n <div className={`${POPOVER_PANEL} w-52`}>\n <input\n autoFocus\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"Search fonts\"\n aria-label=\"Search fonts\"\n className=\"m-1 rounded border border-[var(--border-default)] bg-transparent px-2 py-1 text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]\"\n />\n <div role=\"listbox\" className=\"max-h-60 overflow-y-auto py-1\">\n {filtered.length === 0 ? (\n <div className=\"px-3 py-2 text-[11px] text-[var(--text-muted)]\">No matches</div>\n ) : (\n filtered.map((family) => (\n <button\n key={family}\n type=\"button\"\n role=\"option\"\n aria-selected={family === value}\n onClick={() => {\n onChange(family)\n setOpen(false)\n setQuery('')\n }}\n style={{ fontFamily: family }}\n className={`block w-full px-3 py-1 text-left text-[13px] hover:bg-[var(--brand-primary)]/10 ${\n family === value ? 'text-[var(--brand-primary)]' : 'text-[var(--text-primary)]'\n }`}\n >\n {family}\n </button>\n ))\n )}\n </div>\n </div>\n </Popover>\n </label>\n )\n}\n\n/**\n * Color control: a swatch button (showing the current color) that opens a\n * popover with a native color picker + hex field. Replaces the bare\n * <input type=\"color\"> chrome while keeping the string value/onChange contract.\n */\nfunction ColorSwatch({ label, value, onCommit, disabled }: { label: string; value: string; onCommit(v: string): void; disabled?: boolean }) {\n const [open, setOpen] = useState(false)\n const normalized = value.startsWith('#') ? value : '#ffffff'\n\n return (\n <div className=\"flex flex-col items-center gap-0.5\">\n <span className={FIELD_LABEL}>{label}</span>\n <Popover\n open={open}\n onClose={() => setOpen(false)}\n trigger={\n <button\n type=\"button\"\n disabled={disabled}\n aria-label={`${label} color`}\n onClick={() => setOpen((v) => !v)}\n className=\"h-6 w-10 rounded border border-[var(--border-default)] disabled:cursor-default disabled:opacity-40\"\n style={{ backgroundColor: normalized }}\n />\n }\n >\n <div className={`${POPOVER_PANEL} w-40 gap-2 p-2`}>\n <input\n type=\"color\"\n aria-label={`${label} color picker`}\n value={normalized}\n onChange={(event) => onCommit(event.target.value)}\n className=\"h-8 w-full cursor-pointer rounded border border-[var(--border-default)] p-0.5\"\n />\n <input\n type=\"text\"\n aria-label={`${label} hex value`}\n value={value}\n onChange={(event) => onCommit(event.target.value)}\n className=\"rounded border border-[var(--border-default)] bg-transparent px-2 py-1 text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]\"\n />\n </div>\n </Popover>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Main toolbar\n// ---------------------------------------------------------------------------\n\nexport function Toolbar({\n page,\n selectedElements,\n canWrite,\n canUndo,\n canRedo,\n gridEnabled,\n snapEnabled,\n showRulers,\n showBleed,\n onUndo,\n onRedo,\n onToggleGrid,\n onToggleSnap,\n onToggleRulers,\n onToggleBleed,\n onSetAttrs,\n onSetPageProps,\n onSetPageGuides,\n onReorder,\n onGroup,\n onUngroup,\n onDelete,\n onBindSlot,\n}: ToolbarProps) {\n const hasSelection = selectedElements.length > 0\n const single = selectedElements.length === 1 ? selectedElements[0]! : null\n const allSameKind = selectedElements.length > 0 && selectedElements.every((e) => e.kind === selectedElements[0]!.kind)\n const firstKind = selectedElements[0]?.kind\n\n // Shared multi-element patch helper.\n function patchAll(attrs: SceneAttrsPatch) {\n for (const el of selectedElements) onSetAttrs(el.id, attrs)\n }\n\n // Z-order helpers operate on the single selection only (multi-element\n // z-order is a complex multi-step operation; single is the common case).\n function reorderSingle(direction: 'front' | 'back' | 'forward' | 'backward') {\n if (!single) return\n // ownerLength requires knowing the owner; we use page.elements length for\n // root-level elements. Group children are handled via the layers panel.\n onReorder(single.id, 0, page.elements.length, direction)\n }\n\n const selectedIds = selectedElements.map((e) => e.id)\n const isGroup = single?.kind === 'group'\n const groupable = selectedElements.length >= 2\n\n // ----\n\n return (\n <div className=\"flex min-h-11 shrink-0 flex-wrap items-center gap-x-2 gap-y-1 border-b border-[var(--border-default)] bg-[var(--bg-input)] px-3 py-1\">\n {/* Global controls: pinned first, never wrap away from the left edge. */}\n <div className=\"flex shrink-0 items-center gap-2\">\n {/* Undo / Redo */}\n <button type=\"button\" aria-label=\"Undo\" disabled={!canUndo || !canWrite} onClick={onUndo} className={BTN}>\n <UndoGlyph className=\"h-3.5 w-3.5\" />\n </button>\n <button type=\"button\" aria-label=\"Redo\" disabled={!canRedo || !canWrite} onClick={onRedo} className={BTN}>\n <RedoGlyph className=\"h-3.5 w-3.5\" />\n </button>\n\n {SEP}\n\n {/* View toggles */}\n <button type=\"button\" aria-label=\"Toggle rulers\" aria-pressed={showRulers} onClick={onToggleRulers} className={showRulers ? BTN_ACTIVE : BTN}>\n <RulerGlyph className=\"h-3.5 w-3.5\" />\n </button>\n <button type=\"button\" aria-label=\"Toggle grid\" aria-pressed={gridEnabled} onClick={onToggleGrid} className={gridEnabled ? BTN_ACTIVE : BTN}>\n <GridGlyph className=\"h-3.5 w-3.5\" />\n </button>\n <button type=\"button\" aria-label=\"Toggle snap\" aria-pressed={snapEnabled} onClick={onToggleSnap} className={snapEnabled ? BTN_ACTIVE : BTN}>\n <MagnetGlyph className=\"h-3.5 w-3.5\" />\n </button>\n <button type=\"button\" aria-label=\"Toggle bleed overlay\" aria-pressed={showBleed} onClick={onToggleBleed} className={showBleed ? BTN_ACTIVE : BTN} disabled={!page.bleed}>\n <BleedGlyph className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n\n {SEP}\n\n {/* Selection / page attributes: this group wraps to the next line when\n the column is narrow so nothing is ever clipped or scrolled away. */}\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n {hasSelection ? (\n <SelectionControls\n elements={selectedElements}\n single={single}\n isGroup={isGroup}\n groupable={groupable}\n allSameKind={allSameKind}\n firstKind={firstKind}\n canWrite={canWrite}\n patchAll={patchAll}\n reorderSingle={reorderSingle}\n onGroup={() => onGroup(selectedIds)}\n onUngroup={() => { if (single) onUngroup(single.id) }}\n onDelete={() => onDelete(selectedIds)}\n onBindSlot={single ? (slot) => onBindSlot(single.id, slot) : undefined}\n currentSlot={single?.slot ?? null}\n />\n ) : (\n <PagePropsControls\n page={page}\n canWrite={canWrite}\n onSetPageProps={onSetPageProps}\n onSetPageGuides={onSetPageGuides}\n />\n )}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Selection controls\n// ---------------------------------------------------------------------------\n\ninterface SelectionControlsProps {\n elements: SceneElement[]\n single: SceneElement | null\n isGroup: boolean\n groupable: boolean\n allSameKind: boolean\n firstKind: SceneElement['kind'] | undefined\n canWrite: boolean\n patchAll(attrs: SceneAttrsPatch): void\n reorderSingle(direction: 'front' | 'back' | 'forward' | 'backward'): void\n onGroup(): void\n onUngroup(): void\n onDelete(): void\n onBindSlot?(slot: string | null): void\n currentSlot: string | null\n}\n\nfunction SelectionControls({\n elements,\n single,\n isGroup,\n groupable,\n allSameKind,\n firstKind,\n canWrite,\n patchAll,\n reorderSingle,\n onGroup,\n onUngroup,\n onDelete,\n onBindSlot,\n currentSlot,\n}: SelectionControlsProps) {\n const [slotPopoverOpen, setSlotPopoverOpen] = useState(false)\n const [slotInput, setSlotInput] = useState('')\n const firstEl = elements[0]!\n\n return (\n <>\n {/* Kind-specific attrs */}\n {allSameKind && firstKind === 'text' && single ? (\n <TextControls element={single as TextElement} canWrite={canWrite} onPatch={(attrs) => patchAll(attrs)} />\n ) : null}\n\n {allSameKind && (firstKind === 'rect') && single ? (\n <ShapeControls element={single as RectElement} canWrite={canWrite} onPatch={(attrs) => patchAll(attrs)} showCornerRadius />\n ) : null}\n\n {allSameKind && firstKind === 'ellipse' && single ? (\n <ShapeControls element={single as EllipseElement} canWrite={canWrite} onPatch={(attrs) => patchAll(attrs)} showCornerRadius={false} />\n ) : null}\n\n {allSameKind && firstKind === 'image' && single ? (\n <ImageControls element={single as ImageElement} canWrite={canWrite} onPatch={(attrs) => patchAll(attrs)} />\n ) : null}\n\n {SEP}\n\n {/* Shared: opacity + rotation */}\n <NumberInput\n label=\"Opacity\"\n value={Math.round((firstEl.opacity ?? 1) * 100)}\n min={0}\n onCommit={(v) => patchAll({ opacity: Math.max(0, Math.min(1, v / 100)) })}\n className=\"w-14\"\n />\n <NumberInput\n label=\"Rotation\"\n value={Math.round(firstEl.rotation ?? 0)}\n onCommit={(v) => patchAll({ rotation: v })}\n className=\"w-14\"\n />\n\n {SEP}\n\n {/* Z-order (single selection) */}\n {single ? (\n <>\n <button type=\"button\" aria-label=\"Bring to front\" disabled={!canWrite} onClick={() => reorderSingle('front')} className={BTN}>\n <BringFrontGlyph className=\"h-3.5 w-3.5\" />\n </button>\n <button type=\"button\" aria-label=\"Send to back\" disabled={!canWrite} onClick={() => reorderSingle('back')} className={BTN}>\n <SendBackGlyph className=\"h-3.5 w-3.5\" />\n </button>\n {SEP}\n </>\n ) : null}\n\n {/* Group / Ungroup */}\n {groupable ? (\n <button type=\"button\" aria-label=\"Group elements\" disabled={!canWrite} onClick={onGroup} className={BTN}>\n <GroupGlyph className=\"h-3.5 w-3.5\" />\n </button>\n ) : null}\n {isGroup ? (\n <button type=\"button\" aria-label=\"Ungroup\" disabled={!canWrite} onClick={onUngroup} className={BTN}>\n <UngroupGlyph className=\"h-3.5 w-3.5\" />\n </button>\n ) : null}\n\n {/* Lock */}\n {single ? (\n <button\n type=\"button\"\n aria-label={single.locked ? 'Unlock element' : 'Lock element'}\n disabled={!canWrite}\n onClick={() => patchAll({ locked: !single.locked })}\n className={single.locked ? BTN_ACTIVE : BTN}\n >\n {single.locked ? <LockGlyph className=\"h-3.5 w-3.5\" /> : <UnlockGlyph className=\"h-3.5 w-3.5\" />}\n </button>\n ) : null}\n\n {/* Slot binding (single element only) */}\n {single && onBindSlot ? (\n <Popover\n open={slotPopoverOpen}\n onClose={() => setSlotPopoverOpen(false)}\n trigger={\n <button\n type=\"button\"\n aria-label={currentSlot ? `Slot: ${currentSlot}` : 'Bind slot'}\n onClick={() => { setSlotInput(currentSlot ?? ''); setSlotPopoverOpen((v) => !v) }}\n className={currentSlot ? BTN_ACTIVE : BTN}\n title={currentSlot ? `Slot: ${currentSlot}` : 'Bind slot'}\n >\n <SlotGlyph className=\"h-3.5 w-3.5\" />\n </button>\n }\n >\n <div className={`${POPOVER_PANEL} w-48 gap-2 p-2`}>\n <input\n autoFocus\n value={slotInput}\n onChange={(event) => setSlotInput(event.target.value)}\n placeholder=\"slot-name\"\n className=\"rounded border border-[var(--border-default)] bg-transparent px-2 py-1 text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]\"\n />\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={() => { onBindSlot(slotInput.trim() || null); setSlotPopoverOpen(false) }}\n className=\"flex-1 rounded border border-[var(--brand-primary)] px-2 py-0.5 text-[11px] text-[var(--brand-primary)] hover:bg-[var(--brand-primary)]/10\"\n >\n {slotInput.trim() ? 'Bind' : 'Unbind'}\n </button>\n <button\n type=\"button\"\n onClick={() => setSlotPopoverOpen(false)}\n className=\"rounded border border-[var(--border-default)] px-2 py-0.5 text-[11px] text-[var(--text-secondary)]\"\n >\n Cancel\n </button>\n </div>\n </div>\n </Popover>\n ) : null}\n\n {SEP}\n\n {/* Delete */}\n <button type=\"button\" aria-label=\"Delete selection\" disabled={!canWrite} onClick={onDelete} className={BTN}>\n <TrashGlyph className=\"h-3.5 w-3.5 text-rose-400\" />\n </button>\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Kind-specific controls\n// ---------------------------------------------------------------------------\n\nfunction TextControls({ element, canWrite, onPatch }: { element: TextElement; canWrite: boolean; onPatch(attrs: SceneAttrsPatch): void }) {\n return (\n <>\n <FontPicker value={element.fontFamily} disabled={!canWrite} onChange={(fontFamily) => onPatch({ fontFamily })} />\n <NumberInput label=\"Size\" value={element.fontSize} min={1} onCommit={(v) => onPatch({ fontSize: v })} className=\"w-12\" />\n <button\n type=\"button\"\n aria-label=\"Bold\"\n disabled={!canWrite}\n onClick={() => onPatch({ fontStyle: element.fontStyle === 'bold' || element.fontStyle === 'bold italic' ? (element.fontStyle === 'bold italic' ? 'italic' : 'normal') : (element.fontStyle === 'italic' ? 'bold italic' : 'bold') })}\n className={element.fontStyle?.includes('bold') ? BTN_ACTIVE : BTN}\n >\n <BoldGlyph className=\"h-3.5 w-3.5\" />\n </button>\n <button\n type=\"button\"\n aria-label=\"Italic\"\n disabled={!canWrite}\n onClick={() => onPatch({ fontStyle: element.fontStyle === 'italic' || element.fontStyle === 'bold italic' ? (element.fontStyle === 'bold italic' ? 'bold' : 'normal') : (element.fontStyle === 'bold' ? 'bold italic' : 'italic') })}\n className={element.fontStyle?.includes('italic') ? BTN_ACTIVE : BTN}\n >\n <ItalicGlyph className=\"h-3.5 w-3.5\" />\n </button>\n {(['left', 'center', 'right'] as const).map((align) => (\n <button\n key={align}\n type=\"button\"\n aria-label={`Align ${align}`}\n disabled={!canWrite}\n onClick={() => onPatch({ align })}\n className={element.align === align ? BTN_ACTIVE : BTN}\n >\n {align === 'left' ? <AlignLeftGlyph className=\"h-3.5 w-3.5\" /> : align === 'center' ? <AlignCenterGlyph className=\"h-3.5 w-3.5\" /> : <AlignRightGlyph className=\"h-3.5 w-3.5\" />}\n </button>\n ))}\n <NumberInput label=\"Line H\" value={element.lineHeight} step={0.1} min={0.5} onCommit={(v) => onPatch({ lineHeight: v })} className=\"w-12\" />\n <NumberInput label=\"Spacing\" value={element.letterSpacing} step={0.5} onCommit={(v) => onPatch({ letterSpacing: v })} className=\"w-14\" />\n <ColorSwatch label=\"Fill\" value={element.fill} onCommit={(v) => onPatch({ fill: v })} disabled={!canWrite} />\n </>\n )\n}\n\nfunction ShapeControls({ element, canWrite, onPatch, showCornerRadius }: { element: RectElement | EllipseElement; canWrite: boolean; onPatch(attrs: SceneAttrsPatch): void; showCornerRadius: boolean }) {\n return (\n <>\n <ColorSwatch label=\"Fill\" value={element.fill} onCommit={(v) => onPatch({ fill: v })} disabled={!canWrite} />\n <ColorSwatch label=\"Stroke\" value={element.stroke ?? '#000000'} onCommit={(v) => onPatch({ stroke: v })} disabled={!canWrite} />\n <NumberInput label=\"Stroke W\" value={element.strokeWidth ?? 0} min={0} onCommit={(v) => onPatch({ strokeWidth: v })} className=\"w-14\" />\n {showCornerRadius && 'cornerRadius' in element ? (\n <NumberInput label=\"Corner R\" value={(element as RectElement).cornerRadius ?? 0} min={0} onCommit={(v) => onPatch({ cornerRadius: v })} className=\"w-14\" />\n ) : null}\n </>\n )\n}\n\nfunction ImageControls({ element, canWrite, onPatch }: { element: ImageElement; canWrite: boolean; onPatch(attrs: SceneAttrsPatch): void }) {\n return (\n <SelectControl\n label=\"Fit\"\n value={element.fit}\n disabled={!canWrite}\n onChange={(fit) => onPatch({ fit })}\n buttonClassName=\"w-24\"\n options={[\n { value: 'fill', label: 'Fill' },\n { value: 'cover', label: 'Cover' },\n { value: 'contain', label: 'Contain' },\n ]}\n />\n )\n}\n\n// ---------------------------------------------------------------------------\n// Page props controls (no selection)\n// ---------------------------------------------------------------------------\n\ninterface PagePropsControlsProps {\n page: ScenePage\n canWrite: boolean\n onSetPageProps(props: { name?: string; width?: number; height?: number; background?: string; bleed?: PageBleed | null }): void\n onSetPageGuides(guides: { vertical: number[]; horizontal: number[] }): void\n}\n\nfunction PagePropsControls({ page, canWrite, onSetPageProps, onSetPageGuides }: PagePropsControlsProps) {\n const matchedPreset = matchPreset(page.width, page.height)\n const [customW, setCustomW] = useState<string | null>(null)\n const [customH, setCustomH] = useState<string | null>(null)\n\n function commitDimension(dim: 'width' | 'height', raw: string) {\n const v = parseFloat(raw)\n if (Number.isFinite(v) && v > 0) onSetPageProps({ [dim]: v })\n if (dim === 'width') setCustomW(null)\n else setCustomH(null)\n }\n\n const presetOptions = [\n { value: 'custom', label: 'Custom' },\n ...SIZE_PRESETS.map((p) => ({ value: p.id, label: p.label })),\n ]\n\n return (\n <>\n {/* Page name */}\n <input\n type=\"text\"\n aria-label=\"Page name\"\n value={page.name}\n disabled={!canWrite}\n onChange={(event) => onSetPageProps({ name: event.target.value })}\n className=\"w-28 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-0.5 text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]\"\n />\n\n {SEP}\n\n {/* Size preset */}\n <SelectControl\n label=\"Preset\"\n value={matchedPreset?.id ?? 'custom'}\n disabled={!canWrite}\n onChange={(id) => {\n const preset = SIZE_PRESETS.find((p) => p.id === id)\n if (preset) onSetPageProps({ width: preset.width, height: preset.height })\n }}\n options={presetOptions}\n />\n\n {/* Custom W × H */}\n <label className=\"flex flex-col items-center gap-0.5\">\n <span className={FIELD_LABEL}>W</span>\n <input\n type=\"number\"\n value={customW ?? page.width}\n min={1}\n disabled={!canWrite}\n onChange={(event) => setCustomW(event.target.value)}\n onBlur={(event) => commitDimension('width', event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commitDimension('width', (event.target as HTMLInputElement).value)\n if (event.key === 'Escape') setCustomW(null)\n }}\n className=\"w-16 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-1 py-0.5 text-center text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]\"\n />\n </label>\n <span className=\"text-[var(--text-muted)]\">×</span>\n <label className=\"flex flex-col items-center gap-0.5\">\n <span className={FIELD_LABEL}>H</span>\n <input\n type=\"number\"\n value={customH ?? page.height}\n min={1}\n disabled={!canWrite}\n onChange={(event) => setCustomH(event.target.value)}\n onBlur={(event) => commitDimension('height', event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commitDimension('height', (event.target as HTMLInputElement).value)\n if (event.key === 'Escape') setCustomH(null)\n }}\n className=\"w-16 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-1 py-0.5 text-center text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]\"\n />\n </label>\n\n {SEP}\n\n <ColorSwatch label=\"BG\" value={page.background} onCommit={(v) => onSetPageProps({ background: v })} disabled={!canWrite} />\n\n {SEP}\n\n {/* Bleed controls */}\n <BleedControls page={page} canWrite={canWrite} onSetPageProps={onSetPageProps} />\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Bleed sub-controls\n// ---------------------------------------------------------------------------\n\nfunction BleedControls({ page, canWrite, onSetPageProps }: { page: ScenePage; canWrite: boolean; onSetPageProps: PagePropsControlsProps['onSetPageProps'] }) {\n const bleed = page.bleed\n\n function setBleedSide(side: keyof PageBleed, value: number) {\n const current = bleed ?? { top: 0, right: 0, bottom: 0, left: 0 }\n onSetPageProps({ bleed: { ...current, [side]: value } })\n }\n\n if (!bleed) {\n return (\n <button\n type=\"button\"\n disabled={!canWrite}\n onClick={() => onSetPageProps({ bleed: { top: 3, right: 3, bottom: 3, left: 3 } })}\n className={BTN}\n title=\"Enable bleed\"\n >\n <BleedGlyph className=\"h-3.5 w-3.5\" />\n </button>\n )\n }\n\n return (\n <>\n {(['top', 'right', 'bottom', 'left'] as const).map((side) => (\n <NumberInput\n key={side}\n label={`Bleed ${side[0]!.toUpperCase()}`}\n value={bleed[side]}\n min={0}\n onCommit={(v) => setBleedSide(side, v)}\n className=\"w-12\"\n />\n ))}\n <button\n type=\"button\"\n disabled={!canWrite}\n onClick={() => onSetPageProps({ bleed: null })}\n className={BTN}\n title=\"Remove bleed\"\n >\n ×\n </button>\n </>\n )\n}\n","/**\n * Canvas zoom controls: fit-to-page, 100%, zoom-out/in buttons, and a percent\n * readout. Stateless — zoom lives in the editor's view state, updated through\n * onZoom.\n */\n\nimport { ZoomFitGlyph } from './glyphs'\n\nexport interface ZoomControlsProps {\n zoom: number\n onZoom(zoom: number): void\n onFit(): void\n}\n\nconst STEP = 0.1\nconst MIN = 0.05\nconst MAX = 32\n\nconst BTN =\n 'flex h-6 w-6 items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] disabled:cursor-default disabled:opacity-40'\n\nexport function ZoomControls({ zoom, onZoom, onFit }: ZoomControlsProps) {\n function zoomOut() {\n onZoom(Math.max(MIN, parseFloat((zoom - STEP).toFixed(4))))\n }\n function zoomIn() {\n onZoom(Math.min(MAX, parseFloat((zoom + STEP).toFixed(4))))\n }\n function resetHundred() {\n onZoom(1)\n }\n\n return (\n <div className=\"flex items-center gap-1 px-2\">\n <button\n type=\"button\"\n aria-label=\"Fit page to viewport\"\n onClick={onFit}\n className={BTN}\n title=\"Fit page (F)\"\n >\n <ZoomFitGlyph className=\"h-3.5 w-3.5\" />\n </button>\n\n <button\n type=\"button\"\n aria-label=\"Zoom out\"\n onClick={zoomOut}\n disabled={zoom <= MIN}\n className={BTN}\n >\n <span className=\"text-base leading-none\">−</span>\n </button>\n\n <button\n type=\"button\"\n aria-label=\"Reset to 100%\"\n onClick={resetHundred}\n className=\"rounded px-1.5 py-0.5 font-mono text-[11px] tabular-nums text-[var(--text-secondary)] transition hover:bg-[var(--border-default)] hover:text-[var(--text-primary)]\"\n title=\"Reset to 100%\"\n >\n {Math.round(zoom * 100)}%\n </button>\n\n <button\n type=\"button\"\n aria-label=\"Zoom in\"\n onClick={zoomIn}\n disabled={zoom >= MAX}\n className={BTN}\n >\n <span className=\"text-sm leading-none\">+</span>\n </button>\n </div>\n )\n}\n","/**\n * Compact Export control for the editor chrome's top-right slot. A single\n * button opens a small popover to choose format (PNG/JPEG) and scale (1x/2x);\n * confirming calls `onExport({ format, pixelRatio })`.\n *\n * The chrome is Konva-free, so this control does NOT render the image — it only\n * collects the format/scale and delegates to the workspace (which owns the\n * stage) via the callback the DesignCanvas shell wires through `onExportRef`.\n *\n * Tokens/glyphs follow the canvas convention: CSS-var design tokens and inline\n * SVG glyphs, no icon-library or browser-default `<select>`.\n */\n\nimport { useRef, useState } from 'react'\nimport type { ExportTriggerOptions } from '../contracts'\nimport { ChevronDownGlyph, ExportGlyph } from './glyphs'\n\nexport interface ExportControlProps {\n /** Pre-selected format/scale when the popover opens. Default PNG @ 1x. */\n defaults?: ExportTriggerOptions\n /** Called with the chosen format/scale when the user confirms. */\n onExport(opts: ExportTriggerOptions): void\n className?: string\n}\n\nconst FORMATS: ReadonlyArray<{ id: 'png' | 'jpeg'; label: string }> = [\n { id: 'png', label: 'PNG' },\n { id: 'jpeg', label: 'JPEG' },\n]\n\nconst SCALES: ReadonlyArray<{ value: number; label: string }> = [\n { value: 1, label: '1x' },\n { value: 2, label: '2x' },\n]\n\nexport function ExportControl({ defaults, onExport, className }: ExportControlProps) {\n const [open, setOpen] = useState(false)\n const [format, setFormat] = useState<'png' | 'jpeg'>(defaults?.format ?? 'png')\n const [pixelRatio, setPixelRatio] = useState<number>(defaults?.pixelRatio ?? 1)\n const containerRef = useRef<HTMLDivElement>(null)\n\n function confirm() {\n onExport({ format, pixelRatio })\n setOpen(false)\n }\n\n return (\n <div ref={containerRef} className={`relative ${className ?? ''}`}>\n <button\n type=\"button\"\n aria-label=\"Export\"\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n // Close the popover when focus leaves the whole control (click-away /\n // tab-away) — but not when moving between the control's own children.\n onBlur={(event) => {\n if (!containerRef.current?.contains(event.relatedTarget as Node | null)) {\n setOpen(false)\n }\n }}\n className=\"flex h-8 items-center gap-1.5 rounded-md border border-[var(--border-default)] px-2.5 text-xs font-medium text-[var(--text-primary)] transition-colors hover:border-[var(--brand-primary)]/40\"\n >\n <ExportGlyph className=\"h-3.5 w-3.5\" />\n Export\n <ChevronDownGlyph className=\"h-3 w-3 text-[var(--text-muted)]\" />\n </button>\n\n {open ? (\n <div\n role=\"dialog\"\n aria-label=\"Export options\"\n onBlur={(event) => {\n if (!containerRef.current?.contains(event.relatedTarget as Node | null)) {\n setOpen(false)\n }\n }}\n className=\"absolute right-0 top-full z-50 mt-1 flex w-52 flex-col gap-3 rounded-md border border-[var(--border-default)] bg-[var(--bg-input)] p-3 shadow-lg\"\n >\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-[11px] font-medium text-[var(--text-muted)]\">Format</span>\n <div className=\"flex gap-1.5\">\n {FORMATS.map((f) => (\n <button\n key={f.id}\n type=\"button\"\n aria-pressed={format === f.id}\n onClick={() => setFormat(f.id)}\n className={`flex-1 rounded border px-2 py-1 text-[11px] transition-colors ${\n format === f.id\n ? 'border-[var(--brand-primary)] text-[var(--brand-primary)]'\n : 'border-[var(--border-default)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]'\n }`}\n >\n {f.label}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <span className=\"text-[11px] font-medium text-[var(--text-muted)]\">Scale</span>\n <div className=\"flex gap-1.5\">\n {SCALES.map((s) => (\n <button\n key={s.value}\n type=\"button\"\n aria-pressed={pixelRatio === s.value}\n onClick={() => setPixelRatio(s.value)}\n className={`flex-1 rounded border px-2 py-1 text-[11px] transition-colors ${\n pixelRatio === s.value\n ? 'border-[var(--brand-primary)] text-[var(--brand-primary)]'\n : 'border-[var(--border-default)] text-[var(--text-secondary)] hover:text-[var(--text-primary)]'\n }`}\n >\n {s.label}\n </button>\n ))}\n </div>\n </div>\n\n <button\n type=\"button\"\n aria-label=\"Export image\"\n onClick={confirm}\n className=\"rounded border border-[var(--brand-primary)] px-2 py-1 text-[11px] font-medium text-[var(--brand-primary)] transition-colors hover:bg-[var(--brand-primary)]/10\"\n >\n Export\n </button>\n </div>\n ) : null}\n </div>\n )\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","useState","document","activePageId","Fragment","jsx","jsxs","jsx","jsxs","useRef","useState","Fragment","jsx","jsxs","useRef","useState","useEffect","useRef","useState","Fragment","jsx","jsxs","BTN","useRef","useEffect","useState","jsx","jsxs","BTN","useRef","useState","jsx","jsxs","useState","useRef","jsx","jsxs","useCallback","useRef","useEffect","useState"]}
|
|
@@ -153,6 +153,18 @@ interface ApplySceneResult {
|
|
|
153
153
|
* editor rebases onto it. */
|
|
154
154
|
document?: SceneDocument;
|
|
155
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* What the chrome's Export control collects and hands to the workspace's
|
|
158
|
+
* export callback. The workspace (which owns the Konva stage) renders the
|
|
159
|
+
* page to a data URL with these params and forwards the full result to
|
|
160
|
+
* {@link DesignCanvasProps.onExport}. The chrome is Konva-free, so it cannot
|
|
161
|
+
* produce the data URL itself — it only chooses the format and scale.
|
|
162
|
+
*/
|
|
163
|
+
interface ExportTriggerOptions {
|
|
164
|
+
format: 'png' | 'jpeg';
|
|
165
|
+
/** Output scale multiplier (1 = page size, 2 = retina). */
|
|
166
|
+
pixelRatio: number;
|
|
167
|
+
}
|
|
156
168
|
interface DesignCanvasProps {
|
|
157
169
|
document: SceneDocument;
|
|
158
170
|
/** Revision the document was loaded at; threaded through saves. */
|
|
@@ -176,6 +188,12 @@ interface DesignCanvasProps {
|
|
|
176
188
|
dataUrl: string;
|
|
177
189
|
pixelRatio: number;
|
|
178
190
|
}): Promise<void>;
|
|
191
|
+
/**
|
|
192
|
+
* Optional caller-supplied default for the export popover. The chrome's
|
|
193
|
+
* Export control opens with this format/scale pre-selected. Omitted →
|
|
194
|
+
* PNG @ 1x.
|
|
195
|
+
*/
|
|
196
|
+
exportDefaults?: ExportTriggerOptions;
|
|
179
197
|
className?: string;
|
|
180
198
|
/** Fit the active page to the viewport once, on the first non-zero measurement. Default true. Set false to keep zoom:1/pan:0 (e.g. when restoring a saved viewport). */
|
|
181
199
|
fitOnMount?: boolean;
|
|
@@ -628,6 +646,11 @@ interface DesignCanvasFullProps extends DesignCanvasProps {
|
|
|
628
646
|
stack: ReturnType<typeof createSceneCommandStack>;
|
|
629
647
|
activePage: SceneDocument['pages'][number] | undefined;
|
|
630
648
|
onFitRef: React.MutableRefObject<(() => void) | null>;
|
|
649
|
+
/** A ref the workspace fills with an export callback. The chrome's Export
|
|
650
|
+
* control calls it with the chosen format/scale; the workspace renders the
|
|
651
|
+
* Konva stage to a data URL and forwards the result to `onExport`. Filled
|
|
652
|
+
* only when `onExport` is wired (the workspace skips it otherwise). */
|
|
653
|
+
onExportRef: React.MutableRefObject<((opts: ExportTriggerOptions) => void) | null>;
|
|
631
654
|
/** Forwarded from DesignCanvasProps. Default true: WorkspaceView fits the
|
|
632
655
|
* active page to the viewport once, on the first non-zero measurement. */
|
|
633
656
|
fitOnMount?: boolean;
|
|
@@ -644,7 +667,7 @@ interface DesignCanvasFullProps extends DesignCanvasProps {
|
|
|
644
667
|
*/
|
|
645
668
|
renderThumbnail(page: SceneDocument['pages'][number]): Promise<string | null>;
|
|
646
669
|
}
|
|
647
|
-
declare function DesignCanvas({ document: initialDocument, rev: initialRev, canWrite, onApplyOperations, onSelectionChange, renderAgentPanel, renderSidePanel, onExport, className, fitOnMount, onReady, renderWorkspace, renderThumbnail, }: DesignCanvasFullProps): react.JSX.Element;
|
|
670
|
+
declare function DesignCanvas({ document: initialDocument, rev: initialRev, canWrite, onApplyOperations, onSelectionChange, renderAgentPanel, renderSidePanel, onExport, exportDefaults, className, fitOnMount, onReady, renderWorkspace, renderThumbnail, }: DesignCanvasFullProps): react.JSX.Element;
|
|
648
671
|
|
|
649
672
|
/**
|
|
650
673
|
* Mount this component to get the full editor: toolbar, rulers, layers panel,
|
|
@@ -691,18 +714,23 @@ interface WorkspaceViewProps {
|
|
|
691
714
|
canWrite: boolean;
|
|
692
715
|
onApplyOperations: DesignCanvasProps['onApplyOperations'];
|
|
693
716
|
onSelectionChange?: DesignCanvasProps['onSelectionChange'];
|
|
694
|
-
renderAgentPanel?: DesignCanvasProps['renderAgentPanel'];
|
|
695
|
-
renderSidePanel?: DesignCanvasProps['renderSidePanel'];
|
|
696
717
|
className?: string;
|
|
697
718
|
/** Ref the chrome fills with a fit-page callback. The chrome calls it on F /
|
|
698
719
|
* Fit button; when injected via DesignCanvasEditor the ref is shared. */
|
|
699
720
|
onFitRef?: React.MutableRefObject<(() => void) | null>;
|
|
721
|
+
/** Host export hook. When set, the workspace fills `onExportRef` with a
|
|
722
|
+
* callback that renders the stage to a data URL and forwards the result. */
|
|
723
|
+
onExport?: DesignCanvasProps['onExport'];
|
|
724
|
+
/** Ref the workspace fills with an export callback `(opts) => void`. The
|
|
725
|
+
* chrome's Export control calls it; the workspace owns the Konva stage so it
|
|
726
|
+
* produces the data URL here. Filled only when `onExport` is also set. */
|
|
727
|
+
onExportRef?: React.MutableRefObject<((opts: ExportTriggerOptions) => void) | null>;
|
|
700
728
|
/** Fit the active page to the viewport once, on the first non-zero measurement. Default true. */
|
|
701
729
|
fitOnMount?: boolean;
|
|
702
730
|
/** Called once after the first real (non-zero) measurement, after the initial fit is applied (or skipped). */
|
|
703
731
|
onReady?(): void;
|
|
704
732
|
}
|
|
705
|
-
declare function WorkspaceView({ canWrite, onApplyOperations, onSelectionChange,
|
|
733
|
+
declare function WorkspaceView({ canWrite, onApplyOperations, onSelectionChange, className, stack, activePage, onFitRef, onExport, onExportRef, fitOnMount, onReady, }: WorkspaceViewProps): react.JSX.Element;
|
|
706
734
|
/**
|
|
707
735
|
* Self-contained Konva workspace that creates its own command stack. Mount
|
|
708
736
|
* this when you want the canvas without the toolbar/rulers/pages-strip chrome.
|
|
@@ -807,6 +835,15 @@ interface ZoomControlsProps {
|
|
|
807
835
|
}
|
|
808
836
|
declare function ZoomControls({ zoom, onZoom, onFit }: ZoomControlsProps): react.JSX.Element;
|
|
809
837
|
|
|
838
|
+
interface ExportControlProps {
|
|
839
|
+
/** Pre-selected format/scale when the popover opens. Default PNG @ 1x. */
|
|
840
|
+
defaults?: ExportTriggerOptions;
|
|
841
|
+
/** Called with the chosen format/scale when the user confirms. */
|
|
842
|
+
onExport(opts: ExportTriggerOptions): void;
|
|
843
|
+
className?: string;
|
|
844
|
+
}
|
|
845
|
+
declare function ExportControl({ defaults, onExport, className }: ExportControlProps): react.JSX.Element;
|
|
846
|
+
|
|
810
847
|
interface ElementNodeProps {
|
|
811
848
|
element: SceneElement;
|
|
812
849
|
isSelected: boolean;
|
|
@@ -1015,4 +1052,4 @@ declare const DesignCanvasLazy: react.LazyExoticComponent<typeof DesignCanvasEdi
|
|
|
1015
1052
|
/** Raw chrome only — use when supplying a custom renderWorkspace/renderThumbnail. */
|
|
1016
1053
|
declare const DesignCanvasChromeLazy: react.LazyExoticComponent<typeof DesignCanvas>;
|
|
1017
1054
|
|
|
1018
|
-
export { type AddElementInput, type AddPageInput, type ApplySceneResult, type BakedNodeAttrs, type BindSlotInput, CanvasInsertPanel, type CanvasInsertPanelProps, DEFAULT_INSERT_TEMPLATES, DUPLICATE_OFFSET, type DeleteElementInput, type DeletePageInput, DesignCanvas, DesignCanvasChromeLazy, DesignCanvasEditor, type DesignCanvasFullProps, DesignCanvasLazy, type DesignCanvasProps, type DuplicatePageInput, type EditorSceneState, ElementNode, type ElementNodeProps, ExportCropRect, type ExportPageDataUrlOptions, ExportPreset, type ExportViewSnapshot, GridLayer, type GridLayerProps, type GroupElementsInput, type InsertGeneration, type InsertPageGeometry, type InsertTemplate, LAYERS_PANEL_ROW_LIMIT, type LayerRow, LayersPanel, type LayersPanelProps, MAX_INSERT_DIMENSION, type MarqueeSelectOptions, type MultiSetAttrsEntry, type NudgeDelta, PagesStrip, type PagesStripProps, type ReorderElementInput, type ReorderPageInput, type ResolvedExportParams, type RulerTick, Rulers, type RulersProps, SCENE_COMMAND_HISTORY_LIMIT, type SceneCommand, type SceneCommandStack, SelectionLayer, type SelectionLayerProps, type SetAttrsInput, type SetDocumentTitleInput, type SetPageGuidesInput, type SetPagePropsInput, type SnapEngine, type SnapResult, type SnapTarget, type SnapTargetKind, type SnapTargets, type TickStep, Toolbar, type ToolbarProps, type TransformerNode, type UngroupElementInput, Workspace, WorkspaceView, type WorkspaceViewProps, ZoomControls, type ZoomControlsProps, type ZoomPanConfig, type ZoomPanMath, addElementCommand, addPageCommand, bakeLineTransform, bakeRectTransform, bakeTextTransform, bindSlotCommand, buildInsertImageOp, buildRulerTicks, centeredPosition, collectGridTargets, createSceneCommandStack, createSnapEngine, createZoomPanMath, deleteElementCommand, deletePageCommand, documentCropToStageCoords, downloadDataUrl, duplicatePageCommand, exportDocumentJson, exportPageDataUrl, fittedSize, flattenLayerTree, formatRulerLabel, groupElementsCommand, identifyTaintedSrc, isCrossOriginSrc, isExportHiddenNodeName, marqueeSelect, mintElementId, multiSetAttrsCommand, nudgeDelta, reorderElementCommand, reorderPageCommand, resolveExportParams, selectTickStep, setAttrsCommand, setDocumentTitleCommand, setPageGuidesCommand, setPagePropsCommand, ungroupElementCommand };
|
|
1055
|
+
export { type AddElementInput, type AddPageInput, type ApplySceneResult, type BakedNodeAttrs, type BindSlotInput, CanvasInsertPanel, type CanvasInsertPanelProps, DEFAULT_INSERT_TEMPLATES, DUPLICATE_OFFSET, type DeleteElementInput, type DeletePageInput, DesignCanvas, DesignCanvasChromeLazy, DesignCanvasEditor, type DesignCanvasFullProps, DesignCanvasLazy, type DesignCanvasProps, type DuplicatePageInput, type EditorSceneState, ElementNode, type ElementNodeProps, ExportControl, type ExportControlProps, ExportCropRect, type ExportPageDataUrlOptions, ExportPreset, type ExportTriggerOptions, type ExportViewSnapshot, GridLayer, type GridLayerProps, type GroupElementsInput, type InsertGeneration, type InsertPageGeometry, type InsertTemplate, LAYERS_PANEL_ROW_LIMIT, type LayerRow, LayersPanel, type LayersPanelProps, MAX_INSERT_DIMENSION, type MarqueeSelectOptions, type MultiSetAttrsEntry, type NudgeDelta, PagesStrip, type PagesStripProps, type ReorderElementInput, type ReorderPageInput, type ResolvedExportParams, type RulerTick, Rulers, type RulersProps, SCENE_COMMAND_HISTORY_LIMIT, type SceneCommand, type SceneCommandStack, SelectionLayer, type SelectionLayerProps, type SetAttrsInput, type SetDocumentTitleInput, type SetPageGuidesInput, type SetPagePropsInput, type SnapEngine, type SnapResult, type SnapTarget, type SnapTargetKind, type SnapTargets, type TickStep, Toolbar, type ToolbarProps, type TransformerNode, type UngroupElementInput, Workspace, WorkspaceView, type WorkspaceViewProps, ZoomControls, type ZoomControlsProps, type ZoomPanConfig, type ZoomPanMath, addElementCommand, addPageCommand, bakeLineTransform, bakeRectTransform, bakeTextTransform, bindSlotCommand, buildInsertImageOp, buildRulerTicks, centeredPosition, collectGridTargets, createSceneCommandStack, createSnapEngine, createZoomPanMath, deleteElementCommand, deletePageCommand, documentCropToStageCoords, downloadDataUrl, duplicatePageCommand, exportDocumentJson, exportPageDataUrl, fittedSize, flattenLayerTree, formatRulerLabel, groupElementsCommand, identifyTaintedSrc, isCrossOriginSrc, isExportHiddenNodeName, marqueeSelect, mintElementId, multiSetAttrsCommand, nudgeDelta, reorderElementCommand, reorderPageCommand, resolveExportParams, selectTickStep, setAttrsCommand, setDocumentTitleCommand, setPageGuidesCommand, setPagePropsCommand, ungroupElementCommand };
|