@anvilkit/puck-studio 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,38 +1,35 @@
1
1
  'use strict';
2
2
 
3
- var core = require('@puckeditor/core');
4
3
  var lucideReact = require('lucide-react');
5
- var button = require('@base-ui/react/button');
6
- var classVarianceAuthority = require('class-variance-authority');
7
- var clsx = require('clsx');
8
- var tailwindMerge = require('tailwind-merge');
9
- var jsxRuntime = require('react/jsx-runtime');
10
- var separator = require('@base-ui/react/separator');
11
4
  var zustand = require('zustand');
12
- var React18 = require('react');
13
- var TooltipPrimitive = require('@radix-ui/react-tooltip');
14
- var menu = require('@base-ui/react/menu');
5
+ var React17 = require('react');
6
+ var jsxRuntime = require('react/jsx-runtime');
15
7
  var scrollArea = require('@base-ui/react/scroll-area');
8
+ var clsx = require('clsx');
9
+ var tailwindMerge = require('tailwind-merge');
16
10
  var input = require('@base-ui/react/input');
11
+ var core = require('@puckeditor/core');
12
+ var separator = require('@base-ui/react/separator');
13
+ var tooltip = require('@base-ui/react/tooltip');
17
14
  var mergeProps = require('@base-ui/react/merge-props');
18
15
  var useRender = require('@base-ui/react/use-render');
16
+ var button = require('@base-ui/react/button');
17
+ var classVarianceAuthority = require('class-variance-authority');
19
18
  var select = require('@base-ui/react/select');
20
19
  var core$1 = require('@dnd-kit/core');
21
20
  var sortable = require('@dnd-kit/sortable');
22
21
  var utilities = require('@dnd-kit/utilities');
23
- var popover = require('@base-ui-components/react/popover');
22
+ var popover = require('@base-ui/react/popover');
24
23
  var react = require('motion/react');
25
24
  var toggle = require('@base-ui/react/toggle');
26
25
  var cmdk = require('cmdk');
27
- require('@base-ui/react/dialog');
28
- var pluginAi = require('@puckeditor/plugin-ai');
29
- require('@puckeditor/plugin-ai/styles.css');
30
26
  require('@puckeditor/core/puck.css');
31
- var tabs = require('@base-ui-components/react/tabs');
32
- var motion9 = require('motion/react-client');
27
+ var tabs = require('@base-ui/react/tabs');
28
+ var middleware = require('zustand/middleware');
29
+ var motion8 = require('motion/react-client');
33
30
  var react$1 = require('@floating-ui/react');
34
31
  var avatar = require('@base-ui/react/avatar');
35
- var middleware = require('zustand/middleware');
32
+ var menu = require('@base-ui/react/menu');
36
33
 
37
34
  function _interopNamespace(e) {
38
35
  if (e && e.__esModule) return e;
@@ -52,90 +49,24 @@ function _interopNamespace(e) {
52
49
  return Object.freeze(n);
53
50
  }
54
51
 
55
- var React18__namespace = /*#__PURE__*/_interopNamespace(React18);
56
- var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitive);
57
- var motion9__namespace = /*#__PURE__*/_interopNamespace(motion9);
52
+ var React17__namespace = /*#__PURE__*/_interopNamespace(React17);
53
+ var motion8__namespace = /*#__PURE__*/_interopNamespace(motion8);
58
54
 
59
- // src/components/overrides/layout/EditorHeader.tsx
60
- function cn(...inputs) {
61
- return tailwindMerge.twMerge(clsx.clsx(inputs));
62
- }
63
- var buttonVariants = classVarianceAuthority.cva(
64
- "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
65
- {
66
- variants: {
67
- variant: {
68
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
69
- outline: "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
70
- secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
71
- ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
72
- destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
73
- link: "text-primary underline-offset-4 hover:underline"
74
- },
75
- size: {
76
- default: "h-8 gap-1.5 px-2.5",
77
- xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs [&_svg:not([class*='size-'])]:size-3",
78
- sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] [&_svg:not([class*='size-'])]:size-3.5",
79
- lg: "h-9 gap-1.5 px-2.5",
80
- icon: "size-8",
81
- "icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] [&_svg:not([class*='size-'])]:size-3",
82
- "icon-sm": "size-7 rounded-[min(var(--radius-md),12px)]",
83
- "icon-lg": "size-9"
84
- }
85
- },
86
- defaultVariants: {
87
- variant: "default",
88
- size: "default"
89
- }
90
- }
91
- );
92
- function Button({
93
- className,
94
- variant = "default",
95
- size = "default",
96
- ...props
97
- }) {
98
- return /* @__PURE__ */ jsxRuntime.jsx(
99
- button.Button,
100
- {
101
- "data-slot": "button",
102
- className: cn(buttonVariants({ variant, size, className })),
103
- ...props
104
- }
105
- );
106
- }
107
- function Separator({
108
- className,
109
- orientation = "horizontal",
110
- ...props
111
- }) {
112
- return /* @__PURE__ */ jsxRuntime.jsx(
113
- separator.Separator,
114
- {
115
- "data-slot": "separator",
116
- orientation,
117
- className: cn(
118
- "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
119
- className
120
- ),
121
- ...props
122
- }
123
- );
124
- }
55
+ // src/core/overrides/layout/EditorDrawer.tsx
125
56
  function getStrictContext(name) {
126
- const Context = React18__namespace.createContext(void 0);
127
- const Provider2 = ({
57
+ const Context = React17__namespace.createContext(void 0);
58
+ const Provider = ({
128
59
  value,
129
60
  children
130
61
  }) => /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value, children });
131
62
  const useSafeContext = () => {
132
- const ctx = React18__namespace.useContext(Context);
63
+ const ctx = React17__namespace.useContext(Context);
133
64
  if (ctx === void 0) {
134
65
  throw new Error(`useContext must be used within ${name ?? "a Provider"}`);
135
66
  }
136
67
  return ctx;
137
68
  };
138
- return [Provider2, useSafeContext];
69
+ return [Provider, useSafeContext];
139
70
  }
140
71
 
141
72
  // src/store/ui-context.ts
@@ -166,137 +97,8 @@ function useToggleTheme() {
166
97
  function useMsg(key) {
167
98
  return zustand.useStore(useEditorI18nStoreApi(), (s) => s.messages[key] ?? key);
168
99
  }
169
- var TooltipProvider = TooltipPrimitive__namespace.Provider;
170
- var Tooltip = TooltipPrimitive__namespace.Root;
171
- var TooltipTrigger = TooltipPrimitive__namespace.Trigger;
172
- var TooltipContent = React18__namespace.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(TooltipPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
173
- TooltipPrimitive__namespace.Content,
174
- {
175
- ref,
176
- sideOffset,
177
- className: cn(
178
- "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
179
- className
180
- ),
181
- ...props
182
- }
183
- ) }));
184
- TooltipContent.displayName = TooltipPrimitive__namespace.Content.displayName;
185
- function DropdownMenu({ ...props }) {
186
- return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
187
- }
188
- function DropdownMenuTrigger({ ...props }) {
189
- return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
190
- }
191
- function DropdownMenuContent({
192
- align = "start",
193
- alignOffset = 0,
194
- side = "bottom",
195
- sideOffset = 4,
196
- className,
197
- ...props
198
- }) {
199
- return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
200
- menu.Menu.Positioner,
201
- {
202
- className: "isolate z-50 outline-none",
203
- align,
204
- alignOffset,
205
- side,
206
- sideOffset,
207
- children: /* @__PURE__ */ jsxRuntime.jsx(
208
- menu.Menu.Popup,
209
- {
210
- "data-slot": "dropdown-menu-content",
211
- className: cn(
212
- "data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-lg p-1 shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none data-closed:overflow-hidden",
213
- className
214
- ),
215
- ...props
216
- }
217
- )
218
- }
219
- ) });
220
- }
221
- function DropdownMenuItem({
222
- className,
223
- inset,
224
- variant = "default",
225
- ...props
226
- }) {
227
- return /* @__PURE__ */ jsxRuntime.jsx(
228
- menu.Menu.Item,
229
- {
230
- "data-slot": "dropdown-menu-item",
231
- "data-inset": inset,
232
- "data-variant": variant,
233
- className: cn(
234
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
235
- className
236
- ),
237
- ...props
238
- }
239
- );
240
- }
241
- function EditorHeader({
242
- actions,
243
- children
244
- }) {
245
- const { history, appState } = core.usePuck();
246
- const undo = useMsg("header.undo");
247
- const undoTooltip = useMsg("header.undo.tooltip");
248
- const redo = useMsg("header.redo");
249
- const redoTooltip = useMsg("header.redo.tooltip");
250
- const exportLabel = useMsg("header.export");
251
- const exportJson = useMsg("header.export.json");
252
- return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex h-12 items-center justify-between border-b bg-background px-4 gap-2", children: [
253
- /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowLeft, { className: "h-4 w-4" }) }),
254
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1", children: appState?.data?.root?.props?.title || "" }),
255
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
256
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
257
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
258
- Button,
259
- {
260
- variant: "ghost",
261
- size: "icon",
262
- disabled: !history.hasPast,
263
- onClick: () => history.back(),
264
- "aria-label": undo,
265
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo2, { className: "h-4 w-4" })
266
- }
267
- ) }),
268
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: undoTooltip })
269
- ] }),
270
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
271
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
272
- Button,
273
- {
274
- variant: "ghost",
275
- size: "icon",
276
- disabled: !history.hasFuture,
277
- onClick: () => history.forward(),
278
- "aria-label": redo,
279
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Redo2, { className: "h-4 w-4" })
280
- }
281
- ) }),
282
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: redoTooltip })
283
- ] }),
284
- /* @__PURE__ */ jsxRuntime.jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
285
- /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
286
- /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
287
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { "aria-label": exportLabel, className: "inline-flex items-center justify-center rounded-md h-9 w-9 hover:bg-accent hover:text-accent-foreground", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "h-4 w-4" }) }) }),
288
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: exportLabel })
289
- ] }),
290
- /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuItem, { children: exportJson }) })
291
- ] }),
292
- actions
293
- ] })
294
- ] }) });
295
- }
296
- function EditorHeaderActions({
297
- children
298
- }) {
299
- return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children }) });
100
+ function cn(...inputs) {
101
+ return tailwindMerge.twMerge(clsx.clsx(inputs));
300
102
  }
301
103
  function ScrollArea({
302
104
  className,
@@ -357,7 +159,7 @@ function Input({ className, type, ...props }) {
357
159
  type,
358
160
  "data-slot": "input",
359
161
  className: cn(
360
- "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
162
+ "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-2.5 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
361
163
  className
362
164
  ),
363
165
  ...props
@@ -422,9 +224,9 @@ function DrawerItem({
422
224
  children,
423
225
  name
424
226
  }) {
425
- const { appState } = core.usePuck();
426
- const componentConfig = appState.config?.components?.[name];
427
- const thumbnail = componentConfig?.metadata?.thumbnail;
227
+ const { config } = core.usePuck();
228
+ const componentConfig = config.components?.[name];
229
+ const thumbnail = typeof componentConfig?.metadata?.thumbnail === "string" ? componentConfig.metadata.thumbnail : void 0;
428
230
  const src = thumbnail ?? getPlaceholderUrl(name);
429
231
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col rounded-md border border-border bg-muted/40 cursor-grab select-none transition-colors hover:bg-muted active:cursor-grabbing overflow-hidden", children: [
430
232
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-16 bg-muted overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -441,6 +243,24 @@ function DrawerItem({
441
243
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-2 py-1.5 text-xs font-medium truncate", children: name ?? children })
442
244
  ] });
443
245
  }
246
+ function Separator({
247
+ className,
248
+ orientation = "horizontal",
249
+ ...props
250
+ }) {
251
+ return /* @__PURE__ */ jsxRuntime.jsx(
252
+ separator.Separator,
253
+ {
254
+ "data-slot": "separator",
255
+ orientation,
256
+ className: cn(
257
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
258
+ className
259
+ ),
260
+ ...props
261
+ }
262
+ );
263
+ }
444
264
  function EditorOutline({
445
265
  children
446
266
  }) {
@@ -451,7 +271,7 @@ function EditorOutline({
451
271
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-1.5 text-xs text-muted-foreground truncate", children: [
452
272
  "Selected:",
453
273
  " ",
454
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: selectedItem.type ?? "Component" })
274
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: typeof selectedItem.type === "string" ? selectedItem.type : String(selectedItem.type) })
455
275
  ] }),
456
276
  /* @__PURE__ */ jsxRuntime.jsx(Separator, {})
457
277
  ] }),
@@ -483,6 +303,61 @@ var CANVAS_CSS = `
483
303
  }
484
304
  body { margin: 0; font-family: system-ui, sans-serif; }
485
305
  `;
306
+ var CANVAS_STYLE_ID = "__anvilkit_styles__";
307
+ function resolveDocument(target) {
308
+ if (target) return target;
309
+ if (typeof document === "undefined") return void 0;
310
+ return document;
311
+ }
312
+ function useThemeSync({
313
+ document: targetDocument,
314
+ injectCanvasCss = false
315
+ } = {}) {
316
+ const theme = useTheme();
317
+ React17__namespace.useEffect(() => {
318
+ const resolvedDocument = resolveDocument(targetDocument);
319
+ if (!resolvedDocument || !injectCanvasCss) return;
320
+ const existing = resolvedDocument.getElementById(CANVAS_STYLE_ID);
321
+ if (existing) existing.remove();
322
+ const style = resolvedDocument.createElement("style");
323
+ style.id = CANVAS_STYLE_ID;
324
+ style.textContent = CANVAS_CSS;
325
+ resolvedDocument.head.appendChild(style);
326
+ }, [targetDocument, injectCanvasCss]);
327
+ React17__namespace.useEffect(() => {
328
+ const resolvedDocument = resolveDocument(targetDocument);
329
+ if (!resolvedDocument) return;
330
+ resolvedDocument.documentElement.classList.toggle("dark", theme === "dark");
331
+ }, [targetDocument, theme]);
332
+ }
333
+
334
+ // src/features/library-dnd/drop-contract.ts
335
+ var LIBRARY_DRAG_START = "anvilkit:librarydragstart";
336
+ var IMAGE_DROP = "anvilkit:imagedrop";
337
+ var TEXT_DROP = "anvilkit:textdrop";
338
+ function createLibraryDragEvent(type, detail) {
339
+ return new CustomEvent(type, { detail });
340
+ }
341
+ function addLibraryDragEventListener(type, listener, target = window) {
342
+ const wrapped = (event) => {
343
+ listener(event);
344
+ };
345
+ target.addEventListener(type, wrapped);
346
+ return () => {
347
+ target.removeEventListener(type, wrapped);
348
+ };
349
+ }
350
+ function dispatchLibraryDragStart(type) {
351
+ window.dispatchEvent(createLibraryDragEvent(LIBRARY_DRAG_START, { type }));
352
+ }
353
+ function dispatchImageDrop(detail) {
354
+ window.dispatchEvent(createLibraryDragEvent(IMAGE_DROP, detail));
355
+ }
356
+ function dispatchTextDrop(detail) {
357
+ window.dispatchEvent(createLibraryDragEvent(TEXT_DROP, detail));
358
+ }
359
+
360
+ // src/features/library-dnd/replace-props.ts
486
361
  function isImageUrl(val) {
487
362
  return /\.(jpg|jpeg|png|gif|webp|svg|avif)(\?.*)?$/i.test(val) || val.includes("picsum.photos") || val.includes("unsplash.com") || val.includes("images.") || val.startsWith("data:image/");
488
363
  }
@@ -521,160 +396,187 @@ function replaceTextInProps(props, newText, targetText) {
521
396
  }
522
397
  return { result: props, replaced: false };
523
398
  }
524
- function CanvasIframe({
525
- children,
526
- document: iframeDoc
527
- }) {
399
+
400
+ // src/core/overrides/canvas/drop-targets.ts
401
+ var TEXT_TAGS = /* @__PURE__ */ new Set([
402
+ "P",
403
+ "H1",
404
+ "H2",
405
+ "H3",
406
+ "H4",
407
+ "H5",
408
+ "H6",
409
+ "SPAN",
410
+ "A",
411
+ "LI",
412
+ "BUTTON",
413
+ "LABEL"
414
+ ]);
415
+ function getIframeCoords(iframeEl, clientX, clientY) {
416
+ const rect = iframeEl.getBoundingClientRect();
417
+ const x = clientX - rect.left;
418
+ const y = clientY - rect.top;
419
+ if (x < 0 || y < 0 || x > rect.width || y > rect.height) {
420
+ return null;
421
+ }
422
+ return { x, y };
423
+ }
424
+ function getComponentElAt(iframeDoc, iframeEl, clientX, clientY) {
425
+ const coords = getIframeCoords(iframeEl, clientX, clientY);
426
+ if (!coords) return null;
427
+ const element = iframeDoc.elementFromPoint(coords.x, coords.y);
428
+ if (!element) return null;
429
+ return element.closest("[data-puck-component]");
430
+ }
431
+ function getImageElInComponent(compEl, iframeEl, clientX, clientY) {
432
+ const images = Array.from(compEl.querySelectorAll("img"));
433
+ if (!images.length) return null;
434
+ if (images.length === 1) return images[0];
435
+ const rect = iframeEl.getBoundingClientRect();
436
+ const x = clientX - rect.left;
437
+ const y = clientY - rect.top;
438
+ let closest = null;
439
+ let minDistance = Infinity;
440
+ for (const image of images) {
441
+ const imageRect = image.getBoundingClientRect();
442
+ const centerX = imageRect.left + imageRect.width / 2;
443
+ const centerY = imageRect.top + imageRect.height / 2;
444
+ const distance = Math.hypot(centerX - x, centerY - y);
445
+ if (distance < minDistance) {
446
+ minDistance = distance;
447
+ closest = image;
448
+ }
449
+ }
450
+ return closest;
451
+ }
452
+ function getTextElInComponent(iframeDoc, iframeEl, compEl, clientX, clientY) {
453
+ const coords = getIframeCoords(iframeEl, clientX, clientY);
454
+ if (!coords) return null;
455
+ const element = iframeDoc.elementFromPoint(coords.x, coords.y);
456
+ if (element && compEl.contains(element)) {
457
+ let current = element;
458
+ while (current && current !== iframeDoc.body) {
459
+ if (TEXT_TAGS.has(current.tagName) && current.textContent?.trim()) {
460
+ return current;
461
+ }
462
+ current = current.parentElement;
463
+ }
464
+ }
465
+ for (const tag of TEXT_TAGS) {
466
+ const candidate = compEl.querySelector(tag.toLowerCase());
467
+ if (candidate?.textContent?.trim()) {
468
+ return candidate;
469
+ }
470
+ }
471
+ return null;
472
+ }
473
+
474
+ // src/core/overrides/canvas/highlight.ts
475
+ function createElementHighlighter() {
476
+ let highlightedEl = null;
477
+ function set(el, color) {
478
+ if (highlightedEl && highlightedEl !== el) {
479
+ highlightedEl.style.outline = "";
480
+ highlightedEl.style.outlineOffset = "";
481
+ }
482
+ if (el) {
483
+ el.style.outline = `2px solid ${color}`;
484
+ el.style.outlineOffset = "2px";
485
+ }
486
+ highlightedEl = el;
487
+ }
488
+ function clear() {
489
+ set(null, "");
490
+ }
491
+ return { set, clear };
492
+ }
493
+
494
+ // src/core/overrides/canvas/useLibraryDropBridge.ts
495
+ function useLibraryDropBridge(iframeDoc) {
528
496
  const getPuck = core.useGetPuck();
529
- const theme = useTheme();
530
- React18__namespace.useEffect(() => {
531
- if (!iframeDoc) return;
532
- const existing = iframeDoc.getElementById("__anvilkit_styles__");
533
- if (existing) existing.remove();
534
- const style = iframeDoc.createElement("style");
535
- style.id = "__anvilkit_styles__";
536
- style.textContent = CANVAS_CSS;
537
- iframeDoc.head.appendChild(style);
538
- }, [iframeDoc]);
539
- React18__namespace.useEffect(() => {
540
- if (!iframeDoc) return;
541
- iframeDoc.documentElement.classList.toggle("dark", theme === "dark");
542
- }, [iframeDoc, theme]);
543
- React18__namespace.useEffect(() => {
497
+ React17__namespace.useEffect(() => {
544
498
  if (!iframeDoc) return;
545
499
  const iframeEl = iframeDoc.defaultView?.frameElement;
546
500
  if (!iframeEl) return;
547
- let highlightedEl = null;
548
- function iframeCoords(clientX, clientY) {
549
- const rect = iframeEl.getBoundingClientRect();
550
- const x = clientX - rect.left;
551
- const y = clientY - rect.top;
552
- if (x < 0 || y < 0 || x > rect.width || y > rect.height) return null;
553
- return { x, y };
554
- }
555
- function getComponentElAt(clientX, clientY) {
556
- const coords = iframeCoords(clientX, clientY);
557
- if (!coords) return null;
558
- const el = iframeDoc.elementFromPoint(coords.x, coords.y);
559
- if (!el) return null;
560
- const comp = el.closest("[data-puck-component]");
561
- return comp;
562
- }
563
- function getImgInComponent(compEl, clientX, clientY) {
564
- const imgs = Array.from(compEl.querySelectorAll("img"));
565
- if (!imgs.length) return null;
566
- if (imgs.length === 1) return imgs[0];
567
- const rect = iframeEl.getBoundingClientRect();
568
- const x = clientX - rect.left;
569
- const y = clientY - rect.top;
570
- let closest = null;
571
- let minDist = Infinity;
572
- for (const img of imgs) {
573
- const r = img.getBoundingClientRect();
574
- const cx = r.left + r.width / 2;
575
- const cy = r.top + r.height / 2;
576
- const dist = Math.hypot(cx - x, cy - y);
577
- if (dist < minDist) {
578
- minDist = dist;
579
- closest = img;
580
- }
581
- }
582
- return closest;
583
- }
584
- const TEXT_TAGS = /* @__PURE__ */ new Set(["P", "H1", "H2", "H3", "H4", "H5", "H6", "SPAN", "A", "LI", "BUTTON", "LABEL"]);
585
- function getTextElInComponent(compEl, clientX, clientY) {
586
- const coords = iframeCoords(clientX, clientY);
587
- if (!coords) return null;
588
- const el = iframeDoc.elementFromPoint(coords.x, coords.y);
589
- if (el && compEl.contains(el)) {
590
- let cur = el;
591
- while (cur && cur !== iframeDoc.body) {
592
- if (TEXT_TAGS.has(cur.tagName) && cur.textContent?.trim()) return cur;
593
- cur = cur.parentElement;
501
+ const iframeDocument = iframeDoc;
502
+ const frameElement = iframeEl;
503
+ let activeLibrary = null;
504
+ const highlighter = createElementHighlighter();
505
+ function dispatchReplace(componentId, updatedProps) {
506
+ const { dispatch, getItemById, getSelectorForId } = getPuck();
507
+ const item = getItemById(componentId);
508
+ const selector = getSelectorForId(componentId);
509
+ if (!item || !selector) return false;
510
+ dispatch({
511
+ type: "replace",
512
+ destinationIndex: selector.index,
513
+ destinationZone: selector.zone,
514
+ data: {
515
+ ...item,
516
+ props: { ...item.props, ...updatedProps }
594
517
  }
595
- }
596
- for (const tag of TEXT_TAGS) {
597
- const found = compEl.querySelector(tag.toLowerCase());
598
- if (found?.textContent?.trim()) return found;
599
- }
600
- return null;
601
- }
602
- function setHighlight(el, color) {
603
- if (highlightedEl && highlightedEl !== el) {
604
- highlightedEl.style.outline = "";
605
- highlightedEl.style.outlineOffset = "";
606
- }
607
- if (el) {
608
- el.style.outline = `2px solid ${color}`;
609
- el.style.outlineOffset = "2px";
610
- }
611
- highlightedEl = el;
518
+ });
519
+ return true;
612
520
  }
613
- function clearHighlight() {
614
- setHighlight(null, "");
615
- }
616
- let activeLibrary = null;
617
- function onLibraryDragStart(e) {
618
- activeLibrary = e.detail.type;
521
+ function onLibraryDragStart(type) {
522
+ activeLibrary = type;
619
523
  }
620
524
  function onPointerMove(e) {
621
525
  if (!activeLibrary) return;
622
- const compEl = getComponentElAt(e.clientX, e.clientY);
526
+ const compEl = getComponentElAt(iframeDocument, frameElement, e.clientX, e.clientY);
623
527
  if (!compEl) {
624
- clearHighlight();
528
+ highlighter.clear();
625
529
  return;
626
530
  }
627
531
  if (activeLibrary === "image") {
628
- const img = getImgInComponent(compEl, e.clientX, e.clientY);
629
- setHighlight(img, "#6366f1");
532
+ highlighter.set(
533
+ getImageElInComponent(compEl, frameElement, e.clientX, e.clientY),
534
+ "#6366f1"
535
+ );
630
536
  } else {
631
- const textEl = getTextElInComponent(compEl, e.clientX, e.clientY);
632
- setHighlight(textEl, "#f59e0b");
537
+ highlighter.set(
538
+ getTextElInComponent(iframeDocument, frameElement, compEl, e.clientX, e.clientY),
539
+ "#f59e0b"
540
+ );
633
541
  }
634
542
  }
635
543
  function onPointerUp() {
636
544
  activeLibrary = null;
637
- clearHighlight();
638
- }
639
- function dispatchReplace(componentId, updatedProps) {
640
- const { dispatch, getItemById, getSelectorForId } = getPuck();
641
- const item = getItemById(componentId);
642
- const selector = getSelectorForId(componentId);
643
- if (!item || !selector) return false;
644
- dispatch({
645
- type: "replace",
646
- destinationIndex: selector.index,
647
- destinationZone: selector.zone,
648
- data: { ...item, props: { ...item.props, ...updatedProps } }
649
- });
650
- return true;
545
+ highlighter.clear();
651
546
  }
652
- function onImageDrop(e) {
653
- const { src, clientX, clientY } = e.detail;
654
- clearHighlight();
547
+ function onImageDrop(src, clientX, clientY) {
548
+ highlighter.clear();
655
549
  activeLibrary = null;
656
550
  if (!src) return;
657
- const compEl = getComponentElAt(clientX, clientY);
551
+ const compEl = getComponentElAt(iframeDocument, frameElement, clientX, clientY);
658
552
  if (!compEl) return;
659
- const componentId = compEl.getAttribute("data-puck-component");
660
- const { getItemById } = getPuck();
661
- const item = getItemById(componentId);
553
+ const componentId = compEl.dataset.puckComponent;
554
+ if (!componentId) return;
555
+ const item = getPuck().getItemById(componentId);
662
556
  if (!item) return;
663
- const updatedProps = replaceImageInProps(item.props, src);
557
+ const updatedProps = replaceImageInProps(
558
+ item.props,
559
+ src
560
+ );
664
561
  dispatchReplace(componentId, updatedProps);
665
562
  }
666
- function onTextDrop(e) {
667
- const { text, clientX, clientY } = e.detail;
668
- clearHighlight();
563
+ function onTextDrop(text, clientX, clientY) {
564
+ highlighter.clear();
669
565
  activeLibrary = null;
670
566
  if (!text) return;
671
- const compEl = getComponentElAt(clientX, clientY);
567
+ const compEl = getComponentElAt(iframeDocument, frameElement, clientX, clientY);
672
568
  if (!compEl) return;
673
- const componentId = compEl.getAttribute("data-puck-component");
674
- const textEl = getTextElInComponent(compEl, clientX, clientY);
569
+ const componentId = compEl.dataset.puckComponent;
570
+ if (!componentId) return;
571
+ const textEl = getTextElInComponent(
572
+ iframeDocument,
573
+ frameElement,
574
+ compEl,
575
+ clientX,
576
+ clientY
577
+ );
675
578
  const targetText = textEl?.textContent?.trim() ?? "";
676
- const { getItemById } = getPuck();
677
- const item = getItemById(componentId);
579
+ const item = getPuck().getItemById(componentId);
678
580
  if (!item) return;
679
581
  const { result: updatedProps, replaced } = replaceTextInProps(
680
582
  item.props,
@@ -683,19 +585,38 @@ function CanvasIframe({
683
585
  );
684
586
  if (replaced) dispatchReplace(componentId, updatedProps);
685
587
  }
686
- window.addEventListener("anvilkit:librarydragstart", onLibraryDragStart);
588
+ const removeLibraryDragStart = addLibraryDragEventListener(
589
+ LIBRARY_DRAG_START,
590
+ (event) => {
591
+ onLibraryDragStart(event.detail.type);
592
+ }
593
+ );
687
594
  window.addEventListener("pointermove", onPointerMove);
688
595
  window.addEventListener("pointerup", onPointerUp);
689
- window.addEventListener("anvilkit:imagedrop", onImageDrop);
690
- window.addEventListener("anvilkit:textdrop", onTextDrop);
596
+ const removeImageDrop = addLibraryDragEventListener(IMAGE_DROP, (event) => {
597
+ const { src, clientX, clientY } = event.detail;
598
+ onImageDrop(src, clientX, clientY);
599
+ });
600
+ const removeTextDrop = addLibraryDragEventListener(TEXT_DROP, (event) => {
601
+ const { text, clientX, clientY } = event.detail;
602
+ onTextDrop(text, clientX, clientY);
603
+ });
691
604
  return () => {
692
- window.removeEventListener("anvilkit:librarydragstart", onLibraryDragStart);
605
+ removeLibraryDragStart();
693
606
  window.removeEventListener("pointermove", onPointerMove);
694
607
  window.removeEventListener("pointerup", onPointerUp);
695
- window.removeEventListener("anvilkit:imagedrop", onImageDrop);
696
- window.removeEventListener("anvilkit:textdrop", onTextDrop);
608
+ removeImageDrop();
609
+ removeTextDrop();
610
+ highlighter.clear();
697
611
  };
698
612
  }, [iframeDoc, getPuck]);
613
+ }
614
+ function CanvasIframe({
615
+ children,
616
+ document: iframeDoc
617
+ }) {
618
+ useThemeSync({ document: iframeDoc, injectCanvasCss: true });
619
+ useLibraryDropBridge(iframeDoc);
699
620
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
700
621
  }
701
622
  function CanvasPreview({
@@ -719,6 +640,60 @@ function ComponentOverlay({
719
640
  }
720
641
  );
721
642
  }
643
+ function TooltipProvider({
644
+ delay = 0,
645
+ ...props
646
+ }) {
647
+ return /* @__PURE__ */ jsxRuntime.jsx(
648
+ tooltip.Tooltip.Provider,
649
+ {
650
+ "data-slot": "tooltip-provider",
651
+ delay,
652
+ ...props
653
+ }
654
+ );
655
+ }
656
+ function Tooltip({ ...props }) {
657
+ return /* @__PURE__ */ jsxRuntime.jsx(tooltip.Tooltip.Root, { "data-slot": "tooltip", ...props });
658
+ }
659
+ function TooltipTrigger({ ...props }) {
660
+ return /* @__PURE__ */ jsxRuntime.jsx(tooltip.Tooltip.Trigger, { "data-slot": "tooltip-trigger", ...props });
661
+ }
662
+ function TooltipContent({
663
+ className,
664
+ side = "top",
665
+ sideOffset = 4,
666
+ align = "center",
667
+ alignOffset = 0,
668
+ children,
669
+ ...props
670
+ }) {
671
+ return /* @__PURE__ */ jsxRuntime.jsx(tooltip.Tooltip.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
672
+ tooltip.Tooltip.Positioner,
673
+ {
674
+ align,
675
+ alignOffset,
676
+ side,
677
+ sideOffset,
678
+ className: "isolate z-50",
679
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
680
+ tooltip.Tooltip.Popup,
681
+ {
682
+ "data-slot": "tooltip-content",
683
+ className: cn(
684
+ "z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
685
+ className
686
+ ),
687
+ ...props,
688
+ children: [
689
+ children,
690
+ /* @__PURE__ */ jsxRuntime.jsx(tooltip.Tooltip.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" })
691
+ ]
692
+ }
693
+ )
694
+ }
695
+ ) });
696
+ }
722
697
  function ActionBar({
723
698
  children,
724
699
  label,
@@ -736,16 +711,13 @@ function ActionBar({
736
711
  children
737
712
  ] }) });
738
713
  }
739
- function cn2(...inputs) {
740
- return tailwindMerge.twMerge(clsx.clsx(inputs));
741
- }
742
714
  function Label({ className, ...props }) {
743
715
  return /* @__PURE__ */ jsxRuntime.jsx(
744
716
  "label",
745
717
  {
746
718
  "data-slot": "label",
747
- className: cn2(
748
- "gap-2 text-sm leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
719
+ className: cn(
720
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
749
721
  className
750
722
  ),
751
723
  ...props
@@ -758,7 +730,7 @@ function Breadcrumb({ className, ...props }) {
758
730
  {
759
731
  "aria-label": "breadcrumb",
760
732
  "data-slot": "breadcrumb",
761
- className: cn2(className),
733
+ className: cn(className),
762
734
  ...props
763
735
  }
764
736
  );
@@ -768,8 +740,8 @@ function BreadcrumbList({ className, ...props }) {
768
740
  "ol",
769
741
  {
770
742
  "data-slot": "breadcrumb-list",
771
- className: cn2(
772
- "text-muted-foreground gap-1.5 text-sm flex flex-wrap items-center wrap-break-word",
743
+ className: cn(
744
+ "flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground sm:gap-2.5",
773
745
  className
774
746
  ),
775
747
  ...props
@@ -781,7 +753,7 @@ function BreadcrumbItem({ className, ...props }) {
781
753
  "li",
782
754
  {
783
755
  "data-slot": "breadcrumb-item",
784
- className: cn2("gap-1 inline-flex items-center", className),
756
+ className: cn("inline-flex items-center gap-1.5", className),
785
757
  ...props
786
758
  }
787
759
  );
@@ -795,7 +767,7 @@ function BreadcrumbLink({
795
767
  defaultTagName: "a",
796
768
  props: mergeProps.mergeProps(
797
769
  {
798
- className: cn2("hover:text-foreground transition-colors", className)
770
+ className: cn("transition-colors hover:text-foreground", className)
799
771
  },
800
772
  props
801
773
  ),
@@ -813,7 +785,7 @@ function BreadcrumbPage({ className, ...props }) {
813
785
  role: "link",
814
786
  "aria-disabled": "true",
815
787
  "aria-current": "page",
816
- className: cn2("text-foreground font-normal", className),
788
+ className: cn("font-normal text-foreground", className),
817
789
  ...props
818
790
  }
819
791
  );
@@ -829,32 +801,39 @@ function BreadcrumbSeparator({
829
801
  "data-slot": "breadcrumb-separator",
830
802
  role: "presentation",
831
803
  "aria-hidden": "true",
832
- className: cn2("[&>svg]:size-3.5", className),
804
+ className: cn("[&>svg]:size-3.5", className),
833
805
  ...props,
834
- children: children ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, { className: "cn-rtl-flip" })
806
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRightIcon, {})
835
807
  }
836
808
  );
837
809
  }
810
+ function getComponentTypeLabel(item) {
811
+ if (!item) return "Component";
812
+ return typeof item.type === "string" ? item.type : String(item.type);
813
+ }
814
+ function getComponentId(item) {
815
+ const id = item?.props?.id;
816
+ return typeof id === "string" ? id : null;
817
+ }
838
818
  function useBreadcrumbs() {
839
- const { appState, dispatch, selectedItem, getParentById, getSelectorForId } = core.usePuck();
819
+ const { appState, dispatch, selectedItem, getParentById } = core.usePuck();
840
820
  const { itemSelector } = appState.ui;
841
821
  const selectRoot = () => dispatch({ type: "setUi", ui: { itemSelector: null } });
842
822
  if (!itemSelector || !selectedItem) {
843
823
  return [{ label: "Page" }];
844
824
  }
845
- const selectedType = selectedItem.type ?? "Component";
846
- const parent = getParentById(selectedItem.props?.id ?? "");
825
+ const selectedType = getComponentTypeLabel(selectedItem);
826
+ const parentId = getComponentId(selectedItem);
827
+ const parent = parentId ? getParentById(parentId) : void 0;
847
828
  if (!parent) {
848
829
  return [{ label: "Page", onSelect: selectRoot }, { label: selectedType }];
849
830
  }
850
- parent.type ?? "Component";
851
- let parentSelector = void 0;
852
- try {
853
- parentSelector = getSelectorForId(parent.props?.id ?? "");
854
- } catch {
855
- parentSelector = void 0;
856
- }
857
- return [{ label: "Page", onSelect: selectRoot }, { label: selectedType }];
831
+ const parentType = getComponentTypeLabel(parent);
832
+ return [
833
+ { label: "Page", onSelect: selectRoot },
834
+ { label: parentType },
835
+ { label: selectedType }
836
+ ];
858
837
  }
859
838
  function FieldWrapper({
860
839
  children
@@ -863,7 +842,7 @@ function FieldWrapper({
863
842
  return /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-0", children: [
864
843
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2 border-b", children: /* @__PURE__ */ jsxRuntime.jsx(Breadcrumb, { children: /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbList, { children: crumbs.map((crumb, i) => {
865
844
  const isLast = i === crumbs.length - 1;
866
- return /* @__PURE__ */ jsxRuntime.jsxs(React18__namespace.Fragment, { children: [
845
+ return /* @__PURE__ */ jsxRuntime.jsxs(React17__namespace.Fragment, { children: [
867
846
  i > 0 && /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbSeparator, {}),
868
847
  /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbItem, { children: isLast ? /* @__PURE__ */ jsxRuntime.jsx(BreadcrumbPage, { children: crumb.label }) : /* @__PURE__ */ jsxRuntime.jsx(
869
848
  BreadcrumbLink,
@@ -881,20 +860,33 @@ function FieldWrapper({
881
860
  function FieldLabel({
882
861
  children,
883
862
  label,
863
+ icon,
884
864
  labelIcon,
885
865
  el,
886
- type: _type,
887
866
  readOnly,
888
867
  className
889
868
  }) {
890
- console.log("Lable type", labelIcon);
891
869
  const El = el ?? "div";
870
+ const labelAdornment = icon ?? labelIcon;
892
871
  return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs(El, { className: `flex flex-col gap-1.5 ${className ?? ""}`, children: [
893
872
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
894
- labelIcon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: labelIcon }),
873
+ labelAdornment && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: labelAdornment }),
895
874
  /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-medium text-muted-foreground", children: label }),
896
875
  label && /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
897
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-3 w-3 text-muted-foreground/60 cursor-help" }) }),
876
+ /* @__PURE__ */ jsxRuntime.jsx(
877
+ TooltipTrigger,
878
+ {
879
+ "aria-label": label,
880
+ render: /* @__PURE__ */ jsxRuntime.jsx(
881
+ "button",
882
+ {
883
+ type: "button",
884
+ className: "inline-flex cursor-help items-center justify-center text-muted-foreground/60 transition-colors hover:text-muted-foreground"
885
+ }
886
+ ),
887
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "h-3 w-3 text-muted-foreground/60 cursor-help" })
888
+ }
889
+ ),
898
890
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "right", children: label })
899
891
  ] }),
900
892
  readOnly && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto text-xs text-muted-foreground/50", children: "Read only" })
@@ -902,6 +894,50 @@ function FieldLabel({
902
894
  children
903
895
  ] }) });
904
896
  }
897
+ var buttonVariants = classVarianceAuthority.cva(
898
+ "group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
899
+ {
900
+ variants: {
901
+ variant: {
902
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
903
+ outline: "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
904
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
905
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
906
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
907
+ link: "text-primary underline-offset-4 hover:underline"
908
+ },
909
+ size: {
910
+ default: "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
911
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
912
+ sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
913
+ lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
914
+ icon: "size-9",
915
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
916
+ "icon-sm": "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
917
+ "icon-lg": "size-10"
918
+ }
919
+ },
920
+ defaultVariants: {
921
+ variant: "default",
922
+ size: "default"
923
+ }
924
+ }
925
+ );
926
+ function Button({
927
+ className,
928
+ variant = "default",
929
+ size = "default",
930
+ ...props
931
+ }) {
932
+ return /* @__PURE__ */ jsxRuntime.jsx(
933
+ button.Button,
934
+ {
935
+ "data-slot": "button",
936
+ className: cn(buttonVariants({ variant, size, className })),
937
+ ...props
938
+ }
939
+ );
940
+ }
905
941
  var MOCK_VALUES = {
906
942
  default: ["AI-generated content", "Smart suggestion", "Generated text"]
907
943
  };
@@ -913,7 +949,7 @@ function getMock(instructions) {
913
949
  return pool[Math.floor(Math.random() * pool.length)];
914
950
  }
915
951
  function AiButton({ ai, onGenerate }) {
916
- const [loading, setLoading] = React18__namespace.useState(false);
952
+ const [loading, setLoading] = React17__namespace.useState(false);
917
953
  const handleClick = () => {
918
954
  setLoading(true);
919
955
  setTimeout(() => {
@@ -944,13 +980,22 @@ function TextField({
944
980
  label,
945
981
  labelIcon
946
982
  }) {
947
- const [local, setLocal] = React18__namespace.useState(value ?? "");
948
- React18__namespace.useEffect(() => {
983
+ const [local, setLocal] = React17__namespace.useState(value ?? "");
984
+ const onChangeRef = React17__namespace.useRef(onChange);
985
+ const lastCommittedValueRef = React17__namespace.useRef(value ?? "");
986
+ React17__namespace.useEffect(() => {
987
+ onChangeRef.current = onChange;
988
+ }, [onChange]);
989
+ React17__namespace.useEffect(() => {
990
+ lastCommittedValueRef.current = value ?? "";
949
991
  setLocal(value ?? "");
950
992
  }, [value]);
951
- React18__namespace.useEffect(() => {
993
+ React17__namespace.useEffect(() => {
952
994
  const timer = setTimeout(() => {
953
- if (local !== value) onChange(local);
995
+ if (local !== lastCommittedValueRef.current) {
996
+ onChangeRef.current(local);
997
+ lastCommittedValueRef.current = local;
998
+ }
954
999
  }, 200);
955
1000
  return () => clearTimeout(timer);
956
1001
  }, [local]);
@@ -965,10 +1010,17 @@ function TextField({
965
1010
  className: "h-8 text-sm flex-1"
966
1011
  }
967
1012
  ),
968
- field?.ai && /* @__PURE__ */ jsxRuntime.jsx(AiButton, { ai: field.ai, onGenerate: (v) => {
969
- setLocal(v);
970
- onChange(v);
971
- } })
1013
+ field?.ai && /* @__PURE__ */ jsxRuntime.jsx(
1014
+ AiButton,
1015
+ {
1016
+ ai: field.ai,
1017
+ onGenerate: (nextValue) => {
1018
+ lastCommittedValueRef.current = nextValue;
1019
+ setLocal(nextValue);
1020
+ onChangeRef.current(nextValue);
1021
+ }
1022
+ }
1023
+ )
972
1024
  ] }) });
973
1025
  }
974
1026
  function Textarea({ className, ...props }) {
@@ -977,7 +1029,7 @@ function Textarea({ className, ...props }) {
977
1029
  {
978
1030
  "data-slot": "textarea",
979
1031
  className: cn(
980
- "flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
1032
+ "flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-2.5 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
981
1033
  className
982
1034
  ),
983
1035
  ...props
@@ -985,11 +1037,11 @@ function Textarea({ className, ...props }) {
985
1037
  );
986
1038
  }
987
1039
  function TextareaField({ value, onChange, readOnly, placeholder, label }) {
988
- const [local, setLocal] = React18__namespace.useState(value ?? "");
989
- React18__namespace.useEffect(() => {
1040
+ const [local, setLocal] = React17__namespace.useState(value ?? "");
1041
+ React17__namespace.useEffect(() => {
990
1042
  setLocal(value ?? "");
991
1043
  }, [value]);
992
- React18__namespace.useEffect(() => {
1044
+ React17__namespace.useEffect(() => {
993
1045
  const timer = setTimeout(() => {
994
1046
  if (local !== value) onChange(local);
995
1047
  }, 200);
@@ -1007,11 +1059,11 @@ function TextareaField({ value, onChange, readOnly, placeholder, label }) {
1007
1059
  ) });
1008
1060
  }
1009
1061
  function NumberField({ value, onChange, readOnly, min, max, step, label }) {
1010
- const [local, setLocal] = React18__namespace.useState(String(value ?? ""));
1011
- React18__namespace.useEffect(() => {
1062
+ const [local, setLocal] = React17__namespace.useState(String(value ?? ""));
1063
+ React17__namespace.useEffect(() => {
1012
1064
  setLocal(String(value ?? ""));
1013
1065
  }, [value]);
1014
- React18__namespace.useEffect(() => {
1066
+ React17__namespace.useEffect(() => {
1015
1067
  const parsed = parseFloat(local);
1016
1068
  if (!isNaN(parsed) && parsed !== value) {
1017
1069
  const timer = setTimeout(() => onChange(parsed), 200);
@@ -1065,7 +1117,7 @@ function SelectTrigger({
1065
1117
  "data-slot": "select-trigger",
1066
1118
  "data-size": size,
1067
1119
  className: cn(
1068
- "border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-lg border bg-transparent py-2 pr-2 pl-2.5 text-sm transition-colors select-none focus-visible:ring-3 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-4 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
1120
+ "flex w-fit items-center justify-between gap-1.5 rounded-md border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1069
1121
  className
1070
1122
  ),
1071
1123
  ...props,
@@ -1074,7 +1126,7 @@ function SelectTrigger({
1074
1126
  /* @__PURE__ */ jsxRuntime.jsx(
1075
1127
  select.Select.Icon,
1076
1128
  {
1077
- render: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "text-muted-foreground size-4 pointer-events-none" })
1129
+ render: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "pointer-events-none size-4 text-muted-foreground" })
1078
1130
  }
1079
1131
  )
1080
1132
  ]
@@ -1105,10 +1157,7 @@ function SelectContent({
1105
1157
  {
1106
1158
  "data-slot": "select-content",
1107
1159
  "data-align-trigger": alignItemWithTrigger,
1108
- className: cn(
1109
- "bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 min-w-36 rounded-lg shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 relative isolate z-50 max-h-(--available-height) w-(--anchor-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none",
1110
- className
1111
- ),
1160
+ className: cn("relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
1112
1161
  ...props,
1113
1162
  children: [
1114
1163
  /* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
@@ -1130,16 +1179,17 @@ function SelectItem({
1130
1179
  {
1131
1180
  "data-slot": "select-item",
1132
1181
  className: cn(
1133
- "focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
1182
+ "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
1134
1183
  className
1135
1184
  ),
1136
1185
  ...props,
1137
1186
  children: [
1138
- /* @__PURE__ */ jsxRuntime.jsx(select.Select.ItemText, { className: "flex flex-1 gap-2 shrink-0 whitespace-nowrap", children }),
1187
+ /* @__PURE__ */ jsxRuntime.jsx(select.Select.ItemText, { className: "flex flex-1 shrink-0 gap-2 whitespace-nowrap", children }),
1139
1188
  /* @__PURE__ */ jsxRuntime.jsx(
1140
1189
  select.Select.ItemIndicator,
1141
1190
  {
1142
- render: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "pointer-events-none" }) })
1191
+ render: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center" }),
1192
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "pointer-events-none" })
1143
1193
  }
1144
1194
  )
1145
1195
  ]
@@ -1155,11 +1205,14 @@ function SelectScrollUpButton({
1155
1205
  {
1156
1206
  "data-slot": "select-scroll-up-button",
1157
1207
  className: cn(
1158
- "bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 top-0 w-full",
1208
+ "top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
1159
1209
  className
1160
1210
  ),
1161
1211
  ...props,
1162
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, {})
1212
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1213
+ lucideReact.ChevronUpIcon,
1214
+ {}
1215
+ )
1163
1216
  }
1164
1217
  );
1165
1218
  }
@@ -1172,11 +1225,14 @@ function SelectScrollDownButton({
1172
1225
  {
1173
1226
  "data-slot": "select-scroll-down-button",
1174
1227
  className: cn(
1175
- "bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 bottom-0 w-full",
1228
+ "bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
1176
1229
  className
1177
1230
  ),
1178
1231
  ...props,
1179
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, {})
1232
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1233
+ lucideReact.ChevronDownIcon,
1234
+ {}
1235
+ )
1180
1236
  }
1181
1237
  );
1182
1238
  }
@@ -1198,12 +1254,12 @@ function SelectField({ field, value, onChange, id, readOnly, label }) {
1198
1254
  ) });
1199
1255
  }
1200
1256
  var buttonGroupVariants = classVarianceAuthority.cva(
1201
- "has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-lg flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
1257
+ "flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
1202
1258
  {
1203
1259
  variants: {
1204
1260
  orientation: {
1205
- horizontal: "[&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-lg! *:data-slot:rounded-r-none [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0",
1206
- vertical: "[&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-lg! flex-col *:data-slot:rounded-b-none [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0"
1261
+ horizontal: "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-md! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0",
1262
+ vertical: "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-md! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0"
1207
1263
  }
1208
1264
  },
1209
1265
  defaultVariants: {
@@ -1222,7 +1278,7 @@ function ButtonGroup({
1222
1278
  role: "group",
1223
1279
  "data-slot": "button-group",
1224
1280
  "data-orientation": orientation,
1225
- className: cn2(buttonGroupVariants({ orientation }), className),
1281
+ className: cn(buttonGroupVariants({ orientation }), className),
1226
1282
  ...props
1227
1283
  }
1228
1284
  );
@@ -1252,8 +1308,8 @@ function ItemGroup({ className, ...props }) {
1252
1308
  {
1253
1309
  role: "list",
1254
1310
  "data-slot": "item-group",
1255
- className: cn2(
1256
- "gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2 group/item-group flex w-full flex-col",
1311
+ className: cn(
1312
+ "group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
1257
1313
  className
1258
1314
  ),
1259
1315
  ...props
@@ -1261,16 +1317,16 @@ function ItemGroup({ className, ...props }) {
1261
1317
  );
1262
1318
  }
1263
1319
  var itemVariants = classVarianceAuthority.cva(
1264
- "[a]:hover:bg-muted rounded-lg border text-sm group/item flex w-full flex-wrap items-center transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors",
1320
+ "group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
1265
1321
  {
1266
1322
  variants: {
1267
1323
  variant: {
1268
1324
  default: "border-transparent",
1269
1325
  outline: "border-border",
1270
- muted: "bg-muted/50 border-transparent"
1326
+ muted: "border-transparent bg-muted/50"
1271
1327
  },
1272
1328
  size: {
1273
- default: "gap-2.5 px-3 py-2.5",
1329
+ default: "gap-3.5 px-4 py-3.5",
1274
1330
  sm: "gap-2.5 px-3 py-2.5",
1275
1331
  xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
1276
1332
  }
@@ -1292,7 +1348,7 @@ function Item({
1292
1348
  defaultTagName: "div",
1293
1349
  props: mergeProps.mergeProps(
1294
1350
  {
1295
- className: cn2(itemVariants({ variant, size, className }))
1351
+ className: cn(itemVariants({ variant, size, className }))
1296
1352
  },
1297
1353
  props
1298
1354
  ),
@@ -1305,7 +1361,7 @@ function Item({
1305
1361
  });
1306
1362
  }
1307
1363
  classVarianceAuthority.cva(
1308
- "gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start flex shrink-0 items-center justify-center [&_svg]:pointer-events-none",
1364
+ "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
1309
1365
  {
1310
1366
  variants: {
1311
1367
  variant: {
@@ -1324,8 +1380,8 @@ function ItemContent({ className, ...props }) {
1324
1380
  "div",
1325
1381
  {
1326
1382
  "data-slot": "item-content",
1327
- className: cn2(
1328
- "gap-1 group-data-[size=xs]/item:gap-0 flex flex-1 flex-col [&+[data-slot=item-content]]:flex-none",
1383
+ className: cn(
1384
+ "flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
1329
1385
  className
1330
1386
  ),
1331
1387
  ...props
@@ -1337,8 +1393,8 @@ function ItemTitle({ className, ...props }) {
1337
1393
  "div",
1338
1394
  {
1339
1395
  "data-slot": "item-title",
1340
- className: cn2(
1341
- "gap-2 text-sm leading-snug font-medium underline-offset-4 line-clamp-1 flex w-fit items-center",
1396
+ className: cn(
1397
+ "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
1342
1398
  className
1343
1399
  ),
1344
1400
  ...props
@@ -1350,20 +1406,20 @@ function ItemActions({ className, ...props }) {
1350
1406
  "div",
1351
1407
  {
1352
1408
  "data-slot": "item-actions",
1353
- className: cn2("gap-2 flex items-center", className),
1409
+ className: cn("flex items-center gap-2", className),
1354
1410
  ...props
1355
1411
  }
1356
1412
  );
1357
1413
  }
1358
1414
  function useControlledState(props) {
1359
1415
  const { value, defaultValue, onChange } = props;
1360
- const [state, setInternalState] = React18__namespace.useState(
1416
+ const [state, setInternalState] = React17__namespace.useState(
1361
1417
  value !== void 0 ? value : defaultValue
1362
1418
  );
1363
- React18__namespace.useEffect(() => {
1419
+ React17__namespace.useEffect(() => {
1364
1420
  if (value !== void 0) setInternalState(value);
1365
1421
  }, [value]);
1366
- const setState = React18__namespace.useCallback(
1422
+ const setState = React17__namespace.useCallback(
1367
1423
  (next, ...args) => {
1368
1424
  setInternalState(next);
1369
1425
  onChange?.(next, ...args);
@@ -1476,6 +1532,9 @@ function PopoverPanel({
1476
1532
  function PopoverTitle2(props) {
1477
1533
  return /* @__PURE__ */ jsxRuntime.jsx(PopoverTitle, { ...props });
1478
1534
  }
1535
+ function getArraySubField(subName, subField) {
1536
+ return { ...subField, label: subField.label ?? subName };
1537
+ }
1479
1538
  function SortableItem({
1480
1539
  id,
1481
1540
  index,
@@ -1562,7 +1621,7 @@ function SortableItem({
1562
1621
  children: Object.entries(field.arrayFields).map(([subName, subField]) => /* @__PURE__ */ jsxRuntime.jsx(
1563
1622
  core.AutoField,
1564
1623
  {
1565
- field: { ...subField, label: subField.label ?? subName },
1624
+ field: getArraySubField(subName, subField),
1566
1625
  value: item[subName],
1567
1626
  onChange: (val) => onUpdate(index, subName, val),
1568
1627
  readOnly,
@@ -1582,13 +1641,17 @@ function ArrayField({
1582
1641
  label,
1583
1642
  id = ""
1584
1643
  }) {
1585
- const atMax = field.max !== void 0 && value.length >= field.max;
1586
- const atMin = field.min !== void 0 && value.length <= field.min;
1587
- const [openIndex, setOpenIndex] = React18__namespace.useState(null);
1588
- const itemIds = React18__namespace.useMemo(
1589
- () => value.map((_, i) => `${id}-item-${i}`),
1590
- [value.length, id]
1591
- );
1644
+ const [openIndex, setOpenIndex] = React17__namespace.useState(null);
1645
+ const stableValue = React17__namespace.useMemo(() => {
1646
+ const needsId = value.some((item) => !item._id);
1647
+ if (!needsId) return value;
1648
+ return value.map(
1649
+ (item) => item._id ? item : { ...item, _id: `${id}-${Math.random().toString(36).slice(2)}` }
1650
+ );
1651
+ }, [value, id]);
1652
+ const itemIds = stableValue.map((item) => item._id);
1653
+ const atMax = field.max !== void 0 && stableValue.length >= field.max;
1654
+ const atMin = field.min !== void 0 && stableValue.length <= field.min;
1592
1655
  const sensors = core$1.useSensors(core$1.useSensor(core$1.PointerSensor));
1593
1656
  const handleDragEnd = (event) => {
1594
1657
  const { active, over } = event;
@@ -1596,7 +1659,7 @@ function ArrayField({
1596
1659
  const from = itemIds.indexOf(active.id);
1597
1660
  const to = itemIds.indexOf(over.id);
1598
1661
  if (from === -1 || to === -1) return;
1599
- onChange(sortable.arrayMove(value, from, to));
1662
+ onChange(sortable.arrayMove(stableValue, from, to));
1600
1663
  };
1601
1664
  const defaultItem = () => {
1602
1665
  if (!field.defaultItemProps) return {};
@@ -1604,33 +1667,35 @@ function ArrayField({
1604
1667
  };
1605
1668
  const addItem = () => {
1606
1669
  if (atMax || readOnly) return;
1607
- const newIndex = value.length;
1608
- onChange([...value, defaultItem()]);
1670
+ const newIndex = stableValue.length;
1671
+ onChange([...stableValue, defaultItem()]);
1609
1672
  setOpenIndex(newIndex);
1610
1673
  };
1611
1674
  const removeItem = (i) => {
1612
1675
  if (atMin || readOnly) return;
1613
- const next = [...value];
1676
+ const next = [...stableValue];
1614
1677
  next.splice(i, 1);
1615
1678
  onChange(next);
1616
1679
  };
1617
1680
  const duplicateItem = (i) => {
1618
1681
  if (atMax || readOnly) return;
1619
- const next = [...value];
1620
- next.splice(i + 1, 0, { ...value[i] });
1682
+ const next = [...stableValue];
1683
+ next.splice(i + 1, 0, { ...stableValue[i] });
1621
1684
  onChange(next);
1622
1685
  };
1623
1686
  const updateItem = (i, subName, val) => {
1624
1687
  onChange(
1625
- value.map(
1688
+ stableValue.map(
1626
1689
  (item, idx) => idx === i ? { ...item, [subName]: val } : item
1627
1690
  )
1628
1691
  );
1629
1692
  };
1630
1693
  const getSummary = (item, i) => {
1631
1694
  if (field.getItemSummary) return field.getItemSummary(item, i);
1632
- const first = Object.values(item).find((v) => typeof v === "string" && v);
1633
- return first || `Item ${i + 1}`;
1695
+ const first = Object.entries(item).find(
1696
+ (entry) => entry[0] !== "_id" && typeof entry[1] === "string" && entry[1].length > 0
1697
+ );
1698
+ return first?.[1] ?? `Item ${i + 1}`;
1634
1699
  };
1635
1700
  return /* @__PURE__ */ jsxRuntime.jsx(FieldLabel, { label: label ?? field.label ?? "", readOnly, el: "div", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [
1636
1701
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1644,7 +1709,7 @@ function ArrayField({
1644
1709
  {
1645
1710
  items: itemIds,
1646
1711
  strategy: sortable.verticalListSortingStrategy,
1647
- children: /* @__PURE__ */ jsxRuntime.jsx(ItemGroup, { children: value.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(
1712
+ children: /* @__PURE__ */ jsxRuntime.jsx(ItemGroup, { children: stableValue.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx(
1648
1713
  SortableItem,
1649
1714
  {
1650
1715
  id: itemIds[i],
@@ -1697,7 +1762,7 @@ function Card({
1697
1762
  "data-slot": "card",
1698
1763
  "data-size": size,
1699
1764
  className: cn(
1700
- "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
1765
+ "group/card flex flex-col gap-6 overflow-hidden rounded-xl bg-card py-6 text-sm text-card-foreground shadow-xs ring-1 ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
1701
1766
  className
1702
1767
  ),
1703
1768
  ...props
@@ -1709,7 +1774,7 @@ function CardContent({ className, ...props }) {
1709
1774
  "div",
1710
1775
  {
1711
1776
  "data-slot": "card-content",
1712
- className: cn("px-4 group-data-[size=sm]/card:px-3", className),
1777
+ className: cn("px-6 group-data-[size=sm]/card:px-4", className),
1713
1778
  ...props
1714
1779
  }
1715
1780
  );
@@ -1721,17 +1786,17 @@ function CustomField({ children, label }) {
1721
1786
  return /* @__PURE__ */ jsxRuntime.jsx(FieldLabel, { label: label ?? "", el: "div", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-border/60 p-3", children }) });
1722
1787
  }
1723
1788
  var toggleVariants = classVarianceAuthority.cva(
1724
- "group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1789
+ "group/toggle inline-flex items-center justify-center gap-1 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
1725
1790
  {
1726
1791
  variants: {
1727
1792
  variant: {
1728
1793
  default: "bg-transparent",
1729
- outline: "border border-input bg-transparent hover:bg-muted"
1794
+ outline: "border border-input bg-transparent shadow-xs hover:bg-muted"
1730
1795
  },
1731
1796
  size: {
1732
- default: "h-8 min-w-8 px-2",
1733
- sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-1.5 text-[0.8rem]",
1734
- lg: "h-9 min-w-9 px-2.5"
1797
+ default: "h-9 min-w-9 px-2",
1798
+ sm: "h-8 min-w-8 px-1.5",
1799
+ lg: "h-10 min-w-10 px-2.5"
1735
1800
  }
1736
1801
  },
1737
1802
  defaultVariants: {
@@ -1756,12 +1821,12 @@ function Toggle({
1756
1821
  );
1757
1822
  }
1758
1823
  function RichtextField({ value, onChange, readOnly, label }) {
1759
- const ref = React18__namespace.useRef(null);
1824
+ const ref = React17__namespace.useRef(null);
1760
1825
  const boldLabel = useMsg("richtext.bold");
1761
1826
  const italicLabel = useMsg("richtext.italic");
1762
1827
  const linkLabel = useMsg("richtext.link");
1763
1828
  const linkPrompt = useMsg("richtext.link.prompt");
1764
- React18__namespace.useEffect(() => {
1829
+ React17__namespace.useEffect(() => {
1765
1830
  if (ref.current && ref.current.innerHTML !== value) {
1766
1831
  ref.current.innerHTML = value ?? "";
1767
1832
  }
@@ -1808,17 +1873,7 @@ function InputGroup({ className, ...props }) {
1808
1873
  "data-slot": "input-group",
1809
1874
  role: "group",
1810
1875
  className: cn(
1811
- "group/input-group border-input dark:bg-input/30 shadow-xs relative flex w-full items-center rounded-md border outline-none transition-[color,box-shadow]",
1812
- "h-9 has-[>textarea]:h-auto",
1813
- // Variants based on alignment.
1814
- "has-[>[data-align=inline-start]]:[&>input]:pl-2",
1815
- "has-[>[data-align=inline-end]]:[&>input]:pr-2",
1816
- "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
1817
- "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
1818
- // Focus state.
1819
- "has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1",
1820
- // Error state.
1821
- "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
1876
+ "group/input-group relative flex h-9 w-full min-w-0 items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
1822
1877
  className
1823
1878
  ),
1824
1879
  ...props
@@ -1826,14 +1881,14 @@ function InputGroup({ className, ...props }) {
1826
1881
  );
1827
1882
  }
1828
1883
  var inputGroupAddonVariants = classVarianceAuthority.cva(
1829
- "text-muted-foreground flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 text-sm font-medium group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
1884
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
1830
1885
  {
1831
1886
  variants: {
1832
1887
  align: {
1833
- "inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
1834
- "inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
1835
- "block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5",
1836
- "block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5"
1888
+ "inline-start": "order-first pl-2 has-[>button]:-ml-1 has-[>kbd]:ml-[-0.15rem]",
1889
+ "inline-end": "order-last pr-2 has-[>button]:-mr-1 has-[>kbd]:mr-[-0.15rem]",
1890
+ "block-start": "order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2",
1891
+ "block-end": "order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2"
1837
1892
  }
1838
1893
  },
1839
1894
  defaultVariants: {
@@ -1868,8 +1923,8 @@ classVarianceAuthority.cva(
1868
1923
  {
1869
1924
  variants: {
1870
1925
  size: {
1871
- xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
1872
- sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
1926
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
1927
+ sm: "",
1873
1928
  "icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
1874
1929
  "icon-sm": "size-8 p-0 has-[>svg]:p-0"
1875
1930
  }
@@ -1953,7 +2008,7 @@ function CommandItem({
1953
2008
  {
1954
2009
  "data-slot": "command-item",
1955
2010
  className: cn(
1956
- "group/command-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none in-data-[slot=dialog-content]:rounded-lg! data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-selected:bg-muted data-selected:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-selected:*:[svg]:text-foreground",
2011
+ "group/command-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none in-data-[slot=dialog-content]:rounded-lg! data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-selected:bg-muted data-selected:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-selected:**:[svg]:text-foreground",
1957
2012
  className
1958
2013
  ),
1959
2014
  ...props,
@@ -1975,10 +2030,10 @@ function Skeleton({ className, ...props }) {
1975
2030
  );
1976
2031
  }
1977
2032
  function ExternalField({ value, onChange, fetchList, readOnly, label }) {
1978
- const [query, setQuery] = React18__namespace.useState("");
1979
- const [results, setResults] = React18__namespace.useState([]);
1980
- const [loading, setLoading] = React18__namespace.useState(false);
1981
- React18__namespace.useEffect(() => {
2033
+ const [query, setQuery] = React17__namespace.useState("");
2034
+ const [results, setResults] = React17__namespace.useState([]);
2035
+ const [loading, setLoading] = React17__namespace.useState(false);
2036
+ React17__namespace.useEffect(() => {
1982
2037
  if (!fetchList) return;
1983
2038
  setLoading(true);
1984
2039
  const timer = setTimeout(async () => {
@@ -2024,7 +2079,7 @@ function ExternalField({ value, onChange, fetchList, readOnly, label }) {
2024
2079
  ] }) });
2025
2080
  }
2026
2081
 
2027
- // src/components/overrides/fields/FieldTypesRegistry.ts
2082
+ // src/core/overrides/fields/FieldTypesRegistry.ts
2028
2083
  var fieldTypesRegistry = {
2029
2084
  text: TextField,
2030
2085
  textarea: TextareaField,
@@ -2042,8 +2097,6 @@ function PuckRoot({ children }) {
2042
2097
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
2043
2098
  }
2044
2099
  var puckOverrides = {
2045
- header: EditorHeader,
2046
- headerActions: EditorHeaderActions,
2047
2100
  drawer: EditorDrawer,
2048
2101
  components: EditorComponents,
2049
2102
  drawerItem: DrawerItem,
@@ -2063,9 +2116,9 @@ var DEFAULT_BOUNDS_OFFSET = {
2063
2116
  width: 0,
2064
2117
  height: 0
2065
2118
  };
2066
- var HighlightContext = React18__namespace.createContext(void 0);
2119
+ var HighlightContext = React17__namespace.createContext(void 0);
2067
2120
  function useHighlight() {
2068
- const context = React18__namespace.useContext(HighlightContext);
2121
+ const context = React17__namespace.useContext(HighlightContext);
2069
2122
  if (!context) {
2070
2123
  throw new Error("useHighlight must be used within a HighlightProvider");
2071
2124
  }
@@ -2092,21 +2145,21 @@ function Highlight({
2092
2145
  exitDelay = 200,
2093
2146
  mode = "children"
2094
2147
  } = props;
2095
- const localRef = React18__namespace.useRef(null);
2096
- React18__namespace.useImperativeHandle(ref, () => localRef.current);
2148
+ const localRef = React17__namespace.useRef(null);
2149
+ React17__namespace.useImperativeHandle(ref, () => localRef.current);
2097
2150
  const propsBoundsOffset = props?.boundsOffset;
2098
2151
  const boundsOffset = propsBoundsOffset ?? DEFAULT_BOUNDS_OFFSET;
2099
2152
  const boundsOffsetTop = boundsOffset.top ?? 0;
2100
2153
  const boundsOffsetLeft = boundsOffset.left ?? 0;
2101
2154
  const boundsOffsetWidth = boundsOffset.width ?? 0;
2102
2155
  const boundsOffsetHeight = boundsOffset.height ?? 0;
2103
- const boundsOffsetRef = React18__namespace.useRef({
2156
+ const boundsOffsetRef = React17__namespace.useRef({
2104
2157
  top: boundsOffsetTop,
2105
2158
  left: boundsOffsetLeft,
2106
2159
  width: boundsOffsetWidth,
2107
2160
  height: boundsOffsetHeight
2108
2161
  });
2109
- React18__namespace.useEffect(() => {
2162
+ React17__namespace.useEffect(() => {
2110
2163
  boundsOffsetRef.current = {
2111
2164
  top: boundsOffsetTop,
2112
2165
  left: boundsOffsetLeft,
@@ -2119,11 +2172,11 @@ function Highlight({
2119
2172
  boundsOffsetWidth,
2120
2173
  boundsOffsetHeight
2121
2174
  ]);
2122
- const [activeValue, setActiveValue] = React18__namespace.useState(
2175
+ const [activeValue, setActiveValue] = React17__namespace.useState(
2123
2176
  value ?? defaultValue ?? null
2124
2177
  );
2125
- const [boundsState, setBoundsState] = React18__namespace.useState(null);
2126
- const [activeClassNameState, setActiveClassNameState] = React18__namespace.useState("");
2178
+ const [boundsState, setBoundsState] = React17__namespace.useState(null);
2179
+ const [activeClassNameState, setActiveClassNameState] = React17__namespace.useState("");
2127
2180
  const safeSetActiveValue = (id2) => {
2128
2181
  setActiveValue((prev) => {
2129
2182
  if (prev !== id2) {
@@ -2133,8 +2186,8 @@ function Highlight({
2133
2186
  return prev;
2134
2187
  });
2135
2188
  };
2136
- const safeSetBoundsRef = React18__namespace.useRef(void 0);
2137
- React18__namespace.useEffect(() => {
2189
+ const safeSetBoundsRef = React17__namespace.useRef(void 0);
2190
+ React17__namespace.useEffect(() => {
2138
2191
  safeSetBoundsRef.current = (bounds) => {
2139
2192
  if (!localRef.current) return;
2140
2193
  const containerRect = localRef.current.getBoundingClientRect();
@@ -2156,15 +2209,15 @@ function Highlight({
2156
2209
  const safeSetBounds = (bounds) => {
2157
2210
  safeSetBoundsRef.current?.(bounds);
2158
2211
  };
2159
- const clearBounds = React18__namespace.useCallback(() => {
2212
+ const clearBounds = React17__namespace.useCallback(() => {
2160
2213
  setBoundsState((prev) => prev === null ? prev : null);
2161
2214
  }, []);
2162
- React18__namespace.useEffect(() => {
2215
+ React17__namespace.useEffect(() => {
2163
2216
  if (value !== void 0) setActiveValue(value);
2164
2217
  else if (defaultValue !== void 0) setActiveValue(defaultValue);
2165
2218
  }, [value, defaultValue]);
2166
- const id = React18__namespace.useId();
2167
- React18__namespace.useEffect(() => {
2219
+ const id = React17__namespace.useId();
2220
+ React17__namespace.useEffect(() => {
2168
2221
  if (mode !== "parent") return;
2169
2222
  const container = localRef.current;
2170
2223
  if (!container) return;
@@ -2249,7 +2302,7 @@ function Highlight({
2249
2302
  forceUpdateBounds: props?.forceUpdateBounds
2250
2303
  },
2251
2304
  children: enabled ? controlledItems ? render(children) : render(
2252
- React18__namespace.Children.map(children, (child, index) => /* @__PURE__ */ jsxRuntime.jsx(HighlightItem, { className: props?.itemsClassName, children: child }, index))
2305
+ React17__namespace.Children.map(children, (child, index) => /* @__PURE__ */ jsxRuntime.jsx(HighlightItem, { className: props?.itemsClassName, children: child }, index))
2253
2306
  ) : children
2254
2307
  }
2255
2308
  );
@@ -2281,7 +2334,7 @@ function HighlightItem({
2281
2334
  forceUpdateBounds,
2282
2335
  ...props
2283
2336
  }) {
2284
- const itemId = React18__namespace.useId();
2337
+ const itemId = React17__namespace.useId();
2285
2338
  const {
2286
2339
  activeValue,
2287
2340
  setActiveValue,
@@ -2306,12 +2359,12 @@ function HighlightItem({
2306
2359
  const isActive = activeValue === childValue;
2307
2360
  const isDisabled = disabled === void 0 ? contextDisabled : disabled;
2308
2361
  const itemTransition = transition ?? contextTransition;
2309
- const localRef = React18__namespace.useRef(null);
2310
- React18__namespace.useImperativeHandle(ref, () => localRef.current);
2311
- const refCallback = React18__namespace.useCallback((node) => {
2362
+ const localRef = React17__namespace.useRef(null);
2363
+ React17__namespace.useImperativeHandle(ref, () => localRef.current);
2364
+ const refCallback = React17__namespace.useCallback((node) => {
2312
2365
  localRef.current = node;
2313
2366
  }, []);
2314
- React18__namespace.useEffect(() => {
2367
+ React17__namespace.useEffect(() => {
2315
2368
  if (mode !== "parent") return;
2316
2369
  let rafId;
2317
2370
  let previousBounds = null;
@@ -2345,7 +2398,7 @@ function HighlightItem({
2345
2398
  forceUpdateBounds,
2346
2399
  contextForceUpdateBounds
2347
2400
  ]);
2348
- if (!React18__namespace.isValidElement(children)) return children;
2401
+ if (!React17__namespace.isValidElement(children)) return children;
2349
2402
  const dataAttributes = {
2350
2403
  "data-active": isActive ? "true" : "false",
2351
2404
  "aria-selected": isActive,
@@ -2370,7 +2423,7 @@ function HighlightItem({
2370
2423
  } : {};
2371
2424
  if (asChild) {
2372
2425
  if (mode === "children") {
2373
- return React18__namespace.cloneElement(
2426
+ return React17__namespace.cloneElement(
2374
2427
  element,
2375
2428
  {
2376
2429
  key: childValue,
@@ -2422,7 +2475,7 @@ function HighlightItem({
2422
2475
  ] })
2423
2476
  );
2424
2477
  }
2425
- return React18__namespace.cloneElement(element, {
2478
+ return React17__namespace.cloneElement(element, {
2426
2479
  ref: refCallback,
2427
2480
  ...getNonOverridingDataAttributes(element, {
2428
2481
  ...dataAttributes,
@@ -2466,7 +2519,7 @@ function HighlightItem({
2466
2519
  ...dataAttributes
2467
2520
  }
2468
2521
  ) }),
2469
- React18__namespace.cloneElement(element, {
2522
+ React17__namespace.cloneElement(element, {
2470
2523
  style: { position: "relative", zIndex: 1 },
2471
2524
  className: element.props.className,
2472
2525
  ...getNonOverridingDataAttributes(element, {
@@ -2513,11 +2566,11 @@ function Slot({
2513
2566
  ...props
2514
2567
  }) {
2515
2568
  const isAlreadyMotion = typeof children.type === "object" && children.type !== null && react.isMotionComponent(children.type);
2516
- const Base = React18__namespace.useMemo(
2569
+ const Base = React17__namespace.useMemo(
2517
2570
  () => isAlreadyMotion ? children.type : react.motion.create(children.type),
2518
2571
  [isAlreadyMotion, children.type]
2519
2572
  );
2520
- if (!React18__namespace.isValidElement(children)) return null;
2573
+ if (!React17__namespace.isValidElement(children)) return null;
2521
2574
  const { ref: childRef, ...childProps } = children.props;
2522
2575
  const mergedProps = mergeProps4(childProps, props);
2523
2576
  return /* @__PURE__ */ jsxRuntime.jsx(Base, { ...mergedProps, ref: mergeRefs(childRef, ref) });
@@ -2597,6 +2650,52 @@ function TabsTab2({ className, ...props }) {
2597
2650
  }
2598
2651
  ) });
2599
2652
  }
2653
+ var ACTIVE_TABS = [
2654
+ "insert",
2655
+ "layer",
2656
+ "image",
2657
+ "text",
2658
+ "copilot"
2659
+ ];
2660
+ var activeTabSet = new Set(ACTIVE_TABS);
2661
+ function isActiveTab(value) {
2662
+ return activeTabSet.has(value);
2663
+ }
2664
+ function createEditorUiStore(storeId) {
2665
+ return zustand.createStore()(
2666
+ middleware.persist(
2667
+ (set) => ({
2668
+ drawerSearch: "",
2669
+ setDrawerSearch: (q) => set({ drawerSearch: q }),
2670
+ drawerCollapsed: {},
2671
+ toggleDrawerGroup: (group) => set((s) => ({
2672
+ drawerCollapsed: { ...s.drawerCollapsed, [group]: !s.drawerCollapsed[group] }
2673
+ })),
2674
+ activeTab: "insert",
2675
+ setActiveTab: (tab) => set({ activeTab: tab }),
2676
+ outlineExpanded: {},
2677
+ toggleOutlineItem: (id) => set((s) => ({
2678
+ outlineExpanded: { ...s.outlineExpanded, [id]: !s.outlineExpanded[id] }
2679
+ })),
2680
+ theme: "light",
2681
+ toggleTheme: () => set((s) => {
2682
+ const next = s.theme === "light" ? "dark" : "light";
2683
+ return { theme: next };
2684
+ })
2685
+ }),
2686
+ {
2687
+ name: `anvilkit-ui-${storeId}`,
2688
+ partialize: (s) => ({
2689
+ activeTab: s.activeTab,
2690
+ drawerCollapsed: s.drawerCollapsed,
2691
+ outlineExpanded: s.outlineExpanded,
2692
+ theme: s.theme
2693
+ // drawerSearch intentionally excluded — transient input
2694
+ })
2695
+ }
2696
+ )
2697
+ );
2698
+ }
2600
2699
  function Aside() {
2601
2700
  const activeTab = useActiveTab();
2602
2701
  const setActiveTab = useSetActiveTab();
@@ -2607,10 +2706,35 @@ function Aside() {
2607
2706
  { value: "text", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Type, { className: "h-4 w-4" }), label: useMsg("aside.text") },
2608
2707
  { value: "copilot", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bot, { className: "h-4 w-4" }), label: useMsg("aside.copilot") }
2609
2708
  ];
2610
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-18 h-full py-4 border-r border-neutral-200 dark:border-neutral-800/80", children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(Tabs2, { value: activeTab, onValueChange: setActiveTab, className: "w-full flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(TabsList2, { className: "flex-col h-auto bg-transparent gap-2", children: tabs.map(({ value, icon, label }) => /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
2611
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(TabsTab2, { value, className: "p-2", children: icon }) }) }),
2612
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "right", children: label })
2613
- ] }, value)) }) }) }) });
2709
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-18 h-full py-4 border-r border-neutral-200 dark:border-neutral-800/80", children: /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
2710
+ Tabs2,
2711
+ {
2712
+ value: activeTab,
2713
+ onValueChange: (value) => {
2714
+ if (isActiveTab(value)) {
2715
+ setActiveTab(value);
2716
+ }
2717
+ },
2718
+ className: "w-full flex items-center justify-center",
2719
+ children: /* @__PURE__ */ jsxRuntime.jsx(TabsList2, { className: "flex-col h-auto bg-transparent gap-2", children: tabs.map(({ value, icon, label }) => /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
2720
+ /* @__PURE__ */ jsxRuntime.jsx(
2721
+ TooltipTrigger,
2722
+ {
2723
+ render: /* @__PURE__ */ jsxRuntime.jsx(
2724
+ TabsTab2,
2725
+ {
2726
+ value,
2727
+ className: "p-2",
2728
+ "aria-label": label
2729
+ }
2730
+ ),
2731
+ children: icon
2732
+ }
2733
+ ),
2734
+ /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { side: "right", children: label })
2735
+ ] }, value)) })
2736
+ }
2737
+ ) }) });
2614
2738
  }
2615
2739
  function AnimatedAsana({
2616
2740
  trigger = false,
@@ -2627,15 +2751,15 @@ function AnimatedAsana({
2627
2751
  // Default non-priority
2628
2752
  ...props
2629
2753
  }) {
2630
- const [isHovered, setIsHovered] = React18.useState(false);
2631
- const [animationPhase, setAnimationPhase] = React18.useState("three-circles");
2632
- const animationTimerRef = React18.useRef(null);
2633
- const animationStartedRef = React18.useRef(false);
2634
- const effectiveTrigger = React18.useMemo(
2754
+ const [isHovered, setIsHovered] = React17.useState(false);
2755
+ const [animationPhase, setAnimationPhase] = React17.useState("three-circles");
2756
+ const animationTimerRef = React17.useRef(null);
2757
+ const animationStartedRef = React17.useRef(false);
2758
+ const effectiveTrigger = React17.useMemo(
2635
2759
  () => trigger || useTrigger && isHovered,
2636
2760
  [trigger, useTrigger, isHovered]
2637
2761
  );
2638
- const springTransition = React18.useMemo(
2762
+ const springTransition = React17.useMemo(
2639
2763
  () => ({
2640
2764
  type: "spring",
2641
2765
  stiffness: springConfig.stiffness,
@@ -2644,17 +2768,17 @@ function AnimatedAsana({
2644
2768
  }),
2645
2769
  [springConfig.stiffness, springConfig.damping, springConfig.mass]
2646
2770
  );
2647
- const handleMouseEnter = React18.useCallback(() => {
2771
+ const handleMouseEnter = React17.useCallback(() => {
2648
2772
  if (useTrigger) {
2649
2773
  setIsHovered(true);
2650
2774
  }
2651
2775
  }, [useTrigger]);
2652
- const handleMouseLeave = React18.useCallback(() => {
2776
+ const handleMouseLeave = React17.useCallback(() => {
2653
2777
  if (useTrigger) {
2654
2778
  setIsHovered(false);
2655
2779
  }
2656
2780
  }, [useTrigger]);
2657
- React18.useEffect(() => {
2781
+ React17.useEffect(() => {
2658
2782
  if (animationTimerRef.current) {
2659
2783
  clearTimeout(animationTimerRef.current);
2660
2784
  animationTimerRef.current = null;
@@ -2677,14 +2801,14 @@ function AnimatedAsana({
2677
2801
  }
2678
2802
  };
2679
2803
  }, [effectiveTrigger, animationDuration]);
2680
- const centerCircleAnimation = React18.useMemo(
2804
+ const centerCircleAnimation = React17.useMemo(
2681
2805
  () => ({
2682
2806
  opacity: animationPhase === "one-circle" ? 1 : 0,
2683
2807
  scale: animationPhase === "one-circle" ? 1 : 0
2684
2808
  }),
2685
2809
  [animationPhase]
2686
2810
  );
2687
- const topCircleAnimation = React18.useMemo(
2811
+ const topCircleAnimation = React17.useMemo(
2688
2812
  () => ({
2689
2813
  opacity: animationPhase === "three-circles" ? 1 : 0,
2690
2814
  y: animationPhase === "three-circles" ? 0 : 4.5,
@@ -2692,7 +2816,7 @@ function AnimatedAsana({
2692
2816
  }),
2693
2817
  [animationPhase]
2694
2818
  );
2695
- const leftBottomCircleAnimation = React18.useMemo(
2819
+ const leftBottomCircleAnimation = React17.useMemo(
2696
2820
  () => ({
2697
2821
  opacity: animationPhase === "three-circles" ? 1 : 0,
2698
2822
  x: animationPhase === "three-circles" ? 0 : 5,
@@ -2701,7 +2825,7 @@ function AnimatedAsana({
2701
2825
  }),
2702
2826
  [animationPhase]
2703
2827
  );
2704
- const rightBottomCircleAnimation = React18.useMemo(
2828
+ const rightBottomCircleAnimation = React17.useMemo(
2705
2829
  () => ({
2706
2830
  opacity: animationPhase === "three-circles" ? 1 : 0,
2707
2831
  x: animationPhase === "three-circles" ? 0 : -5,
@@ -2802,10 +2926,10 @@ function AnimatedAsana({
2802
2926
  }
2803
2927
  );
2804
2928
  }
2805
- React18__namespace.default.memo(function TriggerableAsana2(props) {
2929
+ React17__namespace.default.memo(function TriggerableAsana2(props) {
2806
2930
  return /* @__PURE__ */ jsxRuntime.jsx(AnimatedAsana, { useTrigger: true, ...props });
2807
2931
  });
2808
- React18__namespace.default.memo(function ControlledAsana2(props) {
2932
+ React17__namespace.default.memo(function ControlledAsana2(props) {
2809
2933
  return /* @__PURE__ */ jsxRuntime.jsx(AnimatedAsana, { useTrigger: false, ...props });
2810
2934
  });
2811
2935
  var [GlobalTooltipProvider, useGlobalTooltip] = getStrictContext("GlobalTooltipProvider");
@@ -2831,12 +2955,12 @@ function TooltipProvider2({
2831
2955
  closeDelay = 300,
2832
2956
  transition = { type: "spring", stiffness: 300, damping: 35 }
2833
2957
  }) {
2834
- const globalId = React18__namespace.useId();
2835
- const [currentTooltip, setCurrentTooltip] = React18__namespace.useState(null);
2836
- const timeoutRef = React18__namespace.useRef(null);
2837
- const lastCloseTimeRef = React18__namespace.useRef(0);
2838
- const referenceElRef = React18__namespace.useRef(null);
2839
- const showTooltip = React18__namespace.useCallback(
2958
+ const globalId = React17__namespace.useId();
2959
+ const [currentTooltip, setCurrentTooltip] = React17__namespace.useState(null);
2960
+ const timeoutRef = React17__namespace.useRef(null);
2961
+ const lastCloseTimeRef = React17__namespace.useRef(0);
2962
+ const referenceElRef = React17__namespace.useRef(null);
2963
+ const showTooltip = React17__namespace.useCallback(
2840
2964
  (data) => {
2841
2965
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2842
2966
  if (currentTooltip !== null) {
@@ -2852,22 +2976,22 @@ function TooltipProvider2({
2852
2976
  },
2853
2977
  [openDelay, closeDelay, currentTooltip]
2854
2978
  );
2855
- const hideTooltip = React18__namespace.useCallback(() => {
2979
+ const hideTooltip = React17__namespace.useCallback(() => {
2856
2980
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2857
2981
  timeoutRef.current = window.setTimeout(() => {
2858
2982
  setCurrentTooltip(null);
2859
2983
  lastCloseTimeRef.current = Date.now();
2860
2984
  }, closeDelay);
2861
2985
  }, [closeDelay]);
2862
- const hideImmediate = React18__namespace.useCallback(() => {
2986
+ const hideImmediate = React17__namespace.useCallback(() => {
2863
2987
  if (timeoutRef.current) clearTimeout(timeoutRef.current);
2864
2988
  setCurrentTooltip(null);
2865
2989
  lastCloseTimeRef.current = Date.now();
2866
2990
  }, []);
2867
- const setReferenceEl = React18__namespace.useCallback((el) => {
2991
+ const setReferenceEl = React17__namespace.useCallback((el) => {
2868
2992
  referenceElRef.current = el;
2869
2993
  }, []);
2870
- React18__namespace.useEffect(() => {
2994
+ React17__namespace.useEffect(() => {
2871
2995
  const onKeyDown = (e) => {
2872
2996
  if (e.key === "Escape") hideImmediate();
2873
2997
  };
@@ -2911,7 +3035,7 @@ function TooltipArrow({
2911
3035
  const { side, align, open } = useRenderedTooltip();
2912
3036
  const { context, arrowRef } = useFloatingContext();
2913
3037
  const { transition, globalId } = useGlobalTooltip();
2914
- React18__namespace.useImperativeHandle(ref, () => arrowRef.current);
3038
+ React17__namespace.useImperativeHandle(ref, () => arrowRef.current);
2915
3039
  const deg = { top: 0, right: 90, bottom: 180, left: -90 }[side];
2916
3040
  return /* @__PURE__ */ jsxRuntime.jsx(
2917
3041
  MotionTooltipArrow,
@@ -2934,8 +3058,8 @@ function TooltipPortal(props) {
2934
3058
  }
2935
3059
  function TooltipOverlay() {
2936
3060
  const { currentTooltip, transition, globalId, referenceElRef } = useGlobalTooltip();
2937
- const [rendered, setRendered] = React18__namespace.useState({ data: null, open: false });
2938
- const arrowRef = React18__namespace.useRef(null);
3061
+ const [rendered, setRendered] = React17__namespace.useState({ data: null, open: false });
3062
+ const arrowRef = React17__namespace.useRef(null);
2939
3063
  const side = rendered.data?.side ?? "top";
2940
3064
  const align = rendered.data?.align ?? "center";
2941
3065
  const { refs, x, y, strategy, context, update } = react$1.useFloating({
@@ -2951,14 +3075,14 @@ function TooltipOverlay() {
2951
3075
  react$1.arrow({ element: arrowRef })
2952
3076
  ]
2953
3077
  });
2954
- React18__namespace.useEffect(() => {
3078
+ React17__namespace.useEffect(() => {
2955
3079
  if (currentTooltip) {
2956
3080
  setRendered({ data: currentTooltip, open: true });
2957
3081
  } else {
2958
3082
  setRendered((p) => p.data ? { ...p, open: false } : p);
2959
3083
  }
2960
3084
  }, [currentTooltip]);
2961
- React18__namespace.useLayoutEffect(() => {
3085
+ React17__namespace.useLayoutEffect(() => {
2962
3086
  if (referenceElRef.current) {
2963
3087
  refs.setReference(referenceElRef.current);
2964
3088
  update();
@@ -3037,9 +3161,9 @@ function Tooltip2({
3037
3161
  align = "center",
3038
3162
  alignOffset = 0
3039
3163
  }) {
3040
- const id = React18__namespace.useId();
3041
- const [props, setProps] = React18__namespace.useState({});
3042
- const [asChild, setAsChild] = React18__namespace.useState(false);
3164
+ const id = React17__namespace.useId();
3165
+ const [props, setProps] = React17__namespace.useState({});
3166
+ const [asChild, setAsChild] = React17__namespace.useState(false);
3043
3167
  return /* @__PURE__ */ jsxRuntime.jsx(
3044
3168
  LocalTooltipProvider,
3045
3169
  {
@@ -3071,16 +3195,16 @@ function shallowEqualWithoutChildren(a, b) {
3071
3195
  }
3072
3196
  function TooltipContent2({ asChild = false, ...props }) {
3073
3197
  const { setProps, setAsChild } = useTooltip();
3074
- const lastPropsRef = React18__namespace.useRef(
3198
+ const lastPropsRef = React17__namespace.useRef(
3075
3199
  void 0
3076
3200
  );
3077
- React18__namespace.useEffect(() => {
3201
+ React17__namespace.useEffect(() => {
3078
3202
  if (!shallowEqualWithoutChildren(lastPropsRef.current, props)) {
3079
3203
  lastPropsRef.current = props;
3080
3204
  setProps(props);
3081
3205
  }
3082
3206
  }, [props, setProps]);
3083
- React18__namespace.useEffect(() => {
3207
+ React17__namespace.useEffect(() => {
3084
3208
  setAsChild(asChild);
3085
3209
  }, [asChild, setAsChild]);
3086
3210
  return null;
@@ -3111,10 +3235,10 @@ function TooltipTrigger2({
3111
3235
  currentTooltip,
3112
3236
  setReferenceEl
3113
3237
  } = useGlobalTooltip();
3114
- const triggerRef = React18__namespace.useRef(null);
3115
- React18__namespace.useImperativeHandle(ref, () => triggerRef.current);
3116
- const suppressNextFocusRef = React18__namespace.useRef(false);
3117
- const handleOpen = React18__namespace.useCallback(() => {
3238
+ const triggerRef = React17__namespace.useRef(null);
3239
+ React17__namespace.useImperativeHandle(ref, () => triggerRef.current);
3240
+ const suppressNextFocusRef = React17__namespace.useRef(false);
3241
+ const handleOpen = React17__namespace.useCallback(() => {
3118
3242
  if (!triggerRef.current) return;
3119
3243
  setReferenceEl(triggerRef.current);
3120
3244
  const rect = triggerRef.current.getBoundingClientRect();
@@ -3139,7 +3263,7 @@ function TooltipTrigger2({
3139
3263
  alignOffset,
3140
3264
  id
3141
3265
  ]);
3142
- const handlePointerDown = React18__namespace.useCallback(
3266
+ const handlePointerDown = React17__namespace.useCallback(
3143
3267
  (e) => {
3144
3268
  onPointerDown?.(e);
3145
3269
  if (currentTooltip?.id === id) {
@@ -3152,21 +3276,21 @@ function TooltipTrigger2({
3152
3276
  },
3153
3277
  [onPointerDown, currentTooltip?.id, id, hideImmediate]
3154
3278
  );
3155
- const handleMouseEnter = React18__namespace.useCallback(
3279
+ const handleMouseEnter = React17__namespace.useCallback(
3156
3280
  (e) => {
3157
3281
  onMouseEnter?.(e);
3158
3282
  handleOpen();
3159
3283
  },
3160
3284
  [handleOpen, onMouseEnter]
3161
3285
  );
3162
- const handleMouseLeave = React18__namespace.useCallback(
3286
+ const handleMouseLeave = React17__namespace.useCallback(
3163
3287
  (e) => {
3164
3288
  onMouseLeave?.(e);
3165
3289
  hideTooltip();
3166
3290
  },
3167
3291
  [hideTooltip, onMouseLeave]
3168
3292
  );
3169
- const handleFocus = React18__namespace.useCallback(
3293
+ const handleFocus = React17__namespace.useCallback(
3170
3294
  (e) => {
3171
3295
  onFocus?.(e);
3172
3296
  if (suppressNextFocusRef.current) return;
@@ -3174,7 +3298,7 @@ function TooltipTrigger2({
3174
3298
  },
3175
3299
  [handleOpen, onFocus]
3176
3300
  );
3177
- const handleBlur = React18__namespace.useCallback(
3301
+ const handleBlur = React17__namespace.useCallback(
3178
3302
  (e) => {
3179
3303
  onBlur?.(e);
3180
3304
  hideTooltip();
@@ -3276,7 +3400,7 @@ function AvatarGroup({
3276
3400
  children: children?.map((child, index) => /* @__PURE__ */ jsxRuntime.jsx(
3277
3401
  AvatarContainer,
3278
3402
  {
3279
- zIndex: invertOverlap ? React18__namespace.Children.count(children) - index : index,
3403
+ zIndex: invertOverlap ? React17__namespace.Children.count(children) - index : index,
3280
3404
  transition,
3281
3405
  translate,
3282
3406
  side,
@@ -3327,7 +3451,7 @@ function AvatarGroupTooltip2({
3327
3451
  ),
3328
3452
  ...props,
3329
3453
  children: [
3330
- /* @__PURE__ */ jsxRuntime.jsx(motion9__namespace.div, { layout, className: "overflow-hidden", children }),
3454
+ /* @__PURE__ */ jsxRuntime.jsx(motion8__namespace.div, { layout, className: "overflow-hidden", children }),
3331
3455
  /* @__PURE__ */ jsxRuntime.jsx(
3332
3456
  AvatarGroupTooltipArrow,
3333
3457
  {
@@ -3350,7 +3474,7 @@ function Avatar({
3350
3474
  "data-slot": "avatar",
3351
3475
  "data-size": size,
3352
3476
  className: cn(
3353
- "size-8 rounded-full after:rounded-full data-[size=lg]:size-10 data-[size=sm]:size-6 group/avatar relative flex shrink-0 select-none after:absolute after:inset-0 after:border after:border-border after:mix-blend-darken dark:after:mix-blend-lighten",
3477
+ "group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten",
3354
3478
  className
3355
3479
  ),
3356
3480
  ...props
@@ -3363,7 +3487,7 @@ function AvatarImage({ className, ...props }) {
3363
3487
  {
3364
3488
  "data-slot": "avatar-image",
3365
3489
  className: cn(
3366
- "rounded-full aspect-square size-full object-cover",
3490
+ "aspect-square size-full rounded-full object-cover",
3367
3491
  className
3368
3492
  ),
3369
3493
  ...props
@@ -3379,7 +3503,7 @@ function AvatarFallback({
3379
3503
  {
3380
3504
  "data-slot": "avatar-fallback",
3381
3505
  className: cn(
3382
- "bg-muted text-muted-foreground rounded-full flex size-full items-center justify-center text-sm group-data-[size=sm]/avatar:text-xs",
3506
+ "flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs",
3383
3507
  className
3384
3508
  ),
3385
3509
  ...props
@@ -3406,8 +3530,8 @@ var Collaborators = () => {
3406
3530
  ] }, index)) });
3407
3531
  };
3408
3532
  var Share = () => {
3409
- const [access, setAccess] = React18__namespace.useState("private");
3410
- const [copied, setCopied] = React18__namespace.useState(false);
3533
+ const [access, setAccess] = React17__namespace.useState("private");
3534
+ const [copied, setCopied] = React17__namespace.useState(false);
3411
3535
  const shareUrl = typeof window !== "undefined" ? window.location.href : "";
3412
3536
  const shareButton = useMsg("share.button");
3413
3537
  const shareTitle = useMsg("share.title");
@@ -3520,6 +3644,78 @@ var CollaboratorsPopover = () => {
3520
3644
  ] })
3521
3645
  ] });
3522
3646
  };
3647
+
3648
+ // src/features/export/export-json.ts
3649
+ function getFilename(filenameBase) {
3650
+ const safeBase = filenameBase?.trim() || "page";
3651
+ return `${safeBase}.json`;
3652
+ }
3653
+ function exportDataAsJson(data, { filenameBase, document: targetDocument } = {}) {
3654
+ const resolvedDocument = targetDocument ?? (typeof document !== "undefined" ? document : void 0);
3655
+ if (!resolvedDocument) return;
3656
+ const blob = new Blob([JSON.stringify(data, null, 2)], {
3657
+ type: "application/json"
3658
+ });
3659
+ const url = URL.createObjectURL(blob);
3660
+ const link = resolvedDocument.createElement("a");
3661
+ link.href = url;
3662
+ link.download = getFilename(filenameBase);
3663
+ link.click();
3664
+ URL.revokeObjectURL(url);
3665
+ }
3666
+ function DropdownMenu({ ...props }) {
3667
+ return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Root, { "data-slot": "dropdown-menu", ...props });
3668
+ }
3669
+ function DropdownMenuTrigger({ ...props }) {
3670
+ return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
3671
+ }
3672
+ function DropdownMenuContent({
3673
+ align = "start",
3674
+ alignOffset = 0,
3675
+ side = "bottom",
3676
+ sideOffset = 4,
3677
+ className,
3678
+ ...props
3679
+ }) {
3680
+ return /* @__PURE__ */ jsxRuntime.jsx(menu.Menu.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
3681
+ menu.Menu.Positioner,
3682
+ {
3683
+ className: "isolate z-50 outline-none",
3684
+ align,
3685
+ alignOffset,
3686
+ side,
3687
+ sideOffset,
3688
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3689
+ menu.Menu.Popup,
3690
+ {
3691
+ "data-slot": "dropdown-menu-content",
3692
+ className: cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", className),
3693
+ ...props
3694
+ }
3695
+ )
3696
+ }
3697
+ ) });
3698
+ }
3699
+ function DropdownMenuItem({
3700
+ className,
3701
+ inset,
3702
+ variant = "default",
3703
+ ...props
3704
+ }) {
3705
+ return /* @__PURE__ */ jsxRuntime.jsx(
3706
+ menu.Menu.Item,
3707
+ {
3708
+ "data-slot": "dropdown-menu-item",
3709
+ "data-inset": inset,
3710
+ "data-variant": variant,
3711
+ className: cn(
3712
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
3713
+ className
3714
+ ),
3715
+ ...props
3716
+ }
3717
+ );
3718
+ }
3523
3719
  var Header = () => {
3524
3720
  const { history, appState } = core.usePuck();
3525
3721
  const publish = useMsg("header.publish");
@@ -3534,9 +3730,7 @@ var Header = () => {
3534
3730
  const themeLightLabel = useMsg("header.theme.light");
3535
3731
  const themeDarkLabel = useMsg("header.theme.dark");
3536
3732
  const themeLabel = theme === "dark" ? themeLightLabel : themeDarkLabel;
3537
- React18__namespace.useEffect(() => {
3538
- document.documentElement.classList.toggle("dark", theme === "dark");
3539
- }, []);
3733
+ useThemeSync();
3540
3734
  return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex overflow-hidden transition-all duration-300 backdrop-blur-xl w-full border-b border-neutral-200 dark:border-neutral-800 items-center h-[54px] py-0", children: [
3541
3735
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-18 flex items-center justify-center h-full border-r border-neutral-200 dark:border-neutral-800/80", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center w-10 h-10 bg-primary rounded-full", children: /* @__PURE__ */ jsxRuntime.jsx(AnimatedAsana, { className: "text-white text-2xl" }) }) }),
3542
3736
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex flex-1 w-full px-2", children: [
@@ -3544,31 +3738,41 @@ var Header = () => {
3544
3738
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none text-sm font-medium", children: appState?.data?.root?.props?.title || "" }),
3545
3739
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 h-full ml-auto", children: [
3546
3740
  /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3547
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3548
- Button,
3741
+ /* @__PURE__ */ jsxRuntime.jsx(
3742
+ TooltipTrigger,
3549
3743
  {
3550
- variant: "ghost",
3551
- size: "icon",
3552
- disabled: !history.hasPast,
3553
- onClick: () => history.back(),
3554
- "aria-label": undo,
3744
+ render: /* @__PURE__ */ jsxRuntime.jsx(
3745
+ Button,
3746
+ {
3747
+ variant: "ghost",
3748
+ size: "icon",
3749
+ disabled: !history.hasPast,
3750
+ onClick: () => history.back(),
3751
+ "aria-label": undo
3752
+ }
3753
+ ),
3555
3754
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Undo2, { className: "h-4 w-4" })
3556
3755
  }
3557
- ) }),
3756
+ ),
3558
3757
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: undoTooltip })
3559
3758
  ] }),
3560
3759
  /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3561
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
3562
- Button,
3760
+ /* @__PURE__ */ jsxRuntime.jsx(
3761
+ TooltipTrigger,
3563
3762
  {
3564
- variant: "ghost",
3565
- size: "icon",
3566
- disabled: !history.hasFuture,
3567
- onClick: () => history.forward(),
3568
- "aria-label": redo,
3763
+ render: /* @__PURE__ */ jsxRuntime.jsx(
3764
+ Button,
3765
+ {
3766
+ variant: "ghost",
3767
+ size: "icon",
3768
+ disabled: !history.hasFuture,
3769
+ onClick: () => history.forward(),
3770
+ "aria-label": redo
3771
+ }
3772
+ ),
3569
3773
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Redo2, { className: "h-4 w-4" })
3570
3774
  }
3571
- ) }),
3775
+ ),
3572
3776
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: redoTooltip })
3573
3777
  ] }),
3574
3778
  /* @__PURE__ */ jsxRuntime.jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
@@ -3578,21 +3782,34 @@ var Header = () => {
3578
3782
  /* @__PURE__ */ jsxRuntime.jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
3579
3783
  /* @__PURE__ */ jsxRuntime.jsxs(DropdownMenu, { children: [
3580
3784
  /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3581
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuTrigger, { render: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon", "aria-label": exportLabel }), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "h-4 w-4" }) }) }),
3785
+ /* @__PURE__ */ jsxRuntime.jsx(
3786
+ TooltipTrigger,
3787
+ {
3788
+ render: /* @__PURE__ */ jsxRuntime.jsx(
3789
+ DropdownMenuTrigger,
3790
+ {
3791
+ render: /* @__PURE__ */ jsxRuntime.jsx(
3792
+ Button,
3793
+ {
3794
+ variant: "ghost",
3795
+ size: "icon",
3796
+ "aria-label": exportLabel
3797
+ }
3798
+ )
3799
+ }
3800
+ ),
3801
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "h-4 w-4" })
3802
+ }
3803
+ ),
3582
3804
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: exportLabel })
3583
3805
  ] }),
3584
3806
  /* @__PURE__ */ jsxRuntime.jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsxRuntime.jsxs(
3585
3807
  DropdownMenuItem,
3586
3808
  {
3587
3809
  onClick: () => {
3588
- const json = JSON.stringify(appState.data, null, 2);
3589
- const blob = new Blob([json], { type: "application/json" });
3590
- const url = URL.createObjectURL(blob);
3591
- const a = document.createElement("a");
3592
- a.href = url;
3593
- a.download = `${appState.data.root?.props?.title || "page"}.json`;
3594
- a.click();
3595
- URL.revokeObjectURL(url);
3810
+ exportDataAsJson(appState.data, {
3811
+ filenameBase: appState.data.root?.props?.title
3812
+ });
3596
3813
  },
3597
3814
  children: [
3598
3815
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileDown, { className: "h-4 w-4" }),
@@ -3604,21 +3821,79 @@ var Header = () => {
3604
3821
  ] }),
3605
3822
  /* @__PURE__ */ jsxRuntime.jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
3606
3823
  /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3607
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "ghost", size: "icon", onClick: toggleTheme, "aria-label": themeLabel, children: theme === "dark" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { className: "h-4 w-4" }) }) }),
3824
+ /* @__PURE__ */ jsxRuntime.jsx(
3825
+ TooltipTrigger,
3826
+ {
3827
+ render: /* @__PURE__ */ jsxRuntime.jsx(
3828
+ Button,
3829
+ {
3830
+ variant: "ghost",
3831
+ size: "icon",
3832
+ onClick: toggleTheme,
3833
+ "aria-label": themeLabel
3834
+ }
3835
+ ),
3836
+ children: theme === "dark" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sun, { className: "h-4 w-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Moon, { className: "h-4 w-4" })
3837
+ }
3838
+ ),
3608
3839
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: themeLabel })
3609
3840
  ] }),
3610
3841
  /* @__PURE__ */ jsxRuntime.jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
3611
3842
  /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
3612
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(Button, { size: "sm", "aria-label": publish, children: [
3613
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-4 w-4" }),
3614
- publish
3615
- ] }) }),
3843
+ /* @__PURE__ */ jsxRuntime.jsxs(
3844
+ TooltipTrigger,
3845
+ {
3846
+ render: /* @__PURE__ */ jsxRuntime.jsx(Button, { size: "sm", "aria-label": publish }),
3847
+ children: [
3848
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "h-4 w-4" }),
3849
+ publish
3850
+ ]
3851
+ }
3852
+ ),
3616
3853
  /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: publish })
3617
3854
  ] })
3618
3855
  ] })
3619
3856
  ] })
3620
3857
  ] }) });
3621
3858
  };
3859
+ function useGhostDrag({ createGhostEl }) {
3860
+ const ghostRef = React17__namespace.useRef(null);
3861
+ function moveGhost(x, y) {
3862
+ if (!ghostRef.current) return;
3863
+ ghostRef.current.style.left = `${x + 12}px`;
3864
+ ghostRef.current.style.top = `${y + 12}px`;
3865
+ }
3866
+ function removeGhost() {
3867
+ ghostRef.current?.remove();
3868
+ ghostRef.current = null;
3869
+ }
3870
+ const startDrag = React17__namespace.useCallback(
3871
+ (e, type, payload) => {
3872
+ e.stopPropagation();
3873
+ e.currentTarget.setPointerCapture(e.pointerId);
3874
+ ghostRef.current = createGhostEl(payload);
3875
+ moveGhost(e.clientX, e.clientY);
3876
+ dispatchLibraryDragStart(type);
3877
+ function onMove(ev) {
3878
+ moveGhost(ev.clientX, ev.clientY);
3879
+ }
3880
+ function onUp(ev) {
3881
+ removeGhost();
3882
+ window.removeEventListener("pointermove", onMove);
3883
+ window.removeEventListener("pointerup", onUp);
3884
+ if (type === "image") {
3885
+ dispatchImageDrop({ src: payload, clientX: ev.clientX, clientY: ev.clientY });
3886
+ } else {
3887
+ dispatchTextDrop({ text: payload, clientX: ev.clientX, clientY: ev.clientY });
3888
+ }
3889
+ }
3890
+ window.addEventListener("pointermove", onMove);
3891
+ window.addEventListener("pointerup", onUp);
3892
+ },
3893
+ [createGhostEl]
3894
+ );
3895
+ return { startDrag };
3896
+ }
3622
3897
  var DEFAULT_SEEDS = [
3623
3898
  "forest",
3624
3899
  "ocean",
@@ -3650,8 +3925,7 @@ function getSearchImages(query) {
3650
3925
  id: `${query}-${i}`
3651
3926
  }));
3652
3927
  }
3653
- var ghostEl = null;
3654
- function createGhost(src) {
3928
+ function createImageGhost(src) {
3655
3929
  const el = document.createElement("div");
3656
3930
  el.style.cssText = `
3657
3931
  position: fixed; top: -9999px; left: -9999px; z-index: 99999;
@@ -3665,63 +3939,31 @@ function createGhost(src) {
3665
3939
  document.body.appendChild(el);
3666
3940
  return el;
3667
3941
  }
3668
- function moveGhost(x, y) {
3669
- if (!ghostEl) return;
3670
- ghostEl.style.left = `${x + 12}px`;
3671
- ghostEl.style.top = `${y + 12}px`;
3672
- }
3673
- function removeGhost() {
3674
- ghostEl?.remove();
3675
- ghostEl = null;
3676
- }
3677
3942
  function ImageLibrary({
3678
3943
  seeds,
3679
3944
  items: customImages
3680
3945
  } = {}) {
3681
3946
  const effectiveSeeds = seeds ?? DEFAULT_SEEDS;
3682
- const [query, setQuery] = React18__namespace.useState("");
3683
- const [committed, setCommitted] = React18__namespace.useState("");
3684
- const [items, setItems] = React18__namespace.useState(
3947
+ const [query, setQuery] = React17__namespace.useState("");
3948
+ const [committed, setCommitted] = React17__namespace.useState("");
3949
+ const [items, setItems] = React17__namespace.useState(
3685
3950
  () => customImages ?? getDefaultImages(effectiveSeeds)
3686
3951
  );
3687
3952
  const libraryTitle = useMsg("image-library.title");
3688
3953
  const searchPlaceholder = useMsg("image-library.search.placeholder");
3689
- React18__namespace.useEffect(() => {
3954
+ const { startDrag } = useGhostDrag({
3955
+ createGhostEl: createImageGhost
3956
+ });
3957
+ React17__namespace.useEffect(() => {
3690
3958
  const t = setTimeout(() => setCommitted(query.trim()), 400);
3691
3959
  return () => clearTimeout(t);
3692
3960
  }, [query]);
3693
- React18__namespace.useEffect(() => {
3961
+ React17__namespace.useEffect(() => {
3694
3962
  if (customImages) return;
3695
3963
  setItems(
3696
3964
  committed ? getSearchImages(committed) : getDefaultImages(effectiveSeeds)
3697
3965
  );
3698
3966
  }, [committed, customImages, effectiveSeeds]);
3699
- function handlePointerDown(e, src) {
3700
- e.stopPropagation();
3701
- e.currentTarget.setPointerCapture(e.pointerId);
3702
- ghostEl = createGhost(src);
3703
- moveGhost(e.clientX, e.clientY);
3704
- window.dispatchEvent(
3705
- new CustomEvent("anvilkit:librarydragstart", {
3706
- detail: { type: "image" }
3707
- })
3708
- );
3709
- function onMove(ev) {
3710
- moveGhost(ev.clientX, ev.clientY);
3711
- }
3712
- function onUp(ev) {
3713
- removeGhost();
3714
- window.removeEventListener("pointermove", onMove);
3715
- window.removeEventListener("pointerup", onUp);
3716
- window.dispatchEvent(
3717
- new CustomEvent("anvilkit:imagedrop", {
3718
- detail: { src, clientX: ev.clientX, clientY: ev.clientY }
3719
- })
3720
- );
3721
- }
3722
- window.addEventListener("pointermove", onMove);
3723
- window.addEventListener("pointerup", onUp);
3724
- }
3725
3967
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [
3726
3968
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pt-3 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: libraryTitle }),
3727
3969
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
@@ -3736,10 +3978,10 @@ function ImageLibrary({
3736
3978
  }
3737
3979
  )
3738
3980
  ] }) }),
3739
- /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 grid grid-cols-2 gap-2", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs(
3981
+ /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 grid grid-cols-2 gap-2", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
3740
3982
  "div",
3741
3983
  {
3742
- onPointerDown: (e) => handlePointerDown(e, item.src),
3984
+ onPointerDown: (e) => startDrag(e, "image", item.src),
3743
3985
  className: "rounded-md overflow-hidden border border-border bg-muted/40 cursor-grab select-none hover:ring-2 hover:ring-primary/50 active:cursor-grabbing transition-all",
3744
3986
  children: [
3745
3987
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -3754,12 +3996,27 @@ function ImageLibrary({
3754
3996
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1.5 py-1 text-xs text-muted-foreground truncate capitalize", children: item.alt })
3755
3997
  ]
3756
3998
  },
3757
- `${item.src}-${i}`
3999
+ item.id
3758
4000
  )) }) })
3759
4001
  ] });
3760
4002
  }
3761
- var ghostEl2 = null;
3762
- function createGhost2(text) {
4003
+ var DEFAULT_SNIPPETS = [
4004
+ { category: "Headlines", label: "Bold statement", text: "The Future Starts Here" },
4005
+ { category: "Headlines", label: "Question hook", text: "Ready to Transform Your Business?" },
4006
+ { category: "Headlines", label: "Value prop", text: "Simple, Powerful, Built for Teams" },
4007
+ { category: "Headlines", label: "Action-led", text: "Ship Faster. Break Less. Sleep Better." },
4008
+ { category: "Subheadings", label: "Feature intro", text: "Everything you need, nothing you don't." },
4009
+ { category: "Subheadings", label: "Social proof", text: "Trusted by over 10,000 teams worldwide." },
4010
+ { category: "Subheadings", label: "CTA support", text: "Get started in minutes \u2014 no credit card required." },
4011
+ { category: "Body", label: "Product description", text: "Our platform helps teams collaborate in real time, ship products faster, and stay aligned across every stage of the process." },
4012
+ { category: "Body", label: "Feature benefit", text: "With built-in analytics and smart automation, you can focus on what matters most \u2014 building great products." },
4013
+ { category: "Body", label: "About us", text: "We're a small team on a big mission: to make software development feel effortless for everyone." },
4014
+ { category: "CTAs", label: "Primary", text: "Get Started Free" },
4015
+ { category: "CTAs", label: "Secondary", text: "Learn More" },
4016
+ { category: "CTAs", label: "Soft sell", text: "See How It Works" },
4017
+ { category: "CTAs", label: "Urgency", text: "Start Your Free Trial Today" }
4018
+ ];
4019
+ function createTextGhost(text) {
3763
4020
  const el = document.createElement("div");
3764
4021
  el.style.cssText = `
3765
4022
  position: fixed; top: -9999px; left: -9999px; z-index: 99999;
@@ -3772,112 +4029,16 @@ function createGhost2(text) {
3772
4029
  document.body.appendChild(el);
3773
4030
  return el;
3774
4031
  }
3775
- function moveGhost2(x, y) {
3776
- if (!ghostEl2) return;
3777
- ghostEl2.style.left = `${x + 12}px`;
3778
- ghostEl2.style.top = `${y + 12}px`;
3779
- }
3780
- function removeGhost2() {
3781
- ghostEl2?.remove();
3782
- ghostEl2 = null;
3783
- }
3784
- var DEFAULT_SNIPPETS = [
3785
- // Headlines
3786
- {
3787
- category: "Headlines",
3788
- label: "Bold statement",
3789
- text: "The Future Starts Here"
3790
- },
3791
- {
3792
- category: "Headlines",
3793
- label: "Question hook",
3794
- text: "Ready to Transform Your Business?"
3795
- },
3796
- {
3797
- category: "Headlines",
3798
- label: "Value prop",
3799
- text: "Simple, Powerful, Built for Teams"
3800
- },
3801
- {
3802
- category: "Headlines",
3803
- label: "Action-led",
3804
- text: "Ship Faster. Break Less. Sleep Better."
3805
- },
3806
- // Subheadings
3807
- {
3808
- category: "Subheadings",
3809
- label: "Feature intro",
3810
- text: "Everything you need, nothing you don't."
3811
- },
3812
- {
3813
- category: "Subheadings",
3814
- label: "Social proof",
3815
- text: "Trusted by over 10,000 teams worldwide."
3816
- },
3817
- {
3818
- category: "Subheadings",
3819
- label: "CTA support",
3820
- text: "Get started in minutes \u2014 no credit card required."
3821
- },
3822
- // Body
3823
- {
3824
- category: "Body",
3825
- label: "Product description",
3826
- text: "Our platform helps teams collaborate in real time, ship products faster, and stay aligned across every stage of the process."
3827
- },
3828
- {
3829
- category: "Body",
3830
- label: "Feature benefit",
3831
- text: "With built-in analytics and smart automation, you can focus on what matters most \u2014 building great products."
3832
- },
3833
- {
3834
- category: "Body",
3835
- label: "About us",
3836
- text: "We're a small team on a big mission: to make software development feel effortless for everyone."
3837
- },
3838
- // CTAs
3839
- { category: "CTAs", label: "Primary", text: "Get Started Free" },
3840
- { category: "CTAs", label: "Secondary", text: "Learn More" },
3841
- { category: "CTAs", label: "Soft sell", text: "See How It Works" },
3842
- { category: "CTAs", label: "Urgency", text: "Start Your Free Trial Today" }
3843
- ];
3844
- function CopyLibrary({
3845
- items
3846
- } = {}) {
4032
+ function CopyLibrary({ items } = {}) {
3847
4033
  const activeSnippets = items ?? DEFAULT_SNIPPETS;
3848
4034
  const categories = Array.from(new Set(activeSnippets.map((s) => s.category)));
3849
- const [query, setQuery] = React18__namespace.useState("");
4035
+ const [query, setQuery] = React17__namespace.useState("");
3850
4036
  const libraryTitle = useMsg("copy-library.title");
3851
4037
  const searchPlaceholder = useMsg("copy-library.search.placeholder");
4038
+ const { startDrag } = useGhostDrag({ createGhostEl: createTextGhost });
3852
4039
  const filtered = query.trim() ? activeSnippets.filter(
3853
4040
  (s) => s.text.toLowerCase().includes(query.toLowerCase()) || s.label.toLowerCase().includes(query.toLowerCase()) || s.category.toLowerCase().includes(query.toLowerCase())
3854
4041
  ) : activeSnippets;
3855
- function handlePointerDown(e, text) {
3856
- e.stopPropagation();
3857
- e.currentTarget.setPointerCapture(e.pointerId);
3858
- ghostEl2 = createGhost2(text);
3859
- moveGhost2(e.clientX, e.clientY);
3860
- window.dispatchEvent(
3861
- new CustomEvent("anvilkit:librarydragstart", {
3862
- detail: { type: "text" }
3863
- })
3864
- );
3865
- function onMove(ev) {
3866
- moveGhost2(ev.clientX, ev.clientY);
3867
- }
3868
- function onUp(ev) {
3869
- removeGhost2();
3870
- window.removeEventListener("pointermove", onMove);
3871
- window.removeEventListener("pointerup", onUp);
3872
- window.dispatchEvent(
3873
- new CustomEvent("anvilkit:textdrop", {
3874
- detail: { text, clientX: ev.clientX, clientY: ev.clientY }
3875
- })
3876
- );
3877
- }
3878
- window.addEventListener("pointermove", onMove);
3879
- window.addEventListener("pointerup", onUp);
3880
- }
3881
4042
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-full", children: [
3882
4043
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 pt-3 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: libraryTitle }),
3883
4044
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
@@ -3893,24 +4054,24 @@ function CopyLibrary({
3893
4054
  )
3894
4055
  ] }) }),
3895
4056
  /* @__PURE__ */ jsxRuntime.jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2 flex flex-col gap-4", children: (query.trim() ? [null] : categories).map((cat) => {
3896
- const items2 = cat ? filtered.filter((s) => s.category === cat) : filtered;
3897
- if (!items2.length) return null;
4057
+ const snippets = cat ? filtered.filter((s) => s.category === cat) : filtered;
4058
+ if (!snippets.length) return null;
3898
4059
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3899
4060
  cat && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-1 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-1", children: [
3900
4061
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Type, { className: "h-3 w-3" }),
3901
4062
  cat
3902
4063
  ] }),
3903
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: items2.map((snippet, i) => /* @__PURE__ */ jsxRuntime.jsxs(
4064
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: snippets.map((snippet) => /* @__PURE__ */ jsxRuntime.jsxs(
3904
4065
  "div",
3905
4066
  {
3906
- onPointerDown: (e) => handlePointerDown(e, snippet.text),
4067
+ onPointerDown: (e) => startDrag(e, "text", snippet.text),
3907
4068
  className: "rounded-md border border-border bg-muted/40 px-2.5 py-2 cursor-grab select-none hover:bg-muted hover:ring-1 hover:ring-primary/40 active:cursor-grabbing transition-all",
3908
4069
  children: [
3909
4070
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-foreground/70 mb-0.5", children: snippet.label }),
3910
4071
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-foreground leading-snug line-clamp-2", children: snippet.text })
3911
4072
  ]
3912
4073
  },
3913
- i
4074
+ `${snippet.category}-${snippet.label}`
3914
4075
  )) })
3915
4076
  ] }, cat ?? "results");
3916
4077
  }) }) })
@@ -3938,42 +4099,6 @@ var EditorLayout = ({
3938
4099
  ] })
3939
4100
  ] });
3940
4101
  };
3941
- function createEditorUiStore(storeId) {
3942
- return zustand.createStore()(
3943
- middleware.persist(
3944
- (set) => ({
3945
- drawerSearch: "",
3946
- setDrawerSearch: (q) => set({ drawerSearch: q }),
3947
- drawerCollapsed: {},
3948
- toggleDrawerGroup: (group) => set((s) => ({
3949
- drawerCollapsed: { ...s.drawerCollapsed, [group]: !s.drawerCollapsed[group] }
3950
- })),
3951
- activeTab: "insert",
3952
- setActiveTab: (tab) => set({ activeTab: tab }),
3953
- outlineExpanded: {},
3954
- toggleOutlineItem: (id) => set((s) => ({
3955
- outlineExpanded: { ...s.outlineExpanded, [id]: !s.outlineExpanded[id] }
3956
- })),
3957
- theme: "light",
3958
- toggleTheme: () => set((s) => {
3959
- const next = s.theme === "light" ? "dark" : "light";
3960
- document.documentElement.classList.toggle("dark", next === "dark");
3961
- return { theme: next };
3962
- })
3963
- }),
3964
- {
3965
- name: `anvilkit-ui-${storeId}`,
3966
- partialize: (s) => ({
3967
- activeTab: s.activeTab,
3968
- drawerCollapsed: s.drawerCollapsed,
3969
- outlineExpanded: s.outlineExpanded,
3970
- theme: s.theme
3971
- // drawerSearch intentionally excluded — transient input
3972
- })
3973
- }
3974
- )
3975
- );
3976
- }
3977
4102
  function createEditorI18nStore(initial) {
3978
4103
  return zustand.createStore()(
3979
4104
  middleware.persist(
@@ -4047,20 +4172,33 @@ function Studio({
4047
4172
  locale,
4048
4173
  messages
4049
4174
  }) {
4050
- const uiStore2 = React18__namespace.useRef(createEditorUiStore(storeId ?? "default")).current;
4051
- const i18nStore = React18__namespace.useRef(
4175
+ const uiStore2 = React17__namespace.useRef(createEditorUiStore(storeId ?? "default")).current;
4176
+ const i18nStore = React17__namespace.useRef(
4052
4177
  createEditorI18nStore({
4053
4178
  locale: locale ?? "zh",
4054
4179
  messages: messages ?? defaultMessages
4055
4180
  })
4056
4181
  ).current;
4057
- const aiPlugin = React18__namespace.useMemo(
4058
- () => pluginAi.createAiPlugin({ host: aiHost }),
4059
- [aiHost]
4060
- );
4061
- const mergedOverrides = React18__namespace.useMemo(
4062
- () => ({ ...aiPlugin.overrides, ...puckOverrides, ...overrideExtensions }),
4063
- [aiPlugin.overrides, overrideExtensions]
4182
+ React17__namespace.useEffect(() => {
4183
+ i18nStore.getState().setLocale(locale ?? "zh", messages ?? defaultMessages);
4184
+ }, [locale, messages, i18nStore]);
4185
+ const [aiPlugin, setAiPlugin] = React17__namespace.useState(null);
4186
+ React17__namespace.useEffect(() => {
4187
+ if (!aiHost) return;
4188
+ let cancelled = false;
4189
+ import('@puckeditor/plugin-ai').then(({ createAiPlugin }) => {
4190
+ if (cancelled) return;
4191
+ import('@puckeditor/plugin-ai/styles.css').catch(() => {
4192
+ });
4193
+ setAiPlugin(createAiPlugin({ host: aiHost }));
4194
+ });
4195
+ return () => {
4196
+ cancelled = true;
4197
+ };
4198
+ }, [aiHost]);
4199
+ const mergedOverrides = React17__namespace.useMemo(
4200
+ () => ({ ...aiPlugin?.overrides ?? {}, ...puckOverrides, ...overrideExtensions }),
4201
+ [aiPlugin, overrideExtensions]
4064
4202
  );
4065
4203
  return /* @__PURE__ */ jsxRuntime.jsx(EditorUiStoreProvider, { value: uiStore2, children: /* @__PURE__ */ jsxRuntime.jsx(EditorI18nStoreProvider, { value: i18nStore, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsx(
4066
4204
  core.Puck,
@@ -4070,11 +4208,11 @@ function Studio({
4070
4208
  onPublish,
4071
4209
  onChange,
4072
4210
  overrides: mergedOverrides,
4073
- plugins: [aiPlugin],
4211
+ plugins: aiPlugin ? [aiPlugin] : [],
4074
4212
  children: /* @__PURE__ */ jsxRuntime.jsx(
4075
4213
  EditorLayout,
4076
4214
  {
4077
- aiPanel: aiPlugin.render(),
4215
+ aiPanel: aiPlugin?.render(),
4078
4216
  images,
4079
4217
  copywritings
4080
4218
  }
@@ -4084,10 +4222,14 @@ function Studio({
4084
4222
  }
4085
4223
 
4086
4224
  // src/store/index.ts
4087
- var uiStore = createEditorUiStore("default");
4225
+ createEditorUiStore("default");
4088
4226
 
4227
+ exports.EditorI18nStoreProvider = EditorI18nStoreProvider;
4228
+ exports.EditorUiStoreProvider = EditorUiStoreProvider;
4089
4229
  exports.Studio = Studio;
4090
4230
  exports.createEditorI18nStore = createEditorI18nStore;
4091
4231
  exports.createEditorUiStore = createEditorUiStore;
4232
+ exports.defaultMessages = defaultMessages;
4092
4233
  exports.puckOverrides = puckOverrides;
4093
- exports.uiStore = uiStore;
4234
+ exports.useEditorI18nStoreApi = useEditorI18nStoreApi;
4235
+ exports.useEditorUiStoreApi = useEditorUiStoreApi;