@snowcone-app/canvas 0.1.4 → 0.1.6

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/README.md CHANGED
@@ -1,356 +1,131 @@
1
- # Custom Canvas Text Transformation System
1
+ # @snowcone-app/canvas
2
2
 
3
- A professional text transformation and image manipulation system for creating apparel/merchandise designs using HTML Canvas API. Features a clean, maintainable, and extensible architecture.
3
+ **Embeddable design editor for print-on-demand and product customization.**
4
4
 
5
- ## Key Features
5
+ `<SnowconeCanvas />` is a self-contained React component that lets your shoppers
6
+ compose the artwork that goes onto a product — text, images, transforms, and
7
+ effects across one or more print areas. It's the same editor that powers Edit and
8
+ Remix on [snowcone.app](https://snowcone.app). Drop it in, get the design state and
9
+ print-ready exports back out.
6
10
 
7
- - **Direct Canvas Control** - Precise rendering with full control over transformations
8
- - ✅ **Multiple Transform Types** - 8+ text effects (straight, circle, arch, wave, etc.)
9
- - ✅ **Advanced Layer Effects** - Strokes, masks, distress, knockout compositing
10
- - ✅ **Multi-Artboard Workflow** - Manage multiple designs in one session
11
- - ✅ **Professional Export** - Transparent PNG export with Web Worker performance
12
- - ✅ **Maintainable** - Clear separation of concerns, modular architecture
13
- - ✅ **Extensible** - Adding new transforms and effects is straightforward
11
+ 📖 **Full documentation: [developers.snowcone.app/canvas](https://developers.snowcone.app/canvas)**
14
12
 
15
- ## Development Workflow
16
-
17
- This repo uses a **hybrid worktree workflow** for parallel feature development:
18
-
19
- ### Hybrid Approach
20
- - **Generic directory names**: `worktree-1`, `worktree-2`, `worktree-3`, `worktree-4`
21
- - **Descriptive git branches**: `feature/shadows`, `bug/export-crash`, etc.
22
- - **Auto-sync on commit**: Every commit automatically rebases on main to prevent drift
23
- - **Fast context switching**: Reuse the same worktree for multiple features
24
-
25
- ### Quick Start
13
+ ## Installation
26
14
 
27
15
  ```bash
28
- # 1. Initial setup (once) - creates 4 worktrees
29
- /worktree-setup 4
30
-
31
- # 2. Navigate to any worktree and start a feature
32
- cd ../snowcone-canvas-worktree-1
33
- /feature-start shadows
34
-
35
- # 3. Work and commit (auto-syncs with main after every commit!)
36
- /commit Add shadow rendering to text elements
37
-
38
- # 4. Merge to main when stable
39
- /feature-merge
40
-
41
- # 5. Start next feature (same worktree, new branch)
42
- /feature-start export-formats
16
+ npm install @snowcone-app/canvas
17
+ # or: pnpm add @snowcone-app/canvas / yarn add @snowcone-app/canvas
43
18
  ```
44
19
 
45
- ### Available Commands
46
-
47
- #### Core Workflow Commands
48
-
49
- | Command | Description |
50
- |---------|-------------|
51
- | `/worktree-setup <count>` | Create N generic worktrees for parallel work |
52
- | `/feature-start <name>` | Start new feature/bug branch in current worktree |
53
- | `/commit <message>` | Commit all changes and auto-sync with main |
54
- | `/feature-merge` | Merge current feature to main and push |
55
- | `/feature-sync` | Manually sync with main (rarely needed) |
56
- | `/worktree-list` | List all worktrees with branch mapping |
57
-
58
- #### Additional Worktree Commands
59
-
60
- | Command | Description |
61
- |---------|-------------|
62
- | `/worktree-create <feature-name>` | Create dedicated worktree for a feature (alt. to reusing) |
63
- | `/worktree-goto <feature-name>` | Get the path to a worktree directory |
64
- | `/worktree-remove <feature-name>` | Remove a specific worktree and optionally delete branch |
65
- | `/worktree-cleanup` | Clean up all worktrees for merged branches |
66
-
67
- ### Key Benefits
68
-
69
- - ✅ **Merge early, merge often** - Auto-sync on every commit prevents conflicts
70
- - ✅ **Parallel development** - 4 worktrees = 4 features in progress
71
- - ✅ **Fast switching** - Reuse worktrees instead of creating new ones
72
- - ✅ **Clean git history** - Descriptive branch names, generic directories
73
- - ✅ **Conflict prevention** - Handle conflicts immediately, not at merge time
74
-
75
- ## Architecture
76
-
77
- ```
78
- custom-canvas/
79
- ├── src/
80
- │ ├── core/
81
- │ │ ├── TextShape.js - Base class for all text shapes
82
- │ │ ├── TransformHandles.js - Resize & rotation handle system
83
- │ │ └── GeometryUtils.js - Transform math (rotation matrices, etc.)
84
- │ │
85
- │ ├── transforms/
86
- │ │ ├── CustomTransform.js - ✅ Straight text
87
- │ │ ├── CircleTransform.js - ✅ Circular text path
88
- │ │ ├── ArchTransform.js - ✅ Curved arch text
89
- │ │ ├── WaveTransform.js - 🚧 TODO
90
- │ │ ├── RiseTransform.js - 🚧 TODO
91
- │ │ ├── FlagTransform.js - 🚧 TODO
92
- │ │ ├── AngleTransform.js - 🚧 TODO
93
- │ │ └── DistortTransform.js - 🚧 TODO
94
- │ │
95
- │ ├── components/
96
- │ │ └── CanvasEditor.jsx - Main canvas component
97
- │ │
98
- │ ├── App.jsx - Demo app with transform picker
99
- │ └── main.jsx - Entry point
100
-
101
- └── DESIGN.md - Detailed architecture documentation
102
- ```
103
-
104
- ## Core Design Principles
105
-
106
- ### 1. Fixed-Corner Resize
107
-
108
- When dragging a corner handle, the **diagonally opposite corner stays fixed** in world space:
109
-
110
- - Drag top-left → bottom-right stays put
111
- - Drag top-right → bottom-left stays put
112
- - Works correctly even when rotated
113
-
114
- **Implementation:** `GeometryUtils.js:calculateFixedCornerPosition()`
115
-
116
- - Uses rotation matrix math to keep opposite corner stationary
117
- - Transform pipeline: local coords → rotate → translate to world coords
118
-
119
- ### 2. Rotation Handle Position
120
-
121
- - **Distance**: 50px below the bottom edge (world coordinates)
122
- - **Alignment**: Centered horizontally on bounding box
123
- - **Visual consistency**: Distance compensated for scale
124
-
125
- **Implementation:** `GeometryUtils.js:calculateRotationHandlePosition()`
126
-
127
- ### 3. Uniform Scaling
128
-
129
- - Corner handles apply uniform scale (no skewing)
130
- - Side handles (only on straight text) change width only
131
- - Scale immediately baked into dimensions (no accumulated transforms)
132
-
133
- ## Transform Types
134
-
135
- ### Implemented ✅
136
-
137
- 1. **CustomTransform** (`CustomTransform.js`)
138
-
139
- - Straight text in a rectangular container
140
- - Supports both corner handles (uniform scale) and side handles (width only)
141
- - Word wrapping
142
-
143
- 2. **CircleTransform** (`CircleTransform.js`)
144
-
145
- - Text follows a circular path
146
- - Characters positioned along the circle arc
147
- - Centered at top of circle
148
- - Ported from existing `EditableTextPath.jsx` circle mode
149
-
150
- 3. **ArchTransform** (`ArchTransform.js`)
151
- - Text curves upward in an arc
152
- - Parabolic curve shape
153
- - Uniform scaling
154
-
155
- ### To Be Implemented 🚧
156
-
157
- 4. **WaveTransform** - Sine wave pattern
158
- 5. **RiseTransform** - Rising curve effect
159
- 6. **FlagTransform** - Wavy flag effect
160
- 7. **AngleTransform** - Diagonal/angled text
161
- 8. **DistortTransform** - Perspective distortion
162
-
163
- ## Getting Started
164
-
165
- ### Installation
166
-
167
- ```bash
168
- cd custom-canvas
169
- npm install
170
- ```
171
-
172
- ### Development
173
-
174
- ```bash
175
- npm run dev
20
+ `react` and `react-dom` (>=18) are peer dependencies.
21
+
22
+ ## Quick start
23
+
24
+ ```tsx
25
+ import { SnowconeCanvas } from '@snowcone-app/canvas';
26
+ import '@snowcone-app/canvas/style.css';
27
+
28
+ export default function Customizer() {
29
+ return (
30
+ <SnowconeCanvas
31
+ // One artboard per print area. The name is the export key.
32
+ artboards={[{ name: 'Front', width: 1200, height: 1200 }]}
33
+ // Optional: drop the shopper's art in to start from.
34
+ imageConfig={{ src: 'https://cdn.example.com/art.png', scaleMode: 'contain' }}
35
+ // Fires on every edit — persist this JSON to reload the design later.
36
+ onChange={(state) => saveDraft(state)}
37
+ />
38
+ );
39
+ }
176
40
  ```
177
41
 
178
- Open [http://localhost:5173](http://localhost:5173) in your browser.
179
-
180
- ### Build
181
-
182
- ```bash
183
- npm run build
42
+ That renders a working editor out of the box (toolbar, layers, text/image/effects).
43
+ Use the `kit` prop to switch presets (`'pro-studio'` default, `'compact-customizer'`,
44
+ `'embed-only'`) or pass `layoutConfig` to go canvas-only.
45
+
46
+ ## Common recipes
47
+
48
+ ### Multiple print areas (placements)
49
+
50
+ ```tsx
51
+ <SnowconeCanvas
52
+ artboards={[
53
+ { name: 'Front', width: 1200, height: 1200 },
54
+ { name: 'Back', width: 1200, height: 1200 },
55
+ // clipShape masks content to a shape (e.g. a circular badge).
56
+ { name: 'Pocket', width: 400, height: 400, clipShape: 'circle' },
57
+ ]}
58
+ activeArtboard="Front"
59
+ onArtboardChange={(name) => console.log('now editing', name)}
60
+ />
184
61
  ```
185
62
 
186
- ## Usage Example
187
-
188
- ```javascript
189
- import { CustomTransform, CircleTransform } from "./transforms";
190
-
191
- // Create a straight text shape
192
- const straightText = new CustomTransform({
193
- text: "Hello World",
194
- x: 100,
195
- y: 100,
196
- fontSize: 24,
197
- color: "#333",
198
- transformData: { width: 200 },
199
- });
63
+ ### Save and restore a design
200
64
 
201
- // Create a circular text shape
202
- const circularText = new CircleTransform({
203
- text: "Circular Text",
204
- x: 300,
205
- y: 200,
206
- fontSize: 20,
207
- color: "#0066cc",
208
- transformData: { radius: 80, scale: 1 },
209
- });
65
+ ```tsx
66
+ // SAVE onChange hands you a CanvasState (elements + artboards). Persist the
67
+ // JSON. Do NOT save a flattened PNG as the state — you'll lose the layers.
68
+ const [state, setState] = useState<CanvasState | null>(null);
210
69
 
211
- // Render on canvas
212
- const ctx = canvas.getContext("2d");
213
- straightText.render(ctx);
214
- circularText.render(ctx);
70
+ <SnowconeCanvas
71
+ artboards={artboards}
72
+ onChange={setState}
73
+ // RELOAD — feed the saved elements back in to restore an editable design.
74
+ initialElements={savedState?.elements}
75
+ />
215
76
  ```
216
77
 
217
- ## Creating a New Transform Type
218
-
219
- 1. Create a new file in `src/transforms/` (e.g., `WaveTransform.js`)
220
-
221
- 2. Extend `TextShape` base class:
222
-
223
- ```javascript
224
- import { TextShape } from "../core/TextShape.js";
225
-
226
- export class WaveTransform extends TextShape {
227
- constructor(config = {}) {
228
- super(config);
229
- this.transformType = "wave";
230
-
231
- // Transform-specific data
232
- this.transformData.amplitude = config.transformData?.amplitude || 20;
233
- this.transformData.frequency = config.transformData?.frequency || 2;
234
- }
235
-
236
- getBoundingBox() {
237
- // Return {x, y, width, height} in world coordinates
238
- }
239
-
240
- render(ctx, isSelected = false) {
241
- // Draw the transformed text on canvas
242
- }
243
-
244
- resize(anchor, newWidth, newHeight, startData) {
245
- // Handle resize transformation
246
- }
247
-
248
- getEnabledAnchors() {
249
- // Return array of enabled anchor names
250
- return ["top-left", "top-right", "bottom-left", "bottom-right"];
251
- }
252
- }
78
+ ### Print-ready exports
79
+
80
+ ```tsx
81
+ <SnowconeCanvas
82
+ artboards={[{ name: 'Front', width: 1200, height: 1200 }]}
83
+ exportConfig={{
84
+ autoExportConfig: { enabled: true, debounceMs: 200 },
85
+ format: 'blob', // 'blob' for uploads, 'dataUrl' for inline previews
86
+ exportAll: true, // export every artboard, not just the active one
87
+ scale: 2, // resolution multiplier (capped by maxSize)
88
+ }}
89
+ // Keyed by artboard name: { Front: Blob, Back: Blob }
90
+ onExport={(exports) => uploadToBackend(exports)}
91
+ />
253
92
  ```
254
93
 
255
- 3. Export from `src/transforms/index.js`
256
- 4. Add to `TRANSFORM_TYPES` array in `App.jsx`
257
-
258
- ## Key Components
259
-
260
- ### TextShape (Base Class)
261
-
262
- - Common interface for all text shapes
263
- - Properties: text, position, rotation, fontSize, color
264
- - Methods: getBoundingBox(), hitTest(), render(), resize()
265
-
266
- ### TransformHandles
267
-
268
- - Manages 8 resize handles (4 corners + 4 sides)
269
- - Manages rotation handle
270
- - Hit detection
271
- - Rendering with consistent style
272
-
273
- ### CanvasEditor
274
-
275
- - Main React component
276
- - Canvas rendering loop
277
- - Mouse interaction (drag, resize, rotate)
278
- - Selection management
279
-
280
- ### GeometryUtils
281
-
282
- - `calculateFixedCornerPosition()` - Keep opposite corner fixed during resize
283
- - `calculateRotationHandlePosition()` - Position rotation handle
284
- - `calculateResizeHandles()` - Calculate all 8 handle positions
285
- - `hitTestRect()` - Hit test for rotated rectangles
286
- - `hitTestCircle()` - Hit test for circles
287
- - `measureTextWidth()` - Measure text using canvas API
288
-
289
- ## Transform Handle Behavior
290
-
291
- ### Corner Handles
292
-
293
- - **What they do**: Uniform scale (fontSize and dimensions both change)
294
- - **Fixed point**: Diagonally opposite corner stays in place
295
- - **Enabled on**: All transform types
296
-
297
- ### Side Handles
298
-
299
- - **What they do**: Width only (fontSize stays constant)
300
- - **Fixed point**: Opposite side edge
301
- - **Enabled on**: Straight text only (CustomTransform)
302
-
303
- ### Rotation Handle
304
-
305
- - **What it does**: Rotates around center of bounding box
306
- - **Position**: 50px below bottom edge, centered
307
- - **Visual feedback**: Shows angle tooltip while rotating
308
-
309
- ## Architecture Highlights
310
-
311
- | Aspect | Implementation |
312
- | --------------------- | --------------------------------------------------- |
313
- | **Code Organization** | ~200 lines per file, modular components |
314
- | **Transform System** | Direct Canvas API control with rotation matrix math |
315
- | **Maintainability** | Clean separation of concerns, type-safe |
316
- | **Extensibility** | Easy to add transforms (extend base class) |
317
- | **Performance** | Direct canvas API + Web Worker exports |
318
- | **Effects Pipeline** | Strokes, masks, distress, knockout compositing |
319
-
320
- ## Next Steps
321
-
322
- 1. **Implement Remaining Transforms**
94
+ Exports always produce transparent PNGs/WebP — the preview background is never baked in.
323
95
 
324
- - WaveTransform (sine wave pattern)
325
- - RiseTransform (rising curve)
326
- - FlagTransform (wavy flag)
327
- - AngleTransform (diagonal)
328
- - DistortTransform (perspective)
96
+ ## API at a glance
329
97
 
330
- 2. **Add Text Editing**
98
+ `<SnowconeCanvas />` is the single entry point. Key props:
331
99
 
332
- - Double-click to edit text
333
- - Text editor overlay
334
- - Support for font family selection
100
+ | Prop | Type | Purpose |
101
+ |------|------|---------|
102
+ | `artboards` | `ArtboardConfig[]` | One entry per print area; `name` is the export key |
103
+ | `initialElements` | `AnyElementConfig[]` | Restore a previously saved design |
104
+ | `imageConfig` | `ImageConfig` | Initial image: `src`, `alignment`, `scale`, `scaleMode` |
105
+ | `exportConfig` | `ExportConfig` | Auto-export, format, scale, max size |
106
+ | `layoutConfig` | `LayoutConfig` | Sizing, border radius, toggle toolbar/layers |
107
+ | `kit` | `'pro-studio' \| 'compact-customizer' \| 'embed-only' \| KitDefinition` | Editor preset |
108
+ | `onChange` | `(state: CanvasState) => void` | Persist design state on edit |
109
+ | `onExport` | `(exports: Record<string, string \| Blob>) => void` | Receive rendered placements |
110
+ | `onArtboardChange` | `(name: string) => void` | Active placement changed |
335
111
 
336
- 3. **Keyboard Shortcuts**
112
+ Need lower-level control? `@snowcone-app/canvas` also exports React hooks
113
+ (`useEditor`, `useArtboards`, `useLayers`, `useExport`) and state helpers
114
+ (`serializeState`, `deserializeState`). See the docs for the full reference.
337
115
 
338
- - Delete selected shape
339
- - Duplicate shape
340
- - Undo/redo
116
+ All exports are fully typed — TypeScript definitions ship with the package.
341
117
 
342
- 4. **Export/Import**
343
- - Save shapes to JSON
344
- - Load shapes from JSON
345
- - Export as image
118
+ ## Requirements
346
119
 
347
- ## Contributing
120
+ - React 18 or 19
121
+ - A bundler that handles ESM and CSS imports (Vite, Next.js, Remix, etc.)
122
+ - Modern browsers: Chrome 69+, Firefox 105+, Safari 16.4+, Edge 79+
348
123
 
349
- To add a new transform type:
124
+ ## Links
350
125
 
351
- 1. See "Creating a New Transform Type" section above
352
- 2. Follow the existing patterns in `CustomTransform.js` and `CircleTransform.js`
353
- 3. Test resize and rotation behavior match existing transforms
126
+ - 📖 [Documentation](https://developers.snowcone.app/canvas)
127
+ - 🐛 [Issues](https://github.com/snowcone-app/snowcone-monorepo/issues)
128
+ - 🌐 [snowcone.app](https://snowcone.app)
354
129
 
355
130
  ## License
356
131
 
@@ -40,5 +40,6 @@ export type { ArtboardConfig as ArtboardElementConfig, TransformType, AnyElement
40
40
  export { ErrorBoundary } from '../components/embed/ErrorBoundary.js';
41
41
  export type { ErrorBoundaryProps } from '../components/embed/ErrorBoundary.js';
42
42
  export { serializeState, deserializeState, validateState, migrateState, } from '../state/index.js';
43
- export { serializeStateForServer } from '../rendering/serialize-for-server.js';
43
+ export { serializeStateForServer, CANVAS_STATE_SCHEMA_VERSION, } from '../rendering/serialize-for-server.js';
44
+ export type { ServerRenderRequest } from '../rendering/serialize-for-server.js';
44
45
  export type { CanvasStateV1, SerializedArtboard, SerializedElement, DeserializeResult, ValidationResult, } from '../state/index.js';
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const I=require("./compose-Bo108juW.cjs"),U=require("./HybridHistoryManager-BXD93pp8.cjs"),C=require("react/jsx-runtime"),o=require("react"),B=require("./ThemeContext-4mJ_y0Me.cjs"),le=require("./ElementFactory-B7UOaJSD.cjs"),de=require("./CanvasStateV1-D5GzvmnY.cjs"),it=U.createLogger("ErrorBoundary");class ze extends o.Component{constructor(e){super(e),this.resetError=()=>{this.setState({hasError:!1,error:null})},this.state={hasError:!1,error:null}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,r){if(it.error("Caught error:",e,r),this.props.onError&&this.props.onError(e,r),this.props.onCanvasError){const a={category:"unknown",message:e.message,originalError:e,recoverable:!1};this.props.onCanvasError(a)}}render(){return this.state.hasError&&this.state.error?this.props.renderError?this.props.renderError(this.state.error,this.resetError):this.props.fallback?typeof this.props.fallback=="function"?this.props.fallback(this.state.error,this.resetError):this.props.fallback:C.jsxs("div",{style:{padding:"24px",border:"2px solid var(--danger)",borderRadius:"8px",backgroundColor:"color-mix(in oklch, var(--danger) 10%, var(--background))",color:"var(--danger)",fontFamily:"system-ui, sans-serif"},children:[C.jsx("h2",{style:{margin:"0 0 16px 0",fontSize:"18px",fontWeight:600},children:"Something went wrong"}),C.jsx("pre",{style:{margin:"0 0 16px 0",padding:"12px",backgroundColor:"color-mix(in oklch, var(--danger) 15%, var(--background))",borderRadius:"4px",fontSize:"14px",overflow:"auto",maxHeight:"200px"},children:this.state.error.message}),C.jsx("button",{onClick:this.resetError,style:{padding:"8px 16px",backgroundColor:"var(--danger)",color:"var(--danger-foreground)",border:"none",borderRadius:"4px",fontSize:"14px",fontWeight:500,cursor:"pointer"},children:"Try again"})]}):this.props.children}}const ct=U.createLogger("useAutoExport");function Oe(t){const{config:e,historyManager:r,artboards:a,elements:n,onExport:l,onExportScheduled:s,isCanvasReady:c=!1}=t,d=o.useRef(null),b=o.useRef(!1),S=o.useRef({totalExports:0,skippedExports:0,lastExportTime:null,avgExportInterval:0}),[L,k]=o.useState(S.current),y=o.useRef(l);y.current=l,o.useEffect(()=>{const h=new I.AutoExportManager({...I.DEFAULT_AUTO_EXPORT_CONFIG,...e});return h.onExport(async()=>{try{await y.current(),S.current=h.getStats()}catch(R){ct.error("[useAutoExport] Export failed:",R)}}),d.current=h,()=>{h.destroy()}},[]),o.useEffect(()=>{c&&b.current&&d.current&&(b.current=!1,d.current.forceExport())},[c]),o.useEffect(()=>{d.current&&e&&d.current.updateConfig(e)},[e==null?void 0:e.enabled,e==null?void 0:e.debounceMs,e==null?void 0:e.maxWaitMs]),o.useEffect(()=>{d.current&&s&&d.current.onExportScheduled(s)},[s]),o.useEffect(()=>{if(!r||!d.current)return;const h=r.onCommandExecuted(()=>{if(d.current){if(!c){b.current=!0;return}d.current.scheduleExport()}});return()=>{h()}},[r,c]),o.useEffect(()=>{if(d.current){if(!c){b.current=!0;return}d.current.scheduleExport()}},[n,a,c]),o.useEffect(()=>U.subscribeToImageLoads(R=>{if(!d.current||!c)return;n.some(W=>W.id===R)&&d.current.scheduleExport()}),[n,c]);const T=o.useCallback(h=>{d.current&&d.current.updateConfig(h)},[]),w=o.useCallback(async()=>{d.current&&(await d.current.forceExport(),S.current=d.current.getStats(),k(S.current))},[]),P=o.useCallback(()=>{d.current&&(d.current.resetStats(),S.current=d.current.getStats(),k(S.current))},[]),A=o.useCallback(()=>{d.current&&d.current.resetChangeDetection()},[]);return{stats:L,updateConfig:T,forceExport:w,resetStats:P,resetChangeDetection:A}}const Ye=U.createLogger("useContentReady");function lt(t){var r;const e=new Set;for(const a of t)if("fontFamily"in a&&typeof a.fontFamily=="string"&&a.fontFamily&&e.add(a.fontFamily),"getRichText"in a&&typeof a.getRichText=="function")try{const n=a.getRichText();if(n!=null&&n.spans)for(const l of n.spans)(r=l.style)!=null&&r.fontFamily&&e.add(l.style.fontFamily)}catch{}return Array.from(e)}async function dt(t){if(t.length===0||typeof document>"u"||!document.fonts)return;const e=[];for(const r of t){const a=`16px "${r}"`;e.push(document.fonts.load(a))}await Promise.all(e),document.fonts.ready&&await Promise.race([document.fonts.ready,new Promise(r=>setTimeout(r,250))]),Ye.debug(`Awaited ${e.length} font(s)`)}function ut(){return new Promise(t=>requestAnimationFrame(()=>t()))}function $e(t){const{isCanvasReady:e,elements:r,hasInitialElements:a,initialElementsLoaded:n}=t,[l,s]=o.useState(!1),c=o.useRef(!1);return o.useEffect(()=>{if(l||!e||a&&!n||a&&r.length===0||c.current)return;c.current=!0;let d=!1;return(async()=>{try{const b=lt(r);if(b.length>0&&(await dt(b),d)||(await ut(),d))return;s(!0)}catch(b){Ye.error("Error during content readiness check:",b),d||s(!0)}finally{c.current=!1}})(),()=>{d=!0,c.current=!1}},[e,r,a,n,l]),l}const ft={"far-top":"t",top:"t",center:"c",bottom:"b","far-bottom":"b","far-left":"l",left:"l",right:"r","far-right":"r",tl:"tl",t:"t",tr:"tr",l:"l",c:"c",r:"r",bl:"bl",b:"b",br:"br"};function mt(t){return t&&ft[t]||"c"}function ht(t,e){const r=e.scaleMode||"cover",a=(r==="contain"?e.marginTop:0)||0,n=(r==="contain"?e.marginRight:0)||0,l=(r==="contain"?e.marginBottom:0)||0,s=(r==="contain"?e.marginLeft:0)||0,c=e.width-s-n,d=e.height-a-l,b=c/t.width,S=d/t.height,L=r==="contain"?Math.min(b,S):Math.max(b,S),k=e.scale||1,y=L*k,T=t.width*y,w=t.height*y,P=e.align||"c";let A=0,h=0;const R=T-c,E=w-d;switch(P){case"tl":A=0,h=0;break;case"t":A=-R/2,h=0;break;case"tr":A=-R,h=0;break;case"l":A=0,h=-E/2;break;case"c":default:A=-R/2,h=-E/2;break;case"r":A=-R,h=-E/2;break;case"bl":A=0,h=-E;break;case"b":A=-R/2,h=-E;break;case"br":A=-R,h=-E;break}A+=s,h+=a;const W=e.offsetX||0,F=e.offsetY||0,Y=R,_=E;return A+=W*Y,h+=F*_,A=Math.round(A),h=Math.round(h),{scale:y,width:Math.round(T),height:Math.round(w),x:A,y:h,debug:{coverScale:L,userScale:k,overflow:{x:R,y:E},alignment:P,appliedOffset:{x:W*Y,y:F*_}}}}const gt={timeout:3e4,retries:1,retryDelay:1e3,validateUrl:!0};function pt(t){try{const e=new URL(t);return["http:","https:","data:","blob:"].includes(e.protocol)}catch{return!1}}async function bt(t,e={}){const r={...gt,...e};if(r.validateUrl&&!pt(t))return{success:!1,error:new Error(`Invalid image URL: ${t}`)};let a;for(let n=0;n<=r.retries;n++)try{return await xt(t,r.timeout)}catch(l){a=l instanceof Error?l:new Error(String(l)),n<r.retries&&await vt(r.retryDelay)}return{success:!1,error:a||new Error("Failed to load image after retries")}}function xt(t,e){return new Promise(r=>{const a=new Image;a.crossOrigin="anonymous";let n=null,l=!1;const s=()=>{n&&(clearTimeout(n),n=null)},c=()=>{if(l)return;l=!0,s();const b=a.naturalWidth||a.width,S=a.naturalHeight||a.height;r({success:!0,element:a,width:b,height:S,aspectRatio:S>0?b/S:1})},d=b=>{l||(l=!0,s(),r({success:!1,error:new Error(b)}))};a.onload=c,a.onerror=()=>{d(`Failed to load image: ${t}`)},n=setTimeout(()=>{d(`Image load timed out after ${e}ms: ${t}`)},e),a.src=t})}async function Et(t,e,r={},a={}){var k,y,T,w,P,A,h;const n=await bt(t,a);if(!n.success||!n.width||!n.height)return{success:!1,error:n.error||new Error("Failed to get image dimensions")};const l={width:e.artboard.width,height:e.artboard.height,scale:e.scale,align:mt(e.alignment),offsetX:e.offsetX,offsetY:e.offsetY,scaleMode:e.scaleMode,marginTop:e.marginTop,marginRight:e.marginRight,marginBottom:e.marginBottom,marginLeft:e.marginLeft},s=ht({width:n.width,height:n.height},l),c=e.artboard.x+s.x,d=e.artboard.y+s.y,b=c+s.width/2,S=d+s.height/2;return{success:!0,element:new U.ImageElement({...r,x:b,y:S,imageUrl:t,imageAspectRatio:n.aspectRatio,preserveDimensions:!0,transformData:{type:"image",width:s.width,height:s.height,cropX:((k=r.transformData)==null?void 0:k.cropX)??0,cropY:((y=r.transformData)==null?void 0:y.cropY)??0,cropWidth:((T=r.transformData)==null?void 0:T.cropWidth)??1,cropHeight:((w=r.transformData)==null?void 0:w.cropHeight)??1,flipHorizontal:((P=r.transformData)==null?void 0:P.flipHorizontal)??!1,flipVertical:((A=r.transformData)==null?void 0:A.flipVertical)??!1,borderRadius:((h=r.transformData)==null?void 0:h.borderRadius)??0}}),placement:{artworkSize:{width:n.width,height:n.height},finalSize:{width:s.width,height:s.height},position:{x:b,y:S},scale:s.scale}}}function vt(t){return new Promise(e=>setTimeout(e,t))}const V=U.createLogger("SnowconeCanvas");function Ee(t,e,r,a){if(a<=0||!isFinite(a))return r;const n=t*r,l=e*r;if(Math.max(n,l)<=a)return r;const c=Math.max(t,e),d=a/c;return Math.min(d,r)}const Xe=o.forwardRef((t,e)=>{const{exportConfig:r,imageConfig:a,layoutConfig:n,kit:l,artboards:s,activeArtboard:c,onArtboardChange:d,initialElements:b,onChange:S,onSelectionChange:L,autoExportInterval:k,onExport:y,onExportScheduled:T,onExportStatus:w,onExportReady:P,onImageLoad:A,onImageError:h,onError:R,onReady:E,className:W,style:F,enableShortcuts:Y,overlay:_}=t,we=k,Z=t.autoExportConfig??(r==null?void 0:r.autoExportConfig),q=t.autoExportFormat??(r==null?void 0:r.format)??"dataUrl",ue=t.autoExportAll??(r==null?void 0:r.exportAll)??!1,X=t.exportScale??(r==null?void 0:r.scale)??2,j=t.maxExportSize??(r==null?void 0:r.maxSize)??4e3,ee=t.exportImageFormat??(r==null?void 0:r.imageFormat)??"png",te=t.exportImageQuality??(r==null?void 0:r.imageQuality)??.92,z=t.initialImage??(a==null?void 0:a.src),ye=t.initialImageAlignment??(a==null?void 0:a.alignment)??"center",Ae=t.initialImageScale??(a==null?void 0:a.scale)??1,Se=t.initialImageScaleMode??(a==null?void 0:a.scaleMode)??"cover",Ke=t.width??(n==null?void 0:n.width)??1200,Ve=t.height??(n==null?void 0:n.height)??1200,Re=t.viewPadding??(n==null?void 0:n.viewPadding)??.9,Ce=t.artboardBorderRadius??(n==null?void 0:n.artboardBorderRadius)??0,Ie=t.fixedMargin??(n==null?void 0:n.fixedMargin),ke=t.maxHeight??(n==null?void 0:n.maxHeight),Me=t.showRotationHandle??(n==null?void 0:n.showRotationHandle)??!0,qe=t.hideCanvas??(n==null?void 0:n.hideCanvas)??!1,Te=t.canvasWrapperClassName??(n==null?void 0:n.canvasWrapperClassName),Fe=t.canvasWrapperStyle??(n==null?void 0:n.canvasWrapperStyle),De=t.canvasCutouts??(n==null?void 0:n.canvasCutouts),fe=t.pieceGuides,Le=t.pieceFocus,Pe=Y??!0,re=o.useMemo(()=>I.resolveKit(l??"pro-studio"),[l]);o.useEffect(()=>{if(U.process$1.env.NODE_ENV==="development"&&re){const i=I.validateKit(re);i.valid||V.warn("Kit validation warnings:",i.errors),i.warnings.length>0&&V.warn("Kit validation warnings:",i.warnings)}},[re]);const ne=o.useRef(R);ne.current=R;const N=o.useCallback(i=>{var u;V.error(`[${i.category}] ${i.message}`,i.originalError),(u=ne.current)==null||u.call(ne,i)},[]);o.useEffect(()=>(le.CanvasRenderer.onRenderError=N,()=>{le.CanvasRenderer.onRenderError===N&&(le.CanvasRenderer.onRenderError=null)}),[N]);const{elements:K,setElements:ae,selectedId:He,artboardManager:M,refreshArtboards:Ge,historyManager:Qe,isCanvasReady:me,setCanvasReady:oe}=B.useEditor(),{createArtboard:Ze,selectArtboard:Je,artboards:H}=I.useArtboards(),{exportArtboard:G,exportAllArtboards:se,exportArtboardAsBlob:Q,exportAllArtboardsAsBlobs:ie}=I.useExport();o.useImperativeHandle(e,()=>({exportArtboards:async(i={})=>{const u=i.format||q,g=i.scale||X,p=i.all??!1;let m=g;if(j>0&&isFinite(j))for(const v of H){const x=Ee(v.width,v.height,g,j);m=Math.min(m,x)}const f={scale:m,format:ee,quality:te};if(p){const v=u==="blob"?await ie(f):await se(f),x={};for(const[D,O]of Object.entries(v)){const $=H.find(J=>J.id===D);$&&(x[$.name]=O)}return x}else{const v=M.getActiveArtboard();if(!v)throw new Error("[SnowconeCanvas] No active artboard found");if(u==="blob"){const x=await Q(v.id,f);return{[v.name]:x}}else{const x=await G(v.id,f);return{[v.name]:x}}}}}),[G,se,Q,ie,q,X,j,ee,te,M,H]),o.useEffect(()=>{P&&P(async()=>{const u=M.getActiveArtboard();if(!u)throw new Error("[SnowconeCanvas] No active artboard found");const g=Ee(u.width,u.height,X,j),p=q==="blob"?await Q(u.id,{scale:g}):await G(u.id,{scale:g});return{[u.name]:p}})},[P,G,Q,M,q,X,j]);const[Be,ce]=o.useState("idle"),[We,he]=o.useState(null),ge=o.useRef(void 0),pe=o.useRef(!1),Ne=o.useRef(!1),[_e,et]=o.useState(!1),tt=o.useRef(0),rt=o.useRef(0),be=o.useRef(!1);o.useEffect(()=>{if(pe.current)return;pe.current=!0;const i=s||[{name:"Design",width:Ke,height:Ve}],u=M.getAllArtboards();if(u.length>0){const g=i[0],p=u[0],m=fe?"transparent":void 0;p.name=g.name,p.width=g.width,p.height=g.height,p.clipShape=g.clipShape,g.backgroundColor?p.backgroundColor=g.backgroundColor:m&&(p.backgroundColor=m);for(let f=1;f<i.length;f++)Ze(i[f].width,i[f].height,{name:i[f].name,backgroundColor:i[f].backgroundColor??m,clipShape:i[f].clipShape})}Ge()},[]),o.useEffect(()=>{if(!(!b||b.length===0)&&!Ne.current&&pe.current){Ne.current=!0,et(!0);try{const i=le.ElementFactory.createManyFromJSON(b),u=M.getAllArtboards();if(u.length>0){const p=u[0];for(const m of i)M.addElementToArtboard(m.id,p.id)}ae(i);const g=new Set;for(const p of i){const m=p.fontFamily;typeof m=="string"&&m.trim().length>0&&g.add(m)}if(g.size>0&&typeof document<"u"){const p=document.fonts??null,m=Array.from(g).map(f=>{const v=`font-${f.replace(/\s+/g,"-").toLowerCase()}`;let x=document.getElementById(v);return x||(x=document.createElement("link"),x.id=v,x.rel="stylesheet",x.href=`https://fonts.googleapis.com/css2?family=${f.replace(/\s+/g,"+")}:wght@400;700&display=swap`,document.head.appendChild(x)),new Promise(D=>{if(x.sheet){D(f);return}const O=()=>D(f);x.addEventListener("load",O,{once:!0}),x.addEventListener("error",O,{once:!0}),setTimeout(O,4e3)})});Promise.all(m).then(f=>{if(p)return Promise.all(f.flatMap(v=>[p.load(`400 16px "${v}"`).catch(()=>{}),p.load(`700 16px "${v}"`).catch(()=>{})]))}).then(()=>{ae(f=>f.slice())})}}catch(i){V.error("Failed to load initial elements:",i);const u=i instanceof Error?i:new Error(String(i));N({category:"import",message:`Failed to load initial elements: ${u.message}`,originalError:u,recoverable:!0})}}},[b,M,ae,N]),o.useEffect(()=>{if(!c){be.current=!0;return}const i=H.find(u=>u.name===c);if(i){const u=M.getActiveArtboard();(u==null?void 0:u.name)!==c&&Je(i.id),be.current=!0}},[c,H]),o.useEffect(()=>{if(!z||ge.current===z)return;if(K.length>0){ge.current=z;return}ge.current=z,(async()=>{ce("loading"),he(null);try{const u=M.getAllArtboards();if(u.length===0)throw new Error("No artboards available");const g=[];for(const p of u){const m=s==null?void 0:s.find(x=>x.name===p.name),f=(m==null?void 0:m.scaleMode)||Se,v=await Et(z,{artboard:{width:p.width,height:p.height,x:p.x,y:p.y},alignment:(m==null?void 0:m.fitAlign)||ye,scale:Ae,scaleMode:f,marginTop:m==null?void 0:m.fitMarginTop,marginRight:m==null?void 0:m.fitMarginRight,marginBottom:m==null?void 0:m.fitMarginBottom,marginLeft:m==null?void 0:m.fitMarginLeft});v.success&&v.element?(M.addElementToArtboard(v.element.id,p.id),g.push(v.element)):V.error("Failed to load image for artboard:",p.name,v.error)}if(g.length>0)ae(p=>[...p,...g]),ce("success"),A==null||A(z);else{const p=new Error("Failed to load image into any artboard");ce("error"),he(p),h==null||h(z,p),N({category:"image",message:p.message,originalError:p,recoverable:!0})}}catch(u){const g=u instanceof Error?u:new Error(String(u));ce("error"),he(g),h==null||h(z,g),N({category:"image",message:g.message,originalError:g,recoverable:!0})}})()},[z,ye,Ae,Se]),o.useEffect(()=>{L==null||L(He)},[He,L]),o.useEffect(()=>{if(!S)return;const i=M.getActiveArtboard(),u={elements:K.map(g=>g.toJSON()),artboards:H.map(g=>({name:g.name,width:g.width,height:g.height,clipShape:g.clipShape,backgroundColor:g.backgroundColor})),activeArtboard:(i==null?void 0:i.name)||"Design"};S(u)},[K,H,S]),o.useEffect(()=>{if(!d||!be.current)return;const i=M.getActiveArtboard();i&&d(i.name)},[M.getActiveArtboardId()]);const nt=o.useCallback(async()=>{if(!y&&!w)return;const i=++rt.current,u=Date.now();let g=X;if(j>0&&isFinite(j))for(const f of H){const v=Ee(f.width,f.height,X,j);g=Math.min(g,v)}const p=M.getActiveArtboard(),m=(p==null?void 0:p.id)??"unknown";w==null||w({status:"rendering",artboardId:m}),tt.current=u;try{let f;const v={format:ee,scale:g,quality:te};if(q==="blob")if(ue){const x=await ie(v);f={};for(const[D,O]of Object.entries(x)){const $=H.find(J=>J.id===D);$&&(f[$.name]=O)}}else{const x=M.getActiveArtboard();if(!x)return;const D=await Q(x.id,v);f={[x.name]:D}}else if(ue){const x=await se(v);f={};for(const[D,O]of Object.entries(x)){const $=H.find(J=>J.id===D);$&&(f[$.name]=O)}}else{const x=M.getActiveArtboard();if(!x)return;const D=await G(x.id,v);f={[x.name]:D}}y==null||y(f),w==null||w({status:"complete",artboardId:m,result:f})}catch(f){const v=f instanceof Error?f.message:String(f);if(v.includes("Canvas ref not available"))return;const x=Date.now()-u;V.error("Export failed (export #"+i+"):",{duration:`${x}ms`,error:v});const D=f instanceof Error?f:new Error(v);w==null||w({status:"error",artboardId:m,error:D}),N({category:"export",message:D.message,originalError:D,artboardId:m,recoverable:!0})}},[y,w,ue,q,X,j,ee,te,G,se,Q,ie,H,M,K,Z,N]);o.useEffect(()=>{we!==void 0&&we>0&&V.warn("autoExportInterval is deprecated and ignored. Use autoExportConfig={{ enabled: true, debounceMs: 100, maxWaitMs: 1000 }} instead.")},[]),o.useEffect(()=>{},[K]);const at=o.useCallback(()=>{if(T==null||T(),w){const i=M.getActiveArtboard();w({status:"scheduled",artboardId:(i==null?void 0:i.id)??"unknown"})}},[T,w,M]),ot=!!b&&b.length>0,xe=$e({isCanvasReady:me,elements:K,hasInitialElements:ot,initialElementsLoaded:_e}),je=o.useRef(!1);o.useEffect(()=>{xe&&!je.current&&(je.current=!0,E==null||E())},[xe,E]),Oe({config:Z?{enabled:Z.enabled??!0,debounceMs:Z.debounceMs??100,maxWaitMs:Z.maxWaitMs??1e3}:{enabled:!1},historyManager:Qe,artboards:H,elements:K,onExport:nt,onExportScheduled:at,isCanvasReady:xe}),o.useEffect(()=>{if(H.length>0&&!me){const i=requestAnimationFrame(()=>{oe(!0)});return()=>cancelAnimationFrame(i)}},[H.length,me,oe]),o.useEffect(()=>()=>{oe(!1)},[oe]);const st=o.useCallback(i=>{N({category:"unknown",message:i.message,originalError:i,recoverable:!1})},[N]);return Be==="loading"?C.jsx("div",{className:W,style:{...F,display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"var(--surface, #f5f5f5)"},children:C.jsx(I.Spinner,{size:48})}):Be==="error"&&We?C.jsx("div",{className:W,style:{...F,display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"var(--surface, #f5f5f5)",color:"var(--danger, #dc2626)",padding:"1rem"},children:C.jsxs("div",{className:"text-center",children:[C.jsx("div",{className:"font-medium",children:"Failed to load image"}),C.jsx("div",{className:"text-sm mt-1 opacity-70",children:We.message})]})}):C.jsx(I.KitProvider,{kit:re,children:C.jsx("div",{className:`app-modern ${W||""}`,style:{...F,position:"relative"},children:C.jsxs(ze,{onError:st,fallback:(i,u)=>C.jsxs("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"24px",minHeight:"200px",backgroundColor:"var(--surface, #f5f5f5)",color:"var(--foreground, #333)",fontFamily:"system-ui, sans-serif",textAlign:"center"},children:[C.jsx("div",{style:{fontSize:"18px",fontWeight:600,marginBottom:"8px"},children:"Something went wrong"}),C.jsx("div",{style:{fontSize:"14px",opacity:.7,marginBottom:"16px",maxWidth:"400px"},children:i.message}),C.jsx("button",{onClick:u,style:{padding:"8px 20px",backgroundColor:"var(--primary, #333)",color:"var(--primary-foreground, #fff)",border:"none",borderRadius:"6px",fontSize:"14px",fontWeight:500,cursor:"pointer"},children:"Try again"})]}),children:[!qe&&(Te||Fe?C.jsx("div",{className:Te,style:Fe,children:C.jsx(I.Canvas,{style:{width:"100%"},fitPadding:Re,artboardBorderRadius:Ce,fixedMargin:Ie,maxHeight:ke,showRotationHandle:Me,enableShortcuts:Pe,canvasCutouts:De,pieceGuides:fe,pieceFocus:Le})}):C.jsx(I.Canvas,{style:{width:"100%"},fitPadding:Re,artboardBorderRadius:Ce,fixedMargin:Ie,maxHeight:ke,showRotationHandle:Me,enableShortcuts:Pe,canvasCutouts:De,pieceGuides:fe,pieceFocus:Le})),_]})})})});Xe.displayName="SnowconeCanvasInner";const ve=o.forwardRef((t,e)=>{var s;const{inheritTheme:r,externalProvider:a}=t,n=t.viewPadding??((s=t.layoutConfig)==null?void 0:s.viewPadding),l=C.jsx(Xe,{ref:e,...t});return a?C.jsx(B.ThemeProvider,{defaultTheme:"light",passive:r,children:l}):C.jsx(B.ThemeProvider,{defaultTheme:"light",passive:r,children:C.jsx(B.EditorProvider,{viewPadding:n,children:l})})});ve.displayName="SnowconeCanvas";const Ue=U.createLogger("useCommands");function wt(){const t=B.useEditor(),{undo:e,redo:r,canUndo:a,canRedo:n,executeElementUpdate:l,executeAddElement:s,executeRemoveElement:c,executeReorderElement:d,executeCommandBatch:b,executeCreateArtboard:S,executeDeleteArtboard:L,executeUpdateArtboard:k}=t,y=o.useCallback(()=>{Ue.warn("[useCommands] clearHistory is not yet implemented in EditorContext")},[]),T=o.useCallback(w=>{Ue.warn("[useCommands] clearArtboardHistory is not yet implemented in EditorContext")},[]);return{undo:e,redo:r,canUndo:a,canRedo:n,clearHistory:y,clearArtboardHistory:T,executeElementUpdate:l,executeAddElement:s,executeRemoveElement:c,executeReorderElement:d,executeCreateArtboard:S,executeDeleteArtboard:L,executeUpdateArtboard:k,executeCommandBatch:b}}function yt(){const{selectedElement:t}=B.useEditor();return t??null}function At(){const{isCanvasReady:t}=B.useEditor();return t}const St=()=>{},Rt=[];function Ct(t){const{elementStore:e}=B.useElementsContext(),{executeElementUpdate:r}=B.useCommandContext(),a=o.useMemo(()=>e.getAllByName(t).filter(s=>s instanceof U.TextElement),[e,t]),n=o.useCallback(l=>{for(const s of a){const c=s.clone();c.setText(l),r(s,c)}},[a,r]);return a.length===0?{text:"",setText:St,element:null,elements:Rt,isConnected:!1}:{text:a[0].getText(),setText:n,element:a[0],elements:a,isConnected:!0}}const It=()=>{},kt=[];function Mt(t,e,r){const a=t/e;if(r>=a){const n=e,l=n*r,s=t/l;return{width:l,height:n,cropX:(1-s)/2,cropY:0,cropWidth:s,cropHeight:1}}else{const n=t,l=n/r,s=e/l;return{width:n,height:l,cropX:0,cropY:(1-s)/2,cropWidth:1,cropHeight:s}}}function Tt(t,e){const r=(e==null?void 0:e.fit)??"cover",{elementStore:a,setElements:n}=B.useElementsContext(),{executeElementUpdate:l}=B.useCommandContext(),s=o.useMemo(()=>a.getAllByName(t).filter(y=>y instanceof U.ImageElement),[a,t]),c=o.useRef(new Map);for(const k of s)if(!c.current.has(k.id)){const y=k.transformData;c.current.set(k.id,{width:y.width*y.cropWidth,height:y.height*y.cropHeight})}const d=o.useRef(s);d.current=s;const b=o.useRef(l);b.current=l;const S=o.useRef(n);S.current=n;const L=o.useCallback(k=>{const y=d.current,T=b.current;S.current;for(const w of y){const P=c.current.get(w.id);if(!P)continue;const{width:A,height:h}=P,R=w.clone();R.imageLoaded=!1,R.imageElement=null,R.isCropping=!1,R.imageUrl=k,r==="cover"?(R.preserveDimensions=!0,R.onLoadCallback=E=>{const W=E.imageAspectRatio||1,F=Mt(A,h,W);E.transformData.width=F.width,E.transformData.height=F.height,E.transformData.cropX=F.cropX,E.transformData.cropY=F.cropY,E.transformData.cropWidth=F.cropWidth,E.transformData.cropHeight=F.cropHeight,T(w,E)}):(R.preserveDimensions=!1,R.onLoadCallback=E=>{const W=E.transformData.width,F=E.transformData.height,Y=Math.min(A/W,h/F,1);Y<1&&(E.transformData.width=W*Y,E.transformData.height=F*Y),E.transformData.cropX=0,E.transformData.cropY=0,E.transformData.cropWidth=1,E.transformData.cropHeight=1,T(w,E)}),R.loadImage(k)}},[r]);return s.length===0?{imageUrl:"",setImageUrl:It,element:null,elements:kt,isConnected:!1}:{imageUrl:s[0].imageUrl,setImageUrl:L,element:s[0],elements:s,isConnected:!0}}function Ft(t){const{elementStore:e}=B.useElementsContext();return t?e.getByName(t)??null:null}function Dt(){const{zoom:t,panOffset:e,zoomIn:r,zoomOut:a,zoomToFit:n,resetView:l,setZoom:s,setPanOffset:c}=B.useViewportContext();return{zoom:t,panOffset:e,zoomIn:r,zoomOut:a,zoomToFit:n,resetView:l,setZoom:s,setPanOffset:c}}function Lt(t){var a;const e=((a=t.artboards)==null?void 0:a[0])||{name:"Front",width:800,height:800},r=(t.elements||[]).map(Pt);return{artboards:[{id:"artboard-1",name:e.name||"Front",x:0,y:0,width:e.width||800,height:e.height||800,backgroundColor:e.backgroundColor||"transparent",exportBackground:!1,elements:r,distressTexture:e.distressTexture,imageMask:e.imageMask}]}}function Pt(t){const e=t.type||t.transformType;return e==="image"?Ht(t):{...t,type:e}}function Ht(t){var b;const e=t.transformData||{},r=t.masks&&t.masks.length>0,a=e.width||0,n=e.height||0,l=r?a:a*(e.cropWidth??1),s=r?n:n*(e.cropHeight??1),c={id:t.id,type:"image",x:t.x||0,y:t.y||0,width:l,height:s,rotation:t.rotation||0,imageUrl:t.imageUrl,imageAspectRatio:t.imageAspectRatio};return!r&&(e.cropX!==0||e.cropY!==0||e.cropWidth!==1||e.cropHeight!==1)&&(c.cropX=e.cropX,c.cropY=e.cropY,c.cropWidth=e.cropWidth,c.cropHeight=e.cropHeight,c.needsCropPixelConversion=!0),e.flipHorizontal&&(c.flipHorizontal=e.flipHorizontal),e.flipVertical&&(c.flipVertical=e.flipVertical),e.borderRadius&&(c.borderRadius=e.borderRadius),t.opacity!==void 0&&(c.opacity=t.opacity),t.distressEffect&&(c.distressEffect=t.distressEffect),((b=t.masks)==null?void 0:b.length)>0&&(c.masks=t.masks),t.blendMode&&(c.blendMode=t.blendMode),t.knockoutParts&&(c.knockoutParts=t.knockoutParts),t.stroke&&(c.stroke=t.stroke),c}I.ensureIconsRegistered();exports.ALL_CAPABILITIES=I.ALL_CAPABILITIES;exports.COMPACT_CUSTOMIZER=I.COMPACT_CUSTOMIZER;exports.EMBED_ONLY=I.EMBED_ONLY;exports.MINIMAL_CAPABILITIES=I.MINIMAL_CAPABILITIES;exports.PRO_STUDIO=I.PRO_STUDIO;exports.createKit=I.createKit;exports.extendKit=I.extendKit;exports.resolveKit=I.resolveKit;exports.useArtboards=I.useArtboards;exports.useExport=I.useExport;exports.useLayers=I.useLayers;exports.validateKit=I.validateKit;exports.useEditor=B.useEditor;exports.deserializeState=de.deserializeState;exports.migrateState=de.migrateState;exports.serializeState=de.serializeState;exports.validateState=de.validateState;exports.ErrorBoundary=ze;exports.SnowconeCanvas=ve;exports.default=ve;exports.serializeStateForServer=Lt;exports.useAutoExport=Oe;exports.useCanvasReady=At;exports.useCommands=wt;exports.useContentReady=$e;exports.useElementByName=Ft;exports.useImageBinding=Tt;exports.useSelectedElement=yt;exports.useTextBinding=Ct;exports.useViewport=Dt;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const I=require("./compose-Bo108juW.cjs"),U=require("./HybridHistoryManager-BXD93pp8.cjs"),C=require("react/jsx-runtime"),o=require("react"),B=require("./ThemeContext-4mJ_y0Me.cjs"),le=require("./ElementFactory-B7UOaJSD.cjs"),de=require("./CanvasStateV1-D5GzvmnY.cjs"),ct=U.createLogger("ErrorBoundary");class ze extends o.Component{constructor(e){super(e),this.resetError=()=>{this.setState({hasError:!1,error:null})},this.state={hasError:!1,error:null}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,r){if(ct.error("Caught error:",e,r),this.props.onError&&this.props.onError(e,r),this.props.onCanvasError){const a={category:"unknown",message:e.message,originalError:e,recoverable:!1};this.props.onCanvasError(a)}}render(){return this.state.hasError&&this.state.error?this.props.renderError?this.props.renderError(this.state.error,this.resetError):this.props.fallback?typeof this.props.fallback=="function"?this.props.fallback(this.state.error,this.resetError):this.props.fallback:C.jsxs("div",{style:{padding:"24px",border:"2px solid var(--danger)",borderRadius:"8px",backgroundColor:"color-mix(in oklch, var(--danger) 10%, var(--background))",color:"var(--danger)",fontFamily:"system-ui, sans-serif"},children:[C.jsx("h2",{style:{margin:"0 0 16px 0",fontSize:"18px",fontWeight:600},children:"Something went wrong"}),C.jsx("pre",{style:{margin:"0 0 16px 0",padding:"12px",backgroundColor:"color-mix(in oklch, var(--danger) 15%, var(--background))",borderRadius:"4px",fontSize:"14px",overflow:"auto",maxHeight:"200px"},children:this.state.error.message}),C.jsx("button",{onClick:this.resetError,style:{padding:"8px 16px",backgroundColor:"var(--danger)",color:"var(--danger-foreground)",border:"none",borderRadius:"4px",fontSize:"14px",fontWeight:500,cursor:"pointer"},children:"Try again"})]}):this.props.children}}const lt=U.createLogger("useAutoExport");function Oe(t){const{config:e,historyManager:r,artboards:a,elements:n,onExport:l,onExportScheduled:s,isCanvasReady:c=!1}=t,d=o.useRef(null),b=o.useRef(!1),S=o.useRef({totalExports:0,skippedExports:0,lastExportTime:null,avgExportInterval:0}),[L,k]=o.useState(S.current),y=o.useRef(l);y.current=l,o.useEffect(()=>{const h=new I.AutoExportManager({...I.DEFAULT_AUTO_EXPORT_CONFIG,...e});return h.onExport(async()=>{try{await y.current(),S.current=h.getStats()}catch(R){lt.error("[useAutoExport] Export failed:",R)}}),d.current=h,()=>{h.destroy()}},[]),o.useEffect(()=>{c&&b.current&&d.current&&(b.current=!1,d.current.forceExport())},[c]),o.useEffect(()=>{d.current&&e&&d.current.updateConfig(e)},[e==null?void 0:e.enabled,e==null?void 0:e.debounceMs,e==null?void 0:e.maxWaitMs]),o.useEffect(()=>{d.current&&s&&d.current.onExportScheduled(s)},[s]),o.useEffect(()=>{if(!r||!d.current)return;const h=r.onCommandExecuted(()=>{if(d.current){if(!c){b.current=!0;return}d.current.scheduleExport()}});return()=>{h()}},[r,c]),o.useEffect(()=>{if(d.current){if(!c){b.current=!0;return}d.current.scheduleExport()}},[n,a,c]),o.useEffect(()=>U.subscribeToImageLoads(R=>{if(!d.current||!c)return;n.some(N=>N.id===R)&&d.current.scheduleExport()}),[n,c]);const T=o.useCallback(h=>{d.current&&d.current.updateConfig(h)},[]),w=o.useCallback(async()=>{d.current&&(await d.current.forceExport(),S.current=d.current.getStats(),k(S.current))},[]),P=o.useCallback(()=>{d.current&&(d.current.resetStats(),S.current=d.current.getStats(),k(S.current))},[]),A=o.useCallback(()=>{d.current&&d.current.resetChangeDetection()},[]);return{stats:L,updateConfig:T,forceExport:w,resetStats:P,resetChangeDetection:A}}const Ye=U.createLogger("useContentReady");function dt(t){var r;const e=new Set;for(const a of t)if("fontFamily"in a&&typeof a.fontFamily=="string"&&a.fontFamily&&e.add(a.fontFamily),"getRichText"in a&&typeof a.getRichText=="function")try{const n=a.getRichText();if(n!=null&&n.spans)for(const l of n.spans)(r=l.style)!=null&&r.fontFamily&&e.add(l.style.fontFamily)}catch{}return Array.from(e)}async function ut(t){if(t.length===0||typeof document>"u"||!document.fonts)return;const e=[];for(const r of t){const a=`16px "${r}"`;e.push(document.fonts.load(a))}await Promise.all(e),document.fonts.ready&&await Promise.race([document.fonts.ready,new Promise(r=>setTimeout(r,250))]),Ye.debug(`Awaited ${e.length} font(s)`)}function ft(){return new Promise(t=>requestAnimationFrame(()=>t()))}function $e(t){const{isCanvasReady:e,elements:r,hasInitialElements:a,initialElementsLoaded:n}=t,[l,s]=o.useState(!1),c=o.useRef(!1);return o.useEffect(()=>{if(l||!e||a&&!n||a&&r.length===0||c.current)return;c.current=!0;let d=!1;return(async()=>{try{const b=dt(r);if(b.length>0&&(await ut(b),d)||(await ft(),d))return;s(!0)}catch(b){Ye.error("Error during content readiness check:",b),d||s(!0)}finally{c.current=!1}})(),()=>{d=!0,c.current=!1}},[e,r,a,n,l]),l}const mt={"far-top":"t",top:"t",center:"c",bottom:"b","far-bottom":"b","far-left":"l",left:"l",right:"r","far-right":"r",tl:"tl",t:"t",tr:"tr",l:"l",c:"c",r:"r",bl:"bl",b:"b",br:"br"};function ht(t){return t&&mt[t]||"c"}function gt(t,e){const r=e.scaleMode||"cover",a=(r==="contain"?e.marginTop:0)||0,n=(r==="contain"?e.marginRight:0)||0,l=(r==="contain"?e.marginBottom:0)||0,s=(r==="contain"?e.marginLeft:0)||0,c=e.width-s-n,d=e.height-a-l,b=c/t.width,S=d/t.height,L=r==="contain"?Math.min(b,S):Math.max(b,S),k=e.scale||1,y=L*k,T=t.width*y,w=t.height*y,P=e.align||"c";let A=0,h=0;const R=T-c,x=w-d;switch(P){case"tl":A=0,h=0;break;case"t":A=-R/2,h=0;break;case"tr":A=-R,h=0;break;case"l":A=0,h=-x/2;break;case"c":default:A=-R/2,h=-x/2;break;case"r":A=-R,h=-x/2;break;case"bl":A=0,h=-x;break;case"b":A=-R/2,h=-x;break;case"br":A=-R,h=-x;break}A+=s,h+=a;const N=e.offsetX||0,F=e.offsetY||0,Y=R,_=x;return A+=N*Y,h+=F*_,A=Math.round(A),h=Math.round(h),{scale:y,width:Math.round(T),height:Math.round(w),x:A,y:h,debug:{coverScale:L,userScale:k,overflow:{x:R,y:x},alignment:P,appliedOffset:{x:N*Y,y:F*_}}}}const pt={timeout:3e4,retries:1,retryDelay:1e3,validateUrl:!0};function bt(t){try{const e=new URL(t);return["http:","https:","data:","blob:"].includes(e.protocol)}catch{return!1}}async function Et(t,e={}){const r={...pt,...e};if(r.validateUrl&&!bt(t))return{success:!1,error:new Error(`Invalid image URL: ${t}`)};let a;for(let n=0;n<=r.retries;n++)try{return await xt(t,r.timeout)}catch(l){a=l instanceof Error?l:new Error(String(l)),n<r.retries&&await wt(r.retryDelay)}return{success:!1,error:a||new Error("Failed to load image after retries")}}function xt(t,e){return new Promise(r=>{const a=new Image;a.crossOrigin="anonymous";let n=null,l=!1;const s=()=>{n&&(clearTimeout(n),n=null)},c=()=>{if(l)return;l=!0,s();const b=a.naturalWidth||a.width,S=a.naturalHeight||a.height;r({success:!0,element:a,width:b,height:S,aspectRatio:S>0?b/S:1})},d=b=>{l||(l=!0,s(),r({success:!1,error:new Error(b)}))};a.onload=c,a.onerror=()=>{d(`Failed to load image: ${t}`)},n=setTimeout(()=>{d(`Image load timed out after ${e}ms: ${t}`)},e),a.src=t})}async function vt(t,e,r={},a={}){var k,y,T,w,P,A,h;const n=await Et(t,a);if(!n.success||!n.width||!n.height)return{success:!1,error:n.error||new Error("Failed to get image dimensions")};const l={width:e.artboard.width,height:e.artboard.height,scale:e.scale,align:ht(e.alignment),offsetX:e.offsetX,offsetY:e.offsetY,scaleMode:e.scaleMode,marginTop:e.marginTop,marginRight:e.marginRight,marginBottom:e.marginBottom,marginLeft:e.marginLeft},s=gt({width:n.width,height:n.height},l),c=e.artboard.x+s.x,d=e.artboard.y+s.y,b=c+s.width/2,S=d+s.height/2;return{success:!0,element:new U.ImageElement({...r,x:b,y:S,imageUrl:t,imageAspectRatio:n.aspectRatio,preserveDimensions:!0,transformData:{type:"image",width:s.width,height:s.height,cropX:((k=r.transformData)==null?void 0:k.cropX)??0,cropY:((y=r.transformData)==null?void 0:y.cropY)??0,cropWidth:((T=r.transformData)==null?void 0:T.cropWidth)??1,cropHeight:((w=r.transformData)==null?void 0:w.cropHeight)??1,flipHorizontal:((P=r.transformData)==null?void 0:P.flipHorizontal)??!1,flipVertical:((A=r.transformData)==null?void 0:A.flipVertical)??!1,borderRadius:((h=r.transformData)==null?void 0:h.borderRadius)??0}}),placement:{artworkSize:{width:n.width,height:n.height},finalSize:{width:s.width,height:s.height},position:{x:b,y:S},scale:s.scale}}}function wt(t){return new Promise(e=>setTimeout(e,t))}const K=U.createLogger("SnowconeCanvas");function xe(t,e,r,a){if(a<=0||!isFinite(a))return r;const n=t*r,l=e*r;if(Math.max(n,l)<=a)return r;const c=Math.max(t,e),d=a/c;return Math.min(d,r)}const Xe=o.forwardRef((t,e)=>{const{exportConfig:r,imageConfig:a,layoutConfig:n,kit:l,artboards:s,activeArtboard:c,onArtboardChange:d,initialElements:b,onChange:S,onSelectionChange:L,autoExportInterval:k,onExport:y,onExportScheduled:T,onExportStatus:w,onExportReady:P,onImageLoad:A,onImageError:h,onError:R,onReady:x,className:N,style:F,enableShortcuts:Y,overlay:_}=t,we=k,Z=t.autoExportConfig??(r==null?void 0:r.autoExportConfig),q=t.autoExportFormat??(r==null?void 0:r.format)??"dataUrl",ue=t.autoExportAll??(r==null?void 0:r.exportAll)??!1,X=t.exportScale??(r==null?void 0:r.scale)??2,j=t.maxExportSize??(r==null?void 0:r.maxSize)??4e3,ee=t.exportImageFormat??(r==null?void 0:r.imageFormat)??"png",te=t.exportImageQuality??(r==null?void 0:r.imageQuality)??.92,z=t.initialImage??(a==null?void 0:a.src),ye=t.initialImageAlignment??(a==null?void 0:a.alignment)??"center",Ae=t.initialImageScale??(a==null?void 0:a.scale)??1,Se=t.initialImageScaleMode??(a==null?void 0:a.scaleMode)??"cover",Ke=t.width??(n==null?void 0:n.width)??1200,qe=t.height??(n==null?void 0:n.height)??1200,Re=t.viewPadding??(n==null?void 0:n.viewPadding)??.9,Ce=t.artboardBorderRadius??(n==null?void 0:n.artboardBorderRadius)??0,Ie=t.fixedMargin??(n==null?void 0:n.fixedMargin),ke=t.maxHeight??(n==null?void 0:n.maxHeight),Me=t.showRotationHandle??(n==null?void 0:n.showRotationHandle)??!0,Ge=t.hideCanvas??(n==null?void 0:n.hideCanvas)??!1,Te=t.canvasWrapperClassName??(n==null?void 0:n.canvasWrapperClassName),Fe=t.canvasWrapperStyle??(n==null?void 0:n.canvasWrapperStyle),De=t.canvasCutouts??(n==null?void 0:n.canvasCutouts),fe=t.pieceGuides,Le=t.pieceFocus,Pe=Y??!0,re=o.useMemo(()=>I.resolveKit(l??"pro-studio"),[l]);o.useEffect(()=>{if(U.process$1.env.NODE_ENV==="development"&&re){const i=I.validateKit(re);i.valid||K.warn("Kit validation warnings:",i.errors),i.warnings.length>0&&K.warn("Kit validation warnings:",i.warnings)}},[re]);const ne=o.useRef(R);ne.current=R;const W=o.useCallback(i=>{var u;K.error(`[${i.category}] ${i.message}`,i.originalError),(u=ne.current)==null||u.call(ne,i)},[]);o.useEffect(()=>(le.CanvasRenderer.onRenderError=W,()=>{le.CanvasRenderer.onRenderError===W&&(le.CanvasRenderer.onRenderError=null)}),[W]);const{elements:V,setElements:ae,selectedId:He,artboardManager:M,refreshArtboards:Qe,historyManager:Ze,isCanvasReady:me,setCanvasReady:oe}=B.useEditor(),{createArtboard:Je,selectArtboard:_e,artboards:H}=I.useArtboards(),{exportArtboard:G,exportAllArtboards:se,exportArtboardAsBlob:Q,exportAllArtboardsAsBlobs:ie}=I.useExport();o.useImperativeHandle(e,()=>({exportArtboards:async(i={})=>{const u=i.format||q,g=i.scale||X,p=i.all??!1;let m=g;if(j>0&&isFinite(j))for(const v of H){const E=xe(v.width,v.height,g,j);m=Math.min(m,E)}const f={scale:m,format:ee,quality:te};if(p){const v=u==="blob"?await ie(f):await se(f),E={};for(const[D,O]of Object.entries(v)){const $=H.find(J=>J.id===D);$&&(E[$.name]=O)}return E}else{const v=M.getActiveArtboard();if(!v)throw new Error("[SnowconeCanvas] No active artboard found");if(u==="blob"){const E=await Q(v.id,f);return{[v.name]:E}}else{const E=await G(v.id,f);return{[v.name]:E}}}}}),[G,se,Q,ie,q,X,j,ee,te,M,H]),o.useEffect(()=>{P&&P(async()=>{const u=M.getActiveArtboard();if(!u)throw new Error("[SnowconeCanvas] No active artboard found");const g=xe(u.width,u.height,X,j),p=q==="blob"?await Q(u.id,{scale:g}):await G(u.id,{scale:g});return{[u.name]:p}})},[P,G,Q,M,q,X,j]);const[Be,ce]=o.useState("idle"),[Ne,he]=o.useState(null),ge=o.useRef(void 0),pe=o.useRef(!1),We=o.useRef(!1),[et,tt]=o.useState(!1),rt=o.useRef(0),nt=o.useRef(0),be=o.useRef(!1);o.useEffect(()=>{if(pe.current)return;pe.current=!0;const i=s||[{name:"Design",width:Ke,height:qe}],u=M.getAllArtboards();if(u.length>0){const g=i[0],p=u[0],m=fe?"transparent":void 0;p.name=g.name,p.width=g.width,p.height=g.height,p.clipShape=g.clipShape,g.backgroundColor?p.backgroundColor=g.backgroundColor:m&&(p.backgroundColor=m);for(let f=1;f<i.length;f++)Je(i[f].width,i[f].height,{name:i[f].name,backgroundColor:i[f].backgroundColor??m,clipShape:i[f].clipShape})}Qe()},[]),o.useEffect(()=>{if(!(!b||b.length===0)&&!We.current&&pe.current){We.current=!0,tt(!0);try{const i=le.ElementFactory.createManyFromJSON(b),u=M.getAllArtboards();if(u.length>0){const p=u[0];for(const m of i)M.addElementToArtboard(m.id,p.id)}ae(i);const g=new Set;for(const p of i){const m=p.fontFamily;typeof m=="string"&&m.trim().length>0&&g.add(m)}if(g.size>0&&typeof document<"u"){const p=document.fonts??null,m=Array.from(g).map(f=>{const v=`font-${f.replace(/\s+/g,"-").toLowerCase()}`;let E=document.getElementById(v);return E||(E=document.createElement("link"),E.id=v,E.rel="stylesheet",E.href=`https://fonts.googleapis.com/css2?family=${f.replace(/\s+/g,"+")}:wght@400;700&display=swap`,document.head.appendChild(E)),new Promise(D=>{if(E.sheet){D(f);return}const O=()=>D(f);E.addEventListener("load",O,{once:!0}),E.addEventListener("error",O,{once:!0}),setTimeout(O,4e3)})});Promise.all(m).then(f=>{if(p)return Promise.all(f.flatMap(v=>[p.load(`400 16px "${v}"`).catch(()=>{}),p.load(`700 16px "${v}"`).catch(()=>{})]))}).then(()=>{ae(f=>f.slice())})}}catch(i){K.error("Failed to load initial elements:",i);const u=i instanceof Error?i:new Error(String(i));W({category:"import",message:`Failed to load initial elements: ${u.message}`,originalError:u,recoverable:!0})}}},[b,M,ae,W]),o.useEffect(()=>{if(!c){be.current=!0;return}const i=H.find(u=>u.name===c);if(i){const u=M.getActiveArtboard();(u==null?void 0:u.name)!==c&&_e(i.id),be.current=!0}},[c,H]),o.useEffect(()=>{if(!z||ge.current===z)return;if(V.length>0){ge.current=z;return}ge.current=z,(async()=>{ce("loading"),he(null);try{const u=M.getAllArtboards();if(u.length===0)throw new Error("No artboards available");const g=[];for(const p of u){const m=s==null?void 0:s.find(E=>E.name===p.name),f=(m==null?void 0:m.scaleMode)||Se,v=await vt(z,{artboard:{width:p.width,height:p.height,x:p.x,y:p.y},alignment:(m==null?void 0:m.fitAlign)||ye,scale:Ae,scaleMode:f,marginTop:m==null?void 0:m.fitMarginTop,marginRight:m==null?void 0:m.fitMarginRight,marginBottom:m==null?void 0:m.fitMarginBottom,marginLeft:m==null?void 0:m.fitMarginLeft});v.success&&v.element?(M.addElementToArtboard(v.element.id,p.id),g.push(v.element)):K.error("Failed to load image for artboard:",p.name,v.error)}if(g.length>0)ae(p=>[...p,...g]),ce("success"),A==null||A(z);else{const p=new Error("Failed to load image into any artboard");ce("error"),he(p),h==null||h(z,p),W({category:"image",message:p.message,originalError:p,recoverable:!0})}}catch(u){const g=u instanceof Error?u:new Error(String(u));ce("error"),he(g),h==null||h(z,g),W({category:"image",message:g.message,originalError:g,recoverable:!0})}})()},[z,ye,Ae,Se]),o.useEffect(()=>{L==null||L(He)},[He,L]),o.useEffect(()=>{if(!S)return;const i=M.getActiveArtboard(),u={elements:V.map(g=>g.toJSON()),artboards:H.map(g=>({name:g.name,width:g.width,height:g.height,clipShape:g.clipShape,backgroundColor:g.backgroundColor})),activeArtboard:(i==null?void 0:i.name)||"Design"};S(u)},[V,H,S]),o.useEffect(()=>{if(!d||!be.current)return;const i=M.getActiveArtboard();i&&d(i.name)},[M.getActiveArtboardId()]);const at=o.useCallback(async()=>{if(!y&&!w)return;const i=++nt.current,u=Date.now();let g=X;if(j>0&&isFinite(j))for(const f of H){const v=xe(f.width,f.height,X,j);g=Math.min(g,v)}const p=M.getActiveArtboard(),m=(p==null?void 0:p.id)??"unknown";w==null||w({status:"rendering",artboardId:m}),rt.current=u;try{let f;const v={format:ee,scale:g,quality:te};if(q==="blob")if(ue){const E=await ie(v);f={};for(const[D,O]of Object.entries(E)){const $=H.find(J=>J.id===D);$&&(f[$.name]=O)}}else{const E=M.getActiveArtboard();if(!E)return;const D=await Q(E.id,v);f={[E.name]:D}}else if(ue){const E=await se(v);f={};for(const[D,O]of Object.entries(E)){const $=H.find(J=>J.id===D);$&&(f[$.name]=O)}}else{const E=M.getActiveArtboard();if(!E)return;const D=await G(E.id,v);f={[E.name]:D}}y==null||y(f),w==null||w({status:"complete",artboardId:m,result:f})}catch(f){const v=f instanceof Error?f.message:String(f);if(v.includes("Canvas ref not available"))return;const E=Date.now()-u;K.error("Export failed (export #"+i+"):",{duration:`${E}ms`,error:v});const D=f instanceof Error?f:new Error(v);w==null||w({status:"error",artboardId:m,error:D}),W({category:"export",message:D.message,originalError:D,artboardId:m,recoverable:!0})}},[y,w,ue,q,X,j,ee,te,G,se,Q,ie,H,M,V,Z,W]);o.useEffect(()=>{we!==void 0&&we>0&&K.warn("autoExportInterval is deprecated and ignored. Use autoExportConfig={{ enabled: true, debounceMs: 100, maxWaitMs: 1000 }} instead.")},[]),o.useEffect(()=>{},[V]);const ot=o.useCallback(()=>{if(T==null||T(),w){const i=M.getActiveArtboard();w({status:"scheduled",artboardId:(i==null?void 0:i.id)??"unknown"})}},[T,w,M]),st=!!b&&b.length>0,Ee=$e({isCanvasReady:me,elements:V,hasInitialElements:st,initialElementsLoaded:et}),je=o.useRef(!1);o.useEffect(()=>{Ee&&!je.current&&(je.current=!0,x==null||x())},[Ee,x]),Oe({config:Z?{enabled:Z.enabled??!0,debounceMs:Z.debounceMs??100,maxWaitMs:Z.maxWaitMs??1e3}:{enabled:!1},historyManager:Ze,artboards:H,elements:V,onExport:at,onExportScheduled:ot,isCanvasReady:Ee}),o.useEffect(()=>{if(H.length>0&&!me){const i=requestAnimationFrame(()=>{oe(!0)});return()=>cancelAnimationFrame(i)}},[H.length,me,oe]),o.useEffect(()=>()=>{oe(!1)},[oe]);const it=o.useCallback(i=>{W({category:"unknown",message:i.message,originalError:i,recoverable:!1})},[W]);return Be==="loading"?C.jsx("div",{className:N,style:{...F,display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"var(--surface, #f5f5f5)"},children:C.jsx(I.Spinner,{size:48})}):Be==="error"&&Ne?C.jsx("div",{className:N,style:{...F,display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"var(--surface, #f5f5f5)",color:"var(--danger, #dc2626)",padding:"1rem"},children:C.jsxs("div",{className:"text-center",children:[C.jsx("div",{className:"font-medium",children:"Failed to load image"}),C.jsx("div",{className:"text-sm mt-1 opacity-70",children:Ne.message})]})}):C.jsx(I.KitProvider,{kit:re,children:C.jsx("div",{className:`app-modern ${N||""}`,style:{...F,position:"relative"},children:C.jsxs(ze,{onError:it,fallback:(i,u)=>C.jsxs("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:"24px",minHeight:"200px",backgroundColor:"var(--surface, #f5f5f5)",color:"var(--foreground, #333)",fontFamily:"system-ui, sans-serif",textAlign:"center"},children:[C.jsx("div",{style:{fontSize:"18px",fontWeight:600,marginBottom:"8px"},children:"Something went wrong"}),C.jsx("div",{style:{fontSize:"14px",opacity:.7,marginBottom:"16px",maxWidth:"400px"},children:i.message}),C.jsx("button",{onClick:u,style:{padding:"8px 20px",backgroundColor:"var(--primary, #333)",color:"var(--primary-foreground, #fff)",border:"none",borderRadius:"6px",fontSize:"14px",fontWeight:500,cursor:"pointer"},children:"Try again"})]}),children:[!Ge&&(Te||Fe?C.jsx("div",{className:Te,style:Fe,children:C.jsx(I.Canvas,{style:{width:"100%"},fitPadding:Re,artboardBorderRadius:Ce,fixedMargin:Ie,maxHeight:ke,showRotationHandle:Me,enableShortcuts:Pe,canvasCutouts:De,pieceGuides:fe,pieceFocus:Le})}):C.jsx(I.Canvas,{style:{width:"100%"},fitPadding:Re,artboardBorderRadius:Ce,fixedMargin:Ie,maxHeight:ke,showRotationHandle:Me,enableShortcuts:Pe,canvasCutouts:De,pieceGuides:fe,pieceFocus:Le})),_]})})})});Xe.displayName="SnowconeCanvasInner";const ve=o.forwardRef((t,e)=>{var s;const{inheritTheme:r,externalProvider:a}=t,n=t.viewPadding??((s=t.layoutConfig)==null?void 0:s.viewPadding),l=C.jsx(Xe,{ref:e,...t});return a?C.jsx(B.ThemeProvider,{defaultTheme:"light",passive:r,children:l}):C.jsx(B.ThemeProvider,{defaultTheme:"light",passive:r,children:C.jsx(B.EditorProvider,{viewPadding:n,children:l})})});ve.displayName="SnowconeCanvas";const Ue=U.createLogger("useCommands");function yt(){const t=B.useEditor(),{undo:e,redo:r,canUndo:a,canRedo:n,executeElementUpdate:l,executeAddElement:s,executeRemoveElement:c,executeReorderElement:d,executeCommandBatch:b,executeCreateArtboard:S,executeDeleteArtboard:L,executeUpdateArtboard:k}=t,y=o.useCallback(()=>{Ue.warn("[useCommands] clearHistory is not yet implemented in EditorContext")},[]),T=o.useCallback(w=>{Ue.warn("[useCommands] clearArtboardHistory is not yet implemented in EditorContext")},[]);return{undo:e,redo:r,canUndo:a,canRedo:n,clearHistory:y,clearArtboardHistory:T,executeElementUpdate:l,executeAddElement:s,executeRemoveElement:c,executeReorderElement:d,executeCreateArtboard:S,executeDeleteArtboard:L,executeUpdateArtboard:k,executeCommandBatch:b}}function At(){const{selectedElement:t}=B.useEditor();return t??null}function St(){const{isCanvasReady:t}=B.useEditor();return t}const Rt=()=>{},Ct=[];function It(t){const{elementStore:e}=B.useElementsContext(),{executeElementUpdate:r}=B.useCommandContext(),a=o.useMemo(()=>e.getAllByName(t).filter(s=>s instanceof U.TextElement),[e,t]),n=o.useCallback(l=>{for(const s of a){const c=s.clone();c.setText(l),r(s,c)}},[a,r]);return a.length===0?{text:"",setText:Rt,element:null,elements:Ct,isConnected:!1}:{text:a[0].getText(),setText:n,element:a[0],elements:a,isConnected:!0}}const kt=()=>{},Mt=[];function Tt(t,e,r){const a=t/e;if(r>=a){const n=e,l=n*r,s=t/l;return{width:l,height:n,cropX:(1-s)/2,cropY:0,cropWidth:s,cropHeight:1}}else{const n=t,l=n/r,s=e/l;return{width:n,height:l,cropX:0,cropY:(1-s)/2,cropWidth:1,cropHeight:s}}}function Ft(t,e){const r=(e==null?void 0:e.fit)??"cover",{elementStore:a,setElements:n}=B.useElementsContext(),{executeElementUpdate:l}=B.useCommandContext(),s=o.useMemo(()=>a.getAllByName(t).filter(y=>y instanceof U.ImageElement),[a,t]),c=o.useRef(new Map);for(const k of s)if(!c.current.has(k.id)){const y=k.transformData;c.current.set(k.id,{width:y.width*y.cropWidth,height:y.height*y.cropHeight})}const d=o.useRef(s);d.current=s;const b=o.useRef(l);b.current=l;const S=o.useRef(n);S.current=n;const L=o.useCallback(k=>{const y=d.current,T=b.current;S.current;for(const w of y){const P=c.current.get(w.id);if(!P)continue;const{width:A,height:h}=P,R=w.clone();R.imageLoaded=!1,R.imageElement=null,R.isCropping=!1,R.imageUrl=k,r==="cover"?(R.preserveDimensions=!0,R.onLoadCallback=x=>{const N=x.imageAspectRatio||1,F=Tt(A,h,N);x.transformData.width=F.width,x.transformData.height=F.height,x.transformData.cropX=F.cropX,x.transformData.cropY=F.cropY,x.transformData.cropWidth=F.cropWidth,x.transformData.cropHeight=F.cropHeight,T(w,x)}):(R.preserveDimensions=!1,R.onLoadCallback=x=>{const N=x.transformData.width,F=x.transformData.height,Y=Math.min(A/N,h/F,1);Y<1&&(x.transformData.width=N*Y,x.transformData.height=F*Y),x.transformData.cropX=0,x.transformData.cropY=0,x.transformData.cropWidth=1,x.transformData.cropHeight=1,T(w,x)}),R.loadImage(k)}},[r]);return s.length===0?{imageUrl:"",setImageUrl:kt,element:null,elements:Mt,isConnected:!1}:{imageUrl:s[0].imageUrl,setImageUrl:L,element:s[0],elements:s,isConnected:!0}}function Dt(t){const{elementStore:e}=B.useElementsContext();return t?e.getByName(t)??null:null}function Lt(){const{zoom:t,panOffset:e,zoomIn:r,zoomOut:a,zoomToFit:n,resetView:l,setZoom:s,setPanOffset:c}=B.useViewportContext();return{zoom:t,panOffset:e,zoomIn:r,zoomOut:a,zoomToFit:n,resetView:l,setZoom:s,setPanOffset:c}}const Ve=1;function Pt(t){var a;const e=((a=t.artboards)==null?void 0:a[0])||{name:"Front",width:800,height:800},r=(t.elements||[]).map(Ht);return{schemaVersion:Ve,artboards:[{id:"artboard-1",name:e.name||"Front",x:0,y:0,width:e.width||800,height:e.height||800,backgroundColor:e.backgroundColor||"transparent",exportBackground:!1,elements:r,distressTexture:e.distressTexture,imageMask:e.imageMask}]}}function Ht(t){const e=t.type||t.transformType;return e==="image"?Bt(t):{...t,type:e}}function Bt(t){var b;const e=t.transformData||{},r=t.masks&&t.masks.length>0,a=e.width||0,n=e.height||0,l=r?a:a*(e.cropWidth??1),s=r?n:n*(e.cropHeight??1),c={id:t.id,type:"image",x:t.x||0,y:t.y||0,width:l,height:s,rotation:t.rotation||0,imageUrl:t.imageUrl,imageAspectRatio:t.imageAspectRatio};return!r&&(e.cropX!==0||e.cropY!==0||e.cropWidth!==1||e.cropHeight!==1)&&(c.cropX=e.cropX,c.cropY=e.cropY,c.cropWidth=e.cropWidth,c.cropHeight=e.cropHeight,c.needsCropPixelConversion=!0),e.flipHorizontal&&(c.flipHorizontal=e.flipHorizontal),e.flipVertical&&(c.flipVertical=e.flipVertical),e.borderRadius&&(c.borderRadius=e.borderRadius),t.opacity!==void 0&&(c.opacity=t.opacity),t.distressEffect&&(c.distressEffect=t.distressEffect),((b=t.masks)==null?void 0:b.length)>0&&(c.masks=t.masks),t.blendMode&&(c.blendMode=t.blendMode),t.knockoutParts&&(c.knockoutParts=t.knockoutParts),t.stroke&&(c.stroke=t.stroke),c}I.ensureIconsRegistered();exports.ALL_CAPABILITIES=I.ALL_CAPABILITIES;exports.COMPACT_CUSTOMIZER=I.COMPACT_CUSTOMIZER;exports.EMBED_ONLY=I.EMBED_ONLY;exports.MINIMAL_CAPABILITIES=I.MINIMAL_CAPABILITIES;exports.PRO_STUDIO=I.PRO_STUDIO;exports.createKit=I.createKit;exports.extendKit=I.extendKit;exports.resolveKit=I.resolveKit;exports.useArtboards=I.useArtboards;exports.useExport=I.useExport;exports.useLayers=I.useLayers;exports.validateKit=I.validateKit;exports.useEditor=B.useEditor;exports.deserializeState=de.deserializeState;exports.migrateState=de.migrateState;exports.serializeState=de.serializeState;exports.validateState=de.validateState;exports.CANVAS_STATE_SCHEMA_VERSION=Ve;exports.ErrorBoundary=ze;exports.SnowconeCanvas=ve;exports.default=ve;exports.serializeStateForServer=Pt;exports.useAutoExport=Oe;exports.useCanvasReady=St;exports.useCommands=yt;exports.useContentReady=$e;exports.useElementByName=Dt;exports.useImageBinding=Ft;exports.useSelectedElement=At;exports.useTextBinding=It;exports.useViewport=Lt;
2
2
  //# sourceMappingURL=index.js.map