@tangle-network/agent-app 0.43.9 → 0.43.10

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.
Files changed (35) hide show
  1. package/dist/{DesignCanvas-GUTCY763.js → DesignCanvas-5DJAFDNC.js} +2 -2
  2. package/dist/DesignCanvasEditor-XUJZARSN.js +13 -0
  3. package/dist/{TimelineEditor-SNOAGBV6.js → TimelineEditor-I35SJJAJ.js} +2 -2
  4. package/dist/{chunk-LVD37K5V.js → chunk-47C6PJCW.js} +3 -1
  5. package/dist/{chunk-LVD37K5V.js.map → chunk-47C6PJCW.js.map} +1 -1
  6. package/dist/{chunk-6JYDS34Y.js → chunk-4QN75UHX.js} +14 -5
  7. package/dist/chunk-4QN75UHX.js.map +1 -0
  8. package/dist/{chunk-EX3LD5G6.js → chunk-7SUPA2YT.js} +2 -2
  9. package/dist/{chunk-EX3LD5G6.js.map → chunk-7SUPA2YT.js.map} +1 -1
  10. package/dist/{chunk-AFQXKJAE.js → chunk-BN2USWIR.js} +20 -3
  11. package/dist/{chunk-AFQXKJAE.js.map → chunk-BN2USWIR.js.map} +1 -1
  12. package/dist/{chunk-OVUQNKLM.js → chunk-H5FM75MR.js} +8 -7
  13. package/dist/chunk-H5FM75MR.js.map +1 -0
  14. package/dist/{chunk-A5Z53E3A.js → chunk-R4NOKZMD.js} +3 -3
  15. package/dist/{command-stack-CcWi_2bN.d.ts → command-stack-B_-WNfZU.d.ts} +6 -2
  16. package/dist/design-canvas-react/engine.d.ts +3 -2
  17. package/dist/design-canvas-react/engine.js +1 -1
  18. package/dist/design-canvas-react/index.d.ts +4 -4
  19. package/dist/design-canvas-react/index.js +19 -7
  20. package/dist/design-canvas-react/index.js.map +1 -1
  21. package/dist/design-canvas-react/lazy.d.ts +2 -2
  22. package/dist/design-canvas-react/lazy.js +1 -1
  23. package/dist/index.js +1 -1
  24. package/dist/{lazy-2XBVp1_e.d.ts → lazy-C7LiVeFt.d.ts} +1 -1
  25. package/dist/sequences-react/index.js +2 -2
  26. package/dist/theme/index.js +1 -1
  27. package/dist/theme/tokens.css +7 -0
  28. package/package.json +1 -1
  29. package/dist/DesignCanvasEditor-ZO4V7H6A.js +0 -13
  30. package/dist/chunk-6JYDS34Y.js.map +0 -1
  31. package/dist/chunk-OVUQNKLM.js.map +0 -1
  32. /package/dist/{DesignCanvas-GUTCY763.js.map → DesignCanvas-5DJAFDNC.js.map} +0 -0
  33. /package/dist/{DesignCanvasEditor-ZO4V7H6A.js.map → DesignCanvasEditor-XUJZARSN.js.map} +0 -0
  34. /package/dist/{TimelineEditor-SNOAGBV6.js.map → TimelineEditor-I35SJJAJ.js.map} +0 -0
  35. /package/dist/{chunk-A5Z53E3A.js.map → chunk-R4NOKZMD.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/design-canvas-react/components/DesignCanvas.tsx","../src/design-canvas-react/components/BrandKnot.tsx","../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/icon-button.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 { BrandKnot } from './BrandKnot'\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 /** Forwarded from DesignCanvasProps. The Konva render palette; the\n * Konva-free chrome passes it straight through to the workspace. */\n render?: DesignCanvasProps['render']\n /** Forwarded from DesignCanvasProps. Toggles the branded in-canvas empty\n * state and its agent door. */\n showEmptyState?: DesignCanvasProps['showEmptyState']\n onAskAgent?: DesignCanvasProps['onAskAgent']\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 mode = 'edit',\n onApplyOperations,\n onSelectionChange,\n renderAgentPanel,\n renderSidePanel,\n onExport,\n exportDefaults,\n className,\n fitOnMount,\n onReady,\n render,\n showEmptyState,\n onAskAgent,\n pageSizeLabel,\n enableBleedLabel,\n fitLabel,\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-apply\n // THIS command's forward transform (stack.reexecute) — captured at undo\n // time, not a blind canRedo()/redo() that diverges from the server when an\n // edit interleaves before the rejection lands.\n void onApplyOperations(command.inverseOperations())\n .then((result) => {\n if (result.document) stack.reset(result.document)\n })\n .catch((error: unknown) => {\n stack.reexecute(command)\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 // Persist the redo; on rejection re-apply THIS command's inverse\n // (stack.reundo) — captured at redo time, not a blind canUndo()/undo() that\n // undoes the wrong command when an edit interleaves before the rejection.\n void onApplyOperations(command.operations())\n .then((result) => {\n if (result.document) stack.reset(result.document)\n })\n .catch((error: unknown) => {\n stack.reundo(command)\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 const review = mode === 'review'\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, insert panel, etc.).\n Suppressed in review mode: the lean reviewer hides authoring/insert\n surfaces regardless of what the integrator passes. */}\n {renderSidePanel && !review ? (\n <aside className=\"hidden w-64 shrink-0 flex-col overflow-hidden border-r border-[var(--border-default)] lg:flex\">\n {renderSidePanel({ selectedElements, activePageId: activePage.id, activePage })}\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 mode={mode}\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 pageSizeLabel={pageSizeLabel}\n enableBleedLabel={enableBleedLabel}\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-[hsl(var(--destructive)/0.3)] bg-[hsl(var(--destructive)/0.1)] px-3 py-1.5 text-xs text-[var(--text-danger)]\"\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 {/* Phones (<640px): the Konva editor is unusable squeezed, so show a\n clean, on-brand notice instead of a broken canvas. The full editor\n area renders from sm: up. */}\n <div className=\"flex min-h-0 flex-1 flex-col items-center justify-center gap-3 px-6 text-center sm:hidden\">\n <BrandKnot size={32} className=\"shrink-0\" />\n <div className=\"flex flex-col gap-1\">\n <p className=\"text-sm font-semibold text-[var(--text-primary)]\">Best edited on a larger screen</p>\n <p className=\"text-xs leading-5 text-[var(--text-secondary)]\">\n The design canvas needs room to work. Open this on a tablet or desktop to edit pages, elements, and export.\n </p>\n </div>\n </div>\n\n {/* Rulers + Workspace area */}\n <div className=\"relative hidden min-h-0 flex-1 sm:block\">\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 render,\n // Review mode hides authoring affordances; the empty state's doors\n // create content, so they only belong on the editor surface.\n showEmptyState: review ? false : showEmptyState,\n onAskAgent,\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 canManagePages={!review}\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 fitLabel={fitLabel}\n />\n </div>\n </div>\n </div>\n\n {/* Optional right agent panel */}\n {renderAgentPanel ? (\n <aside className=\"hidden w-80 shrink-0 flex-col overflow-hidden border-l border-[var(--border-default)] lg:flex\">\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 * Lazy Tangle knot for the canvas surfaces.\n *\n * The brand mark lives in `../../brand`, which re-exports `TangleKnot` from the\n * `@tangle-network/sandbox-ui` barrel — a heavy, opt-in peer. Importing it\n * statically would drag that whole chain into the eagerly-evaluated canvas\n * module graph (Workspace / DesignCanvasEditor), which must stay importable in\n * environments that don't have the peer wired (SSR, tests). Pulling the mark\n * through a dynamic `import()` behind Suspense keeps the dependency lazy — the\n * same reason `lazy.tsx` defers the Konva editor chunk — so module-load stays\n * dependency-light and the mark resolves only when a surface actually renders it.\n */\n\nimport { lazy, Suspense } from 'react'\n\nconst LazyKnot = lazy(() => import('../../brand').then((m) => ({ default: m.TangleKnot })))\n\nexport interface BrandKnotProps {\n size?: number\n className?: string\n}\n\nexport function BrandKnot({ size = 24, className }: BrandKnotProps) {\n return (\n <Suspense fallback={<span aria-hidden style={{ display: 'inline-block', width: size, height: size }} className={className} />}>\n <LazyKnot size={size} className={className} />\n </Suspense>\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'\nimport { BTN_SM } from './icon-button'\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 /** Show page-management affordances (add / duplicate / delete). Default true.\n * The review surface passes false: pages are navigated, not authored. */\n canManagePages?: boolean\n /** Heading shown above the strip so it reads as page management. Overridable;\n * defaults to \"Pages\". Set to '' to hide the visible label (the container\n * keeps its accessible name regardless). */\n label?: string\n}\n\nconst THUMBNAIL_W = 80\nconst THUMBNAIL_H = 56\n\nexport function PagesStrip({\n pages,\n activePageId,\n canWrite,\n renderThumbnail,\n onSelectPage,\n onAddPage,\n onDuplicatePage,\n onDeletePage,\n onReorderPage,\n canManagePages = true,\n label = 'Pages',\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 className=\"flex shrink-0 flex-col bg-[var(--bg-input)]\">\n {/* Quiet section heading so the thumbnail row reads as page management,\n not a stray strip. The scroll container below keeps the accessible\n \"Pages\" name regardless of whether the visible label is shown. */}\n {label ? (\n <div className=\"flex items-center gap-1.5 px-3 pt-1.5 text-[var(--text-muted)]\">\n <PageGlyph className=\"h-3 w-3\" />\n <span className=\"text-[10px] font-medium uppercase tracking-[0.08em]\">{label}</span>\n </div>\n ) : null}\n <div\n className=\"flex h-[92px] items-center gap-2 overflow-x-auto px-2 pb-2 pt-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 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 className={[\n 'group relative flex shrink-0 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 {/* Selection is a real button so the tile is not an interactive control\n nesting the per-page action buttons (axe: nested-interactive). */}\n <button\n type=\"button\"\n aria-label={`Page ${index + 1}: ${page.name}${isActive ? ' (active)' : ''}`}\n aria-pressed={isActive}\n onClick={() => onSelectPage(page.id)}\n className=\"flex cursor-pointer flex-col items-center gap-1 rounded focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))]\"\n >\n {/* Thumbnail or placeholder */}\n <div\n className=\"overflow-hidden rounded border border-[var(--border-default)] bg-[hsl(var(--card))]\"\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-contain\"\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 </button>\n\n {/* Per-page action buttons — visible on hover or when active */}\n {canWrite && canManagePages ? (\n <div className=\"pointer-events-none absolute right-1 top-1 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_SM}\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_SM}\n >\n <TrashGlyph className=\"h-3 w-3 text-[var(--text-danger)]\" />\n </button>\n </div>\n ) : null}\n </div>\n )\n })}\n\n {/* Add page button */}\n {canWrite && canManagePages ? (\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)] focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))]\"\n >\n <PlusGlyph className=\"h-4 w-4\" />\n <span className=\"text-[10px]\">Add page</span>\n </button>\n ) : null}\n </div>\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\" />)\nexport const SwapGlyph = glyph(<path d=\"M7 4 3 8l4 4M3 8h14M17 20l4-4-4-4M21 16H7\" />)\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\" />)\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 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 * Shared icon-button contract for the canvas chrome (Toolbar, ZoomControls,\n * PagesStrip). One definition so the focus ring, disabled affordance, and\n * active state can never drift between surfaces.\n *\n * The focus ring uses the `--ring` token (defined in src/theme/tokens.css) and\n * is keyboard-only (`focus-visible`) so mouse clicks don't draw a ring.\n */\n\nimport { forwardRef } from 'react'\nimport type { ButtonHTMLAttributes } from 'react'\n\nconst BTN_BASE =\n 'items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))] focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-input)] disabled:cursor-default disabled:opacity-40'\n\nconst BTN_ACTIVE_EXTRA =\n ' border-[var(--brand-primary)] text-[var(--brand-primary)] hover:text-[var(--brand-primary)]'\n\n/** 28px square (h-7) — used by the main toolbar. */\nexport const BTN = `flex h-7 w-7 ${BTN_BASE}`\nexport const BTN_ACTIVE = BTN + BTN_ACTIVE_EXTRA\n\n/** 24px square (h-6) — used by the zoom controls and pages strip. */\nexport const BTN_SM = `flex h-6 w-6 ${BTN_BASE}`\nexport const BTN_SM_ACTIVE = BTN_SM + BTN_ACTIVE_EXTRA\n\nexport interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /** Render the active (brand-colored) variant. */\n active?: boolean\n /** 'md' = 28px (toolbar), 'sm' = 24px (zoom/pages). */\n size?: 'md' | 'sm'\n}\n\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(\n { active = false, size = 'md', className = '', type = 'button', ...rest },\n ref,\n) {\n const base = size === 'sm' ? (active ? BTN_SM_ACTIVE : BTN_SM) : active ? BTN_ACTIVE : BTN\n return <button ref={ref} type={type} className={className ? `${base} ${className}` : base} {...rest} />\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 type { DesignCanvasMode } from '../contracts'\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 SwapGlyph,\n TrashGlyph,\n UndoGlyph,\n UngroupGlyph,\n UnlockGlyph,\n} from './glyphs'\nimport { BTN, BTN_ACTIVE } from './icon-button'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ToolbarProps {\n page: ScenePage\n selectedElements: SceneElement[]\n canWrite: boolean\n /** Capability mode. `'review'` (the lean reviewer) hides the view toggles,\n * page-props controls, and the destructive/structural selection controls\n * (z-order, group/ungroup, lock, slot, delete), keeping only safe direct\n * edits: text content, image fit/replace, opacity/rotation, undo/redo.\n * Defaults to `'edit'` (the full authoring toolbar). */\n mode?: DesignCanvasMode\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 /** Field label for the page-size control. Defaults to the clearer \"Page size\";\n * overridable for consumers that want the older \"Preset\" wording. */\n pageSizeLabel?: string\n /** Title for the \"turn on print bleed\" action. Defaults to \"Show print bleed\"\n * (the outcome) rather than the print-shop term \"bleed\". */\n enableBleedLabel?: string\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 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 mode = 'edit',\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 pageSizeLabel = 'Page size',\n enableBleedLabel = 'Show print bleed',\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 const review = mode === 'review'\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 Grouped by intent so history reads apart from the view utilities:\n Undo/Redo (history) | a labelled View cluster (rulers/grid/snap/bleed). */}\n <div className=\"flex shrink-0 items-center gap-2\">\n {/* History: Undo / Redo */}\n <div className=\"flex items-center gap-1\" role=\"group\" aria-label=\"History\">\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 </div>\n\n {/* View toggles (grid/snap/ruler/bleed) are view utilities, not creation\n actions — a quiet \"View\" label sets them apart by intent. The review\n surface hides them so the bar stays lean. */}\n {!review ? (\n <>\n {SEP}\n <div className=\"flex items-center gap-1\" role=\"group\" aria-label=\"View\">\n <span className={`${FIELD_LABEL} mr-0.5 hidden md:inline`} aria-hidden>\n View\n </span>\n <button type=\"button\" aria-label=\"Toggle rulers\" aria-pressed={showRulers} onClick={onToggleRulers} className={showRulers ? BTN_ACTIVE : BTN} title=\"Rulers\">\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} title=\"Grid\">\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} title=\"Snap to guides\">\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} title=\"Show print bleed\">\n <BleedGlyph className=\"h-3.5 w-3.5\" />\n </button>\n </div>\n </>\n ) : null}\n </div>\n\n {/* Selection attributes: this group wraps to the next line when the column\n is narrow so nothing is ever clipped or scrolled away. In review mode\n the page-props controls (no-selection authoring) are omitted entirely\n and the selection controls drop structural/destructive actions. */}\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n {hasSelection ? (\n <>\n {SEP}\n <SelectionControls\n elements={selectedElements}\n single={single}\n isGroup={isGroup}\n groupable={groupable}\n allSameKind={allSameKind}\n firstKind={firstKind}\n canWrite={canWrite}\n review={review}\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 ) : !review ? (\n <>\n {SEP}\n <PagePropsControls\n page={page}\n canWrite={canWrite}\n onSetPageProps={onSetPageProps}\n onSetPageGuides={onSetPageGuides}\n pageSizeLabel={pageSizeLabel}\n enableBleedLabel={enableBleedLabel}\n />\n </>\n ) : null}\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 /** Review mode drops z-order, group/ungroup, lock, slot-bind, and delete. */\n review: 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 review,\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 {/* Structural + destructive controls: hidden on the review surface, which\n allows only direct attribute edits and reposition (drag). */}\n {review ? null : (\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 aria-pressed={!!single.locked}\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 aria-pressed={!!currentSlot}\n aria-haspopup=\"dialog\"\n aria-expanded={slotPopoverOpen}\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 — destructive, marked apart with a danger-tinted hover. */}\n <button\n type=\"button\"\n aria-label=\"Delete selection\"\n disabled={!canWrite}\n onClick={onDelete}\n className={`${BTN} text-[var(--text-danger)] hover:border-[var(--text-danger)] hover:text-[var(--text-danger)]`}\n >\n <TrashGlyph className=\"h-3.5 w-3.5\" />\n </button>\n </>\n )}\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 aria-pressed={!!element.fontStyle?.includes('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 aria-pressed={!!element.fontStyle?.includes('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 <div role=\"radiogroup\" aria-label=\"Text alignment\" className=\"flex items-center gap-2\">\n {(['left', 'center', 'right'] as const).map((align) => (\n <button\n key={align}\n type=\"button\"\n role=\"radio\"\n aria-label={`Align ${align}`}\n aria-checked={element.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 </div>\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 const [swapOpen, setSwapOpen] = useState(false)\n const [swapUrl, setSwapUrl] = useState('')\n\n return (\n <>\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 {/* Image swap: replace the source in place (size/position preserved). A\n safe direct edit, available in review mode. */}\n <Popover\n open={swapOpen}\n onClose={() => setSwapOpen(false)}\n trigger={\n <button\n type=\"button\"\n aria-label=\"Replace image\"\n disabled={!canWrite}\n onClick={() => { setSwapUrl(element.src); setSwapOpen((v) => !v) }}\n className={BTN}\n title=\"Replace image\"\n >\n <SwapGlyph className=\"h-3.5 w-3.5\" />\n </button>\n }\n >\n <div className={`${POPOVER_PANEL} w-64 gap-2 p-2`}>\n <input\n autoFocus\n value={swapUrl}\n onChange={(event) => setSwapUrl(event.target.value)}\n placeholder=\"https://… image URL\"\n aria-label=\"New image URL\"\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 disabled={!swapUrl.trim() || swapUrl.trim() === element.src}\n onClick={() => { onPatch({ src: swapUrl.trim() }); setSwapOpen(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 disabled:cursor-default disabled:opacity-40\"\n >\n Replace\n </button>\n <button\n type=\"button\"\n onClick={() => setSwapOpen(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 </>\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 pageSizeLabel?: string\n enableBleedLabel?: string\n}\n\nfunction PagePropsControls({ page, canWrite, onSetPageProps, onSetPageGuides, pageSizeLabel = 'Page size', enableBleedLabel = 'Show print bleed' }: 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={pageSizeLabel}\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} enableBleedLabel={enableBleedLabel} />\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Bleed sub-controls\n// ---------------------------------------------------------------------------\n\nfunction BleedControls({ page, canWrite, onSetPageProps, enableBleedLabel = 'Show print bleed' }: { page: ScenePage; canWrite: boolean; onSetPageProps: PagePropsControlsProps['onSetPageProps']; enableBleedLabel?: string }) {\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 aria-label={enableBleedLabel}\n disabled={!canWrite}\n onClick={() => onSetPageProps({ bleed: { top: 3, right: 3, bottom: 3, left: 3 } })}\n className={BTN}\n title={enableBleedLabel}\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={side[0]!.toUpperCase() + side.slice(1)}\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 print bleed\"\n aria-label=\"Remove print 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'\nimport { BTN_SM } from './icon-button'\n\nexport interface ZoomControlsProps {\n zoom: number\n onZoom(zoom: number): void\n onFit(): void\n /** Label/aria for the fit action. Defaults to \"Fit to screen\" — shorter and\n * matching every other tool's wording for the same action. */\n fitLabel?: string\n}\n\nconst STEP = 0.1\nconst MIN = 0.05\nconst MAX = 32\n\nexport function ZoomControls({ zoom, onZoom, onFit, fitLabel = 'Fit to screen' }: 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={fitLabel}\n onClick={onFit}\n className={BTN_SM}\n title={`${fitLabel} (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_SM}\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)] focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))]\"\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_SM}\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","jsx","Fragment","jsx","jsxs","jsx","IconButton","jsx","jsxs","useRef","useState","Fragment","jsx","jsxs","useRef","useState","useEffect","useRef","useState","Fragment","jsx","jsxs","useRef","useEffect","useState","jsx","jsxs","useRef","useState","jsx","jsxs","useState","useRef","jsx","jsxs","useCallback","useRef","useEffect","useState"]}
@@ -1,14 +1,14 @@
1
1
  // src/design-canvas-react/lazy.tsx
2
2
  import { lazy } from "react";
3
3
  var DesignCanvasLazy = lazy(
4
- () => import("./DesignCanvasEditor-ZO4V7H6A.js").then((m) => ({ default: m.DesignCanvasEditor }))
4
+ () => import("./DesignCanvasEditor-XUJZARSN.js").then((m) => ({ default: m.DesignCanvasEditor }))
5
5
  );
6
6
  var DesignCanvasChromeLazy = lazy(
7
- () => import("./DesignCanvas-GUTCY763.js").then((m) => ({ default: m.DesignCanvas }))
7
+ () => import("./DesignCanvas-5DJAFDNC.js").then((m) => ({ default: m.DesignCanvas }))
8
8
  );
9
9
 
10
10
  export {
11
11
  DesignCanvasLazy,
12
12
  DesignCanvasChromeLazy
13
13
  };
14
- //# sourceMappingURL=chunk-A5Z53E3A.js.map
14
+ //# sourceMappingURL=chunk-R4NOKZMD.js.map
@@ -1,4 +1,4 @@
1
- import { c as SceneDocument, d as SceneElement, B as Bounds } from './model-BBwyOuWG.js';
1
+ import { c as SceneDocument, d as SceneElement, g as ScenePage, B as Bounds } from './model-BBwyOuWG.js';
2
2
  import { g as SceneOperation } from './operations-DLIvvD00.js';
3
3
  import { CanvasRenderPalette } from './theme/index.js';
4
4
 
@@ -194,7 +194,11 @@ interface DesignCanvasProps {
194
194
  selectedElements: SceneElement[];
195
195
  activePageId: string;
196
196
  }): React.ReactNode;
197
- renderSidePanel?(): React.ReactNode;
197
+ renderSidePanel?(ctx: {
198
+ selectedElements: SceneElement[];
199
+ activePageId: string;
200
+ activePage: ScenePage;
201
+ }): React.ReactNode;
198
202
  /** Export hook — host persists the rendered blob (upload → asset row). */
199
203
  onExport?(result: {
200
204
  pageId: string;
@@ -1,5 +1,5 @@
1
- import { d as SceneCommand, i as SnapTarget, g as SnapEngine, Z as ZoomPanMath } from '../command-stack-CcWi_2bN.js';
2
- export { A as ApplySceneResult, a as DesignCanvasMode, D as DesignCanvasProps, b as EditorSceneState, E as ExportTriggerOptions, S as SCENE_COMMAND_HISTORY_LIMIT, e as SceneCommandStack, f as SceneCommandStackWithReapply, h as SnapResult, j as SnapTargetKind, k as SnapTargets, c as createSceneCommandStack } from '../command-stack-CcWi_2bN.js';
1
+ import { d as SceneCommand, i as SnapTarget, g as SnapEngine, Z as ZoomPanMath } from '../command-stack-B_-WNfZU.js';
2
+ export { A as ApplySceneResult, a as DesignCanvasMode, D as DesignCanvasProps, b as EditorSceneState, E as ExportTriggerOptions, S as SCENE_COMMAND_HISTORY_LIMIT, e as SceneCommandStack, f as SceneCommandStackWithReapply, h as SnapResult, j as SnapTargetKind, k as SnapTargets, c as createSceneCommandStack } from '../command-stack-B_-WNfZU.js';
3
3
  import { d as SceneElement, N as NewPageOptions, c as SceneDocument, a as PageGuides, P as PageBleed, B as Bounds, g as ScenePage } from '../model-BBwyOuWG.js';
4
4
  import { f as SceneAttrsPatch, g as SceneOperation } from '../operations-DLIvvD00.js';
5
5
  import { d as ExportCropRect, f as ExportPreset } from '../export-presets-DAsU5Wal.js';
@@ -307,6 +307,7 @@ interface InsertPageGeometry {
307
307
  pageId: string;
308
308
  width: number;
309
309
  height: number;
310
+ background?: string;
310
311
  }
311
312
  /** Mint a DOM-safe element id. Prefers `crypto.randomUUID`; falls back to a
312
313
  * time+random id where crypto is unavailable (older runtimes, some test envs). */
@@ -18,7 +18,7 @@ import {
18
18
  mintElementId,
19
19
  nudgeDelta,
20
20
  resolveExportParams
21
- } from "../chunk-AFQXKJAE.js";
21
+ } from "../chunk-BN2USWIR.js";
22
22
  import {
23
23
  SCENE_COMMAND_HISTORY_LIMIT,
24
24
  addElementCommand,
@@ -1,11 +1,11 @@
1
- import { D as DesignCanvasProps, c as createSceneCommandStack, E as ExportTriggerOptions, a as DesignCanvasMode } from '../command-stack-CcWi_2bN.js';
2
- export { A as ApplySceneResult, b as EditorSceneState, S as SCENE_COMMAND_HISTORY_LIMIT, d as SceneCommand, e as SceneCommandStack, f as SceneCommandStackWithReapply, g as SnapEngine, h as SnapResult, i as SnapTarget, j as SnapTargetKind, k as SnapTargets, Z as ZoomPanMath } from '../command-stack-CcWi_2bN.js';
1
+ import { D as DesignCanvasProps, c as createSceneCommandStack, E as ExportTriggerOptions, a as DesignCanvasMode } from '../command-stack-B_-WNfZU.js';
2
+ export { A as ApplySceneResult, b as EditorSceneState, S as SCENE_COMMAND_HISTORY_LIMIT, d as SceneCommand, e as SceneCommandStack, f as SceneCommandStackWithReapply, g as SnapEngine, h as SnapResult, i as SnapTarget, j as SnapTargetKind, k as SnapTargets, Z as ZoomPanMath } from '../command-stack-B_-WNfZU.js';
3
3
  import { InsertPageGeometry, InsertTemplate, MultiSetAttrsEntry } from './engine.js';
4
4
  export { AddElementInput, AddPageInput, BindSlotInput, DEFAULT_INSERT_TEMPLATES, DUPLICATE_OFFSET, DeleteElementInput, DeletePageInput, DuplicatePageInput, ExportViewSnapshot, GroupElementsInput, MAX_INSERT_DIMENSION, MarqueeSelectOptions, NudgeDelta, ReorderElementInput, ReorderPageInput, ResolvedExportParams, SetAttrsInput, SetDocumentTitleInput, SetPageGuidesInput, SetPagePropsInput, UngroupElementInput, ZoomPanConfig, addElementCommand, addPageCommand, bindSlotCommand, buildInsertImageOp, centeredPosition, collectGridTargets, createSnapEngine, createZoomPanMath, deleteElementCommand, deletePageCommand, documentCropToStageCoords, duplicatePageCommand, fittedSize, groupElementsCommand, hitTestPoint, identifyTaintedSrc, isCrossOriginSrc, isExportHiddenNodeName, marqueeSelect, mintElementId, multiSetAttrsCommand, nudgeDelta, reorderElementCommand, reorderPageCommand, resolveExportParams, setAttrsCommand, setDocumentTitleCommand, setPageGuidesCommand, setPagePropsCommand, ungroupElementCommand } from './engine.js';
5
5
  import { c as SceneDocument, g as ScenePage, d as SceneElement, P as PageBleed, a as PageGuides } from '../model-BBwyOuWG.js';
6
6
  import { f as ExportPreset } from '../export-presets-DAsU5Wal.js';
7
7
  export { d as ExportCropRect, h as bleedAwareExportBounds, s as scaleForPreset } from '../export-presets-DAsU5Wal.js';
8
- export { D as DesignCanvas, a as DesignCanvasChromeLazy, b as DesignCanvasEditor, c as DesignCanvasFullProps, d as DesignCanvasLazy } from '../lazy-2XBVp1_e.js';
8
+ export { D as DesignCanvas, a as DesignCanvasChromeLazy, b as DesignCanvasEditor, c as DesignCanvasFullProps, d as DesignCanvasLazy } from '../lazy-C7LiVeFt.js';
9
9
  import * as react from 'react';
10
10
  import { ButtonHTMLAttributes } from 'react';
11
11
  import { g as SceneOperation, f as SceneAttrsPatch } from '../operations-DLIvvD00.js';
@@ -103,7 +103,7 @@ interface CanvasInsertPanelProps {
103
103
  /** Submit operations through the host's apply pipeline. */
104
104
  onInsert(operations: SceneOperation[]): Promise<unknown>;
105
105
  /** Store an uploaded file and return its src (http(s) or rooted `/api/`). */
106
- onUploadImage(file: File): Promise<string>;
106
+ onUploadImage?(file: File): Promise<string>;
107
107
  /** Optional provider for the Generations tab; omit to hide it. */
108
108
  loadGenerations?(): Promise<InsertGeneration[]>;
109
109
  /** Drop-in templates; defaults to the built-in starter set. */
@@ -12,7 +12,7 @@ import {
12
12
  downloadDataUrl,
13
13
  exportDocumentJson,
14
14
  exportPageDataUrl
15
- } from "../chunk-6JYDS34Y.js";
15
+ } from "../chunk-4QN75UHX.js";
16
16
  import {
17
17
  BTN,
18
18
  BTN_ACTIVE,
@@ -41,7 +41,7 @@ import {
41
41
  buildRulerTicks,
42
42
  formatRulerLabel,
43
43
  selectTickStep
44
- } from "../chunk-OVUQNKLM.js";
44
+ } from "../chunk-H5FM75MR.js";
45
45
  import "../chunk-ZN5J47UX.js";
46
46
  import {
47
47
  DEFAULT_INSERT_TEMPLATES,
@@ -62,7 +62,7 @@ import {
62
62
  mintElementId,
63
63
  nudgeDelta,
64
64
  resolveExportParams
65
- } from "../chunk-AFQXKJAE.js";
65
+ } from "../chunk-BN2USWIR.js";
66
66
  import {
67
67
  SCENE_COMMAND_HISTORY_LIMIT,
68
68
  addElementCommand,
@@ -85,8 +85,8 @@ import {
85
85
  import {
86
86
  DesignCanvasChromeLazy,
87
87
  DesignCanvasLazy
88
- } from "../chunk-A5Z53E3A.js";
89
- import "../chunk-LVD37K5V.js";
88
+ } from "../chunk-R4NOKZMD.js";
89
+ import "../chunk-47C6PJCW.js";
90
90
  import {
91
91
  assertSceneMediaSrc,
92
92
  bleedAwareExportBounds,
@@ -172,13 +172,24 @@ function CanvasInsertPanel({
172
172
  accept = DEFAULT_ACCEPT,
173
173
  className
174
174
  }) {
175
- const [tab, setTab] = useState("uploads");
175
+ const [tab, setTab] = useState(() => templates.length > 0 ? "templates" : "uploads");
176
176
  const [busy, setBusy] = useState(false);
177
177
  const [error, setError] = useState("");
178
178
  const [dragOver, setDragOver] = useState(false);
179
179
  const [generations, setGenerations] = useState([]);
180
180
  const [generationsLoaded, setGenerationsLoaded] = useState(false);
181
181
  const fileInputRef = useRef(null);
182
+ useEffect(() => {
183
+ if (tab === "uploads" && !onUploadImage) {
184
+ setTab(templates.length > 0 ? "templates" : loadGenerations ? "generations" : "uploads");
185
+ }
186
+ if (tab === "templates" && templates.length === 0) {
187
+ setTab(onUploadImage ? "uploads" : loadGenerations ? "generations" : "uploads");
188
+ }
189
+ if (tab === "generations" && !loadGenerations) {
190
+ setTab(templates.length > 0 ? "templates" : onUploadImage ? "uploads" : "templates");
191
+ }
192
+ }, [tab, templates.length, onUploadImage, loadGenerations]);
182
193
  useEffect(() => {
183
194
  if (tab !== "generations" || generationsLoaded || !loadGenerations) return;
184
195
  let cancelled = false;
@@ -203,6 +214,7 @@ function CanvasInsertPanel({
203
214
  }
204
215
  async function handleFiles(files) {
205
216
  if (!canWrite || busy) return;
217
+ if (!onUploadImage) return;
206
218
  const list = Array.from(files).filter((f) => f.type.startsWith("image/"));
207
219
  if (list.length === 0) {
208
220
  setError("Only image files can be added to the canvas");
@@ -234,7 +246,7 @@ function CanvasInsertPanel({
234
246
  }
235
247
  }
236
248
  const tabs = [
237
- { id: "uploads", label: "Uploads", icon: ImageGlyph, show: true },
249
+ { id: "uploads", label: "Uploads", icon: ImageGlyph, show: !!onUploadImage },
238
250
  { id: "templates", label: "Templates", icon: ShapesGlyph, show: templates.length > 0 },
239
251
  { id: "generations", label: "Generations", icon: SparkleGlyph, show: !!loadGenerations }
240
252
  ];