@snowcone-app/canvas 0.1.10 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{CanvasStateV1-BmE5V6me.cjs → CanvasStateV1-C4hC1MCe.cjs} +5 -5
- package/dist/{CanvasStateV1-BmE5V6me.cjs.map → CanvasStateV1-C4hC1MCe.cjs.map} +1 -1
- package/dist/{CanvasStateV1-CD3Q94F4.js → CanvasStateV1-CJU_xYW5.js} +3 -3
- package/dist/{CanvasStateV1-CD3Q94F4.js.map → CanvasStateV1-CJU_xYW5.js.map} +1 -1
- package/dist/{HybridHistoryManager-BV6XV0nD.js → HybridHistoryManager-jBBnVim8.js} +54 -54
- package/dist/{HybridHistoryManager-BV6XV0nD.js.map → HybridHistoryManager-jBBnVim8.js.map} +1 -1
- package/dist/{ElementFactory-Ckv6sSev.js → ImportManager-Oqu2yB54.js} +595 -378
- package/dist/ImportManager-Oqu2yB54.js.map +1 -0
- package/dist/{ElementFactory-DEjwp-Wg.cjs → ImportManager-W1eWhfyM.cjs} +5 -5
- package/dist/ImportManager-W1eWhfyM.cjs.map +1 -0
- package/dist/ThemeContext-BMNQKl1c.cjs +2 -0
- package/dist/{ThemeContext-4mJ_y0Me.cjs.map → ThemeContext-BMNQKl1c.cjs.map} +1 -1
- package/dist/ThemeContext-wj-wSO7J.js +1158 -0
- package/dist/{ThemeContext-H0Z-MqqR.js.map → ThemeContext-wj-wSO7J.js.map} +1 -1
- package/dist/advanced.js +5 -32
- package/dist/advanced.js.map +1 -1
- package/dist/advanced.mjs +588 -15069
- package/dist/advanced.mjs.map +1 -1
- package/dist/components/embed/KitLayout.d.ts +22 -0
- package/dist/components/embed/UndoRedoControls.d.ts +3 -0
- package/dist/compose-Dqh2f8tS.js +22222 -0
- package/dist/compose-Dqh2f8tS.js.map +1 -0
- package/dist/compose-HDJp4Z_d.cjs +60 -0
- package/dist/compose-HDJp4Z_d.cjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +600 -516
- package/dist/index.mjs.map +1 -1
- package/dist/internals.js +1 -1
- package/dist/internals.js.map +1 -1
- package/dist/internals.mjs +101 -102
- package/dist/internals.mjs.map +1 -1
- package/dist/style.css.d.ts +4 -0
- package/dist/testing.js +1 -1
- package/dist/testing.mjs +11 -11
- package/package.json +8 -4
- package/dist/ElementFactory-Ckv6sSev.js.map +0 -1
- package/dist/ElementFactory-DEjwp-Wg.cjs.map +0 -1
- package/dist/ImportManager-64OYjELO.js +0 -222
- package/dist/ImportManager-64OYjELO.js.map +0 -1
- package/dist/ImportManager-wSzrR-5a.cjs +0 -2
- package/dist/ImportManager-wSzrR-5a.cjs.map +0 -1
- package/dist/ThemeContext-4mJ_y0Me.cjs +0 -2
- package/dist/ThemeContext-H0Z-MqqR.js +0 -1077
- package/dist/compose-DHBRwi_A.cjs +0 -33
- package/dist/compose-DHBRwi_A.cjs.map +0 -1
- package/dist/compose-DIPiisIw.js +0 -7690
- package/dist/compose-DIPiisIw.js.map +0 -1
package/dist/advanced.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"advanced.mjs","sources":["../src/kits/sections.ts","../src/kits/serialization.ts","../../../node_modules/.pnpm/@dnd-kit+utilities@3.2.2_react@18.3.1/node_modules/@dnd-kit/utilities/dist/utilities.esm.js","../../../node_modules/.pnpm/@dnd-kit+accessibility@3.1.1_react@18.3.1/node_modules/@dnd-kit/accessibility/dist/accessibility.esm.js","../../../node_modules/.pnpm/@dnd-kit+core@6.3.1_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js","../../../node_modules/.pnpm/@dnd-kit+sortable@10.0.0_@dnd-kit+core@6.3.1_react-dom@18.3.1_react@18.3.1__react@18.3.1__react@18.3.1/node_modules/@dnd-kit/sortable/dist/sortable.esm.js","../src/hooks/useLayerDndKit.ts","../src/lib/utils.ts","../src/components/ui/normalized-icon.tsx","../src/components/ui/toolbar-button.tsx","../src/components/ui/custom-icons.tsx","../src/components/ui/icons.ts","../src/components/ui/collapsed-toolbar-header.tsx","../src/components/ui/SliderRow.tsx","../src/components/ui/PresetCarousel.tsx","../src/components/embed/LayersPanel.tsx","../src/components/Drawer.tsx","../../../node_modules/.pnpm/react-colorful@5.7.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/react-colorful/dist/index.mjs","../src/components/ColorPickerDropdown.tsx","../src/components/StrokePanel.tsx","../src/components/MaskItem.tsx","../src/components/MasksPanel.tsx","../src/effects/distress-presets.ts","../src/components/DistressPanel.tsx","../src/rendering/knockout-utils.ts","../src/components/CompositingPanel.tsx","../src/components/GlyphPicker.tsx","../src/components/OpenTypeFeaturesPanel.tsx","../src/components/EffectsPanel.tsx","../src/components/embed/EffectsPanel.tsx","../src/components/embed/ExportPanel.tsx","../src/services/nounProjectApi.ts","../src/services/recraftApi.ts","../src/services/falApi.ts","../src/services/runwareApi.ts","../src/components/ImageBrowserDrawer.tsx","../src/components/embed/ImagePanel.tsx","../src/components/GlyphBrowserDrawer.tsx","../src/components/embed/GlyphPanel.tsx","../src/components/embed/ArtboardTabs.tsx","../src/components/BackButton.tsx","../src/utils/featureApplied.ts","../src/components/ImageToolbar.tsx","../src/presets/artboard-color-presets.ts","../src/components/ShapeToolbar.tsx","../src/components/ShapeTypeDrawer.tsx","../src/components/PathToolbar.tsx","../src/components/BackgroundPickerDropdown.tsx","../src/components/ArtboardDistressPanel.tsx","../src/components/ArtboardImageMaskPanel.tsx","../src/components/ArtboardPropertiesToolbar.tsx","../src/utils/GoogleFontsService.ts","../src/utils/MonotypeCategoryMapping.ts","../src/utils/MonotypeService.ts","../src/utils/UnifiedFontService.ts","../src/utils/textUtils.ts","../src/components/FontBrowserDrawer.tsx","../src/components/TransformControlPanel.tsx","../src/components/TextEffectsDropdown.tsx","../src/components/MoreMenu.tsx","../src/components/text-toolbar/FontColorButton.tsx","../src/components/text-toolbar/BoldButton.tsx","../src/components/text-toolbar/ItalicButton.tsx","../src/components/text-toolbar/UnderlineButton.tsx","../src/components/text-toolbar/UppercaseButton.tsx","../src/components/text-toolbar/TextAlignButton.tsx","../src/components/text-toolbar/TextMoreMenu.tsx","../src/components/TextToolbar.tsx","../src/core/TransformConverter.ts","../src/hooks/useTextToolbar.ts","../src/hooks/useLayerPreview.ts","../src/components/LayerLeadingChip.tsx","../src/components/toolbars/GroupElementToolbar.tsx","../src/components/CropPanel.tsx","../src/components/toolbars/SecondaryPanels.tsx","../src/components/toolbars/ExpandedPanelIcon.tsx","../src/components/toolbars/shared/SecondaryPanelWrapper.tsx","../src/components/toolbars/shared/ColorPanelWrapper.tsx","../src/components/toolbars/EmbeddedToolbarLayout.tsx","../src/components/toolbars/FloatingPanels.tsx","../src/utils/documentColors.ts","../src/components/ContextualToolbars.tsx","../src/components/primitives/Dropdown.tsx","../src/components/primitives/DropdownMenu.tsx","../src/components/primitives/MenuItem.tsx","../src/components/primitives/Panel.tsx","../src/components/primitives/ControlGroup.tsx","../src/components/primitives/ButtonGroup.tsx","../src/components/primitives/Toggle.tsx","../src/components/primitives/Switch.tsx","../src/components/primitives/SecondaryToolbar.tsx","../src/components/embed/MenuButton.tsx","../src/components/embed/ZoomControls.tsx","../src/hooks/useProjectLoader.ts","../src/hooks/useBreakpoint.ts","../src/hooks/usePerformance.ts","../src/hooks/useElementById.ts","../src/hooks/useLayerDragDrop.ts","../src/hooks/useLayerSelection.ts","../src/components/FontSizeDropdown.tsx","../src/components/text-toolbar/FontSizeGroup.tsx","../src/plugins/ElementTypePlugin.ts","../src/core/EventBus.ts","../src/hooks/useCanvasEvents.ts","../src/components/VisualGuideOverlay.tsx","../src/api/advanced.ts"],"sourcesContent":["/**\n * Section Registry\n *\n * A registry for mapping section IDs (used in kit layout slots) to their\n * React component implementations and metadata. Sections are the building\n * blocks of the editor layout — each slot in a kit's layout references\n * section IDs that are resolved to components at render time.\n *\n * Built-in sections (layers-panel, effects-panel, etc.) are registered\n * by calling `registerBuiltinSections()` during editor initialization.\n * Custom sections can be registered by consumers for custom editor layouts.\n *\n * @example Register a custom section\n * ```ts\n * import { registerSection } from '@snowcone-app/canvas/advanced';\n *\n * registerSection('my-custom-panel', {\n * component: MyCustomPanel,\n * label: 'Custom Panel',\n * position: 'right',\n * });\n * ```\n *\n * @example Look up a registered section\n * ```ts\n * import { getSection } from '@snowcone-app/canvas/advanced';\n *\n * const section = getSection('layers-panel');\n * if (section) {\n * const Component = section.component;\n * return <Component />;\n * }\n * ```\n */\n\nimport type React from 'react';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Configuration for a registered section.\n *\n * Each section maps a string ID to a React component, a display label,\n * and the layout position where it is typically rendered.\n */\n/**\n * Type alias for section components in the registry.\n *\n * Section components read their state from context providers,\n * so they can be rendered with no props: `<Component />`.\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type -- Section components read state from context; consumers render them with no props via <Component />\nexport type SectionComponent = React.ComponentType<{}>;\n\nexport interface SectionConfig {\n /**\n * The React component to render for this section.\n *\n * Section components read their state from EditorContext and other context\n * providers, so they are rendered with no explicit props: `<Component />`.\n *\n * If registering a component that has required props (e.g. for direct use),\n * cast it: `component: MyPanel as SectionComponent`.\n */\n component: SectionComponent;\n /** Human-readable label for UI display (e.g., panel headers, settings) */\n label: string;\n /** Optional icon identifier (e.g., an Iconify icon string) */\n icon?: string;\n /** The layout position where this section is typically placed */\n position: 'topbar' | 'left' | 'canvas' | 'right' | 'bottombar';\n}\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\n/** Internal registry map — section ID to config */\nconst sectionRegistry = new Map<string, SectionConfig>();\n\n/**\n * Register a section in the global section registry.\n *\n * If a section with the same ID is already registered, it will be\n * silently overwritten. This allows consumers to replace built-in\n * sections with custom implementations.\n *\n * @param id - Unique section identifier (e.g., 'layers-panel')\n * @param config - Section configuration including component, label, and position\n */\nexport function registerSection(id: string, config: SectionConfig): void {\n sectionRegistry.set(id, config);\n}\n\n/**\n * Retrieve a registered section by ID.\n *\n * @param id - The section identifier to look up\n * @returns The section config if found, or undefined\n */\nexport function getSection(id: string): SectionConfig | undefined {\n return sectionRegistry.get(id);\n}\n\n/**\n * Get all registered section IDs.\n *\n * @returns An array of all registered section ID strings\n */\nexport function getSectionIds(): string[] {\n return Array.from(sectionRegistry.keys());\n}\n\n/**\n * Get all registered sections as `[id, config]` pairs.\n *\n * Useful for iterating over the full registry to build dynamic layouts,\n * settings UIs, or debug views.\n *\n * @returns An array of `[sectionId, SectionConfig]` tuples\n *\n * @example List all registered sections\n * ```ts\n * for (const [id, config] of getAllSections()) {\n * console.log(`${id}: ${config.label} (${config.position})`);\n * }\n * ```\n */\nexport function getAllSections(): Array<[string, SectionConfig]> {\n return Array.from(sectionRegistry.entries());\n}\n\n/**\n * Remove a section from the registry.\n *\n * @param id - The section identifier to unregister\n */\nexport function unregisterSection(id: string): void {\n sectionRegistry.delete(id);\n}\n\n// ---------------------------------------------------------------------------\n// Built-in Section Registration\n// ---------------------------------------------------------------------------\n\n/** Whether built-in sections have been registered */\nlet builtinsRegistered = false;\n\n/**\n * Register all built-in sections from the editor's component library.\n *\n * This function lazily imports the component modules to avoid circular\n * dependencies and is idempotent — calling it multiple times has no\n * additional effect after the first call.\n *\n * Built-in sections registered:\n * - `layers-panel` — LayersPanel (left)\n * - `effects-panel` — EffectsPanel (right)\n * - `export-panel` — ExportPanel (right)\n * - `images-panel` — ImagePanel (right)\n * - `glyph-panel` — GlyphPanel (right)\n * - `artboard-tabs` — ArtboardTabs (topbar)\n * - `contextual-toolbar` — ContextualToolbars (topbar)\n * - `zoom-controls` — ZoomControls (bottombar)\n * - `menu-button` — MenuButton (topbar)\n * - `crop-panel` — CropPanel (right)\n */\nexport async function registerBuiltinSections(): Promise<void> {\n if (builtinsRegistered) return;\n builtinsRegistered = true;\n\n const [\n { LayersPanel },\n { EffectsPanel },\n { ExportPanel },\n { ImagePanel },\n { GlyphPanel },\n { ArtboardTabs },\n { ContextualToolbars },\n { ZoomControls },\n { MenuButton },\n { CropPanel },\n ] = await Promise.all([\n import('../components/embed/LayersPanel.js'),\n import('../components/embed/EffectsPanel.js'),\n import('../components/embed/ExportPanel.js'),\n import('../components/embed/ImagePanel.js'),\n import('../components/embed/GlyphPanel.js'),\n import('../components/embed/ArtboardTabs.js'),\n import('../components/ContextualToolbars.js'),\n import('../components/embed/ZoomControls.js'),\n import('../components/embed/MenuButton.js'),\n import('../components/CropPanel.js'),\n ]);\n\n registerSection('layers-panel', {\n component: LayersPanel,\n label: 'Layers',\n icon: 'gravity-ui:layers',\n position: 'left',\n });\n\n registerSection('effects-panel', {\n component: EffectsPanel as SectionComponent,\n label: 'Effects',\n icon: 'gravity-ui:sparkles',\n position: 'right',\n });\n\n registerSection('export-panel', {\n component: ExportPanel,\n label: 'Export',\n icon: 'gravity-ui:arrow-down-to-square',\n position: 'right',\n });\n\n registerSection('images-panel', {\n component: ImagePanel as SectionComponent,\n label: 'Images',\n icon: 'gravity-ui:picture',\n position: 'right',\n });\n\n registerSection('glyph-panel', {\n component: GlyphPanel as SectionComponent,\n label: 'Glyphs',\n icon: 'gravity-ui:text',\n position: 'right',\n });\n\n registerSection('artboard-tabs', {\n component: ArtboardTabs,\n label: 'Artboards',\n icon: 'gravity-ui:copy',\n position: 'topbar',\n });\n\n registerSection('contextual-toolbar', {\n component: ContextualToolbars,\n label: 'Contextual Toolbar',\n position: 'topbar',\n });\n\n registerSection('zoom-controls', {\n component: ZoomControls,\n label: 'Zoom',\n icon: 'gravity-ui:magnifier',\n position: 'bottombar',\n });\n\n registerSection('menu-button', {\n component: MenuButton,\n label: 'Menu',\n icon: 'gravity-ui:bars',\n position: 'topbar',\n });\n\n registerSection('crop-panel', {\n component: CropPanel as SectionComponent,\n label: 'Crop',\n icon: 'gravity-ui:scissors',\n position: 'right',\n });\n}\n\n/**\n * Synchronously register built-in sections using direct component references.\n *\n * Unlike `registerBuiltinSections()` which uses lazy imports, this function\n * requires that components be passed in directly. Use this when you have\n * already imported the components and want to avoid async registration.\n *\n * @param components - Object mapping section IDs to their component references\n */\nexport function registerBuiltinSectionsSync(components: {\n LayersPanel: SectionComponent;\n EffectsPanel: SectionComponent;\n ExportPanel: SectionComponent;\n ImagePanel: SectionComponent;\n GlyphPanel: SectionComponent;\n ArtboardTabs: SectionComponent;\n ContextualToolbars: SectionComponent;\n ZoomControls: SectionComponent;\n MenuButton: SectionComponent;\n CropPanel: SectionComponent;\n}): void {\n if (builtinsRegistered) return;\n builtinsRegistered = true;\n\n registerSection('layers-panel', {\n component: components.LayersPanel,\n label: 'Layers',\n icon: 'gravity-ui:layers',\n position: 'left',\n });\n\n registerSection('effects-panel', {\n component: components.EffectsPanel,\n label: 'Effects',\n icon: 'gravity-ui:sparkles',\n position: 'right',\n });\n\n registerSection('export-panel', {\n component: components.ExportPanel,\n label: 'Export',\n icon: 'gravity-ui:arrow-down-to-square',\n position: 'right',\n });\n\n registerSection('images-panel', {\n component: components.ImagePanel,\n label: 'Images',\n icon: 'gravity-ui:picture',\n position: 'right',\n });\n\n registerSection('glyph-panel', {\n component: components.GlyphPanel,\n label: 'Glyphs',\n icon: 'gravity-ui:text',\n position: 'right',\n });\n\n registerSection('artboard-tabs', {\n component: components.ArtboardTabs,\n label: 'Artboards',\n icon: 'gravity-ui:copy',\n position: 'topbar',\n });\n\n registerSection('contextual-toolbar', {\n component: components.ContextualToolbars,\n label: 'Contextual Toolbar',\n position: 'topbar',\n });\n\n registerSection('zoom-controls', {\n component: components.ZoomControls,\n label: 'Zoom',\n icon: 'gravity-ui:magnifier',\n position: 'bottombar',\n });\n\n registerSection('menu-button', {\n component: components.MenuButton,\n label: 'Menu',\n icon: 'gravity-ui:bars',\n position: 'topbar',\n });\n\n registerSection('crop-panel', {\n component: components.CropPanel,\n label: 'Crop',\n icon: 'gravity-ui:scissors',\n position: 'right',\n });\n}\n","/**\n * Kit Serialization - JSON import/export for kit definitions\n *\n * Provides functions to serialize a KitDefinition to a JSON-safe format\n * and to load a KitDefinition from JSON. Supports extending base presets\n * via the `extends` field, making it easy to persist and share kit\n * configurations.\n *\n * @example Serialize a kit to JSON\n * ```ts\n * import { serializeKit, COMPACT_CUSTOMIZER } from '@snowcone-app/canvas';\n *\n * const json = serializeKit(COMPACT_CUSTOMIZER);\n * const stored = JSON.stringify(json);\n * ```\n *\n * @example Load a kit from JSON\n * ```ts\n * import { loadKitFromJSON } from '@snowcone-app/canvas';\n *\n * const kit = loadKitFromJSON({\n * name: 'my-custom-kit',\n * extends: 'compact-customizer',\n * capabilities: { effects: ['stroke', 'mask'] },\n * behavior: { autoExport: true },\n * });\n * ```\n */\n\nimport type { EditorCapabilities } from '../types/capabilities.js';\nimport type { KitDefinition, KitPresetId } from './types.js';\nimport { extendKit, createKit } from './compose.js';\nimport { resolveKit } from './registry.js';\nimport { validateKit } from './validation.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * JSON-safe representation of a KitDefinition.\n *\n * When `extends` is provided, the kit is built by resolving the base\n * preset and applying the remaining fields as overrides. When `extends`\n * is omitted, a new kit is created from scratch using `createKit`.\n */\nexport interface KitJSON {\n /** Kit name (required) */\n name: string;\n /** Optional base preset to extend from */\n extends?: KitPresetId;\n /** Partial capability overrides */\n capabilities?: Partial<EditorCapabilities>;\n /** Partial behavior overrides */\n behavior?: Partial<KitDefinition['behavior']>;\n /** Partial layout overrides */\n layout?: Partial<KitDefinition['layout']>;\n /** Partial style overrides */\n style?: Partial<KitDefinition['style']>;\n /** Content configuration */\n content?: KitDefinition['content'];\n}\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a KitDefinition to a JSON-safe format.\n *\n * The resulting object can be safely passed to `JSON.stringify()` and\n * later restored with `loadKitFromJSON()`. All fields from the kit\n * are included in the output for a complete, self-contained representation.\n *\n * @param kit - The KitDefinition to serialize\n * @returns A JSON-safe KitJSON object\n *\n * @example\n * ```ts\n * const json = serializeKit(myKit);\n * localStorage.setItem('kit', JSON.stringify(json));\n * ```\n */\nexport function serializeKit(kit: KitDefinition): KitJSON {\n const json: KitJSON = {\n name: kit.name,\n capabilities: {\n elements: [...kit.capabilities.elements],\n transforms: [...kit.capabilities.transforms],\n effects: [...kit.capabilities.effects],\n panels: [...kit.capabilities.panels],\n tools: [...kit.capabilities.tools],\n features: { ...kit.capabilities.features },\n },\n behavior: { ...kit.behavior },\n layout: {\n slots: {\n ...(kit.layout.slots.topbar && { topbar: [...kit.layout.slots.topbar] }),\n ...(kit.layout.slots.left && { left: [...kit.layout.slots.left] }),\n ...(kit.layout.slots.canvas && { canvas: [...kit.layout.slots.canvas] }),\n ...(kit.layout.slots.right && { right: [...kit.layout.slots.right] }),\n ...(kit.layout.slots.bottombar && { bottombar: [...kit.layout.slots.bottombar] }),\n },\n },\n style: { ...kit.style },\n };\n\n if (kit.content) {\n json.content = { ...kit.content };\n }\n\n return json;\n}\n\n// ---------------------------------------------------------------------------\n// Deserialization\n// ---------------------------------------------------------------------------\n\n/**\n * Load a KitDefinition from a JSON representation.\n *\n * If `extends` is provided, the corresponding preset is resolved and the\n * remaining fields are applied as overrides via `extendKit`. If `extends`\n * is omitted, a new kit is created from scratch via `createKit`.\n *\n * The result is validated with `validateKit`. If validation produces\n * errors (fatal issues), an error is thrown. Warnings are logged to\n * the console but do not prevent loading.\n *\n * @param json - The KitJSON object to deserialize\n * @returns A complete, validated KitDefinition\n * @throws {Error} If the kit name is missing\n * @throws {Error} If a preset ID in `extends` is invalid\n * @throws {Error} If the resulting kit fails validation (has errors)\n *\n * @example Extend a preset\n * ```ts\n * const kit = loadKitFromJSON({\n * name: 'my-pro-variant',\n * extends: 'pro-studio',\n * behavior: { autoExport: true },\n * });\n * ```\n *\n * @example Create from scratch\n * ```ts\n * const kit = loadKitFromJSON({\n * name: 'minimal-editor',\n * capabilities: { elements: ['text'] },\n * behavior: { toolbar: 'none', selection: 'single', panelMode: 'inline', onEmptyClick: 'noop', autoExport: false },\n * });\n * ```\n */\nexport function loadKitFromJSON(json: KitJSON): KitDefinition {\n if (!json.name || json.name.trim() === '') {\n throw new Error('[loadKitFromJSON] Kit name is required');\n }\n\n // Build overrides object from the JSON fields (excluding name and extends)\n const overrides: Record<string, unknown> = {};\n if (json.capabilities) overrides.capabilities = json.capabilities;\n if (json.behavior) overrides.behavior = json.behavior;\n if (json.layout) overrides.layout = json.layout;\n if (json.style) overrides.style = json.style;\n if (json.content) overrides.content = json.content;\n\n let kit: KitDefinition;\n\n if (json.extends) {\n // Resolve the base preset and apply overrides\n const base = resolveKit(json.extends);\n kit = extendKit(base, { name: json.name, ...overrides });\n } else {\n // Create from scratch with defaults\n kit = createKit({ name: json.name, ...overrides });\n }\n\n // Validate the result\n const validation = validateKit(kit);\n\n if (validation.warnings.length > 0) {\n for (const warning of validation.warnings) {\n console.warn(`[loadKitFromJSON] Warning: ${warning}`);\n }\n }\n\n if (!validation.valid) {\n throw new Error(\n `[loadKitFromJSON] Kit \"${json.name}\" failed validation:\\n${validation.errors.join('\\n')}`\n );\n }\n\n return kit;\n}\n","import { useMemo, useLayoutEffect, useEffect, useRef, useCallback } from 'react';\n\nfunction useCombinedRefs() {\n for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) {\n refs[_key] = arguments[_key];\n }\n\n return useMemo(() => node => {\n refs.forEach(ref => ref(node));\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n refs);\n}\n\n// https://github.com/facebook/react/blob/master/packages/shared/ExecutionEnvironment.js\nconst canUseDOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';\n\nfunction isWindow(element) {\n const elementString = Object.prototype.toString.call(element);\n return elementString === '[object Window]' || // In Electron context the Window object serializes to [object global]\n elementString === '[object global]';\n}\n\nfunction isNode(node) {\n return 'nodeType' in node;\n}\n\nfunction getWindow(target) {\n var _target$ownerDocument, _target$ownerDocument2;\n\n if (!target) {\n return window;\n }\n\n if (isWindow(target)) {\n return target;\n }\n\n if (!isNode(target)) {\n return window;\n }\n\n return (_target$ownerDocument = (_target$ownerDocument2 = target.ownerDocument) == null ? void 0 : _target$ownerDocument2.defaultView) != null ? _target$ownerDocument : window;\n}\n\nfunction isDocument(node) {\n const {\n Document\n } = getWindow(node);\n return node instanceof Document;\n}\n\nfunction isHTMLElement(node) {\n if (isWindow(node)) {\n return false;\n }\n\n return node instanceof getWindow(node).HTMLElement;\n}\n\nfunction isSVGElement(node) {\n return node instanceof getWindow(node).SVGElement;\n}\n\nfunction getOwnerDocument(target) {\n if (!target) {\n return document;\n }\n\n if (isWindow(target)) {\n return target.document;\n }\n\n if (!isNode(target)) {\n return document;\n }\n\n if (isDocument(target)) {\n return target;\n }\n\n if (isHTMLElement(target) || isSVGElement(target)) {\n return target.ownerDocument;\n }\n\n return document;\n}\n\n/**\r\n * A hook that resolves to useEffect on the server and useLayoutEffect on the client\r\n * @param callback {function} Callback function that is invoked when the dependencies of the hook change\r\n */\n\nconst useIsomorphicLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;\n\nfunction useEvent(handler) {\n const handlerRef = useRef(handler);\n useIsomorphicLayoutEffect(() => {\n handlerRef.current = handler;\n });\n return useCallback(function () {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return handlerRef.current == null ? void 0 : handlerRef.current(...args);\n }, []);\n}\n\nfunction useInterval() {\n const intervalRef = useRef(null);\n const set = useCallback((listener, duration) => {\n intervalRef.current = setInterval(listener, duration);\n }, []);\n const clear = useCallback(() => {\n if (intervalRef.current !== null) {\n clearInterval(intervalRef.current);\n intervalRef.current = null;\n }\n }, []);\n return [set, clear];\n}\n\nfunction useLatestValue(value, dependencies) {\n if (dependencies === void 0) {\n dependencies = [value];\n }\n\n const valueRef = useRef(value);\n useIsomorphicLayoutEffect(() => {\n if (valueRef.current !== value) {\n valueRef.current = value;\n }\n }, dependencies);\n return valueRef;\n}\n\nfunction useLazyMemo(callback, dependencies) {\n const valueRef = useRef();\n return useMemo(() => {\n const newValue = callback(valueRef.current);\n valueRef.current = newValue;\n return newValue;\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [...dependencies]);\n}\n\nfunction useNodeRef(onChange) {\n const onChangeHandler = useEvent(onChange);\n const node = useRef(null);\n const setNodeRef = useCallback(element => {\n if (element !== node.current) {\n onChangeHandler == null ? void 0 : onChangeHandler(element, node.current);\n }\n\n node.current = element;\n }, //eslint-disable-next-line\n []);\n return [node, setNodeRef];\n}\n\nfunction usePrevious(value) {\n const ref = useRef();\n useEffect(() => {\n ref.current = value;\n }, [value]);\n return ref.current;\n}\n\nlet ids = {};\nfunction useUniqueId(prefix, value) {\n return useMemo(() => {\n if (value) {\n return value;\n }\n\n const id = ids[prefix] == null ? 0 : ids[prefix] + 1;\n ids[prefix] = id;\n return prefix + \"-\" + id;\n }, [prefix, value]);\n}\n\nfunction createAdjustmentFn(modifier) {\n return function (object) {\n for (var _len = arguments.length, adjustments = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n adjustments[_key - 1] = arguments[_key];\n }\n\n return adjustments.reduce((accumulator, adjustment) => {\n const entries = Object.entries(adjustment);\n\n for (const [key, valueAdjustment] of entries) {\n const value = accumulator[key];\n\n if (value != null) {\n accumulator[key] = value + modifier * valueAdjustment;\n }\n }\n\n return accumulator;\n }, { ...object\n });\n };\n}\n\nconst add = /*#__PURE__*/createAdjustmentFn(1);\nconst subtract = /*#__PURE__*/createAdjustmentFn(-1);\n\nfunction hasViewportRelativeCoordinates(event) {\n return 'clientX' in event && 'clientY' in event;\n}\n\nfunction isKeyboardEvent(event) {\n if (!event) {\n return false;\n }\n\n const {\n KeyboardEvent\n } = getWindow(event.target);\n return KeyboardEvent && event instanceof KeyboardEvent;\n}\n\nfunction isTouchEvent(event) {\n if (!event) {\n return false;\n }\n\n const {\n TouchEvent\n } = getWindow(event.target);\n return TouchEvent && event instanceof TouchEvent;\n}\n\n/**\r\n * Returns the normalized x and y coordinates for mouse and touch events.\r\n */\n\nfunction getEventCoordinates(event) {\n if (isTouchEvent(event)) {\n if (event.touches && event.touches.length) {\n const {\n clientX: x,\n clientY: y\n } = event.touches[0];\n return {\n x,\n y\n };\n } else if (event.changedTouches && event.changedTouches.length) {\n const {\n clientX: x,\n clientY: y\n } = event.changedTouches[0];\n return {\n x,\n y\n };\n }\n }\n\n if (hasViewportRelativeCoordinates(event)) {\n return {\n x: event.clientX,\n y: event.clientY\n };\n }\n\n return null;\n}\n\nconst CSS = /*#__PURE__*/Object.freeze({\n Translate: {\n toString(transform) {\n if (!transform) {\n return;\n }\n\n const {\n x,\n y\n } = transform;\n return \"translate3d(\" + (x ? Math.round(x) : 0) + \"px, \" + (y ? Math.round(y) : 0) + \"px, 0)\";\n }\n\n },\n Scale: {\n toString(transform) {\n if (!transform) {\n return;\n }\n\n const {\n scaleX,\n scaleY\n } = transform;\n return \"scaleX(\" + scaleX + \") scaleY(\" + scaleY + \")\";\n }\n\n },\n Transform: {\n toString(transform) {\n if (!transform) {\n return;\n }\n\n return [CSS.Translate.toString(transform), CSS.Scale.toString(transform)].join(' ');\n }\n\n },\n Transition: {\n toString(_ref) {\n let {\n property,\n duration,\n easing\n } = _ref;\n return property + \" \" + duration + \"ms \" + easing;\n }\n\n }\n});\n\nconst SELECTOR = 'a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]';\nfunction findFirstFocusableNode(element) {\n if (element.matches(SELECTOR)) {\n return element;\n }\n\n return element.querySelector(SELECTOR);\n}\n\nexport { CSS, add, canUseDOM, findFirstFocusableNode, getEventCoordinates, getOwnerDocument, getWindow, hasViewportRelativeCoordinates, isDocument, isHTMLElement, isKeyboardEvent, isNode, isSVGElement, isTouchEvent, isWindow, subtract, useCombinedRefs, useEvent, useInterval, useIsomorphicLayoutEffect, useLatestValue, useLazyMemo, useNodeRef, usePrevious, useUniqueId };\n//# sourceMappingURL=utilities.esm.js.map\n","import React, { useState, useCallback } from 'react';\n\nconst hiddenStyles = {\n display: 'none'\n};\nfunction HiddenText(_ref) {\n let {\n id,\n value\n } = _ref;\n return React.createElement(\"div\", {\n id: id,\n style: hiddenStyles\n }, value);\n}\n\nfunction LiveRegion(_ref) {\n let {\n id,\n announcement,\n ariaLiveType = \"assertive\"\n } = _ref;\n // Hide element visually but keep it readable by screen readers\n const visuallyHidden = {\n position: 'fixed',\n top: 0,\n left: 0,\n width: 1,\n height: 1,\n margin: -1,\n border: 0,\n padding: 0,\n overflow: 'hidden',\n clip: 'rect(0 0 0 0)',\n clipPath: 'inset(100%)',\n whiteSpace: 'nowrap'\n };\n return React.createElement(\"div\", {\n id: id,\n style: visuallyHidden,\n role: \"status\",\n \"aria-live\": ariaLiveType,\n \"aria-atomic\": true\n }, announcement);\n}\n\nfunction useAnnouncement() {\n const [announcement, setAnnouncement] = useState('');\n const announce = useCallback(value => {\n if (value != null) {\n setAnnouncement(value);\n }\n }, []);\n return {\n announce,\n announcement\n };\n}\n\nexport { HiddenText, LiveRegion, useAnnouncement };\n//# sourceMappingURL=accessibility.esm.js.map\n","import React, { createContext, useContext, useEffect, useState, useCallback, useMemo, useRef, memo, useReducer, cloneElement, forwardRef } from 'react';\nimport { createPortal, unstable_batchedUpdates } from 'react-dom';\nimport { useUniqueId, getEventCoordinates, getWindow, isDocument, isHTMLElement, isSVGElement, canUseDOM, isWindow, isNode, getOwnerDocument, add, isKeyboardEvent, subtract, useLazyMemo, useInterval, usePrevious, useLatestValue, useEvent, useIsomorphicLayoutEffect, useNodeRef, findFirstFocusableNode, CSS } from '@dnd-kit/utilities';\nimport { useAnnouncement, HiddenText, LiveRegion } from '@dnd-kit/accessibility';\n\nconst DndMonitorContext = /*#__PURE__*/createContext(null);\n\nfunction useDndMonitor(listener) {\n const registerListener = useContext(DndMonitorContext);\n useEffect(() => {\n if (!registerListener) {\n throw new Error('useDndMonitor must be used within a children of <DndContext>');\n }\n\n const unsubscribe = registerListener(listener);\n return unsubscribe;\n }, [listener, registerListener]);\n}\n\nfunction useDndMonitorProvider() {\n const [listeners] = useState(() => new Set());\n const registerListener = useCallback(listener => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n }, [listeners]);\n const dispatch = useCallback(_ref => {\n let {\n type,\n event\n } = _ref;\n listeners.forEach(listener => {\n var _listener$type;\n\n return (_listener$type = listener[type]) == null ? void 0 : _listener$type.call(listener, event);\n });\n }, [listeners]);\n return [dispatch, registerListener];\n}\n\nconst defaultScreenReaderInstructions = {\n draggable: \"\\n To pick up a draggable item, press the space bar.\\n While dragging, use the arrow keys to move the item.\\n Press space again to drop the item in its new position, or press escape to cancel.\\n \"\n};\nconst defaultAnnouncements = {\n onDragStart(_ref) {\n let {\n active\n } = _ref;\n return \"Picked up draggable item \" + active.id + \".\";\n },\n\n onDragOver(_ref2) {\n let {\n active,\n over\n } = _ref2;\n\n if (over) {\n return \"Draggable item \" + active.id + \" was moved over droppable area \" + over.id + \".\";\n }\n\n return \"Draggable item \" + active.id + \" is no longer over a droppable area.\";\n },\n\n onDragEnd(_ref3) {\n let {\n active,\n over\n } = _ref3;\n\n if (over) {\n return \"Draggable item \" + active.id + \" was dropped over droppable area \" + over.id;\n }\n\n return \"Draggable item \" + active.id + \" was dropped.\";\n },\n\n onDragCancel(_ref4) {\n let {\n active\n } = _ref4;\n return \"Dragging was cancelled. Draggable item \" + active.id + \" was dropped.\";\n }\n\n};\n\nfunction Accessibility(_ref) {\n let {\n announcements = defaultAnnouncements,\n container,\n hiddenTextDescribedById,\n screenReaderInstructions = defaultScreenReaderInstructions\n } = _ref;\n const {\n announce,\n announcement\n } = useAnnouncement();\n const liveRegionId = useUniqueId(\"DndLiveRegion\");\n const [mounted, setMounted] = useState(false);\n useEffect(() => {\n setMounted(true);\n }, []);\n useDndMonitor(useMemo(() => ({\n onDragStart(_ref2) {\n let {\n active\n } = _ref2;\n announce(announcements.onDragStart({\n active\n }));\n },\n\n onDragMove(_ref3) {\n let {\n active,\n over\n } = _ref3;\n\n if (announcements.onDragMove) {\n announce(announcements.onDragMove({\n active,\n over\n }));\n }\n },\n\n onDragOver(_ref4) {\n let {\n active,\n over\n } = _ref4;\n announce(announcements.onDragOver({\n active,\n over\n }));\n },\n\n onDragEnd(_ref5) {\n let {\n active,\n over\n } = _ref5;\n announce(announcements.onDragEnd({\n active,\n over\n }));\n },\n\n onDragCancel(_ref6) {\n let {\n active,\n over\n } = _ref6;\n announce(announcements.onDragCancel({\n active,\n over\n }));\n }\n\n }), [announce, announcements]));\n\n if (!mounted) {\n return null;\n }\n\n const markup = React.createElement(React.Fragment, null, React.createElement(HiddenText, {\n id: hiddenTextDescribedById,\n value: screenReaderInstructions.draggable\n }), React.createElement(LiveRegion, {\n id: liveRegionId,\n announcement: announcement\n }));\n return container ? createPortal(markup, container) : markup;\n}\n\nvar Action;\n\n(function (Action) {\n Action[\"DragStart\"] = \"dragStart\";\n Action[\"DragMove\"] = \"dragMove\";\n Action[\"DragEnd\"] = \"dragEnd\";\n Action[\"DragCancel\"] = \"dragCancel\";\n Action[\"DragOver\"] = \"dragOver\";\n Action[\"RegisterDroppable\"] = \"registerDroppable\";\n Action[\"SetDroppableDisabled\"] = \"setDroppableDisabled\";\n Action[\"UnregisterDroppable\"] = \"unregisterDroppable\";\n})(Action || (Action = {}));\n\nfunction noop() {}\n\nfunction useSensor(sensor, options) {\n return useMemo(() => ({\n sensor,\n options: options != null ? options : {}\n }), // eslint-disable-next-line react-hooks/exhaustive-deps\n [sensor, options]);\n}\n\nfunction useSensors() {\n for (var _len = arguments.length, sensors = new Array(_len), _key = 0; _key < _len; _key++) {\n sensors[_key] = arguments[_key];\n }\n\n return useMemo(() => [...sensors].filter(sensor => sensor != null), // eslint-disable-next-line react-hooks/exhaustive-deps\n [...sensors]);\n}\n\nconst defaultCoordinates = /*#__PURE__*/Object.freeze({\n x: 0,\n y: 0\n});\n\n/**\r\n * Returns the distance between two points\r\n */\nfunction distanceBetween(p1, p2) {\n return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));\n}\n\nfunction getRelativeTransformOrigin(event, rect) {\n const eventCoordinates = getEventCoordinates(event);\n\n if (!eventCoordinates) {\n return '0 0';\n }\n\n const transformOrigin = {\n x: (eventCoordinates.x - rect.left) / rect.width * 100,\n y: (eventCoordinates.y - rect.top) / rect.height * 100\n };\n return transformOrigin.x + \"% \" + transformOrigin.y + \"%\";\n}\n\n/**\r\n * Sort collisions from smallest to greatest value\r\n */\nfunction sortCollisionsAsc(_ref, _ref2) {\n let {\n data: {\n value: a\n }\n } = _ref;\n let {\n data: {\n value: b\n }\n } = _ref2;\n return a - b;\n}\n/**\r\n * Sort collisions from greatest to smallest value\r\n */\n\nfunction sortCollisionsDesc(_ref3, _ref4) {\n let {\n data: {\n value: a\n }\n } = _ref3;\n let {\n data: {\n value: b\n }\n } = _ref4;\n return b - a;\n}\n/**\r\n * Returns the coordinates of the corners of a given rectangle:\r\n * [TopLeft {x, y}, TopRight {x, y}, BottomLeft {x, y}, BottomRight {x, y}]\r\n */\n\nfunction cornersOfRectangle(_ref5) {\n let {\n left,\n top,\n height,\n width\n } = _ref5;\n return [{\n x: left,\n y: top\n }, {\n x: left + width,\n y: top\n }, {\n x: left,\n y: top + height\n }, {\n x: left + width,\n y: top + height\n }];\n}\nfunction getFirstCollision(collisions, property) {\n if (!collisions || collisions.length === 0) {\n return null;\n }\n\n const [firstCollision] = collisions;\n return property ? firstCollision[property] : firstCollision;\n}\n\n/**\r\n * Returns the coordinates of the center of a given ClientRect\r\n */\n\nfunction centerOfRectangle(rect, left, top) {\n if (left === void 0) {\n left = rect.left;\n }\n\n if (top === void 0) {\n top = rect.top;\n }\n\n return {\n x: left + rect.width * 0.5,\n y: top + rect.height * 0.5\n };\n}\n/**\r\n * Returns the closest rectangles from an array of rectangles to the center of a given\r\n * rectangle.\r\n */\n\n\nconst closestCenter = _ref => {\n let {\n collisionRect,\n droppableRects,\n droppableContainers\n } = _ref;\n const centerRect = centerOfRectangle(collisionRect, collisionRect.left, collisionRect.top);\n const collisions = [];\n\n for (const droppableContainer of droppableContainers) {\n const {\n id\n } = droppableContainer;\n const rect = droppableRects.get(id);\n\n if (rect) {\n const distBetween = distanceBetween(centerOfRectangle(rect), centerRect);\n collisions.push({\n id,\n data: {\n droppableContainer,\n value: distBetween\n }\n });\n }\n }\n\n return collisions.sort(sortCollisionsAsc);\n};\n\n/**\r\n * Returns the closest rectangles from an array of rectangles to the corners of\r\n * another rectangle.\r\n */\n\nconst closestCorners = _ref => {\n let {\n collisionRect,\n droppableRects,\n droppableContainers\n } = _ref;\n const corners = cornersOfRectangle(collisionRect);\n const collisions = [];\n\n for (const droppableContainer of droppableContainers) {\n const {\n id\n } = droppableContainer;\n const rect = droppableRects.get(id);\n\n if (rect) {\n const rectCorners = cornersOfRectangle(rect);\n const distances = corners.reduce((accumulator, corner, index) => {\n return accumulator + distanceBetween(rectCorners[index], corner);\n }, 0);\n const effectiveDistance = Number((distances / 4).toFixed(4));\n collisions.push({\n id,\n data: {\n droppableContainer,\n value: effectiveDistance\n }\n });\n }\n }\n\n return collisions.sort(sortCollisionsAsc);\n};\n\n/**\r\n * Returns the intersecting rectangle area between two rectangles\r\n */\n\nfunction getIntersectionRatio(entry, target) {\n const top = Math.max(target.top, entry.top);\n const left = Math.max(target.left, entry.left);\n const right = Math.min(target.left + target.width, entry.left + entry.width);\n const bottom = Math.min(target.top + target.height, entry.top + entry.height);\n const width = right - left;\n const height = bottom - top;\n\n if (left < right && top < bottom) {\n const targetArea = target.width * target.height;\n const entryArea = entry.width * entry.height;\n const intersectionArea = width * height;\n const intersectionRatio = intersectionArea / (targetArea + entryArea - intersectionArea);\n return Number(intersectionRatio.toFixed(4));\n } // Rectangles do not overlap, or overlap has an area of zero (edge/corner overlap)\n\n\n return 0;\n}\n/**\r\n * Returns the rectangles that has the greatest intersection area with a given\r\n * rectangle in an array of rectangles.\r\n */\n\nconst rectIntersection = _ref => {\n let {\n collisionRect,\n droppableRects,\n droppableContainers\n } = _ref;\n const collisions = [];\n\n for (const droppableContainer of droppableContainers) {\n const {\n id\n } = droppableContainer;\n const rect = droppableRects.get(id);\n\n if (rect) {\n const intersectionRatio = getIntersectionRatio(rect, collisionRect);\n\n if (intersectionRatio > 0) {\n collisions.push({\n id,\n data: {\n droppableContainer,\n value: intersectionRatio\n }\n });\n }\n }\n }\n\n return collisions.sort(sortCollisionsDesc);\n};\n\n/**\r\n * Check if a given point is contained within a bounding rectangle\r\n */\n\nfunction isPointWithinRect(point, rect) {\n const {\n top,\n left,\n bottom,\n right\n } = rect;\n return top <= point.y && point.y <= bottom && left <= point.x && point.x <= right;\n}\n/**\r\n * Returns the rectangles that the pointer is hovering over\r\n */\n\n\nconst pointerWithin = _ref => {\n let {\n droppableContainers,\n droppableRects,\n pointerCoordinates\n } = _ref;\n\n if (!pointerCoordinates) {\n return [];\n }\n\n const collisions = [];\n\n for (const droppableContainer of droppableContainers) {\n const {\n id\n } = droppableContainer;\n const rect = droppableRects.get(id);\n\n if (rect && isPointWithinRect(pointerCoordinates, rect)) {\n /* There may be more than a single rectangle intersecting\r\n * with the pointer coordinates. In order to sort the\r\n * colliding rectangles, we measure the distance between\r\n * the pointer and the corners of the intersecting rectangle\r\n */\n const corners = cornersOfRectangle(rect);\n const distances = corners.reduce((accumulator, corner) => {\n return accumulator + distanceBetween(pointerCoordinates, corner);\n }, 0);\n const effectiveDistance = Number((distances / 4).toFixed(4));\n collisions.push({\n id,\n data: {\n droppableContainer,\n value: effectiveDistance\n }\n });\n }\n }\n\n return collisions.sort(sortCollisionsAsc);\n};\n\nfunction adjustScale(transform, rect1, rect2) {\n return { ...transform,\n scaleX: rect1 && rect2 ? rect1.width / rect2.width : 1,\n scaleY: rect1 && rect2 ? rect1.height / rect2.height : 1\n };\n}\n\nfunction getRectDelta(rect1, rect2) {\n return rect1 && rect2 ? {\n x: rect1.left - rect2.left,\n y: rect1.top - rect2.top\n } : defaultCoordinates;\n}\n\nfunction createRectAdjustmentFn(modifier) {\n return function adjustClientRect(rect) {\n for (var _len = arguments.length, adjustments = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n adjustments[_key - 1] = arguments[_key];\n }\n\n return adjustments.reduce((acc, adjustment) => ({ ...acc,\n top: acc.top + modifier * adjustment.y,\n bottom: acc.bottom + modifier * adjustment.y,\n left: acc.left + modifier * adjustment.x,\n right: acc.right + modifier * adjustment.x\n }), { ...rect\n });\n };\n}\nconst getAdjustedRect = /*#__PURE__*/createRectAdjustmentFn(1);\n\nfunction parseTransform(transform) {\n if (transform.startsWith('matrix3d(')) {\n const transformArray = transform.slice(9, -1).split(/, /);\n return {\n x: +transformArray[12],\n y: +transformArray[13],\n scaleX: +transformArray[0],\n scaleY: +transformArray[5]\n };\n } else if (transform.startsWith('matrix(')) {\n const transformArray = transform.slice(7, -1).split(/, /);\n return {\n x: +transformArray[4],\n y: +transformArray[5],\n scaleX: +transformArray[0],\n scaleY: +transformArray[3]\n };\n }\n\n return null;\n}\n\nfunction inverseTransform(rect, transform, transformOrigin) {\n const parsedTransform = parseTransform(transform);\n\n if (!parsedTransform) {\n return rect;\n }\n\n const {\n scaleX,\n scaleY,\n x: translateX,\n y: translateY\n } = parsedTransform;\n const x = rect.left - translateX - (1 - scaleX) * parseFloat(transformOrigin);\n const y = rect.top - translateY - (1 - scaleY) * parseFloat(transformOrigin.slice(transformOrigin.indexOf(' ') + 1));\n const w = scaleX ? rect.width / scaleX : rect.width;\n const h = scaleY ? rect.height / scaleY : rect.height;\n return {\n width: w,\n height: h,\n top: y,\n right: x + w,\n bottom: y + h,\n left: x\n };\n}\n\nconst defaultOptions = {\n ignoreTransform: false\n};\n/**\r\n * Returns the bounding client rect of an element relative to the viewport.\r\n */\n\nfunction getClientRect(element, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n let rect = element.getBoundingClientRect();\n\n if (options.ignoreTransform) {\n const {\n transform,\n transformOrigin\n } = getWindow(element).getComputedStyle(element);\n\n if (transform) {\n rect = inverseTransform(rect, transform, transformOrigin);\n }\n }\n\n const {\n top,\n left,\n width,\n height,\n bottom,\n right\n } = rect;\n return {\n top,\n left,\n width,\n height,\n bottom,\n right\n };\n}\n/**\r\n * Returns the bounding client rect of an element relative to the viewport.\r\n *\r\n * @remarks\r\n * The ClientRect returned by this method does not take into account transforms\r\n * applied to the element it measures.\r\n *\r\n */\n\nfunction getTransformAgnosticClientRect(element) {\n return getClientRect(element, {\n ignoreTransform: true\n });\n}\n\nfunction getWindowClientRect(element) {\n const width = element.innerWidth;\n const height = element.innerHeight;\n return {\n top: 0,\n left: 0,\n right: width,\n bottom: height,\n width,\n height\n };\n}\n\nfunction isFixed(node, computedStyle) {\n if (computedStyle === void 0) {\n computedStyle = getWindow(node).getComputedStyle(node);\n }\n\n return computedStyle.position === 'fixed';\n}\n\nfunction isScrollable(element, computedStyle) {\n if (computedStyle === void 0) {\n computedStyle = getWindow(element).getComputedStyle(element);\n }\n\n const overflowRegex = /(auto|scroll|overlay)/;\n const properties = ['overflow', 'overflowX', 'overflowY'];\n return properties.some(property => {\n const value = computedStyle[property];\n return typeof value === 'string' ? overflowRegex.test(value) : false;\n });\n}\n\nfunction getScrollableAncestors(element, limit) {\n const scrollParents = [];\n\n function findScrollableAncestors(node) {\n if (limit != null && scrollParents.length >= limit) {\n return scrollParents;\n }\n\n if (!node) {\n return scrollParents;\n }\n\n if (isDocument(node) && node.scrollingElement != null && !scrollParents.includes(node.scrollingElement)) {\n scrollParents.push(node.scrollingElement);\n return scrollParents;\n }\n\n if (!isHTMLElement(node) || isSVGElement(node)) {\n return scrollParents;\n }\n\n if (scrollParents.includes(node)) {\n return scrollParents;\n }\n\n const computedStyle = getWindow(element).getComputedStyle(node);\n\n if (node !== element) {\n if (isScrollable(node, computedStyle)) {\n scrollParents.push(node);\n }\n }\n\n if (isFixed(node, computedStyle)) {\n return scrollParents;\n }\n\n return findScrollableAncestors(node.parentNode);\n }\n\n if (!element) {\n return scrollParents;\n }\n\n return findScrollableAncestors(element);\n}\nfunction getFirstScrollableAncestor(node) {\n const [firstScrollableAncestor] = getScrollableAncestors(node, 1);\n return firstScrollableAncestor != null ? firstScrollableAncestor : null;\n}\n\nfunction getScrollableElement(element) {\n if (!canUseDOM || !element) {\n return null;\n }\n\n if (isWindow(element)) {\n return element;\n }\n\n if (!isNode(element)) {\n return null;\n }\n\n if (isDocument(element) || element === getOwnerDocument(element).scrollingElement) {\n return window;\n }\n\n if (isHTMLElement(element)) {\n return element;\n }\n\n return null;\n}\n\nfunction getScrollXCoordinate(element) {\n if (isWindow(element)) {\n return element.scrollX;\n }\n\n return element.scrollLeft;\n}\nfunction getScrollYCoordinate(element) {\n if (isWindow(element)) {\n return element.scrollY;\n }\n\n return element.scrollTop;\n}\nfunction getScrollCoordinates(element) {\n return {\n x: getScrollXCoordinate(element),\n y: getScrollYCoordinate(element)\n };\n}\n\nvar Direction;\n\n(function (Direction) {\n Direction[Direction[\"Forward\"] = 1] = \"Forward\";\n Direction[Direction[\"Backward\"] = -1] = \"Backward\";\n})(Direction || (Direction = {}));\n\nfunction isDocumentScrollingElement(element) {\n if (!canUseDOM || !element) {\n return false;\n }\n\n return element === document.scrollingElement;\n}\n\nfunction getScrollPosition(scrollingContainer) {\n const minScroll = {\n x: 0,\n y: 0\n };\n const dimensions = isDocumentScrollingElement(scrollingContainer) ? {\n height: window.innerHeight,\n width: window.innerWidth\n } : {\n height: scrollingContainer.clientHeight,\n width: scrollingContainer.clientWidth\n };\n const maxScroll = {\n x: scrollingContainer.scrollWidth - dimensions.width,\n y: scrollingContainer.scrollHeight - dimensions.height\n };\n const isTop = scrollingContainer.scrollTop <= minScroll.y;\n const isLeft = scrollingContainer.scrollLeft <= minScroll.x;\n const isBottom = scrollingContainer.scrollTop >= maxScroll.y;\n const isRight = scrollingContainer.scrollLeft >= maxScroll.x;\n return {\n isTop,\n isLeft,\n isBottom,\n isRight,\n maxScroll,\n minScroll\n };\n}\n\nconst defaultThreshold = {\n x: 0.2,\n y: 0.2\n};\nfunction getScrollDirectionAndSpeed(scrollContainer, scrollContainerRect, _ref, acceleration, thresholdPercentage) {\n let {\n top,\n left,\n right,\n bottom\n } = _ref;\n\n if (acceleration === void 0) {\n acceleration = 10;\n }\n\n if (thresholdPercentage === void 0) {\n thresholdPercentage = defaultThreshold;\n }\n\n const {\n isTop,\n isBottom,\n isLeft,\n isRight\n } = getScrollPosition(scrollContainer);\n const direction = {\n x: 0,\n y: 0\n };\n const speed = {\n x: 0,\n y: 0\n };\n const threshold = {\n height: scrollContainerRect.height * thresholdPercentage.y,\n width: scrollContainerRect.width * thresholdPercentage.x\n };\n\n if (!isTop && top <= scrollContainerRect.top + threshold.height) {\n // Scroll Up\n direction.y = Direction.Backward;\n speed.y = acceleration * Math.abs((scrollContainerRect.top + threshold.height - top) / threshold.height);\n } else if (!isBottom && bottom >= scrollContainerRect.bottom - threshold.height) {\n // Scroll Down\n direction.y = Direction.Forward;\n speed.y = acceleration * Math.abs((scrollContainerRect.bottom - threshold.height - bottom) / threshold.height);\n }\n\n if (!isRight && right >= scrollContainerRect.right - threshold.width) {\n // Scroll Right\n direction.x = Direction.Forward;\n speed.x = acceleration * Math.abs((scrollContainerRect.right - threshold.width - right) / threshold.width);\n } else if (!isLeft && left <= scrollContainerRect.left + threshold.width) {\n // Scroll Left\n direction.x = Direction.Backward;\n speed.x = acceleration * Math.abs((scrollContainerRect.left + threshold.width - left) / threshold.width);\n }\n\n return {\n direction,\n speed\n };\n}\n\nfunction getScrollElementRect(element) {\n if (element === document.scrollingElement) {\n const {\n innerWidth,\n innerHeight\n } = window;\n return {\n top: 0,\n left: 0,\n right: innerWidth,\n bottom: innerHeight,\n width: innerWidth,\n height: innerHeight\n };\n }\n\n const {\n top,\n left,\n right,\n bottom\n } = element.getBoundingClientRect();\n return {\n top,\n left,\n right,\n bottom,\n width: element.clientWidth,\n height: element.clientHeight\n };\n}\n\nfunction getScrollOffsets(scrollableAncestors) {\n return scrollableAncestors.reduce((acc, node) => {\n return add(acc, getScrollCoordinates(node));\n }, defaultCoordinates);\n}\nfunction getScrollXOffset(scrollableAncestors) {\n return scrollableAncestors.reduce((acc, node) => {\n return acc + getScrollXCoordinate(node);\n }, 0);\n}\nfunction getScrollYOffset(scrollableAncestors) {\n return scrollableAncestors.reduce((acc, node) => {\n return acc + getScrollYCoordinate(node);\n }, 0);\n}\n\nfunction scrollIntoViewIfNeeded(element, measure) {\n if (measure === void 0) {\n measure = getClientRect;\n }\n\n if (!element) {\n return;\n }\n\n const {\n top,\n left,\n bottom,\n right\n } = measure(element);\n const firstScrollableAncestor = getFirstScrollableAncestor(element);\n\n if (!firstScrollableAncestor) {\n return;\n }\n\n if (bottom <= 0 || right <= 0 || top >= window.innerHeight || left >= window.innerWidth) {\n element.scrollIntoView({\n block: 'center',\n inline: 'center'\n });\n }\n}\n\nconst properties = [['x', ['left', 'right'], getScrollXOffset], ['y', ['top', 'bottom'], getScrollYOffset]];\nclass Rect {\n constructor(rect, element) {\n this.rect = void 0;\n this.width = void 0;\n this.height = void 0;\n this.top = void 0;\n this.bottom = void 0;\n this.right = void 0;\n this.left = void 0;\n const scrollableAncestors = getScrollableAncestors(element);\n const scrollOffsets = getScrollOffsets(scrollableAncestors);\n this.rect = { ...rect\n };\n this.width = rect.width;\n this.height = rect.height;\n\n for (const [axis, keys, getScrollOffset] of properties) {\n for (const key of keys) {\n Object.defineProperty(this, key, {\n get: () => {\n const currentOffsets = getScrollOffset(scrollableAncestors);\n const scrollOffsetsDeltla = scrollOffsets[axis] - currentOffsets;\n return this.rect[key] + scrollOffsetsDeltla;\n },\n enumerable: true\n });\n }\n }\n\n Object.defineProperty(this, 'rect', {\n enumerable: false\n });\n }\n\n}\n\nclass Listeners {\n constructor(target) {\n this.target = void 0;\n this.listeners = [];\n\n this.removeAll = () => {\n this.listeners.forEach(listener => {\n var _this$target;\n\n return (_this$target = this.target) == null ? void 0 : _this$target.removeEventListener(...listener);\n });\n };\n\n this.target = target;\n }\n\n add(eventName, handler, options) {\n var _this$target2;\n\n (_this$target2 = this.target) == null ? void 0 : _this$target2.addEventListener(eventName, handler, options);\n this.listeners.push([eventName, handler, options]);\n }\n\n}\n\nfunction getEventListenerTarget(target) {\n // If the `event.target` element is removed from the document events will still be targeted\n // at it, and hence won't always bubble up to the window or document anymore.\n // If there is any risk of an element being removed while it is being dragged,\n // the best practice is to attach the event listeners directly to the target.\n // https://developer.mozilla.org/en-US/docs/Web/API/EventTarget\n const {\n EventTarget\n } = getWindow(target);\n return target instanceof EventTarget ? target : getOwnerDocument(target);\n}\n\nfunction hasExceededDistance(delta, measurement) {\n const dx = Math.abs(delta.x);\n const dy = Math.abs(delta.y);\n\n if (typeof measurement === 'number') {\n return Math.sqrt(dx ** 2 + dy ** 2) > measurement;\n }\n\n if ('x' in measurement && 'y' in measurement) {\n return dx > measurement.x && dy > measurement.y;\n }\n\n if ('x' in measurement) {\n return dx > measurement.x;\n }\n\n if ('y' in measurement) {\n return dy > measurement.y;\n }\n\n return false;\n}\n\nvar EventName;\n\n(function (EventName) {\n EventName[\"Click\"] = \"click\";\n EventName[\"DragStart\"] = \"dragstart\";\n EventName[\"Keydown\"] = \"keydown\";\n EventName[\"ContextMenu\"] = \"contextmenu\";\n EventName[\"Resize\"] = \"resize\";\n EventName[\"SelectionChange\"] = \"selectionchange\";\n EventName[\"VisibilityChange\"] = \"visibilitychange\";\n})(EventName || (EventName = {}));\n\nfunction preventDefault(event) {\n event.preventDefault();\n}\nfunction stopPropagation(event) {\n event.stopPropagation();\n}\n\nvar KeyboardCode;\n\n(function (KeyboardCode) {\n KeyboardCode[\"Space\"] = \"Space\";\n KeyboardCode[\"Down\"] = \"ArrowDown\";\n KeyboardCode[\"Right\"] = \"ArrowRight\";\n KeyboardCode[\"Left\"] = \"ArrowLeft\";\n KeyboardCode[\"Up\"] = \"ArrowUp\";\n KeyboardCode[\"Esc\"] = \"Escape\";\n KeyboardCode[\"Enter\"] = \"Enter\";\n KeyboardCode[\"Tab\"] = \"Tab\";\n})(KeyboardCode || (KeyboardCode = {}));\n\nconst defaultKeyboardCodes = {\n start: [KeyboardCode.Space, KeyboardCode.Enter],\n cancel: [KeyboardCode.Esc],\n end: [KeyboardCode.Space, KeyboardCode.Enter, KeyboardCode.Tab]\n};\nconst defaultKeyboardCoordinateGetter = (event, _ref) => {\n let {\n currentCoordinates\n } = _ref;\n\n switch (event.code) {\n case KeyboardCode.Right:\n return { ...currentCoordinates,\n x: currentCoordinates.x + 25\n };\n\n case KeyboardCode.Left:\n return { ...currentCoordinates,\n x: currentCoordinates.x - 25\n };\n\n case KeyboardCode.Down:\n return { ...currentCoordinates,\n y: currentCoordinates.y + 25\n };\n\n case KeyboardCode.Up:\n return { ...currentCoordinates,\n y: currentCoordinates.y - 25\n };\n }\n\n return undefined;\n};\n\nclass KeyboardSensor {\n constructor(props) {\n this.props = void 0;\n this.autoScrollEnabled = false;\n this.referenceCoordinates = void 0;\n this.listeners = void 0;\n this.windowListeners = void 0;\n this.props = props;\n const {\n event: {\n target\n }\n } = props;\n this.props = props;\n this.listeners = new Listeners(getOwnerDocument(target));\n this.windowListeners = new Listeners(getWindow(target));\n this.handleKeyDown = this.handleKeyDown.bind(this);\n this.handleCancel = this.handleCancel.bind(this);\n this.attach();\n }\n\n attach() {\n this.handleStart();\n this.windowListeners.add(EventName.Resize, this.handleCancel);\n this.windowListeners.add(EventName.VisibilityChange, this.handleCancel);\n setTimeout(() => this.listeners.add(EventName.Keydown, this.handleKeyDown));\n }\n\n handleStart() {\n const {\n activeNode,\n onStart\n } = this.props;\n const node = activeNode.node.current;\n\n if (node) {\n scrollIntoViewIfNeeded(node);\n }\n\n onStart(defaultCoordinates);\n }\n\n handleKeyDown(event) {\n if (isKeyboardEvent(event)) {\n const {\n active,\n context,\n options\n } = this.props;\n const {\n keyboardCodes = defaultKeyboardCodes,\n coordinateGetter = defaultKeyboardCoordinateGetter,\n scrollBehavior = 'smooth'\n } = options;\n const {\n code\n } = event;\n\n if (keyboardCodes.end.includes(code)) {\n this.handleEnd(event);\n return;\n }\n\n if (keyboardCodes.cancel.includes(code)) {\n this.handleCancel(event);\n return;\n }\n\n const {\n collisionRect\n } = context.current;\n const currentCoordinates = collisionRect ? {\n x: collisionRect.left,\n y: collisionRect.top\n } : defaultCoordinates;\n\n if (!this.referenceCoordinates) {\n this.referenceCoordinates = currentCoordinates;\n }\n\n const newCoordinates = coordinateGetter(event, {\n active,\n context: context.current,\n currentCoordinates\n });\n\n if (newCoordinates) {\n const coordinatesDelta = subtract(newCoordinates, currentCoordinates);\n const scrollDelta = {\n x: 0,\n y: 0\n };\n const {\n scrollableAncestors\n } = context.current;\n\n for (const scrollContainer of scrollableAncestors) {\n const direction = event.code;\n const {\n isTop,\n isRight,\n isLeft,\n isBottom,\n maxScroll,\n minScroll\n } = getScrollPosition(scrollContainer);\n const scrollElementRect = getScrollElementRect(scrollContainer);\n const clampedCoordinates = {\n x: Math.min(direction === KeyboardCode.Right ? scrollElementRect.right - scrollElementRect.width / 2 : scrollElementRect.right, Math.max(direction === KeyboardCode.Right ? scrollElementRect.left : scrollElementRect.left + scrollElementRect.width / 2, newCoordinates.x)),\n y: Math.min(direction === KeyboardCode.Down ? scrollElementRect.bottom - scrollElementRect.height / 2 : scrollElementRect.bottom, Math.max(direction === KeyboardCode.Down ? scrollElementRect.top : scrollElementRect.top + scrollElementRect.height / 2, newCoordinates.y))\n };\n const canScrollX = direction === KeyboardCode.Right && !isRight || direction === KeyboardCode.Left && !isLeft;\n const canScrollY = direction === KeyboardCode.Down && !isBottom || direction === KeyboardCode.Up && !isTop;\n\n if (canScrollX && clampedCoordinates.x !== newCoordinates.x) {\n const newScrollCoordinates = scrollContainer.scrollLeft + coordinatesDelta.x;\n const canScrollToNewCoordinates = direction === KeyboardCode.Right && newScrollCoordinates <= maxScroll.x || direction === KeyboardCode.Left && newScrollCoordinates >= minScroll.x;\n\n if (canScrollToNewCoordinates && !coordinatesDelta.y) {\n // We don't need to update coordinates, the scroll adjustment alone will trigger\n // logic to auto-detect the new container we are over\n scrollContainer.scrollTo({\n left: newScrollCoordinates,\n behavior: scrollBehavior\n });\n return;\n }\n\n if (canScrollToNewCoordinates) {\n scrollDelta.x = scrollContainer.scrollLeft - newScrollCoordinates;\n } else {\n scrollDelta.x = direction === KeyboardCode.Right ? scrollContainer.scrollLeft - maxScroll.x : scrollContainer.scrollLeft - minScroll.x;\n }\n\n if (scrollDelta.x) {\n scrollContainer.scrollBy({\n left: -scrollDelta.x,\n behavior: scrollBehavior\n });\n }\n\n break;\n } else if (canScrollY && clampedCoordinates.y !== newCoordinates.y) {\n const newScrollCoordinates = scrollContainer.scrollTop + coordinatesDelta.y;\n const canScrollToNewCoordinates = direction === KeyboardCode.Down && newScrollCoordinates <= maxScroll.y || direction === KeyboardCode.Up && newScrollCoordinates >= minScroll.y;\n\n if (canScrollToNewCoordinates && !coordinatesDelta.x) {\n // We don't need to update coordinates, the scroll adjustment alone will trigger\n // logic to auto-detect the new container we are over\n scrollContainer.scrollTo({\n top: newScrollCoordinates,\n behavior: scrollBehavior\n });\n return;\n }\n\n if (canScrollToNewCoordinates) {\n scrollDelta.y = scrollContainer.scrollTop - newScrollCoordinates;\n } else {\n scrollDelta.y = direction === KeyboardCode.Down ? scrollContainer.scrollTop - maxScroll.y : scrollContainer.scrollTop - minScroll.y;\n }\n\n if (scrollDelta.y) {\n scrollContainer.scrollBy({\n top: -scrollDelta.y,\n behavior: scrollBehavior\n });\n }\n\n break;\n }\n }\n\n this.handleMove(event, add(subtract(newCoordinates, this.referenceCoordinates), scrollDelta));\n }\n }\n }\n\n handleMove(event, coordinates) {\n const {\n onMove\n } = this.props;\n event.preventDefault();\n onMove(coordinates);\n }\n\n handleEnd(event) {\n const {\n onEnd\n } = this.props;\n event.preventDefault();\n this.detach();\n onEnd();\n }\n\n handleCancel(event) {\n const {\n onCancel\n } = this.props;\n event.preventDefault();\n this.detach();\n onCancel();\n }\n\n detach() {\n this.listeners.removeAll();\n this.windowListeners.removeAll();\n }\n\n}\nKeyboardSensor.activators = [{\n eventName: 'onKeyDown',\n handler: (event, _ref, _ref2) => {\n let {\n keyboardCodes = defaultKeyboardCodes,\n onActivation\n } = _ref;\n let {\n active\n } = _ref2;\n const {\n code\n } = event.nativeEvent;\n\n if (keyboardCodes.start.includes(code)) {\n const activator = active.activatorNode.current;\n\n if (activator && event.target !== activator) {\n return false;\n }\n\n event.preventDefault();\n onActivation == null ? void 0 : onActivation({\n event: event.nativeEvent\n });\n return true;\n }\n\n return false;\n }\n}];\n\nfunction isDistanceConstraint(constraint) {\n return Boolean(constraint && 'distance' in constraint);\n}\n\nfunction isDelayConstraint(constraint) {\n return Boolean(constraint && 'delay' in constraint);\n}\n\nclass AbstractPointerSensor {\n constructor(props, events, listenerTarget) {\n var _getEventCoordinates;\n\n if (listenerTarget === void 0) {\n listenerTarget = getEventListenerTarget(props.event.target);\n }\n\n this.props = void 0;\n this.events = void 0;\n this.autoScrollEnabled = true;\n this.document = void 0;\n this.activated = false;\n this.initialCoordinates = void 0;\n this.timeoutId = null;\n this.listeners = void 0;\n this.documentListeners = void 0;\n this.windowListeners = void 0;\n this.props = props;\n this.events = events;\n const {\n event\n } = props;\n const {\n target\n } = event;\n this.props = props;\n this.events = events;\n this.document = getOwnerDocument(target);\n this.documentListeners = new Listeners(this.document);\n this.listeners = new Listeners(listenerTarget);\n this.windowListeners = new Listeners(getWindow(target));\n this.initialCoordinates = (_getEventCoordinates = getEventCoordinates(event)) != null ? _getEventCoordinates : defaultCoordinates;\n this.handleStart = this.handleStart.bind(this);\n this.handleMove = this.handleMove.bind(this);\n this.handleEnd = this.handleEnd.bind(this);\n this.handleCancel = this.handleCancel.bind(this);\n this.handleKeydown = this.handleKeydown.bind(this);\n this.removeTextSelection = this.removeTextSelection.bind(this);\n this.attach();\n }\n\n attach() {\n const {\n events,\n props: {\n options: {\n activationConstraint,\n bypassActivationConstraint\n }\n }\n } = this;\n this.listeners.add(events.move.name, this.handleMove, {\n passive: false\n });\n this.listeners.add(events.end.name, this.handleEnd);\n\n if (events.cancel) {\n this.listeners.add(events.cancel.name, this.handleCancel);\n }\n\n this.windowListeners.add(EventName.Resize, this.handleCancel);\n this.windowListeners.add(EventName.DragStart, preventDefault);\n this.windowListeners.add(EventName.VisibilityChange, this.handleCancel);\n this.windowListeners.add(EventName.ContextMenu, preventDefault);\n this.documentListeners.add(EventName.Keydown, this.handleKeydown);\n\n if (activationConstraint) {\n if (bypassActivationConstraint != null && bypassActivationConstraint({\n event: this.props.event,\n activeNode: this.props.activeNode,\n options: this.props.options\n })) {\n return this.handleStart();\n }\n\n if (isDelayConstraint(activationConstraint)) {\n this.timeoutId = setTimeout(this.handleStart, activationConstraint.delay);\n this.handlePending(activationConstraint);\n return;\n }\n\n if (isDistanceConstraint(activationConstraint)) {\n this.handlePending(activationConstraint);\n return;\n }\n }\n\n this.handleStart();\n }\n\n detach() {\n this.listeners.removeAll();\n this.windowListeners.removeAll(); // Wait until the next event loop before removing document listeners\n // This is necessary because we listen for `click` and `selection` events on the document\n\n setTimeout(this.documentListeners.removeAll, 50);\n\n if (this.timeoutId !== null) {\n clearTimeout(this.timeoutId);\n this.timeoutId = null;\n }\n }\n\n handlePending(constraint, offset) {\n const {\n active,\n onPending\n } = this.props;\n onPending(active, constraint, this.initialCoordinates, offset);\n }\n\n handleStart() {\n const {\n initialCoordinates\n } = this;\n const {\n onStart\n } = this.props;\n\n if (initialCoordinates) {\n this.activated = true; // Stop propagation of click events once activation constraints are met\n\n this.documentListeners.add(EventName.Click, stopPropagation, {\n capture: true\n }); // Remove any text selection from the document\n\n this.removeTextSelection(); // Prevent further text selection while dragging\n\n this.documentListeners.add(EventName.SelectionChange, this.removeTextSelection);\n onStart(initialCoordinates);\n }\n }\n\n handleMove(event) {\n var _getEventCoordinates2;\n\n const {\n activated,\n initialCoordinates,\n props\n } = this;\n const {\n onMove,\n options: {\n activationConstraint\n }\n } = props;\n\n if (!initialCoordinates) {\n return;\n }\n\n const coordinates = (_getEventCoordinates2 = getEventCoordinates(event)) != null ? _getEventCoordinates2 : defaultCoordinates;\n const delta = subtract(initialCoordinates, coordinates); // Constraint validation\n\n if (!activated && activationConstraint) {\n if (isDistanceConstraint(activationConstraint)) {\n if (activationConstraint.tolerance != null && hasExceededDistance(delta, activationConstraint.tolerance)) {\n return this.handleCancel();\n }\n\n if (hasExceededDistance(delta, activationConstraint.distance)) {\n return this.handleStart();\n }\n }\n\n if (isDelayConstraint(activationConstraint)) {\n if (hasExceededDistance(delta, activationConstraint.tolerance)) {\n return this.handleCancel();\n }\n }\n\n this.handlePending(activationConstraint, delta);\n return;\n }\n\n if (event.cancelable) {\n event.preventDefault();\n }\n\n onMove(coordinates);\n }\n\n handleEnd() {\n const {\n onAbort,\n onEnd\n } = this.props;\n this.detach();\n\n if (!this.activated) {\n onAbort(this.props.active);\n }\n\n onEnd();\n }\n\n handleCancel() {\n const {\n onAbort,\n onCancel\n } = this.props;\n this.detach();\n\n if (!this.activated) {\n onAbort(this.props.active);\n }\n\n onCancel();\n }\n\n handleKeydown(event) {\n if (event.code === KeyboardCode.Esc) {\n this.handleCancel();\n }\n }\n\n removeTextSelection() {\n var _this$document$getSel;\n\n (_this$document$getSel = this.document.getSelection()) == null ? void 0 : _this$document$getSel.removeAllRanges();\n }\n\n}\n\nconst events = {\n cancel: {\n name: 'pointercancel'\n },\n move: {\n name: 'pointermove'\n },\n end: {\n name: 'pointerup'\n }\n};\nclass PointerSensor extends AbstractPointerSensor {\n constructor(props) {\n const {\n event\n } = props; // Pointer events stop firing if the target is unmounted while dragging\n // Therefore we attach listeners to the owner document instead\n\n const listenerTarget = getOwnerDocument(event.target);\n super(props, events, listenerTarget);\n }\n\n}\nPointerSensor.activators = [{\n eventName: 'onPointerDown',\n handler: (_ref, _ref2) => {\n let {\n nativeEvent: event\n } = _ref;\n let {\n onActivation\n } = _ref2;\n\n if (!event.isPrimary || event.button !== 0) {\n return false;\n }\n\n onActivation == null ? void 0 : onActivation({\n event\n });\n return true;\n }\n}];\n\nconst events$1 = {\n move: {\n name: 'mousemove'\n },\n end: {\n name: 'mouseup'\n }\n};\nvar MouseButton;\n\n(function (MouseButton) {\n MouseButton[MouseButton[\"RightClick\"] = 2] = \"RightClick\";\n})(MouseButton || (MouseButton = {}));\n\nclass MouseSensor extends AbstractPointerSensor {\n constructor(props) {\n super(props, events$1, getOwnerDocument(props.event.target));\n }\n\n}\nMouseSensor.activators = [{\n eventName: 'onMouseDown',\n handler: (_ref, _ref2) => {\n let {\n nativeEvent: event\n } = _ref;\n let {\n onActivation\n } = _ref2;\n\n if (event.button === MouseButton.RightClick) {\n return false;\n }\n\n onActivation == null ? void 0 : onActivation({\n event\n });\n return true;\n }\n}];\n\nconst events$2 = {\n cancel: {\n name: 'touchcancel'\n },\n move: {\n name: 'touchmove'\n },\n end: {\n name: 'touchend'\n }\n};\nclass TouchSensor extends AbstractPointerSensor {\n constructor(props) {\n super(props, events$2);\n }\n\n static setup() {\n // Adding a non-capture and non-passive `touchmove` listener in order\n // to force `event.preventDefault()` calls to work in dynamically added\n // touchmove event handlers. This is required for iOS Safari.\n window.addEventListener(events$2.move.name, noop, {\n capture: false,\n passive: false\n });\n return function teardown() {\n window.removeEventListener(events$2.move.name, noop);\n }; // We create a new handler because the teardown function of another sensor\n // could remove our event listener if we use a referentially equal listener.\n\n function noop() {}\n }\n\n}\nTouchSensor.activators = [{\n eventName: 'onTouchStart',\n handler: (_ref, _ref2) => {\n let {\n nativeEvent: event\n } = _ref;\n let {\n onActivation\n } = _ref2;\n const {\n touches\n } = event;\n\n if (touches.length > 1) {\n return false;\n }\n\n onActivation == null ? void 0 : onActivation({\n event\n });\n return true;\n }\n}];\n\nvar AutoScrollActivator;\n\n(function (AutoScrollActivator) {\n AutoScrollActivator[AutoScrollActivator[\"Pointer\"] = 0] = \"Pointer\";\n AutoScrollActivator[AutoScrollActivator[\"DraggableRect\"] = 1] = \"DraggableRect\";\n})(AutoScrollActivator || (AutoScrollActivator = {}));\n\nvar TraversalOrder;\n\n(function (TraversalOrder) {\n TraversalOrder[TraversalOrder[\"TreeOrder\"] = 0] = \"TreeOrder\";\n TraversalOrder[TraversalOrder[\"ReversedTreeOrder\"] = 1] = \"ReversedTreeOrder\";\n})(TraversalOrder || (TraversalOrder = {}));\n\nfunction useAutoScroller(_ref) {\n let {\n acceleration,\n activator = AutoScrollActivator.Pointer,\n canScroll,\n draggingRect,\n enabled,\n interval = 5,\n order = TraversalOrder.TreeOrder,\n pointerCoordinates,\n scrollableAncestors,\n scrollableAncestorRects,\n delta,\n threshold\n } = _ref;\n const scrollIntent = useScrollIntent({\n delta,\n disabled: !enabled\n });\n const [setAutoScrollInterval, clearAutoScrollInterval] = useInterval();\n const scrollSpeed = useRef({\n x: 0,\n y: 0\n });\n const scrollDirection = useRef({\n x: 0,\n y: 0\n });\n const rect = useMemo(() => {\n switch (activator) {\n case AutoScrollActivator.Pointer:\n return pointerCoordinates ? {\n top: pointerCoordinates.y,\n bottom: pointerCoordinates.y,\n left: pointerCoordinates.x,\n right: pointerCoordinates.x\n } : null;\n\n case AutoScrollActivator.DraggableRect:\n return draggingRect;\n }\n }, [activator, draggingRect, pointerCoordinates]);\n const scrollContainerRef = useRef(null);\n const autoScroll = useCallback(() => {\n const scrollContainer = scrollContainerRef.current;\n\n if (!scrollContainer) {\n return;\n }\n\n const scrollLeft = scrollSpeed.current.x * scrollDirection.current.x;\n const scrollTop = scrollSpeed.current.y * scrollDirection.current.y;\n scrollContainer.scrollBy(scrollLeft, scrollTop);\n }, []);\n const sortedScrollableAncestors = useMemo(() => order === TraversalOrder.TreeOrder ? [...scrollableAncestors].reverse() : scrollableAncestors, [order, scrollableAncestors]);\n useEffect(() => {\n if (!enabled || !scrollableAncestors.length || !rect) {\n clearAutoScrollInterval();\n return;\n }\n\n for (const scrollContainer of sortedScrollableAncestors) {\n if ((canScroll == null ? void 0 : canScroll(scrollContainer)) === false) {\n continue;\n }\n\n const index = scrollableAncestors.indexOf(scrollContainer);\n const scrollContainerRect = scrollableAncestorRects[index];\n\n if (!scrollContainerRect) {\n continue;\n }\n\n const {\n direction,\n speed\n } = getScrollDirectionAndSpeed(scrollContainer, scrollContainerRect, rect, acceleration, threshold);\n\n for (const axis of ['x', 'y']) {\n if (!scrollIntent[axis][direction[axis]]) {\n speed[axis] = 0;\n direction[axis] = 0;\n }\n }\n\n if (speed.x > 0 || speed.y > 0) {\n clearAutoScrollInterval();\n scrollContainerRef.current = scrollContainer;\n setAutoScrollInterval(autoScroll, interval);\n scrollSpeed.current = speed;\n scrollDirection.current = direction;\n return;\n }\n }\n\n scrollSpeed.current = {\n x: 0,\n y: 0\n };\n scrollDirection.current = {\n x: 0,\n y: 0\n };\n clearAutoScrollInterval();\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [acceleration, autoScroll, canScroll, clearAutoScrollInterval, enabled, interval, // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(rect), // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(scrollIntent), setAutoScrollInterval, scrollableAncestors, sortedScrollableAncestors, scrollableAncestorRects, // eslint-disable-next-line react-hooks/exhaustive-deps\n JSON.stringify(threshold)]);\n}\nconst defaultScrollIntent = {\n x: {\n [Direction.Backward]: false,\n [Direction.Forward]: false\n },\n y: {\n [Direction.Backward]: false,\n [Direction.Forward]: false\n }\n};\n\nfunction useScrollIntent(_ref2) {\n let {\n delta,\n disabled\n } = _ref2;\n const previousDelta = usePrevious(delta);\n return useLazyMemo(previousIntent => {\n if (disabled || !previousDelta || !previousIntent) {\n // Reset scroll intent tracking when auto-scrolling is disabled\n return defaultScrollIntent;\n }\n\n const direction = {\n x: Math.sign(delta.x - previousDelta.x),\n y: Math.sign(delta.y - previousDelta.y)\n }; // Keep track of the user intent to scroll in each direction for both axis\n\n return {\n x: {\n [Direction.Backward]: previousIntent.x[Direction.Backward] || direction.x === -1,\n [Direction.Forward]: previousIntent.x[Direction.Forward] || direction.x === 1\n },\n y: {\n [Direction.Backward]: previousIntent.y[Direction.Backward] || direction.y === -1,\n [Direction.Forward]: previousIntent.y[Direction.Forward] || direction.y === 1\n }\n };\n }, [disabled, delta, previousDelta]);\n}\n\nfunction useCachedNode(draggableNodes, id) {\n const draggableNode = id != null ? draggableNodes.get(id) : undefined;\n const node = draggableNode ? draggableNode.node.current : null;\n return useLazyMemo(cachedNode => {\n var _ref;\n\n if (id == null) {\n return null;\n } // In some cases, the draggable node can unmount while dragging\n // This is the case for virtualized lists. In those situations,\n // we fall back to the last known value for that node.\n\n\n return (_ref = node != null ? node : cachedNode) != null ? _ref : null;\n }, [node, id]);\n}\n\nfunction useCombineActivators(sensors, getSyntheticHandler) {\n return useMemo(() => sensors.reduce((accumulator, sensor) => {\n const {\n sensor: Sensor\n } = sensor;\n const sensorActivators = Sensor.activators.map(activator => ({\n eventName: activator.eventName,\n handler: getSyntheticHandler(activator.handler, sensor)\n }));\n return [...accumulator, ...sensorActivators];\n }, []), [sensors, getSyntheticHandler]);\n}\n\nvar MeasuringStrategy;\n\n(function (MeasuringStrategy) {\n MeasuringStrategy[MeasuringStrategy[\"Always\"] = 0] = \"Always\";\n MeasuringStrategy[MeasuringStrategy[\"BeforeDragging\"] = 1] = \"BeforeDragging\";\n MeasuringStrategy[MeasuringStrategy[\"WhileDragging\"] = 2] = \"WhileDragging\";\n})(MeasuringStrategy || (MeasuringStrategy = {}));\n\nvar MeasuringFrequency;\n\n(function (MeasuringFrequency) {\n MeasuringFrequency[\"Optimized\"] = \"optimized\";\n})(MeasuringFrequency || (MeasuringFrequency = {}));\n\nconst defaultValue = /*#__PURE__*/new Map();\nfunction useDroppableMeasuring(containers, _ref) {\n let {\n dragging,\n dependencies,\n config\n } = _ref;\n const [queue, setQueue] = useState(null);\n const {\n frequency,\n measure,\n strategy\n } = config;\n const containersRef = useRef(containers);\n const disabled = isDisabled();\n const disabledRef = useLatestValue(disabled);\n const measureDroppableContainers = useCallback(function (ids) {\n if (ids === void 0) {\n ids = [];\n }\n\n if (disabledRef.current) {\n return;\n }\n\n setQueue(value => {\n if (value === null) {\n return ids;\n }\n\n return value.concat(ids.filter(id => !value.includes(id)));\n });\n }, [disabledRef]);\n const timeoutId = useRef(null);\n const droppableRects = useLazyMemo(previousValue => {\n if (disabled && !dragging) {\n return defaultValue;\n }\n\n if (!previousValue || previousValue === defaultValue || containersRef.current !== containers || queue != null) {\n const map = new Map();\n\n for (let container of containers) {\n if (!container) {\n continue;\n }\n\n if (queue && queue.length > 0 && !queue.includes(container.id) && container.rect.current) {\n // This container does not need to be re-measured\n map.set(container.id, container.rect.current);\n continue;\n }\n\n const node = container.node.current;\n const rect = node ? new Rect(measure(node), node) : null;\n container.rect.current = rect;\n\n if (rect) {\n map.set(container.id, rect);\n }\n }\n\n return map;\n }\n\n return previousValue;\n }, [containers, queue, dragging, disabled, measure]);\n useEffect(() => {\n containersRef.current = containers;\n }, [containers]);\n useEffect(() => {\n if (disabled) {\n return;\n }\n\n measureDroppableContainers();\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [dragging, disabled]);\n useEffect(() => {\n if (queue && queue.length > 0) {\n setQueue(null);\n }\n }, //eslint-disable-next-line react-hooks/exhaustive-deps\n [JSON.stringify(queue)]);\n useEffect(() => {\n if (disabled || typeof frequency !== 'number' || timeoutId.current !== null) {\n return;\n }\n\n timeoutId.current = setTimeout(() => {\n measureDroppableContainers();\n timeoutId.current = null;\n }, frequency);\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [frequency, disabled, measureDroppableContainers, ...dependencies]);\n return {\n droppableRects,\n measureDroppableContainers,\n measuringScheduled: queue != null\n };\n\n function isDisabled() {\n switch (strategy) {\n case MeasuringStrategy.Always:\n return false;\n\n case MeasuringStrategy.BeforeDragging:\n return dragging;\n\n default:\n return !dragging;\n }\n }\n}\n\nfunction useInitialValue(value, computeFn) {\n return useLazyMemo(previousValue => {\n if (!value) {\n return null;\n }\n\n if (previousValue) {\n return previousValue;\n }\n\n return typeof computeFn === 'function' ? computeFn(value) : value;\n }, [computeFn, value]);\n}\n\nfunction useInitialRect(node, measure) {\n return useInitialValue(node, measure);\n}\n\n/**\r\n * Returns a new MutationObserver instance.\r\n * If `MutationObserver` is undefined in the execution environment, returns `undefined`.\r\n */\n\nfunction useMutationObserver(_ref) {\n let {\n callback,\n disabled\n } = _ref;\n const handleMutations = useEvent(callback);\n const mutationObserver = useMemo(() => {\n if (disabled || typeof window === 'undefined' || typeof window.MutationObserver === 'undefined') {\n return undefined;\n }\n\n const {\n MutationObserver\n } = window;\n return new MutationObserver(handleMutations);\n }, [handleMutations, disabled]);\n useEffect(() => {\n return () => mutationObserver == null ? void 0 : mutationObserver.disconnect();\n }, [mutationObserver]);\n return mutationObserver;\n}\n\n/**\r\n * Returns a new ResizeObserver instance bound to the `onResize` callback.\r\n * If `ResizeObserver` is undefined in the execution environment, returns `undefined`.\r\n */\n\nfunction useResizeObserver(_ref) {\n let {\n callback,\n disabled\n } = _ref;\n const handleResize = useEvent(callback);\n const resizeObserver = useMemo(() => {\n if (disabled || typeof window === 'undefined' || typeof window.ResizeObserver === 'undefined') {\n return undefined;\n }\n\n const {\n ResizeObserver\n } = window;\n return new ResizeObserver(handleResize);\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [disabled]);\n useEffect(() => {\n return () => resizeObserver == null ? void 0 : resizeObserver.disconnect();\n }, [resizeObserver]);\n return resizeObserver;\n}\n\nfunction defaultMeasure(element) {\n return new Rect(getClientRect(element), element);\n}\n\nfunction useRect(element, measure, fallbackRect) {\n if (measure === void 0) {\n measure = defaultMeasure;\n }\n\n const [rect, setRect] = useState(null);\n\n function measureRect() {\n setRect(currentRect => {\n if (!element) {\n return null;\n }\n\n if (element.isConnected === false) {\n var _ref;\n\n // Fall back to last rect we measured if the element is\n // no longer connected to the DOM.\n return (_ref = currentRect != null ? currentRect : fallbackRect) != null ? _ref : null;\n }\n\n const newRect = measure(element);\n\n if (JSON.stringify(currentRect) === JSON.stringify(newRect)) {\n return currentRect;\n }\n\n return newRect;\n });\n }\n\n const mutationObserver = useMutationObserver({\n callback(records) {\n if (!element) {\n return;\n }\n\n for (const record of records) {\n const {\n type,\n target\n } = record;\n\n if (type === 'childList' && target instanceof HTMLElement && target.contains(element)) {\n measureRect();\n break;\n }\n }\n }\n\n });\n const resizeObserver = useResizeObserver({\n callback: measureRect\n });\n useIsomorphicLayoutEffect(() => {\n measureRect();\n\n if (element) {\n resizeObserver == null ? void 0 : resizeObserver.observe(element);\n mutationObserver == null ? void 0 : mutationObserver.observe(document.body, {\n childList: true,\n subtree: true\n });\n } else {\n resizeObserver == null ? void 0 : resizeObserver.disconnect();\n mutationObserver == null ? void 0 : mutationObserver.disconnect();\n }\n }, [element]);\n return rect;\n}\n\nfunction useRectDelta(rect) {\n const initialRect = useInitialValue(rect);\n return getRectDelta(rect, initialRect);\n}\n\nconst defaultValue$1 = [];\nfunction useScrollableAncestors(node) {\n const previousNode = useRef(node);\n const ancestors = useLazyMemo(previousValue => {\n if (!node) {\n return defaultValue$1;\n }\n\n if (previousValue && previousValue !== defaultValue$1 && node && previousNode.current && node.parentNode === previousNode.current.parentNode) {\n return previousValue;\n }\n\n return getScrollableAncestors(node);\n }, [node]);\n useEffect(() => {\n previousNode.current = node;\n }, [node]);\n return ancestors;\n}\n\nfunction useScrollOffsets(elements) {\n const [scrollCoordinates, setScrollCoordinates] = useState(null);\n const prevElements = useRef(elements); // To-do: Throttle the handleScroll callback\n\n const handleScroll = useCallback(event => {\n const scrollingElement = getScrollableElement(event.target);\n\n if (!scrollingElement) {\n return;\n }\n\n setScrollCoordinates(scrollCoordinates => {\n if (!scrollCoordinates) {\n return null;\n }\n\n scrollCoordinates.set(scrollingElement, getScrollCoordinates(scrollingElement));\n return new Map(scrollCoordinates);\n });\n }, []);\n useEffect(() => {\n const previousElements = prevElements.current;\n\n if (elements !== previousElements) {\n cleanup(previousElements);\n const entries = elements.map(element => {\n const scrollableElement = getScrollableElement(element);\n\n if (scrollableElement) {\n scrollableElement.addEventListener('scroll', handleScroll, {\n passive: true\n });\n return [scrollableElement, getScrollCoordinates(scrollableElement)];\n }\n\n return null;\n }).filter(entry => entry != null);\n setScrollCoordinates(entries.length ? new Map(entries) : null);\n prevElements.current = elements;\n }\n\n return () => {\n cleanup(elements);\n cleanup(previousElements);\n };\n\n function cleanup(elements) {\n elements.forEach(element => {\n const scrollableElement = getScrollableElement(element);\n scrollableElement == null ? void 0 : scrollableElement.removeEventListener('scroll', handleScroll);\n });\n }\n }, [handleScroll, elements]);\n return useMemo(() => {\n if (elements.length) {\n return scrollCoordinates ? Array.from(scrollCoordinates.values()).reduce((acc, coordinates) => add(acc, coordinates), defaultCoordinates) : getScrollOffsets(elements);\n }\n\n return defaultCoordinates;\n }, [elements, scrollCoordinates]);\n}\n\nfunction useScrollOffsetsDelta(scrollOffsets, dependencies) {\n if (dependencies === void 0) {\n dependencies = [];\n }\n\n const initialScrollOffsets = useRef(null);\n useEffect(() => {\n initialScrollOffsets.current = null;\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n dependencies);\n useEffect(() => {\n const hasScrollOffsets = scrollOffsets !== defaultCoordinates;\n\n if (hasScrollOffsets && !initialScrollOffsets.current) {\n initialScrollOffsets.current = scrollOffsets;\n }\n\n if (!hasScrollOffsets && initialScrollOffsets.current) {\n initialScrollOffsets.current = null;\n }\n }, [scrollOffsets]);\n return initialScrollOffsets.current ? subtract(scrollOffsets, initialScrollOffsets.current) : defaultCoordinates;\n}\n\nfunction useSensorSetup(sensors) {\n useEffect(() => {\n if (!canUseDOM) {\n return;\n }\n\n const teardownFns = sensors.map(_ref => {\n let {\n sensor\n } = _ref;\n return sensor.setup == null ? void 0 : sensor.setup();\n });\n return () => {\n for (const teardown of teardownFns) {\n teardown == null ? void 0 : teardown();\n }\n };\n }, // TO-DO: Sensors length could theoretically change which would not be a valid dependency\n // eslint-disable-next-line react-hooks/exhaustive-deps\n sensors.map(_ref2 => {\n let {\n sensor\n } = _ref2;\n return sensor;\n }));\n}\n\nfunction useSyntheticListeners(listeners, id) {\n return useMemo(() => {\n return listeners.reduce((acc, _ref) => {\n let {\n eventName,\n handler\n } = _ref;\n\n acc[eventName] = event => {\n handler(event, id);\n };\n\n return acc;\n }, {});\n }, [listeners, id]);\n}\n\nfunction useWindowRect(element) {\n return useMemo(() => element ? getWindowClientRect(element) : null, [element]);\n}\n\nconst defaultValue$2 = [];\nfunction useRects(elements, measure) {\n if (measure === void 0) {\n measure = getClientRect;\n }\n\n const [firstElement] = elements;\n const windowRect = useWindowRect(firstElement ? getWindow(firstElement) : null);\n const [rects, setRects] = useState(defaultValue$2);\n\n function measureRects() {\n setRects(() => {\n if (!elements.length) {\n return defaultValue$2;\n }\n\n return elements.map(element => isDocumentScrollingElement(element) ? windowRect : new Rect(measure(element), element));\n });\n }\n\n const resizeObserver = useResizeObserver({\n callback: measureRects\n });\n useIsomorphicLayoutEffect(() => {\n resizeObserver == null ? void 0 : resizeObserver.disconnect();\n measureRects();\n elements.forEach(element => resizeObserver == null ? void 0 : resizeObserver.observe(element));\n }, [elements]);\n return rects;\n}\n\nfunction getMeasurableNode(node) {\n if (!node) {\n return null;\n }\n\n if (node.children.length > 1) {\n return node;\n }\n\n const firstChild = node.children[0];\n return isHTMLElement(firstChild) ? firstChild : node;\n}\n\nfunction useDragOverlayMeasuring(_ref) {\n let {\n measure\n } = _ref;\n const [rect, setRect] = useState(null);\n const handleResize = useCallback(entries => {\n for (const {\n target\n } of entries) {\n if (isHTMLElement(target)) {\n setRect(rect => {\n const newRect = measure(target);\n return rect ? { ...rect,\n width: newRect.width,\n height: newRect.height\n } : newRect;\n });\n break;\n }\n }\n }, [measure]);\n const resizeObserver = useResizeObserver({\n callback: handleResize\n });\n const handleNodeChange = useCallback(element => {\n const node = getMeasurableNode(element);\n resizeObserver == null ? void 0 : resizeObserver.disconnect();\n\n if (node) {\n resizeObserver == null ? void 0 : resizeObserver.observe(node);\n }\n\n setRect(node ? measure(node) : null);\n }, [measure, resizeObserver]);\n const [nodeRef, setRef] = useNodeRef(handleNodeChange);\n return useMemo(() => ({\n nodeRef,\n rect,\n setRef\n }), [rect, nodeRef, setRef]);\n}\n\nconst defaultSensors = [{\n sensor: PointerSensor,\n options: {}\n}, {\n sensor: KeyboardSensor,\n options: {}\n}];\nconst defaultData = {\n current: {}\n};\nconst defaultMeasuringConfiguration = {\n draggable: {\n measure: getTransformAgnosticClientRect\n },\n droppable: {\n measure: getTransformAgnosticClientRect,\n strategy: MeasuringStrategy.WhileDragging,\n frequency: MeasuringFrequency.Optimized\n },\n dragOverlay: {\n measure: getClientRect\n }\n};\n\nclass DroppableContainersMap extends Map {\n get(id) {\n var _super$get;\n\n return id != null ? (_super$get = super.get(id)) != null ? _super$get : undefined : undefined;\n }\n\n toArray() {\n return Array.from(this.values());\n }\n\n getEnabled() {\n return this.toArray().filter(_ref => {\n let {\n disabled\n } = _ref;\n return !disabled;\n });\n }\n\n getNodeFor(id) {\n var _this$get$node$curren, _this$get;\n\n return (_this$get$node$curren = (_this$get = this.get(id)) == null ? void 0 : _this$get.node.current) != null ? _this$get$node$curren : undefined;\n }\n\n}\n\nconst defaultPublicContext = {\n activatorEvent: null,\n active: null,\n activeNode: null,\n activeNodeRect: null,\n collisions: null,\n containerNodeRect: null,\n draggableNodes: /*#__PURE__*/new Map(),\n droppableRects: /*#__PURE__*/new Map(),\n droppableContainers: /*#__PURE__*/new DroppableContainersMap(),\n over: null,\n dragOverlay: {\n nodeRef: {\n current: null\n },\n rect: null,\n setRef: noop\n },\n scrollableAncestors: [],\n scrollableAncestorRects: [],\n measuringConfiguration: defaultMeasuringConfiguration,\n measureDroppableContainers: noop,\n windowRect: null,\n measuringScheduled: false\n};\nconst defaultInternalContext = {\n activatorEvent: null,\n activators: [],\n active: null,\n activeNodeRect: null,\n ariaDescribedById: {\n draggable: ''\n },\n dispatch: noop,\n draggableNodes: /*#__PURE__*/new Map(),\n over: null,\n measureDroppableContainers: noop\n};\nconst InternalContext = /*#__PURE__*/createContext(defaultInternalContext);\nconst PublicContext = /*#__PURE__*/createContext(defaultPublicContext);\n\nfunction getInitialState() {\n return {\n draggable: {\n active: null,\n initialCoordinates: {\n x: 0,\n y: 0\n },\n nodes: new Map(),\n translate: {\n x: 0,\n y: 0\n }\n },\n droppable: {\n containers: new DroppableContainersMap()\n }\n };\n}\nfunction reducer(state, action) {\n switch (action.type) {\n case Action.DragStart:\n return { ...state,\n draggable: { ...state.draggable,\n initialCoordinates: action.initialCoordinates,\n active: action.active\n }\n };\n\n case Action.DragMove:\n if (state.draggable.active == null) {\n return state;\n }\n\n return { ...state,\n draggable: { ...state.draggable,\n translate: {\n x: action.coordinates.x - state.draggable.initialCoordinates.x,\n y: action.coordinates.y - state.draggable.initialCoordinates.y\n }\n }\n };\n\n case Action.DragEnd:\n case Action.DragCancel:\n return { ...state,\n draggable: { ...state.draggable,\n active: null,\n initialCoordinates: {\n x: 0,\n y: 0\n },\n translate: {\n x: 0,\n y: 0\n }\n }\n };\n\n case Action.RegisterDroppable:\n {\n const {\n element\n } = action;\n const {\n id\n } = element;\n const containers = new DroppableContainersMap(state.droppable.containers);\n containers.set(id, element);\n return { ...state,\n droppable: { ...state.droppable,\n containers\n }\n };\n }\n\n case Action.SetDroppableDisabled:\n {\n const {\n id,\n key,\n disabled\n } = action;\n const element = state.droppable.containers.get(id);\n\n if (!element || key !== element.key) {\n return state;\n }\n\n const containers = new DroppableContainersMap(state.droppable.containers);\n containers.set(id, { ...element,\n disabled\n });\n return { ...state,\n droppable: { ...state.droppable,\n containers\n }\n };\n }\n\n case Action.UnregisterDroppable:\n {\n const {\n id,\n key\n } = action;\n const element = state.droppable.containers.get(id);\n\n if (!element || key !== element.key) {\n return state;\n }\n\n const containers = new DroppableContainersMap(state.droppable.containers);\n containers.delete(id);\n return { ...state,\n droppable: { ...state.droppable,\n containers\n }\n };\n }\n\n default:\n {\n return state;\n }\n }\n}\n\nfunction RestoreFocus(_ref) {\n let {\n disabled\n } = _ref;\n const {\n active,\n activatorEvent,\n draggableNodes\n } = useContext(InternalContext);\n const previousActivatorEvent = usePrevious(activatorEvent);\n const previousActiveId = usePrevious(active == null ? void 0 : active.id); // Restore keyboard focus on the activator node\n\n useEffect(() => {\n if (disabled) {\n return;\n }\n\n if (!activatorEvent && previousActivatorEvent && previousActiveId != null) {\n if (!isKeyboardEvent(previousActivatorEvent)) {\n return;\n }\n\n if (document.activeElement === previousActivatorEvent.target) {\n // No need to restore focus\n return;\n }\n\n const draggableNode = draggableNodes.get(previousActiveId);\n\n if (!draggableNode) {\n return;\n }\n\n const {\n activatorNode,\n node\n } = draggableNode;\n\n if (!activatorNode.current && !node.current) {\n return;\n }\n\n requestAnimationFrame(() => {\n for (const element of [activatorNode.current, node.current]) {\n if (!element) {\n continue;\n }\n\n const focusableNode = findFirstFocusableNode(element);\n\n if (focusableNode) {\n focusableNode.focus();\n break;\n }\n }\n });\n }\n }, [activatorEvent, disabled, draggableNodes, previousActiveId, previousActivatorEvent]);\n return null;\n}\n\nfunction applyModifiers(modifiers, _ref) {\n let {\n transform,\n ...args\n } = _ref;\n return modifiers != null && modifiers.length ? modifiers.reduce((accumulator, modifier) => {\n return modifier({\n transform: accumulator,\n ...args\n });\n }, transform) : transform;\n}\n\nfunction useMeasuringConfiguration(config) {\n return useMemo(() => ({\n draggable: { ...defaultMeasuringConfiguration.draggable,\n ...(config == null ? void 0 : config.draggable)\n },\n droppable: { ...defaultMeasuringConfiguration.droppable,\n ...(config == null ? void 0 : config.droppable)\n },\n dragOverlay: { ...defaultMeasuringConfiguration.dragOverlay,\n ...(config == null ? void 0 : config.dragOverlay)\n }\n }), // eslint-disable-next-line react-hooks/exhaustive-deps\n [config == null ? void 0 : config.draggable, config == null ? void 0 : config.droppable, config == null ? void 0 : config.dragOverlay]);\n}\n\nfunction useLayoutShiftScrollCompensation(_ref) {\n let {\n activeNode,\n measure,\n initialRect,\n config = true\n } = _ref;\n const initialized = useRef(false);\n const {\n x,\n y\n } = typeof config === 'boolean' ? {\n x: config,\n y: config\n } : config;\n useIsomorphicLayoutEffect(() => {\n const disabled = !x && !y;\n\n if (disabled || !activeNode) {\n initialized.current = false;\n return;\n }\n\n if (initialized.current || !initialRect) {\n // Return early if layout shift scroll compensation was already attempted\n // or if there is no initialRect to compare to.\n return;\n } // Get the most up to date node ref for the active draggable\n\n\n const node = activeNode == null ? void 0 : activeNode.node.current;\n\n if (!node || node.isConnected === false) {\n // Return early if there is no attached node ref or if the node is\n // disconnected from the document.\n return;\n }\n\n const rect = measure(node);\n const rectDelta = getRectDelta(rect, initialRect);\n\n if (!x) {\n rectDelta.x = 0;\n }\n\n if (!y) {\n rectDelta.y = 0;\n } // Only perform layout shift scroll compensation once\n\n\n initialized.current = true;\n\n if (Math.abs(rectDelta.x) > 0 || Math.abs(rectDelta.y) > 0) {\n const firstScrollableAncestor = getFirstScrollableAncestor(node);\n\n if (firstScrollableAncestor) {\n firstScrollableAncestor.scrollBy({\n top: rectDelta.y,\n left: rectDelta.x\n });\n }\n }\n }, [activeNode, x, y, initialRect, measure]);\n}\n\nconst ActiveDraggableContext = /*#__PURE__*/createContext({ ...defaultCoordinates,\n scaleX: 1,\n scaleY: 1\n});\nvar Status;\n\n(function (Status) {\n Status[Status[\"Uninitialized\"] = 0] = \"Uninitialized\";\n Status[Status[\"Initializing\"] = 1] = \"Initializing\";\n Status[Status[\"Initialized\"] = 2] = \"Initialized\";\n})(Status || (Status = {}));\n\nconst DndContext = /*#__PURE__*/memo(function DndContext(_ref) {\n var _sensorContext$curren, _dragOverlay$nodeRef$, _dragOverlay$rect, _over$rect;\n\n let {\n id,\n accessibility,\n autoScroll = true,\n children,\n sensors = defaultSensors,\n collisionDetection = rectIntersection,\n measuring,\n modifiers,\n ...props\n } = _ref;\n const store = useReducer(reducer, undefined, getInitialState);\n const [state, dispatch] = store;\n const [dispatchMonitorEvent, registerMonitorListener] = useDndMonitorProvider();\n const [status, setStatus] = useState(Status.Uninitialized);\n const isInitialized = status === Status.Initialized;\n const {\n draggable: {\n active: activeId,\n nodes: draggableNodes,\n translate\n },\n droppable: {\n containers: droppableContainers\n }\n } = state;\n const node = activeId != null ? draggableNodes.get(activeId) : null;\n const activeRects = useRef({\n initial: null,\n translated: null\n });\n const active = useMemo(() => {\n var _node$data;\n\n return activeId != null ? {\n id: activeId,\n // It's possible for the active node to unmount while dragging\n data: (_node$data = node == null ? void 0 : node.data) != null ? _node$data : defaultData,\n rect: activeRects\n } : null;\n }, [activeId, node]);\n const activeRef = useRef(null);\n const [activeSensor, setActiveSensor] = useState(null);\n const [activatorEvent, setActivatorEvent] = useState(null);\n const latestProps = useLatestValue(props, Object.values(props));\n const draggableDescribedById = useUniqueId(\"DndDescribedBy\", id);\n const enabledDroppableContainers = useMemo(() => droppableContainers.getEnabled(), [droppableContainers]);\n const measuringConfiguration = useMeasuringConfiguration(measuring);\n const {\n droppableRects,\n measureDroppableContainers,\n measuringScheduled\n } = useDroppableMeasuring(enabledDroppableContainers, {\n dragging: isInitialized,\n dependencies: [translate.x, translate.y],\n config: measuringConfiguration.droppable\n });\n const activeNode = useCachedNode(draggableNodes, activeId);\n const activationCoordinates = useMemo(() => activatorEvent ? getEventCoordinates(activatorEvent) : null, [activatorEvent]);\n const autoScrollOptions = getAutoScrollerOptions();\n const initialActiveNodeRect = useInitialRect(activeNode, measuringConfiguration.draggable.measure);\n useLayoutShiftScrollCompensation({\n activeNode: activeId != null ? draggableNodes.get(activeId) : null,\n config: autoScrollOptions.layoutShiftCompensation,\n initialRect: initialActiveNodeRect,\n measure: measuringConfiguration.draggable.measure\n });\n const activeNodeRect = useRect(activeNode, measuringConfiguration.draggable.measure, initialActiveNodeRect);\n const containerNodeRect = useRect(activeNode ? activeNode.parentElement : null);\n const sensorContext = useRef({\n activatorEvent: null,\n active: null,\n activeNode,\n collisionRect: null,\n collisions: null,\n droppableRects,\n draggableNodes,\n draggingNode: null,\n draggingNodeRect: null,\n droppableContainers,\n over: null,\n scrollableAncestors: [],\n scrollAdjustedTranslate: null\n });\n const overNode = droppableContainers.getNodeFor((_sensorContext$curren = sensorContext.current.over) == null ? void 0 : _sensorContext$curren.id);\n const dragOverlay = useDragOverlayMeasuring({\n measure: measuringConfiguration.dragOverlay.measure\n }); // Use the rect of the drag overlay if it is mounted\n\n const draggingNode = (_dragOverlay$nodeRef$ = dragOverlay.nodeRef.current) != null ? _dragOverlay$nodeRef$ : activeNode;\n const draggingNodeRect = isInitialized ? (_dragOverlay$rect = dragOverlay.rect) != null ? _dragOverlay$rect : activeNodeRect : null;\n const usesDragOverlay = Boolean(dragOverlay.nodeRef.current && dragOverlay.rect); // The delta between the previous and new position of the draggable node\n // is only relevant when there is no drag overlay\n\n const nodeRectDelta = useRectDelta(usesDragOverlay ? null : activeNodeRect); // Get the window rect of the dragging node\n\n const windowRect = useWindowRect(draggingNode ? getWindow(draggingNode) : null); // Get scrollable ancestors of the dragging node\n\n const scrollableAncestors = useScrollableAncestors(isInitialized ? overNode != null ? overNode : activeNode : null);\n const scrollableAncestorRects = useRects(scrollableAncestors); // Apply modifiers\n\n const modifiedTranslate = applyModifiers(modifiers, {\n transform: {\n x: translate.x - nodeRectDelta.x,\n y: translate.y - nodeRectDelta.y,\n scaleX: 1,\n scaleY: 1\n },\n activatorEvent,\n active,\n activeNodeRect,\n containerNodeRect,\n draggingNodeRect,\n over: sensorContext.current.over,\n overlayNodeRect: dragOverlay.rect,\n scrollableAncestors,\n scrollableAncestorRects,\n windowRect\n });\n const pointerCoordinates = activationCoordinates ? add(activationCoordinates, translate) : null;\n const scrollOffsets = useScrollOffsets(scrollableAncestors); // Represents the scroll delta since dragging was initiated\n\n const scrollAdjustment = useScrollOffsetsDelta(scrollOffsets); // Represents the scroll delta since the last time the active node rect was measured\n\n const activeNodeScrollDelta = useScrollOffsetsDelta(scrollOffsets, [activeNodeRect]);\n const scrollAdjustedTranslate = add(modifiedTranslate, scrollAdjustment);\n const collisionRect = draggingNodeRect ? getAdjustedRect(draggingNodeRect, modifiedTranslate) : null;\n const collisions = active && collisionRect ? collisionDetection({\n active,\n collisionRect,\n droppableRects,\n droppableContainers: enabledDroppableContainers,\n pointerCoordinates\n }) : null;\n const overId = getFirstCollision(collisions, 'id');\n const [over, setOver] = useState(null); // When there is no drag overlay used, we need to account for the\n // window scroll delta\n\n const appliedTranslate = usesDragOverlay ? modifiedTranslate : add(modifiedTranslate, activeNodeScrollDelta);\n const transform = adjustScale(appliedTranslate, (_over$rect = over == null ? void 0 : over.rect) != null ? _over$rect : null, activeNodeRect);\n const activeSensorRef = useRef(null);\n const instantiateSensor = useCallback((event, _ref2) => {\n let {\n sensor: Sensor,\n options\n } = _ref2;\n\n if (activeRef.current == null) {\n return;\n }\n\n const activeNode = draggableNodes.get(activeRef.current);\n\n if (!activeNode) {\n return;\n }\n\n const activatorEvent = event.nativeEvent;\n const sensorInstance = new Sensor({\n active: activeRef.current,\n activeNode,\n event: activatorEvent,\n options,\n // Sensors need to be instantiated with refs for arguments that change over time\n // otherwise they are frozen in time with the stale arguments\n context: sensorContext,\n\n onAbort(id) {\n const draggableNode = draggableNodes.get(id);\n\n if (!draggableNode) {\n return;\n }\n\n const {\n onDragAbort\n } = latestProps.current;\n const event = {\n id\n };\n onDragAbort == null ? void 0 : onDragAbort(event);\n dispatchMonitorEvent({\n type: 'onDragAbort',\n event\n });\n },\n\n onPending(id, constraint, initialCoordinates, offset) {\n const draggableNode = draggableNodes.get(id);\n\n if (!draggableNode) {\n return;\n }\n\n const {\n onDragPending\n } = latestProps.current;\n const event = {\n id,\n constraint,\n initialCoordinates,\n offset\n };\n onDragPending == null ? void 0 : onDragPending(event);\n dispatchMonitorEvent({\n type: 'onDragPending',\n event\n });\n },\n\n onStart(initialCoordinates) {\n const id = activeRef.current;\n\n if (id == null) {\n return;\n }\n\n const draggableNode = draggableNodes.get(id);\n\n if (!draggableNode) {\n return;\n }\n\n const {\n onDragStart\n } = latestProps.current;\n const event = {\n activatorEvent,\n active: {\n id,\n data: draggableNode.data,\n rect: activeRects\n }\n };\n unstable_batchedUpdates(() => {\n onDragStart == null ? void 0 : onDragStart(event);\n setStatus(Status.Initializing);\n dispatch({\n type: Action.DragStart,\n initialCoordinates,\n active: id\n });\n dispatchMonitorEvent({\n type: 'onDragStart',\n event\n });\n setActiveSensor(activeSensorRef.current);\n setActivatorEvent(activatorEvent);\n });\n },\n\n onMove(coordinates) {\n dispatch({\n type: Action.DragMove,\n coordinates\n });\n },\n\n onEnd: createHandler(Action.DragEnd),\n onCancel: createHandler(Action.DragCancel)\n });\n activeSensorRef.current = sensorInstance;\n\n function createHandler(type) {\n return async function handler() {\n const {\n active,\n collisions,\n over,\n scrollAdjustedTranslate\n } = sensorContext.current;\n let event = null;\n\n if (active && scrollAdjustedTranslate) {\n const {\n cancelDrop\n } = latestProps.current;\n event = {\n activatorEvent,\n active: active,\n collisions,\n delta: scrollAdjustedTranslate,\n over\n };\n\n if (type === Action.DragEnd && typeof cancelDrop === 'function') {\n const shouldCancel = await Promise.resolve(cancelDrop(event));\n\n if (shouldCancel) {\n type = Action.DragCancel;\n }\n }\n }\n\n activeRef.current = null;\n unstable_batchedUpdates(() => {\n dispatch({\n type\n });\n setStatus(Status.Uninitialized);\n setOver(null);\n setActiveSensor(null);\n setActivatorEvent(null);\n activeSensorRef.current = null;\n const eventName = type === Action.DragEnd ? 'onDragEnd' : 'onDragCancel';\n\n if (event) {\n const handler = latestProps.current[eventName];\n handler == null ? void 0 : handler(event);\n dispatchMonitorEvent({\n type: eventName,\n event\n });\n }\n });\n };\n }\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [draggableNodes]);\n const bindActivatorToSensorInstantiator = useCallback((handler, sensor) => {\n return (event, active) => {\n const nativeEvent = event.nativeEvent;\n const activeDraggableNode = draggableNodes.get(active);\n\n if ( // Another sensor is already instantiating\n activeRef.current !== null || // No active draggable\n !activeDraggableNode || // Event has already been captured\n nativeEvent.dndKit || nativeEvent.defaultPrevented) {\n return;\n }\n\n const activationContext = {\n active: activeDraggableNode\n };\n const shouldActivate = handler(event, sensor.options, activationContext);\n\n if (shouldActivate === true) {\n nativeEvent.dndKit = {\n capturedBy: sensor.sensor\n };\n activeRef.current = active;\n instantiateSensor(event, sensor);\n }\n };\n }, [draggableNodes, instantiateSensor]);\n const activators = useCombineActivators(sensors, bindActivatorToSensorInstantiator);\n useSensorSetup(sensors);\n useIsomorphicLayoutEffect(() => {\n if (activeNodeRect && status === Status.Initializing) {\n setStatus(Status.Initialized);\n }\n }, [activeNodeRect, status]);\n useEffect(() => {\n const {\n onDragMove\n } = latestProps.current;\n const {\n active,\n activatorEvent,\n collisions,\n over\n } = sensorContext.current;\n\n if (!active || !activatorEvent) {\n return;\n }\n\n const event = {\n active,\n activatorEvent,\n collisions,\n delta: {\n x: scrollAdjustedTranslate.x,\n y: scrollAdjustedTranslate.y\n },\n over\n };\n unstable_batchedUpdates(() => {\n onDragMove == null ? void 0 : onDragMove(event);\n dispatchMonitorEvent({\n type: 'onDragMove',\n event\n });\n });\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [scrollAdjustedTranslate.x, scrollAdjustedTranslate.y]);\n useEffect(() => {\n const {\n active,\n activatorEvent,\n collisions,\n droppableContainers,\n scrollAdjustedTranslate\n } = sensorContext.current;\n\n if (!active || activeRef.current == null || !activatorEvent || !scrollAdjustedTranslate) {\n return;\n }\n\n const {\n onDragOver\n } = latestProps.current;\n const overContainer = droppableContainers.get(overId);\n const over = overContainer && overContainer.rect.current ? {\n id: overContainer.id,\n rect: overContainer.rect.current,\n data: overContainer.data,\n disabled: overContainer.disabled\n } : null;\n const event = {\n active,\n activatorEvent,\n collisions,\n delta: {\n x: scrollAdjustedTranslate.x,\n y: scrollAdjustedTranslate.y\n },\n over\n };\n unstable_batchedUpdates(() => {\n setOver(over);\n onDragOver == null ? void 0 : onDragOver(event);\n dispatchMonitorEvent({\n type: 'onDragOver',\n event\n });\n });\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [overId]);\n useIsomorphicLayoutEffect(() => {\n sensorContext.current = {\n activatorEvent,\n active,\n activeNode,\n collisionRect,\n collisions,\n droppableRects,\n draggableNodes,\n draggingNode,\n draggingNodeRect,\n droppableContainers,\n over,\n scrollableAncestors,\n scrollAdjustedTranslate\n };\n activeRects.current = {\n initial: draggingNodeRect,\n translated: collisionRect\n };\n }, [active, activeNode, collisions, collisionRect, draggableNodes, draggingNode, draggingNodeRect, droppableRects, droppableContainers, over, scrollableAncestors, scrollAdjustedTranslate]);\n useAutoScroller({ ...autoScrollOptions,\n delta: translate,\n draggingRect: collisionRect,\n pointerCoordinates,\n scrollableAncestors,\n scrollableAncestorRects\n });\n const publicContext = useMemo(() => {\n const context = {\n active,\n activeNode,\n activeNodeRect,\n activatorEvent,\n collisions,\n containerNodeRect,\n dragOverlay,\n draggableNodes,\n droppableContainers,\n droppableRects,\n over,\n measureDroppableContainers,\n scrollableAncestors,\n scrollableAncestorRects,\n measuringConfiguration,\n measuringScheduled,\n windowRect\n };\n return context;\n }, [active, activeNode, activeNodeRect, activatorEvent, collisions, containerNodeRect, dragOverlay, draggableNodes, droppableContainers, droppableRects, over, measureDroppableContainers, scrollableAncestors, scrollableAncestorRects, measuringConfiguration, measuringScheduled, windowRect]);\n const internalContext = useMemo(() => {\n const context = {\n activatorEvent,\n activators,\n active,\n activeNodeRect,\n ariaDescribedById: {\n draggable: draggableDescribedById\n },\n dispatch,\n draggableNodes,\n over,\n measureDroppableContainers\n };\n return context;\n }, [activatorEvent, activators, active, activeNodeRect, dispatch, draggableDescribedById, draggableNodes, over, measureDroppableContainers]);\n return React.createElement(DndMonitorContext.Provider, {\n value: registerMonitorListener\n }, React.createElement(InternalContext.Provider, {\n value: internalContext\n }, React.createElement(PublicContext.Provider, {\n value: publicContext\n }, React.createElement(ActiveDraggableContext.Provider, {\n value: transform\n }, children)), React.createElement(RestoreFocus, {\n disabled: (accessibility == null ? void 0 : accessibility.restoreFocus) === false\n })), React.createElement(Accessibility, { ...accessibility,\n hiddenTextDescribedById: draggableDescribedById\n }));\n\n function getAutoScrollerOptions() {\n const activeSensorDisablesAutoscroll = (activeSensor == null ? void 0 : activeSensor.autoScrollEnabled) === false;\n const autoScrollGloballyDisabled = typeof autoScroll === 'object' ? autoScroll.enabled === false : autoScroll === false;\n const enabled = isInitialized && !activeSensorDisablesAutoscroll && !autoScrollGloballyDisabled;\n\n if (typeof autoScroll === 'object') {\n return { ...autoScroll,\n enabled\n };\n }\n\n return {\n enabled\n };\n }\n});\n\nconst NullContext = /*#__PURE__*/createContext(null);\nconst defaultRole = 'button';\nconst ID_PREFIX = 'Draggable';\nfunction useDraggable(_ref) {\n let {\n id,\n data,\n disabled = false,\n attributes\n } = _ref;\n const key = useUniqueId(ID_PREFIX);\n const {\n activators,\n activatorEvent,\n active,\n activeNodeRect,\n ariaDescribedById,\n draggableNodes,\n over\n } = useContext(InternalContext);\n const {\n role = defaultRole,\n roleDescription = 'draggable',\n tabIndex = 0\n } = attributes != null ? attributes : {};\n const isDragging = (active == null ? void 0 : active.id) === id;\n const transform = useContext(isDragging ? ActiveDraggableContext : NullContext);\n const [node, setNodeRef] = useNodeRef();\n const [activatorNode, setActivatorNodeRef] = useNodeRef();\n const listeners = useSyntheticListeners(activators, id);\n const dataRef = useLatestValue(data);\n useIsomorphicLayoutEffect(() => {\n draggableNodes.set(id, {\n id,\n key,\n node,\n activatorNode,\n data: dataRef\n });\n return () => {\n const node = draggableNodes.get(id);\n\n if (node && node.key === key) {\n draggableNodes.delete(id);\n }\n };\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [draggableNodes, id]);\n const memoizedAttributes = useMemo(() => ({\n role,\n tabIndex,\n 'aria-disabled': disabled,\n 'aria-pressed': isDragging && role === defaultRole ? true : undefined,\n 'aria-roledescription': roleDescription,\n 'aria-describedby': ariaDescribedById.draggable\n }), [disabled, role, tabIndex, isDragging, roleDescription, ariaDescribedById.draggable]);\n return {\n active,\n activatorEvent,\n activeNodeRect,\n attributes: memoizedAttributes,\n isDragging,\n listeners: disabled ? undefined : listeners,\n node,\n over,\n setNodeRef,\n setActivatorNodeRef,\n transform\n };\n}\n\nfunction useDndContext() {\n return useContext(PublicContext);\n}\n\nconst ID_PREFIX$1 = 'Droppable';\nconst defaultResizeObserverConfig = {\n timeout: 25\n};\nfunction useDroppable(_ref) {\n let {\n data,\n disabled = false,\n id,\n resizeObserverConfig\n } = _ref;\n const key = useUniqueId(ID_PREFIX$1);\n const {\n active,\n dispatch,\n over,\n measureDroppableContainers\n } = useContext(InternalContext);\n const previous = useRef({\n disabled\n });\n const resizeObserverConnected = useRef(false);\n const rect = useRef(null);\n const callbackId = useRef(null);\n const {\n disabled: resizeObserverDisabled,\n updateMeasurementsFor,\n timeout: resizeObserverTimeout\n } = { ...defaultResizeObserverConfig,\n ...resizeObserverConfig\n };\n const ids = useLatestValue(updateMeasurementsFor != null ? updateMeasurementsFor : id);\n const handleResize = useCallback(() => {\n if (!resizeObserverConnected.current) {\n // ResizeObserver invokes the `handleResize` callback as soon as `observe` is called,\n // assuming the element is rendered and displayed.\n resizeObserverConnected.current = true;\n return;\n }\n\n if (callbackId.current != null) {\n clearTimeout(callbackId.current);\n }\n\n callbackId.current = setTimeout(() => {\n measureDroppableContainers(Array.isArray(ids.current) ? ids.current : [ids.current]);\n callbackId.current = null;\n }, resizeObserverTimeout);\n }, //eslint-disable-next-line react-hooks/exhaustive-deps\n [resizeObserverTimeout]);\n const resizeObserver = useResizeObserver({\n callback: handleResize,\n disabled: resizeObserverDisabled || !active\n });\n const handleNodeChange = useCallback((newElement, previousElement) => {\n if (!resizeObserver) {\n return;\n }\n\n if (previousElement) {\n resizeObserver.unobserve(previousElement);\n resizeObserverConnected.current = false;\n }\n\n if (newElement) {\n resizeObserver.observe(newElement);\n }\n }, [resizeObserver]);\n const [nodeRef, setNodeRef] = useNodeRef(handleNodeChange);\n const dataRef = useLatestValue(data);\n useEffect(() => {\n if (!resizeObserver || !nodeRef.current) {\n return;\n }\n\n resizeObserver.disconnect();\n resizeObserverConnected.current = false;\n resizeObserver.observe(nodeRef.current);\n }, [nodeRef, resizeObserver]);\n useEffect(() => {\n dispatch({\n type: Action.RegisterDroppable,\n element: {\n id,\n key,\n disabled,\n node: nodeRef,\n rect,\n data: dataRef\n }\n });\n return () => dispatch({\n type: Action.UnregisterDroppable,\n key,\n id\n });\n }, // eslint-disable-next-line react-hooks/exhaustive-deps\n [id]);\n useEffect(() => {\n if (disabled !== previous.current.disabled) {\n dispatch({\n type: Action.SetDroppableDisabled,\n id,\n key,\n disabled\n });\n previous.current.disabled = disabled;\n }\n }, [id, key, disabled, dispatch]);\n return {\n active,\n rect,\n isOver: (over == null ? void 0 : over.id) === id,\n node: nodeRef,\n over,\n setNodeRef\n };\n}\n\nfunction AnimationManager(_ref) {\n let {\n animation,\n children\n } = _ref;\n const [clonedChildren, setClonedChildren] = useState(null);\n const [element, setElement] = useState(null);\n const previousChildren = usePrevious(children);\n\n if (!children && !clonedChildren && previousChildren) {\n setClonedChildren(previousChildren);\n }\n\n useIsomorphicLayoutEffect(() => {\n if (!element) {\n return;\n }\n\n const key = clonedChildren == null ? void 0 : clonedChildren.key;\n const id = clonedChildren == null ? void 0 : clonedChildren.props.id;\n\n if (key == null || id == null) {\n setClonedChildren(null);\n return;\n }\n\n Promise.resolve(animation(id, element)).then(() => {\n setClonedChildren(null);\n });\n }, [animation, clonedChildren, element]);\n return React.createElement(React.Fragment, null, children, clonedChildren ? cloneElement(clonedChildren, {\n ref: setElement\n }) : null);\n}\n\nconst defaultTransform = {\n x: 0,\n y: 0,\n scaleX: 1,\n scaleY: 1\n};\nfunction NullifiedContextProvider(_ref) {\n let {\n children\n } = _ref;\n return React.createElement(InternalContext.Provider, {\n value: defaultInternalContext\n }, React.createElement(ActiveDraggableContext.Provider, {\n value: defaultTransform\n }, children));\n}\n\nconst baseStyles = {\n position: 'fixed',\n touchAction: 'none'\n};\n\nconst defaultTransition = activatorEvent => {\n const isKeyboardActivator = isKeyboardEvent(activatorEvent);\n return isKeyboardActivator ? 'transform 250ms ease' : undefined;\n};\n\nconst PositionedOverlay = /*#__PURE__*/forwardRef((_ref, ref) => {\n let {\n as,\n activatorEvent,\n adjustScale,\n children,\n className,\n rect,\n style,\n transform,\n transition = defaultTransition\n } = _ref;\n\n if (!rect) {\n return null;\n }\n\n const scaleAdjustedTransform = adjustScale ? transform : { ...transform,\n scaleX: 1,\n scaleY: 1\n };\n const styles = { ...baseStyles,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n left: rect.left,\n transform: CSS.Transform.toString(scaleAdjustedTransform),\n transformOrigin: adjustScale && activatorEvent ? getRelativeTransformOrigin(activatorEvent, rect) : undefined,\n transition: typeof transition === 'function' ? transition(activatorEvent) : transition,\n ...style\n };\n return React.createElement(as, {\n className,\n style: styles,\n ref\n }, children);\n});\n\nconst defaultDropAnimationSideEffects = options => _ref => {\n let {\n active,\n dragOverlay\n } = _ref;\n const originalStyles = {};\n const {\n styles,\n className\n } = options;\n\n if (styles != null && styles.active) {\n for (const [key, value] of Object.entries(styles.active)) {\n if (value === undefined) {\n continue;\n }\n\n originalStyles[key] = active.node.style.getPropertyValue(key);\n active.node.style.setProperty(key, value);\n }\n }\n\n if (styles != null && styles.dragOverlay) {\n for (const [key, value] of Object.entries(styles.dragOverlay)) {\n if (value === undefined) {\n continue;\n }\n\n dragOverlay.node.style.setProperty(key, value);\n }\n }\n\n if (className != null && className.active) {\n active.node.classList.add(className.active);\n }\n\n if (className != null && className.dragOverlay) {\n dragOverlay.node.classList.add(className.dragOverlay);\n }\n\n return function cleanup() {\n for (const [key, value] of Object.entries(originalStyles)) {\n active.node.style.setProperty(key, value);\n }\n\n if (className != null && className.active) {\n active.node.classList.remove(className.active);\n }\n };\n};\n\nconst defaultKeyframeResolver = _ref2 => {\n let {\n transform: {\n initial,\n final\n }\n } = _ref2;\n return [{\n transform: CSS.Transform.toString(initial)\n }, {\n transform: CSS.Transform.toString(final)\n }];\n};\n\nconst defaultDropAnimationConfiguration = {\n duration: 250,\n easing: 'ease',\n keyframes: defaultKeyframeResolver,\n sideEffects: /*#__PURE__*/defaultDropAnimationSideEffects({\n styles: {\n active: {\n opacity: '0'\n }\n }\n })\n};\nfunction useDropAnimation(_ref3) {\n let {\n config,\n draggableNodes,\n droppableContainers,\n measuringConfiguration\n } = _ref3;\n return useEvent((id, node) => {\n if (config === null) {\n return;\n }\n\n const activeDraggable = draggableNodes.get(id);\n\n if (!activeDraggable) {\n return;\n }\n\n const activeNode = activeDraggable.node.current;\n\n if (!activeNode) {\n return;\n }\n\n const measurableNode = getMeasurableNode(node);\n\n if (!measurableNode) {\n return;\n }\n\n const {\n transform\n } = getWindow(node).getComputedStyle(node);\n const parsedTransform = parseTransform(transform);\n\n if (!parsedTransform) {\n return;\n }\n\n const animation = typeof config === 'function' ? config : createDefaultDropAnimation(config);\n scrollIntoViewIfNeeded(activeNode, measuringConfiguration.draggable.measure);\n return animation({\n active: {\n id,\n data: activeDraggable.data,\n node: activeNode,\n rect: measuringConfiguration.draggable.measure(activeNode)\n },\n draggableNodes,\n dragOverlay: {\n node,\n rect: measuringConfiguration.dragOverlay.measure(measurableNode)\n },\n droppableContainers,\n measuringConfiguration,\n transform: parsedTransform\n });\n });\n}\n\nfunction createDefaultDropAnimation(options) {\n const {\n duration,\n easing,\n sideEffects,\n keyframes\n } = { ...defaultDropAnimationConfiguration,\n ...options\n };\n return _ref4 => {\n let {\n active,\n dragOverlay,\n transform,\n ...rest\n } = _ref4;\n\n if (!duration) {\n // Do not animate if animation duration is zero.\n return;\n }\n\n const delta = {\n x: dragOverlay.rect.left - active.rect.left,\n y: dragOverlay.rect.top - active.rect.top\n };\n const scale = {\n scaleX: transform.scaleX !== 1 ? active.rect.width * transform.scaleX / dragOverlay.rect.width : 1,\n scaleY: transform.scaleY !== 1 ? active.rect.height * transform.scaleY / dragOverlay.rect.height : 1\n };\n const finalTransform = {\n x: transform.x - delta.x,\n y: transform.y - delta.y,\n ...scale\n };\n const animationKeyframes = keyframes({ ...rest,\n active,\n dragOverlay,\n transform: {\n initial: transform,\n final: finalTransform\n }\n });\n const [firstKeyframe] = animationKeyframes;\n const lastKeyframe = animationKeyframes[animationKeyframes.length - 1];\n\n if (JSON.stringify(firstKeyframe) === JSON.stringify(lastKeyframe)) {\n // The start and end keyframes are the same, infer that there is no animation needed.\n return;\n }\n\n const cleanup = sideEffects == null ? void 0 : sideEffects({\n active,\n dragOverlay,\n ...rest\n });\n const animation = dragOverlay.node.animate(animationKeyframes, {\n duration,\n easing,\n fill: 'forwards'\n });\n return new Promise(resolve => {\n animation.onfinish = () => {\n cleanup == null ? void 0 : cleanup();\n resolve();\n };\n });\n };\n}\n\nlet key = 0;\nfunction useKey(id) {\n return useMemo(() => {\n if (id == null) {\n return;\n }\n\n key++;\n return key;\n }, [id]);\n}\n\nconst DragOverlay = /*#__PURE__*/React.memo(_ref => {\n let {\n adjustScale = false,\n children,\n dropAnimation: dropAnimationConfig,\n style,\n transition,\n modifiers,\n wrapperElement = 'div',\n className,\n zIndex = 999\n } = _ref;\n const {\n activatorEvent,\n active,\n activeNodeRect,\n containerNodeRect,\n draggableNodes,\n droppableContainers,\n dragOverlay,\n over,\n measuringConfiguration,\n scrollableAncestors,\n scrollableAncestorRects,\n windowRect\n } = useDndContext();\n const transform = useContext(ActiveDraggableContext);\n const key = useKey(active == null ? void 0 : active.id);\n const modifiedTransform = applyModifiers(modifiers, {\n activatorEvent,\n active,\n activeNodeRect,\n containerNodeRect,\n draggingNodeRect: dragOverlay.rect,\n over,\n overlayNodeRect: dragOverlay.rect,\n scrollableAncestors,\n scrollableAncestorRects,\n transform,\n windowRect\n });\n const initialRect = useInitialValue(activeNodeRect);\n const dropAnimation = useDropAnimation({\n config: dropAnimationConfig,\n draggableNodes,\n droppableContainers,\n measuringConfiguration\n }); // We need to wait for the active node to be measured before connecting the drag overlay ref\n // otherwise collisions can be computed against a mispositioned drag overlay\n\n const ref = initialRect ? dragOverlay.setRef : undefined;\n return React.createElement(NullifiedContextProvider, null, React.createElement(AnimationManager, {\n animation: dropAnimation\n }, active && key ? React.createElement(PositionedOverlay, {\n key: key,\n id: active.id,\n ref: ref,\n as: wrapperElement,\n activatorEvent: activatorEvent,\n adjustScale: adjustScale,\n className: className,\n transition: transition,\n rect: initialRect,\n style: {\n zIndex,\n ...style\n },\n transform: modifiedTransform\n }, children) : null));\n});\n\nexport { AutoScrollActivator, DndContext, DragOverlay, KeyboardCode, KeyboardSensor, MeasuringFrequency, MeasuringStrategy, MouseSensor, PointerSensor, TouchSensor, TraversalOrder, applyModifiers, closestCenter, closestCorners, defaultAnnouncements, defaultCoordinates, defaultDropAnimationConfiguration as defaultDropAnimation, defaultDropAnimationSideEffects, defaultKeyboardCoordinateGetter, defaultScreenReaderInstructions, getClientRect, getFirstCollision, getScrollableAncestors, pointerWithin, rectIntersection, useDndContext, useDndMonitor, useDraggable, useDroppable, useSensor, useSensors };\n//# sourceMappingURL=core.esm.js.map\n","import React, { useMemo, useRef, useEffect, useState, useContext } from 'react';\nimport { useDndContext, getClientRect, useDroppable, useDraggable, closestCorners, getFirstCollision, getScrollableAncestors, KeyboardCode } from '@dnd-kit/core';\nimport { useUniqueId, useIsomorphicLayoutEffect, CSS, useCombinedRefs, isKeyboardEvent, subtract } from '@dnd-kit/utilities';\n\n/**\r\n * Move an array item to a different position. Returns a new array with the item moved to the new position.\r\n */\nfunction arrayMove(array, from, to) {\n const newArray = array.slice();\n newArray.splice(to < 0 ? newArray.length + to : to, 0, newArray.splice(from, 1)[0]);\n return newArray;\n}\n\n/**\r\n * Swap an array item to a different position. Returns a new array with the item swapped to the new position.\r\n */\nfunction arraySwap(array, from, to) {\n const newArray = array.slice();\n newArray[from] = array[to];\n newArray[to] = array[from];\n return newArray;\n}\n\nfunction getSortedRects(items, rects) {\n return items.reduce((accumulator, id, index) => {\n const rect = rects.get(id);\n\n if (rect) {\n accumulator[index] = rect;\n }\n\n return accumulator;\n }, Array(items.length));\n}\n\nfunction isValidIndex(index) {\n return index !== null && index >= 0;\n}\n\nfunction itemsEqual(a, b) {\n if (a === b) {\n return true;\n }\n\n if (a.length !== b.length) {\n return false;\n }\n\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction normalizeDisabled(disabled) {\n if (typeof disabled === 'boolean') {\n return {\n draggable: disabled,\n droppable: disabled\n };\n }\n\n return disabled;\n}\n\n// To-do: We should be calculating scale transformation\nconst defaultScale = {\n scaleX: 1,\n scaleY: 1\n};\nconst horizontalListSortingStrategy = _ref => {\n var _rects$activeIndex;\n\n let {\n rects,\n activeNodeRect: fallbackActiveRect,\n activeIndex,\n overIndex,\n index\n } = _ref;\n const activeNodeRect = (_rects$activeIndex = rects[activeIndex]) != null ? _rects$activeIndex : fallbackActiveRect;\n\n if (!activeNodeRect) {\n return null;\n }\n\n const itemGap = getItemGap(rects, index, activeIndex);\n\n if (index === activeIndex) {\n const newIndexRect = rects[overIndex];\n\n if (!newIndexRect) {\n return null;\n }\n\n return {\n x: activeIndex < overIndex ? newIndexRect.left + newIndexRect.width - (activeNodeRect.left + activeNodeRect.width) : newIndexRect.left - activeNodeRect.left,\n y: 0,\n ...defaultScale\n };\n }\n\n if (index > activeIndex && index <= overIndex) {\n return {\n x: -activeNodeRect.width - itemGap,\n y: 0,\n ...defaultScale\n };\n }\n\n if (index < activeIndex && index >= overIndex) {\n return {\n x: activeNodeRect.width + itemGap,\n y: 0,\n ...defaultScale\n };\n }\n\n return {\n x: 0,\n y: 0,\n ...defaultScale\n };\n};\n\nfunction getItemGap(rects, index, activeIndex) {\n const currentRect = rects[index];\n const previousRect = rects[index - 1];\n const nextRect = rects[index + 1];\n\n if (!currentRect || !previousRect && !nextRect) {\n return 0;\n }\n\n if (activeIndex < index) {\n return previousRect ? currentRect.left - (previousRect.left + previousRect.width) : nextRect.left - (currentRect.left + currentRect.width);\n }\n\n return nextRect ? nextRect.left - (currentRect.left + currentRect.width) : currentRect.left - (previousRect.left + previousRect.width);\n}\n\nconst rectSortingStrategy = _ref => {\n let {\n rects,\n activeIndex,\n overIndex,\n index\n } = _ref;\n const newRects = arrayMove(rects, overIndex, activeIndex);\n const oldRect = rects[index];\n const newRect = newRects[index];\n\n if (!newRect || !oldRect) {\n return null;\n }\n\n return {\n x: newRect.left - oldRect.left,\n y: newRect.top - oldRect.top,\n scaleX: newRect.width / oldRect.width,\n scaleY: newRect.height / oldRect.height\n };\n};\n\nconst rectSwappingStrategy = _ref => {\n let {\n activeIndex,\n index,\n rects,\n overIndex\n } = _ref;\n let oldRect;\n let newRect;\n\n if (index === activeIndex) {\n oldRect = rects[index];\n newRect = rects[overIndex];\n }\n\n if (index === overIndex) {\n oldRect = rects[index];\n newRect = rects[activeIndex];\n }\n\n if (!newRect || !oldRect) {\n return null;\n }\n\n return {\n x: newRect.left - oldRect.left,\n y: newRect.top - oldRect.top,\n scaleX: newRect.width / oldRect.width,\n scaleY: newRect.height / oldRect.height\n };\n};\n\n// To-do: We should be calculating scale transformation\nconst defaultScale$1 = {\n scaleX: 1,\n scaleY: 1\n};\nconst verticalListSortingStrategy = _ref => {\n var _rects$activeIndex;\n\n let {\n activeIndex,\n activeNodeRect: fallbackActiveRect,\n index,\n rects,\n overIndex\n } = _ref;\n const activeNodeRect = (_rects$activeIndex = rects[activeIndex]) != null ? _rects$activeIndex : fallbackActiveRect;\n\n if (!activeNodeRect) {\n return null;\n }\n\n if (index === activeIndex) {\n const overIndexRect = rects[overIndex];\n\n if (!overIndexRect) {\n return null;\n }\n\n return {\n x: 0,\n y: activeIndex < overIndex ? overIndexRect.top + overIndexRect.height - (activeNodeRect.top + activeNodeRect.height) : overIndexRect.top - activeNodeRect.top,\n ...defaultScale$1\n };\n }\n\n const itemGap = getItemGap$1(rects, index, activeIndex);\n\n if (index > activeIndex && index <= overIndex) {\n return {\n x: 0,\n y: -activeNodeRect.height - itemGap,\n ...defaultScale$1\n };\n }\n\n if (index < activeIndex && index >= overIndex) {\n return {\n x: 0,\n y: activeNodeRect.height + itemGap,\n ...defaultScale$1\n };\n }\n\n return {\n x: 0,\n y: 0,\n ...defaultScale$1\n };\n};\n\nfunction getItemGap$1(clientRects, index, activeIndex) {\n const currentRect = clientRects[index];\n const previousRect = clientRects[index - 1];\n const nextRect = clientRects[index + 1];\n\n if (!currentRect) {\n return 0;\n }\n\n if (activeIndex < index) {\n return previousRect ? currentRect.top - (previousRect.top + previousRect.height) : nextRect ? nextRect.top - (currentRect.top + currentRect.height) : 0;\n }\n\n return nextRect ? nextRect.top - (currentRect.top + currentRect.height) : previousRect ? currentRect.top - (previousRect.top + previousRect.height) : 0;\n}\n\nconst ID_PREFIX = 'Sortable';\nconst Context = /*#__PURE__*/React.createContext({\n activeIndex: -1,\n containerId: ID_PREFIX,\n disableTransforms: false,\n items: [],\n overIndex: -1,\n useDragOverlay: false,\n sortedRects: [],\n strategy: rectSortingStrategy,\n disabled: {\n draggable: false,\n droppable: false\n }\n});\nfunction SortableContext(_ref) {\n let {\n children,\n id,\n items: userDefinedItems,\n strategy = rectSortingStrategy,\n disabled: disabledProp = false\n } = _ref;\n const {\n active,\n dragOverlay,\n droppableRects,\n over,\n measureDroppableContainers\n } = useDndContext();\n const containerId = useUniqueId(ID_PREFIX, id);\n const useDragOverlay = Boolean(dragOverlay.rect !== null);\n const items = useMemo(() => userDefinedItems.map(item => typeof item === 'object' && 'id' in item ? item.id : item), [userDefinedItems]);\n const isDragging = active != null;\n const activeIndex = active ? items.indexOf(active.id) : -1;\n const overIndex = over ? items.indexOf(over.id) : -1;\n const previousItemsRef = useRef(items);\n const itemsHaveChanged = !itemsEqual(items, previousItemsRef.current);\n const disableTransforms = overIndex !== -1 && activeIndex === -1 || itemsHaveChanged;\n const disabled = normalizeDisabled(disabledProp);\n useIsomorphicLayoutEffect(() => {\n if (itemsHaveChanged && isDragging) {\n measureDroppableContainers(items);\n }\n }, [itemsHaveChanged, items, isDragging, measureDroppableContainers]);\n useEffect(() => {\n previousItemsRef.current = items;\n }, [items]);\n const contextValue = useMemo(() => ({\n activeIndex,\n containerId,\n disabled,\n disableTransforms,\n items,\n overIndex,\n useDragOverlay,\n sortedRects: getSortedRects(items, droppableRects),\n strategy\n }), // eslint-disable-next-line react-hooks/exhaustive-deps\n [activeIndex, containerId, disabled.draggable, disabled.droppable, disableTransforms, items, overIndex, droppableRects, useDragOverlay, strategy]);\n return React.createElement(Context.Provider, {\n value: contextValue\n }, children);\n}\n\nconst defaultNewIndexGetter = _ref => {\n let {\n id,\n items,\n activeIndex,\n overIndex\n } = _ref;\n return arrayMove(items, activeIndex, overIndex).indexOf(id);\n};\nconst defaultAnimateLayoutChanges = _ref2 => {\n let {\n containerId,\n isSorting,\n wasDragging,\n index,\n items,\n newIndex,\n previousItems,\n previousContainerId,\n transition\n } = _ref2;\n\n if (!transition || !wasDragging) {\n return false;\n }\n\n if (previousItems !== items && index === newIndex) {\n return false;\n }\n\n if (isSorting) {\n return true;\n }\n\n return newIndex !== index && containerId === previousContainerId;\n};\nconst defaultTransition = {\n duration: 200,\n easing: 'ease'\n};\nconst transitionProperty = 'transform';\nconst disabledTransition = /*#__PURE__*/CSS.Transition.toString({\n property: transitionProperty,\n duration: 0,\n easing: 'linear'\n});\nconst defaultAttributes = {\n roleDescription: 'sortable'\n};\n\n/*\r\n * When the index of an item changes while sorting,\r\n * we need to temporarily disable the transforms\r\n */\n\nfunction useDerivedTransform(_ref) {\n let {\n disabled,\n index,\n node,\n rect\n } = _ref;\n const [derivedTransform, setDerivedtransform] = useState(null);\n const previousIndex = useRef(index);\n useIsomorphicLayoutEffect(() => {\n if (!disabled && index !== previousIndex.current && node.current) {\n const initial = rect.current;\n\n if (initial) {\n const current = getClientRect(node.current, {\n ignoreTransform: true\n });\n const delta = {\n x: initial.left - current.left,\n y: initial.top - current.top,\n scaleX: initial.width / current.width,\n scaleY: initial.height / current.height\n };\n\n if (delta.x || delta.y) {\n setDerivedtransform(delta);\n }\n }\n }\n\n if (index !== previousIndex.current) {\n previousIndex.current = index;\n }\n }, [disabled, index, node, rect]);\n useEffect(() => {\n if (derivedTransform) {\n setDerivedtransform(null);\n }\n }, [derivedTransform]);\n return derivedTransform;\n}\n\nfunction useSortable(_ref) {\n let {\n animateLayoutChanges = defaultAnimateLayoutChanges,\n attributes: userDefinedAttributes,\n disabled: localDisabled,\n data: customData,\n getNewIndex = defaultNewIndexGetter,\n id,\n strategy: localStrategy,\n resizeObserverConfig,\n transition = defaultTransition\n } = _ref;\n const {\n items,\n containerId,\n activeIndex,\n disabled: globalDisabled,\n disableTransforms,\n sortedRects,\n overIndex,\n useDragOverlay,\n strategy: globalStrategy\n } = useContext(Context);\n const disabled = normalizeLocalDisabled(localDisabled, globalDisabled);\n const index = items.indexOf(id);\n const data = useMemo(() => ({\n sortable: {\n containerId,\n index,\n items\n },\n ...customData\n }), [containerId, customData, index, items]);\n const itemsAfterCurrentSortable = useMemo(() => items.slice(items.indexOf(id)), [items, id]);\n const {\n rect,\n node,\n isOver,\n setNodeRef: setDroppableNodeRef\n } = useDroppable({\n id,\n data,\n disabled: disabled.droppable,\n resizeObserverConfig: {\n updateMeasurementsFor: itemsAfterCurrentSortable,\n ...resizeObserverConfig\n }\n });\n const {\n active,\n activatorEvent,\n activeNodeRect,\n attributes,\n setNodeRef: setDraggableNodeRef,\n listeners,\n isDragging,\n over,\n setActivatorNodeRef,\n transform\n } = useDraggable({\n id,\n data,\n attributes: { ...defaultAttributes,\n ...userDefinedAttributes\n },\n disabled: disabled.draggable\n });\n const setNodeRef = useCombinedRefs(setDroppableNodeRef, setDraggableNodeRef);\n const isSorting = Boolean(active);\n const displaceItem = isSorting && !disableTransforms && isValidIndex(activeIndex) && isValidIndex(overIndex);\n const shouldDisplaceDragSource = !useDragOverlay && isDragging;\n const dragSourceDisplacement = shouldDisplaceDragSource && displaceItem ? transform : null;\n const strategy = localStrategy != null ? localStrategy : globalStrategy;\n const finalTransform = displaceItem ? dragSourceDisplacement != null ? dragSourceDisplacement : strategy({\n rects: sortedRects,\n activeNodeRect,\n activeIndex,\n overIndex,\n index\n }) : null;\n const newIndex = isValidIndex(activeIndex) && isValidIndex(overIndex) ? getNewIndex({\n id,\n items,\n activeIndex,\n overIndex\n }) : index;\n const activeId = active == null ? void 0 : active.id;\n const previous = useRef({\n activeId,\n items,\n newIndex,\n containerId\n });\n const itemsHaveChanged = items !== previous.current.items;\n const shouldAnimateLayoutChanges = animateLayoutChanges({\n active,\n containerId,\n isDragging,\n isSorting,\n id,\n index,\n items,\n newIndex: previous.current.newIndex,\n previousItems: previous.current.items,\n previousContainerId: previous.current.containerId,\n transition,\n wasDragging: previous.current.activeId != null\n });\n const derivedTransform = useDerivedTransform({\n disabled: !shouldAnimateLayoutChanges,\n index,\n node,\n rect\n });\n useEffect(() => {\n if (isSorting && previous.current.newIndex !== newIndex) {\n previous.current.newIndex = newIndex;\n }\n\n if (containerId !== previous.current.containerId) {\n previous.current.containerId = containerId;\n }\n\n if (items !== previous.current.items) {\n previous.current.items = items;\n }\n }, [isSorting, newIndex, containerId, items]);\n useEffect(() => {\n if (activeId === previous.current.activeId) {\n return;\n }\n\n if (activeId != null && previous.current.activeId == null) {\n previous.current.activeId = activeId;\n return;\n }\n\n const timeoutId = setTimeout(() => {\n previous.current.activeId = activeId;\n }, 50);\n return () => clearTimeout(timeoutId);\n }, [activeId]);\n return {\n active,\n activeIndex,\n attributes,\n data,\n rect,\n index,\n newIndex,\n items,\n isOver,\n isSorting,\n isDragging,\n listeners,\n node,\n overIndex,\n over,\n setNodeRef,\n setActivatorNodeRef,\n setDroppableNodeRef,\n setDraggableNodeRef,\n transform: derivedTransform != null ? derivedTransform : finalTransform,\n transition: getTransition()\n };\n\n function getTransition() {\n if ( // Temporarily disable transitions for a single frame to set up derived transforms\n derivedTransform || // Or to prevent items jumping to back to their \"new\" position when items change\n itemsHaveChanged && previous.current.newIndex === index) {\n return disabledTransition;\n }\n\n if (shouldDisplaceDragSource && !isKeyboardEvent(activatorEvent) || !transition) {\n return undefined;\n }\n\n if (isSorting || shouldAnimateLayoutChanges) {\n return CSS.Transition.toString({ ...transition,\n property: transitionProperty\n });\n }\n\n return undefined;\n }\n}\n\nfunction normalizeLocalDisabled(localDisabled, globalDisabled) {\n var _localDisabled$dragga, _localDisabled$droppa;\n\n if (typeof localDisabled === 'boolean') {\n return {\n draggable: localDisabled,\n // Backwards compatibility\n droppable: false\n };\n }\n\n return {\n draggable: (_localDisabled$dragga = localDisabled == null ? void 0 : localDisabled.draggable) != null ? _localDisabled$dragga : globalDisabled.draggable,\n droppable: (_localDisabled$droppa = localDisabled == null ? void 0 : localDisabled.droppable) != null ? _localDisabled$droppa : globalDisabled.droppable\n };\n}\n\nfunction hasSortableData(entry) {\n if (!entry) {\n return false;\n }\n\n const data = entry.data.current;\n\n if (data && 'sortable' in data && typeof data.sortable === 'object' && 'containerId' in data.sortable && 'items' in data.sortable && 'index' in data.sortable) {\n return true;\n }\n\n return false;\n}\n\nconst directions = [KeyboardCode.Down, KeyboardCode.Right, KeyboardCode.Up, KeyboardCode.Left];\nconst sortableKeyboardCoordinates = (event, _ref) => {\n let {\n context: {\n active,\n collisionRect,\n droppableRects,\n droppableContainers,\n over,\n scrollableAncestors\n }\n } = _ref;\n\n if (directions.includes(event.code)) {\n event.preventDefault();\n\n if (!active || !collisionRect) {\n return;\n }\n\n const filteredContainers = [];\n droppableContainers.getEnabled().forEach(entry => {\n if (!entry || entry != null && entry.disabled) {\n return;\n }\n\n const rect = droppableRects.get(entry.id);\n\n if (!rect) {\n return;\n }\n\n switch (event.code) {\n case KeyboardCode.Down:\n if (collisionRect.top < rect.top) {\n filteredContainers.push(entry);\n }\n\n break;\n\n case KeyboardCode.Up:\n if (collisionRect.top > rect.top) {\n filteredContainers.push(entry);\n }\n\n break;\n\n case KeyboardCode.Left:\n if (collisionRect.left > rect.left) {\n filteredContainers.push(entry);\n }\n\n break;\n\n case KeyboardCode.Right:\n if (collisionRect.left < rect.left) {\n filteredContainers.push(entry);\n }\n\n break;\n }\n });\n const collisions = closestCorners({\n active,\n collisionRect: collisionRect,\n droppableRects,\n droppableContainers: filteredContainers,\n pointerCoordinates: null\n });\n let closestId = getFirstCollision(collisions, 'id');\n\n if (closestId === (over == null ? void 0 : over.id) && collisions.length > 1) {\n closestId = collisions[1].id;\n }\n\n if (closestId != null) {\n const activeDroppable = droppableContainers.get(active.id);\n const newDroppable = droppableContainers.get(closestId);\n const newRect = newDroppable ? droppableRects.get(newDroppable.id) : null;\n const newNode = newDroppable == null ? void 0 : newDroppable.node.current;\n\n if (newNode && newRect && activeDroppable && newDroppable) {\n const newScrollAncestors = getScrollableAncestors(newNode);\n const hasDifferentScrollAncestors = newScrollAncestors.some((element, index) => scrollableAncestors[index] !== element);\n const hasSameContainer = isSameContainer(activeDroppable, newDroppable);\n const isAfterActive = isAfter(activeDroppable, newDroppable);\n const offset = hasDifferentScrollAncestors || !hasSameContainer ? {\n x: 0,\n y: 0\n } : {\n x: isAfterActive ? collisionRect.width - newRect.width : 0,\n y: isAfterActive ? collisionRect.height - newRect.height : 0\n };\n const rectCoordinates = {\n x: newRect.left,\n y: newRect.top\n };\n const newCoordinates = offset.x && offset.y ? rectCoordinates : subtract(rectCoordinates, offset);\n return newCoordinates;\n }\n }\n }\n\n return undefined;\n};\n\nfunction isSameContainer(a, b) {\n if (!hasSortableData(a) || !hasSortableData(b)) {\n return false;\n }\n\n return a.data.current.sortable.containerId === b.data.current.sortable.containerId;\n}\n\nfunction isAfter(a, b) {\n if (!hasSortableData(a) || !hasSortableData(b)) {\n return false;\n }\n\n if (!isSameContainer(a, b)) {\n return false;\n }\n\n return a.data.current.sortable.index < b.data.current.sortable.index;\n}\n\nexport { SortableContext, arrayMove, arraySwap, defaultAnimateLayoutChanges, defaultNewIndexGetter, hasSortableData, horizontalListSortingStrategy, rectSortingStrategy, rectSwappingStrategy, sortableKeyboardCoordinates, useSortable, verticalListSortingStrategy };\n//# sourceMappingURL=sortable.esm.js.map\n","/**\n * useLayerDndKit - Touch-friendly drag-drop for layer reordering\n *\n * Replaces the HTML5-based useLayerDragDrop with @dnd-kit for proper\n * touch support on iOS Safari and mobile browsers.\n *\n * Drop position logic mirrors the original hook:\n * - Groups: top 25% = before, middle 50% = into, bottom 25% = after\n * - Non-groups: top/bottom split at midpoint\n *\n * Display order inversion is applied before callbacks (visual \"before\"\n * = array \"after\") since layers are shown in reverse z-order.\n *\n * ARCHITECTURE:\n *\n * Zone calculation (before/into/after) happens inside the custom\n * CollisionDetection function in LayersPanel.tsx. It runs on every\n * render during a drag and has direct access to pointerCoordinates\n * and droppable rects — no manual pointer tracking or React batching\n * issues.\n *\n * The zone is encoded in collision.data.zone and read here via\n * event.collisions. A ref ensures handleDragEnd always reads the\n * latest zone value.\n */\n\nimport { useState, useCallback, useRef } from 'react';\nimport {\n useSensor,\n useSensors,\n PointerSensor,\n KeyboardSensor,\n type DragStartEvent,\n type DragMoveEvent,\n type DragOverEvent,\n type DragEndEvent,\n type DragCancelEvent,\n} from '@dnd-kit/core';\nimport { sortableKeyboardCoordinates } from '@dnd-kit/sortable';\nimport { GroupElement } from '../core/GroupElement.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\n\nexport interface UseLayerDndKitOptions {\n onReorder: (draggedId: string, targetId: string, position: 'before' | 'after') => void;\n onGroupReorder?: (\n draggedId: string,\n targetId: string,\n position: 'before' | 'after',\n groupId: string\n ) => void;\n onDropIntoGroup?: (draggedId: string, groupId: string) => void;\n onDropIntoGroupAtPosition?: (\n draggedId: string,\n groupId: string,\n targetChildId: string,\n position: 'before' | 'after'\n ) => void;\n onRemoveFromGroup?: (draggedId: string) => void;\n findElement?: (id: string) => EditorElement | null;\n findParentGroup?: (id: string) => GroupElement | null;\n}\n\nexport interface UseLayerDndKitReturn {\n activeId: string | null;\n overId: string | null;\n dropPosition: 'before' | 'after' | 'into' | null;\n sensors: ReturnType<typeof useSensors>;\n onDragStart: (event: DragStartEvent) => void;\n onDragMove: (event: DragMoveEvent) => void;\n onDragOver: (event: DragOverEvent) => void;\n onDragEnd: (event: DragEndEvent) => void;\n onDragCancel: (event: DragCancelEvent) => void;\n}\n\n/** Extract zone from collision data set by layerCollisionDetection */\nfunction getZoneFromCollisions(\n collisions: DragOverEvent['collisions']\n): 'before' | 'after' | 'into' | null {\n if (!collisions || collisions.length === 0) return null;\n const zone = (collisions[0].data as Record<string, unknown>)?.zone;\n if (zone === 'before' || zone === 'after' || zone === 'into') return zone;\n return null;\n}\n\nexport function useLayerDndKit(options: UseLayerDndKitOptions): UseLayerDndKitReturn {\n const {\n onReorder,\n onGroupReorder,\n onDropIntoGroup,\n onDropIntoGroupAtPosition,\n onRemoveFromGroup,\n findParentGroup,\n } = options;\n\n // State for rendering (drives UI indicators)\n const [activeId, setActiveId] = useState<string | null>(null);\n const [overId, setOverId] = useState<string | null>(null);\n const [dropPosition, setDropPosition] = useState<'before' | 'after' | 'into' | null>(null);\n\n // Ref for synchronous access in onDragEnd (avoids React batching issues)\n const dropPositionRef = useRef<'before' | 'after' | 'into' | null>(null);\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 5,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n })\n );\n\n const handleDragStart = useCallback((event: DragStartEvent) => {\n setActiveId(String(event.active.id));\n }, []);\n\n // onDragOver: fires when overId changes\n const handleDragOver = useCallback(\n (event: DragOverEvent) => {\n const { over, collisions } = event;\n setOverId(over ? String(over.id) : null);\n const zone = getZoneFromCollisions(collisions);\n dropPositionRef.current = zone;\n setDropPosition(zone);\n },\n []\n );\n\n // onDragMove: fires on every pointer movement — update zone from collisions\n const handleDragMove = useCallback(\n (event: DragMoveEvent) => {\n const { collisions } = event;\n const zone = getZoneFromCollisions(collisions);\n dropPositionRef.current = zone;\n setDropPosition(zone);\n },\n []\n );\n\n const resetState = useCallback(() => {\n dropPositionRef.current = null;\n setActiveId(null);\n setOverId(null);\n setDropPosition(null);\n }, []);\n\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n // Read from ref for guaranteed latest value\n const currentDropPosition = dropPositionRef.current;\n\n if (!over || active.id === over.id || !currentDropPosition) {\n resetState();\n return;\n }\n\n const draggedId = String(active.id);\n const targetId = String(over.id);\n\n // Group footer drop zone — below a group's children\n if (targetId.startsWith('group-footer::')) {\n const groupId = targetId.replace('group-footer::', '');\n const draggedParent = findParentGroup?.(draggedId);\n\n if (draggedParent && draggedParent.id === groupId) {\n // Dragged from inside the same group → promote to top level\n onRemoveFromGroup?.(draggedId);\n } else {\n // Dragged from outside (top-level or different group) → reorder after the group\n // Visual \"after\" (below) in reverse display = \"before\" in array order\n onReorder(draggedId, groupId, 'before');\n }\n resetState();\n return;\n }\n\n if (currentDropPosition === 'into') {\n onDropIntoGroup?.(draggedId, targetId);\n } else {\n // Invert position for display order (layers shown in reverse z-order)\n const arrayPosition = currentDropPosition === 'before' ? 'after' : 'before';\n\n const draggedParent = findParentGroup?.(draggedId);\n const targetParent = findParentGroup?.(targetId);\n\n if (draggedParent && targetParent && draggedParent.id === targetParent.id) {\n onGroupReorder?.(draggedId, targetId, arrayPosition, draggedParent.id!);\n } else if (!draggedParent && targetParent && onDropIntoGroupAtPosition) {\n onDropIntoGroupAtPosition(draggedId, targetParent.id!, targetId, arrayPosition);\n } else {\n onReorder(draggedId, targetId, arrayPosition);\n }\n }\n\n resetState();\n },\n [\n onReorder,\n onGroupReorder,\n onDropIntoGroup,\n onDropIntoGroupAtPosition,\n onRemoveFromGroup,\n findParentGroup,\n resetState,\n ]\n );\n\n const handleDragCancel = useCallback(() => {\n resetState();\n }, [resetState]);\n\n return {\n activeId,\n overId,\n dropPosition,\n sensors,\n onDragStart: handleDragStart,\n onDragMove: handleDragMove,\n onDragOver: handleDragOver,\n onDragEnd: handleDragEnd,\n onDragCancel: handleDragCancel,\n };\n}\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","/**\n * NormalizedIcon - Renders icons with visual size normalization across icon sets\n *\n * Different icon sets have different visual weight at the same CSS size.\n * This component applies per-set scaling factors to achieve visual consistency.\n *\n * @example\n * // Standard sizes\n * <NormalizedIcon icon=\"lucide:crop\" size=\"md\" />\n * <NormalizedIcon icon=\"gravity-ui:sparkles\" size=\"lg\" />\n *\n * @example\n * // Responsive toolbar size (24px mobile, 20px desktop)\n * <NormalizedIcon icon=\"gravity-ui:bold\" size=\"toolbar\" />\n *\n * @example\n * // With additional className\n * <NormalizedIcon icon=\"lucide:trash\" size=\"md\" className=\"text-danger\" />\n */\n\nimport React from 'react';\nimport { Icon } from '@iconify/react';\nimport { cn } from '../../lib/utils';\n\nexport interface NormalizedIconProps {\n /** Iconify icon string (e.g., \"lucide:crop\" or \"gravity-ui:bold\") */\n icon: string;\n /** Size preset - 'toolbar' is responsive (24px mobile, 20px desktop) */\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'toolbar';\n /** Additional CSS classes (e.g., for color) */\n className?: string;\n}\n\n/**\n * Scaling factors per icon set to achieve visual consistency.\n *\n * These values compensate for differences in stroke width and viewbox padding\n * across icon sets. Lucide (1.0) is the reference.\n *\n * Rationale:\n * - gravity-ui: Thinner strokes, needs +15% to match visual weight\n * - lucide: Reference set, no adjustment needed\n * - hugeicons: Similar visual weight to lucide\n * - mdi: Slightly bolder strokes, reduce by 5%\n * - fa6-solid: Solid fill is visually heavy, reduce by 20%\n */\nconst SET_SCALE_FACTORS: Record<string, number> = {\n 'gravity-ui': 1.2, // Thinner strokes need +20% (20px → 24px)\n lucide: 1.0, // Reference\n hugeicons: 1.05, // Slightly thin\n mdi: 0.95, // Slightly bolder\n 'fa6-solid': 0.7, // Solid fill is very heavy, reduce 30%\n heroicons: 1.0,\n ph: 1.0,\n 'radix-icons': 1.0,\n 'material-symbols': 0.9, // Filled variants are heavy\n 'simple-icons': 0.95,\n 'eos-icons': 1.0,\n};\n\n/** Default scale factor for unknown icon sets */\nconst DEFAULT_SCALE_FACTOR = 1.0;\n\n/**\n * Per-icon offset corrections for centering.\n * Some icons have asymmetric viewbox padding and need manual offset.\n * Values are in pixels at base size, scaled proportionally.\n */\nconst ICON_OFFSETS: Record<string, { x: number; y: number }> = {\n 'gravity-ui:arrow-rotate-left': { x: 4, y: 4 },\n 'gravity-ui:arrow-rotate-right': { x: -4, y: 4 },\n 'gravity-ui:sparkles': { x: 2, y: -2 },\n};\n\n/**\n * Base pixel sizes for each preset.\n * 'toolbar' is special - it has mobile and desktop values.\n */\nconst SIZE_PRESETS: Record<string, number | { mobile: number; desktop: number }> = {\n xs: 12,\n sm: 16,\n md: 20,\n lg: 24,\n xl: 32,\n toolbar: { mobile: 24, desktop: 20 },\n};\n\n/**\n * Extract the icon set prefix from an icon string.\n * @example getIconSet(\"gravity-ui:plus\") => \"gravity-ui\"\n * @example getIconSet(\"lucide:crop\") => \"lucide\"\n */\nfunction getIconSet(icon: string): string {\n const colonIndex = icon.indexOf(':');\n if (colonIndex === -1) return '';\n return icon.substring(0, colonIndex);\n}\n\n/**\n * Get the scale factor for an icon set.\n */\nfunction getScaleFactor(iconSet: string): number {\n return SET_SCALE_FACTORS[iconSet] ?? DEFAULT_SCALE_FACTOR;\n}\n\n/**\n * Get the offset correction for a specific icon.\n */\nfunction getIconOffset(icon: string): { x: number; y: number } | null {\n return ICON_OFFSETS[icon] ?? null;\n}\n\n/**\n * Calculate the normalized pixel size for an icon.\n */\nfunction getNormalizedSize(\n baseSize: number,\n iconSet: string\n): number {\n const scaleFactor = getScaleFactor(iconSet);\n return Math.round(baseSize * scaleFactor);\n}\n\nexport const NormalizedIcon: React.FC<NormalizedIconProps> = ({\n icon,\n size = 'md',\n className,\n}) => {\n const iconSet = getIconSet(icon);\n const sizePreset = SIZE_PRESETS[size];\n const offset = getIconOffset(icon);\n\n // Handle responsive 'toolbar' size with CSS custom properties\n if (typeof sizePreset === 'object') {\n const mobileSize = getNormalizedSize(sizePreset.mobile, iconSet);\n const desktopSize = getNormalizedSize(sizePreset.desktop, iconSet);\n // Scale offset proportionally to size (base is 20px)\n const scaledOffset = offset ? {\n x: (offset.x * mobileSize) / 20,\n y: (offset.y * mobileSize) / 20,\n } : null;\n\n return (\n <span\n className={cn('normalized-icon-responsive inline-flex', className)}\n style={{\n '--icon-size-mobile': `${mobileSize}px`,\n '--icon-size-desktop': `${desktopSize}px`,\n width: `${mobileSize}px`,\n height: `${mobileSize}px`,\n } as React.CSSProperties}\n >\n <Icon\n icon={icon}\n width=\"100%\"\n height=\"100%\"\n style={scaledOffset ? { transform: `translate(${scaledOffset.x}px, ${scaledOffset.y}px)` } : undefined}\n />\n </span>\n );\n }\n\n // Static size - use wrapper span with inline style (Iconify CSS classes don't work with dynamic values)\n const normalizedSize = getNormalizedSize(sizePreset, iconSet);\n // Scale offset proportionally to size (base is 20px)\n const scaledOffset = offset ? {\n x: (offset.x * normalizedSize) / 20,\n y: (offset.y * normalizedSize) / 20,\n } : null;\n\n return (\n <span\n className={cn('inline-flex', className)}\n style={{ width: `${normalizedSize}px`, height: `${normalizedSize}px` }}\n >\n <Icon\n icon={icon}\n width=\"100%\"\n height=\"100%\"\n style={scaledOffset ? { transform: `translate(${scaledOffset.x}px, ${scaledOffset.y}px)` } : undefined}\n />\n </span>\n );\n};\n\nNormalizedIcon.displayName = 'NormalizedIcon';\n\n// Export utilities for advanced use cases\nexport { getIconSet, getScaleFactor, getIconOffset, getNormalizedSize, SET_SCALE_FACTORS, SIZE_PRESETS, ICON_OFFSETS };\n","/**\n * ToolbarButton - Consistent button for contextual toolbars\n *\n * Features:\n * - Responsive sizing via CSS (44px/24px mobile, 36px/20px desktop)\n * - Theme-aware active state (uses --primary color)\n * - Optional built-in Tooltip\n * - Extends Shadcn Button with toolbar presets\n *\n * @example\n * // Simple icon button\n * <ToolbarButton icon=\"lucide:crop\" onClick={handleCrop} tooltip=\"Crop\" />\n *\n * @example\n * // Toggle button with active state\n * <ToolbarButton\n * icon=\"gravity-ui:bold\"\n * active={isBold}\n * onClick={toggleBold}\n * tooltip=\"Bold\"\n * />\n */\n\nimport React from 'react';\nimport { Button } from '@snowcone-app/ui';\nimport { Tooltip, TooltipTrigger, TooltipContent } from './';\nimport { NormalizedIcon } from './normalized-icon';\nimport { cn } from '../../lib/utils';\n\nexport interface ToolbarButtonProps {\n /** Iconify icon string (e.g., \"lucide:crop\" or \"gravity-ui:bold\") or React node for custom icons */\n icon: string | React.ReactNode;\n /** Click handler */\n onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n /** Active/pressed state - applies primary color styling */\n active?: boolean;\n /** Tooltip text (if provided, wraps button in Tooltip) */\n tooltip?: string;\n /** Tooltip delay in ms (default: 300) */\n tooltipDelay?: number;\n /** Temporarily disable the tooltip (useful for preventing tooltip flicker after click) */\n tooltipDisabled?: boolean;\n /** Accessible label */\n 'aria-label'?: string;\n /** Disabled state */\n disabled?: boolean;\n /** Additional CSS classes */\n className?: string;\n /** Optional mouse leave handler (for tooltip management) */\n onMouseLeave?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n}\n\n\nexport const ToolbarButton = React.forwardRef<HTMLButtonElement, ToolbarButtonProps>(\n (\n {\n icon,\n onClick,\n active = false,\n tooltip,\n tooltipDelay = 300,\n tooltipDisabled = false,\n 'aria-label': ariaLabel,\n disabled = false,\n className,\n onMouseLeave,\n },\n ref\n ) => {\n const buttonElement = (\n <Button\n ref={ref}\n variant=\"ghost\"\n size=\"toolbar\"\n onClick={onClick}\n disabled={disabled}\n aria-label={ariaLabel || tooltip}\n aria-pressed={active}\n data-active={active}\n onMouseLeave={onMouseLeave}\n className={cn(className)}\n >\n {typeof icon === 'string' ? <NormalizedIcon icon={icon} size=\"toolbar\" /> : icon}\n </Button>\n );\n\n // No tooltip requested or tooltip is temporarily disabled\n if (!tooltip || tooltipDisabled) {\n return buttonElement;\n }\n\n return (\n <Tooltip delay={tooltipDelay}>\n <TooltipTrigger asChild>{buttonElement}</TooltipTrigger>\n <TooltipContent>{tooltip}</TooltipContent>\n </Tooltip>\n );\n }\n);\n\nToolbarButton.displayName = 'ToolbarButton';\n","/**\n * Custom Icons - Centered versions of icons from various sets\n *\n * These are copies of icons with adjusted viewBox to center properly.\n * Use these instead of the original iconify versions for consistent alignment.\n */\n\nimport React from 'react';\nimport { cn } from '../../lib/utils';\n\ninterface IconProps {\n className?: string;\n size?: number | string;\n}\n\n/**\n * Rotate Left icon (lucide-style stroked version)\n */\nexport const RotateLeftIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n width={size}\n height={size}\n className={cn('inline-block iconify', className)}\n >\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </svg>\n);\n\n/**\n * Rotate Right icon (lucide-style stroked version)\n */\nexport const RotateRightIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n width={size}\n height={size}\n className={cn('inline-block iconify', className)}\n >\n <path d=\"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\" />\n <path d=\"M21 3v5h-5\" />\n </svg>\n);\n\n/**\n * Sparkles icon (based on gravity-ui:sparkles)\n * Two sparkle shapes - main 4-point star and smaller accent\n */\nexport const SparklesIcon: React.FC<IconProps> = ({ className, size = 24 }) => (\n <svg\n viewBox=\"0 0 28 28\"\n fill=\"currentColor\"\n width={size}\n height={size}\n className={cn('inline-block', className)}\n >\n <path d=\"M10.06 18.701a1.628 1.628 0 0 0 2.43-.676l.77-2.34a3.82 3.82 0 0 1 2.416-2.418l2.238-.727a1.6 1.6 0 0 0 .786-.595a1.62 1.62 0 0 0-.849-2.489l-2.215-.72a3.82 3.82 0 0 1-2.42-2.414l-.727-2.237a1.62 1.62 0 0 0-.594-.785a1.655 1.655 0 0 0-1.879 0a1.63 1.63 0 0 0-.6.8L8.68 6.365a3.82 3.82 0 0 1-2.359 2.37l-2.24.726a1.626 1.626 0 0 0 .02 3.073l2.216.72a3.86 3.86 0 0 1 1.816 1.286c.266.343.471.728.606 1.14l.728 2.234c.112.318.32.593.595.787m-3.273-6.873l-2.22-.72s-.085-.038-.085-.108a.14.14 0 0 1 .084-.115L6.8 10.16a5.34 5.34 0 0 0 3.32-3.375l.721-2.219s.043-.084.114-.084s.113.084.113.084l.723 2.223a5.32 5.32 0 0 0 3.377 3.372l2.27.735a.13.13 0 0 1 .078.11a.15.15 0 0 1-.083.113l-2.225.722a5.32 5.32 0 0 0-3.374 3.374l-.715 2.2a.11.11 0 0 1-.115.093c-.104 0-.118-.075-.118-.075l-.723-2.22a5.32 5.32 0 0 0-3.376-3.385m13.017 12.954A1.2 1.2 0 0 0 20.5 25a1.2 1.2 0 0 0 .692-.216a1.2 1.2 0 0 0 .446-.6l.372-1.143a1.61 1.61 0 0 1 1.017-1.02l1.166-.378A1.21 1.21 0 0 0 25 20.505a1.2 1.2 0 0 0-.844-1.146l-1.144-.37a1.61 1.61 0 0 1-1.02-1.018l-.38-1.163a1.2 1.2 0 0 0-2.274.016l-.374 1.146a1.61 1.61 0 0 1-.993 1.017l-1.166.378a1.21 1.21 0 0 0-.807 1.139a1.2 1.2 0 0 0 .823 1.138l1.144.372a1.6 1.6 0 0 1 1.02 1.023l.379 1.163a1.2 1.2 0 0 0 .44.582m-1.371-4.194l-.27-.088l.283-.096a3.12 3.12 0 0 0 1.943-1.974l.088-.27l.089.272a3.11 3.11 0 0 0 1.974 1.975l.293.1l-.271.087a3.12 3.12 0 0 0-1.974 1.977l-.088.27l-.088-.272a3.12 3.12 0 0 0-1.98-1.98\" />\n </svg>\n);\n\n// Map of icon names to components for easy lookup\nexport const CustomIcons = {\n 'rotate-left': RotateLeftIcon,\n 'rotate-right': RotateRightIcon,\n 'sparkles': SparklesIcon,\n} as const;\n\nexport type CustomIconName = keyof typeof CustomIcons;\n","/**\n * Icon Constants\n *\n * Centralized icon definitions using lucide (preferred) with custom icons where needed.\n * Import icons from here instead of using iconify strings directly.\n */\n\n// =============================================================================\n// ICON STRINGS (for use with <Icon icon={...} />)\n// =============================================================================\n\nexport const icons = {\n // Navigation/Actions\n plus: 'lucide:plus',\n minus: 'lucide:minus',\n close: 'lucide:x',\n check: 'lucide:check',\n menu: 'lucide:menu',\n moreHorizontal: 'lucide:ellipsis',\n moreVertical: 'lucide:ellipsis-vertical',\n\n // Chevrons\n chevronDown: 'lucide:chevron-down',\n chevronUp: 'lucide:chevron-up',\n chevronLeft: 'lucide:chevron-left',\n chevronRight: 'lucide:chevron-right',\n\n // Objects\n text: 'lucide:type',\n image: 'lucide:image',\n layers: 'lucide:layers',\n shapes: 'lucide:shapes',\n\n // Actions\n trash: 'lucide:trash-2',\n copy: 'lucide:copy',\n pencil: 'lucide:pencil',\n scissors: 'lucide:scissors',\n\n // File operations\n save: 'lucide:save',\n folderOpen: 'lucide:folder-open',\n download: 'lucide:download',\n upload: 'lucide:upload',\n\n // Visibility\n eye: 'lucide:eye',\n eyeOff: 'lucide:eye-off',\n lock: 'lucide:lock',\n lockOpen: 'lucide:lock-open',\n\n // Search/Navigation\n search: 'lucide:search',\n link: 'lucide:link',\n settings: 'lucide:settings',\n\n // Color/Style\n palette: 'lucide:palette',\n\n // Theme\n sun: 'lucide:sun',\n moon: 'lucide:moon',\n\n // Rotate (lucide versions)\n rotateLeft: 'lucide:rotate-ccw',\n rotateRight: 'lucide:rotate-cw',\n rotateCcwSquare: 'lucide:rotate-ccw-square',\n\n // Text formatting\n bold: 'lucide:bold',\n italic: 'lucide:italic',\n underline: 'lucide:underline',\n\n // Alignment\n alignLeft: 'lucide:align-left',\n alignCenter: 'lucide:align-center',\n alignRight: 'lucide:align-right',\n alignJustify: 'lucide:align-justify',\n\n // Media controls\n play: 'lucide:play',\n pause: 'lucide:pause',\n\n // Image toolbar\n crop: 'lucide:crop',\n flipHorizontal: 'lucide:flip-horizontal-2',\n flipVertical: 'lucide:flip-vertical-2',\n blend: 'lucide:blend',\n cornerRadius: 'lucide:square-round-corner',\n\n // Misc\n grip: 'lucide:grip-vertical',\n folder: 'lucide:folder',\n file: 'lucide:file',\n fileText: 'lucide:file-text',\n\n // Layer operations\n layerForward: 'lucide:bring-to-front',\n layerBackward: 'lucide:send-to-back',\n group: 'lucide:group',\n ungroup: 'lucide:ungroup',\n\n // Undo/Redo\n undo: 'lucide:undo-2',\n redo: 'lucide:redo-2',\n\n // Zoom\n zoomIn: 'lucide:zoom-in',\n zoomOut: 'lucide:zoom-out',\n fitScreen: 'lucide:scan',\n maximize: 'lucide:maximize',\n\n // Transform\n move: 'lucide:move',\n resize: 'lucide:maximize-2',\n\n // Export/Share\n share: 'lucide:share',\n externalLink: 'lucide:external-link',\n cloudUpload: 'lucide:cloud-upload',\n\n // Info\n info: 'lucide:info',\n helpCircle: 'lucide:help-circle',\n alertCircle: 'lucide:alert-circle',\n alertTriangle: 'lucide:triangle-alert',\n checkCircle: 'lucide:circle-check',\n\n // Arrows\n arrowLeft: 'lucide:arrow-left',\n arrowRight: 'lucide:arrow-right',\n arrowUp: 'lucide:arrow-up',\n arrowDown: 'lucide:arrow-down',\n\n // Layout\n layout: 'lucide:layout-grid',\n grid: 'lucide:grid-3x3',\n list: 'lucide:list',\n\n // Droplet (color fill)\n droplet: 'lucide:droplet',\n paintBucket: 'lucide:paint-bucket',\n\n // Text specific\n letterSpacing: 'lucide:space',\n lineHeight: 'lucide:arrow-up-down',\n\n // Special purpose\n wand: 'lucide:wand-2',\n rocket: 'lucide:rocket',\n refresh: 'lucide:refresh-cw',\n circle: 'lucide:circle',\n circleFill: 'lucide:circle-dot',\n} as const;\n\n// Type for icon keys\nexport type IconName = keyof typeof icons;\n\n// =============================================================================\n// CUSTOM ICON COMPONENTS (for icons that need viewBox correction)\n// =============================================================================\n\n// Re-export custom icons that need special handling\nexport { RotateLeftIcon, RotateRightIcon, SparklesIcon } from './custom-icons';\n","/**\n * CollapsedToolbarHeader - Header shown when a toolbar panel is expanded\n *\n * Displays:\n * - Icon on the left (same as the button that opened the panel)\n * - Label text\n * - Close button on the far right\n *\n * Used for corner radius, effects, and other expandable panels.\n *\n * @example\n * <CollapsedToolbarHeader\n * icon=\"lucide:square-round-corner\"\n * label=\"Corner Radius\"\n * onClose={() => setIsOpen(false)}\n * />\n */\n\nimport React, { useRef, useEffect } from 'react';\nimport { Icon } from '@iconify/react';\nimport { cn } from '../../lib/utils';\nimport { icons } from './icons';\n\nexport interface CollapsedToolbarHeaderProps {\n /** Iconify icon string (e.g., \"lucide:square-round-corner\") or custom React node */\n icon: string | React.ReactNode;\n /** Label text to display */\n label: string;\n /** Callback when close button is clicked */\n onClose: () => void;\n /** Additional CSS classes */\n className?: string;\n /** Close button style: 'icon' shows X, 'done' shows Done button */\n closeButtonStyle?: 'icon' | 'done';\n}\n\nexport const CollapsedToolbarHeader: React.FC<CollapsedToolbarHeaderProps> = ({\n icon,\n label,\n onClose,\n className,\n closeButtonStyle = 'icon',\n}) => {\n // Block horizontal touch movement to prevent drawer/page from being dragged\n const containerRef = useRef<HTMLDivElement>(null);\n const touchStartPos = useRef({ x: 0, y: 0 });\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const handleTouchStart = (e: TouchEvent) => {\n touchStartPos.current = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n const deltaX = Math.abs(e.touches[0].clientX - touchStartPos.current.x);\n const deltaY = Math.abs(e.touches[0].clientY - touchStartPos.current.y);\n\n // If horizontal movement is greater than vertical, prevent it\n if (deltaX > 10 && deltaX > deltaY) {\n e.preventDefault();\n }\n };\n\n el.addEventListener('touchstart', handleTouchStart, { passive: true });\n el.addEventListener('touchmove', handleTouchMove, { passive: false });\n\n return () => {\n el.removeEventListener('touchstart', handleTouchStart);\n el.removeEventListener('touchmove', handleTouchMove);\n };\n }, []);\n\n return (\n <div\n ref={containerRef}\n className={cn('flex w-full items-center justify-between', className)}\n style={{ touchAction: 'pan-y' }}\n >\n {/* Left side: Icon + Label */}\n <div className=\"flex items-center gap-3 md:gap-2\">\n {typeof icon === 'string' ? (\n <Icon icon={icon} className=\"text-primary size-7 md:size-5\" />\n ) : (\n icon\n )}\n <span className=\"text-foreground text-lg font-semibold md:text-sm md:font-medium\">{label}</span>\n </div>\n\n {/* Right side: Close button */}\n {closeButtonStyle === 'done' ? (\n <button\n onClick={onClose}\n className=\"bg-primary text-primary-foreground rounded-xl hover:bg-primary/90 shadow-sm px-8 py-3.5 text-xl font-bold transition-colors md:rounded-button md:shadow-none md:px-4 md:py-2 md:text-sm md:font-medium\"\n aria-label=\"Done\"\n >\n Done\n </button>\n ) : (\n <button\n onClick={onClose}\n className=\"hover:bg-muted text-foreground/70 hover:text-foreground flex size-11 items-center justify-center rounded-md transition-colors md:size-7\"\n aria-label=\"Close panel\"\n >\n <Icon icon={icons.close} className=\"size-7 md:size-4\" />\n </button>\n )}\n </div>\n );\n};\n\nCollapsedToolbarHeader.displayName = 'CollapsedToolbarHeader';\n","/**\n * SliderRow - Reusable slider component with label, optional input, and touch guard\n *\n * Used in secondary panels (corner radius, rotation, etc.) for consistent styling\n * and proper touch handling on mobile devices.\n *\n * @example\n * <SliderRow\n * label=\"Radius\"\n * value={50}\n * onChange={setValue}\n * min={0}\n * max={100}\n * unit=\"%\"\n * />\n */\n\nimport React, { useRef, useEffect } from 'react';\nimport { Slider } from '@snowcone-app/ui';\nimport { cn } from '../../lib/utils';\n\n/**\n * TouchGuard - Wraps interactive elements to prevent parent scroll from capturing touches\n *\n * Uses native event listeners with { passive: false } because:\n * 1. React's synthetic events can't properly preventDefault on touch events\n * 2. CSS touch-action: none is evaluated at gesture start on the ancestor chain,\n * so a parent with pan-y can still capture the gesture before child CSS applies\n * 3. Native listeners with passive: false intercept events before the browser decides to scroll\n */\nfunction TouchGuard({ children, className }: { children: React.ReactNode; className?: string }) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n const handleTouchStart = (e: TouchEvent) => {\n // Stop the event from reaching parent scroll containers\n e.stopPropagation();\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n // Prevent default scroll behavior and stop propagation\n e.preventDefault();\n e.stopPropagation();\n };\n\n // Must use passive: false to allow preventDefault\n el.addEventListener('touchstart', handleTouchStart, { passive: false });\n el.addEventListener('touchmove', handleTouchMove, { passive: false });\n\n return () => {\n el.removeEventListener('touchstart', handleTouchStart);\n el.removeEventListener('touchmove', handleTouchMove);\n };\n }, []);\n\n return (\n <div ref={ref} className={className} style={{ touchAction: 'none' }}>\n {children}\n </div>\n );\n}\n\nexport interface SliderRowProps {\n /** Label displayed to the left of the slider */\n label: string;\n /** Current value */\n value: number;\n /** Callback when value changes */\n onChange: (value: number) => void;\n /** Minimum value */\n min: number;\n /** Maximum value */\n max: number;\n /** Step increment (default: 1) */\n step?: number;\n /** Unit to display after value (e.g., \"%\", \"°\", \"px\") */\n unit?: string;\n /** Show number input field (default: false) */\n showInput?: boolean;\n /** Width of the number input (default: '56px') */\n inputWidth?: string;\n /** Additional class name for the container */\n className?: string;\n /** Layout variant: 'inline' (default) or 'stacked' */\n variant?: 'inline' | 'stacked';\n}\n\n/**\n * SliderRow - A labeled slider with optional input and value display\n */\nexport const SliderRow: React.FC<SliderRowProps> = ({\n label,\n value,\n onChange,\n min,\n max,\n step = 1,\n unit = '',\n showInput = false,\n inputWidth = '56px',\n className,\n variant = 'inline',\n}) => {\n const displayValue = Math.round(value);\n\n if (variant === 'stacked') {\n // Stacked layout: label/input on top, slider below\n return (\n <div className={cn('flex flex-col gap-2.5 md:gap-1.5', className)}>\n <div className=\"flex items-center justify-between\">\n <span className=\"text-foreground/60 text-base md:text-xs\">{label}</span>\n {showInput && (\n <input\n type=\"number\"\n value={displayValue}\n onChange={(e) => onChange(Math.max(min, Math.min(max, Number(e.target.value))))}\n min={min}\n max={max}\n aria-label={`${label} value`}\n className=\"bg-transparent text-foreground w-14 rounded-md border-none px-2.5 py-2 text-right text-base md:w-14 md:rounded md:px-1.5 md:py-1 md:text-[13px]\"\n style={{ width: inputWidth }}\n />\n )}\n </div>\n <TouchGuard>\n <Slider\n value={[value]}\n onValueChange={(val) => onChange(val[0])}\n min={min}\n max={max}\n step={step}\n >\n <Slider.Track className=\"bg-foreground/10 h-2.5 md:h-2\">\n <Slider.Fill className=\"bg-primary\" />\n </Slider.Track>\n <Slider.Thumb className=\"size-7 md:size-6\" />\n </Slider>\n </TouchGuard>\n </div>\n );\n }\n\n // Inline layout: label, slider, value all in one row\n return (\n <div className={cn('flex items-center gap-3', className)}>\n <span className=\"text-foreground/70 text-base md:text-[13px] whitespace-nowrap\">{label}</span>\n {showInput ? (\n <input\n type=\"number\"\n value={displayValue}\n onChange={(e) => onChange(Math.max(min, Math.min(max, Number(e.target.value))))}\n min={min}\n max={max}\n aria-label={`${label} value`}\n className=\"bg-transparent text-foreground rounded-md border-none px-2 py-2 text-right text-base md:py-1.5 md:text-[13px]\"\n style={{ width: inputWidth }}\n />\n ) : null}\n <TouchGuard className=\"flex-1\">\n <Slider\n value={[value]}\n onValueChange={(val) => onChange(val[0])}\n min={min}\n max={max}\n step={step}\n >\n <Slider.Track className=\"bg-foreground/10 h-2.5 md:h-2\">\n <Slider.Fill className=\"bg-primary\" />\n </Slider.Track>\n <Slider.Thumb className=\"size-7 md:size-6\" />\n </Slider>\n </TouchGuard>\n <span className=\"text-foreground text-base md:text-[13px] min-w-[44px] md:min-w-[32px] text-right\">\n {displayValue}{unit}\n </span>\n </div>\n );\n};\n\nexport default SliderRow;\n","/**\n * PresetCarousel - Reusable horizontal scrolling preset thumbnail carousel\n *\n * Features:\n * - Visual selection indicator (primary accent border + ring)\n * - Keyboard navigation (left/right arrow keys)\n * - Accessible focus management with roving tabindex\n * - Optional \"Off\" button as first item\n */\n\nimport React, { useRef, useCallback } from 'react';\n\nexport interface PresetItem {\n id: string;\n name: string;\n thumbnailUrl?: string;\n}\n\nexport interface PresetCarouselProps {\n /** Array of preset items to display */\n presets: PresetItem[];\n /** Currently selected preset ID, or empty string for \"Off\" */\n selectedId: string;\n /** Called when a preset is selected. Empty string means \"Off\". */\n onSelect: (id: string) => void;\n /** Show an \"Off\" button as the first item. Default: true */\n showOff?: boolean;\n /** Thumbnail size in pixels. Default: 40 */\n size?: number;\n /** Accessible label for the carousel */\n ariaLabel?: string;\n}\n\nconst SELECTED_CLASSES = 'border-2 border-primary overflow-hidden';\nconst UNSELECTED_CLASSES = 'border-2 border-border-primary hover:border-border-focus overflow-hidden';\n\nexport const PresetCarousel: React.FC<PresetCarouselProps> = ({\n presets,\n selectedId,\n onSelect,\n showOff = true,\n size = 40,\n ariaLabel = 'Preset options',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n\n const scrollToItem = useCallback((button: HTMLButtonElement) => {\n button.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });\n }, []);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;\n e.preventDefault();\n e.stopPropagation();\n\n const container = containerRef.current;\n if (!container) return;\n\n const buttons = Array.from(container.querySelectorAll<HTMLButtonElement>('button[data-preset-id]'));\n const focused = document.activeElement as HTMLButtonElement;\n let currentIndex = buttons.indexOf(focused);\n\n // If no button is focused, start from selected or first\n if (currentIndex === -1) {\n currentIndex = buttons.findIndex((btn) => btn.getAttribute('aria-selected') === 'true');\n if (currentIndex === -1) currentIndex = 0;\n }\n\n let nextIndex: number;\n if (e.key === 'ArrowRight') {\n nextIndex = currentIndex < buttons.length - 1 ? currentIndex + 1 : 0;\n } else {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : buttons.length - 1;\n }\n\n const nextButton = buttons[nextIndex];\n nextButton.focus();\n scrollToItem(nextButton);\n\n // Also select the item on arrow navigation\n const presetId = nextButton.getAttribute('data-preset-id');\n if (presetId !== null) {\n onSelect(presetId);\n }\n },\n [scrollToItem, onSelect]\n );\n\n const isOffSelected = showOff && !selectedId;\n // Determine which item gets tabIndex 0 for initial Tab entry\n const hasSelection = showOff ? true : presets.some((p) => p.id === selectedId);\n\n return (\n <div\n ref={containerRef}\n className=\"flex gap-1.5 overflow-x-auto p-1 -m-1\"\n style={{ flexWrap: 'nowrap' }}\n role=\"listbox\"\n aria-label={ariaLabel}\n onKeyDown={handleKeyDown}\n >\n {showOff && (\n <button\n data-preset-id=\"\"\n role=\"option\"\n aria-selected={isOffSelected}\n tabIndex={isOffSelected || (!hasSelection) ? 0 : -1}\n onClick={() => onSelect('')}\n className={`shrink-0 rounded-md transition-all flex items-center justify-center ${\n isOffSelected ? SELECTED_CLASSES : UNSELECTED_CLASSES\n }`}\n style={{ width: size, height: size }}\n title=\"None\"\n >\n <span className=\"text-xs text-muted-foreground\">Off</span>\n </button>\n )}\n {presets.map((preset, index) => {\n const isSelected = selectedId === preset.id;\n // First item gets tabIndex 0 if nothing else is selected (and no Off button)\n const isTabbable = isSelected || (!showOff && !hasSelection && index === 0);\n return (\n <button\n key={preset.id}\n data-preset-id={preset.id}\n role=\"option\"\n aria-selected={isSelected}\n tabIndex={isTabbable ? 0 : -1}\n onClick={() => onSelect(preset.id)}\n className={`shrink-0 rounded-md transition-all ${\n isSelected ? SELECTED_CLASSES : UNSELECTED_CLASSES\n }`}\n style={{ width: size, height: size }}\n title={preset.name}\n >\n {preset.thumbnailUrl && (\n <img\n src={preset.thumbnailUrl}\n alt={preset.name}\n className=\"w-full h-full object-cover\"\n loading=\"lazy\"\n />\n )}\n </button>\n );\n })}\n </div>\n );\n};\n","/**\n * LayersPanel - Standalone layer management component\n * Uses useLayers hook for data and operations.\n * Supports touch-friendly drag-to-reorder via @dnd-kit.\n * Groups displayed as folder structure with visual indentation.\n */\n\nimport React, { useEffect, useMemo, useCallback } from 'react';\nimport { useLayers, type UseLayersOptions, type LayerInfo } from '../../hooks/useLayers.js';\nimport { useArtboards } from '../../hooks/useArtboards.js';\nimport { useLayerDndKit } from '../../hooks/useLayerDndKit.js';\nimport { Icon } from '@iconify/react';\nimport { icons } from '../ui';\nimport {\n DndContext,\n DragOverlay,\n closestCenter,\n pointerWithin,\n useDroppable,\n useDraggable,\n type CollisionDetection,\n} from '@dnd-kit/core';\n\n// Custom collision detection that computes drop zones (before/into/after)\n// and encodes them in the collision data. This runs on every pointer movement\n// during render, so the zone is always fresh — no React batching issues.\nconst layerCollisionDetection: CollisionDetection = (args) => {\n const { pointerCoordinates, droppableContainers, droppableRects } = args;\n\n // Prefer pointer-based collision (accurate for small group targets),\n // fall back to closest-center when pointer is between items.\n let collisions = pointerWithin(args);\n if (collisions.length === 0) {\n collisions = closestCenter(args);\n }\n if (collisions.length === 0 || !pointerCoordinates) return collisions;\n\n // Enrich the winning collision with zone data\n const winner = collisions[0];\n\n // Group footer drop zones don't need zone calculation\n if (String(winner.id).startsWith('group-footer::')) {\n return [{ ...winner, data: { ...winner.data, zone: 'after' } }];\n }\n\n const rect = droppableRects.get(winner.id);\n if (!rect) return collisions;\n\n const relativeY = pointerCoordinates.y - rect.top;\n const height = rect.height;\n\n // Look up isGroup from the droppable's data prop\n const container = droppableContainers.find((c) => c.id === winner.id);\n const isGroup = container?.data?.current?.isGroup === true;\n\n let zone: 'before' | 'after' | 'into';\n if (isGroup) {\n if (relativeY < height * 0.25) zone = 'before';\n else if (relativeY > height * 0.75) zone = 'after';\n else zone = 'into';\n } else {\n zone = relativeY < height / 2 ? 'before' : 'after';\n }\n\n // Return collision with zone encoded in data\n return [{\n ...winner,\n data: { ...winner.data, zone },\n }];\n};\n\nexport interface LayersPanelProps extends UseLayersOptions {\n width?: number;\n height?: number;\n showPreviewImages?: boolean;\n enableDragReorder?: boolean;\n enableGrouping?: boolean;\n style?: React.CSSProperties;\n className?: string;\n showHeader?: boolean;\n}\n\n// ── Sortable layer item ──────────────────────────────────────────────────\n\ninterface SortableLayerItemProps {\n layer: LayerInfo;\n isOver: boolean;\n dropPosition: 'before' | 'after' | 'into' | null;\n isDragActive: boolean;\n showPreviewImages: boolean;\n previewDisplaySize: number;\n onSelect: (id: string) => void;\n onToggleVisibility: (id: string) => void;\n onToggleLock: (id: string) => void;\n onDuplicate: (id: string) => void;\n onDelete: (id: string) => void;\n}\n\nconst SortableLayerItem: React.FC<SortableLayerItemProps> = ({\n layer,\n isOver,\n dropPosition,\n isDragActive,\n showPreviewImages,\n previewDisplaySize,\n onSelect,\n onToggleVisibility,\n onToggleLock,\n onDuplicate,\n onDelete,\n}) => {\n const { attributes, listeners, setNodeRef: setDragRef, isDragging } = useDraggable({ id: layer.id });\n const { setNodeRef: setDropRef } = useDroppable({ id: layer.id, data: { isGroup: !!layer.isGroup } });\n\n // Merge refs so the same DOM node is both draggable and droppable\n const setNodeRef = useCallback((node: HTMLElement | null) => {\n setDragRef(node);\n setDropRef(node);\n }, [setDragRef, setDropRef]);\n\n const isGroupRow = layer.isGroup;\n const isChild = layer.depth > 0;\n const indentPx = isChild ? layer.depth * 24 : 0;\n\n const style: React.CSSProperties = {\n opacity: isDragging ? 0.3 : 1,\n paddingLeft: indentPx + 8,\n paddingRight: 8,\n paddingTop: isGroupRow ? 6 : 8,\n paddingBottom: isGroupRow ? 6 : 8,\n minHeight: isGroupRow ? 32 : 36,\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n cursor: 'pointer',\n position: 'relative',\n touchAction: 'manipulation',\n };\n\n // Group rows and children get a light gray background\n if (isChild || isGroupRow) {\n style.backgroundColor = 'var(--surface-secondary, rgba(0,0,0,0.04))';\n }\n\n // Drop indicator styles\n if (isOver && !isDragging) {\n if (dropPosition === 'before') {\n style.borderTop = '2px solid var(--primary, var(--accent-primary, #007AFF))';\n } else if (dropPosition === 'after') {\n style.borderBottom = '2px solid var(--primary, var(--accent-primary, #007AFF))';\n } else if (dropPosition === 'into') {\n style.outline = '2px solid var(--primary, var(--accent-primary, #007AFF))';\n style.outlineOffset = '-2px';\n style.backgroundColor = 'var(--accent-primary-alpha, rgba(0, 122, 255, 0.08))';\n }\n }\n\n const selectionRingStyle = layer.isSelected\n ? {\n outline: '3px solid var(--primary, var(--accent-primary, #007AFF))',\n outlineOffset: '2px',\n }\n : {};\n\n const handleClick = () => onSelect(layer.id);\n\n // Drag handle — the only element with `{...listeners}` and\n // `touchAction: 'none'`. This is what reserves a touch sequence\n // for dnd-kit. Everything outside this handle stays freely\n // tappable / scrollable, so the drawer's vertical scroll engages\n // when the user starts a touch on the rest of the row.\n const dragHandle = (\n <span\n {...listeners}\n aria-label=\"Drag to reorder\"\n title=\"Drag to reorder\"\n style={{\n touchAction: 'none',\n cursor: 'grab',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n // Wide enough to be an easy touch target on mobile (≥ 36px)\n // and visually reads as a deliberate \"grab here\" affordance\n // rather than a tiny indicator squished between the row edge\n // and the thumbnail.\n width: 36,\n alignSelf: 'stretch',\n marginLeft: -4,\n marginRight: 4,\n flexShrink: 0,\n color: 'var(--text-secondary, #888)',\n opacity: 0.6,\n }}\n >\n <Icon icon=\"lucide:grip-vertical\" style={{ fontSize: 24 }} />\n </span>\n );\n\n // Group folder row\n if (isGroupRow) {\n return (\n <div ref={setNodeRef} style={style} {...attributes}>\n {dragHandle}\n <Icon\n icon=\"lucide:folder-open\"\n style={{ fontSize: 18, color: 'var(--text-secondary, #888)', flexShrink: 0 }}\n />\n <span\n onClick={handleClick}\n style={{\n fontSize: 13,\n fontWeight: 600,\n color: 'var(--foreground, #333)',\n flex: 1,\n minWidth: 0,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {layer.name}\n </span>\n {!isDragActive && (!layer.children || layer.children.length === 0) && (\n <div style={{ display: 'flex', gap: 4, flexShrink: 0 }}>\n <LayerActionButton\n title=\"Delete Group\"\n onClick={() => onDelete(layer.id)}\n style={{ color: 'var(--error, #ef4444)' }}\n >\n <Icon icon={icons.trash} className=\"size-6\" />\n </LayerActionButton>\n </div>\n )}\n </div>\n );\n }\n\n // Regular layer row\n return (\n <div ref={setNodeRef} style={style} {...attributes}>\n {dragHandle}\n {showPreviewImages && layer.previewUrl ? (\n <img\n src={layer.previewUrl}\n alt={layer.name}\n onClick={handleClick}\n style={{\n width: previewDisplaySize,\n height: previewDisplaySize,\n objectFit: 'contain',\n borderRadius: 4,\n border: '1px solid var(--border-primary, #e5e5e5)',\n cursor: 'pointer',\n flexShrink: 0,\n ...selectionRingStyle,\n }}\n />\n ) : (\n <div\n style={{\n width: previewDisplaySize,\n height: previewDisplaySize,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 24,\n opacity: 0.6,\n border: '1px solid var(--border-primary, #e5e5e5)',\n borderRadius: 4,\n cursor: 'pointer',\n flexShrink: 0,\n ...selectionRingStyle,\n }}\n onClick={handleClick}\n >\n <Icon icon={icons.fileText} />\n </div>\n )}\n {/* Spacer / tap area — drag listeners no longer span this, so\n it stays freely scrollable on touch. */}\n <div style={{ flex: 1, minWidth: 0 }} onClick={handleClick} />\n\n {/* Actions */}\n {!isDragActive && (\n <div style={{ display: 'flex', gap: 4, flexShrink: 0 }}>\n <LayerActionButton\n title={layer.visible ? 'Hide' : 'Show'}\n onClick={() => onToggleVisibility(layer.id)}\n style={{ opacity: layer.visible ? 1 : 0.4 }}\n >\n <Icon icon={layer.visible ? icons.eye : icons.eyeOff} className=\"size-6\" />\n </LayerActionButton>\n <LayerActionButton\n title={layer.locked ? 'Unlock' : 'Lock'}\n onClick={() => onToggleLock(layer.id)}\n style={{ opacity: layer.locked ? 1 : 0.4 }}\n >\n <Icon icon={layer.locked ? icons.lock : icons.lockOpen} className=\"size-6\" />\n </LayerActionButton>\n <LayerActionButton title=\"Duplicate\" onClick={() => onDuplicate(layer.id)}>\n <Icon icon={icons.copy} className=\"size-6\" />\n </LayerActionButton>\n <LayerActionButton\n title=\"Delete\"\n onClick={() => onDelete(layer.id)}\n style={{ color: 'var(--error, #ef4444)' }}\n >\n <Icon icon={icons.trash} className=\"size-6\" />\n </LayerActionButton>\n </div>\n )}\n </div>\n );\n};\n\n/** Small action button used in layer items */\nconst LayerActionButton: React.FC<{\n title: string;\n onClick: () => void;\n style?: React.CSSProperties;\n children: React.ReactNode;\n}> = ({ title, onClick, style: extraStyle, children }) => (\n <button\n onClick={(e) => { e.stopPropagation(); onClick(); }}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: 4,\n opacity: 0.6,\n ...extraStyle,\n }}\n title={title}\n >\n {children}\n </button>\n);\n\n// ── Group footer drop zone (allows dragging items out below a group) ─────\n\nconst GroupFooterDropZone: React.FC<{\n groupId: string;\n isOver: boolean;\n depth: number;\n}> = ({ groupId, isOver, depth }) => {\n const { setNodeRef } = useDroppable({ id: `group-footer::${groupId}` });\n const indentPx = (depth + 1) * 24;\n\n return (\n <div\n ref={setNodeRef}\n style={{\n height: 8,\n marginLeft: indentPx,\n position: 'relative',\n ...(isOver ? {\n borderBottom: '2px solid var(--primary, var(--accent-primary, #007AFF))',\n } : {}),\n }}\n />\n );\n};\n\n// ── Drag overlay content ─────────────────────────────────────────────────\n\nconst DragOverlayContent: React.FC<{\n layer: LayerInfo;\n showPreviewImages: boolean;\n previewDisplaySize: number;\n}> = ({ layer, showPreviewImages, previewDisplaySize }) => (\n <div\n style={{\n paddingLeft: 8,\n paddingRight: 8,\n paddingTop: 8,\n paddingBottom: 8,\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n backgroundColor: 'var(--surface, #fff)',\n borderRadius: 8,\n boxShadow: '0 4px 16px rgba(0,0,0,0.15)',\n opacity: 0.9,\n }}\n >\n {layer.isGroup ? (\n <Icon icon=\"lucide:folder-open\" style={{ fontSize: 18, color: 'var(--text-secondary, #888)' }} />\n ) : showPreviewImages && layer.previewUrl ? (\n <img\n src={layer.previewUrl}\n alt={layer.name}\n style={{\n width: previewDisplaySize,\n height: previewDisplaySize,\n objectFit: 'contain',\n borderRadius: 4,\n border: '1px solid var(--border-primary, #e5e5e5)',\n }}\n />\n ) : (\n <div\n style={{\n width: previewDisplaySize,\n height: previewDisplaySize,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 24,\n opacity: 0.6,\n border: '1px solid var(--border-primary, #e5e5e5)',\n borderRadius: 4,\n }}\n >\n <Icon icon={icons.fileText} />\n </div>\n )}\n <span style={{ fontSize: 13, color: 'var(--foreground, #333)' }}>{layer.name}</span>\n </div>\n);\n\n// ── Main panel ───────────────────────────────────────────────────────────\n\nexport const LayersPanel: React.FC<LayersPanelProps> = ({\n width = 250,\n height,\n showPreviewImages = true,\n enableDragReorder = false,\n enableGrouping = false,\n style = {},\n className = '',\n showHeader = true,\n ...layerOptions\n}) => {\n const { activeArtboard } = useArtboards();\n const previewBgColor = activeArtboard?.previewBackgroundColor || activeArtboard?.backgroundColor || 'transparent';\n const previewDisplaySize = 80;\n const previewResolution = 160;\n\n const {\n layers,\n flatLayers,\n selectLayer,\n toggleVisibility,\n toggleLock,\n deleteLayer,\n duplicateLayer,\n reorderById,\n reorderWithinGroup,\n addToGroup,\n removeFromGroup,\n createEmptyGroup,\n findElementById,\n findParentGroup,\n generateAllPreviews,\n } = useLayers({\n ...layerOptions,\n previewSize: previewResolution,\n previewBackgroundColor: previewBgColor,\n });\n\n useEffect(() => {\n if (showPreviewImages && flatLayers.length > 0) {\n generateAllPreviews();\n }\n }, [showPreviewImages, flatLayers.length, previewBgColor, generateAllPreviews]);\n\n // Build a lookup map for finding layers by ID\n const layerMap = useMemo(() => {\n const map = new Map<string, LayerInfo>();\n const collect = (layerList: LayerInfo[]) => {\n for (const layer of layerList) {\n map.set(layer.id, layer);\n if (layer.children) collect(layer.children);\n }\n };\n collect(layers);\n return map;\n }, [layers]);\n\n // When a child is dragged to a top-level position, remove it from its group.\n // removeFromGroup handles everything: clones the child with absolute positioning,\n // updates/removes the group, adds the promoted element, and selects it.\n // No follow-up reorder — it causes state conflicts since removeFromGroup\n // already mutates the element list.\n const handleReorder = useCallback(\n (draggedId: string, targetId: string, position: 'before' | 'after') => {\n const draggedParent = findParentGroup(draggedId);\n const targetParent = findParentGroup(targetId);\n\n if (draggedParent && !targetParent) {\n removeFromGroup(draggedId, targetId, position);\n } else {\n reorderById(draggedId, targetId, position);\n }\n },\n [findParentGroup, removeFromGroup, reorderById]\n );\n\n // dnd-kit hook\n const activeDnd = useLayerDndKit({\n onReorder: handleReorder,\n onDropIntoGroup: addToGroup,\n onDropIntoGroupAtPosition: (draggedId, groupId) => addToGroup(draggedId, groupId),\n onGroupReorder: reorderWithinGroup,\n onRemoveFromGroup: removeFromGroup,\n findElement: findElementById,\n findParentGroup,\n });\n\n // ── Render helpers ─────────────────────────────────────────────────────\n\n const renderDraggableLayerTree = (layerList: LayerInfo[]): React.ReactNode => {\n const reversedList = [...layerList].reverse();\n return reversedList.map((layer) => (\n <React.Fragment key={layer.id}>\n <SortableLayerItem\n layer={layer}\n isOver={activeDnd.overId === layer.id}\n dropPosition={activeDnd.overId === layer.id ? activeDnd.dropPosition : null}\n isDragActive={!!activeDnd.activeId}\n showPreviewImages={showPreviewImages}\n previewDisplaySize={previewDisplaySize}\n onSelect={selectLayer}\n onToggleVisibility={toggleVisibility}\n onToggleLock={toggleLock}\n onDuplicate={duplicateLayer}\n onDelete={deleteLayer}\n />\n {layer.children && renderDraggableLayerTree(layer.children)}\n {layer.isGroup && (\n <GroupFooterDropZone\n groupId={layer.id}\n isOver={activeDnd.overId === `group-footer::${layer.id}`}\n depth={layer.depth}\n />\n )}\n </React.Fragment>\n ));\n };\n\n const renderStaticLayerTree = (layerList: LayerInfo[]): React.ReactNode => {\n const reversedList = [...layerList].reverse();\n return reversedList.map((layer) => (\n <React.Fragment key={layer.id}>\n <StaticLayerItem\n layer={layer}\n showPreviewImages={showPreviewImages}\n previewDisplaySize={previewDisplaySize}\n onSelect={selectLayer}\n onToggleVisibility={toggleVisibility}\n onToggleLock={toggleLock}\n onDuplicate={duplicateLayer}\n onDelete={deleteLayer}\n />\n {layer.children && renderStaticLayerTree(layer.children)}\n </React.Fragment>\n ));\n };\n\n // Active drag overlay\n const activeLayer = activeDnd.activeId ? layerMap.get(activeDnd.activeId) : null;\n\n // ── Layout ─────────────────────────────────────────────────────────────\n\n const { width: styleWidth, height: styleHeight, flex, ...restStyle } = style;\n const finalWidth = styleWidth ? styleWidth : className.includes('w-full') ? '100%' : width ? `${width}px` : undefined;\n const finalHeight = height || styleHeight || undefined;\n const shouldFill = finalHeight === '100%' || finalHeight === '100vh';\n const flexValue = flex !== undefined ? flex : shouldFill ? 1 : undefined;\n\n return (\n <div\n className={`layers-panel ${className}`}\n style={{\n width: finalWidth,\n height: finalHeight,\n flex: flexValue,\n display: 'flex',\n flexDirection: 'column',\n backgroundColor: 'transparent',\n minHeight: 0,\n ...restStyle,\n }}\n >\n {/* Header */}\n {(showHeader || enableGrouping) && (\n <div\n style={{\n padding: '10px 16px',\n borderBottom: '1px solid var(--border-primary, #e5e5e5)',\n fontWeight: 500,\n fontSize: 13,\n color: 'var(--text-secondary, #666)',\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n }}\n >\n {showHeader && <span>Layers ({flatLayers.length})</span>}\n {!showHeader && <span />}\n {enableGrouping && (\n <button\n onClick={createEmptyGroup}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n fontSize: 13,\n fontWeight: 500,\n color: 'var(--primary, var(--accent-primary, #007AFF))',\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n }}\n >\n <Icon icon=\"lucide:folder-plus\" style={{ fontSize: 16 }} />\n Add Group\n </button>\n )}\n </div>\n )}\n\n <div style={{ flex: 1, overflow: 'auto', minHeight: 0 }}>\n {layers.length > 0 ? (\n enableDragReorder ? (\n <DndContext\n sensors={activeDnd.sensors}\n collisionDetection={layerCollisionDetection}\n onDragStart={activeDnd.onDragStart}\n onDragMove={activeDnd.onDragMove}\n onDragOver={activeDnd.onDragOver}\n onDragEnd={activeDnd.onDragEnd}\n onDragCancel={activeDnd.onDragCancel}\n >\n {renderDraggableLayerTree(layers)}\n <DragOverlay dropAnimation={null}>\n {activeLayer ? (\n <DragOverlayContent\n layer={activeLayer}\n showPreviewImages={showPreviewImages}\n previewDisplaySize={previewDisplaySize}\n />\n ) : null}\n </DragOverlay>\n </DndContext>\n ) : (\n renderStaticLayerTree(layers)\n )\n ) : (\n <div\n style={{\n padding: 24,\n textAlign: 'center',\n color: 'var(--text-secondary, #999)',\n fontSize: 12,\n }}\n >\n No layers\n </div>\n )}\n\n {/* Drag hint */}\n {enableDragReorder && layers.length > 1 && (\n <div\n style={{\n padding: '12px 16px',\n textAlign: 'center',\n color: 'var(--text-secondary, #aaa)',\n fontSize: 12,\n }}\n >\n Drag to reorder\n </div>\n )}\n </div>\n </div>\n );\n};\n\n// ── Static layer item (no drag) ──────────────────────────────────────────\n\nconst StaticLayerItem: React.FC<{\n layer: LayerInfo;\n showPreviewImages: boolean;\n previewDisplaySize: number;\n onSelect: (id: string) => void;\n onToggleVisibility: (id: string) => void;\n onToggleLock: (id: string) => void;\n onDuplicate: (id: string) => void;\n onDelete: (id: string) => void;\n}> = ({ layer, showPreviewImages, previewDisplaySize, onSelect, onToggleVisibility, onToggleLock, onDuplicate, onDelete }) => {\n const isChild = layer.depth > 0;\n const indentPx = isChild ? layer.depth * 24 : 0;\n\n const selectionRingStyle = layer.isSelected\n ? { outline: '3px solid var(--primary, var(--accent-primary, #007AFF))', outlineOffset: '2px' }\n : {};\n\n const rowStyle: React.CSSProperties = {\n paddingLeft: indentPx + 8,\n paddingRight: 8,\n paddingTop: layer.isGroup ? 6 : 8,\n paddingBottom: layer.isGroup ? 6 : 8,\n minHeight: layer.isGroup ? 32 : 36,\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n cursor: 'pointer',\n };\n\n if (isChild || layer.isGroup) {\n rowStyle.backgroundColor = 'var(--surface-secondary, rgba(0,0,0,0.04))';\n }\n\n if (layer.isGroup) {\n return (\n <div key={layer.id} style={rowStyle}>\n <Icon icon=\"lucide:folder-open\" style={{ fontSize: 18, color: 'var(--text-secondary, #888)' }} />\n <span onClick={() => onSelect(layer.id)} style={{ fontSize: 13, fontWeight: 600, flex: 1 }}>\n {layer.name}\n </span>\n </div>\n );\n }\n\n return (\n <div key={layer.id} style={rowStyle}>\n {showPreviewImages && layer.previewUrl ? (\n <img\n src={layer.previewUrl}\n alt={layer.name}\n onClick={() => onSelect(layer.id)}\n style={{\n width: previewDisplaySize,\n height: previewDisplaySize,\n objectFit: 'contain',\n borderRadius: 4,\n border: '1px solid var(--border-primary, #e5e5e5)',\n cursor: 'pointer',\n ...selectionRingStyle,\n }}\n />\n ) : (\n <div\n style={{\n width: previewDisplaySize,\n height: previewDisplaySize,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: 24,\n opacity: 0.6,\n border: '1px solid var(--border-primary, #e5e5e5)',\n borderRadius: 4,\n cursor: 'pointer',\n ...selectionRingStyle,\n }}\n onClick={() => onSelect(layer.id)}\n >\n <Icon icon={icons.fileText} />\n </div>\n )}\n <div style={{ flex: 1 }} onClick={() => onSelect(layer.id)} />\n <div style={{ display: 'flex', gap: 4 }}>\n <LayerActionButton\n title={layer.visible ? 'Hide' : 'Show'}\n onClick={() => onToggleVisibility(layer.id)}\n style={{ opacity: layer.visible ? 1 : 0.4 }}\n >\n <Icon icon={layer.visible ? icons.eye : icons.eyeOff} className=\"size-6\" />\n </LayerActionButton>\n <LayerActionButton\n title={layer.locked ? 'Unlock' : 'Lock'}\n onClick={() => onToggleLock(layer.id)}\n style={{ opacity: layer.locked ? 1 : 0.4 }}\n >\n <Icon icon={layer.locked ? icons.lock : icons.lockOpen} className=\"size-6\" />\n </LayerActionButton>\n <LayerActionButton title=\"Duplicate\" onClick={() => onDuplicate(layer.id)}>\n <Icon icon={icons.copy} className=\"size-6\" />\n </LayerActionButton>\n <LayerActionButton\n title=\"Delete\"\n onClick={() => onDelete(layer.id)}\n style={{ color: 'var(--error, #ef4444)' }}\n >\n <Icon icon={icons.trash} className=\"size-6\" />\n </LayerActionButton>\n </div>\n </div>\n );\n};\n","/**\n * Drawer - Shared drawer component for canvas editor\n * Built on top of @snowcone-app/ui Drawer (iOS-safe, no Vaul dependency)\n *\n * Z-INDEX IMPORTANT:\n * - Overlay: var(--z-overlay) = 10001 (above modals at 10000)\n * - Content: var(--z-drawer) = 10002 (highest z-index in app)\n * - See docs/Z_INDEX_HIERARCHY.md for complete reference\n */\n\nimport React from 'react';\nimport {\n Drawer as BaseDrawer,\n DrawerContent,\n DrawerTitle,\n DrawerDescription,\n} from '@snowcone-app/ui';\nimport { Button, icons } from './ui';\nimport { Icon } from '@iconify/react';\n\nexport interface DrawerProps {\n /** Whether the drawer is open */\n isOpen: boolean;\n /** Callback when drawer should close */\n onClose: () => void;\n /** Drawer title (for accessibility and header) */\n title: string;\n /** Optional description (for accessibility) */\n description?: string;\n /** Drawer content */\n children: React.ReactNode;\n /** Placement of drawer */\n placement?: 'bottom' | 'right' | 'left';\n /** Fixed height (for bottom drawer) */\n height?: string;\n /** Maximum height (for bottom drawer) */\n maxHeight?: string;\n /** Fixed width (for side drawers) */\n width?: string;\n /** Maximum width (for side drawers) */\n maxWidth?: string;\n /** Show close button in header */\n showCloseButton?: boolean;\n /** Additional header content (placed next to title) */\n headerActions?: React.ReactNode;\n /** Hide the visible title (keeps sr-only title for accessibility) */\n hideVisibleTitle?: boolean;\n /** Hide the drag handle (bottom drawer only) */\n hideHandle?: boolean;\n /** Disable built-in overflow-y-auto wrapper (for custom scroll containers) */\n disableScrollWrapper?: boolean;\n /** Disable overflow-hidden on drawer content (needed for backdrop-filter to work properly) */\n disableOverflowHidden?: boolean;\n /** Test ID for the drawer content element */\n 'data-testid'?: string;\n}\n\n/**\n * Drawer component for canvas editor\n *\n * @example\n * ```tsx\n * <Drawer\n * isOpen={isOpen}\n * onClose={() => setIsOpen(false)}\n * title=\"Export Settings\"\n * description=\"Configure export options\"\n * >\n * <div className=\"p-6\">Content here</div>\n * </Drawer>\n * ```\n */\n/**\n * Tracks whether the document is in dark mode (driven by `.dark` on the\n * <html> element, the project-wide convention). Re-runs when the class\n * toggles via theme switch.\n *\n * Used to bump the drawer scrim opacity in dark mode — the default 0.4\n * black overlay barely darkens the page when the page background is\n * already near-black, so the drawer card's medium-gray border doesn't\n * read against the page behind it. A heavier scrim restores separation.\n */\nfunction useIsDocumentDark(): boolean {\n const [isDark, setIsDark] = React.useState(false);\n React.useEffect(() => {\n if (typeof document === 'undefined') return;\n const update = () =>\n setIsDark(document.documentElement.classList.contains('dark'));\n update();\n const obs = new MutationObserver(update);\n obs.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['class'],\n });\n return () => obs.disconnect();\n }, []);\n return isDark;\n}\n\nexport const Drawer: React.FC<DrawerProps> = ({\n isOpen,\n onClose,\n title,\n description,\n children,\n placement = 'bottom',\n height,\n maxHeight = '70vh',\n width,\n maxWidth = '400px',\n showCloseButton = true,\n headerActions,\n hideVisibleTitle = false,\n hideHandle = false,\n disableScrollWrapper = false,\n disableOverflowHidden = false,\n 'data-testid': dataTestId,\n}) => {\n // Calculate heightRatio for bottom drawer\n // The new Drawer uses heightRatio (0-1) but canvas uses CSS height values\n // We'll use className to set custom height instead\n const heightStyle = placement === 'bottom' ? (height || maxHeight) : undefined;\n\n // Dark mode gets a heavier scrim so the drawer's medium-gray border has\n // somewhere to push against and the blurred page reads as muted, not\n // bright-leaking. Surface lift is handled by the design-system token\n // bump on `--surface` in dark mode (see globals.css) — no per-component\n // background override needed.\n const isDark = useIsDocumentDark();\n const scrimOpacity = isDark ? 0.65 : 0.4;\n\n return (\n <BaseDrawer\n open={isOpen}\n onOpenChange={(open) => !open && onClose()}\n >\n <DrawerContent\n placement={placement}\n width={width}\n maxWidth={maxWidth}\n hideHandle={hideHandle || placement !== 'bottom'}\n showOverlay={true}\n overlayOpacity={scrimOpacity}\n className={disableOverflowHidden ? '' : 'overflow-hidden'}\n style={{\n // Override height for canvas-specific needs\n ...(heightStyle && placement === 'bottom' ? { height: heightStyle } : {}),\n // Canvas uses custom z-index variables\n zIndex: 'var(--z-drawer, 10002)',\n }}\n data-testid={dataTestId}\n data-preserve-selection\n >\n {/* Accessibility - Hidden title and description */}\n <DrawerTitle className=\"sr-only\">{title}</DrawerTitle>\n {description && <DrawerDescription className=\"sr-only\">{description}</DrawerDescription>}\n\n {/* Content wrapper - conditionally scrollable */}\n {/* Note: @snowcone-app/ui DrawerContent already provides Surface context, so we don't need a wrapper here */}\n {disableScrollWrapper ? (\n // Custom scroll control - children manage their own scrolling\n <div className=\"flex flex-col flex-1 min-h-0\">\n {/* Drag handle is rendered by DrawerContent (the underlying\n primitive). Don't render it here too — that creates a stale\n second handle and wastes ~28px of vertical space above the\n drawer header. */}\n\n {/* Header */}\n {(!hideVisibleTitle || headerActions || showCloseButton) && (\n <div className=\"border-border-primary flex shrink-0 items-center justify-between gap-4 border-b px-6 py-4\">\n {!hideVisibleTitle && <h2 className=\"text-foreground text-lg font-semibold\">{title}</h2>}\n <div className=\"flex items-center gap-2\">\n {headerActions}\n {showCloseButton && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onClose}\n className=\"min-w-8 px-2\"\n aria-label=\"Close drawer\"\n >\n <Icon icon={icons.close} className=\"size-6\" />\n </Button>\n )}\n </div>\n </div>\n )}\n\n {children}\n </div>\n ) : (\n // Default: built-in overflow-y-auto wrapper\n <div className=\"flex-1 overflow-y-auto min-h-0\">\n {/* Drag handle rendered by DrawerContent — see note above. */}\n\n {/* Header */}\n {(!hideVisibleTitle || headerActions || showCloseButton) && (\n <div className=\"border-border-primary flex shrink-0 items-center justify-between gap-4 border-b px-6 py-4\">\n {!hideVisibleTitle && <h2 className=\"text-foreground text-lg font-semibold\">{title}</h2>}\n <div className=\"flex items-center gap-2\">\n {headerActions}\n {showCloseButton && (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={onClose}\n className=\"min-w-8 px-2\"\n aria-label=\"Close drawer\"\n >\n <Icon icon={icons.close} className=\"size-6\" />\n </Button>\n )}\n </div>\n </div>\n )}\n\n {children}\n </div>\n )}\n </DrawerContent>\n </BaseDrawer>\n );\n};\n\nexport default Drawer;\n","import e,{useRef as r,useMemo as n,useEffect as t,useState as o,useCallback as a,useLayoutEffect as l}from\"react\";function u(){return(u=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var n=arguments[r];for(var t in n)Object.prototype.hasOwnProperty.call(n,t)&&(e[t]=n[t])}return e}).apply(this,arguments)}function c(e,r){if(null==e)return{};var n,t,o={},a=Object.keys(e);for(t=0;t<a.length;t++)r.indexOf(n=a[t])>=0||(o[n]=e[n]);return o}function i(e){var n=r(e),t=r(function(e){n.current&&n.current(e)});return n.current=e,t.current}var s=function(e,r,n){return void 0===r&&(r=0),void 0===n&&(n=1),e>n?n:e<r?r:e},f=function(e){return\"touches\"in e},v=function(e){return e&&e.ownerDocument.defaultView||self},d=function(e,r,n){var t=e.getBoundingClientRect(),o=f(r)?function(e,r){for(var n=0;n<e.length;n++)if(e[n].identifier===r)return e[n];return e[0]}(r.touches,n):r;return{left:s((o.pageX-(t.left+v(e).pageXOffset))/t.width),top:s((o.pageY-(t.top+v(e).pageYOffset))/t.height)}},h=function(e){!f(e)&&e.preventDefault()},g=e.memo(function(o){var a=o.onMove,l=o.onKey,s=o.onEnd,g=c(o,[\"onMove\",\"onKey\",\"onEnd\"]),m=r(null),p=i(a),b=i(l),_=i(s),E=r(null),C=r(!1),x=n(function(){var e=function(e){h(e),(f(e)?e.touches.length>0:e.buttons>0)&&m.current?p(d(m.current,e,E.current)):(n(!1),_())},r=function(){n(!1),_()};function n(n){var t=C.current,o=v(m.current),a=n?o.addEventListener:o.removeEventListener;a(t?\"touchmove\":\"mousemove\",e),a(t?\"touchend\":\"mouseup\",r)}return[function(e){var r=e.nativeEvent,t=m.current;if(t&&(h(r),!function(e,r){return r&&!f(e)}(r,C.current)&&t)){if(f(r)){C.current=!0;var o=r.changedTouches||[];o.length&&(E.current=o[0].identifier)}t.focus(),p(d(t,r,E.current)),n(!0)}},function(e){var r=e.which||e.keyCode;r<37||r>40||(e.preventDefault(),b({left:39===r?.05:37===r?-.05:0,top:40===r?.05:38===r?-.05:0}))},function(e){var r=e.which||e.keyCode;r>=37&&r<=40&&_()},n]},[b,p,_]),H=x[0],M=x[1],N=x[2],w=x[3];return t(function(){return w},[w]),e.createElement(\"div\",u({},g,{onTouchStart:H,onMouseDown:H,className:\"react-colorful__interactive\",ref:m,onKeyDown:M,onKeyUp:N,tabIndex:0,role:\"slider\"}))}),m=function(e){return e.filter(Boolean).join(\" \")},p=function(r){var n=r.color,t=r.left,o=r.top,a=void 0===o?.5:o,l=m([\"react-colorful__pointer\",r.className]);return e.createElement(\"div\",{className:l,style:{top:100*a+\"%\",left:100*t+\"%\"}},e.createElement(\"div\",{className:\"react-colorful__pointer-fill\",style:{backgroundColor:n}}))},b=function(e,r,n){return void 0===r&&(r=0),void 0===n&&(n=Math.pow(10,r)),Math.round(n*e)/n},_={grad:.9,turn:360,rad:360/(2*Math.PI)},E=function(e){return L(C(e))},C=function(e){return\"#\"===e[0]&&(e=e.substring(1)),e.length<6?{r:parseInt(e[0]+e[0],16),g:parseInt(e[1]+e[1],16),b:parseInt(e[2]+e[2],16),a:4===e.length?b(parseInt(e[3]+e[3],16)/255,2):1}:{r:parseInt(e.substring(0,2),16),g:parseInt(e.substring(2,4),16),b:parseInt(e.substring(4,6),16),a:8===e.length?b(parseInt(e.substring(6,8),16)/255,2):1}},x=function(e,r){return void 0===r&&(r=\"deg\"),Number(e)*(_[r]||1)},H=function(e){var r=/hsla?\\(?\\s*(-?\\d*\\.?\\d+)(deg|rad|grad|turn)?[,\\s]+(-?\\d*\\.?\\d+)%?[,\\s]+(-?\\d*\\.?\\d+)%?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?N({h:x(r[1],r[2]),s:Number(r[3]),l:Number(r[4]),a:void 0===r[5]?1:Number(r[5])/(r[6]?100:1)}):{h:0,s:0,v:0,a:1}},M=H,N=function(e){var r=e.s,n=e.l;return{h:e.h,s:(r*=(n<50?n:100-n)/100)>0?2*r/(n+r)*100:0,v:n+r,a:e.a}},w=function(e){return D(I(e))},y=function(e){var r=e.s,n=e.v,t=e.a,o=(200-r)*n/100;return{h:b(e.h),s:b(o>0&&o<200?r*n/100/(o<=100?o:200-o)*100:0),l:b(o/2),a:b(t,2)}},q=function(e){var r=y(e);return\"hsl(\"+r.h+\", \"+r.s+\"%, \"+r.l+\"%)\"},k=function(e){var r=y(e);return\"hsla(\"+r.h+\", \"+r.s+\"%, \"+r.l+\"%, \"+r.a+\")\"},I=function(e){var r=e.h,n=e.s,t=e.v,o=e.a;r=r/360*6,n/=100,t/=100;var a=Math.floor(r),l=t*(1-n),u=t*(1-(r-a)*n),c=t*(1-(1-r+a)*n),i=a%6;return{r:b(255*[t,u,l,l,c,t][i]),g:b(255*[c,t,t,u,l,l][i]),b:b(255*[l,l,c,t,t,u][i]),a:b(o,2)}},O=function(e){var r=/hsva?\\(?\\s*(-?\\d*\\.?\\d+)(deg|rad|grad|turn)?[,\\s]+(-?\\d*\\.?\\d+)%?[,\\s]+(-?\\d*\\.?\\d+)%?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?A({h:x(r[1],r[2]),s:Number(r[3]),v:Number(r[4]),a:void 0===r[5]?1:Number(r[5])/(r[6]?100:1)}):{h:0,s:0,v:0,a:1}},j=O,z=function(e){var r=/rgba?\\(?\\s*(-?\\d*\\.?\\d+)(%)?[,\\s]+(-?\\d*\\.?\\d+)(%)?[,\\s]+(-?\\d*\\.?\\d+)(%)?,?\\s*[/\\s]*(-?\\d*\\.?\\d+)?(%)?\\s*\\)?/i.exec(e);return r?L({r:Number(r[1])/(r[2]?100/255:1),g:Number(r[3])/(r[4]?100/255:1),b:Number(r[5])/(r[6]?100/255:1),a:void 0===r[7]?1:Number(r[7])/(r[8]?100:1)}):{h:0,s:0,v:0,a:1}},K=z,B=function(e){var r=e.toString(16);return r.length<2?\"0\"+r:r},D=function(e){var r=e.r,n=e.g,t=e.b,o=e.a,a=o<1?B(b(255*o)):\"\";return\"#\"+B(r)+B(n)+B(t)+a},L=function(e){var r=e.r,n=e.g,t=e.b,o=e.a,a=Math.max(r,n,t),l=a-Math.min(r,n,t),u=l?a===r?(n-t)/l:a===n?2+(t-r)/l:4+(r-n)/l:0;return{h:b(60*(u<0?u+6:u)),s:b(a?l/a*100:0),v:b(a/255*100),a:o}},A=function(e){return{h:b(e.h),s:b(e.s),v:b(e.v),a:b(e.a,2)}},S=e.memo(function(r){var n=r.hue,t=r.onChange,o=r.onChangeEnd,a=m([\"react-colorful__hue\",r.className]);return e.createElement(\"div\",{className:a},e.createElement(g,{onMove:function(e){t({h:360*e.left})},onKey:function(e){t({h:s(n+360*e.left,0,360)})},onEnd:o,\"aria-label\":\"Hue\",\"aria-valuenow\":b(n),\"aria-valuemax\":\"360\",\"aria-valuemin\":\"0\"},e.createElement(p,{className:\"react-colorful__hue-pointer\",left:n/360,color:q({h:n,s:100,v:100,a:1})})))}),T=e.memo(function(r){var n=r.hsva,t=r.onChange,o=r.onChangeEnd,a={backgroundColor:q({h:n.h,s:100,v:100,a:1})};return e.createElement(\"div\",{className:\"react-colorful__saturation\",style:a},e.createElement(g,{onMove:function(e){t({s:100*e.left,v:100-100*e.top})},onKey:function(e){t({s:s(n.s+100*e.left,0,100),v:s(n.v-100*e.top,0,100)})},onEnd:o,\"aria-label\":\"Color\",\"aria-valuetext\":\"Saturation \"+b(n.s)+\"%, Brightness \"+b(n.v)+\"%\"},e.createElement(p,{className:\"react-colorful__saturation-pointer\",top:1-n.v/100,left:n.s/100,color:q(n)})))}),F=function(e,r){if(e===r)return!0;for(var n in e)if(e[n]!==r[n])return!1;return!0},P=function(e,r){return e.replace(/\\s/g,\"\")===r.replace(/\\s/g,\"\")},X=function(e,r){return e.toLowerCase()===r.toLowerCase()||F(C(e),C(r))};function Y(e,n,l,u){var c=i(l),s=i(u),f=o(function(){return e.toHsva(n)}),v=f[0],d=f[1],h=r({color:n,hsva:v}),g=r(!1);t(function(){if(!e.equal(n,h.current.color)){var r=e.toHsva(n);h.current={hsva:r,color:n},d(r),g.current=!1}},[n,e]),t(function(){var r;F(v,h.current.hsva)||e.equal(r=e.fromHsva(v),h.current.color)||(h.current={hsva:v,color:r},c(r),g.current=!0)},[v,e,c]);var m=a(function(e){d(function(r){return Object.assign({},r,e)})},[]),p=a(function(){g.current&&(g.current=!1,s(h.current.color))},[s]);return[v,m,p]}var R,U=\"undefined\"!=typeof window?l:t,V=function(){return R||(\"undefined\"!=typeof __webpack_nonce__?__webpack_nonce__:void 0)},$=function(e){R=e},G=new Map,J=function(e){U(function(){var r=e.current?e.current.ownerDocument:document;if(void 0!==r&&!G.has(r)){var n=r.createElement(\"style\");n.innerHTML='.react-colorful{position:relative;display:flex;flex-direction:column;width:200px;height:200px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default}.react-colorful__saturation{position:relative;flex-grow:1;border-color:transparent;border-bottom:12px solid #000;border-radius:8px 8px 0 0;background-image:linear-gradient(0deg,#000,transparent),linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.react-colorful__alpha-gradient,.react-colorful__pointer-fill{content:\"\";position:absolute;left:0;top:0;right:0;bottom:0;pointer-events:none;border-radius:inherit}.react-colorful__alpha-gradient,.react-colorful__saturation{box-shadow:inset 0 0 0 1px rgba(0,0,0,.05)}.react-colorful__alpha,.react-colorful__hue{position:relative;height:24px}.react-colorful__hue{background:linear-gradient(90deg,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red)}.react-colorful__last-control{border-radius:0 0 8px 8px}.react-colorful__interactive{position:absolute;left:0;top:0;right:0;bottom:0;border-radius:inherit;outline:none;touch-action:none}.react-colorful__pointer{position:absolute;z-index:1;box-sizing:border-box;width:28px;height:28px;transform:translate(-50%,-50%);background-color:#fff;border:2px solid #fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2)}.react-colorful__interactive:focus .react-colorful__pointer{transform:translate(-50%,-50%) scale(1.1)}.react-colorful__alpha,.react-colorful__alpha-pointer{background-color:#fff;background-image:url(\\'data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill-opacity=\".05\"><path d=\"M8 0h8v8H8zM0 8h8v8H0z\"/></svg>\\')}.react-colorful__saturation-pointer{z-index:3}.react-colorful__hue-pointer{z-index:2}',G.set(r,n);var t=V();t&&n.setAttribute(\"nonce\",t),r.head.appendChild(n)}},[])},Q=function(n){var t=n.className,o=n.colorModel,a=n.color,l=void 0===a?o.defaultColor:a,i=n.onChange,s=n.onChangeEnd,f=c(n,[\"className\",\"colorModel\",\"color\",\"onChange\",\"onChangeEnd\"]),v=r(null);J(v);var d=Y(o,l,i,s),h=d[0],g=d[1],p=d[2],b=m([\"react-colorful\",t]);return e.createElement(\"div\",u({},f,{ref:v,className:b}),e.createElement(T,{hsva:h,onChange:g,onChangeEnd:p}),e.createElement(S,{hue:h.h,onChange:g,onChangeEnd:p,className:\"react-colorful__last-control\"}))},W={defaultColor:\"000\",toHsva:E,fromHsva:function(e){return w({h:e.h,s:e.s,v:e.v,a:1})},equal:X},Z=function(r){return e.createElement(Q,u({},r,{colorModel:W}))},ee=function(r){var n=r.className,t=r.hsva,o=r.onChange,a=r.onChangeEnd,l={backgroundImage:\"linear-gradient(90deg, \"+k(Object.assign({},t,{a:0}))+\", \"+k(Object.assign({},t,{a:1}))+\")\"},u=m([\"react-colorful__alpha\",n]),c=b(100*t.a);return e.createElement(\"div\",{className:u},e.createElement(\"div\",{className:\"react-colorful__alpha-gradient\",style:l}),e.createElement(g,{onMove:function(e){o({a:e.left})},onKey:function(e){o({a:s(t.a+e.left)})},onEnd:a,\"aria-label\":\"Alpha\",\"aria-valuetext\":c+\"%\",\"aria-valuenow\":c,\"aria-valuemin\":\"0\",\"aria-valuemax\":\"100\"},e.createElement(p,{className:\"react-colorful__alpha-pointer\",left:t.a,color:k(t)})))},re=function(n){var t=n.className,o=n.colorModel,a=n.color,l=void 0===a?o.defaultColor:a,i=n.onChange,s=n.onChangeEnd,f=c(n,[\"className\",\"colorModel\",\"color\",\"onChange\",\"onChangeEnd\"]),v=r(null);J(v);var d=Y(o,l,i,s),h=d[0],g=d[1],p=d[2],b=m([\"react-colorful\",t]);return e.createElement(\"div\",u({},f,{ref:v,className:b}),e.createElement(T,{hsva:h,onChange:g,onChangeEnd:p}),e.createElement(S,{hue:h.h,onChange:g,onChangeEnd:p}),e.createElement(ee,{hsva:h,onChange:g,onChangeEnd:p,className:\"react-colorful__last-control\"}))},ne={defaultColor:\"0001\",toHsva:E,fromHsva:w,equal:X},te=function(r){return e.createElement(re,u({},r,{colorModel:ne}))},oe={defaultColor:{h:0,s:0,l:0,a:1},toHsva:N,fromHsva:y,equal:F},ae=function(r){return e.createElement(re,u({},r,{colorModel:oe}))},le={defaultColor:\"hsla(0, 0%, 0%, 1)\",toHsva:H,fromHsva:k,equal:P},ue=function(r){return e.createElement(re,u({},r,{colorModel:le}))},ce={defaultColor:{h:0,s:0,l:0},toHsva:function(e){return N({h:e.h,s:e.s,l:e.l,a:1})},fromHsva:function(e){return{h:(r=y(e)).h,s:r.s,l:r.l};var r},equal:F},ie=function(r){return e.createElement(Q,u({},r,{colorModel:ce}))},se={defaultColor:\"hsl(0, 0%, 0%)\",toHsva:M,fromHsva:q,equal:P},fe=function(r){return e.createElement(Q,u({},r,{colorModel:se}))},ve={defaultColor:{h:0,s:0,v:0,a:1},toHsva:function(e){return e},fromHsva:A,equal:F},de=function(r){return e.createElement(re,u({},r,{colorModel:ve}))},he={defaultColor:\"hsva(0, 0%, 0%, 1)\",toHsva:O,fromHsva:function(e){var r=A(e);return\"hsva(\"+r.h+\", \"+r.s+\"%, \"+r.v+\"%, \"+r.a+\")\"},equal:P},ge=function(r){return e.createElement(re,u({},r,{colorModel:he}))},me={defaultColor:{h:0,s:0,v:0},toHsva:function(e){return{h:e.h,s:e.s,v:e.v,a:1}},fromHsva:function(e){var r=A(e);return{h:r.h,s:r.s,v:r.v}},equal:F},pe=function(r){return e.createElement(Q,u({},r,{colorModel:me}))},be={defaultColor:\"hsv(0, 0%, 0%)\",toHsva:j,fromHsva:function(e){var r=A(e);return\"hsv(\"+r.h+\", \"+r.s+\"%, \"+r.v+\"%)\"},equal:P},_e=function(r){return e.createElement(Q,u({},r,{colorModel:be}))},Ee={defaultColor:{r:0,g:0,b:0,a:1},toHsva:L,fromHsva:I,equal:F},Ce=function(r){return e.createElement(re,u({},r,{colorModel:Ee}))},xe={defaultColor:\"rgba(0, 0, 0, 1)\",toHsva:z,fromHsva:function(e){var r=I(e);return\"rgba(\"+r.r+\", \"+r.g+\", \"+r.b+\", \"+r.a+\")\"},equal:P},He=function(r){return e.createElement(re,u({},r,{colorModel:xe}))},Me={defaultColor:{r:0,g:0,b:0},toHsva:function(e){return L({r:e.r,g:e.g,b:e.b,a:1})},fromHsva:function(e){return{r:(r=I(e)).r,g:r.g,b:r.b};var r},equal:F},Ne=function(r){return e.createElement(Q,u({},r,{colorModel:Me}))},we={defaultColor:\"rgb(0, 0, 0)\",toHsva:K,fromHsva:function(e){var r=I(e);return\"rgb(\"+r.r+\", \"+r.g+\", \"+r.b+\")\"},equal:P},ye=function(r){return e.createElement(Q,u({},r,{colorModel:we}))},qe=/^#?([0-9A-F]{3,8})$/i,ke=function(r){var n=r.color,l=void 0===n?\"\":n,s=r.onChange,f=r.onBlur,v=r.escape,d=r.validate,h=r.format,g=r.process,m=c(r,[\"color\",\"onChange\",\"onBlur\",\"escape\",\"validate\",\"format\",\"process\"]),p=o(function(){return v(l)}),b=p[0],_=p[1],E=i(s),C=i(f),x=a(function(e){var r=v(e.target.value);_(r),d(r)&&E(g?g(r):r)},[v,g,d,E]),H=a(function(e){d(e.target.value)||_(v(l)),C(e)},[l,v,d,C]);return t(function(){_(v(l))},[l,v]),e.createElement(\"input\",u({},m,{value:h?h(b):b,spellCheck:\"false\",onChange:x,onBlur:H}))},Ie=function(e){return\"#\"+e},Oe=function(r){var n=r.prefixed,t=r.alpha,o=c(r,[\"prefixed\",\"alpha\"]),l=a(function(e){return e.replace(/([^0-9A-F]+)/gi,\"\").substring(0,t?8:6)},[t]),i=a(function(e){return function(e,r){var n=qe.exec(e),t=n?n[1].length:0;return 3===t||6===t||!!r&&4===t||!!r&&8===t}(e,t)},[t]);return e.createElement(ke,u({},o,{escape:l,format:n?Ie:void 0,process:Ie,validate:i}))};export{te as HexAlphaColorPicker,Oe as HexColorInput,Z as HexColorPicker,ie as HslColorPicker,fe as HslStringColorPicker,ae as HslaColorPicker,ue as HslaStringColorPicker,pe as HsvColorPicker,_e as HsvStringColorPicker,de as HsvaColorPicker,ge as HsvaStringColorPicker,Ne as RgbColorPicker,ye as RgbStringColorPicker,Ce as RgbaColorPicker,He as RgbaStringColorPicker,$ as setNonce};\n//# sourceMappingURL=index.module.js.map\n","/**\n * ColorPickerDropdown - Custom color picker with dropdown\n * Uses react-colorful for a better UX than native browser picker\n */\n\nimport { useState, useEffect, memo, useRef } from 'react';\nimport { HexColorPicker } from 'react-colorful';\nimport { Button, Popover, PopoverTrigger, PopoverContent } from './ui';\n\nexport interface ColorPickerDropdownProps {\n value: string;\n onChange: (event: { target: { value: string } }) => void;\n /** Colours already in use elsewhere in the design (text, shapes,\n * paths, strokes, artboard background). Surfaced as the\n * \"Document colors\" row. */\n documentColors?: string[];\n /** Dominant colours sampled from image elements in the design.\n * Surfaced as a separate \"Image colors\" row so users can match\n * a colour from their artwork. Empty / omitted hides the row. */\n imageColors?: string[];\n icon?: React.ReactNode;\n showSquare?: boolean;\n allowTransparent?: boolean;\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n /** When true, renders the color picker content directly without a popover trigger button */\n embedded?: boolean;\n}\n\nconst ColorPickerDropdown = memo(({\n value,\n onChange,\n documentColors = [],\n imageColors = [],\n icon,\n showSquare = false,\n allowTransparent = false,\n isOpen: controlledIsOpen,\n onOpenChange: controlledOnOpenChange,\n embedded = false,\n}: ColorPickerDropdownProps) => {\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n const [hexInput, setHexInput] = useState(value);\n const [localColor, setLocalColor] = useState(value);\n const lastUpdateTimeRef = useRef<number>(0);\n const pendingUpdateRef = useRef<NodeJS.Timeout | null>(null);\n const isDraggingRef = useRef<boolean>(false);\n\n // CRITICAL: Store onChange in a ref to avoid stale closure bug\n // When throttled updates fire via setTimeout, they need the LATEST onChange,\n // not the one captured when the timeout was created\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n // Use controlled state if provided, otherwise use internal state\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen;\n const setIsOpen = controlledOnOpenChange || setInternalIsOpen;\n\n // Sync local state with value prop - but ONLY when not actively dragging\n // This prevents jank from prop updates conflicting with local drag state\n useEffect(() => {\n if (!isDraggingRef.current && value !== 'transparent') {\n setHexInput(value);\n setLocalColor(value);\n }\n }, [value]);\n\n // Throttled color change - updates at max 60fps for smooth real-time feedback\n const handleColorChange = (color: string) => {\n // Mark as dragging to prevent prop sync from causing jank\n isDraggingRef.current = true;\n\n // Update local state immediately for smooth UI\n setLocalColor(color);\n setHexInput(color);\n\n const now = Date.now();\n const timeSinceLastUpdate = now - lastUpdateTimeRef.current;\n\n // Throttle: update max once every 16ms (~60fps) for smooth real-time updates\n if (timeSinceLastUpdate >= 16) {\n // Call immediately if enough time has passed\n // Use ref to always get latest onChange (avoids stale closure on mobile)\n onChangeRef.current({ target: { value: color } });\n lastUpdateTimeRef.current = now;\n\n // Clear any pending update\n if (pendingUpdateRef.current) {\n clearTimeout(pendingUpdateRef.current);\n pendingUpdateRef.current = null;\n }\n } else {\n // Schedule an update for the remaining throttle time\n if (pendingUpdateRef.current) {\n clearTimeout(pendingUpdateRef.current);\n }\n\n pendingUpdateRef.current = setTimeout(() => {\n // CRITICAL: Use ref to get latest onChange, not captured closure value\n // This fixes intermittent color update failures on mobile\n onChangeRef.current({ target: { value: color } });\n lastUpdateTimeRef.current = Date.now();\n pendingUpdateRef.current = null;\n // Clear dragging state after final update\n isDraggingRef.current = false;\n }, 16 - timeSinceLastUpdate);\n }\n };\n\n // Store localColor in a ref for the pointerup handler to access\n const localColorRef = useRef(localColor);\n localColorRef.current = localColor;\n\n // Clear dragging state when mouse/touch is released and flush any pending update\n useEffect(() => {\n const handlePointerUp = () => {\n // If there's a pending throttled update, cancel it and send immediately\n // This ensures the final color is always applied even if component re-renders\n if (pendingUpdateRef.current) {\n clearTimeout(pendingUpdateRef.current);\n pendingUpdateRef.current = null;\n // Send the final color using the latest refs\n onChangeRef.current({ target: { value: localColorRef.current } });\n }\n // Clear dragging state after a small delay\n setTimeout(() => {\n isDraggingRef.current = false;\n }, 50);\n };\n\n window.addEventListener('pointerup', handlePointerUp);\n window.addEventListener('pointercancel', handlePointerUp);\n\n return () => {\n window.removeEventListener('pointerup', handlePointerUp);\n window.removeEventListener('pointercancel', handlePointerUp);\n };\n }, []);\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return () => {\n if (pendingUpdateRef.current) {\n clearTimeout(pendingUpdateRef.current);\n }\n };\n }, []);\n\n const handleHexInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const input = e.target.value;\n setHexInput(input);\n\n // Validate hex color (with or without #)\n const hexPattern = /^#?([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/;\n const withHash = input.startsWith('#') ? input : `#${input}`;\n\n if (hexPattern.test(withHash)) {\n // Use ref to ensure we always call the latest onChange\n onChangeRef.current({ target: { value: withHash } });\n }\n };\n\n const handlePresetClick = (color: string) => {\n handleColorChange(color);\n };\n\n const handleTransparentClick = () => {\n // Use ref to ensure we always call the latest onChange\n onChangeRef.current({ target: { value: 'transparent' } });\n };\n\n const isTransparent = value === 'transparent';\n\n const buttonContent = showSquare ? (\n <div\n className={`size-8 md:size-6 rounded-md border border-border-primary ${isTransparent ? 'transparent-pattern-small' : ''}`}\n style={isTransparent ? {} : { backgroundColor: value }}\n />\n ) : (\n <div className=\"relative flex items-center justify-center h-5 w-5\">\n {icon ? <span className=\"flex items-center -translate-y-0.5\">{icon}</span> : <span className=\"font-bold text-lg leading-none -translate-y-0.5\">A</span>}\n <div\n className={`absolute bottom-0 left-1/2 -translate-x-1/2 h-[3px] w-4 rounded-sm ${isTransparent ? 'transparent-pattern-small' : ''}`}\n style={isTransparent ? {} : { backgroundColor: value }}\n />\n </div>\n );\n\n const pickerContent = (\n <div className=\"space-y-4 min-w-[232px]\">\n {allowTransparent && (\n <Button\n variant=\"ghost\"\n className={`flex w-full cursor-pointer items-center justify-start gap-2 rounded-lg ${isTransparent ? 'bg-primary/10' : ''}`}\n onClick={handleTransparentClick}\n >\n <div className=\"transparent-pattern-small h-6 w-6 rounded\" />\n <span className=\"text-sm font-medium\">Transparent</span>\n </Button>\n )}\n\n <div className=\"w-[200px]\">\n <HexColorPicker color={isTransparent ? '#ffffff' : localColor} onChange={handleColorChange} />\n </div>\n\n <div className=\"flex items-center gap-2\">\n <label htmlFor=\"hex-input\" className=\"text-sm font-medium uppercase text-foreground/60\">\n HEX\n </label>\n <input\n id=\"hex-input\"\n type=\"text\"\n className=\"w-24 rounded-lg border border-divider bg-field px-2 py-1.5 text-sm text-foreground focus:border-primary focus:outline-none\"\n value={hexInput}\n onChange={handleHexInputChange}\n placeholder=\"#000000\"\n maxLength={7}\n />\n </div>\n\n {documentColors.length > 0 && (\n <div className=\"flex flex-col gap-1.5\">\n <div className=\"text-sm font-medium text-foreground/60\">Document colors</div>\n <div className=\"grid grid-cols-8 gap-1\">\n {documentColors.map((color, index) => (\n <button\n key={index}\n className={`h-6 w-6 cursor-pointer rounded border-2 transition-all duration-150 hover:scale-110 ${color === value ? 'border-primary' : 'border-transparent'}`}\n style={{ backgroundColor: color }}\n onClick={() => handlePresetClick(color)}\n aria-label={color}\n />\n ))}\n </div>\n </div>\n )}\n\n {imageColors.length > 0 && (\n <div className=\"flex flex-col gap-1.5\">\n <div className=\"text-sm font-medium text-foreground/60\">Image colors</div>\n <div className=\"grid grid-cols-8 gap-1\">\n {imageColors.map((color, index) => (\n <button\n key={`img-${index}`}\n className={`h-6 w-6 cursor-pointer rounded border-2 transition-all duration-150 hover:scale-110 ${color === value ? 'border-primary' : 'border-transparent'}`}\n style={{ backgroundColor: color }}\n onClick={() => handlePresetClick(color)}\n aria-label={color}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n );\n\n // Embedded mode: render just the picker content without popover wrapper\n if (embedded) {\n return pickerContent;\n }\n\n return (\n <Popover open={isOpen} onOpenChange={setIsOpen}>\n <PopoverTrigger asChild>\n <button\n className={\n showSquare\n ? 'flex items-center justify-center bg-transparent border-0 p-0 cursor-pointer rounded-md hover:opacity-80 transition-opacity'\n : 'toolbar-btn'\n }\n aria-label=\"Color Picker\"\n >\n {buttonContent}\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto\" maxZIndex>\n {pickerContent}\n </PopoverContent>\n </Popover>\n );\n});\n\nColorPickerDropdown.displayName = 'ColorPickerDropdown';\n\nexport default ColorPickerDropdown;\n","/**\n * StrokePanel - UI component for configuring stroke properties\n * Provides controls for universal stroke system\n *\n * Migrated to Shadcn/Radix:\n * - Disclosure (Collapsible)\n * - RadioGroup\n * - Slider\n * - Fieldset\n */\n\nimport { useState } from 'react';\nimport type { StrokeConfig } from '../types/index.js';\nimport ColorPickerDropdown from './ColorPickerDropdown.js';\nimport {\n Disclosure,\n DisclosureTrigger,\n DisclosureContent,\n Switch,\n Label,\n RadioGroup,\n Radio,\n Slider,\n Fieldset,\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n TooltipProvider,\n} from './ui';\n\ninterface StrokePanelProps {\n stroke?: StrokeConfig;\n onChange: (stroke: StrokeConfig | undefined) => void;\n}\n\nconst StrokePanel = ({ stroke, onChange }: StrokePanelProps) => {\n const [isExpanded, setIsExpanded] = useState(stroke?.enabled || false);\n\n const enabled = stroke?.enabled || false;\n const color = stroke?.color || '#000000';\n const width = stroke?.width || 5;\n const lineCap = stroke?.lineCap || 'butt';\n const lineJoin = stroke?.lineJoin || 'miter';\n const opacity = stroke?.opacity !== undefined ? stroke.opacity : 1;\n\n const handleEnabledChange = (newEnabled: boolean) => {\n if (newEnabled) {\n onChange({\n enabled: true,\n color,\n width,\n lineCap,\n lineJoin,\n opacity,\n });\n } else {\n onChange(undefined);\n }\n setIsExpanded(newEnabled);\n };\n\n const handleColorChange = (e: { target: { value: string } }) => {\n if (!stroke) return;\n onChange({\n ...stroke,\n color: e.target.value,\n });\n };\n\n const handleWidthChange = (newWidth: number[]) => {\n if (!stroke) return;\n onChange({\n ...stroke,\n width: newWidth[0],\n });\n };\n\n const handleOpacityChange = (newOpacity: number[]) => {\n if (!stroke) return;\n onChange({\n ...stroke,\n opacity: newOpacity[0],\n });\n };\n\n const handleLineCapChange = (newLineCap: string) => {\n if (!stroke) return;\n onChange({\n ...stroke,\n lineCap: newLineCap as 'butt' | 'round' | 'square',\n });\n };\n\n const handleLineJoinChange = (newLineJoin: string) => {\n if (!stroke) return;\n onChange({\n ...stroke,\n lineJoin: newLineJoin as 'miter' | 'round' | 'bevel',\n });\n };\n\n return (\n <Disclosure open={isExpanded} onOpenChange={setIsExpanded} className=\"mb-xl\">\n <DisclosureTrigger className=\"w-full\">\n <div className=\"flex items-center justify-between w-full\">\n <Label>Stroke</Label>\n <Switch checked={enabled} onCheckedChange={handleEnabledChange} />\n </div>\n </DisclosureTrigger>\n <DisclosureContent className=\"flex flex-col gap-lg pt-lg\">\n {/* Color picker */}\n <Fieldset className=\"flex flex-col gap-sm\">\n <div className=\"flex items-center justify-between\">\n <Label>Color</Label>\n <ColorPickerDropdown value={color} onChange={handleColorChange} />\n </div>\n </Fieldset>\n\n {/* Width slider */}\n <div className=\"flex flex-col gap-sm\">\n <Label>Width</Label>\n <Slider\n value={[width]}\n onValueChange={handleWidthChange}\n min={1}\n max={50}\n step={1}\n />\n <div className=\"text-sm text-text-muted\">{width}px</div>\n </div>\n\n {/* Opacity slider */}\n <div className=\"flex flex-col gap-sm\">\n <Label>Opacity</Label>\n <Slider\n value={[opacity]}\n onValueChange={handleOpacityChange}\n min={0}\n max={1}\n step={0.01}\n />\n <div className=\"text-sm text-text-muted\">{Math.round(opacity * 100)}%</div>\n </div>\n\n {/* Line cap options */}\n <TooltipProvider delayDuration={300}>\n <Fieldset className=\"flex flex-col gap-sm\">\n <Label>Line Cap</Label>\n <RadioGroup value={lineCap} onValueChange={handleLineCapChange} orientation=\"horizontal\">\n <Tooltip>\n <TooltipTrigger asChild>\n <div>\n <Radio value=\"butt\" id=\"cap-butt\">Butt</Radio>\n </div>\n </TooltipTrigger>\n <TooltipContent>Butt - Flat edges</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <div>\n <Radio value=\"round\" id=\"cap-round\">Round</Radio>\n </div>\n </TooltipTrigger>\n <TooltipContent>Round - Rounded edges</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <div>\n <Radio value=\"square\" id=\"cap-square\">Square</Radio>\n </div>\n </TooltipTrigger>\n <TooltipContent>Square - Extended square edges</TooltipContent>\n </Tooltip>\n </RadioGroup>\n </Fieldset>\n\n {/* Line join options */}\n <Fieldset className=\"flex flex-col gap-sm\">\n <Label>Line Join</Label>\n <RadioGroup value={lineJoin} onValueChange={handleLineJoinChange} orientation=\"horizontal\">\n <Tooltip>\n <TooltipTrigger asChild>\n <div>\n <Radio value=\"miter\" id=\"join-miter\">Miter</Radio>\n </div>\n </TooltipTrigger>\n <TooltipContent>Miter - Sharp corners</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <div>\n <Radio value=\"round\" id=\"join-round\">Round</Radio>\n </div>\n </TooltipTrigger>\n <TooltipContent>Round - Rounded corners</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <div>\n <Radio value=\"bevel\" id=\"join-bevel\">Bevel</Radio>\n </div>\n </TooltipTrigger>\n <TooltipContent>Bevel - Beveled corners</TooltipContent>\n </Tooltip>\n </RadioGroup>\n </Fieldset>\n </TooltipProvider>\n </DisclosureContent>\n </Disclosure>\n );\n};\n\nexport default StrokePanel;\n","/**\n * MaskItem - Individual mask item in the masks list\n * Displays mask properties and controls\n */\n\nimport { useState } from 'react';\nimport { Button, Tooltip, TooltipTrigger, TooltipContent, Slider, Label } from './ui';\nimport type { MaskDefinition, ShapeType, ShapeTransformData, BaseTextElementConfig, ImageElementConfig, ImageTransformData } from '../types/index.js';\n\ninterface MaskItemProps {\n mask: MaskDefinition;\n index: number;\n isFirst: boolean;\n isLast: boolean;\n onUpdate: (updates: Partial<MaskDefinition>) => void;\n onRemove: () => void;\n onReorder: (direction: 'up' | 'down') => void;\n}\n\nconst MaskItem = ({ mask, index, isFirst, isLast, onUpdate, onRemove, onReorder }: MaskItemProps) => {\n const [isExpanded, setIsExpanded] = useState(false);\n\n const getMaskIcon = (type: string): string => {\n switch (type) {\n case 'clip':\n return '🎭';\n case 'alpha':\n return '🌫️';\n case 'luma':\n return '🌗';\n case 'distress':\n return '⚡';\n default:\n return '🎭';\n }\n };\n\n const getMaskLabel = (type: string): string => {\n switch (type) {\n case 'clip':\n return 'Clip Mask';\n case 'alpha':\n return 'Alpha Mask';\n case 'luma':\n return 'Luma Mask';\n case 'distress':\n return 'Distress Mask';\n default:\n return 'Unknown Mask';\n }\n };\n\n const handleOpacityChange = (value: number) => {\n onUpdate({ opacity: value });\n };\n\n const handleFeatherChange = (value: number) => {\n onUpdate({ feather: value });\n };\n\n const handleInvertedToggle = () => {\n onUpdate({ inverted: !mask.inverted });\n };\n\n const handleMaskElementTypeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const transformType = e.target.value as 'custom' | 'shape' | 'image';\n\n if (transformType === 'image') {\n // Create a new image element config\n const existingUrl = mask.maskElement.transformType === 'image'\n ? (mask.maskElement as ImageElementConfig).imageUrl || ''\n : '';\n onUpdate({\n maskElement: {\n transformType: 'image',\n imageUrl: existingUrl,\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n transformData: {\n type: 'image',\n width: 200,\n height: 200,\n cropX: 0,\n cropY: 0,\n cropWidth: 1,\n cropHeight: 1,\n flipHorizontal: false,\n flipVertical: false,\n borderRadius: 0,\n },\n },\n });\n } else if (transformType === 'shape') {\n // Create a completely new shape element config (don't spread old properties)\n onUpdate({\n maskElement: {\n transformType: 'shape',\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n transformData: {\n type: 'shape',\n shapeType: 'star',\n width: 200,\n height: 200,\n fillColor: '#000000',\n fillOpacity: 1,\n points: 5,\n innerRadius: 0.4,\n },\n },\n });\n } else {\n // Create a completely new text element config (don't spread old properties)\n onUpdate({\n maskElement: {\n transformType: 'custom',\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n text: 'MASK',\n fontSize: 80,\n fontFamily: 'Anton',\n color: '#000000',\n },\n });\n }\n };\n\n const handleShapeTypeChange = (e: React.ChangeEvent<HTMLSelectElement>) => {\n const shapeType = e.target.value as ShapeType;\n if (mask.maskElement.transformType === 'shape') {\n onUpdate({\n maskElement: {\n transformType: 'shape',\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n transformData: {\n ...(mask.maskElement.transformData as Partial<ShapeTransformData>),\n shapeType,\n },\n },\n });\n }\n };\n\n const handleTextChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (mask.maskElement.transformType !== 'shape') {\n const textConfig = mask.maskElement as BaseTextElementConfig & { transformType: string; x?: number; y?: number; rotation?: number };\n onUpdate({\n maskElement: {\n transformType: mask.maskElement.transformType,\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n text: e.target.value,\n fontSize: textConfig.fontSize || 80,\n fontFamily: textConfig.fontFamily || 'Anton',\n color: textConfig.color || '#000000',\n },\n });\n }\n };\n\n const handleImageUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n if (mask.maskElement.transformType === 'image') {\n const imgConfig = mask.maskElement as ImageElementConfig;\n onUpdate({\n maskElement: {\n transformType: 'image',\n imageUrl: e.target.value,\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n transformData: imgConfig.transformData || {\n type: 'image',\n width: 200,\n height: 200,\n cropX: 0,\n cropY: 0,\n cropWidth: 1,\n cropHeight: 1,\n flipHorizontal: false,\n flipVertical: false,\n borderRadius: 0,\n },\n },\n });\n }\n };\n\n const handleSizeChange = (size: number) => {\n if (mask.maskElement.transformType === 'image') {\n const imgConfig = mask.maskElement as ImageElementConfig;\n onUpdate({\n maskElement: {\n transformType: 'image',\n imageUrl: imgConfig.imageUrl || '',\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n transformData: {\n ...(imgConfig.transformData as Partial<ImageTransformData>),\n width: size,\n height: size,\n },\n },\n });\n } else if (mask.maskElement.transformType === 'shape') {\n onUpdate({\n maskElement: {\n transformType: 'shape',\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n transformData: {\n ...(mask.maskElement.transformData as Partial<ShapeTransformData>),\n width: size,\n height: size,\n },\n },\n });\n } else {\n const textConfig = mask.maskElement as BaseTextElementConfig & { transformType: string; x?: number; y?: number; rotation?: number };\n onUpdate({\n maskElement: {\n transformType: mask.maskElement.transformType,\n x: mask.maskElement.x || 0,\n y: mask.maskElement.y || 0,\n rotation: mask.maskElement.rotation || 0,\n text: textConfig.text || 'MASK',\n fontSize: size,\n fontFamily: textConfig.fontFamily || 'Anton',\n color: textConfig.color || '#000000',\n },\n });\n }\n };\n\n const getMaskElementSize = (): number => {\n if (mask.maskElement.transformType === 'image') {\n return (mask.maskElement as ImageElementConfig).transformData?.width || 200;\n }\n if (mask.maskElement.transformType === 'shape') {\n return (mask.maskElement.transformData as Partial<ShapeTransformData>)?.width || 200;\n }\n return (mask.maskElement as BaseTextElementConfig).fontSize || 80;\n };\n\n return (\n <div className=\"rounded-md border border-border-secondary bg-bg-tertiary p-lg\">\n {/* Mask header */}\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-lg\">\n <span className=\"text-lg\">{getMaskIcon(mask.type)}</span>\n <div className=\"flex flex-col gap-xs\">\n <strong className=\"text-lg text-text-primary\">{getMaskLabel(mask.type)}</strong>\n <small className=\"text-sm text-text-muted\">#{index + 1}</small>\n </div>\n </div>\n <div className=\"flex gap-1\">\n <Tooltip delay={0}>\n <TooltipTrigger asChild>\n <Button\n size=\"icon\"\n variant=\"ghost\"\n aria-label=\"Toggle mask details\"\n aria-expanded={isExpanded}\n onClick={() => setIsExpanded(!isExpanded)}\n >\n {isExpanded ? '▼' : '▶'}\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>{isExpanded ? 'Collapse' : 'Expand'}</p>\n </TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {/* Mask controls (when expanded) */}\n {isExpanded && (\n <div className=\"mt-xl flex flex-col gap-xl border-t border-border-secondary pt-xl\">\n {/* Opacity slider */}\n <Slider\n className=\"slider-no-fill\"\n value={[mask.opacity || 1]}\n onValueChange={(val) => handleOpacityChange(val[0])}\n min={0}\n max={1}\n step={0.01}\n >\n <Label>Opacity</Label>\n <Slider.Output>{({ state }) => `${Math.round(state.values[0] * 100)}%`}</Slider.Output>\n <Slider.Track />\n <Slider.Thumb />\n </Slider>\n\n {/* Feather slider */}\n <Slider\n className=\"slider-no-fill\"\n value={[mask.feather || 0]}\n onValueChange={(val) => handleFeatherChange(val[0])}\n min={0}\n max={50}\n step={1}\n >\n <Label>Feather</Label>\n <Slider.Output>{({ state }) => `${state.values[0]}px`}</Slider.Output>\n <Slider.Track />\n <Slider.Thumb />\n </Slider>\n\n {/* Inverted toggle */}\n <label className=\"flex cursor-pointer items-center gap-md text-base text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={mask.inverted || false}\n onChange={handleInvertedToggle}\n className=\"h-4 w-4 cursor-pointer\"\n />\n <span>Invert Mask</span>\n </label>\n\n {/* Mask Element Configuration */}\n <div className=\"flex flex-col gap-lg rounded-md border border-border-dark bg-bg-secondary p-xl\">\n <div className=\"mb-xs text-md font-semibold uppercase tracking-wide text-accent-primary\">Mask Shape</div>\n\n {/* Element Type Selector */}\n <div className=\"flex flex-col gap-sm\">\n <label htmlFor={`mask-type-${mask.id}`} className=\"text-base text-text-secondary\">Type</label>\n <select\n id={`mask-type-${mask.id}`}\n value={mask.maskElement.transformType === 'shape' ? 'shape' : mask.maskElement.transformType === 'image' ? 'image' : 'custom'}\n onChange={handleMaskElementTypeChange}\n className=\"w-full cursor-pointer rounded-md border border-border-dark bg-bg-tertiary px-md py-sm text-base text-text-primary transition-all duration-base hover:border-accent-primary focus:border-accent-primary focus:outline-none\"\n >\n <option value=\"custom\">Text</option>\n <option value=\"shape\">Shape</option>\n <option value=\"image\">Image</option>\n </select>\n </div>\n\n {/* Shape-specific controls */}\n {mask.maskElement.transformType === 'shape' && (\n <div className=\"flex flex-col gap-sm\">\n <label htmlFor={`mask-shape-${mask.id}`} className=\"text-base text-text-secondary\">Shape</label>\n <select\n id={`mask-shape-${mask.id}`}\n value={(mask.maskElement.transformData as Partial<ShapeTransformData>)?.shapeType || 'star'}\n onChange={handleShapeTypeChange}\n className=\"w-full cursor-pointer rounded-md border border-border-dark bg-bg-tertiary px-md py-sm text-base text-text-primary transition-all duration-base hover:border-accent-primary focus:border-accent-primary focus:outline-none\"\n >\n <option value=\"rectangle\">Rectangle</option>\n <option value=\"circle\">Circle</option>\n <option value=\"ellipse\">Ellipse</option>\n <option value=\"star\">Star</option>\n </select>\n </div>\n )}\n\n {/* Image-specific controls */}\n {mask.maskElement.transformType === 'image' && (\n <div className=\"flex flex-col gap-sm\">\n <label htmlFor={`mask-image-${mask.id}`} className=\"text-base text-text-secondary\">Image URL</label>\n <input\n id={`mask-image-${mask.id}`}\n type=\"text\"\n value={(mask.maskElement as ImageElementConfig).imageUrl || ''}\n onChange={handleImageUrlChange}\n className=\"w-full rounded-md border border-border-dark bg-bg-tertiary px-md py-sm text-base text-text-primary transition-all duration-base hover:border-accent-primary focus:border-accent-primary focus:outline-none\"\n placeholder=\"https://... or data:image/...\"\n />\n </div>\n )}\n\n {/* Text-specific controls */}\n {mask.maskElement.transformType !== 'shape' && mask.maskElement.transformType !== 'image' && (\n <div className=\"flex flex-col gap-sm\">\n <label htmlFor={`mask-text-${mask.id}`} className=\"text-base text-text-secondary\">Text</label>\n <input\n id={`mask-text-${mask.id}`}\n type=\"text\"\n value={(mask.maskElement as BaseTextElementConfig).text || 'MASK'}\n onChange={handleTextChange}\n className=\"w-full rounded-md border border-border-dark bg-bg-tertiary px-md py-sm text-base text-text-primary transition-all duration-base hover:border-accent-primary focus:border-accent-primary focus:outline-none\"\n placeholder=\"Mask text\"\n />\n </div>\n )}\n\n {/* Size control (works for both text and shapes) */}\n <Slider\n className=\"slider-no-fill\"\n value={[getMaskElementSize()]}\n onValueChange={(val) => handleSizeChange(val[0])}\n min={20}\n max={500}\n step={10}\n >\n <Label>Size</Label>\n <Slider.Output />\n <Slider.Track />\n <Slider.Thumb />\n </Slider>\n </div>\n\n {/* Action buttons */}\n <div className=\"mt-md flex gap-sm\">\n <button\n onClick={() => onReorder('up')}\n disabled={isFirst}\n title=\"Move Up\"\n aria-label=\"Move mask up\"\n className=\"flex-1 cursor-pointer rounded-md border border-border-dark bg-bg-hover px-md py-sm text-xl text-text-secondary transition-all duration-slow hover:border-accent-primary hover:bg-bg-dark-hover hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-disabled\"\n >\n ↑\n </button>\n <button\n onClick={() => onReorder('down')}\n disabled={isLast}\n title=\"Move Down\"\n aria-label=\"Move mask down\"\n className=\"flex-1 cursor-pointer rounded-md border border-border-dark bg-bg-hover px-md py-sm text-xl text-text-secondary transition-all duration-slow hover:border-accent-primary hover:bg-bg-dark-hover hover:text-text-primary disabled:cursor-not-allowed disabled:opacity-disabled\"\n >\n ↓\n </button>\n <button\n onClick={onRemove}\n title=\"Remove Mask\"\n aria-label=\"Remove mask\"\n className=\"flex-[2] cursor-pointer rounded-md border border-error-light bg-error px-md py-sm text-base font-semibold text-text-on-dark transition-all duration-slow hover:bg-error-light\"\n >\n ✕ Remove\n </button>\n </div>\n </div>\n )}\n </div>\n );\n};\n\nexport default MaskItem;\n","/**\n * MasksPanel - UI component for managing element masks\n * Displays and controls the mask stack for selected elements\n *\n * Migrated to use primitives:\n * - Custom panel structure (masks don't have enable/disable, only collapsible)\n * - Button primitive for add button and mask type buttons\n * - Tailwind utilities for all styling\n */\n\nimport { useState } from 'react';\nimport type { MaskDefinition, MaskType, AnyElementConfig } from '../types/index.js';\nimport MaskItem from './MaskItem.js';\nimport { Button } from './ui';\n\ninterface MasksPanelProps {\n masks?: MaskDefinition[];\n onChange: (masks: MaskDefinition[]) => void;\n}\n\nconst MasksPanel = ({ masks = [], onChange }: MasksPanelProps) => {\n const [isExpanded, setIsExpanded] = useState(masks.length > 0);\n const [showAddMenu, setShowAddMenu] = useState(false);\n\n const handleAddMask = (type: MaskType) => {\n const newMask: MaskDefinition = {\n id: `mask-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,\n type,\n maskElement: createDefaultMaskElement(type),\n inverted: false,\n feather: 0,\n opacity: 1.0,\n };\n\n onChange([...masks, newMask]);\n setShowAddMenu(false);\n };\n\n const handleRemoveMask = (maskId: string) => {\n onChange(masks.filter((m) => m.id !== maskId));\n };\n\n const handleUpdateMask = (maskId: string, updates: Partial<MaskDefinition>) => {\n onChange(masks.map((m) => (m.id === maskId ? { ...m, ...updates } : m)));\n };\n\n const handleReorderMask = (maskId: string, direction: 'up' | 'down') => {\n const index = masks.findIndex((m) => m.id === maskId);\n if (index === -1) return;\n\n const newMasks = [...masks];\n if (direction === 'up' && index > 0) {\n [newMasks[index], newMasks[index - 1]] = [newMasks[index - 1], newMasks[index]];\n } else if (direction === 'down' && index < masks.length - 1) {\n [newMasks[index], newMasks[index + 1]] = [newMasks[index + 1], newMasks[index]];\n }\n\n onChange(newMasks);\n };\n\n return (\n <div className=\"mb-xl rounded-xl border border-border-primary bg-bg-secondary p-xl\">\n {/* Header */}\n <div className=\"mb-md flex items-center justify-between\">\n <div className=\"flex items-center gap-md text-xl font-semibold text-text-primary\">\n <span>Masks ({masks.length})</span>\n {masks.length > 0 && (\n <button\n onClick={() => setIsExpanded(!isExpanded)}\n className=\"rounded-lg border-none bg-transparent px-md py-xs text-base text-text-muted transition-colors duration-fast hover:text-text-primary\"\n title={isExpanded ? 'Collapse' : 'Expand'}\n >\n {isExpanded ? '▼' : '▶'}\n </button>\n )}\n </div>\n <div className=\"flex gap-sm\">\n <Button\n variant=\"default\"\n onClick={() => setShowAddMenu(!showAddMenu)}\n className=\"rounded-lg bg-accent px-xl py-sm font-semibold text-text-on-accent transition-all duration-medium hover:bg-accent-medium\"\n >\n + Add\n </Button>\n </div>\n </div>\n\n {/* Add mask dropdown menu */}\n {showAddMenu && (\n <div className=\"mb-md mt-md flex flex-col gap-sm rounded-lg border border-border-medium bg-surface p-md\">\n <button\n onClick={() => handleAddMask('clip')}\n className=\"flex cursor-pointer items-center gap-xl rounded-lg border border-border-light bg-bg-secondary p-lg text-left text-text-primary transition-all duration-medium hover:border-accent hover:bg-bg-hover\"\n >\n <span className=\"shrink-0 text-xl\">🎭</span>\n <div className=\"flex flex-col gap-xs\">\n <strong className=\"text-lg text-text-primary\">Clip Mask</strong>\n <small className=\"text-base text-text-secondary\">Hard edge clipping (text, shapes)</small>\n </div>\n </button>\n <button\n onClick={() => handleAddMask('alpha')}\n className=\"flex cursor-pointer items-center gap-xl rounded-lg border border-border-light bg-bg-secondary p-lg text-left text-text-primary transition-all duration-medium hover:border-accent hover:bg-bg-hover\"\n >\n <span className=\"shrink-0 text-xl\">🌫️</span>\n <div className=\"flex flex-col gap-xs\">\n <strong className=\"text-lg text-text-primary\">Alpha Mask</strong>\n <small className=\"text-base text-text-secondary\">Transparency-based masking</small>\n </div>\n </button>\n <button\n onClick={() => handleAddMask('luma')}\n className=\"flex cursor-pointer items-center gap-xl rounded-lg border border-border-light bg-bg-secondary p-lg text-left text-text-primary transition-all duration-medium hover:border-accent hover:bg-bg-hover\"\n >\n <span className=\"shrink-0 text-xl\">🌗</span>\n <div className=\"flex flex-col gap-xs\">\n <strong className=\"text-lg text-text-primary\">Luma Mask</strong>\n <small className=\"text-base text-text-secondary\">Luminosity-based masking</small>\n </div>\n </button>\n <button\n onClick={() => handleAddMask('distress')}\n className=\"flex cursor-pointer items-center gap-xl rounded-lg border border-border-light bg-bg-secondary p-lg text-left text-text-primary transition-all duration-medium hover:border-accent hover:bg-bg-hover\"\n >\n <span className=\"shrink-0 text-xl\">⚡</span>\n <div className=\"flex flex-col gap-xs\">\n <strong className=\"text-lg text-text-primary\">Distress Mask</strong>\n <small className=\"text-base text-text-secondary\">Vintage/grunge texture effects</small>\n </div>\n </button>\n </div>\n )}\n\n {/* Mask list */}\n {isExpanded && masks.length > 0 && (\n <div className=\"mt-xl flex flex-col gap-md\">\n {masks.map((mask, index) => (\n <MaskItem\n key={mask.id}\n mask={mask}\n index={index}\n isFirst={index === 0}\n isLast={index === masks.length - 1}\n onUpdate={(updates) => handleUpdateMask(mask.id, updates)}\n onRemove={() => handleRemoveMask(mask.id)}\n onReorder={(direction) => handleReorderMask(mask.id, direction)}\n />\n ))}\n </div>\n )}\n\n {masks.length === 0 && (\n <div className=\"p-3xl text-center text-text-secondary\">\n <p className=\"mb-xs text-lg\">No masks applied</p>\n <small className=\"text-base text-border-medium\">Click \"+ Add\" to add a mask</small>\n </div>\n )}\n </div>\n );\n};\n\n/**\n * Create default mask element based on mask type\n */\nfunction createDefaultMaskElement(type: MaskType): AnyElementConfig {\n switch (type) {\n case 'clip':\n return {\n transformType: 'custom',\n text: 'MASK',\n fontSize: 80,\n fontFamily: 'Anton',\n x: 0,\n y: 0,\n rotation: 0,\n color: '#000000',\n };\n\n case 'alpha':\n case 'luma':\n return {\n transformType: 'custom',\n text: 'FADE',\n fontSize: 100,\n fontFamily: 'Arial',\n x: 0,\n y: 0,\n rotation: 0,\n color: '#888888',\n };\n\n case 'distress':\n // Placeholder - will be replaced with actual texture\n return {\n transformType: 'image',\n imageUrl: '', // Will be set when texture is loaded\n x: 0,\n y: 0,\n rotation: 0,\n transformData: {\n type: 'image',\n width: 500,\n height: 500,\n cropX: 0,\n cropY: 0,\n cropWidth: 1,\n cropHeight: 1,\n flipHorizontal: false,\n flipVertical: false,\n borderRadius: 0,\n },\n };\n\n default:\n return {\n transformType: 'custom',\n text: 'MASK',\n fontSize: 80,\n x: 0,\n y: 0,\n rotation: 0,\n color: '#000000',\n };\n }\n}\n\nexport default MasksPanel;\n","/**\n * Distress Effect Presets\n * Predefined configurations for common distress styles\n */\n\nimport type { DistressEffect } from '../types/index.js';\n\n/**\n * Vintage worn preset - Light edge wear\n */\nexport const WORN_LIGHT: DistressEffect = {\n enabled: true,\n style: 'worn',\n intensity: 30,\n fadeAmount: 20,\n grainAmount: 15,\n edgeWear: 40,\n seed: undefined, // Will be generated when applied\n};\n\n/**\n * Vintage worn preset - Medium wear\n */\nexport const WORN_MEDIUM: DistressEffect = {\n enabled: true,\n style: 'worn',\n intensity: 55,\n fadeAmount: 35,\n grainAmount: 25,\n edgeWear: 60,\n seed: undefined,\n};\n\n/**\n * Vintage worn preset - Heavy wear\n */\nexport const WORN_HEAVY: DistressEffect = {\n enabled: true,\n style: 'worn',\n intensity: 75,\n fadeAmount: 50,\n grainAmount: 40,\n edgeWear: 80,\n seed: undefined,\n};\n\n/**\n * Cracked preset - Light cracks\n */\nexport const CRACKED_LIGHT: DistressEffect = {\n enabled: true,\n style: 'cracked',\n intensity: 25,\n scratchAmount: 30,\n edgeWear: 20,\n seed: undefined,\n};\n\n/**\n * Cracked preset - Medium cracks\n */\nexport const CRACKED_MEDIUM: DistressEffect = {\n enabled: true,\n style: 'cracked',\n intensity: 50,\n scratchAmount: 50,\n edgeWear: 35,\n seed: undefined,\n};\n\n/**\n * Cracked preset - Heavy cracks\n */\nexport const CRACKED_HEAVY: DistressEffect = {\n enabled: true,\n style: 'cracked',\n intensity: 80,\n scratchAmount: 75,\n edgeWear: 60,\n seed: undefined,\n};\n\n/**\n * Grunge preset - Light texture\n */\nexport const GRUNGE_LIGHT: DistressEffect = {\n enabled: true,\n style: 'grunge',\n intensity: 35,\n grainAmount: 40,\n fadeAmount: 25,\n seed: undefined,\n};\n\n/**\n * Grunge preset - Medium texture\n */\nexport const GRUNGE_MEDIUM: DistressEffect = {\n enabled: true,\n style: 'grunge',\n intensity: 60,\n grainAmount: 60,\n fadeAmount: 40,\n seed: undefined,\n};\n\n/**\n * Grunge preset - Heavy texture\n */\nexport const GRUNGE_HEAVY: DistressEffect = {\n enabled: true,\n style: 'grunge',\n intensity: 85,\n grainAmount: 80,\n fadeAmount: 55,\n seed: undefined,\n};\n\n/**\n * Retro preset - Light halftone\n */\nexport const RETRO_LIGHT: DistressEffect = {\n enabled: true,\n style: 'retro',\n intensity: 30,\n fadeAmount: 30,\n grainAmount: 25,\n seed: undefined,\n};\n\n/**\n * Retro preset - Medium halftone\n */\nexport const RETRO_MEDIUM: DistressEffect = {\n enabled: true,\n style: 'retro',\n intensity: 55,\n fadeAmount: 45,\n grainAmount: 40,\n seed: undefined,\n};\n\n/**\n * Retro preset - Heavy halftone\n */\nexport const RETRO_HEAVY: DistressEffect = {\n enabled: true,\n style: 'retro',\n intensity: 75,\n fadeAmount: 60,\n grainAmount: 55,\n seed: undefined,\n};\n\n/**\n * All presets organized by category\n */\nexport const DISTRESS_PRESETS = {\n worn: {\n light: WORN_LIGHT,\n medium: WORN_MEDIUM,\n heavy: WORN_HEAVY,\n },\n cracked: {\n light: CRACKED_LIGHT,\n medium: CRACKED_MEDIUM,\n heavy: CRACKED_HEAVY,\n },\n grunge: {\n light: GRUNGE_LIGHT,\n medium: GRUNGE_MEDIUM,\n heavy: GRUNGE_HEAVY,\n },\n retro: {\n light: RETRO_LIGHT,\n medium: RETRO_MEDIUM,\n heavy: RETRO_HEAVY,\n },\n};\n\n/**\n * Get preset by name\n */\nexport function getPreset(\n category: 'worn' | 'cracked' | 'grunge' | 'retro',\n level: 'light' | 'medium' | 'heavy'\n): DistressEffect {\n const preset = { ...DISTRESS_PRESETS[category][level] };\n // Generate unique seed for this application\n preset.seed = Date.now();\n return preset;\n}\n\n/**\n * Get all preset names\n */\nexport function getAllPresetNames(): Array<{ category: string; level: string; name: string }> {\n return [\n { category: 'worn', level: 'light', name: 'Vintage Worn (Light)' },\n { category: 'worn', level: 'medium', name: 'Vintage Worn (Medium)' },\n { category: 'worn', level: 'heavy', name: 'Vintage Worn (Heavy)' },\n { category: 'cracked', level: 'light', name: 'Cracked (Light)' },\n { category: 'cracked', level: 'medium', name: 'Cracked (Medium)' },\n { category: 'cracked', level: 'heavy', name: 'Cracked (Heavy)' },\n { category: 'grunge', level: 'light', name: 'Grunge (Light)' },\n { category: 'grunge', level: 'medium', name: 'Grunge (Medium)' },\n { category: 'grunge', level: 'heavy', name: 'Grunge (Heavy)' },\n { category: 'retro', level: 'light', name: 'Retro Halftone (Light)' },\n { category: 'retro', level: 'medium', name: 'Retro Halftone (Medium)' },\n { category: 'retro', level: 'heavy', name: 'Retro Halftone (Heavy)' },\n ];\n}\n","/**\n * DistressPanel - UI component for distress effects\n * HIGH PRIORITY for t-shirt design\n *\n * Provides quick access to vintage/grunge effects:\n * - Worn, Cracked, Grunge, Retro presets\n * - Intensity and parameter controls\n * - Preview functionality\n *\n * Migrated to Shadcn/Radix:\n * - Disclosure (Collapsible)\n * - RadioGroup\n * - Slider\n * - Button\n */\n\nimport type React from 'react';\nimport { useState } from 'react';\nimport type { DistressEffect, DistressStyle } from '../types/index.js';\nimport { getPreset } from '../effects/distress-presets.js';\nimport { DISTRESS_TEXTURE_PRESETS, ensureBuiltinTexturesReady } from '../effects/distress-textures.js';\nimport { preloadTexture } from '../effects/DistressTextureCache.js';\nimport {\n Disclosure,\n DisclosureTrigger,\n DisclosureContent,\n Switch,\n Label,\n RadioGroup,\n Radio,\n Slider,\n Button,\n Fieldset,\n} from './ui';\n\ninterface DistressPanelProps {\n distressEffect?: DistressEffect;\n onChange: (distress: DistressEffect | undefined) => void;\n}\n\nconst DistressPanel = ({ distressEffect, onChange }: DistressPanelProps) => {\n ensureBuiltinTexturesReady();\n const [showPresets, setShowPresets] = useState(false);\n\n const enabled = distressEffect?.enabled || false;\n const style = distressEffect?.style || 'worn';\n const intensity = distressEffect?.intensity || 50;\n const fadeAmount = distressEffect?.fadeAmount || 30;\n const grainAmount = distressEffect?.grainAmount || 30;\n const scratchAmount = distressEffect?.scratchAmount || 30;\n const edgeWear = distressEffect?.edgeWear || 40;\n\n const handleEnabledChange = (newEnabled: boolean) => {\n if (newEnabled) {\n onChange({\n enabled: true,\n style,\n intensity,\n fadeAmount,\n grainAmount,\n scratchAmount,\n edgeWear,\n seed: Date.now(),\n });\n } else {\n onChange(undefined);\n }\n };\n\n const handlePresetApply = (category: string, level: string) => {\n const preset = getPreset(category as 'worn' | 'cracked' | 'grunge' | 'retro', level as 'light' | 'medium' | 'heavy');\n onChange(preset);\n setShowPresets(false);\n };\n\n const handleStyleChange = (newStyle: string) => {\n if (!distressEffect) return;\n if (newStyle === 'custom') {\n // Switch to custom texture mode\n const url = distressEffect.textureUrl || DISTRESS_TEXTURE_PRESETS[0].textureUrl;\n preloadTexture(url);\n onChange({\n ...distressEffect,\n style: 'custom',\n textureUrl: url,\n textureOpacity: distressEffect.textureOpacity ?? (distressEffect.intensity / 100),\n });\n } else {\n onChange({\n ...distressEffect,\n style: newStyle as DistressStyle,\n seed: Date.now(), // New seed for new style\n });\n }\n };\n\n const handleTextureSelect = (url: string) => {\n if (!distressEffect) return;\n preloadTexture(url);\n onChange({\n ...distressEffect,\n style: 'custom',\n textureUrl: url,\n });\n };\n\n const handleTextureOpacityChange = (value: number[]) => {\n if (!distressEffect) return;\n onChange({\n ...distressEffect,\n textureOpacity: value[0] / 100,\n });\n };\n\n const handleIntensityChange = (value: number[]) => {\n if (!distressEffect) return;\n onChange({\n ...distressEffect,\n intensity: value[0],\n });\n };\n\n const handleFadeChange = (value: number[]) => {\n if (!distressEffect) return;\n onChange({\n ...distressEffect,\n fadeAmount: value[0],\n });\n };\n\n const handleGrainChange = (value: number[]) => {\n if (!distressEffect) return;\n onChange({\n ...distressEffect,\n grainAmount: value[0],\n });\n };\n\n const handleScratchChange = (value: number[]) => {\n if (!distressEffect) return;\n onChange({\n ...distressEffect,\n scratchAmount: value[0],\n });\n };\n\n const handleEdgeWearChange = (value: number[]) => {\n if (!distressEffect) return;\n onChange({\n ...distressEffect,\n edgeWear: value[0],\n });\n };\n\n const handleRandomize = () => {\n if (!distressEffect) return;\n onChange({\n ...distressEffect,\n seed: Date.now(), // Generate new random seed\n });\n };\n\n return (\n <Disclosure open={enabled} onOpenChange={handleEnabledChange} className=\"mb-xl\">\n <DisclosureTrigger className=\"w-full\">\n <div className=\"flex items-center justify-between w-full\">\n <Label>Distress Effect</Label>\n <Switch\n checked={enabled}\n onCheckedChange={handleEnabledChange}\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n />\n </div>\n </DisclosureTrigger>\n <DisclosureContent className=\"flex flex-col gap-lg pt-lg\">\n {/* Presets Button */}\n <div className=\"flex gap-sm\">\n <Button\n variant=\"outline\"\n onClick={() => setShowPresets(!showPresets)}\n className=\"flex-1\"\n >\n Presets\n </Button>\n </div>\n\n {/* Presets menu */}\n {showPresets && (\n <div className=\"flex flex-col gap-xl rounded-md border border-border-primary bg-bg-tertiary p-xl\">\n {/* Vintage Worn */}\n <div>\n <h4 className=\"mb-sm text-base font-semibold text-accent-primary\">Vintage Worn</h4>\n <div className=\"flex gap-sm\">\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('worn', 'light')}\n className=\"flex-1\"\n >\n Light\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('worn', 'medium')}\n className=\"flex-1\"\n >\n Medium\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('worn', 'heavy')}\n className=\"flex-1\"\n >\n Heavy\n </Button>\n </div>\n </div>\n\n {/* Cracked */}\n <div>\n <h4 className=\"mb-sm text-base font-semibold text-accent-primary\">Cracked</h4>\n <div className=\"flex gap-sm\">\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('cracked', 'light')}\n className=\"flex-1\"\n >\n Light\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('cracked', 'medium')}\n className=\"flex-1\"\n >\n Medium\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('cracked', 'heavy')}\n className=\"flex-1\"\n >\n Heavy\n </Button>\n </div>\n </div>\n\n {/* Grunge */}\n <div>\n <h4 className=\"mb-sm text-base font-semibold text-accent-primary\">Grunge</h4>\n <div className=\"flex gap-sm\">\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('grunge', 'light')}\n className=\"flex-1\"\n >\n Light\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('grunge', 'medium')}\n className=\"flex-1\"\n >\n Medium\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('grunge', 'heavy')}\n className=\"flex-1\"\n >\n Heavy\n </Button>\n </div>\n </div>\n\n {/* Retro Halftone */}\n <div>\n <h4 className=\"mb-sm text-base font-semibold text-accent-primary\">Retro Halftone</h4>\n <div className=\"flex gap-sm\">\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('retro', 'light')}\n className=\"flex-1\"\n >\n Light\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('retro', 'medium')}\n className=\"flex-1\"\n >\n Medium\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => handlePresetApply('retro', 'heavy')}\n className=\"flex-1\"\n >\n Heavy\n </Button>\n </div>\n </div>\n </div>\n )}\n\n {/* Style selector */}\n <Fieldset className=\"flex flex-col gap-sm\">\n <Label>Style</Label>\n <RadioGroup value={style} onValueChange={handleStyleChange} orientation=\"horizontal\">\n <Radio value=\"worn\" id=\"style-worn\">Worn</Radio>\n <Radio value=\"cracked\" id=\"style-cracked\">Cracked</Radio>\n <Radio value=\"grunge\" id=\"style-grunge\">Grunge</Radio>\n <Radio value=\"retro\" id=\"style-retro\">Retro</Radio>\n <Radio value=\"custom\" id=\"style-custom\">Custom</Radio>\n </RadioGroup>\n </Fieldset>\n\n {/* Custom texture controls */}\n {style === 'custom' && (\n <>\n {/* Texture grid */}\n <div className=\"grid grid-cols-4 gap-1.5\">\n {DISTRESS_TEXTURE_PRESETS.map((preset) => (\n <button\n key={preset.id}\n onClick={() => handleTextureSelect(preset.textureUrl)}\n className={`aspect-square rounded-md border-2 overflow-hidden transition-colors ${\n distressEffect?.textureUrl === preset.textureUrl\n ? 'border-accent-primary'\n : 'border-border-primary hover:border-border-focus'\n }`}\n title={preset.name}\n >\n <img\n src={preset.thumbnailUrl}\n alt={preset.name}\n className=\"w-full h-full object-cover\"\n loading=\"lazy\"\n />\n </button>\n ))}\n </div>\n\n {/* Texture opacity slider */}\n <div className=\"flex flex-col gap-sm\">\n <Label>Texture Opacity</Label>\n <Slider\n value={[Math.round((distressEffect?.textureOpacity ?? 0.5) * 100)]}\n onValueChange={handleTextureOpacityChange}\n min={0}\n max={100}\n step={1}\n />\n <div className=\"text-sm text-text-muted\">{Math.round((distressEffect?.textureOpacity ?? 0.5) * 100)}%</div>\n </div>\n </>\n )}\n\n {/* Intensity slider (for procedural styles) */}\n {style !== 'custom' && (\n <div className=\"flex flex-col gap-sm\">\n <Label>Intensity</Label>\n <Slider\n value={[intensity]}\n onValueChange={handleIntensityChange}\n min={0}\n max={100}\n step={1}\n />\n <div className=\"text-sm text-text-muted\">{intensity}%</div>\n </div>\n )}\n\n {/* Style-specific parameters */}\n {(style === 'worn' || style === 'grunge' || style === 'retro') && (\n <div className=\"flex flex-col gap-sm\">\n <Label>Fade</Label>\n <Slider\n value={[fadeAmount]}\n onValueChange={handleFadeChange}\n min={0}\n max={100}\n step={1}\n />\n <div className=\"text-sm text-text-muted\">{fadeAmount}%</div>\n </div>\n )}\n\n {(style === 'worn' || style === 'grunge' || style === 'retro') && (\n <div className=\"flex flex-col gap-sm\">\n <Label>Grain</Label>\n <Slider\n value={[grainAmount]}\n onValueChange={handleGrainChange}\n min={0}\n max={100}\n step={1}\n />\n <div className=\"text-sm text-text-muted\">{grainAmount}%</div>\n </div>\n )}\n\n {style === 'cracked' && (\n <div className=\"flex flex-col gap-sm\">\n <Label>Scratches</Label>\n <Slider\n value={[scratchAmount]}\n onValueChange={handleScratchChange}\n min={0}\n max={100}\n step={1}\n />\n <div className=\"text-sm text-text-muted\">{scratchAmount}%</div>\n </div>\n )}\n\n {(style === 'worn' || style === 'cracked') && (\n <div className=\"flex flex-col gap-sm\">\n <Label>Edge Wear</Label>\n <Slider\n value={[edgeWear]}\n onValueChange={handleEdgeWearChange}\n min={0}\n max={100}\n step={1}\n />\n <div className=\"text-sm text-text-muted\">{edgeWear}%</div>\n </div>\n )}\n\n {/* Randomize button */}\n <Button variant=\"outline\" onClick={handleRandomize} className=\"w-full\">\n Randomize Pattern\n </Button>\n </DisclosureContent>\n </Disclosure>\n );\n};\n\nexport default DistressPanel;\n","/**\n * Compositing utility functions\n * Helper functions for knockout/clip compositing and scope management\n */\n\nimport type { BlendMode, CompositingConfig, CompositingScope, KnockoutConfig, KnockoutScope } from '../types/index.js';\n\n/**\n * Create default knockout configuration\n */\nexport function createKnockoutConfig(\n fill: boolean = false,\n stroke: boolean = false,\n scope: CompositingScope = 'group'\n): CompositingConfig {\n return { fill, stroke, scope };\n}\n\n/**\n * Create stroke knockout configuration (common for t-shirt design)\n */\nexport function createStrokeKnockout(scope: CompositingScope = 'artboard'): CompositingConfig {\n return {\n fill: false,\n stroke: true,\n scope,\n };\n}\n\n/**\n * Create fill knockout configuration\n */\nexport function createFillKnockout(scope: CompositingScope = 'artboard'): CompositingConfig {\n return {\n fill: true,\n stroke: false,\n scope,\n };\n}\n\n/**\n * Check if element has any compositing parts enabled (knockout or clip)\n */\nexport function hasCompositing(config: CompositingConfig | undefined): boolean {\n if (!config) return false;\n return !!(config.fill || config.stroke);\n}\n\n/** @deprecated Use hasCompositing instead */\nexport function hasKnockout(config: KnockoutConfig | undefined): boolean {\n return hasCompositing(config);\n}\n\n/**\n * Get compositing parts as array of strings\n */\nexport function getCompositingParts(config: CompositingConfig | undefined): string[] {\n if (!config) return [];\n\n const parts: string[] = [];\n if (config.fill) parts.push('fill');\n if (config.stroke) parts.push('stroke');\n return parts;\n}\n\n/** @deprecated Use getCompositingParts instead */\nexport function getKnockoutParts(config: KnockoutConfig | undefined): string[] {\n return getCompositingParts(config);\n}\n\n/**\n * Get human-readable description of compositing configuration\n */\nexport function describeCompositing(config: CompositingConfig | undefined, mode: BlendMode = 'knockout'): string {\n if (!config || !hasCompositing(config)) {\n return 'No compositing';\n }\n\n const parts = getCompositingParts(config);\n const scope = config.scope || 'group';\n const modeLabel = mode === 'clip' ? 'clip' : 'knockout';\n\n if (parts.length === 0) return 'No compositing';\n if (parts.length === 1) return `${parts[0]} ${modeLabel} (${scope})`;\n\n const partsList = parts.slice(0, -1).join(', ') + ' & ' + parts[parts.length - 1];\n return `${partsList} ${modeLabel} (${scope})`;\n}\n\n/** @deprecated Use describeCompositing instead */\nexport function describeKnockout(config: KnockoutConfig | undefined): string {\n if (!config || !hasCompositing(config)) {\n return 'No knockout';\n }\n return describeCompositing(config, 'knockout');\n}\n\n/**\n * Validate knockout configuration\n */\nexport function isValidKnockoutConfig(config: KnockoutConfig): boolean {\n // At least one part must be enabled\n if (!config.fill && !config.stroke) {\n return false;\n }\n\n // Scope must be valid\n if (config.scope && !['group', 'artboard'].includes(config.scope)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Merge knockout configurations\n * Combines two configs, with priority given to the second one\n */\nexport function mergeKnockoutConfigs(\n config1: KnockoutConfig | undefined,\n config2: KnockoutConfig | undefined\n): KnockoutConfig | undefined {\n if (!config1) return config2;\n if (!config2) return config1;\n\n return {\n fill: config2.fill !== undefined ? config2.fill : config1.fill,\n stroke: config2.stroke !== undefined ? config2.stroke : config1.stroke,\n scope: config2.scope || config1.scope,\n };\n}\n\n/**\n * Clone knockout configuration\n */\nexport function cloneKnockoutConfig(config: KnockoutConfig): KnockoutConfig {\n return { ...config };\n}\n\n/**\n * Get recommended scope for use case\n */\nexport function getRecommendedScope(useCase: 'tshirt' | 'pillow' | 'pattern' | 'general'): KnockoutScope {\n switch (useCase) {\n case 'tshirt':\n return 'artboard'; // Cut through to transparent background\n case 'pillow':\n case 'pattern':\n return 'group'; // Knockout within design group only\n default:\n return 'group'; // Default to safer group scope\n }\n}\n","/**\n * CompositingPanel - UI component for knockout compositing\n * Controls blend mode and knockout configuration with dual scope support\n *\n * Migrated to Shadcn/Radix:\n * - Disclosure (Collapsible)\n * - RadioGroup\n * - Fieldset\n */\n\nimport { useState } from 'react';\nimport type { BlendMode, KnockoutConfig, KnockoutScope } from '../types/index.js';\nimport { describeKnockout } from '../rendering/knockout-utils.js';\nimport {\n Disclosure,\n DisclosureTrigger,\n DisclosureContent,\n Label,\n RadioGroup,\n Radio,\n Fieldset,\n} from './ui';\n\ninterface CompositingPanelProps {\n blendMode?: BlendMode;\n knockoutParts?: KnockoutConfig;\n onChange: (blendMode: BlendMode, knockoutParts?: KnockoutConfig) => void;\n}\n\nconst CompositingPanel = ({ blendMode = 'normal', knockoutParts, onChange }: CompositingPanelProps) => {\n const isCompositing = blendMode === 'knockout' || blendMode === 'clip';\n const [isExpanded, setIsExpanded] = useState(isCompositing);\n\n const isKnockout = isCompositing;\n const fillEnabled = knockoutParts?.fill || false;\n const strokeEnabled = knockoutParts?.stroke || false;\n const scope: KnockoutScope = knockoutParts?.scope || 'group';\n\n const handleBlendModeChange = (newMode: string) => {\n if (newMode === 'knockout' || newMode === 'clip') {\n // Enable stroke knockout by default (common for t-shirt design)\n onChange(newMode as BlendMode, {\n fill: false,\n stroke: true,\n scope: 'artboard',\n });\n setIsExpanded(true);\n } else {\n onChange(newMode as BlendMode, undefined);\n setIsExpanded(false);\n }\n };\n\n const handleFillToggle = () => {\n if (!knockoutParts) return;\n onChange(blendMode, {\n ...knockoutParts,\n fill: !fillEnabled,\n });\n };\n\n const handleStrokeToggle = () => {\n if (!knockoutParts) return;\n onChange(blendMode, {\n ...knockoutParts,\n stroke: !strokeEnabled,\n });\n };\n\n const handleScopeChange = (newScope: KnockoutScope) => {\n if (!knockoutParts) return;\n onChange(blendMode, {\n ...knockoutParts,\n scope: newScope,\n });\n };\n\n return (\n <Disclosure\n open={isExpanded}\n onOpenChange={isKnockout ? setIsExpanded : undefined}\n className=\"mb-xl\"\n >\n <DisclosureTrigger className=\"w-full\">\n <div className=\"flex items-center justify-between w-full\">\n <Label>Compositing</Label>\n </div>\n </DisclosureTrigger>\n <DisclosureContent className=\"flex flex-col gap-lg pt-lg\">\n {/* Blend Mode Selector */}\n <Fieldset className=\"flex flex-col gap-sm\">\n <Label>Blend Mode</Label>\n <RadioGroup value={blendMode} onValueChange={handleBlendModeChange} orientation=\"horizontal\">\n <Radio value=\"normal\" id=\"blend-normal\">Normal</Radio>\n <Radio value=\"knockout\" id=\"blend-knockout\">Knockout</Radio>\n </RadioGroup>\n </Fieldset>\n\n {/* Knockout Configuration (shown when knockout mode is active) */}\n {isKnockout && (\n <>\n {/* Knockout Parts */}\n <div className=\"flex flex-col gap-md border-t border-border-primary pt-2xl\">\n <label className=\"text-base font-medium text-text-secondary\">Knockout Parts</label>\n <div className=\"flex flex-col gap-sm\">\n <label\n className=\"flex cursor-pointer flex-col gap-xs rounded-lg border border-border-primary bg-bg-tertiary p-md transition-all duration-fast hover:border-border-secondary hover:bg-bg-hover\"\n onClick={handleFillToggle}\n >\n <span className=\"flex items-center gap-sm text-lg font-semibold text-text-primary\">\n <span className=\"text-base\">{fillEnabled ? '☑' : '☐'}</span>\n Fill\n </span>\n <small className=\"ml-[22px] text-sm text-text-muted\">Element content cuts through</small>\n </label>\n <label\n className=\"flex cursor-pointer flex-col gap-xs rounded-lg border border-border-primary bg-bg-tertiary p-md transition-all duration-fast hover:border-border-secondary hover:bg-bg-hover\"\n onClick={handleStrokeToggle}\n >\n <span className=\"flex items-center gap-sm text-lg font-semibold text-text-primary\">\n <span className=\"text-base\">{strokeEnabled ? '☑' : '☐'}</span>\n Stroke\n </span>\n <small className=\"ml-[22px] text-sm text-text-muted\">Border/outline cuts through</small>\n </label>\n </div>\n </div>\n\n {/* Knockout Scope */}\n <Fieldset className=\"flex flex-col gap-sm\">\n <Label>Knockout Scope</Label>\n <div className=\"flex gap-sm\">\n <button\n className={`flex flex-1 cursor-pointer flex-col gap-xs rounded-lg border p-lg text-center transition-all duration-fast ${\n scope === 'group'\n ? 'border-accent-primary bg-accent-primary'\n : 'border-border-primary bg-bg-tertiary hover:border-border-secondary hover:bg-bg-hover'\n }`}\n onClick={() => handleScopeChange('group')}\n title=\"Knockout within group siblings only\"\n >\n <strong className={`text-lg ${scope === 'group' ? 'text-text-on-accent' : 'text-text-primary'}`}>\n Group\n </strong>\n <small className={`text-sm ${scope === 'group' ? 'text-bg-tertiary' : 'text-text-muted'}`}>\n Affects siblings in group\n </small>\n </button>\n <button\n className={`flex flex-1 cursor-pointer flex-col gap-xs rounded-lg border p-lg text-center transition-all duration-fast ${\n scope === 'artboard'\n ? 'border-accent-primary bg-accent-primary'\n : 'border-border-primary bg-bg-tertiary hover:border-border-secondary hover:bg-bg-hover'\n }`}\n onClick={() => handleScopeChange('artboard')}\n title=\"Knockout cuts through to artboard\"\n >\n <strong className={`text-lg ${scope === 'artboard' ? 'text-text-on-accent' : 'text-text-primary'}`}>\n Artboard\n </strong>\n <small className={`text-sm ${scope === 'artboard' ? 'text-bg-tertiary' : 'text-text-muted'}`}>\n Cuts to transparent background\n </small>\n </button>\n </div>\n </Fieldset>\n\n {/* Description/Preview */}\n <div className=\"flex flex-col gap-md\">\n <div className=\"rounded-lg border border-border-primary bg-bg-tertiary p-md\">\n <strong className=\"text-sm font-semibold uppercase tracking-wide text-accent-primary\">Effect:</strong>\n <p className=\"mt-xs text-base text-text-secondary\">{describeKnockout(knockoutParts)}</p>\n </div>\n <div className=\"rounded-sm border-l-2 border-accent-primary bg-accent-light p-md\">\n <small className=\"text-sm leading-relaxed text-text-secondary\">\n <strong>Tip:</strong> Use <em className=\"font-semibold not-italic text-accent-primary\">Artboard</em>{' '}\n scope for t-shirt designs, <em className=\"font-semibold not-italic text-accent-primary\">Group</em> scope\n for pillow patterns.\n </small>\n </div>\n </div>\n </>\n )}\n </DisclosureContent>\n </Disclosure>\n );\n};\n\nexport default CompositingPanel;\n","/**\n * GlyphPicker - Interactive picker for selecting glyph alternates\n *\n * Displays available alternates for a selected character with visual previews\n */\n\nimport { useState, useEffect } from 'react';\nimport { Drawer, DrawerContent, DrawerTitle } from '@snowcone-app/ui';\nimport { Icon } from '@iconify/react';\nimport { Button, icons, SparklesIcon } from './ui';\nimport { FontAnalyzer } from '../utils/FontAnalyzer';\nimport { createLogger } from '../utils/logger.js';\nimport type { GlyphAlternate, GlyphOverride } from '../types';\n\nconst logger = createLogger('GlyphPicker');\n\ninterface GlyphPickerProps {\n isOpen: boolean;\n onClose: () => void;\n character: string;\n charIndex: number;\n fontFamily: string;\n fontWeight?: number;\n currentGlyphOverride?: GlyphOverride;\n onSelectGlyph: (override: GlyphOverride | null) => void;\n browseAll?: boolean; // If true, show all glyphs in the font instead of just alternates for the character\n}\n\nexport const GlyphPicker = ({\n isOpen,\n onClose,\n character,\n charIndex,\n fontFamily,\n fontWeight = 400,\n currentGlyphOverride,\n onSelectGlyph,\n browseAll = false,\n}: GlyphPickerProps) => {\n const [alternates, setAlternates] = useState<GlyphAlternate[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // Load glyph alternates when picker opens\n useEffect(() => {\n if (!isOpen) return;\n\n setLoading(true);\n setError(null);\n\n const loadPromise = browseAll\n ? FontAnalyzer.getAllGlyphs(fontFamily, fontWeight)\n : FontAnalyzer.getGlyphAlternates(fontFamily, character, fontWeight);\n\n loadPromise\n .then((alts) => {\n if (alts.length === 0) {\n setError(\n browseAll ? `No glyphs found in ${fontFamily}` : `No alternates found for \"${character}\" in ${fontFamily}`\n );\n }\n setAlternates(alts);\n setLoading(false);\n })\n .catch((err) => {\n logger.error('Error loading glyphs:', err);\n setError(browseAll ? 'Failed to load glyphs' : 'Failed to load glyph alternates');\n setLoading(false);\n });\n }, [isOpen, character, fontFamily, fontWeight, browseAll]);\n\n const handleSelectGlyph = (alternate: GlyphAlternate) => {\n // In browse all mode, always apply the selection\n // In character-specific mode, check if it's the default glyph\n if (!browseAll && alternate.category === 'default') {\n onSelectGlyph(null);\n } else {\n onSelectGlyph({\n charIndex,\n glyphIndex: alternate.glyphIndex,\n unicode: browseAll ? alternate.unicode : character,\n alternateName: alternate.name,\n });\n }\n onClose();\n };\n\n const title = browseAll ? `Browse All Glyphs - ${fontFamily}` : `Alternates for \"${character}\"`;\n\n return (\n <Drawer open={isOpen} onOpenChange={(open) => !open && onClose()}>\n <DrawerContent\n placement=\"bottom\"\n overlayOpacity={0.4}\n className=\"flex flex-col overflow-hidden\"\n style={{ zIndex: 'var(--z-drawer, 10002)' }}\n >\n {/* Accessibility title (sr-only) */}\n <DrawerTitle className=\"sr-only\">{title}</DrawerTitle>\n\n {/* Header */}\n <div className=\"flex items-center justify-between px-3xl pb-2xl pt-2xl border-b border-border-primary\">\n <div className=\"flex items-center gap-md\">\n <SparklesIcon size={24} className=\"text-text-muted\" />\n <h3 className=\"m-0 text-3xl font-semibold text-text-primary\">\n {title}\n </h3>\n </div>\n <Button size=\"icon\" variant=\"ghost\" onClick={onClose}>\n <Icon icon={icons.close} className=\"size-6\" />\n </Button>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-3xl\">\n {loading && (\n <div className=\"text-center py-6xl text-text-muted\">Loading alternates...</div>\n )}\n\n {error && (\n <div className=\"text-center px-3xl py-6xl text-text-placeholder text-xl\">\n {error}\n <div className=\"mt-md text-base\">\n This font may not have alternate glyphs for this character.\n </div>\n </div>\n )}\n\n {!loading && !error && alternates.length > 0 && (\n <div className=\"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-xl\">\n {alternates.map((alternate, index) => {\n const isSelected = currentGlyphOverride?.glyphIndex === alternate.glyphIndex;\n const isDefault = alternate.category === 'default';\n\n return (\n <button\n key={`${alternate.glyphIndex}-${index}`}\n onClick={() => handleSelectGlyph(alternate)}\n className={`\n flex flex-col items-center gap-md p-xl rounded-xl\n border-2 cursor-pointer transition-all duration-base\n relative aspect-square\n ${isSelected\n ? 'bg-accent-primary border-accent-primary'\n : 'bg-bg-secondary border-border-primary hover:bg-accent-light hover:border-accent-primary'\n }\n `.trim()}\n >\n {/* Preview */}\n {alternate.previewDataUrl ? (\n <img\n src={alternate.previewDataUrl}\n alt={alternate.name}\n className={`w-full h-auto object-contain ${isSelected ? 'brightness-0 invert' : ''}`}\n />\n ) : (\n <div\n style={{ fontFamily }}\n className={`text-[48px] leading-none ${isSelected ? 'text-text-on-dark' : 'text-text-primary'}`}\n >\n {character}\n </div>\n )}\n\n {/* Label */}\n <div\n className={`\n text-sm text-center whitespace-nowrap overflow-hidden\n text-ellipsis w-full\n ${isSelected ? 'text-text-on-dark' : 'text-text-muted'}\n `.trim()}\n >\n {isDefault ? 'Default' : alternate.name}\n </div>\n\n {/* Badge for default */}\n {isDefault && (\n <div className=\"absolute top-xs right-xs bg-accent-primary text-text-on-dark text-xs px-sm py-[2px] rounded-md font-semibold\">\n DEFAULT\n </div>\n )}\n </button>\n );\n })}\n </div>\n )}\n </div>\n\n {/* Footer */}\n {!loading && !error && alternates.length > 1 && (\n <div className=\"px-3xl py-xl border-t border-border-primary bg-bg-secondary text-base text-text-muted text-center\">\n {alternates.length} alternate{alternates.length !== 1 ? 's' : ''} available\n </div>\n )}\n </DrawerContent>\n </Drawer>\n );\n};\n","/**\n * OpenTypeFeaturesPanel - UI component for configuring OpenType features\n * Provides toggles for advanced typography features\n *\n * Migrated to use Tailwind utilities:\n * - Removed all inline styles (100+ style objects)\n * - Pure Tailwind classes with design tokens\n * - Button primitive for Browse All Glyphs button\n * - Maintains exact visual appearance\n */\n\nimport { useState, useEffect } from 'react';\nimport { Icon } from '@iconify/react';\nimport type { OpenTypeFeatures, GlyphOverride } from '../types/index.js';\nimport { FontAnalyzer } from '../utils/FontAnalyzer';\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger('OpenTypeFeaturesPanel');\nimport { GlyphPicker } from './GlyphPicker';\nimport { Button, icons, SparklesIcon } from './ui';\n\ninterface OpenTypeFeaturesPanelProps {\n fontFamily?: string;\n fontWeight?: number;\n text?: string;\n openTypeFeatures?: OpenTypeFeatures;\n glyphOverrides?: GlyphOverride[];\n onChange: (features: OpenTypeFeatures | undefined) => void;\n onGlyphOverridesChange?: (overrides: GlyphOverride[] | undefined) => void;\n}\n\ninterface FeatureDefinition {\n tag: keyof OpenTypeFeatures;\n label: string;\n description: string;\n category: 'ligatures' | 'alternates' | 'numerals' | 'stylistic';\n}\n\nconst FEATURE_DEFINITIONS: FeatureDefinition[] = [\n // Ligatures\n { tag: 'liga', label: 'Standard Ligatures', description: 'Common ligatures like fi, fl', category: 'ligatures' },\n {\n tag: 'dlig',\n label: 'Discretionary Ligatures',\n description: 'Optional ligatures like ct, st',\n category: 'ligatures',\n },\n {\n tag: 'calt',\n label: 'Contextual Alternates',\n description: 'Context-aware glyph substitution',\n category: 'ligatures',\n },\n { tag: 'ccmp', label: 'Glyph Composition', description: 'Combine glyphs for proper display', category: 'ligatures' },\n { tag: 'locl', label: 'Localized Forms', description: 'Language-specific glyph variants', category: 'ligatures' },\n\n // Alternates\n { tag: 'swsh', label: 'Swashes', description: 'Decorative flourishes', category: 'alternates' },\n { tag: 'smcp', label: 'Small Caps', description: 'Small capital letters', category: 'alternates' },\n { tag: 'c2sc', label: 'Caps to Small Caps', description: 'Convert caps to small caps', category: 'alternates' },\n\n // Numerals\n { tag: 'onum', label: 'Old Style Figures', description: 'Varying height numbers', category: 'numerals' },\n { tag: 'lnum', label: 'Lining Figures', description: 'Uniform height numbers', category: 'numerals' },\n { tag: 'tnum', label: 'Tabular Figures', description: 'Fixed-width numbers', category: 'numerals' },\n { tag: 'pnum', label: 'Proportional Figures', description: 'Variable-width numbers', category: 'numerals' },\n\n // Stylistic Sets (first 10)\n { tag: 'ss01', label: 'Stylistic Set 1', description: 'Alternate character set 1', category: 'stylistic' },\n { tag: 'ss02', label: 'Stylistic Set 2', description: 'Alternate character set 2', category: 'stylistic' },\n { tag: 'ss03', label: 'Stylistic Set 3', description: 'Alternate character set 3', category: 'stylistic' },\n { tag: 'ss04', label: 'Stylistic Set 4', description: 'Alternate character set 4', category: 'stylistic' },\n { tag: 'ss05', label: 'Stylistic Set 5', description: 'Alternate character set 5', category: 'stylistic' },\n { tag: 'ss06', label: 'Stylistic Set 6', description: 'Alternate character set 6', category: 'stylistic' },\n { tag: 'ss07', label: 'Stylistic Set 7', description: 'Alternate character set 7', category: 'stylistic' },\n { tag: 'ss08', label: 'Stylistic Set 8', description: 'Alternate character set 8', category: 'stylistic' },\n { tag: 'ss09', label: 'Stylistic Set 9', description: 'Alternate character set 9', category: 'stylistic' },\n { tag: 'ss10', label: 'Stylistic Set 10', description: 'Alternate character set 10', category: 'stylistic' },\n\n // Technical features (usually enabled by default)\n { tag: 'kern', label: 'Kerning', description: 'Adjust spacing between letter pairs', category: 'stylistic' },\n { tag: 'mark', label: 'Mark Positioning', description: 'Position diacritical marks', category: 'stylistic' },\n { tag: 'mkmk', label: 'Mark to Mark', description: 'Position marks relative to marks', category: 'stylistic' },\n];\n\nconst OpenTypeFeaturesPanel = ({\n fontFamily,\n fontWeight = 400,\n text = '',\n openTypeFeatures,\n glyphOverrides = [],\n onChange,\n onGlyphOverridesChange,\n}: OpenTypeFeaturesPanelProps) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const [availableFeatures, setAvailableFeatures] = useState<string[]>([]);\n const [loading, setLoading] = useState(false);\n\n // Glyph picker state\n const [glyphPickerOpen, setGlyphPickerOpen] = useState(false);\n const [selectedCharIndex, setSelectedCharIndex] = useState(0);\n const [selectedCharacter, setSelectedCharacter] = useState('');\n const [browseAllMode, setBrowseAllMode] = useState(false);\n\n // Alternate counts for each unique character\n const [alternateCounts, setAlternateCounts] = useState<Map<string, number>>(new Map());\n const [_loadingCounts, setLoadingCounts] = useState(false);\n\n // Load available features when font changes\n useEffect(() => {\n if (!fontFamily) {\n setAvailableFeatures([]);\n return;\n }\n\n setLoading(true);\n FontAnalyzer.getAvailableFeatures(fontFamily, fontWeight)\n .then((features) => {\n setAvailableFeatures(features);\n setLoading(false);\n })\n .catch((err) => {\n logger.error('Error loading OpenType features:', err);\n setAvailableFeatures([]);\n setLoading(false);\n });\n }, [fontFamily, fontWeight]);\n\n // Load alternate counts for each unique character when text or font changes\n useEffect(() => {\n if (!text || !fontFamily) {\n setAlternateCounts(new Map());\n return;\n }\n\n // Get unique characters (excluding spaces)\n const uniqueChars = Array.from(new Set(Array.from(text).filter((c) => c !== ' ')));\n\n if (uniqueChars.length === 0) {\n setAlternateCounts(new Map());\n return;\n }\n\n setLoadingCounts(true);\n\n const loadCounts = async () => {\n const counts = new Map<string, number>();\n\n for (const char of uniqueChars) {\n try {\n const alternates = await FontAnalyzer.getGlyphAlternates(fontFamily, char, fontWeight);\n // Count only the alternates (exclude the default glyph which is first)\n const alternateCount = alternates.length > 0 ? alternates.length - 1 : 0;\n counts.set(char, alternateCount);\n } catch (err) {\n logger.error(`Error loading alternates for '${char}':`, err);\n counts.set(char, 0);\n }\n }\n\n setAlternateCounts(counts);\n setLoadingCounts(false);\n };\n\n loadCounts();\n }, [text, fontFamily, fontWeight]);\n\n const handleToggleFeature = (tag: keyof OpenTypeFeatures) => {\n const currentValue = openTypeFeatures?.[tag];\n const newFeatures = {\n ...openTypeFeatures,\n [tag]: !currentValue,\n };\n\n // Remove undefined/false values to keep the object clean\n Object.keys(newFeatures).forEach((key) => {\n if (!newFeatures[key as keyof OpenTypeFeatures]) {\n delete newFeatures[key as keyof OpenTypeFeatures];\n }\n });\n\n // Pre-load font to ensure it's in cache for rendering\n if (fontFamily && Object.keys(newFeatures).length > 0) {\n FontAnalyzer.loadFont(fontFamily, fontWeight).catch((err) => {\n logger.error('Error pre-loading font for OpenType features:', err);\n });\n }\n\n // If no features enabled, set to undefined\n onChange(Object.keys(newFeatures).length > 0 ? newFeatures : undefined);\n };\n\n const handleCharacterClick = (charIndex: number, character: string) => {\n setSelectedCharIndex(charIndex);\n setSelectedCharacter(character);\n setBrowseAllMode(false);\n setGlyphPickerOpen(true);\n };\n\n const handleBrowseAllGlyphs = () => {\n setBrowseAllMode(true);\n setGlyphPickerOpen(true);\n };\n\n const handleSelectGlyph = (override: GlyphOverride | null) => {\n if (!onGlyphOverridesChange) return;\n\n let newOverrides = [...glyphOverrides];\n\n if (override) {\n // Add or update the override\n const existingIndex = newOverrides.findIndex((o) => o.charIndex === override.charIndex);\n if (existingIndex >= 0) {\n newOverrides[existingIndex] = override;\n } else {\n newOverrides.push(override);\n }\n } else {\n // Remove override\n newOverrides = newOverrides.filter((o) => o.charIndex !== selectedCharIndex);\n }\n\n onGlyphOverridesChange(newOverrides.length > 0 ? newOverrides : undefined);\n };\n\n const enabledCount = openTypeFeatures ? Object.values(openTypeFeatures).filter(Boolean).length : 0;\n\n const glyphOverridesCount = glyphOverrides.length;\n\n // Group features by category\n const groupedFeatures = FEATURE_DEFINITIONS.reduce(\n (acc, feature) => {\n if (!acc[feature.category]) {\n acc[feature.category] = [];\n }\n acc[feature.category].push(feature);\n return acc;\n },\n {} as Record<string, FeatureDefinition[]>\n );\n\n return (\n <div className=\"mb-lg\">\n {/* Header */}\n <div\n className={`flex cursor-pointer items-center justify-between py-sm ${isExpanded ? 'border-b border-border-light' : ''}`}\n onClick={() => setIsExpanded(!isExpanded)}\n >\n <div className=\"flex items-center gap-sm\">\n <Icon icon={icons.text} className=\"size-4\" />\n <span className=\"text-xl font-medium\">OpenType Features</span>\n {enabledCount > 0 && (\n <span className=\"rounded-full bg-info px-xs py-[2px] text-2xs font-semibold text-info-foreground\">\n {enabledCount}\n </span>\n )}\n </div>\n <button className=\"cursor-pointer border-none bg-transparent p-xs text-xs\">\n {isExpanded ? '▼' : '▶'}\n </button>\n </div>\n\n {/* Content */}\n {isExpanded && (\n <div className=\"py-md\">\n {loading && <div className=\"py-md text-sm text-text-secondary\">Loading available features...</div>}\n\n {!loading && !fontFamily && (\n <div className=\"py-md text-sm text-text-muted\">Select a text element to configure OpenType features</div>\n )}\n\n {!loading && fontFamily && availableFeatures.length === 0 && (\n <div className=\"py-md text-sm text-text-muted\">\n This font does not support advanced OpenType features\n </div>\n )}\n\n {/* Glyph Picker Section */}\n {!loading && fontFamily && text && onGlyphOverridesChange && (\n <div className=\"mb-lg border-b border-border-light pb-lg\">\n <div className=\"mb-md flex items-center justify-between\">\n <div className=\"flex items-center gap-sm\">\n <SparklesIcon size={14} className=\"text-text-secondary\" />\n <span className=\"text-2xs font-semibold uppercase tracking-wide text-text-secondary\">\n Alternate Glyphs\n </span>\n {glyphOverridesCount > 0 && (\n <span className=\"rounded-full bg-success px-xs py-[2px] text-3xs font-semibold text-success-foreground\">\n {glyphOverridesCount}\n </span>\n )}\n </div>\n </div>\n\n <div className=\"mb-md flex items-center justify-between gap-md\">\n <div className=\"text-xs text-text-secondary\">Click on any letter to pick alternate glyphs</div>\n <Button\n variant=\"ghost\"\n onClick={handleBrowseAllGlyphs}\n className=\"whitespace-nowrap rounded-md border border-info bg-info/10 px-md py-xs text-xs font-medium text-info transition-all duration-fast hover:bg-info hover:text-info-foreground\"\n >\n Browse All Glyphs\n </Button>\n </div>\n\n {/* Text preview with clickable characters */}\n <div className=\"flex flex-wrap gap-xs rounded-md border border-border-medium bg-surface p-md\">\n {Array.from(text).map((char, index) => {\n const hasOverride = glyphOverrides.some((o) => o.charIndex === index);\n const isSpace = char === ' ';\n\n if (isSpace) {\n return <div key={index} className=\"h-4xl w-sm\" />;\n }\n\n const alternateCount = alternateCounts.get(char) || 0;\n\n return (\n <button\n key={index}\n onClick={() => handleCharacterClick(index, char)}\n className={`\n relative min-w-4xl cursor-pointer rounded border-2 p-xs text-center text-3xl transition-all duration-fast\n ${\n hasOverride\n ? 'border-success bg-success text-success-foreground'\n : 'border-border-medium bg-surface text-text-primary hover:border-info hover:bg-info/10'\n }\n `}\n style={{ fontFamily }}\n >\n {char}\n {/* Show count badge if there are alternates */}\n {alternateCount > 0 && (\n <span\n className={`absolute -right-[4px] -top-[4px] min-w-lg rounded-full border-2 border-surface px-xs py-[2px] text-center text-3xs font-semibold leading-none shadow-md ${\n hasOverride ? 'bg-success text-success-foreground' : 'bg-info text-info-foreground'\n }`}\n >\n {alternateCount}\n </span>\n )}\n </button>\n );\n })}\n </div>\n </div>\n )}\n\n {!loading && fontFamily && availableFeatures.length > 0 && (\n <>\n {Object.entries(groupedFeatures).map(([category, features]) => {\n // Filter to only show features available in the font\n const availableFeaturesInCategory = features.filter((f) => availableFeatures.includes(f.tag));\n\n if (availableFeaturesInCategory.length === 0) return null;\n\n return (\n <div key={category} className=\"mb-lg\">\n <div className=\"mb-sm text-2xs font-semibold uppercase tracking-wide text-text-secondary\">\n {category}\n </div>\n <div className=\"flex flex-col gap-sm\">\n {availableFeaturesInCategory.map((feature) => (\n <label\n key={feature.tag}\n className=\"flex cursor-pointer items-start gap-sm rounded p-xs transition-colors duration-fast hover:bg-surface\"\n >\n <input\n type=\"checkbox\"\n checked={openTypeFeatures?.[feature.tag] || false}\n onChange={() => handleToggleFeature(feature.tag)}\n className=\"mt-[2px] h-4 w-4 cursor-pointer rounded border-border-primary bg-bg-input accent-accent-primary\"\n />\n <div className=\"flex-1\">\n <div className=\"text-sm font-medium\">{feature.label}</div>\n <div className=\"mt-[2px] text-2xs text-text-secondary\">{feature.description}</div>\n </div>\n </label>\n ))}\n </div>\n </div>\n );\n })}\n </>\n )}\n </div>\n )}\n\n {/* Glyph Picker Drawer */}\n {fontFamily && (\n <GlyphPicker\n isOpen={glyphPickerOpen}\n onClose={() => setGlyphPickerOpen(false)}\n character={selectedCharacter}\n charIndex={selectedCharIndex}\n fontFamily={fontFamily}\n fontWeight={fontWeight}\n currentGlyphOverride={glyphOverrides.find((o) => o.charIndex === selectedCharIndex)}\n onSelectGlyph={handleSelectGlyph}\n browseAll={browseAllMode}\n />\n )}\n </div>\n );\n};\n\nexport default OpenTypeFeaturesPanel;\n","/**\n * @deprecated Use the contextual toolbar secondary panels instead.\n * Stroke, masks, distress, and knockout are now available as inline secondary panels\n * in the contextual toolbar (see SecondaryPanels.tsx).\n *\n * EffectsPanel - Unified panel for all layer effects\n * Provides tabbed interface for Stroke, Masks, Distress, and Compositing (Knockout)\n */\n\nimport { useState } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Tabs, Badge, icons } from './ui';\nimport { Drawer } from './Drawer';\nimport { TextElement } from '../core/TextElement.js';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { ShapeElement } from '../core/ShapeElement.js';\nimport { PathElement } from '../core/PathElement.js';\nimport StrokePanel from './StrokePanel.js';\nimport MasksPanel from './MasksPanel.js';\nimport DistressPanel from './DistressPanel.js';\nimport CompositingPanel from './CompositingPanel.js';\nimport OpenTypeFeaturesPanel from './OpenTypeFeaturesPanel.js';\n\ntype EditorElement = TextElement | ImageElement | GroupElement | ShapeElement | PathElement;\n\ninterface EffectsPanelProps {\n element: EditorElement | null;\n onElementUpdate: (element: EditorElement) => void;\n isOpen: boolean;\n onClose: () => void;\n}\n\ntype EffectTab = 'stroke' | 'masks' | 'distress' | 'compositing' | 'typography';\n\nconst EffectsPanel = ({ element, onElementUpdate, isOpen, onClose }: EffectsPanelProps) => {\n const [activeTab, setActiveTab] = useState<EffectTab>('stroke');\n\n if (!element) return null;\n\n // Check if element has any effects enabled\n const hasStroke = element.stroke?.enabled;\n const hasMasks = element.masks && element.masks.length > 0;\n const hasDistress = element.distressEffect?.enabled;\n const hasKnockout = element.blendMode === 'knockout' || element.blendMode === 'clip';\n\n // Check if element is a text element with typography features\n const isTextElement = element instanceof TextElement;\n const hasTypography =\n isTextElement &&\n ((element.glyphOverrides && element.glyphOverrides.length > 0) ||\n (element.openTypeFeatures && Object.keys(element.openTypeFeatures).length > 0));\n\n return (\n <Drawer\n isOpen={isOpen}\n onClose={onClose}\n title=\"Layer Effects\"\n description=\"Configure stroke, masks, distress, and knockout effects\"\n maxHeight=\"90vh\"\n placement=\"right\"\n maxWidth=\"600px\"\n >\n <Tabs\n value={activeTab}\n onValueChange={(value) => setActiveTab(value as EffectTab)}\n className=\"flex flex-col h-full\"\n >\n <Tabs.ListContainer className=\"px-6\">\n <Tabs.List aria-label=\"Effect types\">\n <Tabs.Tab id=\"stroke\">\n <Icon icon={icons.minus} className=\"size-4\" />\n Stroke\n {hasStroke && <Badge variant=\"default\" className=\"ml-2 size-2 rounded-full p-0\" />}\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab id=\"masks\">\n <Icon icon={icons.group} className=\"size-4\" />\n Masks\n {hasMasks && <Badge variant=\"default\" className=\"ml-2 size-2 rounded-full p-0\" />}\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab id=\"distress\">\n <Icon icon=\"lucide:cloud\" className=\"size-4\" />\n Distress\n {hasDistress && <Badge variant=\"default\" className=\"ml-2 size-2 rounded-full p-0\" />}\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab id=\"compositing\">\n <Icon icon={icons.scissors} className=\"size-4\" />\n Knockout\n {hasKnockout && <Badge variant=\"default\" className=\"ml-2 size-2 rounded-full p-0\" />}\n <Tabs.Indicator />\n </Tabs.Tab>\n {isTextElement && (\n <Tabs.Tab id=\"typography\">\n <Icon icon={icons.text} className=\"size-4\" />\n Typography\n {hasTypography && <Badge variant=\"default\" className=\"ml-2 size-2 rounded-full p-0\" />}\n <Tabs.Indicator />\n </Tabs.Tab>\n )}\n </Tabs.List>\n </Tabs.ListContainer>\n\n {/* Tab Panels */}\n <Tabs.Panel id=\"stroke\" className=\"flex-1 overflow-y-auto p-6\">\n <StrokePanel\n stroke={element.stroke}\n onChange={(stroke) => {\n const updated = element.clone();\n updated.stroke = stroke;\n onElementUpdate(updated);\n }}\n />\n <div className=\"mt-6 pt-4 border-t border-black/10 dark:border-white/10\">\n <div className=\"flex items-start gap-2 text-xs text-muted\">\n <Icon icon=\"lucide:lightbulb\" className=\"size-4 shrink-0 mt-0.5\" />\n <span>Add outlines to text and shapes</span>\n </div>\n </div>\n </Tabs.Panel>\n\n <Tabs.Panel id=\"masks\" className=\"flex-1 overflow-y-auto p-6\">\n <MasksPanel\n masks={element.masks}\n onChange={(masks) => {\n const updated = element.clone();\n updated.masks = masks;\n onElementUpdate(updated);\n }}\n />\n <div className=\"mt-6 pt-4 border-t border-black/10 dark:border-white/10\">\n <div className=\"flex items-start gap-2 text-xs text-muted\">\n <Icon icon=\"lucide:lightbulb\" className=\"size-4 shrink-0 mt-0.5\" />\n <span>Use masks to control visibility</span>\n </div>\n </div>\n </Tabs.Panel>\n\n <Tabs.Panel id=\"distress\" className=\"flex-1 overflow-y-auto p-6\">\n <DistressPanel\n distressEffect={element.distressEffect}\n onChange={(distressEffect) => {\n const updated = element.clone();\n updated.distressEffect = distressEffect;\n onElementUpdate(updated);\n }}\n />\n <div className=\"mt-6 pt-4 border-t border-black/10 dark:border-white/10\">\n <div className=\"flex items-start gap-2 text-xs text-muted\">\n <Icon icon=\"lucide:lightbulb\" className=\"size-4 shrink-0 mt-0.5\" />\n <span>Add vintage/grunge effects for t-shirt designs</span>\n </div>\n </div>\n </Tabs.Panel>\n\n <Tabs.Panel id=\"compositing\" className=\"flex-1 overflow-y-auto p-6\">\n <CompositingPanel\n blendMode={element.blendMode}\n knockoutParts={element.knockoutParts}\n onChange={(blendMode, knockoutParts) => {\n const updated = element.clone();\n updated.blendMode = blendMode;\n updated.knockoutParts = knockoutParts;\n onElementUpdate(updated);\n }}\n />\n <div className=\"mt-6 pt-4 border-t border-black/10 dark:border-white/10\">\n <div className=\"flex items-start gap-2 text-xs text-muted\">\n <Icon icon=\"lucide:lightbulb\" className=\"size-4 shrink-0 mt-0.5\" />\n <span>Use Artboard scope for t-shirts, Group scope for patterns</span>\n </div>\n </div>\n </Tabs.Panel>\n\n {isTextElement && (\n <Tabs.Panel id=\"typography\" className=\"flex-1 overflow-y-auto p-6\">\n <OpenTypeFeaturesPanel\n fontFamily={element.fontFamily}\n fontWeight={element.bold ? 700 : 400}\n text={element.text}\n openTypeFeatures={element.openTypeFeatures}\n glyphOverrides={element.glyphOverrides}\n onChange={(features) => {\n const updated = element.clone();\n updated.openTypeFeatures = features;\n onElementUpdate(updated);\n }}\n onGlyphOverridesChange={(overrides) => {\n const updated = element.clone();\n updated.glyphOverrides = overrides;\n onElementUpdate(updated);\n }}\n />\n <div className=\"mt-6 pt-4 border-t border-black/10 dark:border-white/10\">\n <div className=\"flex items-start gap-2 text-xs text-muted\">\n <Icon icon=\"lucide:lightbulb\" className=\"size-4 shrink-0 mt-0.5\" />\n <span>Enable advanced OpenType features like ligatures and stylistic sets</span>\n </div>\n </div>\n </Tabs.Panel>\n )}\n </Tabs>\n </Drawer>\n );\n};\n\nexport default EffectsPanel;\n","/**\n * @deprecated Use the contextual toolbar secondary panels instead.\n * Stroke, masks, distress, and knockout are now available as inline secondary panels\n * in the contextual toolbar (see SecondaryPanels.tsx).\n *\n * EffectsPanel - Standalone effects panel component for embedding\n * Provides tabbed interface for Stroke, Masks, Distress, Knockout, and Typography\n *\n * This is a wrapper around the main EffectsPanel that integrates with EditorContext\n */\n\nimport React, { useCallback } from 'react';\nimport { useEditor } from '../../contexts/EditorContext.js';\nimport EffectsPanelCore from '../EffectsPanel.js';\nimport { TextElement } from '../../core/TextElement.js';\nimport { ImageElement } from '../../core/ImageElement.js';\nimport { GroupElement } from '../../core/GroupElement.js';\nimport { ShapeElement } from '../../core/ShapeElement.js';\nimport { PathElement } from '../../core/PathElement.js';\n\ntype EditorElement = TextElement | ImageElement | GroupElement | ShapeElement | PathElement;\n\nexport interface EffectsPanelProps {\n /**\n * Whether the panel is open\n */\n isOpen: boolean;\n\n /**\n * Callback when panel should close\n */\n onClose: () => void;\n\n /**\n * Element to edit effects for\n * If not provided, uses the selected element from context\n */\n element?: EditorElement | null;\n\n /**\n * Callback when element is updated\n * If not provided, uses the command history from context\n */\n onElementUpdate?: (element: EditorElement) => void;\n\n /**\n * Custom CSS styles\n */\n style?: React.CSSProperties;\n\n /**\n * Custom class name\n */\n className?: string;\n}\n\n/**\n * Standalone effects panel component\n *\n * @example Using with context (automatic)\n * ```tsx\n * function App() {\n * const [isOpen, setIsOpen] = useState(false);\n *\n * return (\n * <EditorProvider>\n * <Canvas />\n * <button onClick={() => setIsOpen(true)}>Edit Effects</button>\n * <EffectsPanel\n * isOpen={isOpen}\n * onClose={() => setIsOpen(false)}\n * />\n * </EditorProvider>\n * );\n * }\n * ```\n *\n * @example Using with custom element (manual)\n * ```tsx\n * function App() {\n * const [element, setElement] = useState(myElement);\n *\n * return (\n * <EditorProvider>\n * <EffectsPanel\n * isOpen={true}\n * onClose={() => {}}\n * element={element}\n * onElementUpdate={setElement}\n * />\n * </EditorProvider>\n * );\n * }\n * ```\n */\nexport const EffectsPanel: React.FC<EffectsPanelProps> = ({\n isOpen,\n onClose,\n element: externalElement,\n onElementUpdate: externalOnElementUpdate,\n style,\n className,\n}) => {\n const { selectedElement, executeElementUpdate } = useEditor();\n\n // Use external element if provided, otherwise use selected element from context\n const element = externalElement !== undefined ? externalElement : (selectedElement || null);\n\n // Use external update handler if provided, otherwise use command history\n const handleElementUpdate = useCallback(\n (updatedElement: EditorElement) => {\n if (externalOnElementUpdate) {\n externalOnElementUpdate(updatedElement);\n } else if (element) {\n executeElementUpdate(element, updatedElement);\n }\n },\n [externalOnElementUpdate, executeElementUpdate, element]\n );\n\n return (\n <div style={style} className={className}>\n <EffectsPanelCore\n element={element}\n onElementUpdate={handleElementUpdate}\n isOpen={isOpen}\n onClose={onClose}\n />\n </div>\n );\n};\n","/**\n * ExportPanel - Standalone export controls component\n * Uses useExport hook for export operations\n */\n\nimport React, { useState } from 'react';\nimport { useExport } from '../../hooks/useExport.js';\nimport { useArtboards } from '../../hooks/useArtboards.js';\nimport { Icon } from '@iconify/react';\nimport { icons } from '../ui';\nimport { createLogger } from '../../utils/logger.js';\n\nconst logger = createLogger('ExportPanel');\n\nexport interface ExportPanelProps {\n /**\n * Show continuous export controls\n */\n showContinuousExport?: boolean;\n\n /**\n * Default export scale\n */\n defaultScale?: number;\n\n /**\n * Default export format\n */\n defaultFormat?: 'png' | 'jpg';\n\n /**\n * Callback when export is complete\n */\n onExportComplete?: (exports: Record<string, string>) => void;\n\n /**\n * Custom CSS styles\n */\n style?: React.CSSProperties;\n\n /**\n * Custom class name\n */\n className?: string;\n}\n\n/**\n * Standalone export panel component\n *\n * @example\n * ```tsx\n * function EditorWithExport() {\n * return (\n * <EditorProvider>\n * <div style={{ display: 'flex' }}>\n * <Canvas />\n * <ExportPanel\n * showContinuousExport={true}\n * defaultScale={3}\n * onExportComplete={(exports) => {\n * console.log('Exports:', exports);\n * }}\n * />\n * </div>\n * </EditorProvider>\n * );\n * }\n * ```\n */\nexport const ExportPanel: React.FC<ExportPanelProps> = ({\n showContinuousExport = true,\n defaultScale = 3,\n defaultFormat = 'png',\n onExportComplete,\n style = {},\n className = '',\n}) => {\n const {\n exportArtboard,\n exportAllArtboards,\n startContinuousExport,\n stopContinuousExport,\n isExporting,\n isContinuousExporting,\n progress,\n supportsWorkerExport,\n workerStats,\n } = useExport();\n\n const { artboardsInfo, activeArtboardId } = useArtboards();\n\n const [scale, setScale] = useState(defaultScale);\n const [format, setFormat] = useState<'png' | 'jpg'>(defaultFormat);\n const [interval, setInterval] = useState(500);\n\n // Export active artboard\n const handleExportActive = async () => {\n if (!activeArtboardId) return;\n\n try {\n const dataUrl = await exportArtboard(activeArtboardId, { scale, format });\n\n // Download the image with timestamp to avoid overwriting\n const link = document.createElement('a');\n const artboard = artboardsInfo.find((a) => a.id === activeArtboardId);\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n const baseName = artboard?.name || 'artboard';\n link.download = `${baseName}-${timestamp}.${format}`;\n link.href = dataUrl;\n link.click();\n\n if (onExportComplete) {\n onExportComplete({ [activeArtboardId]: dataUrl });\n }\n } catch (error) {\n logger.error('Export failed:', error);\n alert('Export failed. Please try again.');\n }\n };\n\n // Export all artboards\n const handleExportAll = async () => {\n try {\n const exports = await exportAllArtboards({ scale, format });\n\n // Download all images with timestamp to avoid overwriting\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n Object.entries(exports).forEach(([artboardId, dataUrl]) => {\n const artboard = artboardsInfo.find((a) => a.id === artboardId);\n const baseName = artboard?.name || artboardId;\n const link = document.createElement('a');\n link.download = `${baseName}-${timestamp}.${format}`;\n link.href = dataUrl;\n link.click();\n });\n\n if (onExportComplete) {\n onExportComplete(exports);\n }\n } catch (error) {\n logger.error('Export all failed:', error);\n alert('Export failed. Please try again.');\n }\n };\n\n // Toggle continuous export\n const handleToggleContinuous = () => {\n if (isContinuousExporting) {\n stopContinuousExport();\n } else {\n startContinuousExport({\n interval,\n scale,\n format,\n onChange: (exports) => {\n if (onExportComplete) {\n onExportComplete(exports);\n }\n },\n });\n }\n };\n\n return (\n <div\n className={`export-panel ${className}`}\n style={{\n width: 300,\n padding: 16,\n backgroundColor: 'var(--bg-primary)',\n border: '1px solid var(--border-primary)',\n borderRadius: 8,\n ...style,\n }}\n >\n {/* Header */}\n <h3\n style={{\n margin: '0 0 16px 0',\n fontSize: 16,\n fontWeight: 600,\n }}\n >\n Export Settings\n </h3>\n\n {/* Export settings */}\n <div style={{ marginBottom: 16 }}>\n {/* Scale */}\n <label\n htmlFor=\"export-scale\"\n style={{\n display: 'block',\n fontSize: 13,\n marginBottom: 4,\n fontWeight: 500,\n }}\n >\n Scale\n </label>\n <select\n id=\"export-scale\"\n value={scale}\n onChange={(e) => setScale(Number(e.target.value))}\n style={{\n width: '100%',\n padding: 8,\n fontSize: 13,\n border: '1px solid var(--border-primary)',\n borderRadius: 4,\n marginBottom: 12,\n }}\n >\n <option value={1}>1x (Original)</option>\n <option value={2}>2x (Retina)</option>\n <option value={3}>3x (High-Res)</option>\n <option value={4}>4x (Ultra)</option>\n </select>\n\n {/* Format */}\n <label\n htmlFor=\"export-format\"\n style={{\n display: 'block',\n fontSize: 13,\n marginBottom: 4,\n fontWeight: 500,\n }}\n >\n Format\n </label>\n <select\n id=\"export-format\"\n value={format}\n onChange={(e) => setFormat(e.target.value as 'png' | 'jpg')}\n style={{\n width: '100%',\n padding: 8,\n fontSize: 13,\n border: '1px solid var(--border-primary)',\n borderRadius: 4,\n marginBottom: 12,\n }}\n >\n <option value=\"png\">PNG (Transparent)</option>\n <option value=\"jpg\">JPEG (Smaller)</option>\n </select>\n\n {/* Interval (for continuous export) */}\n {showContinuousExport && (\n <>\n <label\n htmlFor=\"export-interval\"\n style={{\n display: 'block',\n fontSize: 13,\n marginBottom: 4,\n fontWeight: 500,\n }}\n >\n Continuous Export Interval\n </label>\n <select\n id=\"export-interval\"\n value={interval}\n onChange={(e) => setInterval(Number(e.target.value))}\n style={{\n width: '100%',\n padding: 8,\n fontSize: 13,\n border: '1px solid var(--border-primary)',\n borderRadius: 4,\n marginBottom: 12,\n }}\n >\n <option value={250}>250ms (Fast)</option>\n <option value={500}>500ms (Recommended)</option>\n <option value={1000}>1s (Slow)</option>\n <option value={2000}>2s (Very Slow)</option>\n </select>\n </>\n )}\n </div>\n\n {/* Export buttons */}\n <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginBottom: 16 }}>\n <button\n onClick={handleExportActive}\n disabled={isExporting || !activeArtboardId}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: 12,\n backgroundColor: 'var(--accent-primary)',\n color: 'var(--primary-foreground)',\n border: 'none',\n borderRadius: 6,\n cursor: isExporting || !activeArtboardId ? 'not-allowed' : 'pointer',\n fontSize: 14,\n fontWeight: 500,\n opacity: isExporting || !activeArtboardId ? 0.5 : 1,\n }}\n >\n <Icon icon={icons.download} className=\"size-4\" />\n {isExporting ? 'Exporting...' : 'Export Active Artboard'}\n </button>\n\n <button\n onClick={handleExportAll}\n disabled={isExporting || artboardsInfo.length === 0}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: 12,\n backgroundColor: 'var(--bg-secondary)',\n color: 'var(--text-primary)',\n border: '1px solid var(--border-primary)',\n borderRadius: 6,\n cursor: isExporting || artboardsInfo.length === 0 ? 'not-allowed' : 'pointer',\n fontSize: 14,\n fontWeight: 500,\n opacity: isExporting || artboardsInfo.length === 0 ? 0.5 : 1,\n }}\n >\n <Icon icon={icons.image} className=\"size-4\" />\n {isExporting ? 'Exporting...' : 'Export All Artboards'}\n </button>\n\n {showContinuousExport && (\n <button\n onClick={handleToggleContinuous}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n padding: 12,\n backgroundColor: isContinuousExporting ? 'var(--danger)' : 'var(--success)',\n color: isContinuousExporting ? 'var(--danger-foreground)' : 'var(--success-foreground)',\n border: 'none',\n borderRadius: 6,\n cursor: 'pointer',\n fontSize: 14,\n fontWeight: 500,\n }}\n >\n {isContinuousExporting ? <Icon icon={icons.pause} className=\"size-4\" /> : <Icon icon={icons.play} className=\"size-4\" />}\n {isContinuousExporting ? 'Stop Continuous Export' : 'Start Continuous Export'}\n </button>\n )}\n </div>\n\n {/* Export status */}\n {progress.length > 0 && (\n <div\n style={{\n padding: 12,\n backgroundColor: 'var(--bg-secondary)',\n borderRadius: 6,\n fontSize: 12,\n marginBottom: 16,\n }}\n >\n <div style={{ fontWeight: 600, marginBottom: 8 }}>Export Progress</div>\n {progress.slice(-3).map((p) => (\n <div\n key={p.artboardId}\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: 4,\n }}\n >\n <span>{p.artboardName}</span>\n <span style={{ color: p.status === 'complete' ? 'var(--success)' : 'var(--text-secondary)' }}>\n {p.status === 'complete' ? '✓' : p.status === 'error' ? '✗' : '...'}\n </span>\n </div>\n ))}\n </div>\n )}\n\n {/* Worker stats */}\n {supportsWorkerExport && (\n <div\n style={{\n padding: 12,\n backgroundColor: 'var(--bg-secondary)',\n borderRadius: 6,\n fontSize: 11,\n }}\n >\n <div style={{ fontWeight: 600, marginBottom: 4 }}>Worker Export Enabled ✓</div>\n <div style={{ opacity: 0.7 }}>\n Total Exports: {workerStats.totalExports}\n <br />\n Avg Time: {workerStats.avgExportTime.toFixed(0)}ms\n </div>\n </div>\n )}\n </div>\n );\n};\n","/**\n * Noun Project API Service\n *\n * Provides access to The Noun Project's icon/vector graphics API\n * API Documentation: https://api.thenounproject.com/documentation.html\n *\n * Authentication: OAuth 1.0\n * - API Key and Secret required (set via environment variables)\n * - VITE_NOUN_PROJECT_API_KEY\n * - VITE_NOUN_PROJECT_API_SECRET\n *\n * Note: For production, OAuth 1.0 authentication should be handled server-side\n * to protect the API secret. This client-side implementation is for development only.\n */\n\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger('nounProjectApi');\n\n// OAuth 1.0 Authentication Implementation\nclass OAuth1 {\n private apiKey: string;\n private apiSecret: string;\n\n constructor(apiKey: string, apiSecret: string) {\n this.apiKey = apiKey;\n this.apiSecret = apiSecret;\n }\n\n /**\n * Generate OAuth 1.0 signature for the request\n */\n private async generateSignature(\n method: string,\n url: string,\n params: Record<string, string>\n ): Promise<string> {\n // Combine all parameters (OAuth + query params)\n const allParams = { ...params };\n\n // Sort parameters alphabetically\n const sortedKeys = Object.keys(allParams).sort();\n const paramString = sortedKeys\n .map((key) => `${this.percentEncode(key)}=${this.percentEncode(allParams[key])}`)\n .join('&');\n\n // Create signature base string\n const signatureBase = [\n method.toUpperCase(),\n this.percentEncode(url),\n this.percentEncode(paramString),\n ].join('&');\n\n // Create signing key (consumer_secret&token_secret)\n // For 2-legged OAuth (no token), token_secret is empty\n const signingKey = `${this.percentEncode(this.apiSecret)}&`;\n\n // Sign using HMAC-SHA1\n const encoder = new TextEncoder();\n const keyData = encoder.encode(signingKey);\n const messageData = encoder.encode(signatureBase);\n\n const cryptoKey = await crypto.subtle.importKey(\n 'raw',\n keyData,\n { name: 'HMAC', hash: 'SHA-1' },\n false,\n ['sign']\n );\n\n const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);\n\n // Convert to base64\n return btoa(String.fromCharCode(...new Uint8Array(signature)));\n }\n\n /**\n * Percent-encode as per RFC 3986\n */\n private percentEncode(str: string): string {\n return encodeURIComponent(str).replace(/[!'()*]/g, (c) => {\n return '%' + c.charCodeAt(0).toString(16).toUpperCase();\n });\n }\n\n /**\n * Generate a random nonce\n */\n private generateNonce(): string {\n const array = new Uint8Array(16);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');\n }\n\n /**\n * Generate OAuth 1.0 authorization header\n */\n async generateAuthHeader(method: string, url: string, queryParams: Record<string, string> = {}): Promise<string> {\n const timestamp = Math.floor(Date.now() / 1000).toString();\n const nonce = this.generateNonce();\n\n const oauthParams: Record<string, string> = {\n oauth_consumer_key: this.apiKey,\n oauth_nonce: nonce,\n oauth_signature_method: 'HMAC-SHA1',\n oauth_timestamp: timestamp,\n oauth_version: '1.0',\n };\n\n // Generate signature\n const signature = await this.generateSignature(method, url, {\n ...oauthParams,\n ...queryParams,\n });\n\n oauthParams.oauth_signature = signature;\n\n // Build Authorization header\n const headerParams = Object.keys(oauthParams)\n .sort()\n .map((key) => `${this.percentEncode(key)}=\"${this.percentEncode(oauthParams[key])}\"`)\n .join(', ');\n\n return `OAuth ${headerParams}`;\n }\n}\n\n// Vector/Icon result from Noun Project API\nexport interface NounProjectIcon {\n id: string;\n term: string;\n thumbnail_url: string; // PNG thumbnail\n permalink: string;\n attribution: string;\n license_description: string;\n creator: {\n name: string;\n username: string;\n permalink: string;\n };\n collections?: Array<{ id: string; name: string }>;\n tags?: string[];\n styles?: Array<{ id: string; name: string }>;\n // Additional URLs (when include_svg=1 is passed, icon_url contains SVG URL)\n icon_url?: string; // SVG URL when include_svg=1, otherwise PNG URL\n preview_url?: string;\n preview_url_42?: string;\n preview_url_84?: string;\n preview_url_200?: string;\n}\n\n// Normalized vector result (similar to ImageResult)\nexport interface VectorResult {\n id: string;\n urls: {\n svg?: string; // SVG URL or data URL\n png: string; // PNG preview\n preview: string; // Small preview\n thumbnail: string; // Smallest preview\n };\n term: string; // Search term/name\n attribution: string | null;\n uploader: {\n name: string;\n username: string;\n };\n source: 'noun-project';\n}\n\n// API Response from Noun Project\ninterface NounProjectSearchResponse {\n icons: NounProjectIcon[];\n generated_at?: string;\n next_page?: string; // Pagination token\n}\n\n// Use proxy server for development (avoids CORS issues)\n// In production, you should use a proper backend API or serverless function\nconst USE_PROXY = true;\nconst PROXY_URL = import.meta.env?.VITE_NOUN_PROJECT_PROXY_URL || 'http://localhost:3001';\nconst API_BASE_URL = USE_PROXY ? PROXY_URL : 'https://api.thenounproject.com/v2';\n\n// API credentials (from environment variables)\nconst NOUN_PROJECT_API_KEY = import.meta.env?.VITE_NOUN_PROJECT_API_KEY || '';\nconst NOUN_PROJECT_API_SECRET = import.meta.env?.VITE_NOUN_PROJECT_API_SECRET || '';\n\n/**\n * Check if API keys are configured\n * When using proxy, we assume the proxy has the keys configured\n */\nexport const isNounProjectConfigured = (): boolean => {\n if (USE_PROXY) {\n // Assume proxy is configured (it will return error if not)\n return true;\n }\n return NOUN_PROJECT_API_KEY !== '' && NOUN_PROJECT_API_SECRET !== '';\n};\n\n/**\n * Map Noun Project icon to VectorResult format\n */\nconst mapNounProjectToVectorResult = (icon: NounProjectIcon): VectorResult => {\n // If icon_url is present and contains .svg (even with query params), use it directly\n // Free tier users: Only public domain icons will have icon_url with .svg\n // Restricted icons: Don't have SVG access, so we only provide PNG\n const hasSvgUrl = icon.icon_url?.includes('.svg');\n const svgUrl = hasSvgUrl ? icon.icon_url : undefined;\n\n return {\n id: `noun-${icon.id}`,\n urls: {\n svg: svgUrl, // Only set if API provided direct SVG URL (public domain or paid access)\n png: icon.icon_url && !hasSvgUrl ? icon.icon_url : icon.thumbnail_url,\n preview: icon.preview_url_200 || icon.preview_url_84 || icon.thumbnail_url,\n thumbnail: icon.thumbnail_url,\n },\n term: icon.term,\n attribution: icon.attribution || null,\n uploader: {\n name: icon.creator?.name || 'Unknown',\n username: icon.creator?.username || 'unknown',\n },\n source: 'noun-project',\n };\n};\n\n/**\n * Search for icons/vectors\n */\nexport const searchIcons = async (\n query: string,\n options: {\n limit?: number;\n includeSvg?: boolean;\n limitToPublicDomain?: boolean;\n nextPage?: string;\n } = {}\n): Promise<{ results: VectorResult[]; nextPage: string | null }> => {\n if (!isNounProjectConfigured()) {\n throw new Error('Noun Project API keys not configured');\n }\n\n const { limit = 30, includeSvg = true, limitToPublicDomain = true, nextPage } = options;\n\n // Build query parameters\n const params: Record<string, string> = {\n query,\n limit: limit.toString(),\n };\n\n if (includeSvg) {\n params.include_svg = '1';\n }\n\n // Free API tier only has SVG access to public domain icons\n if (limitToPublicDomain) {\n params.limit_to_public_domain = '1';\n }\n\n if (nextPage) {\n params.next_page = nextPage;\n }\n\n // Build URL\n const url = `${API_BASE_URL}/v2/icon`;\n const queryString = Object.keys(params)\n .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)\n .join('&');\n\n const fullUrl = `${url}?${queryString}`;\n\n // Make request\n let response: Response;\n\n if (USE_PROXY) {\n // When using proxy, no need for OAuth headers (proxy handles authentication)\n response = await fetch(fullUrl, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n });\n } else {\n // Direct API call with OAuth (for production with serverless functions)\n // Note: For direct calls, we need to use the base URL without /v2 in the signature\n const directUrl = 'https://api.thenounproject.com/v2/icon';\n const oauth = new OAuth1(NOUN_PROJECT_API_KEY, NOUN_PROJECT_API_SECRET);\n const authHeader = await oauth.generateAuthHeader('GET', directUrl, params);\n\n response = await fetch(fullUrl, {\n method: 'GET',\n headers: {\n Authorization: authHeader,\n Accept: 'application/json',\n },\n });\n }\n\n if (!response.ok) {\n const errorText = await response.text();\n logger.error('Noun Project API error:', errorText);\n throw new Error(`Failed to search icons: ${response.status} ${response.statusText}`);\n }\n\n const data: NounProjectSearchResponse = await response.json();\n\n return {\n results: data.icons.map(mapNounProjectToVectorResult),\n nextPage: data.next_page || null,\n };\n};\n\n/**\n * Get popular/featured icons\n */\nexport const getFeaturedIcons = async (options: {\n limit?: number;\n includeSvg?: boolean;\n}): Promise<VectorResult[]> => {\n // Use a generic search term to get popular icons\n const featuredTerms = ['design', 'business', 'technology', 'nature', 'food'];\n const randomTerm = featuredTerms[Math.floor(Math.random() * featuredTerms.length)];\n\n const { results } = await searchIcons(randomTerm, options);\n return results;\n};\n\n/**\n * Get SVG download URL for a specific icon\n * Uses the /v2/icon/{id}/download endpoint\n *\n * @param iconId - The icon ID (without 'noun-' prefix)\n * @param color - Optional hex color (without #)\n * @returns Download URL for the SVG file\n */\nexport const getIconSvgUrl = (iconId: string, color?: string): string => {\n // Remove 'noun-' prefix if present\n const cleanId = iconId.replace(/^noun-/, '');\n\n const baseUrl = `${API_BASE_URL}/v2/icon/${cleanId}/download`;\n const params = new URLSearchParams({\n filetype: 'svg',\n // Noun Project API requires a color parameter for downloads (default to black)\n color: color ? color.replace('#', '') : '000000',\n });\n\n return `${baseUrl}?${params.toString()}`;\n};\n","/**\n * Recraft V3 API Service\n *\n * Provides AI-powered image generation capabilities using Recraft's API.\n * Supports both photo-realistic and vector (SVG) digital illustration styles.\n *\n * API Documentation: https://www.recraft.ai/docs/api-reference/getting-started\n *\n * Environment Variable:\n * - VITE_RECRAFT_API_TOKEN - Get from https://www.recraft.ai/\n */\n\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger('recraftApi');\n\ninterface RecraftGenerationRequest {\n prompt: string;\n style: string; // Can be 'realistic_image', 'digital_illustration', or a custom style ID\n model?: 'recraftv3';\n size?: '1024x1024' | '1365x1024' | '1024x1365' | '1536x1024' | '1024x1536' | '1820x1024' | '1024x1820' | '1024x2048' | '2048x1024' | '1434x1024' | '1024x1434' | '1024x1280' | '1280x1024' | '1024x1707' | '1707x1024';\n n?: number; // Number of images (1-2)\n}\n\ninterface RecraftImageData {\n url: string;\n b64_json?: string;\n}\n\ninterface RecraftGenerationResponse {\n data: RecraftImageData[];\n created: number;\n id: string;\n}\n\nexport interface RecraftResult {\n id: string;\n url: string;\n prompt: string;\n style: string;\n format: 'png' | 'svg';\n created: number;\n}\n\n// =============================================================================\n// COMMENTED OUT: Previous implementation with custom style IDs\n// =============================================================================\n// export interface RecraftStyle {\n// id: string;\n// name: string;\n// thumbnail: string;\n// format: 'svg' | 'png';\n// }\n// export const VECTOR_ILLUSTRATION_STYLES: RecraftStyle[] = [\n// { id: '3da159ea-7b83-4fe5-81bb-6a8defa61815', name: 'Cozy Noir-Blue', ... },\n// ...\n// ];\n// =============================================================================\n\n/**\n * Recraft V3 Styles and Substyles\n * Based on official API documentation\n */\n\nexport type RecraftStyleType = 'realistic_image' | 'digital_illustration' | 'vector_illustration';\n\nexport interface RecraftStyleOption {\n value: RecraftStyleType;\n label: string;\n substyles: string[];\n}\n\n/**\n * Available styles with their substyles (Recraft V3 only)\n */\nexport const RECRAFT_STYLES: RecraftStyleOption[] = [\n {\n value: 'realistic_image',\n label: 'Realistic Image',\n substyles: [\n 'b_and_w',\n 'enterprise',\n 'evening_light',\n 'faded_nostalgia',\n 'forest_life',\n 'hard_flash',\n 'hdr',\n 'motion_blur',\n 'mystic_naturalism',\n 'natural_light',\n 'natural_tones',\n 'organic_calm',\n 'real_life_glow',\n 'retro_realism',\n 'retro_snapshot',\n 'studio_portrait',\n 'urban_drama',\n 'village_realism',\n 'warm_folk',\n ],\n },\n {\n value: 'digital_illustration',\n label: 'Digital Illustration',\n substyles: [\n '2d_art_poster',\n '2d_art_poster_2',\n 'antiquarian',\n 'bold_fantasy',\n 'child_book',\n 'cover',\n 'crosshatch',\n 'digital_engraving',\n 'engraving_color',\n 'expressionism',\n 'freehand_details',\n 'grain',\n 'grain_20',\n 'graphic_intensity',\n 'hand_drawn',\n 'hand_drawn_outline',\n 'handmade_3d',\n 'hard_comics',\n 'infantile_sketch',\n 'long_shadow',\n 'modern_folk',\n 'multicolor',\n 'neon_calm',\n 'noir',\n 'nostalgic_pastel',\n 'outline_details',\n 'pastel_gradient',\n 'pastel_sketch',\n 'pixel_art',\n 'plastic',\n 'pop_art',\n 'pop_renaissance',\n 'seamless',\n 'street_art',\n 'tablet_sketch',\n 'urban_glow',\n 'urban_sketching',\n 'young_adult_book',\n 'young_adult_book_2',\n ],\n },\n {\n value: 'vector_illustration',\n label: 'Vector Illustration',\n substyles: [\n 'bold_stroke',\n 'chemistry',\n 'colored_stencil',\n 'cosmics',\n 'cutout',\n 'depressive',\n 'editorial',\n 'emotional_flat',\n 'engraving',\n 'line_art',\n 'line_circuit',\n 'linocut',\n 'marker_outline',\n 'mosaic',\n 'naivector',\n 'roundish_flat',\n 'seamless',\n 'segmented_colors',\n 'sharp_contrast',\n 'thin',\n 'vector_photo',\n 'vivid_shapes',\n ],\n },\n];\n\nconst RECRAFT_API_BASE = 'https://external.api.recraft.ai/v1';\n\n/**\n * Check if Recraft API is configured\n */\nexport function isRecraftConfigured(): boolean {\n const token = import.meta.env?.VITE_RECRAFT_API_TOKEN || '';\n return token !== '' && token !== 'YOUR_API_TOKEN_HERE';\n}\n\n/**\n * Generate an image using Recraft V3 API\n *\n * @param prompt - Text description of the image to generate\n * @param style - Style type ('realistic_image', 'digital_illustration', 'vector_illustration')\n * @param substyle - Optional substyle name for the selected style\n * @param options - Additional generation options (size, n)\n * @returns Promise resolving to generated image result\n */\nexport async function generateImage(\n prompt: string,\n style: RecraftStyleType,\n substyle?: string,\n options: { size?: RecraftGenerationRequest['size']; n?: number } = {}\n): Promise<RecraftResult> {\n if (!isRecraftConfigured()) {\n throw new Error('Recraft API token not configured. Set VITE_RECRAFT_API_TOKEN in your .env file.');\n }\n\n const token = import.meta.env.VITE_RECRAFT_API_TOKEN;\n\n const requestBody: RecraftGenerationRequest & { substyle?: string } = {\n prompt: prompt.trim(),\n style,\n model: 'recraftv3',\n };\n\n // Add substyle if provided\n if (substyle) {\n requestBody.substyle = substyle;\n }\n\n // Add optional parameters\n if (options.size) {\n requestBody.size = options.size;\n }\n if (options.n) {\n requestBody.n = options.n;\n }\n\n try {\n const response = await fetch(`${RECRAFT_API_BASE}/images/generations`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Recraft API error (${response.status}): ${errorText}`);\n }\n\n const data: RecraftGenerationResponse = await response.json();\n\n if (!data.data || data.data.length === 0) {\n throw new Error('No images returned from Recraft API');\n }\n\n const imageData = data.data[0];\n\n // Determine format based on style\n // vector_illustration and digital_illustration return SVG, realistic_image returns PNG\n const format = style === 'vector_illustration' || style === 'digital_illustration' ? 'svg' : 'png';\n\n return {\n id: data.id,\n url: imageData.url,\n prompt,\n style,\n format,\n created: data.created,\n };\n } catch (err) {\n logger.error('Error generating image with Recraft:', err);\n throw err;\n }\n}\n\n/**\n * Download image data from Recraft URL\n *\n * @param url - Image URL from Recraft API\n * @returns Promise resolving to data URL (for SVG) or blob URL (for PNG)\n */\nexport async function downloadRecraftImage(url: string): Promise<string> {\n try {\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to download image: ${response.status}`);\n }\n\n const contentType = response.headers.get('content-type') || '';\n\n if (contentType.includes('svg')) {\n // SVG - convert to data URL\n const text = await response.text();\n return `data:image/svg+xml;base64,${btoa(text)}`;\n } else {\n // PNG or other - convert to blob URL\n const blob = await response.blob();\n return URL.createObjectURL(blob);\n }\n } catch (err) {\n logger.error('Error downloading Recraft image:', err);\n throw err;\n }\n}\n","/**\n * fal.ai API Service - Background Removal\n *\n * Uses the fal.ai/bria/background/remove API (Bria RMBG 2.0) to remove backgrounds from images.\n * This model is trained exclusively on licensed data for commercial use.\n *\n * API Key: Set VITE_FAL_API_KEY in your .env file\n * Get your API key from: https://fal.ai/dashboard/keys\n *\n * Documentation: https://fal.ai/models/fal-ai/bria/background/remove/api\n */\n\nconst FAL_API_KEY = import.meta.env?.VITE_FAL_API_KEY || '';\n\nexport interface RemoveBackgroundRequest {\n image_url: string;\n sync_mode?: boolean;\n}\n\nexport interface RemoveBackgroundResponse {\n image: {\n url: string;\n content_type: string;\n file_name: string;\n file_size: number;\n width: number;\n height: number;\n };\n}\n\n/**\n * Check if fal.ai API is configured\n */\nexport function isFalConfigured(): boolean {\n return FAL_API_KEY !== '' && FAL_API_KEY !== 'YOUR_FAL_KEY_HERE';\n}\n\n/**\n * Remove background from an image using fal.ai Bria RMBG 2.0 API\n * This model is trained on licensed data and suitable for commercial use.\n *\n * @param imageUrl - URL of the image to process\n * @param options - Optional parameters (sync_mode)\n * @returns Promise with the processed image data\n */\nexport async function removeBackground(\n imageUrl: string,\n options: { syncMode?: boolean } = {}\n): Promise<RemoveBackgroundResponse> {\n if (!isFalConfigured()) {\n throw new Error('fal.ai API key not configured. Set VITE_FAL_API_KEY in your .env file.');\n }\n\n const requestBody: RemoveBackgroundRequest = {\n image_url: imageUrl,\n sync_mode: options.syncMode ?? false,\n };\n\n try {\n const response = await fetch('https://fal.run/fal-ai/bria/background/remove', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Key ${FAL_API_KEY}`,\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`fal.ai API error (${response.status}): ${errorText}`);\n }\n\n const data: RemoveBackgroundResponse = await response.json();\n\n // Validate response structure\n if (!data.image || !data.image.url) {\n throw new Error('Invalid response from fal.ai API');\n }\n\n return data;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error('Failed to remove background');\n }\n}\n\n/**\n * Convert the fal.ai response image to a data URL\n * Useful for immediate preview without external dependencies\n *\n * @param imageUrl - URL from fal.ai response\n * @returns Promise with data URL\n */\nexport async function convertToDataUrl(imageUrl: string): Promise<string> {\n const response = await fetch(imageUrl);\n const blob = await response.blob();\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n}\n\n/**\n * Check if a URL or data URL points to an SVG image\n *\n * @param url - Image URL or data URL\n * @returns true if the image is SVG\n */\nexport function isSvgImage(url: string): boolean {\n // Check data URL\n if (url.startsWith('data:')) {\n return url.startsWith('data:image/svg+xml');\n }\n\n // Check file extension\n const urlLower = url.toLowerCase();\n return urlLower.endsWith('.svg') || urlLower.includes('.svg?') || urlLower.includes('.svg#');\n}\n\n/**\n * Convert an SVG image to PNG using canvas\n *\n * @param svgUrl - URL or data URL of the SVG image\n * @param maxWidth - Maximum width for the output PNG (default: 2048)\n * @returns Promise with PNG data URL\n */\nexport async function convertSvgToPng(svgUrl: string, maxWidth: number = 2048): Promise<string> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n\n img.onload = () => {\n try {\n // Calculate dimensions while maintaining aspect ratio\n let width = img.width || img.naturalWidth;\n let height = img.height || img.naturalHeight;\n\n // Default to reasonable size if dimensions are not available\n if (width === 0 || height === 0) {\n width = 1024;\n height = 1024;\n }\n\n // Scale down if needed\n if (width > maxWidth) {\n const scale = maxWidth / width;\n width = maxWidth;\n height = height * scale;\n }\n\n // Create canvas and draw image\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n reject(new Error('Failed to get canvas context'));\n return;\n }\n\n // Fill with transparent background\n ctx.clearRect(0, 0, width, height);\n\n // Draw the SVG image\n ctx.drawImage(img, 0, 0, width, height);\n\n // Convert to PNG data URL\n const pngDataUrl = canvas.toDataURL('image/png');\n resolve(pngDataUrl);\n } catch (error) {\n reject(error);\n }\n };\n\n img.onerror = () => {\n reject(new Error('Failed to load SVG image'));\n };\n\n img.src = svgUrl;\n });\n}\n","/**\n * Runware API Service - AI Image Generation\n *\n * Uses the Runware AI SDK for high-performance image generation via WebSocket.\n *\n * API Key: Set VITE_RUNWARE_API_KEY in your .env file\n * Get your API key from: https://runware.ai/\n *\n * Documentation: https://runware.ai/docs/en/libraries/javascript\n * SDK: @runware/sdk-js\n */\n\nimport { Runware } from '@runware/sdk-js';\nimport type { IRequestImage, ITextToImage } from '@runware/sdk-js';\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger('runwareApi');\n\nconst RUNWARE_API_KEY = import.meta.env?.VITE_RUNWARE_API_KEY || '';\n\n// Available models for image generation\n// Based on Runware documentation: https://runware.ai/docs/en/providers/google\nexport const RUNWARE_MODELS = [\n {\n id: 'runware:101@1',\n name: 'Flux Dev',\n description: 'High-quality generation with excellent detail and composition',\n supportsSteps: true,\n supportsCFGScale: true,\n supportsNegativePrompt: true,\n },\n {\n id: 'google:4@2',\n name: 'Nano Banana 2 Pro',\n description: 'Advanced Google model for controlled visual creation',\n supportsSteps: false, // Not mentioned in Google model spec\n supportsCFGScale: false, // Not mentioned in Google model spec\n supportsNegativePrompt: false, // Not mentioned in Nano Banana 2 Pro spec (supported by other Google models)\n },\n] as const;\n\nexport type RunwareModelId = (typeof RUNWARE_MODELS)[number]['id'];\n\nexport interface GenerateImageRequest {\n prompt: string;\n model: RunwareModelId;\n width?: number;\n height?: number;\n steps?: number;\n cfgScale?: number;\n negativePrompt?: string;\n}\n\nexport interface GeneratedImage {\n imageURL: string;\n imageUUID: string;\n width: number;\n height: number;\n}\n\nexport interface GenerateImageResponse {\n images: GeneratedImage[];\n taskUUID: string;\n}\n\nlet runwareInstance: InstanceType<typeof Runware> | null = null;\n\n/**\n * Check if Runware API is configured\n */\nexport function isRunwareConfigured(): boolean {\n return RUNWARE_API_KEY !== '' && RUNWARE_API_KEY !== 'YOUR_RUNWARE_KEY_HERE';\n}\n\n/**\n * Get or create Runware SDK instance\n * The SDK maintains a persistent WebSocket connection for better performance\n */\nasync function getRunwareInstance(): Promise<InstanceType<typeof Runware>> {\n if (!runwareInstance) {\n if (!isRunwareConfigured()) {\n throw new Error('Runware API key not configured. Set VITE_RUNWARE_API_KEY in your .env file.');\n }\n // Use initialize() to ensure connection is established before returning\n runwareInstance = await Runware.initialize({\n apiKey: RUNWARE_API_KEY,\n timeoutDuration: 60000, // 60 seconds timeout\n });\n }\n return runwareInstance;\n}\n\n/**\n * Generate images using Runware AI\n *\n * @param request - Image generation parameters\n * @returns Promise with generated images\n */\nexport async function generateImages(request: GenerateImageRequest): Promise<GenerateImageResponse> {\n if (!isRunwareConfigured()) {\n throw new Error('Runware API key not configured. Set VITE_RUNWARE_API_KEY in your .env file.');\n }\n\n try {\n const runware = await getRunwareInstance();\n\n // Check model capabilities\n const modelConfig = RUNWARE_MODELS.find((m) => m.id === request.model);\n const supportsSteps = modelConfig?.supportsSteps ?? true; // Default to true for unknown models\n const supportsCFGScale = modelConfig?.supportsCFGScale ?? true; // Default to true for unknown models\n const supportsNegativePrompt = modelConfig?.supportsNegativePrompt ?? true; // Default to true for unknown models\n\n\n // Build request parameters conditionally based on model capabilities\n const requestParams: IRequestImage = {\n positivePrompt: request.prompt,\n model: request.model,\n width: request.width || 1024,\n height: request.height || 1024,\n numberResults: 1,\n outputFormat: 'PNG', // Image format (PNG/JPG/WEBP) - API returns URLs by default\n };\n\n // Only include 'steps' if the model supports it\n if (supportsSteps) {\n requestParams.steps = request.steps || 25;\n }\n\n // Only include 'CFGScale' if the model supports it\n if (supportsCFGScale) {\n requestParams.CFGScale = request.cfgScale || 7.0;\n }\n\n // Only include 'negativePrompt' if the model supports it and one was provided\n if (supportsNegativePrompt && request.negativePrompt) {\n requestParams.negativePrompt = request.negativePrompt;\n }\n\n // Call Runware SDK\n const images = await runware.requestImages(requestParams);\n\n if (!images || images.length === 0) {\n throw new Error('No images generated from Runware API');\n }\n\n // Map Runware response to our format\n return {\n images: images.map((img: ITextToImage) => ({\n imageURL: img.imageURL || '',\n imageUUID: img.imageUUID || '',\n width: request.width || 1024,\n height: request.height || 1024,\n })),\n taskUUID: images[0]?.taskUUID || '',\n };\n } catch (error) {\n logger.error('Runware API error:', error);\n if (error instanceof Error) {\n throw new Error(`Runware API error: ${error.message}`);\n }\n throw new Error('Failed to generate image with Runware');\n }\n}\n\n/**\n * Convert image URL to data URL for immediate use\n *\n * @param imageUrl - URL from Runware response\n * @returns Promise with data URL\n */\nexport async function convertImageToDataUrl(imageUrl: string): Promise<string> {\n const response = await fetch(imageUrl);\n const blob = await response.blob();\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(blob);\n });\n}\n\n/**\n * Disconnect the Runware SDK instance\n * Call this when the app is closing or you want to clean up the connection\n */\nexport async function disconnectRunware(): Promise<void> {\n if (runwareInstance) {\n try {\n await runwareInstance.disconnect();\n runwareInstance = null;\n } catch (error) {\n logger.error('Error disconnecting Runware:', error);\n }\n }\n}\n","/**\n * ImageBrowserDrawer - Drawer for browsing and selecting images\n *\n * Features:\n * - Dual-source image search: Fetches from both Unsplash and Pixabay APIs in parallel\n * - Seamless integration: Results are interleaved so users don't realize we're using multiple sources\n * - Graceful fallback: Works with 0, 1, or 2 API keys configured\n * - Custom URL/upload: Supports uploading images from computer or pasting URLs\n *\n * API Keys (optional, set via environment variables):\n * - VITE_UNSPLASH_ACCESS_KEY - Get from https://unsplash.com/developers\n * - VITE_PIXABAY_API_KEY - Get from https://pixabay.com/api/docs/\n *\n * Image Quality:\n * - Unsplash: 'regular' size (~1080px width)\n * - Pixabay: 'largeImageURL' size (~1280px width)\n */\n\nimport React, { useEffect, useState, useRef, useCallback } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Tabs, TextField, Label, Input, TextArea, Button, icons, SparklesIcon } from './ui';\nimport { Drawer } from './Drawer';\nimport { searchIcons, getFeaturedIcons, VectorResult, isNounProjectConfigured } from '../services/nounProjectApi';\nimport {\n generateImage,\n downloadRecraftImage,\n isRecraftConfigured,\n RecraftResult,\n RECRAFT_STYLES,\n RecraftStyleType,\n} from '../services/recraftApi';\nimport { removeBackground, convertToDataUrl, isFalConfigured, isSvgImage, convertSvgToPng } from '../services/falApi';\nimport {\n generateImages,\n convertImageToDataUrl,\n isRunwareConfigured,\n RUNWARE_MODELS,\n RunwareModelId,\n} from '../services/runwareApi';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('ImageBrowser');\n\n// Source-agnostic image result (can be from Unsplash, Pixabay, etc.)\ninterface ImageResult {\n id: string;\n urls: {\n raw: string;\n full: string;\n regular: string;\n small: string;\n thumb: string;\n };\n alt_description: string | null;\n user: {\n name: string;\n username: string;\n };\n width: number;\n height: number;\n source: 'unsplash' | 'pixabay'; // Track image source\n}\n\n// Pixabay API response types\ninterface PixabayImage {\n id: number;\n pageURL: string;\n type: string;\n tags: string;\n previewURL: string;\n previewWidth: number;\n previewHeight: number;\n webformatURL: string;\n webformatWidth: number;\n webformatHeight: number;\n largeImageURL: string;\n imageWidth: number;\n imageHeight: number;\n imageSize: number;\n views: number;\n downloads: number;\n likes: number;\n comments: number;\n user_id: number;\n user: string;\n userImageURL: string;\n}\n\n// Unsplash API response types\ninterface UnsplashImage {\n id: string;\n urls: {\n raw: string;\n full: string;\n regular: string;\n small: string;\n thumb: string;\n };\n alt_description: string | null;\n user: {\n name: string;\n username: string;\n };\n width: number;\n height: number;\n}\n\ninterface ImageBrowserPanelProps {\n isOpen: boolean;\n onToggle: (open: boolean) => void;\n onImageSelect: (imageUrl: string) => void;\n currentImageUrl?: string;\n /** Placement of drawer - defaults to 'bottom' */\n placement?: 'bottom' | 'left' | 'right';\n}\n\ninterface ImageCardProps {\n image: ImageResult;\n onImageSelect: (image: ImageResult) => void;\n fixedHeight?: boolean; // For grid mode with fixed height\n}\n\n// Grid layout constants\nconst MASONRY_GAP = '1px'; // Gap in pixels between images (Pinterest-style)\nconst GRID_GAP = '1px'; // Gap for fixed-height grid mode\n\nconst ImageCard = React.memo(function ImageCard({ image, onImageSelect, fixedHeight = false }: ImageCardProps) {\n const [isHovered, setIsHovered] = useState(false);\n const [showInfo, setShowInfo] = useState(false);\n const [direction, setDirection] = useState<'top' | 'bottom' | 'left' | 'right'>('top');\n const openTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const cardRef = useRef<HTMLDivElement>(null);\n const isFirstRender = useRef(true);\n const [noTransition, setNoTransition] = useState(false);\n const enterFrameRef = useRef<number | null>(null);\n\n const handleImageClick = () => {\n if (!showInfo) {\n onImageSelect(image);\n }\n };\n\n const getDirection = (e: React.MouseEvent<HTMLDivElement>) => {\n if (!cardRef.current) return 'top';\n\n const rect = cardRef.current.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n const width = rect.width;\n const height = rect.height;\n\n // Calculate which edge is closest\n const directions = {\n top: y,\n bottom: height - y,\n left: x,\n right: width - x,\n };\n\n const min = Math.min(directions.top, directions.bottom, directions.left, directions.right);\n\n if (min === directions.top) return 'top';\n if (min === directions.bottom) return 'bottom';\n if (min === directions.left) return 'left';\n return 'right';\n };\n\n const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {\n const newDirection = getDirection(e);\n\n // Cancel any pending enter logic\n if (enterFrameRef.current) {\n cancelAnimationFrame(enterFrameRef.current);\n enterFrameRef.current = null;\n }\n\n if (newDirection !== direction) {\n // Temporarily disable transition to snap to new start position\n setNoTransition(true);\n setDirection(newDirection);\n\n // Wait for next frame(s) to ensure DOM update before animating\n enterFrameRef.current = requestAnimationFrame(() => {\n enterFrameRef.current = requestAnimationFrame(() => {\n setNoTransition(false);\n setIsHovered(true);\n enterFrameRef.current = null;\n });\n });\n } else {\n setDirection(newDirection);\n setIsHovered(true);\n }\n\n isFirstRender.current = false;\n };\n\n const handleMouseLeave = (e: React.MouseEvent<HTMLDivElement>) => {\n if (enterFrameRef.current) {\n cancelAnimationFrame(enterFrameRef.current);\n enterFrameRef.current = null;\n }\n\n const newDirection = getDirection(e);\n setDirection(newDirection);\n\n // Ensure transition is re-enabled if we cancelled mid-setup\n setNoTransition(false);\n setIsHovered(false);\n };\n\n const handleIconMouseEnter = () => {\n // Clear any pending close timeout\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current);\n closeTimeoutRef.current = null;\n }\n // Wait 400ms before showing info\n openTimeoutRef.current = setTimeout(() => {\n setShowInfo(true);\n }, 400);\n };\n\n const handleIconMouseLeave = () => {\n // Cancel pending open\n if (openTimeoutRef.current) {\n clearTimeout(openTimeoutRef.current);\n openTimeoutRef.current = null;\n }\n // Hide immediately\n setShowInfo(false);\n };\n\n const handleInfoMouseEnter = () => {\n // Cancel pending open\n if (openTimeoutRef.current) {\n clearTimeout(openTimeoutRef.current);\n openTimeoutRef.current = null;\n }\n // Cancel any close timeout\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current);\n closeTimeoutRef.current = null;\n }\n };\n\n const handleInfoMouseLeave = () => {\n // Close immediately when leaving info area\n setShowInfo(false);\n };\n\n const sourceName = image.source === 'unsplash' ? 'Unsplash' : 'Pixabay';\n\n // Keep button visible while info is shown\n const showButton = isHovered || showInfo;\n\n // Calculate image pan based on direction\n const getImageTransform = () => {\n const scale = 1.12; // Zoomed in\n const move = 5; // % to pan (relative to image size) - reduced for subtlety\n\n // When not hovered (or resetting), just show zoomed center\n if (!isHovered) return `scale(${scale})`;\n\n // Pan in the direction of entry (creates a parallax-like follow effect)\n // using percentages ensures we stay within bounds regardless of image size\n switch (direction) {\n case 'top':\n return `scale(${scale}) translateY(${move}%)`;\n case 'bottom':\n return `scale(${scale}) translateY(-${move}%)`;\n case 'left':\n return `scale(${scale}) translateX(${move}%)`;\n case 'right':\n return `scale(${scale}) translateX(-${move}%)`;\n default:\n return `scale(${scale})`;\n }\n };\n\n return (\n <div\n ref={cardRef}\n onClick={handleImageClick}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n className={`group relative cursor-pointer overflow-hidden ${\n fixedHeight ? 'h-full rounded-xs' : 'break-inside-avoid rounded-lg'\n }`}\n >\n {/* Image */}\n <img\n src={image.urls.small}\n alt={image.alt_description || 'Image'}\n className={`duration-500 ease-out ${\n noTransition ? 'transition-none' : 'transition-transform'\n } ${fixedHeight ? 'h-full w-full object-cover' : 'w-full object-cover'}`}\n style={{\n transform: getImageTransform(),\n filter: isHovered ? 'brightness(1)' : 'brightness(0.95)',\n }}\n />\n\n {/* Info button in top-right corner */}\n <div className=\"absolute top-2 right-2 z-10\">\n <button\n className={`relative flex h-6 w-6 items-center justify-center rounded-full bg-black/30 backdrop-blur-sm transition-all duration-300 ease-in-out hover:scale-110 ${\n showButton ? 'opacity-100' : 'pointer-events-none opacity-0'\n }`}\n aria-label=\"Image info\"\n onMouseEnter={handleIconMouseEnter}\n onMouseLeave={handleIconMouseLeave}\n >\n <Icon icon=\"lucide:aperture\" className=\"size-4 text-white/80\" />\n </button>\n </div>\n\n {/* Info overlay at bottom with scrim */}\n <div\n className={`absolute inset-x-0 bottom-0 z-0 bg-linear-to-t from-black/80 via-black/60 to-transparent px-3 py-3 pt-8 transition-transform duration-300 ease-out ${\n showInfo ? 'translate-y-0' : 'translate-y-full'\n }`}\n onMouseEnter={handleInfoMouseEnter}\n onMouseLeave={handleInfoMouseLeave}\n >\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-2\">\n <Icon\n icon={image.source === 'unsplash' ? 'simple-icons:unsplash' : 'simple-icons:pixabay'}\n className=\"size-3 text-white/80\"\n />\n <span className=\"text-xs font-medium text-white/80\">{sourceName}</span>\n </div>\n <div className=\"flex flex-col gap-0.5\">\n <span className=\"text-xs text-white/60\">Photo by</span>\n <span className=\"text-sm font-medium text-white\">{image.user.name}</span>\n </div>\n </div>\n </div>\n </div>\n );\n});\n\n// Vector Card Component (for Noun Project icons)\ninterface VectorCardProps {\n vector: VectorResult;\n onVectorSelect: (vector: VectorResult) => void;\n fixedHeight?: boolean; // For grid mode with fixed height\n}\n\nconst VectorCard = React.memo(function VectorCard({ vector, onVectorSelect, fixedHeight = false }: VectorCardProps) {\n const [isHovered, setIsHovered] = useState(false);\n const [showInfo, setShowInfo] = useState(false);\n const openTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n const handleVectorClick = () => {\n if (!showInfo) {\n onVectorSelect(vector);\n }\n };\n\n const handleIconMouseEnter = () => {\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current);\n closeTimeoutRef.current = null;\n }\n openTimeoutRef.current = setTimeout(() => {\n setShowInfo(true);\n }, 400);\n };\n\n const handleIconMouseLeave = () => {\n if (openTimeoutRef.current) {\n clearTimeout(openTimeoutRef.current);\n openTimeoutRef.current = null;\n }\n setShowInfo(false);\n };\n\n const handleInfoMouseEnter = () => {\n if (openTimeoutRef.current) {\n clearTimeout(openTimeoutRef.current);\n openTimeoutRef.current = null;\n }\n if (closeTimeoutRef.current) {\n clearTimeout(closeTimeoutRef.current);\n closeTimeoutRef.current = null;\n }\n };\n\n const handleInfoMouseLeave = () => {\n setShowInfo(false);\n };\n\n const showButton = isHovered || showInfo;\n\n return (\n <div\n onClick={handleVectorClick}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n className={`group relative cursor-pointer overflow-hidden bg-white/10 transition-all duration-300 ${\n fixedHeight ? 'h-full rounded-xs' : 'break-inside-avoid rounded-lg'\n } ${isHovered ? 'scale-105 bg-white/20' : ''}`}\n >\n {/* Vector Icon - centered with padding */}\n <div\n className={`flex items-center justify-center p-6 transition-all duration-300 ${\n fixedHeight ? 'h-full w-full' : 'aspect-square w-full'\n }`}\n >\n <img\n src={vector.urls.preview}\n alt={vector.term}\n className={`max-h-full max-w-full object-contain transition-all duration-300 ${\n isHovered ? 'scale-110' : 'scale-100'\n }`}\n style={{\n filter: isHovered ? 'brightness(1.1)' : 'brightness(0.95)',\n }}\n />\n </div>\n\n {/* PNG badge and Info button in top-right corner */}\n <div className=\"absolute top-2 right-2 z-10 flex items-center gap-2\">\n {/* PNG format badge - shows on image hover */}\n {!vector.urls.svg && (\n <span\n className={`rounded-xs bg-amber-500/90 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-white shadow-sm transition-all duration-300 ease-in-out ${\n showButton ? 'opacity-100' : 'pointer-events-none opacity-0'\n }`}\n >\n PNG\n </span>\n )}\n\n {/* Info button */}\n <button\n className={`relative flex h-6 w-6 items-center justify-center rounded-full bg-black/30 backdrop-blur-sm transition-all duration-300 ease-in-out hover:scale-110 ${\n showButton ? 'opacity-100' : 'pointer-events-none opacity-0'\n }`}\n aria-label=\"Vector info\"\n onMouseEnter={handleIconMouseEnter}\n onMouseLeave={handleIconMouseLeave}\n >\n <Icon icon=\"lucide:aperture\" className=\"size-4 text-white/80\" />\n </button>\n </div>\n\n {/* Info overlay at bottom */}\n <div\n className={`absolute inset-x-0 bottom-0 z-0 bg-linear-to-t from-black/80 via-black/60 to-transparent px-3 py-3 pt-8 transition-transform duration-300 ease-out ${\n showInfo ? 'translate-y-0' : 'translate-y-full'\n }`}\n onMouseEnter={handleInfoMouseEnter}\n onMouseLeave={handleInfoMouseLeave}\n >\n\n <div className=\"mb-1\">\n <Icon icon=\"mdi:cube-outline\" className=\"mr-2 inline-block size-3 text-white/80\" />\n <span className=\"text-xs font-medium text-white/80\">Noun Project</span>\n </div>\n <div className=\"text-xs text-white/60\">Icon by</div>\n <div className=\"text-sm font-medium text-white\">{vector.uploader.name}</div>\n </div>\n </div>\n );\n});\n\nconst ImageBrowserPanel = ({\n isOpen,\n onToggle,\n onImageSelect,\n currentImageUrl,\n placement = 'bottom',\n}: ImageBrowserPanelProps) => {\n const [searchQuery, setSearchQuery] = useState('');\n const [customUrl, setCustomUrl] = useState('');\n const [images, setImages] = useState<ImageResult[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [activeTab, setActiveTab] = useState<'search' | 'url' | 'vector' | 'ai'>('search');\n const [unsplashPage, setUnsplashPage] = useState(1);\n const [pixabayPage, setPixabayPage] = useState(1);\n const [hasMore, setHasMore] = useState(true);\n const [usedCollections, setUsedCollections] = useState<string[]>([]);\n const [viewMode, setViewMode] = useState<'grid' | 'masonry'>('masonry');\n\n // Vector graphics state (separate from images)\n const [vectorSearchQuery, setVectorSearchQuery] = useState('');\n const [vectors, setVectors] = useState<VectorResult[]>([]);\n const [vectorLoading, setVectorLoading] = useState(false);\n const [vectorError, setVectorError] = useState<string | null>(null);\n const [vectorNextPage, setVectorNextPage] = useState<string | null>(null);\n const [vectorHasMore, setVectorHasMore] = useState(true);\n const [vectorViewMode, setVectorViewMode] = useState<'grid' | 'masonry'>('grid');\n const [vectorPublicDomainExhausted, setVectorPublicDomainExhausted] = useState(false);\n\n // AI generation state\n const [aiProvider, setAiProvider] = useState<'recraft' | 'runware'>('runware');\n const [aiPrompt, setAiPrompt] = useState('');\n // Recraft-specific state\n const [aiStyle, setAiStyle] = useState<RecraftStyleType>('vector_illustration');\n const [aiSubstyle, setAiSubstyle] = useState<string>('');\n // Runware-specific state\n const [runwareModel, setRunwareModel] = useState<RunwareModelId>('runware:101@1');\n // Shared state\n const [aiGenerating, setAiGenerating] = useState(false);\n const [aiError, setAiError] = useState<string | null>(null);\n const [aiResult, setAiResult] = useState<RecraftResult | null>(null);\n const [aiImageUrl, setAiImageUrl] = useState<string | null>(null);\n\n // Background removal state\n const [removingBackground, setRemovingBackground] = useState(false);\n const [backgroundRemovalError, setBackgroundRemovalError] = useState<string | null>(null);\n\n // Ref for infinite scroll sentinel\n const sentinelRef = useRef<HTMLDivElement>(null);\n const vectorSentinelRef = useRef<HTMLDivElement>(null);\n // Ref for file input\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // API access keys - users can set these via environment variables\n // Supports both Vite (VITE_*) and Next.js (NEXT_PUBLIC_*) environment variables\n const UNSPLASH_ACCESS_KEY =\n import.meta.env?.VITE_UNSPLASH_ACCESS_KEY ||\n (typeof process !== 'undefined' ? (process.env as Record<string, string | undefined>).NEXT_PUBLIC_UNSPLASH_ACCESS_KEY : undefined) ||\n 'YOUR_ACCESS_KEY_HERE';\n const PIXABAY_API_KEY =\n import.meta.env?.VITE_PIXABAY_API_KEY ||\n (typeof process !== 'undefined' ? (process.env as Record<string, string | undefined>).NEXT_PUBLIC_PIXABAY_API_KEY : undefined) ||\n 'YOUR_ACCESS_KEY_HERE';\n\n // Collection IDs to fetch from (Unsplash)\n const COLLECTION_IDS = [\n '907841',\n 'LZDKIWvumJc',\n '19740055',\n 'iTaneIvWKvE',\n '8354123',\n '2538204',\n '8262349',\n '6714897',\n 'uYpFBR3_CTc',\n ];\n\n // Helper: Map Pixabay response to ImageResult format\n const mapPixabayToImageResult = (pixabayImage: PixabayImage): ImageResult => {\n return {\n id: `pixabay-${pixabayImage.id}`,\n urls: {\n raw: pixabayImage.largeImageURL,\n full: pixabayImage.largeImageURL,\n regular: pixabayImage.largeImageURL,\n small: pixabayImage.webformatURL, // Use webformatURL for better quality (~640px)\n thumb: pixabayImage.previewURL,\n },\n alt_description: pixabayImage.tags,\n user: {\n name: pixabayImage.user,\n username: pixabayImage.user,\n },\n width: pixabayImage.imageWidth,\n height: pixabayImage.imageHeight,\n source: 'pixabay',\n };\n };\n\n // Helper: Map Unsplash response to ImageResult format\n const mapUnsplashToImageResult = (unsplashImage: UnsplashImage): ImageResult => {\n return {\n id: `unsplash-${unsplashImage.id}`,\n urls: unsplashImage.urls,\n alt_description: unsplashImage.alt_description,\n user: unsplashImage.user,\n width: unsplashImage.width,\n height: unsplashImage.height,\n source: 'unsplash',\n };\n };\n\n // Initialize with current image URL when opening\n useEffect(() => {\n if (isOpen && currentImageUrl) {\n setCustomUrl(currentImageUrl);\n setActiveTab('url');\n }\n }, [isOpen, currentImageUrl]);\n\n // Reset state when closing\n useEffect(() => {\n if (!isOpen) {\n setSearchQuery('');\n setCustomUrl('');\n setImages([]);\n setError(null);\n setUnsplashPage(1);\n setPixabayPage(1);\n setHasMore(true);\n setUsedCollections([]);\n // Reset vector state\n setVectorSearchQuery('');\n setVectors([]);\n setVectorError(null);\n setVectorNextPage(null);\n setVectorHasMore(true);\n }\n }, [isOpen]);\n\n // Load featured images on mount (when search is empty)\n useEffect(() => {\n if (isOpen && !searchQuery && activeTab === 'search' && images.length === 0) {\n loadFeaturedImages();\n }\n }, [isOpen, activeTab]);\n\n const loadFeaturedImages = async () => {\n setLoading(true);\n setError(null);\n try {\n const requests: Promise<Response>[] = [];\n\n // Fetch from Unsplash if API key is available\n if (UNSPLASH_ACCESS_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n // Pick 2 random collections\n const availableCollections = COLLECTION_IDS.filter((id) => !usedCollections.includes(id));\n const collectionsToUse = availableCollections.length >= 2 ? availableCollections : COLLECTION_IDS;\n const shuffled = [...collectionsToUse].sort(() => Math.random() - 0.5);\n const selectedCollections = shuffled.slice(0, 2);\n\n // Fetch 30 photos from each collection (60 total from Unsplash)\n selectedCollections.forEach((collectionId) => {\n requests.push(\n fetch(`https://api.unsplash.com/collections/${collectionId}/photos?per_page=30`, {\n headers: {\n Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`,\n },\n })\n );\n });\n\n setUsedCollections((prev) => {\n const newUsed = [...prev, ...selectedCollections];\n return newUsed.length >= COLLECTION_IDS.length ? selectedCollections : newUsed;\n });\n }\n\n // Fetch from Pixabay if API key is available (30 images)\n if (PIXABAY_API_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n requests.push(\n fetch(`https://pixabay.com/api/?key=${PIXABAY_API_KEY}&per_page=30&image_type=photo&order=popular`)\n );\n }\n\n if (requests.length === 0) {\n throw new Error('No API keys configured. Please set VITE_UNSPLASH_ACCESS_KEY or VITE_PIXABAY_API_KEY.');\n }\n\n const responses = await Promise.all(requests);\n\n // Check if responses are ok\n const failedResponses = responses.filter((r) => !r.ok);\n if (failedResponses.length === responses.length) {\n throw new Error('Failed to load images from all sources');\n }\n\n const allImages: ImageResult[] = [];\n\n // Process responses\n for (let i = 0; i < responses.length; i++) {\n if (!responses[i].ok) continue;\n\n const data = await responses[i].json();\n\n // Check if this is Pixabay response (has 'hits' property)\n if ('hits' in data) {\n const pixabayImages = data.hits.map(mapPixabayToImageResult);\n allImages.push(...pixabayImages);\n } else {\n // Unsplash response (array of images)\n const unsplashImages = data.map(mapUnsplashToImageResult);\n allImages.push(...unsplashImages);\n }\n }\n\n // Shuffle to interleave Unsplash and Pixabay results\n const shuffledImages = allImages.sort(() => Math.random() - 0.5);\n\n setImages(shuffledImages);\n setHasMore(true);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load images');\n log.error('Error loading featured images:', err);\n } finally {\n setLoading(false);\n }\n };\n\n const searchImages = async (query: string, unsplashPageNum: number = 1, pixabayPageNum: number = 1) => {\n if (!query.trim()) {\n loadFeaturedImages();\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n if (unsplashPageNum === 1 && pixabayPageNum === 1) {\n // Initial search - fetch from both sources in parallel\n const requests: Promise<Response>[] = [];\n\n // Fetch 2 pages from Unsplash if API key available (60 images)\n if (UNSPLASH_ACCESS_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n requests.push(\n fetch(`https://api.unsplash.com/search/photos?query=${encodeURIComponent(query)}&page=1&per_page=30`, {\n headers: {\n Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`,\n },\n }),\n fetch(`https://api.unsplash.com/search/photos?query=${encodeURIComponent(query)}&page=2&per_page=30`, {\n headers: {\n Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`,\n },\n })\n );\n }\n\n // Fetch from Pixabay if API key available (30 images)\n if (PIXABAY_API_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n requests.push(\n fetch(\n `https://pixabay.com/api/?key=${PIXABAY_API_KEY}&q=${encodeURIComponent(query)}&page=1&per_page=30&image_type=photo`\n )\n );\n }\n\n if (requests.length === 0) {\n throw new Error('No API keys configured. Please set VITE_UNSPLASH_ACCESS_KEY or VITE_PIXABAY_API_KEY.');\n }\n\n const responses = await Promise.all(requests);\n\n const failedResponses = responses.filter((r) => !r.ok);\n if (failedResponses.length === responses.length) {\n throw new Error('Failed to search images from all sources');\n }\n\n const allResults: ImageResult[] = [];\n\n // Process responses\n for (let i = 0; i < responses.length; i++) {\n if (!responses[i].ok) continue;\n\n const data = await responses[i].json();\n\n // Check if this is Pixabay response\n if ('hits' in data) {\n const pixabayImages = data.hits.map(mapPixabayToImageResult);\n allResults.push(...pixabayImages);\n } else {\n // Unsplash response\n const unsplashImages = data.results.map(mapUnsplashToImageResult);\n allResults.push(...unsplashImages);\n }\n }\n\n // Shuffle to interleave results\n const shuffledResults = allResults.sort(() => Math.random() - 0.5);\n\n setImages(shuffledResults);\n setHasMore(allResults.length > 0);\n } else {\n // Load more - fetch next page from both sources\n const requests: Promise<Response>[] = [];\n\n // Fetch next Unsplash page if available\n if (UNSPLASH_ACCESS_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n requests.push(\n fetch(\n `https://api.unsplash.com/search/photos?query=${encodeURIComponent(query)}&page=${unsplashPageNum + 2}&per_page=30`,\n {\n headers: {\n Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`,\n },\n }\n )\n );\n }\n\n // Fetch next Pixabay page if available\n if (PIXABAY_API_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n requests.push(\n fetch(\n `https://pixabay.com/api/?key=${PIXABAY_API_KEY}&q=${encodeURIComponent(query)}&page=${pixabayPageNum + 1}&per_page=30&image_type=photo`\n )\n );\n }\n\n const responses = await Promise.all(requests);\n const newResults: ImageResult[] = [];\n\n // Process responses\n for (let i = 0; i < responses.length; i++) {\n if (!responses[i].ok) continue;\n\n const data = await responses[i].json();\n\n // Check if this is Pixabay response\n if ('hits' in data) {\n const pixabayImages = data.hits.map(mapPixabayToImageResult);\n newResults.push(...pixabayImages);\n } else {\n // Unsplash response\n const unsplashImages = data.results.map(mapUnsplashToImageResult);\n newResults.push(...unsplashImages);\n }\n }\n\n // Shuffle new results and append\n const shuffledNewResults = newResults.sort(() => Math.random() - 0.5);\n setImages((prev) => [...prev, ...shuffledNewResults]);\n setHasMore(newResults.length > 0);\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to search images');\n log.error('Error searching images:', err);\n } finally {\n setLoading(false);\n }\n };\n\n const handleSearch = (e: React.FormEvent) => {\n e.preventDefault();\n setUnsplashPage(1);\n setPixabayPage(1);\n searchImages(searchQuery, 1, 1);\n };\n\n const handleLoadMore = useCallback(async () => {\n // Don't load if already loading or no more results\n if (loading || !hasMore) return;\n\n // If searching, load more search results\n if (searchQuery.trim()) {\n const nextUnsplashPage = unsplashPage + 1;\n const nextPixabayPage = pixabayPage + 1;\n setUnsplashPage(nextUnsplashPage);\n setPixabayPage(nextPixabayPage);\n searchImages(searchQuery, nextUnsplashPage, nextPixabayPage);\n return;\n }\n\n // Otherwise, load more featured images from both sources\n setLoading(true);\n setError(null);\n\n try {\n const requests: Promise<Response>[] = [];\n\n // Load more from Unsplash collections if available\n if (UNSPLASH_ACCESS_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n const availableCollections = COLLECTION_IDS.filter((id) => !usedCollections.includes(id));\n const collectionsToUse = availableCollections.length >= 2 ? availableCollections : COLLECTION_IDS;\n const shuffled = [...collectionsToUse].sort(() => Math.random() - 0.5);\n const selectedCollections = shuffled.slice(0, 2);\n\n selectedCollections.forEach((collectionId) => {\n requests.push(\n fetch(`https://api.unsplash.com/collections/${collectionId}/photos?per_page=30`, {\n headers: {\n Authorization: `Client-ID ${UNSPLASH_ACCESS_KEY}`,\n },\n })\n );\n });\n\n setUsedCollections((prev) => {\n const newUsed = [...prev, ...selectedCollections];\n return newUsed.length >= COLLECTION_IDS.length ? selectedCollections : newUsed;\n });\n }\n\n // Load more from Pixabay if available\n if (PIXABAY_API_KEY !== 'YOUR_ACCESS_KEY_HERE') {\n const nextPage = pixabayPage + 1;\n requests.push(\n fetch(\n `https://pixabay.com/api/?key=${PIXABAY_API_KEY}&page=${nextPage}&per_page=30&image_type=photo&order=popular`\n )\n );\n setPixabayPage(nextPage);\n }\n\n const responses = await Promise.all(requests);\n const newImages: ImageResult[] = [];\n\n // Process responses\n for (let i = 0; i < responses.length; i++) {\n if (!responses[i].ok) continue;\n\n const data = await responses[i].json();\n\n // Check if this is Pixabay response\n if ('hits' in data) {\n const pixabayImages = data.hits.map(mapPixabayToImageResult);\n newImages.push(...pixabayImages);\n } else {\n // Unsplash response\n const unsplashImages = data.map(mapUnsplashToImageResult);\n newImages.push(...unsplashImages);\n }\n }\n\n // Shuffle and append\n const shuffledNewImages = newImages.sort(() => Math.random() - 0.5);\n setImages((prev) => [...prev, ...shuffledNewImages]);\n setHasMore(newImages.length > 0);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to load more images');\n log.error('Error loading more images:', err);\n } finally {\n setLoading(false);\n }\n }, [loading, hasMore, searchQuery, unsplashPage, pixabayPage, usedCollections, UNSPLASH_ACCESS_KEY, PIXABAY_API_KEY]);\n\n // Infinite scroll: Observe sentinel element to trigger loading\n useEffect(() => {\n const sentinel = sentinelRef.current;\n if (!sentinel || !isOpen || activeTab !== 'search') return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n // When sentinel becomes visible, load more\n if (entries[0].isIntersecting && hasMore && !loading) {\n handleLoadMore();\n }\n },\n {\n root: null, // viewport\n rootMargin: '200px', // Trigger 200px before sentinel is visible\n threshold: 0,\n }\n );\n\n observer.observe(sentinel);\n\n return () => {\n observer.disconnect();\n };\n }, [isOpen, activeTab, hasMore, loading, handleLoadMore]);\n\n // ===== VECTOR GRAPHICS FUNCTIONS =====\n\n // Load featured vectors on mount\n useEffect(() => {\n if (isOpen && !vectorSearchQuery && activeTab === 'vector' && vectors.length === 0 && isNounProjectConfigured()) {\n loadFeaturedVectors();\n }\n }, [isOpen, activeTab]);\n\n const loadFeaturedVectors = async () => {\n setVectorLoading(true);\n setVectorError(null);\n try {\n const results = await getFeaturedIcons({ limit: 30, includeSvg: true });\n setVectors(results);\n setVectorHasMore(true);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to load vectors';\n // Check if it's a network error (proxy not running)\n if (errorMessage.includes('Failed to fetch') || errorMessage.includes('NetworkError')) {\n setVectorError(\n 'Cannot connect to proxy server. Make sure to run \"npm run dev:proxy\" in a separate terminal.'\n );\n } else {\n setVectorError(errorMessage);\n }\n log.error('Error loading featured vectors:', err);\n } finally {\n setVectorLoading(false);\n }\n };\n\n const searchVectors = async (query: string, nextPageToken?: string) => {\n if (!query.trim() && !nextPageToken) {\n loadFeaturedVectors();\n return;\n }\n\n setVectorLoading(true);\n setVectorError(null);\n try {\n // Determine if we should limit to public domain\n // Start with public domain, then switch to all icons when exhausted\n const limitToPublicDomain = !vectorPublicDomainExhausted;\n\n const { results, nextPage } = await searchIcons(query, {\n limit: 30,\n includeSvg: true,\n limitToPublicDomain,\n nextPage: nextPageToken,\n });\n\n // If we get results, process them\n if (results.length > 0) {\n if (nextPageToken) {\n // Appending more results - filter out duplicates by ID\n setVectors((prev) => {\n const existingIds = new Set(prev.map((v) => v.id));\n const newResults = results.filter((r) => !existingIds.has(r.id));\n return [...prev, ...newResults];\n });\n } else {\n // Initial search\n setVectors(results);\n setVectorPublicDomainExhausted(false); // Reset on new search\n }\n\n setVectorNextPage(nextPage);\n setVectorHasMore(nextPage !== null);\n\n // If initial search with public domain returned fewer results than requested AND no more pages,\n // automatically augment with non-public domain results\n if (!nextPageToken && limitToPublicDomain && !nextPage && results.length < 30) {\n setVectorPublicDomainExhausted(true);\n\n // Fetch additional results from all icons\n const { results: allResults, nextPage: allNextPage } = await searchIcons(query, {\n limit: 30,\n includeSvg: true,\n limitToPublicDomain: false,\n });\n\n // Filter out duplicates and append\n setVectors((prev) => {\n const existingIds = new Set(prev.map((v) => v.id));\n const newResults = allResults.filter((r) => !existingIds.has(r.id));\n return [...prev, ...newResults];\n });\n\n setVectorNextPage(allNextPage);\n setVectorHasMore(allNextPage !== null);\n }\n } else if (!vectorPublicDomainExhausted && !nextPageToken) {\n // No public domain results for initial search - immediately try all icons\n setVectorPublicDomainExhausted(true);\n // Retry search with all icons\n const { results: allResults, nextPage: allNextPage } = await searchIcons(query, {\n limit: 30,\n includeSvg: true,\n limitToPublicDomain: false,\n });\n\n setVectors(allResults);\n setVectorNextPage(allNextPage);\n setVectorHasMore(allNextPage !== null);\n } else if (limitToPublicDomain && nextPageToken && !nextPage) {\n // Public domain results exhausted during pagination - switch to all icons\n setVectorPublicDomainExhausted(true);\n\n // Start fetching from all icons (without nextPage to start fresh)\n const { results: allResults, nextPage: allNextPage } = await searchIcons(query, {\n limit: 30,\n includeSvg: true,\n limitToPublicDomain: false,\n });\n\n // Filter out duplicates and append\n setVectors((prev) => {\n const existingIds = new Set(prev.map((v) => v.id));\n const newResults = allResults.filter((r) => !existingIds.has(r.id));\n return [...prev, ...newResults];\n });\n\n setVectorNextPage(allNextPage);\n setVectorHasMore(allNextPage !== null);\n } else {\n // Truly no more results\n setVectorHasMore(false);\n setVectorNextPage(null);\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to search vectors';\n // Check if it's a network error (proxy not running)\n if (errorMessage.includes('Failed to fetch') || errorMessage.includes('NetworkError')) {\n setVectorError(\n 'Cannot connect to proxy server. Make sure to run \"npm run dev:proxy\" in a separate terminal.'\n );\n } else {\n setVectorError(errorMessage);\n }\n log.error('Error searching vectors:', err);\n } finally {\n setVectorLoading(false);\n }\n };\n\n const handleVectorSearch = (e: React.FormEvent) => {\n e.preventDefault();\n searchVectors(vectorSearchQuery);\n };\n\n const handleVectorLoadMore = useCallback(async () => {\n if (vectorLoading || !vectorHasMore || !vectorNextPage) return;\n\n if (vectorSearchQuery.trim()) {\n searchVectors(vectorSearchQuery, vectorNextPage);\n } else {\n // Load more featured vectors (we can repeat the featured call)\n loadFeaturedVectors();\n }\n }, [vectorLoading, vectorHasMore, vectorNextPage, vectorSearchQuery]);\n\n // Infinite scroll for vectors\n useEffect(() => {\n const sentinel = vectorSentinelRef.current;\n if (!sentinel || !isOpen || activeTab !== 'vector') return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n if (entries[0].isIntersecting && vectorHasMore && !vectorLoading) {\n handleVectorLoadMore();\n }\n },\n {\n root: null,\n rootMargin: '200px',\n threshold: 0,\n }\n );\n\n observer.observe(sentinel);\n\n return () => {\n observer.disconnect();\n };\n }, [isOpen, activeTab, vectorHasMore, vectorLoading, handleVectorLoadMore]);\n\n const handleVectorSelect = (vector: VectorResult) => {\n // Use SVG if available, otherwise use PNG\n let url = vector.urls.svg || vector.urls.png;\n\n // Only proxy external URLs, not URLs that already point to our proxy\n const isProxyUrl = url.startsWith('http://localhost:3001');\n const finalUrl = isProxyUrl ? url : `http://localhost:3001/proxy-image?url=${encodeURIComponent(url)}`;\n\n onImageSelect(finalUrl);\n onToggle(false);\n };\n\n // ===== IMAGE FUNCTIONS =====\n\n const handleImageSelect = (image: ImageResult) => {\n // Use 'regular' size for good quality without being too large\n onImageSelect(image.urls.regular);\n onToggle(false);\n };\n\n const handleCustomUrlSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (customUrl.trim()) {\n onImageSelect(customUrl.trim());\n onToggle(false);\n }\n };\n\n const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file && file.type.startsWith('image/')) {\n const reader = new FileReader();\n reader.onload = (event) => {\n const dataUrl = event.target?.result as string;\n setCustomUrl(dataUrl);\n };\n reader.readAsDataURL(file);\n }\n };\n\n const handleUploadClick = () => {\n fileInputRef.current?.click();\n };\n\n const handleRemoveBackground = async () => {\n if (!customUrl.trim()) {\n setBackgroundRemovalError('No image URL provided');\n return;\n }\n\n if (!isFalConfigured()) {\n setBackgroundRemovalError('fal.ai API key not configured. Set VITE_FAL_API_KEY in your .env file.');\n return;\n }\n\n setRemovingBackground(true);\n setBackgroundRemovalError(null);\n\n try {\n let imageUrlToProcess = customUrl;\n\n // If the image is SVG, convert it to PNG first\n if (isSvgImage(customUrl)) {\n imageUrlToProcess = await convertSvgToPng(customUrl);\n }\n\n // Call fal.ai API to remove background (Bria RMBG 2.0)\n const result = await removeBackground(imageUrlToProcess, {\n syncMode: false, // Get URL, not data URI\n });\n\n // Convert the result to a data URL for immediate use\n const dataUrl = await convertToDataUrl(result.image.url);\n\n // Update the custom URL with the processed image\n setCustomUrl(dataUrl);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to remove background';\n setBackgroundRemovalError(errorMessage);\n log.error('Error removing background:', err);\n } finally {\n setRemovingBackground(false);\n }\n };\n\n // ===== AI GENERATION FUNCTIONS =====\n\n const handleAiGenerate = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!aiPrompt.trim()) {\n setAiError('Please enter a prompt');\n return;\n }\n\n // Check configuration based on provider\n if (aiProvider === 'recraft' && !isRecraftConfigured()) {\n setAiError('Recraft API token not configured. Set VITE_RECRAFT_API_TOKEN in your .env file.');\n return;\n }\n\n if (aiProvider === 'runware' && !isRunwareConfigured()) {\n setAiError('Runware API key not configured. Set VITE_RUNWARE_API_KEY in your .env file.');\n return;\n }\n\n setAiGenerating(true);\n setAiError(null);\n setAiResult(null);\n setAiImageUrl(null);\n\n try {\n if (aiProvider === 'recraft') {\n // Generate image with Recraft API using style and substyle\n const result = await generateImage(aiPrompt, aiStyle, aiSubstyle || undefined);\n setAiResult(result);\n\n // Download the image data\n const imageUrl = await downloadRecraftImage(result.url);\n setAiImageUrl(imageUrl);\n } else {\n // Generate image with Runware API\n const result = await generateImages({\n prompt: aiPrompt,\n model: runwareModel,\n width: 1024,\n height: 1024,\n steps: 25,\n cfgScale: 7.0,\n });\n\n // Convert the image to data URL\n const dataUrl = await convertImageToDataUrl(result.images[0].imageURL);\n setAiImageUrl(dataUrl);\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Failed to generate image';\n setAiError(errorMessage);\n log.error('Error generating AI image:', err);\n } finally {\n setAiGenerating(false);\n }\n };\n\n const handleAiImageSelect = () => {\n if (aiImageUrl) {\n onImageSelect(aiImageUrl);\n onToggle(false);\n }\n };\n\n // Determine span classes for CSS Grid Masonry\n const getItemSpanClass = (image: ImageResult, index: number) => {\n const ar = image.width / image.height;\n\n // Occasional \"Big\" items (every ~12 items, if roughly square)\n // 2x2 span\n if (index % 12 === 0 && ar > 0.8 && ar < 1.2) {\n return 'col-span-2 row-span-2';\n }\n\n // Tall images (Portrait)\n // 1x2 span\n if (ar < 0.75) {\n return 'row-span-2';\n }\n\n // Wide images (Landscape)\n // 2x1 span\n if (ar > 1.5) {\n return 'col-span-2';\n }\n\n // Default (Square-ish/Standard)\n // 1x1 span\n return '';\n };\n\n return (\n <Drawer\n isOpen={isOpen}\n onClose={() => onToggle(false)}\n title=\"Image Browser\"\n description=\"Browse Unsplash images or enter a custom image URL\"\n placement={placement}\n height={placement === 'bottom' ? '90vh' : undefined}\n width={placement !== 'bottom' ? '500px' : undefined}\n hideHandle={true}\n hideVisibleTitle={true}\n showCloseButton={false}\n data-testid=\"image-browser-drawer\"\n >\n <Tabs\n value={activeTab}\n onValueChange={(value) => setActiveTab(value as 'search' | 'url' | 'vector' | 'ai')}\n className=\"flex flex-col\"\n data-testid=\"image-browser-container\"\n >\n <Tabs.ListContainer className=\"flex justify-center pt-4 pb-2\">\n <Tabs.List\n className=\"h-14 gap-1 px-1.5 md:h-12\"\n aria-label=\"Image source\"\n >\n <Tabs.Tab\n id=\"search\"\n className=\"h-11 w-14 px-0 md:h-9 md:w-11\"\n data-testid=\"image-tab-search\"\n >\n <Icon icon={icons.image} className=\"size-6\" />\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab\n id=\"url\"\n className=\"h-11 w-14 px-0 md:h-9 md:w-11\"\n data-testid=\"image-tab-url\"\n >\n <Icon icon={icons.link} className=\"size-6\" />\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab\n id=\"vector\"\n className=\"h-11 w-14 px-0 md:h-9 md:w-11\"\n data-testid=\"image-tab-vector\"\n >\n <Icon icon=\"fa6-solid:icons\" className=\"size-5\" />\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab\n id=\"ai\"\n className=\"h-11 w-14 px-0 md:h-9 md:w-11\"\n data-testid=\"image-tab-ai\"\n >\n <SparklesIcon size={24} />\n <Tabs.Indicator />\n </Tabs.Tab>\n </Tabs.List>\n </Tabs.ListContainer>\n\n {/* Search Tab */}\n <Tabs.Panel id=\"search\" className=\"flex flex-col\">\n {/* Search Input */}\n <form onSubmit={handleSearch} className=\"sticky top-0 z-9 flex gap-2 bg-surface px-6 pt-4 pb-3\">\n <TextField className=\"flex-1\" aria-label=\"Search for images\">\n <Input\n type=\"text\"\n placeholder=\"Search for images...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n variant=\"subtle\"\n data-testid=\"image-search-input\"\n />\n </TextField>\n <Button type=\"submit\" size=\"icon\" variant=\"secondary\" disabled={loading} aria-label=\"Search\">\n <Icon icon={icons.search} className=\"size-5\" />\n </Button>\n <Button\n size=\"icon\"\n variant=\"secondary\"\n onClick={() => setViewMode(viewMode === 'grid' ? 'masonry' : 'grid')}\n aria-label={viewMode === 'grid' ? 'Switch to masonry view' : 'Switch to grid view'}\n >\n {viewMode === 'grid' ? (\n <Icon icon=\"lucide:layout-grid\" className=\"size-5\" />\n ) : (\n <Icon icon={icons.grip} className=\"size-5\" />\n )}\n </Button>\n </form>\n\n {/* Error Message */}\n {error && (\n <div className=\"border-danger bg-danger/10 text-danger mx-6 mb-3 rounded-2xl border-2 px-4 py-3 text-sm\">\n {error}\n {error.includes('Failed') && UNSPLASH_ACCESS_KEY === 'YOUR_ACCESS_KEY_HERE' && (\n <div className=\"mt-2 text-sm opacity-75\">\n Set VITE_UNSPLASH_ACCESS_KEY in your .env file to enable Unsplash search\n </div>\n )}\n </div>\n )}\n\n {/* Loading State */}\n {loading && images.length === 0 && (\n <div className=\"text-muted px-6 py-8 text-center text-sm\">Loading images...</div>\n )}\n\n {/* Image Grid - wrapped in clip container for rounded scroll effect */}\n {images.length > 0 && (\n <div className=\"mx-6 overflow-hidden rounded-t-2xl\">\n {viewMode === 'masonry' ? (\n /* CSS Grid Masonry (Dense) */\n <div\n className=\"grid grid-flow-dense pb-4\"\n style={{\n display: 'grid',\n gridTemplateColumns:\n placement === 'bottom' ? 'repeat(auto-fill, minmax(200px, 1fr))' : 'repeat(3, 1fr)',\n gridAutoRows: placement === 'bottom' ? '200px' : '120px',\n gap: MASONRY_GAP,\n }}\n >\n {images.map((image, index) => (\n <div key={image.id} className={getItemSpanClass(image, index)}>\n <ImageCard image={image} onImageSelect={handleImageSelect} fixedHeight={true} />\n </div>\n ))}\n </div>\n ) : (\n /* Fixed Height Grid - Square Tiles */\n <div\n className=\"pb-4\"\n style={{\n display: 'grid',\n gridTemplateColumns:\n placement === 'bottom'\n ? 'repeat(auto-fill, minmax(150px, 1fr))'\n : 'repeat(auto-fill, minmax(120px, 1fr))',\n gap: GRID_GAP,\n }}\n >\n {images.map((image) => (\n <div key={image.id} style={{ aspectRatio: '1 / 1' }}>\n <ImageCard image={image} onImageSelect={handleImageSelect} fixedHeight={true} />\n </div>\n ))}\n </div>\n )}\n\n {/* Infinite Scroll Sentinel - triggers loading when visible */}\n {hasMore && <div ref={sentinelRef} className=\"h-px\" />}\n\n {/* Loading More State */}\n {loading && <div className=\"text-muted py-4 text-center text-sm\">Loading more...</div>}\n\n {/* End of results indicator */}\n {!hasMore && !loading && <div className=\"text-muted py-6 text-center text-sm\">No more images</div>}\n </div>\n )}\n\n {/* No Results */}\n {!loading && images.length === 0 && searchQuery && (\n <div className=\"text-muted px-6 py-12 text-center text-sm\">No images found for \"{searchQuery}\"</div>\n )}\n </Tabs.Panel>\n\n {/* Custom URL Tab — upload-or-paste pattern.\n Big tappable upload card on top, URL field below, single\n primary action. Preview only renders once a URL is entered. */}\n <Tabs.Panel id=\"url\" className=\"flex flex-col gap-5 p-6\">\n {/* Hidden file input — triggered by the upload card */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileUpload}\n className=\"hidden\"\n />\n\n {/* Upload card — large tap target, mimics drag-drop affordance\n even without actual DnD wiring. */}\n <button\n type=\"button\"\n onClick={handleUploadClick}\n className=\"flex flex-col items-center justify-center gap-3 rounded-2xl border-2 border-dashed border-divider bg-muted/30 px-6 py-10 transition-colors hover:bg-muted/50 active:bg-muted/60\"\n data-testid=\"image-upload-btn\"\n >\n <Icon\n icon=\"lucide:upload-cloud\"\n className=\"size-10 text-foreground/60\"\n />\n <div className=\"flex flex-col items-center gap-1\">\n <span className=\"text-base font-medium text-foreground\">\n Upload from device\n </span>\n <span className=\"text-xs text-muted-foreground\">\n PNG · JPG · SVG · GIF\n </span>\n </div>\n </button>\n\n {/* Divider */}\n <div className=\"relative flex items-center gap-3\">\n <div className=\"h-px flex-1 bg-divider\" />\n <span className=\"text-muted-foreground text-xs uppercase tracking-wider\">\n or paste a link\n </span>\n <div className=\"h-px flex-1 bg-divider\" />\n </div>\n\n {/* URL form — single-line input + primary action */}\n <form\n onSubmit={handleCustomUrlSubmit}\n className=\"flex flex-col gap-3\"\n >\n <TextField>\n <Label className=\"sr-only\">Image URL</Label>\n <Input\n type=\"url\"\n placeholder=\"https://example.com/image.jpg\"\n value={customUrl}\n onChange={(e) => setCustomUrl(e.target.value)}\n variant=\"subtle\"\n data-testid=\"image-url-input\"\n />\n </TextField>\n\n <Button\n type=\"submit\"\n variant=\"default\"\n disabled={!customUrl.trim()}\n className=\"w-full\"\n data-testid=\"image-url-submit-btn\"\n >\n Use This Image\n </Button>\n </form>\n\n {/* Preview — only when URL has content */}\n {customUrl.trim() && (\n <div className=\"flex flex-col gap-3 rounded-2xl border border-divider bg-muted/30 p-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <span className=\"text-xs font-medium uppercase tracking-wider text-muted-foreground\">\n Preview\n </span>\n {isFalConfigured() && (\n <Button\n onClick={handleRemoveBackground}\n disabled={removingBackground || !customUrl.trim()}\n variant=\"secondary\"\n size=\"sm\"\n className=\"gap-2\"\n data-testid=\"remove-background-btn\"\n >\n {removingBackground ? (\n <>\n <Icon\n icon=\"eos-icons:loading\"\n className=\"size-4 animate-spin\"\n />\n Removing…\n </>\n ) : (\n <>\n <Icon icon=\"mdi:image-remove\" className=\"size-4\" />\n Remove BG\n </>\n )}\n </Button>\n )}\n </div>\n\n {backgroundRemovalError && (\n <div className=\"rounded-lg border border-danger bg-danger/10 px-3 py-2 text-xs text-danger\">\n {backgroundRemovalError}\n </div>\n )}\n\n <img\n src={customUrl}\n alt=\"Preview\"\n className=\"max-h-[280px] w-full rounded-lg object-contain\"\n onError={(e) => {\n (e.target as HTMLImageElement).style.display = 'none';\n }}\n onLoad={(e) => {\n (e.target as HTMLImageElement).style.display = 'block';\n }}\n />\n\n {!isFalConfigured() && (\n <div className=\"rounded-lg border border-warning bg-warning/10 px-3 py-2 text-xs text-warning\">\n Set VITE_FAL_API_KEY in your .env file to enable background\n removal.\n </div>\n )}\n </div>\n )}\n </Tabs.Panel>\n\n {/* Vector Graphics Tab */}\n <Tabs.Panel id=\"vector\" className=\"flex flex-col\">\n {/* Search Input */}\n <form onSubmit={handleVectorSearch} className=\"sticky top-0 z-9 flex gap-2 bg-surface px-6 pt-4 pb-3\">\n <TextField className=\"flex-1\" aria-label=\"Search for vector graphics\">\n <Input\n type=\"text\"\n placeholder=\"Search for icons...\"\n value={vectorSearchQuery}\n onChange={(e) => setVectorSearchQuery(e.target.value)}\n variant=\"subtle\"\n data-testid=\"vector-search-input\"\n />\n </TextField>\n <Button type=\"submit\" size=\"icon\" variant=\"secondary\" disabled={vectorLoading} aria-label=\"Search\">\n <Icon icon={icons.search} className=\"size-5\" />\n </Button>\n <Button\n size=\"icon\"\n variant=\"secondary\"\n onClick={() => setVectorViewMode(vectorViewMode === 'grid' ? 'masonry' : 'grid')}\n aria-label={vectorViewMode === 'grid' ? 'Switch to masonry view' : 'Switch to grid view'}\n >\n {vectorViewMode === 'grid' ? (\n <Icon icon=\"lucide:layout-grid\" className=\"size-5\" />\n ) : (\n <Icon icon={icons.grip} className=\"size-5\" />\n )}\n </Button>\n </form>\n\n {/* Error Message */}\n {vectorError && (\n <div className=\"border-danger bg-danger/10 text-danger mx-6 mb-3 rounded-2xl border-2 px-4 py-3 text-sm\">\n {vectorError}\n </div>\n )}\n\n {/* Not Configured Message */}\n {!isNounProjectConfigured() && (\n <div className=\"bg-warning/10 text-warning mx-6 mb-3 rounded-2xl border-2 border-warning px-4 py-3 text-sm\">\n Noun Project API keys not configured. Set VITE_NOUN_PROJECT_API_KEY and VITE_NOUN_PROJECT_API_SECRET in your\n .env file.\n </div>\n )}\n\n {/* Loading State */}\n {vectorLoading && vectors.length === 0 && (\n <div className=\"text-muted px-6 py-8 text-center text-sm\">Loading vectors...</div>\n )}\n\n {/* Vector Grid - wrapped in clip container for rounded scroll effect */}\n {vectors.length > 0 && (\n <div className=\"mx-6 overflow-hidden rounded-t-2xl\">\n {vectorViewMode === 'masonry' ? (\n /* CSS Grid Masonry */\n <div\n className=\"grid grid-flow-dense pb-4\"\n style={{\n display: 'grid',\n gridTemplateColumns:\n placement === 'bottom' ? 'repeat(auto-fill, minmax(150px, 1fr))' : 'repeat(3, 1fr)',\n gridAutoRows: placement === 'bottom' ? '150px' : '120px',\n gap: GRID_GAP,\n }}\n >\n {vectors.map((vector) => (\n <div key={vector.id}>\n <VectorCard vector={vector} onVectorSelect={handleVectorSelect} fixedHeight={true} />\n </div>\n ))}\n </div>\n ) : (\n /* Fixed Height Grid - Square Tiles */\n <div\n className=\"pb-4\"\n style={{\n display: 'grid',\n gridTemplateColumns:\n placement === 'bottom'\n ? 'repeat(auto-fill, minmax(120px, 1fr))'\n : 'repeat(auto-fill, minmax(100px, 1fr))',\n gap: GRID_GAP,\n }}\n >\n {vectors.map((vector) => (\n <div key={vector.id} style={{ aspectRatio: '1 / 1' }}>\n <VectorCard vector={vector} onVectorSelect={handleVectorSelect} fixedHeight={true} />\n </div>\n ))}\n </div>\n )}\n\n {/* Infinite Scroll Sentinel */}\n {vectorHasMore && <div ref={vectorSentinelRef} className=\"h-px\" />}\n\n {/* Loading More State */}\n {vectorLoading && <div className=\"text-muted py-4 text-center text-sm\">Loading more...</div>}\n\n {/* End of results indicator */}\n {!vectorHasMore && !vectorLoading && <div className=\"text-muted py-6 text-center text-sm\">No more vectors</div>}\n </div>\n )}\n\n {/* No Results */}\n {!vectorLoading && vectors.length === 0 && vectorSearchQuery && isNounProjectConfigured() && (\n <div className=\"text-muted px-6 py-12 text-center text-sm\">No vectors found for \"{vectorSearchQuery}\"</div>\n )}\n </Tabs.Panel>\n\n {/* AI Generation Tab */}\n <Tabs.Panel id=\"ai\" className=\"flex flex-col gap-6 p-6\">\n {/* Provider Selection */}\n <TextField>\n <Label>AI Provider</Label>\n <select\n value={aiProvider}\n onChange={(e) => setAiProvider(e.target.value as 'recraft' | 'runware')}\n className=\"w-full rounded-xl border border-divider bg-field text-foreground px-4 py-3 text-sm\"\n >\n <option value=\"runware\">Runware (Flux Dev / Nano Banana 2 Pro)</option>\n <option value=\"recraft\">Recraft (Vector Illustrations)</option>\n </select>\n </TextField>\n\n {/* Runware Model Selection */}\n {aiProvider === 'runware' && (\n <TextField>\n <Label>Model</Label>\n <select\n value={runwareModel}\n onChange={(e) => setRunwareModel(e.target.value as RunwareModelId)}\n className=\"w-full rounded-xl border border-divider bg-field text-foreground px-4 py-3 text-sm\"\n >\n {RUNWARE_MODELS.map((model) => (\n <option key={model.id} value={model.id}>\n {model.name} - {model.description}\n </option>\n ))}\n </select>\n </TextField>\n )}\n\n {/* Recraft Style Dropdown */}\n {aiProvider === 'recraft' && (\n <TextField>\n <Label>Style</Label>\n <select\n value={aiStyle}\n onChange={(e) => {\n setAiStyle(e.target.value as RecraftStyleType);\n setAiSubstyle(''); // Reset substyle when style changes\n }}\n className=\"w-full rounded-xl border border-divider bg-field text-foreground px-4 py-3 text-sm\"\n >\n {RECRAFT_STYLES.map((style) => (\n <option key={style.value} value={style.value}>\n {style.label}\n </option>\n ))}\n </select>\n </TextField>\n )}\n\n {/* Recraft Substyle Dropdown - only show if recraft is selected and substyles are available */}\n {aiProvider === 'recraft' &&\n (() => {\n const selectedStyle = RECRAFT_STYLES.find((s) => s.value === aiStyle);\n return selectedStyle && selectedStyle.substyles.length > 0 ? (\n <TextField>\n <Label>Substyle (Optional)</Label>\n <select\n value={aiSubstyle}\n onChange={(e) => setAiSubstyle(e.target.value)}\n className=\"w-full rounded-xl border border-divider bg-field text-foreground px-4 py-3 text-sm\"\n >\n <option value=\"\">None (Default)</option>\n {selectedStyle.substyles.map((substyle) => (\n <option key={substyle} value={substyle}>\n {substyle.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </TextField>\n ) : null;\n })()}\n\n {/* Prompt Input */}\n <form onSubmit={handleAiGenerate} className=\"flex flex-col gap-6\">\n <TextField>\n <Label>Prompt</Label>\n <TextArea\n placeholder=\"Describe the image you want to generate... (e.g., 'avocado, transparent background')\"\n value={aiPrompt}\n onChange={(e) => setAiPrompt(e.target.value)}\n className=\"min-h-[100px] resize-y\"\n rows={4}\n data-testid=\"ai-prompt-input\"\n disabled={aiGenerating}\n />\n </TextField>\n\n <Button\n type=\"submit\"\n variant=\"default\"\n disabled={\n !aiPrompt.trim() ||\n aiGenerating ||\n (aiProvider === 'recraft' && !isRecraftConfigured()) ||\n (aiProvider === 'runware' && !isRunwareConfigured())\n }\n className=\"w-full\"\n data-testid=\"ai-generate-btn\"\n >\n {aiGenerating ? (\n <>\n <Icon icon=\"eos-icons:loading\" className=\"size-5 animate-spin\" />\n Generating...\n </>\n ) : (\n <>\n <SparklesIcon size={24} />\n Generate Image\n </>\n )}\n </Button>\n </form>\n\n {/* API Configuration Warnings */}\n {aiProvider === 'recraft' && !isRecraftConfigured() && (\n <div className=\"bg-warning/10 text-warning rounded-2xl border-2 border-warning px-4 py-3 text-sm\">\n Recraft API token not configured. Set VITE_RECRAFT_API_TOKEN in your .env file to enable AI generation.\n </div>\n )}\n\n {aiProvider === 'runware' && !isRunwareConfigured() && (\n <div className=\"bg-warning/10 text-warning rounded-2xl border-2 border-warning px-4 py-3 text-sm\">\n Runware API key not configured. Set VITE_RUNWARE_API_KEY in your .env file to enable AI generation.\n </div>\n )}\n\n {/* Error Message */}\n {aiError && (\n <div className=\"border-danger bg-danger/10 text-danger rounded-2xl border-2 px-4 py-3 text-sm\">\n {aiError}\n </div>\n )}\n\n {/* Generated Result */}\n {aiImageUrl && (\n <div className=\"flex flex-col gap-4 rounded-2xl border border-divider bg-muted/40 p-6\">\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-muted text-xs uppercase tracking-wide\">Generated Image</Label>\n {aiProvider === 'recraft' && aiResult && (\n <span className=\"rounded-xs bg-muted px-2 py-1 text-[10px] font-semibold uppercase tracking-wide text-foreground/80\">\n {aiResult.format.toUpperCase()}\n </span>\n )}\n {aiProvider === 'runware' && (\n <span className=\"rounded-xs bg-muted px-2 py-1 text-[10px] font-semibold uppercase tracking-wide text-foreground/80\">\n {RUNWARE_MODELS.find((m) => m.id === runwareModel)?.name}\n </span>\n )}\n </div>\n\n {/* Image Preview */}\n <div className=\"flex w-fit items-center justify-center overflow-hidden rounded-lg bg-white/50 dark:bg-black/50\" style={{ maxHeight: '500px', maxWidth: '100%' }}>\n <img\n src={aiImageUrl}\n alt={aiPrompt}\n className=\"max-h-full max-w-full object-contain\"\n />\n </div>\n\n {/* Prompt Display */}\n <div className=\"flex flex-col gap-1\">\n <Label className=\"text-muted text-xs\">Prompt</Label>\n <p className=\"text-sm\">{aiProvider === 'recraft' && aiResult ? aiResult.prompt : aiPrompt}</p>\n </div>\n\n {/* Action Buttons */}\n <div className=\"flex flex-col gap-3\">\n {/* Remove Background Button */}\n {isFalConfigured() && (\n <Button\n onClick={async () => {\n if (!aiImageUrl) return;\n\n setRemovingBackground(true);\n setBackgroundRemovalError(null);\n\n try {\n let imageUrlToProcess = aiImageUrl;\n\n // Convert SVG to PNG if needed\n if (isSvgImage(aiImageUrl)) {\n imageUrlToProcess = await convertSvgToPng(aiImageUrl);\n }\n\n // Call fal.ai API\n const result = await removeBackground(imageUrlToProcess, {\n syncMode: false,\n });\n\n // Convert result to data URL\n const dataUrl = await convertToDataUrl(result.image.url);\n\n // Update AI image preview\n setAiImageUrl(dataUrl);\n } catch (err) {\n setBackgroundRemovalError(err instanceof Error ? err.message : 'Failed to remove background');\n } finally {\n setRemovingBackground(false);\n }\n }}\n disabled={removingBackground || !aiImageUrl}\n variant=\"secondary\"\n size=\"sm\"\n className=\"w-full gap-2\"\n data-testid=\"ai-remove-background-btn\"\n >\n {removingBackground ? (\n <>\n <Icon icon=\"eos-icons:loading\" className=\"size-4 animate-spin\" />\n Removing...\n </>\n ) : (\n <>\n <Icon icon=\"mdi:image-remove\" className=\"size-4\" />\n Remove Background\n </>\n )}\n </Button>\n )}\n\n {/* Background Removal Error */}\n {backgroundRemovalError && (\n <div className=\"border-danger bg-danger/10 text-danger rounded-xl border-2 px-3 py-2 text-xs\">\n {backgroundRemovalError}\n </div>\n )}\n\n {/* Use Button */}\n <Button\n onClick={handleAiImageSelect}\n variant=\"default\"\n className=\"w-full\"\n data-testid=\"ai-use-image-btn\"\n >\n Use This Image\n </Button>\n </div>\n </div>\n )}\n </Tabs.Panel>\n </Tabs>\n </Drawer>\n );\n};\n\nexport default ImageBrowserPanel;\n","/**\n * ImagePanel - Standalone image browser component for embedding\n * Uses ImageBrowserPanel internally with editor context integration\n */\n\nimport React, { useState, useCallback, useRef } from 'react';\nimport { useEditor } from '../../contexts/EditorContext.js';\nimport { useSelectionContext } from '../../contexts/SelectionContext.js';\nimport { useArtboards } from '../../hooks/useArtboards.js';\nimport ImageBrowserPanel from '../ImageBrowserDrawer.jsx';\nimport { ImageElement } from '../../core/ImageElement.js';\nimport { isImageElement } from '../../types/guards.js';\n\nexport interface ImagePanelProps {\n /**\n * Whether the panel is open\n */\n isOpen: boolean;\n\n /**\n * Callback when panel open state changes\n */\n onOpenChange: (open: boolean) => void;\n\n /**\n * Callback after image is selected and element is created/updated\n */\n onImageAdded?: (element: ImageElement) => void;\n\n /**\n * Callback after existing image is changed\n */\n onImageChanged?: (element: ImageElement) => void;\n\n /**\n * ID of element to change image for (if changing existing image)\n * If not provided, a new image element will be created\n */\n changingElementId?: string | null;\n\n /**\n * Callback when changing element ID changes\n */\n onChangingElementIdChange?: (id: string | null) => void;\n}\n\n/**\n * Standalone image browser panel component\n *\n * @example\n * ```tsx\n * function EditorWithImageBrowser() {\n * const [isImagePanelOpen, setIsImagePanelOpen] = useState(false);\n * const [changingImageId, setChangingImageId] = useState(null);\n *\n * return (\n * <EditorProvider>\n * <div style={{ display: 'flex' }}>\n * <Canvas />\n * <button onClick={() => setIsImagePanelOpen(true)}>\n * Add Image\n * </button>\n * <ImagePanel\n * isOpen={isImagePanelOpen}\n * onOpenChange={setIsImagePanelOpen}\n * changingElementId={changingImageId}\n * onChangingElementIdChange={setChangingImageId}\n * />\n * </div>\n * </EditorProvider>\n * );\n * }\n * ```\n */\nexport const ImagePanel: React.FC<ImagePanelProps> = ({\n isOpen,\n onOpenChange,\n onImageAdded,\n onImageChanged,\n changingElementId: externalChangingId,\n onChangingElementIdChange,\n}) => {\n const { elements, setElements, canvasEditorRef, artboardManager, executeAddElement, executeElementUpdate } = useEditor();\n const { selectedId, setSelectedId } = useSelectionContext();\n const { activeArtboardId } = useArtboards();\n\n // Use refs for values that change frequently but shouldn't cause callback recreation\n // This prevents ImageCard re-renders when context values change\n const elementsRef = useRef(elements);\n elementsRef.current = elements;\n const selectedIdRef = useRef(selectedId);\n selectedIdRef.current = selectedId;\n\n // Use external changing ID if provided, otherwise manage internally\n const [internalChangingId, setInternalChangingId] = useState<string | null>(null);\n const changingImageElementId = externalChangingId ?? internalChangingId;\n const setChangingImageElementId = onChangingElementIdChange ?? setInternalChangingId;\n\n // Handle image selection from image browser\n const handleImageSelect = useCallback(\n (imageUrl: string) => {\n // Use refs to access latest values without recreating callback\n const currentElements = elementsRef.current;\n const currentSelectedId = selectedIdRef.current;\n\n // If we're changing an existing image\n if (changingImageElementId) {\n const existingElement = currentElements.find((e) => e.id === changingImageElementId);\n if (existingElement && isImageElement(existingElement)) {\n const oldElement = existingElement;\n const updatedElement = existingElement.clone();\n\n // Update the image URL and dimensions\n // Get zoom to scale image dimensions appropriately\n const zoom = canvasEditorRef.current?.getZoom() || 1.0;\n updatedElement.imageUrl = imageUrl;\n updatedElement.transformData.width = 300 / zoom;\n updatedElement.transformData.height = 300 / zoom;\n\n // Reset all image transform properties to defaults for new image\n updatedElement.transformData.cropX = 0;\n updatedElement.transformData.cropY = 0;\n updatedElement.transformData.cropWidth = 1;\n updatedElement.transformData.cropHeight = 1;\n updatedElement.transformData.flipHorizontal = false;\n updatedElement.transformData.flipVertical = false;\n updatedElement.transformData.borderRadius = 0;\n\n // IMPORTANT: Reset imageLoaded flag and crop mode before loading new image\n updatedElement.imageLoaded = false;\n updatedElement.imageElement = null;\n updatedElement.isCropping = false;\n\n // Set up callback for when the image loads\n updatedElement.onLoadCallback = (loadedElement) => {\n // When image loads and dimensions change, update the element in state\n // This bypasses command history since it's just adjusting dimensions\n const el = loadedElement as ImageElement;\n setElements((prevElements) => prevElements.map((s) => (s.id === el.id ? el : s)));\n };\n\n // Load the new image\n updatedElement.loadImage(imageUrl);\n\n // Update through command history (captures the URL change)\n executeElementUpdate(oldElement, updatedElement);\n\n // Callback\n if (onImageChanged) {\n onImageChanged(updatedElement);\n }\n }\n setChangingImageElementId(null);\n return;\n }\n\n // Otherwise, add a new image element\n // Check for active artboard\n if (!activeArtboardId) {\n alert('Please create or select an artboard first');\n return;\n }\n\n // Generate unique ID\n const newId = `element-${Date.now()}`;\n\n // Calculate center of active artboard\n const activeArtboard = artboardManager.getActiveArtboard();\n const centerX = activeArtboard ? activeArtboard.x + activeArtboard.width / 2 : window.innerWidth / 2;\n const centerY = activeArtboard ? activeArtboard.y + activeArtboard.height / 2 : window.innerHeight / 2;\n\n // Get zoom to scale image dimensions appropriately\n const zoom = canvasEditorRef.current?.getZoom() || 1.0;\n\n // Create new image element with selected URL\n const newElement = new ImageElement({\n id: newId,\n x: centerX,\n y: centerY,\n imageUrl: imageUrl,\n transformData: {\n width: 300 / zoom,\n height: 300 / zoom,\n },\n onLoadCallback: (loadedElement) => {\n // When image loads and dimensions change, update the element in state\n const el = loadedElement as ImageElement;\n setElements((prevElements) => prevElements.map((s) => (s.id === el.id ? el : s)));\n },\n });\n\n // Add to elements array and artboard with undo support\n artboardManager.addElementToArtboard(newId, activeArtboardId);\n executeAddElement(newElement, activeArtboardId, currentSelectedId || undefined);\n\n // Select the new element\n setSelectedId(newId);\n\n // Callback\n if (onImageAdded) {\n onImageAdded(newElement);\n }\n },\n [\n changingImageElementId,\n // Note: elements and selectedId are accessed via refs (elementsRef, selectedIdRef)\n // to prevent callback recreation on every context update\n artboardManager,\n executeAddElement,\n executeElementUpdate,\n activeArtboardId,\n canvasEditorRef,\n setElements,\n setSelectedId,\n setChangingImageElementId,\n onImageAdded,\n onImageChanged,\n ]\n );\n\n // Handle panel close - reset changing element ID\n const handleToggle = useCallback(\n (open: boolean) => {\n onOpenChange(open);\n // Reset changing image element ID when drawer closes\n if (!open) {\n setChangingImageElementId(null);\n }\n },\n [onOpenChange, setChangingImageElementId]\n );\n\n // Get current image URL if changing existing element\n // Use elements directly here as this value is used for display, not callbacks\n const currentImageUrl = changingImageElementId\n ? (elements.find((e) => e.id === changingImageElementId) as ImageElement)?.imageUrl\n : undefined;\n\n return (\n <ImageBrowserPanel\n isOpen={isOpen}\n onToggle={handleToggle}\n onImageSelect={handleImageSelect}\n currentImageUrl={currentImageUrl}\n />\n );\n};\n","/**\n * GlyphBrowserDrawer - Browse and insert all glyphs from the current font\n * Opens as a bottom drawer and inserts glyphs at cursor position or appends to text\n */\n\nimport { useState, useEffect } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Input, Badge, Spinner, icons } from './ui';\nimport { Drawer } from './Drawer';\nimport { FontAnalyzer } from '../utils/FontAnalyzer';\nimport { createLogger } from '../utils/logger.js';\nimport type { GlyphAlternate } from '../types';\n\nconst logger = createLogger('GlyphBrowserDrawer');\n\ninterface GlyphBrowserDrawerProps {\n isOpen: boolean;\n onClose: () => void;\n fontFamily: string;\n fontWeight?: number;\n onInsertGlyph: (unicode: string) => void;\n}\n\nexport const GlyphBrowserDrawer = ({\n isOpen,\n onClose,\n fontFamily,\n fontWeight = 400,\n onInsertGlyph,\n}: GlyphBrowserDrawerProps) => {\n const [glyphs, setGlyphs] = useState<GlyphAlternate[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [searchQuery, setSearchQuery] = useState('');\n\n // Load all glyphs when drawer opens\n useEffect(() => {\n if (!isOpen) return;\n\n setLoading(true);\n setError(null);\n setSearchQuery('');\n\n FontAnalyzer.getAllGlyphs(fontFamily, fontWeight)\n .then((glyphList) => {\n if (glyphList.length === 0) {\n setError(`No alternate glyphs found in ${fontFamily}`);\n }\n setGlyphs(glyphList);\n setLoading(false);\n })\n .catch((err) => {\n logger.error('Error loading glyphs:', err);\n setError('Failed to load glyphs');\n setLoading(false);\n });\n }, [isOpen, fontFamily, fontWeight]);\n\n const handleSelectGlyph = (glyph: GlyphAlternate) => {\n // Calculate the character to insert\n // If glyph has a real Unicode codepoint, use it\n // Otherwise, map to PUA (Private Use Area) using: U+F0000 + glyphIndex\n let charToInsert = glyph.unicode;\n\n // Check if this is already a valid single character with a codepoint\n if (!charToInsert || charToInsert.length === 0) {\n // No unicode - use PUA mapping\n charToInsert = String.fromCodePoint(0xf0000 + glyph.glyphIndex);\n } else {\n // Check if the unicode is actually mapped (not just extracted from name)\n // If unicode is a single basic letter like \"T\", this might be an alternate\n // without its own codepoint, so use PUA mapping\n const codePoint = charToInsert.codePointAt(0);\n if (codePoint && codePoint < 0xe000) {\n // This is a basic character (A-Z, etc), likely extracted from glyph name\n // Use PUA mapping instead\n charToInsert = String.fromCodePoint(0xf0000 + glyph.glyphIndex);\n }\n }\n\n onInsertGlyph(charToInsert);\n // Don't close the drawer - allow multiple insertions\n };\n\n // Filter glyphs based on search\n const filteredGlyphs = searchQuery\n ? glyphs.filter(\n (g) =>\n g.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n g.unicode.toLowerCase().includes(searchQuery.toLowerCase())\n )\n : glyphs;\n\n return (\n <Drawer\n isOpen={isOpen}\n onClose={onClose}\n title={`Browse Glyphs - ${fontFamily}`}\n description={`Browse and select alternate glyphs for the ${fontFamily} font`}\n maxHeight=\"75vh\"\n showCloseButton={true}\n >\n {/* Search Header */}\n <div className=\"px-6 py-4 border-b border-black/10 dark:border-white/10\">\n <div className=\"relative\">\n <Icon\n icon={icons.search}\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-muted pointer-events-none size-4 z-10\"\n />\n <Input\n type=\"text\"\n placeholder=\"Search glyphs...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n </div>\n\n {/* Content */}\n <div className=\"flex-1 overflow-y-auto p-6\">\n {loading && (\n <div className=\"py-12 text-center text-muted\">\n <Spinner size=\"lg\" className=\"mx-auto mb-4\" />\n <div className=\"text-sm\">Loading glyphs...</div>\n </div>\n )}\n\n {error && (\n <div className=\"py-12 text-center\">\n <Icon icon={icons.alertCircle} className=\"size-12 mx-auto mb-4 text-danger\" />\n <div className=\"text-base font-medium mb-2\">{error}</div>\n <div className=\"text-sm text-muted\">This font may not have alternate glyphs.</div>\n </div>\n )}\n\n {!loading && !error && filteredGlyphs.length === 0 && searchQuery && (\n <div className=\"py-12 text-center\">\n <Icon icon={icons.search} className=\"size-12 mx-auto mb-4 text-muted\" />\n <div className=\"text-base font-medium\">No glyphs found matching \"{searchQuery}\"</div>\n </div>\n )}\n\n {!loading && !error && filteredGlyphs.length > 0 && (\n <div className=\"grid grid-cols-[repeat(auto-fill,minmax(100px,1fr))] gap-4\">\n {filteredGlyphs.map((glyph, index) => (\n <button\n key={`${glyph.glyphIndex}-${index}`}\n onClick={() => handleSelectGlyph(glyph)}\n className=\"group relative flex aspect-square cursor-pointer flex-col items-center gap-2 rounded-xl border-2 border-black/10 bg-black/5 p-3 transition-all hover:border-accent hover:bg-black/10 hover:shadow-lg dark:border-white/10 dark:bg-white/5 dark:hover:border-accent dark:hover:bg-white/10\"\n >\n {/* Preview */}\n {glyph.previewDataUrl ? (\n <img src={glyph.previewDataUrl} alt={glyph.name} className=\"h-auto w-full object-contain\" />\n ) : (\n <div className=\"text-5xl leading-none\" style={{ fontFamily }}>\n {glyph.unicode}\n </div>\n )}\n\n {/* Label */}\n <div className=\"w-full overflow-hidden text-ellipsis whitespace-nowrap text-center text-xs text-muted\">\n {glyph.name}\n </div>\n\n {/* Category badge */}\n {glyph.category !== 'default' && (\n <Badge\n size=\"sm\"\n color={\n glyph.category === 'swash'\n ? 'warning'\n : glyph.category === 'stylistic'\n ? 'primary'\n : 'success'\n }\n className=\"absolute right-1 top-1 text-[10px] font-semibold uppercase\"\n >\n {glyph.category === 'swash'\n ? 'SW'\n : glyph.category === 'stylistic'\n ? 'ALT'\n : glyph.category === 'ligature'\n ? 'LIG'\n : ''}\n </Badge>\n )}\n </button>\n ))}\n </div>\n )}\n\n {/* Footer Info */}\n {!loading && !error && filteredGlyphs.length > 0 && (\n <div className=\"mt-6 pt-4 border-t border-black/10 dark:border-white/10 text-center text-sm text-muted\">\n {filteredGlyphs.length} glyph{filteredGlyphs.length !== 1 ? 's' : ''} available\n {searchQuery && ` matching \"${searchQuery}\"`}\n </div>\n )}\n </div>\n </Drawer>\n );\n};\n","/**\n * GlyphPanel - Standalone glyph browser component for embedding\n * Browses and inserts font glyphs (alternates, ligatures, swashes) into text elements\n */\n\nimport React, { useCallback } from 'react';\nimport { useEditor } from '../../contexts/EditorContext.js';\nimport { GlyphBrowserDrawer } from '../GlyphBrowserDrawer.js';\nimport { TextElement } from '../../core/TextElement.js';\nimport { FontAnalyzer } from '../../utils/FontAnalyzer.js';\nimport { createLogger } from '../../utils/logger.js';\n\nconst logger = createLogger('GlyphPanel');\n\nexport interface GlyphPanelProps {\n /**\n * Whether the panel is open\n */\n isOpen: boolean;\n\n /**\n * Callback when panel should close\n */\n onClose: () => void;\n\n /**\n * Font family to browse glyphs for\n * If not provided, uses the selected text element's font\n */\n fontFamily?: string;\n\n /**\n * Font weight to browse glyphs for\n * If not provided, uses the selected text element's weight\n */\n fontWeight?: number;\n\n /**\n * Custom glyph insertion handler\n * If not provided, uses the default handler that updates the selected element\n */\n onInsertGlyph?: (unicode: string) => void;\n\n /**\n * Text element to insert glyphs into\n * If not provided, uses the selected element from context\n */\n element?: TextElement | null;\n}\n\n/**\n * Standalone glyph browser panel component\n *\n * @example Using with context (automatic)\n * ```tsx\n * function App() {\n * const [isOpen, setIsOpen] = useState(false);\n *\n * return (\n * <EditorProvider>\n * <Canvas />\n * <button onClick={() => setIsOpen(true)}>Browse Glyphs</button>\n * <GlyphPanel\n * isOpen={isOpen}\n * onClose={() => setIsOpen(false)}\n * />\n * </EditorProvider>\n * );\n * }\n * ```\n *\n * @example Using with custom font\n * ```tsx\n * function App() {\n * return (\n * <EditorProvider>\n * <GlyphPanel\n * isOpen={true}\n * onClose={() => {}}\n * fontFamily=\"Playfair Display\"\n * fontWeight={700}\n * />\n * </EditorProvider>\n * );\n * }\n * ```\n */\nexport const GlyphPanel: React.FC<GlyphPanelProps> = ({\n isOpen,\n onClose,\n fontFamily: externalFontFamily,\n fontWeight: externalFontWeight,\n onInsertGlyph: externalOnInsertGlyph,\n element: externalElement,\n}) => {\n const { selectedElement, executeElementUpdate } = useEditor();\n\n // Use external element if provided, otherwise use selected element\n const element = externalElement !== undefined ? externalElement : (selectedElement || null);\n\n // Get font family from props or element\n const fontFamily = externalFontFamily || (element instanceof TextElement ? element.fontFamily : 'Arial');\n\n // Get font weight from props or element\n const fontWeight = externalFontWeight || (element instanceof TextElement && element.bold ? 700 : 400);\n\n // Handle glyph insertion\n const handleInsertGlyph = useCallback(\n async (unicode: string) => {\n if (externalOnInsertGlyph) {\n // Use external handler if provided\n externalOnInsertGlyph(unicode);\n return;\n }\n\n // Default behavior: insert into selected text element\n if (!element || !(element instanceof TextElement)) {\n logger.warn('No text element selected for glyph insertion');\n return;\n }\n\n // Pre-load the font to ensure rendering works\n try {\n await FontAnalyzer.loadFont(fontFamily, fontWeight);\n } catch (err) {\n logger.error('Error pre-loading font for glyph rendering:', err);\n }\n\n const updatedElement = element.clone();\n\n // Simply append the unicode/PUA character to the text\n updatedElement.text = updatedElement.text + unicode;\n\n executeElementUpdate(element, updatedElement);\n },\n [externalOnInsertGlyph, element, fontFamily, fontWeight, executeElementUpdate]\n );\n\n return (\n <GlyphBrowserDrawer\n isOpen={isOpen}\n onClose={onClose}\n fontFamily={fontFamily}\n fontWeight={fontWeight}\n onInsertGlyph={handleInsertGlyph}\n />\n );\n};\n","/**\n * ArtboardTabs - Standalone artboard switcher component\n * Uses useArtboards hook for data and operations\n */\n\nimport React, { useState } from 'react';\nimport { useArtboards } from '../../hooks/useArtboards.js';\nimport { Icon } from '@iconify/react';\nimport { icons } from '../ui';\n\nexport interface ArtboardTabsProps {\n /**\n * Tab orientation\n */\n orientation?: 'horizontal' | 'vertical';\n\n /**\n * Show \"Add Artboard\" button\n */\n showAddButton?: boolean;\n\n /**\n * Show close buttons on tabs\n */\n showCloseButtons?: boolean;\n\n /**\n * Maximum tab width (for horizontal tabs)\n */\n maxTabWidth?: number;\n\n /**\n * Custom CSS styles\n */\n style?: React.CSSProperties;\n\n /**\n * Custom class name\n */\n className?: string;\n\n /**\n * Callback when a new artboard is created\n */\n onArtboardCreate?: (artboardId: string) => void;\n\n /**\n * Callback when an artboard is deleted\n */\n onArtboardDelete?: (artboardId: string) => void;\n}\n\n/**\n * Standalone artboard tabs component\n *\n * @example Horizontal tabs\n * ```tsx\n * function EditorWithTabs() {\n * return (\n * <EditorProvider>\n * <div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>\n * <ArtboardTabs\n * orientation=\"horizontal\"\n * showAddButton={true}\n * showCloseButtons={true}\n * />\n * <Canvas />\n * </div>\n * </EditorProvider>\n * );\n * }\n * ```\n *\n * @example Vertical tabs\n * ```tsx\n * function EditorWithSideTabs() {\n * return (\n * <EditorProvider>\n * <div style={{ display: 'flex' }}>\n * <ArtboardTabs\n * orientation=\"vertical\"\n * showAddButton={true}\n * />\n * <Canvas />\n * </div>\n * </EditorProvider>\n * );\n * }\n * ```\n */\nexport const ArtboardTabs: React.FC<ArtboardTabsProps> = ({\n orientation = 'horizontal',\n showAddButton = true,\n showCloseButtons = false,\n maxTabWidth = 200,\n style = {},\n className = '',\n onArtboardCreate,\n onArtboardDelete,\n}) => {\n const {\n artboardsInfo,\n selectArtboard,\n createArtboard,\n deleteArtboard,\n renameArtboard,\n } = useArtboards();\n\n const [renamingId, setRenamingId] = useState<string | null>(null);\n const [newName, setNewName] = useState('');\n\n // Start renaming an artboard\n const startRename = (id: string, currentName: string) => {\n setRenamingId(id);\n setNewName(currentName);\n };\n\n // Finish renaming\n const finishRename = () => {\n if (renamingId && newName.trim()) {\n renameArtboard(renamingId, newName.trim());\n }\n setRenamingId(null);\n setNewName('');\n };\n\n // Cancel renaming\n const cancelRename = () => {\n setRenamingId(null);\n setNewName('');\n };\n\n // Handle add artboard\n const handleAddArtboard = () => {\n createArtboard(1200, 1200, {\n name: `Artboard ${artboardsInfo.length + 1}`,\n });\n\n // Get the newly created artboard (last in the list)\n // Note: In a real implementation, createArtboard should return the new artboard ID\n // For now, we'll call the callback after a short delay\n if (onArtboardCreate) {\n setTimeout(() => {\n const newArtboard = artboardsInfo[artboardsInfo.length];\n if (newArtboard) {\n onArtboardCreate(newArtboard.id);\n }\n }, 10);\n }\n };\n\n // Handle delete artboard\n const handleDeleteArtboard = (id: string, e: React.MouseEvent) => {\n e.stopPropagation();\n\n // Prevent deleting the last artboard\n if (artboardsInfo.length <= 1) {\n alert('Cannot delete the last artboard');\n return;\n }\n\n if (confirm('Delete this artboard?')) {\n deleteArtboard(id);\n if (onArtboardDelete) {\n onArtboardDelete(id);\n }\n }\n };\n\n // Container styles based on orientation\n const containerStyle: React.CSSProperties =\n orientation === 'horizontal'\n ? {\n display: 'flex',\n flexDirection: 'row',\n gap: 4,\n padding: 8,\n backgroundColor: 'var(--bg-secondary)',\n borderBottom: '1px solid var(--border-primary)',\n overflowX: 'auto',\n overflowY: 'hidden',\n ...style,\n }\n : {\n display: 'flex',\n flexDirection: 'column',\n gap: 4,\n padding: 8,\n backgroundColor: 'var(--bg-secondary)',\n borderRight: '1px solid var(--border-primary)',\n overflowY: 'auto',\n overflowX: 'hidden',\n minWidth: 200,\n ...style,\n };\n\n // Tab styles\n const tabStyle = (isActive: boolean): React.CSSProperties => ({\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: '8px 12px',\n backgroundColor: isActive ? 'var(--accent-primary)' : 'var(--bg-primary)',\n color: isActive ? 'var(--primary-foreground)' : 'var(--text-primary)',\n border: isActive ? 'none' : '1px solid var(--border-primary)',\n borderRadius: 6,\n cursor: 'pointer',\n fontSize: 13,\n fontWeight: isActive ? 600 : 400,\n whiteSpace: 'nowrap',\n maxWidth: orientation === 'horizontal' ? maxTabWidth : undefined,\n minWidth: orientation === 'horizontal' ? 120 : undefined,\n transition: 'all 0.2s',\n });\n\n return (\n <div className={`artboard-tabs ${className}`} style={containerStyle}>\n {/* Artboard tabs */}\n {artboardsInfo.map((artboard) => {\n const isRenaming = renamingId === artboard.id;\n\n return (\n <div\n key={artboard.id}\n style={tabStyle(artboard.isActive)}\n onClick={() => !isRenaming && selectArtboard(artboard.id)}\n onDoubleClick={() => startRename(artboard.id, artboard.name)}\n >\n {/* Artboard name or rename input */}\n {isRenaming ? (\n <input\n type=\"text\"\n value={newName}\n onChange={(e) => setNewName(e.target.value)}\n onBlur={finishRename}\n onKeyDown={(e) => {\n if (e.key === 'Enter') finishRename();\n if (e.key === 'Escape') cancelRename();\n }}\n autoFocus\n onClick={(e) => e.stopPropagation()}\n style={{\n flex: 1,\n padding: '2px 4px',\n border: '1px solid var(--border-primary)',\n borderRadius: 4,\n fontSize: 13,\n minWidth: 80,\n }}\n />\n ) : (\n <span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {artboard.name}\n </span>\n )}\n\n {/* Element count badge */}\n <span\n style={{\n fontSize: 11,\n opacity: 0.7,\n padding: '2px 6px',\n borderRadius: 10,\n backgroundColor: artboard.isActive ? 'color-mix(in srgb, var(--primary-foreground) 20%, transparent)' : 'var(--bg-secondary)',\n }}\n >\n {artboard.elementCount}\n </span>\n\n {/* Close button */}\n {showCloseButtons && (\n <button\n onClick={(e) => handleDeleteArtboard(artboard.id, e)}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: 2,\n display: 'flex',\n alignItems: 'center',\n opacity: 0.7,\n transition: 'opacity 0.2s',\n }}\n onMouseEnter={(e) => (e.currentTarget.style.opacity = '1')}\n onMouseLeave={(e) => (e.currentTarget.style.opacity = '0.7')}\n title=\"Delete artboard\"\n >\n <Icon icon={icons.close} className=\"size-3.5\" />\n </button>\n )}\n </div>\n );\n })}\n\n {/* Add artboard button */}\n {showAddButton && (\n <button\n onClick={handleAddArtboard}\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 6,\n padding: '8px 12px',\n backgroundColor: 'var(--bg-primary)',\n border: '1px dashed var(--border-primary)',\n borderRadius: 6,\n cursor: 'pointer',\n fontSize: 13,\n color: 'var(--text-secondary)',\n minWidth: orientation === 'horizontal' ? 120 : undefined,\n transition: 'all 0.2s',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--bg-tertiary)';\n e.currentTarget.style.borderColor = 'var(--accent-primary)';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'var(--bg-primary)';\n e.currentTarget.style.borderColor = 'var(--border-primary)';\n }}\n title=\"Add new artboard\"\n >\n <Icon icon={icons.plus} className=\"size-3.5\" />\n <span>New Artboard</span>\n </button>\n )}\n </div>\n );\n};\n","/**\n * BackButton - Reusable back button for toolbar menus\n */\n\nimport { Button, Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './ui';\n\nconst BackIcon = () => (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n className=\"shrink-0\"\n >\n <path d=\"M19 12H5M12 19l-7-7 7-7\" />\n </svg>\n);\n\nexport function BackButton({ onClick }: { onClick: () => void }) {\n return (\n <TooltipProvider delayDuration={300}>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"outline\"\n onClick={onClick}\n className=\"mr-sm border-r-border-primary pr-md\"\n aria-label=\"Back\"\n >\n <BackIcon />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Back</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n );\n}\n\nexport default BackButton;\n","/**\n * featureApplied — derive boolean flags from a canvas element saying\n * \"this feature has a non-default value.\" Used by toolbar buttons to\n * paint the active/selected style not just when the panel is open\n * but also when the property has actually been applied to the\n * element. Lets users tell at a glance whether a layer is rotated /\n * has a stroke / has a knockout / etc.\n *\n * Default values match the element constructors: rotation=0,\n * opacity=1, borderRadius=0, fillOpacity=1, blendMode unset, no\n * masks, no stroke, no distress.\n */\n\nimport type { BaseElement } from '../core/BaseElement.js';\n\nconst EPSILON = 0.001;\n\nexport interface FeatureAppliedFlags {\n rotation: boolean;\n opacity: boolean;\n stroke: boolean;\n knockout: boolean;\n distress: boolean;\n imageMask: boolean;\n /** Image: `transformData.borderRadius`. */\n cornerRadius: boolean;\n /** Shape: `transformData.fillOpacity`. */\n shapeTransparency: boolean;\n}\n\nexport function getFeatureApplied(element: BaseElement | null | undefined): FeatureAppliedFlags {\n if (!element) {\n return {\n rotation: false,\n opacity: false,\n stroke: false,\n knockout: false,\n distress: false,\n imageMask: false,\n cornerRadius: false,\n shapeTransparency: false,\n };\n }\n\n const td = element.transformData as\n | { borderRadius?: number; fillOpacity?: number }\n | undefined;\n\n return {\n rotation: Math.abs(element.rotation ?? 0) > EPSILON,\n opacity: (element.opacity ?? 1) < 1 - EPSILON,\n stroke: element.stroke?.enabled === true,\n knockout: element.blendMode === 'knockout' || element.blendMode === 'clip',\n distress: element.distressEffect?.enabled === true,\n imageMask: !!element.masks && element.masks.length > 0,\n cornerRadius: (td?.borderRadius ?? 0) > 0,\n shapeTransparency: (td?.fillOpacity ?? 1) < 1 - EPSILON,\n };\n}\n","/**\n * ImageToolbar - Toolbar for image-specific controls\n * Handles crop, flip, and border radius controls\n */\n\nimport React, { useState } from 'react';\nimport { Tooltip, TooltipTrigger, TooltipContent, ToolbarButton, Button, Popover, PopoverTrigger, PopoverContent } from './ui';\nimport { Icon } from '@iconify/react';\nimport { ImageElement } from '../core/ImageElement';\nimport { RotateLeftIcon } from './ui/custom-icons';\nimport { icons } from './ui/icons';\nimport { getFeatureApplied } from '../utils/featureApplied.js';\n\ninterface ImageToolbarProps {\n element: ImageElement;\n onElementUpdate: (element: ImageElement) => void;\n showUngroupButton?: boolean;\n onUngroup?: () => void;\n onMoveForward?: () => void;\n onMoveBackward?: () => void;\n onChangeImage?: () => void;\n /** Callback when element should be deleted */\n onDelete?: () => void;\n /** Whether the corner radius panel is expanded */\n cornerRadiusExpanded?: boolean;\n /** Callback when corner radius panel should be toggled */\n onCornerRadiusToggle?: () => void;\n /** Whether the crop panel is expanded */\n cropExpanded?: boolean;\n /** Callback when crop panel should be toggled */\n onCropToggle?: () => void;\n /** Whether the rotation panel is expanded */\n rotationExpanded?: boolean;\n /** Callback when rotation panel should be toggled */\n onRotationToggle?: () => void;\n /** Whether the opacity panel is expanded */\n opacityExpanded?: boolean;\n /** Callback when opacity panel should be toggled */\n onOpacityToggle?: () => void;\n /** Whether the stroke panel is expanded */\n strokeExpanded?: boolean;\n /** Callback when stroke panel should be toggled */\n onStrokeToggle?: () => void;\n /** Whether the knockout panel is expanded */\n knockoutExpanded?: boolean;\n /** Callback when knockout panel should be toggled */\n onKnockoutToggle?: () => void;\n /** Whether the distress texture panel is expanded */\n distressTextureExpanded?: boolean;\n /** Callback when distress texture panel should be toggled */\n onDistressTextureToggle?: () => void;\n /** Whether the image mask panel is expanded */\n imageMaskExpanded?: boolean;\n /** Callback when image mask panel should be toggled */\n onImageMaskToggle?: () => void;\n}\n\nconst ImageToolbar: React.FC<ImageToolbarProps> = ({\n element,\n onElementUpdate,\n showUngroupButton = false,\n onUngroup,\n onMoveForward,\n onMoveBackward,\n onChangeImage,\n onDelete,\n cornerRadiusExpanded = false,\n onCornerRadiusToggle,\n cropExpanded = false,\n onCropToggle,\n rotationExpanded = false,\n onRotationToggle,\n opacityExpanded = false,\n onOpacityToggle,\n strokeExpanded = false,\n onStrokeToggle,\n knockoutExpanded = false,\n onKnockoutToggle,\n distressTextureExpanded = false,\n onDistressTextureToggle,\n imageMaskExpanded = false,\n onImageMaskToggle,\n}) => {\n const [moreMenuOpen, setMoreMenuOpen] = useState<boolean>(false);\n const [changeImageTooltipDisabled, setChangeImageTooltipDisabled] = useState(false);\n const [cornerRadiusTooltipDisabled, setCornerRadiusTooltipDisabled] = useState(false);\n const [cropTooltipDisabled, setCropTooltipDisabled] = useState(false);\n const [rotationTooltipDisabled, setRotationTooltipDisabled] = useState(false);\n const [opacityTooltipDisabled, setOpacityTooltipDisabled] = useState(false);\n const [strokeTooltipDisabled, setStrokeTooltipDisabled] = useState(false);\n const [knockoutTooltipDisabled, setKnockoutTooltipDisabled] = useState(false);\n const [distressTooltipDisabled, setDistressTooltipDisabled] = useState(false);\n const [imageMaskTooltipDisabled, setImageMaskTooltipDisabled] = useState(false);\n\n // Check if element is in crop mode\n const isCropping = element.isCropping;\n\n // Feature-applied flags — drive the \"selected\" highlight on the\n // toolbar buttons whose underlying property is set to a non-default\n // value. Combined with the panel-open flag below.\n const applied = getFeatureApplied(element);\n\n const handleCropToggle = () => {\n setCropTooltipDisabled(true);\n if (isCropping) {\n // Exit crop mode\n const updatedElement = element.clone();\n updatedElement.exitCropMode();\n onElementUpdate(updatedElement);\n } else {\n // Enter crop mode\n const updatedElement = element.clone();\n updatedElement.enterCropMode();\n onElementUpdate(updatedElement);\n }\n onCropToggle?.();\n };\n\n const handleFlipHorizontal = () => {\n const updatedElement = element.clone();\n updatedElement.transformData.flipHorizontal = !updatedElement.transformData.flipHorizontal;\n onElementUpdate(updatedElement);\n };\n\n const handleFlipVertical = () => {\n const updatedElement = element.clone();\n updatedElement.transformData.flipVertical = !updatedElement.transformData.flipVertical;\n onElementUpdate(updatedElement);\n };\n\n return (\n <div className=\"toolbar-items\">\n {/* Change Image button */}\n {onChangeImage && (\n <ToolbarButton\n icon=\"lucide:image\"\n onClick={() => {\n setChangeImageTooltipDisabled(true);\n onChangeImage();\n }}\n onMouseLeave={() => setChangeImageTooltipDisabled(false)}\n tooltip=\"Change Image\"\n tooltipDisabled={changeImageTooltipDisabled}\n />\n )}\n\n {/* Crop button */}\n <ToolbarButton\n icon=\"lucide:crop\"\n onClick={handleCropToggle}\n onMouseLeave={() => setCropTooltipDisabled(false)}\n tooltip={isCropping ? 'Exit Crop Mode' : 'Crop'}\n tooltipDisabled={cropTooltipDisabled || cropExpanded}\n active={isCropping || cropExpanded}\n />\n\n {/* Flip Horizontal button */}\n <ToolbarButton icon=\"lucide:flip-horizontal-2\" onClick={handleFlipHorizontal} tooltip=\"Flip Horizontal\" />\n\n {/* Flip Vertical button */}\n <ToolbarButton icon=\"lucide:flip-vertical-2\" onClick={handleFlipVertical} tooltip=\"Flip Vertical\" />\n\n {/* Rotate button - toggles rotation panel */}\n <ToolbarButton\n icon={<RotateLeftIcon size={20} className=\"md:size-5\" />}\n onClick={() => {\n setRotationTooltipDisabled(true);\n onRotationToggle?.();\n }}\n onMouseLeave={() => setRotationTooltipDisabled(false)}\n tooltip=\"Rotate\"\n tooltipDisabled={rotationTooltipDisabled || rotationExpanded}\n active={rotationExpanded || applied.rotation}\n />\n\n {/* Transparency button - toggles transparency panel */}\n <ToolbarButton\n icon=\"lucide:blend\"\n onClick={() => {\n setOpacityTooltipDisabled(true);\n onOpacityToggle?.();\n }}\n onMouseLeave={() => setOpacityTooltipDisabled(false)}\n tooltip=\"Transparency\"\n tooltipDisabled={opacityTooltipDisabled || opacityExpanded}\n active={opacityExpanded || applied.opacity}\n />\n\n {/* Border radius control - toggle button for embedded panel */}\n <ToolbarButton\n icon=\"lucide:square-round-corner\"\n onClick={() => {\n setCornerRadiusTooltipDisabled(true);\n onCornerRadiusToggle?.();\n }}\n onMouseLeave={() => setCornerRadiusTooltipDisabled(false)}\n tooltip=\"Corner Radius\"\n tooltipDisabled={cornerRadiusTooltipDisabled || cornerRadiusExpanded}\n active={cornerRadiusExpanded || applied.cornerRadius}\n />\n\n {/* Knockout */}\n {onKnockoutToggle && (\n <ToolbarButton\n icon=\"lucide:scissors\"\n onClick={() => {\n setKnockoutTooltipDisabled(true);\n onKnockoutToggle();\n }}\n onMouseLeave={() => setKnockoutTooltipDisabled(false)}\n tooltip=\"Clip / Knockout\"\n tooltipDisabled={knockoutTooltipDisabled || knockoutExpanded}\n active={knockoutExpanded || applied.knockout}\n />\n )}\n\n {/* Distress Texture */}\n {onDistressTextureToggle && (\n <ToolbarButton\n icon=\"lucide:stamp\"\n onClick={() => {\n setDistressTooltipDisabled(true);\n onDistressTextureToggle();\n }}\n onMouseLeave={() => setDistressTooltipDisabled(false)}\n tooltip=\"Distress Texture\"\n tooltipDisabled={distressTooltipDisabled || distressTextureExpanded}\n active={distressTextureExpanded || applied.distress}\n />\n )}\n\n {/* Image Mask */}\n {onImageMaskToggle && (\n <ToolbarButton\n icon=\"lucide:venetian-mask\"\n onClick={() => {\n setImageMaskTooltipDisabled(true);\n onImageMaskToggle();\n }}\n onMouseLeave={() => setImageMaskTooltipDisabled(false)}\n tooltip=\"Image Mask\"\n tooltipDisabled={imageMaskTooltipDisabled || imageMaskExpanded}\n active={imageMaskExpanded || applied.imageMask}\n />\n )}\n\n {/* Stroke */}\n {onStrokeToggle && (\n <ToolbarButton\n icon=\"lucide:pen-line\"\n onClick={() => {\n setStrokeTooltipDisabled(true);\n onStrokeToggle();\n }}\n onMouseLeave={() => setStrokeTooltipDisabled(false)}\n tooltip=\"Stroke\"\n tooltipDisabled={strokeTooltipDisabled || strokeExpanded}\n active={strokeExpanded || applied.stroke}\n />\n )}\n\n {/* More Menu - overflow menu for additional options */}\n {(onMoveForward || onMoveBackward || onDelete) && (\n <Popover open={moreMenuOpen} onOpenChange={setMoreMenuOpen}>\n <PopoverTrigger asChild>\n <button className=\"toolbar-btn\" aria-label=\"More options\">\n <Icon icon=\"lucide:ellipsis-vertical\" className=\"size-6\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-auto p-1\" maxZIndex>\n <div className=\"flex items-center gap-1\">\n {onMoveForward && (\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n onMoveForward();\n setMoreMenuOpen(false);\n }}\n aria-label=\"Move Forward\"\n >\n <Icon icon=\"hugeicons:layer-bring-forward\" className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Forward</TooltipContent>\n </Tooltip>\n )}\n {onMoveBackward && (\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n onMoveBackward();\n setMoreMenuOpen(false);\n }}\n aria-label=\"Move Backward\"\n >\n <Icon icon=\"hugeicons:layer-send-backward\" className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Backward</TooltipContent>\n </Tooltip>\n )}\n {onDelete && (\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n setMoreMenuOpen(false);\n onDelete();\n }}\n aria-label=\"Delete\"\n >\n <Icon icon={icons.trash} className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n )}\n </div>\n </PopoverContent>\n </Popover>\n )}\n\n {/* Ungroup button - shown when editing a child in a group */}\n {showUngroupButton && onUngroup && (\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" onClick={onUngroup}>\n Ungroup\n </Button>\n </TooltipTrigger>\n <TooltipContent>Ungroup this group</TooltipContent>\n </Tooltip>\n )}\n </div>\n );\n};\n\nexport default ImageToolbar;\n","/**\n * Artboard Color Presets\n * A curated set of 10 background colors for artboards\n */\n\nexport interface ArtboardColor {\n id: string;\n name: string;\n color: string; // Hex color\n}\n\n/**\n * Artboard color presets\n * Includes a variety of colors for different design needs\n */\nexport const ARTBOARD_COLORS: ArtboardColor[] = [\n { id: 'white', name: 'White', color: '#FFFFFF' },\n { id: 'light-gray', name: 'Light Gray', color: '#E5E5E5' },\n { id: 'medium-gray', name: 'Medium Gray', color: '#999999' },\n { id: 'dark-gray', name: 'Dark Gray', color: '#333333' },\n { id: 'black', name: 'Black', color: '#000000' },\n { id: 'orange', name: 'Orange', color: '#FF8800' },\n { id: 'blue', name: 'Blue', color: '#0074D9' },\n { id: 'indigo', name: 'Indigo', color: '#4B0082' },\n { id: 'teal', name: 'Teal', color: '#39CCCC' },\n { id: 'coral', name: 'Coral', color: '#FF6B6B' },\n];\n\n/**\n * Get a random artboard color\n */\nexport function getRandomArtboardColor(): string {\n const randomIndex = Math.floor(Math.random() * ARTBOARD_COLORS.length);\n return ARTBOARD_COLORS[randomIndex].color;\n}\n\n/**\n * Find artboard color by hex value\n */\nexport function findArtboardColor(hexColor: string): ArtboardColor | undefined {\n return ARTBOARD_COLORS.find((c) => c.color.toLowerCase() === hexColor.toLowerCase());\n}\n","/**\n * ShapeToolbar - Toolbar for shape-specific controls\n * Handles shape type, fill color, opacity, and shape-specific parameters\n *\n * Uses callback props for secondary panels (like ImageToolbar) for better mobile UX\n */\n\nimport React, { useState, useMemo } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Button, Popover, PopoverTrigger, PopoverContent, Tooltip, TooltipTrigger, TooltipContent, ToolbarButton, icons, RotateLeftIcon } from './ui';\nimport { ShapeElement } from '../core/ShapeElement';\nimport { getFeatureApplied } from '../utils/featureApplied.js';\n\nimport type { ShapeType } from '../types/index.js';\nimport { ARTBOARD_COLORS } from '../presets/artboard-color-presets.js';\nimport ColorPickerDropdown from './ColorPickerDropdown.jsx';\n\ninterface ShapeToolbarProps {\n element: ShapeElement;\n onElementUpdate: (element: ShapeElement) => void;\n /**\n * Colours actually in use elsewhere in the design (text colours,\n * shape fills, strokes, paths, artboard background). Surfaced in\n * the colour picker so users can match an existing colour. Pass\n * `[]` (or omit) to fall back to the artboard-preset palette.\n */\n documentColors?: string[];\n /**\n * Dominant colours sampled from image elements in the design.\n * Surfaced as a separate \"Image colors\" row in the colour picker.\n */\n imageColors?: string[];\n showUngroupButton?: boolean;\n onUngroup?: () => void;\n onMoveForward?: () => void;\n onMoveBackward?: () => void;\n onOpenShapeTypeDrawer?: () => void;\n /** Callback when element should be deleted */\n onDelete?: () => void;\n /** Whether the rotation panel is expanded */\n rotationExpanded?: boolean;\n /** Callback when rotation panel should be toggled */\n onRotationToggle?: () => void;\n /** Whether the corner radius panel is expanded */\n cornerRadiusExpanded?: boolean;\n /** Callback when corner radius panel should be toggled */\n onCornerRadiusToggle?: () => void;\n /** Whether the transparency/opacity panel is expanded */\n transparencyExpanded?: boolean;\n /** Callback when transparency panel should be toggled */\n onTransparencyToggle?: () => void;\n /** Whether the sides panel is expanded (polygon) */\n sidesExpanded?: boolean;\n /** Callback when sides panel should be toggled */\n onSidesToggle?: () => void;\n /** Whether the points panel is expanded (star) */\n pointsExpanded?: boolean;\n /** Callback when points panel should be toggled */\n onPointsToggle?: () => void;\n /** Whether the inner radius panel is expanded (star) */\n innerRadiusExpanded?: boolean;\n /** Callback when inner radius panel should be toggled */\n onInnerRadiusToggle?: () => void;\n /** Whether the fill color panel is expanded */\n colorExpanded?: boolean;\n /** Callback when fill color panel should be toggled */\n onColorToggle?: () => void;\n /** Whether the stroke panel is expanded */\n strokeExpanded?: boolean;\n /** Callback when stroke panel should be toggled */\n onStrokeToggle?: () => void;\n /** Whether the knockout panel is expanded */\n knockoutExpanded?: boolean;\n /** Callback when knockout panel should be toggled */\n onKnockoutToggle?: () => void;\n /** Whether the distress texture panel is expanded */\n distressTextureExpanded?: boolean;\n /** Callback when distress texture panel should be toggled */\n onDistressTextureToggle?: () => void;\n /** Whether the image mask panel is expanded */\n imageMaskExpanded?: boolean;\n /** Callback when image mask panel should be toggled */\n onImageMaskToggle?: () => void;\n}\n\nconst ShapeToolbar: React.FC<ShapeToolbarProps> = ({\n element,\n onElementUpdate,\n documentColors,\n imageColors,\n showUngroupButton = false,\n onUngroup,\n onMoveForward,\n onMoveBackward,\n onOpenShapeTypeDrawer,\n onDelete,\n rotationExpanded = false,\n onRotationToggle,\n cornerRadiusExpanded = false,\n onCornerRadiusToggle,\n transparencyExpanded = false,\n onTransparencyToggle,\n sidesExpanded = false,\n onSidesToggle,\n pointsExpanded = false,\n onPointsToggle,\n innerRadiusExpanded = false,\n onInnerRadiusToggle,\n colorExpanded = false,\n onColorToggle,\n strokeExpanded = false,\n onStrokeToggle,\n knockoutExpanded = false,\n onKnockoutToggle,\n distressTextureExpanded = false,\n onDistressTextureToggle,\n imageMaskExpanded = false,\n onImageMaskToggle,\n}) => {\n const [moreMenuOpen, setMoreMenuOpen] = useState<boolean>(false);\n const [shapeTypeTooltipDisabled, setShapeTypeTooltipDisabled] = useState<boolean>(false);\n const [rotationTooltipDisabled, setRotationTooltipDisabled] = useState<boolean>(false);\n const [cornerRadiusTooltipDisabled, setCornerRadiusTooltipDisabled] = useState<boolean>(false);\n const [transparencyTooltipDisabled, setTransparencyTooltipDisabled] = useState<boolean>(false);\n const [sidesTooltipDisabled, setSidesTooltipDisabled] = useState<boolean>(false);\n const [pointsTooltipDisabled, setPointsTooltipDisabled] = useState<boolean>(false);\n const [innerRadiusTooltipDisabled, setInnerRadiusTooltipDisabled] = useState<boolean>(false);\n const [colorTooltipDisabled, setColorTooltipDisabled] = useState<boolean>(false);\n const [strokeTooltipDisabled, setStrokeTooltipDisabled] = useState<boolean>(false);\n const [knockoutTooltipDisabled, setKnockoutTooltipDisabled] = useState<boolean>(false);\n const [distressTooltipDisabled, setDistressTooltipDisabled] = useState<boolean>(false);\n const [imageMaskTooltipDisabled, setImageMaskTooltipDisabled] = useState<boolean>(false);\n\n // Prefer colours from the active design (passed in by\n // ContextualToolbars) so users can match a colour they're already\n // using. Fall back to the artboard-preset palette only when the\n // design has no colours yet.\n const presetDocumentColors = useMemo(() => ARTBOARD_COLORS.map((c) => c.color), []);\n const effectiveDocumentColors = useMemo(() => {\n if (documentColors && documentColors.length > 0) return documentColors;\n return presetDocumentColors;\n }, [documentColors, presetDocumentColors]);\n\n // Feature-applied flags — drive the \"selected\" highlight on the\n // toolbar buttons whose underlying property has been set to a\n // non-default value.\n const applied = getFeatureApplied(element);\n\n const handleFillColorChange = (e: { target: { value: string } }) => {\n const updatedElement = element.clone();\n updatedElement.transformData.fillColor = e.target.value;\n onElementUpdate(updatedElement);\n };\n\n // Shape labels for the tooltip — the toolbar button itself uses\n // a generic \"shapes picker\" icon (icons.shapes) rather than the\n // current shape's outline. Showing the current shape made it look\n // like a static label, so users couldn't discover that tapping it\n // opens a picker. The label still names the current shape so the\n // hover tooltip (\"Change Shape (Star)\") gives context.\n const shapeTypeLabels: Record<ShapeType, string> = {\n rectangle: 'Rectangle',\n circle: 'Circle',\n ellipse: 'Ellipse',\n triangle: 'Triangle',\n polygon: 'Polygon',\n star: 'Star',\n line: 'Line',\n };\n\n const currentShapeType = element.transformData.shapeType;\n const currentLabel = shapeTypeLabels[currentShapeType] || 'Shape';\n\n return (\n <div className=\"toolbar-items\">\n {/* Shape Type Button - Opens Drawer (picker affordance) */}\n {onOpenShapeTypeDrawer && (\n <ToolbarButton\n icon={icons.shapes}\n onClick={() => {\n setShapeTypeTooltipDisabled(true);\n onOpenShapeTypeDrawer();\n }}\n onMouseLeave={() => setShapeTypeTooltipDisabled(false)}\n tooltip={`Change Shape (${currentLabel})`}\n tooltipDisabled={shapeTypeTooltipDisabled}\n />\n )}\n\n {/* Fill Color Button - toggles secondary panel */}\n {onColorToggle ? (\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <button\n className=\"toolbar-btn\"\n onClick={() => {\n setColorTooltipDisabled(true);\n onColorToggle();\n }}\n onMouseLeave={() => setColorTooltipDisabled(false)}\n aria-label=\"Fill Color\"\n data-active={colorExpanded}\n >\n <div\n className=\"h-6 w-6 rounded-md border border-border-primary\"\n style={{ backgroundColor: element.transformData.fillColor || '#3b82f6' }}\n />\n </button>\n </TooltipTrigger>\n {!colorTooltipDisabled && !colorExpanded && <TooltipContent>Fill Color</TooltipContent>}\n </Tooltip>\n ) : (\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <div>\n <ColorPickerDropdown\n value={element.transformData.fillColor || '#3b82f6'}\n onChange={handleFillColorChange}\n documentColors={effectiveDocumentColors}\n imageColors={imageColors}\n showSquare={true}\n />\n </div>\n </TooltipTrigger>\n <TooltipContent>Fill Color</TooltipContent>\n </Tooltip>\n )}\n\n {/* Border Radius (Rectangle only) - toggles secondary panel */}\n {element.transformData.shapeType === 'rectangle' && onCornerRadiusToggle && (\n <ToolbarButton\n icon=\"lucide:square-round-corner\"\n onClick={() => {\n setCornerRadiusTooltipDisabled(true);\n onCornerRadiusToggle();\n }}\n onMouseLeave={() => setCornerRadiusTooltipDisabled(false)}\n tooltip=\"Corner Radius\"\n tooltipDisabled={cornerRadiusTooltipDisabled || cornerRadiusExpanded}\n active={cornerRadiusExpanded || applied.cornerRadius}\n />\n )}\n\n {/* Sides (Polygon only) - toggles secondary panel */}\n {element.transformData.shapeType === 'polygon' && onSidesToggle && (\n <ToolbarButton\n icon=\"healthicons:polygon\"\n onClick={() => {\n setSidesTooltipDisabled(true);\n onSidesToggle();\n }}\n onMouseLeave={() => setSidesTooltipDisabled(false)}\n tooltip=\"Sides\"\n tooltipDisabled={sidesTooltipDisabled || sidesExpanded}\n active={sidesExpanded}\n />\n )}\n\n {/* Points (Star only) - toggles secondary panel */}\n {element.transformData.shapeType === 'star' && onPointsToggle && (\n <ToolbarButton\n icon=\"material-symbols:award-star-outline\"\n onClick={() => {\n setPointsTooltipDisabled(true);\n onPointsToggle();\n }}\n onMouseLeave={() => setPointsTooltipDisabled(false)}\n tooltip=\"Points\"\n tooltipDisabled={pointsTooltipDisabled || pointsExpanded}\n active={pointsExpanded}\n />\n )}\n\n {/* Inner Radius (Star only) - toggles secondary panel */}\n {element.transformData.shapeType === 'star' && onInnerRadiusToggle && (\n <ToolbarButton\n icon=\"lucide:circle-dashed\"\n onClick={() => {\n setInnerRadiusTooltipDisabled(true);\n onInnerRadiusToggle();\n }}\n onMouseLeave={() => setInnerRadiusTooltipDisabled(false)}\n tooltip=\"Inner Radius\"\n tooltipDisabled={innerRadiusTooltipDisabled || innerRadiusExpanded}\n active={innerRadiusExpanded}\n />\n )}\n\n {/* Transparency - toggles secondary panel */}\n {onTransparencyToggle && (\n <ToolbarButton\n icon=\"lucide:blend\"\n onClick={() => {\n setTransparencyTooltipDisabled(true);\n onTransparencyToggle();\n }}\n onMouseLeave={() => setTransparencyTooltipDisabled(false)}\n tooltip=\"Transparency\"\n tooltipDisabled={transparencyTooltipDisabled || transparencyExpanded}\n active={transparencyExpanded || applied.shapeTransparency}\n />\n )}\n\n {/* Rotate - toggles rotation panel */}\n {onRotationToggle && (\n <ToolbarButton\n icon={<RotateLeftIcon size={20} className=\"md:size-5\" />}\n onClick={() => {\n setRotationTooltipDisabled(true);\n onRotationToggle();\n }}\n onMouseLeave={() => setRotationTooltipDisabled(false)}\n tooltip=\"Rotate\"\n tooltipDisabled={rotationTooltipDisabled || rotationExpanded}\n active={rotationExpanded || applied.rotation}\n />\n )}\n\n {/* Knockout */}\n {onKnockoutToggle && (\n <ToolbarButton\n icon=\"lucide:scissors\"\n onClick={() => {\n setKnockoutTooltipDisabled(true);\n onKnockoutToggle();\n }}\n onMouseLeave={() => setKnockoutTooltipDisabled(false)}\n tooltip=\"Clip / Knockout\"\n tooltipDisabled={knockoutTooltipDisabled || knockoutExpanded}\n active={knockoutExpanded || applied.knockout}\n />\n )}\n\n {/* Distress Texture */}\n {onDistressTextureToggle && (\n <ToolbarButton\n icon=\"lucide:stamp\"\n onClick={() => {\n setDistressTooltipDisabled(true);\n onDistressTextureToggle();\n }}\n onMouseLeave={() => setDistressTooltipDisabled(false)}\n tooltip=\"Distress Texture\"\n tooltipDisabled={distressTooltipDisabled || distressTextureExpanded}\n active={distressTextureExpanded || applied.distress}\n />\n )}\n\n {/* Image Mask */}\n {onImageMaskToggle && (\n <ToolbarButton\n icon=\"lucide:venetian-mask\"\n onClick={() => {\n setImageMaskTooltipDisabled(true);\n onImageMaskToggle();\n }}\n onMouseLeave={() => setImageMaskTooltipDisabled(false)}\n tooltip=\"Image Mask\"\n tooltipDisabled={imageMaskTooltipDisabled || imageMaskExpanded}\n active={imageMaskExpanded || applied.imageMask}\n />\n )}\n\n {/* Stroke */}\n {onStrokeToggle && (\n <ToolbarButton\n icon=\"lucide:pen-line\"\n onClick={() => {\n setStrokeTooltipDisabled(true);\n onStrokeToggle();\n }}\n onMouseLeave={() => setStrokeTooltipDisabled(false)}\n tooltip=\"Stroke\"\n tooltipDisabled={strokeTooltipDisabled || strokeExpanded}\n active={strokeExpanded || applied.stroke}\n />\n )}\n\n {/* More Menu - overflow menu for additional options */}\n {(onMoveForward || onMoveBackward || onDelete) && (\n <Popover open={moreMenuOpen} onOpenChange={setMoreMenuOpen}>\n <PopoverTrigger asChild>\n <button className=\"toolbar-btn\" aria-label=\"More options\">\n <Icon icon=\"lucide:ellipsis-vertical\" className=\"size-6\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-auto p-1\" maxZIndex>\n <div className=\"flex items-center gap-1\">\n {onMoveForward && (\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n onMoveForward();\n setMoreMenuOpen(false);\n }}\n aria-label=\"Move Forward\"\n >\n <Icon icon=\"hugeicons:layer-bring-forward\" className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Forward</TooltipContent>\n </Tooltip>\n )}\n {onMoveBackward && (\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n onMoveBackward();\n setMoreMenuOpen(false);\n }}\n aria-label=\"Move Backward\"\n >\n <Icon icon=\"hugeicons:layer-send-backward\" className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Backward</TooltipContent>\n </Tooltip>\n )}\n {onDelete && (\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n setMoreMenuOpen(false);\n onDelete();\n }}\n aria-label=\"Delete\"\n >\n <Icon icon={icons.trash} className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n )}\n </div>\n </PopoverContent>\n </Popover>\n )}\n\n {/* Ungroup button - shown when editing a child in a group */}\n {showUngroupButton && onUngroup && (\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" onClick={onUngroup}>\n Ungroup\n </Button>\n </TooltipTrigger>\n <TooltipContent>Ungroup this group</TooltipContent>\n </Tooltip>\n )}\n </div>\n );\n};\n\nexport default ShapeToolbar;\n","/**\n * ShapeTypeDrawer — Tile picker for selecting / changing shape type.\n *\n * Implements the canonical tile-picker pattern from the design system:\n * `/design-system/page/drawers` (section 05).\n *\n * - Bottom drawer, height: auto (hugs the 7-tile grid)\n * - Custom header (no divider) with sr-only title for accessibility\n * - 3-col grid of square tiles, icon centered + label below\n * - Selected tile fills with primary tint and ink shifts to primary\n */\n\nimport React from 'react';\nimport { Drawer } from './Drawer';\nimport { icons } from './ui';\nimport { Icon } from '@iconify/react';\n\ninterface ShapeTypeDrawerProps {\n isOpen: boolean;\n onClose: () => void;\n onSelectType: (type: string) => void;\n /** The currently selected shape type (optional, for highlighting) */\n currentType?: string;\n}\n\ninterface ShapeType {\n id: string;\n label: string;\n /** Iconify icon name. Either this or `reactIcon` must be provided. */\n icon?: string;\n /** Custom React node — used for shapes that aren't in our icon set. */\n reactIcon?: React.ReactNode;\n}\n\n// Custom polygon (pentagon) — lucide doesn't ship one in our iconify set\nconst PolygonIcon = ({ className }: { className?: string }) => (\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 <path d=\"M12 2L21 8L18 19L6 19L3 8L12 2Z\" />\n </svg>\n);\n\n// Custom ellipse — also missing\nconst EllipseIcon = ({ className }: { className?: string }) => (\n <svg\n className={className}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n aria-hidden\n >\n <ellipse cx=\"12\" cy=\"12\" rx=\"9\" ry=\"6\" />\n </svg>\n);\n\nconst TILE_ICON_CLASS = 'size-10';\n\nconst shapeTypes: ShapeType[] = [\n { id: 'rectangle', label: 'Rectangle', icon: 'lucide:square' },\n { id: 'circle', label: 'Circle', icon: 'lucide:circle' },\n { id: 'ellipse', label: 'Ellipse', reactIcon: <EllipseIcon className={TILE_ICON_CLASS} /> },\n { id: 'triangle', label: 'Triangle', icon: 'lucide:triangle' },\n { id: 'polygon', label: 'Polygon', reactIcon: <PolygonIcon className={TILE_ICON_CLASS} /> },\n { id: 'star', label: 'Star', icon: 'lucide:star' },\n { id: 'line', label: 'Line', icon: 'lucide:minus' },\n];\n\nexport const ShapeTypeDrawer: React.FC<ShapeTypeDrawerProps> = ({\n isOpen,\n onClose,\n onSelectType,\n currentType,\n}) => {\n const headingText = currentType ? 'Change Shape' : 'Select Shape';\n const descriptionText = currentType ? 'Select a new shape type' : 'Choose a shape to add';\n\n const handleSelect = (type: string) => {\n onSelectType(type);\n onClose();\n };\n\n return (\n <Drawer\n isOpen={isOpen}\n onClose={onClose}\n title={headingText}\n description={descriptionText}\n placement=\"bottom\"\n height=\"auto\"\n hideVisibleTitle\n showCloseButton={false}\n data-testid=\"shape-type-drawer\"\n >\n {/* Custom header — no divider, sits right under the drag handle */}\n <div className=\"px-6 pt-1 pb-2 flex items-center justify-between\">\n <h3 className=\"text-lg font-semibold tracking-tight text-foreground\">\n {headingText}\n </h3>\n <button\n onClick={onClose}\n className=\"size-11 rounded-full hover:bg-foreground/[0.06] flex items-center justify-center text-foreground/70 -mr-2\"\n aria-label=\"Close\"\n >\n <Icon icon={icons.close} className=\"size-5\" />\n </button>\n </div>\n\n {/* Tile grid */}\n <div\n className=\"grid grid-cols-3 gap-2 p-4\"\n data-testid=\"shape-type-list\"\n >\n {shapeTypes.map((type) => {\n const isSelected = type.id === currentType;\n return (\n <button\n key={type.id}\n type=\"button\"\n onClick={() => handleSelect(type.id)}\n aria-pressed={isSelected}\n data-testid={`shape-type-${type.id}`}\n className={`aspect-square flex flex-col items-center justify-center gap-2.5 rounded-xl border transition-colors ${\n isSelected\n ? 'bg-primary/10 border-primary/40'\n : 'bg-transparent border-transparent hover:bg-foreground/[0.04] active:bg-foreground/[0.06]'\n }`}\n >\n <span\n className={isSelected ? 'text-primary' : 'text-foreground/85'}\n >\n {type.reactIcon ? (\n type.reactIcon\n ) : (\n <Icon icon={type.icon!} className={TILE_ICON_CLASS} />\n )}\n </span>\n <span\n className={`text-xs ${\n isSelected\n ? 'text-primary font-medium'\n : 'text-foreground/70'\n }`}\n >\n {type.label}\n </span>\n </button>\n );\n })}\n </div>\n </Drawer>\n );\n};\n\nexport default ShapeTypeDrawer;\n","/**\n * PathToolbar - Toolbar for path-specific controls\n * Handles stroke color, width, fill properties, and path editing\n */\n\nimport React, { useState } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Button, Popover, PopoverTrigger, PopoverContent, Slider, Tooltip, TooltipTrigger, TooltipContent, Label } from './ui';\nimport { PathElement } from '../core/PathElement';\nimport { ARTBOARD_COLORS } from '../presets/artboard-color-presets.js';\n\ninterface PathToolbarProps {\n element: PathElement;\n onElementUpdate: (element: PathElement) => void;\n onMoveForward?: () => void;\n onMoveBackward?: () => void;\n}\n\nconst PathToolbar: React.FC<PathToolbarProps> = ({ element, onElementUpdate, onMoveForward, onMoveBackward }) => {\n const [strokeColorOpen, setStrokeColorOpen] = useState<boolean>(false);\n const [fillColorOpen, setFillColorOpen] = useState<boolean>(false);\n const [strokeWidthOpen, setStrokeWidthOpen] = useState<boolean>(false);\n\n const handleStrokeColorChange = (color: string) => {\n const updatedElement = element.clone();\n updatedElement.transformData.strokeColor = color;\n onElementUpdate(updatedElement);\n setStrokeColorOpen(false);\n };\n\n const handleFillColorChange = (color: string) => {\n const updatedElement = element.clone();\n updatedElement.transformData.fillColor = color;\n onElementUpdate(updatedElement);\n setFillColorOpen(false);\n };\n\n const handleStrokeEnabledToggle = () => {\n const updatedElement = element.clone();\n updatedElement.transformData.strokeEnabled = !updatedElement.transformData.strokeEnabled;\n onElementUpdate(updatedElement);\n };\n\n const handleFillEnabledToggle = () => {\n const updatedElement = element.clone();\n updatedElement.transformData.fillEnabled = !updatedElement.transformData.fillEnabled;\n onElementUpdate(updatedElement);\n };\n\n const handleStrokeWidthChange = (value: number) => {\n const updatedElement = element.clone();\n updatedElement.transformData.strokeWidth = value;\n onElementUpdate(updatedElement);\n };\n\n const strokeColor = element.transformData.strokeColor || '#000000';\n const fillColor = element.transformData.fillColor || '#3b82f6';\n const strokeEnabled = element.transformData.strokeEnabled ?? true;\n const fillEnabled = element.transformData.fillEnabled ?? false;\n const strokeWidth = element.transformData.strokeWidth ?? 2;\n const isClosed = element.transformData.closed;\n const pointCount = element.transformData.points.length;\n\n return (\n <div className=\"fixed top-3xl left-1/2 -translate-x-1/2 flex items-center gap-md px-xl py-md bg-bg-primary rounded-xl shadow-md\" style={{ zIndex: 'var(--z-dropdown)' }}>\n {/* Path Info */}\n <div className=\"px-xl text-base text-text-muted border-r border-border-primary\">\n <span className=\"font-semibold\">Path</span>\n <span className=\"ml-md text-text-placeholder\">\n {pointCount} {pointCount === 1 ? 'point' : 'points'}\n {isClosed && ' • Closed'}\n </span>\n </div>\n\n {/* Stroke Enabled Toggle */}\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button\n variant={strokeEnabled ? 'default' : 'ghost'}\n onClick={handleStrokeEnabledToggle}\n className=\"px-xl text-base\"\n >\n Stroke\n </Button>\n </TooltipTrigger>\n <TooltipContent>{strokeEnabled ? 'Disable Stroke' : 'Enable Stroke'}</TooltipContent>\n </Tooltip>\n\n {/* Stroke Color Picker */}\n {strokeEnabled && (\n <Popover open={strokeColorOpen} onOpenChange={setStrokeColorOpen}>\n <PopoverTrigger asChild>\n <button\n className=\"w-8 h-8 p-xs rounded-md border-2 border-border-primary cursor-pointer transition-transform hover:scale-105\"\n style={{ background: strokeColor }}\n title=\"Stroke Color\"\n />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"p-0\">\n <div className=\"bg-bg-primary rounded-xl shadow-lg p-6 min-w-[240px]\">\n <div className=\"grid grid-cols-6 gap-sm mb-md\">\n {ARTBOARD_COLORS.map((color) => (\n <Button\n key={color.color}\n onClick={() => handleStrokeColorChange(color.color)}\n aria-label={color.name}\n className={`w-8 h-8 rounded-md cursor-pointer transition-all min-h-0 min-w-0 p-0 ${\n strokeColor === color.color\n ? 'border-2 border-accent-primary scale-110'\n : 'border border-border-primary hover:scale-105'\n }`}\n style={{ background: color.color }}\n />\n ))}\n </div>\n <input\n type=\"color\"\n value={strokeColor}\n onChange={(e) => handleStrokeColorChange(e.target.value)}\n className=\"w-full h-8 cursor-pointer rounded-md border border-border-primary\"\n />\n </div>\n </PopoverContent>\n </Popover>\n )}\n\n {/* Stroke Width */}\n {strokeEnabled && (\n <Popover open={strokeWidthOpen} onOpenChange={setStrokeWidthOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"ghost\" className=\"px-xl text-base\">\n {strokeWidth}px\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"p-0\">\n <div className=\"bg-bg-primary rounded-xl shadow-lg p-6 min-w-[200px]\">\n <Slider\n value={[strokeWidth]}\n onValueChange={(val) => handleStrokeWidthChange(val[0])}\n min={1}\n max={20}\n step={0.5}\n className=\"slider-no-fill w-full\"\n >\n <Label>Width (px)</Label>\n <Slider.Output />\n <Slider.Track />\n <Slider.Thumb />\n </Slider>\n </div>\n </PopoverContent>\n </Popover>\n )}\n\n <div className=\"w-px h-6 bg-border-primary mx-xs\" />\n\n {/* Fill Enabled Toggle */}\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button\n variant={fillEnabled ? 'default' : 'ghost'}\n onClick={handleFillEnabledToggle}\n className=\"px-xl text-base\"\n >\n Fill\n </Button>\n </TooltipTrigger>\n <TooltipContent>{fillEnabled ? 'Disable Fill' : 'Enable Fill'}</TooltipContent>\n </Tooltip>\n\n {/* Fill Color Picker */}\n {fillEnabled && (\n <Popover open={fillColorOpen} onOpenChange={setFillColorOpen}>\n <PopoverTrigger asChild>\n <button\n className=\"w-8 h-8 p-xs rounded-md border-2 border-border-primary cursor-pointer transition-transform hover:scale-105\"\n style={{ background: fillColor }}\n title=\"Fill Color\"\n />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"p-0\">\n <div className=\"bg-bg-primary rounded-xl shadow-lg p-6 min-w-[240px]\">\n <div className=\"grid grid-cols-6 gap-sm mb-md\">\n {ARTBOARD_COLORS.map((color) => (\n <Button\n key={color.color}\n onClick={() => handleFillColorChange(color.color)}\n aria-label={color.name}\n className={`w-8 h-8 rounded-md cursor-pointer transition-all min-h-0 min-w-0 p-0 ${\n fillColor === color.color\n ? 'border-2 border-accent-primary scale-110'\n : 'border border-border-primary hover:scale-105'\n }`}\n style={{ background: color.color }}\n />\n ))}\n </div>\n <input\n type=\"color\"\n value={fillColor}\n onChange={(e) => handleFillColorChange(e.target.value)}\n className=\"w-full h-8 cursor-pointer rounded-md border border-border-primary\"\n />\n </div>\n </PopoverContent>\n </Popover>\n )}\n\n <div className=\"w-px h-6 bg-border-primary mx-xs\" />\n\n {/* Layer Order Controls */}\n {onMoveForward && (\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" onClick={onMoveForward}>\n <Icon icon=\"hugeicons:layer-bring-forward\" className=\"size-[18px]\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Forward</TooltipContent>\n </Tooltip>\n )}\n\n {onMoveBackward && (\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" onClick={onMoveBackward}>\n <Icon icon=\"hugeicons:layer-send-backward\" className=\"size-[18px]\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Backward</TooltipContent>\n </Tooltip>\n )}\n </div>\n );\n};\n\nexport default PathToolbar;\n","/**\n * BackgroundPickerDropdown - Unified picker for artboard backgrounds\n * Supports color, texture, and gradient (future) backgrounds\n */\n\nimport { useState, useEffect, memo } from 'react';\nimport { HexColorPicker } from 'react-colorful';\nimport { Button, Popover, PopoverTrigger, PopoverContent, icons } from './ui';\nimport { Icon } from '@iconify/react';\nimport { TextureManager } from '../utils/TextureManager';\nimport type { ArtboardBackgroundType } from '../types/index';\n\nexport interface BackgroundPickerDropdownProps {\n backgroundType: ArtboardBackgroundType;\n backgroundColor: string;\n backgroundTexture?: string;\n onBackgroundTypeChange: (type: ArtboardBackgroundType) => void;\n onColorChange: (color: string) => void;\n onTextureChange: (textureId: string) => void;\n}\n\ntype BackgroundTab = 'color' | 'texture' | 'gradient';\n\nconst BackgroundPickerDropdown = memo(({\n backgroundType,\n backgroundColor,\n backgroundTexture,\n onBackgroundTypeChange,\n onColorChange,\n onTextureChange,\n}: BackgroundPickerDropdownProps) => {\n const [isOpen, setIsOpen] = useState(false);\n const [activeTab, setActiveTab] = useState<BackgroundTab>('color');\n const [hexInput, setHexInput] = useState(backgroundColor);\n\n // Sync active tab with background type\n useEffect(() => {\n if (backgroundType === 'texture') {\n setActiveTab('texture');\n } else {\n setActiveTab('color');\n }\n }, [backgroundType]);\n\n // Sync hex input with color prop\n useEffect(() => {\n if (backgroundColor !== 'transparent') {\n setHexInput(backgroundColor);\n }\n }, [backgroundColor]);\n\n const handleColorChange = (color: string) => {\n setHexInput(color);\n onColorChange(color);\n onBackgroundTypeChange('color');\n };\n\n const handleHexInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const input = e.target.value;\n setHexInput(input);\n\n // Validate hex color (with or without #)\n const hexPattern = /^#?([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/;\n const withHash = input.startsWith('#') ? input : `#${input}`;\n\n if (hexPattern.test(withHash)) {\n onColorChange(withHash);\n onBackgroundTypeChange('color');\n }\n };\n\n const handleTransparentClick = () => {\n onColorChange('transparent');\n onBackgroundTypeChange('transparent');\n };\n\n const handleTextureClick = (textureId: string) => {\n onTextureChange(textureId);\n onBackgroundTypeChange('texture');\n };\n\n const handleTabChange = (tab: BackgroundTab) => {\n setActiveTab(tab);\n if (tab === 'color') {\n onBackgroundTypeChange(backgroundColor === 'transparent' ? 'transparent' : 'color');\n } else if (tab === 'texture') {\n if (!backgroundTexture) {\n // Set default texture if none is set\n const defaultTexture = TextureManager.getAllTextures()[0];\n if (defaultTexture) {\n onTextureChange(defaultTexture.id);\n }\n }\n onBackgroundTypeChange('texture');\n }\n };\n\n const isTransparent = backgroundColor === 'transparent';\n\n return (\n <Popover open={isOpen} onOpenChange={setIsOpen}>\n <PopoverTrigger asChild>\n <Button variant={isOpen ? 'default' : 'ghost'} aria-label=\"Background\">\n <Icon icon={icons.palette} className=\"size-[18px]\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-3\">\n <div className=\"flex min-w-[220px] flex-col gap-3\">\n {/* Tab selector */}\n <div className=\"flex gap-1 border-b border-divider pb-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={`flex-1 ${activeTab === 'color' ? 'bg-primary text-primary-foreground' : ''}`}\n onClick={() => handleTabChange('color')}\n >\n Color\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className={`flex-1 ${activeTab === 'texture' ? 'bg-primary text-primary-foreground' : ''}`}\n onClick={() => handleTabChange('texture')}\n >\n Texture\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"flex-1 cursor-not-allowed opacity-50\"\n disabled\n aria-label=\"Gradient (Coming soon)\"\n >\n Gradient\n </Button>\n </div>\n\n {/* Color picker panel */}\n {activeTab === 'color' && (\n <div className=\"flex flex-col gap-3\">\n <Button\n variant=\"ghost\"\n className={`flex w-full cursor-pointer items-center justify-start gap-2 rounded-lg ${isTransparent ? 'bg-primary/10' : ''}`}\n onClick={handleTransparentClick}\n >\n <div className=\"transparent-pattern-small h-6 w-6 rounded\" />\n <span className=\"text-sm font-medium\">Transparent</span>\n </Button>\n\n <HexColorPicker color={isTransparent ? '#ffffff' : backgroundColor} onChange={handleColorChange} />\n\n <div className=\"flex items-center gap-2\">\n <label htmlFor=\"bg-hex-input\" className=\"text-sm font-medium uppercase text-foreground/60\">\n HEX\n </label>\n <input\n id=\"bg-hex-input\"\n type=\"text\"\n className=\"flex-1 rounded-lg border border-divider bg-field px-2 py-1.5 text-sm text-foreground focus:border-primary focus:outline-none\"\n value={hexInput}\n onChange={handleHexInputChange}\n placeholder=\"#000000\"\n maxLength={7}\n />\n </div>\n </div>\n )}\n\n {/* Texture picker panel */}\n {activeTab === 'texture' && (\n <div className=\"flex flex-col gap-3\">\n <div className=\"text-sm font-medium text-foreground/60\">Select a texture</div>\n <div className=\"grid grid-cols-4 gap-1.5\">\n {TextureManager.getAllTextures().map((texture) => (\n <button\n key={texture.id}\n className={`flex items-center justify-center p-1 rounded-lg cursor-pointer transition-all border-2 ${\n backgroundTexture === texture.id\n ? 'border-primary'\n : 'border-transparent hover:border-primary/50'\n }`}\n onClick={() => handleTextureClick(texture.id)}\n aria-label={texture.name}\n >\n <img src={texture.url} alt={texture.name} className=\"w-full h-full rounded\" />\n </button>\n ))}\n </div>\n </div>\n )}\n\n {/* Gradient picker panel (future) */}\n {activeTab === 'gradient' && (\n <div className=\"flex flex-col items-center justify-center gap-3 py-8 text-foreground/60\">\n <div className=\"text-sm\">Gradient backgrounds</div>\n <div className=\"text-xs\">Coming soon</div>\n </div>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n});\n\nBackgroundPickerDropdown.displayName = 'BackgroundPickerDropdown';\n\nexport default BackgroundPickerDropdown;\n","/**\n * ArtboardDistressPanel - UI panel for artboard-level distress texture\n *\n * Allows applying a grayscale texture as an alpha mask over all elements\n * on the artboard. Dark areas knock out pixels, light areas preserve them.\n */\n\nimport React, { useCallback } from 'react';\nimport type { ArtboardDistressTexture } from '../types/index.js';\nimport { DISTRESS_TEXTURE_PRESETS, ensureBuiltinTexturesReady } from '../effects/distress-textures.js';\nimport { preloadTexture } from '../effects/DistressTextureCache.js';\nimport {\n Disclosure,\n DisclosureTrigger,\n DisclosureContent,\n Switch,\n Label,\n SliderRow,\n PresetCarousel,\n} from './ui';\nimport type { PresetItem } from './ui';\n\ninterface ArtboardDistressPanelProps {\n distressTexture?: ArtboardDistressTexture;\n onChange: (distressTexture: ArtboardDistressTexture | undefined) => void;\n}\n\nconst ArtboardDistressPanel = ({ distressTexture, onChange }: ArtboardDistressPanelProps) => {\n ensureBuiltinTexturesReady();\n\n const enabled = distressTexture?.enabled || false;\n const textureUrl = distressTexture?.textureUrl || '';\n const intensity = distressTexture?.intensity ?? 50;\n\n const presetItems: PresetItem[] = DISTRESS_TEXTURE_PRESETS.map((p) => ({ id: p.textureUrl, name: p.name, thumbnailUrl: p.thumbnailUrl }));\n\n const handleEnabledChange = (newEnabled: boolean) => {\n if (newEnabled) {\n const url = textureUrl || DISTRESS_TEXTURE_PRESETS[0].textureUrl;\n preloadTexture(url);\n onChange({\n enabled: true,\n textureUrl: url,\n intensity,\n });\n } else {\n onChange(undefined);\n }\n };\n\n const handleTextureSelect = useCallback(\n (id: string) => {\n preloadTexture(id);\n onChange({\n enabled: true,\n textureUrl: id,\n intensity,\n });\n },\n [onChange, intensity]\n );\n\n const handleIntensityChange = (value: number[]) => {\n if (!distressTexture) return;\n onChange({\n ...distressTexture,\n intensity: value[0],\n });\n };\n\n return (\n <Disclosure open={enabled} onOpenChange={handleEnabledChange} className=\"mb-xl\">\n <DisclosureTrigger className=\"w-full\">\n <div className=\"flex items-center justify-between w-full\">\n <Label>Distress Texture</Label>\n <Switch\n checked={enabled}\n onCheckedChange={handleEnabledChange}\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n />\n </div>\n </DisclosureTrigger>\n <DisclosureContent className=\"flex flex-col gap-lg py-lg\">\n <PresetCarousel\n presets={presetItems}\n selectedId={textureUrl}\n onSelect={handleTextureSelect}\n showOff={false}\n ariaLabel=\"Distress texture presets\"\n />\n\n {/* Intensity slider */}\n <SliderRow\n label=\"Intensity\"\n value={intensity}\n onChange={(v) => handleIntensityChange([v])}\n min={0}\n max={100}\n step={1}\n unit=\"%\"\n />\n </DisclosureContent>\n </Disclosure>\n );\n};\n\nexport default ArtboardDistressPanel;\n","/**\n * ArtboardImageMaskPanel - UI panel for artboard-level image mask\n *\n * Allows applying an image mask over all elements on the artboard.\n * Supports clip, alpha, and luma mask types with inversion and opacity.\n */\n\nimport React, { useCallback } from 'react';\nimport type { ArtboardImageMask } from '../types/index.js';\nimport { MASK_IMAGE_PRESETS, ensureMaskPresetsReady } from '../effects/mask-presets.js';\nimport {\n Disclosure,\n DisclosureTrigger,\n DisclosureContent,\n Switch,\n Label,\n SliderRow,\n Checkbox,\n PresetCarousel,\n} from './ui';\nimport type { PresetItem } from './ui';\n\ninterface ArtboardImageMaskPanelProps {\n imageMask?: ArtboardImageMask;\n onChange: (imageMask: ArtboardImageMask | undefined) => void;\n}\n\nconst ArtboardImageMaskPanel = ({ imageMask, onChange }: ArtboardImageMaskPanelProps) => {\n ensureMaskPresetsReady();\n\n const enabled = imageMask?.enabled || false;\n const imageUrl = imageMask?.imageUrl || '';\n const maskType = imageMask?.maskType || 'clip';\n const opacity = imageMask?.opacity ?? 100;\n const inverted = imageMask?.inverted ?? false;\n\n const presetItems: PresetItem[] = MASK_IMAGE_PRESETS.map((p) => ({ id: p.imageUrl, name: p.name, thumbnailUrl: p.thumbnailUrl }));\n\n const handleEnabledChange = (newEnabled: boolean) => {\n if (newEnabled) {\n const url = imageUrl || MASK_IMAGE_PRESETS[0].imageUrl;\n onChange({\n enabled: true,\n imageUrl: url,\n maskType,\n opacity,\n inverted,\n });\n } else {\n onChange(undefined);\n }\n };\n\n const handleImageSelect = useCallback(\n (id: string) => {\n onChange({\n enabled: true,\n imageUrl: id,\n maskType,\n opacity,\n inverted,\n });\n },\n [onChange, maskType, opacity, inverted]\n );\n\n const handleMaskTypeChange = (type: 'clip' | 'alpha' | 'luma') => {\n if (!imageMask) return;\n onChange({ ...imageMask, maskType: type });\n };\n\n const handleOpacityChange = (value: number[]) => {\n if (!imageMask) return;\n onChange({ ...imageMask, opacity: value[0] });\n };\n\n const handleInvertedChange = (checked: boolean) => {\n if (!imageMask) return;\n onChange({ ...imageMask, inverted: checked });\n };\n\n return (\n <Disclosure open={enabled} onOpenChange={handleEnabledChange} className=\"mb-xl\">\n <DisclosureTrigger className=\"w-full\">\n <div className=\"flex items-center justify-between w-full\">\n <Label>Image Mask</Label>\n <Switch\n checked={enabled}\n onCheckedChange={handleEnabledChange}\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n />\n </div>\n </DisclosureTrigger>\n <DisclosureContent className=\"flex flex-col gap-lg py-lg\">\n <PresetCarousel\n presets={presetItems}\n selectedId={imageUrl}\n onSelect={handleImageSelect}\n showOff={false}\n ariaLabel=\"Image mask presets\"\n />\n\n {/* Mask type selector */}\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-sm\">Type</Label>\n <div className=\"flex rounded-md border border-divider overflow-hidden\">\n {(['clip', 'alpha', 'luma'] as const).map((type) => (\n <button\n key={type}\n className={`px-3 py-1 text-xs capitalize transition-colors ${\n maskType === type\n ? 'bg-primary text-primary-foreground'\n : 'text-foreground hover:bg-muted'\n }`}\n onClick={() => handleMaskTypeChange(type)}\n >\n {type}\n </button>\n ))}\n </div>\n </div>\n\n {/* Opacity slider */}\n <SliderRow\n label=\"Opacity\"\n value={opacity}\n onChange={(v) => handleOpacityChange([v])}\n min={0}\n max={100}\n step={1}\n unit=\"%\"\n />\n\n {/* Inverted checkbox */}\n <label className=\"flex items-center gap-2 text-sm text-foreground\">\n <Checkbox checked={inverted} onCheckedChange={(v) => handleInvertedChange(v === true)} />\n Invert Mask\n </label>\n </DisclosureContent>\n </Disclosure>\n );\n};\n\nexport default ArtboardImageMaskPanel;\n","/**\n * ArtboardPropertiesToolbar - Contextual toolbar for editing artboard properties\n * Shows when an artboard is selected (instead of an element)\n */\n\nimport React, { useState, useRef, useEffect } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Button, Switch, Popover, PopoverTrigger, PopoverContent, Label, Tooltip, TooltipTrigger, TooltipContent, Surface, Separator, icons } from './ui';\nimport { ArtboardElement } from '../core/ArtboardElement';\nimport BackgroundPickerDropdown from './BackgroundPickerDropdown';\nimport ArtboardDistressPanel from './ArtboardDistressPanel';\nimport ArtboardImageMaskPanel from './ArtboardImageMaskPanel';\nimport type { ArtboardBackgroundType, ArtboardDistressTexture, ArtboardImageMask } from '../types/index';\n\ninterface ArtboardPropertiesToolbarProps {\n artboard: ArtboardElement;\n artboards: ArtboardElement[];\n onArtboardUpdate: (artboard: ArtboardElement) => void;\n onRenameArtboard: (artboardId: string, newName: string) => void;\n onDeleteArtboard: (artboardId: string) => void;\n artboardScreenBounds?: {\n left: number;\n top: number;\n width: number;\n height: number;\n bottom: number;\n centerX: number;\n };\n}\n\nconst ArtboardPropertiesToolbar: React.FC<ArtboardPropertiesToolbarProps> = ({\n artboard,\n artboards,\n onArtboardUpdate,\n onRenameArtboard,\n onDeleteArtboard,\n artboardScreenBounds,\n}) => {\n const [isEditing, setIsEditing] = useState(false);\n const [editingName, setEditingName] = useState('');\n const [moreMenuOpen, setMoreMenuOpen] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n\n const handleBackgroundTypeChange = (type: ArtboardBackgroundType) => {\n const updatedArtboard = artboard.clone();\n updatedArtboard.backgroundType = type;\n onArtboardUpdate(updatedArtboard);\n };\n\n const handleColorChange = (color: string) => {\n const updatedArtboard = artboard.clone();\n updatedArtboard.backgroundColor = color;\n onArtboardUpdate(updatedArtboard);\n };\n\n const handleTextureChange = (textureId: string) => {\n const updatedArtboard = artboard.clone();\n updatedArtboard.backgroundTexture = textureId;\n onArtboardUpdate(updatedArtboard);\n };\n\n const handleExportBackgroundToggle = (checked: boolean) => {\n const updatedArtboard = artboard.clone();\n updatedArtboard.exportBackground = checked;\n onArtboardUpdate(updatedArtboard);\n };\n\n const handleDistressTextureChange = (distressTexture: ArtboardDistressTexture | undefined) => {\n const updatedArtboard = artboard.clone();\n updatedArtboard.distressTexture = distressTexture;\n onArtboardUpdate(updatedArtboard);\n };\n\n const handleImageMaskChange = (imageMask: ArtboardImageMask | undefined) => {\n const updatedArtboard = artboard.clone();\n updatedArtboard.imageMask = imageMask;\n onArtboardUpdate(updatedArtboard);\n };\n\n const handleStartEdit = () => {\n setIsEditing(true);\n setEditingName(artboard.name);\n };\n\n const handleSaveEdit = () => {\n if (editingName.trim()) {\n onRenameArtboard(artboard.id, editingName.trim());\n }\n setIsEditing(false);\n setEditingName('');\n };\n\n const handleCancelEdit = () => {\n setIsEditing(false);\n setEditingName('');\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter') {\n handleSaveEdit();\n } else if (e.key === 'Escape') {\n handleCancelEdit();\n }\n };\n\n const handleDelete = () => {\n if (artboards.length <= 1) {\n alert('Cannot delete the last artboard');\n return;\n }\n\n if (artboard.getElementCount() > 0) {\n if (!confirm(`Delete \"${artboard.name}\" with ${artboard.getElementCount()} element(s)?`)) {\n return;\n }\n }\n\n onDeleteArtboard(artboard.id);\n };\n\n // Focus input when editing starts\n useEffect(() => {\n if (isEditing && inputRef.current) {\n inputRef.current.focus();\n inputRef.current.select();\n }\n }, [isEditing]);\n\n return (\n <Surface\n className=\"absolute px-4 py-2 flex items-center gap-2 shadow-lg z-50 rounded-full bg-bg-primary border border-border-primary\"\n style={{\n left: '50%',\n top: artboardScreenBounds ? `${artboardScreenBounds.top - 68}px` : '32px',\n transform: 'translateX(-50%)',\n }}\n >\n {/* Artboard name with edit/delete controls */}\n {isEditing ? (\n <div className=\"flex items-center gap-2\">\n <input\n ref={inputRef}\n type=\"text\"\n value={editingName}\n onChange={(e) => setEditingName(e.target.value)}\n onKeyDown={handleKeyDown}\n className=\"px-3 py-1 border border-border-primary rounded-lg text-base text-text-primary bg-bg-primary outline-none min-w-[120px] transition-colors focus:border-border-focus\"\n />\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" onClick={handleSaveEdit} aria-label=\"Save\">\n <Icon icon={icons.check} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Save</TooltipContent>\n </Tooltip>\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" onClick={handleCancelEdit} aria-label=\"Cancel\">\n <Icon icon={icons.close} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Cancel</TooltipContent>\n </Tooltip>\n </div>\n ) : (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xl font-semibold text-text-primary\">{artboard.name}</span>\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" onClick={handleStartEdit} aria-label=\"Rename\">\n <Icon icon={icons.pencil} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Rename</TooltipContent>\n </Tooltip>\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" onClick={handleDelete} disabled={artboards.length <= 1} aria-label=\"Delete\">\n <Icon icon={icons.trash} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n </div>\n )}\n\n <Separator orientation=\"vertical\" className=\"h-6\" />\n\n {/* Background picker */}\n <BackgroundPickerDropdown\n backgroundType={artboard.backgroundType}\n backgroundColor={artboard.backgroundColor}\n backgroundTexture={artboard.backgroundTexture}\n onBackgroundTypeChange={handleBackgroundTypeChange}\n onColorChange={handleColorChange}\n onTextureChange={handleTextureChange}\n />\n\n <Separator orientation=\"vertical\" className=\"h-6\" />\n\n {/* Dimensions display */}\n <div className=\"text-base font-mono text-text-muted uppercase\">\n {Math.round(artboard.width)} × {Math.round(artboard.height)}\n </div>\n\n <Separator orientation=\"vertical\" className=\"h-6\" />\n\n {/* More Menu - overflow menu for additional options */}\n <Popover open={moreMenuOpen} onOpenChange={setMoreMenuOpen}>\n <PopoverTrigger asChild>\n <Button variant={moreMenuOpen ? 'default' : 'ghost'} aria-label=\"More options\">\n <Icon icon={icons.menu} className=\"size-6\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\">\n <div className=\"flex flex-col gap-2 min-w-[240px]\">\n <div className=\"flex items-center gap-3\">\n <Switch\n checked={artboard.exportBackground}\n onCheckedChange={handleExportBackgroundToggle}\n />\n <Label>Export Background</Label>\n </div>\n <Separator />\n <ArtboardDistressPanel\n distressTexture={artboard.distressTexture}\n onChange={handleDistressTextureChange}\n />\n <ArtboardImageMaskPanel\n imageMask={artboard.imageMask}\n onChange={handleImageMaskChange}\n />\n </div>\n </PopoverContent>\n </Popover>\n </Surface>\n );\n};\n\nexport default ArtboardPropertiesToolbar;\n","/**\n * Service for fetching and managing all Google Fonts\n */\n\nimport { createLogger } from './logger';\n\nconst logger = createLogger('GoogleFontsService');\n\nexport interface GoogleFontMetadata {\n family: string;\n category: string;\n subsets?: string[];\n variants?: string[];\n version?: string;\n lastModified?: string;\n popularity?: number;\n}\n\nlet allGoogleFonts: GoogleFontMetadata[] = [];\nlet fetchPromise: Promise<GoogleFontMetadata[]> | null = null;\n\n/**\n * Fetch all Google Fonts from metadata endpoint\n * Results are cached after first fetch\n */\nexport async function fetchAllGoogleFonts(): Promise<GoogleFontMetadata[]> {\n // Return cached if available\n if (allGoogleFonts.length > 0) {\n return allGoogleFonts;\n }\n\n // Return existing promise if fetch in progress\n if (fetchPromise) {\n return fetchPromise;\n }\n\n // Start new fetch - Use local static file\n fetchPromise = fetch('/google-fonts.json')\n .then((response) => {\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n return response.json();\n })\n .then((data) => {\n\n // Handle font array format\n if (Array.isArray(data)) {\n allGoogleFonts = data.map((font: Record<string, unknown>) => ({\n family: font.family as string,\n category: (font.category as string) || 'sans-serif',\n subsets: (font.subsets as string[]) || [],\n variants: (font.variants as string[]) || [],\n popularity: font.popularity as number | undefined,\n }));\n } else {\n logger.error('Unexpected API response structure:', data);\n }\n return allGoogleFonts;\n })\n .catch((error) => {\n logger.error('Error fetching Google Fonts:', error);\n fetchPromise = null; // Reset promise on error so it can be retried\n return [];\n });\n\n return fetchPromise;\n}\n\n/**\n * Get all Google Fonts (uses cache if available)\n */\nexport function getAllGoogleFonts(): GoogleFontMetadata[] {\n return allGoogleFonts;\n}\n\n/**\n * Check if fonts have been loaded\n */\nexport function isFontsLoaded(): boolean {\n return allGoogleFonts.length > 0;\n}\n\n/**\n * Search Google Fonts by name\n */\nexport function searchGoogleFonts(query: string): GoogleFontMetadata[] {\n if (!query) return allGoogleFonts;\n\n const searchTerm = query.toLowerCase();\n return allGoogleFonts.filter((font) => font.family.toLowerCase().includes(searchTerm));\n}\n\n/**\n * Filter Google Fonts by category\n */\nexport function filterGoogleFontsByCategory(category: string): GoogleFontMetadata[] {\n if (!category || category === 'all') return allGoogleFonts;\n\n return allGoogleFonts.filter((font) => font.category.toLowerCase() === category.toLowerCase());\n}\n\n/**\n * Map Google Fonts category to our internal categories\n */\nexport function mapGoogleCategory(googleCategory: string): string {\n const mapping: Record<string, string> = {\n 'sans serif': 'sans-serif',\n serif: 'serif',\n display: 'display',\n handwriting: 'script',\n monospace: 'monospace',\n };\n\n return mapping[googleCategory.toLowerCase()] || 'display';\n}\n","/**\n * Monotype Category Mapping\n * Maps Monotype's classification system to our unified 8-category taxonomy\n *\n * Key Insight: Monotype fonts have MULTIPLE classifications (e.g., [\"SERIF\", \"OLD STYLE SERIF\", \"DISPLAY\"])\n * Solution: Use priority-based mapping to select the most specific category\n */\n\nimport { FontCategory } from '../fonts/google-fonts.js';\n\nexport interface CategoryRule {\n canonical: FontCategory;\n monotypeClassifications: string[];\n googleCategory?: string;\n displayName: string;\n description: string;\n icon?: string; // For future UI enhancements\n}\n\n/**\n * Category mapping rules with priority order\n * Most specific categories first, general categories last\n */\nexport const CATEGORY_MAPPINGS: CategoryRule[] = [\n {\n canonical: 'slab-serif',\n monotypeClassifications: [\n 'SLAB SERIF',\n 'CLARENDON SERIF',\n ],\n googleCategory: 'serif',\n displayName: 'Slab Serif',\n description: 'Bold, chunky serifs perfect for t-shirt designs',\n },\n {\n canonical: 'decorative',\n monotypeClassifications: [\n 'BLACKLETTER',\n 'SPECIALIZED',\n 'DESIGN',\n 'DINGBATS',\n 'SYMBOL',\n 'ORNATE',\n ],\n googleCategory: 'display',\n displayName: 'Decorative',\n description: 'Artistic and ornate fonts for special effects',\n },\n {\n canonical: 'display',\n monotypeClassifications: [\n 'DISPLAY',\n 'HIGH CONTRAST',\n 'GRAPHIC STYLE',\n ],\n googleCategory: 'display',\n displayName: 'Display',\n description: 'Eye-catching fonts for headlines and logos',\n },\n {\n canonical: 'script',\n monotypeClassifications: [\n 'SCRIPT',\n 'FORMAL SCRIPT',\n 'INFORMAL SCRIPT',\n 'CASUAL SCRIPT',\n 'HANDWRITING',\n ],\n googleCategory: 'handwriting',\n displayName: 'Script & Handwriting',\n description: 'Calligraphy and handwritten styles',\n },\n {\n canonical: 'monospace',\n monotypeClassifications: [\n 'MONOSPACED',\n ],\n googleCategory: 'monospace',\n displayName: 'Monospace',\n description: 'Fixed-width fonts for coding and technical text',\n },\n {\n canonical: 'serif',\n monotypeClassifications: [\n 'SERIF',\n 'OLD STYLE SERIF',\n 'TRANSITIONAL SERIF',\n 'MODERN SERIF',\n 'NEOCLASSICAL',\n 'TRANSITIONAL',\n ],\n googleCategory: 'serif',\n displayName: 'Serif',\n description: 'Traditional fonts with decorative strokes at letter ends',\n },\n {\n canonical: 'sans-serif',\n monotypeClassifications: [\n 'SANS SERIF',\n 'GEOMETRIC SANS',\n 'HUMANIST SANS',\n 'GROTESQUE SANS',\n ],\n googleCategory: 'sans-serif',\n displayName: 'Sans Serif',\n description: 'Clean, modern fonts without decorative strokes',\n },\n];\n\n/**\n * Map Monotype classifications to canonical category\n * Uses priority order (most specific first)\n *\n * Example:\n * - [\"SERIF\", \"SLAB SERIF\"] → 'slab-serif' (most specific wins)\n * - [\"SERIF\", \"OLD STYLE SERIF\", \"DISPLAY\"] → 'display' (priority order)\n * - [\"SANS SERIF\", \"GEOMETRIC SANS\"] → 'sans-serif'\n *\n * @param classifications - Array of Monotype classifications\n * @returns Canonical category\n */\nexport function mapMonotypeClassifications(\n classifications: string[]\n): FontCategory {\n // Priority order (most specific first)\n const priorityOrder: FontCategory[] = [\n 'slab-serif', // Most specific\n 'decorative',\n 'display',\n 'script',\n 'monospace',\n 'serif',\n 'sans-serif', // Least specific (fallback)\n ];\n\n for (const category of priorityOrder) {\n const mapping = CATEGORY_MAPPINGS.find(m => m.canonical === category);\n if (mapping) {\n const hasMatch = classifications.some(c =>\n mapping.monotypeClassifications.includes(c)\n );\n if (hasMatch) return category;\n }\n }\n\n return 'sans-serif'; // Default fallback\n}\n\n/**\n * Get category mapping by canonical name\n */\nexport function getCategoryMapping(category: FontCategory): CategoryRule | undefined {\n return CATEGORY_MAPPINGS.find(m => m.canonical === category);\n}\n\n/**\n * Get all Monotype classifications for a canonical category\n * Useful for API searches\n */\nexport function getMonotypeClassifications(category: FontCategory): string[] {\n const mapping = getCategoryMapping(category);\n return mapping?.monotypeClassifications || [];\n}\n","/**\n * MonotypeService - Service for integrating Monotype Fonts API\n *\n * Features:\n * - OAuth 2.0 authentication with automatic token refresh\n * - Font catalog fetching with pagination and caching\n * - Search with fuzzy/partial matching\n * - Category filtering\n * - WebFont kit generation with persistent caching\n * - Font family grouping (492 fonts → ~120 families)\n *\n * Architecture: See docs/MONOTYPE_INTEGRATION_ARCHITECTURE.md\n */\n\nimport { FontCategory, FontDefinition } from '../fonts/google-fonts.js';\nimport { mapMonotypeClassifications, getMonotypeClassifications } from './MonotypeCategoryMapping.js';\nimport { createLogger } from './logger.js';\n\nconst log = createLogger('Monotype');\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface MonotypeFont {\n fontId: string;\n name: string; // \"Albertina™ Pro Bold\"\n friendlyName: string; // \"Albertina Pro Bold\"\n family: string; // \"Albertina™\"\n familyId: string;\n foundry: string; // \"Monotype\", \"Linotype\", etc.\n classification: string[]; // [\"SERIF\", \"OLD STYLE SERIF\"]\n tag: string[]; // [\"CLEAR\", \"LEGIBLE\"]\n publicTags: string[];\n weightCSS: number; // 400, 700, etc.\n sample: string; // Preview image URL\n format?: string; // \"OT-CFF\", etc.\n}\n\nexport interface MonotypeSearchParams {\n // Text search\n name?: string;\n family?: string;\n\n // Filters\n classification?: string[];\n foundry?: string;\n tag?: string[];\n\n // Search settings\n searchSettings?: {\n fuzzy?: string[]; // Fields to fuzzy search\n partial?: string[]; // Fields to partial search\n exact?: string[]; // Fields to exact search\n };\n\n // Pagination\n pageSize?: number; // Default 50, max 500\n pageNumber?: number; // Page number (0-indexed)\n pageId?: string; // Cursor-based pagination\n}\n\nexport interface MonotypeSearchResponse {\n fonts: MonotypeFont[];\n nextPageId?: string;\n totalCount?: number;\n}\n\nexport interface WebFontKit {\n fontFamily: string;\n cssUrl: string; // Persistent CDN URL\n timestamp: number;\n}\n\ninterface MonotypeTokenResponse {\n access_token: string;\n expires_in: number; // Seconds until expiration\n token_type: string;\n}\n\n// ============================================================================\n// MonotypeService Class\n// ============================================================================\n\nclass MonotypeServiceClass {\n // Authentication\n private accessToken: string | null = null;\n private tokenExpiry: number = 0;\n\n // Font catalog cache\n private fonts: Map<string, MonotypeFont> = new Map();\n private fontsLoaded: boolean = false;\n\n // WebFont kit cache (PERSISTENT!)\n private webfontKits: Map<string, WebFontKit> = new Map();\n\n // Search result cache\n private searchCache: Map<string, FontDefinition[]> = new Map();\n\n // API Configuration\n private readonly API_BASE = 'https://api.monotype.com';\n private readonly CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours\n private monotypeEnabled: boolean = false;\n\n constructor() {\n // Load persistent caches from localStorage on init\n this.loadCachesFromStorage();\n // Check if Monotype is enabled\n this.monotypeEnabled = this.checkMonotypeEnabled();\n }\n\n /**\n * Check if Monotype credentials are configured\n */\n private checkMonotypeEnabled(): boolean {\n const clientId = import.meta.env.VITE_MONOTYPE_CLIENT_ID;\n const clientSecret = import.meta.env.VITE_MONOTYPE_CLIENT_SECRET;\n return !!(clientId && clientSecret);\n }\n\n /**\n * Check if Monotype integration is enabled\n */\n isMonotypeEnabled(): boolean {\n return this.monotypeEnabled;\n }\n\n // ========================================\n // Authentication\n // ========================================\n\n /**\n * Authenticate with Monotype API using OAuth 2.0\n * Token is cached and automatically refreshed when expired\n * Returns silently if Monotype is not enabled\n */\n async authenticate(): Promise<void> {\n // Check credentials (dynamic check for testing)\n const clientId = import.meta.env.VITE_MONOTYPE_CLIENT_ID;\n const clientSecret = import.meta.env.VITE_MONOTYPE_CLIENT_SECRET;\n\n // Skip if credentials not configured\n if (!clientId || !clientSecret) {\n return;\n }\n\n // Skip if Monotype is not enabled\n if (!this.monotypeEnabled) {\n return;\n }\n\n // Check if token is still valid\n if (this.accessToken && Date.now() < this.tokenExpiry) {\n return; // Token still valid\n }\n\n try {\n\n // Encode credentials as Basic Auth\n const credentials = btoa(`${clientId}:${clientSecret}`);\n\n const response = await fetch(`${this.API_BASE}/v2/oauth/token`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'Authorization': `Basic ${credentials}`,\n },\n body: new URLSearchParams({\n grant_type: 'client_credentials',\n scope: 'read:font:data read:font:download read:font:pair read:font:similar read:font:preview create:webfonts:kit',\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n log.error('OAuth failed:', {\n status: response.status,\n statusText: response.statusText,\n error: errorText,\n });\n throw new Error(`OAuth failed: ${response.status} ${response.statusText}`);\n }\n\n const data: MonotypeTokenResponse = await response.json();\n\n if (!data.access_token) {\n throw new Error('OAuth response missing access_token');\n }\n\n this.accessToken = data.access_token;\n // Set expiry with 5 minute buffer for safety\n const expiresInSeconds = data.expires_in || 3600; // Default to 1 hour if not provided\n this.tokenExpiry = Date.now() + ((expiresInSeconds - 300) * 1000);\n\n } catch (error) {\n log.error('Failed to authenticate with Monotype:', error);\n this.accessToken = null;\n this.tokenExpiry = 0;\n throw error;\n }\n }\n\n /**\n * Check if service is authenticated\n */\n isAuthenticated(): boolean {\n return this.accessToken !== null && Date.now() < this.tokenExpiry;\n }\n\n // ========================================\n // Font Catalog Loading\n // ========================================\n\n /**\n * Fetch all Monotype fonts with pagination and caching\n * Strategy: Fetch fonts by category to get classification data\n * Returns silently if Monotype is not enabled\n */\n async fetchAllFonts(): Promise<void> {\n // Skip if Monotype is not enabled\n if (!this.monotypeEnabled) {\n this.fontsLoaded = true; // Mark as loaded (empty is valid)\n return;\n }\n\n // Check cache first\n const cached = localStorage.getItem('monotype_fonts_cache');\n if (cached) {\n try {\n const { data, timestamp } = JSON.parse(cached);\n if (Date.now() - timestamp < this.CACHE_TTL) {\n this.fonts = new Map(data);\n this.fontsLoaded = true;\n return;\n }\n } catch (error) {\n log.error('Failed to parse font cache:', error);\n }\n }\n\n // Fetch fresh data\n try {\n await this.authenticate();\n } catch (error) {\n log.error('Authentication failed, cannot fetch fonts:', error);\n throw error;\n }\n\n // Verify we have a valid token\n if (!this.accessToken) {\n const error = new Error('No access token available after authentication');\n log.error(error.message);\n throw error;\n }\n\n\n // Strategy: Fetch fonts by category to get classification data\n const categories = [\n 'SANS SERIF',\n 'SERIF',\n 'SCRIPT',\n 'DISPLAY',\n 'SLAB SERIF',\n 'MONOSPACED',\n 'HANDWRITING',\n 'BLACKLETTER',\n ];\n\n const allFonts = new Map<string, MonotypeFont>();\n\n for (const classification of categories) {\n try {\n let pageId: string | null = null;\n let pageCount = 0;\n\n do {\n const result = await this.searchFontsRaw({\n classification: [classification],\n pageSize: 50, // API maximum\n pageId: pageId || undefined,\n });\n\n // Add fonts to map (using fontId as key to dedupe)\n result.fonts.forEach((font) => {\n if (!allFonts.has(font.fontId)) {\n allFonts.set(font.fontId, font);\n }\n });\n\n pageId = result.nextPageId || null;\n pageCount++;\n\n } while (pageId);\n } catch (error) {\n log.error(`Failed to fetch ${classification} fonts:`, error);\n }\n }\n\n this.fonts = allFonts;\n this.fontsLoaded = true;\n\n // Cache to localStorage\n try {\n localStorage.setItem('monotype_fonts_cache', JSON.stringify({\n data: Array.from(allFonts.entries()),\n timestamp: Date.now(),\n }));\n } catch (error) {\n log.error('Failed to cache fonts:', error);\n }\n }\n\n /**\n * Get all Monotype fonts (uses cache if available)\n */\n getAllFonts(): MonotypeFont[] {\n return Array.from(this.fonts.values());\n }\n\n /**\n * Check if fonts have been loaded\n */\n isFontsLoaded(): boolean {\n return this.fontsLoaded;\n }\n\n // ========================================\n // Search API\n // ========================================\n\n /**\n * Search Monotype fonts (returns raw API response)\n * For internal use - external callers should use searchFonts()\n */\n private async searchFontsRaw(params: MonotypeSearchParams): Promise<MonotypeSearchResponse> {\n // Ensure we're authenticated\n await this.authenticate();\n\n if (!this.accessToken) {\n log.warn('Cannot search fonts: No access token available');\n return { fonts: [] };\n }\n\n try {\n const response = await fetch(`${this.API_BASE}/v1/fonts/search`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorDetail;\n try {\n errorDetail = JSON.parse(errorText);\n } catch {\n errorDetail = errorText;\n }\n\n log.error('Font search failed:', {\n status: response.status,\n statusText: response.statusText,\n error: errorDetail,\n params,\n });\n\n throw new Error(`Search failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n return {\n fonts: data.fonts || [],\n nextPageId: data.nextPageId,\n totalCount: data.totalCount,\n };\n } catch (error) {\n log.error('Font search failed:', error);\n return { fonts: [] };\n }\n }\n\n /**\n * Search Monotype fonts and return FontDefinitions\n * Supports text search, fuzzy matching, and category filtering\n */\n async searchFonts(params: MonotypeSearchParams): Promise<FontDefinition[]> {\n // Check cache\n const cacheKey = JSON.stringify(params);\n if (this.searchCache.has(cacheKey)) {\n return this.searchCache.get(cacheKey)!;\n }\n\n // Fetch results\n const result = await this.searchFontsRaw(params);\n\n // Group by family and convert to FontDefinitions\n const fontDefinitions = this.groupMonotypeFontsByFamily(result.fonts);\n\n // Cache results\n this.searchCache.set(cacheKey, fontDefinitions);\n\n return fontDefinitions;\n }\n\n /**\n * Search fonts by name with fuzzy matching\n */\n async searchFontsByName(query: string): Promise<FontDefinition[]> {\n if (!query.trim()) {\n return this.groupMonotypeFontsByFamily(this.getAllFonts());\n }\n\n return this.searchFonts({\n name: query,\n searchSettings: {\n fuzzy: ['name'], // Typo tolerance: \"Helvtica\" finds \"Helvetica\"\n },\n pageSize: 50, // API maximum\n });\n }\n\n /**\n * Filter fonts by category\n */\n async filterFontsByCategory(category: FontCategory): Promise<FontDefinition[]> {\n if (category === 'system') {\n return []; // Monotype has no system fonts\n }\n\n const classifications = getMonotypeClassifications(category);\n if (classifications.length === 0) {\n return [];\n }\n\n return this.searchFonts({\n classification: classifications,\n pageSize: 50, // API maximum (pagination handles the rest)\n });\n }\n\n // ========================================\n // Font Family Grouping\n // ========================================\n\n /**\n * Group Monotype fonts by family\n * Reduces 492 font variants to ~120 font families\n */\n groupMonotypeFontsByFamily(fonts: MonotypeFont[]): FontDefinition[] {\n const familyMap = new Map<string, MonotypeFont[]>();\n\n // Group by family\n fonts.forEach((font) => {\n const familyKey = font.family || font.name;\n if (!familyMap.has(familyKey)) {\n familyMap.set(familyKey, []);\n }\n familyMap.get(familyKey)!.push(font);\n });\n\n // Create one FontDefinition per family\n return Array.from(familyMap.entries()).map(([family, variants]) => {\n const representative = variants[0]; // Use first variant for metadata\n\n return {\n name: family.replace(/[™®]/g, '').trim(), // Remove trademark symbols\n category: mapMonotypeClassifications(representative.classification || []),\n monotypeFont: true,\n googleFont: false, // Mutually exclusive\n monotypeId: representative.fontId,\n source: 'monotype' as const,\n foundry: representative.foundry,\n weights: this.extractWeights(variants),\n tags: representative.tag || [],\n preview: representative.sample,\n };\n });\n }\n\n /**\n * Extract font weights from variants\n */\n private extractWeights(variants: MonotypeFont[]): number[] {\n const weights = new Set<number>();\n variants.forEach((variant) => {\n if (variant.weightCSS) {\n weights.add(variant.weightCSS);\n }\n });\n return Array.from(weights).sort();\n }\n\n // ========================================\n // WebFont Kit Generation & Caching\n // ========================================\n\n /**\n * Get or generate WebFont kit for a Monotype font\n * Kit URLs are persistent and cached forever\n */\n async getWebFontKit(fontId: string, fontFamily: string): Promise<WebFontKit> {\n // Check memory cache first\n if (this.webfontKits.has(fontId)) {\n return this.webfontKits.get(fontId)!;\n }\n\n // Check localStorage persistent cache\n const cachedKits = localStorage.getItem('monotype_webfont_kits');\n if (cachedKits) {\n try {\n const kits = new Map<string, WebFontKit>(JSON.parse(cachedKits));\n if (kits.has(fontId)) {\n const kit = kits.get(fontId)!;\n this.webfontKits.set(fontId, kit);\n return kit;\n }\n } catch (error) {\n log.error('Failed to parse webfont kit cache:', error);\n }\n }\n\n // Generate new kit\n await this.authenticate();\n\n if (!this.accessToken) {\n throw new Error('Not authenticated - no access token available');\n }\n\n try {\n const response = await fetch(`${this.API_BASE}/v1/webfonts/kit`, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${this.accessToken}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n kitName: `MonotypeFontKit_${fontId.substring(0, 8)}`,\n kitType: 'Embed',\n fontFormats: ['WOFF2', 'WOFF'],\n fonts: [{ fontId }],\n includeDefaultWordpressFiles: false,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let errorDetail;\n try {\n errorDetail = JSON.parse(errorText);\n } catch {\n errorDetail = errorText;\n }\n\n log.error('WebFont kit generation failed:', {\n status: response.status,\n statusText: response.statusText,\n error: errorDetail,\n fontId,\n fontFamily,\n });\n\n throw new Error(`Kit generation failed: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json();\n\n const kit: WebFontKit = {\n fontFamily: data.webFonts[0]?.fontFamily || fontFamily,\n cssUrl: data.kitUrl, // PERSISTENT CDN URL!\n timestamp: Date.now(),\n };\n\n // Cache in memory\n this.webfontKits.set(fontId, kit);\n\n // Persist to localStorage\n this.saveCachesToStorage();\n\n return kit;\n } catch (error) {\n log.error('Failed to generate WebFont kit:', error);\n throw error;\n }\n }\n\n /**\n * Load Monotype font by injecting CSS link\n */\n async loadMonotypeFont(fontId: string, fontFamily: string): Promise<void> {\n try {\n const kit = await this.getWebFontKit(fontId, fontFamily);\n\n // Check if already loaded\n const linkId = `monotype-font-${fontId}`;\n if (document.getElementById(linkId)) {\n return;\n }\n\n // Inject CSS link\n const link = document.createElement('link');\n link.id = linkId;\n link.rel = 'stylesheet';\n link.href = kit.cssUrl; // Points to Monotype CDN!\n document.head.appendChild(link);\n\n // Wait for font to load\n await document.fonts.ready;\n } catch (error) {\n log.error(`Failed to load Monotype font ${fontFamily}:`, error);\n throw error;\n }\n }\n\n // ========================================\n // Cache Management\n // ========================================\n\n /**\n * Load caches from localStorage\n */\n private loadCachesFromStorage(): void {\n // Skip during SSR - localStorage is not available\n if (typeof window === 'undefined') {\n return;\n }\n try {\n // Load webfont kits\n const cachedKits = localStorage.getItem('monotype_webfont_kits');\n if (cachedKits) {\n this.webfontKits = new Map(JSON.parse(cachedKits));\n }\n } catch (error) {\n log.error('Failed to load caches:', error);\n }\n }\n\n /**\n * Save caches to localStorage\n */\n private saveCachesToStorage(): void {\n // Skip during SSR - localStorage is not available\n if (typeof window === 'undefined') {\n return;\n }\n try {\n localStorage.setItem(\n 'monotype_webfont_kits',\n JSON.stringify(Array.from(this.webfontKits.entries()))\n );\n } catch (error) {\n log.error('Failed to save caches:', error);\n }\n }\n\n /**\n * Clear all caches (including auth state)\n */\n clearCaches(): void {\n this.fonts.clear();\n this.webfontKits.clear();\n this.searchCache.clear();\n this.fontsLoaded = false;\n this.accessToken = null;\n this.tokenExpiry = 0;\n localStorage.removeItem('monotype_fonts_cache');\n localStorage.removeItem('monotype_webfont_kits');\n }\n\n /**\n * Get service stats for debugging\n */\n getStats() {\n return {\n monotypeEnabled: this.monotypeEnabled,\n authenticated: this.isAuthenticated(),\n hasAccessToken: !!this.accessToken,\n tokenExpiry: this.tokenExpiry > 0 ? new Date(this.tokenExpiry).toISOString() : null,\n fontsLoaded: this.fontsLoaded,\n fontCount: this.fonts.size,\n familyCount: this.groupMonotypeFontsByFamily(this.getAllFonts()).length,\n webfontKitCount: this.webfontKits.size,\n searchCacheSize: this.searchCache.size,\n };\n }\n}\n\n// Export singleton instance\nexport const MonotypeService = new MonotypeServiceClass();\n","/**\n * UnifiedFontService - Combines Google Fonts and Monotype Fonts\n *\n * Features:\n * - Seamless integration of Google Fonts + Monotype fonts\n * - Dual search strategy: text search + category filtering\n * - Font deduplication (if same family exists in both sources)\n * - Unified font loading (Google CSS vs Monotype WebFont kits)\n *\n * Architecture: See docs/MONOTYPE_INTEGRATION_ARCHITECTURE.md\n */\n\nimport { FontCategory, FontDefinition, TSHIRT_FONTS } from '../fonts/google-fonts.js';\nimport {\n fetchAllGoogleFonts,\n getAllGoogleFonts,\n isFontsLoaded as isGoogleFontsLoaded,\n GoogleFontMetadata,\n mapGoogleCategory,\n} from './GoogleFontsService.js';\nimport { MonotypeService } from './MonotypeService.js';\nimport { getCategoryMapping } from './MonotypeCategoryMapping.js';\nimport { createLogger } from './logger.js';\n\nconst logger = createLogger('UnifiedFontService');\n\n// ============================================================================\n// UnifiedFontService Class\n// ============================================================================\n\nclass UnifiedFontServiceClass {\n // Search result cache\n private searchCache: Map<string, FontDefinition[]> = new Map();\n\n // Track preview font links for cleanup (prevents iOS Safari memory crashes)\n // With text= parameter, each preview font is ~0.1KB (not 50KB), so we can keep many loaded\n // Cleanup happens when drawer closes via clearPreviewFonts()\n private previewFontLinks: Set<string> = new Set();\n\n // ========================================\n // Initialization\n // ========================================\n\n /**\n * Initialize both Google Fonts and Monotype\n * Monotype is optional - app works with Google Fonts only if credentials not configured\n */\n async initialize(): Promise<void> {\n try {\n // Always fetch Google Fonts\n await fetchAllGoogleFonts();\n\n // Try to load Monotype fonts (optional)\n if (MonotypeService.isMonotypeEnabled()) {\n try {\n await MonotypeService.authenticate();\n await MonotypeService.fetchAllFonts();\n } catch (error) {\n logger.warn('Monotype fonts failed to load (continuing with Google Fonts only):', error);\n }\n } else {\n }\n\n } catch (error) {\n logger.error('Failed to initialize UnifiedFontService:', error);\n // Graceful degradation: Continue even if Google Fonts fail\n }\n }\n\n /**\n * Check if fonts are loaded\n */\n isFontsLoaded(): boolean {\n return isGoogleFontsLoaded() || MonotypeService.isFontsLoaded();\n }\n\n /**\n * Check if Monotype integration is enabled\n */\n isMonotypeEnabled(): boolean {\n return MonotypeService.isMonotypeEnabled();\n }\n\n // ========================================\n // Font Retrieval\n // ========================================\n\n /**\n * Get all fonts from both sources\n * Returns system fonts + Google Fonts + Monotype Fonts (deduplicated)\n */\n getAllFonts(): FontDefinition[] {\n const systemFonts = TSHIRT_FONTS.filter(f => !f.googleFont && !f.monotypeFont);\n const googleFonts = this.mapGoogleFonts(getAllGoogleFonts());\n const monotopeFonts = MonotypeService.groupMonotypeFontsByFamily(\n MonotypeService.getAllFonts()\n );\n\n return this.mergeFonts([...systemFonts, ...googleFonts, ...monotopeFonts]);\n }\n\n /**\n * Get recommended fonts (TSHIRT_FONTS curated list)\n */\n getRecommendedFonts(): FontDefinition[] {\n return TSHIRT_FONTS;\n }\n\n // ========================================\n // Dual Search Strategy\n // ========================================\n\n /**\n * Search fonts by name (text search with fuzzy matching)\n * Combines results from both Google Fonts and Monotype\n */\n async searchFontsByName(query: string): Promise<FontDefinition[]> {\n if (!query.trim()) {\n return this.getAllFonts();\n }\n\n // Check cache\n const cacheKey = `search:${query.toLowerCase()}`;\n if (this.searchCache.has(cacheKey)) {\n return this.searchCache.get(cacheKey)!;\n }\n\n const normalizedQuery = query.toLowerCase().trim();\n\n // Search Google Fonts (client-side filter)\n const googleResults = getAllGoogleFonts()\n .filter((f) => f.family.toLowerCase().includes(normalizedQuery))\n .map((f) => this.mapGoogleFont(f));\n\n // Search Monotype Fonts (API with fuzzy matching)\n const monotypeResults = await MonotypeService.searchFontsByName(query);\n\n // Merge and deduplicate\n const results = this.mergeFonts([...googleResults, ...monotypeResults]);\n\n // Cache results\n this.searchCache.set(cacheKey, results);\n\n return results;\n }\n\n /**\n * Filter fonts by category\n * Combines results from both Google Fonts and Monotype\n */\n async filterFontsByCategory(category: FontCategory): Promise<FontDefinition[]> {\n if (category === 'system') {\n // System fonts only\n return TSHIRT_FONTS.filter((f) => !f.googleFont && !f.monotypeFont);\n }\n\n // Check cache\n const cacheKey = `category:${category}`;\n if (this.searchCache.has(cacheKey)) {\n return this.searchCache.get(cacheKey)!;\n }\n\n const mapping = getCategoryMapping(category);\n if (!mapping) {\n return [];\n }\n\n // Filter Google Fonts (client-side)\n const googleResults = getAllGoogleFonts()\n .filter((f) => {\n const mappedCategory = mapGoogleCategory(f.category);\n return mappedCategory === category;\n })\n .map((f) => this.mapGoogleFont(f));\n\n // Filter Monotype Fonts (API)\n const monotypeResults = await MonotypeService.filterFontsByCategory(category);\n\n // Merge and deduplicate\n const results = this.mergeFonts([...googleResults, ...monotypeResults]);\n\n // Cache results\n this.searchCache.set(cacheKey, results);\n\n return results;\n }\n\n /**\n * Combined search: text search + category filter\n * Option A: Search overrides category (simpler UX)\n */\n async searchAndFilterFonts(\n query: string,\n category: FontCategory | 'all'\n ): Promise<FontDefinition[]> {\n if (query.trim()) {\n // Search overrides category\n return this.searchFontsByName(query);\n } else if (category !== 'all') {\n // Category filter\n return this.filterFontsByCategory(category);\n } else {\n // Show all\n return this.getAllFonts();\n }\n }\n\n // ========================================\n // Font Loading\n // ========================================\n\n /**\n * Load a font (Google or Monotype). All exposed fonts are one or\n * the other; the picker no longer offers true \"system\" fonts that\n * aren't on Google Fonts because Android lacks them and we'd render\n * inconsistently across platforms.\n */\n async loadFont(font: FontDefinition): Promise<void> {\n try {\n if (font.googleFont && !font.monotypeFont) {\n this.loadGoogleFont(font.name);\n } else if (font.monotypeFont && font.monotypeId) {\n await MonotypeService.loadMonotypeFont(font.monotypeId, font.name);\n }\n } catch (error) {\n logger.error(`Failed to load font ${font.name}:`, error);\n }\n }\n\n /**\n * Load Google Font via CSS link injection (full font)\n */\n private loadGoogleFont(fontName: string): void {\n // Check if font is already loaded\n const linkId = `font-${fontName.replace(/\\s+/g, '-').toLowerCase()}`;\n if (document.getElementById(linkId)) return;\n\n // Create link element\n const link = document.createElement('link');\n link.id = linkId;\n link.rel = 'stylesheet';\n link.href = `https://fonts.googleapis.com/css2?family=${fontName.replace(/\\s+/g, '+')}:wght@400;700&display=swap`;\n document.head.appendChild(link);\n }\n\n /**\n * Load Google Font with only specific characters (for previews)\n * Uses the text= parameter to load minimal glyphs (~99.9% smaller than full font)\n * See: https://developers.google.com/fonts/docs/getting_started#optimizing_your_font_requests\n *\n * @param fontName - Font family name\n * @param text - Text to render (only these characters will be loaded)\n */\n loadGoogleFontForPreview(fontName: string, text: string): void {\n // Encode text for URL (handles spaces, international characters, etc.)\n const encodedText = encodeURIComponent(text);\n // Use simple link ID based on font name only - we just need the font loaded\n // for preview, the exact characters don't matter for the ID\n const linkId = `font-preview-${fontName.replace(/\\s+/g, '-').toLowerCase()}`;\n\n // Check if already loaded\n if (document.getElementById(linkId)) return;\n\n // No eviction during browsing - with text= parameter each font is ~0.1KB\n // Cleanup happens when drawer closes via clearPreviewFonts()\n\n // Create link element with text= parameter for minimal glyph loading\n const link = document.createElement('link');\n link.id = linkId;\n link.rel = 'stylesheet';\n // Use text= parameter - only loads glyphs needed for the preview text\n link.href = `https://fonts.googleapis.com/css2?family=${fontName.replace(/\\s+/g, '+')}&display=swap&text=${encodedText}`;\n document.head.appendChild(link);\n this.previewFontLinks.add(linkId);\n }\n\n /**\n * Clear all preview font links from DOM\n * Call this when closing the font browser to free memory\n */\n clearPreviewFonts(): void {\n this.previewFontLinks.forEach((linkId) => {\n const link = document.getElementById(linkId);\n if (link) {\n link.remove();\n }\n });\n this.previewFontLinks.clear();\n }\n\n /**\n * Get count of loaded preview fonts\n */\n getPreviewFontCount(): number {\n return this.previewFontLinks.size;\n }\n\n // ========================================\n // Font Mapping & Merging\n // ========================================\n\n /**\n * Map Google Font metadata to FontDefinition\n */\n private mapGoogleFont(googleFont: GoogleFontMetadata): FontDefinition {\n return {\n name: googleFont.family,\n category: mapGoogleCategory(googleFont.category) as FontCategory,\n googleFont: true,\n monotypeFont: false,\n source: 'google',\n weights: googleFont.variants\n ?.map((v) => {\n // Map variant strings like \"regular\", \"700\", \"700italic\" to numbers\n const match = v.match(/\\d+/);\n if (match) return parseInt(match[0], 10);\n if (v === 'regular') return 400;\n return null;\n })\n .filter((w): w is number => w !== null) || [400],\n };\n }\n\n /**\n * Map Google Fonts array to FontDefinitions\n */\n private mapGoogleFonts(googleFonts: GoogleFontMetadata[]): FontDefinition[] {\n return googleFonts.map((f) => this.mapGoogleFont(f));\n }\n\n /**\n * Merge fonts from multiple sources and deduplicate by family name\n * Priority: Monotype > Google (Monotype fonts are premium)\n */\n private mergeFonts(fonts: FontDefinition[]): FontDefinition[] {\n const fontMap = new Map<string, FontDefinition>();\n\n fonts.forEach((font) => {\n const key = font.name.toLowerCase().trim();\n\n // If font doesn't exist, add it\n if (!fontMap.has(key)) {\n fontMap.set(key, font);\n } else {\n // If both exist, prefer Monotype (premium source)\n const existing = fontMap.get(key)!;\n if (font.monotypeFont && !existing.monotypeFont) {\n fontMap.set(key, font);\n }\n }\n });\n\n // Sort alphabetically\n return Array.from(fontMap.values()).sort((a, b) => a.name.localeCompare(b.name));\n }\n\n // ========================================\n // Cache Management\n // ========================================\n\n /**\n * Clear search cache\n */\n clearSearchCache(): void {\n this.searchCache.clear();\n }\n\n /**\n * Clear all caches (including Monotype service caches)\n */\n clearAllCaches(): void {\n this.clearSearchCache();\n MonotypeService.clearCaches();\n }\n\n // ========================================\n // Stats & Debugging\n // ========================================\n\n /**\n * Get service stats for debugging\n */\n getStats() {\n const allFonts = this.getAllFonts();\n const googleFonts = allFonts.filter((f) => f.googleFont && !f.monotypeFont);\n const monotopeFonts = allFonts.filter((f) => f.monotypeFont);\n const systemFonts = allFonts.filter((f) => !f.googleFont && !f.monotypeFont);\n\n return {\n initialized: this.isFontsLoaded(),\n monotypeEnabled: this.isMonotypeEnabled(),\n totalFonts: allFonts.length,\n googleFontsCount: googleFonts.length,\n monotopeFontsCount: monotopeFonts.length,\n systemFontsCount: systemFonts.length,\n searchCacheSize: this.searchCache.size,\n monotypeStats: MonotypeService.getStats(),\n };\n }\n}\n\n// Export singleton instance\nexport const UnifiedFontService = new UnifiedFontServiceClass();\n","/**\n * Text utility functions\n */\n\n/**\n * Strip glyph characters from text for display purposes\n * Removes PUA (Private Use Area) characters used for alternate glyphs\n *\n * @param text - Text that may contain glyph characters\n * @returns Text with glyph characters removed\n */\nexport function stripGlyphs(text: string): string {\n // Remove PUA (Private Use Area) characters used for glyphs\n // PUA range: U+E000 to U+F8FF (standard), U+F0000 to U+FFFFD (supplementary)\n return Array.from(text)\n .filter((char) => {\n const cp = char.codePointAt(0);\n return !cp || cp < 0xf0000 || cp > 0xffffd;\n })\n .join('');\n}\n","/**\n * FontBrowserDrawer - Drawer for selecting font family with search and category filters\n * Refactored to use HeroUI design system\n */\n\nimport React, { useRef, useEffect, useState, useMemo } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Input, Button, Tabs, Surface, Tooltip, TooltipTrigger, TooltipContent, TextField } from './ui';\nimport { Drawer } from './Drawer';\nimport { TSHIRT_FONTS, CATEGORY_LABELS, FontCategory, FontDefinition } from '../fonts/google-fonts.js';\nimport { UnifiedFontService } from '../utils/UnifiedFontService.js';\nimport { stripGlyphs } from '../utils/textUtils.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger('FontBrowserDrawer');\n\nexport interface FontBrowserDrawerProps {\n value: string;\n onChange: (event: { target: { value: string } }) => void;\n fontFamilies?: string[]; // Optional - uses TSHIRT_FONTS by default\n isOpen: boolean;\n onToggle: (open: boolean) => void;\n showLabel?: boolean;\n previewText?: string; // Text to preview in each font\n elements?: Array<Record<string, unknown>>; // Elements to extract fonts used in document\n}\n\nconst FontBrowserDrawer = ({\n value,\n onChange,\n fontFamilies: _fontFamilies,\n isOpen,\n onToggle,\n showLabel: _,\n previewText,\n elements,\n}: FontBrowserDrawerProps) => {\n const selectedFontRef = useRef<HTMLDivElement>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedCategory, setSelectedCategory] = useState<FontCategory | 'all'>('all');\n const [fontsLoadedTrigger, setFontsLoadedTrigger] = useState(0); // Used to trigger re-render when fonts load\n const [displayMode, setDisplayMode] = useState<'both' | 'name' | 'preview'>('name'); // Three-way toggle: preview+name, name only, preview only\n const [cardSize, setCardSize] = useState<'small' | 'medium' | 'large'>('medium'); // Card size: small (1.0), medium (1.8), large (3.0)\n const [viewMode, setViewMode] = useState<'grid' | 'masonry'>('masonry'); // Toggle between grid and masonry layout\n const [loadedFonts, setLoadedFonts] = useState<Set<string>>(new Set()); // Track which fonts have been loaded\n const loadQueueRef = useRef<string[]>([]); // Queue of fonts to load\n const loadingRef = useRef(false); // Flag to prevent concurrent loading\n\n // Convert size name to numeric scale value\n const getCardSizeScale = (size: 'small' | 'medium' | 'large'): number => {\n switch (size) {\n case 'small':\n return 1.0;\n case 'medium':\n return 1.8;\n case 'large':\n return 3.0;\n }\n };\n\n const cardSizeScale = getCardSizeScale(cardSize);\n\n // Inject font-preview CSS rule to ensure it overrides body font-family\n useEffect(() => {\n const styleId = 'font-preview-style';\n if (!document.getElementById(styleId)) {\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = '.font-preview { font-family: var(--font-preview) !important; }';\n document.head.appendChild(style);\n }\n }, []);\n\n // Fetch all fonts (Google + Monotype) on mount\n useEffect(() => {\n if (!UnifiedFontService.isFontsLoaded()) {\n UnifiedFontService.initialize()\n .then(() => {\n setFontsLoadedTrigger((prev) => prev + 1); // Trigger re-render\n })\n .catch((error) => {\n logger.error('Failed to load fonts:', error);\n });\n }\n }, []);\n\n // Function to dynamically load a font for preview\n // Uses text= parameter to load only required glyphs (~99.9% smaller than full font)\n const loadFont = async (font: FontDefinition, forSelection: boolean = false) => {\n try {\n if (forSelection) {\n // Loading for actual selection - load full font\n await UnifiedFontService.loadFont(font);\n } else if (font.googleFont && !font.monotypeFont) {\n // Google Font preview - load only characters needed for preview text AND font name\n // This prevents iOS Safari memory crashes from loading full fonts\n // We need both: the preview text to display, and the font name for the label\n const textToLoad = previewText ? `${previewText}${font.name}` : font.name;\n UnifiedFontService.loadGoogleFontForPreview(font.name, textToLoad);\n } else {\n // Monotype or system font - use regular loading\n await UnifiedFontService.loadFont(font);\n }\n // Update state immediately (no batching) to prevent accumulating 50+ fonts in one render\n setLoadedFonts((prev) => new Set(prev).add(font.name));\n } catch (error) {\n logger.error(`Failed to load font ${font.name}:`, error);\n }\n };\n\n // Load all queued fonts concurrently (no delays)\n useEffect(() => {\n const processQueue = async () => {\n if (loadingRef.current || loadQueueRef.current.length === 0) return;\n\n loadingRef.current = true;\n\n // Take all queued fonts and load them concurrently\n const fontsToLoad = [...loadQueueRef.current];\n loadQueueRef.current = [];\n\n const allFonts = UnifiedFontService.getAllFonts();\n\n // Load all fonts at once\n await Promise.all(\n fontsToLoad.map(async (fontName) => {\n const font = allFonts.find((f) => f.name === fontName);\n if (font && !loadedFonts.has(fontName)) {\n await loadFont(font);\n }\n })\n );\n\n loadingRef.current = false;\n };\n\n processQueue();\n }, [loadedFonts]);\n\n // Add font to load queue (called when font comes into view)\n const queueFontLoad = (fontName: string) => {\n // Check if already loaded or queued to avoid duplicates\n const alreadyLoaded = loadedFonts.has(fontName);\n const alreadyQueued = loadQueueRef.current.includes(fontName);\n\n if (!alreadyLoaded && !alreadyQueued) {\n loadQueueRef.current.push(fontName);\n // Trigger queue processing immediately if not already running\n if (!loadingRef.current && loadQueueRef.current.length === 1) {\n setLoadedFonts((prev) => new Set(prev)); // Trigger useEffect\n }\n }\n };\n\n // Focus search input when drawer opens\n useEffect(() => {\n if (isOpen) {\n // Scroll to selected font\n setTimeout(() => {\n if (selectedFontRef.current) {\n selectedFontRef.current.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n }, 150);\n }\n // Reset filters and clear preview fonts when closing\n if (!isOpen) {\n setSearchQuery('');\n setSelectedCategory('all');\n // Clear preview font links from DOM to free memory (prevents iOS Safari crashes)\n UnifiedFontService.clearPreviewFonts();\n // Reset loaded fonts set so previews will load fresh next time\n setLoadedFonts(new Set());\n }\n }, [isOpen, value]);\n\n // Load the currently selected font so it displays correctly in the toolbar button\n // This needs to be the full font since it's actively being used\n useEffect(() => {\n if (value && !loadedFonts.has(value)) {\n const allFonts = UnifiedFontService.getAllFonts();\n const font = allFonts.find((f) => f.name === value);\n if (font) {\n loadFont(font, true); // forSelection=true to load full font\n }\n }\n }, [value, loadedFonts, fontsLoadedTrigger]);\n\n // When user starts searching, reset category to all\n useEffect(() => {\n if (searchQuery.trim()) {\n setSelectedCategory('all');\n }\n }, [searchQuery]);\n\n const handleSelect = async (family: string) => {\n // Load full font on selection (preview only loaded subset characters)\n const allFonts = UnifiedFontService.getAllFonts();\n const selectedFont = allFonts.find((f) => f.name === family);\n if (selectedFont) {\n try {\n // Load full font for actual use (forSelection=true)\n await loadFont(selectedFont, true);\n } catch (error) {\n logger.warn(`Failed to load font ${family}, will use fallback`);\n }\n }\n\n onChange({ target: { value: family } });\n // Small delay to allow tooltip to close properly before drawer closes\n setTimeout(() => onToggle(false), 0);\n };\n\n // Font Item Component - Memoized to prevent unnecessary re-renders\n const FontItem = React.memo(\n ({ font, isUsedInDocument = false }: { font: FontDefinition; isUsedInDocument?: boolean }) => {\n const fontItemRef = useRef<HTMLDivElement>(null);\n const isSelected = value === font.name;\n const isLoaded = loadedFonts.has(font.name);\n const isPremium = font.monotypeFont === true;\n\n // Lazy load fonts when they come into view\n useEffect(() => {\n if (!fontItemRef.current) return;\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting && !isLoaded) {\n queueFontLoad(font.name);\n }\n });\n },\n { rootMargin: '600px' } // Load fonts before they come into view for smoother scrolling\n );\n\n observer.observe(fontItemRef.current);\n\n return () => observer.disconnect();\n }, [font.name, isLoaded]);\n\n // Determine what text to display based on mode\n let mainText = '';\n let showSecondaryLabel = false;\n\n if (displayMode === 'name') {\n mainText = font.name;\n showSecondaryLabel = false;\n } else if (displayMode === 'preview') {\n mainText = previewText || font.name;\n // Only show font name underneath in \"Used in Document\" section\n showSecondaryLabel = isUsedInDocument;\n } else {\n // displayMode === 'both'\n mainText = previewText || font.name;\n showSecondaryLabel = true;\n }\n\n // Check if we should show a tooltip (when displaying user text and not showing secondary label)\n const shouldShowTooltip = displayMode === 'preview' && !showSecondaryLabel;\n\n const surfaceContent = (\n <Surface\n ref={(el) => {\n // Assign to both refs: selectedFontRef for scrolling, fontItemRef for intersection observer\n if (isSelected && selectedFontRef) {\n selectedFontRef.current = el;\n }\n fontItemRef.current = el;\n }}\n className={`relative flex cursor-pointer flex-col justify-center rounded-lg border-2 text-left ${viewMode === 'masonry' ? 'w-fit' : 'min-w-0'} ${isSelected ? 'border-accent' : 'hover:border-muted border-transparent'}`}\n onClick={shouldShowTooltip ? undefined : () => handleSelect(font.name)}\n role={shouldShowTooltip ? undefined : 'button'}\n aria-label={shouldShowTooltip ? undefined : `Select ${font.name} font`}\n tabIndex={shouldShowTooltip ? undefined : 0}\n onKeyDown={\n shouldShowTooltip\n ? undefined\n : (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelect(font.name);\n }\n }\n }\n style={{\n minHeight: `${showSecondaryLabel ? 48 * cardSizeScale : 36 * cardSizeScale}px`,\n padding: `${6 * cardSizeScale}px ${10 * cardSizeScale}px`,\n gap: `${2 * cardSizeScale}px`,\n }}\n >\n {/* Simple loading background - no animation for performance */}\n {!isLoaded && (\n <div\n className=\"absolute inset-0 rounded-lg bg-gray-100\"\n style={{\n opacity: 0.5,\n }}\n />\n )}\n\n <div\n className=\"font-preview text-foreground overflow-hidden leading-[1.1] font-medium text-ellipsis whitespace-nowrap\"\n style={{\n '--font-preview': isLoaded ? `\"${font.name}\", sans-serif` : 'sans-serif',\n fontSize: `${15 * cardSizeScale}px`,\n opacity: isLoaded ? 1 : 0.4,\n } as React.CSSProperties}\n >\n {mainText}\n </div>\n {showSecondaryLabel && (\n <div\n className=\"text-muted overflow-hidden font-sans leading-[1.1] font-normal text-ellipsis whitespace-nowrap\"\n style={{\n fontSize: `${7 * cardSizeScale}px`,\n opacity: isLoaded ? 1 : 0.4,\n }}\n >\n {font.name}\n </div>\n )}\n\n {/* Premium indicator - orange dot */}\n {isPremium && (\n <div\n className=\"absolute rounded-full bg-orange-500\"\n style={{\n top: `${4 * cardSizeScale}px`,\n right: `${4 * cardSizeScale}px`,\n width: `${6 * cardSizeScale}px`,\n height: `${6 * cardSizeScale}px`,\n }}\n title=\"Premium Monotype Font\"\n />\n )}\n </Surface>\n );\n\n // Wrap with Tooltip if needed\n if (shouldShowTooltip) {\n return (\n <Tooltip key={font.name} delayDuration={200}>\n <TooltipTrigger asChild>\n <Button\n className=\"m-0 inline-block h-auto min-h-0 border-0 bg-transparent p-0 hover:bg-transparent\"\n style={{ width: viewMode === 'masonry' ? 'auto' : '100%' }}\n onClick={() => handleSelect(font.name)}\n aria-label={`Select ${font.name} font`}\n >\n <Surface\n ref={(el) => {\n // Assign to both refs: selectedFontRef for scrolling, fontItemRef for intersection observer\n if (isSelected && selectedFontRef) {\n selectedFontRef.current = el;\n }\n fontItemRef.current = el;\n }}\n className={`relative flex cursor-pointer flex-col justify-center rounded-lg border-2 text-left ${viewMode === 'masonry' ? 'w-fit' : 'min-w-0'} ${isSelected ? 'border-accent' : 'hover:border-muted border-transparent'}`}\n style={{\n minHeight: `${showSecondaryLabel ? 48 * cardSizeScale : 36 * cardSizeScale}px`,\n padding: `${6 * cardSizeScale}px ${10 * cardSizeScale}px`,\n gap: `${2 * cardSizeScale}px`,\n }}\n >\n {/* Simple loading background - no animation for performance */}\n {!isLoaded && (\n <div\n className=\"absolute inset-0 rounded-lg bg-gray-100\"\n style={{\n opacity: 0.5,\n }}\n />\n )}\n\n <div\n className=\"font-preview text-foreground overflow-hidden leading-[1.1] font-medium text-ellipsis whitespace-nowrap\"\n style={{\n '--font-preview': isLoaded ? `\"${font.name}\", sans-serif` : 'sans-serif',\n fontSize: `${15 * cardSizeScale}px`,\n opacity: isLoaded ? 1 : 0.4,\n } as React.CSSProperties}\n >\n {mainText}\n </div>\n {showSecondaryLabel && (\n <div\n className=\"text-muted overflow-hidden font-sans leading-[1.1] font-normal text-ellipsis whitespace-nowrap\"\n style={{\n fontSize: `${7 * cardSizeScale}px`,\n opacity: isLoaded ? 1 : 0.4,\n }}\n >\n {font.name}\n </div>\n )}\n\n {/* Premium indicator - orange dot */}\n {isPremium && (\n <div\n className=\"absolute rounded-full bg-orange-500\"\n style={{\n top: `${4 * cardSizeScale}px`,\n right: `${4 * cardSizeScale}px`,\n width: `${6 * cardSizeScale}px`,\n height: `${6 * cardSizeScale}px`,\n }}\n title=\"Premium Monotype Font\"\n />\n )}\n </Surface>\n </Button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">\n <p>{font.name}</p>\n </TooltipContent>\n </Tooltip>\n );\n }\n\n return <React.Fragment key={font.name}>{surfaceContent}</React.Fragment>;\n },\n (prevProps, nextProps) => {\n // Custom comparison for memoization\n return prevProps.font.name === nextProps.font.name && prevProps.isUsedInDocument === nextProps.isUsedInDocument;\n }\n );\n\n // Extract fonts used in the document (excluding glyph-only elements)\n const fontsUsedInDocument = useMemo(() => {\n if (!elements) return new Set<string>();\n\n const usedFonts = new Set<string>();\n\n const addFontIfValid = (el: Record<string, unknown>) => {\n // Only add font if element has a fontFamily and non-glyph text\n const fontFamily = el.fontFamily as string | undefined;\n const text = el.text as string | undefined;\n if (fontFamily && text) {\n const cleanText = stripGlyphs(text);\n // Only add if there's actual text left after stripping glyphs\n if (cleanText.trim().length > 0) {\n usedFonts.add(fontFamily);\n }\n }\n };\n\n elements.forEach((el) => {\n addFontIfValid(el);\n\n // Check children for groups\n if (el.children && Array.isArray(el.children)) {\n (el.children as Record<string, unknown>[]).forEach((child) => {\n addFontIfValid(child);\n });\n }\n });\n\n return usedFonts;\n }, [elements]);\n\n // Organize fonts into sections\n const fontSections = useMemo(() => {\n // Get all fonts from UnifiedFontService (system + Google + Monotype)\n const allFonts = UnifiedFontService.isFontsLoaded() ? UnifiedFontService.getAllFonts() : TSHIRT_FONTS; // Fallback to recommended fonts only if not loaded\n\n const recommendedNames = new Set(TSHIRT_FONTS.map((f) => f.name));\n\n // Extract \"Used in Document\" fonts first (only filter by search, not category)\n const usedFonts: FontDefinition[] = [];\n allFonts.forEach((font) => {\n if (fontsUsedInDocument.has(font.name)) {\n // Only apply search filter, not category filter\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n if (font.name.toLowerCase().includes(query)) {\n usedFonts.push(font);\n }\n } else {\n usedFonts.push(font);\n }\n }\n });\n\n // For remaining fonts, apply both category and search filters\n let remainingFonts = allFonts.filter((font) => !fontsUsedInDocument.has(font.name));\n\n // Filter by category\n if (selectedCategory !== 'all') {\n remainingFonts = remainingFonts.filter((font) => font.category === selectedCategory);\n }\n\n // Filter by search query\n if (searchQuery) {\n const query = searchQuery.toLowerCase();\n remainingFonts = remainingFonts.filter((font) => font.name.toLowerCase().includes(query));\n }\n\n // Separate remaining into recommended and other\n const recommendedFonts: FontDefinition[] = [];\n const otherFonts: FontDefinition[] = [];\n\n remainingFonts.forEach((font) => {\n if (recommendedNames.has(font.name)) {\n recommendedFonts.push(font);\n } else {\n otherFonts.push(font);\n }\n });\n\n // Sort each section alphabetically\n usedFonts.sort((a, b) => a.name.localeCompare(b.name));\n recommendedFonts.sort((a, b) => a.name.localeCompare(b.name));\n otherFonts.sort((a, b) => a.name.localeCompare(b.name));\n\n return { usedFonts, recommendedFonts, otherFonts };\n }, [searchQuery, selectedCategory, fontsLoadedTrigger, fontsUsedInDocument]);\n\n // Render a font section - simple grid layout (all fonts same height, no masonry needed)\n const renderFontSection = (fonts: FontDefinition[], isUsedInDocument = false) => {\n if (viewMode === 'masonry') {\n // Flex wrap layout - simpler than true masonry since all items same height\n return (\n <div className=\"flex flex-wrap content-start items-start gap-2 px-4 pb-4\">\n {fonts.map((font) => (\n <FontItem key={font.name} font={font} isUsedInDocument={isUsedInDocument} />\n ))}\n </div>\n );\n } else {\n // Grid layout - optimized for uniform height items\n return (\n <div\n className=\"px-4 pb-4\"\n style={{\n display: 'grid',\n gridTemplateColumns: `repeat(auto-fill, minmax(${140 * cardSizeScale}px, 1fr))`,\n gap: '8px',\n }}\n >\n {fonts.map((font) => (\n <FontItem key={font.name} font={font} isUsedInDocument={isUsedInDocument} />\n ))}\n </div>\n );\n }\n };\n\n // Get unique categories in order\n const categories: Array<FontCategory | 'all'> = [\n 'all',\n 'system',\n 'display',\n 'sans-serif',\n 'script',\n 'serif',\n 'slab-serif',\n 'vintage',\n 'decorative',\n 'monospace',\n ];\n\n return (\n <>\n {/*\n Fixed at 3× the standard toolbar button width so the contextual\n toolbar's button grid stays aligned regardless of font name\n length. Long names (e.g. \"Permanent Marker\", \"Architects\n Daughter\") truncate with ellipsis. The full name is still\n visible in the drawer once opened, and the tooltip shows it.\n */}\n <button\n onClick={() => onToggle(!isOpen)}\n className={`h-11 md:h-9 w-[132px] md:w-[108px] flex items-center justify-center px-2 text-foreground cursor-pointer rounded-lg border border-transparent text-base font-medium transition-all hover:bg-black/5 dark:hover:bg-white/5 ${isOpen ? 'bg-black/10 dark:bg-white/10' : 'bg-transparent'}`}\n aria-label={isOpen ? 'Close font browser' : 'Open font browser'}\n title={value}\n >\n <span\n className=\"font-preview overflow-hidden text-ellipsis whitespace-nowrap min-w-0\"\n style={{ '--font-preview': `\"${value}\", sans-serif`, fontWeight: 400 } as React.CSSProperties}\n >\n {value}\n </span>\n </button>\n\n <Drawer\n isOpen={isOpen}\n onClose={() => onToggle(false)}\n title=\"Fonts\"\n description=\"\"\n height=\"85vh\"\n placement=\"bottom\"\n showCloseButton={false}\n hideVisibleTitle={true}\n hideHandle={true}\n disableScrollWrapper={true}\n >\n {/* IMPORTANT: Wrapper pattern to avoid backdrop-filter compositing bugs */}\n {/* Outer wrapper: defines border-radius + overflow clipping */}\n {/* Inner element: no border-radius, just backdrop-filter */}\n {/* See docs/BACKDROP_FILTER_GOTCHAS.md for details */}\n <div className=\"relative flex-1 overflow-hidden\">\n <div className=\"h-full bg-white\">\n {/* Inner scrollable container */}\n <div className=\"h-full overflow-y-auto\">\n {/* Search Input & Controls - Scrolls away */}\n <div className=\"px-4 pt-5\">\n <Surface className=\"flex gap-2\">\n <TextField className=\"flex-1\" aria-label=\"Search fonts\">\n <Input\n type=\"text\"\n className=\"rounded-2xl pt-[10px] pb-[9px]\"\n placeholder=\"Search fonts...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n autoFocus\n aria-label=\"Search fonts\"\n />\n </TextField>\n\n <Tabs\n value={cardSize}\n onValueChange={(value) => setCardSize(value as 'small' | 'medium' | 'large')}\n >\n <Tabs.ListContainer>\n <Tabs.List aria-label=\"Card size\">\n <Tabs.Tab id=\"small\" className=\"text-xs font-semibold\" aria-label=\"Small card size\">\n A\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab id=\"medium\" className=\"text-base font-semibold\" aria-label=\"Medium card size\">\n A\n <Tabs.Indicator />\n </Tabs.Tab>\n <Tabs.Tab id=\"large\" className=\"text-xl font-semibold\" aria-label=\"Large card size\">\n A\n <Tabs.Indicator />\n </Tabs.Tab>\n </Tabs.List>\n </Tabs.ListContainer>\n </Tabs>\n\n <Button\n variant=\"secondary\"\n onClick={() => {\n setDisplayMode((prev) => {\n if (prev === 'both') return 'name';\n if (prev === 'name') return 'preview';\n return 'both';\n });\n }}\n aria-label={\n displayMode === 'both'\n ? 'Show font name only'\n : displayMode === 'name'\n ? 'Show preview only'\n : 'Show preview with font name'\n }\n className=\"h-10 w-10 p-0\"\n >\n {displayMode === 'both' ? (\n <Icon icon=\"lucide:credit-card\" className=\"size-[22px]\" />\n ) : displayMode === 'name' ? (\n <Icon icon=\"lucide:type\" className=\"size-[22px]\" />\n ) : (\n <Icon icon=\"lucide:text-cursor\" className=\"size-[22px]\" />\n )}\n </Button>\n\n <Button\n variant=\"secondary\"\n onClick={() => setViewMode(viewMode === 'grid' ? 'masonry' : 'grid')}\n aria-label={viewMode === 'grid' ? 'Switch to masonry view' : 'Switch to grid view'}\n className=\"h-10 w-10 p-0\"\n >\n {viewMode === 'grid' ? (\n <Icon icon=\"lucide:grid-2x2\" className=\"size-[22px]\" />\n ) : (\n <Icon icon=\"lucide:grid-3x3\" className=\"size-[22px]\" />\n )}\n </Button>\n </Surface>\n </div>\n\n {/* Category Filters - Sticky at top with blur and gradient */}\n <div className=\"sticky top-0 z-20 shrink-0\">\n {/* Gradient overlay - sticky with pills */}\n <div\n className=\"pointer-events-none absolute top-0 right-0 left-0\"\n style={{\n height: '64px',\n background:\n 'linear-gradient(to bottom, var(--background) 0%, color-mix(in srgb, var(--background) 80%, transparent) 40%, transparent 100%)',\n zIndex: 16,\n }}\n />\n\n {/* Pills content */}\n <div className=\"relative z-20 px-4 py-4 pt-3\">\n <div className=\"flex gap-2 overflow-x-auto\">\n {categories.map((category) => {\n const label = category === 'all' ? 'All' : CATEGORY_LABELS[category as FontCategory];\n\n return (\n <Button\n key={category}\n size=\"sm\"\n variant={selectedCategory === category ? 'default' : 'secondary'}\n onClick={() => setSelectedCategory(category)}\n className={`shrink-0 ${selectedCategory === category ? '' : 'hover:brightness-95'}`}\n >\n {label}\n </Button>\n );\n })}\n </div>\n </div>\n </div>\n\n {/* Font List with Sections */}\n <div className=\"flex-1\">\n {/* Used in Document Section */}\n {fontSections.usedFonts.length > 0 && (\n <div className=\"shrink-0 p-0\">\n <div className=\"text-muted bg-white px-4 pt-2 pb-2 text-xs font-bold tracking-wider uppercase\">\n Used in Document\n </div>\n {renderFontSection(fontSections.usedFonts, true)}\n </div>\n )}\n\n {fontSections.recommendedFonts.length === 0 && fontSections.otherFonts.length === 0 ? (\n <div className=\"text-muted col-span-full px-4 py-8 text-center text-sm\">No fonts found</div>\n ) : (\n <>\n {/* Recommended Section */}\n {fontSections.recommendedFonts.length > 0 && (\n <div className=\"p-0\">\n <div className=\"text-muted bg-white px-4 pt-2 pb-2 text-xs font-bold tracking-wider uppercase\">\n Recommended\n </div>\n {renderFontSection(fontSections.recommendedFonts)}\n </div>\n )}\n\n {/* All Fonts Section */}\n {fontSections.otherFonts.length > 0 && (\n <div className=\"p-0\">\n <div className=\"text-muted bg-white px-4 pt-4 pb-2 text-xs font-bold tracking-wider uppercase\">\n All Fonts\n </div>\n {renderFontSection(fontSections.otherFonts)}\n </div>\n )}\n </>\n )}\n </div>\n </div>\n </div>\n </div>\n </Drawer>\n </>\n );\n};\n\nexport default FontBrowserDrawer;\n","/**\n * TransformControlPanel - Reusable component for transform-specific sliders\n * Eliminates duplication of slider control code across transforms\n *\n * Migrated to Shadcn/Radix:\n * - Switch\n * - Slider\n * - Label\n */\n\nimport React, { useState } from 'react';\nimport { TextElement } from '../core/TextElement';\nimport { ImageElement } from '../core/ImageElement';\nimport { ShapeElement } from '../core/ShapeElement';\nimport type { TransformControl } from '../types/index.js';\nimport { Switch, Slider, Label } from './ui';\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger('TransformControlPanel');\n\ninterface TransformControlPanelProps {\n element: TextElement | ImageElement | ShapeElement;\n controls: TransformControl[];\n onUpdate: (element: TextElement | ImageElement | ShapeElement) => void;\n}\n\nexport const TransformControlPanel: React.FC<TransformControlPanelProps> = ({ element, controls, onUpdate }) => {\n // Track which slider is being dragged to show preview value\n const [draggingValues, setDraggingValues] = useState<Record<string, number>>({});\n\n return (\n <div className=\"w-full space-y-4\">\n {controls.map((control) => {\n // Get the stored value (internal representation)\n const storedValue =\n (element.transformData as Record<string, unknown>)[control.key] ?? control.defaultInternalValue ?? control.defaultValue;\n\n // Handle checkbox controls\n if (control.type === 'checkbox') {\n return (\n <div key={control.key} className=\"flex items-center space-x-2\">\n <Switch\n id={`control-${control.key}`}\n checked={storedValue as boolean}\n onCheckedChange={(checked: boolean) => {\n const newElement = element.clone();\n (newElement.transformData as Record<string, unknown>)[control.key] = checked;\n onUpdate(newElement);\n }}\n />\n <Label htmlFor={`control-${control.key}`}>{control.label}</Label>\n </div>\n );\n }\n\n // Handle slider controls (default)\n // Safety check: ensure storedValue is a valid number\n const safeStoredValue = typeof storedValue === 'number' && !isNaN(storedValue)\n ? storedValue\n : (control.defaultInternalValue ?? 0);\n\n // Use preview value while dragging, otherwise use stored value\n const currentInternalValue = draggingValues[control.key] !== undefined\n ? draggingValues[control.key]\n : safeStoredValue;\n\n // Convert to slider position (0-100 scale for simplicity)\n const sliderValue = control.toSlider ? control.toSlider(currentInternalValue) : currentInternalValue;\n\n // Convert to display string\n const formatValue = (value: number): string => {\n // Note: value is the slider position, we need to convert back to stored value for display\n const internalValue = control.fromSlider ? control.fromSlider(value) : value;\n\n // Safety check: ensure internalValue is a number\n if (typeof internalValue !== 'number' || isNaN(internalValue)) {\n logger.warn('Invalid internalValue:', internalValue, 'for control:', control.key);\n return '0';\n }\n\n return control.toDisplay\n ? control.toDisplay(internalValue)\n : 'isPercentage' in control && control.isPercentage\n ? `${(internalValue * 100).toFixed(0)}%`\n : internalValue.toFixed(1);\n };\n\n return (\n <div key={control.key} className=\"flex flex-col gap-sm\">\n <div className=\"flex justify-between\">\n <Label>{control.label}</Label>\n <span className=\"text-sm text-foreground/60\">{formatValue(sliderValue)}</span>\n </div>\n <Slider\n value={[sliderValue]}\n onValueChange={(val) => {\n // Update preview value while dragging\n const newSliderValue = val[0];\n const newInternalValue = control.fromSlider\n ? control.fromSlider(newSliderValue)\n : newSliderValue;\n setDraggingValues(prev => ({ ...prev, [control.key]: newInternalValue }));\n }}\n onChangeEnd={(val) => {\n // Only update element when drag ends\n const newSliderValue = val[0];\n const newElement = element.clone();\n (newElement.transformData as Record<string, unknown>)[control.key] = control.fromSlider\n ? control.fromSlider(newSliderValue)\n : newSliderValue;\n onUpdate(newElement);\n // Clear preview value\n setDraggingValues(prev => {\n const updated = { ...prev };\n delete updated[control.key];\n return updated;\n });\n }}\n min={0}\n max={100}\n step={control.step ?? 1}\n className=\"slider-no-fill\"\n />\n </div>\n );\n })}\n </div>\n );\n};\n\nexport default TransformControlPanel;\n","/**\n * TextEffectsDropdown - Dropdown for selecting and configuring text transforms\n * Shows currently selected transform and configuration controls\n */\n\nimport React, { useState } from 'react';\nimport { Popover, PopoverTrigger, PopoverContent, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Label, icons } from './ui';\nimport { Icon } from '@iconify/react';\nimport { TRANSFORM_TYPES, getTransformControls } from '../transforms/registry.js';\nimport { TransformControlPanel } from './TransformControlPanel.js';\nimport type { TransformType } from '../types/index.js';\nimport type { TextElement } from '../core/TextElement.js';\nimport type { ImageElement } from '../core/ImageElement.js';\nimport type { ShapeElement } from '../core/ShapeElement.js';\n\nexport interface TextEffectsDropdownProps {\n element: TextElement;\n onTransformTypeChange: (newType: TransformType) => void;\n onElementUpdate: (updatedElement: TextElement | ImageElement | ShapeElement) => void;\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n}\n\nexport const TextEffectsDropdown: React.FC<TextEffectsDropdownProps> = ({\n element,\n onTransformTypeChange,\n onElementUpdate,\n isOpen: controlledIsOpen,\n onOpenChange: controlledOnOpenChange,\n}) => {\n const [internalIsOpen, setInternalIsOpen] = useState(false);\n\n // Use controlled state if provided, otherwise use internal state\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen;\n const setIsOpen = controlledOnOpenChange || setInternalIsOpen;\n\n const currentTransformType = element.transformType;\n const controls = getTransformControls(currentTransformType);\n\n // Filter to only text transform types (exclude image, group, shape, path)\n const textTransformTypes = TRANSFORM_TYPES.filter(\n (t) => t.Component && t.id !== 'image' && t.id !== 'group' && t.id !== 'shape' && t.id !== 'path'\n );\n\n const handleTransformChange = (newType: string) => {\n if (newType !== currentTransformType) {\n onTransformTypeChange(newType as TransformType);\n }\n };\n\n return (\n <Popover open={isOpen} onOpenChange={setIsOpen}>\n <PopoverTrigger asChild>\n <button className=\"toolbar-btn\" aria-label=\"Text Effects\">\n <Icon icon={icons.wand} className=\"size-6\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-[280px] p-0\" maxZIndex>\n <div className=\"space-y-4 p-6\">\n {/* Transform Type Select */}\n <div className=\"space-y-2\">\n <Label>Text Effect</Label>\n <Select value={currentTransformType} onValueChange={handleTransformChange}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select effect\" />\n </SelectTrigger>\n <SelectContent style={{ zIndex: 2147483647 }}>\n {textTransformTypes.map((transform) => (\n <SelectItem key={transform.id} value={transform.id}>\n {transform.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n\n {/* Transform Configuration Controls */}\n {controls.length > 0 && (\n <TransformControlPanel element={element} controls={controls} onUpdate={onElementUpdate} />\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\nexport default TextEffectsDropdown;\n","/**\n * MoreMenu - Overflow menu for toolbar items\n * Shows a \"...\" menu with items that don't fit or are always hidden\n */\n\nimport { useState } from 'react';\nimport { Button, Popover, PopoverTrigger, PopoverContent, Tooltip, TooltipTrigger, TooltipContent, icons } from './ui';\nimport { Icon } from '@iconify/react';\n\ninterface MoreMenuItem {\n label: string;\n icon: React.ReactNode;\n onClick: () => void;\n active?: boolean;\n}\n\ninterface MoreMenuProps {\n items: MoreMenuItem[];\n}\n\nconst MoreMenu = ({ items }: MoreMenuProps) => {\n const [showMenu, setShowMenu] = useState(false);\n\n return (\n <Popover open={showMenu} onOpenChange={setShowMenu}>\n <PopoverTrigger asChild>\n <button className=\"toolbar-btn\" aria-label=\"More options\">\n <Icon icon={icons.moreHorizontal} className=\"size-6\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-auto p-1\" maxZIndex>\n <div className=\"flex items-center gap-1\">\n {items.map((item, index) => (\n <Tooltip key={index} delay={300}>\n <TooltipTrigger asChild>\n <Button\n variant={item.active ? 'default' : 'ghost'}\n size=\"icon\"\n onClick={() => {\n item.onClick();\n setShowMenu(false);\n }}\n aria-label={item.label}\n >\n {item.icon}\n </Button>\n </TooltipTrigger>\n <TooltipContent>{item.label}</TooltipContent>\n </Tooltip>\n ))}\n </div>\n </PopoverContent>\n </Popover>\n );\n};\n\nexport default MoreMenu;\n","import { Tooltip, TooltipTrigger, TooltipContent } from '../ui';\n\nexport interface FontColorButtonProps {\n colorPickerValue: string;\n isActive: boolean;\n onClick: () => void;\n}\n\nexport function FontColorButton({ colorPickerValue, isActive, onClick }: FontColorButtonProps) {\n return (\n <Tooltip delay={300}>\n <TooltipTrigger asChild>\n <button\n className=\"toolbar-btn\"\n onClick={onClick}\n aria-label=\"Font Color\"\n data-active={isActive}\n >\n <div className=\"relative flex h-5 w-5 items-center justify-center\">\n <span className=\"-translate-y-0.5 text-lg leading-none font-bold\">A</span>\n <div\n className=\"absolute bottom-0 left-1/2 h-[3px] w-4 -translate-x-1/2 rounded-sm\"\n style={{ backgroundColor: colorPickerValue }}\n />\n </div>\n </button>\n </TooltipTrigger>\n {!isActive && <TooltipContent>Font Color</TooltipContent>}\n </Tooltip>\n );\n}\n","import { ToolbarButton, icons } from '../ui';\nimport type { UseTextToolbarReturn } from '../../hooks/useTextToolbar.js';\n\nexport interface BoldButtonProps {\n toolbar: UseTextToolbarReturn;\n}\n\nexport function BoldButton({ toolbar }: BoldButtonProps) {\n return (\n <ToolbarButton\n icon={icons.bold}\n onClick={toolbar.handleBoldToggle}\n active={toolbar.getEffectiveStyle().bold}\n tooltip=\"Bold\"\n />\n );\n}\n","import { ToolbarButton, icons } from '../ui';\nimport type { UseTextToolbarReturn } from '../../hooks/useTextToolbar.js';\n\nexport interface ItalicButtonProps {\n toolbar: UseTextToolbarReturn;\n}\n\nexport function ItalicButton({ toolbar }: ItalicButtonProps) {\n return (\n <ToolbarButton\n icon={icons.italic}\n onClick={toolbar.handleItalicToggle}\n active={toolbar.getEffectiveStyle().italic}\n tooltip=\"Italic\"\n />\n );\n}\n","import { ToolbarButton, icons } from '../ui';\nimport type { UseTextToolbarReturn } from '../../hooks/useTextToolbar.js';\n\nexport interface UnderlineButtonProps {\n toolbar: UseTextToolbarReturn;\n}\n\nexport function UnderlineButton({ toolbar }: UnderlineButtonProps) {\n return (\n <ToolbarButton\n icon={icons.underline}\n onClick={toolbar.handleUnderlineToggle}\n active={toolbar.getEffectiveStyle().underline}\n tooltip=\"Underline\"\n />\n );\n}\n","import { ToolbarButton } from '../ui';\nimport type { UseTextToolbarReturn } from '../../hooks/useTextToolbar.js';\n\nexport interface UppercaseButtonProps {\n toolbar: UseTextToolbarReturn;\n}\n\nexport function UppercaseButton({ toolbar }: UppercaseButtonProps) {\n return (\n <ToolbarButton\n icon=\"lucide:case-upper\"\n onClick={toolbar.handleLetterCaseToggle}\n active={toolbar.isLetterCaseActive()}\n tooltip=\"Uppercase\"\n />\n );\n}\n","import { ToolbarButton, icons } from '../ui';\nimport type { UseTextToolbarReturn } from '../../hooks/useTextToolbar.js';\n\nexport interface TextAlignButtonProps {\n toolbar: UseTextToolbarReturn;\n}\n\nexport function TextAlignButton({ toolbar }: TextAlignButtonProps) {\n const { textAlign, handleTextAlignToggle } = toolbar;\n const icon =\n textAlign === 'left' ? icons.alignLeft : textAlign === 'center' ? icons.alignCenter : icons.alignRight;\n\n return (\n <ToolbarButton\n icon={icon}\n onClick={handleTextAlignToggle}\n tooltip={`Align ${textAlign.charAt(0).toUpperCase() + textAlign.slice(1)}`}\n />\n );\n}\n","import { useState } from 'react';\nimport { Icon } from '@iconify/react';\nimport {\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n Button,\n Popover,\n PopoverTrigger,\n PopoverContent,\n icons,\n} from '../ui';\n\nexport interface TextMoreMenuProps {\n onMoveForward: () => void;\n onMoveBackward: () => void;\n onDelete: () => void;\n onOpenChange?: (open: boolean) => void;\n}\n\nexport function TextMoreMenu({ onMoveForward, onMoveBackward, onDelete, onOpenChange }: TextMoreMenuProps) {\n const [isOpen, setIsOpen] = useState(false);\n\n const handleOpenChange = (open: boolean) => {\n setIsOpen(open);\n onOpenChange?.(open);\n };\n\n return (\n <Popover open={isOpen} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <button className=\"toolbar-btn\" aria-label=\"More options\">\n <Icon icon=\"lucide:ellipsis-vertical\" className=\"size-6\" />\n </button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-auto p-1\" maxZIndex>\n <div className=\"flex items-center gap-1\">\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n onMoveForward();\n handleOpenChange(false);\n }}\n aria-label=\"Move Forward\"\n >\n <Icon icon=\"hugeicons:layer-bring-forward\" className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Forward</TooltipContent>\n </Tooltip>\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n onMoveBackward();\n handleOpenChange(false);\n }}\n aria-label=\"Move Backward\"\n >\n <Icon icon=\"hugeicons:layer-send-backward\" className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Move Backward</TooltipContent>\n </Tooltip>\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n handleOpenChange(false);\n onDelete();\n }}\n aria-label=\"Delete\"\n >\n <Icon icon={icons.trash} className=\"size-5\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","/**\n * TextToolbar - Composed text formatting toolbar using primitives.\n *\n * Replaces the inline text toolbar JSX from ContextualToolbars.\n * Accepts a `toolbar` prop (from useTextToolbar) so the parent can\n * share the same state with other panels (e.g. text color picker).\n *\n * For standalone usage, call useTextToolbar() in your component and\n * pass the result as the `toolbar` prop.\n */\n\nimport React, { useState } from 'react';\nimport FontBrowserDrawer from './FontBrowserDrawer.jsx';\nimport TextEffectsDropdown from './TextEffectsDropdown.jsx';\nimport MoreMenu from './MoreMenu.jsx';\nimport { FontColorButton } from './text-toolbar/FontColorButton.js';\nimport { BoldButton } from './text-toolbar/BoldButton.js';\nimport { ItalicButton } from './text-toolbar/ItalicButton.js';\nimport { UnderlineButton } from './text-toolbar/UnderlineButton.js';\nimport { UppercaseButton } from './text-toolbar/UppercaseButton.js';\nimport { TextAlignButton } from './text-toolbar/TextAlignButton.js';\nimport { TextMoreMenu } from './text-toolbar/TextMoreMenu.js';\nimport { ToolbarButton, RotateLeftIcon } from './ui';\nimport { FONT_FAMILIES } from '../constants.js';\nimport { getFeatureApplied } from '../utils/featureApplied.js';\nimport type { UseTextToolbarReturn } from '../hooks/useTextToolbar.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\nimport type { TextElement } from '../core/TextElement.js';\n\nexport interface TextToolbarProps {\n toolbar: UseTextToolbarReturn;\n stableElementId?: string;\n viewportWidth?: number;\n colorPickerValue: string;\n isColorActive: boolean;\n onColorToggle: () => void;\n onOpenGlyphBrowser?: () => void;\n hasGlyphs?: boolean;\n expandedPanel: { type: string } | null;\n onRotationToggle: () => void;\n onOpacityToggle: () => void;\n onFontSizeToggle: () => void;\n getMoreMenuItems?: () => Array<{ label: string; onClick: () => void; icon: React.ReactNode; active?: boolean }>;\n strokeExpanded?: boolean;\n onStrokeToggle?: () => void;\n knockoutExpanded?: boolean;\n onKnockoutToggle?: () => void;\n distressTextureExpanded?: boolean;\n onDistressTextureToggle?: () => void;\n imageMaskExpanded?: boolean;\n onImageMaskToggle?: () => void;\n onMoveForward: () => void;\n onMoveBackward: () => void;\n onDelete: () => void;\n elementForProperties: EditorElement;\n elements: EditorElement[];\n isTransformMenuOpen: boolean;\n onTransformMenuOpenChange: (open: boolean) => void;\n elementUpdateHandler: (updatedElement: EditorElement) => void;\n showUngroupButton?: boolean;\n onUngroup?: () => void;\n isFontBrowserOpen?: boolean;\n onFontBrowserToggle: (isOpen: boolean) => void;\n onTextMoreMenuOpenChange?: (open: boolean) => void;\n}\n\nexport function TextToolbar({\n toolbar,\n stableElementId,\n viewportWidth = window.innerWidth,\n colorPickerValue,\n isColorActive,\n onColorToggle,\n onOpenGlyphBrowser,\n hasGlyphs = false,\n expandedPanel,\n onRotationToggle,\n onOpacityToggle,\n onFontSizeToggle,\n strokeExpanded = false,\n onStrokeToggle,\n knockoutExpanded = false,\n onKnockoutToggle,\n distressTextureExpanded = false,\n onDistressTextureToggle,\n imageMaskExpanded = false,\n onImageMaskToggle,\n getMoreMenuItems,\n onMoveForward,\n onMoveBackward,\n onDelete,\n elementForProperties,\n elements,\n isTransformMenuOpen,\n onTransformMenuOpenChange,\n elementUpdateHandler,\n showUngroupButton = false,\n onUngroup,\n isFontBrowserOpen = false,\n onFontBrowserToggle,\n onTextMoreMenuOpenChange,\n}: TextToolbarProps) {\n // Tooltip disabled states (prevent flicker after click)\n const [strokeTooltipDisabled, setStrokeTooltipDisabled] = useState(false);\n const [glyphTooltipDisabled, setGlyphTooltipDisabled] = useState(false);\n const [rotationTooltipDisabled, setRotationTooltipDisabled] = useState(false);\n const [fontSizeTooltipDisabled, setFontSizeTooltipDisabled] = useState(false);\n\n // Feature-applied flags — drive the \"selected\" highlight on the\n // toolbar buttons whose underlying property has been set to a\n // non-default value.\n const applied = getFeatureApplied(elementForProperties);\n const [opacityTooltipDisabled, setOpacityTooltipDisabled] = useState(false);\n const [knockoutTooltipDisabled, setKnockoutTooltipDisabled] = useState(false);\n const [distressTooltipDisabled, setDistressTooltipDisabled] = useState(false);\n const [imageMaskTooltipDisabled, setImageMaskTooltipDisabled] = useState(false);\n\n return (\n <div key={`text-toolbar-${stableElementId}`} className=\"toolbar-items\">\n {/* Font Browser Drawer */}\n <FontBrowserDrawer\n value={toolbar.getEffectiveStyle().fontFamily || toolbar.fontFamily}\n onChange={(e: { target: { value: string } }) => toolbar.handleFontFamilyChange(e.target.value)}\n fontFamilies={FONT_FAMILIES}\n isOpen={isFontBrowserOpen}\n onToggle={onFontBrowserToggle}\n showLabel={viewportWidth > 700}\n previewText={'text' in elementForProperties ? (elementForProperties as { text: string }).text : undefined}\n elements={elements as unknown as Array<Record<string, unknown>>}\n />\n\n {/* Font Size — toolbar button using the standard \"Aa\" font-size\n icon. Tapping opens the secondary panel (slider + number\n input). Earlier this button rendered the current size as\n its label — but at 3 digits (\"148\") that broke the toolbar's\n uniform button-width grid. The current size still shows in\n the tooltip and inside the panel; the icon keeps the\n toolbar visually aligned with the rest of its buttons. */}\n <ToolbarButton\n icon=\"lucide:a-large-small\"\n onClick={() => {\n setFontSizeTooltipDisabled(true);\n onFontSizeToggle();\n }}\n onMouseLeave={() => setFontSizeTooltipDisabled(false)}\n tooltip={`Font Size · ${Math.round(toolbar.fontSize)}`}\n tooltipDisabled={fontSizeTooltipDisabled || expandedPanel?.type === 'fontSize'}\n active={expandedPanel?.type === 'fontSize'}\n />\n\n {/* Font Color */}\n <FontColorButton\n colorPickerValue={colorPickerValue}\n isActive={isColorActive}\n onClick={onColorToggle}\n />\n\n {/* Text formatting buttons */}\n <BoldButton toolbar={toolbar} />\n <ItalicButton toolbar={toolbar} />\n <UnderlineButton toolbar={toolbar} />\n <UppercaseButton toolbar={toolbar} />\n\n {/* Text Alignment */}\n <TextAlignButton toolbar={toolbar} />\n\n {/* Text Effects Dropdown */}\n <TextEffectsDropdown\n element={elementForProperties as TextElement}\n onTransformTypeChange={toolbar.handleTransformTypeChange}\n onElementUpdate={elementUpdateHandler}\n isOpen={isTransformMenuOpen}\n onOpenChange={onTransformMenuOpenChange}\n />\n\n {/* Stroke */}\n {onStrokeToggle && (\n <ToolbarButton\n icon=\"lucide:pen-line\"\n onClick={() => {\n setStrokeTooltipDisabled(true);\n onStrokeToggle();\n }}\n onMouseLeave={() => setStrokeTooltipDisabled(false)}\n tooltip=\"Stroke\"\n tooltipDisabled={strokeTooltipDisabled || strokeExpanded}\n active={strokeExpanded || applied.stroke}\n />\n )}\n\n {/* Rotation */}\n <ToolbarButton\n icon={<RotateLeftIcon size={20} className=\"md:size-5\" />}\n onClick={() => {\n setRotationTooltipDisabled(true);\n onRotationToggle();\n }}\n onMouseLeave={() => setRotationTooltipDisabled(false)}\n tooltip=\"Rotate\"\n tooltipDisabled={rotationTooltipDisabled || expandedPanel?.type === 'rotation'}\n active={expandedPanel?.type === 'rotation' || applied.rotation}\n />\n\n {/* Transparency */}\n <ToolbarButton\n icon=\"lucide:blend\"\n onClick={() => {\n setOpacityTooltipDisabled(true);\n onOpacityToggle();\n }}\n onMouseLeave={() => setOpacityTooltipDisabled(false)}\n tooltip=\"Transparency\"\n tooltipDisabled={opacityTooltipDisabled || expandedPanel?.type === 'opacity'}\n active={expandedPanel?.type === 'opacity' || applied.opacity}\n />\n\n {/* Knockout */}\n {onKnockoutToggle && (\n <ToolbarButton\n icon=\"lucide:scissors\"\n onClick={() => {\n setKnockoutTooltipDisabled(true);\n onKnockoutToggle();\n }}\n onMouseLeave={() => setKnockoutTooltipDisabled(false)}\n tooltip=\"Clip / Knockout\"\n tooltipDisabled={knockoutTooltipDisabled || knockoutExpanded}\n active={knockoutExpanded || applied.knockout}\n />\n )}\n\n {/* Distress Texture */}\n {onDistressTextureToggle && (\n <ToolbarButton\n icon=\"lucide:stamp\"\n onClick={() => {\n setDistressTooltipDisabled(true);\n onDistressTextureToggle();\n }}\n onMouseLeave={() => setDistressTooltipDisabled(false)}\n tooltip=\"Distress Texture\"\n tooltipDisabled={distressTooltipDisabled || distressTextureExpanded}\n active={distressTextureExpanded || applied.distress}\n />\n )}\n\n {/* Image Mask */}\n {onImageMaskToggle && (\n <ToolbarButton\n icon=\"lucide:venetian-mask\"\n onClick={() => {\n setImageMaskTooltipDisabled(true);\n onImageMaskToggle();\n }}\n onMouseLeave={() => setImageMaskTooltipDisabled(false)}\n tooltip=\"Image Mask\"\n tooltipDisabled={imageMaskTooltipDisabled || imageMaskExpanded}\n active={imageMaskExpanded || applied.imageMask}\n />\n )}\n\n {/* Glyph Browser */}\n <ToolbarButton\n icon=\"lucide:flag\"\n onClick={() => {\n setGlyphTooltipDisabled(true);\n onOpenGlyphBrowser?.();\n }}\n onMouseLeave={() => setGlyphTooltipDisabled(false)}\n tooltip={hasGlyphs ? 'Browse All Glyphs' : 'No alternate glyphs available'}\n tooltipDisabled={glyphTooltipDisabled}\n disabled={!hasGlyphs}\n className={!hasGlyphs ? 'opacity-50' : ''}\n />\n\n {/* More Menu - custom items passed via prop */}\n {getMoreMenuItems && <MoreMenu items={getMoreMenuItems()} />}\n\n {/* More Menu - layer order and delete */}\n <TextMoreMenu\n onMoveForward={onMoveForward}\n onMoveBackward={onMoveBackward}\n onDelete={onDelete}\n onOpenChange={onTextMoreMenuOpenChange}\n />\n\n {/* Ungroup button - shown when editing a child in a group */}\n {showUngroupButton && (\n <button className=\"toolbar-btn\" onClick={onUngroup}>\n Ungroup\n </button>\n )}\n </div>\n );\n}\n","/**\n * TransformConverter - Utility for converting between transform types\n * Handles position and dimension adjustments when switching transforms\n */\n\nimport { WAVE_DEFAULTS, FLAG_DEFAULTS, ARCH_DEFAULTS, LEAN_DEFAULTS } from '../transforms/defaults.js';\nimport type { TextElement } from './TextElement.js';\nimport type { TransformType, Point } from '../types/index.js';\n\n/** Configuration result for a transform conversion */\ninterface TransformConfig {\n x: number;\n y: number;\n fontSize: number;\n transformData: Record<string, unknown>;\n}\n\n/**\n * Convert an element from one transform type to another\n * Maintains visual size and position during conversion\n *\n * @param sourceElement - Element to convert from\n * @param targetType - Target transform type id\n * @param TargetClass - Target transform class constructor\n * @returns New element with target transform type\n */\nexport function convertTransform(\n sourceElement: TextElement,\n targetType: TransformType,\n TargetClass: new (config: Record<string, unknown>) => TextElement\n): TextElement {\n // Get the current element's rotation anchor as the consistent reference point\n const rotationAnchor = sourceElement.getRotationAnchor();\n\n // Get the current effective fontSize to maintain visual size\n let currentEffectiveFontSize: number;\n if (sourceElement.transformType === 'circle' && 'getEffectiveFontSize' in sourceElement) {\n // Circle mode uses scale, so get effective font size\n currentEffectiveFontSize = (sourceElement as unknown as { getEffectiveFontSize: () => number }).getEffectiveFontSize();\n } else {\n currentEffectiveFontSize = sourceElement.fontSize;\n }\n\n // Calculate appropriate transformData based on target type\n const config = calculateTransformConfig(sourceElement, targetType, currentEffectiveFontSize, rotationAnchor);\n\n // Create new element with converted properties\n return new TargetClass({\n id: sourceElement.id,\n text: sourceElement.text,\n x: config.x,\n y: config.y,\n rotation: sourceElement.rotation,\n fontSize: config.fontSize,\n fontFamily: sourceElement.fontFamily,\n color: sourceElement.color,\n textAlign: sourceElement.textAlign,\n transformData: config.transformData,\n });\n}\n\n/**\n * Calculate configuration for target transform type\n * @private\n */\nfunction calculateTransformConfig(\n sourceElement: TextElement,\n targetType: TransformType,\n effectiveFontSize: number,\n rotationAnchor: Point\n): TransformConfig {\n let transformData: Record<string, unknown>;\n let x: number, y: number;\n const fontSize = effectiveFontSize;\n\n switch (targetType) {\n case 'circle':\n // For circle, maintain the visual size by calculating radius from current dimensions\n // Use the height as the primary dimension since it's consistent across transforms\n const textHeight = effectiveFontSize * 1.2;\n // Use text height as basis for circle radius\n const radius = textHeight * 2; // Reasonable default circle size\n transformData = { radius, scale: 1 };\n // Circle's (x, y) is its center, which matches rotation anchor\n x = rotationAnchor.x;\n y = rotationAnchor.y;\n break;\n\n case 'custom':\n // For custom, preserve the fontSize and calculate appropriate width\n // Measure the actual text to determine minimum required width\n const minWidth = 200;\n const estimatedTextWidth = effectiveFontSize * sourceElement.text.length * 0.6;\n const targetWidth = Math.max(estimatedTextWidth, minWidth);\n\n transformData = { width: targetWidth };\n // CustomTransform's (x, y) is top-left, but rotation anchor is center\n // So we need to calculate top-left from the center\n const targetHeight = effectiveFontSize * 1.2;\n x = rotationAnchor.x - targetWidth / 2;\n y = rotationAnchor.y - targetHeight / 2;\n break;\n\n case 'arch':\n // For arch, use reasonable width based on text size\n const archMinWidth = 200;\n const archEstimatedWidth = effectiveFontSize * sourceElement.text.length * 0.6;\n transformData = {\n width: Math.max(archEstimatedWidth, archMinWidth),\n archHeight: ARCH_DEFAULTS.archHeight,\n };\n // Arch's (x, y) is center, which matches rotation anchor\n x = rotationAnchor.x;\n y = rotationAnchor.y;\n break;\n\n case 'wave':\n // Wave transform config\n const waveMinWidth = 200;\n const waveEstimatedWidth = effectiveFontSize * sourceElement.text.length * 0.6;\n transformData = {\n width: Math.max(waveEstimatedWidth, waveMinWidth),\n amplitude: WAVE_DEFAULTS.amplitude,\n frequency: WAVE_DEFAULTS.frequency,\n };\n x = rotationAnchor.x;\n y = rotationAnchor.y;\n break;\n\n case 'flag':\n // Flag transform config\n const flagMinWidth = 200;\n const flagEstimatedWidth = effectiveFontSize * sourceElement.text.length * 0.6;\n transformData = {\n width: Math.max(flagEstimatedWidth, flagMinWidth),\n amplitude: FLAG_DEFAULTS.amplitude,\n frequency: FLAG_DEFAULTS.frequency,\n };\n x = rotationAnchor.x;\n y = rotationAnchor.y;\n break;\n\n case 'lean':\n // Lean transform config\n const leanMinWidth = 200;\n const leanEstimatedWidth = effectiveFontSize * sourceElement.text.length * 0.6;\n transformData = {\n width: Math.max(leanEstimatedWidth, leanMinWidth),\n leanAmount: LEAN_DEFAULTS.leanAmount,\n };\n x = rotationAnchor.x;\n y = rotationAnchor.y;\n break;\n\n default:\n // Fallback for unknown transform types\n transformData = { width: 200 };\n x = rotationAnchor.x;\n y = rotationAnchor.y;\n }\n\n return { x, y, fontSize, transformData };\n}\n\nexport default { convertTransform };\n","/**\n * useTextToolbar - Hook for text element formatting state and handlers.\n *\n * Extracts all text-specific toolbar logic (font size, color, family,\n * bold/italic/underline, letter case, text align, transform type) from\n * ContextualToolbars so it can be reused in composed toolbar layouts.\n *\n * Uses `useEditor()` internally — no need to pass element/elements as props.\n * The only external dependency is `canvasEditorRef` for character-level formatting.\n */\n\nimport { useState, useCallback, useEffect, useRef } from 'react';\nimport { useEditor } from '../contexts/EditorContext.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\nimport { TextElement } from '../core/TextElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { getTransformById } from '../transforms/registry.js';\nimport { convertTransform } from '../core/TransformConverter.js';\nimport type { TransformType, TextAlign, CharacterStyle } from '../types/index.js';\nimport type { CanvasEditorHandle } from '../components/CanvasEditor.js';\nimport type { CircleTransform } from '../transforms/CircleTransform.js';\n\nexport interface UseTextToolbarOptions {\n canvasEditorRef?: React.RefObject<CanvasEditorHandle | null>;\n}\n\nexport interface UseTextToolbarReturn {\n // State\n fontSize: number;\n fontColor: string;\n fontFamily: string;\n textAlign: TextAlign;\n bold: boolean;\n italic: boolean;\n underline: boolean;\n letterCase: string;\n\n // Handlers\n handleFontSizeChange: (size: number) => void;\n handleFontSizeIncrement: (delta: number) => void;\n handleFontFamilyChange: (family: string) => void;\n handleFontColorChange: (e: React.ChangeEvent<HTMLInputElement>) => void;\n handleBoldToggle: () => void;\n handleItalicToggle: () => void;\n handleUnderlineToggle: () => void;\n handleLetterCaseToggle: () => void;\n isLetterCaseActive: () => boolean;\n handleTextAlignToggle: () => void;\n\n // Rich text support\n getEffectiveStyle: () => CharacterStyle;\n\n // Transform type\n handleTransformTypeChange: (type: TransformType) => void;\n}\n\n/**\n * Hook for text element formatting state and handlers.\n *\n * Extracts all text-specific toolbar logic (font size, color, family,\n * bold/italic/underline, letter case, text align, transform type) so it\n * can be reused across different toolbar layouts.\n *\n * Uses `useEditor()` internally. Pass a `canvasEditorRef` to enable\n * character-level rich text formatting during text editing mode.\n *\n * @param options - Configuration options\n * @returns Text toolbar state and handler functions\n *\n * @example\n * ```tsx\n * function MyTextToolbar() {\n * const toolbar = useTextToolbar({ canvasEditorRef });\n *\n * return (\n * <div>\n * <button onClick={toolbar.handleBoldToggle}>\n * Bold: {toolbar.bold ? 'ON' : 'OFF'}\n * </button>\n * <input\n * type=\"number\"\n * value={toolbar.fontSize}\n * onChange={(e) => toolbar.handleFontSizeChange(Number(e.target.value))}\n * />\n * </div>\n * );\n * }\n * ```\n */\nexport function useTextToolbar(options: UseTextToolbarOptions = {}): UseTextToolbarReturn {\n const { canvasEditorRef } = options;\n\n const {\n selectedElement,\n activeChildElement,\n handleElementUpdate,\n } = useEditor();\n\n // Determine which element to show properties for\n const elementForProperties = activeChildElement || selectedElement;\n\n // Element update handler (handles group children)\n const elementUpdateHandler = useCallback(\n (updatedElement: EditorElement) => {\n if (!selectedElement) return;\n\n if (activeChildElement) {\n // Update child within group\n if (!(selectedElement instanceof GroupElement)) return;\n const updatedGroup = selectedElement.clone();\n const childIndex = updatedGroup.children.findIndex((c) => c.id === activeChildElement.id);\n if (childIndex !== -1) {\n updatedGroup.children[childIndex] = updatedElement as typeof updatedGroup.children[number];\n handleElementUpdate(updatedGroup);\n }\n } else {\n handleElementUpdate(updatedElement);\n }\n },\n [selectedElement, activeChildElement, handleElementUpdate]\n );\n\n // Track element ID to detect real selection changes\n const currentElementId = elementForProperties?.id;\n const prevElementIdRef = useRef<string | undefined>(undefined);\n\n // Local state for toolbar\n const [localFontSize, setLocalFontSize] = useState<number>(32);\n const [localFontColor, setLocalFontColor] = useState<string>('#333333');\n const [localFontFamily, setLocalFontFamily] = useState<string>('Arial');\n const [localTextAlign, setLocalTextAlign] = useState<TextAlign>('center');\n\n // Sync local state ONLY when element ID changes (selection change)\n useEffect(() => {\n if (currentElementId !== prevElementIdRef.current) {\n prevElementIdRef.current = currentElementId;\n\n if (elementForProperties && elementForProperties instanceof TextElement) {\n if (elementForProperties.transformType === 'circle' && 'getEffectiveFontSize' in elementForProperties) {\n setLocalFontSize(Math.round((elementForProperties as CircleTransform).getEffectiveFontSize()));\n } else if (elementForProperties.fontSize !== undefined) {\n setLocalFontSize(Math.round(elementForProperties.fontSize));\n }\n if (elementForProperties.color !== undefined) {\n setLocalFontColor(elementForProperties.color);\n }\n if (elementForProperties.fontFamily !== undefined) {\n setLocalFontFamily(elementForProperties.fontFamily);\n }\n setLocalTextAlign(elementForProperties.textAlign || 'center');\n }\n }\n }, [currentElementId, elementForProperties]);\n\n // Derived display values\n const fontSize = localFontSize;\n const fontColor = localFontColor;\n const fontFamily = localFontFamily;\n const textAlign = localTextAlign;\n\n // Element-level text style properties\n const textElement = elementForProperties instanceof TextElement ? elementForProperties : null;\n const bold = textElement?.bold ?? false;\n const italic = textElement?.italic ?? false;\n const underline = textElement?.underline ?? false;\n // letterCase is not declared in TextElement's type but is stored as a dynamic property at runtime\n const letterCase = (textElement as Record<string, unknown> | null)?.letterCase as string ?? 'none';\n\n // Commit handlers\n const setFontSizeValue = useCallback(\n (newSize: number) => {\n setLocalFontSize(newSize);\n if (!elementForProperties || !(elementForProperties instanceof TextElement)) return;\n\n const updatedElement = elementForProperties.clone();\n if (updatedElement.transformType === 'circle' && 'setEffectiveFontSize' in updatedElement) {\n (updatedElement as CircleTransform).setEffectiveFontSize(newSize);\n } else {\n updatedElement.setFontSize(newSize);\n }\n\n if (updatedElement.richText) {\n updatedElement.richText.clearStyleProperty('fontSize');\n }\n\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const updateFontFamily = useCallback(\n (newFamily: string) => {\n setLocalFontFamily(newFamily);\n if (!elementForProperties || !(elementForProperties instanceof TextElement)) return;\n\n const updatedElement = elementForProperties.clone();\n updatedElement.fontFamily = newFamily;\n\n if (updatedElement.richText) {\n updatedElement.richText.clearStyleProperty('fontFamily');\n }\n\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const updateFontColor = useCallback(\n (newColor: string) => {\n setLocalFontColor(newColor);\n if (!elementForProperties || !(elementForProperties instanceof TextElement)) return;\n\n const updatedElement = elementForProperties.clone();\n updatedElement.color = newColor;\n if (updatedElement.richText) {\n updatedElement.richText.clearStyleProperty('color');\n }\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const updateTextAlign = useCallback(\n (alignment: TextAlign) => {\n setLocalTextAlign(alignment);\n if (!elementForProperties || !(elementForProperties instanceof TextElement)) return;\n\n const updatedElement = elementForProperties.clone();\n updatedElement.textAlign = alignment;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // Character-level aware handlers\n const handleFontSizeChange = useCallback(\n (newSize: number) => {\n if (canvasEditorRef?.current?.isEditingText()) {\n canvasEditorRef.current.applyTextFormatting({ fontSize: newSize });\n } else {\n setFontSizeValue(newSize);\n }\n },\n [setFontSizeValue, canvasEditorRef]\n );\n\n const handleFontSizeIncrement = useCallback(\n (delta: number) => {\n const newSize = fontSize + delta;\n if (newSize >= 8 && newSize <= 500) {\n handleFontSizeChange(newSize);\n }\n },\n [fontSize, handleFontSizeChange]\n );\n\n const handleFontFamilyChange = useCallback(\n (newFamily: string) => {\n if (canvasEditorRef?.current?.isEditingText()) {\n canvasEditorRef.current.applyTextFormatting({ fontFamily: newFamily });\n } else {\n updateFontFamily(newFamily);\n }\n },\n [updateFontFamily, canvasEditorRef]\n );\n\n const handleFontColorChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newColor = e.target.value;\n const isEditing = canvasEditorRef?.current?.isEditingText();\n if (isEditing && canvasEditorRef?.current) {\n canvasEditorRef.current.applyTextFormatting({ color: newColor });\n } else {\n updateFontColor(newColor);\n }\n },\n [updateFontColor, canvasEditorRef]\n );\n\n const handleBoldToggle = useCallback(() => {\n if (canvasEditorRef?.current?.isEditingText()) {\n canvasEditorRef.current.toggleFormattingProperty('bold');\n } else {\n if (!elementForProperties || !(elementForProperties instanceof TextElement)) return;\n const updated = elementForProperties.clone();\n updated.bold = !bold;\n if (updated.richText) {\n updated.richText.clearStyleProperty('bold');\n }\n elementUpdateHandler(updated);\n }\n }, [bold, elementForProperties, elementUpdateHandler, canvasEditorRef]);\n\n const handleItalicToggle = useCallback(() => {\n if (canvasEditorRef?.current?.isEditingText()) {\n canvasEditorRef.current.toggleFormattingProperty('italic');\n } else {\n if (!elementForProperties || !(elementForProperties instanceof TextElement)) return;\n const updated = elementForProperties.clone();\n updated.italic = !italic;\n if (updated.richText) {\n updated.richText.clearStyleProperty('italic');\n }\n elementUpdateHandler(updated);\n }\n }, [italic, elementForProperties, elementUpdateHandler, canvasEditorRef]);\n\n const handleUnderlineToggle = useCallback(() => {\n if (canvasEditorRef?.current?.isEditingText()) {\n canvasEditorRef.current.toggleFormattingProperty('underline');\n } else {\n if (!elementForProperties || !(elementForProperties instanceof TextElement)) return;\n const updated = elementForProperties.clone();\n updated.underline = !underline;\n if (updated.richText) {\n updated.richText.clearStyleProperty('underline');\n }\n elementUpdateHandler(updated);\n }\n }, [underline, elementForProperties, elementUpdateHandler, canvasEditorRef]);\n\n const handleLetterCaseToggle = useCallback(() => {\n if (!elementForProperties) return;\n const newCase = letterCase === 'uppercase' ? 'none' : 'uppercase';\n const updated = elementForProperties.clone();\n // letterCase is not declared in TextElement's type but is stored as a dynamic property at runtime\n (updated as unknown as Record<string, unknown>).letterCase = newCase;\n elementUpdateHandler(updated);\n }, [letterCase, elementForProperties, elementUpdateHandler]);\n\n const isLetterCaseActive = useCallback(() => {\n return letterCase === 'uppercase';\n }, [letterCase]);\n\n const handleTextAlignToggle = useCallback(() => {\n const alignments: TextAlign[] = ['left', 'center', 'right'];\n const currentIndex = alignments.indexOf(textAlign);\n const nextAlign = alignments[(currentIndex + 1) % alignments.length];\n updateTextAlign(nextAlign);\n }, [textAlign, updateTextAlign]);\n\n // Get effective style (for rich text support)\n const getEffectiveStyle = useCallback((): CharacterStyle => {\n if (canvasEditorRef?.current?.isEditingText?.()) {\n const selectionStyle = canvasEditorRef.current.getSelectionStyle?.();\n if (selectionStyle) {\n return {\n fontFamily: selectionStyle.fontFamily ?? fontFamily,\n fontSize: selectionStyle.fontSize ?? fontSize,\n color: selectionStyle.color ?? fontColor,\n bold: selectionStyle.bold ?? bold,\n italic: selectionStyle.italic ?? italic,\n underline: selectionStyle.underline ?? underline,\n };\n }\n }\n return {\n fontFamily,\n fontSize,\n color: fontColor,\n bold,\n italic,\n underline,\n };\n }, [canvasEditorRef, fontFamily, fontSize, fontColor, bold, italic, underline]);\n\n // Transform type change handler\n const handleTransformTypeChange = useCallback(\n (newType: TransformType) => {\n if (!elementForProperties) return;\n\n const transformDef = getTransformById(newType);\n if (!transformDef?.Component) return;\n\n const updated = convertTransform(elementForProperties as TextElement, newType, transformDef.Component as unknown as new (config: Record<string, unknown>) => TextElement);\n elementUpdateHandler(updated);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n return {\n fontSize,\n fontColor,\n fontFamily,\n textAlign,\n bold,\n italic,\n underline,\n letterCase,\n handleFontSizeChange,\n handleFontSizeIncrement,\n handleFontFamilyChange,\n handleFontColorChange,\n handleBoldToggle,\n handleItalicToggle,\n handleUnderlineToggle,\n handleLetterCaseToggle,\n isLetterCaseActive,\n handleTextAlignToggle,\n getEffectiveStyle,\n handleTransformTypeChange,\n };\n}\n","/**\n * useLayerPreview - Hook for generating element preview thumbnails\n *\n * Extracts the preview/thumbnail generation logic from LayersPanel's\n * LayerPreview component into a reusable hook. Handles async image loading\n * for ImageElements and synchronous preview generation for other element types.\n *\n * @example\n * ```tsx\n * function LayerThumbnail({ element }: { element: EditorElement }) {\n * const { previewUrl, isLoading } = useLayerPreview({\n * element,\n * size: 148,\n * backgroundColor: 'transparent',\n * });\n *\n * if (isLoading || !previewUrl) return <Spinner />;\n * return <img src={previewUrl} alt=\"\" />;\n * }\n * ```\n */\n\nimport { useState, useEffect, useRef } from 'react';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { TextElement } from '../core/TextElement.js';\nimport { ShapeElement } from '../core/ShapeElement.js';\nimport { PathElement } from '../core/PathElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { generateElementPreview } from '../utils/ElementPreviewRenderer.js';\nimport { createLogger } from '../utils/logger.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\n\nconst logger = createLogger('useLayerPreview');\n\nexport interface UseLayerPreviewOptions {\n /** The element to generate a preview for */\n element: EditorElement;\n /** Preview size in pixels (width and height). Default: 148 */\n size?: number;\n /** Background color for the preview. Default: 'transparent' */\n backgroundColor?: string;\n /** Whether preview generation is enabled. Default: true */\n enabled?: boolean;\n}\n\nexport interface UseLayerPreviewReturn {\n /** Data URL of the preview image, or null if not yet generated */\n previewUrl: string | null;\n /** Whether the preview is currently being generated */\n isLoading: boolean;\n}\n\n/**\n * Hook for generating element preview thumbnails.\n *\n * Handles image elements by waiting for the image to load before\n * generating the preview. For text, shape, path, and group elements,\n * the preview is generated synchronously.\n *\n * Automatically regenerates when visual properties change (position,\n * rotation, transform data, text content, image URL, etc.).\n *\n * Debounces regeneration with a 50ms delay to avoid excessive\n * canvas operations during rapid property changes.\n */\nexport function useLayerPreview(options: UseLayerPreviewOptions): UseLayerPreviewReturn {\n const { element, size = 148, backgroundColor = 'transparent', enabled = true } = options;\n\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n if (!enabled) {\n setPreviewUrl(null);\n setIsLoading(false);\n return;\n }\n\n let mounted = true;\n setIsLoading(true);\n\n // Clear any pending debounce\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n\n debounceRef.current = setTimeout(() => {\n const generatePreview = async () => {\n try {\n // For image elements, wait for the image to load first\n if (element instanceof ImageElement && element.imageUrl) {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error('Failed to load image'));\n img.src = element.imageUrl;\n });\n\n if (!mounted) return;\n }\n\n // Generate the preview\n const url = generateElementPreview(element, {\n width: size,\n height: size,\n padding: 8,\n backgroundColor,\n });\n\n if (mounted) {\n setPreviewUrl(url);\n setIsLoading(false);\n }\n } catch (error) {\n logger.warn('Failed to generate preview:', error);\n // Generate a fallback preview without the loaded image\n if (mounted) {\n const url = generateElementPreview(element, {\n width: size,\n height: size,\n padding: 8,\n backgroundColor,\n });\n setPreviewUrl(url);\n setIsLoading(false);\n }\n }\n };\n\n generatePreview();\n }, 50); // 50ms debounce\n\n return () => {\n mounted = false;\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n };\n }, [\n element.id,\n backgroundColor,\n size,\n enabled,\n // Re-generate preview when visual properties change\n element.x,\n element.y,\n element.rotation,\n // Reference comparison is sufficient — elements are cloned before modification\n element.transformData,\n element instanceof TextElement ? element.text : null,\n element instanceof TextElement ? element.fontSize : null,\n element instanceof TextElement ? element.fontFamily : null,\n element instanceof TextElement ? element.color : null,\n element instanceof ImageElement ? element.imageUrl : null,\n element instanceof ImageElement ? element.imageLoaded : null,\n element instanceof ImageElement ? element.isCropping : null,\n element instanceof ShapeElement ? element.transformData?.fillColor : null,\n element instanceof PathElement ? element.transformData?.points?.length : null,\n element instanceof GroupElement ? element.children?.length : null,\n ]);\n\n return { previewUrl, isLoading };\n}\n","/**\n * LayerLeadingChip — leading slot for the contextual toolbar.\n *\n * Shows the selected element's thumbnail and a lock toggle, inline\n * with the rest of the toolbar buttons.\n *\n * The thumbnail uses `useLayerPreview` — the same hook the LayersPanel\n * uses to render real per-element previews via the canvas pipeline.\n * That way a star shape looks like a star, a rotated layer looks\n * rotated, and a masked / distressed layer reads accordingly. Earlier\n * versions used a hand-coded element-type-specific glyph (a square\n * for any shape, a single character for any text), which lied to the\n * user about what they had selected.\n *\n * The toolbar wrapper carries `data-preserve-selection` already, so\n * tapping the lock toggle won't trigger the document-level deselect\n * listener.\n *\n * The lock button uses `ToolbarButton` so it inherits the standard\n * toolbar sizing, the standard 20px icon, and the standard\n * `data-active='true'` \"selected\" styling.\n */\n\nimport { BaseElement } from '../core/BaseElement.js';\nimport { ToolbarButton } from './ui/toolbar-button.js';\nimport { useLayerPreview } from '../hooks/useLayerPreview.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\n\nexport function LayerLeadingChip({\n element,\n onToggleLock,\n onThumbnailClick,\n}: {\n element: BaseElement | null;\n onToggleLock: () => void;\n /** Optional click handler for the thumbnail. When provided, the\n * thumbnail becomes a button — typical use is to open the\n * \"Manage Layers\" drawer with the current layer focused. */\n onThumbnailClick?: () => void;\n}) {\n if (!element) return null;\n const locked = element.locked === true;\n return (\n <>\n <SelectionThumbnail\n element={element as EditorElement}\n onClick={onThumbnailClick}\n />\n <ToolbarButton\n icon={<LockIcon locked={locked} />}\n onClick={onToggleLock}\n active={locked}\n tooltip={locked ? 'Unlock layer' : 'Lock layer'}\n aria-label={locked ? 'Unlock layer' : 'Lock layer'}\n />\n </>\n );\n}\n\n// Outer cell is a button-sized slot for layout alignment with the\n// toolbar buttons. Inner thumbnail is icon-sized so it carries the\n// same visual weight as an icon. We render the actual preview from\n// `useLayerPreview` (already used by the LayersPanel) — for shapes\n// that means a star renders as a star, polygon as polygon, etc.\nfunction SelectionThumbnail({\n element,\n onClick,\n}: {\n element: EditorElement;\n onClick?: () => void;\n}) {\n // 64px source — small enough to be cheap to regenerate, big enough\n // that browser downscale to 20–24px stays sharp. Transparent bg\n // so the muted backdrop shows through the layer's empty space.\n const { previewUrl } = useLayerPreview({\n element,\n size: 64,\n backgroundColor: 'transparent',\n });\n\n const inner = (\n <span\n className=\"size-6 md:size-5 rounded-md shrink-0 flex items-center justify-center overflow-hidden\"\n style={{ background: 'var(--color-muted, rgba(120,120,120,0.18))' }}\n >\n {previewUrl ? (\n <img\n src={previewUrl}\n alt=\"\"\n style={{ width: '100%', height: '100%', objectFit: 'contain' }}\n />\n ) : null}\n </span>\n );\n\n // When a click handler is wired (e.g. open layers drawer), render\n // the cell as a button so it gets the standard hover affordance and\n // keyboard focus. Otherwise keep it as a plain decorative span.\n if (onClick) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n onPointerDown={(e) => e.stopPropagation()}\n onPointerUp={(e) => e.stopPropagation()}\n aria-label=\"Manage layers\"\n title=\"Manage layers\"\n className=\"size-11 md:size-9 shrink-0 flex items-center justify-center\"\n >\n {inner}\n </button>\n );\n }\n return (\n <span\n aria-hidden\n className=\"size-11 md:size-9 shrink-0 flex items-center justify-center\"\n >\n {inner}\n </span>\n );\n}\n\n// 20px lock icon (size-5) matches the other toolbar icons. Closed\n// shackle when locked, open shackle when unlocked. `currentColor`\n// so the data-active=true styling tints the icon too.\nfunction LockIcon({ locked }: { locked: boolean }) {\n return (\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden>\n <rect\n x=\"4\"\n y=\"9\"\n width=\"12\"\n height=\"8.5\"\n rx=\"1.6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n fill={locked ? 'currentColor' : 'none'}\n fillOpacity={locked ? 0.18 : 0}\n />\n {locked ? (\n <path\n d=\"M6.5 9V6.25a3.5 3.5 0 0 1 7 0V9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n ) : (\n <path\n d=\"M6.5 9V6.25a3.5 3.5 0 0 1 7 0\"\n stroke=\"currentColor\"\n strokeWidth=\"1.6\"\n strokeLinecap=\"round\"\n />\n )}\n </svg>\n );\n}\n","/**\n * GroupElementToolbar - Toolbar for group element controls.\n *\n * Shows when a group element is selected (not when editing a child within it).\n * Provides stroke, rotation, transparency, and ungroup controls.\n */\n\nimport React, { useState } from 'react';\nimport {\n Tooltip,\n TooltipTrigger,\n TooltipContent,\n ToolbarButton,\n Button,\n RotateLeftIcon,\n} from '../ui/index.js';\nimport { getFeatureApplied } from '../../utils/featureApplied.js';\nimport type { GroupElement } from '../../core/GroupElement.js';\n\nexport interface GroupElementToolbarProps {\n /** The group element being edited — used to derive feature-applied\n * flags so the toolbar buttons highlight when a property is set. */\n element?: GroupElement;\n /** Whether the rotation panel is expanded */\n rotationExpanded?: boolean;\n /** Callback when rotation panel should be toggled */\n onRotationToggle: () => void;\n /** Whether the opacity panel is expanded */\n opacityExpanded?: boolean;\n /** Callback when opacity panel should be toggled */\n onOpacityToggle: () => void;\n /** Whether the stroke panel is expanded */\n strokeExpanded?: boolean;\n /** Callback when stroke panel should be toggled */\n onStrokeToggle?: () => void;\n /** Whether the knockout panel is expanded */\n knockoutExpanded?: boolean;\n /** Callback when knockout panel should be toggled */\n onKnockoutToggle?: () => void;\n /** Whether the distress texture panel is expanded */\n distressTextureExpanded?: boolean;\n /** Callback when distress texture panel should be toggled */\n onDistressTextureToggle?: () => void;\n /** Whether the image mask panel is expanded */\n imageMaskExpanded?: boolean;\n /** Callback when image mask panel should be toggled */\n onImageMaskToggle?: () => void;\n /** Callback when the group should be ungrouped */\n onUngroup: () => void;\n}\n\nexport const GroupElementToolbar: React.FC<GroupElementToolbarProps> = ({\n element,\n rotationExpanded = false,\n onRotationToggle,\n opacityExpanded = false,\n onOpacityToggle,\n strokeExpanded = false,\n onStrokeToggle,\n knockoutExpanded = false,\n onKnockoutToggle,\n distressTextureExpanded = false,\n onDistressTextureToggle,\n imageMaskExpanded = false,\n onImageMaskToggle,\n onUngroup,\n}) => {\n const [rotationTooltipDisabled, setRotationTooltipDisabled] = useState(false);\n const [opacityTooltipDisabled, setOpacityTooltipDisabled] = useState(false);\n const [strokeTooltipDisabled, setStrokeTooltipDisabled] = useState(false);\n const [knockoutTooltipDisabled, setKnockoutTooltipDisabled] = useState(false);\n const [distressTooltipDisabled, setDistressTooltipDisabled] = useState(false);\n const [imageMaskTooltipDisabled, setImageMaskTooltipDisabled] = useState(false);\n\n // Feature-applied flags — drive the \"selected\" highlight on the\n // toolbar buttons whose underlying property has been set to a\n // non-default value on the group element.\n const applied = getFeatureApplied(element ?? null);\n\n return (\n <div className=\"toolbar-items\">\n {/* Rotation */}\n <ToolbarButton\n icon={<RotateLeftIcon size={20} className=\"md:size-5\" />}\n onClick={() => {\n setRotationTooltipDisabled(true);\n onRotationToggle();\n }}\n onMouseLeave={() => setRotationTooltipDisabled(false)}\n tooltip=\"Rotate\"\n tooltipDisabled={rotationTooltipDisabled || rotationExpanded}\n active={rotationExpanded || applied.rotation}\n />\n\n {/* Transparency */}\n <ToolbarButton\n icon=\"lucide:blend\"\n onClick={() => {\n setOpacityTooltipDisabled(true);\n onOpacityToggle();\n }}\n onMouseLeave={() => setOpacityTooltipDisabled(false)}\n tooltip=\"Transparency\"\n tooltipDisabled={opacityTooltipDisabled || opacityExpanded}\n active={opacityExpanded || applied.opacity}\n />\n\n {/* Stroke */}\n {onStrokeToggle && (\n <ToolbarButton\n icon=\"lucide:pen-line\"\n onClick={() => {\n setStrokeTooltipDisabled(true);\n onStrokeToggle();\n }}\n onMouseLeave={() => setStrokeTooltipDisabled(false)}\n tooltip=\"Stroke\"\n tooltipDisabled={strokeTooltipDisabled || strokeExpanded}\n active={strokeExpanded || applied.stroke}\n />\n )}\n\n {/* Knockout */}\n {onKnockoutToggle && (\n <ToolbarButton\n icon=\"lucide:scissors\"\n onClick={() => {\n setKnockoutTooltipDisabled(true);\n onKnockoutToggle();\n }}\n onMouseLeave={() => setKnockoutTooltipDisabled(false)}\n tooltip=\"Knockout\"\n tooltipDisabled={knockoutTooltipDisabled || knockoutExpanded}\n active={knockoutExpanded || applied.knockout}\n />\n )}\n\n {/* Distress Texture */}\n {onDistressTextureToggle && (\n <ToolbarButton\n icon=\"lucide:stamp\"\n onClick={() => {\n setDistressTooltipDisabled(true);\n onDistressTextureToggle();\n }}\n onMouseLeave={() => setDistressTooltipDisabled(false)}\n tooltip=\"Distress Texture\"\n tooltipDisabled={distressTooltipDisabled || distressTextureExpanded}\n active={distressTextureExpanded || applied.distress}\n />\n )}\n\n {/* Image Mask */}\n {onImageMaskToggle && (\n <ToolbarButton\n icon=\"lucide:venetian-mask\"\n onClick={() => {\n setImageMaskTooltipDisabled(true);\n onImageMaskToggle();\n }}\n onMouseLeave={() => setImageMaskTooltipDisabled(false)}\n tooltip=\"Image Mask\"\n tooltipDisabled={imageMaskTooltipDisabled || imageMaskExpanded}\n active={imageMaskExpanded || applied.imageMask}\n />\n )}\n\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"sm\" onClick={onUngroup}>\n Ungroup\n </Button>\n </TooltipTrigger>\n <TooltipContent>Ungroup this group</TooltipContent>\n </Tooltip>\n </div>\n );\n};\n\nexport default GroupElementToolbar;\n","/**\n * CropPanel - Reusable crop controls for image elements\n *\n * Can be used standalone in a drawer or embedded in the contextual toolbar.\n * Provides anchor point selection and width/height sliders.\n *\n * @example\n * // In a drawer\n * <Drawer open={cropDrawerOpen} onOpenChange={setCropDrawerOpen}>\n * <DrawerContent>\n * <CropPanel\n * element={selectedImageElement}\n * onElementUpdate={handleElementUpdate}\n * />\n * </DrawerContent>\n * </Drawer>\n */\n\nimport React, { useState, useCallback, useRef, useEffect } from 'react';\nimport { Slider } from './ui';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { cn } from '../lib/utils.js';\n\n/**\n * TouchGuard - Wraps interactive elements to prevent parent scroll from capturing touches\n *\n * Uses native event listeners with { passive: false } because:\n * 1. React's synthetic events can't properly preventDefault on touch events\n * 2. CSS touch-action: none is evaluated at gesture start on the ancestor chain,\n * so a parent with pan-y can still capture the gesture before child CSS applies\n * 3. Native listeners with passive: false intercept events before the browser decides to scroll\n */\nfunction TouchGuard({ children, className }: { children: React.ReactNode; className?: string }) {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n\n const handleTouchStart = (e: TouchEvent) => {\n // Stop the event from reaching parent scroll containers\n e.stopPropagation();\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n // Prevent default scroll behavior and stop propagation\n e.preventDefault();\n e.stopPropagation();\n };\n\n // Must use passive: false to allow preventDefault\n el.addEventListener('touchstart', handleTouchStart, { passive: false });\n el.addEventListener('touchmove', handleTouchMove, { passive: false });\n\n return () => {\n el.removeEventListener('touchstart', handleTouchStart);\n el.removeEventListener('touchmove', handleTouchMove);\n };\n }, []);\n\n return (\n <div ref={ref} className={className} style={{ touchAction: 'none' }}>\n {children}\n </div>\n );\n}\n\ntype CropAnchor =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'middle-left'\n | 'center'\n | 'middle-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right';\n\nexport interface CropPanelProps {\n /** The image element to crop */\n element: ImageElement;\n /** Callback when element is updated */\n onElementUpdate: (element: ImageElement) => void;\n /** Optional class name for the container */\n className?: string;\n}\n\n/**\n * CropPanel - Controls for cropping image elements\n *\n * Provides:\n * - 3x3 anchor grid for selecting resize origin\n * - Width slider (10-100%)\n * - Height slider (10-100%)\n */\nexport const CropPanel: React.FC<CropPanelProps> = ({ element, onElementUpdate, className }) => {\n // Crop anchor point - determines where the crop resizes from\n const [cropAnchor, setCropAnchor] = useState<CropAnchor>('center');\n\n // Block horizontal touch movement to prevent drawer/page from being dragged\n const containerRef = useRef<HTMLDivElement>(null);\n const touchStartPos = useRef({ x: 0, y: 0 });\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n\n const handleTouchStart = (e: TouchEvent) => {\n touchStartPos.current = {\n x: e.touches[0].clientX,\n y: e.touches[0].clientY,\n };\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n const deltaX = Math.abs(e.touches[0].clientX - touchStartPos.current.x);\n const deltaY = Math.abs(e.touches[0].clientY - touchStartPos.current.y);\n\n // If horizontal movement is greater than vertical, prevent it\n if (deltaX > 10 && deltaX > deltaY) {\n e.preventDefault();\n }\n };\n\n el.addEventListener('touchstart', handleTouchStart, { passive: true });\n el.addEventListener('touchmove', handleTouchMove, { passive: false });\n\n return () => {\n el.removeEventListener('touchstart', handleTouchStart);\n el.removeEventListener('touchmove', handleTouchMove);\n };\n }, []);\n\n // Get current crop values\n const currentCropWidth = element.transformData?.cropWidth || 1;\n const currentCropHeight = element.transformData?.cropHeight || 1;\n\n // Handle crop changes\n const handleCropChange = useCallback(\n (cropX: number, cropY: number, cropWidth: number, cropHeight: number) => {\n const updatedElement = element.clone();\n updatedElement.updateCrop(cropX, cropY, cropWidth, cropHeight, true);\n onElementUpdate(updatedElement);\n },\n [element, onElementUpdate]\n );\n\n const handleCropWidthChange = useCallback(\n (value: number, anchor: CropAnchor = cropAnchor) => {\n const oldWidth = element.transformData.cropWidth;\n const oldX = element.transformData.cropX;\n const widthDiff = value - oldWidth;\n\n let newX = oldX;\n // Adjust X based on horizontal anchor position\n if (anchor.includes('center')) {\n newX = oldX - widthDiff / 2;\n } else if (anchor.includes('right')) {\n newX = oldX - widthDiff;\n }\n\n // Clamp X to valid range\n newX = Math.max(0, Math.min(1 - value, newX));\n\n handleCropChange(newX, element.transformData.cropY, value, element.transformData.cropHeight);\n },\n [element, handleCropChange, cropAnchor]\n );\n\n const handleCropHeightChange = useCallback(\n (value: number, anchor: CropAnchor = cropAnchor) => {\n const oldHeight = element.transformData.cropHeight;\n const oldY = element.transformData.cropY;\n const heightDiff = value - oldHeight;\n\n let newY = oldY;\n // Adjust Y based on vertical anchor position\n if (anchor.includes('middle') || anchor === 'center') {\n newY = oldY - heightDiff / 2;\n } else if (anchor.includes('bottom')) {\n newY = oldY - heightDiff;\n }\n\n // Clamp Y to valid range\n newY = Math.max(0, Math.min(1 - value, newY));\n\n handleCropChange(element.transformData.cropX, newY, element.transformData.cropWidth, value);\n },\n [element, handleCropChange, cropAnchor]\n );\n\n // Anchor grid positions\n const anchorPositions: CropAnchor[] = [\n 'top-left',\n 'top-center',\n 'top-right',\n 'middle-left',\n 'center',\n 'middle-right',\n 'bottom-left',\n 'bottom-center',\n 'bottom-right',\n ];\n\n return (\n <div\n ref={containerRef}\n data-preserve-selection\n className={cn('flex min-h-0 flex-1 flex-col', className)}\n style={{ touchAction: 'pan-y' }}\n >\n <div className=\"flex flex-col gap-5 px-5 pt-1 pb-[calc(env(safe-area-inset-bottom,0px)+20px)] md:gap-4 md:px-4 md:pt-0 md:pb-[calc(env(safe-area-inset-bottom,0px)+16px)]\">\n {/* Main content: Anchor Grid + Sliders */}\n <div className=\"flex items-start gap-6 md:gap-5\">\n {/* Anchor Grid */}\n <div className=\"flex flex-col gap-2\">\n <span className=\"text-foreground/60 text-sm md:text-xs\">Anchor</span>\n <div className=\"grid grid-cols-3 gap-0.5 rounded-md p-1\">\n {anchorPositions.map((pos) => (\n <button\n key={pos}\n onClick={() => setCropAnchor(pos)}\n className={cn(\n 'crop-anchor-btn size-8 rounded-md md:size-6 md:rounded',\n cropAnchor === pos && 'active'\n )}\n title={pos.replace('-', ' ')}\n >\n <div\n className={cn(\n 'crop-anchor-dot size-2 md:size-1.5',\n cropAnchor === pos && 'active size-2.5 md:size-2'\n )}\n />\n </button>\n ))}\n </div>\n </div>\n\n {/* Size Sliders */}\n <div className=\"flex flex-1 flex-col gap-4 md:gap-3\">\n {/* Width Slider */}\n <div className=\"flex flex-col gap-2.5 md:gap-1.5\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-foreground/60 text-sm md:text-xs\">Width</span>\n <input\n type=\"number\"\n value={Math.round(currentCropWidth * 100)}\n onChange={(e) => handleCropWidthChange(Math.max(10, Math.min(100, Number(e.target.value))) / 100)}\n min={10}\n max={100}\n className=\"bg-transparent text-foreground w-14 rounded-md border-none px-2.5 py-2 text-right text-base md:w-14 md:rounded md:px-1.5 md:py-1 md:text-[13px]\"\n />\n </div>\n {/* TouchGuard prevents parent scroll from capturing slider touches */}\n <TouchGuard>\n <Slider\n value={[currentCropWidth * 100]}\n onValueChange={(val) => handleCropWidthChange(val[0] / 100)}\n min={10}\n max={100}\n step={1}\n >\n <Slider.Track className=\"bg-foreground/10 h-2\">\n <Slider.Fill className=\"bg-primary\" />\n </Slider.Track>\n <Slider.Thumb />\n </Slider>\n </TouchGuard>\n </div>\n\n {/* Height Slider */}\n <div className=\"flex flex-col gap-2.5 md:gap-1.5\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-foreground/60 text-sm md:text-xs\">Height</span>\n <input\n type=\"number\"\n value={Math.round(currentCropHeight * 100)}\n onChange={(e) => handleCropHeightChange(Math.max(10, Math.min(100, Number(e.target.value))) / 100)}\n min={10}\n max={100}\n className=\"bg-transparent text-foreground w-14 rounded-md border-none px-2.5 py-2 text-right text-base md:w-14 md:rounded md:px-1.5 md:py-1 md:text-[13px]\"\n />\n </div>\n {/* TouchGuard prevents parent scroll from capturing slider touches */}\n <TouchGuard>\n <Slider\n value={[currentCropHeight * 100]}\n onValueChange={(val) => handleCropHeightChange(val[0] / 100)}\n min={10}\n max={100}\n step={1}\n >\n <Slider.Track className=\"bg-foreground/10 h-2\">\n <Slider.Fill className=\"bg-primary\" />\n </Slider.Track>\n <Slider.Thumb />\n </Slider>\n </TouchGuard>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default CropPanel;\n","/**\n * SecondaryPanels - Panel content components for expanded toolbar panels.\n *\n * These are the content areas rendered below the collapsed toolbar header\n * when a secondary panel (corner radius, rotation, opacity, etc.) is expanded.\n */\n\nimport React, { useCallback, useState } from 'react';\nimport { SliderRow, ToolbarButton, Checkbox, Label, icons, PresetCarousel, Switch } from '../ui/index.js';\nimport type { PresetItem } from '../ui/index.js';\nimport ColorPickerDropdown from '../ColorPickerDropdown.jsx';\nimport CropPanel from '../CropPanel.jsx';\nimport type { ImageElement } from '../../core/ImageElement.js';\nimport type { StrokeConfig, CompositingScope } from '../../types/index.js';\nimport { DISTRESS_TEXTURE_PRESETS, ensureBuiltinTexturesReady } from '../../effects/distress-textures.js';\nimport { preloadTexture } from '../../effects/DistressTextureCache.js';\nimport { MASK_IMAGE_PRESETS, ensureMaskPresetsReady } from '../../effects/mask-presets.js';\n\n// ── Shared panel body styling ───────────────────────────────────────────────\nconst PANEL_BODY_CLASSES =\n 'flex flex-col gap-5 px-5 pt-4 pb-4 md:gap-4 md:px-4 md:pt-3 md:pb-3';\n\nconst COLOR_PANEL_BODY_CLASSES =\n 'flex flex-col gap-5 px-5 pt-4 pb-[calc(env(safe-area-inset-bottom,0px)+20px)] md:gap-4 md:px-4 md:pt-2 md:pb-[calc(env(safe-area-inset-bottom,0px)+16px)]';\n\n// ── Corner Radius Panel (Image) ─────────────────────────────────────────────\n\nexport interface CornerRadiusPanelProps {\n value: number;\n onChange: (value: number) => void;\n}\n\nexport const CornerRadiusPanel: React.FC<CornerRadiusPanelProps> = ({ value, onChange }) => (\n <div\n className=\"corner-radius-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow label=\"Radius\" value={value} onChange={onChange} min={0} max={50} unit=\"%\" />\n </div>\n </div>\n);\n\n// ── Rotation Panel ──────────────────────────────────────────────────────────\n\nexport interface RotationPanelProps {\n value: number;\n onChange: (value: number) => void;\n onRotate90: () => void;\n}\n\nexport const RotationPanel: React.FC<RotationPanelProps> = ({ value, onChange, onRotate90 }) => (\n <div\n className=\"rotation-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <div className=\"flex items-end gap-3\">\n <SliderRow\n label=\"Rotation\"\n value={value}\n onChange={onChange}\n min={-180}\n max={180}\n unit=\"°\"\n showInput\n inputWidth=\"56px\"\n variant=\"stacked\"\n className=\"flex-1\"\n />\n {/* 90 Degree Button */}\n <div className=\"pb-0.5\">\n <ToolbarButton icon={icons.rotateCcwSquare} onClick={onRotate90} tooltip=\"Rotate 90° CCW\" />\n </div>\n </div>\n </div>\n </div>\n);\n\n// ── Font Size Panel ─────────────────────────────────────────────────────────\n\nexport interface FontSizePanelProps {\n value: number;\n onChange: (value: number) => void;\n /** Current text-box width. When null/undefined the width slider is\n * hidden (e.g. element type doesn't expose a width on transformData). */\n widthValue?: number | null;\n /** Called when the width slider moves. */\n onWidthChange?: (value: number) => void;\n}\n\n// Font size panel — slider + number input. Replaces the older +/-\n// stepper which moved in 1px steps (too small to be useful) and\n// stretched the toolbar to fit a long number. Min/max give plenty\n// of headroom: 8 (smallest legible) → 256 (very large display\n// type). Step 1 because the input lets users dial precisely; the\n// slider handles coarse motion.\n//\n// Width slider sits directly under the font size slider — same\n// section because both control the layout of the text element. The\n// width slider operates on the text-box width (`transformData.width`)\n// which drives line-wrapping for custom text and the bounding box\n// for transformed text (wave, arch, etc.).\nexport const FontSizePanel: React.FC<FontSizePanelProps> = ({\n value,\n onChange,\n widthValue,\n onWidthChange,\n}) => (\n <div\n className=\"font-size-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow\n label=\"Font Size\"\n value={Math.round(value)}\n onChange={onChange}\n min={8}\n max={256}\n step={1}\n unit=\"px\"\n showInput\n inputWidth=\"64px\"\n />\n {widthValue != null && onWidthChange && (\n <SliderRow\n label=\"Width\"\n value={Math.round(widthValue)}\n onChange={onWidthChange}\n min={50}\n max={4000}\n step={1}\n unit=\"px\"\n showInput\n inputWidth=\"64px\"\n />\n )}\n </div>\n </div>\n);\n\n// ── Opacity Panel ───────────────────────────────────────────────────────────\n\nexport interface OpacityPanelProps {\n /** Opacity value 0-1 */\n value: number;\n /** Called with 0-1 range */\n onChange: (value: number) => void;\n}\n\nexport const OpacityPanel: React.FC<OpacityPanelProps> = ({ value, onChange }) => (\n <div\n className=\"opacity-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow\n label=\"Opacity\"\n value={Math.round(value * 100)}\n onChange={(v) => onChange(v / 100)}\n min={0}\n max={100}\n unit=\"%\"\n />\n </div>\n </div>\n);\n\n// ── Shape Corner Radius Panel ───────────────────────────────────────────────\n\nexport interface ShapeCornerRadiusPanelProps {\n value: number;\n onChange: (value: number) => void;\n}\n\nexport const ShapeCornerRadiusPanel: React.FC<ShapeCornerRadiusPanelProps> = ({ value, onChange }) => (\n <div\n className=\"shape-corner-radius-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow label=\"Radius\" value={value} onChange={onChange} min={0} max={50} unit=\"%\" />\n </div>\n </div>\n);\n\n// ── Shape Transparency Panel ────────────────────────────────────────────────\n\nexport interface ShapeTransparencyPanelProps {\n /** Fill opacity 0-1 */\n value: number;\n /** Called with 0-1 range */\n onChange: (value: number) => void;\n}\n\nexport const ShapeTransparencyPanel: React.FC<ShapeTransparencyPanelProps> = ({ value, onChange }) => (\n <div\n className=\"shape-transparency-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow\n label=\"Opacity\"\n value={Math.round(value * 100)}\n onChange={(val) => onChange(val / 100)}\n min={0}\n max={100}\n unit=\"%\"\n />\n </div>\n </div>\n);\n\n// ── Shape Sides Panel (Polygon) ─────────────────────────────────────────────\n\nexport interface ShapeSidesPanelProps {\n value: number;\n onChange: (value: number) => void;\n}\n\nexport const ShapeSidesPanel: React.FC<ShapeSidesPanelProps> = ({ value, onChange }) => (\n <div\n className=\"shape-sides-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow label=\"Sides\" value={value} onChange={onChange} min={3} max={20} />\n </div>\n </div>\n);\n\n// ── Shape Points Panel (Star) ───────────────────────────────────────────────\n\nexport interface ShapePointsPanelProps {\n value: number;\n onChange: (value: number) => void;\n}\n\nexport const ShapePointsPanel: React.FC<ShapePointsPanelProps> = ({ value, onChange }) => (\n <div\n className=\"shape-points-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow label=\"Points\" value={value} onChange={onChange} min={3} max={20} />\n </div>\n </div>\n);\n\n// ── Shape Inner Radius Panel (Star) ─────────────────────────────────────────\n\nexport interface ShapeInnerRadiusPanelProps {\n /** Inner radius 0-1 */\n value: number;\n /** Called with 0-1 range */\n onChange: (value: number) => void;\n}\n\nexport const ShapeInnerRadiusPanel: React.FC<ShapeInnerRadiusPanelProps> = ({ value, onChange }) => (\n <div\n className=\"shape-inner-radius-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <SliderRow\n label=\"Inner Radius\"\n value={Math.round(value * 100)}\n onChange={(val) => onChange(val / 100)}\n min={10}\n max={90}\n unit=\"%\"\n />\n </div>\n </div>\n);\n\n// ── Shape Fill Color Panel ──────────────────────────────────────────────────\n\nexport interface ShapeColorPanelProps {\n value: string;\n onChange: (color: string) => void;\n documentColors: string[];\n imageColors?: string[];\n}\n\nexport const ShapeColorPanel: React.FC<ShapeColorPanelProps> = ({ value, onChange, documentColors, imageColors }) => (\n <div\n className=\"shape-color-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={COLOR_PANEL_BODY_CLASSES}>\n <ColorPickerDropdown\n value={value}\n onChange={(e: { target: { value: string } }) => onChange(e.target.value)}\n documentColors={documentColors}\n imageColors={imageColors}\n showSquare={true}\n embedded={true}\n />\n </div>\n </div>\n);\n\n// ── Text Color Panel ────────────────────────────────────────────────────────\n\nexport interface TextColorPanelProps {\n value: string;\n onChange: (e: { target: { value: string } }) => void;\n documentColors: string[];\n imageColors?: string[];\n}\n\nexport const TextColorPanel: React.FC<TextColorPanelProps> = ({ value, onChange, documentColors, imageColors }) => (\n <div\n className=\"text-color-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={COLOR_PANEL_BODY_CLASSES}>\n <ColorPickerDropdown value={value} onChange={onChange} documentColors={documentColors} imageColors={imageColors} embedded={true} />\n </div>\n </div>\n);\n\n// ── Compositing Panel (Clip / Knockout) ─────────────────────────────────────\n\nexport type CompositingMode = 'clip' | 'knockout';\n\nexport interface CompositingPanelProps {\n mode: CompositingMode;\n fill: boolean;\n stroke: boolean;\n scope: CompositingScope;\n onModeChange: (mode: CompositingMode) => void;\n onFillChange: (fill: boolean) => void;\n onStrokeChange: (stroke: boolean) => void;\n onScopeChange: (scope: CompositingScope) => void;\n}\n\nexport const CompositingPanel: React.FC<CompositingPanelProps> = ({\n mode,\n fill,\n stroke,\n scope,\n onModeChange,\n onFillChange,\n onStrokeChange,\n onScopeChange,\n}) => (\n <div\n className=\"knockout-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n {/* Mode selector: Clip / Knockout */}\n <div className=\"flex items-center gap-3\">\n <Label className=\"text-base md:text-sm font-medium\">Mode</Label>\n <div className=\"flex rounded-md border border-divider overflow-hidden\">\n <button\n className={`px-4 py-2.5 text-base md:px-3 md:py-1.5 md:text-sm transition-colors ${mode === 'clip' ? 'bg-primary text-primary-foreground' : 'text-foreground hover:bg-muted'}`}\n onClick={() => onModeChange('clip')}\n >\n Clip\n </button>\n <button\n className={`px-4 py-2.5 text-base md:px-3 md:py-1.5 md:text-sm transition-colors ${mode === 'knockout' ? 'bg-primary text-primary-foreground' : 'text-foreground hover:bg-muted'}`}\n onClick={() => onModeChange('knockout')}\n >\n Knockout\n </button>\n </div>\n </div>\n\n {/* Fill / Stroke checkboxes */}\n <div className=\"flex items-center gap-5\">\n <label className=\"flex items-center gap-2 text-base md:text-sm text-foreground\">\n <Checkbox checked={fill} onCheckedChange={(v) => onFillChange(v === true)} />\n Fill\n </label>\n <label className=\"flex items-center gap-2 text-base md:text-sm text-foreground\">\n <Checkbox checked={stroke} onCheckedChange={(v) => onStrokeChange(v === true)} />\n Stroke\n </label>\n </div>\n\n {/* Scope selector */}\n <div className=\"flex items-center gap-3\">\n <Label className=\"text-base md:text-sm font-medium\">Scope</Label>\n <div className=\"flex rounded-md border border-divider overflow-hidden\">\n <button\n className={`px-4 py-2.5 text-base md:px-3 md:py-1.5 md:text-sm transition-colors ${scope === 'group' ? 'bg-primary text-primary-foreground' : 'text-foreground hover:bg-muted'}`}\n onClick={() => onScopeChange('group')}\n >\n Group\n </button>\n <button\n className={`px-4 py-2.5 text-base md:px-3 md:py-1.5 md:text-sm transition-colors ${scope === 'artboard' ? 'bg-primary text-primary-foreground' : 'text-foreground hover:bg-muted'}`}\n onClick={() => onScopeChange('artboard')}\n >\n Artboard\n </button>\n </div>\n </div>\n </div>\n </div>\n);\n\n/** @deprecated Use CompositingPanel instead */\nexport type KnockoutPanelProps = CompositingPanelProps;\n/** @deprecated Use CompositingPanel instead */\nexport const KnockoutPanel = CompositingPanel;\n\n// ── Distress Texture Panel ──────────────────────────────────────────────────\n\nexport interface DistressTexturePanelProps {\n textureUrl: string;\n /** Opacity 0-100 (percentage) */\n opacity: number;\n onTextureChange: (url: string) => void;\n onOpacityChange: (pct: number) => void;\n}\n\nexport const DistressTexturePanel: React.FC<DistressTexturePanelProps> = ({\n textureUrl,\n opacity,\n onTextureChange,\n onOpacityChange,\n}) => {\n // Call synchronously so thumbnailUrls are populated before we read them\n ensureBuiltinTexturesReady();\n\n const presetItems: PresetItem[] = DISTRESS_TEXTURE_PRESETS.map((p) => ({ id: p.textureUrl, name: p.name, thumbnailUrl: p.thumbnailUrl }));\n\n const handleSelect = useCallback(\n (id: string) => {\n if (id) preloadTexture(id);\n onTextureChange(id);\n },\n [onTextureChange]\n );\n\n return (\n <div\n className=\"distress-texture-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <PresetCarousel\n presets={presetItems}\n selectedId={textureUrl}\n onSelect={handleSelect}\n ariaLabel=\"Distress texture presets\"\n />\n\n {/* Opacity slider */}\n <SliderRow\n label=\"Opacity\"\n value={opacity}\n onChange={onOpacityChange}\n min={0}\n max={100}\n unit=\"%\"\n />\n </div>\n </div>\n );\n};\n\n// ── Image Mask Panel ────────────────────────────────────────────────────\n\nexport interface ImageMaskPanelProps {\n imageUrl: string;\n maskType: 'clip' | 'alpha' | 'luma';\n opacity: number; // 0-100\n inverted: boolean;\n onImageChange: (url: string) => void;\n onMaskTypeChange: (type: 'clip' | 'alpha' | 'luma') => void;\n onOpacityChange: (pct: number) => void;\n onInvertedChange: (inverted: boolean) => void;\n}\n\nexport const ImageMaskPanel: React.FC<ImageMaskPanelProps> = ({\n imageUrl,\n maskType,\n opacity,\n inverted,\n onImageChange,\n onMaskTypeChange,\n onOpacityChange,\n onInvertedChange,\n}) => {\n // Call synchronously so thumbnailUrls are populated before we read them\n ensureMaskPresetsReady();\n\n const presetItems: PresetItem[] = MASK_IMAGE_PRESETS.map((p) => ({ id: p.imageUrl, name: p.name, thumbnailUrl: p.thumbnailUrl }));\n\n return (\n <div\n className=\"image-mask-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n <PresetCarousel\n presets={presetItems}\n selectedId={imageUrl}\n onSelect={onImageChange}\n ariaLabel=\"Image mask presets\"\n />\n\n {/* Mask type row */}\n <div className=\"flex items-center gap-2\">\n <Label className=\"text-base md:text-sm font-medium\">Type</Label>\n <div className=\"flex rounded-md border border-divider overflow-hidden\">\n {(['clip', 'alpha', 'luma'] as const).map((type) => (\n <button\n key={type}\n className={`px-4 py-2.5 text-base md:px-3 md:py-1.5 md:text-sm capitalize transition-colors ${\n maskType === type\n ? 'bg-primary text-primary-foreground'\n : 'text-foreground hover:bg-muted'\n }`}\n onClick={() => onMaskTypeChange(type)}\n >\n {type}\n </button>\n ))}\n </div>\n </div>\n\n {/* Opacity slider */}\n <SliderRow\n label=\"Opacity\"\n value={opacity}\n onChange={onOpacityChange}\n min={0}\n max={100}\n unit=\"%\"\n />\n\n {/* Inverted checkbox */}\n <label className=\"flex items-center gap-2 text-base md:text-sm text-foreground\">\n <Checkbox checked={inverted} onCheckedChange={(v) => onInvertedChange(v === true)} />\n Invert Mask\n </label>\n </div>\n </div>\n );\n};\n\n// ── Stroke Panel ────────────────────────────────────────────────────────────\n\nexport interface StrokePanelProps {\n stroke?: StrokeConfig;\n onChange: (stroke: StrokeConfig | undefined) => void;\n documentColors?: string[];\n imageColors?: string[];\n}\n\nexport const StrokePanel: React.FC<StrokePanelProps> = ({ stroke, onChange, documentColors, imageColors }) => {\n const [showAdvanced, setShowAdvanced] = useState(false);\n\n const enabled = stroke?.enabled ?? false;\n const color = stroke?.color ?? '#000000';\n const width = stroke?.width ?? 5;\n const opacity = stroke?.opacity ?? 1;\n const lineCap = stroke?.lineCap ?? 'butt';\n const lineJoin = stroke?.lineJoin ?? 'miter';\n\n const handleEnabledChange = useCallback(\n (newEnabled: boolean) => {\n if (newEnabled) {\n onChange({ enabled: true, color, width, lineCap, lineJoin, opacity });\n } else {\n onChange(undefined);\n }\n },\n [onChange, color, width, lineCap, lineJoin, opacity]\n );\n\n const update = useCallback(\n (patch: Partial<StrokeConfig>) => {\n if (!stroke) return;\n onChange({ ...stroke, ...patch });\n },\n [stroke, onChange]\n );\n\n return (\n <div\n className=\"stroke-panel flex flex-col\"\n data-preserve-selection\n style={{ touchAction: 'pan-y' }}\n >\n <div className={PANEL_BODY_CLASSES}>\n {/* Enable/disable toggle */}\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-foreground/70 text-base md:text-[13px]\">Stroke</Label>\n <Switch checked={enabled} onCheckedChange={handleEnabledChange} />\n </div>\n\n {enabled && (\n <>\n {/* Color picker */}\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-foreground/70 text-base md:text-[13px]\">Color</Label>\n <ColorPickerDropdown\n value={color}\n onChange={(e: { target: { value: string } }) => update({ color: e.target.value })}\n documentColors={documentColors}\n imageColors={imageColors}\n showSquare={true}\n />\n </div>\n\n {/* Width slider */}\n <SliderRow\n label=\"Width\"\n value={width}\n onChange={(v) => update({ width: v })}\n min={1}\n max={50}\n unit=\"px\"\n />\n\n {/* Opacity slider */}\n <SliderRow\n label=\"Opacity\"\n value={Math.round(opacity * 100)}\n onChange={(v) => update({ opacity: v / 100 })}\n min={0}\n max={100}\n unit=\"%\"\n />\n\n {/* Advanced toggle */}\n <button\n className=\"flex items-center gap-1 text-base md:text-sm text-muted-foreground hover:text-foreground transition-colors py-1.5 md:py-0\"\n onClick={() => setShowAdvanced((prev) => !prev)}\n >\n {showAdvanced ? 'Hide' : 'Show'} Advanced\n </button>\n\n {showAdvanced && (\n <>\n {/* Line Cap */}\n <div className=\"flex items-center gap-3\">\n <Label className=\"text-foreground/70 text-base md:text-[13px]\">Line Cap</Label>\n <div className=\"flex rounded-md border border-divider overflow-hidden\">\n {(['butt', 'round', 'square'] as const).map((cap) => (\n <button\n key={cap}\n className={`px-4 py-2.5 text-base md:px-3 md:py-1.5 md:text-sm capitalize transition-colors ${\n lineCap === cap\n ? 'bg-primary text-primary-foreground'\n : 'text-foreground hover:bg-muted'\n }`}\n onClick={() => update({ lineCap: cap })}\n >\n {cap}\n </button>\n ))}\n </div>\n </div>\n\n {/* Line Join */}\n <div className=\"flex items-center gap-3\">\n <Label className=\"text-foreground/70 text-base md:text-[13px]\">Line Join</Label>\n <div className=\"flex rounded-md border border-divider overflow-hidden\">\n {(['miter', 'round', 'bevel'] as const).map((join) => (\n <button\n key={join}\n className={`px-4 py-2.5 text-base md:px-3 md:py-1.5 md:text-sm capitalize transition-colors ${\n lineJoin === join\n ? 'bg-primary text-primary-foreground'\n : 'text-foreground hover:bg-muted'\n }`}\n onClick={() => update({ lineJoin: join })}\n >\n {join}\n </button>\n ))}\n </div>\n </div>\n </>\n )}\n </>\n )}\n </div>\n </div>\n );\n};\n\n// ── Crop Panel Content ──────────────────────────────────────────────────────\n\nexport interface CropPanelContentProps {\n element: ImageElement;\n onElementUpdate: (element: ImageElement) => void;\n}\n\nexport const CropPanelContent: React.FC<CropPanelContentProps> = ({ element, onElementUpdate }) => (\n <CropPanel element={element} onElementUpdate={onElementUpdate} />\n);\n","/**\n * ExpandedPanelIcon - Renders the icon for the collapsed toolbar header\n * when a secondary panel is expanded.\n *\n * Special rendering for text color (shows \"A\" with color underline)\n * and shape color (shows fill icon with color underline).\n */\n\nimport React from 'react';\nimport { Icon } from '@iconify/react';\n\nexport interface ExpandedPanelIconProps {\n /** The type of expanded panel */\n panelType: string;\n /** The default icon from the panel config (used for non-special types) */\n defaultIcon: string | React.ReactNode;\n /** Current text color value (for textColor type) */\n textColorValue?: string;\n /** Current shape fill color value (for shapeColor type) */\n shapeFillColor?: string;\n}\n\nexport const ExpandedPanelIcon: React.FC<ExpandedPanelIconProps> = ({\n panelType,\n defaultIcon,\n textColorValue,\n shapeFillColor,\n}) => {\n if (panelType === 'textColor') {\n return (\n <div className=\"relative flex size-6 items-center justify-center md:size-5\">\n <span className=\"text-primary text-xl leading-none font-bold md:text-lg\">A</span>\n <div\n className=\"absolute bottom-0 left-1/2 h-[3px] w-4 -translate-x-1/2 rounded-sm\"\n style={{ backgroundColor: textColorValue }}\n />\n </div>\n );\n }\n\n if (panelType === 'shapeColor') {\n return (\n <div className=\"relative flex size-6 items-center justify-center md:size-5\">\n <Icon icon=\"mdi:format-color-fill\" className=\"text-primary size-5 md:size-4\" />\n <div\n className=\"absolute -bottom-0.5 left-1/2 h-[3px] w-4 -translate-x-1/2 rounded-sm\"\n style={{ backgroundColor: shapeFillColor || '#3b82f6' }}\n />\n </div>\n );\n }\n\n if (typeof defaultIcon === 'string') {\n return <Icon icon={defaultIcon} className=\"text-primary size-6 md:size-5\" />;\n }\n\n return <>{defaultIcon}</>;\n};\n\nexport default ExpandedPanelIcon;\n","/**\n * SecondaryPanelWrapper - Animated wrapper for secondary toolbar panels.\n *\n * Provides consistent expand/collapse animation for secondary panels\n * (corner radius, crop, rotation, opacity, shape panels, color panels).\n *\n * Used in embedded mode to wrap each panel with flex + transition styling.\n */\n\nimport React from 'react';\n\nexport interface SecondaryPanelWrapperProps {\n /** Whether this panel is currently open/expanded */\n isOpen: boolean;\n /** The panel content to render inside the wrapper */\n children: React.ReactNode;\n}\n\nexport const SecondaryPanelWrapper: React.FC<SecondaryPanelWrapperProps> = ({ isOpen, children }) => {\n return (\n <div\n className=\"secondary-toolbar-panel-wrapper\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n flex: isOpen ? 1 : 0,\n minHeight: isOpen ? 0 : undefined,\n transition: 'flex 300ms cubic-bezier(0.32, 0.72, 0, 1)',\n }}\n >\n <div\n className={isOpen ? 'secondary-panel-scroll-container' : ''}\n style={{\n flex: 1,\n display: 'flex',\n flexDirection: 'column',\n overflowY: isOpen ? 'auto' : 'hidden',\n overscrollBehaviorY: 'contain',\n WebkitOverflowScrolling: 'touch',\n transform: isOpen ? 'translateY(0)' : 'translateY(100%)',\n opacity: isOpen ? 1 : 0,\n transition: 'transform 300ms cubic-bezier(0.32, 0.72, 0, 1), opacity 200ms ease-out',\n }}\n >\n {children}\n </div>\n </div>\n );\n};\n\nexport default SecondaryPanelWrapper;\n","/**\n * ColorPanelWrapper - Animated wrapper for color picker secondary panels.\n *\n * Similar to SecondaryPanelWrapper but with minHeight: 0 on the inner\n * scroll container for proper color picker layout.\n */\n\nimport React from 'react';\n\nexport interface ColorPanelWrapperProps {\n /** Whether this panel is currently open/expanded */\n isOpen: boolean;\n /** The panel content to render inside the wrapper */\n children: React.ReactNode;\n}\n\nexport const ColorPanelWrapper: React.FC<ColorPanelWrapperProps> = ({ isOpen, children }) => {\n return (\n <div\n className=\"secondary-toolbar-panel-wrapper\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n flex: isOpen ? 1 : 0,\n minHeight: isOpen ? 0 : undefined,\n transition: 'flex 300ms cubic-bezier(0.32, 0.72, 0, 1)',\n }}\n >\n <div\n className={isOpen ? 'secondary-panel-scroll-container' : ''}\n style={{\n flex: 1,\n minHeight: 0,\n overflowY: isOpen ? undefined : 'hidden',\n overscrollBehaviorY: 'contain',\n WebkitOverflowScrolling: 'touch',\n transform: isOpen ? 'translateY(0)' : 'translateY(100%)',\n opacity: isOpen ? 1 : 0,\n transition: 'transform 300ms cubic-bezier(0.32, 0.72, 0, 1), opacity 200ms ease-out',\n }}\n >\n {children}\n </div>\n </div>\n );\n};\n\nexport default ColorPanelWrapper;\n","/**\n * EmbeddedToolbarLayout - Layout wrapper for embedded mode toolbar.\n *\n * Manages the height animation container, secondary panel wrappers,\n * and empty state display for embedded mode.\n */\n\nimport React from 'react';\nimport { SecondaryPanelWrapper } from './shared/SecondaryPanelWrapper.js';\nimport { ColorPanelWrapper } from './shared/ColorPanelWrapper.js';\n\nexport interface EmbeddedToolbarLayoutProps {\n /** The toolbar content (collapsed header + regular buttons) */\n toolbarContent: React.ReactNode;\n /** Inner content ref for height measurement */\n innerContentRef: React.RefObject<HTMLDivElement | null>;\n /** Whether the toolbar should be rendered */\n shouldRender: boolean;\n /** Whether exit animation is playing */\n isExiting: boolean;\n /** Explicit transition height (null = use CSS Grid) */\n transitionHeight: number | null;\n /** Empty state message content */\n emptyStateContent: React.ReactNode;\n\n // Panel open states\n isCornerRadiusPanelOpen: boolean;\n isCropPanelOpen: boolean;\n isRotationPanelOpen: boolean;\n isOpacityPanelOpen: boolean;\n isFontSizePanelOpen: boolean;\n isShapeCornerRadiusPanelOpen: boolean;\n isShapeTransparencyPanelOpen: boolean;\n isShapeSidesPanelOpen: boolean;\n isShapePointsPanelOpen: boolean;\n isShapeInnerRadiusPanelOpen: boolean;\n isShapeColorPanelOpen: boolean;\n isTextColorPanelOpen: boolean;\n isStrokePanelOpen: boolean;\n isKnockoutPanelOpen: boolean;\n isDistressTexturePanelOpen: boolean;\n isImageMaskPanelOpen: boolean;\n\n // Panel content\n cornerRadiusPanel: React.ReactNode;\n cropPanelContent: React.ReactNode;\n rotationPanel: React.ReactNode;\n opacityPanel: React.ReactNode;\n fontSizePanel: React.ReactNode;\n shapeCornerRadiusPanel: React.ReactNode;\n shapeTransparencyPanel: React.ReactNode;\n shapeSidesPanel: React.ReactNode;\n shapePointsPanel: React.ReactNode;\n shapeInnerRadiusPanel: React.ReactNode;\n shapeColorPanel: React.ReactNode;\n textColorPanel: React.ReactNode;\n strokePanel: React.ReactNode;\n knockoutPanel: React.ReactNode;\n distressTexturePanel: React.ReactNode;\n imageMaskPanel: React.ReactNode;\n}\n\nexport const EmbeddedToolbarLayout: React.FC<EmbeddedToolbarLayoutProps> = ({\n toolbarContent,\n innerContentRef,\n shouldRender,\n isExiting,\n transitionHeight,\n emptyStateContent,\n // Panel open states\n isCornerRadiusPanelOpen,\n isCropPanelOpen,\n isRotationPanelOpen,\n isOpacityPanelOpen,\n isFontSizePanelOpen,\n isShapeCornerRadiusPanelOpen,\n isShapeTransparencyPanelOpen,\n isShapeSidesPanelOpen,\n isShapePointsPanelOpen,\n isShapeInnerRadiusPanelOpen,\n isShapeColorPanelOpen,\n isTextColorPanelOpen,\n isStrokePanelOpen,\n isKnockoutPanelOpen,\n isDistressTexturePanelOpen,\n isImageMaskPanelOpen,\n // Panel content\n cornerRadiusPanel,\n cropPanelContent,\n rotationPanel,\n opacityPanel,\n fontSizePanel,\n shapeCornerRadiusPanel,\n shapeTransparencyPanel,\n shapeSidesPanel,\n shapePointsPanel,\n shapeInnerRadiusPanel,\n shapeColorPanel,\n textColorPanel,\n strokePanel,\n knockoutPanel,\n distressTexturePanel,\n imageMaskPanel,\n}) => {\n return (\n <div\n className=\"toolbar-embedded-wrapper\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n flex: 1,\n minHeight: 0, // Critical: allows flex children to shrink and enables nested scrolling\n overscrollBehaviorY: 'contain',\n }}\n >\n {/* Empty state when no element selected */}\n {emptyStateContent}\n\n <div\n className=\"toolbar-height-wrapper\"\n style={\n transitionHeight !== null\n ? {\n // During type transitions: use explicit height for direct height-to-height animation\n height: transitionHeight,\n overflow: 'hidden',\n transition: 'height 200ms cubic-bezier(0.22, 1, 0.36, 1)',\n }\n : {\n // Normal show/hide: use CSS Grid for 0fr/1fr animation\n display: 'grid',\n gridTemplateRows: shouldRender && !isExiting ? '1fr' : '0fr',\n transition: 'grid-template-rows 200ms cubic-bezier(0.22, 1, 0.36, 1)',\n }\n }\n >\n <div ref={innerContentRef}>{toolbarContent}</div>\n </div>\n\n {/* Corner radius panel */}\n <SecondaryPanelWrapper isOpen={isCornerRadiusPanelOpen}>{cornerRadiusPanel}</SecondaryPanelWrapper>\n\n {/* Crop panel */}\n <SecondaryPanelWrapper isOpen={isCropPanelOpen}>{cropPanelContent}</SecondaryPanelWrapper>\n\n {/* Rotation panel */}\n <SecondaryPanelWrapper isOpen={isRotationPanelOpen}>{rotationPanel}</SecondaryPanelWrapper>\n\n {/* Opacity panel */}\n <SecondaryPanelWrapper isOpen={isOpacityPanelOpen}>{opacityPanel}</SecondaryPanelWrapper>\n\n {/* Font size panel */}\n <SecondaryPanelWrapper isOpen={isFontSizePanelOpen}>{fontSizePanel}</SecondaryPanelWrapper>\n\n {/* Shape corner radius panel */}\n <SecondaryPanelWrapper isOpen={isShapeCornerRadiusPanelOpen}>\n {shapeCornerRadiusPanel}\n </SecondaryPanelWrapper>\n\n {/* Shape transparency panel */}\n <SecondaryPanelWrapper isOpen={isShapeTransparencyPanelOpen}>\n {shapeTransparencyPanel}\n </SecondaryPanelWrapper>\n\n {/* Shape sides panel (polygon) */}\n <SecondaryPanelWrapper isOpen={isShapeSidesPanelOpen}>{shapeSidesPanel}</SecondaryPanelWrapper>\n\n {/* Shape points panel (star) */}\n <SecondaryPanelWrapper isOpen={isShapePointsPanelOpen}>{shapePointsPanel}</SecondaryPanelWrapper>\n\n {/* Shape inner radius panel (star) */}\n <SecondaryPanelWrapper isOpen={isShapeInnerRadiusPanelOpen}>\n {shapeInnerRadiusPanel}\n </SecondaryPanelWrapper>\n\n {/* Shape fill color panel */}\n <ColorPanelWrapper isOpen={isShapeColorPanelOpen}>{shapeColorPanel}</ColorPanelWrapper>\n\n {/* Text font color panel */}\n <ColorPanelWrapper isOpen={isTextColorPanelOpen}>{textColorPanel}</ColorPanelWrapper>\n\n {/* Stroke panel */}\n <SecondaryPanelWrapper isOpen={isStrokePanelOpen}>{strokePanel}</SecondaryPanelWrapper>\n\n {/* Knockout panel */}\n <SecondaryPanelWrapper isOpen={isKnockoutPanelOpen}>{knockoutPanel}</SecondaryPanelWrapper>\n\n {/* Distress texture panel */}\n <SecondaryPanelWrapper isOpen={isDistressTexturePanelOpen}>{distressTexturePanel}</SecondaryPanelWrapper>\n\n {/* Image mask panel */}\n <SecondaryPanelWrapper isOpen={isImageMaskPanelOpen}>{imageMaskPanel}</SecondaryPanelWrapper>\n </div>\n );\n};\n\nexport default EmbeddedToolbarLayout;\n","/**\n * FloatingPanels - Secondary panels rendered in floating mode.\n *\n * These panels appear below the floating toolbar in a portal,\n * positioned relative to the toolbar's screen position.\n */\n\nimport React from 'react';\nimport { SliderRow } from '../ui/index.js';\nimport CropPanel from '../CropPanel.jsx';\nimport type { ImageElement } from '../../core/ImageElement.js';\n\nexport interface FloatingCornerRadiusPanelProps {\n toolbarPosition: { top: number; left: number };\n toolbarHeight: number;\n panelWidth: number;\n value: number;\n onChange: (value: number) => void;\n}\n\nexport const FloatingCornerRadiusPanel: React.FC<FloatingCornerRadiusPanelProps> = ({\n toolbarPosition,\n toolbarHeight,\n panelWidth,\n value,\n onChange,\n}) => (\n <div\n className=\"corner-radius-panel\"\n style={{\n position: 'fixed',\n top: `${toolbarPosition.top + toolbarHeight + 8}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateX(-50%)',\n padding: '12px 24px',\n marginTop: '-12px',\n borderRadius: 0,\n border: '1px solid var(--divider)',\n boxShadow: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',\n zIndex: 'var(--z-tooltip)',\n width: `${panelWidth}px`,\n boxSizing: 'border-box',\n }}\n >\n <SliderRow label=\"Radius\" value={value} onChange={onChange} min={0} max={50} unit=\"%\" />\n </div>\n);\n\nexport interface FloatingCropPanelProps {\n toolbarPosition: { top: number; left: number };\n toolbarHeight: number;\n element: ImageElement;\n onElementUpdate: (element: ImageElement) => void;\n}\n\nexport const FloatingCropPanel: React.FC<FloatingCropPanelProps> = ({\n toolbarPosition,\n toolbarHeight,\n element,\n onElementUpdate,\n}) => (\n <div\n className=\"crop-panel\"\n style={{\n position: 'fixed',\n top: `${toolbarPosition.top + toolbarHeight + 8}px`,\n left: `${toolbarPosition.left}px`,\n transform: 'translateX(-50%)',\n background: 'var(--background)',\n border: '1px solid var(--divider)',\n borderRadius: '12px',\n boxShadow: '0 4px 12px 0 rgb(0 0 0 / 0.15)',\n zIndex: 'var(--z-tooltip)',\n minWidth: '300px',\n }}\n >\n <CropPanel element={element} onElementUpdate={onElementUpdate} />\n </div>\n);\n","/**\n * documentColors — collect every colour actually in use in a design.\n *\n * Surfaced in the colour-picker dropdowns (\"Document colors\" /\n * \"Image colors\" rows) so users can match a colour they're already\n * using elsewhere in the artwork instead of eyeballing it.\n *\n * Two kinds of colours are exposed:\n *\n * - **Vector colours** (`collectDocumentColors`) — text colours,\n * rich-text span colours, shape fills, path fills, path strokes,\n * element-level stroke colours, and artboard background. Cheap,\n * synchronous read off the data model.\n *\n * - **Image colours** (`extractImagePalette` / `collectImageColors`) —\n * a small dominant-colour palette per image element. Async, requires\n * pixel access (the image must be CORS-loaded — see CLAUDE.md\n * \"CORS Cache Poisoning\"). Cached by URL.\n */\n\nimport type { BaseElement } from '../core/BaseElement.js';\nimport { TextElement } from '../core/TextElement.js';\nimport { ShapeElement } from '../core/ShapeElement.js';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { PathElement } from '../core/PathElement.js';\nimport type { ArtboardElement } from '../core/ArtboardElement.js';\n\nconst isPaintable = (c: unknown): c is string =>\n typeof c === 'string' && c.length > 0 && c !== 'transparent';\n\n/**\n * Walk one element and push every paint colour it carries into `out`.\n * Recurses into group children. Element-level stroke is only counted\n * when `stroke.enabled === true` so disabled-but-configured strokes\n * don't pollute the palette.\n */\nfunction collectFromElement(el: BaseElement, out: Set<string>): void {\n // Element-level stroke (StrokeConfig) — applies to text, image,\n // shape, group, path uniformly.\n const stroke = (el as { stroke?: { enabled?: boolean; color?: string } })\n .stroke;\n if (stroke?.enabled && isPaintable(stroke.color)) {\n out.add(stroke.color);\n }\n\n if (el instanceof TextElement) {\n if (isPaintable(el.color)) out.add(el.color);\n // Rich-text span colours — each per-character span can override\n // the element default. Skip undefined (means \"inherit element\n // colour\" — already added above).\n const richText = (el as { richText?: { spans?: Array<{ style?: { color?: string } }> } }).richText;\n if (richText?.spans) {\n for (const span of richText.spans) {\n if (isPaintable(span.style?.color)) out.add(span.style!.color!);\n }\n }\n return;\n }\n\n if (el instanceof ShapeElement) {\n const fill = el.transformData.fillColor;\n if (isPaintable(fill)) out.add(fill);\n return;\n }\n\n if (el instanceof PathElement) {\n const td = (el as PathElement).transformData;\n if (td.fillEnabled && isPaintable(td.fillColor)) out.add(td.fillColor);\n if (td.strokeEnabled && isPaintable(td.strokeColor)) out.add(td.strokeColor);\n return;\n }\n\n if (el instanceof GroupElement) {\n // Group itself doesn't paint — children do. Recurse.\n for (const child of el.children) {\n collectFromElement(child, out);\n }\n return;\n }\n\n // ImageElement contributes via image-palette extraction, not vector\n // colours.\n}\n\n/**\n * Collect every vector colour in the design. Synchronous.\n *\n * @param elements - Top-level elements (groups recurse internally)\n * @param artboards - Optional. When provided, `backgroundColor` from\n * each artboard is included (real exported background; the UI-only\n * `previewBackgroundColor` is intentionally skipped — it's the\n * shirt-colour preview, not part of the artwork).\n */\nexport function collectDocumentColors(\n elements: ReadonlyArray<BaseElement>,\n artboards?: ReadonlyArray<ArtboardElement>\n): Set<string> {\n const out = new Set<string>();\n for (const el of elements) collectFromElement(el, out);\n if (artboards) {\n for (const ab of artboards) {\n const bg = (ab as { backgroundColor?: string }).backgroundColor;\n if (isPaintable(bg)) out.add(bg);\n }\n }\n return out;\n}\n\n// ============================================================================\n// Image palette extraction\n// ============================================================================\n\nconst IMAGE_PALETTE_CACHE = new Map<string, string[]>();\nconst IMAGE_PALETTE_INFLIGHT = new Map<string, Promise<string[]>>();\n\ntype RGB = { r: number; g: number; b: number };\n\n/**\n * Median cut box — a region of RGB space holding some pixels plus\n * the per-channel ranges (cached so we can pick the longest axis\n * cheaply when deciding which axis to split next).\n */\ntype Box = {\n pixels: RGB[];\n rRange: number;\n gRange: number;\n bRange: number;\n};\n\nfunction computeRanges(pixels: RGB[]): { rRange: number; gRange: number; bRange: number } {\n if (pixels.length === 0) return { rRange: 0, gRange: 0, bRange: 0 };\n let rMin = 255, rMax = 0, gMin = 255, gMax = 0, bMin = 255, bMax = 0;\n for (const p of pixels) {\n if (p.r < rMin) rMin = p.r;\n if (p.r > rMax) rMax = p.r;\n if (p.g < gMin) gMin = p.g;\n if (p.g > gMax) gMax = p.g;\n if (p.b < bMin) bMin = p.b;\n if (p.b > bMax) bMax = p.b;\n }\n return { rRange: rMax - rMin, gRange: gMax - gMin, bRange: bMax - bMin };\n}\n\nfunction boxLongestAxis(box: Box): 'r' | 'g' | 'b' {\n const max = Math.max(box.rRange, box.gRange, box.bRange);\n if (box.rRange === max) return 'r';\n if (box.gRange === max) return 'g';\n return 'b';\n}\n\nfunction boxSize(box: Box): number {\n return Math.max(box.rRange, box.gRange, box.bRange);\n}\n\nfunction splitBox(box: Box): [Box, Box] {\n const axis = boxLongestAxis(box);\n // Sort by the longest axis so the median split actually balances\n // pixel count across the most-spread channel.\n const sorted = box.pixels.slice().sort((a, b) => a[axis] - b[axis]);\n const mid = sorted.length >> 1;\n const leftPixels = sorted.slice(0, mid);\n const rightPixels = sorted.slice(mid);\n return [\n { pixels: leftPixels, ...computeRanges(leftPixels) },\n { pixels: rightPixels, ...computeRanges(rightPixels) },\n ];\n}\n\nfunction averageColor(pixels: RGB[]): RGB {\n let r = 0, g = 0, b = 0;\n for (const p of pixels) {\n r += p.r;\n g += p.g;\n b += p.b;\n }\n const n = pixels.length;\n return {\n r: Math.round(r / n),\n g: Math.round(g / n),\n b: Math.round(b / n),\n };\n}\n\n/**\n * Median-cut quantisation, internal Box-returning variant. Recursively\n * splits the colour-space box with the largest spread until we reach\n * `targetBuckets`. Boxes are returned so callers that need the per-box\n * pixel population (e.g. for sorting before dedupe) can read it.\n */\nfunction medianCutBoxes(pixels: RGB[], targetBuckets: number): Box[] {\n if (pixels.length === 0) return [];\n const boxes: Box[] = [{ pixels, ...computeRanges(pixels) }];\n\n while (boxes.length < targetBuckets) {\n // Always split the box with the largest single-axis spread —\n // that's where we'll get the most colour diversity from one\n // additional bucket.\n let bestIdx = -1;\n let bestSize = 0;\n for (let i = 0; i < boxes.length; i++) {\n const size = boxSize(boxes[i]);\n if (size > bestSize && boxes[i].pixels.length >= 2) {\n bestSize = size;\n bestIdx = i;\n }\n }\n if (bestIdx === -1) break; // every remaining box is unsplittable\n const target = boxes[bestIdx];\n boxes.splice(bestIdx, 1);\n boxes.push(...splitBox(target));\n }\n\n return boxes;\n}\n\n/**\n * Median-cut quantisation. Returns the average colour of each box.\n *\n * Why this beats a frequency histogram for our use case: a frequency\n * histogram returns the most-populated buckets, which means a smooth\n * gradient (sunset reds spread across many adjacent buckets) loses\n * to a flat region (solid black sky) even when the gradient is the\n * visually salient subject. Median cut splits by *spread* in colour\n * space, so red, orange, and yellow each get their own bucket.\n *\n * @internal exported for tests\n */\nexport function medianCut(pixels: RGB[], targetBuckets: number): RGB[] {\n return medianCutBoxes(pixels, targetBuckets).map((box) => averageColor(box.pixels));\n}\n\n/**\n * Redmean ΔE — a cheap perceptual-distance approximation. Pure\n * Euclidean RGB distance treats (50,0,0) vs (0,0,50) as identical,\n * which is wrong because the eye is more sensitive to green than red\n * or blue. Redmean weights each channel by the average of the two\n * reds, which biases the metric toward perceived difference at low\n * cost. See https://www.compuphase.com/cmetric.htm.\n *\n * Returned distance is roughly comparable to a CIE-76 ΔE: ~25 means\n * \"noticeably different,\" ~50+ means \"obviously different.\"\n *\n * @internal exported for tests\n */\nexport function redmeanDistance(a: RGB, b: RGB): number {\n const rMean = (a.r + b.r) / 2;\n const dr = a.r - b.r;\n const dg = a.g - b.g;\n const db = a.b - b.b;\n return Math.sqrt(\n (2 + rMean / 256) * dr * dr +\n 4 * dg * dg +\n (2 + (255 - rMean) / 256) * db * db\n );\n}\n\n/**\n * Drop palette entries that are visually indistinguishable from one\n * we already kept. Walks in input order, so callers should pre-sort\n * by importance (we sort by population — bigger boxes first — so\n * the most-prominent shade in a \"near-duplicate\" cluster wins).\n *\n * @internal exported for tests\n */\nexport function dedupeByPerceptualDistance(\n palette: RGB[],\n threshold: number\n): RGB[] {\n const out: RGB[] = [];\n for (const c of palette) {\n let dup = false;\n for (const kept of out) {\n if (redmeanDistance(c, kept) <= threshold) {\n dup = true;\n break;\n }\n }\n if (!dup) out.push(c);\n }\n return out;\n}\n\n/**\n * Pick a diverse palette from a population-sorted candidate list via\n * furthest-point sampling. The first candidate is taken as the anchor\n * (most populous). Each subsequent pick maximises the minimum redmean\n * distance to every already-picked colour, so the row spans the image's\n * actual colour variation instead of N shades of whatever hue dominates.\n *\n * Candidates closer than `threshold` to an already-picked colour are\n * skipped — that's the dedupe step folded into the same pass. Stops\n * when there are no further candidates above the threshold.\n *\n * @internal exported for tests\n */\nexport function furthestPointPalette(\n candidates: RGB[],\n paletteSize: number,\n threshold: number\n): RGB[] {\n if (candidates.length === 0 || paletteSize <= 0) return [];\n const picked: RGB[] = [candidates[0]];\n const used = new Set<number>([0]);\n while (picked.length < paletteSize) {\n let bestIdx = -1;\n let bestMinDist = -1;\n for (let i = 1; i < candidates.length; i++) {\n if (used.has(i)) continue;\n let minDist = Infinity;\n for (const p of picked) {\n const d = redmeanDistance(candidates[i], p);\n if (d < minDist) minDist = d;\n }\n if (minDist > bestMinDist) {\n bestMinDist = minDist;\n bestIdx = i;\n }\n }\n if (bestIdx === -1 || bestMinDist <= threshold) break;\n picked.push(candidates[bestIdx]);\n used.add(bestIdx);\n }\n return picked;\n}\n\nconst toHex = (n: number) => n.toString(16).padStart(2, '0');\nfunction rgbToHex(c: RGB): string {\n return `#${toHex(c.r)}${toHex(c.g)}${toHex(c.b)}`;\n}\n\n/**\n * Extract up to `paletteSize` dominant colours from an image URL.\n *\n * Implementation:\n * 1. Draw the image into a small offscreen canvas (48×48). Smaller\n * than the source, but enough resolution for dominant colours\n * and *much* faster than walking the full image.\n * 2. Sample every pixel; skip fully-transparent and near-white\n * (background swamps the palette and isn't useful for matching).\n * 3. Run median cut to produce ~2× the requested palette size\n * (gives dedupe headroom).\n * 4. Sort by box population so visually-prominent shades come first\n * within near-duplicate clusters.\n * 5. Drop near-duplicates by redmean-weighted ΔE — without this\n * step a photo with a big black region returns 3 indistinguishable\n * blacks instead of black + the actual subject colours.\n * 6. Truncate to `paletteSize`.\n *\n * Cached per URL in module-scope (cache survives component unmount;\n * wiped on hard reload).\n *\n * Requires `crossOrigin=\"anonymous\"` on the source image. If the\n * image is CORS-tainted, `getImageData` throws and we cache an empty\n * array. Per CLAUDE.md \"CORS Cache Poisoning\" all canvas images\n * already set this.\n */\nexport async function extractImagePalette(\n imageUrl: string,\n paletteSize = 5\n): Promise<string[]> {\n if (!imageUrl) return [];\n const cached = IMAGE_PALETTE_CACHE.get(imageUrl);\n if (cached) return cached;\n const inflight = IMAGE_PALETTE_INFLIGHT.get(imageUrl);\n if (inflight) return inflight;\n\n const promise = (async (): Promise<string[]> => {\n try {\n const img = await loadCorsImage(imageUrl);\n const SAMPLE = 48; // 48×48 = 2304 pixels — plenty for dominant colours.\n const canvas = typeof OffscreenCanvas !== 'undefined'\n ? new OffscreenCanvas(SAMPLE, SAMPLE)\n : (() => {\n const c = document.createElement('canvas');\n c.width = SAMPLE;\n c.height = SAMPLE;\n return c;\n })();\n const ctx = (canvas as HTMLCanvasElement | OffscreenCanvas)\n .getContext('2d') as\n | CanvasRenderingContext2D\n | OffscreenCanvasRenderingContext2D\n | null;\n if (!ctx) return [];\n ctx.drawImage(img, 0, 0, SAMPLE, SAMPLE);\n const { data } = ctx.getImageData(0, 0, SAMPLE, SAMPLE);\n\n const pixels: RGB[] = [];\n for (let i = 0; i < data.length; i += 4) {\n const a = data[i + 3];\n if (a < 128) continue; // skip transparent\n const r = data[i];\n const g = data[i + 1];\n const b = data[i + 2];\n // Skip near-white pixels — typical background.\n if (r > 240 && g > 240 && b > 240) continue;\n pixels.push({ r, g, b });\n }\n if (pixels.length === 0) {\n IMAGE_PALETTE_CACHE.set(imageUrl, []);\n return [];\n }\n\n // Over-extract aggressively so diversity selection has lots of\n // candidates to choose from. Without this, photos dominated by\n // one hue (e.g. green leaves) fill every box with a slight\n // variant of that hue and a visually-prominent minority colour\n // (gold accents on a green background) never makes it into the\n // candidate pool.\n const overExtract = Math.max(paletteSize * 4, 16);\n const boxes = medianCutBoxes(pixels, overExtract);\n // Sort by population so the biggest cluster's average wins\n // as our anchor for furthest-point sampling.\n boxes.sort((a, b) => b.pixels.length - a.pixels.length);\n\n const candidates = boxes.map((box) => averageColor(box.pixels));\n // Furthest-point sampling: pick the most populous colour as the\n // anchor, then each subsequent pick is the candidate with the\n // largest minimum redmean distance to everything already picked.\n // This serves two goals at once — drops perceptually-indistinct\n // near-duplicates (via the threshold cutoff) AND surfaces\n // visually-salient minority colours that pure population-sort\n // would push out of the top-N slice. Threshold tuned against\n // the sunset failure case: (8,8,8) and (24,24,24) sit ~48\n // redmean apart and should collapse into one swatch.\n // Tradeoff: subtle gradients (deep-red vs red, ~33 apart)\n // collapse — but for a \"match a colour in your design\" picker\n // that's the right call. Five obviously-different swatches beats\n // five shades-of-the-same-thing, AND gold on a green photo\n // actually appears in the row.\n const top = furthestPointPalette(candidates, paletteSize, 50).map(rgbToHex);\n\n IMAGE_PALETTE_CACHE.set(imageUrl, top);\n return top;\n } catch {\n // CORS taint, decode failure, etc. Cache empty result so we\n // don't re-attempt every render.\n IMAGE_PALETTE_CACHE.set(imageUrl, []);\n return [];\n } finally {\n IMAGE_PALETTE_INFLIGHT.delete(imageUrl);\n }\n })();\n IMAGE_PALETTE_INFLIGHT.set(imageUrl, promise);\n return promise;\n}\n\nfunction loadCorsImage(url: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image();\n // CORS attr MUST be set before src — see CLAUDE.md gotcha #13.\n img.crossOrigin = 'anonymous';\n img.onload = () => resolve(img);\n img.onerror = () => reject(new Error(`Failed to load image: ${url}`));\n img.src = url;\n });\n}\n\n/**\n * Walk every ImageElement (recursing into groups), pull the unique\n * URLs, extract a small palette per image, and return the deduped\n * union. Order is \"first image first, top-N per image\" so the row\n * has predictable colours. Returns [] if no images.\n */\nexport async function collectImageColors(\n elements: ReadonlyArray<BaseElement>,\n paletteSize = 5\n): Promise<string[]> {\n const urls: string[] = [];\n const seen = new Set<string>();\n const visit = (el: BaseElement) => {\n if (el instanceof ImageElement) {\n const url = el.imageUrl;\n if (url && !seen.has(url)) {\n seen.add(url);\n urls.push(url);\n }\n } else if (el instanceof GroupElement) {\n for (const c of el.children) visit(c);\n }\n };\n for (const el of elements) visit(el);\n if (urls.length === 0) return [];\n\n const palettes = await Promise.all(\n urls.map((u) => extractImagePalette(u, paletteSize))\n );\n const out: string[] = [];\n const dedupe = new Set<string>();\n for (const palette of palettes) {\n for (const c of palette) {\n if (!dedupe.has(c)) {\n dedupe.add(c);\n out.push(c);\n }\n }\n }\n return out;\n}\n\n/**\n * Test-only: clear the in-memory palette caches so unit tests start\n * from a known state.\n * @internal\n */\nexport function _resetImagePaletteCache(): void {\n IMAGE_PALETTE_CACHE.clear();\n IMAGE_PALETTE_INFLIGHT.clear();\n}\n","/**\n * ContextualToolbars - Renders the appropriate toolbar for the selected element type.\n *\n * Dispatches to element-specific toolbars (text, image, shape, path, artboard)\n * based on the current selection in `EditorContext`. Also manages expanded\n * sub-panels (crop, corner radius, effects, rotation) and floating overlays.\n *\n * Place anywhere inside an `EditorProvider` -- it reads selection state from context.\n *\n * @example\n * ```tsx\n * <EditorProvider>\n * <Canvas />\n * <ContextualToolbars />\n * </EditorProvider>\n * ```\n */\n\nimport React, { useState, useCallback, useEffect, useLayoutEffect, useRef, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useEditor } from '../contexts/EditorContext.js';\nimport { useViewportContext } from '../contexts/ViewportContext.js';\nimport { useSelectionContext } from '../contexts/SelectionContext.js';\nimport { useToolStateContext } from '../contexts/ToolStateContext.js';\nimport BackButton from './BackButton.jsx';\nimport ImageToolbar from './ImageToolbar.jsx';\nimport ShapeToolbar from './ShapeToolbar.jsx';\nimport ShapeTypeDrawer from './ShapeTypeDrawer.jsx';\nimport PathToolbar from './PathToolbar.jsx';\nimport ArtboardPropertiesToolbar from './ArtboardPropertiesToolbar.jsx';\nimport { TextToolbar } from './TextToolbar.js';\nimport { useTextToolbar } from '../hooks/useTextToolbar.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { ShapeElement } from '../core/ShapeElement.js';\nimport { PathElement } from '../core/PathElement.js';\nimport { CollapsedToolbarHeader, icons } from './ui';\nimport { LayerLeadingChip } from './LayerLeadingChip.js';\nimport {\n GroupElementToolbar,\n ExpandedPanelIcon,\n EmbeddedToolbarLayout,\n FloatingCornerRadiusPanel,\n FloatingCropPanel,\n CornerRadiusPanel,\n RotationPanel,\n OpacityPanel,\n FontSizePanel,\n ShapeCornerRadiusPanel,\n ShapeTransparencyPanel,\n ShapeSidesPanel,\n ShapePointsPanel,\n ShapeInnerRadiusPanel,\n ShapeColorPanel,\n TextColorPanel,\n CompositingPanel,\n StrokePanel,\n CropPanelContent,\n DistressTexturePanel,\n ImageMaskPanel,\n} from './toolbars/index.js';\nimport type { CompositingMode } from './toolbars/SecondaryPanels.js';\nimport type { CompositingScope } from '../types/index.js';\nimport ArtboardDistressPanel from './ArtboardDistressPanel.jsx';\nimport ArtboardImageMaskPanel from './ArtboardImageMaskPanel.jsx';\nimport { createLogger } from '../utils/logger.js';\nimport { collectDocumentColors, collectImageColors } from '../utils/documentColors.js';\n\nconst logger = createLogger('ContextualToolbars');\n\ntype MenuType = 'root' | 'transforms' | 'align' | 'color';\ntype DropdownType = 'fontSize' | 'fontFamily' | null;\n\n/** Panel configuration for collapsed header */\ntype ExpandedPanelConfig = {\n type:\n | 'cornerRadius'\n | 'effects'\n | 'crop'\n | 'rotation'\n | 'opacity'\n | 'fontSize'\n | 'shapeCornerRadius'\n | 'shapeTransparency'\n | 'shapeSides'\n | 'shapePoints'\n | 'shapeInnerRadius'\n | 'shapeColor'\n | 'textColor'\n | 'stroke'\n | 'compositing'\n | 'distressTexture'\n | 'imageMask';\n icon: string | React.ReactNode;\n label: string;\n} | null;\n\nexport interface ContextualToolbarsProps {\n /**\n * Positioning mode for the toolbar\n * - 'floating': Positioned relative to selected element (default)\n * - 'embedded': Static positioning for embedding in a container\n */\n mode?: 'floating' | 'embedded';\n\n /**\n * @deprecated Effects panel drawer has been replaced by inline secondary panels.\n * Stroke, masks, distress, and knockout are now accessible directly from the toolbar.\n */\n onOpenEffectsPanel?: () => void;\n\n /**\n * Callback when glyph browser should be opened\n */\n onOpenGlyphBrowser?: () => void;\n\n /**\n * Callback when image should be changed\n */\n onChangeImage?: () => void;\n\n /**\n * Callback when shape type drawer should be opened\n */\n onOpenShapeTypeDrawer?: () => void;\n\n /**\n * Document colors for color picker\n */\n documentColors?: Set<string>;\n\n /**\n * Current viewport width for responsive behavior\n */\n viewportWidth?: number;\n\n /**\n * Responsive breakpoints for layout\n * - full: All controls visible (default: 1024)\n * - compact: Some controls in overflow menu (default: 768)\n * - minimal: Only essential controls, rest in overflow (default: 480)\n */\n breakpoints?: {\n full?: number;\n compact?: number;\n minimal?: number;\n };\n\n /**\n * Whether element has glyphs available\n */\n hasGlyphs?: boolean;\n\n /**\n * Callback to get more menu items for text elements\n */\n getMoreMenuItems?: () => Array<{ label: string; onClick: () => void; icon: React.ReactNode; active?: boolean }>;\n\n /**\n * Callback when artboard is updated\n */\n onArtboardUpdate?: (artboardId: string, oldProps: Record<string, unknown>, newProps: Record<string, unknown>) => void;\n\n /**\n * Artboard screen bounds for positioning toolbars\n */\n artboardScreenBounds?: {\n left: number;\n top: number;\n width: number;\n height: number;\n bottom: number;\n centerX: number;\n };\n\n /**\n * Maximum width for the toolbar. When set, enables flex-wrap for multi-row layout.\n * Can be a number (pixels) or a CSS string (e.g., '100%', '400px').\n */\n maxWidth?: number | string;\n\n /**\n * When true, removes the toolbar background, border, and shadow for a transparent look.\n * Useful when embedding in a custom UI where you want only the controls visible.\n */\n transparent?: boolean;\n\n /**\n * Callback when a secondary panel is expanded or collapsed.\n * Useful for styling the container as a bottom drawer when panels are visible.\n */\n onPanelExpandChange?: (expanded: boolean) => void;\n\n /**\n * Default expanded panel type. Used to open a specific panel on mount.\n * Useful when rendering in a drawer that needs to show a specific panel.\n */\n defaultExpandedPanel?: 'cornerRadius' | 'effects' | 'crop' | 'rotation' | null;\n\n /**\n * Callback when expanded panel changes, passing the panel type.\n * Useful for tracking which specific panel is expanded.\n */\n onExpandedPanelTypeChange?: (panelType: 'cornerRadius' | 'effects' | 'crop' | 'rotation' | null) => void;\n\n /**\n * Callback when crop drawer should be opened.\n * When provided, clicking the crop button will call this instead of showing inline panel.\n * Use this to render the crop controls in a drawer in the parent component.\n */\n onOpenCropDrawer?: () => void;\n\n /**\n * Callback when corner radius drawer should be opened.\n * When provided, clicking the corner radius button will call this instead of showing inline panel.\n * Use this to render the corner radius controls in a drawer in the parent component.\n */\n onOpenCornerRadiusDrawer?: () => void;\n\n /**\n * Style for the close button in expanded panel headers.\n * - 'icon': Shows X icon (default)\n * - 'done': Shows \"Done\" text button\n */\n closeButtonStyle?: 'icon' | 'done';\n\n /**\n * Message to display when no element is selected (embedded mode only).\n * Set to null to hide the empty state completely.\n * Default: \"Tap an element to select and edit\"\n */\n emptyStateMessage?: string | null;\n\n /**\n * Custom content to render when no element is selected (embedded mode only).\n * Replaces the default emptyStateMessage text. Use for live mockup previews, etc.\n */\n emptyStateRender?: React.ReactNode;\n\n /**\n * When true and no element is selected, shows artboard distress panel\n * in the empty state slot (embedded mode only).\n */\n editArtboardMode?: boolean;\n\n /**\n * Called when artboard edit mode should change (e.g. dismissed by selecting\n * an element or clicking the \"Done\" button).\n */\n onEditArtboardModeChange?: (active: boolean) => void;\n\n /**\n * Called when the leading layer thumbnail in the toolbar is clicked.\n * Typical wiring: open the host app's \"Manage Layers\" drawer with\n * the currently-selected layer focused. The selected layer is\n * already tracked by EditorContext so the drawer's `LayersPanel`\n * will highlight the right row automatically.\n *\n * When omitted, the thumbnail is non-interactive (just a visual\n * indicator of the selection).\n */\n onLayerThumbnailClick?: () => void;\n}\n\nexport const ContextualToolbars: React.FC<ContextualToolbarsProps> = ({\n mode = 'floating',\n onOpenGlyphBrowser,\n onChangeImage,\n onOpenShapeTypeDrawer,\n documentColors = new Set(),\n viewportWidth = window.innerWidth,\n breakpoints: _breakpoints = {},\n hasGlyphs = false,\n getMoreMenuItems,\n onArtboardUpdate,\n artboardScreenBounds,\n maxWidth,\n transparent = false,\n onPanelExpandChange,\n defaultExpandedPanel,\n onExpandedPanelTypeChange,\n onOpenCropDrawer,\n onOpenCornerRadiusDrawer,\n closeButtonStyle = 'icon',\n emptyStateMessage = 'Tap an element to select and edit',\n emptyStateRender,\n editArtboardMode = false,\n onEditArtboardModeChange,\n onLayerThumbnailClick,\n}) => {\n // ── Focused sub-contexts ────────────────────────────────────────────────\n // Use sub-context hooks to avoid re-renders from unrelated state changes.\n const { panOffset } = useViewportContext();\n const { multiSelection, setSelectedId } = useSelectionContext();\n const {\n expandedPanelType: contextExpandedPanelType,\n setExpandedPanelType: setContextExpandedPanelType,\n setIsToolbarMenuOpen,\n isRotating,\n } = useToolStateContext();\n\n // ── Editor context (core state not available in sub-contexts) ──────────\n const {\n elements,\n selectedElement,\n activeChildElement,\n handleElementUpdate,\n artboardManager,\n artboards,\n canvasEditorRef,\n canvasRef,\n executeRemoveElement,\n executeAddElement,\n executeReorderElement,\n refreshArtboards,\n } = useEditor();\n\n // ── Text toolbar hook ───────────────────────────────────────────────────\n const textToolbar = useTextToolbar({ canvasEditorRef });\n\n // ── Local state ─────────────────────────────────────────────────────────\n const [activeMenu, setActiveMenu] = useState<MenuType>('root');\n const [openDropdown, setOpenDropdown] = useState<DropdownType>(null);\n const [toolbarPosition, setToolbarPosition] = useState<{ top: number; left: number } | null>(null);\n const [_isDragging, setIsDragging] = useState<boolean>(false);\n const [isTransformMenuOpen, setIsTransformMenuOpen] = useState<boolean>(false);\n const [isColorPickerOpen] = useState<boolean>(false);\n const [isTextMoreMenuOpen, setIsTextMoreMenuOpen] = useState<boolean>(false);\n const [isShapeTypeDrawerOpen, setIsShapeTypeDrawerOpen] = useState<boolean>(false);\n\n // ── Expanded panel state ────────────────────────────────────────────────\n const [expandedPanel, setExpandedPanel] = useState<ExpandedPanelConfig>(() => {\n if (!defaultExpandedPanel) return null;\n const panelConfigs: Record<string, ExpandedPanelConfig> = {\n cornerRadius: { type: 'cornerRadius', icon: 'lucide:square-round-corner', label: 'Corner Radius' },\n crop: { type: 'crop', icon: 'lucide:crop', label: 'Crop' },\n rotation: { type: 'rotation', icon: icons.rotateLeft, label: 'Rotate' },\n opacity: { type: 'opacity', icon: 'lucide:blend', label: 'Transparency' },\n effects: { type: 'effects', icon: 'lucide:sparkles', label: 'Effects' },\n };\n return panelConfigs[defaultExpandedPanel] || null;\n });\n\n // ── Animation states ────────────────────────────────────────────────────\n const [isEntering, setIsEntering] = useState<boolean>(false);\n const [isExiting, setIsExiting] = useState<boolean>(false);\n const [shouldRender, setShouldRender] = useState<boolean>(false);\n const [isWaitingForPosition, setIsWaitingForPosition] = useState<boolean>(false);\n const [positionedElementId, setPositionedElementId] = useState<string | null>(null);\n const [transitionHeight, setTransitionHeight] = useState<number | null>(null);\n const [toolbarDimensions, setToolbarDimensions] = useState({ width: 0, height: 0 });\n\n // ── Refs ────────────────────────────────────────────────────────────────\n const toolbarRef = useRef<HTMLDivElement>(null);\n const innerContentRef = useRef<HTMLDivElement>(null);\n const lastKnownHeightRef = useRef<number>(0);\n const prevShouldShowRef = useRef<boolean>(false);\n const isMouseDownRef = useRef<boolean>(false);\n const frozenPositionRef = useRef<{ top: number; left: number } | null>(null);\n const lastElementRotationRef = useRef<number | undefined>(undefined);\n const lastSyncedToContextRef = useRef<string | null>(null);\n const prevContextExpandedPanelTypeRef = useRef(contextExpandedPanelType);\n const prevSelectedIdRef = useRef<string | undefined>(undefined);\n const prevElementTypeRef = useRef<string | undefined>(undefined);\n const prevIsRotatingRef = useRef<boolean>(false);\n const isRotatingRef = useRef<boolean>(false);\n const isDrawerModeAtMount = useRef(!!defaultExpandedPanel);\n const isFullyMountedRef = useRef(false);\n const expandedPanelRef = useRef(expandedPanel);\n const elementForPropertiesRef = useRef<EditorElement | null>(null);\n const elementUpdateHandlerRef = useRef<(el: EditorElement) => void>(() => {});\n const prevStableSelectedIdRef = useRef<string | undefined>(undefined);\n const prevIsCroppingRef = useRef<boolean | undefined>(undefined);\n\n // Keep isRotatingRef current on every render so stale-closure handlers can read it\n isRotatingRef.current = isRotating;\n\n // ── Derived state ───────────────────────────────────────────────────────\n const elementForProperties = activeChildElement || selectedElement;\n const stableElementId = elementForProperties?.id;\n const stableSelectedId = selectedElement?.id;\n const currentElementType = elementForProperties?.transformType;\n const { fontColor, getEffectiveStyle, handleFontColorChange } = textToolbar;\n const shouldShowToolbar = !!(selectedElement && !isRotating);\n\n // ── Element update handler ──────────────────────────────────────────────\n const elementUpdateHandler = useCallback(\n (updatedElement: EditorElement) => {\n if (!selectedElement) return;\n if (activeChildElement) {\n const groupElement = selectedElement as GroupElement;\n const updatedGroup = groupElement.clone() as GroupElement;\n const childIndex = updatedGroup.children.findIndex((c) => c.id === activeChildElement.id);\n if (childIndex !== -1) {\n updatedGroup.children[childIndex] = updatedElement;\n handleElementUpdate(updatedGroup);\n }\n } else {\n handleElementUpdate(updatedElement);\n }\n },\n [selectedElement, activeChildElement, handleElementUpdate]\n );\n\n // ── Image border radius handler ────────────────────────────────────────\n const handleBorderRadiusChange = useCallback(\n (value: number) => {\n if (!elementForProperties || elementForProperties.transformType !== 'image') return;\n const updatedElement = (elementForProperties as ImageElement).clone();\n updatedElement.transformData.borderRadius = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // ── Shape property change handlers ─────────────────────────────────────\n const handleShapeBorderRadiusChange = useCallback(\n (value: number) => {\n if (!elementForProperties || elementForProperties.transformType !== 'shape') return;\n const updatedElement = (elementForProperties as ShapeElement).clone();\n updatedElement.transformData.borderRadius = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleShapeOpacityChange = useCallback(\n (value: number) => {\n if (!elementForProperties || elementForProperties.transformType !== 'shape') return;\n const updatedElement = (elementForProperties as ShapeElement).clone();\n updatedElement.transformData.fillOpacity = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleShapeSidesChange = useCallback(\n (value: number) => {\n if (!elementForProperties || elementForProperties.transformType !== 'shape') return;\n const updatedElement = (elementForProperties as ShapeElement).clone();\n updatedElement.transformData.sides = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleShapePointsChange = useCallback(\n (value: number) => {\n if (!elementForProperties || elementForProperties.transformType !== 'shape') return;\n const updatedElement = (elementForProperties as ShapeElement).clone();\n updatedElement.transformData.points = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleShapeInnerRadiusChange = useCallback(\n (value: number) => {\n if (!elementForProperties || elementForProperties.transformType !== 'shape') return;\n const updatedElement = (elementForProperties as ShapeElement).clone();\n updatedElement.transformData.innerRadius = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleShapeFillColorChange = useCallback(\n (color: string) => {\n if (!elementForProperties || elementForProperties.transformType !== 'shape') return;\n const updatedElement = (elementForProperties as ShapeElement).clone();\n updatedElement.transformData.fillColor = color;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // ── Panel toggle handlers ──────────────────────────────────────────────\n const handleCornerRadiusToggle = useCallback(() => {\n if (onOpenCornerRadiusDrawer) {\n onOpenCornerRadiusDrawer();\n } else {\n setExpandedPanel((prev) =>\n prev?.type === 'cornerRadius'\n ? null\n : { type: 'cornerRadius', icon: 'lucide:square-round-corner', label: 'Corner Radius' }\n );\n }\n }, [onOpenCornerRadiusDrawer]);\n\n const handleCropToggle = useCallback(() => {\n if (onOpenCropDrawer) {\n onOpenCropDrawer();\n } else {\n setExpandedPanel((prev) => (prev?.type === 'crop' ? null : { type: 'crop', icon: 'lucide:crop', label: 'Crop' }));\n }\n }, [onOpenCropDrawer]);\n\n const handleRotationToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'rotation' ? null : { type: 'rotation', icon: icons.rotateLeft, label: 'Rotate' }\n );\n }, []);\n\n const handleOpacityToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'opacity' ? null : { type: 'opacity', icon: 'lucide:blend', label: 'Transparency' }\n );\n }, []);\n\n const handleFontSizeToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'fontSize' ? null : { type: 'fontSize', icon: 'lucide:type', label: 'Font Size' }\n );\n }, []);\n\n // Text-box width handler. Custom text and transformed text (wave,\n // arch, etc.) store their bounding-box width on `transformData.width`\n // — the same field the resize handle writes. Updating it from the\n // slider is just a clone + assign, routed through `elementUpdateHandler`\n // so the change lands in undo/redo.\n const handleTextWidthChange = useCallback(\n (next: number) => {\n if (!elementForProperties) return;\n const td = elementForProperties.transformData as { width?: number } | undefined;\n if (!td || td.width === undefined) return;\n const updated = elementForProperties.clone();\n (updated.transformData as { width: number }).width = next;\n elementUpdateHandler(updated);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // Read current text-box width if the element exposes one. Used to\n // drive the width slider in the font-size panel.\n const currentTextWidth =\n (elementForProperties?.transformData as { width?: number } | undefined)?.width ?? null;\n\n const handleShapeCornerRadiusToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'shapeCornerRadius'\n ? null\n : { type: 'shapeCornerRadius', icon: 'lucide:square-round-corner', label: 'Corner Radius' }\n );\n }, []);\n\n const handleShapeTransparencyToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'shapeTransparency'\n ? null\n : { type: 'shapeTransparency', icon: 'lucide:blend', label: 'Transparency' }\n );\n }, []);\n\n const handleShapeSidesToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'shapeSides' ? null : { type: 'shapeSides', icon: 'lucide:hexagon', label: 'Sides' }\n );\n }, []);\n\n const handleShapePointsToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'shapePoints' ? null : { type: 'shapePoints', icon: 'lucide:star', label: 'Points' }\n );\n }, []);\n\n const handleShapeInnerRadiusToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'shapeInnerRadius'\n ? null\n : { type: 'shapeInnerRadius', icon: 'lucide:circle-dashed', label: 'Inner Radius' }\n );\n }, []);\n\n const handleShapeColorToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'shapeColor' ? null : { type: 'shapeColor', icon: 'lucide:paint-bucket', label: 'Fill Color' }\n );\n }, []);\n\n const handleTextColorToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'textColor' ? null : { type: 'textColor', icon: icons.palette, label: 'Font Color' }\n );\n }, []);\n\n const handleCompositingToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'compositing' ? null : { type: 'compositing', icon: 'lucide:scissors', label: 'Clip / Knockout' }\n );\n }, []);\n\n const handleDistressTextureToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'distressTexture'\n ? null\n : { type: 'distressTexture', icon: 'lucide:stamp', label: 'Distress Texture' }\n );\n }, []);\n\n const handleImageMaskToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'imageMask'\n ? null\n : { type: 'imageMask', icon: 'lucide:venetian-mask', label: 'Image Mask' }\n );\n }, []);\n\n const handleStrokeToggle = useCallback(() => {\n setExpandedPanel((prev) =>\n prev?.type === 'stroke'\n ? null\n : { type: 'stroke', icon: 'lucide:pen-line', label: 'Stroke' }\n );\n }, []);\n\n const handleCloseExpandedPanel = useCallback(() => {\n if (expandedPanel?.type === 'crop' && elementForProperties?.transformType === 'image') {\n const imageElement = elementForProperties as ImageElement;\n if (imageElement.isCropping) {\n const updatedElement = imageElement.clone();\n updatedElement.exitCropMode();\n elementUpdateHandler(updatedElement);\n }\n }\n setExpandedPanel(null);\n }, [expandedPanel, elementForProperties, elementUpdateHandler]);\n\n // ── Layer ordering handlers ────────────────────────────────────────────\n const handleMoveForward = useCallback(() => {\n if (!selectedElement) return;\n const idx = elements.findIndex((e) => e.id === selectedElement.id);\n if (idx < elements.length - 1) {\n const targetElement = elements[idx + 1];\n executeReorderElement(selectedElement.id, targetElement.id, 'after');\n }\n }, [selectedElement, elements, executeReorderElement]);\n\n const handleMoveBackward = useCallback(() => {\n if (!selectedElement) return;\n const idx = elements.findIndex((e) => e.id === selectedElement.id);\n if (idx > 0) {\n const targetElement = elements[idx - 1];\n executeReorderElement(selectedElement.id, targetElement.id, 'before');\n }\n }, [selectedElement, elements, executeReorderElement]);\n\n const handleDeleteElement = useCallback(() => {\n const elementToDelete = activeChildElement || selectedElement;\n // Locked elements ARE deletable — locking gates manipulation\n // (drag/resize/rotate), not removal.\n if (!elementToDelete) return;\n executeRemoveElement(elementToDelete);\n setSelectedId(null);\n }, [activeChildElement, selectedElement, executeRemoveElement, setSelectedId]);\n\n // Lock / unlock toggle for the leading chip in the toolbar. Operates\n // on `elementForProperties` so a focused group child gets locked\n // (not the parent group) — `elementUpdateHandler` already routes the\n // updated child back through the group when needed.\n const handleToggleLock = useCallback(() => {\n if (!elementForProperties) return;\n const next = elementForProperties.clone();\n next.locked = !elementForProperties.locked;\n elementUpdateHandler(next);\n }, [elementForProperties, elementUpdateHandler]);\n\n const handleUngroupElement = useCallback(() => {\n if (!selectedElement || selectedElement.transformType !== 'group') return;\n const group = selectedElement as GroupElement;\n if (!group.children || group.children.length === 0) return;\n\n const artboardId = artboardManager.getArtboardIdForElement(group.id);\n if (!artboardId) return;\n\n const extractedChildren = group.children.map(child => {\n const clone = child.clone();\n clone.x = child.x + group.x;\n clone.y = child.y + group.y;\n return clone;\n });\n\n executeRemoveElement(group);\n extractedChildren.forEach(child => executeAddElement(child, artboardId));\n\n setSelectedId(extractedChildren.length > 0 ? extractedChildren[0].id : null);\n }, [selectedElement, artboardManager, executeRemoveElement, executeAddElement, setSelectedId]);\n\n // ── Rotation / opacity handlers (before multiSelection early return) ──\n const handleRotationChange = useCallback(\n (value: number) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n updatedElement.rotation = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleRotate90 = useCallback(() => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n let newRotation = Math.floor(updatedElement.rotation / 90) * 90 + 90;\n newRotation = ((newRotation % 360) + 360) % 360;\n if (newRotation > 180) {\n newRotation -= 360;\n }\n updatedElement.rotation = newRotation;\n elementUpdateHandler(updatedElement);\n }, [elementForProperties, elementUpdateHandler]);\n\n const handleOpacityChange = useCallback(\n (value: number) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n updatedElement.opacity = value;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // ── Compositing handlers (Clip / Knockout) ───────────────────────────\n const handleCompositingModeChange = useCallback(\n (mode: CompositingMode) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n updatedElement.blendMode = mode;\n if (!updatedElement.knockoutParts) {\n updatedElement.knockoutParts = { fill: true, scope: 'group' };\n }\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleCompositingFillChange = useCallback(\n (fill: boolean) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n const currentMode = updatedElement.blendMode === 'clip' ? 'clip' : 'knockout';\n const newParts = { ...updatedElement.knockoutParts, fill };\n updatedElement.knockoutParts = newParts;\n updatedElement.blendMode = (newParts.fill || newParts.stroke) ? currentMode : 'normal';\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleCompositingStrokeChange = useCallback(\n (stroke: boolean) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n const currentMode = updatedElement.blendMode === 'clip' ? 'clip' : 'knockout';\n const newParts = { ...updatedElement.knockoutParts, stroke };\n updatedElement.knockoutParts = newParts;\n updatedElement.blendMode = (newParts.fill || newParts.stroke) ? currentMode : 'normal';\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleCompositingScopeChange = useCallback(\n (scope: CompositingScope) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n updatedElement.knockoutParts = { ...updatedElement.knockoutParts, scope };\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // ── Distress texture handlers ─────────────────────────────────────────\n const handleDistressTextureChange = useCallback(\n (url: string) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n if (!url) {\n updatedElement.distressEffect = undefined;\n } else {\n updatedElement.distressEffect = {\n enabled: true,\n style: 'custom',\n intensity: updatedElement.distressEffect?.intensity ?? 50,\n textureUrl: url,\n textureOpacity: updatedElement.distressEffect?.textureOpacity ?? 0.5,\n };\n }\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleDistressOpacityChange = useCallback(\n (pct: number) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n if (updatedElement.distressEffect) {\n updatedElement.distressEffect = {\n ...updatedElement.distressEffect,\n textureOpacity: pct / 100,\n };\n }\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // ── Image mask handlers (quick-mask via masks[] with id='quick-image-mask') ──\n const handleImageMaskImageChange = useCallback(\n (url: string) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n if (!url) {\n // Remove quick-image-mask\n updatedElement.masks = (updatedElement.masks || []).filter((m: { id: string }) => m.id !== 'quick-image-mask');\n } else {\n // Store the mask's natural dimensions (512×512 for builtin presets).\n // MaskRenderer uses these to compute object-cover scaling at render time,\n // preserving the mask shape's aspect ratio on non-square images.\n const BUILTIN_MASK_SIZE = 512;\n\n const makeMaskElement = () => ({\n transformType: 'image' as const,\n imageUrl: url,\n x: 0, y: 0, rotation: 0,\n transformData: { type: 'image' as const, width: BUILTIN_MASK_SIZE, height: BUILTIN_MASK_SIZE, cropX: 0, cropY: 0, cropWidth: 1, cropHeight: 1, flipHorizontal: false, flipVertical: false, borderRadius: 0 },\n }) as import('../types/index.js').ImageElementConfig;\n\n // Reset crop when applying a mask — the mask handles clipping,\n // and stale crop values would cause position/rendering issues.\n if ('transformData' in updatedElement && updatedElement.transformData) {\n const td = updatedElement.transformData as Record<string, unknown>;\n td.cropX = 0;\n td.cropY = 0;\n td.cropWidth = 1;\n td.cropHeight = 1;\n }\n\n const existing = (updatedElement.masks || []).find((m: { id: string }) => m.id === 'quick-image-mask');\n if (existing) {\n existing.maskElement = makeMaskElement();\n } else {\n const masks = updatedElement.masks || [];\n masks.push({\n id: 'quick-image-mask',\n type: 'clip',\n maskElement: makeMaskElement(),\n opacity: 1,\n inverted: false,\n });\n updatedElement.masks = masks;\n }\n }\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleImageMaskTypeChange = useCallback(\n (type: 'clip' | 'alpha' | 'luma') => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n const mask = (updatedElement.masks || []).find((m: { id: string }) => m.id === 'quick-image-mask');\n if (mask) {\n mask.type = type;\n elementUpdateHandler(updatedElement);\n }\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleImageMaskOpacityChange = useCallback(\n (pct: number) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n const mask = (updatedElement.masks || []).find((m: { id: string }) => m.id === 'quick-image-mask');\n if (mask) {\n mask.opacity = pct / 100;\n elementUpdateHandler(updatedElement);\n }\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleImageMaskInvertedChange = useCallback(\n (inv: boolean) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n const mask = (updatedElement.masks || []).find((m: { id: string }) => m.id === 'quick-image-mask');\n if (mask) {\n mask.inverted = inv;\n elementUpdateHandler(updatedElement);\n }\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // ── Stroke change handler ─────────────────────────────────────────────\n const handleStrokeChange = useCallback(\n (stroke: import('../types/index.js').StrokeConfig | undefined) => {\n if (!elementForProperties) return;\n const updatedElement = elementForProperties.clone();\n updatedElement.stroke = stroke;\n elementUpdateHandler(updatedElement);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n // ── Shape type change handler ──────────────────────────────────────────\n const handleShapeTypeChange = useCallback(\n (newShapeType: string) => {\n if (!elementForProperties || elementForProperties.transformType !== 'shape') return;\n const shapeElement = elementForProperties as ShapeElement;\n const updatedElement = shapeElement.clone() as ShapeElement;\n updatedElement.transformData.shapeType = newShapeType as ShapeElement['transformData']['shapeType'];\n elementUpdateHandler(updatedElement);\n setIsShapeTypeDrawerOpen(false);\n },\n [elementForProperties, elementUpdateHandler]\n );\n\n const handleOpenShapeTypeDrawer = useCallback(() => {\n if (onOpenShapeTypeDrawer) {\n onOpenShapeTypeDrawer();\n } else {\n setIsShapeTypeDrawerOpen(true);\n }\n }, [onOpenShapeTypeDrawer]);\n\n // ── Panel expand change notification ───────────────────────────────────\n useEffect(() => {\n onPanelExpandChange?.(expandedPanel !== null);\n onExpandedPanelTypeChange?.(\n (expandedPanel?.type as 'cornerRadius' | 'effects' | 'crop' | 'rotation' | null) ?? null\n );\n }, [expandedPanel, onPanelExpandChange, onExpandedPanelTypeChange]);\n\n // ── Sync local panel state TO context ──────────────────────────────────\n useEffect(() => {\n const localType = expandedPanel?.type ?? null;\n if (localType !== lastSyncedToContextRef.current) {\n lastSyncedToContextRef.current = localType;\n setContextExpandedPanelType(localType as Parameters<typeof setContextExpandedPanelType>[0]);\n }\n }, [expandedPanel, setContextExpandedPanelType]);\n\n // ── Sync FROM context when it changes externally ───────────────────────\n useEffect(() => {\n const prevType = prevContextExpandedPanelTypeRef.current;\n const currentType = contextExpandedPanelType;\n if (prevType === currentType) return;\n prevContextExpandedPanelTypeRef.current = currentType;\n\n if (prevType !== null && currentType === null && expandedPanel !== null) {\n lastSyncedToContextRef.current = null;\n setExpandedPanel(null);\n return;\n }\n\n if (currentType !== null && expandedPanel?.type !== currentType) {\n type PanelType = NonNullable<ExpandedPanelConfig>['type'];\n const panelConfigs: Record<PanelType, NonNullable<ExpandedPanelConfig>> = {\n crop: { type: 'crop', icon: 'lucide:crop', label: 'Crop' },\n cornerRadius: { type: 'cornerRadius', icon: 'lucide:square-round-corner', label: 'Corner Radius' },\n rotation: { type: 'rotation', icon: icons.rotateLeft, label: 'Rotate' },\n opacity: { type: 'opacity', icon: 'lucide:blend', label: 'Transparency' },\n fontSize: { type: 'fontSize', icon: 'lucide:type', label: 'Font Size' },\n effects: { type: 'effects', icon: 'lucide:sparkles', label: 'Effects' },\n shapeCornerRadius: { type: 'shapeCornerRadius', icon: 'lucide:square-round-corner', label: 'Corner Radius' },\n shapeTransparency: { type: 'shapeTransparency', icon: icons.eye, label: 'Transparency' },\n shapeSides: { type: 'shapeSides', icon: 'lucide:triangle', label: 'Sides' },\n shapePoints: { type: 'shapePoints', icon: 'lucide:star', label: 'Points' },\n shapeInnerRadius: { type: 'shapeInnerRadius', icon: 'lucide:circle-dashed', label: 'Inner Radius' },\n shapeColor: { type: 'shapeColor', icon: icons.palette, label: 'Color' },\n textColor: { type: 'textColor', icon: icons.palette, label: 'Color' },\n stroke: { type: 'stroke', icon: 'lucide:pen-line', label: 'Stroke' },\n compositing: { type: 'compositing', icon: 'lucide:scissors', label: 'Clip / Knockout' },\n distressTexture: { type: 'distressTexture', icon: 'lucide:stamp', label: 'Distress Texture' },\n imageMask: { type: 'imageMask', icon: 'lucide:venetian-mask', label: 'Image Mask' },\n };\n const config = panelConfigs[currentType as PanelType];\n if (config) {\n lastSyncedToContextRef.current = currentType;\n setExpandedPanel(config);\n }\n }\n }, [contextExpandedPanelType, expandedPanel]);\n\n // ── Sync toolbar menu open state to context ────────────────────────────\n useEffect(() => {\n const isAnyMenuOpen =\n expandedPanel !== null ||\n openDropdown !== null ||\n isTransformMenuOpen ||\n isColorPickerOpen ||\n isTextMoreMenuOpen ||\n activeMenu !== 'root';\n setIsToolbarMenuOpen(isAnyMenuOpen);\n }, [expandedPanel, openDropdown, isTransformMenuOpen, isColorPickerOpen, isTextMoreMenuOpen, activeMenu, setIsToolbarMenuOpen]);\n\n // ── Close expanded panel when element changes or is deselected ─────────\n useEffect(() => {\n if (defaultExpandedPanel) return;\n if (prevStableSelectedIdRef.current !== undefined && prevStableSelectedIdRef.current !== stableSelectedId) {\n setExpandedPanel(null);\n }\n prevStableSelectedIdRef.current = stableSelectedId;\n }, [stableSelectedId, defaultExpandedPanel]);\n\n // ── Auto-dismiss artboard edit mode when an element is selected ────────\n useEffect(() => {\n if (editArtboardMode && selectedElement) {\n onEditArtboardModeChange?.(false);\n }\n }, [editArtboardMode, selectedElement, onEditArtboardModeChange]);\n\n // ── Close crop panel when element exits crop mode ──────────────────────\n useEffect(() => {\n const currentIsCropping =\n elementForProperties?.transformType === 'image' ? (elementForProperties as ImageElement).isCropping : false;\n if (expandedPanel?.type === 'crop' && prevIsCroppingRef.current === true && currentIsCropping === false) {\n setExpandedPanel(null);\n }\n prevIsCroppingRef.current = currentIsCropping;\n }, [elementForProperties, expandedPanel?.type]);\n\n // ── Cleanup on unmount: exit crop mode ─────────────────────────────────\n useEffect(() => {\n expandedPanelRef.current = expandedPanel;\n elementForPropertiesRef.current = elementForProperties ?? null;\n elementUpdateHandlerRef.current = elementUpdateHandler;\n });\n\n useEffect(() => {\n const timeoutId = setTimeout(() => {\n isFullyMountedRef.current = true;\n }, 0);\n return () => { clearTimeout(timeoutId); };\n }, []);\n\n useEffect(() => {\n return () => {\n if (!isFullyMountedRef.current) return;\n if (!isDrawerModeAtMount.current) return;\n if (expandedPanelRef.current?.type === 'crop') {\n const element = elementForPropertiesRef.current;\n if (element?.transformType === 'image') {\n const imageElement = element as ImageElement;\n if (imageElement.isCropping) {\n const updatedElement = imageElement.clone();\n updatedElement.exitCropMode();\n elementUpdateHandlerRef.current(updatedElement);\n }\n }\n }\n };\n }, []);\n\n // ── Dragging detection ─────────────────────────────────────────────────\n useEffect(() => {\n let mouseDownPos: { x: number; y: number } | null = null;\n let isDraggingStarted = false;\n const DRAG_THRESHOLD = 3;\n\n const handleMouseDown = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (toolbarRef.current?.contains(target)) return;\n if (\n target.closest('[data-slot=\"popover-content\"]') ||\n target.closest('[data-slot=\"dialog\"]') ||\n target.closest('[role=\"dialog\"]') ||\n target.closest('.popover-content') ||\n target.closest('[data-slot]')\n ) return;\n isMouseDownRef.current = true;\n mouseDownPos = { x: e.clientX, y: e.clientY };\n isDraggingStarted = false;\n };\n\n const handleMouseMove = (e: MouseEvent) => {\n if (mouseDownPos && !isDraggingStarted && !isRotatingRef.current) {\n const deltaX = e.clientX - mouseDownPos.x;\n const deltaY = e.clientY - mouseDownPos.y;\n const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);\n if (distance > DRAG_THRESHOLD) {\n isDraggingStarted = true;\n setIsDragging(true);\n }\n }\n };\n\n const handleMouseUp = () => {\n isMouseDownRef.current = false;\n mouseDownPos = null;\n isDraggingStarted = false;\n setIsDragging(false);\n };\n\n window.addEventListener('mousedown', handleMouseDown);\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n return () => {\n window.removeEventListener('mousedown', handleMouseDown);\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n }, []);\n\n // ── Toolbar dimension tracking ─────────────────────────────────────────\n useEffect(() => {\n if (!toolbarRef.current) return;\n let timeoutId: number | null = null;\n\n const observer = new ResizeObserver((entries) => {\n if (timeoutId !== null) clearTimeout(timeoutId);\n timeoutId = window.setTimeout(() => {\n for (const entry of entries) {\n const newWidth = entry.contentRect.width;\n const newHeight = entry.contentRect.height;\n setToolbarDimensions((prev) => {\n if (prev.width === newWidth && prev.height === newHeight) return prev;\n return { width: newWidth, height: newHeight };\n });\n }\n }, 50);\n });\n\n observer.observe(toolbarRef.current);\n return () => {\n observer.disconnect();\n if (timeoutId !== null) clearTimeout(timeoutId);\n };\n }, [selectedElement]);\n\n // ── Floating toolbar position calculation ──────────────────────────────\n useEffect(() => {\n if (mode === 'embedded') return;\n if (isExiting) return;\n\n const currentRotation = (activeChildElement || selectedElement)?.rotation;\n lastElementRotationRef.current = currentRotation;\n\n if (!selectedElement) {\n setToolbarPosition(null);\n return;\n }\n\n const updateToolbarPosition = () => {\n try {\n const toolbarWidth = toolbarRef.current?.offsetWidth || toolbarDimensions.width || 0;\n const toolbarHeight = toolbarRef.current?.offsetHeight || toolbarDimensions.height || 48;\n const canvas = canvasRef?.current;\n const elementToPosition = activeChildElement || selectedElement;\n const transformData = elementToPosition.transformData as Record<string, unknown> | undefined;\n const elementBounds = elementToPosition.getBoundingBox?.() || {\n x: elementToPosition.x,\n y: elementToPosition.y,\n width: (transformData?.width as number) || 100,\n height: (transformData?.height as number) || 50,\n };\n\n const activeArtboard = artboardManager.getActiveArtboard();\n const artboardX = activeArtboard?.x || 0;\n const artboardY = activeArtboard?.y || 0;\n const currentZoom = canvasEditorRef?.current?.getZoom?.() || 1;\n\n let elementScreenX: number;\n let elementScreenY: number;\n let elementScreenWidth: number;\n let elementScreenHeight: number;\n\n if (canvas) {\n const canvasRect = canvas.getBoundingClientRect();\n elementScreenX = canvasRect.left + (elementBounds.x - artboardX) * currentZoom;\n elementScreenY = canvasRect.top + (elementBounds.y - artboardY) * currentZoom;\n elementScreenWidth = elementBounds.width * currentZoom;\n elementScreenHeight = elementBounds.height * currentZoom;\n } else if (artboardScreenBounds) {\n elementScreenX = artboardScreenBounds.left + (elementBounds.x - artboardX) * currentZoom;\n elementScreenY = artboardScreenBounds.top + (elementBounds.y - artboardY) * currentZoom;\n elementScreenWidth = elementBounds.width * currentZoom;\n elementScreenHeight = elementBounds.height * currentZoom;\n } else {\n const viewportCenterX = window.innerWidth / 2;\n const viewportCenterY = window.innerHeight / 2;\n elementScreenX = viewportCenterX - (elementBounds.width * currentZoom) / 2;\n elementScreenY = viewportCenterY - (elementBounds.height * currentZoom) / 2;\n elementScreenWidth = elementBounds.width * currentZoom;\n elementScreenHeight = elementBounds.height * currentZoom;\n }\n\n const gap = 12;\n const elementTop = elementScreenY;\n const elementCenterX = elementScreenX + elementScreenWidth / 2;\n\n let top = elementTop - toolbarHeight - gap;\n let left = elementCenterX;\n\n if (toolbarWidth > 0) {\n const padding = 20;\n const minLeft = toolbarWidth / 2 + padding;\n const maxLeft = window.innerWidth - toolbarWidth / 2 - padding;\n left = Math.max(minLeft, Math.min(maxLeft, left));\n }\n\n if (top < 10) {\n top = elementScreenY + elementScreenHeight + gap;\n }\n\n const maxTop = window.innerHeight - toolbarHeight - 10;\n top = Math.min(top, maxTop);\n top = Math.max(10, top);\n\n setToolbarPosition({ top, left });\n setPositionedElementId(elementToPosition.id);\n } catch (error) {\n logger.error('Error calculating toolbar position:', error);\n setToolbarPosition(null);\n }\n };\n\n updateToolbarPosition();\n window.addEventListener('resize', updateToolbarPosition);\n return () => { window.removeEventListener('resize', updateToolbarPosition); };\n }, [mode, selectedElement, activeChildElement, canvasRef, artboardManager, canvasEditorRef, artboardScreenBounds, toolbarDimensions, isExiting, panOffset]);\n\n // ── Memoized color picker props ────────────────────────────────────────\n const colorPickerValue = getEffectiveStyle().color || fontColor;\n const colorPickerOnChange = useCallback(\n (e: { target: { value: string } }) => handleFontColorChange(e as React.ChangeEvent<HTMLInputElement>),\n [handleFontColorChange]\n );\n\n // Auto-derive every paint colour in the design — text colours,\n // rich-text span colours, shape fills, path fills + strokes,\n // element-level strokes, and artboard backgrounds — and union with\n // whatever the consumer explicitly passed in. Lets the shape /\n // text colour pickers offer \"match a colour already on the page\"\n // without every host app having to plumb the set through.\n // See `utils/documentColors.ts` for the full enumeration.\n const autoDocumentColors = useMemo(\n () => collectDocumentColors(elements, artboards),\n [elements, artboards]\n );\n\n const mergedDocumentColors = useMemo(() => {\n const out = new Set<string>(autoDocumentColors);\n for (const c of documentColors) out.add(c);\n return out;\n }, [autoDocumentColors, documentColors]);\n\n const documentColorsKey = Array.from(mergedDocumentColors).sort().join(',');\n const colorPickerDocumentColors = useMemo(\n () => Array.from(mergedDocumentColors),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [documentColorsKey]\n );\n\n // Image colours — dominant palette extracted from each ImageElement\n // (recursing into groups), surfaced as a separate row in the\n // colour picker. Async because pixel access requires the image to\n // be loaded; cache lives in `documentColors.ts` so re-renders are\n // free after the first extraction. Empty until the first promise\n // resolves; the picker just hides the row in that case.\n const imageUrlsKey = useMemo(() => {\n const urls: string[] = [];\n const seen = new Set<string>();\n const walk = (el: EditorElement) => {\n if (el instanceof ImageElement) {\n if (el.imageUrl && !seen.has(el.imageUrl)) {\n seen.add(el.imageUrl);\n urls.push(el.imageUrl);\n }\n } else if (el instanceof GroupElement) {\n for (const c of el.children) walk(c as EditorElement);\n }\n };\n for (const el of elements) walk(el);\n urls.sort();\n return urls.join('|');\n }, [elements]);\n\n const [colorPickerImageColors, setColorPickerImageColors] = useState<string[]>([]);\n useEffect(() => {\n if (!imageUrlsKey) {\n setColorPickerImageColors([]);\n return;\n }\n let cancelled = false;\n collectImageColors(elements).then((colors) => {\n if (!cancelled) setColorPickerImageColors(colors);\n });\n return () => {\n cancelled = true;\n };\n // We deliberately key off the stable `imageUrlsKey` so that\n // dragging an image around (which mutates `elements` but not the\n // URL set) doesn't re-trigger palette extraction.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [imageUrlsKey]);\n\n // ── Toolbar div ref callback ───────────────────────────────────────────\n const toolbarDivRef = useCallback((node: HTMLDivElement | null) => {\n if (toolbarRef) {\n // MutableRefObject is needed to write to .current in a callback ref\n (toolbarRef as React.MutableRefObject<HTMLDivElement | null>).current = node;\n if (node) {\n const { width, height } = node.getBoundingClientRect();\n if (width > 0 && height > 0) {\n setToolbarDimensions({ width, height });\n }\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // ── Freeze toolbar position during rotation ────────────────────────────\n useEffect(() => {\n const wasRotating = prevIsRotatingRef.current;\n const isNowRotating = isRotating;\n if (!wasRotating && isNowRotating && toolbarPosition) {\n frozenPositionRef.current = { ...toolbarPosition };\n }\n if (wasRotating && !isNowRotating) {\n frozenPositionRef.current = null;\n }\n prevIsRotatingRef.current = isRotating;\n }, [isRotating, toolbarPosition]);\n\n // ── Entrance/exit animations ───────────────────────────────────────────\n useEffect(() => {\n const prevShouldShow = prevShouldShowRef.current;\n const prevSelectedId = prevSelectedIdRef.current;\n prevShouldShowRef.current = shouldShowToolbar;\n prevSelectedIdRef.current = stableSelectedId;\n\n if (!prevShouldShow && shouldShowToolbar) {\n setShouldRender(true);\n if (mode === 'embedded') {\n setIsWaitingForPosition(false);\n setIsEntering(true);\n setIsExiting(false);\n const enterTimer = setTimeout(() => { setIsEntering(false); }, 200);\n return () => clearTimeout(enterTimer);\n }\n setIsWaitingForPosition(true);\n setIsEntering(false);\n setIsExiting(false);\n return undefined;\n }\n\n if (prevShouldShow && shouldShowToolbar && prevSelectedId !== stableSelectedId && stableSelectedId !== undefined) {\n if (mode === 'embedded') {\n setIsEntering(false);\n return undefined;\n }\n setIsWaitingForPosition(true);\n setIsEntering(false);\n setIsExiting(false);\n return undefined;\n }\n\n if (prevShouldShow && !shouldShowToolbar) {\n if (isRotating) {\n setShouldRender(false);\n setIsEntering(false);\n setIsExiting(false);\n setIsWaitingForPosition(false);\n return undefined;\n }\n\n if (mode === 'embedded') {\n setIsExiting(true);\n setIsEntering(false);\n if (innerContentRef.current) {\n const currentHeight = innerContentRef.current.offsetHeight;\n setTransitionHeight(currentHeight);\n requestAnimationFrame(() => { setTransitionHeight(0); });\n }\n const exitTimer = setTimeout(() => {\n setShouldRender(false);\n setIsExiting(false);\n setTransitionHeight(null);\n }, 200);\n return () => clearTimeout(exitTimer);\n }\n\n setIsExiting(true);\n setIsEntering(false);\n setIsWaitingForPosition(false);\n const exitTimer = setTimeout(() => {\n setShouldRender(false);\n setIsExiting(false);\n setToolbarPosition(null);\n setPositionedElementId(null);\n }, 150);\n return () => clearTimeout(exitTimer);\n }\n\n return undefined;\n }, [shouldShowToolbar, isRotating, stableSelectedId, mode, currentElementType]);\n\n // ── Trigger entrance animation once position is ready ──────────────────\n useEffect(() => {\n if (isWaitingForPosition && toolbarPosition && positionedElementId === stableElementId) {\n setIsWaitingForPosition(false);\n setIsEntering(true);\n const enterTimer = setTimeout(() => { setIsEntering(false); }, 200);\n return () => clearTimeout(enterTimer);\n }\n return undefined;\n }, [isWaitingForPosition, toolbarPosition, positionedElementId, stableElementId]);\n\n // ── Height transitions for type changes (embedded mode) ────────────────\n useLayoutEffect(() => {\n if (mode !== 'embedded') return;\n const prevType = prevElementTypeRef.current;\n const typeChanged = prevType !== undefined && currentElementType !== undefined && prevType !== currentElementType;\n\n if (typeChanged && lastKnownHeightRef.current > 0 && transitionHeight === null) {\n const startHeight = lastKnownHeightRef.current;\n setTransitionHeight(startHeight);\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (innerContentRef.current) {\n const newHeight = innerContentRef.current.scrollHeight;\n setTransitionHeight(newHeight);\n setTimeout(() => { setTransitionHeight(null); }, 200);\n }\n });\n });\n }\n\n if (innerContentRef.current && transitionHeight === null && !isEntering && !isExiting) {\n lastKnownHeightRef.current = innerContentRef.current.offsetHeight;\n }\n\n prevElementTypeRef.current = currentElementType;\n }, [mode, currentElementType, transitionHeight, isEntering, isExiting]);\n\n // ── Memoized toolbar style ─────────────────────────────────────────────\n const toolbarStyle = useMemo(() => {\n const maxWidthValue = maxWidth ? (typeof maxWidth === 'number' ? `${maxWidth}px` : maxWidth) : undefined;\n\n if (mode === 'embedded') {\n return {\n borderRadius: maxWidth ? '16px' : '9999px',\n visibility: 'visible' as const,\n position: 'static' as const,\n maxWidth: maxWidthValue,\n display: 'flex',\n justifyContent: 'flex-start',\n };\n }\n\n const position = frozenPositionRef.current || toolbarPosition;\n if (position && !isWaitingForPosition) {\n return {\n top: `${position.top}px`,\n left: `${position.left}px`,\n position: 'fixed' as const,\n transform: 'translateX(-50%)',\n borderRadius: maxWidth ? '16px' : '9999px',\n visibility: 'visible' as const,\n maxWidth: maxWidthValue,\n zIndex: 'var(--z-tooltip)',\n };\n }\n\n return {\n borderRadius: maxWidth ? '16px' : '9999px',\n visibility: 'hidden' as const,\n maxWidth: maxWidthValue,\n position: 'fixed' as const,\n top: '-9999px',\n left: '-9999px',\n zIndex: 'var(--z-tooltip)',\n };\n }, [mode, toolbarPosition, isWaitingForPosition, maxWidth]);\n\n // ── Early return for multi-selection ────────────────────────────────────\n if (multiSelection.length > 0) {\n return null;\n }\n\n // ══════════════════════════════════════════════════════════════════════════\n // RENDER: Toolbar dispatch — select element-specific toolbar\n // ══════════════════════════════════════════════════════════════════════════\n\n const regularToolbarContent = (\n <>\n {/* Leading chip: thumbnail + lock toggle. Replaces the floating\n SelectionChip that used to live top-left of the canvas — now\n inline with the rest of the toolbar buttons. Only shows when\n there's actually a selected element (the empty / artboard\n states render their own content elsewhere). */}\n {activeMenu === 'root' && elementForProperties && (\n <LayerLeadingChip\n element={elementForProperties}\n onToggleLock={handleToggleLock}\n onThumbnailClick={onLayerThumbnailClick}\n />\n )}\n\n {/* Image elements */}\n {activeMenu === 'root' && elementForProperties?.transformType === 'image' && (\n <ImageToolbar\n element={elementForProperties as ImageElement}\n onElementUpdate={elementUpdateHandler}\n showUngroupButton={!!activeChildElement && selectedElement?.transformType === 'group'}\n onUngroup={handleUngroupElement}\n onMoveForward={handleMoveForward}\n onMoveBackward={handleMoveBackward}\n onChangeImage={onChangeImage}\n onDelete={handleDeleteElement}\n cornerRadiusExpanded={expandedPanel?.type === 'cornerRadius'}\n onCornerRadiusToggle={handleCornerRadiusToggle}\n cropExpanded={expandedPanel?.type === 'crop'}\n onCropToggle={handleCropToggle}\n rotationExpanded={expandedPanel?.type === 'rotation'}\n onRotationToggle={handleRotationToggle}\n opacityExpanded={expandedPanel?.type === 'opacity'}\n onOpacityToggle={handleOpacityToggle}\n strokeExpanded={expandedPanel?.type === 'stroke'}\n onStrokeToggle={handleStrokeToggle}\n knockoutExpanded={expandedPanel?.type === 'compositing'}\n onKnockoutToggle={handleCompositingToggle}\n distressTextureExpanded={expandedPanel?.type === 'distressTexture'}\n onDistressTextureToggle={handleDistressTextureToggle}\n imageMaskExpanded={expandedPanel?.type === 'imageMask'}\n onImageMaskToggle={handleImageMaskToggle}\n />\n )}\n\n {/* Group elements (only when no child is active) */}\n {activeMenu === 'root' && selectedElement?.transformType === 'group' && !activeChildElement && (\n <GroupElementToolbar\n element={selectedElement as GroupElement}\n rotationExpanded={expandedPanel?.type === 'rotation'}\n onRotationToggle={handleRotationToggle}\n opacityExpanded={expandedPanel?.type === 'opacity'}\n onOpacityToggle={handleOpacityToggle}\n strokeExpanded={expandedPanel?.type === 'stroke'}\n onStrokeToggle={handleStrokeToggle}\n knockoutExpanded={expandedPanel?.type === 'compositing'}\n onKnockoutToggle={handleCompositingToggle}\n distressTextureExpanded={expandedPanel?.type === 'distressTexture'}\n onDistressTextureToggle={handleDistressTextureToggle}\n imageMaskExpanded={expandedPanel?.type === 'imageMask'}\n onImageMaskToggle={handleImageMaskToggle}\n onUngroup={handleUngroupElement}\n />\n )}\n\n {/* Shape elements */}\n {activeMenu === 'root' && elementForProperties?.transformType === 'shape' && (\n <ShapeToolbar\n element={elementForProperties as ShapeElement}\n onElementUpdate={elementUpdateHandler}\n documentColors={colorPickerDocumentColors}\n imageColors={colorPickerImageColors}\n showUngroupButton={!!activeChildElement && selectedElement?.transformType === 'group'}\n onUngroup={handleUngroupElement}\n onMoveForward={handleMoveForward}\n onMoveBackward={handleMoveBackward}\n onOpenShapeTypeDrawer={handleOpenShapeTypeDrawer}\n onDelete={handleDeleteElement}\n rotationExpanded={expandedPanel?.type === 'rotation'}\n onRotationToggle={handleRotationToggle}\n cornerRadiusExpanded={expandedPanel?.type === 'shapeCornerRadius'}\n onCornerRadiusToggle={handleShapeCornerRadiusToggle}\n transparencyExpanded={expandedPanel?.type === 'shapeTransparency'}\n onTransparencyToggle={handleShapeTransparencyToggle}\n sidesExpanded={expandedPanel?.type === 'shapeSides'}\n onSidesToggle={handleShapeSidesToggle}\n pointsExpanded={expandedPanel?.type === 'shapePoints'}\n onPointsToggle={handleShapePointsToggle}\n innerRadiusExpanded={expandedPanel?.type === 'shapeInnerRadius'}\n onInnerRadiusToggle={handleShapeInnerRadiusToggle}\n colorExpanded={expandedPanel?.type === 'shapeColor'}\n onColorToggle={handleShapeColorToggle}\n strokeExpanded={expandedPanel?.type === 'stroke'}\n onStrokeToggle={handleStrokeToggle}\n knockoutExpanded={expandedPanel?.type === 'compositing'}\n onKnockoutToggle={handleCompositingToggle}\n distressTextureExpanded={expandedPanel?.type === 'distressTexture'}\n onDistressTextureToggle={handleDistressTextureToggle}\n imageMaskExpanded={expandedPanel?.type === 'imageMask'}\n onImageMaskToggle={handleImageMaskToggle}\n />\n )}\n\n {/* Path elements */}\n {activeMenu === 'root' && elementForProperties?.transformType === 'path' && (\n <PathToolbar\n element={elementForProperties as PathElement}\n onElementUpdate={elementUpdateHandler}\n onMoveForward={handleMoveForward}\n onMoveBackward={handleMoveBackward}\n />\n )}\n\n {/* Text elements (anything not image/group/shape/path) */}\n {activeMenu === 'root' &&\n elementForProperties &&\n elementForProperties.transformType !== 'image' &&\n elementForProperties.transformType !== 'group' &&\n elementForProperties.transformType !== 'shape' &&\n elementForProperties.transformType !== 'path' && (\n <TextToolbar\n toolbar={textToolbar}\n stableElementId={stableElementId}\n viewportWidth={viewportWidth}\n colorPickerValue={colorPickerValue}\n isColorActive={expandedPanel?.type === 'textColor'}\n onColorToggle={handleTextColorToggle}\n onOpenGlyphBrowser={onOpenGlyphBrowser}\n strokeExpanded={expandedPanel?.type === 'stroke'}\n onStrokeToggle={handleStrokeToggle}\n hasGlyphs={hasGlyphs}\n expandedPanel={expandedPanel}\n onRotationToggle={handleRotationToggle}\n onOpacityToggle={handleOpacityToggle}\n onFontSizeToggle={handleFontSizeToggle}\n knockoutExpanded={expandedPanel?.type === 'compositing'}\n onKnockoutToggle={handleCompositingToggle}\n distressTextureExpanded={expandedPanel?.type === 'distressTexture'}\n onDistressTextureToggle={handleDistressTextureToggle}\n imageMaskExpanded={expandedPanel?.type === 'imageMask'}\n onImageMaskToggle={handleImageMaskToggle}\n getMoreMenuItems={getMoreMenuItems}\n onMoveForward={handleMoveForward}\n onMoveBackward={handleMoveBackward}\n onDelete={handleDeleteElement}\n elementForProperties={elementForProperties}\n elements={elements}\n isTransformMenuOpen={isTransformMenuOpen}\n onTransformMenuOpenChange={setIsTransformMenuOpen}\n elementUpdateHandler={elementUpdateHandler}\n showUngroupButton={!!activeChildElement && selectedElement?.transformType === 'group'}\n onUngroup={handleUngroupElement}\n isFontBrowserOpen={openDropdown === 'fontFamily'}\n onFontBrowserToggle={(isOpen) => setOpenDropdown(isOpen ? 'fontFamily' : null)}\n onTextMoreMenuOpenChange={setIsTextMoreMenuOpen}\n />\n )}\n\n {/* Color Menu (legacy) */}\n {activeMenu === 'color' && (\n <div className=\"toolbar-items\">\n <BackButton onClick={() => setActiveMenu('root')} />\n <div className=\"toolbar-scroll\">\n <input\n className=\"toolbar-color\"\n type=\"color\"\n value={fontColor}\n onChange={(e) => { handleFontColorChange(e); }}\n />\n <span className=\"toolbar-label\">{fontColor}</span>\n </div>\n </div>\n )}\n </>\n );\n\n // ── Build toolbar chrome (header + regular content) ────────────────────\n const shapeElement = elementForProperties?.transformType === 'shape' ? (elementForProperties as ShapeElement) : null;\n\n const toolbarContent = shouldRender ? (\n <div\n ref={toolbarDivRef}\n className=\"toolbar\"\n data-mode={mode}\n data-wrap={maxWidth ? '' : undefined}\n data-transparent={transparent ? '' : undefined}\n data-panel-expanded={expandedPanel ? '' : undefined}\n data-preserve-selection\n style={{\n ...toolbarStyle,\n opacity: isRotating ? 0 : 1,\n pointerEvents: isRotating ? 'none' : 'auto',\n transition: 'opacity 0.05s ease-out',\n }}\n data-entering={isEntering ? '' : undefined}\n data-exiting={isExiting ? '' : undefined}\n >\n <div className=\"toolbar-slide-container\">\n <div className=\"toolbar-regular-content\" data-hidden={expandedPanel ? '' : undefined}>\n {regularToolbarContent}\n </div>\n <div className=\"toolbar-collapsed-header\" data-visible={expandedPanel ? '' : undefined}>\n {expandedPanel && (\n <CollapsedToolbarHeader\n icon={\n <ExpandedPanelIcon\n panelType={expandedPanel.type}\n defaultIcon={expandedPanel.icon}\n textColorValue={colorPickerValue}\n shapeFillColor={shapeElement?.transformData?.fillColor}\n />\n }\n label={expandedPanel.label}\n onClose={handleCloseExpandedPanel}\n closeButtonStyle={closeButtonStyle}\n />\n )}\n </div>\n </div>\n </div>\n ) : null;\n\n // ── Derive panel open states ───────────────────────────────────────────\n const isCornerRadiusPanelOpen = expandedPanel?.type === 'cornerRadius';\n const isCropPanelOpen = expandedPanel?.type === 'crop';\n const isRotationPanelOpen = expandedPanel?.type === 'rotation';\n const isOpacityPanelOpen = expandedPanel?.type === 'opacity';\n const isFontSizePanelOpen = expandedPanel?.type === 'fontSize';\n const isShapeCornerRadiusPanelOpen = expandedPanel?.type === 'shapeCornerRadius';\n const isShapeTransparencyPanelOpen = expandedPanel?.type === 'shapeTransparency';\n const isShapeSidesPanelOpen = expandedPanel?.type === 'shapeSides';\n const isShapePointsPanelOpen = expandedPanel?.type === 'shapePoints';\n const isShapeInnerRadiusPanelOpen = expandedPanel?.type === 'shapeInnerRadius';\n const isShapeColorPanelOpen = expandedPanel?.type === 'shapeColor';\n const isTextColorPanelOpen = expandedPanel?.type === 'textColor';\n const isKnockoutPanelOpen = expandedPanel?.type === 'compositing';\n const isDistressTexturePanelOpen = expandedPanel?.type === 'distressTexture';\n const isStrokePanelOpen = expandedPanel?.type === 'stroke';\n const isImageMaskPanelOpen = expandedPanel?.type === 'imageMask';\n\n // ── Derive property values for panels ──────────────────────────────────\n const currentBorderRadius =\n elementForProperties?.transformType === 'image'\n ? (elementForProperties as ImageElement).transformData?.borderRadius || 0\n : 0;\n const currentRotation = elementForProperties?.rotation || 0;\n const currentOpacity = elementForProperties?.opacity ?? 1;\n const currentShapeBorderRadius = shapeElement?.transformData?.borderRadius || 0;\n const currentShapeOpacity = shapeElement?.transformData?.fillOpacity ?? 1;\n const currentShapeSides = shapeElement?.transformData?.sides || 5;\n const currentShapePoints = shapeElement?.transformData?.points || 5;\n const currentShapeInnerRadius = shapeElement?.transformData?.innerRadius || 0.4;\n const currentShapeFillColor = shapeElement?.transformData?.fillColor || '#3b82f6';\n const compositingFill = elementForProperties?.knockoutParts?.fill ?? false;\n const compositingStroke = elementForProperties?.knockoutParts?.stroke ?? false;\n const compositingScope: CompositingScope = elementForProperties?.knockoutParts?.scope ?? 'group';\n const compositingMode: CompositingMode = elementForProperties?.blendMode === 'clip' ? 'clip' : 'knockout';\n\n // ── Build secondary panel content ──────────────────────────────────────\n const cornerRadiusPanel = isCornerRadiusPanelOpen && elementForProperties?.transformType === 'image'\n ? <CornerRadiusPanel value={currentBorderRadius} onChange={handleBorderRadiusChange} />\n : null;\n\n const cropPanelContent = isCropPanelOpen && elementForProperties?.transformType === 'image'\n ? <CropPanelContent element={elementForProperties as ImageElement} onElementUpdate={elementUpdateHandler} />\n : null;\n\n const rotationPanel = isRotationPanelOpen && elementForProperties\n ? <RotationPanel value={currentRotation} onChange={handleRotationChange} onRotate90={handleRotate90} />\n : null;\n\n const opacityPanel = isOpacityPanelOpen && elementForProperties\n ? <OpacityPanel value={currentOpacity} onChange={handleOpacityChange} />\n : null;\n\n // Font size panel — only relevant for text elements (and circle\n // text via getEffectiveFontSize). useTextToolbar's fontSize value\n // tracks the active text element's size and handleFontSizeChange\n // routes the update through the right element-specific path.\n const fontSizePanel = isFontSizePanelOpen\n ? (\n <FontSizePanel\n value={textToolbar.fontSize}\n onChange={textToolbar.handleFontSizeChange}\n widthValue={currentTextWidth}\n onWidthChange={handleTextWidthChange}\n />\n )\n : null;\n\n const shapeCornerRadiusPanel = isShapeCornerRadiusPanelOpen && shapeElement\n ? <ShapeCornerRadiusPanel value={currentShapeBorderRadius} onChange={handleShapeBorderRadiusChange} />\n : null;\n\n const shapeTransparencyPanel = isShapeTransparencyPanelOpen && shapeElement\n ? <ShapeTransparencyPanel value={currentShapeOpacity} onChange={handleShapeOpacityChange} />\n : null;\n\n const shapeSidesPanel = isShapeSidesPanelOpen && shapeElement\n ? <ShapeSidesPanel value={currentShapeSides} onChange={handleShapeSidesChange} />\n : null;\n\n const shapePointsPanel = isShapePointsPanelOpen && shapeElement\n ? <ShapePointsPanel value={currentShapePoints} onChange={handleShapePointsChange} />\n : null;\n\n const shapeInnerRadiusPanel = isShapeInnerRadiusPanelOpen && shapeElement\n ? <ShapeInnerRadiusPanel value={currentShapeInnerRadius} onChange={handleShapeInnerRadiusChange} />\n : null;\n\n const shapeColorPanel = isShapeColorPanelOpen && shapeElement\n ? <ShapeColorPanel value={currentShapeFillColor} onChange={handleShapeFillColorChange} documentColors={colorPickerDocumentColors} imageColors={colorPickerImageColors} />\n : null;\n\n const textColorPanel = isTextColorPanelOpen && elementForProperties\n ? <TextColorPanel value={colorPickerValue} onChange={colorPickerOnChange} documentColors={colorPickerDocumentColors} imageColors={colorPickerImageColors} />\n : null;\n\n const knockoutPanel = isKnockoutPanelOpen && elementForProperties\n ? <CompositingPanel\n mode={compositingMode}\n fill={compositingFill}\n stroke={compositingStroke}\n scope={compositingScope}\n onModeChange={handleCompositingModeChange}\n onFillChange={handleCompositingFillChange}\n onStrokeChange={handleCompositingStrokeChange}\n onScopeChange={handleCompositingScopeChange}\n />\n : null;\n\n const strokePanel = isStrokePanelOpen && elementForProperties\n ? <StrokePanel\n stroke={elementForProperties.stroke}\n onChange={handleStrokeChange}\n documentColors={colorPickerDocumentColors}\n imageColors={colorPickerImageColors}\n />\n : null;\n\n const distressTexturePanel = isDistressTexturePanelOpen && elementForProperties\n ? <DistressTexturePanel\n textureUrl={elementForProperties.distressEffect?.textureUrl ?? ''}\n opacity={Math.round((elementForProperties.distressEffect?.textureOpacity ?? 0.5) * 100)}\n onTextureChange={handleDistressTextureChange}\n onOpacityChange={handleDistressOpacityChange}\n />\n : null;\n\n const quickMask = elementForProperties?.masks?.find((m: { id: string }) => m.id === 'quick-image-mask');\n const imageMaskPanel = isImageMaskPanelOpen && elementForProperties\n ? <ImageMaskPanel\n imageUrl={(quickMask?.maskElement as { imageUrl?: string })?.imageUrl ?? ''}\n maskType={(quickMask?.type as 'clip' | 'alpha' | 'luma') ?? 'clip'}\n opacity={Math.round((quickMask?.opacity ?? 1) * 100)}\n inverted={quickMask?.inverted ?? false}\n onImageChange={handleImageMaskImageChange}\n onMaskTypeChange={handleImageMaskTypeChange}\n onOpacityChange={handleImageMaskOpacityChange}\n onInvertedChange={handleImageMaskInvertedChange}\n />\n : null;\n\n // ── Empty state ────────────────────────────────────────────────────────\n const emptyStateContent =\n mode === 'embedded' && !selectedElement && !editArtboardMode ? (\n emptyStateRender ? (\n <div className=\"toolbar-empty-state\">{emptyStateRender}</div>\n ) : emptyStateMessage !== null ? (\n <div\n className=\"toolbar-empty-state\"\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '16px 24px',\n color: 'var(--foreground)',\n opacity: 0.5,\n fontSize: '14px',\n textAlign: 'center',\n }}\n >\n {emptyStateMessage}\n </div>\n ) : null\n ) : null;\n\n // ── Artboard edit mode content (embedded only) ────────────────────────\n const artboardEditContent =\n mode === 'embedded' && editArtboardMode && !selectedElement && artboardManager.getActiveArtboard() ? (\n <div className=\"px-4 py-3 flex flex-col gap-3\">\n <CollapsedToolbarHeader\n icon=\"lucide:palette\"\n label=\"Artboard Properties\"\n onClose={() => onEditArtboardModeChange?.(false)}\n closeButtonStyle=\"done\"\n />\n <ArtboardDistressPanel\n distressTexture={artboardManager.getActiveArtboard()!.distressTexture}\n onChange={(distressTexture) => {\n const currentArtboard = artboardManager.getActiveArtboard()!;\n if (onArtboardUpdate) {\n onArtboardUpdate(\n currentArtboard.id,\n { distressTexture: currentArtboard.distressTexture },\n { distressTexture }\n );\n } else {\n artboardManager.updateArtboard(currentArtboard.id, { distressTexture });\n refreshArtboards();\n }\n }}\n />\n <ArtboardImageMaskPanel\n imageMask={artboardManager.getActiveArtboard()!.imageMask}\n onChange={(imageMask) => {\n const currentArtboard = artboardManager.getActiveArtboard()!;\n if (onArtboardUpdate) {\n onArtboardUpdate(\n currentArtboard.id,\n { imageMask: currentArtboard.imageMask },\n { imageMask }\n );\n } else {\n artboardManager.updateArtboard(currentArtboard.id, { imageMask });\n refreshArtboards();\n }\n }}\n />\n </div>\n ) : null;\n\n // ── Embedded content ───────────────────────────────────────────────────\n const embeddedContent =\n mode === 'embedded' ? (\n <EmbeddedToolbarLayout\n toolbarContent={toolbarContent}\n innerContentRef={innerContentRef}\n shouldRender={shouldRender}\n isExiting={isExiting}\n transitionHeight={transitionHeight}\n emptyStateContent={artboardEditContent || emptyStateContent}\n isCornerRadiusPanelOpen={isCornerRadiusPanelOpen}\n isCropPanelOpen={isCropPanelOpen}\n isRotationPanelOpen={isRotationPanelOpen}\n isOpacityPanelOpen={isOpacityPanelOpen}\n isFontSizePanelOpen={isFontSizePanelOpen}\n isShapeCornerRadiusPanelOpen={isShapeCornerRadiusPanelOpen}\n isShapeTransparencyPanelOpen={isShapeTransparencyPanelOpen}\n isShapeSidesPanelOpen={isShapeSidesPanelOpen}\n isShapePointsPanelOpen={isShapePointsPanelOpen}\n isShapeInnerRadiusPanelOpen={isShapeInnerRadiusPanelOpen}\n isShapeColorPanelOpen={isShapeColorPanelOpen}\n isTextColorPanelOpen={isTextColorPanelOpen}\n isStrokePanelOpen={isStrokePanelOpen}\n isKnockoutPanelOpen={isKnockoutPanelOpen}\n isDistressTexturePanelOpen={isDistressTexturePanelOpen}\n isImageMaskPanelOpen={isImageMaskPanelOpen}\n cornerRadiusPanel={cornerRadiusPanel}\n cropPanelContent={cropPanelContent}\n rotationPanel={rotationPanel}\n opacityPanel={opacityPanel}\n fontSizePanel={fontSizePanel}\n shapeCornerRadiusPanel={shapeCornerRadiusPanel}\n shapeTransparencyPanel={shapeTransparencyPanel}\n shapeSidesPanel={shapeSidesPanel}\n shapePointsPanel={shapePointsPanel}\n shapeInnerRadiusPanel={shapeInnerRadiusPanel}\n shapeColorPanel={shapeColorPanel}\n textColorPanel={textColorPanel}\n strokePanel={strokePanel}\n knockoutPanel={knockoutPanel}\n distressTexturePanel={distressTexturePanel}\n imageMaskPanel={imageMaskPanel}\n />\n ) : null;\n\n // ── Floating mode secondary panels ─────────────────────────────────────\n const panelWidth = toolbarDimensions.width > 0 ? Math.max(toolbarDimensions.width, 200) : 280;\n\n const floatingCornerRadiusPanel =\n mode === 'floating' && isCornerRadiusPanelOpen && elementForProperties?.transformType === 'image' && toolbarPosition ? (\n <FloatingCornerRadiusPanel\n toolbarPosition={toolbarPosition}\n toolbarHeight={toolbarDimensions.height || 56}\n panelWidth={panelWidth}\n value={currentBorderRadius}\n onChange={handleBorderRadiusChange}\n />\n ) : null;\n\n const floatingCropPanel =\n mode === 'floating' && isCropPanelOpen && elementForProperties?.transformType === 'image' && toolbarPosition ? (\n <FloatingCropPanel\n toolbarPosition={toolbarPosition}\n toolbarHeight={toolbarDimensions.height || 56}\n element={elementForProperties as ImageElement}\n onElementUpdate={elementUpdateHandler}\n />\n ) : null;\n\n // ══════════════════════════════════════════════════════════════════════════\n // FINAL RENDER\n // ══════════════════════════════════════════════════════════════════════════\n\n return (\n <>\n {/* Contextual toolbar - use portal for floating mode to escape parent overflow:hidden */}\n {mode === 'floating' && typeof document !== 'undefined'\n ? createPortal(\n <>\n {toolbarContent}\n {floatingCornerRadiusPanel}\n {floatingCropPanel}\n </>,\n document.body\n )\n : embeddedContent}\n\n {/* Artboard Properties Toolbar - Show when no element is selected (floating mode only) */}\n {mode !== 'embedded' && !selectedElement && artboardManager.getActiveArtboard() && onArtboardUpdate && (\n <ArtboardPropertiesToolbar\n artboard={artboardManager.getActiveArtboard()!}\n artboards={artboards}\n onArtboardUpdate={(updatedArtboard) => {\n const currentArtboard = artboardManager.getActiveArtboard()!;\n onArtboardUpdate(\n currentArtboard.id,\n {\n backgroundColor: currentArtboard.backgroundColor,\n backgroundType: currentArtboard.backgroundType,\n backgroundTexture: currentArtboard.backgroundTexture,\n exportBackground: currentArtboard.exportBackground,\n },\n {\n backgroundColor: updatedArtboard.backgroundColor,\n backgroundType: updatedArtboard.backgroundType,\n backgroundTexture: updatedArtboard.backgroundTexture,\n exportBackground: updatedArtboard.exportBackground,\n }\n );\n }}\n onRenameArtboard={(artboardId: string, newName: string) => {\n artboardManager.renameArtboard(artboardId, newName);\n refreshArtboards();\n }}\n onDeleteArtboard={(artboardId: string) => {\n artboardManager.deleteArtboard(artboardId);\n refreshArtboards();\n }}\n artboardScreenBounds={artboardScreenBounds}\n />\n )}\n\n {/* Shape Type Drawer - internal drawer when no external callback is provided */}\n {!onOpenShapeTypeDrawer && elementForProperties?.transformType === 'shape' && (\n <ShapeTypeDrawer\n isOpen={isShapeTypeDrawerOpen}\n onClose={() => setIsShapeTypeDrawerOpen(false)}\n onSelectType={handleShapeTypeChange}\n currentType={(elementForProperties as ShapeElement).transformData.shapeType}\n />\n )}\n </>\n );\n};\n\nexport default ContextualToolbars;\n","/**\n * Dropdown - Reusable dropdown container with click-outside handling\n *\n * Features:\n * - Built-in click-outside detection\n * - Flexible positioning (top/bottom/left/right)\n * - Flexible alignment (start/center/end)\n * - Auto click protection for canvas\n * - Slide-down animation\n * - Z-index management\n *\n * Usage:\n * ```tsx\n * <Dropdown\n * trigger={<Button>Open</Button>}\n * isOpen={isOpen}\n * onToggle={setIsOpen}\n * position=\"bottom\"\n * align=\"center\"\n * >\n * <DropdownMenu>\n * <MenuItem>Item 1</MenuItem>\n * <MenuItem>Item 2</MenuItem>\n * </DropdownMenu>\n * </Dropdown>\n * ```\n */\n\nimport React, { ReactNode, useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { clickProtection } from '../../utils/clickProtection';\n\ntype DropdownPosition = 'top' | 'bottom' | 'left' | 'right';\ntype DropdownAlign = 'start' | 'center' | 'end';\n\nexport interface DropdownProps {\n /** Trigger element that opens the dropdown when clicked */\n trigger: ReactNode;\n /** Dropdown content */\n children: ReactNode;\n /** Whether the dropdown is currently open */\n isOpen: boolean;\n /** Callback when dropdown open state changes */\n onToggle: (open: boolean) => void;\n /** Position relative to trigger (default: bottom) */\n position?: DropdownPosition;\n /** Alignment along the position axis (default: start) */\n align?: DropdownAlign;\n /** Distance from trigger in pixels (default: 8) */\n offset?: number;\n /** Protect canvas from clicks when opening (default: true) */\n protectClick?: boolean;\n /** Additional CSS classes for container */\n className?: string;\n /** Additional CSS classes for content */\n contentClassName?: string;\n}\n\nconst Dropdown: React.FC<DropdownProps> = ({\n trigger,\n children,\n isOpen,\n onToggle,\n position = 'bottom',\n align = 'start',\n offset = 8,\n protectClick = true,\n className = '',\n contentClassName = '',\n}) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const [dropdownStyle, setDropdownStyle] = useState<React.CSSProperties>({});\n const [useFixed, setUseFixed] = useState(false);\n\n const handleTriggerClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (!isOpen && protectClick) {\n clickProtection.protectNextClick();\n }\n onToggle(!isOpen);\n };\n\n // Click-outside detection: check both container and portal content\n useEffect(() => {\n if (!isOpen) return;\n\n let cleanup = () => {};\n const timer = setTimeout(() => {\n const handleMouseDown = (event: MouseEvent) => {\n const target = event.target as Node;\n const isInsideContainer = containerRef.current?.contains(target);\n const isInsideContent = contentRef.current?.contains(target);\n if (!isInsideContainer && !isInsideContent) {\n onToggle(false);\n }\n };\n document.addEventListener('mousedown', handleMouseDown);\n cleanup = () => document.removeEventListener('mousedown', handleMouseDown);\n }, 0);\n\n return () => {\n clearTimeout(timer);\n cleanup();\n };\n }, [isOpen, onToggle]);\n\n // Escape key handler: close dropdown and return focus to trigger\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n e.preventDefault();\n onToggle(false);\n const focusable = triggerRef.current?.querySelector<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n focusable?.focus();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [isOpen, onToggle]);\n\n // Reset useFixed when dropdown closes so next open starts fresh\n useEffect(() => {\n if (!isOpen) {\n setUseFixed(false);\n }\n }, [isOpen]);\n\n // Calculate position to keep dropdown on screen\n useEffect(() => {\n if (!isOpen || !triggerRef.current || !contentRef.current) return;\n\n const calculatePosition = () => {\n const trigger = triggerRef.current;\n const content = contentRef.current;\n if (!trigger || !content) return;\n\n const triggerRect = trigger.getBoundingClientRect();\n const contentRect = content.getBoundingClientRect();\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const padding = 16;\n\n // Calculate ideal position\n let top = 0;\n let left = 0;\n\n // Position and alignment logic based on position direction\n if (position === 'bottom' || position === 'top') {\n // Vertical positioning\n if (position === 'bottom') {\n top = triggerRect.bottom + offset;\n } else {\n top = triggerRect.top - contentRect.height - offset;\n }\n\n // Horizontal alignment\n if (align === 'start') {\n left = triggerRect.left;\n } else if (align === 'end') {\n // Align right edges: menu's right edge = button's right edge\n left = triggerRect.right - contentRect.width;\n } else if (align === 'center') {\n left = triggerRect.left + (triggerRect.width - contentRect.width) / 2;\n }\n } else if (position === 'left' || position === 'right') {\n // Horizontal positioning\n if (position === 'left') {\n left = triggerRect.left - contentRect.width - offset;\n } else {\n left = triggerRect.right + offset;\n }\n\n // Vertical alignment\n if (align === 'start') {\n top = triggerRect.top;\n } else if (align === 'end') {\n top = triggerRect.bottom - contentRect.height;\n } else if (align === 'center') {\n top = triggerRect.top + (triggerRect.height - contentRect.height) / 2;\n }\n }\n\n // Only adjust for viewport boundaries if NOT using 'end' alignment\n // For 'end' alignment, we want to maintain the right edge alignment\n if (align !== 'end') {\n // Check if dropdown would go off right edge\n if (left + contentRect.width > viewportWidth - padding) {\n left = viewportWidth - contentRect.width - padding;\n }\n\n // Check if dropdown would go off left edge\n if (left < padding) {\n left = padding;\n }\n } else {\n // For 'end' alignment, only prevent going off left edge\n if (left < padding) {\n left = padding;\n }\n }\n\n // Check if dropdown would go off bottom edge\n if (top + contentRect.height > viewportHeight - padding) {\n // Try to flip to top if there's more space\n const spaceAbove = triggerRect.top;\n const spaceBelow = viewportHeight - triggerRect.bottom;\n if (spaceAbove > spaceBelow) {\n top = triggerRect.top - contentRect.height - offset;\n }\n }\n\n // Check if dropdown would go off top edge\n if (top < padding) {\n top = padding;\n }\n\n // Calculate max width to ensure it fits in viewport\n const maxWidth = viewportWidth - (padding * 2);\n\n setUseFixed(true);\n setDropdownStyle({\n position: 'fixed',\n top: `${top}px`,\n left: `${left}px`,\n maxWidth: `${maxWidth}px`,\n visibility: 'visible',\n });\n };\n\n requestAnimationFrame(calculatePosition);\n }, [isOpen, position, align, offset]);\n\n // Dropdown content - rendered in a portal to escape parent overflow:hidden\n // Start with visibility:hidden until position is calculated to prevent flash at wrong location\n // IMPORTANT: data-preserve-selection prevents clicks from deselecting canvas elements\n const dropdownContent = isOpen && (\n <div\n ref={contentRef}\n className={`z-dropdown ${contentClassName}`.trim()}\n data-preserve-selection\n style={\n useFixed\n ? dropdownStyle\n : {\n // Initially hidden and positioned off-screen until useEffect calculates position\n position: 'fixed',\n visibility: 'hidden',\n top: 0,\n left: 0,\n }\n }\n >\n {children}\n </div>\n );\n\n return (\n <div className={`relative inline-flex ${className}`.trim()} ref={containerRef}>\n <div ref={triggerRef} onClick={handleTriggerClick}>{trigger}</div>\n\n {/* Render dropdown in portal to escape overflow:hidden clipping */}\n {dropdownContent && createPortal(dropdownContent, document.body)}\n </div>\n );\n};\n\nexport default Dropdown;\n","/**\n * DropdownMenu - Styled container for dropdown menu content\n *\n * Usage:\n * ```tsx\n * <Dropdown ...>\n * <DropdownMenu>\n * <MenuItem>Item 1</MenuItem>\n * <MenuItem>Item 2</MenuItem>\n * </DropdownMenu>\n * </Dropdown>\n * ```\n */\n\nimport React, { ReactNode } from 'react';\n\nexport interface DropdownMenuProps {\n children: ReactNode;\n className?: string;\n minWidth?: string;\n maxHeight?: string;\n}\n\nconst DropdownMenu: React.FC<DropdownMenuProps> = ({ children, className = '', minWidth = '160px', maxHeight }) => {\n const maxHeightClass = maxHeight ? `max-h-[${maxHeight}]` : '';\n const minWidthStyle = { minWidth };\n\n // bg-surface (not bg-bg-primary) so the dropdown picks up the design\n // system's elevated surface token. `--bg-primary` resolves to the page\n // background in dark mode and gave dropdowns zero elevation against\n // the page — the wrong default for a raised menu.\n return (\n <div\n role=\"menu\"\n className={`flex flex-col gap-px rounded-xl border border-border-primary bg-surface p-xs shadow-md ${maxHeightClass} ${className}`.trim()}\n style={minWidthStyle}\n >\n {children}\n </div>\n );\n};\n\nexport default DropdownMenu;\n","/**\n * MenuItem - Reusable menu item component\n *\n * Features:\n * - Icon support\n * - Active state with checkmark\n * - Keyboard shortcut display\n * - Disabled state\n * - Click handling\n *\n * Usage:\n * ```tsx\n * <MenuItem\n * icon={<Icon />}\n * label=\"Save\"\n * shortcut=\"⌘S\"\n * active={false}\n * onClick={handleSave}\n * />\n * ```\n */\n\nimport React from 'react';\n\nexport interface MenuItemProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n icon?: React.ReactNode;\n label: string;\n shortcut?: string;\n active?: boolean;\n disabled?: boolean;\n onClick?: () => void;\n className?: string;\n children?: React.ReactNode;\n}\n\nconst MenuItem: React.FC<MenuItemProps> = ({\n icon,\n label,\n shortcut,\n active = false,\n disabled = false,\n onClick,\n className = '',\n children,\n ...props\n}) => {\n const baseClasses = [\n 'flex items-center gap-md',\n 'px-lg py-md',\n 'bg-transparent border-none',\n 'rounded-lg',\n 'text-text-primary text-base font-normal',\n 'cursor-pointer',\n 'transition-all duration-fast',\n 'text-left w-full',\n ];\n\n const stateClasses = [\n active ? 'bg-accent-light font-medium' : '',\n disabled ? 'opacity-disabled cursor-not-allowed' : 'hover:bg-bg-hover',\n ];\n\n const combinedClassName = [...baseClasses, ...stateClasses, className].filter(Boolean).join(' ');\n\n const handleClick = () => {\n if (!disabled && onClick) {\n onClick();\n }\n };\n\n return (\n <button role=\"menuitem\" className={combinedClassName} onClick={handleClick} disabled={disabled} type=\"button\" {...props}>\n {icon && <span className=\"flex shrink-0 items-center\">{icon}</span>}\n\n <span className=\"flex-1\">{children || label}</span>\n\n {shortcut && <span className=\"ml-auto text-sm text-text-muted\">{shortcut}</span>}\n\n {active && !shortcut && (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" className=\"ml-auto shrink-0\">\n <path d=\"M13 4L6 11L3 8\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )}\n </button>\n );\n};\n\nexport default MenuItem;\n","/**\n * Panel - Collapsible panel with optional enable/disable toggle\n *\n * A reusable panel component that eliminates boilerplate for property panels.\n * Supports:\n * - Simple panel (no toggle, no expand)\n * - Collapsible panel (no toggle, with expand/collapse)\n * - Toggle panel (with enable/disable toggle and expand/collapse)\n *\n * @example\n * // Simple panel\n * <Panel title=\"Settings\">\n * <p>Panel content</p>\n * </Panel>\n *\n * @example\n * // Collapsible panel\n * <Panel title=\"Settings\" collapsible expanded={expanded} onExpandChange={setExpanded}>\n * <p>Panel content</p>\n * </Panel>\n *\n * @example\n * // Toggle panel (enable/disable + expand/collapse)\n * <Panel\n * title=\"Stroke\"\n * enableable\n * enabled={enabled}\n * onEnabledChange={setEnabled}\n * expanded={expanded}\n * onExpandChange={setExpanded}\n * >\n * <p>Panel content (only shown when enabled and expanded)</p>\n * </Panel>\n */\n\nimport React from 'react';\n\nexport interface PanelProps {\n /** Panel title */\n title: string;\n\n /** Panel icon (optional) */\n icon?: React.ReactNode;\n\n /** Panel content */\n children: React.ReactNode;\n\n /** Enable toggle functionality (checkbox to enable/disable) */\n enableable?: boolean;\n\n /** Enabled state (only used if enableable=true) */\n enabled?: boolean;\n\n /** Callback when enabled state changes */\n onEnabledChange?: (enabled: boolean) => void;\n\n /** Enable expand/collapse functionality */\n collapsible?: boolean;\n\n /** Expanded state (only used if collapsible=true or enableable=true) */\n expanded?: boolean;\n\n /** Callback when expanded state changes */\n onExpandChange?: (expanded: boolean) => void;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport const Panel: React.FC<PanelProps> = ({\n title,\n icon,\n children,\n enableable = false,\n enabled = false,\n onEnabledChange,\n collapsible = false,\n expanded = true,\n onExpandChange,\n className = '',\n}) => {\n // Determine if content should be shown\n const showContent = enableable ? enabled && expanded : collapsible ? expanded : true;\n\n // Determine if expand button should be shown\n const showExpandButton = (enableable && enabled) || collapsible;\n\n const handleToggle = () => {\n if (onEnabledChange) {\n onEnabledChange(!enabled);\n }\n };\n\n const handleExpandToggle = () => {\n if (onExpandChange) {\n onExpandChange(!expanded);\n }\n };\n\n return (\n <div className={`rounded-xl border border-border-primary bg-bg-secondary p-xl ${className}`}>\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n {/* Left side: toggle + title */}\n <div className=\"flex items-center gap-md\">\n {enableable && (\n <label className=\"flex cursor-pointer items-center\">\n <input\n type=\"checkbox\"\n checked={enabled}\n onChange={handleToggle}\n className=\"h-4 w-4 cursor-pointer rounded border-border-primary bg-bg-input accent-accent-primary\"\n />\n </label>\n )}\n <div className=\"flex items-center gap-md\">\n {icon && <span className=\"flex items-center text-text-secondary\">{icon}</span>}\n <h3 className=\"text-xl font-semibold text-text-primary\">{title}</h3>\n </div>\n </div>\n\n {/* Right side: expand button */}\n {showExpandButton && (\n <button\n onClick={handleExpandToggle}\n className=\"rounded-lg border-none bg-transparent px-md py-xs text-base text-text-muted transition-colors duration-fast hover:text-text-primary\"\n title={expanded ? 'Collapse' : 'Expand'}\n >\n {expanded ? '▼' : '▶'}\n </button>\n )}\n </div>\n\n {/* Content */}\n {showContent && <div className=\"mt-xl flex flex-col gap-xl\">{children}</div>}\n </div>\n );\n};\n\nexport default Panel;\n","/**\n * ControlGroup - Label + control wrapper with consistent spacing\n *\n * Provides a consistent layout for form controls with labels.\n * Eliminates repeated label + wrapper markup.\n *\n * @example\n * <ControlGroup label=\"Width\">\n * <input type=\"range\" ... />\n * </ControlGroup>\n *\n * @example\n * <ControlGroup label=\"Color\" inline>\n * <ColorPickerDropdown ... />\n * </ControlGroup>\n */\n\nimport React from 'react';\n\nexport interface ControlGroupProps {\n /** Label text */\n label: string;\n\n /** Optional label suffix (e.g., value display \"50px\") */\n labelSuffix?: React.ReactNode;\n\n /** Control element(s) */\n children: React.ReactNode;\n\n /** Inline layout (label and control side-by-side) */\n inline?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport const ControlGroup: React.FC<ControlGroupProps> = ({\n label,\n labelSuffix,\n children,\n inline = false,\n className = '',\n}) => {\n return (\n <div className={`flex ${inline ? 'items-center justify-between' : 'flex-col'} gap-sm ${className}`}>\n {/* Label */}\n <label className=\"flex items-center justify-between text-base font-medium text-text-secondary\">\n <span>{label}</span>\n {labelSuffix && <span className=\"font-semibold text-accent-primary\">{labelSuffix}</span>}\n </label>\n\n {/* Control */}\n <div className={inline ? 'flex-shrink-0' : ''}>{children}</div>\n </div>\n );\n};\n\nexport default ControlGroup;\n","/**\n * ButtonGroup - Group of buttons with active state\n *\n * A reusable button group for selecting one option from multiple choices.\n * Eliminates 10-15 lines of repeated button group markup.\n *\n * @example\n * <ButtonGroup\n * options={[\n * { value: 'butt', label: 'Butt', tooltip: 'Flat edges' },\n * { value: 'round', label: 'Round', tooltip: 'Rounded edges' },\n * { value: 'square', label: 'Square', tooltip: 'Extended square edges' }\n * ]}\n * value={lineCap}\n * onChange={setLineCap}\n * />\n */\n\nimport React from 'react';\n\nexport interface ButtonGroupOption<T = string> {\n /** Option value */\n value: T;\n\n /** Display label */\n label: string;\n\n /** Optional icon */\n icon?: React.ReactNode;\n\n /** Optional tooltip */\n tooltip?: string;\n\n /** Disabled state */\n disabled?: boolean;\n}\n\nexport interface ButtonGroupProps<T = string> {\n /** Available options */\n options: ButtonGroupOption<T>[];\n\n /** Current value */\n value: T;\n\n /** Callback when value changes */\n onChange: (value: T) => void;\n\n /** Full width buttons */\n fullWidth?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport function ButtonGroup<T = string>({\n options,\n value,\n onChange,\n fullWidth = true,\n className = '',\n}: ButtonGroupProps<T>) {\n return (\n <div className={`flex gap-sm ${className}`}>\n {options.map((option) => {\n const isActive = option.value === value;\n\n return (\n <button\n key={String(option.value)}\n onClick={() => !option.disabled && onChange(option.value)}\n disabled={option.disabled}\n title={option.tooltip}\n className={` ${fullWidth ? 'flex-1' : ''} flex items-center justify-center gap-xs rounded-lg border px-md py-sm text-base font-medium transition-all duration-fast ${\n isActive\n ? 'border-accent-primary bg-accent-primary text-text-on-accent'\n : 'border-border-primary bg-bg-tertiary text-text-secondary hover:border-border-secondary hover:bg-bg-hover hover:text-text-primary'\n } ${option.disabled ? 'cursor-not-allowed opacity-disabled' : 'cursor-pointer'} `}\n >\n {option.icon && <span className=\"flex items-center\">{option.icon}</span>}\n <span>{option.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n\nexport default ButtonGroup;\n","/**\n * Toggle - Styled checkbox for enable/disable controls\n *\n * A consistent toggle/checkbox component with label.\n * Eliminates 5-10 lines of repeated toggle markup.\n *\n * @example\n * <Toggle\n * label=\"Enable Stroke\"\n * checked={enabled}\n * onChange={setEnabled}\n * />\n *\n * @example\n * <Toggle\n * label=\"Flip Horizontal\"\n * checked={flipH}\n * onChange={setFlipH}\n * icon={<LuFlipHorizontal2 />}\n * />\n */\n\nimport React from 'react';\n\nexport interface ToggleProps {\n /** Label text */\n label: string;\n\n /** Optional icon */\n icon?: React.ReactNode;\n\n /** Checked state */\n checked: boolean;\n\n /** Callback when checked state changes */\n onChange: (checked: boolean) => void;\n\n /** Disabled state */\n disabled?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport const Toggle: React.FC<ToggleProps> = ({ label, icon, checked, onChange, disabled = false, className = '' }) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <label\n className={`flex cursor-pointer items-center gap-md ${disabled ? 'cursor-not-allowed opacity-disabled' : ''} ${className}`}\n >\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n className=\"h-4 w-4 cursor-pointer rounded border-border-primary bg-bg-input accent-accent-primary disabled:cursor-not-allowed\"\n />\n <span className=\"flex items-center gap-sm text-base font-medium text-text-primary\">\n {icon && <span className=\"flex items-center text-text-secondary\">{icon}</span>}\n <span>{label}</span>\n </span>\n </label>\n );\n};\n\nexport default Toggle;\n","/**\n * Switch - Toggle switch component\n *\n * Features:\n * - Accessible checkbox input\n * - Smooth animation\n * - Fixed border radius (not affected by theme)\n * - Support for labels\n *\n * Usage:\n * ```tsx\n * <Switch\n * checked={isEnabled}\n * onChange={setIsEnabled}\n * label=\"Enable feature\"\n * />\n * ```\n */\n\nimport React from 'react';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n label?: string;\n disabled?: boolean;\n className?: string;\n}\n\nconst Switch: React.FC<SwitchProps> = ({\n checked,\n onChange,\n label,\n disabled = false,\n className = '',\n}) => {\n const handleChange = () => {\n if (!disabled) {\n onChange(!checked);\n }\n };\n\n return (\n <label\n className={`flex items-center gap-md cursor-pointer select-none ${disabled ? 'opacity-50 cursor-not-allowed' : ''} ${className}`.trim()}\n >\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n className=\"absolute opacity-0 w-0 h-0 peer\"\n />\n <span\n className={`\n relative inline-block w-9 h-5 rounded-[999px] transition-colors\n ${checked ? 'bg-accent-primary' : 'bg-bg-tertiary'}\n after:content-[''] after:absolute after:top-[2px] after:left-[2px]\n after:w-4 after:h-4 after:bg-white after:rounded-full\n after:transition-transform after:shadow-md\n ${checked ? 'after:translate-x-4' : ''}\n `.trim()}\n />\n {label && <span className=\"text-md text-text-primary font-medium\">{label}</span>}\n </label>\n );\n};\n\nexport default Switch;\n","/**\n * SecondaryToolbar - Overflow toolbar for uncommonly used controls\n *\n * Renders as a proper toolbar positioned below the primary toolbar,\n * right-aligned with a gap above it. Used for 3-dot overflow menus.\n *\n * Features:\n * - Same height and styling as primary toolbar\n * - Positioned below trigger, right-aligned\n * - Gap between primary and secondary toolbar\n * - Click-outside handling via Dropdown primitive\n *\n * Usage:\n * ```tsx\n * <SecondaryToolbar\n * isOpen={showMore}\n * onToggle={setShowMore}\n * trigger={<Button variant=\"toolbar\" icon={<DotsIcon />} />}\n * >\n * <Button variant=\"toolbar\" icon={<Icon />} onClick={handler} />\n * <Switch checked={value} onChange={handler} label=\"Label\" />\n * </SecondaryToolbar>\n * ```\n */\n\nimport React from 'react';\nimport { Icon } from '@iconify/react';\nimport { Button, Tooltip, TooltipTrigger, TooltipContent } from '../ui';\nimport { Dropdown } from './index';\n\nexport interface SecondaryToolbarProps {\n isOpen: boolean;\n onToggle: (open: boolean) => void;\n trigger?: React.ReactNode;\n children: React.ReactNode;\n}\n\nconst SecondaryToolbar: React.FC<SecondaryToolbarProps> = ({\n isOpen,\n onToggle,\n trigger,\n children,\n}) => {\n // Default trigger: 3-dot icon button with tooltip\n // The Button has its own onClick to ensure clicks are captured even when\n // wrapped by Radix's TooltipTrigger which can interfere with event bubbling\n const defaultTrigger = (\n <Tooltip delayDuration={0}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"toolbar\"\n onClick={(e) => {\n // Stop propagation to prevent Dropdown's wrapper div from double-toggling\n e.stopPropagation();\n onToggle(!isOpen);\n }}\n >\n <Icon icon=\"lucide:ellipsis-vertical\" className=\"size-6\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>More</p>\n </TooltipContent>\n </Tooltip>\n );\n\n return (\n <Dropdown\n isOpen={isOpen}\n onToggle={onToggle}\n trigger={trigger || defaultTrigger}\n position=\"bottom\"\n align=\"end\"\n offset={4}\n >\n {/* Secondary toolbar - matches primary toolbar styling */}\n <div className=\"flex items-center gap-sm bg-bg-primary border border-border-primary rounded-xl px-xl py-md shadow-sm h-[52px]\">\n {children}\n </div>\n </Dropdown>\n );\n};\n\nexport default SecondaryToolbar;\n","/**\n * MenuButton - Unified menu button for embedding\n * Combines save, open, export, and layers functionality\n */\n\nimport React, { useState, useRef } from 'react';\nimport { useEditor } from '../../contexts/EditorContext.js';\nimport { Icon } from '@iconify/react';\nimport { Button, Tooltip, TooltipTrigger, TooltipContent, icons } from '../ui';\nimport { Dropdown, DropdownMenu, MenuItem } from '../primitives';\nimport { ExportManager } from '../../utils/ExportManager.js';\nimport { ImportManager } from '../../utils/ImportManager.js';\nimport { createLogger } from '../../utils/logger.js';\nimport ShapeTypeDrawer from '../ShapeTypeDrawer.js';\nimport type { ShapeType } from '../../types/index.js';\n\nconst logger = createLogger('MenuButton');\n\nexport interface MenuButtonProps {\n /**\n * Whether the layers panel is open\n */\n isLayersPanelOpen?: boolean;\n\n /**\n * Callback when layers panel toggle is requested\n */\n onToggleLayersPanel?: () => void;\n\n /**\n * Callback when image browser should be opened\n * If provided, this will be called when user selects \"Add Image\" instead of using the default handler\n */\n onOpenImageBrowser?: () => void;\n\n /**\n * Additional menu items to append\n */\n additionalItems?: React.ReactNode;\n\n /**\n * Custom button icon\n */\n icon?: React.ReactNode;\n\n /**\n * Button tooltip\n */\n tooltip?: string;\n\n /**\n * Additional CSS class name\n */\n className?: string;\n}\n\n/**\n * MenuButton - Unified menu for save/open/export/layers\n * Must be used within EditorProvider\n *\n * @example\n * ```tsx\n * <EditorProvider>\n * <MenuButton\n * isLayersPanelOpen={layersOpen}\n * onToggleLayersPanel={() => setLayersOpen(!layersOpen)}\n * />\n * </EditorProvider>\n * ```\n */\nexport const MenuButton: React.FC<MenuButtonProps> = ({\n isLayersPanelOpen = false,\n onToggleLayersPanel,\n onOpenImageBrowser,\n additionalItems,\n icon = <Icon icon={icons.menu} className=\"size-6\" />,\n tooltip = 'Menu',\n className,\n}) => {\n const {\n artboardManager,\n elements,\n canvasRef,\n handleLoadWorkspace,\n handleAddElement,\n } = useEditor();\n\n const [isOpen, setIsOpen] = useState(false);\n const [addMenuOpen, setAddMenuOpen] = useState(false);\n const [isShapeTypeDrawerOpen, setIsShapeTypeDrawerOpen] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n // Save workspace\n const handleSave = () => {\n try {\n const freshArtboards = artboardManager.getAllArtboards();\n ExportManager.exportToJSON(freshArtboards, elements, artboardManager);\n setIsOpen(false);\n } catch (error) {\n logger.error('Failed to save workspace:', error);\n alert('Failed to save workspace. Please try again.');\n }\n };\n\n // Open file picker\n const handleLoadClick = () => {\n fileInputRef.current?.click();\n setIsOpen(false);\n };\n\n // Handle file selection\n const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n\n try {\n const result = await ImportManager.importFromJSON(file);\n\n if (result.success && result.artboards && result.elements) {\n const validation = ImportManager.validateImportedData(result.artboards, result.elements);\n\n if (!validation.valid) {\n const proceed = confirm(\n `Found ${validation.errors.length} issue(s) in the file:\\n\\n` +\n validation.errors.slice(0, 3).join('\\n') +\n (validation.errors.length > 3 ? `\\n...and ${validation.errors.length - 3} more` : '') +\n '\\n\\nDo you want to load anyway?'\n );\n\n if (!proceed) {\n return;\n }\n }\n\n const summary = ImportManager.getImportSummary(result.artboards, result.elements);\n const proceed = confirm(\n `Load workspace with:\\n\\n` +\n `• ${summary.artboardCount} artboard(s): ${summary.artboardNames.join(', ')}\\n` +\n `• ${summary.elementCount} element(s)\\n\\n` +\n `This will replace your current workspace. Continue?`\n );\n\n if (proceed) {\n handleLoadWorkspace(result.artboards, result.elements, result.activeArtboardId || null);\n }\n } else {\n alert(`Failed to load: ${result.error || 'Unknown error'}`);\n }\n } catch (error) {\n logger.error('Failed to load workspace:', error);\n alert('Failed to load workspace. Please check the file and try again.');\n }\n\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n // Export image\n const handleExportImage = async () => {\n if (!canvasRef?.current) {\n alert('Canvas not available for export');\n return;\n }\n\n const activeArtboard = artboardManager.getActiveArtboard();\n if (!activeArtboard) {\n alert('No active artboard to export');\n return;\n }\n\n try {\n await ExportManager.exportArtboardToImage(activeArtboard, elements, canvasRef.current, {\n format: 'png',\n scale: 2,\n transparentBackground: false,\n });\n setIsOpen(false);\n } catch (error) {\n logger.error('Failed to export artboard:', error);\n alert('Failed to export artboard. Please try again.');\n }\n };\n\n // Add element\n const handleAddElementClick = async (elementType: string) => {\n // If adding an image and we have a custom handler, use it\n if (elementType === 'image' && onOpenImageBrowser) {\n onOpenImageBrowser();\n setIsOpen(false);\n setAddMenuOpen(false);\n return;\n }\n\n // For shapes, ask which shape first instead of defaulting\n // to a rectangle — users were confused that \"Add Shape\"\n // produced a fixed shape type with no obvious way to change it.\n if (elementType === 'shape') {\n setIsOpen(false);\n setAddMenuOpen(false);\n setIsShapeTypeDrawerOpen(true);\n return;\n }\n\n // Otherwise use default handler\n await handleAddElement(elementType);\n setIsOpen(false);\n setAddMenuOpen(false);\n };\n\n const handleSelectShapeType = async (shapeType: string) => {\n setIsShapeTypeDrawerOpen(false);\n await handleAddElement('shape', { shapeType: shapeType as ShapeType });\n };\n\n const elementTypes = [\n { type: 'custom', label: 'Text', icon: <Icon icon={icons.text} className=\"size-[18px]\" /> },\n { type: 'image', label: 'Image', icon: <Icon icon={icons.image} className=\"size-[18px]\" /> },\n { type: 'shape', label: 'Shape', icon: <Icon icon={icons.shapes} className=\"size-[18px]\" /> },\n { type: 'circle', label: 'Circle Text', icon: <Icon icon=\"lucide:circle\" className=\"size-[18px]\" /> },\n { type: 'wave', label: 'Wave Text', icon: <Icon icon=\"lucide:waves\" className=\"size-[18px]\" /> },\n { type: 'arch', label: 'Arch Text', icon: <Icon icon=\"lucide:arrow-up-from-dot\" className=\"size-[18px]\" /> },\n ];\n\n const MenuDivider = () => <div className=\"my-xs h-px bg-border-primary\" />;\n\n return (\n <>\n <Dropdown\n trigger={\n <Tooltip delayDuration={0}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n aria-label={tooltip}\n className={className}\n >\n {icon}\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>{tooltip}</p>\n </TooltipContent>\n </Tooltip>\n }\n isOpen={isOpen}\n onToggle={setIsOpen}\n position=\"bottom\"\n align=\"end\"\n >\n <DropdownMenu minWidth=\"200px\">\n {/* Add Element submenu */}\n <div\n style={{ position: 'relative' }}\n onMouseEnter={() => setAddMenuOpen(true)}\n onMouseLeave={() => setAddMenuOpen(false)}\n >\n <MenuItem icon={<Icon icon={icons.plus} className=\"size-[18px]\" />} label=\"Add Element\" />\n {addMenuOpen && (\n <div\n style={{\n position: 'absolute',\n left: '100%',\n top: 0,\n zIndex: 'var(--z-sticky)',\n }}\n >\n <DropdownMenu minWidth=\"180px\">\n {elementTypes.map((et) => (\n <MenuItem\n key={et.type}\n icon={et.icon}\n label={et.label}\n onClick={() => handleAddElementClick(et.type)}\n />\n ))}\n </DropdownMenu>\n </div>\n )}\n </div>\n\n <MenuDivider />\n\n <MenuItem icon={<Icon icon={icons.save} className=\"size-[18px]\" />} label=\"Save\" onClick={handleSave} />\n <MenuItem icon={<Icon icon={icons.folderOpen} className=\"size-[18px]\" />} label=\"Open\" onClick={handleLoadClick} />\n <MenuItem\n icon={<Icon icon={icons.download} className=\"size-[18px]\" />}\n label=\"Export Image\"\n onClick={handleExportImage}\n disabled={!canvasRef?.current}\n />\n\n {onToggleLayersPanel && (\n <>\n <MenuDivider />\n <MenuItem\n icon={<Icon icon={icons.layers} className=\"size-[18px]\" />}\n label={`${isLayersPanelOpen ? 'Hide' : 'Show'} Layers`}\n onClick={() => {\n onToggleLayersPanel();\n setIsOpen(false);\n }}\n />\n </>\n )}\n\n {additionalItems && (\n <>\n <MenuDivider />\n {additionalItems}\n </>\n )}\n </DropdownMenu>\n </Dropdown>\n\n {/* Hidden file input for loading */}\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\".json\"\n style={{ display: 'none' }}\n onChange={handleFileChange}\n />\n\n {/* Shape type picker — asks which shape to add */}\n <ShapeTypeDrawer\n isOpen={isShapeTypeDrawerOpen}\n onClose={() => setIsShapeTypeDrawerOpen(false)}\n onSelectType={handleSelectShapeType}\n />\n </>\n );\n};\n","/**\n * ZoomControls - Floating zoom control panel for interactive canvas mode\n *\n * Provides:\n * - Zoom in/out buttons\n * - Current zoom percentage display\n * - Fit to screen button\n * - Reset view (100%) button\n */\n\nimport React from 'react';\nimport { Icon } from '@iconify/react';\nimport { useViewportContext } from '../../contexts/ViewportContext.js';\nimport { Button, icons } from '../ui';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../ui';\n\nexport interface ZoomControlsProps {\n /** CSS class name for the container */\n className?: string;\n /** Position of the controls */\n position?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';\n /** Whether to show the fit-to-screen button */\n showFitButton?: boolean;\n /** Whether to show the reset button */\n showResetButton?: boolean;\n}\n\n/**\n * Floating zoom controls for interactive canvas mode\n */\nexport const ZoomControls: React.FC<ZoomControlsProps> = ({\n className,\n position = 'bottom-right',\n showFitButton = true,\n showResetButton = true,\n}) => {\n const { zoom, zoomIn, zoomOut, zoomToFit, resetView } = useViewportContext();\n\n // Format zoom as percentage\n const zoomPercentage = Math.round(zoom * 100);\n\n // Position styles\n const positionStyles: Record<string, React.CSSProperties> = {\n 'bottom-left': { bottom: 16, left: 16 },\n 'bottom-right': { bottom: 16, right: 16 },\n 'top-left': { top: 16, left: 16 },\n 'top-right': { top: 16, right: 16 },\n };\n\n return (\n <div\n className={className}\n style={{\n position: 'absolute',\n ...positionStyles[position],\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n padding: 4,\n backgroundColor: 'var(--surface)',\n borderRadius: 'var(--radius-lg)',\n boxShadow: 'var(--shadow-md)',\n zIndex: 'var(--z-sticky)',\n }}\n >\n {/* Zoom Out */}\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={zoomOut}\n disabled={zoom <= 0.1}\n aria-label=\"Zoom out\"\n >\n <Icon icon={icons.minus} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Zoom out</TooltipContent>\n </Tooltip>\n\n {/* Zoom Percentage */}\n <div\n style={{\n minWidth: 48,\n textAlign: 'center',\n fontSize: 13,\n fontWeight: 500,\n color: 'var(--foreground)',\n fontVariantNumeric: 'tabular-nums',\n }}\n >\n {zoomPercentage}%\n </div>\n\n {/* Zoom In */}\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={zoomIn}\n disabled={zoom >= 4}\n aria-label=\"Zoom in\"\n >\n <Icon icon={icons.plus} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Zoom in</TooltipContent>\n </Tooltip>\n\n {/* Separator */}\n {(showFitButton || showResetButton) && (\n <div\n style={{\n width: 1,\n height: 20,\n backgroundColor: 'var(--divider)',\n margin: '0 4px',\n }}\n />\n )}\n\n {/* Fit to Screen */}\n {showFitButton && (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={zoomToFit}\n aria-label=\"Fit to screen\"\n >\n <Icon icon={icons.fitScreen} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Fit to screen</TooltipContent>\n </Tooltip>\n )}\n\n {/* Reset to 100% */}\n {showResetButton && (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={resetView}\n aria-label=\"Reset to 100%\"\n >\n <Icon icon={icons.maximize} className=\"size-4\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>Reset to 100%</TooltipContent>\n </Tooltip>\n )}\n </div>\n );\n};\n\nexport default ZoomControls;\n","/**\n * useProjectLoader - Hook for loading saved projects programmatically\n * Supports loading from JSON, files, and templates\n */\n\nimport { useState, useCallback } from 'react';\nimport { useEditor } from '../contexts/EditorContext.js';\nimport { ImportManager } from '../utils/ImportManager.js';\nimport { createLogger } from '../utils/logger.js';\nimport type { CanvasDocument } from '../utils/ExportManager.js';\nimport type { AnyElementConfig } from '../types/index.js';\n\nconst logger = createLogger('useProjectLoader');\n\nexport interface ProjectTemplate {\n name: string;\n description?: string;\n artboards: Array<{\n name: string;\n width: number;\n height: number;\n backgroundColor: string;\n elements?: AnyElementConfig[];\n }>;\n}\n\nexport interface ProjectMetadata {\n version: string;\n timestamp: string;\n artboardCount: number;\n elementCount: number;\n}\n\nexport interface UseProjectLoaderReturn {\n // Load from JSON\n loadFromJSON: (json: string | CanvasDocument) => Promise<void>;\n\n // Load from file\n loadFromFile: (file: File) => Promise<void>;\n\n // Create from template\n loadTemplate: (template: ProjectTemplate) => Promise<void>;\n\n // State\n isLoading: boolean;\n loadError: Error | null;\n currentProject: CanvasDocument | null;\n\n // Metadata\n projectMetadata: ProjectMetadata | null;\n}\n\n/**\n * Hook for loading saved projects\n * Must be used within EditorProvider\n *\n * @example Load from API\n * ```tsx\n * function ProductCustomizer({ productId }: { productId: string }) {\n * const { loadFromJSON, isLoading } = useProjectLoader();\n *\n * useEffect(() => {\n * fetch(`/api/designs/${productId}`)\n * .then(res => res.json())\n * .then(design => loadFromJSON(design))\n * .catch(console.error);\n * }, [productId]);\n *\n * if (isLoading) return <div>Loading design...</div>;\n *\n * return <Canvas />;\n * }\n * ```\n *\n * @example Load from template\n * ```tsx\n * function TemplateGallery() {\n * const { loadTemplate } = useProjectLoader();\n *\n * const handleSelectTemplate = (template: ProjectTemplate) => {\n * loadTemplate(template);\n * };\n *\n * return <div>Template gallery...</div>;\n * }\n * ```\n */\nexport function useProjectLoader(): UseProjectLoaderReturn {\n const {\n handleLoadWorkspace,\n } = useEditor();\n\n const [isLoading, setIsLoading] = useState(false);\n const [loadError, setLoadError] = useState<Error | null>(null);\n const [currentProject, setCurrentProject] = useState<CanvasDocument | null>(null);\n const [projectMetadata, setProjectMetadata] = useState<ProjectMetadata | null>(null);\n\n /**\n * Load from JSON string or CanvasDocument object\n */\n const loadFromJSON = useCallback(async (json: string | CanvasDocument) => {\n setIsLoading(true);\n setLoadError(null);\n\n try {\n // Parse JSON if it's a string\n const document: CanvasDocument = typeof json === 'string' ? JSON.parse(json) : json;\n\n // Validate document structure\n if (!document.artboards || !Array.isArray(document.artboards)) {\n throw new Error('Invalid document format: missing artboards array');\n }\n\n // Import the document using ImportManager\n // Note: We need to create a JSON string and then parse it\n const jsonString = JSON.stringify(document);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const file = new File([blob], 'project.json', { type: 'application/json' });\n\n const result = await ImportManager.importFromJSON(file);\n\n if (!result.success || !result.artboards || !result.elements) {\n throw new Error(result.error || 'Failed to import project');\n }\n\n // Load into editor\n handleLoadWorkspace(result.artboards, result.elements, result.activeArtboardId || null);\n\n // Update state\n setCurrentProject(document);\n\n // Calculate metadata\n const totalElements = document.artboards.reduce((sum, ab) => sum + (ab.elements?.length || 0), 0);\n setProjectMetadata({\n version: document.metadata.version,\n timestamp: document.metadata.timestamp,\n artboardCount: document.artboards.length,\n elementCount: totalElements,\n });\n\n } catch (error) {\n logger.error('[useProjectLoader] Failed to load project:', error);\n setLoadError(error as Error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [handleLoadWorkspace]);\n\n /**\n * Load from file (File API)\n */\n const loadFromFile = useCallback(async (file: File) => {\n setIsLoading(true);\n setLoadError(null);\n\n try {\n // Read file as text\n const text = await file.text();\n\n // Load from JSON\n await loadFromJSON(text);\n } catch (error) {\n logger.error('[useProjectLoader] Failed to load file:', error);\n setLoadError(error as Error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [loadFromJSON]);\n\n /**\n * Create from template\n * Templates define artboards with optional default elements\n */\n const loadTemplate = useCallback(async (template: ProjectTemplate) => {\n setIsLoading(true);\n setLoadError(null);\n\n try {\n // Convert template to CanvasDocument format\n const document: CanvasDocument = {\n metadata: {\n version: '2.0.0',\n timestamp: new Date().toISOString(),\n appVersion: '1.0.0',\n },\n artboards: template.artboards.map((artboard, index) => ({\n id: `artboard-${Date.now()}-${index}`,\n name: artboard.name,\n x: 0,\n y: 0,\n width: artboard.width,\n height: artboard.height,\n backgroundColor: artboard.backgroundColor,\n elements: artboard.elements || [],\n })),\n activeArtboardId: null, // First artboard will be active by default\n };\n\n // Load the document\n await loadFromJSON(document);\n\n } catch (error) {\n logger.error('[useProjectLoader] Failed to load template:', error);\n setLoadError(error as Error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [loadFromJSON]);\n\n return {\n loadFromJSON,\n loadFromFile,\n loadTemplate,\n isLoading,\n loadError,\n currentProject,\n projectMetadata,\n };\n}\n","/**\n * useBreakpoint - Hook for responsive breakpoint detection\n * Provides responsive utilities for building adaptive UIs\n *\n * @example\n * ```tsx\n * function ResponsiveLayout() {\n * const { isAtLeast, breakpoint } = useBreakpoint();\n *\n * return (\n * <div>\n * {isAtLeast('md') ? (\n * <div className=\"desktop-layout\">\n * <LayersPanel />\n * <Canvas />\n * <ExportPanel />\n * </div>\n * ) : (\n * <div className=\"mobile-layout\">\n * <Canvas />\n * </div>\n * )}\n * <p>Current breakpoint: {breakpoint}</p>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { useState, useEffect, useMemo } from 'react';\n\nexport interface BreakpointConfig {\n xs?: number; // Extra small (default: 320)\n sm?: number; // Small (default: 480)\n md?: number; // Medium (default: 768)\n lg?: number; // Large (default: 1024)\n xl?: number; // Extra large (default: 1280)\n xxl?: number; // Extra extra large (default: 1536)\n}\n\nexport type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';\n\nexport interface UseBreakpointReturn {\n breakpoint: Breakpoint;\n width: number;\n isXs: boolean;\n isSm: boolean;\n isMd: boolean;\n isLg: boolean;\n isXl: boolean;\n isXxl: boolean;\n isAtLeast: (bp: Breakpoint) => boolean;\n isAtMost: (bp: Breakpoint) => boolean;\n}\n\nconst DEFAULT_BREAKPOINTS: Required<BreakpointConfig> = {\n xs: 320,\n sm: 480,\n md: 768,\n lg: 1024,\n xl: 1280,\n xxl: 1536,\n};\n\n/**\n * Get current breakpoint based on window width\n */\nfunction getCurrentBreakpoint(width: number, config: Required<BreakpointConfig>): Breakpoint {\n if (width >= config.xxl) return 'xxl';\n if (width >= config.xl) return 'xl';\n if (width >= config.lg) return 'lg';\n if (width >= config.md) return 'md';\n if (width >= config.sm) return 'sm';\n return 'xs';\n}\n\n/**\n * Hook for responsive breakpoint detection\n */\nexport function useBreakpoint(config?: BreakpointConfig): UseBreakpointReturn {\n const breakpointConfig: Required<BreakpointConfig> = {\n ...DEFAULT_BREAKPOINTS,\n ...config,\n };\n\n const [width, setWidth] = useState<number>(() => {\n if (typeof window !== 'undefined') {\n return window.innerWidth;\n }\n return DEFAULT_BREAKPOINTS.lg; // Default for SSR\n });\n\n // Update width on window resize\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const handleResize = () => {\n setWidth(window.innerWidth);\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n // Calculate current breakpoint\n const breakpoint = useMemo(\n () => getCurrentBreakpoint(width, breakpointConfig),\n [width, breakpointConfig]\n );\n\n // Boolean helpers for each breakpoint\n const isXs = breakpoint === 'xs';\n const isSm = breakpoint === 'sm';\n const isMd = breakpoint === 'md';\n const isLg = breakpoint === 'lg';\n const isXl = breakpoint === 'xl';\n const isXxl = breakpoint === 'xxl';\n\n // Breakpoint ordering for comparisons\n const breakpointOrder: Breakpoint[] = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];\n\n // Check if current breakpoint is at least the specified breakpoint\n const isAtLeast = (bp: Breakpoint): boolean => {\n const currentIndex = breakpointOrder.indexOf(breakpoint);\n const targetIndex = breakpointOrder.indexOf(bp);\n return currentIndex >= targetIndex;\n };\n\n // Check if current breakpoint is at most the specified breakpoint\n const isAtMost = (bp: Breakpoint): boolean => {\n const currentIndex = breakpointOrder.indexOf(breakpoint);\n const targetIndex = breakpointOrder.indexOf(bp);\n return currentIndex <= targetIndex;\n };\n\n return {\n breakpoint,\n width,\n isXs,\n isSm,\n isMd,\n isLg,\n isXl,\n isXxl,\n isAtLeast,\n isAtMost,\n };\n}\n","/**\n * usePerformance - Hook for performance monitoring\n * Provides metrics for tracking editor performance\n *\n * @example\n * ```tsx\n * function PerformanceMonitor() {\n * const { metrics, startProfiling } = usePerformance();\n *\n * useEffect(() => {\n * startProfiling();\n * }, []);\n *\n * if (metrics.fps < 30) {\n * console.warn('Low FPS:', metrics.fps);\n * }\n *\n * return (\n * <div>\n * <p>FPS: {Math.round(metrics.fps)}</p>\n * <p>Render Time: {metrics.avgRenderTime.toFixed(2)}ms</p>\n * <p>Elements: {metrics.elementCount}</p>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { useState, useCallback, useRef, useEffect } from 'react';\n\nexport interface PerformanceMetrics {\n fps: number;\n avgRenderTime: number;\n peakRenderTime: number;\n memoryUsage: number;\n elementCount: number;\n exportCount: number;\n avgExportTime: number;\n}\n\nexport interface UsePerformanceReturn {\n metrics: PerformanceMetrics;\n startProfiling: () => void;\n stopProfiling: () => void;\n clearMetrics: () => void;\n getReport: () => string;\n isProfiling: boolean;\n}\n\nconst DEFAULT_METRICS: PerformanceMetrics = {\n fps: 0,\n avgRenderTime: 0,\n peakRenderTime: 0,\n memoryUsage: 0,\n elementCount: 0,\n exportCount: 0,\n avgExportTime: 0,\n};\n\n/**\n * Hook for performance monitoring\n */\nexport function usePerformance(): UsePerformanceReturn {\n const [metrics, setMetrics] = useState<PerformanceMetrics>(DEFAULT_METRICS);\n const [isProfiling, setIsProfiling] = useState(false);\n\n const frameTimesRef = useRef<number[]>([]);\n const renderTimesRef = useRef<number[]>([]);\n const exportTimesRef = useRef<number[]>([]);\n const lastFrameTimeRef = useRef<number>(performance.now());\n const rafIdRef = useRef<number | null>(null);\n\n // Calculate FPS from frame times\n const calculateFPS = useCallback((frameTimes: number[]): number => {\n if (frameTimes.length === 0) return 0;\n const avg = frameTimes.reduce((sum, time) => sum + time, 0) / frameTimes.length;\n return 1000 / avg; // Convert to FPS\n }, []);\n\n // Calculate average\n const calculateAverage = useCallback((values: number[]): number => {\n if (values.length === 0) return 0;\n return values.reduce((sum, val) => sum + val, 0) / values.length;\n }, []);\n\n // Get memory usage (if available)\n const getMemoryUsage = useCallback((): number => {\n if ('memory' in performance && (performance as { memory?: { usedJSHeapSize: number } }).memory) {\n const memory = (performance as { memory: { usedJSHeapSize: number } }).memory;\n return memory.usedJSHeapSize / (1024 * 1024); // Convert to MB\n }\n return 0;\n }, []);\n\n // Update metrics\n const updateMetrics = useCallback(() => {\n const newMetrics: PerformanceMetrics = {\n fps: calculateFPS(frameTimesRef.current),\n avgRenderTime: calculateAverage(renderTimesRef.current),\n peakRenderTime: Math.max(...renderTimesRef.current, 0),\n memoryUsage: getMemoryUsage(),\n elementCount: 0, // Would need to be updated by editor context\n exportCount: exportTimesRef.current.length,\n avgExportTime: calculateAverage(exportTimesRef.current),\n };\n\n setMetrics(newMetrics);\n }, [calculateFPS, calculateAverage, getMemoryUsage]);\n\n // Frame measurement loop\n const measureFrame = useCallback(() => {\n const now = performance.now();\n const frameTime = now - lastFrameTimeRef.current;\n lastFrameTimeRef.current = now;\n\n // Add frame time\n frameTimesRef.current.push(frameTime);\n if (frameTimesRef.current.length > 60) {\n frameTimesRef.current.shift(); // Keep last 60 frames (1 second at 60fps)\n }\n\n // Update metrics every 30 frames (~500ms at 60fps)\n if (frameTimesRef.current.length % 30 === 0) {\n updateMetrics();\n }\n\n if (isProfiling) {\n rafIdRef.current = requestAnimationFrame(measureFrame);\n }\n }, [isProfiling, updateMetrics]);\n\n // Start profiling\n const startProfiling = useCallback(() => {\n setIsProfiling(true);\n lastFrameTimeRef.current = performance.now();\n rafIdRef.current = requestAnimationFrame(measureFrame);\n }, [measureFrame]);\n\n // Stop profiling\n const stopProfiling = useCallback(() => {\n setIsProfiling(false);\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n rafIdRef.current = null;\n }\n }, []);\n\n // Clear metrics\n const clearMetrics = useCallback(() => {\n frameTimesRef.current = [];\n renderTimesRef.current = [];\n exportTimesRef.current = [];\n setMetrics(DEFAULT_METRICS);\n }, []);\n\n // Get human-readable report\n const getReport = useCallback((): string => {\n return `\nPerformance Report\n==================\nFPS: ${metrics.fps.toFixed(1)}\nAvg Render Time: ${metrics.avgRenderTime.toFixed(2)}ms\nPeak Render Time: ${metrics.peakRenderTime.toFixed(2)}ms\nMemory Usage: ${metrics.memoryUsage.toFixed(1)}MB\nElement Count: ${metrics.elementCount}\nExport Count: ${metrics.exportCount}\nAvg Export Time: ${metrics.avgExportTime.toFixed(2)}ms\n `.trim();\n }, [metrics]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n }\n };\n }, []);\n\n return {\n metrics,\n startProfiling,\n stopProfiling,\n clearMetrics,\n getReport,\n isProfiling,\n };\n}\n","import { useEditor } from '../contexts/EditorContext.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\n\n/**\n * Returns a specific element by its ID, or null if not found.\n *\n * Useful for components that need to display or react to a particular\n * element without subscribing to the full editor state.\n *\n * @param id - The element ID to look up, or null to skip the lookup.\n * @returns The matching element, or null if the ID is null or no element matches.\n *\n * @example\n * ```tsx\n * function ElementInspector({ elementId }: { elementId: string }) {\n * const element = useElementById(elementId);\n * if (!element) return <p>Element not found</p>;\n * return <p>Position: ({element.x}, {element.y})</p>;\n * }\n * ```\n */\nexport function useElementById(id: string | null): EditorElement | null {\n const { getElementById } = useEditor();\n if (!id) return null;\n return getElementById(id) ?? null;\n}\n","/**\n * useLayerDragDrop - Hook for layer drag-drop reordering\n *\n * Extracts drag-drop reordering logic from LayersPanel.tsx into a\n * reusable hook. Handles drag state management, drop position\n * calculation (before/after/into for groups), and dispatches to\n * the appropriate reorder callback.\n *\n * @example\n * ```tsx\n * function LayersList({ elements, onReorder }) {\n * const { draggedId, dragOverId, dropPosition, handlers } = useLayerDragDrop({\n * onReorder,\n * findElement: (id) => elements.find(e => e.id === id) ?? null,\n * findParentGroup: (id) => findGroupParent(elements, id),\n * });\n *\n * return elements.map(el => (\n * <div\n * key={el.id}\n * draggable\n * onDragStart={(e) => handlers.onDragStart(e, el.id)}\n * onDragOver={(e) => handlers.onDragOver(e, el.id)}\n * onDrop={(e) => handlers.onDrop(e, el.id)}\n * onDragEnd={handlers.onDragEnd}\n * />\n * ));\n * }\n * ```\n */\n\nimport { useState, useCallback } from 'react';\nimport { GroupElement } from '../core/GroupElement.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\n\nexport interface UseLayerDragDropOptions {\n /**\n * Called when reordering top-level elements or elements in different groups.\n * Position is already inverted for reversed display order.\n */\n onReorder: (draggedId: string, targetId: string, position: 'before' | 'after') => void;\n\n /**\n * Called when reordering elements within the same group.\n * Position is already inverted for reversed display order.\n */\n onGroupReorder?: (\n draggedId: string,\n targetId: string,\n position: 'before' | 'after',\n groupId: string\n ) => void;\n\n /**\n * Called when dropping an element into a group (center drop zone).\n */\n onDropIntoGroup?: (draggedId: string, groupId: string) => void;\n\n /**\n * Called when dropping a top-level element between children of a group.\n * Position is already inverted for reversed display order.\n */\n onDropIntoGroupAtPosition?: (\n draggedId: string,\n groupId: string,\n targetChildId: string,\n position: 'before' | 'after'\n ) => void;\n\n /**\n * Look up an element by ID. Required for determining if a target is a group.\n */\n findElement?: (id: string) => EditorElement | null;\n\n /**\n * Find the parent group of an element. Required for intra-group reordering.\n */\n findParentGroup?: (id: string) => GroupElement | null;\n}\n\nexport interface UseLayerDragDropReturn {\n /** ID of the currently dragged element, or null */\n draggedId: string | null;\n /** ID of the element being dragged over, or null */\n dragOverId: string | null;\n /** Where the dragged element will be dropped relative to the target */\n dropPosition: 'before' | 'after' | 'into' | null;\n /** Event handlers to attach to draggable layer items */\n handlers: {\n onDragStart: (e: React.DragEvent, elementId: string) => void;\n onDragOver: (e: React.DragEvent, elementId: string) => void;\n onDrop: (e: React.DragEvent, targetId: string) => void;\n onDragEnd: () => void;\n };\n}\n\n/**\n * Hook for managing drag-drop reordering in layer panels.\n *\n * Calculates drop position based on mouse position within the target element:\n * - For groups: top 25% = before, middle 50% = into, bottom 25% = after\n * - For non-groups: top/bottom split at 40%/60%\n *\n * Handles the display-order inversion: layers are displayed in reverse\n * order (topmost layer first), so visual \"before\" maps to array \"after\"\n * and vice versa. This inversion is applied before calling the callbacks.\n */\nexport function useLayerDragDrop(options: UseLayerDragDropOptions): UseLayerDragDropReturn {\n const {\n onReorder,\n onGroupReorder,\n onDropIntoGroup,\n onDropIntoGroupAtPosition,\n findElement,\n findParentGroup,\n } = options;\n\n const [draggedId, setDraggedId] = useState<string | null>(null);\n const [dragOverId, setDragOverId] = useState<string | null>(null);\n const [dropPosition, setDropPosition] = useState<'before' | 'after' | 'into' | null>(null);\n\n const handleDragStart = useCallback((e: React.DragEvent, elementId: string) => {\n e.dataTransfer.effectAllowed = 'move';\n // Delay setting dragged state until after browser captures drag image\n requestAnimationFrame(() => {\n setDraggedId(elementId);\n });\n }, []);\n\n const handleDragOver = useCallback(\n (e: React.DragEvent, elementId: string) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n\n const rect = e.currentTarget.getBoundingClientRect();\n const mouseY = e.clientY;\n const relativeY = mouseY - rect.top;\n const height = rect.height;\n\n // Check if target is a group\n const targetElement = findElement?.(elementId);\n const isGroup = targetElement instanceof GroupElement;\n\n let position: 'before' | 'after' | 'into';\n\n if (isGroup) {\n // For groups: top 25% = before, bottom 25% = after, middle 50% = into\n if (relativeY < height * 0.25) {\n position = 'before';\n } else if (relativeY > height * 0.75) {\n position = 'after';\n } else {\n position = 'into';\n }\n } else {\n // For non-groups: top 40% = before, bottom 40% = after, middle = split\n if (relativeY < height * 0.4) {\n position = 'before';\n } else if (relativeY > height * 0.6) {\n position = 'after';\n } else {\n position = relativeY < height / 2 ? 'before' : 'after';\n }\n }\n\n setDragOverId(elementId);\n setDropPosition(position);\n },\n [findElement]\n );\n\n const resetDragState = useCallback(() => {\n setDraggedId(null);\n setDragOverId(null);\n setDropPosition(null);\n }, []);\n\n const handleDrop = useCallback(\n (e: React.DragEvent, targetId: string) => {\n e.preventDefault();\n if (!draggedId || draggedId === targetId || !dropPosition) {\n resetDragState();\n return;\n }\n\n if (dropPosition === 'into') {\n // Dropping into a group\n if (onDropIntoGroup) {\n onDropIntoGroup(draggedId, targetId);\n }\n } else {\n // Reordering (before/after)\n // Check if both elements are children of the same group\n const draggedParent = findParentGroup?.(draggedId);\n const targetParent = findParentGroup?.(targetId);\n\n // Layers are displayed in reverse order, so invert the position\n // Visual \"before\" = Array \"after\", Visual \"after\" = Array \"before\"\n const arrayPosition = dropPosition === 'before' ? 'after' : 'before';\n\n if (draggedParent && targetParent && draggedParent.id === targetParent.id) {\n // Both are children of the same group - reorder within the group\n if (onGroupReorder) {\n onGroupReorder(draggedId, targetId, arrayPosition, draggedParent.id!);\n }\n } else if (!draggedParent && targetParent && onDropIntoGroupAtPosition) {\n // Dragging from top-level into between children of a group\n onDropIntoGroupAtPosition(draggedId, targetParent.id!, targetId, arrayPosition);\n } else {\n // Top-level reordering\n onReorder(draggedId, targetId, arrayPosition);\n }\n }\n\n // Clear drag state immediately since dragEnd may not fire when DOM changes\n resetDragState();\n },\n [\n draggedId,\n dropPosition,\n onReorder,\n onGroupReorder,\n onDropIntoGroup,\n onDropIntoGroupAtPosition,\n findParentGroup,\n resetDragState,\n ]\n );\n\n return {\n draggedId,\n dragOverId,\n dropPosition,\n handlers: {\n onDragStart: handleDragStart,\n onDragOver: handleDragOver,\n onDrop: handleDrop,\n onDragEnd: resetDragState,\n },\n };\n}\n","/**\n * useLayerSelection - Hook for layer selection logic\n *\n * Extracts the selection logic (shift-click multi-select, single-click,\n * deselection) from LayersPanel.tsx into a reusable hook.\n *\n * @example\n * ```tsx\n * function LayersList({ elements }) {\n * const [selectedId, setSelectedId] = useState<string | null>(null);\n * const [multiSelection, setMultiSelection] = useState<string[]>([]);\n *\n * const { isSelected, handleClick } = useLayerSelection({\n * selectedId,\n * multiSelection,\n * onSelectionChange: setSelectedId,\n * onMultiSelectionChange: setMultiSelection,\n * });\n *\n * return elements.map(el => (\n * <div\n * key={el.id}\n * className={isSelected(el.id) ? 'selected' : ''}\n * onClick={(e) => handleClick(e, el.id)}\n * />\n * ));\n * }\n * ```\n */\n\nimport { useCallback } from 'react';\n\nexport interface UseLayerSelectionOptions {\n /** Currently selected single element ID, or null */\n selectedId: string | null;\n /** Array of multi-selected element IDs */\n multiSelection: string[];\n /** Callback for single selection changes */\n onSelectionChange: (id: string | null) => void;\n /** Callback for multi-selection changes */\n onMultiSelectionChange: (ids: string[]) => void;\n}\n\nexport interface UseLayerSelectionReturn {\n /**\n * Check if an element is selected (either single or multi-selected).\n * Does not account for activeChildElement priority -- callers handling\n * group children should check that separately.\n */\n isSelected: (id: string) => boolean;\n\n /**\n * Handle a click on a layer element.\n * - Normal click: selects only this element, clears multi-selection\n * - Shift+click: toggles the element in/out of multi-selection\n */\n handleClick: (e: React.MouseEvent | React.KeyboardEvent, elementId: string) => void;\n}\n\n/**\n * Hook for managing layer selection state.\n *\n * Implements the following selection behaviors:\n *\n * **Normal click:**\n * - Selects only the clicked element\n * - Clears any multi-selection\n *\n * **Shift+click with existing multi-selection:**\n * - If element is in multi-selection: removes it\n * - If only 1 remains: converts back to single selection\n * - If 0 remain: clears selection\n * - If element is not in multi-selection: adds it\n *\n * **Shift+click with single selection:**\n * - If clicking the already-selected element: no-op\n * - If clicking a different element: starts multi-selection with both\n *\n * **Shift+click with no selection:**\n * - Selects the clicked element as a single selection\n */\nexport function useLayerSelection(options: UseLayerSelectionOptions): UseLayerSelectionReturn {\n const { selectedId, multiSelection, onSelectionChange, onMultiSelectionChange } = options;\n\n const isSelected = useCallback(\n (id: string): boolean => {\n return id === selectedId || multiSelection.includes(id);\n },\n [selectedId, multiSelection]\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent | React.KeyboardEvent, elementId: string) => {\n if (e.shiftKey) {\n // Shift-click: multi-selection behavior\n const isInMultiSelection = multiSelection.includes(elementId);\n const isCurrentlySelected = selectedId === elementId;\n\n if (multiSelection.length > 0) {\n // Already have multi-selection\n if (isInMultiSelection) {\n // Remove from multi-selection\n const newSelection = multiSelection.filter((id) => id !== elementId);\n if (newSelection.length === 1) {\n // Only one left, convert back to single selection\n onMultiSelectionChange([]);\n onSelectionChange(newSelection[0]);\n } else if (newSelection.length === 0) {\n // All deselected\n onMultiSelectionChange([]);\n onSelectionChange(null);\n } else {\n // Keep multi-selection\n onMultiSelectionChange(newSelection);\n }\n } else {\n // Add to multi-selection\n onMultiSelectionChange([...multiSelection, elementId]);\n }\n } else if (isCurrentlySelected) {\n // Single selection exists and shift-clicking it: do nothing\n return;\n } else if (selectedId !== null) {\n // Convert single selection to multi-selection\n onMultiSelectionChange([selectedId, elementId]);\n onSelectionChange(null);\n } else {\n // No selection, just select this element\n onSelectionChange(elementId);\n }\n } else {\n // Normal click: select only this element\n onSelectionChange(elementId);\n onMultiSelectionChange([]);\n }\n },\n [selectedId, multiSelection, onSelectionChange, onMultiSelectionChange]\n );\n\n return { isSelected, handleClick };\n}\n","/**\n * FontSizeDropdown - Dropdown for selecting font size\n */\n\nimport { memo } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Popover, PopoverTrigger, PopoverContent } from './ui';\n\nexport interface FontSizeDropdownProps {\n value: number;\n onChange: (size: number) => void;\n fontSizes: number[];\n isOpen: boolean;\n onToggle: (open: boolean) => void;\n}\n\nconst FontSizeDropdown = memo(({ value, onChange, fontSizes, isOpen, onToggle }: FontSizeDropdownProps) => {\n const handleSelect = (size: number) => {\n onChange(size);\n onToggle(false);\n };\n\n return (\n <Popover open={isOpen} onOpenChange={onToggle}>\n <PopoverTrigger asChild>\n <button className=\"toolbar-btn\" aria-label=\"Font size\">\n <Icon icon=\"radix-icons:font-size\" className=\"size-5\" />\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[120px] max-h-[300px] overflow-y-auto p-1\" maxZIndex>\n <div className=\"flex flex-col gap-0.5\">\n {fontSizes.map((size) => (\n <button\n key={size}\n onClick={() => handleSelect(size)}\n className={`w-full rounded-md px-3 py-1.5 text-center text-sm transition-colors hover:bg-muted ${\n value === size ? 'bg-muted font-medium' : ''\n }`}\n >\n {size}\n </button>\n ))}\n </div>\n </PopoverContent>\n </Popover>\n );\n});\n\nFontSizeDropdown.displayName = 'FontSizeDropdown';\n\nexport default FontSizeDropdown;\n","import { useState } from 'react';\nimport { Tooltip, TooltipTrigger, TooltipContent } from '../ui';\nimport { FONT_SIZES } from '../../constants.js';\nimport { clickProtection } from '../../utils/clickProtection.js';\nimport type { UseTextToolbarReturn } from '../../hooks/useTextToolbar.js';\n\nexport interface FontSizeGroupProps {\n toolbar: UseTextToolbarReturn;\n}\n\nexport function FontSizeGroup({ toolbar }: FontSizeGroupProps) {\n const { fontSize, handleFontSizeIncrement, handleFontSizeChange } = toolbar;\n const [openDropdown, setOpenDropdown] = useState(false);\n\n return (\n <div className=\"toolbar-group\">\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <button className=\"toolbar-btn-sm\" onClick={() => handleFontSizeIncrement(-1)}>\n -\n </button>\n </TooltipTrigger>\n <TooltipContent>Decrease Font Size</TooltipContent>\n </Tooltip>\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <div style={{ position: 'relative' }}>\n <button\n className=\"toolbar-font-size-display\"\n onClick={() => {\n clickProtection.protectNextClick();\n setOpenDropdown(!openDropdown);\n }}\n >\n {fontSize}\n </button>\n {openDropdown && (\n <div\n className=\"font-dropdown\"\n ref={(el: HTMLDivElement | null) => {\n if (el) {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (!el.contains(target) && !target.closest('.toolbar-font-size-display')) {\n setOpenDropdown(false);\n }\n };\n setTimeout(() => {\n document.addEventListener('mousedown', handleClickOutside);\n }, 0);\n }\n }}\n >\n {FONT_SIZES.map((size) => (\n <button\n key={size}\n className={`font-dropdown-option ${fontSize === size ? 'selected' : ''}`}\n onClick={() => {\n handleFontSizeChange(size);\n setOpenDropdown(false);\n }}\n >\n {size}\n </button>\n ))}\n </div>\n )}\n </div>\n </TooltipTrigger>\n <TooltipContent>Font Size</TooltipContent>\n </Tooltip>\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <button className=\"toolbar-btn-sm\" onClick={() => handleFontSizeIncrement(1)}>\n +\n </button>\n </TooltipTrigger>\n <TooltipContent>Increase Font Size</TooltipContent>\n </Tooltip>\n </div>\n );\n}\n","/**\n * ElementTypePlugin - Plugin API for registering custom element types\n *\n * Allows external developers to add new element types without modifying\n * core canvas files. Custom types integrate with the transform registry\n * so that GroupElement reconstruction, ElementFactory, and all other\n * registry consumers work seamlessly.\n *\n * @example\n * ```typescript\n * import { registerElementType } from '@snowcone-app/canvas/advanced';\n *\n * registerElementType({\n * type: 'custom-shape',\n * Component: CustomShapeElement,\n * label: 'Custom Shape',\n * icon: 'lucide:shapes',\n * category: 'custom',\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport {\n registerTransform,\n unregisterTransform,\n getTransformById,\n _resetDynamicTransforms,\n} from '../transforms/registry.js';\n\n/**\n * Registration descriptor for a custom element type.\n */\nexport interface ElementTypeRegistration {\n /** Unique type identifier (must not conflict with built-in types) */\n type: string;\n\n /**\n * Element class constructor.\n * Must accept a config object and produce a valid element instance\n * (i.e., something that extends BaseElement).\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Constructors have varying signatures\n Component: new (config: any) => any;\n\n /** Display label for UI (e.g., \"Custom Shape\") */\n label: string;\n\n /** Icon identifier in Iconify format (e.g., \"lucide:shapes\") */\n icon?: string;\n\n /** Category for grouping in the add-element menu */\n category?: 'text' | 'image' | 'shape' | 'custom';\n\n /** Default config for new elements of this type */\n defaultConfig?: Record<string, unknown>;\n}\n\n/**\n * Internal store for custom element type registrations.\n * Keyed by type string.\n */\nconst _customElementTypes = new Map<string, ElementTypeRegistration>();\n\n/**\n * Register a custom element type.\n *\n * - Validates the registration (type must be non-empty, Component must be a constructor)\n * - Prevents conflicts with built-in types and duplicate registrations\n * - Adds the type to the transform registry so GroupElement, ElementFactory,\n * and other registry consumers recognize it\n *\n * @param registration - The element type registration descriptor\n * @throws Error if type conflicts with a built-in type\n * @throws Error if type is already registered as a custom type\n * @throws Error if registration is invalid (missing type/Component/label)\n */\nexport function registerElementType(registration: ElementTypeRegistration): void {\n // Validate required fields\n if (!registration.type || typeof registration.type !== 'string') {\n throw new Error('ElementTypeRegistration requires a non-empty \"type\" string');\n }\n if (typeof registration.Component !== 'function') {\n throw new Error(\n `ElementTypeRegistration for \"${registration.type}\" requires a \"Component\" constructor function`\n );\n }\n if (!registration.label || typeof registration.label !== 'string') {\n throw new Error(\n `ElementTypeRegistration for \"${registration.type}\" requires a non-empty \"label\" string`\n );\n }\n\n // registerTransform will throw if the id conflicts with built-in or duplicate\n registerTransform(registration.type, {\n id: registration.type,\n label: registration.label,\n Component: registration.Component,\n });\n\n // Store the full registration (including icon, category, defaultConfig)\n _customElementTypes.set(registration.type, { ...registration });\n}\n\n/**\n * Unregister a custom element type.\n *\n * Removes the type from both the plugin registry and the transform registry.\n * Built-in types cannot be unregistered.\n *\n * @param type - The type identifier to unregister\n * @throws Error if attempting to unregister a built-in type\n */\nexport function unregisterElementType(type: string): void {\n // unregisterTransform throws if it's a built-in type\n unregisterTransform(type);\n _customElementTypes.delete(type);\n}\n\n/**\n * Get all registered custom element types.\n *\n * Returns only plugin-registered types, not built-in types.\n * The returned array is a snapshot; mutations do not affect the registry.\n *\n * @returns Array of ElementTypeRegistration descriptors\n */\nexport function getCustomElementTypes(): ElementTypeRegistration[] {\n return Array.from(_customElementTypes.values());\n}\n\n/**\n * Check if a type identifier is registered (built-in or custom).\n *\n * @param type - The type identifier to check\n * @returns true if the type exists in the transform registry\n */\nexport function isRegisteredElementType(type: string): boolean {\n return getTransformById(type) !== undefined;\n}\n\n/**\n * Reset all custom element type registrations (for testing only).\n * Also resets the underlying dynamic transforms in the registry.\n * @internal\n */\nexport function _resetCustomElementTypes(): void {\n _customElementTypes.clear();\n _resetDynamicTransforms();\n}\n","/**\n * Canvas Event Bus\n *\n * A typed publish/subscribe event system for cross-component communication\n * within the canvas editor. Components can emit and listen for events without\n * direct coupling, enabling loose coordination between panels, tools, and\n * the canvas itself.\n *\n * All event types are defined in {@link CanvasEventMap} for compile-time\n * type safety -- subscribers receive correctly-typed payloads and emitters\n * are checked against the event map at compile time.\n *\n * A singleton instance is available via {@link canvasEventBus} for use\n * across the editor. The {@link useCanvasEvents} hook provides React\n * integration.\n *\n * @example Subscribe to element creation\n * ```ts\n * import { canvasEventBus } from '@snowcone-app/canvas/advanced';\n *\n * const unsub = canvasEventBus.on('element:created', ({ elementId, type }) => {\n * console.log(`Created ${type} element: ${elementId}`);\n * });\n *\n * // Later: clean up\n * unsub();\n * ```\n *\n * @example One-shot listener\n * ```ts\n * canvasEventBus.once('export:completed', ({ durationMs }) => {\n * console.log(`Export finished in ${durationMs}ms`);\n * });\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Event Map\n// ---------------------------------------------------------------------------\n\n/**\n * Map of all canvas event names to their payload types.\n *\n * Extend this interface (via module augmentation) to add custom events:\n * ```ts\n * declare module '@snowcone-app/canvas/advanced' {\n * interface CanvasEventMap {\n * 'my-plugin:action': { value: number };\n * }\n * }\n * ```\n */\nexport interface CanvasEventMap {\n /** Fired after a new element is added to the canvas */\n 'element:created': { elementId: string; type: string };\n /** Fired after one or more properties of an element change */\n 'element:updated': { elementId: string; changes: string[] };\n /** Fired after an element is removed from the canvas */\n 'element:deleted': { elementId: string };\n /** Fired when the selected element changes (null = deselected) */\n 'element:selected': { elementId: string | null };\n /** Fired when the active artboard changes */\n 'artboard:changed': { artboardId: string; artboardName: string };\n /** Fired when an export operation begins */\n 'export:started': { artboardId: string };\n /** Fired when an export operation completes successfully */\n 'export:completed': { artboardId: string; durationMs: number };\n /** Fired when an export operation fails */\n 'export:error': { artboardId: string; error: Error };\n /** Fired after an undo operation */\n 'undo': { commandDescription?: string };\n /** Fired after a redo operation */\n 'redo': { commandDescription?: string };\n}\n\n// ---------------------------------------------------------------------------\n// Handler type\n// ---------------------------------------------------------------------------\n\n/** Strongly-typed event handler for a specific event name */\nexport type CanvasEventHandler<K extends keyof CanvasEventMap> = (\n event: CanvasEventMap[K],\n) => void;\n\n// ---------------------------------------------------------------------------\n// CanvasEventBus\n// ---------------------------------------------------------------------------\n\n/**\n * A typed event bus for the canvas editor.\n *\n * Provides subscribe ({@link on}, {@link once}), publish ({@link emit}),\n * and unsubscribe ({@link off}) operations with full type safety.\n *\n * Listeners for a given event are called in the order they were registered.\n * Errors thrown inside a handler are caught and logged to `console.error`\n * so that one failing handler does not prevent others from executing.\n */\nexport class CanvasEventBus {\n /** Map of event name to the set of registered handler functions */\n private listeners = new Map<string, Set<Function>>();\n\n // -----------------------------------------------------------------------\n // Subscribe\n // -----------------------------------------------------------------------\n\n /**\n * Subscribe to an event.\n *\n * @param event - The event name to listen for\n * @param handler - Callback invoked with the event payload\n * @returns An unsubscribe function -- call it to remove this handler\n */\n on<K extends keyof CanvasEventMap>(\n event: K,\n handler: CanvasEventHandler<K>,\n ): () => void {\n let handlers = this.listeners.get(event as string);\n if (!handlers) {\n handlers = new Set();\n this.listeners.set(event as string, handlers);\n }\n handlers.add(handler);\n\n // Return unsubscribe function\n return () => {\n handlers!.delete(handler);\n if (handlers!.size === 0) {\n this.listeners.delete(event as string);\n }\n };\n }\n\n /**\n * Subscribe to an event for a single invocation.\n *\n * The handler is automatically removed after the first time the event\n * fires. The returned unsubscribe function can also be used to cancel\n * before the event fires.\n *\n * @param event - The event name to listen for\n * @param handler - Callback invoked once with the event payload\n * @returns An unsubscribe function\n */\n once<K extends keyof CanvasEventMap>(\n event: K,\n handler: CanvasEventHandler<K>,\n ): () => void {\n const wrapper = ((data: CanvasEventMap[K]) => {\n unsubscribe();\n handler(data);\n }) as CanvasEventHandler<K>;\n\n const unsubscribe = this.on(event, wrapper);\n return unsubscribe;\n }\n\n // -----------------------------------------------------------------------\n // Publish\n // -----------------------------------------------------------------------\n\n /**\n * Emit an event, invoking all registered handlers for that event name.\n *\n * Handlers are called synchronously in registration order. If a handler\n * throws, the error is logged and remaining handlers still execute.\n *\n * @param event - The event name to emit\n * @param data - The payload to pass to each handler\n */\n emit<K extends keyof CanvasEventMap>(\n event: K,\n data: CanvasEventMap[K],\n ): void {\n const handlers = this.listeners.get(event as string);\n if (!handlers) return;\n\n // Iterate over a snapshot so that handlers can safely unsubscribe\n for (const handler of [...handlers]) {\n try {\n handler(data);\n } catch (err) {\n console.error(\n `[CanvasEventBus] Error in handler for \"${String(event)}\":`,\n err,\n );\n }\n }\n }\n\n // -----------------------------------------------------------------------\n // Unsubscribe\n // -----------------------------------------------------------------------\n\n /**\n * Remove listeners.\n *\n * - If called with an event name, removes all handlers for that event.\n * - If called with no arguments, removes all handlers for all events.\n *\n * @param event - Optional event name to clear. Omit to clear everything.\n */\n off<K extends keyof CanvasEventMap>(event?: K): void {\n if (event === undefined) {\n this.listeners.clear();\n } else {\n this.listeners.delete(event as string);\n }\n }\n\n // -----------------------------------------------------------------------\n // Introspection\n // -----------------------------------------------------------------------\n\n /**\n * Get the number of registered listeners for a specific event.\n *\n * @param event - The event name to query\n * @returns The number of handlers currently registered\n */\n listenerCount(event: keyof CanvasEventMap): number {\n return this.listeners.get(event as string)?.size ?? 0;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton\n// ---------------------------------------------------------------------------\n\n/**\n * The singleton CanvasEventBus instance shared across the editor.\n *\n * Use this directly or via the {@link useCanvasEvents} hook in React\n * components.\n */\nexport const canvasEventBus = new CanvasEventBus();\n","/**\n * useCanvasEvents Hook\n *\n * Provides access to the singleton {@link CanvasEventBus} instance for\n * cross-component communication within the canvas editor.\n *\n * This is a thin convenience wrapper -- it simply returns the shared\n * singleton so that React components have a consistent hook-based API\n * for accessing the event bus.\n *\n * @example Subscribe to events in a component\n * ```tsx\n * import { useCanvasEvents } from '@snowcone-app/canvas/advanced';\n *\n * function MyPanel() {\n * const events = useCanvasEvents();\n *\n * useEffect(() => {\n * const unsub = events.on('element:selected', ({ elementId }) => {\n * console.log('Selected:', elementId);\n * });\n * return unsub;\n * }, [events]);\n *\n * return <div>My Panel</div>;\n * }\n * ```\n *\n * @example Emit events from a component\n * ```tsx\n * function ExportButton() {\n * const events = useCanvasEvents();\n *\n * const handleExport = () => {\n * events.emit('export:started', { artboardId: 'ab-1' });\n * };\n *\n * return <button onClick={handleExport}>Export</button>;\n * }\n * ```\n */\n\nimport { canvasEventBus, type CanvasEventBus } from '../core/EventBus.js';\n\n/**\n * Returns the singleton {@link CanvasEventBus} instance.\n *\n * The returned reference is stable across renders -- it always points to\n * the same singleton, so it is safe to include in dependency arrays.\n */\nexport function useCanvasEvents(): CanvasEventBus {\n return canvasEventBus;\n}\n","/**\n * ADR-0054: SVG-based visual-guide overlay.\n *\n * Duplicated intentionally between:\n * - snowcone-loom/app/components/VisualGuideOverlay.tsx (Loom editor)\n * - ui-components/packages/canvas/src/components/VisualGuideOverlay.tsx\n * (this file — consumed by the Snowcone consumer editor via\n * @snowcone-app/canvas)\n * Loom doesn't depend on @snowcone-app/canvas. Keep these two files\n * byte-identical below the header; if you change one, mirror the other.\n *\n * Renders structured piece guides (boundary, safe area, zones, labels) as\n * stacked SVG layers on top of an artboard preview. The entire overlay\n * lives inside a single `<svg viewBox=\"0 0 artboardWidth artboardHeight\">`\n * so piece-local coordinates compose directly and strokes can opt into\n * `vector-effect=\"non-scaling-stroke\"` to stay visually crisp at every\n * viewport scale.\n *\n * Falls back cleanly when no guides are authored:\n * - `boundary` → the piece's bounding rect (0,0 to pieceWidth, pieceHeight)\n * - `safeArea` → an inset rect derived from `safeAreaInsetPx` when present,\n * omitted otherwise\n */\n\nimport { useMemo } from \"react\";\n\n// ── Types (mirror the backend layouts.ts shape) ───────────────────────────────\n\nexport type SvgPath =\n | { kind: \"rect\"; x: number; y: number; width: number; height: number }\n | {\n kind: \"roundedRect\";\n x: number;\n y: number;\n width: number;\n height: number;\n rx?: number;\n ry?: number;\n }\n | { kind: \"path\"; d: string };\n\nexport interface ZoneShape {\n kind: \"wrap\" | \"binding\" | \"dieCut\" | \"warning\" | \"custom\";\n label?: string;\n path: SvgPath;\n}\n\nexport interface GuideLabel {\n text: string;\n x: number;\n y: number;\n anchor?: \"tl\" | \"tc\" | \"tr\" | \"cl\" | \"c\" | \"cr\" | \"bl\" | \"bc\" | \"br\";\n}\n\nexport interface PieceGuide {\n boundary?: SvgPath;\n safeArea?: SvgPath;\n zones?: ZoneShape[];\n labels?: GuideLabel[];\n /**\n * Corner radius of the piece's *physical outer shape* (e.g. a phone\n * case's outer curve) in piece-local pixels. When set, the bleed\n * ring's outer edge uses a rounded rectangle of `(pieceWidth,\n * pieceHeight)` with this radius, and the entire piece render is\n * clipped to that shape — so nothing bleeds into the sharp corners\n * of the piece's bounding rect. Omit / 0 = sharp corners (current\n * default behaviour).\n */\n outerRadius?: number;\n}\n\nexport interface OverlayPiece {\n /** Stable piece id (matches `placements[].name`). */\n id: string;\n /** Piece's top-left position on the artboard, in artboard pixel coords. */\n x: number;\n y: number;\n /** Piece-local dimensions in px. */\n width: number;\n height: number;\n /**\n * Fallback safe-area inset when no authored `safeArea` is present. In\n * piece-local pixels (caller converts from inches). Omit to skip the\n * fallback safe area entirely.\n */\n safeAreaInsetPx?: number;\n /** Clockwise rotation in degrees about the piece center. Default 0. */\n rotation?: number;\n}\n\nexport interface VisualGuideOverlayStyle {\n bleedFill?: string;\n bleedOpacity?: number;\n boundaryStroke?: string;\n boundaryStrokeWidth?: number;\n /**\n * Safe-area wash: fills the region outside the safe area (inside the\n * piece) with a semi-transparent color. Replaces the old dashed\n * safe-area outline as the default — de-emphasizes the bleed margin so\n * the safe area reads as the \"clean\" zone without adding line chrome.\n */\n safeAreaWashFill?: string;\n safeAreaWashOpacity?: number;\n /**\n * Corner radius (in viewBox px) for the wash's outer edge so it hugs\n * rounded products (phone cases, rounded cards, etc.) instead of\n * boxing sharp corners. Pass `0` for hard corners. Omit to use an\n * artboard-proportional default (~2% of the shorter axis).\n */\n safeAreaWashCornerRadius?: number;\n /**\n * Safe-area stroke settings — legacy dashed outline. Disabled by default\n * (wash does the work). Set `safeAreaStroke` to any color to re-enable.\n */\n safeAreaStroke?: string;\n safeAreaStrokeWidth?: number;\n safeAreaDashArray?: string;\n zoneFill?: Partial<Record<ZoneShape[\"kind\"], string>>;\n zoneStroke?: Partial<Record<ZoneShape[\"kind\"], string>>;\n labelColor?: string;\n labelFontSize?: number;\n labelFontFamily?: string;\n}\n\nexport interface VisualGuideOverlayProps {\n /** Artboard dimensions in px — defines the SVG viewBox. */\n artboardWidth: number;\n artboardHeight: number;\n /**\n * @deprecated Do not use — leave at 0 (the default).\n *\n * This was intended to mirror SnowconeCanvas's `fixedMargin`, but\n * `fixedMargin` is in CSS pixels (converted to world units via\n * `worldMargin = fixedMargin / zoom` in useCanvasLayout.ts) while\n * this prop treated the value as viewBox/world units. The two only\n * match at zoom === 1, so passing a non-zero value silently drifted\n * the overlay content by tens of pixels at typical editor zooms.\n *\n * Correct usage: keep the SVG viewBox equal to the artboard, and\n * position the wrapping div with `inset: ${fixedMargin}px` so the\n * overlay covers only the artboard region of the padded canvas.\n */\n canvasPadding?: number;\n /** Pieces to render guides for. */\n pieces: OverlayPiece[];\n /** Authored guides keyed by piece id. Pieces without a guide fall back. */\n pieceGuides?: Record<string, PieceGuide>;\n /** Per-layer visibility toggles. All default to true. */\n show?: {\n bleed?: boolean;\n zones?: boolean;\n boundary?: boolean;\n safeArea?: boolean;\n labels?: boolean;\n };\n /** Optional style overrides. */\n style?: VisualGuideOverlayStyle;\n /** `className` applied to the wrapping SVG element. */\n className?: string;\n}\n\n// ── Defaults ──────────────────────────────────────────────────────────────────\n\nconst DEFAULT_STYLE: Required<\n Omit<VisualGuideOverlayStyle, \"zoneFill\" | \"zoneStroke\">\n> & {\n zoneFill: Record<ZoneShape[\"kind\"], string>;\n zoneStroke: Record<ZoneShape[\"kind\"], string>;\n} = {\n bleedFill: \"#ffffff\",\n bleedOpacity: 0.5,\n // Subtle boundary — the wash already draws the eye to the safe area,\n // so the piece outline is just a quiet frame for context. Consumers\n // can dial it up to a harder blue / thicker stroke via style overrides.\n // Default to no boundary outline — the bleed wash's soft inner edge\n // carries the design-canvas edge on its own. Consumers can set any\n // colour via `style.boundaryStroke` to opt back in.\n boundaryStroke: \"\",\n boundaryStrokeWidth: 1,\n // New default: 25%-opacity white wash over the non-safe area. Apple-y\n // \"fade out the edges\" approach rather than a dashed line, so the safe\n // area reads as the clean canvas rather than a bordered box.\n safeAreaWashFill: \"#ffffff\",\n safeAreaWashOpacity: 0.25,\n // Sentinel: -1 means \"auto\" — the component computes an artboard-\n // proportional radius at render time. A real value overrides.\n safeAreaWashCornerRadius: -1,\n // Legacy dashed safe-area outline — disabled by default now. Set\n // `safeAreaStroke` to a color to re-enable for any consumer that\n // prefers the old look.\n safeAreaStroke: \"\",\n safeAreaStrokeWidth: 1.5,\n safeAreaDashArray: \"6 4\",\n zoneFill: {\n wrap: \"rgba(148, 163, 184, 0.25)\", // slate-400\n binding: \"rgba(234, 88, 12, 0.20)\", // orange-600\n // A die-cut is material *removed* from the product, so the fill reads\n // as a dark \"hole\" rather than a coloured region. 70% black gives\n // strong contrast over any artwork underneath.\n dieCut: \"rgba(0, 0, 0, 0.7)\",\n warning: \"rgba(245, 158, 11, 0.25)\", // amber-500\n custom: \"rgba(100, 100, 100, 0.15)\",\n },\n zoneStroke: {\n wrap: \"#64748b\",\n binding: \"#ea580c\",\n // White outline on die-cut pairs with the black fill to read as a\n // clean perforation. A red outline would compete with the fill.\n dieCut: \"#ffffff\",\n warning: \"#f59e0b\",\n custom: \"#6b7280\",\n },\n labelColor: \"#111827\",\n // Placeholder — replaced at render time with an artboard-proportional\n // default (see `autoLabelFontSize` in the component). Callers can still\n // pin via `style.labelFontSize`.\n labelFontSize: 14,\n labelFontFamily:\n \"ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif\",\n};\n\n// ── Rendering helpers ─────────────────────────────────────────────────────────\n\nconst ANCHOR_TO_SVG: Record<\n NonNullable<GuideLabel[\"anchor\"]>,\n {\n textAnchor: React.SVGProps<SVGTextElement>[\"textAnchor\"];\n dominantBaseline: React.SVGProps<SVGTextElement>[\"dominantBaseline\"];\n }\n> = {\n // SVG `dominant-baseline` has no \"baseline\" keyword; \"alphabetic\" is the\n // bottom/baseline alignment (and React's typed union enforces this).\n tl: { textAnchor: \"start\", dominantBaseline: \"hanging\" },\n tc: { textAnchor: \"middle\", dominantBaseline: \"hanging\" },\n tr: { textAnchor: \"end\", dominantBaseline: \"hanging\" },\n cl: { textAnchor: \"start\", dominantBaseline: \"middle\" },\n c: { textAnchor: \"middle\", dominantBaseline: \"middle\" },\n cr: { textAnchor: \"end\", dominantBaseline: \"middle\" },\n bl: { textAnchor: \"start\", dominantBaseline: \"alphabetic\" },\n bc: { textAnchor: \"middle\", dominantBaseline: \"alphabetic\" },\n br: { textAnchor: \"end\", dominantBaseline: \"alphabetic\" },\n};\n\nfunction renderShape(\n path: SvgPath,\n commonProps: React.SVGProps<SVGElement>,\n): JSX.Element {\n if (path.kind === \"rect\") {\n return (\n <rect\n x={path.x}\n y={path.y}\n width={path.width}\n height={path.height}\n {...(commonProps as React.SVGProps<SVGRectElement>)}\n />\n );\n }\n if (path.kind === \"roundedRect\") {\n return (\n <rect\n x={path.x}\n y={path.y}\n width={path.width}\n height={path.height}\n rx={path.rx}\n ry={path.ry}\n {...(commonProps as React.SVGProps<SVGRectElement>)}\n />\n );\n }\n return (\n <path\n d={path.d}\n {...(commonProps as React.SVGProps<SVGPathElement>)}\n />\n );\n}\n\nfunction resolveBoundary(\n guide: PieceGuide | undefined,\n naturalW: number,\n naturalH: number,\n): SvgPath {\n // Authored boundaries live in the piece's NATURAL coord system (the\n // unrotated frame the layout was authored in). The fallback \"full\n // piece\" rect must therefore also be in natural dims, not the\n // displayed (post-rotation) `piece.width × piece.height`. Otherwise a\n // 90°/270° piece's fallback boundary lands sideways in the rotated\n // local frame. See PieceGuideRenderer.ts for the canvas-side mirror.\n return (\n guide?.boundary ?? {\n kind: \"rect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n }\n );\n}\n\n/**\n * Serialize an SvgPath to its SVG `d` attribute string. Used to build\n * evenodd compound paths (e.g. piece rect minus safe area) for the wash.\n */\nfunction svgPathD(path: SvgPath): string {\n if (path.kind === \"rect\") {\n return `M ${path.x} ${path.y} h ${path.width} v ${path.height} h ${-path.width} Z`;\n }\n if (path.kind === \"roundedRect\") {\n const rx = path.rx ?? path.ry ?? 0;\n const ry = path.ry ?? path.rx ?? 0;\n if (rx <= 0 && ry <= 0) {\n return `M ${path.x} ${path.y} h ${path.width} v ${path.height} h ${-path.width} Z`;\n }\n const { x, y, width: w, height: h } = path;\n return [\n `M ${x + rx} ${y}`,\n `h ${w - 2 * rx}`,\n `a ${rx} ${ry} 0 0 1 ${rx} ${ry}`,\n `v ${h - 2 * ry}`,\n `a ${rx} ${ry} 0 0 1 ${-rx} ${ry}`,\n `h ${-(w - 2 * rx)}`,\n `a ${rx} ${ry} 0 0 1 ${-rx} ${-ry}`,\n `v ${-(h - 2 * ry)}`,\n `a ${rx} ${ry} 0 0 1 ${rx} ${-ry}`,\n \"Z\",\n ].join(\" \");\n }\n return path.d;\n}\n\nfunction resolveSafeArea(\n guide: PieceGuide | undefined,\n piece: OverlayPiece,\n naturalW: number,\n naturalH: number,\n): SvgPath | null {\n if (guide?.safeArea) return guide.safeArea;\n if (piece.safeAreaInsetPx && piece.safeAreaInsetPx > 0) {\n const inset = piece.safeAreaInsetPx;\n return {\n kind: \"rect\",\n x: inset,\n y: inset,\n width: Math.max(0, naturalW - inset * 2),\n height: Math.max(0, naturalH - inset * 2),\n };\n }\n return null;\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport function VisualGuideOverlay({\n artboardWidth,\n artboardHeight,\n canvasPadding = 0,\n pieces,\n pieceGuides,\n show,\n style,\n className,\n}: VisualGuideOverlayProps): JSX.Element {\n const s = useMemo(() => {\n // Artboard-proportional default so labels stay legible at typical\n // viewport scales. Bumps with artboard size but clamped to a sane\n // floor. Callers can still override via `style.labelFontSize` to pin\n // an exact viewBox-unit value. 3% of the shorter axis reads clearly\n // at the zoom levels Snowcone's consumer editor typically renders at.\n const autoLabelFontSize = Math.max(\n 16,\n Math.round(Math.min(artboardWidth, artboardHeight) * 0.03),\n );\n const merged = {\n ...DEFAULT_STYLE,\n ...(style ?? {}),\n zoneFill: { ...DEFAULT_STYLE.zoneFill, ...(style?.zoneFill ?? {}) },\n zoneStroke: { ...DEFAULT_STYLE.zoneStroke, ...(style?.zoneStroke ?? {}) },\n };\n if (style?.labelFontSize === undefined) {\n merged.labelFontSize = autoLabelFontSize;\n }\n return merged;\n }, [style, artboardWidth, artboardHeight]);\n\n const visibility = {\n bleed: show?.bleed ?? true,\n zones: show?.zones ?? true,\n boundary: show?.boundary ?? true,\n safeArea: show?.safeArea ?? true,\n labels: show?.labels ?? true,\n };\n\n // Expand the viewBox to include SnowconeCanvas's padding on each side,\n // and translate all content by that padding so artboard-local coords\n // paint at the actual artboard position inside the padded canvas.\n // Without this, the SVG's painted rect matches the full padded canvas\n // (auto-centered by preserveAspectRatio) and drifts away from where\n // the canvas element paints the artboard — typically a few percent of\n // the smaller axis.\n const viewBoxWidth = artboardWidth + canvasPadding * 2;\n const viewBoxHeight = artboardHeight + canvasPadding * 2;\n\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}\n preserveAspectRatio=\"xMidYMid meet\"\n className={className}\n // Overlay mustn't swallow canvas interaction; individual elements\n // can opt back in with pointer-events if we later add hover/labels.\n style={{ pointerEvents: \"none\", width: \"100%\", height: \"100%\" }}\n >\n <g transform={`translate(${canvasPadding} ${canvasPadding})`}>\n {pieces.map((piece) => {\n const guide = pieceGuides?.[piece.id];\n const zones = guide?.zones ?? [];\n const labels = guide?.labels ?? [];\n\n // `piece.rotation` swaps the piece's displayed dim relative to\n // its natural (bbox) dim. Boundary / safeArea / wash etc. are\n // authored against the NATURAL coord system, so we need a\n // transform that maps natural (0, 0)→displayed corner exactly,\n // then draw at natural dims. The earlier `rotate(angle, cx, cy)`\n // around the *displayed* center offsets the rotated rect by\n // ((Nw−Dw)/2, (Nh−Dh)/2) — visible as a halo on rotated pieces.\n // Mirrors `PieceGuideRenderer.ts`'s canvas-side fix.\n //\n // SVG composes left-to-right; right-most transform applies\n // first. So for rotation = 90° CW the inner coord is rotated\n // first, then translated by (W, 0):\n // 90°: translate(piece.x piece.y) translate(W, 0) rotate(90)\n // 180°: translate(piece.x piece.y) translate(W, H) rotate(180)\n // 270°: translate(piece.x piece.y) translate(0, H) rotate(270)\n const rotation = piece.rotation ?? 0;\n const isOrtho = rotation === 90 || rotation === 270;\n const naturalW = isOrtho ? piece.height : piece.width;\n const naturalH = isOrtho ? piece.width : piece.height;\n const boundary = resolveBoundary(guide, naturalW, naturalH);\n const safeArea = resolveSafeArea(guide, piece, naturalW, naturalH);\n const originXform = `translate(${piece.x} ${piece.y})`;\n let rotationXform = \"\";\n if (rotation === 90) {\n rotationXform = `translate(${piece.width} 0) rotate(90)`;\n } else if (rotation === 180) {\n rotationXform = `translate(${piece.width} ${piece.height}) rotate(180)`;\n } else if (rotation === 270) {\n rotationXform = `translate(0 ${piece.height}) rotate(270)`;\n }\n const transform = rotationXform\n ? `${originXform} ${rotationXform}`\n : originXform;\n\n // Safe-area wash: fills the piece minus the safe area with a\n // subtle translucent color. This is the primary safe-area\n // indicator — replaces the old dashed outline for an Apple-y\n // \"fade out the edges\" feel. Only rendered when the safeArea is\n // rect/roundedRect (path-kind falls through until we parse SVG\n // path bounds in Phase 4).\n //\n // Wash outer uses a rounded rect by default so the fade hugs the\n // product's visual corners (phone cases, rounded cards) instead\n // of boxing sharp 90° corners. Consumers can set\n // `style.safeAreaWashCornerRadius = 0` for hard corners.\n const washRadius =\n s.safeAreaWashCornerRadius < 0\n ? Math.round(Math.min(naturalW, naturalH) * 0.02)\n : s.safeAreaWashCornerRadius;\n // Wash outer: prefer the authored boundary (it's the product's\n // actual design canvas — a rounded-rect phone case outline, a\n // book cover rectangle, etc.). Fall back to the piece rect only\n // when no boundary is authored. Apply the corner radius to a\n // plain-rect boundary at render time so the fade hugs the\n // product's visual curves even without explicit author geometry.\n const boundaryForWash: SvgPath | null =\n guide?.boundary &&\n (guide.boundary.kind === \"rect\" || guide.boundary.kind === \"roundedRect\")\n ? guide.boundary\n : null;\n const washOuter: SvgPath = boundaryForWash\n ? boundaryForWash.kind === \"rect\" && washRadius > 0\n ? {\n kind: \"roundedRect\",\n x: boundaryForWash.x,\n y: boundaryForWash.y,\n width: boundaryForWash.width,\n height: boundaryForWash.height,\n rx: washRadius,\n ry: washRadius,\n }\n : boundaryForWash\n : washRadius > 0\n ? {\n kind: \"roundedRect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n rx: washRadius,\n ry: washRadius,\n }\n : {\n kind: \"rect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n };\n // Bleed ring = piece rect ∖ boundary (the area OUTSIDE the\n // design canvas that physically wraps or trims). The inner\n // edge of the ring matches the boundary shape exactly, which\n // is the \"design canvas edge\" — where the sharp art stops.\n // No boundary stroke is drawn; the fade from bleed wash to\n // sharp art reads as the design-canvas edge on its own.\n const bleedFilterId = `bleed-blur-${piece.id}`;\n // Drawing happens in the natural coord system (post-rotation\n // transform), so the bleed-ring outer rect is sized at natural\n // dims. Same invariant as `washOuter` above.\n const pieceRect: SvgPath = {\n kind: \"rect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n };\n const canRenderBleed =\n washOuter.kind === \"rect\" || washOuter.kind === \"roundedRect\";\n\n return (\n <g key={piece.id} transform={transform}>\n {/* Bleed ring: (pieceRect ∖ boundary). Fills the wrap/trim\n zone outside the design canvas. Flat 55% bg-tertiary\n fill, softened with a big Gaussian blur so the inner\n edge fades smoothly out of the sharp design canvas —\n Apple vignette, no hard lines, no wash stroke. Clipped\n to the piece rect so the blur can't leak outside. */}\n {visibility.safeArea && canRenderBleed && (\n <>\n <defs>\n <filter\n id={bleedFilterId}\n x=\"-20%\"\n y=\"-20%\"\n width=\"140%\"\n height=\"140%\"\n >\n <feGaussianBlur\n in=\"SourceGraphic\"\n stdDeviation={\n // Scales with piece size so the fade feels\n // consistent across phones, notebook covers,\n // and tiny artboards alike. `Math.min` is\n // commutative, so the swap natural↔displayed\n // dim doesn't change the value here, but we\n // use natural dims for consistency with the\n // other piece-local geometry.\n Math.max(\n 12,\n Math.round(Math.min(naturalW, naturalH) * 0.025),\n )\n }\n />\n </filter>\n <clipPath id={`piece-clip-${piece.id}`}>\n <rect\n x={0}\n y={0}\n width={naturalW}\n height={naturalH}\n />\n </clipPath>\n </defs>\n <g\n clipPath={`url(#piece-clip-${piece.id})`}\n filter={`url(#${bleedFilterId})`}\n >\n <path\n d={`${svgPathD(pieceRect)} ${svgPathD(washOuter)}`}\n style={{\n // Honor `style.bleedFill` / `style.bleedOpacity`\n // overrides — previously hardcoded, which silently\n // dropped ADR-0054 Phase 5 `pieceGuidesStyle` edits\n // in the Loom authoring preview.\n fill: s.bleedFill || \"var(--color-bg-tertiary, #333)\",\n }}\n fillOpacity={s.bleedOpacity ?? 0.55}\n fillRule=\"evenodd\"\n />\n </g>\n </>\n )}\n\n {/* Non-die-cut zones render as a single filled+stroked shape.\n Die-cuts get a different treatment (blur + alpha) below\n so they share visual language with the canvas's own\n \"outside the artboard\" dim treatment. */}\n {visibility.zones &&\n zones\n .filter((z) => z.kind !== \"dieCut\")\n .map((zone, i) => (\n <g key={`zone-${i}`}>\n {renderShape(zone.path, {\n fill: s.zoneFill[zone.kind],\n stroke: s.zoneStroke[zone.kind],\n strokeWidth: 1.5,\n strokeDasharray: zone.kind === \"wrap\" ? \"4 3\" : undefined,\n vectorEffect: \"non-scaling-stroke\",\n } as unknown as React.SVGProps<SVGElement>)}\n </g>\n ))}\n\n {/* Die-cut zones: same visual language as elements that\n overflow the artboard in CanvasRenderer.ts (4px blur +\n ~30% white tint). Implemented via <foreignObject> so we\n can use CSS `backdrop-filter` to blur the canvas pixels\n beneath in place — no coordinate translation needed,\n since the foreignObject inherits the SVG viewBox\n coordinate system. Matches CanvasRenderer.ts:263-264. */}\n {visibility.zones &&\n zones\n .filter((z) => z.kind === \"dieCut\")\n .map((zone, i) => {\n const p = zone.path;\n if (p.kind !== \"rect\" && p.kind !== \"roundedRect\") {\n return null;\n }\n const rx =\n p.kind === \"roundedRect\" ? (p.rx ?? p.ry ?? 0) : 0;\n const ry =\n p.kind === \"roundedRect\" ? (p.ry ?? p.rx ?? 0) : 0;\n return (\n <foreignObject\n key={`diecut-${i}`}\n x={p.x}\n y={p.y}\n width={p.width}\n height={p.height}\n >\n <div\n // xmlns is required inside foreignObject so the\n // HTML child is parsed as HTML, not SVG. React's\n // HTMLDivElement prop types don't declare `xmlns`,\n // so spread it as a narrowly-typed extra attribute\n // rather than weaken the whole element's typing.\n {...({ xmlns: \"http://www.w3.org/1999/xhtml\" } as {\n xmlns: string;\n })}\n style={{\n width: \"100%\",\n height: \"100%\",\n borderRadius: `${rx}px / ${ry}px`,\n backdropFilter: \"blur(4px)\",\n WebkitBackdropFilter: \"blur(4px)\",\n // Match the canvas's own \"outside-artboard\"\n // tint (CanvasRenderer.ts uses globalAlpha=0.3\n // against `--color-bg-tertiary`). We stack the\n // bg-tertiary colour at 70% alpha on top of the\n // blurred artwork to achieve the same visual\n // blend. color-mix lets us stay theme-aware in\n // both light and dark modes.\n background:\n \"color-mix(in srgb, var(--color-bg-tertiary, #333) 70%, transparent)\",\n }}\n />\n </foreignObject>\n );\n })}\n\n {/* Boundary outline — only rendered when `boundaryStroke`\n is explicitly set by a consumer. Default is no stroke;\n the bleed wash's soft inner edge carries the\n design-canvas edge on its own. */}\n {visibility.boundary &&\n s.boundaryStroke &&\n renderShape(boundary, {\n fill: \"none\",\n stroke: s.boundaryStroke,\n strokeWidth: s.boundaryStrokeWidth,\n vectorEffect: \"non-scaling-stroke\",\n } as unknown as React.SVGProps<SVGElement>)}\n\n {/* Optional dashed safe-area outline (opt-in: empty by\n default so the wash alone carries the signal; consumers\n can set `style.safeAreaStroke` to a color to restore). */}\n {visibility.safeArea &&\n safeArea &&\n s.safeAreaStroke &&\n renderShape(safeArea, {\n fill: \"none\",\n stroke: s.safeAreaStroke,\n strokeWidth: s.safeAreaStrokeWidth,\n strokeDasharray: s.safeAreaDashArray,\n vectorEffect: \"non-scaling-stroke\",\n } as unknown as React.SVGProps<SVGElement>)}\n\n {/* Labels — font-size in CSS px via non-scaling approach.\n We draw at the piece-local coords but inside the viewBox\n the text honors its own font-size unchanged (fonts don't\n scale with SVG viewBox), so we bake the intended visual\n font size directly. */}\n {visibility.labels &&\n labels.map((label, i) => {\n const a = ANCHOR_TO_SVG[label.anchor ?? \"c\"];\n return (\n <text\n key={`label-${i}`}\n x={label.x}\n y={label.y}\n textAnchor={a.textAnchor}\n dominantBaseline={a.dominantBaseline}\n fontSize={s.labelFontSize}\n fontFamily={s.labelFontFamily}\n fill={s.labelColor}\n style={{ paintOrder: \"stroke\" }}\n stroke=\"#ffffff\"\n // Halo width tracks font size so labels stay legible\n // over any background at any zoom.\n strokeWidth={Math.max(2, s.labelFontSize * 0.25)}\n strokeLinejoin=\"round\"\n >\n {label.text}\n </text>\n );\n })}\n </g>\n );\n })}\n </g>\n </svg>\n );\n}\n\n","/**\n * @snowcone-app/canvas/advanced — Advanced API (Tier 2)\n *\n * May add new exports in minor versions. Breaking changes with migration\n * guide in minor versions. For developers building custom editor layouts\n * and integrations.\n *\n * @packageDocumentation\n */\n\n// Register all icons on module load\nimport { ensureIconsRegistered } from '../icons/registry.js';\nensureIconsRegistered();\n\n// =============================================================================\n// Individual Panel Components\n// =============================================================================\n\nexport { Canvas } from '../components/embed/Canvas.js';\nexport type { CanvasProps } from '../components/embed/Canvas.js';\n\nexport { LayersPanel } from '../components/embed/LayersPanel.js';\nexport type { LayersPanelProps } from '../components/embed/LayersPanel.js';\n\nexport { EffectsPanel } from '../components/embed/EffectsPanel.js';\nexport type { EffectsPanelProps } from '../components/embed/EffectsPanel.js';\n\nexport { ExportPanel } from '../components/embed/ExportPanel.js';\nexport type { ExportPanelProps } from '../components/embed/ExportPanel.js';\n\nexport { ImagePanel } from '../components/embed/ImagePanel.js';\nexport type { ImagePanelProps } from '../components/embed/ImagePanel.js';\n\nexport { GlyphPanel } from '../components/embed/GlyphPanel.js';\nexport type { GlyphPanelProps } from '../components/embed/GlyphPanel.js';\n\nexport { ArtboardTabs } from '../components/embed/ArtboardTabs.js';\nexport type { ArtboardTabsProps } from '../components/embed/ArtboardTabs.js';\n\nexport { ContextualToolbars } from '../components/ContextualToolbars.js';\nexport type { ContextualToolbarsProps } from '../components/ContextualToolbars.js';\n\nexport { default as ShapeTypeDrawer } from '../components/ShapeTypeDrawer.js';\n\nexport { MenuButton } from '../components/embed/MenuButton.js';\nexport type { MenuButtonProps } from '../components/embed/MenuButton.js';\n\nexport { ZoomControls } from '../components/embed/ZoomControls.js';\nexport type { ZoomControlsProps } from '../components/embed/ZoomControls.js';\n\nexport { CropPanel } from '../components/CropPanel.js';\nexport type { CropPanelProps } from '../components/CropPanel.js';\n\n// =============================================================================\n// Providers (for custom composition)\n// =============================================================================\n\nexport { EditorProvider } from '../contexts/EditorContext.js';\nexport type { EditorElement, PanOffset, ExpandedPanelType } from '../contexts/EditorContext.js';\n\nexport { ThemeProvider, useTheme } from '../contexts/ThemeContext.js';\nexport type { Theme } from '../contexts/ThemeContext.js';\n\nexport { KitProvider, useKit, useCapabilities } from '../contexts/KitContext.js';\nexport type { KitContextValue, KitProviderProps } from '../contexts/KitContext.js';\n\n// =============================================================================\n// Sub-Context Hooks\n// =============================================================================\n\nexport { useViewportContext } from '../contexts/ViewportContext.js';\nexport type { ViewportContextValue, ViewportProviderProps } from '../contexts/ViewportContext.js';\n\nexport { useSelectionContext } from '../contexts/SelectionContext.js';\nexport type { SelectionContextValue, SelectionProviderProps } from '../contexts/SelectionContext.js';\n\nexport { useHistoryContext } from '../contexts/HistoryContext.js';\nexport type { HistoryContextValue, HistoryProviderProps } from '../contexts/HistoryContext.js';\n\nexport { useToolStateContext } from '../contexts/ToolStateContext.js';\nexport type { ToolStateContextValue, ToolStateProviderProps } from '../contexts/ToolStateContext.js';\n\nexport { useElementsContext } from '../contexts/ElementsContext.js';\nexport type { ElementsContextValue, ElementsProviderProps } from '../contexts/ElementsContext.js';\n\nexport { useCommandContext } from '../contexts/CommandContext.js';\nexport type { CommandContextValue, CommandProviderProps } from '../contexts/CommandContext.js';\n\n// =============================================================================\n// Element Types (classes for instanceof checks)\n// =============================================================================\n\nexport { TextElement } from '../core/TextElement.js';\nexport { ImageElement } from '../core/ImageElement.js';\nexport { GroupElement } from '../core/GroupElement.js';\nexport { ShapeElement } from '../core/ShapeElement.js';\nexport { PathElement } from '../core/PathElement.js';\nexport { BaseElement } from '../core/BaseElement.js';\nexport { ArtboardElement } from '../core/ArtboardElement.js';\n\n// Config type guards\nexport {\n isTextElementConfig,\n isImageElementConfig,\n isCustomElementConfig,\n isCircleElementConfig,\n isGroupElementConfig,\n isShapeElementConfig,\n isPathElementConfig,\n} from '../types/index.js';\n\n// Instance type guards\nexport {\n isTextElement,\n isImageElement,\n isGroupElement,\n isShapeElement,\n isPathElement,\n} from '../types/guards.js';\n\n// Element config types\nexport type {\n BaseElementConfig,\n BaseTextElementConfig,\n TextOnlyElementConfig,\n CustomElementConfig,\n ImageElementConfig,\n GroupElementConfig,\n ShapeElementConfig,\n PathElementConfig,\n CircleElementConfig,\n ArchElementConfig,\n WaveElementConfig,\n FlagElementConfig,\n LeanElementConfig,\n AscendElementConfig,\n} from '../types/index.js';\n\n// =============================================================================\n// Advanced Hooks\n// =============================================================================\n\nexport { useProjectLoader } from '../hooks/useProjectLoader.js';\nexport type { ProjectTemplate, ProjectMetadata, UseProjectLoaderReturn } from '../hooks/useProjectLoader.js';\n\nexport { useTextToolbar } from '../hooks/useTextToolbar.js';\nexport type { UseTextToolbarOptions, UseTextToolbarReturn } from '../hooks/useTextToolbar.js';\n\nexport { useBreakpoint } from '../hooks/useBreakpoint.js';\nexport type { BreakpointConfig, Breakpoint, UseBreakpointReturn } from '../hooks/useBreakpoint.js';\n\nexport { usePerformance } from '../hooks/usePerformance.js';\nexport type { PerformanceMetrics, UsePerformanceReturn } from '../hooks/usePerformance.js';\n\nexport { useElementById } from '../hooks/useElementById.js';\n\nexport { useLayerPreview } from '../hooks/useLayerPreview.js';\nexport type { UseLayerPreviewOptions, UseLayerPreviewReturn } from '../hooks/useLayerPreview.js';\n\nexport { useLayerDragDrop } from '../hooks/useLayerDragDrop.js';\nexport type { UseLayerDragDropOptions, UseLayerDragDropReturn } from '../hooks/useLayerDragDrop.js';\n\nexport { useLayerSelection } from '../hooks/useLayerSelection.js';\nexport type { UseLayerSelectionOptions, UseLayerSelectionReturn } from '../hooks/useLayerSelection.js';\n\n// =============================================================================\n// UI Primitives\n// =============================================================================\n\nexport * from '../components/embed/primitives/index.js';\nexport * from '../components/embed/ui/index.js';\n\n// =============================================================================\n// Text Toolbar\n// =============================================================================\n\nexport { TextToolbar } from '../components/TextToolbar.js';\nexport type { TextToolbarProps } from '../components/TextToolbar.js';\nexport * from '../components/text-toolbar/index.js';\n\n// =============================================================================\n// Loading States\n// =============================================================================\n\nexport { CanvasSkeleton, LayersPanelSkeleton, ToolbarSkeleton, Spinner } from '../components/embed/LoadingStates.js';\nexport type { CanvasSkeletonProps, LayersPanelSkeletonProps, ToolbarSkeletonProps } from '../components/embed/LoadingStates.js';\n\n// =============================================================================\n// Auto Export Manager\n// =============================================================================\n\nexport { AutoExportManager, DEFAULT_AUTO_EXPORT_CONFIG } from '../services/AutoExportManager.js';\nexport type { AutoExportConfig, AutoExportStats } from '../services/AutoExportManager.js';\n\n// =============================================================================\n// Selection Preservation\n// =============================================================================\n\nexport {\n shouldPreserveSelection,\n preserveSelectionProps,\n PRESERVE_SELECTION_ATTR,\n} from '../utils/selectionPreservation.js';\n\n// =============================================================================\n// Advanced Types\n// =============================================================================\n\nexport type {\n AnyTransformData,\n CustomTransformData,\n CircleTransformData,\n ArchTransformData,\n WaveTransformData,\n FlagTransformData,\n LeanTransformData,\n AscendTransformData,\n ImageTransformData,\n GroupTransformData,\n ShapeTransformData,\n PathTransformData,\n StrokeConfig,\n MaskType,\n MaskDefinition,\n KnockoutScope,\n KnockoutConfig,\n DistressStyle,\n DistressEffect,\n CharacterStyle,\n TextSpan,\n GlyphOverride,\n GlyphAlternate,\n OpenTypeFeatures,\n ShapeType,\n PathPointType,\n PathPoint,\n InteractionMode,\n SelectionState,\n ResizeAnchor,\n RenderingContext,\n} from '../types/index.js';\n\nexport { RichText } from '../types/index.js';\n\n// Transform data type guards\nexport {\n isCustomTransform,\n isCircleTransform,\n isArchTransform,\n isWaveTransform,\n isFlagTransform,\n isImageTransform,\n isGroupTransform,\n isShapeTransform,\n isPathTransform,\n hasStroke,\n hasMasks,\n isKnockout,\n hasDistressEffect,\n} from '../types/index.js';\n\n// Kit registry\nexport { KIT_PRESETS } from '../kits/registry.js';\n\n// =============================================================================\n// Section Registry\n// =============================================================================\n\nexport {\n registerSection,\n getSection,\n getSectionIds,\n getAllSections,\n unregisterSection,\n registerBuiltinSections,\n registerBuiltinSectionsSync,\n} from '../kits/sections.js';\nexport type { SectionConfig, SectionComponent } from '../kits/sections.js';\n\n// =============================================================================\n// Kit Serialization\n// =============================================================================\n\nexport { serializeKit, loadKitFromJSON } from '../kits/serialization.js';\nexport type { KitJSON } from '../kits/serialization.js';\n\n// =============================================================================\n// Plugin System: Custom Element Types\n// =============================================================================\n\nexport {\n registerElementType,\n unregisterElementType,\n getCustomElementTypes,\n isRegisteredElementType,\n} from '../plugins/ElementTypePlugin.js';\nexport type { ElementTypeRegistration } from '../plugins/ElementTypePlugin.js';\n\n// =============================================================================\n// Event Bus\n// =============================================================================\n\nexport { CanvasEventBus, canvasEventBus } from '../core/EventBus.js';\nexport type { CanvasEventMap, CanvasEventHandler } from '../core/EventBus.js';\nexport { useCanvasEvents } from '../hooks/useCanvasEvents.js';\n\n// =============================================================================\n// ADR-0054: Visual Guide Overlay\n// =============================================================================\n\nexport { VisualGuideOverlay } from '../components/VisualGuideOverlay.js';\nexport type {\n VisualGuideOverlayProps,\n VisualGuideOverlayStyle,\n OverlayPiece,\n PieceGuide,\n SvgPath,\n ZoneShape,\n GuideLabel,\n} from '../components/VisualGuideOverlay.js';\n\n/**\n * Canvas-native piece-guide rendering (ADR-0054). Prefer the\n * `pieceGuides` prop on `SnowconeCanvas` over mounting a\n * `VisualGuideOverlay` — the canvas-native path draws inside the\n * render loop and avoids the coordinate-system drift of the DOM\n * overlay.\n */\nexport { renderPieceGuides } from '../rendering/PieceGuideRenderer.js';\nexport type {\n PieceGuideRenderParams,\n PieceGuideRendererPiece,\n PieceGuideRendererStyle,\n PieceGuideVisibility,\n} from '../rendering/PieceGuideRenderer.js';\nexport type { PieceGuidesConfig } from '../components/embed/SnowconeCanvas.js';\n"],"names":["sectionRegistry","registerSection","id","config","getSection","getSectionIds","getAllSections","unregisterSection","builtinsRegistered","registerBuiltinSections","LayersPanel","EffectsPanel","ExportPanel","ImagePanel","GlyphPanel","ArtboardTabs","ContextualToolbars","ZoomControls","MenuButton","CropPanel","LayersPanel$1","EffectsPanel$1","ExportPanel$1","ImagePanel$1","GlyphPanel$1","ArtboardTabs$1","ContextualToolbars$1","ZoomControls$1","MenuButton$1","CropPanel$1","registerBuiltinSectionsSync","components","serializeKit","kit","json","loadKitFromJSON","overrides","base","resolveKit","extendKit","createKit","validation","validateKit","warning","canUseDOM","isWindow","element","elementString","isNode","node","getWindow","target","_target$ownerDocument","_target$ownerDocument2","isDocument","Document","isHTMLElement","isSVGElement","getOwnerDocument","useIsomorphicLayoutEffect","useLayoutEffect","useEffect","useEvent","handler","handlerRef","useRef","useCallback","_len","args","_key","useInterval","intervalRef","set","listener","duration","clear","useLatestValue","value","dependencies","valueRef","useLazyMemo","callback","useMemo","newValue","useNodeRef","onChange","onChangeHandler","setNodeRef","usePrevious","ref","ids","useUniqueId","prefix","createAdjustmentFn","modifier","object","adjustments","accumulator","adjustment","entries","key","valueAdjustment","add","subtract","hasViewportRelativeCoordinates","event","isKeyboardEvent","KeyboardEvent","isTouchEvent","TouchEvent","getEventCoordinates","x","y","CSS","transform","scaleX","scaleY","_ref","property","easing","SELECTOR","findFirstFocusableNode","hiddenStyles","HiddenText","React","LiveRegion","announcement","ariaLiveType","visuallyHidden","useAnnouncement","setAnnouncement","useState","DndMonitorContext","createContext","useDndMonitor","registerListener","useContext","useDndMonitorProvider","listeners","type","_listener$type","defaultScreenReaderInstructions","defaultAnnouncements","active","_ref2","over","_ref3","_ref4","Accessibility","announcements","container","hiddenTextDescribedById","screenReaderInstructions","announce","liveRegionId","mounted","setMounted","_ref5","_ref6","markup","createPortal","Action","noop","useSensor","sensor","options","useSensors","sensors","defaultCoordinates","distanceBetween","p1","p2","getRelativeTransformOrigin","rect","eventCoordinates","transformOrigin","sortCollisionsAsc","a","b","sortCollisionsDesc","cornersOfRectangle","left","top","height","width","getFirstCollision","collisions","firstCollision","centerOfRectangle","closestCenter","collisionRect","droppableRects","droppableContainers","centerRect","droppableContainer","distBetween","closestCorners","corners","rectCorners","distances","corner","index","effectiveDistance","getIntersectionRatio","entry","right","bottom","targetArea","entryArea","intersectionArea","intersectionRatio","rectIntersection","isPointWithinRect","point","pointerWithin","pointerCoordinates","adjustScale","rect1","rect2","getRectDelta","createRectAdjustmentFn","acc","getAdjustedRect","parseTransform","transformArray","inverseTransform","parsedTransform","translateX","translateY","w","defaultOptions","getClientRect","getTransformAgnosticClientRect","getWindowClientRect","isFixed","computedStyle","isScrollable","overflowRegex","getScrollableAncestors","limit","scrollParents","findScrollableAncestors","getFirstScrollableAncestor","firstScrollableAncestor","getScrollableElement","getScrollXCoordinate","getScrollYCoordinate","getScrollCoordinates","Direction","isDocumentScrollingElement","getScrollPosition","scrollingContainer","minScroll","dimensions","maxScroll","isTop","isLeft","isBottom","isRight","defaultThreshold","getScrollDirectionAndSpeed","scrollContainer","scrollContainerRect","acceleration","thresholdPercentage","direction","speed","threshold","getScrollElementRect","innerWidth","innerHeight","getScrollOffsets","scrollableAncestors","getScrollXOffset","getScrollYOffset","scrollIntoViewIfNeeded","measure","properties","Rect","scrollOffsets","axis","keys","getScrollOffset","currentOffsets","scrollOffsetsDeltla","Listeners","_this$target","eventName","_this$target2","getEventListenerTarget","EventTarget","hasExceededDistance","delta","measurement","dx","dy","EventName","preventDefault","stopPropagation","KeyboardCode","defaultKeyboardCodes","defaultKeyboardCoordinateGetter","currentCoordinates","KeyboardSensor","props","activeNode","onStart","context","keyboardCodes","coordinateGetter","scrollBehavior","code","newCoordinates","coordinatesDelta","scrollDelta","scrollElementRect","clampedCoordinates","canScrollX","canScrollY","newScrollCoordinates","canScrollToNewCoordinates","coordinates","onMove","onEnd","onCancel","onActivation","activator","isDistanceConstraint","constraint","isDelayConstraint","AbstractPointerSensor","events","listenerTarget","_getEventCoordinates","activationConstraint","bypassActivationConstraint","offset","onPending","initialCoordinates","_getEventCoordinates2","activated","onAbort","_this$document$getSel","PointerSensor","events$1","MouseButton","MouseSensor","events$2","TouchSensor","touches","AutoScrollActivator","TraversalOrder","useAutoScroller","canScroll","draggingRect","enabled","interval","order","scrollableAncestorRects","scrollIntent","useScrollIntent","setAutoScrollInterval","clearAutoScrollInterval","scrollSpeed","scrollDirection","scrollContainerRef","autoScroll","scrollLeft","scrollTop","sortedScrollableAncestors","defaultScrollIntent","disabled","previousDelta","previousIntent","useCachedNode","draggableNodes","draggableNode","cachedNode","useCombineActivators","getSyntheticHandler","Sensor","sensorActivators","MeasuringStrategy","MeasuringFrequency","defaultValue","useDroppableMeasuring","containers","dragging","queue","setQueue","frequency","strategy","containersRef","isDisabled","disabledRef","measureDroppableContainers","timeoutId","previousValue","map","useInitialValue","computeFn","useInitialRect","useMutationObserver","handleMutations","mutationObserver","MutationObserver","useResizeObserver","handleResize","resizeObserver","ResizeObserver","defaultMeasure","useRect","fallbackRect","setRect","measureRect","currentRect","newRect","records","record","useRectDelta","initialRect","defaultValue$1","useScrollableAncestors","previousNode","ancestors","useScrollOffsets","elements","scrollCoordinates","setScrollCoordinates","prevElements","handleScroll","scrollingElement","previousElements","cleanup","scrollableElement","useScrollOffsetsDelta","initialScrollOffsets","hasScrollOffsets","useSensorSetup","teardownFns","teardown","useSyntheticListeners","useWindowRect","defaultValue$2","useRects","firstElement","windowRect","rects","setRects","measureRects","getMeasurableNode","firstChild","useDragOverlayMeasuring","handleNodeChange","nodeRef","setRef","defaultSensors","defaultData","defaultMeasuringConfiguration","DroppableContainersMap","_super$get","_this$get$node$curren","_this$get","defaultPublicContext","defaultInternalContext","InternalContext","PublicContext","getInitialState","reducer","state","action","RestoreFocus","activatorEvent","previousActivatorEvent","previousActiveId","activatorNode","focusableNode","applyModifiers","modifiers","useMeasuringConfiguration","useLayoutShiftScrollCompensation","initialized","rectDelta","ActiveDraggableContext","Status","DndContext","memo","_sensorContext$curren","_dragOverlay$nodeRef$","_dragOverlay$rect","_over$rect","accessibility","children","collisionDetection","measuring","store","useReducer","dispatch","dispatchMonitorEvent","registerMonitorListener","status","setStatus","isInitialized","activeId","translate","activeRects","_node$data","activeRef","activeSensor","setActiveSensor","setActivatorEvent","latestProps","draggableDescribedById","enabledDroppableContainers","measuringConfiguration","measuringScheduled","activationCoordinates","autoScrollOptions","getAutoScrollerOptions","initialActiveNodeRect","activeNodeRect","containerNodeRect","sensorContext","overNode","dragOverlay","draggingNode","draggingNodeRect","usesDragOverlay","nodeRectDelta","modifiedTranslate","scrollAdjustment","activeNodeScrollDelta","scrollAdjustedTranslate","overId","setOver","appliedTranslate","activeSensorRef","instantiateSensor","sensorInstance","onDragAbort","onDragPending","onDragStart","unstable_batchedUpdates","createHandler","cancelDrop","bindActivatorToSensorInstantiator","nativeEvent","activeDraggableNode","activationContext","activators","onDragMove","onDragOver","overContainer","publicContext","internalContext","activeSensorDisablesAutoscroll","autoScrollGloballyDisabled","NullContext","defaultRole","ID_PREFIX","useDraggable","data","attributes","ariaDescribedById","role","roleDescription","tabIndex","isDragging","setActivatorNodeRef","dataRef","memoizedAttributes","useDndContext","ID_PREFIX$1","defaultResizeObserverConfig","useDroppable","resizeObserverConfig","previous","resizeObserverConnected","callbackId","resizeObserverDisabled","updateMeasurementsFor","resizeObserverTimeout","newElement","previousElement","AnimationManager","animation","clonedChildren","setClonedChildren","setElement","previousChildren","cloneElement","defaultTransform","NullifiedContextProvider","baseStyles","defaultTransition","PositionedOverlay","forwardRef","as","className","style","transition","scaleAdjustedTransform","styles","defaultDropAnimationSideEffects","originalStyles","defaultKeyframeResolver","initial","final","defaultDropAnimationConfiguration","useDropAnimation","activeDraggable","measurableNode","createDefaultDropAnimation","sideEffects","keyframes","rest","scale","finalTransform","animationKeyframes","firstKeyframe","lastKeyframe","resolve","useKey","DragOverlay","dropAnimationConfig","wrapperElement","zIndex","modifiedTransform","dropAnimation","hasSortableData","directions","sortableKeyboardCoordinates","filteredContainers","closestId","activeDroppable","newDroppable","newNode","hasDifferentScrollAncestors","hasSameContainer","isSameContainer","isAfterActive","isAfter","rectCoordinates","getZoneFromCollisions","zone","_a","useLayerDndKit","onReorder","onGroupReorder","onDropIntoGroup","onDropIntoGroupAtPosition","onRemoveFromGroup","findParentGroup","setActiveId","setOverId","dropPosition","setDropPosition","dropPositionRef","handleDragStart","handleDragOver","handleDragMove","resetState","handleDragEnd","currentDropPosition","draggedId","targetId","groupId","draggedParent","arrayPosition","targetParent","handleDragCancel","cn","inputs","twMerge","clsx","SET_SCALE_FACTORS","DEFAULT_SCALE_FACTOR","ICON_OFFSETS","SIZE_PRESETS","getIconSet","icon","colonIndex","getScaleFactor","iconSet","getIconOffset","getNormalizedSize","baseSize","scaleFactor","NormalizedIcon","size","sizePreset","mobileSize","desktopSize","scaledOffset","jsx","Icon","normalizedSize","ToolbarButton","onClick","tooltip","tooltipDelay","tooltipDisabled","ariaLabel","onMouseLeave","buttonElement","Button","jsxs","Tooltip","TooltipTrigger","TooltipContent","RotateLeftIcon","SparklesIcon","icons","CollapsedToolbarHeader","label","onClose","closeButtonStyle","containerRef","touchStartPos","el","handleTouchStart","e","handleTouchMove","deltaX","deltaY","TouchGuard","SliderRow","min","max","step","unit","showInput","inputWidth","variant","displayValue","Slider","val","SELECTED_CLASSES","UNSELECTED_CLASSES","PresetCarousel","presets","selectedId","onSelect","showOff","scrollToItem","button","handleKeyDown","buttons","focused","currentIndex","btn","nextIndex","nextButton","presetId","isOffSelected","hasSelection","p","preset","isSelected","isTabbable","layerCollisionDetection","winner","relativeY","c","isGroup","_b","SortableLayerItem","layer","isOver","isDragActive","showPreviewImages","previewDisplaySize","onToggleVisibility","onToggleLock","onDuplicate","onDelete","setDragRef","setDropRef","isGroupRow","isChild","indentPx","selectionRingStyle","handleClick","dragHandle","LayerActionButton","title","extraStyle","GroupFooterDropZone","depth","DragOverlayContent","enableDragReorder","enableGrouping","showHeader","layerOptions","activeArtboard","useArtboards","previewBgColor","previewResolution","layers","flatLayers","selectLayer","toggleVisibility","toggleLock","deleteLayer","duplicateLayer","reorderById","reorderWithinGroup","addToGroup","removeFromGroup","createEmptyGroup","findElementById","generateAllPreviews","useLayers","layerMap","collect","layerList","handleReorder","position","activeDnd","renderDraggableLayerTree","renderStaticLayerTree","StaticLayerItem","activeLayer","styleWidth","styleHeight","flex","restStyle","finalWidth","finalHeight","flexValue","rowStyle","useIsDocumentDark","isDark","setIsDark","update","obs","Drawer","isOpen","description","placement","maxHeight","maxWidth","showCloseButton","headerActions","hideVisibleTitle","hideHandle","disableScrollWrapper","disableOverflowHidden","dataTestId","heightStyle","scrimOpacity","BaseDrawer","open","DrawerContent","DrawerTitle","DrawerDescription","u","r","n","t","o","i","s","f","v","d","h","g","l","m","_","E","C","H","M","N","L","D","I","q","B","S","T","F","X","Y","U","V","G","J","Q","W","Z","ColorPickerDropdown","documentColors","imageColors","showSquare","allowTransparent","controlledIsOpen","controlledOnOpenChange","embedded","internalIsOpen","setInternalIsOpen","hexInput","setHexInput","localColor","setLocalColor","lastUpdateTimeRef","pendingUpdateRef","isDraggingRef","onChangeRef","setIsOpen","handleColorChange","color","now","timeSinceLastUpdate","localColorRef","handlePointerUp","handleHexInputChange","input","hexPattern","withHash","handlePresetClick","handleTransparentClick","isTransparent","buttonContent","pickerContent","HexColorPicker","Popover","PopoverTrigger","PopoverContent","StrokePanel","stroke","isExpanded","setIsExpanded","lineCap","lineJoin","opacity","handleEnabledChange","newEnabled","handleWidthChange","newWidth","handleOpacityChange","newOpacity","handleLineCapChange","newLineCap","handleLineJoinChange","newLineJoin","Disclosure","DisclosureTrigger","Label","Switch","DisclosureContent","Fieldset","TooltipProvider","RadioGroup","Radio","MaskItem","mask","isFirst","isLast","onUpdate","onRemove","getMaskIcon","getMaskLabel","handleFeatherChange","handleInvertedToggle","handleMaskElementTypeChange","transformType","existingUrl","handleShapeTypeChange","shapeType","handleTextChange","textConfig","handleImageUrlChange","imgConfig","handleSizeChange","getMaskElementSize","MasksPanel","masks","showAddMenu","setShowAddMenu","handleAddMask","newMask","createDefaultMaskElement","handleRemoveMask","maskId","handleUpdateMask","updates","handleReorderMask","newMasks","WORN_LIGHT","WORN_MEDIUM","WORN_HEAVY","CRACKED_LIGHT","CRACKED_MEDIUM","CRACKED_HEAVY","GRUNGE_LIGHT","GRUNGE_MEDIUM","GRUNGE_HEAVY","RETRO_LIGHT","RETRO_MEDIUM","RETRO_HEAVY","DISTRESS_PRESETS","getPreset","category","level","DistressPanel","distressEffect","ensureBuiltinTexturesReady","showPresets","setShowPresets","intensity","fadeAmount","grainAmount","scratchAmount","edgeWear","handlePresetApply","handleStyleChange","newStyle","url","DISTRESS_TEXTURE_PRESETS","preloadTexture","handleTextureSelect","handleTextureOpacityChange","handleIntensityChange","handleFadeChange","handleGrainChange","handleScratchChange","handleEdgeWearChange","handleRandomize","Fragment","hasCompositing","getCompositingParts","parts","describeCompositing","mode","scope","modeLabel","describeKnockout","CompositingPanel","blendMode","knockoutParts","isCompositing","isKnockout","fillEnabled","strokeEnabled","handleBlendModeChange","newMode","handleFillToggle","handleStrokeToggle","handleScopeChange","newScope","logger","createLogger","GlyphPicker","character","charIndex","fontFamily","fontWeight","currentGlyphOverride","onSelectGlyph","browseAll","alternates","setAlternates","loading","setLoading","error","setError","FontAnalyzer","alts","err","handleSelectGlyph","alternate","isDefault","FEATURE_DEFINITIONS","OpenTypeFeaturesPanel","text","openTypeFeatures","glyphOverrides","onGlyphOverridesChange","availableFeatures","setAvailableFeatures","glyphPickerOpen","setGlyphPickerOpen","selectedCharIndex","setSelectedCharIndex","selectedCharacter","setSelectedCharacter","browseAllMode","setBrowseAllMode","alternateCounts","setAlternateCounts","_loadingCounts","setLoadingCounts","features","uniqueChars","counts","char","alternateCount","handleToggleFeature","tag","currentValue","newFeatures","handleCharacterClick","handleBrowseAllGlyphs","override","newOverrides","existingIndex","enabledCount","glyphOverridesCount","groupedFeatures","feature","hasOverride","availableFeaturesInCategory","onElementUpdate","activeTab","setActiveTab","hasStroke","hasMasks","hasDistress","hasKnockout","isTextElement","TextElement","hasTypography","Tabs","Badge","updated","externalElement","externalOnElementUpdate","selectedElement","executeElementUpdate","useEditor","handleElementUpdate","updatedElement","EffectsPanelCore","showContinuousExport","defaultScale","defaultFormat","onExportComplete","exportArtboard","exportAllArtboards","startContinuousExport","stopContinuousExport","isExporting","isContinuousExporting","progress","supportsWorkerExport","workerStats","useExport","artboardsInfo","activeArtboardId","setScale","format","setFormat","setInterval","handleExportActive","dataUrl","link","artboard","timestamp","baseName","handleExportAll","exports","artboardId","handleToggleContinuous","PROXY_URL","__vite_import_meta_env__","API_BASE_URL","isNounProjectConfigured","mapNounProjectToVectorResult","hasSvgUrl","svgUrl","_c","searchIcons","query","includeSvg","limitToPublicDomain","nextPage","params","queryString","fullUrl","response","errorText","getFeaturedIcons","featuredTerms","randomTerm","results","RECRAFT_STYLES","RECRAFT_API_BASE","isRecraftConfigured","token","generateImage","prompt","substyle","requestBody","imageData","downloadRecraftImage","blob","FAL_API_KEY","isFalConfigured","removeBackground","imageUrl","convertToDataUrl","reject","reader","isSvgImage","urlLower","convertSvgToPng","img","canvas","ctx","pngDataUrl","RUNWARE_API_KEY","RUNWARE_MODELS","runwareInstance","isRunwareConfigured","getRunwareInstance","Runware","generateImages","request","runware","modelConfig","supportsSteps","supportsCFGScale","supportsNegativePrompt","requestParams","images","convertImageToDataUrl","log","MASONRY_GAP","GRID_GAP","ImageCard","image","onImageSelect","fixedHeight","isHovered","setIsHovered","showInfo","setShowInfo","setDirection","openTimeoutRef","closeTimeoutRef","cardRef","isFirstRender","noTransition","setNoTransition","enterFrameRef","handleImageClick","getDirection","handleMouseEnter","newDirection","handleMouseLeave","handleIconMouseEnter","handleIconMouseLeave","handleInfoMouseEnter","handleInfoMouseLeave","sourceName","showButton","getImageTransform","VectorCard","vector","onVectorSelect","handleVectorClick","ImageBrowserPanel","onToggle","currentImageUrl","searchQuery","setSearchQuery","customUrl","setCustomUrl","setImages","unsplashPage","setUnsplashPage","pixabayPage","setPixabayPage","hasMore","setHasMore","usedCollections","setUsedCollections","viewMode","setViewMode","vectorSearchQuery","setVectorSearchQuery","vectors","setVectors","vectorLoading","setVectorLoading","vectorError","setVectorError","vectorNextPage","setVectorNextPage","vectorHasMore","setVectorHasMore","vectorViewMode","setVectorViewMode","vectorPublicDomainExhausted","setVectorPublicDomainExhausted","aiProvider","setAiProvider","aiPrompt","setAiPrompt","aiStyle","setAiStyle","aiSubstyle","setAiSubstyle","runwareModel","setRunwareModel","aiGenerating","setAiGenerating","aiError","setAiError","aiResult","setAiResult","aiImageUrl","setAiImageUrl","removingBackground","setRemovingBackground","backgroundRemovalError","setBackgroundRemovalError","sentinelRef","vectorSentinelRef","fileInputRef","UNSPLASH_ACCESS_KEY","process","PIXABAY_API_KEY","COLLECTION_IDS","mapPixabayToImageResult","pixabayImage","mapUnsplashToImageResult","unsplashImage","loadFeaturedImages","requests","availableCollections","selectedCollections","collectionId","prev","newUsed","responses","allImages","pixabayImages","unsplashImages","shuffledImages","searchImages","unsplashPageNum","pixabayPageNum","allResults","shuffledResults","newResults","shuffledNewResults","handleSearch","handleLoadMore","nextUnsplashPage","nextPixabayPage","newImages","shuffledNewImages","sentinel","observer","loadFeaturedVectors","errorMessage","searchVectors","nextPageToken","existingIds","allNextPage","handleVectorSearch","handleVectorLoadMore","handleVectorSelect","finalUrl","handleImageSelect","handleCustomUrlSubmit","handleFileUpload","file","handleUploadClick","handleRemoveBackground","imageUrlToProcess","result","handleAiGenerate","handleAiImageSelect","getItemSpanClass","ar","TextField","Input","model","selectedStyle","TextArea","onOpenChange","onImageAdded","onImageChanged","externalChangingId","onChangingElementIdChange","setElements","canvasEditorRef","artboardManager","executeAddElement","setSelectedId","useSelectionContext","elementsRef","selectedIdRef","internalChangingId","setInternalChangingId","changingImageElementId","setChangingImageElementId","currentElements","currentSelectedId","existingElement","isImageElement","oldElement","zoom","loadedElement","newId","centerX","centerY","ImageElement","handleToggle","GlyphBrowserDrawer","onInsertGlyph","glyphs","setGlyphs","glyphList","glyph","charToInsert","codePoint","filteredGlyphs","Spinner","externalFontFamily","externalFontWeight","externalOnInsertGlyph","handleInsertGlyph","unicode","orientation","showAddButton","showCloseButtons","maxTabWidth","onArtboardCreate","onArtboardDelete","selectArtboard","createArtboard","deleteArtboard","renameArtboard","renamingId","setRenamingId","newName","setNewName","startRename","currentName","finishRename","cancelRename","handleAddArtboard","newArtboard","handleDeleteArtboard","containerStyle","tabStyle","isActive","isRenaming","BackIcon","BackButton","EPSILON","getFeatureApplied","td","ImageToolbar","showUngroupButton","onUngroup","onMoveForward","onMoveBackward","onChangeImage","cornerRadiusExpanded","onCornerRadiusToggle","cropExpanded","onCropToggle","rotationExpanded","onRotationToggle","opacityExpanded","onOpacityToggle","strokeExpanded","onStrokeToggle","knockoutExpanded","onKnockoutToggle","distressTextureExpanded","onDistressTextureToggle","imageMaskExpanded","onImageMaskToggle","moreMenuOpen","setMoreMenuOpen","changeImageTooltipDisabled","setChangeImageTooltipDisabled","cornerRadiusTooltipDisabled","setCornerRadiusTooltipDisabled","cropTooltipDisabled","setCropTooltipDisabled","rotationTooltipDisabled","setRotationTooltipDisabled","opacityTooltipDisabled","setOpacityTooltipDisabled","strokeTooltipDisabled","setStrokeTooltipDisabled","knockoutTooltipDisabled","setKnockoutTooltipDisabled","distressTooltipDisabled","setDistressTooltipDisabled","imageMaskTooltipDisabled","setImageMaskTooltipDisabled","isCropping","applied","ARTBOARD_COLORS","ShapeToolbar","onOpenShapeTypeDrawer","transparencyExpanded","onTransparencyToggle","sidesExpanded","onSidesToggle","pointsExpanded","onPointsToggle","innerRadiusExpanded","onInnerRadiusToggle","colorExpanded","onColorToggle","shapeTypeTooltipDisabled","setShapeTypeTooltipDisabled","transparencyTooltipDisabled","setTransparencyTooltipDisabled","sidesTooltipDisabled","setSidesTooltipDisabled","pointsTooltipDisabled","setPointsTooltipDisabled","innerRadiusTooltipDisabled","setInnerRadiusTooltipDisabled","colorTooltipDisabled","setColorTooltipDisabled","presetDocumentColors","effectiveDocumentColors","handleFillColorChange","shapeTypeLabels","currentShapeType","currentLabel","PolygonIcon","EllipseIcon","TILE_ICON_CLASS","shapeTypes","ShapeTypeDrawer","onSelectType","currentType","headingText","descriptionText","handleSelect","PathToolbar","strokeColorOpen","setStrokeColorOpen","fillColorOpen","setFillColorOpen","strokeWidthOpen","setStrokeWidthOpen","handleStrokeColorChange","handleStrokeEnabledToggle","handleFillEnabledToggle","handleStrokeWidthChange","strokeColor","fillColor","strokeWidth","isClosed","pointCount","BackgroundPickerDropdown","backgroundType","backgroundColor","backgroundTexture","onBackgroundTypeChange","onColorChange","onTextureChange","handleTextureClick","textureId","handleTabChange","tab","defaultTexture","TextureManager","texture","ArtboardDistressPanel","distressTexture","textureUrl","presetItems","ArtboardImageMaskPanel","imageMask","ensureMaskPresetsReady","maskType","inverted","MASK_IMAGE_PRESETS","handleMaskTypeChange","handleInvertedChange","checked","Checkbox","ArtboardPropertiesToolbar","artboards","onArtboardUpdate","onRenameArtboard","onDeleteArtboard","artboardScreenBounds","isEditing","setIsEditing","editingName","setEditingName","inputRef","handleBackgroundTypeChange","updatedArtboard","handleTextureChange","handleExportBackgroundToggle","handleDistressTextureChange","handleImageMaskChange","handleStartEdit","handleSaveEdit","handleCancelEdit","handleDelete","Surface","Separator","allGoogleFonts","fetchPromise","fetchAllGoogleFonts","font","getAllGoogleFonts","isFontsLoaded","mapGoogleCategory","googleCategory","CATEGORY_MAPPINGS","mapMonotypeClassifications","classifications","priorityOrder","mapping","getCategoryMapping","getMonotypeClassifications","MonotypeServiceClass","cached","categories","allFonts","classification","pageId","pageCount","errorDetail","cacheKey","fontDefinitions","fonts","familyMap","familyKey","family","variants","representative","weights","fontId","cachedKits","kits","linkId","MonotypeService","UnifiedFontServiceClass","isGoogleFontsLoaded","systemFonts","TSHIRT_FONTS","googleFonts","monotopeFonts","normalizedQuery","googleResults","monotypeResults","fontName","encodedText","googleFont","match","fontMap","existing","UnifiedFontService","stripGlyphs","cp","FontBrowserDrawer","_fontFamilies","previewText","selectedFontRef","selectedCategory","setSelectedCategory","fontsLoadedTrigger","setFontsLoadedTrigger","displayMode","setDisplayMode","cardSize","setCardSize","loadedFonts","setLoadedFonts","loadQueueRef","loadingRef","cardSizeScale","styleId","loadFont","forSelection","textToLoad","fontsToLoad","queueFontLoad","alreadyLoaded","alreadyQueued","selectedFont","FontItem","isUsedInDocument","fontItemRef","isLoaded","isPremium","mainText","showSecondaryLabel","shouldShowTooltip","surfaceContent","prevProps","nextProps","fontsUsedInDocument","usedFonts","addFontIfValid","child","fontSections","recommendedNames","remainingFonts","recommendedFonts","otherFonts","renderFontSection","CATEGORY_LABELS","TransformControlPanel","controls","draggingValues","setDraggingValues","control","storedValue","safeStoredValue","currentInternalValue","sliderValue","formatValue","internalValue","newSliderValue","newInternalValue","TextEffectsDropdown","onTransformTypeChange","currentTransformType","getTransformControls","textTransformTypes","TRANSFORM_TYPES","handleTransformChange","newType","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","MoreMenu","items","showMenu","setShowMenu","item","FontColorButton","colorPickerValue","BoldButton","toolbar","ItalicButton","UnderlineButton","UppercaseButton","TextAlignButton","textAlign","handleTextAlignToggle","TextMoreMenu","handleOpenChange","TextToolbar","stableElementId","viewportWidth","isColorActive","onOpenGlyphBrowser","hasGlyphs","expandedPanel","onFontSizeToggle","getMoreMenuItems","elementForProperties","isTransformMenuOpen","onTransformMenuOpenChange","elementUpdateHandler","isFontBrowserOpen","onFontBrowserToggle","onTextMoreMenuOpenChange","glyphTooltipDisabled","setGlyphTooltipDisabled","fontSizeTooltipDisabled","setFontSizeTooltipDisabled","FONT_FAMILIES","convertTransform","sourceElement","targetType","TargetClass","rotationAnchor","currentEffectiveFontSize","calculateTransformConfig","effectiveFontSize","transformData","fontSize","minWidth","estimatedTextWidth","targetWidth","targetHeight","archMinWidth","archEstimatedWidth","ARCH_DEFAULTS","waveMinWidth","waveEstimatedWidth","WAVE_DEFAULTS","flagMinWidth","flagEstimatedWidth","FLAG_DEFAULTS","leanMinWidth","leanEstimatedWidth","LEAN_DEFAULTS","useTextToolbar","activeChildElement","GroupElement","updatedGroup","childIndex","currentElementId","prevElementIdRef","localFontSize","setLocalFontSize","localFontColor","setLocalFontColor","localFontFamily","setLocalFontFamily","localTextAlign","setLocalTextAlign","fontColor","textElement","bold","italic","underline","letterCase","setFontSizeValue","newSize","updateFontFamily","newFamily","updateFontColor","newColor","updateTextAlign","alignment","handleFontSizeChange","handleFontSizeIncrement","handleFontFamilyChange","handleFontColorChange","handleBoldToggle","handleItalicToggle","handleUnderlineToggle","handleLetterCaseToggle","newCase","isLetterCaseActive","alignments","nextAlign","getEffectiveStyle","selectionStyle","_d","handleTransformTypeChange","transformDef","getTransformById","useLayerPreview","previewUrl","setPreviewUrl","isLoading","setIsLoading","debounceRef","generateElementPreview","ShapeElement","PathElement","LayerLeadingChip","onThumbnailClick","locked","SelectionThumbnail","LockIcon","inner","GroupElementToolbar","cropAnchor","setCropAnchor","currentCropWidth","currentCropHeight","handleCropChange","cropX","cropY","cropWidth","cropHeight","handleCropWidthChange","anchor","oldWidth","oldX","widthDiff","newX","handleCropHeightChange","oldHeight","oldY","heightDiff","newY","anchorPositions","pos","PANEL_BODY_CLASSES","COLOR_PANEL_BODY_CLASSES","CornerRadiusPanel","RotationPanel","onRotate90","FontSizePanel","widthValue","onWidthChange","OpacityPanel","ShapeCornerRadiusPanel","ShapeTransparencyPanel","ShapeSidesPanel","ShapePointsPanel","ShapeInnerRadiusPanel","ShapeColorPanel","TextColorPanel","fill","onModeChange","onFillChange","onStrokeChange","onScopeChange","DistressTexturePanel","onOpacityChange","ImageMaskPanel","onImageChange","onMaskTypeChange","onInvertedChange","showAdvanced","setShowAdvanced","patch","cap","join","CropPanelContent","ExpandedPanelIcon","panelType","defaultIcon","textColorValue","shapeFillColor","SecondaryPanelWrapper","ColorPanelWrapper","EmbeddedToolbarLayout","toolbarContent","innerContentRef","shouldRender","isExiting","transitionHeight","emptyStateContent","isCornerRadiusPanelOpen","isCropPanelOpen","isRotationPanelOpen","isOpacityPanelOpen","isFontSizePanelOpen","isShapeCornerRadiusPanelOpen","isShapeTransparencyPanelOpen","isShapeSidesPanelOpen","isShapePointsPanelOpen","isShapeInnerRadiusPanelOpen","isShapeColorPanelOpen","isTextColorPanelOpen","isStrokePanelOpen","isKnockoutPanelOpen","isDistressTexturePanelOpen","isImageMaskPanelOpen","cornerRadiusPanel","cropPanelContent","rotationPanel","opacityPanel","fontSizePanel","shapeCornerRadiusPanel","shapeTransparencyPanel","shapeSidesPanel","shapePointsPanel","shapeInnerRadiusPanel","shapeColorPanel","textColorPanel","strokePanel","knockoutPanel","distressTexturePanel","imageMaskPanel","FloatingCornerRadiusPanel","toolbarPosition","toolbarHeight","panelWidth","FloatingCropPanel","isPaintable","collectFromElement","out","richText","span","collectDocumentColors","ab","bg","IMAGE_PALETTE_CACHE","IMAGE_PALETTE_INFLIGHT","computeRanges","pixels","rMin","rMax","gMin","gMax","bMin","bMax","boxLongestAxis","box","boxSize","splitBox","sorted","mid","leftPixels","rightPixels","averageColor","medianCutBoxes","targetBuckets","boxes","bestIdx","bestSize","redmeanDistance","rMean","dr","dg","db","furthestPointPalette","candidates","paletteSize","picked","used","bestMinDist","minDist","toHex","rgbToHex","extractImagePalette","inflight","promise","loadCorsImage","SAMPLE","overExtract","collectImageColors","urls","seen","visit","palettes","dedupe","palette","_breakpoints","transparent","onPanelExpandChange","defaultExpandedPanel","onExpandedPanelTypeChange","onOpenCropDrawer","onOpenCornerRadiusDrawer","emptyStateMessage","emptyStateRender","editArtboardMode","onEditArtboardModeChange","onLayerThumbnailClick","panOffset","useViewportContext","multiSelection","contextExpandedPanelType","setContextExpandedPanelType","setIsToolbarMenuOpen","isRotating","useToolStateContext","canvasRef","executeRemoveElement","executeReorderElement","refreshArtboards","textToolbar","activeMenu","setActiveMenu","openDropdown","setOpenDropdown","setToolbarPosition","_isDragging","setIsDragging","setIsTransformMenuOpen","isColorPickerOpen","isTextMoreMenuOpen","setIsTextMoreMenuOpen","isShapeTypeDrawerOpen","setIsShapeTypeDrawerOpen","setExpandedPanel","isEntering","setIsEntering","setIsExiting","setShouldRender","isWaitingForPosition","setIsWaitingForPosition","positionedElementId","setPositionedElementId","setTransitionHeight","toolbarDimensions","setToolbarDimensions","toolbarRef","lastKnownHeightRef","prevShouldShowRef","isMouseDownRef","frozenPositionRef","lastElementRotationRef","lastSyncedToContextRef","prevContextExpandedPanelTypeRef","prevSelectedIdRef","prevElementTypeRef","prevIsRotatingRef","isRotatingRef","isDrawerModeAtMount","isFullyMountedRef","expandedPanelRef","elementForPropertiesRef","elementUpdateHandlerRef","prevStableSelectedIdRef","prevIsCroppingRef","stableSelectedId","currentElementType","shouldShowToolbar","handleBorderRadiusChange","handleShapeBorderRadiusChange","handleShapeOpacityChange","handleShapeSidesChange","handleShapePointsChange","handleShapeInnerRadiusChange","handleShapeFillColorChange","handleCornerRadiusToggle","handleCropToggle","handleRotationToggle","handleOpacityToggle","handleFontSizeToggle","handleTextWidthChange","next","currentTextWidth","handleShapeCornerRadiusToggle","handleShapeTransparencyToggle","handleShapeSidesToggle","handleShapePointsToggle","handleShapeInnerRadiusToggle","handleShapeColorToggle","handleTextColorToggle","handleCompositingToggle","handleDistressTextureToggle","handleImageMaskToggle","handleCloseExpandedPanel","imageElement","handleMoveForward","idx","targetElement","handleMoveBackward","handleDeleteElement","elementToDelete","handleToggleLock","handleUngroupElement","group","extractedChildren","clone","handleRotationChange","handleRotate90","newRotation","handleCompositingModeChange","handleCompositingFillChange","currentMode","newParts","handleCompositingStrokeChange","handleCompositingScopeChange","handleDistressOpacityChange","pct","handleImageMaskImageChange","makeMaskElement","handleImageMaskTypeChange","handleImageMaskOpacityChange","handleImageMaskInvertedChange","inv","handleStrokeChange","newShapeType","handleOpenShapeTypeDrawer","localType","prevType","currentIsCropping","mouseDownPos","isDraggingStarted","DRAG_THRESHOLD","handleMouseDown","handleMouseMove","handleMouseUp","newHeight","currentRotation","updateToolbarPosition","toolbarWidth","elementToPosition","elementBounds","artboardX","artboardY","currentZoom","_e","elementScreenX","elementScreenY","elementScreenWidth","elementScreenHeight","canvasRect","viewportCenterX","viewportCenterY","gap","elementTop","elementCenterX","minLeft","maxLeft","maxTop","colorPickerOnChange","autoDocumentColors","mergedDocumentColors","documentColorsKey","colorPickerDocumentColors","imageUrlsKey","walk","colorPickerImageColors","setColorPickerImageColors","cancelled","colors","toolbarDivRef","wasRotating","isNowRotating","prevShouldShow","prevSelectedId","enterTimer","currentHeight","exitTimer","startHeight","toolbarStyle","maxWidthValue","regularToolbarContent","shapeElement","currentBorderRadius","currentOpacity","currentShapeBorderRadius","currentShapeOpacity","currentShapeSides","_f","currentShapePoints","_g","currentShapeInnerRadius","_h","currentShapeFillColor","_i","compositingFill","_j","compositingStroke","_k","compositingScope","_l","compositingMode","_m","_n","quickMask","_o","_p","artboardEditContent","currentArtboard","embeddedContent","floatingCornerRadiusPanel","floatingCropPanel","Dropdown","trigger","align","protectClick","contentClassName","triggerRef","contentRef","dropdownStyle","setDropdownStyle","useFixed","setUseFixed","handleTriggerClick","clickProtection","timer","isInsideContainer","isInsideContent","focusable","content","triggerRect","contentRect","viewportHeight","padding","spaceAbove","spaceBelow","dropdownContent","DropdownMenu","maxHeightClass","minWidthStyle","MenuItem","shortcut","baseClasses","stateClasses","combinedClassName","Panel","enableable","onEnabledChange","collapsible","expanded","onExpandChange","showContent","showExpandButton","handleExpandToggle","ControlGroup","labelSuffix","inline","ButtonGroup","fullWidth","option","Toggle","handleChange","SecondaryToolbar","isLayersPanelOpen","onToggleLayersPanel","onOpenImageBrowser","additionalItems","handleLoadWorkspace","handleAddElement","addMenuOpen","setAddMenuOpen","handleSave","freshArtboards","ExportManager","handleLoadClick","handleFileChange","ImportManager","summary","handleExportImage","handleAddElementClick","elementType","handleSelectShapeType","elementTypes","MenuDivider","et","showFitButton","showResetButton","zoomIn","zoomOut","zoomToFit","resetView","zoomPercentage","useProjectLoader","loadError","setLoadError","currentProject","setCurrentProject","projectMetadata","setProjectMetadata","loadFromJSON","document","jsonString","totalElements","sum","loadFromFile","loadTemplate","template","DEFAULT_BREAKPOINTS","getCurrentBreakpoint","useBreakpoint","breakpointConfig","setWidth","breakpoint","isXs","isSm","isMd","isLg","isXl","isXxl","breakpointOrder","bp","targetIndex","DEFAULT_METRICS","usePerformance","metrics","setMetrics","isProfiling","setIsProfiling","frameTimesRef","renderTimesRef","exportTimesRef","lastFrameTimeRef","rafIdRef","calculateFPS","frameTimes","time","calculateAverage","values","getMemoryUsage","updateMetrics","newMetrics","measureFrame","frameTime","startProfiling","stopProfiling","clearMetrics","getReport","useElementById","getElementById","useLayerDragDrop","findElement","setDraggedId","dragOverId","setDragOverId","elementId","resetDragState","handleDrop","useLayerSelection","onSelectionChange","onMultiSelectionChange","isInMultiSelection","isCurrentlySelected","newSelection","FontSizeDropdown","fontSizes","FontSizeGroup","handleClickOutside","FONT_SIZES","_customElementTypes","registerElementType","registration","registerTransform","unregisterElementType","unregisterTransform","getCustomElementTypes","isRegisteredElementType","CanvasEventBus","handlers","wrapper","unsubscribe","canvasEventBus","useCanvasEvents","DEFAULT_STYLE","ANCHOR_TO_SVG","renderShape","path","commonProps","resolveBoundary","guide","naturalW","naturalH","svgPathD","rx","ry","resolveSafeArea","piece","inset","VisualGuideOverlay","artboardWidth","artboardHeight","canvasPadding","pieces","pieceGuides","show","autoLabelFontSize","merged","visibility","viewBoxWidth","viewBoxHeight","zones","labels","rotation","isOrtho","boundary","safeArea","originXform","rotationXform","washRadius","boundaryForWash","washOuter","bleedFilterId","pieceRect","canRenderBleed","z","ensureIconsRegistered"],"mappings":"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","x_google_ignoreList":[2,3,4,5,17]}
|
|
1
|
+
{"version":3,"file":"advanced.mjs","sources":["../src/components/primitives/Panel.tsx","../src/components/primitives/ControlGroup.tsx","../src/components/primitives/ButtonGroup.tsx","../src/components/primitives/Toggle.tsx","../src/components/primitives/Switch.tsx","../src/components/primitives/SecondaryToolbar.tsx","../src/kits/serialization.ts","../src/hooks/useProjectLoader.ts","../src/hooks/useBreakpoint.ts","../src/hooks/usePerformance.ts","../src/hooks/useElementById.ts","../src/hooks/useLayerDragDrop.ts","../src/hooks/useLayerSelection.ts","../src/components/FontSizeDropdown.tsx","../src/components/text-toolbar/FontSizeGroup.tsx","../src/plugins/ElementTypePlugin.ts","../src/core/EventBus.ts","../src/hooks/useCanvasEvents.ts","../src/components/VisualGuideOverlay.tsx","../src/api/advanced.ts"],"sourcesContent":["/**\n * Panel - Collapsible panel with optional enable/disable toggle\n *\n * A reusable panel component that eliminates boilerplate for property panels.\n * Supports:\n * - Simple panel (no toggle, no expand)\n * - Collapsible panel (no toggle, with expand/collapse)\n * - Toggle panel (with enable/disable toggle and expand/collapse)\n *\n * @example\n * // Simple panel\n * <Panel title=\"Settings\">\n * <p>Panel content</p>\n * </Panel>\n *\n * @example\n * // Collapsible panel\n * <Panel title=\"Settings\" collapsible expanded={expanded} onExpandChange={setExpanded}>\n * <p>Panel content</p>\n * </Panel>\n *\n * @example\n * // Toggle panel (enable/disable + expand/collapse)\n * <Panel\n * title=\"Stroke\"\n * enableable\n * enabled={enabled}\n * onEnabledChange={setEnabled}\n * expanded={expanded}\n * onExpandChange={setExpanded}\n * >\n * <p>Panel content (only shown when enabled and expanded)</p>\n * </Panel>\n */\n\nimport React from 'react';\n\nexport interface PanelProps {\n /** Panel title */\n title: string;\n\n /** Panel icon (optional) */\n icon?: React.ReactNode;\n\n /** Panel content */\n children: React.ReactNode;\n\n /** Enable toggle functionality (checkbox to enable/disable) */\n enableable?: boolean;\n\n /** Enabled state (only used if enableable=true) */\n enabled?: boolean;\n\n /** Callback when enabled state changes */\n onEnabledChange?: (enabled: boolean) => void;\n\n /** Enable expand/collapse functionality */\n collapsible?: boolean;\n\n /** Expanded state (only used if collapsible=true or enableable=true) */\n expanded?: boolean;\n\n /** Callback when expanded state changes */\n onExpandChange?: (expanded: boolean) => void;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport const Panel: React.FC<PanelProps> = ({\n title,\n icon,\n children,\n enableable = false,\n enabled = false,\n onEnabledChange,\n collapsible = false,\n expanded = true,\n onExpandChange,\n className = '',\n}) => {\n // Determine if content should be shown\n const showContent = enableable ? enabled && expanded : collapsible ? expanded : true;\n\n // Determine if expand button should be shown\n const showExpandButton = (enableable && enabled) || collapsible;\n\n const handleToggle = () => {\n if (onEnabledChange) {\n onEnabledChange(!enabled);\n }\n };\n\n const handleExpandToggle = () => {\n if (onExpandChange) {\n onExpandChange(!expanded);\n }\n };\n\n return (\n <div className={`rounded-xl border border-border-primary bg-bg-secondary p-xl ${className}`}>\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n {/* Left side: toggle + title */}\n <div className=\"flex items-center gap-md\">\n {enableable && (\n <label className=\"flex cursor-pointer items-center\">\n <input\n type=\"checkbox\"\n checked={enabled}\n onChange={handleToggle}\n className=\"h-4 w-4 cursor-pointer rounded border-border-primary bg-bg-input accent-accent-primary\"\n />\n </label>\n )}\n <div className=\"flex items-center gap-md\">\n {icon && <span className=\"flex items-center text-text-secondary\">{icon}</span>}\n <h3 className=\"text-xl font-semibold text-text-primary\">{title}</h3>\n </div>\n </div>\n\n {/* Right side: expand button */}\n {showExpandButton && (\n <button\n onClick={handleExpandToggle}\n className=\"rounded-lg border-none bg-transparent px-md py-xs text-base text-text-muted transition-colors duration-fast hover:text-text-primary\"\n title={expanded ? 'Collapse' : 'Expand'}\n >\n {expanded ? '▼' : '▶'}\n </button>\n )}\n </div>\n\n {/* Content */}\n {showContent && <div className=\"mt-xl flex flex-col gap-xl\">{children}</div>}\n </div>\n );\n};\n\nexport default Panel;\n","/**\n * ControlGroup - Label + control wrapper with consistent spacing\n *\n * Provides a consistent layout for form controls with labels.\n * Eliminates repeated label + wrapper markup.\n *\n * @example\n * <ControlGroup label=\"Width\">\n * <input type=\"range\" ... />\n * </ControlGroup>\n *\n * @example\n * <ControlGroup label=\"Color\" inline>\n * <ColorPickerDropdown ... />\n * </ControlGroup>\n */\n\nimport React from 'react';\n\nexport interface ControlGroupProps {\n /** Label text */\n label: string;\n\n /** Optional label suffix (e.g., value display \"50px\") */\n labelSuffix?: React.ReactNode;\n\n /** Control element(s) */\n children: React.ReactNode;\n\n /** Inline layout (label and control side-by-side) */\n inline?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport const ControlGroup: React.FC<ControlGroupProps> = ({\n label,\n labelSuffix,\n children,\n inline = false,\n className = '',\n}) => {\n return (\n <div className={`flex ${inline ? 'items-center justify-between' : 'flex-col'} gap-sm ${className}`}>\n {/* Label */}\n <label className=\"flex items-center justify-between text-base font-medium text-text-secondary\">\n <span>{label}</span>\n {labelSuffix && <span className=\"font-semibold text-accent-primary\">{labelSuffix}</span>}\n </label>\n\n {/* Control */}\n <div className={inline ? 'flex-shrink-0' : ''}>{children}</div>\n </div>\n );\n};\n\nexport default ControlGroup;\n","/**\n * ButtonGroup - Group of buttons with active state\n *\n * A reusable button group for selecting one option from multiple choices.\n * Eliminates 10-15 lines of repeated button group markup.\n *\n * @example\n * <ButtonGroup\n * options={[\n * { value: 'butt', label: 'Butt', tooltip: 'Flat edges' },\n * { value: 'round', label: 'Round', tooltip: 'Rounded edges' },\n * { value: 'square', label: 'Square', tooltip: 'Extended square edges' }\n * ]}\n * value={lineCap}\n * onChange={setLineCap}\n * />\n */\n\nimport React from 'react';\n\nexport interface ButtonGroupOption<T = string> {\n /** Option value */\n value: T;\n\n /** Display label */\n label: string;\n\n /** Optional icon */\n icon?: React.ReactNode;\n\n /** Optional tooltip */\n tooltip?: string;\n\n /** Disabled state */\n disabled?: boolean;\n}\n\nexport interface ButtonGroupProps<T = string> {\n /** Available options */\n options: ButtonGroupOption<T>[];\n\n /** Current value */\n value: T;\n\n /** Callback when value changes */\n onChange: (value: T) => void;\n\n /** Full width buttons */\n fullWidth?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport function ButtonGroup<T = string>({\n options,\n value,\n onChange,\n fullWidth = true,\n className = '',\n}: ButtonGroupProps<T>) {\n return (\n <div className={`flex gap-sm ${className}`}>\n {options.map((option) => {\n const isActive = option.value === value;\n\n return (\n <button\n key={String(option.value)}\n onClick={() => !option.disabled && onChange(option.value)}\n disabled={option.disabled}\n title={option.tooltip}\n className={` ${fullWidth ? 'flex-1' : ''} flex items-center justify-center gap-xs rounded-lg border px-md py-sm text-base font-medium transition-all duration-fast ${\n isActive\n ? 'border-accent-primary bg-accent-primary text-text-on-accent'\n : 'border-border-primary bg-bg-tertiary text-text-secondary hover:border-border-secondary hover:bg-bg-hover hover:text-text-primary'\n } ${option.disabled ? 'cursor-not-allowed opacity-disabled' : 'cursor-pointer'} `}\n >\n {option.icon && <span className=\"flex items-center\">{option.icon}</span>}\n <span>{option.label}</span>\n </button>\n );\n })}\n </div>\n );\n}\n\nexport default ButtonGroup;\n","/**\n * Toggle - Styled checkbox for enable/disable controls\n *\n * A consistent toggle/checkbox component with label.\n * Eliminates 5-10 lines of repeated toggle markup.\n *\n * @example\n * <Toggle\n * label=\"Enable Stroke\"\n * checked={enabled}\n * onChange={setEnabled}\n * />\n *\n * @example\n * <Toggle\n * label=\"Flip Horizontal\"\n * checked={flipH}\n * onChange={setFlipH}\n * icon={<LuFlipHorizontal2 />}\n * />\n */\n\nimport React from 'react';\n\nexport interface ToggleProps {\n /** Label text */\n label: string;\n\n /** Optional icon */\n icon?: React.ReactNode;\n\n /** Checked state */\n checked: boolean;\n\n /** Callback when checked state changes */\n onChange: (checked: boolean) => void;\n\n /** Disabled state */\n disabled?: boolean;\n\n /** Additional CSS classes */\n className?: string;\n}\n\nexport const Toggle: React.FC<ToggleProps> = ({ label, icon, checked, onChange, disabled = false, className = '' }) => {\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.checked);\n };\n\n return (\n <label\n className={`flex cursor-pointer items-center gap-md ${disabled ? 'cursor-not-allowed opacity-disabled' : ''} ${className}`}\n >\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n className=\"h-4 w-4 cursor-pointer rounded border-border-primary bg-bg-input accent-accent-primary disabled:cursor-not-allowed\"\n />\n <span className=\"flex items-center gap-sm text-base font-medium text-text-primary\">\n {icon && <span className=\"flex items-center text-text-secondary\">{icon}</span>}\n <span>{label}</span>\n </span>\n </label>\n );\n};\n\nexport default Toggle;\n","/**\n * Switch - Toggle switch component\n *\n * Features:\n * - Accessible checkbox input\n * - Smooth animation\n * - Fixed border radius (not affected by theme)\n * - Support for labels\n *\n * Usage:\n * ```tsx\n * <Switch\n * checked={isEnabled}\n * onChange={setIsEnabled}\n * label=\"Enable feature\"\n * />\n * ```\n */\n\nimport React from 'react';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n label?: string;\n disabled?: boolean;\n className?: string;\n}\n\nconst Switch: React.FC<SwitchProps> = ({\n checked,\n onChange,\n label,\n disabled = false,\n className = '',\n}) => {\n const handleChange = () => {\n if (!disabled) {\n onChange(!checked);\n }\n };\n\n return (\n <label\n className={`flex items-center gap-md cursor-pointer select-none ${disabled ? 'opacity-50 cursor-not-allowed' : ''} ${className}`.trim()}\n >\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={handleChange}\n disabled={disabled}\n className=\"absolute opacity-0 w-0 h-0 peer\"\n />\n <span\n className={`\n relative inline-block w-9 h-5 rounded-[999px] transition-colors\n ${checked ? 'bg-accent-primary' : 'bg-bg-tertiary'}\n after:content-[''] after:absolute after:top-[2px] after:left-[2px]\n after:w-4 after:h-4 after:bg-white after:rounded-full\n after:transition-transform after:shadow-md\n ${checked ? 'after:translate-x-4' : ''}\n `.trim()}\n />\n {label && <span className=\"text-md text-text-primary font-medium\">{label}</span>}\n </label>\n );\n};\n\nexport default Switch;\n","/**\n * SecondaryToolbar - Overflow toolbar for uncommonly used controls\n *\n * Renders as a proper toolbar positioned below the primary toolbar,\n * right-aligned with a gap above it. Used for 3-dot overflow menus.\n *\n * Features:\n * - Same height and styling as primary toolbar\n * - Positioned below trigger, right-aligned\n * - Gap between primary and secondary toolbar\n * - Click-outside handling via Dropdown primitive\n *\n * Usage:\n * ```tsx\n * <SecondaryToolbar\n * isOpen={showMore}\n * onToggle={setShowMore}\n * trigger={<Button variant=\"toolbar\" icon={<DotsIcon />} />}\n * >\n * <Button variant=\"toolbar\" icon={<Icon />} onClick={handler} />\n * <Switch checked={value} onChange={handler} label=\"Label\" />\n * </SecondaryToolbar>\n * ```\n */\n\nimport React from 'react';\nimport { Icon } from '@iconify/react';\nimport { Button, Tooltip, TooltipTrigger, TooltipContent } from '../ui';\nimport { Dropdown } from './index';\n\nexport interface SecondaryToolbarProps {\n isOpen: boolean;\n onToggle: (open: boolean) => void;\n trigger?: React.ReactNode;\n children: React.ReactNode;\n}\n\nconst SecondaryToolbar: React.FC<SecondaryToolbarProps> = ({\n isOpen,\n onToggle,\n trigger,\n children,\n}) => {\n // Default trigger: 3-dot icon button with tooltip\n // The Button has its own onClick to ensure clicks are captured even when\n // wrapped by Radix's TooltipTrigger which can interfere with event bubbling\n const defaultTrigger = (\n <Tooltip delayDuration={0}>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"toolbar\"\n onClick={(e) => {\n // Stop propagation to prevent Dropdown's wrapper div from double-toggling\n e.stopPropagation();\n onToggle(!isOpen);\n }}\n >\n <Icon icon=\"lucide:ellipsis-vertical\" className=\"size-6\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n <p>More</p>\n </TooltipContent>\n </Tooltip>\n );\n\n return (\n <Dropdown\n isOpen={isOpen}\n onToggle={onToggle}\n trigger={trigger || defaultTrigger}\n position=\"bottom\"\n align=\"end\"\n offset={4}\n >\n {/* Secondary toolbar - matches primary toolbar styling */}\n <div className=\"flex items-center gap-sm bg-bg-primary border border-border-primary rounded-xl px-xl py-md shadow-sm h-[52px]\">\n {children}\n </div>\n </Dropdown>\n );\n};\n\nexport default SecondaryToolbar;\n","/**\n * Kit Serialization - JSON import/export for kit definitions\n *\n * Provides functions to serialize a KitDefinition to a JSON-safe format\n * and to load a KitDefinition from JSON. Supports extending base presets\n * via the `extends` field, making it easy to persist and share kit\n * configurations.\n *\n * @example Serialize a kit to JSON\n * ```ts\n * import { serializeKit, COMPACT_CUSTOMIZER } from '@snowcone-app/canvas';\n *\n * const json = serializeKit(COMPACT_CUSTOMIZER);\n * const stored = JSON.stringify(json);\n * ```\n *\n * @example Load a kit from JSON\n * ```ts\n * import { loadKitFromJSON } from '@snowcone-app/canvas';\n *\n * const kit = loadKitFromJSON({\n * name: 'my-custom-kit',\n * extends: 'compact-customizer',\n * capabilities: { effects: ['stroke', 'mask'] },\n * behavior: { autoExport: true },\n * });\n * ```\n */\n\nimport type { EditorCapabilities } from '../types/capabilities.js';\nimport type { KitDefinition, KitPresetId } from './types.js';\nimport { extendKit, createKit } from './compose.js';\nimport { resolveKit } from './registry.js';\nimport { validateKit } from './validation.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * JSON-safe representation of a KitDefinition.\n *\n * When `extends` is provided, the kit is built by resolving the base\n * preset and applying the remaining fields as overrides. When `extends`\n * is omitted, a new kit is created from scratch using `createKit`.\n */\nexport interface KitJSON {\n /** Kit name (required) */\n name: string;\n /** Optional base preset to extend from */\n extends?: KitPresetId;\n /** Partial capability overrides */\n capabilities?: Partial<EditorCapabilities>;\n /** Partial behavior overrides */\n behavior?: Partial<KitDefinition['behavior']>;\n /** Partial layout overrides */\n layout?: Partial<KitDefinition['layout']>;\n /** Partial style overrides */\n style?: Partial<KitDefinition['style']>;\n /** Content configuration */\n content?: KitDefinition['content'];\n}\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\n/**\n * Serialize a KitDefinition to a JSON-safe format.\n *\n * The resulting object can be safely passed to `JSON.stringify()` and\n * later restored with `loadKitFromJSON()`. All fields from the kit\n * are included in the output for a complete, self-contained representation.\n *\n * @param kit - The KitDefinition to serialize\n * @returns A JSON-safe KitJSON object\n *\n * @example\n * ```ts\n * const json = serializeKit(myKit);\n * localStorage.setItem('kit', JSON.stringify(json));\n * ```\n */\nexport function serializeKit(kit: KitDefinition): KitJSON {\n const json: KitJSON = {\n name: kit.name,\n capabilities: {\n elements: [...kit.capabilities.elements],\n transforms: [...kit.capabilities.transforms],\n effects: [...kit.capabilities.effects],\n panels: [...kit.capabilities.panels],\n tools: [...kit.capabilities.tools],\n features: { ...kit.capabilities.features },\n },\n behavior: { ...kit.behavior },\n layout: {\n slots: {\n ...(kit.layout.slots.topbar && { topbar: [...kit.layout.slots.topbar] }),\n ...(kit.layout.slots.left && { left: [...kit.layout.slots.left] }),\n ...(kit.layout.slots.canvas && { canvas: [...kit.layout.slots.canvas] }),\n ...(kit.layout.slots.right && { right: [...kit.layout.slots.right] }),\n ...(kit.layout.slots.bottombar && { bottombar: [...kit.layout.slots.bottombar] }),\n },\n },\n style: { ...kit.style },\n };\n\n if (kit.content) {\n json.content = { ...kit.content };\n }\n\n return json;\n}\n\n// ---------------------------------------------------------------------------\n// Deserialization\n// ---------------------------------------------------------------------------\n\n/**\n * Load a KitDefinition from a JSON representation.\n *\n * If `extends` is provided, the corresponding preset is resolved and the\n * remaining fields are applied as overrides via `extendKit`. If `extends`\n * is omitted, a new kit is created from scratch via `createKit`.\n *\n * The result is validated with `validateKit`. If validation produces\n * errors (fatal issues), an error is thrown. Warnings are logged to\n * the console but do not prevent loading.\n *\n * @param json - The KitJSON object to deserialize\n * @returns A complete, validated KitDefinition\n * @throws {Error} If the kit name is missing\n * @throws {Error} If a preset ID in `extends` is invalid\n * @throws {Error} If the resulting kit fails validation (has errors)\n *\n * @example Extend a preset\n * ```ts\n * const kit = loadKitFromJSON({\n * name: 'my-pro-variant',\n * extends: 'pro-studio',\n * behavior: { autoExport: true },\n * });\n * ```\n *\n * @example Create from scratch\n * ```ts\n * const kit = loadKitFromJSON({\n * name: 'minimal-editor',\n * capabilities: { elements: ['text'] },\n * behavior: { toolbar: 'none', selection: 'single', panelMode: 'inline', onEmptyClick: 'noop', autoExport: false },\n * });\n * ```\n */\nexport function loadKitFromJSON(json: KitJSON): KitDefinition {\n if (!json.name || json.name.trim() === '') {\n throw new Error('[loadKitFromJSON] Kit name is required');\n }\n\n // Build overrides object from the JSON fields (excluding name and extends)\n const overrides: Record<string, unknown> = {};\n if (json.capabilities) overrides.capabilities = json.capabilities;\n if (json.behavior) overrides.behavior = json.behavior;\n if (json.layout) overrides.layout = json.layout;\n if (json.style) overrides.style = json.style;\n if (json.content) overrides.content = json.content;\n\n let kit: KitDefinition;\n\n if (json.extends) {\n // Resolve the base preset and apply overrides\n const base = resolveKit(json.extends);\n kit = extendKit(base, { name: json.name, ...overrides });\n } else {\n // Create from scratch with defaults\n kit = createKit({ name: json.name, ...overrides });\n }\n\n // Validate the result\n const validation = validateKit(kit);\n\n if (validation.warnings.length > 0) {\n for (const warning of validation.warnings) {\n console.warn(`[loadKitFromJSON] Warning: ${warning}`);\n }\n }\n\n if (!validation.valid) {\n throw new Error(\n `[loadKitFromJSON] Kit \"${json.name}\" failed validation:\\n${validation.errors.join('\\n')}`\n );\n }\n\n return kit;\n}\n","/**\n * useProjectLoader - Hook for loading saved projects programmatically\n * Supports loading from JSON, files, and templates\n */\n\nimport { useState, useCallback } from 'react';\nimport { useEditor } from '../contexts/EditorContext.js';\nimport { ImportManager } from '../utils/ImportManager.js';\nimport { createLogger } from '../utils/logger.js';\nimport type { CanvasDocument } from '../utils/ExportManager.js';\nimport type { AnyElementConfig } from '../types/index.js';\n\nconst logger = createLogger('useProjectLoader');\n\nexport interface ProjectTemplate {\n name: string;\n description?: string;\n artboards: Array<{\n name: string;\n width: number;\n height: number;\n backgroundColor: string;\n elements?: AnyElementConfig[];\n }>;\n}\n\nexport interface ProjectMetadata {\n version: string;\n timestamp: string;\n artboardCount: number;\n elementCount: number;\n}\n\nexport interface UseProjectLoaderReturn {\n // Load from JSON\n loadFromJSON: (json: string | CanvasDocument) => Promise<void>;\n\n // Load from file\n loadFromFile: (file: File) => Promise<void>;\n\n // Create from template\n loadTemplate: (template: ProjectTemplate) => Promise<void>;\n\n // State\n isLoading: boolean;\n loadError: Error | null;\n currentProject: CanvasDocument | null;\n\n // Metadata\n projectMetadata: ProjectMetadata | null;\n}\n\n/**\n * Hook for loading saved projects\n * Must be used within EditorProvider\n *\n * @example Load from API\n * ```tsx\n * function ProductCustomizer({ productId }: { productId: string }) {\n * const { loadFromJSON, isLoading } = useProjectLoader();\n *\n * useEffect(() => {\n * fetch(`/api/designs/${productId}`)\n * .then(res => res.json())\n * .then(design => loadFromJSON(design))\n * .catch(console.error);\n * }, [productId]);\n *\n * if (isLoading) return <div>Loading design...</div>;\n *\n * return <Canvas />;\n * }\n * ```\n *\n * @example Load from template\n * ```tsx\n * function TemplateGallery() {\n * const { loadTemplate } = useProjectLoader();\n *\n * const handleSelectTemplate = (template: ProjectTemplate) => {\n * loadTemplate(template);\n * };\n *\n * return <div>Template gallery...</div>;\n * }\n * ```\n */\nexport function useProjectLoader(): UseProjectLoaderReturn {\n const {\n handleLoadWorkspace,\n } = useEditor();\n\n const [isLoading, setIsLoading] = useState(false);\n const [loadError, setLoadError] = useState<Error | null>(null);\n const [currentProject, setCurrentProject] = useState<CanvasDocument | null>(null);\n const [projectMetadata, setProjectMetadata] = useState<ProjectMetadata | null>(null);\n\n /**\n * Load from JSON string or CanvasDocument object\n */\n const loadFromJSON = useCallback(async (json: string | CanvasDocument) => {\n setIsLoading(true);\n setLoadError(null);\n\n try {\n // Parse JSON if it's a string\n const document: CanvasDocument = typeof json === 'string' ? JSON.parse(json) : json;\n\n // Validate document structure\n if (!document.artboards || !Array.isArray(document.artboards)) {\n throw new Error('Invalid document format: missing artboards array');\n }\n\n // Import the document using ImportManager\n // Note: We need to create a JSON string and then parse it\n const jsonString = JSON.stringify(document);\n const blob = new Blob([jsonString], { type: 'application/json' });\n const file = new File([blob], 'project.json', { type: 'application/json' });\n\n const result = await ImportManager.importFromJSON(file);\n\n if (!result.success || !result.artboards || !result.elements) {\n throw new Error(result.error || 'Failed to import project');\n }\n\n // Load into editor\n handleLoadWorkspace(result.artboards, result.elements, result.activeArtboardId || null);\n\n // Update state\n setCurrentProject(document);\n\n // Calculate metadata\n const totalElements = document.artboards.reduce((sum, ab) => sum + (ab.elements?.length || 0), 0);\n setProjectMetadata({\n version: document.metadata.version,\n timestamp: document.metadata.timestamp,\n artboardCount: document.artboards.length,\n elementCount: totalElements,\n });\n\n } catch (error) {\n logger.error('[useProjectLoader] Failed to load project:', error);\n setLoadError(error as Error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [handleLoadWorkspace]);\n\n /**\n * Load from file (File API)\n */\n const loadFromFile = useCallback(async (file: File) => {\n setIsLoading(true);\n setLoadError(null);\n\n try {\n // Read file as text\n const text = await file.text();\n\n // Load from JSON\n await loadFromJSON(text);\n } catch (error) {\n logger.error('[useProjectLoader] Failed to load file:', error);\n setLoadError(error as Error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [loadFromJSON]);\n\n /**\n * Create from template\n * Templates define artboards with optional default elements\n */\n const loadTemplate = useCallback(async (template: ProjectTemplate) => {\n setIsLoading(true);\n setLoadError(null);\n\n try {\n // Convert template to CanvasDocument format\n const document: CanvasDocument = {\n metadata: {\n version: '2.0.0',\n timestamp: new Date().toISOString(),\n appVersion: '1.0.0',\n },\n artboards: template.artboards.map((artboard, index) => ({\n id: `artboard-${Date.now()}-${index}`,\n name: artboard.name,\n x: 0,\n y: 0,\n width: artboard.width,\n height: artboard.height,\n backgroundColor: artboard.backgroundColor,\n elements: artboard.elements || [],\n })),\n activeArtboardId: null, // First artboard will be active by default\n };\n\n // Load the document\n await loadFromJSON(document);\n\n } catch (error) {\n logger.error('[useProjectLoader] Failed to load template:', error);\n setLoadError(error as Error);\n throw error;\n } finally {\n setIsLoading(false);\n }\n }, [loadFromJSON]);\n\n return {\n loadFromJSON,\n loadFromFile,\n loadTemplate,\n isLoading,\n loadError,\n currentProject,\n projectMetadata,\n };\n}\n","/**\n * useBreakpoint - Hook for responsive breakpoint detection\n * Provides responsive utilities for building adaptive UIs\n *\n * @example\n * ```tsx\n * function ResponsiveLayout() {\n * const { isAtLeast, breakpoint } = useBreakpoint();\n *\n * return (\n * <div>\n * {isAtLeast('md') ? (\n * <div className=\"desktop-layout\">\n * <LayersPanel />\n * <Canvas />\n * <ExportPanel />\n * </div>\n * ) : (\n * <div className=\"mobile-layout\">\n * <Canvas />\n * </div>\n * )}\n * <p>Current breakpoint: {breakpoint}</p>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { useState, useEffect, useMemo } from 'react';\n\nexport interface BreakpointConfig {\n xs?: number; // Extra small (default: 320)\n sm?: number; // Small (default: 480)\n md?: number; // Medium (default: 768)\n lg?: number; // Large (default: 1024)\n xl?: number; // Extra large (default: 1280)\n xxl?: number; // Extra extra large (default: 1536)\n}\n\nexport type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl';\n\nexport interface UseBreakpointReturn {\n breakpoint: Breakpoint;\n width: number;\n isXs: boolean;\n isSm: boolean;\n isMd: boolean;\n isLg: boolean;\n isXl: boolean;\n isXxl: boolean;\n isAtLeast: (bp: Breakpoint) => boolean;\n isAtMost: (bp: Breakpoint) => boolean;\n}\n\nconst DEFAULT_BREAKPOINTS: Required<BreakpointConfig> = {\n xs: 320,\n sm: 480,\n md: 768,\n lg: 1024,\n xl: 1280,\n xxl: 1536,\n};\n\n/**\n * Get current breakpoint based on window width\n */\nfunction getCurrentBreakpoint(width: number, config: Required<BreakpointConfig>): Breakpoint {\n if (width >= config.xxl) return 'xxl';\n if (width >= config.xl) return 'xl';\n if (width >= config.lg) return 'lg';\n if (width >= config.md) return 'md';\n if (width >= config.sm) return 'sm';\n return 'xs';\n}\n\n/**\n * Hook for responsive breakpoint detection\n */\nexport function useBreakpoint(config?: BreakpointConfig): UseBreakpointReturn {\n const breakpointConfig: Required<BreakpointConfig> = {\n ...DEFAULT_BREAKPOINTS,\n ...config,\n };\n\n const [width, setWidth] = useState<number>(() => {\n if (typeof window !== 'undefined') {\n return window.innerWidth;\n }\n return DEFAULT_BREAKPOINTS.lg; // Default for SSR\n });\n\n // Update width on window resize\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const handleResize = () => {\n setWidth(window.innerWidth);\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, []);\n\n // Calculate current breakpoint\n const breakpoint = useMemo(\n () => getCurrentBreakpoint(width, breakpointConfig),\n [width, breakpointConfig]\n );\n\n // Boolean helpers for each breakpoint\n const isXs = breakpoint === 'xs';\n const isSm = breakpoint === 'sm';\n const isMd = breakpoint === 'md';\n const isLg = breakpoint === 'lg';\n const isXl = breakpoint === 'xl';\n const isXxl = breakpoint === 'xxl';\n\n // Breakpoint ordering for comparisons\n const breakpointOrder: Breakpoint[] = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];\n\n // Check if current breakpoint is at least the specified breakpoint\n const isAtLeast = (bp: Breakpoint): boolean => {\n const currentIndex = breakpointOrder.indexOf(breakpoint);\n const targetIndex = breakpointOrder.indexOf(bp);\n return currentIndex >= targetIndex;\n };\n\n // Check if current breakpoint is at most the specified breakpoint\n const isAtMost = (bp: Breakpoint): boolean => {\n const currentIndex = breakpointOrder.indexOf(breakpoint);\n const targetIndex = breakpointOrder.indexOf(bp);\n return currentIndex <= targetIndex;\n };\n\n return {\n breakpoint,\n width,\n isXs,\n isSm,\n isMd,\n isLg,\n isXl,\n isXxl,\n isAtLeast,\n isAtMost,\n };\n}\n","/**\n * usePerformance - Hook for performance monitoring\n * Provides metrics for tracking editor performance\n *\n * @example\n * ```tsx\n * function PerformanceMonitor() {\n * const { metrics, startProfiling } = usePerformance();\n *\n * useEffect(() => {\n * startProfiling();\n * }, []);\n *\n * if (metrics.fps < 30) {\n * console.warn('Low FPS:', metrics.fps);\n * }\n *\n * return (\n * <div>\n * <p>FPS: {Math.round(metrics.fps)}</p>\n * <p>Render Time: {metrics.avgRenderTime.toFixed(2)}ms</p>\n * <p>Elements: {metrics.elementCount}</p>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { useState, useCallback, useRef, useEffect } from 'react';\n\nexport interface PerformanceMetrics {\n fps: number;\n avgRenderTime: number;\n peakRenderTime: number;\n memoryUsage: number;\n elementCount: number;\n exportCount: number;\n avgExportTime: number;\n}\n\nexport interface UsePerformanceReturn {\n metrics: PerformanceMetrics;\n startProfiling: () => void;\n stopProfiling: () => void;\n clearMetrics: () => void;\n getReport: () => string;\n isProfiling: boolean;\n}\n\nconst DEFAULT_METRICS: PerformanceMetrics = {\n fps: 0,\n avgRenderTime: 0,\n peakRenderTime: 0,\n memoryUsage: 0,\n elementCount: 0,\n exportCount: 0,\n avgExportTime: 0,\n};\n\n/**\n * Hook for performance monitoring\n */\nexport function usePerformance(): UsePerformanceReturn {\n const [metrics, setMetrics] = useState<PerformanceMetrics>(DEFAULT_METRICS);\n const [isProfiling, setIsProfiling] = useState(false);\n\n const frameTimesRef = useRef<number[]>([]);\n const renderTimesRef = useRef<number[]>([]);\n const exportTimesRef = useRef<number[]>([]);\n const lastFrameTimeRef = useRef<number>(performance.now());\n const rafIdRef = useRef<number | null>(null);\n\n // Calculate FPS from frame times\n const calculateFPS = useCallback((frameTimes: number[]): number => {\n if (frameTimes.length === 0) return 0;\n const avg = frameTimes.reduce((sum, time) => sum + time, 0) / frameTimes.length;\n return 1000 / avg; // Convert to FPS\n }, []);\n\n // Calculate average\n const calculateAverage = useCallback((values: number[]): number => {\n if (values.length === 0) return 0;\n return values.reduce((sum, val) => sum + val, 0) / values.length;\n }, []);\n\n // Get memory usage (if available)\n const getMemoryUsage = useCallback((): number => {\n if ('memory' in performance && (performance as { memory?: { usedJSHeapSize: number } }).memory) {\n const memory = (performance as { memory: { usedJSHeapSize: number } }).memory;\n return memory.usedJSHeapSize / (1024 * 1024); // Convert to MB\n }\n return 0;\n }, []);\n\n // Update metrics\n const updateMetrics = useCallback(() => {\n const newMetrics: PerformanceMetrics = {\n fps: calculateFPS(frameTimesRef.current),\n avgRenderTime: calculateAverage(renderTimesRef.current),\n peakRenderTime: Math.max(...renderTimesRef.current, 0),\n memoryUsage: getMemoryUsage(),\n elementCount: 0, // Would need to be updated by editor context\n exportCount: exportTimesRef.current.length,\n avgExportTime: calculateAverage(exportTimesRef.current),\n };\n\n setMetrics(newMetrics);\n }, [calculateFPS, calculateAverage, getMemoryUsage]);\n\n // Frame measurement loop\n const measureFrame = useCallback(() => {\n const now = performance.now();\n const frameTime = now - lastFrameTimeRef.current;\n lastFrameTimeRef.current = now;\n\n // Add frame time\n frameTimesRef.current.push(frameTime);\n if (frameTimesRef.current.length > 60) {\n frameTimesRef.current.shift(); // Keep last 60 frames (1 second at 60fps)\n }\n\n // Update metrics every 30 frames (~500ms at 60fps)\n if (frameTimesRef.current.length % 30 === 0) {\n updateMetrics();\n }\n\n if (isProfiling) {\n rafIdRef.current = requestAnimationFrame(measureFrame);\n }\n }, [isProfiling, updateMetrics]);\n\n // Start profiling\n const startProfiling = useCallback(() => {\n setIsProfiling(true);\n lastFrameTimeRef.current = performance.now();\n rafIdRef.current = requestAnimationFrame(measureFrame);\n }, [measureFrame]);\n\n // Stop profiling\n const stopProfiling = useCallback(() => {\n setIsProfiling(false);\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n rafIdRef.current = null;\n }\n }, []);\n\n // Clear metrics\n const clearMetrics = useCallback(() => {\n frameTimesRef.current = [];\n renderTimesRef.current = [];\n exportTimesRef.current = [];\n setMetrics(DEFAULT_METRICS);\n }, []);\n\n // Get human-readable report\n const getReport = useCallback((): string => {\n return `\nPerformance Report\n==================\nFPS: ${metrics.fps.toFixed(1)}\nAvg Render Time: ${metrics.avgRenderTime.toFixed(2)}ms\nPeak Render Time: ${metrics.peakRenderTime.toFixed(2)}ms\nMemory Usage: ${metrics.memoryUsage.toFixed(1)}MB\nElement Count: ${metrics.elementCount}\nExport Count: ${metrics.exportCount}\nAvg Export Time: ${metrics.avgExportTime.toFixed(2)}ms\n `.trim();\n }, [metrics]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (rafIdRef.current !== null) {\n cancelAnimationFrame(rafIdRef.current);\n }\n };\n }, []);\n\n return {\n metrics,\n startProfiling,\n stopProfiling,\n clearMetrics,\n getReport,\n isProfiling,\n };\n}\n","import { useEditor } from '../contexts/EditorContext.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\n\n/**\n * Returns a specific element by its ID, or null if not found.\n *\n * Useful for components that need to display or react to a particular\n * element without subscribing to the full editor state.\n *\n * @param id - The element ID to look up, or null to skip the lookup.\n * @returns The matching element, or null if the ID is null or no element matches.\n *\n * @example\n * ```tsx\n * function ElementInspector({ elementId }: { elementId: string }) {\n * const element = useElementById(elementId);\n * if (!element) return <p>Element not found</p>;\n * return <p>Position: ({element.x}, {element.y})</p>;\n * }\n * ```\n */\nexport function useElementById(id: string | null): EditorElement | null {\n const { getElementById } = useEditor();\n if (!id) return null;\n return getElementById(id) ?? null;\n}\n","/**\n * useLayerDragDrop - Hook for layer drag-drop reordering\n *\n * Extracts drag-drop reordering logic from LayersPanel.tsx into a\n * reusable hook. Handles drag state management, drop position\n * calculation (before/after/into for groups), and dispatches to\n * the appropriate reorder callback.\n *\n * @example\n * ```tsx\n * function LayersList({ elements, onReorder }) {\n * const { draggedId, dragOverId, dropPosition, handlers } = useLayerDragDrop({\n * onReorder,\n * findElement: (id) => elements.find(e => e.id === id) ?? null,\n * findParentGroup: (id) => findGroupParent(elements, id),\n * });\n *\n * return elements.map(el => (\n * <div\n * key={el.id}\n * draggable\n * onDragStart={(e) => handlers.onDragStart(e, el.id)}\n * onDragOver={(e) => handlers.onDragOver(e, el.id)}\n * onDrop={(e) => handlers.onDrop(e, el.id)}\n * onDragEnd={handlers.onDragEnd}\n * />\n * ));\n * }\n * ```\n */\n\nimport { useState, useCallback } from 'react';\nimport { GroupElement } from '../core/GroupElement.js';\nimport type { EditorElement } from '../contexts/EditorContext.js';\n\nexport interface UseLayerDragDropOptions {\n /**\n * Called when reordering top-level elements or elements in different groups.\n * Position is already inverted for reversed display order.\n */\n onReorder: (draggedId: string, targetId: string, position: 'before' | 'after') => void;\n\n /**\n * Called when reordering elements within the same group.\n * Position is already inverted for reversed display order.\n */\n onGroupReorder?: (\n draggedId: string,\n targetId: string,\n position: 'before' | 'after',\n groupId: string\n ) => void;\n\n /**\n * Called when dropping an element into a group (center drop zone).\n */\n onDropIntoGroup?: (draggedId: string, groupId: string) => void;\n\n /**\n * Called when dropping a top-level element between children of a group.\n * Position is already inverted for reversed display order.\n */\n onDropIntoGroupAtPosition?: (\n draggedId: string,\n groupId: string,\n targetChildId: string,\n position: 'before' | 'after'\n ) => void;\n\n /**\n * Look up an element by ID. Required for determining if a target is a group.\n */\n findElement?: (id: string) => EditorElement | null;\n\n /**\n * Find the parent group of an element. Required for intra-group reordering.\n */\n findParentGroup?: (id: string) => GroupElement | null;\n}\n\nexport interface UseLayerDragDropReturn {\n /** ID of the currently dragged element, or null */\n draggedId: string | null;\n /** ID of the element being dragged over, or null */\n dragOverId: string | null;\n /** Where the dragged element will be dropped relative to the target */\n dropPosition: 'before' | 'after' | 'into' | null;\n /** Event handlers to attach to draggable layer items */\n handlers: {\n onDragStart: (e: React.DragEvent, elementId: string) => void;\n onDragOver: (e: React.DragEvent, elementId: string) => void;\n onDrop: (e: React.DragEvent, targetId: string) => void;\n onDragEnd: () => void;\n };\n}\n\n/**\n * Hook for managing drag-drop reordering in layer panels.\n *\n * Calculates drop position based on mouse position within the target element:\n * - For groups: top 25% = before, middle 50% = into, bottom 25% = after\n * - For non-groups: top/bottom split at 40%/60%\n *\n * Handles the display-order inversion: layers are displayed in reverse\n * order (topmost layer first), so visual \"before\" maps to array \"after\"\n * and vice versa. This inversion is applied before calling the callbacks.\n */\nexport function useLayerDragDrop(options: UseLayerDragDropOptions): UseLayerDragDropReturn {\n const {\n onReorder,\n onGroupReorder,\n onDropIntoGroup,\n onDropIntoGroupAtPosition,\n findElement,\n findParentGroup,\n } = options;\n\n const [draggedId, setDraggedId] = useState<string | null>(null);\n const [dragOverId, setDragOverId] = useState<string | null>(null);\n const [dropPosition, setDropPosition] = useState<'before' | 'after' | 'into' | null>(null);\n\n const handleDragStart = useCallback((e: React.DragEvent, elementId: string) => {\n e.dataTransfer.effectAllowed = 'move';\n // Delay setting dragged state until after browser captures drag image\n requestAnimationFrame(() => {\n setDraggedId(elementId);\n });\n }, []);\n\n const handleDragOver = useCallback(\n (e: React.DragEvent, elementId: string) => {\n e.preventDefault();\n e.dataTransfer.dropEffect = 'move';\n\n const rect = e.currentTarget.getBoundingClientRect();\n const mouseY = e.clientY;\n const relativeY = mouseY - rect.top;\n const height = rect.height;\n\n // Check if target is a group\n const targetElement = findElement?.(elementId);\n const isGroup = targetElement instanceof GroupElement;\n\n let position: 'before' | 'after' | 'into';\n\n if (isGroup) {\n // For groups: top 25% = before, bottom 25% = after, middle 50% = into\n if (relativeY < height * 0.25) {\n position = 'before';\n } else if (relativeY > height * 0.75) {\n position = 'after';\n } else {\n position = 'into';\n }\n } else {\n // For non-groups: top 40% = before, bottom 40% = after, middle = split\n if (relativeY < height * 0.4) {\n position = 'before';\n } else if (relativeY > height * 0.6) {\n position = 'after';\n } else {\n position = relativeY < height / 2 ? 'before' : 'after';\n }\n }\n\n setDragOverId(elementId);\n setDropPosition(position);\n },\n [findElement]\n );\n\n const resetDragState = useCallback(() => {\n setDraggedId(null);\n setDragOverId(null);\n setDropPosition(null);\n }, []);\n\n const handleDrop = useCallback(\n (e: React.DragEvent, targetId: string) => {\n e.preventDefault();\n if (!draggedId || draggedId === targetId || !dropPosition) {\n resetDragState();\n return;\n }\n\n if (dropPosition === 'into') {\n // Dropping into a group\n if (onDropIntoGroup) {\n onDropIntoGroup(draggedId, targetId);\n }\n } else {\n // Reordering (before/after)\n // Check if both elements are children of the same group\n const draggedParent = findParentGroup?.(draggedId);\n const targetParent = findParentGroup?.(targetId);\n\n // Layers are displayed in reverse order, so invert the position\n // Visual \"before\" = Array \"after\", Visual \"after\" = Array \"before\"\n const arrayPosition = dropPosition === 'before' ? 'after' : 'before';\n\n if (draggedParent && targetParent && draggedParent.id === targetParent.id) {\n // Both are children of the same group - reorder within the group\n if (onGroupReorder) {\n onGroupReorder(draggedId, targetId, arrayPosition, draggedParent.id!);\n }\n } else if (!draggedParent && targetParent && onDropIntoGroupAtPosition) {\n // Dragging from top-level into between children of a group\n onDropIntoGroupAtPosition(draggedId, targetParent.id!, targetId, arrayPosition);\n } else {\n // Top-level reordering\n onReorder(draggedId, targetId, arrayPosition);\n }\n }\n\n // Clear drag state immediately since dragEnd may not fire when DOM changes\n resetDragState();\n },\n [\n draggedId,\n dropPosition,\n onReorder,\n onGroupReorder,\n onDropIntoGroup,\n onDropIntoGroupAtPosition,\n findParentGroup,\n resetDragState,\n ]\n );\n\n return {\n draggedId,\n dragOverId,\n dropPosition,\n handlers: {\n onDragStart: handleDragStart,\n onDragOver: handleDragOver,\n onDrop: handleDrop,\n onDragEnd: resetDragState,\n },\n };\n}\n","/**\n * useLayerSelection - Hook for layer selection logic\n *\n * Extracts the selection logic (shift-click multi-select, single-click,\n * deselection) from LayersPanel.tsx into a reusable hook.\n *\n * @example\n * ```tsx\n * function LayersList({ elements }) {\n * const [selectedId, setSelectedId] = useState<string | null>(null);\n * const [multiSelection, setMultiSelection] = useState<string[]>([]);\n *\n * const { isSelected, handleClick } = useLayerSelection({\n * selectedId,\n * multiSelection,\n * onSelectionChange: setSelectedId,\n * onMultiSelectionChange: setMultiSelection,\n * });\n *\n * return elements.map(el => (\n * <div\n * key={el.id}\n * className={isSelected(el.id) ? 'selected' : ''}\n * onClick={(e) => handleClick(e, el.id)}\n * />\n * ));\n * }\n * ```\n */\n\nimport { useCallback } from 'react';\n\nexport interface UseLayerSelectionOptions {\n /** Currently selected single element ID, or null */\n selectedId: string | null;\n /** Array of multi-selected element IDs */\n multiSelection: string[];\n /** Callback for single selection changes */\n onSelectionChange: (id: string | null) => void;\n /** Callback for multi-selection changes */\n onMultiSelectionChange: (ids: string[]) => void;\n}\n\nexport interface UseLayerSelectionReturn {\n /**\n * Check if an element is selected (either single or multi-selected).\n * Does not account for activeChildElement priority -- callers handling\n * group children should check that separately.\n */\n isSelected: (id: string) => boolean;\n\n /**\n * Handle a click on a layer element.\n * - Normal click: selects only this element, clears multi-selection\n * - Shift+click: toggles the element in/out of multi-selection\n */\n handleClick: (e: React.MouseEvent | React.KeyboardEvent, elementId: string) => void;\n}\n\n/**\n * Hook for managing layer selection state.\n *\n * Implements the following selection behaviors:\n *\n * **Normal click:**\n * - Selects only the clicked element\n * - Clears any multi-selection\n *\n * **Shift+click with existing multi-selection:**\n * - If element is in multi-selection: removes it\n * - If only 1 remains: converts back to single selection\n * - If 0 remain: clears selection\n * - If element is not in multi-selection: adds it\n *\n * **Shift+click with single selection:**\n * - If clicking the already-selected element: no-op\n * - If clicking a different element: starts multi-selection with both\n *\n * **Shift+click with no selection:**\n * - Selects the clicked element as a single selection\n */\nexport function useLayerSelection(options: UseLayerSelectionOptions): UseLayerSelectionReturn {\n const { selectedId, multiSelection, onSelectionChange, onMultiSelectionChange } = options;\n\n const isSelected = useCallback(\n (id: string): boolean => {\n return id === selectedId || multiSelection.includes(id);\n },\n [selectedId, multiSelection]\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent | React.KeyboardEvent, elementId: string) => {\n if (e.shiftKey) {\n // Shift-click: multi-selection behavior\n const isInMultiSelection = multiSelection.includes(elementId);\n const isCurrentlySelected = selectedId === elementId;\n\n if (multiSelection.length > 0) {\n // Already have multi-selection\n if (isInMultiSelection) {\n // Remove from multi-selection\n const newSelection = multiSelection.filter((id) => id !== elementId);\n if (newSelection.length === 1) {\n // Only one left, convert back to single selection\n onMultiSelectionChange([]);\n onSelectionChange(newSelection[0]);\n } else if (newSelection.length === 0) {\n // All deselected\n onMultiSelectionChange([]);\n onSelectionChange(null);\n } else {\n // Keep multi-selection\n onMultiSelectionChange(newSelection);\n }\n } else {\n // Add to multi-selection\n onMultiSelectionChange([...multiSelection, elementId]);\n }\n } else if (isCurrentlySelected) {\n // Single selection exists and shift-clicking it: do nothing\n return;\n } else if (selectedId !== null) {\n // Convert single selection to multi-selection\n onMultiSelectionChange([selectedId, elementId]);\n onSelectionChange(null);\n } else {\n // No selection, just select this element\n onSelectionChange(elementId);\n }\n } else {\n // Normal click: select only this element\n onSelectionChange(elementId);\n onMultiSelectionChange([]);\n }\n },\n [selectedId, multiSelection, onSelectionChange, onMultiSelectionChange]\n );\n\n return { isSelected, handleClick };\n}\n","/**\n * FontSizeDropdown - Dropdown for selecting font size\n */\n\nimport { memo } from 'react';\nimport { Icon } from '@iconify/react';\nimport { Popover, PopoverTrigger, PopoverContent } from './ui';\n\nexport interface FontSizeDropdownProps {\n value: number;\n onChange: (size: number) => void;\n fontSizes: number[];\n isOpen: boolean;\n onToggle: (open: boolean) => void;\n}\n\nconst FontSizeDropdown = memo(({ value, onChange, fontSizes, isOpen, onToggle }: FontSizeDropdownProps) => {\n const handleSelect = (size: number) => {\n onChange(size);\n onToggle(false);\n };\n\n return (\n <Popover open={isOpen} onOpenChange={onToggle}>\n <PopoverTrigger asChild>\n <button className=\"toolbar-btn\" aria-label=\"Font size\">\n <Icon icon=\"radix-icons:font-size\" className=\"size-5\" />\n </button>\n </PopoverTrigger>\n <PopoverContent className=\"w-[120px] max-h-[300px] overflow-y-auto p-1\" maxZIndex>\n <div className=\"flex flex-col gap-0.5\">\n {fontSizes.map((size) => (\n <button\n key={size}\n onClick={() => handleSelect(size)}\n className={`w-full rounded-md px-3 py-1.5 text-center text-sm transition-colors hover:bg-muted ${\n value === size ? 'bg-muted font-medium' : ''\n }`}\n >\n {size}\n </button>\n ))}\n </div>\n </PopoverContent>\n </Popover>\n );\n});\n\nFontSizeDropdown.displayName = 'FontSizeDropdown';\n\nexport default FontSizeDropdown;\n","import { useState } from 'react';\nimport { Tooltip, TooltipTrigger, TooltipContent } from '../ui';\nimport { FONT_SIZES } from '../../constants.js';\nimport { clickProtection } from '../../utils/clickProtection.js';\nimport type { UseTextToolbarReturn } from '../../hooks/useTextToolbar.js';\n\nexport interface FontSizeGroupProps {\n toolbar: UseTextToolbarReturn;\n}\n\nexport function FontSizeGroup({ toolbar }: FontSizeGroupProps) {\n const { fontSize, handleFontSizeIncrement, handleFontSizeChange } = toolbar;\n const [openDropdown, setOpenDropdown] = useState(false);\n\n return (\n <div className=\"toolbar-group\">\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <button className=\"toolbar-btn-sm\" onClick={() => handleFontSizeIncrement(-1)}>\n -\n </button>\n </TooltipTrigger>\n <TooltipContent>Decrease Font Size</TooltipContent>\n </Tooltip>\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <div style={{ position: 'relative' }}>\n <button\n className=\"toolbar-font-size-display\"\n onClick={() => {\n clickProtection.protectNextClick();\n setOpenDropdown(!openDropdown);\n }}\n >\n {fontSize}\n </button>\n {openDropdown && (\n <div\n className=\"font-dropdown\"\n ref={(el: HTMLDivElement | null) => {\n if (el) {\n const handleClickOutside = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (!el.contains(target) && !target.closest('.toolbar-font-size-display')) {\n setOpenDropdown(false);\n }\n };\n setTimeout(() => {\n document.addEventListener('mousedown', handleClickOutside);\n }, 0);\n }\n }}\n >\n {FONT_SIZES.map((size) => (\n <button\n key={size}\n className={`font-dropdown-option ${fontSize === size ? 'selected' : ''}`}\n onClick={() => {\n handleFontSizeChange(size);\n setOpenDropdown(false);\n }}\n >\n {size}\n </button>\n ))}\n </div>\n )}\n </div>\n </TooltipTrigger>\n <TooltipContent>Font Size</TooltipContent>\n </Tooltip>\n <Tooltip delayDuration={300}>\n <TooltipTrigger asChild>\n <button className=\"toolbar-btn-sm\" onClick={() => handleFontSizeIncrement(1)}>\n +\n </button>\n </TooltipTrigger>\n <TooltipContent>Increase Font Size</TooltipContent>\n </Tooltip>\n </div>\n );\n}\n","/**\n * ElementTypePlugin - Plugin API for registering custom element types\n *\n * Allows external developers to add new element types without modifying\n * core canvas files. Custom types integrate with the transform registry\n * so that GroupElement reconstruction, ElementFactory, and all other\n * registry consumers work seamlessly.\n *\n * @example\n * ```typescript\n * import { registerElementType } from '@snowcone-app/canvas/advanced';\n *\n * registerElementType({\n * type: 'custom-shape',\n * Component: CustomShapeElement,\n * label: 'Custom Shape',\n * icon: 'lucide:shapes',\n * category: 'custom',\n * });\n * ```\n *\n * @packageDocumentation\n */\n\nimport {\n registerTransform,\n unregisterTransform,\n getTransformById,\n _resetDynamicTransforms,\n} from '../transforms/registry.js';\n\n/**\n * Registration descriptor for a custom element type.\n */\nexport interface ElementTypeRegistration {\n /** Unique type identifier (must not conflict with built-in types) */\n type: string;\n\n /**\n * Element class constructor.\n * Must accept a config object and produce a valid element instance\n * (i.e., something that extends BaseElement).\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Constructors have varying signatures\n Component: new (config: any) => any;\n\n /** Display label for UI (e.g., \"Custom Shape\") */\n label: string;\n\n /** Icon identifier in Iconify format (e.g., \"lucide:shapes\") */\n icon?: string;\n\n /** Category for grouping in the add-element menu */\n category?: 'text' | 'image' | 'shape' | 'custom';\n\n /** Default config for new elements of this type */\n defaultConfig?: Record<string, unknown>;\n}\n\n/**\n * Internal store for custom element type registrations.\n * Keyed by type string.\n */\nconst _customElementTypes = new Map<string, ElementTypeRegistration>();\n\n/**\n * Register a custom element type.\n *\n * - Validates the registration (type must be non-empty, Component must be a constructor)\n * - Prevents conflicts with built-in types and duplicate registrations\n * - Adds the type to the transform registry so GroupElement, ElementFactory,\n * and other registry consumers recognize it\n *\n * @param registration - The element type registration descriptor\n * @throws Error if type conflicts with a built-in type\n * @throws Error if type is already registered as a custom type\n * @throws Error if registration is invalid (missing type/Component/label)\n */\nexport function registerElementType(registration: ElementTypeRegistration): void {\n // Validate required fields\n if (!registration.type || typeof registration.type !== 'string') {\n throw new Error('ElementTypeRegistration requires a non-empty \"type\" string');\n }\n if (typeof registration.Component !== 'function') {\n throw new Error(\n `ElementTypeRegistration for \"${registration.type}\" requires a \"Component\" constructor function`\n );\n }\n if (!registration.label || typeof registration.label !== 'string') {\n throw new Error(\n `ElementTypeRegistration for \"${registration.type}\" requires a non-empty \"label\" string`\n );\n }\n\n // registerTransform will throw if the id conflicts with built-in or duplicate\n registerTransform(registration.type, {\n id: registration.type,\n label: registration.label,\n Component: registration.Component,\n });\n\n // Store the full registration (including icon, category, defaultConfig)\n _customElementTypes.set(registration.type, { ...registration });\n}\n\n/**\n * Unregister a custom element type.\n *\n * Removes the type from both the plugin registry and the transform registry.\n * Built-in types cannot be unregistered.\n *\n * @param type - The type identifier to unregister\n * @throws Error if attempting to unregister a built-in type\n */\nexport function unregisterElementType(type: string): void {\n // unregisterTransform throws if it's a built-in type\n unregisterTransform(type);\n _customElementTypes.delete(type);\n}\n\n/**\n * Get all registered custom element types.\n *\n * Returns only plugin-registered types, not built-in types.\n * The returned array is a snapshot; mutations do not affect the registry.\n *\n * @returns Array of ElementTypeRegistration descriptors\n */\nexport function getCustomElementTypes(): ElementTypeRegistration[] {\n return Array.from(_customElementTypes.values());\n}\n\n/**\n * Check if a type identifier is registered (built-in or custom).\n *\n * @param type - The type identifier to check\n * @returns true if the type exists in the transform registry\n */\nexport function isRegisteredElementType(type: string): boolean {\n return getTransformById(type) !== undefined;\n}\n\n/**\n * Reset all custom element type registrations (for testing only).\n * Also resets the underlying dynamic transforms in the registry.\n * @internal\n */\nexport function _resetCustomElementTypes(): void {\n _customElementTypes.clear();\n _resetDynamicTransforms();\n}\n","/**\n * Canvas Event Bus\n *\n * A typed publish/subscribe event system for cross-component communication\n * within the canvas editor. Components can emit and listen for events without\n * direct coupling, enabling loose coordination between panels, tools, and\n * the canvas itself.\n *\n * All event types are defined in {@link CanvasEventMap} for compile-time\n * type safety -- subscribers receive correctly-typed payloads and emitters\n * are checked against the event map at compile time.\n *\n * A singleton instance is available via {@link canvasEventBus} for use\n * across the editor. The {@link useCanvasEvents} hook provides React\n * integration.\n *\n * @example Subscribe to element creation\n * ```ts\n * import { canvasEventBus } from '@snowcone-app/canvas/advanced';\n *\n * const unsub = canvasEventBus.on('element:created', ({ elementId, type }) => {\n * console.log(`Created ${type} element: ${elementId}`);\n * });\n *\n * // Later: clean up\n * unsub();\n * ```\n *\n * @example One-shot listener\n * ```ts\n * canvasEventBus.once('export:completed', ({ durationMs }) => {\n * console.log(`Export finished in ${durationMs}ms`);\n * });\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Event Map\n// ---------------------------------------------------------------------------\n\n/**\n * Map of all canvas event names to their payload types.\n *\n * Extend this interface (via module augmentation) to add custom events:\n * ```ts\n * declare module '@snowcone-app/canvas/advanced' {\n * interface CanvasEventMap {\n * 'my-plugin:action': { value: number };\n * }\n * }\n * ```\n */\nexport interface CanvasEventMap {\n /** Fired after a new element is added to the canvas */\n 'element:created': { elementId: string; type: string };\n /** Fired after one or more properties of an element change */\n 'element:updated': { elementId: string; changes: string[] };\n /** Fired after an element is removed from the canvas */\n 'element:deleted': { elementId: string };\n /** Fired when the selected element changes (null = deselected) */\n 'element:selected': { elementId: string | null };\n /** Fired when the active artboard changes */\n 'artboard:changed': { artboardId: string; artboardName: string };\n /** Fired when an export operation begins */\n 'export:started': { artboardId: string };\n /** Fired when an export operation completes successfully */\n 'export:completed': { artboardId: string; durationMs: number };\n /** Fired when an export operation fails */\n 'export:error': { artboardId: string; error: Error };\n /** Fired after an undo operation */\n 'undo': { commandDescription?: string };\n /** Fired after a redo operation */\n 'redo': { commandDescription?: string };\n}\n\n// ---------------------------------------------------------------------------\n// Handler type\n// ---------------------------------------------------------------------------\n\n/** Strongly-typed event handler for a specific event name */\nexport type CanvasEventHandler<K extends keyof CanvasEventMap> = (\n event: CanvasEventMap[K],\n) => void;\n\n// ---------------------------------------------------------------------------\n// CanvasEventBus\n// ---------------------------------------------------------------------------\n\n/**\n * A typed event bus for the canvas editor.\n *\n * Provides subscribe ({@link on}, {@link once}), publish ({@link emit}),\n * and unsubscribe ({@link off}) operations with full type safety.\n *\n * Listeners for a given event are called in the order they were registered.\n * Errors thrown inside a handler are caught and logged to `console.error`\n * so that one failing handler does not prevent others from executing.\n */\nexport class CanvasEventBus {\n /** Map of event name to the set of registered handler functions */\n private listeners = new Map<string, Set<Function>>();\n\n // -----------------------------------------------------------------------\n // Subscribe\n // -----------------------------------------------------------------------\n\n /**\n * Subscribe to an event.\n *\n * @param event - The event name to listen for\n * @param handler - Callback invoked with the event payload\n * @returns An unsubscribe function -- call it to remove this handler\n */\n on<K extends keyof CanvasEventMap>(\n event: K,\n handler: CanvasEventHandler<K>,\n ): () => void {\n let handlers = this.listeners.get(event as string);\n if (!handlers) {\n handlers = new Set();\n this.listeners.set(event as string, handlers);\n }\n handlers.add(handler);\n\n // Return unsubscribe function\n return () => {\n handlers!.delete(handler);\n if (handlers!.size === 0) {\n this.listeners.delete(event as string);\n }\n };\n }\n\n /**\n * Subscribe to an event for a single invocation.\n *\n * The handler is automatically removed after the first time the event\n * fires. The returned unsubscribe function can also be used to cancel\n * before the event fires.\n *\n * @param event - The event name to listen for\n * @param handler - Callback invoked once with the event payload\n * @returns An unsubscribe function\n */\n once<K extends keyof CanvasEventMap>(\n event: K,\n handler: CanvasEventHandler<K>,\n ): () => void {\n const wrapper = ((data: CanvasEventMap[K]) => {\n unsubscribe();\n handler(data);\n }) as CanvasEventHandler<K>;\n\n const unsubscribe = this.on(event, wrapper);\n return unsubscribe;\n }\n\n // -----------------------------------------------------------------------\n // Publish\n // -----------------------------------------------------------------------\n\n /**\n * Emit an event, invoking all registered handlers for that event name.\n *\n * Handlers are called synchronously in registration order. If a handler\n * throws, the error is logged and remaining handlers still execute.\n *\n * @param event - The event name to emit\n * @param data - The payload to pass to each handler\n */\n emit<K extends keyof CanvasEventMap>(\n event: K,\n data: CanvasEventMap[K],\n ): void {\n const handlers = this.listeners.get(event as string);\n if (!handlers) return;\n\n // Iterate over a snapshot so that handlers can safely unsubscribe\n for (const handler of [...handlers]) {\n try {\n handler(data);\n } catch (err) {\n console.error(\n `[CanvasEventBus] Error in handler for \"${String(event)}\":`,\n err,\n );\n }\n }\n }\n\n // -----------------------------------------------------------------------\n // Unsubscribe\n // -----------------------------------------------------------------------\n\n /**\n * Remove listeners.\n *\n * - If called with an event name, removes all handlers for that event.\n * - If called with no arguments, removes all handlers for all events.\n *\n * @param event - Optional event name to clear. Omit to clear everything.\n */\n off<K extends keyof CanvasEventMap>(event?: K): void {\n if (event === undefined) {\n this.listeners.clear();\n } else {\n this.listeners.delete(event as string);\n }\n }\n\n // -----------------------------------------------------------------------\n // Introspection\n // -----------------------------------------------------------------------\n\n /**\n * Get the number of registered listeners for a specific event.\n *\n * @param event - The event name to query\n * @returns The number of handlers currently registered\n */\n listenerCount(event: keyof CanvasEventMap): number {\n return this.listeners.get(event as string)?.size ?? 0;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton\n// ---------------------------------------------------------------------------\n\n/**\n * The singleton CanvasEventBus instance shared across the editor.\n *\n * Use this directly or via the {@link useCanvasEvents} hook in React\n * components.\n */\nexport const canvasEventBus = new CanvasEventBus();\n","/**\n * useCanvasEvents Hook\n *\n * Provides access to the singleton {@link CanvasEventBus} instance for\n * cross-component communication within the canvas editor.\n *\n * This is a thin convenience wrapper -- it simply returns the shared\n * singleton so that React components have a consistent hook-based API\n * for accessing the event bus.\n *\n * @example Subscribe to events in a component\n * ```tsx\n * import { useCanvasEvents } from '@snowcone-app/canvas/advanced';\n *\n * function MyPanel() {\n * const events = useCanvasEvents();\n *\n * useEffect(() => {\n * const unsub = events.on('element:selected', ({ elementId }) => {\n * console.log('Selected:', elementId);\n * });\n * return unsub;\n * }, [events]);\n *\n * return <div>My Panel</div>;\n * }\n * ```\n *\n * @example Emit events from a component\n * ```tsx\n * function ExportButton() {\n * const events = useCanvasEvents();\n *\n * const handleExport = () => {\n * events.emit('export:started', { artboardId: 'ab-1' });\n * };\n *\n * return <button onClick={handleExport}>Export</button>;\n * }\n * ```\n */\n\nimport { canvasEventBus, type CanvasEventBus } from '../core/EventBus.js';\n\n/**\n * Returns the singleton {@link CanvasEventBus} instance.\n *\n * The returned reference is stable across renders -- it always points to\n * the same singleton, so it is safe to include in dependency arrays.\n */\nexport function useCanvasEvents(): CanvasEventBus {\n return canvasEventBus;\n}\n","/**\n * ADR-0054: SVG-based visual-guide overlay.\n *\n * Duplicated intentionally between:\n * - snowcone-loom/app/components/VisualGuideOverlay.tsx (Loom editor)\n * - ui-components/packages/canvas/src/components/VisualGuideOverlay.tsx\n * (this file — consumed by the Snowcone consumer editor via\n * @snowcone-app/canvas)\n * Loom doesn't depend on @snowcone-app/canvas. Keep these two files\n * byte-identical below the header; if you change one, mirror the other.\n *\n * Renders structured piece guides (boundary, safe area, zones, labels) as\n * stacked SVG layers on top of an artboard preview. The entire overlay\n * lives inside a single `<svg viewBox=\"0 0 artboardWidth artboardHeight\">`\n * so piece-local coordinates compose directly and strokes can opt into\n * `vector-effect=\"non-scaling-stroke\"` to stay visually crisp at every\n * viewport scale.\n *\n * Falls back cleanly when no guides are authored:\n * - `boundary` → the piece's bounding rect (0,0 to pieceWidth, pieceHeight)\n * - `safeArea` → an inset rect derived from `safeAreaInsetPx` when present,\n * omitted otherwise\n */\n\nimport { useMemo } from \"react\";\n\n// ── Types (mirror the backend layouts.ts shape) ───────────────────────────────\n\nexport type SvgPath =\n | { kind: \"rect\"; x: number; y: number; width: number; height: number }\n | {\n kind: \"roundedRect\";\n x: number;\n y: number;\n width: number;\n height: number;\n rx?: number;\n ry?: number;\n }\n | { kind: \"path\"; d: string };\n\nexport interface ZoneShape {\n kind: \"wrap\" | \"binding\" | \"dieCut\" | \"warning\" | \"custom\";\n label?: string;\n path: SvgPath;\n}\n\nexport interface GuideLabel {\n text: string;\n x: number;\n y: number;\n anchor?: \"tl\" | \"tc\" | \"tr\" | \"cl\" | \"c\" | \"cr\" | \"bl\" | \"bc\" | \"br\";\n}\n\nexport interface PieceGuide {\n boundary?: SvgPath;\n safeArea?: SvgPath;\n zones?: ZoneShape[];\n labels?: GuideLabel[];\n /**\n * Corner radius of the piece's *physical outer shape* (e.g. a phone\n * case's outer curve) in piece-local pixels. When set, the bleed\n * ring's outer edge uses a rounded rectangle of `(pieceWidth,\n * pieceHeight)` with this radius, and the entire piece render is\n * clipped to that shape — so nothing bleeds into the sharp corners\n * of the piece's bounding rect. Omit / 0 = sharp corners (current\n * default behaviour).\n */\n outerRadius?: number;\n}\n\nexport interface OverlayPiece {\n /** Stable piece id (matches `placements[].name`). */\n id: string;\n /** Piece's top-left position on the artboard, in artboard pixel coords. */\n x: number;\n y: number;\n /** Piece-local dimensions in px. */\n width: number;\n height: number;\n /**\n * Fallback safe-area inset when no authored `safeArea` is present. In\n * piece-local pixels (caller converts from inches). Omit to skip the\n * fallback safe area entirely.\n */\n safeAreaInsetPx?: number;\n /** Clockwise rotation in degrees about the piece center. Default 0. */\n rotation?: number;\n}\n\nexport interface VisualGuideOverlayStyle {\n bleedFill?: string;\n bleedOpacity?: number;\n boundaryStroke?: string;\n boundaryStrokeWidth?: number;\n /**\n * Safe-area wash: fills the region outside the safe area (inside the\n * piece) with a semi-transparent color. Replaces the old dashed\n * safe-area outline as the default — de-emphasizes the bleed margin so\n * the safe area reads as the \"clean\" zone without adding line chrome.\n */\n safeAreaWashFill?: string;\n safeAreaWashOpacity?: number;\n /**\n * Corner radius (in viewBox px) for the wash's outer edge so it hugs\n * rounded products (phone cases, rounded cards, etc.) instead of\n * boxing sharp corners. Pass `0` for hard corners. Omit to use an\n * artboard-proportional default (~2% of the shorter axis).\n */\n safeAreaWashCornerRadius?: number;\n /**\n * Safe-area stroke settings — legacy dashed outline. Disabled by default\n * (wash does the work). Set `safeAreaStroke` to any color to re-enable.\n */\n safeAreaStroke?: string;\n safeAreaStrokeWidth?: number;\n safeAreaDashArray?: string;\n zoneFill?: Partial<Record<ZoneShape[\"kind\"], string>>;\n zoneStroke?: Partial<Record<ZoneShape[\"kind\"], string>>;\n labelColor?: string;\n labelFontSize?: number;\n labelFontFamily?: string;\n}\n\nexport interface VisualGuideOverlayProps {\n /** Artboard dimensions in px — defines the SVG viewBox. */\n artboardWidth: number;\n artboardHeight: number;\n /**\n * @deprecated Do not use — leave at 0 (the default).\n *\n * This was intended to mirror SnowconeCanvas's `fixedMargin`, but\n * `fixedMargin` is in CSS pixels (converted to world units via\n * `worldMargin = fixedMargin / zoom` in useCanvasLayout.ts) while\n * this prop treated the value as viewBox/world units. The two only\n * match at zoom === 1, so passing a non-zero value silently drifted\n * the overlay content by tens of pixels at typical editor zooms.\n *\n * Correct usage: keep the SVG viewBox equal to the artboard, and\n * position the wrapping div with `inset: ${fixedMargin}px` so the\n * overlay covers only the artboard region of the padded canvas.\n */\n canvasPadding?: number;\n /** Pieces to render guides for. */\n pieces: OverlayPiece[];\n /** Authored guides keyed by piece id. Pieces without a guide fall back. */\n pieceGuides?: Record<string, PieceGuide>;\n /** Per-layer visibility toggles. All default to true. */\n show?: {\n bleed?: boolean;\n zones?: boolean;\n boundary?: boolean;\n safeArea?: boolean;\n labels?: boolean;\n };\n /** Optional style overrides. */\n style?: VisualGuideOverlayStyle;\n /** `className` applied to the wrapping SVG element. */\n className?: string;\n}\n\n// ── Defaults ──────────────────────────────────────────────────────────────────\n\nconst DEFAULT_STYLE: Required<\n Omit<VisualGuideOverlayStyle, \"zoneFill\" | \"zoneStroke\">\n> & {\n zoneFill: Record<ZoneShape[\"kind\"], string>;\n zoneStroke: Record<ZoneShape[\"kind\"], string>;\n} = {\n bleedFill: \"#ffffff\",\n bleedOpacity: 0.5,\n // Subtle boundary — the wash already draws the eye to the safe area,\n // so the piece outline is just a quiet frame for context. Consumers\n // can dial it up to a harder blue / thicker stroke via style overrides.\n // Default to no boundary outline — the bleed wash's soft inner edge\n // carries the design-canvas edge on its own. Consumers can set any\n // colour via `style.boundaryStroke` to opt back in.\n boundaryStroke: \"\",\n boundaryStrokeWidth: 1,\n // New default: 25%-opacity white wash over the non-safe area. Apple-y\n // \"fade out the edges\" approach rather than a dashed line, so the safe\n // area reads as the clean canvas rather than a bordered box.\n safeAreaWashFill: \"#ffffff\",\n safeAreaWashOpacity: 0.25,\n // Sentinel: -1 means \"auto\" — the component computes an artboard-\n // proportional radius at render time. A real value overrides.\n safeAreaWashCornerRadius: -1,\n // Legacy dashed safe-area outline — disabled by default now. Set\n // `safeAreaStroke` to a color to re-enable for any consumer that\n // prefers the old look.\n safeAreaStroke: \"\",\n safeAreaStrokeWidth: 1.5,\n safeAreaDashArray: \"6 4\",\n zoneFill: {\n wrap: \"rgba(148, 163, 184, 0.25)\", // slate-400\n binding: \"rgba(234, 88, 12, 0.20)\", // orange-600\n // A die-cut is material *removed* from the product, so the fill reads\n // as a dark \"hole\" rather than a coloured region. 70% black gives\n // strong contrast over any artwork underneath.\n dieCut: \"rgba(0, 0, 0, 0.7)\",\n warning: \"rgba(245, 158, 11, 0.25)\", // amber-500\n custom: \"rgba(100, 100, 100, 0.15)\",\n },\n zoneStroke: {\n wrap: \"#64748b\",\n binding: \"#ea580c\",\n // White outline on die-cut pairs with the black fill to read as a\n // clean perforation. A red outline would compete with the fill.\n dieCut: \"#ffffff\",\n warning: \"#f59e0b\",\n custom: \"#6b7280\",\n },\n labelColor: \"#111827\",\n // Placeholder — replaced at render time with an artboard-proportional\n // default (see `autoLabelFontSize` in the component). Callers can still\n // pin via `style.labelFontSize`.\n labelFontSize: 14,\n labelFontFamily:\n \"ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif\",\n};\n\n// ── Rendering helpers ─────────────────────────────────────────────────────────\n\nconst ANCHOR_TO_SVG: Record<\n NonNullable<GuideLabel[\"anchor\"]>,\n {\n textAnchor: React.SVGProps<SVGTextElement>[\"textAnchor\"];\n dominantBaseline: React.SVGProps<SVGTextElement>[\"dominantBaseline\"];\n }\n> = {\n // SVG `dominant-baseline` has no \"baseline\" keyword; \"alphabetic\" is the\n // bottom/baseline alignment (and React's typed union enforces this).\n tl: { textAnchor: \"start\", dominantBaseline: \"hanging\" },\n tc: { textAnchor: \"middle\", dominantBaseline: \"hanging\" },\n tr: { textAnchor: \"end\", dominantBaseline: \"hanging\" },\n cl: { textAnchor: \"start\", dominantBaseline: \"middle\" },\n c: { textAnchor: \"middle\", dominantBaseline: \"middle\" },\n cr: { textAnchor: \"end\", dominantBaseline: \"middle\" },\n bl: { textAnchor: \"start\", dominantBaseline: \"alphabetic\" },\n bc: { textAnchor: \"middle\", dominantBaseline: \"alphabetic\" },\n br: { textAnchor: \"end\", dominantBaseline: \"alphabetic\" },\n};\n\nfunction renderShape(\n path: SvgPath,\n commonProps: React.SVGProps<SVGElement>,\n): JSX.Element {\n if (path.kind === \"rect\") {\n return (\n <rect\n x={path.x}\n y={path.y}\n width={path.width}\n height={path.height}\n {...(commonProps as React.SVGProps<SVGRectElement>)}\n />\n );\n }\n if (path.kind === \"roundedRect\") {\n return (\n <rect\n x={path.x}\n y={path.y}\n width={path.width}\n height={path.height}\n rx={path.rx}\n ry={path.ry}\n {...(commonProps as React.SVGProps<SVGRectElement>)}\n />\n );\n }\n return (\n <path\n d={path.d}\n {...(commonProps as React.SVGProps<SVGPathElement>)}\n />\n );\n}\n\nfunction resolveBoundary(\n guide: PieceGuide | undefined,\n naturalW: number,\n naturalH: number,\n): SvgPath {\n // Authored boundaries live in the piece's NATURAL coord system (the\n // unrotated frame the layout was authored in). The fallback \"full\n // piece\" rect must therefore also be in natural dims, not the\n // displayed (post-rotation) `piece.width × piece.height`. Otherwise a\n // 90°/270° piece's fallback boundary lands sideways in the rotated\n // local frame. See PieceGuideRenderer.ts for the canvas-side mirror.\n return (\n guide?.boundary ?? {\n kind: \"rect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n }\n );\n}\n\n/**\n * Serialize an SvgPath to its SVG `d` attribute string. Used to build\n * evenodd compound paths (e.g. piece rect minus safe area) for the wash.\n */\nfunction svgPathD(path: SvgPath): string {\n if (path.kind === \"rect\") {\n return `M ${path.x} ${path.y} h ${path.width} v ${path.height} h ${-path.width} Z`;\n }\n if (path.kind === \"roundedRect\") {\n const rx = path.rx ?? path.ry ?? 0;\n const ry = path.ry ?? path.rx ?? 0;\n if (rx <= 0 && ry <= 0) {\n return `M ${path.x} ${path.y} h ${path.width} v ${path.height} h ${-path.width} Z`;\n }\n const { x, y, width: w, height: h } = path;\n return [\n `M ${x + rx} ${y}`,\n `h ${w - 2 * rx}`,\n `a ${rx} ${ry} 0 0 1 ${rx} ${ry}`,\n `v ${h - 2 * ry}`,\n `a ${rx} ${ry} 0 0 1 ${-rx} ${ry}`,\n `h ${-(w - 2 * rx)}`,\n `a ${rx} ${ry} 0 0 1 ${-rx} ${-ry}`,\n `v ${-(h - 2 * ry)}`,\n `a ${rx} ${ry} 0 0 1 ${rx} ${-ry}`,\n \"Z\",\n ].join(\" \");\n }\n return path.d;\n}\n\nfunction resolveSafeArea(\n guide: PieceGuide | undefined,\n piece: OverlayPiece,\n naturalW: number,\n naturalH: number,\n): SvgPath | null {\n if (guide?.safeArea) return guide.safeArea;\n if (piece.safeAreaInsetPx && piece.safeAreaInsetPx > 0) {\n const inset = piece.safeAreaInsetPx;\n return {\n kind: \"rect\",\n x: inset,\n y: inset,\n width: Math.max(0, naturalW - inset * 2),\n height: Math.max(0, naturalH - inset * 2),\n };\n }\n return null;\n}\n\n// ── Component ─────────────────────────────────────────────────────────────────\n\nexport function VisualGuideOverlay({\n artboardWidth,\n artboardHeight,\n canvasPadding = 0,\n pieces,\n pieceGuides,\n show,\n style,\n className,\n}: VisualGuideOverlayProps): JSX.Element {\n const s = useMemo(() => {\n // Artboard-proportional default so labels stay legible at typical\n // viewport scales. Bumps with artboard size but clamped to a sane\n // floor. Callers can still override via `style.labelFontSize` to pin\n // an exact viewBox-unit value. 3% of the shorter axis reads clearly\n // at the zoom levels Snowcone's consumer editor typically renders at.\n const autoLabelFontSize = Math.max(\n 16,\n Math.round(Math.min(artboardWidth, artboardHeight) * 0.03),\n );\n const merged = {\n ...DEFAULT_STYLE,\n ...(style ?? {}),\n zoneFill: { ...DEFAULT_STYLE.zoneFill, ...(style?.zoneFill ?? {}) },\n zoneStroke: { ...DEFAULT_STYLE.zoneStroke, ...(style?.zoneStroke ?? {}) },\n };\n if (style?.labelFontSize === undefined) {\n merged.labelFontSize = autoLabelFontSize;\n }\n return merged;\n }, [style, artboardWidth, artboardHeight]);\n\n const visibility = {\n bleed: show?.bleed ?? true,\n zones: show?.zones ?? true,\n boundary: show?.boundary ?? true,\n safeArea: show?.safeArea ?? true,\n labels: show?.labels ?? true,\n };\n\n // Expand the viewBox to include SnowconeCanvas's padding on each side,\n // and translate all content by that padding so artboard-local coords\n // paint at the actual artboard position inside the padded canvas.\n // Without this, the SVG's painted rect matches the full padded canvas\n // (auto-centered by preserveAspectRatio) and drifts away from where\n // the canvas element paints the artboard — typically a few percent of\n // the smaller axis.\n const viewBoxWidth = artboardWidth + canvasPadding * 2;\n const viewBoxHeight = artboardHeight + canvasPadding * 2;\n\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}\n preserveAspectRatio=\"xMidYMid meet\"\n className={className}\n // Overlay mustn't swallow canvas interaction; individual elements\n // can opt back in with pointer-events if we later add hover/labels.\n style={{ pointerEvents: \"none\", width: \"100%\", height: \"100%\" }}\n >\n <g transform={`translate(${canvasPadding} ${canvasPadding})`}>\n {pieces.map((piece) => {\n const guide = pieceGuides?.[piece.id];\n const zones = guide?.zones ?? [];\n const labels = guide?.labels ?? [];\n\n // `piece.rotation` swaps the piece's displayed dim relative to\n // its natural (bbox) dim. Boundary / safeArea / wash etc. are\n // authored against the NATURAL coord system, so we need a\n // transform that maps natural (0, 0)→displayed corner exactly,\n // then draw at natural dims. The earlier `rotate(angle, cx, cy)`\n // around the *displayed* center offsets the rotated rect by\n // ((Nw−Dw)/2, (Nh−Dh)/2) — visible as a halo on rotated pieces.\n // Mirrors `PieceGuideRenderer.ts`'s canvas-side fix.\n //\n // SVG composes left-to-right; right-most transform applies\n // first. So for rotation = 90° CW the inner coord is rotated\n // first, then translated by (W, 0):\n // 90°: translate(piece.x piece.y) translate(W, 0) rotate(90)\n // 180°: translate(piece.x piece.y) translate(W, H) rotate(180)\n // 270°: translate(piece.x piece.y) translate(0, H) rotate(270)\n const rotation = piece.rotation ?? 0;\n const isOrtho = rotation === 90 || rotation === 270;\n const naturalW = isOrtho ? piece.height : piece.width;\n const naturalH = isOrtho ? piece.width : piece.height;\n const boundary = resolveBoundary(guide, naturalW, naturalH);\n const safeArea = resolveSafeArea(guide, piece, naturalW, naturalH);\n const originXform = `translate(${piece.x} ${piece.y})`;\n let rotationXform = \"\";\n if (rotation === 90) {\n rotationXform = `translate(${piece.width} 0) rotate(90)`;\n } else if (rotation === 180) {\n rotationXform = `translate(${piece.width} ${piece.height}) rotate(180)`;\n } else if (rotation === 270) {\n rotationXform = `translate(0 ${piece.height}) rotate(270)`;\n }\n const transform = rotationXform\n ? `${originXform} ${rotationXform}`\n : originXform;\n\n // Safe-area wash: fills the piece minus the safe area with a\n // subtle translucent color. This is the primary safe-area\n // indicator — replaces the old dashed outline for an Apple-y\n // \"fade out the edges\" feel. Only rendered when the safeArea is\n // rect/roundedRect (path-kind falls through until we parse SVG\n // path bounds in Phase 4).\n //\n // Wash outer uses a rounded rect by default so the fade hugs the\n // product's visual corners (phone cases, rounded cards) instead\n // of boxing sharp 90° corners. Consumers can set\n // `style.safeAreaWashCornerRadius = 0` for hard corners.\n const washRadius =\n s.safeAreaWashCornerRadius < 0\n ? Math.round(Math.min(naturalW, naturalH) * 0.02)\n : s.safeAreaWashCornerRadius;\n // Wash outer: prefer the authored boundary (it's the product's\n // actual design canvas — a rounded-rect phone case outline, a\n // book cover rectangle, etc.). Fall back to the piece rect only\n // when no boundary is authored. Apply the corner radius to a\n // plain-rect boundary at render time so the fade hugs the\n // product's visual curves even without explicit author geometry.\n const boundaryForWash: SvgPath | null =\n guide?.boundary &&\n (guide.boundary.kind === \"rect\" || guide.boundary.kind === \"roundedRect\")\n ? guide.boundary\n : null;\n const washOuter: SvgPath = boundaryForWash\n ? boundaryForWash.kind === \"rect\" && washRadius > 0\n ? {\n kind: \"roundedRect\",\n x: boundaryForWash.x,\n y: boundaryForWash.y,\n width: boundaryForWash.width,\n height: boundaryForWash.height,\n rx: washRadius,\n ry: washRadius,\n }\n : boundaryForWash\n : washRadius > 0\n ? {\n kind: \"roundedRect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n rx: washRadius,\n ry: washRadius,\n }\n : {\n kind: \"rect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n };\n // Bleed ring = piece rect ∖ boundary (the area OUTSIDE the\n // design canvas that physically wraps or trims). The inner\n // edge of the ring matches the boundary shape exactly, which\n // is the \"design canvas edge\" — where the sharp art stops.\n // No boundary stroke is drawn; the fade from bleed wash to\n // sharp art reads as the design-canvas edge on its own.\n const bleedFilterId = `bleed-blur-${piece.id}`;\n // Drawing happens in the natural coord system (post-rotation\n // transform), so the bleed-ring outer rect is sized at natural\n // dims. Same invariant as `washOuter` above.\n const pieceRect: SvgPath = {\n kind: \"rect\",\n x: 0,\n y: 0,\n width: naturalW,\n height: naturalH,\n };\n const canRenderBleed =\n washOuter.kind === \"rect\" || washOuter.kind === \"roundedRect\";\n\n return (\n <g key={piece.id} transform={transform}>\n {/* Bleed ring: (pieceRect ∖ boundary). Fills the wrap/trim\n zone outside the design canvas. Flat 55% bg-tertiary\n fill, softened with a big Gaussian blur so the inner\n edge fades smoothly out of the sharp design canvas —\n Apple vignette, no hard lines, no wash stroke. Clipped\n to the piece rect so the blur can't leak outside. */}\n {visibility.safeArea && canRenderBleed && (\n <>\n <defs>\n <filter\n id={bleedFilterId}\n x=\"-20%\"\n y=\"-20%\"\n width=\"140%\"\n height=\"140%\"\n >\n <feGaussianBlur\n in=\"SourceGraphic\"\n stdDeviation={\n // Scales with piece size so the fade feels\n // consistent across phones, notebook covers,\n // and tiny artboards alike. `Math.min` is\n // commutative, so the swap natural↔displayed\n // dim doesn't change the value here, but we\n // use natural dims for consistency with the\n // other piece-local geometry.\n Math.max(\n 12,\n Math.round(Math.min(naturalW, naturalH) * 0.025),\n )\n }\n />\n </filter>\n <clipPath id={`piece-clip-${piece.id}`}>\n <rect\n x={0}\n y={0}\n width={naturalW}\n height={naturalH}\n />\n </clipPath>\n </defs>\n <g\n clipPath={`url(#piece-clip-${piece.id})`}\n filter={`url(#${bleedFilterId})`}\n >\n <path\n d={`${svgPathD(pieceRect)} ${svgPathD(washOuter)}`}\n style={{\n // Honor `style.bleedFill` / `style.bleedOpacity`\n // overrides — previously hardcoded, which silently\n // dropped ADR-0054 Phase 5 `pieceGuidesStyle` edits\n // in the Loom authoring preview.\n fill: s.bleedFill || \"var(--color-bg-tertiary, #333)\",\n }}\n fillOpacity={s.bleedOpacity ?? 0.55}\n fillRule=\"evenodd\"\n />\n </g>\n </>\n )}\n\n {/* Non-die-cut zones render as a single filled+stroked shape.\n Die-cuts get a different treatment (blur + alpha) below\n so they share visual language with the canvas's own\n \"outside the artboard\" dim treatment. */}\n {visibility.zones &&\n zones\n .filter((z) => z.kind !== \"dieCut\")\n .map((zone, i) => (\n <g key={`zone-${i}`}>\n {renderShape(zone.path, {\n fill: s.zoneFill[zone.kind],\n stroke: s.zoneStroke[zone.kind],\n strokeWidth: 1.5,\n strokeDasharray: zone.kind === \"wrap\" ? \"4 3\" : undefined,\n vectorEffect: \"non-scaling-stroke\",\n } as unknown as React.SVGProps<SVGElement>)}\n </g>\n ))}\n\n {/* Die-cut zones: same visual language as elements that\n overflow the artboard in CanvasRenderer.ts (4px blur +\n ~30% white tint). Implemented via <foreignObject> so we\n can use CSS `backdrop-filter` to blur the canvas pixels\n beneath in place — no coordinate translation needed,\n since the foreignObject inherits the SVG viewBox\n coordinate system. Matches CanvasRenderer.ts:263-264. */}\n {visibility.zones &&\n zones\n .filter((z) => z.kind === \"dieCut\")\n .map((zone, i) => {\n const p = zone.path;\n if (p.kind !== \"rect\" && p.kind !== \"roundedRect\") {\n return null;\n }\n const rx =\n p.kind === \"roundedRect\" ? (p.rx ?? p.ry ?? 0) : 0;\n const ry =\n p.kind === \"roundedRect\" ? (p.ry ?? p.rx ?? 0) : 0;\n return (\n <foreignObject\n key={`diecut-${i}`}\n x={p.x}\n y={p.y}\n width={p.width}\n height={p.height}\n >\n <div\n // xmlns is required inside foreignObject so the\n // HTML child is parsed as HTML, not SVG. React's\n // HTMLDivElement prop types don't declare `xmlns`,\n // so spread it as a narrowly-typed extra attribute\n // rather than weaken the whole element's typing.\n {...({ xmlns: \"http://www.w3.org/1999/xhtml\" } as {\n xmlns: string;\n })}\n style={{\n width: \"100%\",\n height: \"100%\",\n borderRadius: `${rx}px / ${ry}px`,\n backdropFilter: \"blur(4px)\",\n WebkitBackdropFilter: \"blur(4px)\",\n // Match the canvas's own \"outside-artboard\"\n // tint (CanvasRenderer.ts uses globalAlpha=0.3\n // against `--color-bg-tertiary`). We stack the\n // bg-tertiary colour at 70% alpha on top of the\n // blurred artwork to achieve the same visual\n // blend. color-mix lets us stay theme-aware in\n // both light and dark modes.\n background:\n \"color-mix(in srgb, var(--color-bg-tertiary, #333) 70%, transparent)\",\n }}\n />\n </foreignObject>\n );\n })}\n\n {/* Boundary outline — only rendered when `boundaryStroke`\n is explicitly set by a consumer. Default is no stroke;\n the bleed wash's soft inner edge carries the\n design-canvas edge on its own. */}\n {visibility.boundary &&\n s.boundaryStroke &&\n renderShape(boundary, {\n fill: \"none\",\n stroke: s.boundaryStroke,\n strokeWidth: s.boundaryStrokeWidth,\n vectorEffect: \"non-scaling-stroke\",\n } as unknown as React.SVGProps<SVGElement>)}\n\n {/* Optional dashed safe-area outline (opt-in: empty by\n default so the wash alone carries the signal; consumers\n can set `style.safeAreaStroke` to a color to restore). */}\n {visibility.safeArea &&\n safeArea &&\n s.safeAreaStroke &&\n renderShape(safeArea, {\n fill: \"none\",\n stroke: s.safeAreaStroke,\n strokeWidth: s.safeAreaStrokeWidth,\n strokeDasharray: s.safeAreaDashArray,\n vectorEffect: \"non-scaling-stroke\",\n } as unknown as React.SVGProps<SVGElement>)}\n\n {/* Labels — font-size in CSS px via non-scaling approach.\n We draw at the piece-local coords but inside the viewBox\n the text honors its own font-size unchanged (fonts don't\n scale with SVG viewBox), so we bake the intended visual\n font size directly. */}\n {visibility.labels &&\n labels.map((label, i) => {\n const a = ANCHOR_TO_SVG[label.anchor ?? \"c\"];\n return (\n <text\n key={`label-${i}`}\n x={label.x}\n y={label.y}\n textAnchor={a.textAnchor}\n dominantBaseline={a.dominantBaseline}\n fontSize={s.labelFontSize}\n fontFamily={s.labelFontFamily}\n fill={s.labelColor}\n style={{ paintOrder: \"stroke\" }}\n stroke=\"#ffffff\"\n // Halo width tracks font size so labels stay legible\n // over any background at any zoom.\n strokeWidth={Math.max(2, s.labelFontSize * 0.25)}\n strokeLinejoin=\"round\"\n >\n {label.text}\n </text>\n );\n })}\n </g>\n );\n })}\n </g>\n </svg>\n );\n}\n\n","/**\n * @snowcone-app/canvas/advanced — Advanced API (Tier 2)\n *\n * May add new exports in minor versions. Breaking changes with migration\n * guide in minor versions. For developers building custom editor layouts\n * and integrations.\n *\n * @packageDocumentation\n */\n\n// Register all icons on module load\nimport { ensureIconsRegistered } from '../icons/registry.js';\nensureIconsRegistered();\n\n// =============================================================================\n// Individual Panel Components\n// =============================================================================\n\nexport { Canvas } from '../components/embed/Canvas.js';\nexport type { CanvasProps } from '../components/embed/Canvas.js';\n\nexport { LayersPanel } from '../components/embed/LayersPanel.js';\nexport type { LayersPanelProps } from '../components/embed/LayersPanel.js';\n\nexport { EffectsPanel } from '../components/embed/EffectsPanel.js';\nexport type { EffectsPanelProps } from '../components/embed/EffectsPanel.js';\n\nexport { ExportPanel } from '../components/embed/ExportPanel.js';\nexport type { ExportPanelProps } from '../components/embed/ExportPanel.js';\n\nexport { ImagePanel } from '../components/embed/ImagePanel.js';\nexport type { ImagePanelProps } from '../components/embed/ImagePanel.js';\n\nexport { GlyphPanel } from '../components/embed/GlyphPanel.js';\nexport type { GlyphPanelProps } from '../components/embed/GlyphPanel.js';\n\nexport { ArtboardTabs } from '../components/embed/ArtboardTabs.js';\nexport type { ArtboardTabsProps } from '../components/embed/ArtboardTabs.js';\n\nexport { ContextualToolbars } from '../components/ContextualToolbars.js';\nexport type { ContextualToolbarsProps } from '../components/ContextualToolbars.js';\n\nexport { default as ShapeTypeDrawer } from '../components/ShapeTypeDrawer.js';\n\nexport { MenuButton } from '../components/embed/MenuButton.js';\nexport type { MenuButtonProps } from '../components/embed/MenuButton.js';\n\nexport { ZoomControls } from '../components/embed/ZoomControls.js';\nexport type { ZoomControlsProps } from '../components/embed/ZoomControls.js';\n\nexport { CropPanel } from '../components/CropPanel.js';\nexport type { CropPanelProps } from '../components/CropPanel.js';\n\n// =============================================================================\n// Providers (for custom composition)\n// =============================================================================\n\nexport { EditorProvider } from '../contexts/EditorContext.js';\nexport type { EditorElement, PanOffset, ExpandedPanelType } from '../contexts/EditorContext.js';\n\nexport { ThemeProvider, useTheme } from '../contexts/ThemeContext.js';\nexport type { Theme } from '../contexts/ThemeContext.js';\n\nexport { KitProvider, useKit, useCapabilities } from '../contexts/KitContext.js';\nexport type { KitContextValue, KitProviderProps } from '../contexts/KitContext.js';\n\n// =============================================================================\n// Sub-Context Hooks\n// =============================================================================\n\nexport { useViewportContext } from '../contexts/ViewportContext.js';\nexport type { ViewportContextValue, ViewportProviderProps } from '../contexts/ViewportContext.js';\n\nexport { useSelectionContext } from '../contexts/SelectionContext.js';\nexport type { SelectionContextValue, SelectionProviderProps } from '../contexts/SelectionContext.js';\n\nexport { useHistoryContext } from '../contexts/HistoryContext.js';\nexport type { HistoryContextValue, HistoryProviderProps } from '../contexts/HistoryContext.js';\n\nexport { useToolStateContext } from '../contexts/ToolStateContext.js';\nexport type { ToolStateContextValue, ToolStateProviderProps } from '../contexts/ToolStateContext.js';\n\nexport { useElementsContext } from '../contexts/ElementsContext.js';\nexport type { ElementsContextValue, ElementsProviderProps } from '../contexts/ElementsContext.js';\n\nexport { useCommandContext } from '../contexts/CommandContext.js';\nexport type { CommandContextValue, CommandProviderProps } from '../contexts/CommandContext.js';\n\n// =============================================================================\n// Element Types (classes for instanceof checks)\n// =============================================================================\n\nexport { TextElement } from '../core/TextElement.js';\nexport { ImageElement } from '../core/ImageElement.js';\nexport { GroupElement } from '../core/GroupElement.js';\nexport { ShapeElement } from '../core/ShapeElement.js';\nexport { PathElement } from '../core/PathElement.js';\nexport { BaseElement } from '../core/BaseElement.js';\nexport { ArtboardElement } from '../core/ArtboardElement.js';\n\n// Config type guards\nexport {\n isTextElementConfig,\n isImageElementConfig,\n isCustomElementConfig,\n isCircleElementConfig,\n isGroupElementConfig,\n isShapeElementConfig,\n isPathElementConfig,\n} from '../types/index.js';\n\n// Instance type guards\nexport {\n isTextElement,\n isImageElement,\n isGroupElement,\n isShapeElement,\n isPathElement,\n} from '../types/guards.js';\n\n// Element config types\nexport type {\n BaseElementConfig,\n BaseTextElementConfig,\n TextOnlyElementConfig,\n CustomElementConfig,\n ImageElementConfig,\n GroupElementConfig,\n ShapeElementConfig,\n PathElementConfig,\n CircleElementConfig,\n ArchElementConfig,\n WaveElementConfig,\n FlagElementConfig,\n LeanElementConfig,\n AscendElementConfig,\n} from '../types/index.js';\n\n// =============================================================================\n// Advanced Hooks\n// =============================================================================\n\nexport { useProjectLoader } from '../hooks/useProjectLoader.js';\nexport type { ProjectTemplate, ProjectMetadata, UseProjectLoaderReturn } from '../hooks/useProjectLoader.js';\n\nexport { useTextToolbar } from '../hooks/useTextToolbar.js';\nexport type { UseTextToolbarOptions, UseTextToolbarReturn } from '../hooks/useTextToolbar.js';\n\nexport { useBreakpoint } from '../hooks/useBreakpoint.js';\nexport type { BreakpointConfig, Breakpoint, UseBreakpointReturn } from '../hooks/useBreakpoint.js';\n\nexport { usePerformance } from '../hooks/usePerformance.js';\nexport type { PerformanceMetrics, UsePerformanceReturn } from '../hooks/usePerformance.js';\n\nexport { useElementById } from '../hooks/useElementById.js';\n\nexport { useLayerPreview } from '../hooks/useLayerPreview.js';\nexport type { UseLayerPreviewOptions, UseLayerPreviewReturn } from '../hooks/useLayerPreview.js';\n\nexport { useLayerDragDrop } from '../hooks/useLayerDragDrop.js';\nexport type { UseLayerDragDropOptions, UseLayerDragDropReturn } from '../hooks/useLayerDragDrop.js';\n\nexport { useLayerSelection } from '../hooks/useLayerSelection.js';\nexport type { UseLayerSelectionOptions, UseLayerSelectionReturn } from '../hooks/useLayerSelection.js';\n\n// =============================================================================\n// UI Primitives\n// =============================================================================\n\nexport * from '../components/embed/primitives/index.js';\nexport * from '../components/embed/ui/index.js';\n\n// =============================================================================\n// Text Toolbar\n// =============================================================================\n\nexport { TextToolbar } from '../components/TextToolbar.js';\nexport type { TextToolbarProps } from '../components/TextToolbar.js';\nexport * from '../components/text-toolbar/index.js';\n\n// =============================================================================\n// Loading States\n// =============================================================================\n\nexport { CanvasSkeleton, LayersPanelSkeleton, ToolbarSkeleton, Spinner } from '../components/embed/LoadingStates.js';\nexport type { CanvasSkeletonProps, LayersPanelSkeletonProps, ToolbarSkeletonProps } from '../components/embed/LoadingStates.js';\n\n// =============================================================================\n// Auto Export Manager\n// =============================================================================\n\nexport { AutoExportManager, DEFAULT_AUTO_EXPORT_CONFIG } from '../services/AutoExportManager.js';\nexport type { AutoExportConfig, AutoExportStats } from '../services/AutoExportManager.js';\n\n// =============================================================================\n// Selection Preservation\n// =============================================================================\n\nexport {\n shouldPreserveSelection,\n preserveSelectionProps,\n PRESERVE_SELECTION_ATTR,\n} from '../utils/selectionPreservation.js';\n\n// =============================================================================\n// Advanced Types\n// =============================================================================\n\nexport type {\n AnyTransformData,\n CustomTransformData,\n CircleTransformData,\n ArchTransformData,\n WaveTransformData,\n FlagTransformData,\n LeanTransformData,\n AscendTransformData,\n ImageTransformData,\n GroupTransformData,\n ShapeTransformData,\n PathTransformData,\n StrokeConfig,\n MaskType,\n MaskDefinition,\n KnockoutScope,\n KnockoutConfig,\n DistressStyle,\n DistressEffect,\n CharacterStyle,\n TextSpan,\n GlyphOverride,\n GlyphAlternate,\n OpenTypeFeatures,\n ShapeType,\n PathPointType,\n PathPoint,\n InteractionMode,\n SelectionState,\n ResizeAnchor,\n RenderingContext,\n} from '../types/index.js';\n\nexport { RichText } from '../types/index.js';\n\n// Transform data type guards\nexport {\n isCustomTransform,\n isCircleTransform,\n isArchTransform,\n isWaveTransform,\n isFlagTransform,\n isImageTransform,\n isGroupTransform,\n isShapeTransform,\n isPathTransform,\n hasStroke,\n hasMasks,\n isKnockout,\n hasDistressEffect,\n} from '../types/index.js';\n\n// Kit registry\nexport { KIT_PRESETS } from '../kits/registry.js';\n\n// =============================================================================\n// Section Registry\n// =============================================================================\n\nexport {\n registerSection,\n getSection,\n getSectionIds,\n getAllSections,\n unregisterSection,\n registerBuiltinSections,\n registerBuiltinSectionsSync,\n} from '../kits/sections.js';\nexport type { SectionConfig, SectionComponent } from '../kits/sections.js';\n\n// =============================================================================\n// Kit Serialization\n// =============================================================================\n\nexport { serializeKit, loadKitFromJSON } from '../kits/serialization.js';\nexport type { KitJSON } from '../kits/serialization.js';\n\n// =============================================================================\n// Plugin System: Custom Element Types\n// =============================================================================\n\nexport {\n registerElementType,\n unregisterElementType,\n getCustomElementTypes,\n isRegisteredElementType,\n} from '../plugins/ElementTypePlugin.js';\nexport type { ElementTypeRegistration } from '../plugins/ElementTypePlugin.js';\n\n// =============================================================================\n// Event Bus\n// =============================================================================\n\nexport { CanvasEventBus, canvasEventBus } from '../core/EventBus.js';\nexport type { CanvasEventMap, CanvasEventHandler } from '../core/EventBus.js';\nexport { useCanvasEvents } from '../hooks/useCanvasEvents.js';\n\n// =============================================================================\n// ADR-0054: Visual Guide Overlay\n// =============================================================================\n\nexport { VisualGuideOverlay } from '../components/VisualGuideOverlay.js';\nexport type {\n VisualGuideOverlayProps,\n VisualGuideOverlayStyle,\n OverlayPiece,\n PieceGuide,\n SvgPath,\n ZoneShape,\n GuideLabel,\n} from '../components/VisualGuideOverlay.js';\n\n/**\n * Canvas-native piece-guide rendering (ADR-0054). Prefer the\n * `pieceGuides` prop on `SnowconeCanvas` over mounting a\n * `VisualGuideOverlay` — the canvas-native path draws inside the\n * render loop and avoids the coordinate-system drift of the DOM\n * overlay.\n */\nexport { renderPieceGuides } from '../rendering/PieceGuideRenderer.js';\nexport type {\n PieceGuideRenderParams,\n PieceGuideRendererPiece,\n PieceGuideRendererStyle,\n PieceGuideVisibility,\n} from '../rendering/PieceGuideRenderer.js';\nexport type { PieceGuidesConfig } from '../components/embed/SnowconeCanvas.js';\n"],"names":["Panel","title","icon","children","enableable","enabled","onEnabledChange","collapsible","expanded","onExpandChange","className","showContent","showExpandButton","handleToggle","handleExpandToggle","jsxs","jsx","ControlGroup","label","labelSuffix","inline","ButtonGroup","options","value","onChange","fullWidth","option","isActive","Toggle","checked","disabled","handleChange","e","Switch","SecondaryToolbar","isOpen","onToggle","trigger","Dropdown","Tooltip","TooltipTrigger","Button","Icon","TooltipContent","serializeKit","kit","json","loadKitFromJSON","overrides","base","resolveKit","extendKit","createKit","validation","validateKit","warning","logger","createLogger","useProjectLoader","handleLoadWorkspace","useEditor","isLoading","setIsLoading","useState","loadError","setLoadError","currentProject","setCurrentProject","projectMetadata","setProjectMetadata","loadFromJSON","useCallback","document","jsonString","blob","file","result","ImportManager","totalElements","sum","ab","_a","error","loadFromFile","text","loadTemplate","template","artboard","index","DEFAULT_BREAKPOINTS","getCurrentBreakpoint","width","config","useBreakpoint","breakpointConfig","setWidth","useEffect","handleResize","breakpoint","useMemo","isXs","isSm","isMd","isLg","isXl","isXxl","breakpointOrder","bp","currentIndex","targetIndex","DEFAULT_METRICS","usePerformance","metrics","setMetrics","isProfiling","setIsProfiling","frameTimesRef","useRef","renderTimesRef","exportTimesRef","lastFrameTimeRef","rafIdRef","calculateFPS","frameTimes","time","calculateAverage","values","val","getMemoryUsage","updateMetrics","newMetrics","measureFrame","now","frameTime","startProfiling","stopProfiling","clearMetrics","getReport","useElementById","id","getElementById","useLayerDragDrop","onReorder","onGroupReorder","onDropIntoGroup","onDropIntoGroupAtPosition","findElement","findParentGroup","draggedId","setDraggedId","dragOverId","setDragOverId","dropPosition","setDropPosition","handleDragStart","elementId","handleDragOver","rect","relativeY","height","isGroup","GroupElement","position","resetDragState","handleDrop","targetId","draggedParent","targetParent","arrayPosition","useLayerSelection","selectedId","multiSelection","onSelectionChange","onMultiSelectionChange","isSelected","handleClick","isInMultiSelection","isCurrentlySelected","newSelection","FontSizeDropdown","memo","fontSizes","handleSelect","size","Popover","PopoverTrigger","PopoverContent","FontSizeGroup","toolbar","fontSize","handleFontSizeIncrement","handleFontSizeChange","openDropdown","setOpenDropdown","clickProtection","el","handleClickOutside","event","target","FONT_SIZES","_customElementTypes","registerElementType","registration","registerTransform","unregisterElementType","type","unregisterTransform","getCustomElementTypes","isRegisteredElementType","getTransformById","CanvasEventBus","handler","handlers","wrapper","data","unsubscribe","err","canvasEventBus","useCanvasEvents","DEFAULT_STYLE","ANCHOR_TO_SVG","renderShape","path","commonProps","resolveBoundary","guide","naturalW","naturalH","svgPathD","rx","ry","x","y","w","h","resolveSafeArea","piece","inset","VisualGuideOverlay","artboardWidth","artboardHeight","canvasPadding","pieces","pieceGuides","show","style","s","autoLabelFontSize","merged","visibility","viewBoxWidth","viewBoxHeight","zones","labels","rotation","isOrtho","boundary","safeArea","originXform","rotationXform","transform","washRadius","boundaryForWash","washOuter","bleedFilterId","pieceRect","canRenderBleed","Fragment","z","zone","i","p","a","ensureIconsRegistered"],"mappings":"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"}
|