@tangle-network/agent-app 0.27.2 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/DesignCanvas-AOIVN3SJ.js +12 -0
  2. package/dist/DesignCanvasEditor-TN7CWUJW.js +13 -0
  3. package/dist/{TimelineEditor-JDG54OBP.js → TimelineEditor-Z7C6BFP5.js} +2 -2
  4. package/dist/{apply-Cp8c3K9D.d.ts → apply-Gk4raT2j.d.ts} +3 -1
  5. package/dist/{chunk-AFDROJ64.js → chunk-2QI7XV2T.js} +1 -1
  6. package/dist/chunk-2QI7XV2T.js.map +1 -0
  7. package/dist/{chunk-LUE4HO5C.js → chunk-4IQMTTNE.js} +10 -10
  8. package/dist/chunk-4IQMTTNE.js.map +1 -0
  9. package/dist/{chunk-HABVCJJT.js → chunk-7I37CO5D.js} +271 -404
  10. package/dist/chunk-7I37CO5D.js.map +1 -0
  11. package/dist/{chunk-5RT6KY4G.js → chunk-GQRL6VNU.js} +1 -1
  12. package/dist/chunk-GQRL6VNU.js.map +1 -0
  13. package/dist/{chunk-SCG5JJ4C.js → chunk-HFC4BTWJ.js} +32 -4
  14. package/dist/chunk-HFC4BTWJ.js.map +1 -0
  15. package/dist/{chunk-7QCIYDGC.js → chunk-IOREXWLM.js} +2 -2
  16. package/dist/chunk-J7JNV5BH.js +14 -0
  17. package/dist/chunk-J7JNV5BH.js.map +1 -0
  18. package/dist/{chunk-6UOE5CTA.js → chunk-JT6HHO5P.js} +5 -10
  19. package/dist/chunk-JT6HHO5P.js.map +1 -0
  20. package/dist/{chunk-JZAJE3JL.js → chunk-M2EBUDZ7.js} +19 -5
  21. package/dist/chunk-M2EBUDZ7.js.map +1 -0
  22. package/dist/{chunk-RJ2ZHK5D.js → chunk-S6WS2B32.js} +132 -7
  23. package/dist/chunk-S6WS2B32.js.map +1 -0
  24. package/dist/chunk-SQV7NUEM.js +136 -0
  25. package/dist/chunk-SQV7NUEM.js.map +1 -0
  26. package/dist/chunk-UAKFCMWK.js +1 -0
  27. package/dist/chunk-UAKFCMWK.js.map +1 -0
  28. package/dist/chunk-V5XZKHCL.js +296 -0
  29. package/dist/chunk-V5XZKHCL.js.map +1 -0
  30. package/dist/chunk-XWJXZ6WE.js +604 -0
  31. package/dist/chunk-XWJXZ6WE.js.map +1 -0
  32. package/dist/chunk-Y2SZVW35.js +125 -0
  33. package/dist/chunk-Y2SZVW35.js.map +1 -0
  34. package/dist/{chunk-27LQXQSS.js → chunk-YEWTVDDT.js} +224 -767
  35. package/dist/chunk-YEWTVDDT.js.map +1 -0
  36. package/dist/{chunk-UDXMR3AD.js → chunk-YNALYIQ3.js} +56 -18
  37. package/dist/chunk-YNALYIQ3.js.map +1 -0
  38. package/dist/command-stack-CkjelfK_.d.ts +267 -0
  39. package/dist/design-canvas/drizzle.d.ts +2 -2
  40. package/dist/design-canvas/index.d.ts +7 -6
  41. package/dist/design-canvas/index.js +3 -2
  42. package/dist/design-canvas-react/engine.d.ts +349 -0
  43. package/dist/design-canvas-react/engine.js +86 -0
  44. package/dist/design-canvas-react/engine.js.map +1 -0
  45. package/dist/design-canvas-react/index.d.ts +69 -649
  46. package/dist/design-canvas-react/index.js +84 -173
  47. package/dist/design-canvas-react/index.js.map +1 -1
  48. package/dist/design-canvas-react/lazy.d.ts +6 -0
  49. package/dist/design-canvas-react/lazy.js +9 -0
  50. package/dist/design-canvas-react/lazy.js.map +1 -0
  51. package/dist/{export-presets-Dl5Aa5xj.d.ts → export-presets-DAsU5Wal.d.ts} +2 -143
  52. package/dist/flow-types-Cb_AblZs.d.ts +25 -0
  53. package/dist/index.d.ts +11 -8
  54. package/dist/index.js +21 -8
  55. package/dist/lazy-BHHqS8-j.d.ts +72 -0
  56. package/dist/missions/index.d.ts +12 -0
  57. package/dist/missions/index.js +1 -1
  58. package/dist/{model-BHLN208Z.d.ts → model-BBwyOuWG.d.ts} +3 -1
  59. package/dist/operations-DLIvvD00.d.ts +144 -0
  60. package/dist/platform/index.js +1 -1
  61. package/dist/runtime/index.d.ts +33 -33
  62. package/dist/runtime/index.js +1 -1
  63. package/dist/sequences/index.d.ts +1 -1
  64. package/dist/sequences/index.js +2 -1
  65. package/dist/sequences-react/index.d.ts +15 -1
  66. package/dist/sequences-react/index.js +2 -2
  67. package/dist/{store-CUStmtdH.d.ts → store-CFyxgTlD.d.ts} +1 -1
  68. package/dist/theme/index.d.ts +80 -0
  69. package/dist/theme/index.js +14 -0
  70. package/dist/theme/index.js.map +1 -0
  71. package/dist/theme/tailwind-preset.d.ts +65 -0
  72. package/dist/theme/tailwind-preset.js +33 -0
  73. package/dist/theme/tailwind-preset.js.map +1 -0
  74. package/dist/theme/tokens.css +95 -0
  75. package/dist/trace/index.d.ts +2 -18
  76. package/dist/trace/index.js +2 -2
  77. package/dist/web/index.d.ts +25 -2
  78. package/dist/web/index.js +3 -1
  79. package/dist/web-react/index.d.ts +71 -31
  80. package/dist/web-react/index.js +625 -486
  81. package/dist/web-react/index.js.map +1 -1
  82. package/package.json +28 -3
  83. package/dist/DesignCanvas-73IUJJUP.js +0 -10
  84. package/dist/DesignCanvasEditor-6F2UTOSW.js +0 -9
  85. package/dist/chunk-27LQXQSS.js.map +0 -1
  86. package/dist/chunk-5RT6KY4G.js.map +0 -1
  87. package/dist/chunk-6UOE5CTA.js.map +0 -1
  88. package/dist/chunk-AFDROJ64.js.map +0 -1
  89. package/dist/chunk-HABVCJJT.js.map +0 -1
  90. package/dist/chunk-JZAJE3JL.js.map +0 -1
  91. package/dist/chunk-LUE4HO5C.js.map +0 -1
  92. package/dist/chunk-RJ2ZHK5D.js.map +0 -1
  93. package/dist/chunk-SCG5JJ4C.js.map +0 -1
  94. package/dist/chunk-UDXMR3AD.js.map +0 -1
  95. /package/dist/{DesignCanvas-73IUJJUP.js.map → DesignCanvas-AOIVN3SJ.js.map} +0 -0
  96. /package/dist/{DesignCanvasEditor-6F2UTOSW.js.map → DesignCanvasEditor-TN7CWUJW.js.map} +0 -0
  97. /package/dist/{TimelineEditor-JDG54OBP.js.map → TimelineEditor-Z7C6BFP5.js.map} +0 -0
  98. /package/dist/{chunk-7QCIYDGC.js.map → chunk-IOREXWLM.js.map} +0 -0
@@ -1,564 +1,29 @@
1
+ import {
2
+ addPageCommand,
3
+ bindSlotCommand,
4
+ createSceneCommandStack,
5
+ deleteElementCommand,
6
+ deletePageCommand,
7
+ duplicatePageCommand,
8
+ groupElementsCommand,
9
+ multiSetAttrsCommand,
10
+ reorderElementCommand,
11
+ reorderPageCommand,
12
+ setAttrsCommand,
13
+ setPageGuidesCommand,
14
+ setPagePropsCommand,
15
+ ungroupElementCommand
16
+ } from "./chunk-XWJXZ6WE.js";
1
17
  import {
2
18
  SIZE_PRESETS,
3
- applySceneOperation,
4
- applySceneOperations,
5
19
  findElement,
6
20
  matchPreset,
7
- requireElement,
8
21
  requirePage
9
- } from "./chunk-JZAJE3JL.js";
22
+ } from "./chunk-M2EBUDZ7.js";
10
23
 
11
24
  // src/design-canvas-react/components/DesignCanvas.tsx
12
25
  import { useCallback as useCallback2, useEffect as useEffect3, useMemo, useRef as useRef5, useState as useState5, useSyncExternalStore } from "react";
13
26
 
14
- // src/design-canvas-react/engine/command-stack.ts
15
- var SCENE_COMMAND_HISTORY_LIMIT = 200;
16
- function createSceneCommandStack(document2, activePageId) {
17
- let state = {
18
- document: document2,
19
- activePageId,
20
- selectedElementIds: [],
21
- zoom: 1,
22
- panX: 0,
23
- panY: 0,
24
- gridEnabled: false,
25
- gridSize: 10,
26
- snapEnabled: true,
27
- showRulers: true,
28
- showBleed: false
29
- };
30
- const undoStack = [];
31
- const redoStack = [];
32
- const listeners = /* @__PURE__ */ new Set();
33
- const notify = () => {
34
- for (const listener of [...listeners]) listener();
35
- };
36
- return {
37
- execute(command) {
38
- state = command.execute(state);
39
- undoStack.push(command);
40
- if (undoStack.length > SCENE_COMMAND_HISTORY_LIMIT) {
41
- undoStack.splice(0, undoStack.length - SCENE_COMMAND_HISTORY_LIMIT);
42
- }
43
- redoStack.length = 0;
44
- notify();
45
- },
46
- // Both transforms run BEFORE the stacks move: a throwing transform (e.g.
47
- // missing element after reset()) leaves history and state exactly as they
48
- // were. The entry is never silently destroyed — the caller can retry after
49
- // the next server refresh restores the target.
50
- undo() {
51
- const command = undoStack[undoStack.length - 1];
52
- if (!command) throw new Error("nothing to undo \u2014 guard with canUndo() before calling undo()");
53
- state = command.undo(state);
54
- undoStack.pop();
55
- redoStack.push(command);
56
- notify();
57
- return command;
58
- },
59
- redo() {
60
- const command = redoStack[redoStack.length - 1];
61
- if (!command) throw new Error("nothing to redo \u2014 guard with canRedo() before calling redo()");
62
- state = command.execute(state);
63
- redoStack.pop();
64
- undoStack.push(command);
65
- notify();
66
- return command;
67
- },
68
- canUndo() {
69
- return undoStack.length > 0;
70
- },
71
- canRedo() {
72
- return redoStack.length > 0;
73
- },
74
- subscribe(listener) {
75
- listeners.add(listener);
76
- return () => {
77
- listeners.delete(listener);
78
- };
79
- },
80
- getState() {
81
- return state;
82
- },
83
- setView(patch) {
84
- state = { ...state, ...patch };
85
- notify();
86
- },
87
- rollback(command) {
88
- const idx = undoStack.lastIndexOf(command);
89
- if (idx === -1) return;
90
- state = command.undo(state);
91
- undoStack.splice(idx, 1);
92
- redoStack.length = 0;
93
- notify();
94
- },
95
- /** Rebase onto a server-refreshed document. History survives; selection
96
- * drops ids the refresh removed so view state never dangles. */
97
- reset(newDocument) {
98
- const liveElementIds = /* @__PURE__ */ new Set();
99
- for (const page of newDocument.pages) {
100
- collectElementIds(page.elements, liveElementIds);
101
- }
102
- const activePageExists = newDocument.pages.some((p) => p.id === state.activePageId);
103
- const activePageId2 = activePageExists ? state.activePageId : newDocument.pages[0]?.id ?? state.activePageId;
104
- state = {
105
- ...state,
106
- document: newDocument,
107
- activePageId: activePageId2,
108
- selectedElementIds: state.selectedElementIds.filter((id) => liveElementIds.has(id))
109
- };
110
- notify();
111
- }
112
- };
113
- }
114
- function collectElementIds(elements, ids) {
115
- for (const el of elements) {
116
- ids.add(el.id);
117
- if (el.kind === "group" && Array.isArray(el.children)) {
118
- collectElementIds(el.children, ids);
119
- }
120
- }
121
- }
122
-
123
- // src/design-canvas-react/engine/commands.ts
124
- function applyOps(state, ops) {
125
- return { ...state, document: applySceneOperations(state.document, ops) };
126
- }
127
- function applyOp(state, op) {
128
- return { ...state, document: applySceneOperation(state.document, op) };
129
- }
130
- function addElementCommand(input) {
131
- const addOp = {
132
- type: "add_element",
133
- pageId: input.pageId,
134
- element: structuredClone(input.element),
135
- ...input.index !== void 0 ? { index: input.index } : {},
136
- ...input.parentGroupId !== void 0 ? { parentGroupId: input.parentGroupId } : {}
137
- };
138
- const deleteOp = {
139
- type: "delete_element",
140
- pageId: input.pageId,
141
- elementId: input.element.id
142
- };
143
- return {
144
- label: `Add ${input.element.kind}`,
145
- execute: (state) => applyOp(state, addOp),
146
- undo: (state) => applyOp(state, deleteOp),
147
- operations: () => [structuredClone(addOp)],
148
- inverseOperations: () => [structuredClone(deleteOp)]
149
- };
150
- }
151
- function setAttrsCommand(input) {
152
- const forwardOp = {
153
- type: "set_attrs",
154
- pageId: input.pageId,
155
- elementId: input.elementId,
156
- attrs: structuredClone(input.attrs)
157
- };
158
- const inverseOp = {
159
- type: "set_attrs",
160
- pageId: input.pageId,
161
- elementId: input.elementId,
162
- attrs: structuredClone(input.priorAttrs)
163
- };
164
- return {
165
- label: "Edit element",
166
- execute: (state) => applyOp(state, forwardOp),
167
- undo: (state) => applyOp(state, inverseOp),
168
- operations: () => [structuredClone(forwardOp)],
169
- inverseOperations: () => [structuredClone(inverseOp)]
170
- };
171
- }
172
- function multiSetAttrsCommand(entries) {
173
- if (entries.length === 0) throw new Error("multiSetAttrsCommand: entries must not be empty");
174
- const forwardOps = entries.map((e) => ({
175
- type: "set_attrs",
176
- pageId: e.pageId,
177
- elementId: e.elementId,
178
- attrs: structuredClone(e.attrs)
179
- }));
180
- const inverseOps = entries.map((e) => ({
181
- type: "set_attrs",
182
- pageId: e.pageId,
183
- elementId: e.elementId,
184
- attrs: structuredClone(e.priorAttrs)
185
- }));
186
- return {
187
- label: `Edit ${entries.length} elements`,
188
- execute: (state) => applyOps(state, forwardOps),
189
- undo: (state) => applyOps(state, inverseOps),
190
- operations: () => structuredClone(forwardOps),
191
- inverseOperations: () => structuredClone(inverseOps)
192
- };
193
- }
194
- function reorderElementCommand(input) {
195
- let capturedFromIndex = null;
196
- const forwardOp = {
197
- type: "reorder_element",
198
- pageId: input.pageId,
199
- elementId: input.elementId,
200
- toIndex: input.toIndex
201
- };
202
- return {
203
- label: "Reorder element",
204
- execute: (state) => {
205
- if (capturedFromIndex === null) {
206
- const page = requirePage(state.document, input.pageId);
207
- const { index } = requireElement(page, input.elementId);
208
- capturedFromIndex = index;
209
- }
210
- return applyOp(state, forwardOp);
211
- },
212
- undo: (state) => {
213
- if (capturedFromIndex === null) {
214
- throw new Error("reorderElementCommand: undo called before execute");
215
- }
216
- return applyOp(state, {
217
- type: "reorder_element",
218
- pageId: input.pageId,
219
- elementId: input.elementId,
220
- toIndex: capturedFromIndex
221
- });
222
- },
223
- operations: () => [structuredClone(forwardOp)],
224
- inverseOperations: () => {
225
- if (capturedFromIndex === null) {
226
- throw new Error("reorderElementCommand: inverseOperations called before execute");
227
- }
228
- return [{
229
- type: "reorder_element",
230
- pageId: input.pageId,
231
- elementId: input.elementId,
232
- toIndex: capturedFromIndex
233
- }];
234
- }
235
- };
236
- }
237
- function deleteElementCommand(input) {
238
- const page = requirePage(input.document, input.pageId);
239
- const { element, owner, index } = requireElement(page, input.elementId);
240
- const snapshot = structuredClone(element);
241
- const parentGroupId = findParentGroupId(page, owner);
242
- const deleteOp = {
243
- type: "delete_element",
244
- pageId: input.pageId,
245
- elementId: input.elementId
246
- };
247
- const addOp = {
248
- type: "add_element",
249
- pageId: input.pageId,
250
- element: snapshot,
251
- index,
252
- ...parentGroupId !== void 0 ? { parentGroupId } : {}
253
- };
254
- return {
255
- label: `Delete ${element.kind}`,
256
- execute: (state) => {
257
- const next = applyOp(state, deleteOp);
258
- return {
259
- ...next,
260
- selectedElementIds: next.selectedElementIds.filter((id) => id !== input.elementId)
261
- };
262
- },
263
- undo: (state) => applyOp(state, addOp),
264
- operations: () => [structuredClone(deleteOp)],
265
- inverseOperations: () => [structuredClone(addOp)]
266
- };
267
- }
268
- function findParentGroupId(page, owner) {
269
- if (owner === page.elements) return void 0;
270
- return findGroupWithChildren(page.elements, owner);
271
- }
272
- function findGroupWithChildren(elements, target) {
273
- for (const el of elements) {
274
- if (el.kind === "group") {
275
- if (el.children === target) return el.id;
276
- const found = findGroupWithChildren(el.children, target);
277
- if (found !== void 0) return found;
278
- }
279
- }
280
- return void 0;
281
- }
282
- function groupElementsCommand(input) {
283
- if (input.elementIds.length < 2) {
284
- throw new Error("groupElementsCommand: requires \u2265 2 elementIds");
285
- }
286
- const groupOp = {
287
- type: "group_elements",
288
- pageId: input.pageId,
289
- elementIds: input.elementIds.slice(),
290
- groupId: input.groupId,
291
- ...input.name !== void 0 ? { name: input.name } : {}
292
- };
293
- const ungroupOp = {
294
- type: "ungroup_element",
295
- pageId: input.pageId,
296
- groupId: input.groupId
297
- };
298
- return {
299
- label: `Group ${input.elementIds.length} elements`,
300
- execute: (state) => {
301
- const next = applyOp(state, groupOp);
302
- return {
303
- ...next,
304
- selectedElementIds: [input.groupId]
305
- };
306
- },
307
- undo: (state) => {
308
- const next = applyOp(state, ungroupOp);
309
- return { ...next, selectedElementIds: input.elementIds.slice() };
310
- },
311
- operations: () => [structuredClone(groupOp)],
312
- inverseOperations: () => [structuredClone(ungroupOp)]
313
- };
314
- }
315
- function ungroupElementCommand(input) {
316
- const page = requirePage(input.document, input.pageId);
317
- const { element } = requireElement(page, input.groupId);
318
- if (element.kind !== "group") {
319
- throw new Error(`ungroupElementCommand: element ${input.groupId} is kind ${element.kind}, not group`);
320
- }
321
- const childIds = element.children.map((c) => c.id);
322
- const ungroupOp = {
323
- type: "ungroup_element",
324
- pageId: input.pageId,
325
- groupId: input.groupId
326
- };
327
- const regroupOp = {
328
- type: "group_elements",
329
- pageId: input.pageId,
330
- elementIds: childIds,
331
- groupId: input.groupId,
332
- name: element.name
333
- };
334
- return {
335
- label: `Ungroup`,
336
- execute: (state) => {
337
- const next = applyOp(state, ungroupOp);
338
- return { ...next, selectedElementIds: childIds.slice() };
339
- },
340
- undo: (state) => {
341
- const next = applyOp(state, regroupOp);
342
- return { ...next, selectedElementIds: [input.groupId] };
343
- },
344
- operations: () => [structuredClone(ungroupOp)],
345
- inverseOperations: () => [structuredClone(regroupOp)]
346
- };
347
- }
348
- function addPageCommand(input) {
349
- const addOp = {
350
- type: "add_page",
351
- pageId: input.pageId,
352
- ...input.options !== void 0 ? { options: input.options } : {},
353
- ...input.index !== void 0 ? { index: input.index } : {}
354
- };
355
- const deleteOp = { type: "delete_page", pageId: input.pageId };
356
- return {
357
- label: "Add page",
358
- execute: (state) => {
359
- const next = applyOp(state, addOp);
360
- return { ...next, activePageId: input.pageId };
361
- },
362
- undo: (state) => {
363
- const next = applyOp(state, deleteOp);
364
- const activeExists = next.document.pages.some((p) => p.id === next.activePageId);
365
- return activeExists ? next : { ...next, activePageId: next.document.pages[0].id };
366
- },
367
- operations: () => [structuredClone(addOp)],
368
- inverseOperations: () => [structuredClone(deleteOp)]
369
- };
370
- }
371
- function duplicatePageCommand(input) {
372
- requirePage(input.document, input.sourcePageId);
373
- const dupOp = {
374
- type: "duplicate_page",
375
- sourcePageId: input.sourcePageId,
376
- pageId: input.pageId
377
- };
378
- const deleteOp = { type: "delete_page", pageId: input.pageId };
379
- return {
380
- label: "Duplicate page",
381
- execute: (state) => {
382
- const next = applyOp(state, dupOp);
383
- return { ...next, activePageId: input.pageId };
384
- },
385
- undo: (state) => {
386
- const next = applyOp(state, deleteOp);
387
- const activeExists = next.document.pages.some((p) => p.id === next.activePageId);
388
- return activeExists ? next : { ...next, activePageId: input.sourcePageId };
389
- },
390
- operations: () => [structuredClone(dupOp)],
391
- inverseOperations: () => [structuredClone(deleteOp)]
392
- };
393
- }
394
- function deletePageCommand(input) {
395
- if (input.document.pages.length <= 1) {
396
- throw new Error("deletePageCommand: cannot delete the last page");
397
- }
398
- const page = requirePage(input.document, input.pageId);
399
- const currentIndex = input.document.pages.findIndex((p) => p.id === input.pageId);
400
- const snapshot = structuredClone(page);
401
- const deleteOp = { type: "delete_page", pageId: input.pageId };
402
- function buildRestoreOps() {
403
- const ops = [
404
- {
405
- type: "add_page",
406
- pageId: snapshot.id,
407
- options: {
408
- name: snapshot.name,
409
- width: snapshot.width,
410
- height: snapshot.height,
411
- background: snapshot.background
412
- },
413
- index: currentIndex
414
- }
415
- ];
416
- if (snapshot.bleed) {
417
- ops.push({ type: "set_page_props", pageId: snapshot.id, bleed: snapshot.bleed });
418
- }
419
- if (snapshot.guides.vertical.length > 0 || snapshot.guides.horizontal.length > 0) {
420
- ops.push({ type: "set_page_guides", pageId: snapshot.id, guides: snapshot.guides });
421
- }
422
- for (let i = 0; i < snapshot.elements.length; i++) {
423
- ops.push({
424
- type: "add_element",
425
- pageId: snapshot.id,
426
- element: structuredClone(snapshot.elements[i]),
427
- index: i
428
- });
429
- }
430
- return ops;
431
- }
432
- return {
433
- label: "Delete page",
434
- execute: (state) => {
435
- const next = applyOp(state, deleteOp);
436
- const activeExists = next.document.pages.some((p) => p.id === next.activePageId);
437
- if (activeExists) return next;
438
- const fallbackIndex = Math.min(currentIndex, next.document.pages.length - 1);
439
- return { ...next, activePageId: next.document.pages[fallbackIndex].id };
440
- },
441
- undo: (state) => {
442
- const next = applyOps(state, buildRestoreOps());
443
- return { ...next, activePageId: input.pageId };
444
- },
445
- operations: () => [structuredClone(deleteOp)],
446
- inverseOperations: () => buildRestoreOps()
447
- };
448
- }
449
- function reorderPageCommand(input) {
450
- let capturedFromIndex = null;
451
- const forwardOp = {
452
- type: "reorder_page",
453
- pageId: input.pageId,
454
- toIndex: input.toIndex
455
- };
456
- return {
457
- label: "Reorder page",
458
- execute: (state) => {
459
- if (capturedFromIndex === null) {
460
- capturedFromIndex = state.document.pages.findIndex((p) => p.id === input.pageId);
461
- if (capturedFromIndex === -1) throw new Error(`reorderPageCommand: page ${input.pageId} not found`);
462
- }
463
- return applyOp(state, forwardOp);
464
- },
465
- undo: (state) => {
466
- if (capturedFromIndex === null) throw new Error("reorderPageCommand: undo called before execute");
467
- return applyOp(state, {
468
- type: "reorder_page",
469
- pageId: input.pageId,
470
- toIndex: capturedFromIndex
471
- });
472
- },
473
- operations: () => [structuredClone(forwardOp)],
474
- inverseOperations: () => {
475
- if (capturedFromIndex === null) throw new Error("reorderPageCommand: inverseOperations called before execute");
476
- return [{ type: "reorder_page", pageId: input.pageId, toIndex: capturedFromIndex }];
477
- }
478
- };
479
- }
480
- function setPagePropsCommand(input) {
481
- const page = requirePage(input.document, input.pageId);
482
- const prior = {
483
- type: "set_page_props",
484
- pageId: input.pageId,
485
- ...input.props.name !== void 0 ? { name: page.name } : {},
486
- ...input.props.width !== void 0 ? { width: page.width } : {},
487
- ...input.props.height !== void 0 ? { height: page.height } : {},
488
- ...input.props.background !== void 0 ? { background: page.background } : {},
489
- ...input.props.bleed !== void 0 ? { bleed: page.bleed } : {}
490
- };
491
- const forwardOp = {
492
- type: "set_page_props",
493
- pageId: input.pageId,
494
- ...input.props
495
- };
496
- return {
497
- label: "Edit page",
498
- execute: (state) => applyOp(state, forwardOp),
499
- undo: (state) => applyOp(state, prior),
500
- operations: () => [structuredClone(forwardOp)],
501
- inverseOperations: () => [structuredClone(prior)]
502
- };
503
- }
504
- function setPageGuidesCommand(input) {
505
- const page = requirePage(input.document, input.pageId);
506
- const priorGuides = structuredClone(page.guides);
507
- const forwardOp = {
508
- type: "set_page_guides",
509
- pageId: input.pageId,
510
- guides: structuredClone(input.guides)
511
- };
512
- const inverseOp = {
513
- type: "set_page_guides",
514
- pageId: input.pageId,
515
- guides: priorGuides
516
- };
517
- return {
518
- label: "Edit guides",
519
- execute: (state) => applyOp(state, forwardOp),
520
- undo: (state) => applyOp(state, inverseOp),
521
- operations: () => [structuredClone(forwardOp)],
522
- inverseOperations: () => [structuredClone(inverseOp)]
523
- };
524
- }
525
- function bindSlotCommand(input) {
526
- const page = requirePage(input.document, input.pageId);
527
- const { element } = requireElement(page, input.elementId);
528
- const priorSlot = element.slot ?? null;
529
- const forwardOp = {
530
- type: "bind_slot",
531
- pageId: input.pageId,
532
- elementId: input.elementId,
533
- slot: input.slot
534
- };
535
- const inverseOp = {
536
- type: "bind_slot",
537
- pageId: input.pageId,
538
- elementId: input.elementId,
539
- slot: priorSlot
540
- };
541
- return {
542
- label: input.slot === null ? "Unbind slot" : `Bind slot "${input.slot}"`,
543
- execute: (state) => applyOp(state, forwardOp),
544
- undo: (state) => applyOp(state, inverseOp),
545
- operations: () => [structuredClone(forwardOp)],
546
- inverseOperations: () => [structuredClone(inverseOp)]
547
- };
548
- }
549
- function setDocumentTitleCommand(input) {
550
- const priorTitle = input.document.title;
551
- const forwardOp = { type: "set_document_title", title: input.title };
552
- const inverseOp = { type: "set_document_title", title: priorTitle };
553
- return {
554
- label: `Rename document`,
555
- execute: (state) => applyOp(state, forwardOp),
556
- undo: (state) => applyOp(state, inverseOp),
557
- operations: () => [structuredClone(forwardOp)],
558
- inverseOperations: () => [structuredClone(inverseOp)]
559
- };
560
- }
561
-
562
27
  // src/design-canvas-react/components/ruler-math.ts
563
28
  var TICK_STEP_CANDIDATES_PX = [1, 2, 5, 10, 25, 50, 100, 250, 500, 1e3, 2500, 5e3];
564
29
  function selectTickStep(input) {
@@ -796,7 +261,6 @@ var BoldGlyph = glyph(/* @__PURE__ */ jsx2("path", { d: "M6 4h8a4 4 0 0 1 0 8H6z
796
261
  var ItalicGlyph = glyph(/* @__PURE__ */ jsx2("path", { d: "M11 4h6M7 20h6M14 4 8 20" }));
797
262
  var PlusGlyph = glyph(/* @__PURE__ */ jsx2("path", { d: "M12 5v14M5 12h14" }));
798
263
  var ChevronDownGlyph = glyph(/* @__PURE__ */ jsx2("path", { d: "m6 9 6 6 6-6" }));
799
- var ChevronRightGlyph = glyph(/* @__PURE__ */ jsx2("path", { d: "m9 18 6-6-6-6" }));
800
264
  var RectGlyph = glyph(/* @__PURE__ */ jsx2("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }));
801
265
  var EllipseGlyph = glyph(/* @__PURE__ */ jsx2("ellipse", { cx: "12", cy: "12", rx: "10", ry: "7" }));
802
266
  var LineGlyph = glyph(/* @__PURE__ */ jsx2("path", { d: "M5 19 19 5" }));
@@ -820,12 +284,6 @@ var SlotGlyph = glyph(
820
284
  /* @__PURE__ */ jsx2("path", { d: "M12 1v4M12 19v4M4.2 4.2l2.8 2.8M17 17l2.8 2.8M1 12h4M19 12h4M4.2 19.8l2.8-2.8M17 7 19.8 4.2" })
821
285
  ] })
822
286
  );
823
- var FitGlyph = glyph(
824
- /* @__PURE__ */ jsxs2(Fragment2, { children: [
825
- /* @__PURE__ */ jsx2("path", { d: "M3 3h4v4H3zM17 3h4v4h-4zM3 17h4v4H3zM17 17h4v4h-4z" }),
826
- /* @__PURE__ */ jsx2("path", { d: "M7 5h10M5 7v10M19 7v10M7 19h10" })
827
- ] })
828
- );
829
287
  var PageGlyph = glyph(
830
288
  /* @__PURE__ */ jsxs2(Fragment2, { children: [
831
289
  /* @__PURE__ */ jsx2("path", { d: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" }),
@@ -874,11 +332,24 @@ var ShapesGlyph = glyph(
874
332
  ] })
875
333
  );
876
334
 
335
+ // src/design-canvas-react/components/icon-button.tsx
336
+ import { forwardRef } from "react";
337
+ import { jsx as jsx3 } from "react/jsx-runtime";
338
+ var BTN_BASE = "items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))] focus-visible:ring-offset-1 focus-visible:ring-offset-[var(--bg-input)] disabled:cursor-default disabled:opacity-40";
339
+ var BTN_ACTIVE_EXTRA = " border-[var(--brand-primary)] text-[var(--brand-primary)] hover:text-[var(--brand-primary)]";
340
+ var BTN = `flex h-7 w-7 ${BTN_BASE}`;
341
+ var BTN_ACTIVE = BTN + BTN_ACTIVE_EXTRA;
342
+ var BTN_SM = `flex h-6 w-6 ${BTN_BASE}`;
343
+ var BTN_SM_ACTIVE = BTN_SM + BTN_ACTIVE_EXTRA;
344
+ var IconButton = forwardRef(function IconButton2({ active = false, size = "md", className = "", type = "button", ...rest }, ref) {
345
+ const base = size === "sm" ? active ? BTN_SM_ACTIVE : BTN_SM : active ? BTN_ACTIVE : BTN;
346
+ return /* @__PURE__ */ jsx3("button", { ref, type, className: className ? `${base} ${className}` : base, ...rest });
347
+ });
348
+
877
349
  // src/design-canvas-react/components/PagesStrip.tsx
878
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
350
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
879
351
  var THUMBNAIL_W = 80;
880
352
  var THUMBNAIL_H = 56;
881
- var BTN = "flex h-6 w-6 items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] disabled:cursor-default disabled:opacity-40";
882
353
  function PagesStrip({
883
354
  pages,
884
355
  activePageId,
@@ -929,10 +400,6 @@ function PagesStrip({
929
400
  return /* @__PURE__ */ jsxs3(
930
401
  "div",
931
402
  {
932
- role: "button",
933
- tabIndex: 0,
934
- "aria-label": `Page ${index + 1}: ${page.name}${isActive ? " (active)" : ""}`,
935
- "aria-pressed": isActive,
936
403
  draggable: canWrite,
937
404
  onDragStart: () => {
938
405
  dragIndexRef.current = index;
@@ -955,38 +422,43 @@ function PagesStrip({
955
422
  dragIndexRef.current = null;
956
423
  setDragOverIndex(null);
957
424
  },
958
- onClick: () => onSelectPage(page.id),
959
- onKeyDown: (event) => {
960
- if (event.key === "Enter" || event.key === " ") {
961
- event.preventDefault();
962
- onSelectPage(page.id);
963
- }
964
- },
965
425
  className: [
966
- "group relative flex shrink-0 cursor-pointer flex-col items-center gap-1 rounded p-1 transition",
426
+ "group relative flex shrink-0 flex-col items-center gap-1 rounded p-1 transition",
967
427
  isActive ? "ring-2 ring-[var(--brand-primary)]" : "hover:bg-[var(--border-default)]/40",
968
428
  dragOverIndex === index ? "ring-1 ring-[var(--brand-primary)]/60" : ""
969
429
  ].join(" "),
970
430
  children: [
971
- /* @__PURE__ */ jsx3(
972
- "div",
431
+ /* @__PURE__ */ jsxs3(
432
+ "button",
973
433
  {
974
- className: "overflow-hidden rounded border border-[var(--border-default)] bg-white",
975
- style: { width: THUMBNAIL_W, height: THUMBNAIL_H },
976
- children: thumbUrl ? /* @__PURE__ */ jsx3(
977
- "img",
978
- {
979
- src: thumbUrl,
980
- alt: page.name,
981
- className: "h-full w-full object-cover",
982
- draggable: false
983
- }
984
- ) : /* @__PURE__ */ jsx3("div", { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsx3(PageGlyph, { className: "h-5 w-5 text-[var(--text-muted)]" }) })
434
+ type: "button",
435
+ "aria-label": `Page ${index + 1}: ${page.name}${isActive ? " (active)" : ""}`,
436
+ "aria-pressed": isActive,
437
+ onClick: () => onSelectPage(page.id),
438
+ className: "flex cursor-pointer flex-col items-center gap-1 rounded focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))]",
439
+ children: [
440
+ /* @__PURE__ */ jsx4(
441
+ "div",
442
+ {
443
+ className: "overflow-hidden rounded border border-[var(--border-default)] bg-[hsl(var(--card))]",
444
+ style: { width: THUMBNAIL_W, height: THUMBNAIL_H },
445
+ children: thumbUrl ? /* @__PURE__ */ jsx4(
446
+ "img",
447
+ {
448
+ src: thumbUrl,
449
+ alt: page.name,
450
+ className: "h-full w-full object-cover",
451
+ draggable: false
452
+ }
453
+ ) : /* @__PURE__ */ jsx4("div", { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsx4(PageGlyph, { className: "h-5 w-5 text-[var(--text-muted)]" }) })
454
+ }
455
+ ),
456
+ /* @__PURE__ */ jsx4("span", { className: "max-w-[80px] truncate text-[10px] text-[var(--text-secondary)]", children: page.name })
457
+ ]
985
458
  }
986
459
  ),
987
- /* @__PURE__ */ jsx3("span", { className: "max-w-[80px] truncate text-[10px] text-[var(--text-secondary)]", children: page.name }),
988
460
  canWrite && canManagePages ? /* @__PURE__ */ jsxs3("div", { className: "pointer-events-none absolute -top-1 right-0 flex gap-0.5 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100", children: [
989
- /* @__PURE__ */ jsx3(
461
+ /* @__PURE__ */ jsx4(
990
462
  "button",
991
463
  {
992
464
  type: "button",
@@ -995,11 +467,11 @@ function PagesStrip({
995
467
  event.stopPropagation();
996
468
  onDuplicatePage(page.id);
997
469
  },
998
- className: BTN,
999
- children: /* @__PURE__ */ jsx3(DuplicateGlyph, { className: "h-3 w-3" })
470
+ className: BTN_SM,
471
+ children: /* @__PURE__ */ jsx4(DuplicateGlyph, { className: "h-3 w-3" })
1000
472
  }
1001
473
  ),
1002
- /* @__PURE__ */ jsx3(
474
+ /* @__PURE__ */ jsx4(
1003
475
  "button",
1004
476
  {
1005
477
  type: "button",
@@ -1009,8 +481,8 @@ function PagesStrip({
1009
481
  event.stopPropagation();
1010
482
  if (pages.length > 1) onDeletePage(page.id);
1011
483
  },
1012
- className: BTN,
1013
- children: /* @__PURE__ */ jsx3(TrashGlyph, { className: "h-3 w-3 text-rose-400" })
484
+ className: BTN_SM,
485
+ children: /* @__PURE__ */ jsx4(TrashGlyph, { className: "h-3 w-3 text-[var(--text-danger)]" })
1014
486
  }
1015
487
  )
1016
488
  ] }) : null
@@ -1025,10 +497,10 @@ function PagesStrip({
1025
497
  type: "button",
1026
498
  "aria-label": "Add page",
1027
499
  onClick: onAddPage,
1028
- className: "flex h-[72px] w-[80px] shrink-0 flex-col items-center justify-center gap-1 rounded border border-dashed border-[var(--border-default)] text-[var(--text-muted)] transition hover:border-[var(--brand-primary)] hover:text-[var(--brand-primary)]",
500
+ className: "flex h-[72px] w-[80px] shrink-0 flex-col items-center justify-center gap-1 rounded border border-dashed border-[var(--border-default)] text-[var(--text-muted)] transition hover:border-[var(--brand-primary)] hover:text-[var(--brand-primary)] focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))]",
1029
501
  children: [
1030
- /* @__PURE__ */ jsx3(PlusGlyph, { className: "h-4 w-4" }),
1031
- /* @__PURE__ */ jsx3("span", { className: "text-[10px]", children: "Add page" })
502
+ /* @__PURE__ */ jsx4(PlusGlyph, { className: "h-4 w-4" }),
503
+ /* @__PURE__ */ jsx4("span", { className: "text-[10px]", children: "Add page" })
1032
504
  ]
1033
505
  }
1034
506
  ) : null
@@ -1039,20 +511,20 @@ function PagesStrip({
1039
511
 
1040
512
  // src/design-canvas-react/components/Rulers.tsx
1041
513
  import { useRef as useRef2, useState as useState2 } from "react";
1042
- import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
514
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1043
515
  var RULER_SIZE_PX = 20;
1044
516
  var DELETE_THRESHOLD_PX = RULER_SIZE_PX + 4;
1045
517
  function Rulers({ pageWidth, pageHeight, zoom, scrollLeft, scrollTop, showRulers, guides, onGuidesChange }) {
1046
518
  if (!showRulers) return null;
1047
519
  return /* @__PURE__ */ jsxs4(Fragment3, { children: [
1048
- /* @__PURE__ */ jsx4(
520
+ /* @__PURE__ */ jsx5(
1049
521
  "div",
1050
522
  {
1051
523
  className: "absolute top-0 left-0 z-20 shrink-0 border-b border-r border-[var(--border-default)] bg-[var(--bg-input)]",
1052
524
  style: { width: RULER_SIZE_PX, height: RULER_SIZE_PX }
1053
525
  }
1054
526
  ),
1055
- /* @__PURE__ */ jsx4(
527
+ /* @__PURE__ */ jsx5(
1056
528
  HorizontalRuler,
1057
529
  {
1058
530
  pageWidth,
@@ -1062,7 +534,7 @@ function Rulers({ pageWidth, pageHeight, zoom, scrollLeft, scrollTop, showRulers
1062
534
  onGuidesChange
1063
535
  }
1064
536
  ),
1065
- /* @__PURE__ */ jsx4(
537
+ /* @__PURE__ */ jsx5(
1066
538
  VerticalRuler,
1067
539
  {
1068
540
  pageHeight,
@@ -1150,18 +622,18 @@ function HorizontalRuler({ pageWidth, zoom, scrollLeft, guides, onGuidesChange }
1150
622
  children: [
1151
623
  ticks.map((tick) => {
1152
624
  const screenX = tick.position * zoom - scrollLeft * zoom;
1153
- return /* @__PURE__ */ jsx4(
625
+ return /* @__PURE__ */ jsx5(
1154
626
  "div",
1155
627
  {
1156
628
  className: `absolute bottom-0 w-px bg-[var(--border-default)] ${tick.label !== null ? "top-1.5" : "top-[14px]"}`,
1157
629
  style: { left: screenX },
1158
- children: tick.label !== null ? /* @__PURE__ */ jsx4("span", { className: "absolute -top-1 left-0.5 whitespace-nowrap font-mono text-[9px] leading-none text-[var(--text-muted)]", children: tick.label }) : null
630
+ children: tick.label !== null ? /* @__PURE__ */ jsx5("span", { className: "absolute -top-1 left-0.5 whitespace-nowrap font-mono text-[9px] leading-none text-[var(--text-muted)]", children: tick.label }) : null
1159
631
  },
1160
632
  tick.position
1161
633
  );
1162
634
  }),
1163
- pointerX !== null ? /* @__PURE__ */ jsx4("div", { className: "pointer-events-none absolute top-0 bottom-0 w-px bg-[var(--brand-primary)]/60", style: { left: pointerX } }) : null,
1164
- dragGuideX !== null ? /* @__PURE__ */ jsx4(
635
+ pointerX !== null ? /* @__PURE__ */ jsx5("div", { className: "pointer-events-none absolute top-0 bottom-0 w-px bg-[var(--brand-primary)]/60", style: { left: pointerX } }) : null,
636
+ dragGuideX !== null ? /* @__PURE__ */ jsx5(
1165
637
  "div",
1166
638
  {
1167
639
  className: "pointer-events-none absolute top-0 bottom-0 w-px bg-[var(--brand-primary)]",
@@ -1244,12 +716,12 @@ function VerticalRuler({ pageHeight, zoom, scrollTop, guides, onGuidesChange })
1244
716
  children: [
1245
717
  ticks.map((tick) => {
1246
718
  const screenY = tick.position * zoom - scrollTop * zoom;
1247
- return /* @__PURE__ */ jsx4(
719
+ return /* @__PURE__ */ jsx5(
1248
720
  "div",
1249
721
  {
1250
722
  className: `absolute right-0 h-px bg-[var(--border-default)] ${tick.label !== null ? "left-1.5" : "left-[14px]"}`,
1251
723
  style: { top: screenY },
1252
- children: tick.label !== null ? /* @__PURE__ */ jsx4(
724
+ children: tick.label !== null ? /* @__PURE__ */ jsx5(
1253
725
  "span",
1254
726
  {
1255
727
  className: "absolute top-0.5 left-0 whitespace-nowrap font-mono text-[9px] leading-none text-[var(--text-muted)]",
@@ -1261,8 +733,8 @@ function VerticalRuler({ pageHeight, zoom, scrollTop, guides, onGuidesChange })
1261
733
  tick.position
1262
734
  );
1263
735
  }),
1264
- pointerY !== null ? /* @__PURE__ */ jsx4("div", { className: "pointer-events-none absolute left-0 right-0 h-px bg-[var(--brand-primary)]/60", style: { top: pointerY } }) : null,
1265
- dragGuideY !== null ? /* @__PURE__ */ jsx4(
736
+ pointerY !== null ? /* @__PURE__ */ jsx5("div", { className: "pointer-events-none absolute left-0 right-0 h-px bg-[var(--brand-primary)]/60", style: { top: pointerY } }) : null,
737
+ dragGuideY !== null ? /* @__PURE__ */ jsx5(
1266
738
  "div",
1267
739
  {
1268
740
  className: "pointer-events-none absolute left-0 right-0 h-px bg-[var(--brand-primary)]",
@@ -1276,7 +748,7 @@ function VerticalRuler({ pageHeight, zoom, scrollTop, guides, onGuidesChange })
1276
748
 
1277
749
  // src/design-canvas-react/components/Toolbar.tsx
1278
750
  import { useEffect as useEffect2, useRef as useRef3, useState as useState3 } from "react";
1279
- import { Fragment as Fragment4, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
751
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1280
752
  var FONT_FAMILIES = [
1281
753
  "Inter",
1282
754
  "Arial",
@@ -1291,9 +763,7 @@ var FONT_FAMILIES = [
1291
763
  "Brush Script MT",
1292
764
  "Impact"
1293
765
  ];
1294
- var BTN2 = "flex h-7 w-7 items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] disabled:cursor-default disabled:opacity-40";
1295
- var BTN_ACTIVE = `${BTN2} border-[var(--brand-primary)] text-[var(--brand-primary)] hover:text-[var(--brand-primary)]`;
1296
- var SEP = /* @__PURE__ */ jsx5("div", { className: "mx-1 h-5 w-px shrink-0 bg-[var(--border-default)]" });
766
+ var SEP = /* @__PURE__ */ jsx6("div", { className: "mx-1 h-5 w-px shrink-0 bg-[var(--border-default)]" });
1297
767
  var POPOVER_PANEL = "absolute top-full left-0 z-50 mt-1 flex flex-col rounded border border-[var(--border-default)] bg-[var(--bg-input)] shadow-lg";
1298
768
  function Popover({
1299
769
  open,
@@ -1338,8 +808,8 @@ function NumberInput({
1338
808
  setRaw(null);
1339
809
  }
1340
810
  return /* @__PURE__ */ jsxs5("label", { className: "flex flex-col items-center gap-0.5", children: [
1341
- /* @__PURE__ */ jsx5("span", { className: FIELD_LABEL, children: label }),
1342
- /* @__PURE__ */ jsx5(
811
+ /* @__PURE__ */ jsx6("span", { className: FIELD_LABEL, children: label }),
812
+ /* @__PURE__ */ jsx6(
1343
813
  "input",
1344
814
  {
1345
815
  type: "number",
@@ -1368,8 +838,8 @@ function SelectControl({
1368
838
  const [open, setOpen] = useState3(false);
1369
839
  const current = options.find((o) => o.value === value);
1370
840
  return /* @__PURE__ */ jsxs5("label", { className: "flex flex-col items-center gap-0.5", children: [
1371
- /* @__PURE__ */ jsx5("span", { className: FIELD_LABEL, children: label }),
1372
- /* @__PURE__ */ jsx5(
841
+ /* @__PURE__ */ jsx6("span", { className: FIELD_LABEL, children: label }),
842
+ /* @__PURE__ */ jsx6(
1373
843
  Popover,
1374
844
  {
1375
845
  open,
@@ -1384,12 +854,12 @@ function SelectControl({
1384
854
  onClick: () => setOpen((v) => !v),
1385
855
  className: `${buttonClassName} flex items-center justify-between gap-1 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-0.5 text-left text-[12px] text-[var(--text-primary)] outline-none hover:border-[var(--brand-primary)] disabled:cursor-default disabled:opacity-40`,
1386
856
  children: [
1387
- /* @__PURE__ */ jsx5("span", { className: "truncate", children: current?.label ?? value }),
1388
- /* @__PURE__ */ jsx5("span", { className: "text-[8px] text-[var(--text-muted)]", children: "\u25BE" })
857
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children: current?.label ?? value }),
858
+ /* @__PURE__ */ jsx6("span", { className: "text-[8px] text-[var(--text-muted)]", children: "\u25BE" })
1389
859
  ]
1390
860
  }
1391
861
  ),
1392
- children: /* @__PURE__ */ jsx5("div", { role: "listbox", className: `${POPOVER_PANEL} max-h-64 w-44 overflow-y-auto py-1`, children: options.map((opt) => /* @__PURE__ */ jsx5(
862
+ children: /* @__PURE__ */ jsx6("div", { role: "listbox", className: `${POPOVER_PANEL} max-h-64 w-44 overflow-y-auto py-1`, children: options.map((opt) => /* @__PURE__ */ jsx6(
1393
863
  "button",
1394
864
  {
1395
865
  type: "button",
@@ -1418,8 +888,8 @@ function FontPicker({
1418
888
  const families = FONT_FAMILIES.includes(value) ? [...FONT_FAMILIES] : [value, ...FONT_FAMILIES];
1419
889
  const filtered = families.filter((f) => f.toLowerCase().includes(query.trim().toLowerCase()));
1420
890
  return /* @__PURE__ */ jsxs5("label", { className: "flex flex-col items-center gap-0.5", children: [
1421
- /* @__PURE__ */ jsx5("span", { className: FIELD_LABEL, children: "Font" }),
1422
- /* @__PURE__ */ jsx5(
891
+ /* @__PURE__ */ jsx6("span", { className: FIELD_LABEL, children: "Font" }),
892
+ /* @__PURE__ */ jsx6(
1423
893
  Popover,
1424
894
  {
1425
895
  open,
@@ -1439,13 +909,13 @@ function FontPicker({
1439
909
  className: "flex w-28 items-center justify-between gap-1 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-0.5 text-left text-[12px] text-[var(--text-primary)] outline-none hover:border-[var(--brand-primary)] disabled:cursor-default disabled:opacity-40",
1440
910
  style: { fontFamily: value },
1441
911
  children: [
1442
- /* @__PURE__ */ jsx5("span", { className: "truncate", children: value }),
1443
- /* @__PURE__ */ jsx5("span", { className: "text-[8px] text-[var(--text-muted)]", children: "\u25BE" })
912
+ /* @__PURE__ */ jsx6("span", { className: "truncate", children: value }),
913
+ /* @__PURE__ */ jsx6("span", { className: "text-[8px] text-[var(--text-muted)]", children: "\u25BE" })
1444
914
  ]
1445
915
  }
1446
916
  ),
1447
917
  children: /* @__PURE__ */ jsxs5("div", { className: `${POPOVER_PANEL} w-52`, children: [
1448
- /* @__PURE__ */ jsx5(
918
+ /* @__PURE__ */ jsx6(
1449
919
  "input",
1450
920
  {
1451
921
  autoFocus: true,
@@ -1456,7 +926,7 @@ function FontPicker({
1456
926
  className: "m-1 rounded border border-[var(--border-default)] bg-transparent px-2 py-1 text-[12px] text-[var(--text-primary)] outline-none focus:border-[var(--brand-primary)]"
1457
927
  }
1458
928
  ),
1459
- /* @__PURE__ */ jsx5("div", { role: "listbox", className: "max-h-60 overflow-y-auto py-1", children: filtered.length === 0 ? /* @__PURE__ */ jsx5("div", { className: "px-3 py-2 text-[11px] text-[var(--text-muted)]", children: "No matches" }) : filtered.map((family) => /* @__PURE__ */ jsx5(
929
+ /* @__PURE__ */ jsx6("div", { role: "listbox", className: "max-h-60 overflow-y-auto py-1", children: filtered.length === 0 ? /* @__PURE__ */ jsx6("div", { className: "px-3 py-2 text-[11px] text-[var(--text-muted)]", children: "No matches" }) : filtered.map((family) => /* @__PURE__ */ jsx6(
1460
930
  "button",
1461
931
  {
1462
932
  type: "button",
@@ -1482,13 +952,13 @@ function ColorSwatch({ label, value, onCommit, disabled }) {
1482
952
  const [open, setOpen] = useState3(false);
1483
953
  const normalized = value.startsWith("#") ? value : "#ffffff";
1484
954
  return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col items-center gap-0.5", children: [
1485
- /* @__PURE__ */ jsx5("span", { className: FIELD_LABEL, children: label }),
1486
- /* @__PURE__ */ jsx5(
955
+ /* @__PURE__ */ jsx6("span", { className: FIELD_LABEL, children: label }),
956
+ /* @__PURE__ */ jsx6(
1487
957
  Popover,
1488
958
  {
1489
959
  open,
1490
960
  onClose: () => setOpen(false),
1491
- trigger: /* @__PURE__ */ jsx5(
961
+ trigger: /* @__PURE__ */ jsx6(
1492
962
  "button",
1493
963
  {
1494
964
  type: "button",
@@ -1500,7 +970,7 @@ function ColorSwatch({ label, value, onCommit, disabled }) {
1500
970
  }
1501
971
  ),
1502
972
  children: /* @__PURE__ */ jsxs5("div", { className: `${POPOVER_PANEL} w-40 gap-2 p-2`, children: [
1503
- /* @__PURE__ */ jsx5(
973
+ /* @__PURE__ */ jsx6(
1504
974
  "input",
1505
975
  {
1506
976
  type: "color",
@@ -1510,7 +980,7 @@ function ColorSwatch({ label, value, onCommit, disabled }) {
1510
980
  className: "h-8 w-full cursor-pointer rounded border border-[var(--border-default)] p-0.5"
1511
981
  }
1512
982
  ),
1513
- /* @__PURE__ */ jsx5(
983
+ /* @__PURE__ */ jsx6(
1514
984
  "input",
1515
985
  {
1516
986
  type: "text",
@@ -1568,19 +1038,19 @@ function Toolbar({
1568
1038
  const review = mode === "review";
1569
1039
  return /* @__PURE__ */ jsxs5("div", { className: "flex min-h-11 shrink-0 flex-wrap items-center gap-x-2 gap-y-1 border-b border-[var(--border-default)] bg-[var(--bg-input)] px-3 py-1", children: [
1570
1040
  /* @__PURE__ */ jsxs5("div", { className: "flex shrink-0 items-center gap-2", children: [
1571
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Undo", disabled: !canUndo || !canWrite, onClick: onUndo, className: BTN2, children: /* @__PURE__ */ jsx5(UndoGlyph, { className: "h-3.5 w-3.5" }) }),
1572
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Redo", disabled: !canRedo || !canWrite, onClick: onRedo, className: BTN2, children: /* @__PURE__ */ jsx5(RedoGlyph, { className: "h-3.5 w-3.5" }) }),
1041
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Undo", disabled: !canUndo || !canWrite, onClick: onUndo, className: BTN, children: /* @__PURE__ */ jsx6(UndoGlyph, { className: "h-3.5 w-3.5" }) }),
1042
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Redo", disabled: !canRedo || !canWrite, onClick: onRedo, className: BTN, children: /* @__PURE__ */ jsx6(RedoGlyph, { className: "h-3.5 w-3.5" }) }),
1573
1043
  !review ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
1574
1044
  SEP,
1575
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Toggle rulers", "aria-pressed": showRulers, onClick: onToggleRulers, className: showRulers ? BTN_ACTIVE : BTN2, children: /* @__PURE__ */ jsx5(RulerGlyph, { className: "h-3.5 w-3.5" }) }),
1576
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Toggle grid", "aria-pressed": gridEnabled, onClick: onToggleGrid, className: gridEnabled ? BTN_ACTIVE : BTN2, children: /* @__PURE__ */ jsx5(GridGlyph, { className: "h-3.5 w-3.5" }) }),
1577
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Toggle snap", "aria-pressed": snapEnabled, onClick: onToggleSnap, className: snapEnabled ? BTN_ACTIVE : BTN2, children: /* @__PURE__ */ jsx5(MagnetGlyph, { className: "h-3.5 w-3.5" }) }),
1578
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Toggle bleed overlay", "aria-pressed": showBleed, onClick: onToggleBleed, className: showBleed ? BTN_ACTIVE : BTN2, disabled: !page.bleed, children: /* @__PURE__ */ jsx5(BleedGlyph, { className: "h-3.5 w-3.5" }) })
1045
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Toggle rulers", "aria-pressed": showRulers, onClick: onToggleRulers, className: showRulers ? BTN_ACTIVE : BTN, children: /* @__PURE__ */ jsx6(RulerGlyph, { className: "h-3.5 w-3.5" }) }),
1046
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Toggle grid", "aria-pressed": gridEnabled, onClick: onToggleGrid, className: gridEnabled ? BTN_ACTIVE : BTN, children: /* @__PURE__ */ jsx6(GridGlyph, { className: "h-3.5 w-3.5" }) }),
1047
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Toggle snap", "aria-pressed": snapEnabled, onClick: onToggleSnap, className: snapEnabled ? BTN_ACTIVE : BTN, children: /* @__PURE__ */ jsx6(MagnetGlyph, { className: "h-3.5 w-3.5" }) }),
1048
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Toggle bleed overlay", "aria-pressed": showBleed, onClick: onToggleBleed, className: showBleed ? BTN_ACTIVE : BTN, disabled: !page.bleed, children: /* @__PURE__ */ jsx6(BleedGlyph, { className: "h-3.5 w-3.5" }) })
1579
1049
  ] }) : null
1580
1050
  ] }),
1581
- /* @__PURE__ */ jsx5("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: hasSelection ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
1051
+ /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: hasSelection ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
1582
1052
  SEP,
1583
- /* @__PURE__ */ jsx5(
1053
+ /* @__PURE__ */ jsx6(
1584
1054
  SelectionControls,
1585
1055
  {
1586
1056
  elements: selectedElements,
@@ -1604,7 +1074,7 @@ function Toolbar({
1604
1074
  )
1605
1075
  ] }) : !review ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
1606
1076
  SEP,
1607
- /* @__PURE__ */ jsx5(
1077
+ /* @__PURE__ */ jsx6(
1608
1078
  PagePropsControls,
1609
1079
  {
1610
1080
  page,
@@ -1637,12 +1107,12 @@ function SelectionControls({
1637
1107
  const [slotInput, setSlotInput] = useState3("");
1638
1108
  const firstEl = elements[0];
1639
1109
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
1640
- allSameKind && firstKind === "text" && single ? /* @__PURE__ */ jsx5(TextControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs) }) : null,
1641
- allSameKind && firstKind === "rect" && single ? /* @__PURE__ */ jsx5(ShapeControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs), showCornerRadius: true }) : null,
1642
- allSameKind && firstKind === "ellipse" && single ? /* @__PURE__ */ jsx5(ShapeControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs), showCornerRadius: false }) : null,
1643
- allSameKind && firstKind === "image" && single ? /* @__PURE__ */ jsx5(ImageControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs) }) : null,
1110
+ allSameKind && firstKind === "text" && single ? /* @__PURE__ */ jsx6(TextControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs) }) : null,
1111
+ allSameKind && firstKind === "rect" && single ? /* @__PURE__ */ jsx6(ShapeControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs), showCornerRadius: true }) : null,
1112
+ allSameKind && firstKind === "ellipse" && single ? /* @__PURE__ */ jsx6(ShapeControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs), showCornerRadius: false }) : null,
1113
+ allSameKind && firstKind === "image" && single ? /* @__PURE__ */ jsx6(ImageControls, { element: single, canWrite, onPatch: (attrs) => patchAll(attrs) }) : null,
1644
1114
  SEP,
1645
- /* @__PURE__ */ jsx5(
1115
+ /* @__PURE__ */ jsx6(
1646
1116
  NumberInput,
1647
1117
  {
1648
1118
  label: "Opacity",
@@ -1652,7 +1122,7 @@ function SelectionControls({
1652
1122
  className: "w-14"
1653
1123
  }
1654
1124
  ),
1655
- /* @__PURE__ */ jsx5(
1125
+ /* @__PURE__ */ jsx6(
1656
1126
  NumberInput,
1657
1127
  {
1658
1128
  label: "Rotation",
@@ -1664,44 +1134,48 @@ function SelectionControls({
1664
1134
  review ? null : /* @__PURE__ */ jsxs5(Fragment4, { children: [
1665
1135
  SEP,
1666
1136
  single ? /* @__PURE__ */ jsxs5(Fragment4, { children: [
1667
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Bring to front", disabled: !canWrite, onClick: () => reorderSingle("front"), className: BTN2, children: /* @__PURE__ */ jsx5(BringFrontGlyph, { className: "h-3.5 w-3.5" }) }),
1668
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Send to back", disabled: !canWrite, onClick: () => reorderSingle("back"), className: BTN2, children: /* @__PURE__ */ jsx5(SendBackGlyph, { className: "h-3.5 w-3.5" }) }),
1137
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Bring to front", disabled: !canWrite, onClick: () => reorderSingle("front"), className: BTN, children: /* @__PURE__ */ jsx6(BringFrontGlyph, { className: "h-3.5 w-3.5" }) }),
1138
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Send to back", disabled: !canWrite, onClick: () => reorderSingle("back"), className: BTN, children: /* @__PURE__ */ jsx6(SendBackGlyph, { className: "h-3.5 w-3.5" }) }),
1669
1139
  SEP
1670
1140
  ] }) : null,
1671
- groupable ? /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Group elements", disabled: !canWrite, onClick: onGroup, className: BTN2, children: /* @__PURE__ */ jsx5(GroupGlyph, { className: "h-3.5 w-3.5" }) }) : null,
1672
- isGroup ? /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Ungroup", disabled: !canWrite, onClick: onUngroup, className: BTN2, children: /* @__PURE__ */ jsx5(UngroupGlyph, { className: "h-3.5 w-3.5" }) }) : null,
1673
- single ? /* @__PURE__ */ jsx5(
1141
+ groupable ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Group elements", disabled: !canWrite, onClick: onGroup, className: BTN, children: /* @__PURE__ */ jsx6(GroupGlyph, { className: "h-3.5 w-3.5" }) }) : null,
1142
+ isGroup ? /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Ungroup", disabled: !canWrite, onClick: onUngroup, className: BTN, children: /* @__PURE__ */ jsx6(UngroupGlyph, { className: "h-3.5 w-3.5" }) }) : null,
1143
+ single ? /* @__PURE__ */ jsx6(
1674
1144
  "button",
1675
1145
  {
1676
1146
  type: "button",
1677
1147
  "aria-label": single.locked ? "Unlock element" : "Lock element",
1148
+ "aria-pressed": !!single.locked,
1678
1149
  disabled: !canWrite,
1679
1150
  onClick: () => patchAll({ locked: !single.locked }),
1680
- className: single.locked ? BTN_ACTIVE : BTN2,
1681
- children: single.locked ? /* @__PURE__ */ jsx5(LockGlyph, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx5(UnlockGlyph, { className: "h-3.5 w-3.5" })
1151
+ className: single.locked ? BTN_ACTIVE : BTN,
1152
+ children: single.locked ? /* @__PURE__ */ jsx6(LockGlyph, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx6(UnlockGlyph, { className: "h-3.5 w-3.5" })
1682
1153
  }
1683
1154
  ) : null,
1684
- single && onBindSlot ? /* @__PURE__ */ jsx5(
1155
+ single && onBindSlot ? /* @__PURE__ */ jsx6(
1685
1156
  Popover,
1686
1157
  {
1687
1158
  open: slotPopoverOpen,
1688
1159
  onClose: () => setSlotPopoverOpen(false),
1689
- trigger: /* @__PURE__ */ jsx5(
1160
+ trigger: /* @__PURE__ */ jsx6(
1690
1161
  "button",
1691
1162
  {
1692
1163
  type: "button",
1693
1164
  "aria-label": currentSlot ? `Slot: ${currentSlot}` : "Bind slot",
1165
+ "aria-pressed": !!currentSlot,
1166
+ "aria-haspopup": "dialog",
1167
+ "aria-expanded": slotPopoverOpen,
1694
1168
  onClick: () => {
1695
1169
  setSlotInput(currentSlot ?? "");
1696
1170
  setSlotPopoverOpen((v) => !v);
1697
1171
  },
1698
- className: currentSlot ? BTN_ACTIVE : BTN2,
1172
+ className: currentSlot ? BTN_ACTIVE : BTN,
1699
1173
  title: currentSlot ? `Slot: ${currentSlot}` : "Bind slot",
1700
- children: /* @__PURE__ */ jsx5(SlotGlyph, { className: "h-3.5 w-3.5" })
1174
+ children: /* @__PURE__ */ jsx6(SlotGlyph, { className: "h-3.5 w-3.5" })
1701
1175
  }
1702
1176
  ),
1703
1177
  children: /* @__PURE__ */ jsxs5("div", { className: `${POPOVER_PANEL} w-48 gap-2 p-2`, children: [
1704
- /* @__PURE__ */ jsx5(
1178
+ /* @__PURE__ */ jsx6(
1705
1179
  "input",
1706
1180
  {
1707
1181
  autoFocus: true,
@@ -1712,7 +1186,7 @@ function SelectionControls({
1712
1186
  }
1713
1187
  ),
1714
1188
  /* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
1715
- /* @__PURE__ */ jsx5(
1189
+ /* @__PURE__ */ jsx6(
1716
1190
  "button",
1717
1191
  {
1718
1192
  type: "button",
@@ -1724,7 +1198,7 @@ function SelectionControls({
1724
1198
  children: slotInput.trim() ? "Bind" : "Unbind"
1725
1199
  }
1726
1200
  ),
1727
- /* @__PURE__ */ jsx5(
1201
+ /* @__PURE__ */ jsx6(
1728
1202
  "button",
1729
1203
  {
1730
1204
  type: "button",
@@ -1738,66 +1212,70 @@ function SelectionControls({
1738
1212
  }
1739
1213
  ) : null,
1740
1214
  SEP,
1741
- /* @__PURE__ */ jsx5("button", { type: "button", "aria-label": "Delete selection", disabled: !canWrite, onClick: onDelete, className: BTN2, children: /* @__PURE__ */ jsx5(TrashGlyph, { className: "h-3.5 w-3.5 text-rose-400" }) })
1215
+ /* @__PURE__ */ jsx6("button", { type: "button", "aria-label": "Delete selection", disabled: !canWrite, onClick: onDelete, className: BTN, children: /* @__PURE__ */ jsx6(TrashGlyph, { className: "h-3.5 w-3.5 text-[var(--text-danger)]" }) })
1742
1216
  ] })
1743
1217
  ] });
1744
1218
  }
1745
1219
  function TextControls({ element, canWrite, onPatch }) {
1746
1220
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
1747
- /* @__PURE__ */ jsx5(FontPicker, { value: element.fontFamily, disabled: !canWrite, onChange: (fontFamily) => onPatch({ fontFamily }) }),
1748
- /* @__PURE__ */ jsx5(NumberInput, { label: "Size", value: element.fontSize, min: 1, onCommit: (v) => onPatch({ fontSize: v }), className: "w-12" }),
1749
- /* @__PURE__ */ jsx5(
1221
+ /* @__PURE__ */ jsx6(FontPicker, { value: element.fontFamily, disabled: !canWrite, onChange: (fontFamily) => onPatch({ fontFamily }) }),
1222
+ /* @__PURE__ */ jsx6(NumberInput, { label: "Size", value: element.fontSize, min: 1, onCommit: (v) => onPatch({ fontSize: v }), className: "w-12" }),
1223
+ /* @__PURE__ */ jsx6(
1750
1224
  "button",
1751
1225
  {
1752
1226
  type: "button",
1753
1227
  "aria-label": "Bold",
1228
+ "aria-pressed": !!element.fontStyle?.includes("bold"),
1754
1229
  disabled: !canWrite,
1755
1230
  onClick: () => onPatch({ fontStyle: element.fontStyle === "bold" || element.fontStyle === "bold italic" ? element.fontStyle === "bold italic" ? "italic" : "normal" : element.fontStyle === "italic" ? "bold italic" : "bold" }),
1756
- className: element.fontStyle?.includes("bold") ? BTN_ACTIVE : BTN2,
1757
- children: /* @__PURE__ */ jsx5(BoldGlyph, { className: "h-3.5 w-3.5" })
1231
+ className: element.fontStyle?.includes("bold") ? BTN_ACTIVE : BTN,
1232
+ children: /* @__PURE__ */ jsx6(BoldGlyph, { className: "h-3.5 w-3.5" })
1758
1233
  }
1759
1234
  ),
1760
- /* @__PURE__ */ jsx5(
1235
+ /* @__PURE__ */ jsx6(
1761
1236
  "button",
1762
1237
  {
1763
1238
  type: "button",
1764
1239
  "aria-label": "Italic",
1240
+ "aria-pressed": !!element.fontStyle?.includes("italic"),
1765
1241
  disabled: !canWrite,
1766
1242
  onClick: () => onPatch({ fontStyle: element.fontStyle === "italic" || element.fontStyle === "bold italic" ? element.fontStyle === "bold italic" ? "bold" : "normal" : element.fontStyle === "bold" ? "bold italic" : "italic" }),
1767
- className: element.fontStyle?.includes("italic") ? BTN_ACTIVE : BTN2,
1768
- children: /* @__PURE__ */ jsx5(ItalicGlyph, { className: "h-3.5 w-3.5" })
1243
+ className: element.fontStyle?.includes("italic") ? BTN_ACTIVE : BTN,
1244
+ children: /* @__PURE__ */ jsx6(ItalicGlyph, { className: "h-3.5 w-3.5" })
1769
1245
  }
1770
1246
  ),
1771
- ["left", "center", "right"].map((align) => /* @__PURE__ */ jsx5(
1247
+ /* @__PURE__ */ jsx6("div", { role: "radiogroup", "aria-label": "Text alignment", className: "flex items-center gap-2", children: ["left", "center", "right"].map((align) => /* @__PURE__ */ jsx6(
1772
1248
  "button",
1773
1249
  {
1774
1250
  type: "button",
1251
+ role: "radio",
1775
1252
  "aria-label": `Align ${align}`,
1253
+ "aria-checked": element.align === align,
1776
1254
  disabled: !canWrite,
1777
1255
  onClick: () => onPatch({ align }),
1778
- className: element.align === align ? BTN_ACTIVE : BTN2,
1779
- children: align === "left" ? /* @__PURE__ */ jsx5(AlignLeftGlyph, { className: "h-3.5 w-3.5" }) : align === "center" ? /* @__PURE__ */ jsx5(AlignCenterGlyph, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx5(AlignRightGlyph, { className: "h-3.5 w-3.5" })
1256
+ className: element.align === align ? BTN_ACTIVE : BTN,
1257
+ children: align === "left" ? /* @__PURE__ */ jsx6(AlignLeftGlyph, { className: "h-3.5 w-3.5" }) : align === "center" ? /* @__PURE__ */ jsx6(AlignCenterGlyph, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx6(AlignRightGlyph, { className: "h-3.5 w-3.5" })
1780
1258
  },
1781
1259
  align
1782
- )),
1783
- /* @__PURE__ */ jsx5(NumberInput, { label: "Line H", value: element.lineHeight, step: 0.1, min: 0.5, onCommit: (v) => onPatch({ lineHeight: v }), className: "w-12" }),
1784
- /* @__PURE__ */ jsx5(NumberInput, { label: "Spacing", value: element.letterSpacing, step: 0.5, onCommit: (v) => onPatch({ letterSpacing: v }), className: "w-14" }),
1785
- /* @__PURE__ */ jsx5(ColorSwatch, { label: "Fill", value: element.fill, onCommit: (v) => onPatch({ fill: v }), disabled: !canWrite })
1260
+ )) }),
1261
+ /* @__PURE__ */ jsx6(NumberInput, { label: "Line H", value: element.lineHeight, step: 0.1, min: 0.5, onCommit: (v) => onPatch({ lineHeight: v }), className: "w-12" }),
1262
+ /* @__PURE__ */ jsx6(NumberInput, { label: "Spacing", value: element.letterSpacing, step: 0.5, onCommit: (v) => onPatch({ letterSpacing: v }), className: "w-14" }),
1263
+ /* @__PURE__ */ jsx6(ColorSwatch, { label: "Fill", value: element.fill, onCommit: (v) => onPatch({ fill: v }), disabled: !canWrite })
1786
1264
  ] });
1787
1265
  }
1788
1266
  function ShapeControls({ element, canWrite, onPatch, showCornerRadius }) {
1789
1267
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
1790
- /* @__PURE__ */ jsx5(ColorSwatch, { label: "Fill", value: element.fill, onCommit: (v) => onPatch({ fill: v }), disabled: !canWrite }),
1791
- /* @__PURE__ */ jsx5(ColorSwatch, { label: "Stroke", value: element.stroke ?? "#000000", onCommit: (v) => onPatch({ stroke: v }), disabled: !canWrite }),
1792
- /* @__PURE__ */ jsx5(NumberInput, { label: "Stroke W", value: element.strokeWidth ?? 0, min: 0, onCommit: (v) => onPatch({ strokeWidth: v }), className: "w-14" }),
1793
- showCornerRadius && "cornerRadius" in element ? /* @__PURE__ */ jsx5(NumberInput, { label: "Corner R", value: element.cornerRadius ?? 0, min: 0, onCommit: (v) => onPatch({ cornerRadius: v }), className: "w-14" }) : null
1268
+ /* @__PURE__ */ jsx6(ColorSwatch, { label: "Fill", value: element.fill, onCommit: (v) => onPatch({ fill: v }), disabled: !canWrite }),
1269
+ /* @__PURE__ */ jsx6(ColorSwatch, { label: "Stroke", value: element.stroke ?? "#000000", onCommit: (v) => onPatch({ stroke: v }), disabled: !canWrite }),
1270
+ /* @__PURE__ */ jsx6(NumberInput, { label: "Stroke W", value: element.strokeWidth ?? 0, min: 0, onCommit: (v) => onPatch({ strokeWidth: v }), className: "w-14" }),
1271
+ showCornerRadius && "cornerRadius" in element ? /* @__PURE__ */ jsx6(NumberInput, { label: "Corner R", value: element.cornerRadius ?? 0, min: 0, onCommit: (v) => onPatch({ cornerRadius: v }), className: "w-14" }) : null
1794
1272
  ] });
1795
1273
  }
1796
1274
  function ImageControls({ element, canWrite, onPatch }) {
1797
1275
  const [swapOpen, setSwapOpen] = useState3(false);
1798
1276
  const [swapUrl, setSwapUrl] = useState3("");
1799
1277
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
1800
- /* @__PURE__ */ jsx5(
1278
+ /* @__PURE__ */ jsx6(
1801
1279
  SelectControl,
1802
1280
  {
1803
1281
  label: "Fit",
@@ -1812,12 +1290,12 @@ function ImageControls({ element, canWrite, onPatch }) {
1812
1290
  ]
1813
1291
  }
1814
1292
  ),
1815
- /* @__PURE__ */ jsx5(
1293
+ /* @__PURE__ */ jsx6(
1816
1294
  Popover,
1817
1295
  {
1818
1296
  open: swapOpen,
1819
1297
  onClose: () => setSwapOpen(false),
1820
- trigger: /* @__PURE__ */ jsx5(
1298
+ trigger: /* @__PURE__ */ jsx6(
1821
1299
  "button",
1822
1300
  {
1823
1301
  type: "button",
@@ -1827,13 +1305,13 @@ function ImageControls({ element, canWrite, onPatch }) {
1827
1305
  setSwapUrl(element.src);
1828
1306
  setSwapOpen((v) => !v);
1829
1307
  },
1830
- className: BTN2,
1308
+ className: BTN,
1831
1309
  title: "Replace image",
1832
- children: /* @__PURE__ */ jsx5(SwapGlyph, { className: "h-3.5 w-3.5" })
1310
+ children: /* @__PURE__ */ jsx6(SwapGlyph, { className: "h-3.5 w-3.5" })
1833
1311
  }
1834
1312
  ),
1835
1313
  children: /* @__PURE__ */ jsxs5("div", { className: `${POPOVER_PANEL} w-64 gap-2 p-2`, children: [
1836
- /* @__PURE__ */ jsx5(
1314
+ /* @__PURE__ */ jsx6(
1837
1315
  "input",
1838
1316
  {
1839
1317
  autoFocus: true,
@@ -1845,7 +1323,7 @@ function ImageControls({ element, canWrite, onPatch }) {
1845
1323
  }
1846
1324
  ),
1847
1325
  /* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
1848
- /* @__PURE__ */ jsx5(
1326
+ /* @__PURE__ */ jsx6(
1849
1327
  "button",
1850
1328
  {
1851
1329
  type: "button",
@@ -1858,7 +1336,7 @@ function ImageControls({ element, canWrite, onPatch }) {
1858
1336
  children: "Replace"
1859
1337
  }
1860
1338
  ),
1861
- /* @__PURE__ */ jsx5(
1339
+ /* @__PURE__ */ jsx6(
1862
1340
  "button",
1863
1341
  {
1864
1342
  type: "button",
@@ -1888,7 +1366,7 @@ function PagePropsControls({ page, canWrite, onSetPageProps, onSetPageGuides })
1888
1366
  ...SIZE_PRESETS.map((p) => ({ value: p.id, label: p.label }))
1889
1367
  ];
1890
1368
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
1891
- /* @__PURE__ */ jsx5(
1369
+ /* @__PURE__ */ jsx6(
1892
1370
  "input",
1893
1371
  {
1894
1372
  type: "text",
@@ -1900,7 +1378,7 @@ function PagePropsControls({ page, canWrite, onSetPageProps, onSetPageGuides })
1900
1378
  }
1901
1379
  ),
1902
1380
  SEP,
1903
- /* @__PURE__ */ jsx5(
1381
+ /* @__PURE__ */ jsx6(
1904
1382
  SelectControl,
1905
1383
  {
1906
1384
  label: "Preset",
@@ -1914,8 +1392,8 @@ function PagePropsControls({ page, canWrite, onSetPageProps, onSetPageGuides })
1914
1392
  }
1915
1393
  ),
1916
1394
  /* @__PURE__ */ jsxs5("label", { className: "flex flex-col items-center gap-0.5", children: [
1917
- /* @__PURE__ */ jsx5("span", { className: FIELD_LABEL, children: "W" }),
1918
- /* @__PURE__ */ jsx5(
1395
+ /* @__PURE__ */ jsx6("span", { className: FIELD_LABEL, children: "W" }),
1396
+ /* @__PURE__ */ jsx6(
1919
1397
  "input",
1920
1398
  {
1921
1399
  type: "number",
@@ -1932,10 +1410,10 @@ function PagePropsControls({ page, canWrite, onSetPageProps, onSetPageGuides })
1932
1410
  }
1933
1411
  )
1934
1412
  ] }),
1935
- /* @__PURE__ */ jsx5("span", { className: "text-[var(--text-muted)]", children: "\xD7" }),
1413
+ /* @__PURE__ */ jsx6("span", { className: "text-[var(--text-muted)]", children: "\xD7" }),
1936
1414
  /* @__PURE__ */ jsxs5("label", { className: "flex flex-col items-center gap-0.5", children: [
1937
- /* @__PURE__ */ jsx5("span", { className: FIELD_LABEL, children: "H" }),
1938
- /* @__PURE__ */ jsx5(
1415
+ /* @__PURE__ */ jsx6("span", { className: FIELD_LABEL, children: "H" }),
1416
+ /* @__PURE__ */ jsx6(
1939
1417
  "input",
1940
1418
  {
1941
1419
  type: "number",
@@ -1953,9 +1431,9 @@ function PagePropsControls({ page, canWrite, onSetPageProps, onSetPageGuides })
1953
1431
  )
1954
1432
  ] }),
1955
1433
  SEP,
1956
- /* @__PURE__ */ jsx5(ColorSwatch, { label: "BG", value: page.background, onCommit: (v) => onSetPageProps({ background: v }), disabled: !canWrite }),
1434
+ /* @__PURE__ */ jsx6(ColorSwatch, { label: "BG", value: page.background, onCommit: (v) => onSetPageProps({ background: v }), disabled: !canWrite }),
1957
1435
  SEP,
1958
- /* @__PURE__ */ jsx5(BleedControls, { page, canWrite, onSetPageProps })
1436
+ /* @__PURE__ */ jsx6(BleedControls, { page, canWrite, onSetPageProps })
1959
1437
  ] });
1960
1438
  }
1961
1439
  function BleedControls({ page, canWrite, onSetPageProps }) {
@@ -1965,20 +1443,20 @@ function BleedControls({ page, canWrite, onSetPageProps }) {
1965
1443
  onSetPageProps({ bleed: { ...current, [side]: value } });
1966
1444
  }
1967
1445
  if (!bleed) {
1968
- return /* @__PURE__ */ jsx5(
1446
+ return /* @__PURE__ */ jsx6(
1969
1447
  "button",
1970
1448
  {
1971
1449
  type: "button",
1972
1450
  disabled: !canWrite,
1973
1451
  onClick: () => onSetPageProps({ bleed: { top: 3, right: 3, bottom: 3, left: 3 } }),
1974
- className: BTN2,
1452
+ className: BTN,
1975
1453
  title: "Enable bleed",
1976
- children: /* @__PURE__ */ jsx5(BleedGlyph, { className: "h-3.5 w-3.5" })
1454
+ children: /* @__PURE__ */ jsx6(BleedGlyph, { className: "h-3.5 w-3.5" })
1977
1455
  }
1978
1456
  );
1979
1457
  }
1980
1458
  return /* @__PURE__ */ jsxs5(Fragment4, { children: [
1981
- ["top", "right", "bottom", "left"].map((side) => /* @__PURE__ */ jsx5(
1459
+ ["top", "right", "bottom", "left"].map((side) => /* @__PURE__ */ jsx6(
1982
1460
  NumberInput,
1983
1461
  {
1984
1462
  label: `Bleed ${side[0].toUpperCase()}`,
@@ -1989,13 +1467,13 @@ function BleedControls({ page, canWrite, onSetPageProps }) {
1989
1467
  },
1990
1468
  side
1991
1469
  )),
1992
- /* @__PURE__ */ jsx5(
1470
+ /* @__PURE__ */ jsx6(
1993
1471
  "button",
1994
1472
  {
1995
1473
  type: "button",
1996
1474
  disabled: !canWrite,
1997
1475
  onClick: () => onSetPageProps({ bleed: null }),
1998
- className: BTN2,
1476
+ className: BTN,
1999
1477
  title: "Remove bleed",
2000
1478
  children: "\xD7"
2001
1479
  }
@@ -2004,11 +1482,10 @@ function BleedControls({ page, canWrite, onSetPageProps }) {
2004
1482
  }
2005
1483
 
2006
1484
  // src/design-canvas-react/components/ZoomControls.tsx
2007
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1485
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
2008
1486
  var STEP = 0.1;
2009
1487
  var MIN = 0.05;
2010
1488
  var MAX = 32;
2011
- var BTN3 = "flex h-6 w-6 items-center justify-center rounded border border-[var(--border-default)] text-[var(--text-secondary)] transition hover:text-[var(--text-primary)] disabled:cursor-default disabled:opacity-40";
2012
1489
  function ZoomControls({ zoom, onZoom, onFit }) {
2013
1490
  function zoomOut() {
2014
1491
  onZoom(Math.max(MIN, parseFloat((zoom - STEP).toFixed(4))));
@@ -2020,26 +1497,26 @@ function ZoomControls({ zoom, onZoom, onFit }) {
2020
1497
  onZoom(1);
2021
1498
  }
2022
1499
  return /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1 px-2", children: [
2023
- /* @__PURE__ */ jsx6(
1500
+ /* @__PURE__ */ jsx7(
2024
1501
  "button",
2025
1502
  {
2026
1503
  type: "button",
2027
1504
  "aria-label": "Fit page to viewport",
2028
1505
  onClick: onFit,
2029
- className: BTN3,
1506
+ className: BTN_SM,
2030
1507
  title: "Fit page (F)",
2031
- children: /* @__PURE__ */ jsx6(ZoomFitGlyph, { className: "h-3.5 w-3.5" })
1508
+ children: /* @__PURE__ */ jsx7(ZoomFitGlyph, { className: "h-3.5 w-3.5" })
2032
1509
  }
2033
1510
  ),
2034
- /* @__PURE__ */ jsx6(
1511
+ /* @__PURE__ */ jsx7(
2035
1512
  "button",
2036
1513
  {
2037
1514
  type: "button",
2038
1515
  "aria-label": "Zoom out",
2039
1516
  onClick: zoomOut,
2040
1517
  disabled: zoom <= MIN,
2041
- className: BTN3,
2042
- children: /* @__PURE__ */ jsx6("span", { className: "text-base leading-none", children: "\u2212" })
1518
+ className: BTN_SM,
1519
+ children: /* @__PURE__ */ jsx7("span", { className: "text-base leading-none", children: "\u2212" })
2043
1520
  }
2044
1521
  ),
2045
1522
  /* @__PURE__ */ jsxs6(
@@ -2048,7 +1525,7 @@ function ZoomControls({ zoom, onZoom, onFit }) {
2048
1525
  type: "button",
2049
1526
  "aria-label": "Reset to 100%",
2050
1527
  onClick: resetHundred,
2051
- className: "rounded px-1.5 py-0.5 font-mono text-[11px] tabular-nums text-[var(--text-secondary)] transition hover:bg-[var(--border-default)] hover:text-[var(--text-primary)]",
1528
+ className: "rounded px-1.5 py-0.5 font-mono text-[11px] tabular-nums text-[var(--text-secondary)] transition hover:bg-[var(--border-default)] hover:text-[var(--text-primary)] focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[hsl(var(--ring))]",
2052
1529
  title: "Reset to 100%",
2053
1530
  children: [
2054
1531
  Math.round(zoom * 100),
@@ -2056,15 +1533,15 @@ function ZoomControls({ zoom, onZoom, onFit }) {
2056
1533
  ]
2057
1534
  }
2058
1535
  ),
2059
- /* @__PURE__ */ jsx6(
1536
+ /* @__PURE__ */ jsx7(
2060
1537
  "button",
2061
1538
  {
2062
1539
  type: "button",
2063
1540
  "aria-label": "Zoom in",
2064
1541
  onClick: zoomIn,
2065
1542
  disabled: zoom >= MAX,
2066
- className: BTN3,
2067
- children: /* @__PURE__ */ jsx6("span", { className: "text-sm leading-none", children: "+" })
1543
+ className: BTN_SM,
1544
+ children: /* @__PURE__ */ jsx7("span", { className: "text-sm leading-none", children: "+" })
2068
1545
  }
2069
1546
  )
2070
1547
  ] });
@@ -2072,7 +1549,7 @@ function ZoomControls({ zoom, onZoom, onFit }) {
2072
1549
 
2073
1550
  // src/design-canvas-react/components/ExportControl.tsx
2074
1551
  import { useRef as useRef4, useState as useState4 } from "react";
2075
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1552
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2076
1553
  var FORMATS = [
2077
1554
  { id: "png", label: "PNG" },
2078
1555
  { id: "jpeg", label: "JPEG" }
@@ -2106,9 +1583,9 @@ function ExportControl({ defaults, onExport, className }) {
2106
1583
  },
2107
1584
  className: "flex h-8 items-center gap-1.5 rounded-md border border-[var(--border-default)] px-2.5 text-xs font-medium text-[var(--text-primary)] transition-colors hover:border-[var(--brand-primary)]/40",
2108
1585
  children: [
2109
- /* @__PURE__ */ jsx7(ExportGlyph, { className: "h-3.5 w-3.5" }),
1586
+ /* @__PURE__ */ jsx8(ExportGlyph, { className: "h-3.5 w-3.5" }),
2110
1587
  "Export",
2111
- /* @__PURE__ */ jsx7(ChevronDownGlyph, { className: "h-3 w-3 text-[var(--text-muted)]" })
1588
+ /* @__PURE__ */ jsx8(ChevronDownGlyph, { className: "h-3 w-3 text-[var(--text-muted)]" })
2112
1589
  ]
2113
1590
  }
2114
1591
  ),
@@ -2125,8 +1602,8 @@ function ExportControl({ defaults, onExport, className }) {
2125
1602
  className: "absolute right-0 top-full z-50 mt-1 flex w-52 flex-col gap-3 rounded-md border border-[var(--border-default)] bg-[var(--bg-input)] p-3 shadow-lg",
2126
1603
  children: [
2127
1604
  /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1.5", children: [
2128
- /* @__PURE__ */ jsx7("span", { className: "text-[11px] font-medium text-[var(--text-muted)]", children: "Format" }),
2129
- /* @__PURE__ */ jsx7("div", { className: "flex gap-1.5", children: FORMATS.map((f) => /* @__PURE__ */ jsx7(
1605
+ /* @__PURE__ */ jsx8("span", { className: "text-[11px] font-medium text-[var(--text-muted)]", children: "Format" }),
1606
+ /* @__PURE__ */ jsx8("div", { className: "flex gap-1.5", children: FORMATS.map((f) => /* @__PURE__ */ jsx8(
2130
1607
  "button",
2131
1608
  {
2132
1609
  type: "button",
@@ -2139,8 +1616,8 @@ function ExportControl({ defaults, onExport, className }) {
2139
1616
  )) })
2140
1617
  ] }),
2141
1618
  /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1.5", children: [
2142
- /* @__PURE__ */ jsx7("span", { className: "text-[11px] font-medium text-[var(--text-muted)]", children: "Scale" }),
2143
- /* @__PURE__ */ jsx7("div", { className: "flex gap-1.5", children: SCALES.map((s) => /* @__PURE__ */ jsx7(
1619
+ /* @__PURE__ */ jsx8("span", { className: "text-[11px] font-medium text-[var(--text-muted)]", children: "Scale" }),
1620
+ /* @__PURE__ */ jsx8("div", { className: "flex gap-1.5", children: SCALES.map((s) => /* @__PURE__ */ jsx8(
2144
1621
  "button",
2145
1622
  {
2146
1623
  type: "button",
@@ -2152,7 +1629,7 @@ function ExportControl({ defaults, onExport, className }) {
2152
1629
  s.value
2153
1630
  )) })
2154
1631
  ] }),
2155
- /* @__PURE__ */ jsx7(
1632
+ /* @__PURE__ */ jsx8(
2156
1633
  "button",
2157
1634
  {
2158
1635
  type: "button",
@@ -2169,7 +1646,7 @@ function ExportControl({ defaults, onExport, className }) {
2169
1646
  }
2170
1647
 
2171
1648
  // src/design-canvas-react/components/DesignCanvas.tsx
2172
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
1649
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2173
1650
  function mintId() {
2174
1651
  const uuid = globalThis.crypto && "randomUUID" in globalThis.crypto ? globalThis.crypto.randomUUID() : null;
2175
1652
  return `local-${uuid ?? `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}`;
@@ -2214,6 +1691,7 @@ function DesignCanvas({
2214
1691
  className,
2215
1692
  fitOnMount,
2216
1693
  onReady,
1694
+ render,
2217
1695
  renderWorkspace,
2218
1696
  renderThumbnail
2219
1697
  }) {
@@ -2396,12 +1874,7 @@ function DesignCanvas({
2396
1874
  void onApplyOperations(command.inverseOperations()).then((result) => {
2397
1875
  if (result.document) stack.reset(result.document);
2398
1876
  }).catch((error) => {
2399
- if (stack.canRedo()) {
2400
- try {
2401
- stack.redo();
2402
- } catch {
2403
- }
2404
- }
1877
+ stack.reexecute(command);
2405
1878
  setCommitError(error instanceof Error ? error.message : String(error));
2406
1879
  });
2407
1880
  }, [stack, canWrite, onApplyOperations]);
@@ -2417,12 +1890,7 @@ function DesignCanvas({
2417
1890
  void onApplyOperations(command.operations()).then((result) => {
2418
1891
  if (result.document) stack.reset(result.document);
2419
1892
  }).catch((error) => {
2420
- if (stack.canUndo()) {
2421
- try {
2422
- stack.undo();
2423
- } catch {
2424
- }
2425
- }
1893
+ stack.reundo(command);
2426
1894
  setCommitError(error instanceof Error ? error.message : String(error));
2427
1895
  });
2428
1896
  }, [stack, canWrite, onApplyOperations]);
@@ -2466,7 +1934,7 @@ function DesignCanvas({
2466
1934
  }, [activePage, editorState.selectedElementIds]);
2467
1935
  const review = mode === "review";
2468
1936
  if (!activePage) {
2469
- return /* @__PURE__ */ jsx8("div", { className: `flex h-full items-center justify-center bg-[var(--bg-input)] text-[var(--text-muted)] ${className ?? ""}`, children: "No pages in document" });
1937
+ return /* @__PURE__ */ jsx9("div", { className: `flex h-full items-center justify-center bg-[var(--bg-input)] text-[var(--text-muted)] ${className ?? ""}`, children: "No pages in document" });
2470
1938
  }
2471
1939
  const bleedScreen = editorState.showBleed && activePage.bleed ? {
2472
1940
  top: activePage.bleed.top * editorState.zoom,
@@ -2475,10 +1943,10 @@ function DesignCanvas({
2475
1943
  left: activePage.bleed.left * editorState.zoom
2476
1944
  } : null;
2477
1945
  return /* @__PURE__ */ jsxs8("div", { className: `flex h-full min-h-0 bg-[var(--bg-input)] text-[var(--text-primary)] ${className ?? ""}`, children: [
2478
- renderSidePanel && !review ? /* @__PURE__ */ jsx8("aside", { className: "flex w-64 shrink-0 flex-col overflow-hidden border-r border-[var(--border-default)]", children: renderSidePanel() }) : null,
1946
+ renderSidePanel && !review ? /* @__PURE__ */ jsx9("aside", { className: "flex w-64 shrink-0 flex-col overflow-hidden border-r border-[var(--border-default)]", children: renderSidePanel() }) : null,
2479
1947
  /* @__PURE__ */ jsxs8("div", { className: "flex min-w-0 flex-1 flex-col", children: [
2480
1948
  /* @__PURE__ */ jsxs8("div", { className: "flex shrink-0 items-stretch", children: [
2481
- /* @__PURE__ */ jsx8("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx8(
1949
+ /* @__PURE__ */ jsx9("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsx9(
2482
1950
  Toolbar,
2483
1951
  {
2484
1952
  page: activePage,
@@ -2507,7 +1975,7 @@ function DesignCanvas({
2507
1975
  onBindSlot: handleBindSlot
2508
1976
  }
2509
1977
  ) }),
2510
- onExport ? /* @__PURE__ */ jsx8("div", { className: "flex shrink-0 items-center border-b border-l border-[var(--border-default)] bg-[var(--bg-input)] px-2", children: /* @__PURE__ */ jsx8(
1978
+ onExport ? /* @__PURE__ */ jsx9("div", { className: "flex shrink-0 items-center border-b border-l border-[var(--border-default)] bg-[var(--bg-input)] px-2", children: /* @__PURE__ */ jsx9(
2511
1979
  ExportControl,
2512
1980
  {
2513
1981
  defaults: exportDefaults,
@@ -2518,11 +1986,11 @@ function DesignCanvas({
2518
1986
  commitError ? /* @__PURE__ */ jsxs8(
2519
1987
  "div",
2520
1988
  {
2521
- className: "flex shrink-0 items-center justify-between gap-3 border-b border-rose-500/30 bg-rose-500/10 px-3 py-1.5 text-xs text-rose-300",
1989
+ className: "flex shrink-0 items-center justify-between gap-3 border-b border-[hsl(var(--destructive)/0.3)] bg-[hsl(var(--destructive)/0.1)] px-3 py-1.5 text-xs text-[var(--text-danger)]",
2522
1990
  role: "alert",
2523
1991
  children: [
2524
- /* @__PURE__ */ jsx8("span", { className: "min-w-0 truncate", children: commitError }),
2525
- /* @__PURE__ */ jsx8(
1992
+ /* @__PURE__ */ jsx9("span", { className: "min-w-0 truncate", children: commitError }),
1993
+ /* @__PURE__ */ jsx9(
2526
1994
  "button",
2527
1995
  {
2528
1996
  type: "button",
@@ -2535,7 +2003,7 @@ function DesignCanvas({
2535
2003
  }
2536
2004
  ) : null,
2537
2005
  /* @__PURE__ */ jsxs8("div", { className: "relative min-h-0 flex-1", children: [
2538
- /* @__PURE__ */ jsx8(
2006
+ /* @__PURE__ */ jsx9(
2539
2007
  Rulers,
2540
2008
  {
2541
2009
  pageWidth: activePage.width,
@@ -2548,12 +2016,12 @@ function DesignCanvas({
2548
2016
  onGuidesChange: handleSetPageGuides
2549
2017
  }
2550
2018
  ),
2551
- bleedScreen && activePage.bleed ? /* @__PURE__ */ jsx8(
2019
+ bleedScreen && activePage.bleed ? /* @__PURE__ */ jsx9(
2552
2020
  "div",
2553
2021
  {
2554
2022
  className: "pointer-events-none absolute inset-0 z-10 overflow-hidden",
2555
2023
  "aria-hidden": true,
2556
- children: /* @__PURE__ */ jsx8(
2024
+ children: /* @__PURE__ */ jsx9(
2557
2025
  "div",
2558
2026
  {
2559
2027
  style: {
@@ -2561,7 +2029,7 @@ function DesignCanvas({
2561
2029
  left: editorState.panX,
2562
2030
  top: editorState.panY
2563
2031
  },
2564
- children: /* @__PURE__ */ jsx8(
2032
+ children: /* @__PURE__ */ jsx9(
2565
2033
  BleedTrimOverlay,
2566
2034
  {
2567
2035
  pageWidthPx: activePage.width * editorState.zoom,
@@ -2591,13 +2059,14 @@ function DesignCanvas({
2591
2059
  onExportRef: exportRef,
2592
2060
  fitOnMount,
2593
2061
  onReady,
2062
+ render,
2594
2063
  onZoomChange: setZoom,
2595
2064
  onPanChange: setPan,
2596
2065
  onSelectElements: setSelectedElements
2597
2066
  })
2598
2067
  ] }),
2599
2068
  /* @__PURE__ */ jsxs8("div", { className: "flex shrink-0 items-stretch border-t border-[var(--border-default)]", children: [
2600
- /* @__PURE__ */ jsx8("div", { className: "min-w-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsx8(
2069
+ /* @__PURE__ */ jsx9("div", { className: "min-w-0 flex-1 overflow-hidden", children: /* @__PURE__ */ jsx9(
2601
2070
  PagesStrip,
2602
2071
  {
2603
2072
  pages: editorState.document.pages,
@@ -2612,7 +2081,7 @@ function DesignCanvas({
2612
2081
  onReorderPage: handleReorderPage
2613
2082
  }
2614
2083
  ) }),
2615
- /* @__PURE__ */ jsx8("div", { className: "flex shrink-0 items-center border-l border-[var(--border-default)]", children: /* @__PURE__ */ jsx8(
2084
+ /* @__PURE__ */ jsx9("div", { className: "flex shrink-0 items-center border-l border-[var(--border-default)]", children: /* @__PURE__ */ jsx9(
2616
2085
  ZoomControls,
2617
2086
  {
2618
2087
  zoom: editorState.zoom,
@@ -2622,29 +2091,12 @@ function DesignCanvas({
2622
2091
  ) })
2623
2092
  ] })
2624
2093
  ] }),
2625
- renderAgentPanel ? /* @__PURE__ */ jsx8("aside", { className: "flex w-80 shrink-0 flex-col overflow-hidden border-l border-[var(--border-default)]", children: renderAgentPanel({ selectedElements, activePageId: editorState.activePageId }) }) : null
2094
+ renderAgentPanel ? /* @__PURE__ */ jsx9("aside", { className: "flex w-80 shrink-0 flex-col overflow-hidden border-l border-[var(--border-default)]", children: renderAgentPanel({ selectedElements, activePageId: editorState.activePageId }) }) : null
2626
2095
  ] });
2627
2096
  }
2628
2097
  var DesignCanvas_default = DesignCanvas;
2629
2098
 
2630
2099
  export {
2631
- SCENE_COMMAND_HISTORY_LIMIT,
2632
- createSceneCommandStack,
2633
- addElementCommand,
2634
- setAttrsCommand,
2635
- multiSetAttrsCommand,
2636
- reorderElementCommand,
2637
- deleteElementCommand,
2638
- groupElementsCommand,
2639
- ungroupElementCommand,
2640
- addPageCommand,
2641
- duplicatePageCommand,
2642
- deletePageCommand,
2643
- reorderPageCommand,
2644
- setPagePropsCommand,
2645
- setPageGuidesCommand,
2646
- bindSlotCommand,
2647
- setDocumentTitleCommand,
2648
2100
  selectTickStep,
2649
2101
  buildRulerTicks,
2650
2102
  formatRulerLabel,
@@ -2662,6 +2114,11 @@ export {
2662
2114
  VideoGlyph,
2663
2115
  SlotGlyph,
2664
2116
  ShapesGlyph,
2117
+ BTN,
2118
+ BTN_ACTIVE,
2119
+ BTN_SM,
2120
+ BTN_SM_ACTIVE,
2121
+ IconButton,
2665
2122
  PagesStrip,
2666
2123
  Rulers,
2667
2124
  Toolbar,
@@ -2670,4 +2127,4 @@ export {
2670
2127
  DesignCanvas,
2671
2128
  DesignCanvas_default
2672
2129
  };
2673
- //# sourceMappingURL=chunk-27LQXQSS.js.map
2130
+ //# sourceMappingURL=chunk-YEWTVDDT.js.map