@anvilkit/puck-studio 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -0
- package/dist/index.cjs +4093 -0
- package/dist/index.d.cts +151 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.js +4066 -0
- package/package.json +65 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,4066 @@
|
|
|
1
|
+
import { usePuck, useGetPuck, Puck, AutoField } from '@puckeditor/core';
|
|
2
|
+
import { ArrowLeft, Undo2, Redo2, Download, Search, Plus, Bold, Italic, Link, ChevronRightIcon, Info, Sparkles, ChevronDownIcon, CheckIcon, GripVertical, Copy, Trash2, SearchIcon, ChevronUpIcon, FileDown, Sun, Moon, Send, Layers2, Image, Type, Bot, Lock, Globe, Users, Link2, Check } from 'lucide-react';
|
|
3
|
+
import { Button as Button$1 } from '@base-ui/react/button';
|
|
4
|
+
import { cva } from 'class-variance-authority';
|
|
5
|
+
import { clsx } from 'clsx';
|
|
6
|
+
import { twMerge } from 'tailwind-merge';
|
|
7
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
+
import { Separator as Separator$1 } from '@base-ui/react/separator';
|
|
9
|
+
import { createStore, useStore } from 'zustand';
|
|
10
|
+
import * as React18 from 'react';
|
|
11
|
+
import React18__default, { useState, useRef, useMemo, useCallback, useEffect } from 'react';
|
|
12
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
13
|
+
import { Menu } from '@base-ui/react/menu';
|
|
14
|
+
import { ScrollArea as ScrollArea$1 } from '@base-ui/react/scroll-area';
|
|
15
|
+
import { Input as Input$1 } from '@base-ui/react/input';
|
|
16
|
+
import { mergeProps } from '@base-ui/react/merge-props';
|
|
17
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
18
|
+
import { Select as Select$1 } from '@base-ui/react/select';
|
|
19
|
+
import { useSensors, useSensor, PointerSensor, DndContext, closestCenter } from '@dnd-kit/core';
|
|
20
|
+
import { SortableContext, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
|
|
21
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
22
|
+
import { Popover as Popover$1 } from '@base-ui-components/react/popover';
|
|
23
|
+
import { motion, AnimatePresence, LayoutGroup, isMotionComponent } from 'motion/react';
|
|
24
|
+
import { Toggle as Toggle$1 } from '@base-ui/react/toggle';
|
|
25
|
+
import { Command as Command$1 } from 'cmdk';
|
|
26
|
+
import '@base-ui/react/dialog';
|
|
27
|
+
import { createAiPlugin } from '@puckeditor/plugin-ai';
|
|
28
|
+
import '@puckeditor/plugin-ai/styles.css';
|
|
29
|
+
import '@puckeditor/core/puck.css';
|
|
30
|
+
import { Tabs as Tabs$1 } from '@base-ui-components/react/tabs';
|
|
31
|
+
import * as motion9 from 'motion/react-client';
|
|
32
|
+
import { FloatingArrow, useFloating, autoUpdate, offset, flip, shift, arrow, FloatingPortal } from '@floating-ui/react';
|
|
33
|
+
import { Avatar as Avatar$1 } from '@base-ui/react/avatar';
|
|
34
|
+
import { persist } from 'zustand/middleware';
|
|
35
|
+
|
|
36
|
+
// src/components/overrides/layout/EditorHeader.tsx
|
|
37
|
+
function cn(...inputs) {
|
|
38
|
+
return twMerge(clsx(inputs));
|
|
39
|
+
}
|
|
40
|
+
var buttonVariants = cva(
|
|
41
|
+
"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",
|
|
42
|
+
{
|
|
43
|
+
variants: {
|
|
44
|
+
variant: {
|
|
45
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
46
|
+
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",
|
|
47
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
48
|
+
ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
49
|
+
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",
|
|
50
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
51
|
+
},
|
|
52
|
+
size: {
|
|
53
|
+
default: "h-8 gap-1.5 px-2.5",
|
|
54
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs [&_svg:not([class*='size-'])]:size-3",
|
|
55
|
+
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] [&_svg:not([class*='size-'])]:size-3.5",
|
|
56
|
+
lg: "h-9 gap-1.5 px-2.5",
|
|
57
|
+
icon: "size-8",
|
|
58
|
+
"icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] [&_svg:not([class*='size-'])]:size-3",
|
|
59
|
+
"icon-sm": "size-7 rounded-[min(var(--radius-md),12px)]",
|
|
60
|
+
"icon-lg": "size-9"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
defaultVariants: {
|
|
64
|
+
variant: "default",
|
|
65
|
+
size: "default"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
function Button({
|
|
70
|
+
className,
|
|
71
|
+
variant = "default",
|
|
72
|
+
size = "default",
|
|
73
|
+
...props
|
|
74
|
+
}) {
|
|
75
|
+
return /* @__PURE__ */ jsx(
|
|
76
|
+
Button$1,
|
|
77
|
+
{
|
|
78
|
+
"data-slot": "button",
|
|
79
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
80
|
+
...props
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
function Separator({
|
|
85
|
+
className,
|
|
86
|
+
orientation = "horizontal",
|
|
87
|
+
...props
|
|
88
|
+
}) {
|
|
89
|
+
return /* @__PURE__ */ jsx(
|
|
90
|
+
Separator$1,
|
|
91
|
+
{
|
|
92
|
+
"data-slot": "separator",
|
|
93
|
+
orientation,
|
|
94
|
+
className: cn(
|
|
95
|
+
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
|
|
96
|
+
className
|
|
97
|
+
),
|
|
98
|
+
...props
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
function getStrictContext(name) {
|
|
103
|
+
const Context = React18.createContext(void 0);
|
|
104
|
+
const Provider2 = ({
|
|
105
|
+
value,
|
|
106
|
+
children
|
|
107
|
+
}) => /* @__PURE__ */ jsx(Context.Provider, { value, children });
|
|
108
|
+
const useSafeContext = () => {
|
|
109
|
+
const ctx = React18.useContext(Context);
|
|
110
|
+
if (ctx === void 0) {
|
|
111
|
+
throw new Error(`useContext must be used within ${name ?? "a Provider"}`);
|
|
112
|
+
}
|
|
113
|
+
return ctx;
|
|
114
|
+
};
|
|
115
|
+
return [Provider2, useSafeContext];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/store/ui-context.ts
|
|
119
|
+
var [EditorUiStoreProvider, useEditorUiStoreApi] = getStrictContext("EditorUiStoreProvider");
|
|
120
|
+
|
|
121
|
+
// src/store/i18n-context.ts
|
|
122
|
+
var [EditorI18nStoreProvider, useEditorI18nStoreApi] = getStrictContext("EditorI18nStoreProvider");
|
|
123
|
+
|
|
124
|
+
// src/store/hooks.ts
|
|
125
|
+
function useActiveTab() {
|
|
126
|
+
return useStore(useEditorUiStoreApi(), (s) => s.activeTab);
|
|
127
|
+
}
|
|
128
|
+
function useSetActiveTab() {
|
|
129
|
+
return useStore(useEditorUiStoreApi(), (s) => s.setActiveTab);
|
|
130
|
+
}
|
|
131
|
+
function useDrawerSearch() {
|
|
132
|
+
return useStore(useEditorUiStoreApi(), (s) => s.drawerSearch);
|
|
133
|
+
}
|
|
134
|
+
function useSetDrawerSearch() {
|
|
135
|
+
return useStore(useEditorUiStoreApi(), (s) => s.setDrawerSearch);
|
|
136
|
+
}
|
|
137
|
+
function useTheme() {
|
|
138
|
+
return useStore(useEditorUiStoreApi(), (s) => s.theme);
|
|
139
|
+
}
|
|
140
|
+
function useToggleTheme() {
|
|
141
|
+
return useStore(useEditorUiStoreApi(), (s) => s.toggleTheme);
|
|
142
|
+
}
|
|
143
|
+
function useMsg(key) {
|
|
144
|
+
return useStore(useEditorI18nStoreApi(), (s) => s.messages[key] ?? key);
|
|
145
|
+
}
|
|
146
|
+
var TooltipProvider = TooltipPrimitive.Provider;
|
|
147
|
+
var Tooltip = TooltipPrimitive.Root;
|
|
148
|
+
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
149
|
+
var TooltipContent = React18.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
150
|
+
TooltipPrimitive.Content,
|
|
151
|
+
{
|
|
152
|
+
ref,
|
|
153
|
+
sideOffset,
|
|
154
|
+
className: cn(
|
|
155
|
+
"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]",
|
|
156
|
+
className
|
|
157
|
+
),
|
|
158
|
+
...props
|
|
159
|
+
}
|
|
160
|
+
) }));
|
|
161
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
162
|
+
function DropdownMenu({ ...props }) {
|
|
163
|
+
return /* @__PURE__ */ jsx(Menu.Root, { "data-slot": "dropdown-menu", ...props });
|
|
164
|
+
}
|
|
165
|
+
function DropdownMenuTrigger({ ...props }) {
|
|
166
|
+
return /* @__PURE__ */ jsx(Menu.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
|
|
167
|
+
}
|
|
168
|
+
function DropdownMenuContent({
|
|
169
|
+
align = "start",
|
|
170
|
+
alignOffset = 0,
|
|
171
|
+
side = "bottom",
|
|
172
|
+
sideOffset = 4,
|
|
173
|
+
className,
|
|
174
|
+
...props
|
|
175
|
+
}) {
|
|
176
|
+
return /* @__PURE__ */ jsx(Menu.Portal, { children: /* @__PURE__ */ jsx(
|
|
177
|
+
Menu.Positioner,
|
|
178
|
+
{
|
|
179
|
+
className: "isolate z-50 outline-none",
|
|
180
|
+
align,
|
|
181
|
+
alignOffset,
|
|
182
|
+
side,
|
|
183
|
+
sideOffset,
|
|
184
|
+
children: /* @__PURE__ */ jsx(
|
|
185
|
+
Menu.Popup,
|
|
186
|
+
{
|
|
187
|
+
"data-slot": "dropdown-menu-content",
|
|
188
|
+
className: cn(
|
|
189
|
+
"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",
|
|
190
|
+
className
|
|
191
|
+
),
|
|
192
|
+
...props
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
) });
|
|
197
|
+
}
|
|
198
|
+
function DropdownMenuItem({
|
|
199
|
+
className,
|
|
200
|
+
inset,
|
|
201
|
+
variant = "default",
|
|
202
|
+
...props
|
|
203
|
+
}) {
|
|
204
|
+
return /* @__PURE__ */ jsx(
|
|
205
|
+
Menu.Item,
|
|
206
|
+
{
|
|
207
|
+
"data-slot": "dropdown-menu-item",
|
|
208
|
+
"data-inset": inset,
|
|
209
|
+
"data-variant": variant,
|
|
210
|
+
className: cn(
|
|
211
|
+
"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",
|
|
212
|
+
className
|
|
213
|
+
),
|
|
214
|
+
...props
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
function EditorHeader({
|
|
219
|
+
actions,
|
|
220
|
+
children
|
|
221
|
+
}) {
|
|
222
|
+
const { history, appState } = usePuck();
|
|
223
|
+
const undo = useMsg("header.undo");
|
|
224
|
+
const undoTooltip = useMsg("header.undo.tooltip");
|
|
225
|
+
const redo = useMsg("header.redo");
|
|
226
|
+
const redoTooltip = useMsg("header.redo.tooltip");
|
|
227
|
+
const exportLabel = useMsg("header.export");
|
|
228
|
+
const exportJson = useMsg("header.export.json");
|
|
229
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs("header", { className: "flex h-12 items-center justify-between border-b bg-background px-4 gap-2", children: [
|
|
230
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }) }),
|
|
231
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: appState?.data?.root?.props?.title || "" }),
|
|
232
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
233
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
234
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
235
|
+
Button,
|
|
236
|
+
{
|
|
237
|
+
variant: "ghost",
|
|
238
|
+
size: "icon",
|
|
239
|
+
disabled: !history.hasPast,
|
|
240
|
+
onClick: () => history.back(),
|
|
241
|
+
"aria-label": undo,
|
|
242
|
+
children: /* @__PURE__ */ jsx(Undo2, { className: "h-4 w-4" })
|
|
243
|
+
}
|
|
244
|
+
) }),
|
|
245
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: undoTooltip })
|
|
246
|
+
] }),
|
|
247
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
248
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
249
|
+
Button,
|
|
250
|
+
{
|
|
251
|
+
variant: "ghost",
|
|
252
|
+
size: "icon",
|
|
253
|
+
disabled: !history.hasFuture,
|
|
254
|
+
onClick: () => history.forward(),
|
|
255
|
+
"aria-label": redo,
|
|
256
|
+
children: /* @__PURE__ */ jsx(Redo2, { className: "h-4 w-4" })
|
|
257
|
+
}
|
|
258
|
+
) }),
|
|
259
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: redoTooltip })
|
|
260
|
+
] }),
|
|
261
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
|
|
262
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
263
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
264
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ 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__ */ jsx(Download, { className: "h-4 w-4" }) }) }),
|
|
265
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: exportLabel })
|
|
266
|
+
] }),
|
|
267
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx(DropdownMenuItem, { children: exportJson }) })
|
|
268
|
+
] }),
|
|
269
|
+
actions
|
|
270
|
+
] })
|
|
271
|
+
] }) });
|
|
272
|
+
}
|
|
273
|
+
function EditorHeaderActions({
|
|
274
|
+
children
|
|
275
|
+
}) {
|
|
276
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children }) });
|
|
277
|
+
}
|
|
278
|
+
function ScrollArea({
|
|
279
|
+
className,
|
|
280
|
+
children,
|
|
281
|
+
...props
|
|
282
|
+
}) {
|
|
283
|
+
return /* @__PURE__ */ jsxs(
|
|
284
|
+
ScrollArea$1.Root,
|
|
285
|
+
{
|
|
286
|
+
"data-slot": "scroll-area",
|
|
287
|
+
className: cn("relative", className),
|
|
288
|
+
...props,
|
|
289
|
+
children: [
|
|
290
|
+
/* @__PURE__ */ jsx(
|
|
291
|
+
ScrollArea$1.Viewport,
|
|
292
|
+
{
|
|
293
|
+
"data-slot": "scroll-area-viewport",
|
|
294
|
+
className: "size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1",
|
|
295
|
+
children
|
|
296
|
+
}
|
|
297
|
+
),
|
|
298
|
+
/* @__PURE__ */ jsx(ScrollBar, {}),
|
|
299
|
+
/* @__PURE__ */ jsx(ScrollArea$1.Corner, {})
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
function ScrollBar({
|
|
305
|
+
className,
|
|
306
|
+
orientation = "vertical",
|
|
307
|
+
...props
|
|
308
|
+
}) {
|
|
309
|
+
return /* @__PURE__ */ jsx(
|
|
310
|
+
ScrollArea$1.Scrollbar,
|
|
311
|
+
{
|
|
312
|
+
"data-slot": "scroll-area-scrollbar",
|
|
313
|
+
"data-orientation": orientation,
|
|
314
|
+
orientation,
|
|
315
|
+
className: cn(
|
|
316
|
+
"flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent",
|
|
317
|
+
className
|
|
318
|
+
),
|
|
319
|
+
...props,
|
|
320
|
+
children: /* @__PURE__ */ jsx(
|
|
321
|
+
ScrollArea$1.Thumb,
|
|
322
|
+
{
|
|
323
|
+
"data-slot": "scroll-area-thumb",
|
|
324
|
+
className: "relative flex-1 rounded-full bg-border"
|
|
325
|
+
}
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
function Input({ className, type, ...props }) {
|
|
331
|
+
return /* @__PURE__ */ jsx(
|
|
332
|
+
Input$1,
|
|
333
|
+
{
|
|
334
|
+
type,
|
|
335
|
+
"data-slot": "input",
|
|
336
|
+
className: cn(
|
|
337
|
+
"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",
|
|
338
|
+
className
|
|
339
|
+
),
|
|
340
|
+
...props
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
function EditorDrawer({
|
|
345
|
+
children
|
|
346
|
+
}) {
|
|
347
|
+
const search = useDrawerSearch();
|
|
348
|
+
const setSearch = useSetDrawerSearch();
|
|
349
|
+
const drawerTitle = useMsg("drawer.title");
|
|
350
|
+
const searchPlaceholder = useMsg("drawer.search.placeholder");
|
|
351
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
352
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: drawerTitle }),
|
|
353
|
+
/* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
354
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
355
|
+
/* @__PURE__ */ jsx(
|
|
356
|
+
Input,
|
|
357
|
+
{
|
|
358
|
+
className: "pl-8",
|
|
359
|
+
placeholder: searchPlaceholder,
|
|
360
|
+
value: search,
|
|
361
|
+
onChange: (e) => setSearch(e.target.value)
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
] }) }),
|
|
365
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children })
|
|
366
|
+
] });
|
|
367
|
+
}
|
|
368
|
+
function EditorComponents({
|
|
369
|
+
children
|
|
370
|
+
}) {
|
|
371
|
+
return /* @__PURE__ */ jsxs("div", { "data-puck-components-grid": true, className: "p-2", children: [
|
|
372
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
373
|
+
[data-puck-components-grid] [data-puck-drawer] {
|
|
374
|
+
display: grid;
|
|
375
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
376
|
+
gap: 6px;
|
|
377
|
+
}
|
|
378
|
+
/* flatten item wrapper and draggable wrapper */
|
|
379
|
+
[data-puck-components-grid] [data-puck-drawer] > div,
|
|
380
|
+
[data-puck-components-grid] [data-puck-drawer] > div > div {
|
|
381
|
+
display: contents;
|
|
382
|
+
}
|
|
383
|
+
/* hide the ghost/bg copy */
|
|
384
|
+
[data-puck-components-grid] [data-puck-drawer] > div > div > div:first-child {
|
|
385
|
+
display: none;
|
|
386
|
+
}
|
|
387
|
+
/* flatten the real draggable wrapper */
|
|
388
|
+
[data-puck-components-grid] [data-puck-drawer] > div > div > div:last-child {
|
|
389
|
+
display: contents;
|
|
390
|
+
}
|
|
391
|
+
` }),
|
|
392
|
+
children
|
|
393
|
+
] });
|
|
394
|
+
}
|
|
395
|
+
function getPlaceholderUrl(name) {
|
|
396
|
+
return `https://picsum.photos/seed/${encodeURIComponent(name)}/120/80`;
|
|
397
|
+
}
|
|
398
|
+
function DrawerItem({
|
|
399
|
+
children,
|
|
400
|
+
name
|
|
401
|
+
}) {
|
|
402
|
+
const { appState } = usePuck();
|
|
403
|
+
const componentConfig = appState.config?.components?.[name];
|
|
404
|
+
const thumbnail = componentConfig?.metadata?.thumbnail;
|
|
405
|
+
const src = thumbnail ?? getPlaceholderUrl(name);
|
|
406
|
+
return /* @__PURE__ */ 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: [
|
|
407
|
+
/* @__PURE__ */ jsx("div", { className: "w-full h-16 bg-muted overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
408
|
+
"img",
|
|
409
|
+
{
|
|
410
|
+
src,
|
|
411
|
+
alt: name,
|
|
412
|
+
className: "w-full h-full object-cover",
|
|
413
|
+
onError: (e) => {
|
|
414
|
+
e.currentTarget.style.display = "none";
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
) }),
|
|
418
|
+
/* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs font-medium truncate", children: name ?? children })
|
|
419
|
+
] });
|
|
420
|
+
}
|
|
421
|
+
function EditorOutline({
|
|
422
|
+
children
|
|
423
|
+
}) {
|
|
424
|
+
const { selectedItem } = usePuck();
|
|
425
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
|
|
426
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-b", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Outline" }) }),
|
|
427
|
+
selectedItem && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
428
|
+
/* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 text-xs text-muted-foreground truncate", children: [
|
|
429
|
+
"Selected:",
|
|
430
|
+
" ",
|
|
431
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: selectedItem.type ?? "Component" })
|
|
432
|
+
] }),
|
|
433
|
+
/* @__PURE__ */ jsx(Separator, {})
|
|
434
|
+
] }),
|
|
435
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-2 text-sm", children }) })
|
|
436
|
+
] });
|
|
437
|
+
}
|
|
438
|
+
var CANVAS_CSS = `
|
|
439
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
440
|
+
:root {
|
|
441
|
+
--background: 0 0% 100%;
|
|
442
|
+
--foreground: 222.2 84% 4.9%;
|
|
443
|
+
--primary: 222.2 47.4% 11.2%;
|
|
444
|
+
--primary-foreground: 210 40% 98%;
|
|
445
|
+
--secondary: 210 40% 96.1%;
|
|
446
|
+
--muted: 210 40% 96.1%;
|
|
447
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
448
|
+
--border: 214.3 31.8% 91.4%;
|
|
449
|
+
--radius: 0.5rem;
|
|
450
|
+
}
|
|
451
|
+
.dark {
|
|
452
|
+
--background: 222.2 84% 4.9%;
|
|
453
|
+
--foreground: 210 40% 98%;
|
|
454
|
+
--primary: 210 40% 98%;
|
|
455
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
456
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
457
|
+
--muted: 217.2 32.6% 17.5%;
|
|
458
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
459
|
+
--border: 217.2 32.6% 17.5%;
|
|
460
|
+
}
|
|
461
|
+
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
462
|
+
`;
|
|
463
|
+
function isImageUrl(val) {
|
|
464
|
+
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/");
|
|
465
|
+
}
|
|
466
|
+
function replaceImageInProps(props, newSrc) {
|
|
467
|
+
const result = {};
|
|
468
|
+
for (const key of Object.keys(props)) {
|
|
469
|
+
const val = props[key];
|
|
470
|
+
if (typeof val === "string" && isImageUrl(val)) {
|
|
471
|
+
result[key] = newSrc;
|
|
472
|
+
} else if (Array.isArray(val)) {
|
|
473
|
+
result[key] = val.map(
|
|
474
|
+
(item) => item && typeof item === "object" ? replaceImageInProps(item, newSrc) : item
|
|
475
|
+
);
|
|
476
|
+
} else if (val && typeof val === "object") {
|
|
477
|
+
result[key] = replaceImageInProps(val, newSrc);
|
|
478
|
+
} else {
|
|
479
|
+
result[key] = val;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
function replaceTextInProps(props, newText, targetText) {
|
|
485
|
+
for (const key of Object.keys(props)) {
|
|
486
|
+
if (key === "id") continue;
|
|
487
|
+
const val = props[key];
|
|
488
|
+
if (typeof val === "string" && val === targetText && !isImageUrl(val)) {
|
|
489
|
+
return { result: { ...props, [key]: newText }, replaced: true };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
for (const key of Object.keys(props)) {
|
|
493
|
+
if (key === "id") continue;
|
|
494
|
+
const val = props[key];
|
|
495
|
+
if (typeof val === "string" && !isImageUrl(val) && val.length > 0) {
|
|
496
|
+
return { result: { ...props, [key]: newText }, replaced: true };
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return { result: props, replaced: false };
|
|
500
|
+
}
|
|
501
|
+
function CanvasIframe({
|
|
502
|
+
children,
|
|
503
|
+
document: iframeDoc
|
|
504
|
+
}) {
|
|
505
|
+
const getPuck = useGetPuck();
|
|
506
|
+
const theme = useTheme();
|
|
507
|
+
React18.useEffect(() => {
|
|
508
|
+
if (!iframeDoc) return;
|
|
509
|
+
const existing = iframeDoc.getElementById("__anvilkit_styles__");
|
|
510
|
+
if (existing) existing.remove();
|
|
511
|
+
const style = iframeDoc.createElement("style");
|
|
512
|
+
style.id = "__anvilkit_styles__";
|
|
513
|
+
style.textContent = CANVAS_CSS;
|
|
514
|
+
iframeDoc.head.appendChild(style);
|
|
515
|
+
}, [iframeDoc]);
|
|
516
|
+
React18.useEffect(() => {
|
|
517
|
+
if (!iframeDoc) return;
|
|
518
|
+
iframeDoc.documentElement.classList.toggle("dark", theme === "dark");
|
|
519
|
+
}, [iframeDoc, theme]);
|
|
520
|
+
React18.useEffect(() => {
|
|
521
|
+
if (!iframeDoc) return;
|
|
522
|
+
const iframeEl = iframeDoc.defaultView?.frameElement;
|
|
523
|
+
if (!iframeEl) return;
|
|
524
|
+
let highlightedEl = null;
|
|
525
|
+
function iframeCoords(clientX, clientY) {
|
|
526
|
+
const rect = iframeEl.getBoundingClientRect();
|
|
527
|
+
const x = clientX - rect.left;
|
|
528
|
+
const y = clientY - rect.top;
|
|
529
|
+
if (x < 0 || y < 0 || x > rect.width || y > rect.height) return null;
|
|
530
|
+
return { x, y };
|
|
531
|
+
}
|
|
532
|
+
function getComponentElAt(clientX, clientY) {
|
|
533
|
+
const coords = iframeCoords(clientX, clientY);
|
|
534
|
+
if (!coords) return null;
|
|
535
|
+
const el = iframeDoc.elementFromPoint(coords.x, coords.y);
|
|
536
|
+
if (!el) return null;
|
|
537
|
+
const comp = el.closest("[data-puck-component]");
|
|
538
|
+
return comp;
|
|
539
|
+
}
|
|
540
|
+
function getImgInComponent(compEl, clientX, clientY) {
|
|
541
|
+
const imgs = Array.from(compEl.querySelectorAll("img"));
|
|
542
|
+
if (!imgs.length) return null;
|
|
543
|
+
if (imgs.length === 1) return imgs[0];
|
|
544
|
+
const rect = iframeEl.getBoundingClientRect();
|
|
545
|
+
const x = clientX - rect.left;
|
|
546
|
+
const y = clientY - rect.top;
|
|
547
|
+
let closest = null;
|
|
548
|
+
let minDist = Infinity;
|
|
549
|
+
for (const img of imgs) {
|
|
550
|
+
const r = img.getBoundingClientRect();
|
|
551
|
+
const cx = r.left + r.width / 2;
|
|
552
|
+
const cy = r.top + r.height / 2;
|
|
553
|
+
const dist = Math.hypot(cx - x, cy - y);
|
|
554
|
+
if (dist < minDist) {
|
|
555
|
+
minDist = dist;
|
|
556
|
+
closest = img;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return closest;
|
|
560
|
+
}
|
|
561
|
+
const TEXT_TAGS = /* @__PURE__ */ new Set(["P", "H1", "H2", "H3", "H4", "H5", "H6", "SPAN", "A", "LI", "BUTTON", "LABEL"]);
|
|
562
|
+
function getTextElInComponent(compEl, clientX, clientY) {
|
|
563
|
+
const coords = iframeCoords(clientX, clientY);
|
|
564
|
+
if (!coords) return null;
|
|
565
|
+
const el = iframeDoc.elementFromPoint(coords.x, coords.y);
|
|
566
|
+
if (el && compEl.contains(el)) {
|
|
567
|
+
let cur = el;
|
|
568
|
+
while (cur && cur !== iframeDoc.body) {
|
|
569
|
+
if (TEXT_TAGS.has(cur.tagName) && cur.textContent?.trim()) return cur;
|
|
570
|
+
cur = cur.parentElement;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
for (const tag of TEXT_TAGS) {
|
|
574
|
+
const found = compEl.querySelector(tag.toLowerCase());
|
|
575
|
+
if (found?.textContent?.trim()) return found;
|
|
576
|
+
}
|
|
577
|
+
return null;
|
|
578
|
+
}
|
|
579
|
+
function setHighlight(el, color) {
|
|
580
|
+
if (highlightedEl && highlightedEl !== el) {
|
|
581
|
+
highlightedEl.style.outline = "";
|
|
582
|
+
highlightedEl.style.outlineOffset = "";
|
|
583
|
+
}
|
|
584
|
+
if (el) {
|
|
585
|
+
el.style.outline = `2px solid ${color}`;
|
|
586
|
+
el.style.outlineOffset = "2px";
|
|
587
|
+
}
|
|
588
|
+
highlightedEl = el;
|
|
589
|
+
}
|
|
590
|
+
function clearHighlight() {
|
|
591
|
+
setHighlight(null, "");
|
|
592
|
+
}
|
|
593
|
+
let activeLibrary = null;
|
|
594
|
+
function onLibraryDragStart(e) {
|
|
595
|
+
activeLibrary = e.detail.type;
|
|
596
|
+
}
|
|
597
|
+
function onPointerMove(e) {
|
|
598
|
+
if (!activeLibrary) return;
|
|
599
|
+
const compEl = getComponentElAt(e.clientX, e.clientY);
|
|
600
|
+
if (!compEl) {
|
|
601
|
+
clearHighlight();
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (activeLibrary === "image") {
|
|
605
|
+
const img = getImgInComponent(compEl, e.clientX, e.clientY);
|
|
606
|
+
setHighlight(img, "#6366f1");
|
|
607
|
+
} else {
|
|
608
|
+
const textEl = getTextElInComponent(compEl, e.clientX, e.clientY);
|
|
609
|
+
setHighlight(textEl, "#f59e0b");
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function onPointerUp() {
|
|
613
|
+
activeLibrary = null;
|
|
614
|
+
clearHighlight();
|
|
615
|
+
}
|
|
616
|
+
function dispatchReplace(componentId, updatedProps) {
|
|
617
|
+
const { dispatch, getItemById, getSelectorForId } = getPuck();
|
|
618
|
+
const item = getItemById(componentId);
|
|
619
|
+
const selector = getSelectorForId(componentId);
|
|
620
|
+
if (!item || !selector) return false;
|
|
621
|
+
dispatch({
|
|
622
|
+
type: "replace",
|
|
623
|
+
destinationIndex: selector.index,
|
|
624
|
+
destinationZone: selector.zone,
|
|
625
|
+
data: { ...item, props: { ...item.props, ...updatedProps } }
|
|
626
|
+
});
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
function onImageDrop(e) {
|
|
630
|
+
const { src, clientX, clientY } = e.detail;
|
|
631
|
+
clearHighlight();
|
|
632
|
+
activeLibrary = null;
|
|
633
|
+
if (!src) return;
|
|
634
|
+
const compEl = getComponentElAt(clientX, clientY);
|
|
635
|
+
if (!compEl) return;
|
|
636
|
+
const componentId = compEl.getAttribute("data-puck-component");
|
|
637
|
+
const { getItemById } = getPuck();
|
|
638
|
+
const item = getItemById(componentId);
|
|
639
|
+
if (!item) return;
|
|
640
|
+
const updatedProps = replaceImageInProps(item.props, src);
|
|
641
|
+
dispatchReplace(componentId, updatedProps);
|
|
642
|
+
}
|
|
643
|
+
function onTextDrop(e) {
|
|
644
|
+
const { text, clientX, clientY } = e.detail;
|
|
645
|
+
clearHighlight();
|
|
646
|
+
activeLibrary = null;
|
|
647
|
+
if (!text) return;
|
|
648
|
+
const compEl = getComponentElAt(clientX, clientY);
|
|
649
|
+
if (!compEl) return;
|
|
650
|
+
const componentId = compEl.getAttribute("data-puck-component");
|
|
651
|
+
const textEl = getTextElInComponent(compEl, clientX, clientY);
|
|
652
|
+
const targetText = textEl?.textContent?.trim() ?? "";
|
|
653
|
+
const { getItemById } = getPuck();
|
|
654
|
+
const item = getItemById(componentId);
|
|
655
|
+
if (!item) return;
|
|
656
|
+
const { result: updatedProps, replaced } = replaceTextInProps(
|
|
657
|
+
item.props,
|
|
658
|
+
text,
|
|
659
|
+
targetText
|
|
660
|
+
);
|
|
661
|
+
if (replaced) dispatchReplace(componentId, updatedProps);
|
|
662
|
+
}
|
|
663
|
+
window.addEventListener("anvilkit:librarydragstart", onLibraryDragStart);
|
|
664
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
665
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
666
|
+
window.addEventListener("anvilkit:imagedrop", onImageDrop);
|
|
667
|
+
window.addEventListener("anvilkit:textdrop", onTextDrop);
|
|
668
|
+
return () => {
|
|
669
|
+
window.removeEventListener("anvilkit:librarydragstart", onLibraryDragStart);
|
|
670
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
671
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
672
|
+
window.removeEventListener("anvilkit:imagedrop", onImageDrop);
|
|
673
|
+
window.removeEventListener("anvilkit:textdrop", onTextDrop);
|
|
674
|
+
};
|
|
675
|
+
}, [iframeDoc, getPuck]);
|
|
676
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
677
|
+
}
|
|
678
|
+
function CanvasPreview({
|
|
679
|
+
children
|
|
680
|
+
}) {
|
|
681
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full h-full px-3 py-2 text-sm font-medium text-foreground", children });
|
|
682
|
+
}
|
|
683
|
+
function ComponentOverlay({
|
|
684
|
+
children,
|
|
685
|
+
hover,
|
|
686
|
+
isSelected
|
|
687
|
+
}) {
|
|
688
|
+
return /* @__PURE__ */ jsx(
|
|
689
|
+
"div",
|
|
690
|
+
{
|
|
691
|
+
className: [
|
|
692
|
+
"absolute inset-0 rounded-sm pointer-events-none z-10 transition-colors",
|
|
693
|
+
isSelected ? "border-2 border-primary/80" : hover ? "border-2 border-primary/40" : ""
|
|
694
|
+
].filter(Boolean).join(" "),
|
|
695
|
+
children
|
|
696
|
+
}
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
function ActionBar({
|
|
700
|
+
children,
|
|
701
|
+
label,
|
|
702
|
+
parentAction
|
|
703
|
+
}) {
|
|
704
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 rounded-md border bg-background shadow-md px-1 py-0.5", children: [
|
|
705
|
+
label && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
706
|
+
/* @__PURE__ */ jsx("span", { className: "px-2 text-xs font-medium text-muted-foreground truncate max-w-[120px]", children: label }),
|
|
707
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5" })
|
|
708
|
+
] }),
|
|
709
|
+
parentAction && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
710
|
+
parentAction,
|
|
711
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5" })
|
|
712
|
+
] }),
|
|
713
|
+
children
|
|
714
|
+
] }) });
|
|
715
|
+
}
|
|
716
|
+
function cn2(...inputs) {
|
|
717
|
+
return twMerge(clsx(inputs));
|
|
718
|
+
}
|
|
719
|
+
function Label({ className, ...props }) {
|
|
720
|
+
return /* @__PURE__ */ jsx(
|
|
721
|
+
"label",
|
|
722
|
+
{
|
|
723
|
+
"data-slot": "label",
|
|
724
|
+
className: cn2(
|
|
725
|
+
"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",
|
|
726
|
+
className
|
|
727
|
+
),
|
|
728
|
+
...props
|
|
729
|
+
}
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
function Breadcrumb({ className, ...props }) {
|
|
733
|
+
return /* @__PURE__ */ jsx(
|
|
734
|
+
"nav",
|
|
735
|
+
{
|
|
736
|
+
"aria-label": "breadcrumb",
|
|
737
|
+
"data-slot": "breadcrumb",
|
|
738
|
+
className: cn2(className),
|
|
739
|
+
...props
|
|
740
|
+
}
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
function BreadcrumbList({ className, ...props }) {
|
|
744
|
+
return /* @__PURE__ */ jsx(
|
|
745
|
+
"ol",
|
|
746
|
+
{
|
|
747
|
+
"data-slot": "breadcrumb-list",
|
|
748
|
+
className: cn2(
|
|
749
|
+
"text-muted-foreground gap-1.5 text-sm flex flex-wrap items-center wrap-break-word",
|
|
750
|
+
className
|
|
751
|
+
),
|
|
752
|
+
...props
|
|
753
|
+
}
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
function BreadcrumbItem({ className, ...props }) {
|
|
757
|
+
return /* @__PURE__ */ jsx(
|
|
758
|
+
"li",
|
|
759
|
+
{
|
|
760
|
+
"data-slot": "breadcrumb-item",
|
|
761
|
+
className: cn2("gap-1 inline-flex items-center", className),
|
|
762
|
+
...props
|
|
763
|
+
}
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
function BreadcrumbLink({
|
|
767
|
+
className,
|
|
768
|
+
render,
|
|
769
|
+
...props
|
|
770
|
+
}) {
|
|
771
|
+
return useRender({
|
|
772
|
+
defaultTagName: "a",
|
|
773
|
+
props: mergeProps(
|
|
774
|
+
{
|
|
775
|
+
className: cn2("hover:text-foreground transition-colors", className)
|
|
776
|
+
},
|
|
777
|
+
props
|
|
778
|
+
),
|
|
779
|
+
render,
|
|
780
|
+
state: {
|
|
781
|
+
slot: "breadcrumb-link"
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
function BreadcrumbPage({ className, ...props }) {
|
|
786
|
+
return /* @__PURE__ */ jsx(
|
|
787
|
+
"span",
|
|
788
|
+
{
|
|
789
|
+
"data-slot": "breadcrumb-page",
|
|
790
|
+
role: "link",
|
|
791
|
+
"aria-disabled": "true",
|
|
792
|
+
"aria-current": "page",
|
|
793
|
+
className: cn2("text-foreground font-normal", className),
|
|
794
|
+
...props
|
|
795
|
+
}
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
function BreadcrumbSeparator({
|
|
799
|
+
children,
|
|
800
|
+
className,
|
|
801
|
+
...props
|
|
802
|
+
}) {
|
|
803
|
+
return /* @__PURE__ */ jsx(
|
|
804
|
+
"li",
|
|
805
|
+
{
|
|
806
|
+
"data-slot": "breadcrumb-separator",
|
|
807
|
+
role: "presentation",
|
|
808
|
+
"aria-hidden": "true",
|
|
809
|
+
className: cn2("[&>svg]:size-3.5", className),
|
|
810
|
+
...props,
|
|
811
|
+
children: children ?? /* @__PURE__ */ jsx(ChevronRightIcon, { className: "cn-rtl-flip" })
|
|
812
|
+
}
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
function useBreadcrumbs() {
|
|
816
|
+
const { appState, dispatch, selectedItem, getParentById, getSelectorForId } = usePuck();
|
|
817
|
+
const { itemSelector } = appState.ui;
|
|
818
|
+
const selectRoot = () => dispatch({ type: "setUi", ui: { itemSelector: null } });
|
|
819
|
+
if (!itemSelector || !selectedItem) {
|
|
820
|
+
return [{ label: "Page" }];
|
|
821
|
+
}
|
|
822
|
+
const selectedType = selectedItem.type ?? "Component";
|
|
823
|
+
const parent = getParentById(selectedItem.props?.id ?? "");
|
|
824
|
+
if (!parent) {
|
|
825
|
+
return [{ label: "Page", onSelect: selectRoot }, { label: selectedType }];
|
|
826
|
+
}
|
|
827
|
+
parent.type ?? "Component";
|
|
828
|
+
let parentSelector = void 0;
|
|
829
|
+
try {
|
|
830
|
+
parentSelector = getSelectorForId(parent.props?.id ?? "");
|
|
831
|
+
} catch {
|
|
832
|
+
parentSelector = void 0;
|
|
833
|
+
}
|
|
834
|
+
return [{ label: "Page", onSelect: selectRoot }, { label: selectedType }];
|
|
835
|
+
}
|
|
836
|
+
function FieldWrapper({
|
|
837
|
+
children
|
|
838
|
+
}) {
|
|
839
|
+
const crumbs = useBreadcrumbs();
|
|
840
|
+
return /* @__PURE__ */ jsx(ScrollArea, { className: "h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0", children: [
|
|
841
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-b", children: /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsx(BreadcrumbList, { children: crumbs.map((crumb, i) => {
|
|
842
|
+
const isLast = i === crumbs.length - 1;
|
|
843
|
+
return /* @__PURE__ */ jsxs(React18.Fragment, { children: [
|
|
844
|
+
i > 0 && /* @__PURE__ */ jsx(BreadcrumbSeparator, {}),
|
|
845
|
+
/* @__PURE__ */ jsx(BreadcrumbItem, { children: isLast ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: crumb.label }) : /* @__PURE__ */ jsx(
|
|
846
|
+
BreadcrumbLink,
|
|
847
|
+
{
|
|
848
|
+
className: "cursor-pointer",
|
|
849
|
+
onClick: crumb.onSelect,
|
|
850
|
+
children: crumb.label
|
|
851
|
+
}
|
|
852
|
+
) })
|
|
853
|
+
] }, i);
|
|
854
|
+
}) }) }) }),
|
|
855
|
+
children
|
|
856
|
+
] }) });
|
|
857
|
+
}
|
|
858
|
+
function FieldLabel({
|
|
859
|
+
children,
|
|
860
|
+
label,
|
|
861
|
+
labelIcon,
|
|
862
|
+
el,
|
|
863
|
+
type: _type,
|
|
864
|
+
readOnly,
|
|
865
|
+
className
|
|
866
|
+
}) {
|
|
867
|
+
console.log("Lable type", labelIcon);
|
|
868
|
+
const El = el ?? "div";
|
|
869
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(El, { className: `flex flex-col gap-1.5 ${className ?? ""}`, children: [
|
|
870
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
871
|
+
labelIcon && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: labelIcon }),
|
|
872
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
873
|
+
label && /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
874
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Info, { className: "h-3 w-3 text-muted-foreground/60 cursor-help" }) }),
|
|
875
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "right", children: label })
|
|
876
|
+
] }),
|
|
877
|
+
readOnly && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-muted-foreground/50", children: "Read only" })
|
|
878
|
+
] }),
|
|
879
|
+
children
|
|
880
|
+
] }) });
|
|
881
|
+
}
|
|
882
|
+
var MOCK_VALUES = {
|
|
883
|
+
default: ["AI-generated content", "Smart suggestion", "Generated text"]
|
|
884
|
+
};
|
|
885
|
+
function getMock(instructions) {
|
|
886
|
+
if (instructions?.toLowerCase().includes("caps")) {
|
|
887
|
+
return "AI GENERATED TITLE";
|
|
888
|
+
}
|
|
889
|
+
const pool = MOCK_VALUES.default;
|
|
890
|
+
return pool[Math.floor(Math.random() * pool.length)];
|
|
891
|
+
}
|
|
892
|
+
function AiButton({ ai, onGenerate }) {
|
|
893
|
+
const [loading, setLoading] = React18.useState(false);
|
|
894
|
+
const handleClick = () => {
|
|
895
|
+
setLoading(true);
|
|
896
|
+
setTimeout(() => {
|
|
897
|
+
onGenerate(getMock(ai.instructions));
|
|
898
|
+
setLoading(false);
|
|
899
|
+
}, 600);
|
|
900
|
+
};
|
|
901
|
+
return /* @__PURE__ */ jsx(
|
|
902
|
+
Button,
|
|
903
|
+
{
|
|
904
|
+
type: "button",
|
|
905
|
+
variant: "outline",
|
|
906
|
+
size: "icon",
|
|
907
|
+
className: "h-8 w-8 shrink-0 text-muted-foreground hover:text-primary",
|
|
908
|
+
onClick: handleClick,
|
|
909
|
+
disabled: loading,
|
|
910
|
+
"aria-label": "Generate with AI",
|
|
911
|
+
children: /* @__PURE__ */ jsx(Sparkles, { className: `h-3.5 w-3.5 ${loading ? "animate-pulse" : ""}` })
|
|
912
|
+
}
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
function TextField({
|
|
916
|
+
field,
|
|
917
|
+
value,
|
|
918
|
+
onChange,
|
|
919
|
+
readOnly,
|
|
920
|
+
placeholder,
|
|
921
|
+
label,
|
|
922
|
+
labelIcon
|
|
923
|
+
}) {
|
|
924
|
+
const [local, setLocal] = React18.useState(value ?? "");
|
|
925
|
+
React18.useEffect(() => {
|
|
926
|
+
setLocal(value ?? "");
|
|
927
|
+
}, [value]);
|
|
928
|
+
React18.useEffect(() => {
|
|
929
|
+
const timer = setTimeout(() => {
|
|
930
|
+
if (local !== value) onChange(local);
|
|
931
|
+
}, 200);
|
|
932
|
+
return () => clearTimeout(timer);
|
|
933
|
+
}, [local]);
|
|
934
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", labelIcon, readOnly, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
935
|
+
/* @__PURE__ */ jsx(
|
|
936
|
+
Input,
|
|
937
|
+
{
|
|
938
|
+
value: local,
|
|
939
|
+
onChange: (e) => setLocal(e.target.value),
|
|
940
|
+
readOnly,
|
|
941
|
+
placeholder,
|
|
942
|
+
className: "h-8 text-sm flex-1"
|
|
943
|
+
}
|
|
944
|
+
),
|
|
945
|
+
field?.ai && /* @__PURE__ */ jsx(AiButton, { ai: field.ai, onGenerate: (v) => {
|
|
946
|
+
setLocal(v);
|
|
947
|
+
onChange(v);
|
|
948
|
+
} })
|
|
949
|
+
] }) });
|
|
950
|
+
}
|
|
951
|
+
function Textarea({ className, ...props }) {
|
|
952
|
+
return /* @__PURE__ */ jsx(
|
|
953
|
+
"textarea",
|
|
954
|
+
{
|
|
955
|
+
"data-slot": "textarea",
|
|
956
|
+
className: cn(
|
|
957
|
+
"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",
|
|
958
|
+
className
|
|
959
|
+
),
|
|
960
|
+
...props
|
|
961
|
+
}
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
function TextareaField({ value, onChange, readOnly, placeholder, label }) {
|
|
965
|
+
const [local, setLocal] = React18.useState(value ?? "");
|
|
966
|
+
React18.useEffect(() => {
|
|
967
|
+
setLocal(value ?? "");
|
|
968
|
+
}, [value]);
|
|
969
|
+
React18.useEffect(() => {
|
|
970
|
+
const timer = setTimeout(() => {
|
|
971
|
+
if (local !== value) onChange(local);
|
|
972
|
+
}, 200);
|
|
973
|
+
return () => clearTimeout(timer);
|
|
974
|
+
}, [local]);
|
|
975
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsx(
|
|
976
|
+
Textarea,
|
|
977
|
+
{
|
|
978
|
+
value: local,
|
|
979
|
+
onChange: (e) => setLocal(e.target.value),
|
|
980
|
+
readOnly,
|
|
981
|
+
placeholder,
|
|
982
|
+
className: "min-h-[80px] text-sm resize-y"
|
|
983
|
+
}
|
|
984
|
+
) });
|
|
985
|
+
}
|
|
986
|
+
function NumberField({ value, onChange, readOnly, min, max, step, label }) {
|
|
987
|
+
const [local, setLocal] = React18.useState(String(value ?? ""));
|
|
988
|
+
React18.useEffect(() => {
|
|
989
|
+
setLocal(String(value ?? ""));
|
|
990
|
+
}, [value]);
|
|
991
|
+
React18.useEffect(() => {
|
|
992
|
+
const parsed = parseFloat(local);
|
|
993
|
+
if (!isNaN(parsed) && parsed !== value) {
|
|
994
|
+
const timer = setTimeout(() => onChange(parsed), 200);
|
|
995
|
+
return () => clearTimeout(timer);
|
|
996
|
+
}
|
|
997
|
+
}, [local]);
|
|
998
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsx(
|
|
999
|
+
Input,
|
|
1000
|
+
{
|
|
1001
|
+
type: "number",
|
|
1002
|
+
value: local,
|
|
1003
|
+
onChange: (e) => setLocal(e.target.value),
|
|
1004
|
+
readOnly,
|
|
1005
|
+
min,
|
|
1006
|
+
max,
|
|
1007
|
+
step,
|
|
1008
|
+
className: "h-8 text-sm"
|
|
1009
|
+
}
|
|
1010
|
+
) });
|
|
1011
|
+
}
|
|
1012
|
+
var Select = Select$1.Root;
|
|
1013
|
+
function SelectGroup({ className, ...props }) {
|
|
1014
|
+
return /* @__PURE__ */ jsx(
|
|
1015
|
+
Select$1.Group,
|
|
1016
|
+
{
|
|
1017
|
+
"data-slot": "select-group",
|
|
1018
|
+
className: cn("scroll-my-1 p-1", className),
|
|
1019
|
+
...props
|
|
1020
|
+
}
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
function SelectValue({ className, ...props }) {
|
|
1024
|
+
return /* @__PURE__ */ jsx(
|
|
1025
|
+
Select$1.Value,
|
|
1026
|
+
{
|
|
1027
|
+
"data-slot": "select-value",
|
|
1028
|
+
className: cn("flex flex-1 text-left", className),
|
|
1029
|
+
...props
|
|
1030
|
+
}
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
function SelectTrigger({
|
|
1034
|
+
className,
|
|
1035
|
+
size = "default",
|
|
1036
|
+
children,
|
|
1037
|
+
...props
|
|
1038
|
+
}) {
|
|
1039
|
+
return /* @__PURE__ */ jsxs(
|
|
1040
|
+
Select$1.Trigger,
|
|
1041
|
+
{
|
|
1042
|
+
"data-slot": "select-trigger",
|
|
1043
|
+
"data-size": size,
|
|
1044
|
+
className: cn(
|
|
1045
|
+
"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",
|
|
1046
|
+
className
|
|
1047
|
+
),
|
|
1048
|
+
...props,
|
|
1049
|
+
children: [
|
|
1050
|
+
children,
|
|
1051
|
+
/* @__PURE__ */ jsx(
|
|
1052
|
+
Select$1.Icon,
|
|
1053
|
+
{
|
|
1054
|
+
render: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "text-muted-foreground size-4 pointer-events-none" })
|
|
1055
|
+
}
|
|
1056
|
+
)
|
|
1057
|
+
]
|
|
1058
|
+
}
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
function SelectContent({
|
|
1062
|
+
className,
|
|
1063
|
+
children,
|
|
1064
|
+
side = "bottom",
|
|
1065
|
+
sideOffset = 4,
|
|
1066
|
+
align = "center",
|
|
1067
|
+
alignOffset = 0,
|
|
1068
|
+
alignItemWithTrigger = true,
|
|
1069
|
+
...props
|
|
1070
|
+
}) {
|
|
1071
|
+
return /* @__PURE__ */ jsx(Select$1.Portal, { children: /* @__PURE__ */ jsx(
|
|
1072
|
+
Select$1.Positioner,
|
|
1073
|
+
{
|
|
1074
|
+
side,
|
|
1075
|
+
sideOffset,
|
|
1076
|
+
align,
|
|
1077
|
+
alignOffset,
|
|
1078
|
+
alignItemWithTrigger,
|
|
1079
|
+
className: "isolate z-50",
|
|
1080
|
+
children: /* @__PURE__ */ jsxs(
|
|
1081
|
+
Select$1.Popup,
|
|
1082
|
+
{
|
|
1083
|
+
"data-slot": "select-content",
|
|
1084
|
+
"data-align-trigger": alignItemWithTrigger,
|
|
1085
|
+
className: cn(
|
|
1086
|
+
"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",
|
|
1087
|
+
className
|
|
1088
|
+
),
|
|
1089
|
+
...props,
|
|
1090
|
+
children: [
|
|
1091
|
+
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
1092
|
+
/* @__PURE__ */ jsx(Select$1.List, { children }),
|
|
1093
|
+
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
1094
|
+
]
|
|
1095
|
+
}
|
|
1096
|
+
)
|
|
1097
|
+
}
|
|
1098
|
+
) });
|
|
1099
|
+
}
|
|
1100
|
+
function SelectItem({
|
|
1101
|
+
className,
|
|
1102
|
+
children,
|
|
1103
|
+
...props
|
|
1104
|
+
}) {
|
|
1105
|
+
return /* @__PURE__ */ jsxs(
|
|
1106
|
+
Select$1.Item,
|
|
1107
|
+
{
|
|
1108
|
+
"data-slot": "select-item",
|
|
1109
|
+
className: cn(
|
|
1110
|
+
"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",
|
|
1111
|
+
className
|
|
1112
|
+
),
|
|
1113
|
+
...props,
|
|
1114
|
+
children: [
|
|
1115
|
+
/* @__PURE__ */ jsx(Select$1.ItemText, { className: "flex flex-1 gap-2 shrink-0 whitespace-nowrap", children }),
|
|
1116
|
+
/* @__PURE__ */ jsx(
|
|
1117
|
+
Select$1.ItemIndicator,
|
|
1118
|
+
{
|
|
1119
|
+
render: /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center", children: /* @__PURE__ */ jsx(CheckIcon, { className: "pointer-events-none" }) })
|
|
1120
|
+
}
|
|
1121
|
+
)
|
|
1122
|
+
]
|
|
1123
|
+
}
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
function SelectScrollUpButton({
|
|
1127
|
+
className,
|
|
1128
|
+
...props
|
|
1129
|
+
}) {
|
|
1130
|
+
return /* @__PURE__ */ jsx(
|
|
1131
|
+
Select$1.ScrollUpArrow,
|
|
1132
|
+
{
|
|
1133
|
+
"data-slot": "select-scroll-up-button",
|
|
1134
|
+
className: cn(
|
|
1135
|
+
"bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 top-0 w-full",
|
|
1136
|
+
className
|
|
1137
|
+
),
|
|
1138
|
+
...props,
|
|
1139
|
+
children: /* @__PURE__ */ jsx(ChevronUpIcon, {})
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
1142
|
+
}
|
|
1143
|
+
function SelectScrollDownButton({
|
|
1144
|
+
className,
|
|
1145
|
+
...props
|
|
1146
|
+
}) {
|
|
1147
|
+
return /* @__PURE__ */ jsx(
|
|
1148
|
+
Select$1.ScrollDownArrow,
|
|
1149
|
+
{
|
|
1150
|
+
"data-slot": "select-scroll-down-button",
|
|
1151
|
+
className: cn(
|
|
1152
|
+
"bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4 bottom-0 w-full",
|
|
1153
|
+
className
|
|
1154
|
+
),
|
|
1155
|
+
...props,
|
|
1156
|
+
children: /* @__PURE__ */ jsx(ChevronDownIcon, {})
|
|
1157
|
+
}
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
function SelectField({ field, value, onChange, id, readOnly, label }) {
|
|
1161
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsxs(
|
|
1162
|
+
Select,
|
|
1163
|
+
{
|
|
1164
|
+
value: String(value ?? ""),
|
|
1165
|
+
onValueChange: (v) => {
|
|
1166
|
+
if (v === null) return;
|
|
1167
|
+
const match = field.options.find((o) => String(o.value) === v);
|
|
1168
|
+
onChange(match ? match.value : v);
|
|
1169
|
+
},
|
|
1170
|
+
children: [
|
|
1171
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id, className: "h-8 text-sm w-full", disabled: readOnly, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select..." }) }),
|
|
1172
|
+
/* @__PURE__ */ jsx(SelectContent, { children: /* @__PURE__ */ jsx(SelectGroup, { children: field.options.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: String(opt.value), children: opt.label }, String(opt.value))) }) })
|
|
1173
|
+
]
|
|
1174
|
+
}
|
|
1175
|
+
) });
|
|
1176
|
+
}
|
|
1177
|
+
var buttonGroupVariants = cva(
|
|
1178
|
+
"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",
|
|
1179
|
+
{
|
|
1180
|
+
variants: {
|
|
1181
|
+
orientation: {
|
|
1182
|
+
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",
|
|
1183
|
+
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"
|
|
1184
|
+
}
|
|
1185
|
+
},
|
|
1186
|
+
defaultVariants: {
|
|
1187
|
+
orientation: "horizontal"
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
);
|
|
1191
|
+
function ButtonGroup({
|
|
1192
|
+
className,
|
|
1193
|
+
orientation,
|
|
1194
|
+
...props
|
|
1195
|
+
}) {
|
|
1196
|
+
return /* @__PURE__ */ jsx(
|
|
1197
|
+
"div",
|
|
1198
|
+
{
|
|
1199
|
+
role: "group",
|
|
1200
|
+
"data-slot": "button-group",
|
|
1201
|
+
"data-orientation": orientation,
|
|
1202
|
+
className: cn2(buttonGroupVariants({ orientation }), className),
|
|
1203
|
+
...props
|
|
1204
|
+
}
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
function RadioField({ field, value, onChange, readOnly, label }) {
|
|
1208
|
+
const options = field.options ?? [];
|
|
1209
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, el: "div", children: /* @__PURE__ */ jsx(ButtonGroup, { className: "w-full", children: options.map((opt) => {
|
|
1210
|
+
const selected = String(opt.value) === String(value ?? "");
|
|
1211
|
+
return /* @__PURE__ */ jsx(
|
|
1212
|
+
Button,
|
|
1213
|
+
{
|
|
1214
|
+
type: "button",
|
|
1215
|
+
variant: selected ? "default" : "outline",
|
|
1216
|
+
size: "sm",
|
|
1217
|
+
className: "flex-1 text-xs",
|
|
1218
|
+
disabled: readOnly,
|
|
1219
|
+
onClick: () => onChange(opt.value),
|
|
1220
|
+
children: opt.label
|
|
1221
|
+
},
|
|
1222
|
+
String(opt.value)
|
|
1223
|
+
);
|
|
1224
|
+
}) }) });
|
|
1225
|
+
}
|
|
1226
|
+
function ItemGroup({ className, ...props }) {
|
|
1227
|
+
return /* @__PURE__ */ jsx(
|
|
1228
|
+
"div",
|
|
1229
|
+
{
|
|
1230
|
+
role: "list",
|
|
1231
|
+
"data-slot": "item-group",
|
|
1232
|
+
className: cn2(
|
|
1233
|
+
"gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2 group/item-group flex w-full flex-col",
|
|
1234
|
+
className
|
|
1235
|
+
),
|
|
1236
|
+
...props
|
|
1237
|
+
}
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
var itemVariants = cva(
|
|
1241
|
+
"[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",
|
|
1242
|
+
{
|
|
1243
|
+
variants: {
|
|
1244
|
+
variant: {
|
|
1245
|
+
default: "border-transparent",
|
|
1246
|
+
outline: "border-border",
|
|
1247
|
+
muted: "bg-muted/50 border-transparent"
|
|
1248
|
+
},
|
|
1249
|
+
size: {
|
|
1250
|
+
default: "gap-2.5 px-3 py-2.5",
|
|
1251
|
+
sm: "gap-2.5 px-3 py-2.5",
|
|
1252
|
+
xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
|
|
1253
|
+
}
|
|
1254
|
+
},
|
|
1255
|
+
defaultVariants: {
|
|
1256
|
+
variant: "default",
|
|
1257
|
+
size: "default"
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
);
|
|
1261
|
+
function Item({
|
|
1262
|
+
className,
|
|
1263
|
+
variant = "default",
|
|
1264
|
+
size = "default",
|
|
1265
|
+
render,
|
|
1266
|
+
...props
|
|
1267
|
+
}) {
|
|
1268
|
+
return useRender({
|
|
1269
|
+
defaultTagName: "div",
|
|
1270
|
+
props: mergeProps(
|
|
1271
|
+
{
|
|
1272
|
+
className: cn2(itemVariants({ variant, size, className }))
|
|
1273
|
+
},
|
|
1274
|
+
props
|
|
1275
|
+
),
|
|
1276
|
+
render,
|
|
1277
|
+
state: {
|
|
1278
|
+
slot: "item",
|
|
1279
|
+
variant,
|
|
1280
|
+
size
|
|
1281
|
+
}
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
cva(
|
|
1285
|
+
"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",
|
|
1286
|
+
{
|
|
1287
|
+
variants: {
|
|
1288
|
+
variant: {
|
|
1289
|
+
default: "bg-transparent",
|
|
1290
|
+
icon: "[&_svg:not([class*='size-'])]:size-4",
|
|
1291
|
+
image: "size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover"
|
|
1292
|
+
}
|
|
1293
|
+
},
|
|
1294
|
+
defaultVariants: {
|
|
1295
|
+
variant: "default"
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
);
|
|
1299
|
+
function ItemContent({ className, ...props }) {
|
|
1300
|
+
return /* @__PURE__ */ jsx(
|
|
1301
|
+
"div",
|
|
1302
|
+
{
|
|
1303
|
+
"data-slot": "item-content",
|
|
1304
|
+
className: cn2(
|
|
1305
|
+
"gap-1 group-data-[size=xs]/item:gap-0 flex flex-1 flex-col [&+[data-slot=item-content]]:flex-none",
|
|
1306
|
+
className
|
|
1307
|
+
),
|
|
1308
|
+
...props
|
|
1309
|
+
}
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
function ItemTitle({ className, ...props }) {
|
|
1313
|
+
return /* @__PURE__ */ jsx(
|
|
1314
|
+
"div",
|
|
1315
|
+
{
|
|
1316
|
+
"data-slot": "item-title",
|
|
1317
|
+
className: cn2(
|
|
1318
|
+
"gap-2 text-sm leading-snug font-medium underline-offset-4 line-clamp-1 flex w-fit items-center",
|
|
1319
|
+
className
|
|
1320
|
+
),
|
|
1321
|
+
...props
|
|
1322
|
+
}
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
function ItemActions({ className, ...props }) {
|
|
1326
|
+
return /* @__PURE__ */ jsx(
|
|
1327
|
+
"div",
|
|
1328
|
+
{
|
|
1329
|
+
"data-slot": "item-actions",
|
|
1330
|
+
className: cn2("gap-2 flex items-center", className),
|
|
1331
|
+
...props
|
|
1332
|
+
}
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
function useControlledState(props) {
|
|
1336
|
+
const { value, defaultValue, onChange } = props;
|
|
1337
|
+
const [state, setInternalState] = React18.useState(
|
|
1338
|
+
value !== void 0 ? value : defaultValue
|
|
1339
|
+
);
|
|
1340
|
+
React18.useEffect(() => {
|
|
1341
|
+
if (value !== void 0) setInternalState(value);
|
|
1342
|
+
}, [value]);
|
|
1343
|
+
const setState = React18.useCallback(
|
|
1344
|
+
(next, ...args) => {
|
|
1345
|
+
setInternalState(next);
|
|
1346
|
+
onChange?.(next, ...args);
|
|
1347
|
+
},
|
|
1348
|
+
[onChange]
|
|
1349
|
+
);
|
|
1350
|
+
return [state, setState];
|
|
1351
|
+
}
|
|
1352
|
+
var [PopoverProvider, usePopover] = getStrictContext("PopoverContext");
|
|
1353
|
+
function Popover(props) {
|
|
1354
|
+
const [isOpen, setIsOpen] = useControlledState({
|
|
1355
|
+
value: props?.open,
|
|
1356
|
+
defaultValue: props?.defaultOpen,
|
|
1357
|
+
onChange: props?.onOpenChange
|
|
1358
|
+
});
|
|
1359
|
+
return /* @__PURE__ */ jsx(PopoverProvider, { value: { isOpen, setIsOpen }, children: /* @__PURE__ */ jsx(
|
|
1360
|
+
Popover$1.Root,
|
|
1361
|
+
{
|
|
1362
|
+
"data-slot": "popover",
|
|
1363
|
+
...props,
|
|
1364
|
+
onOpenChange: setIsOpen
|
|
1365
|
+
}
|
|
1366
|
+
) });
|
|
1367
|
+
}
|
|
1368
|
+
function PopoverTrigger(props) {
|
|
1369
|
+
return /* @__PURE__ */ jsx(Popover$1.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
1370
|
+
}
|
|
1371
|
+
function PopoverPortal(props) {
|
|
1372
|
+
const { isOpen } = usePopover();
|
|
1373
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(
|
|
1374
|
+
Popover$1.Portal,
|
|
1375
|
+
{
|
|
1376
|
+
keepMounted: true,
|
|
1377
|
+
"data-slot": "popover-portal",
|
|
1378
|
+
...props
|
|
1379
|
+
}
|
|
1380
|
+
) });
|
|
1381
|
+
}
|
|
1382
|
+
function PopoverPositioner(props) {
|
|
1383
|
+
return /* @__PURE__ */ jsx(Popover$1.Positioner, { "data-slot": "popover-positioner", ...props });
|
|
1384
|
+
}
|
|
1385
|
+
function PopoverPopup({
|
|
1386
|
+
initialFocus,
|
|
1387
|
+
finalFocus,
|
|
1388
|
+
transition = { type: "spring", stiffness: 300, damping: 25 },
|
|
1389
|
+
...props
|
|
1390
|
+
}) {
|
|
1391
|
+
return /* @__PURE__ */ jsx(
|
|
1392
|
+
Popover$1.Popup,
|
|
1393
|
+
{
|
|
1394
|
+
initialFocus,
|
|
1395
|
+
finalFocus,
|
|
1396
|
+
render: /* @__PURE__ */ jsx(
|
|
1397
|
+
motion.div,
|
|
1398
|
+
{
|
|
1399
|
+
"data-slot": "popover-popup",
|
|
1400
|
+
initial: { opacity: 0, scale: 0.5 },
|
|
1401
|
+
animate: { opacity: 1, scale: 1 },
|
|
1402
|
+
exit: { opacity: 0, scale: 0.5 },
|
|
1403
|
+
transition,
|
|
1404
|
+
...props
|
|
1405
|
+
},
|
|
1406
|
+
"popover-popup"
|
|
1407
|
+
)
|
|
1408
|
+
}
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
function PopoverTitle(props) {
|
|
1412
|
+
return /* @__PURE__ */ jsx(Popover$1.Title, { "data-slot": "popover-title", ...props });
|
|
1413
|
+
}
|
|
1414
|
+
function Popover2(props) {
|
|
1415
|
+
return /* @__PURE__ */ jsx(Popover, { ...props });
|
|
1416
|
+
}
|
|
1417
|
+
function PopoverTrigger2(props) {
|
|
1418
|
+
return /* @__PURE__ */ jsx(PopoverTrigger, { ...props });
|
|
1419
|
+
}
|
|
1420
|
+
function PopoverPanel({
|
|
1421
|
+
className,
|
|
1422
|
+
align = "center",
|
|
1423
|
+
sideOffset = 4,
|
|
1424
|
+
initialFocus,
|
|
1425
|
+
finalFocus,
|
|
1426
|
+
style,
|
|
1427
|
+
children,
|
|
1428
|
+
...props
|
|
1429
|
+
}) {
|
|
1430
|
+
return /* @__PURE__ */ jsx(PopoverPortal, { children: /* @__PURE__ */ jsx(
|
|
1431
|
+
PopoverPositioner,
|
|
1432
|
+
{
|
|
1433
|
+
align,
|
|
1434
|
+
sideOffset,
|
|
1435
|
+
className: "z-50",
|
|
1436
|
+
...props,
|
|
1437
|
+
children: /* @__PURE__ */ jsx(
|
|
1438
|
+
PopoverPopup,
|
|
1439
|
+
{
|
|
1440
|
+
initialFocus,
|
|
1441
|
+
finalFocus,
|
|
1442
|
+
className: cn(
|
|
1443
|
+
"bg-popover text-popover-foreground w-72 rounded-md border p-4 shadow-md outline-hidden origin-(--transform-origin)",
|
|
1444
|
+
className
|
|
1445
|
+
),
|
|
1446
|
+
style,
|
|
1447
|
+
children
|
|
1448
|
+
}
|
|
1449
|
+
)
|
|
1450
|
+
}
|
|
1451
|
+
) });
|
|
1452
|
+
}
|
|
1453
|
+
function PopoverTitle2(props) {
|
|
1454
|
+
return /* @__PURE__ */ jsx(PopoverTitle, { ...props });
|
|
1455
|
+
}
|
|
1456
|
+
function SortableItem({
|
|
1457
|
+
id,
|
|
1458
|
+
index,
|
|
1459
|
+
item,
|
|
1460
|
+
field,
|
|
1461
|
+
readOnly,
|
|
1462
|
+
atMax,
|
|
1463
|
+
atMin,
|
|
1464
|
+
fieldId,
|
|
1465
|
+
open,
|
|
1466
|
+
onOpenChange,
|
|
1467
|
+
onDuplicate,
|
|
1468
|
+
onRemove,
|
|
1469
|
+
onUpdate,
|
|
1470
|
+
getSummary
|
|
1471
|
+
}) {
|
|
1472
|
+
const {
|
|
1473
|
+
attributes,
|
|
1474
|
+
listeners,
|
|
1475
|
+
setNodeRef,
|
|
1476
|
+
transform,
|
|
1477
|
+
transition,
|
|
1478
|
+
isDragging
|
|
1479
|
+
} = useSortable({ id });
|
|
1480
|
+
const style = {
|
|
1481
|
+
transform: CSS.Transform.toString(transform),
|
|
1482
|
+
transition,
|
|
1483
|
+
opacity: isDragging ? 0.5 : 1
|
|
1484
|
+
};
|
|
1485
|
+
return /* @__PURE__ */ jsx("div", { ref: setNodeRef, style, children: /* @__PURE__ */ jsxs(Popover2, { open, onOpenChange, children: [
|
|
1486
|
+
/* @__PURE__ */ jsxs(Item, { variant: "outline", size: "sm", className: "cursor-pointer", children: [
|
|
1487
|
+
/* @__PURE__ */ jsx(
|
|
1488
|
+
"button",
|
|
1489
|
+
{
|
|
1490
|
+
type: "button",
|
|
1491
|
+
className: "cursor-grab active:cursor-grabbing touch-none p-0.5 text-muted-foreground/40 hover:text-muted-foreground",
|
|
1492
|
+
...attributes,
|
|
1493
|
+
...listeners,
|
|
1494
|
+
children: /* @__PURE__ */ jsx(GripVertical, { className: "h-3.5 w-3.5 shrink-0" })
|
|
1495
|
+
}
|
|
1496
|
+
),
|
|
1497
|
+
/* @__PURE__ */ jsx(PopoverTrigger2, { className: "flex-1 min-w-0 text-left", children: /* @__PURE__ */ jsx(ItemContent, { children: /* @__PURE__ */ jsx(ItemTitle, { className: "text-xs", children: getSummary(item, index) }) }) }),
|
|
1498
|
+
!readOnly && /* @__PURE__ */ jsxs(ItemActions, { children: [
|
|
1499
|
+
/* @__PURE__ */ jsx(
|
|
1500
|
+
Button,
|
|
1501
|
+
{
|
|
1502
|
+
variant: "ghost",
|
|
1503
|
+
size: "icon",
|
|
1504
|
+
className: "h-5 w-5",
|
|
1505
|
+
disabled: atMax,
|
|
1506
|
+
onClick: (e) => {
|
|
1507
|
+
e.stopPropagation();
|
|
1508
|
+
onDuplicate(index);
|
|
1509
|
+
},
|
|
1510
|
+
title: "Duplicate",
|
|
1511
|
+
children: /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" })
|
|
1512
|
+
}
|
|
1513
|
+
),
|
|
1514
|
+
/* @__PURE__ */ jsx(
|
|
1515
|
+
Button,
|
|
1516
|
+
{
|
|
1517
|
+
variant: "ghost",
|
|
1518
|
+
size: "icon",
|
|
1519
|
+
className: "h-5 w-5 text-destructive hover:text-destructive",
|
|
1520
|
+
disabled: atMin,
|
|
1521
|
+
onClick: (e) => {
|
|
1522
|
+
e.stopPropagation();
|
|
1523
|
+
onRemove(index);
|
|
1524
|
+
},
|
|
1525
|
+
title: "Delete",
|
|
1526
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
1527
|
+
}
|
|
1528
|
+
)
|
|
1529
|
+
] })
|
|
1530
|
+
] }),
|
|
1531
|
+
/* @__PURE__ */ jsx(
|
|
1532
|
+
PopoverPanel,
|
|
1533
|
+
{
|
|
1534
|
+
side: "left",
|
|
1535
|
+
sideOffset: 60,
|
|
1536
|
+
align: "start",
|
|
1537
|
+
alignOffset: -14,
|
|
1538
|
+
className: "w-56 p-3 flex flex-col gap-2",
|
|
1539
|
+
children: Object.entries(field.arrayFields).map(([subName, subField]) => /* @__PURE__ */ jsx(
|
|
1540
|
+
AutoField,
|
|
1541
|
+
{
|
|
1542
|
+
field: { ...subField, label: subField.label ?? subName },
|
|
1543
|
+
value: item[subName],
|
|
1544
|
+
onChange: (val) => onUpdate(index, subName, val),
|
|
1545
|
+
readOnly,
|
|
1546
|
+
id: `${fieldId}-${index}-${subName}`
|
|
1547
|
+
},
|
|
1548
|
+
subName
|
|
1549
|
+
))
|
|
1550
|
+
}
|
|
1551
|
+
)
|
|
1552
|
+
] }) });
|
|
1553
|
+
}
|
|
1554
|
+
function ArrayField({
|
|
1555
|
+
field,
|
|
1556
|
+
value = [],
|
|
1557
|
+
onChange,
|
|
1558
|
+
readOnly,
|
|
1559
|
+
label,
|
|
1560
|
+
id = ""
|
|
1561
|
+
}) {
|
|
1562
|
+
const atMax = field.max !== void 0 && value.length >= field.max;
|
|
1563
|
+
const atMin = field.min !== void 0 && value.length <= field.min;
|
|
1564
|
+
const [openIndex, setOpenIndex] = React18.useState(null);
|
|
1565
|
+
const itemIds = React18.useMemo(
|
|
1566
|
+
() => value.map((_, i) => `${id}-item-${i}`),
|
|
1567
|
+
[value.length, id]
|
|
1568
|
+
);
|
|
1569
|
+
const sensors = useSensors(useSensor(PointerSensor));
|
|
1570
|
+
const handleDragEnd = (event) => {
|
|
1571
|
+
const { active, over } = event;
|
|
1572
|
+
if (!over || active.id === over.id) return;
|
|
1573
|
+
const from = itemIds.indexOf(active.id);
|
|
1574
|
+
const to = itemIds.indexOf(over.id);
|
|
1575
|
+
if (from === -1 || to === -1) return;
|
|
1576
|
+
onChange(arrayMove(value, from, to));
|
|
1577
|
+
};
|
|
1578
|
+
const defaultItem = () => {
|
|
1579
|
+
if (!field.defaultItemProps) return {};
|
|
1580
|
+
return typeof field.defaultItemProps === "function" ? field.defaultItemProps(value.length) : { ...field.defaultItemProps };
|
|
1581
|
+
};
|
|
1582
|
+
const addItem = () => {
|
|
1583
|
+
if (atMax || readOnly) return;
|
|
1584
|
+
const newIndex = value.length;
|
|
1585
|
+
onChange([...value, defaultItem()]);
|
|
1586
|
+
setOpenIndex(newIndex);
|
|
1587
|
+
};
|
|
1588
|
+
const removeItem = (i) => {
|
|
1589
|
+
if (atMin || readOnly) return;
|
|
1590
|
+
const next = [...value];
|
|
1591
|
+
next.splice(i, 1);
|
|
1592
|
+
onChange(next);
|
|
1593
|
+
};
|
|
1594
|
+
const duplicateItem = (i) => {
|
|
1595
|
+
if (atMax || readOnly) return;
|
|
1596
|
+
const next = [...value];
|
|
1597
|
+
next.splice(i + 1, 0, { ...value[i] });
|
|
1598
|
+
onChange(next);
|
|
1599
|
+
};
|
|
1600
|
+
const updateItem = (i, subName, val) => {
|
|
1601
|
+
onChange(
|
|
1602
|
+
value.map(
|
|
1603
|
+
(item, idx) => idx === i ? { ...item, [subName]: val } : item
|
|
1604
|
+
)
|
|
1605
|
+
);
|
|
1606
|
+
};
|
|
1607
|
+
const getSummary = (item, i) => {
|
|
1608
|
+
if (field.getItemSummary) return field.getItemSummary(item, i);
|
|
1609
|
+
const first = Object.values(item).find((v) => typeof v === "string" && v);
|
|
1610
|
+
return first || `Item ${i + 1}`;
|
|
1611
|
+
};
|
|
1612
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? field.label ?? "", readOnly, el: "div", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
1613
|
+
/* @__PURE__ */ jsx(
|
|
1614
|
+
DndContext,
|
|
1615
|
+
{
|
|
1616
|
+
sensors,
|
|
1617
|
+
collisionDetection: closestCenter,
|
|
1618
|
+
onDragEnd: handleDragEnd,
|
|
1619
|
+
children: /* @__PURE__ */ jsx(
|
|
1620
|
+
SortableContext,
|
|
1621
|
+
{
|
|
1622
|
+
items: itemIds,
|
|
1623
|
+
strategy: verticalListSortingStrategy,
|
|
1624
|
+
children: /* @__PURE__ */ jsx(ItemGroup, { children: value.map((item, i) => /* @__PURE__ */ jsx(
|
|
1625
|
+
SortableItem,
|
|
1626
|
+
{
|
|
1627
|
+
id: itemIds[i],
|
|
1628
|
+
index: i,
|
|
1629
|
+
item,
|
|
1630
|
+
field,
|
|
1631
|
+
readOnly,
|
|
1632
|
+
atMax,
|
|
1633
|
+
atMin,
|
|
1634
|
+
fieldId: id,
|
|
1635
|
+
open: openIndex === i,
|
|
1636
|
+
onOpenChange: (o) => setOpenIndex(o ? i : null),
|
|
1637
|
+
onDuplicate: duplicateItem,
|
|
1638
|
+
onRemove: removeItem,
|
|
1639
|
+
onUpdate: updateItem,
|
|
1640
|
+
getSummary
|
|
1641
|
+
},
|
|
1642
|
+
itemIds[i]
|
|
1643
|
+
)) })
|
|
1644
|
+
}
|
|
1645
|
+
)
|
|
1646
|
+
}
|
|
1647
|
+
),
|
|
1648
|
+
!readOnly && !atMax && /* @__PURE__ */ jsxs(
|
|
1649
|
+
Button,
|
|
1650
|
+
{
|
|
1651
|
+
variant: "outline",
|
|
1652
|
+
size: "sm",
|
|
1653
|
+
onClick: addItem,
|
|
1654
|
+
className: "w-full gap-1.5 mt-0.5",
|
|
1655
|
+
children: [
|
|
1656
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
1657
|
+
"Add item"
|
|
1658
|
+
]
|
|
1659
|
+
}
|
|
1660
|
+
)
|
|
1661
|
+
] }) });
|
|
1662
|
+
}
|
|
1663
|
+
function ObjectField({ children, name, readOnly }) {
|
|
1664
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: name, el: "div", readOnly, children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 pl-3 border-l-2 border-border/60 ml-1", children }) });
|
|
1665
|
+
}
|
|
1666
|
+
function Card({
|
|
1667
|
+
className,
|
|
1668
|
+
size = "default",
|
|
1669
|
+
...props
|
|
1670
|
+
}) {
|
|
1671
|
+
return /* @__PURE__ */ jsx(
|
|
1672
|
+
"div",
|
|
1673
|
+
{
|
|
1674
|
+
"data-slot": "card",
|
|
1675
|
+
"data-size": size,
|
|
1676
|
+
className: cn(
|
|
1677
|
+
"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",
|
|
1678
|
+
className
|
|
1679
|
+
),
|
|
1680
|
+
...props
|
|
1681
|
+
}
|
|
1682
|
+
);
|
|
1683
|
+
}
|
|
1684
|
+
function CardContent({ className, ...props }) {
|
|
1685
|
+
return /* @__PURE__ */ jsx(
|
|
1686
|
+
"div",
|
|
1687
|
+
{
|
|
1688
|
+
"data-slot": "card-content",
|
|
1689
|
+
className: cn("px-4 group-data-[size=sm]/card:px-3", className),
|
|
1690
|
+
...props
|
|
1691
|
+
}
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
1694
|
+
function SlotField({ children, label }) {
|
|
1695
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", el: "div", children: /* @__PURE__ */ jsx(Card, { className: "border-dashed", children: /* @__PURE__ */ jsx(CardContent, { className: "py-3 px-3", children: children ?? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center", children: "Slot content is managed directly on the canvas." }) }) }) });
|
|
1696
|
+
}
|
|
1697
|
+
function CustomField({ children, label }) {
|
|
1698
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", el: "div", children: /* @__PURE__ */ jsx("div", { className: "rounded-md border border-border/60 p-3", children }) });
|
|
1699
|
+
}
|
|
1700
|
+
var toggleVariants = cva(
|
|
1701
|
+
"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",
|
|
1702
|
+
{
|
|
1703
|
+
variants: {
|
|
1704
|
+
variant: {
|
|
1705
|
+
default: "bg-transparent",
|
|
1706
|
+
outline: "border border-input bg-transparent hover:bg-muted"
|
|
1707
|
+
},
|
|
1708
|
+
size: {
|
|
1709
|
+
default: "h-8 min-w-8 px-2",
|
|
1710
|
+
sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-1.5 text-[0.8rem]",
|
|
1711
|
+
lg: "h-9 min-w-9 px-2.5"
|
|
1712
|
+
}
|
|
1713
|
+
},
|
|
1714
|
+
defaultVariants: {
|
|
1715
|
+
variant: "default",
|
|
1716
|
+
size: "default"
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
);
|
|
1720
|
+
function Toggle({
|
|
1721
|
+
className,
|
|
1722
|
+
variant = "default",
|
|
1723
|
+
size = "default",
|
|
1724
|
+
...props
|
|
1725
|
+
}) {
|
|
1726
|
+
return /* @__PURE__ */ jsx(
|
|
1727
|
+
Toggle$1,
|
|
1728
|
+
{
|
|
1729
|
+
"data-slot": "toggle",
|
|
1730
|
+
className: cn(toggleVariants({ variant, size, className })),
|
|
1731
|
+
...props
|
|
1732
|
+
}
|
|
1733
|
+
);
|
|
1734
|
+
}
|
|
1735
|
+
function RichtextField({ value, onChange, readOnly, label }) {
|
|
1736
|
+
const ref = React18.useRef(null);
|
|
1737
|
+
const boldLabel = useMsg("richtext.bold");
|
|
1738
|
+
const italicLabel = useMsg("richtext.italic");
|
|
1739
|
+
const linkLabel = useMsg("richtext.link");
|
|
1740
|
+
const linkPrompt = useMsg("richtext.link.prompt");
|
|
1741
|
+
React18.useEffect(() => {
|
|
1742
|
+
if (ref.current && ref.current.innerHTML !== value) {
|
|
1743
|
+
ref.current.innerHTML = value ?? "";
|
|
1744
|
+
}
|
|
1745
|
+
}, [value]);
|
|
1746
|
+
const exec = (cmd, val) => {
|
|
1747
|
+
document.execCommand(cmd, false, val);
|
|
1748
|
+
if (ref.current) onChange(ref.current.innerHTML);
|
|
1749
|
+
};
|
|
1750
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1 rounded-md border border-input overflow-hidden", children: [
|
|
1751
|
+
!readOnly && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 border-b px-1 py-0.5 bg-muted/30", children: [
|
|
1752
|
+
/* @__PURE__ */ jsx(Toggle, { size: "sm", onPressedChange: () => exec("bold"), "aria-label": boldLabel, children: /* @__PURE__ */ jsx(Bold, { className: "h-3.5 w-3.5" }) }),
|
|
1753
|
+
/* @__PURE__ */ jsx(Toggle, { size: "sm", onPressedChange: () => exec("italic"), "aria-label": italicLabel, children: /* @__PURE__ */ jsx(Italic, { className: "h-3.5 w-3.5" }) }),
|
|
1754
|
+
/* @__PURE__ */ jsx(
|
|
1755
|
+
Toggle,
|
|
1756
|
+
{
|
|
1757
|
+
size: "sm",
|
|
1758
|
+
onPressedChange: () => {
|
|
1759
|
+
const url = window.prompt(linkPrompt);
|
|
1760
|
+
if (url) exec("createLink", url);
|
|
1761
|
+
},
|
|
1762
|
+
"aria-label": linkLabel,
|
|
1763
|
+
children: /* @__PURE__ */ jsx(Link, { className: "h-3.5 w-3.5" })
|
|
1764
|
+
}
|
|
1765
|
+
)
|
|
1766
|
+
] }),
|
|
1767
|
+
/* @__PURE__ */ jsx(
|
|
1768
|
+
"div",
|
|
1769
|
+
{
|
|
1770
|
+
ref,
|
|
1771
|
+
contentEditable: !readOnly,
|
|
1772
|
+
suppressContentEditableWarning: true,
|
|
1773
|
+
onInput: () => {
|
|
1774
|
+
if (ref.current) onChange(ref.current.innerHTML);
|
|
1775
|
+
},
|
|
1776
|
+
className: "min-h-[60px] px-3 py-2 text-sm outline-none"
|
|
1777
|
+
}
|
|
1778
|
+
)
|
|
1779
|
+
] }) });
|
|
1780
|
+
}
|
|
1781
|
+
function InputGroup({ className, ...props }) {
|
|
1782
|
+
return /* @__PURE__ */ jsx(
|
|
1783
|
+
"div",
|
|
1784
|
+
{
|
|
1785
|
+
"data-slot": "input-group",
|
|
1786
|
+
role: "group",
|
|
1787
|
+
className: cn(
|
|
1788
|
+
"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]",
|
|
1789
|
+
"h-9 has-[>textarea]:h-auto",
|
|
1790
|
+
// Variants based on alignment.
|
|
1791
|
+
"has-[>[data-align=inline-start]]:[&>input]:pl-2",
|
|
1792
|
+
"has-[>[data-align=inline-end]]:[&>input]:pr-2",
|
|
1793
|
+
"has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
|
|
1794
|
+
"has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
|
|
1795
|
+
// Focus state.
|
|
1796
|
+
"has-[[data-slot=input-group-control]:focus-visible]:ring-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1",
|
|
1797
|
+
// Error state.
|
|
1798
|
+
"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",
|
|
1799
|
+
className
|
|
1800
|
+
),
|
|
1801
|
+
...props
|
|
1802
|
+
}
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
var inputGroupAddonVariants = cva(
|
|
1806
|
+
"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",
|
|
1807
|
+
{
|
|
1808
|
+
variants: {
|
|
1809
|
+
align: {
|
|
1810
|
+
"inline-start": "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
|
|
1811
|
+
"inline-end": "order-last pr-3 has-[>button]:mr-[-0.4rem] has-[>kbd]:mr-[-0.35rem]",
|
|
1812
|
+
"block-start": "[.border-b]:pb-3 order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5",
|
|
1813
|
+
"block-end": "[.border-t]:pt-3 order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5"
|
|
1814
|
+
}
|
|
1815
|
+
},
|
|
1816
|
+
defaultVariants: {
|
|
1817
|
+
align: "inline-start"
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
);
|
|
1821
|
+
function InputGroupAddon({
|
|
1822
|
+
className,
|
|
1823
|
+
align = "inline-start",
|
|
1824
|
+
...props
|
|
1825
|
+
}) {
|
|
1826
|
+
return /* @__PURE__ */ jsx(
|
|
1827
|
+
"div",
|
|
1828
|
+
{
|
|
1829
|
+
role: "group",
|
|
1830
|
+
"data-slot": "input-group-addon",
|
|
1831
|
+
"data-align": align,
|
|
1832
|
+
className: cn(inputGroupAddonVariants({ align }), className),
|
|
1833
|
+
onClick: (e) => {
|
|
1834
|
+
if (e.target.closest("button")) {
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
e.currentTarget.parentElement?.querySelector("input")?.focus();
|
|
1838
|
+
},
|
|
1839
|
+
...props
|
|
1840
|
+
}
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
cva(
|
|
1844
|
+
"flex items-center gap-2 text-sm shadow-none",
|
|
1845
|
+
{
|
|
1846
|
+
variants: {
|
|
1847
|
+
size: {
|
|
1848
|
+
xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
|
|
1849
|
+
sm: "h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5",
|
|
1850
|
+
"icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
|
|
1851
|
+
"icon-sm": "size-8 p-0 has-[>svg]:p-0"
|
|
1852
|
+
}
|
|
1853
|
+
},
|
|
1854
|
+
defaultVariants: {
|
|
1855
|
+
size: "xs"
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
);
|
|
1859
|
+
function Command({
|
|
1860
|
+
className,
|
|
1861
|
+
...props
|
|
1862
|
+
}) {
|
|
1863
|
+
return /* @__PURE__ */ jsx(
|
|
1864
|
+
Command$1,
|
|
1865
|
+
{
|
|
1866
|
+
"data-slot": "command",
|
|
1867
|
+
className: cn(
|
|
1868
|
+
"flex size-full flex-col overflow-hidden rounded-xl! bg-popover p-1 text-popover-foreground",
|
|
1869
|
+
className
|
|
1870
|
+
),
|
|
1871
|
+
...props
|
|
1872
|
+
}
|
|
1873
|
+
);
|
|
1874
|
+
}
|
|
1875
|
+
function CommandInput({
|
|
1876
|
+
className,
|
|
1877
|
+
...props
|
|
1878
|
+
}) {
|
|
1879
|
+
return /* @__PURE__ */ jsx("div", { "data-slot": "command-input-wrapper", className: "p-1 pb-0", children: /* @__PURE__ */ jsxs(InputGroup, { className: "h-8! rounded-lg! border-input/30 bg-input/30 shadow-none! *:data-[slot=input-group-addon]:pl-2!", children: [
|
|
1880
|
+
/* @__PURE__ */ jsx(
|
|
1881
|
+
Command$1.Input,
|
|
1882
|
+
{
|
|
1883
|
+
"data-slot": "command-input",
|
|
1884
|
+
className: cn(
|
|
1885
|
+
"w-full text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
|
1886
|
+
className
|
|
1887
|
+
),
|
|
1888
|
+
...props
|
|
1889
|
+
}
|
|
1890
|
+
),
|
|
1891
|
+
/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }) })
|
|
1892
|
+
] }) });
|
|
1893
|
+
}
|
|
1894
|
+
function CommandList({
|
|
1895
|
+
className,
|
|
1896
|
+
...props
|
|
1897
|
+
}) {
|
|
1898
|
+
return /* @__PURE__ */ jsx(
|
|
1899
|
+
Command$1.List,
|
|
1900
|
+
{
|
|
1901
|
+
"data-slot": "command-list",
|
|
1902
|
+
className: cn(
|
|
1903
|
+
"no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none",
|
|
1904
|
+
className
|
|
1905
|
+
),
|
|
1906
|
+
...props
|
|
1907
|
+
}
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1910
|
+
function CommandEmpty({
|
|
1911
|
+
className,
|
|
1912
|
+
...props
|
|
1913
|
+
}) {
|
|
1914
|
+
return /* @__PURE__ */ jsx(
|
|
1915
|
+
Command$1.Empty,
|
|
1916
|
+
{
|
|
1917
|
+
"data-slot": "command-empty",
|
|
1918
|
+
className: cn("py-6 text-center text-sm", className),
|
|
1919
|
+
...props
|
|
1920
|
+
}
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
function CommandItem({
|
|
1924
|
+
className,
|
|
1925
|
+
children,
|
|
1926
|
+
...props
|
|
1927
|
+
}) {
|
|
1928
|
+
return /* @__PURE__ */ jsxs(
|
|
1929
|
+
Command$1.Item,
|
|
1930
|
+
{
|
|
1931
|
+
"data-slot": "command-item",
|
|
1932
|
+
className: cn(
|
|
1933
|
+
"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",
|
|
1934
|
+
className
|
|
1935
|
+
),
|
|
1936
|
+
...props,
|
|
1937
|
+
children: [
|
|
1938
|
+
children,
|
|
1939
|
+
/* @__PURE__ */ jsx(CheckIcon, { className: "ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" })
|
|
1940
|
+
]
|
|
1941
|
+
}
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
function Skeleton({ className, ...props }) {
|
|
1945
|
+
return /* @__PURE__ */ jsx(
|
|
1946
|
+
"div",
|
|
1947
|
+
{
|
|
1948
|
+
"data-slot": "skeleton",
|
|
1949
|
+
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
1950
|
+
...props
|
|
1951
|
+
}
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
function ExternalField({ value, onChange, fetchList, readOnly, label }) {
|
|
1955
|
+
const [query, setQuery] = React18.useState("");
|
|
1956
|
+
const [results, setResults] = React18.useState([]);
|
|
1957
|
+
const [loading, setLoading] = React18.useState(false);
|
|
1958
|
+
React18.useEffect(() => {
|
|
1959
|
+
if (!fetchList) return;
|
|
1960
|
+
setLoading(true);
|
|
1961
|
+
const timer = setTimeout(async () => {
|
|
1962
|
+
try {
|
|
1963
|
+
const data = await fetchList(query);
|
|
1964
|
+
setResults(data);
|
|
1965
|
+
} catch {
|
|
1966
|
+
setResults([]);
|
|
1967
|
+
} finally {
|
|
1968
|
+
setLoading(false);
|
|
1969
|
+
}
|
|
1970
|
+
}, 300);
|
|
1971
|
+
return () => clearTimeout(timer);
|
|
1972
|
+
}, [query, fetchList]);
|
|
1973
|
+
const selectedLabel = results.find((r) => r.value === value)?.label ?? String(value ?? "");
|
|
1974
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsxs(Command, { className: "rounded-md border border-input", children: [
|
|
1975
|
+
/* @__PURE__ */ jsx(
|
|
1976
|
+
CommandInput,
|
|
1977
|
+
{
|
|
1978
|
+
placeholder: "Search...",
|
|
1979
|
+
value: query,
|
|
1980
|
+
onValueChange: setQuery,
|
|
1981
|
+
disabled: readOnly
|
|
1982
|
+
}
|
|
1983
|
+
),
|
|
1984
|
+
/* @__PURE__ */ jsx(CommandList, { children: loading ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 p-2", children: [
|
|
1985
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-full" }),
|
|
1986
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-3/4" }),
|
|
1987
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-1/2" })
|
|
1988
|
+
] }) : results.length === 0 ? /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }) : results.map((r, i) => /* @__PURE__ */ jsx(
|
|
1989
|
+
CommandItem,
|
|
1990
|
+
{
|
|
1991
|
+
"data-checked": r.value === value,
|
|
1992
|
+
onSelect: () => onChange(r.value),
|
|
1993
|
+
children: r.label
|
|
1994
|
+
},
|
|
1995
|
+
i
|
|
1996
|
+
)) }),
|
|
1997
|
+
value != null && /* @__PURE__ */ jsxs("div", { className: "border-t px-3 py-1.5 text-xs text-muted-foreground truncate", children: [
|
|
1998
|
+
"Selected: ",
|
|
1999
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: selectedLabel })
|
|
2000
|
+
] })
|
|
2001
|
+
] }) });
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// src/components/overrides/fields/FieldTypesRegistry.ts
|
|
2005
|
+
var fieldTypesRegistry = {
|
|
2006
|
+
text: TextField,
|
|
2007
|
+
textarea: TextareaField,
|
|
2008
|
+
number: NumberField,
|
|
2009
|
+
select: SelectField,
|
|
2010
|
+
radio: RadioField,
|
|
2011
|
+
array: ArrayField,
|
|
2012
|
+
object: ObjectField,
|
|
2013
|
+
slot: SlotField,
|
|
2014
|
+
custom: CustomField,
|
|
2015
|
+
richtext: RichtextField,
|
|
2016
|
+
external: ExternalField
|
|
2017
|
+
};
|
|
2018
|
+
function PuckRoot({ children }) {
|
|
2019
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
2020
|
+
}
|
|
2021
|
+
var puckOverrides = {
|
|
2022
|
+
header: EditorHeader,
|
|
2023
|
+
headerActions: EditorHeaderActions,
|
|
2024
|
+
drawer: EditorDrawer,
|
|
2025
|
+
components: EditorComponents,
|
|
2026
|
+
drawerItem: DrawerItem,
|
|
2027
|
+
componentItem: DrawerItem,
|
|
2028
|
+
outline: EditorOutline,
|
|
2029
|
+
iframe: CanvasIframe,
|
|
2030
|
+
preview: CanvasPreview,
|
|
2031
|
+
componentOverlay: ComponentOverlay,
|
|
2032
|
+
actionBar: ActionBar,
|
|
2033
|
+
fields: FieldWrapper,
|
|
2034
|
+
fieldTypes: fieldTypesRegistry,
|
|
2035
|
+
puck: PuckRoot
|
|
2036
|
+
};
|
|
2037
|
+
var DEFAULT_BOUNDS_OFFSET = {
|
|
2038
|
+
top: 0,
|
|
2039
|
+
left: 0,
|
|
2040
|
+
width: 0,
|
|
2041
|
+
height: 0
|
|
2042
|
+
};
|
|
2043
|
+
var HighlightContext = React18.createContext(void 0);
|
|
2044
|
+
function useHighlight() {
|
|
2045
|
+
const context = React18.useContext(HighlightContext);
|
|
2046
|
+
if (!context) {
|
|
2047
|
+
throw new Error("useHighlight must be used within a HighlightProvider");
|
|
2048
|
+
}
|
|
2049
|
+
return context;
|
|
2050
|
+
}
|
|
2051
|
+
function Highlight({
|
|
2052
|
+
ref,
|
|
2053
|
+
...props
|
|
2054
|
+
}) {
|
|
2055
|
+
const {
|
|
2056
|
+
as: Component = "div",
|
|
2057
|
+
children,
|
|
2058
|
+
value,
|
|
2059
|
+
defaultValue,
|
|
2060
|
+
onValueChange,
|
|
2061
|
+
className,
|
|
2062
|
+
style,
|
|
2063
|
+
transition = { type: "spring", stiffness: 350, damping: 35 },
|
|
2064
|
+
hover = false,
|
|
2065
|
+
click = true,
|
|
2066
|
+
enabled = true,
|
|
2067
|
+
controlledItems,
|
|
2068
|
+
disabled = false,
|
|
2069
|
+
exitDelay = 200,
|
|
2070
|
+
mode = "children"
|
|
2071
|
+
} = props;
|
|
2072
|
+
const localRef = React18.useRef(null);
|
|
2073
|
+
React18.useImperativeHandle(ref, () => localRef.current);
|
|
2074
|
+
const propsBoundsOffset = props?.boundsOffset;
|
|
2075
|
+
const boundsOffset = propsBoundsOffset ?? DEFAULT_BOUNDS_OFFSET;
|
|
2076
|
+
const boundsOffsetTop = boundsOffset.top ?? 0;
|
|
2077
|
+
const boundsOffsetLeft = boundsOffset.left ?? 0;
|
|
2078
|
+
const boundsOffsetWidth = boundsOffset.width ?? 0;
|
|
2079
|
+
const boundsOffsetHeight = boundsOffset.height ?? 0;
|
|
2080
|
+
const boundsOffsetRef = React18.useRef({
|
|
2081
|
+
top: boundsOffsetTop,
|
|
2082
|
+
left: boundsOffsetLeft,
|
|
2083
|
+
width: boundsOffsetWidth,
|
|
2084
|
+
height: boundsOffsetHeight
|
|
2085
|
+
});
|
|
2086
|
+
React18.useEffect(() => {
|
|
2087
|
+
boundsOffsetRef.current = {
|
|
2088
|
+
top: boundsOffsetTop,
|
|
2089
|
+
left: boundsOffsetLeft,
|
|
2090
|
+
width: boundsOffsetWidth,
|
|
2091
|
+
height: boundsOffsetHeight
|
|
2092
|
+
};
|
|
2093
|
+
}, [
|
|
2094
|
+
boundsOffsetTop,
|
|
2095
|
+
boundsOffsetLeft,
|
|
2096
|
+
boundsOffsetWidth,
|
|
2097
|
+
boundsOffsetHeight
|
|
2098
|
+
]);
|
|
2099
|
+
const [activeValue, setActiveValue] = React18.useState(
|
|
2100
|
+
value ?? defaultValue ?? null
|
|
2101
|
+
);
|
|
2102
|
+
const [boundsState, setBoundsState] = React18.useState(null);
|
|
2103
|
+
const [activeClassNameState, setActiveClassNameState] = React18.useState("");
|
|
2104
|
+
const safeSetActiveValue = (id2) => {
|
|
2105
|
+
setActiveValue((prev) => {
|
|
2106
|
+
if (prev !== id2) {
|
|
2107
|
+
onValueChange?.(id2);
|
|
2108
|
+
return id2;
|
|
2109
|
+
}
|
|
2110
|
+
return prev;
|
|
2111
|
+
});
|
|
2112
|
+
};
|
|
2113
|
+
const safeSetBoundsRef = React18.useRef(void 0);
|
|
2114
|
+
React18.useEffect(() => {
|
|
2115
|
+
safeSetBoundsRef.current = (bounds) => {
|
|
2116
|
+
if (!localRef.current) return;
|
|
2117
|
+
const containerRect = localRef.current.getBoundingClientRect();
|
|
2118
|
+
const offset = boundsOffsetRef.current;
|
|
2119
|
+
const newBounds = {
|
|
2120
|
+
top: bounds.top - containerRect.top + offset.top,
|
|
2121
|
+
left: bounds.left - containerRect.left + offset.left,
|
|
2122
|
+
width: bounds.width + offset.width,
|
|
2123
|
+
height: bounds.height + offset.height
|
|
2124
|
+
};
|
|
2125
|
+
setBoundsState((prev) => {
|
|
2126
|
+
if (prev && prev.top === newBounds.top && prev.left === newBounds.left && prev.width === newBounds.width && prev.height === newBounds.height) {
|
|
2127
|
+
return prev;
|
|
2128
|
+
}
|
|
2129
|
+
return newBounds;
|
|
2130
|
+
});
|
|
2131
|
+
};
|
|
2132
|
+
});
|
|
2133
|
+
const safeSetBounds = (bounds) => {
|
|
2134
|
+
safeSetBoundsRef.current?.(bounds);
|
|
2135
|
+
};
|
|
2136
|
+
const clearBounds = React18.useCallback(() => {
|
|
2137
|
+
setBoundsState((prev) => prev === null ? prev : null);
|
|
2138
|
+
}, []);
|
|
2139
|
+
React18.useEffect(() => {
|
|
2140
|
+
if (value !== void 0) setActiveValue(value);
|
|
2141
|
+
else if (defaultValue !== void 0) setActiveValue(defaultValue);
|
|
2142
|
+
}, [value, defaultValue]);
|
|
2143
|
+
const id = React18.useId();
|
|
2144
|
+
React18.useEffect(() => {
|
|
2145
|
+
if (mode !== "parent") return;
|
|
2146
|
+
const container = localRef.current;
|
|
2147
|
+
if (!container) return;
|
|
2148
|
+
const onScroll = () => {
|
|
2149
|
+
if (!activeValue) return;
|
|
2150
|
+
const activeEl = container.querySelector(
|
|
2151
|
+
`[data-value="${activeValue}"][data-highlight="true"]`
|
|
2152
|
+
);
|
|
2153
|
+
if (activeEl)
|
|
2154
|
+
safeSetBoundsRef.current?.(activeEl.getBoundingClientRect());
|
|
2155
|
+
};
|
|
2156
|
+
container.addEventListener("scroll", onScroll, { passive: true });
|
|
2157
|
+
return () => container.removeEventListener("scroll", onScroll);
|
|
2158
|
+
}, [mode, activeValue]);
|
|
2159
|
+
const render = (children2) => {
|
|
2160
|
+
if (mode === "parent") {
|
|
2161
|
+
return /* @__PURE__ */ jsxs(
|
|
2162
|
+
Component,
|
|
2163
|
+
{
|
|
2164
|
+
ref: localRef,
|
|
2165
|
+
"data-slot": "motion-highlight-container",
|
|
2166
|
+
style: { position: "relative", zIndex: 1 },
|
|
2167
|
+
className: props?.containerClassName,
|
|
2168
|
+
children: [
|
|
2169
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: boundsState && /* @__PURE__ */ jsx(
|
|
2170
|
+
motion.div,
|
|
2171
|
+
{
|
|
2172
|
+
"data-slot": "motion-highlight",
|
|
2173
|
+
animate: {
|
|
2174
|
+
top: boundsState.top,
|
|
2175
|
+
left: boundsState.left,
|
|
2176
|
+
width: boundsState.width,
|
|
2177
|
+
height: boundsState.height,
|
|
2178
|
+
opacity: 1
|
|
2179
|
+
},
|
|
2180
|
+
initial: {
|
|
2181
|
+
top: boundsState.top,
|
|
2182
|
+
left: boundsState.left,
|
|
2183
|
+
width: boundsState.width,
|
|
2184
|
+
height: boundsState.height,
|
|
2185
|
+
opacity: 0
|
|
2186
|
+
},
|
|
2187
|
+
exit: {
|
|
2188
|
+
opacity: 0,
|
|
2189
|
+
transition: {
|
|
2190
|
+
...transition,
|
|
2191
|
+
delay: (transition?.delay ?? 0) + (exitDelay ?? 0) / 1e3
|
|
2192
|
+
}
|
|
2193
|
+
},
|
|
2194
|
+
transition,
|
|
2195
|
+
style: { position: "absolute", zIndex: 0, ...style },
|
|
2196
|
+
className: cn(className, activeClassNameState)
|
|
2197
|
+
}
|
|
2198
|
+
) }),
|
|
2199
|
+
children2
|
|
2200
|
+
]
|
|
2201
|
+
}
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
return children2;
|
|
2205
|
+
};
|
|
2206
|
+
return /* @__PURE__ */ jsx(
|
|
2207
|
+
HighlightContext.Provider,
|
|
2208
|
+
{
|
|
2209
|
+
value: {
|
|
2210
|
+
mode,
|
|
2211
|
+
activeValue,
|
|
2212
|
+
setActiveValue: safeSetActiveValue,
|
|
2213
|
+
id,
|
|
2214
|
+
hover,
|
|
2215
|
+
click,
|
|
2216
|
+
className,
|
|
2217
|
+
style,
|
|
2218
|
+
transition,
|
|
2219
|
+
disabled,
|
|
2220
|
+
enabled,
|
|
2221
|
+
exitDelay,
|
|
2222
|
+
setBounds: safeSetBounds,
|
|
2223
|
+
clearBounds,
|
|
2224
|
+
activeClassName: activeClassNameState,
|
|
2225
|
+
setActiveClassName: setActiveClassNameState,
|
|
2226
|
+
forceUpdateBounds: props?.forceUpdateBounds
|
|
2227
|
+
},
|
|
2228
|
+
children: enabled ? controlledItems ? render(children) : render(
|
|
2229
|
+
React18.Children.map(children, (child, index) => /* @__PURE__ */ jsx(HighlightItem, { className: props?.itemsClassName, children: child }, index))
|
|
2230
|
+
) : children
|
|
2231
|
+
}
|
|
2232
|
+
);
|
|
2233
|
+
}
|
|
2234
|
+
function getNonOverridingDataAttributes(element, dataAttributes) {
|
|
2235
|
+
return Object.keys(dataAttributes).reduce(
|
|
2236
|
+
(acc, key) => {
|
|
2237
|
+
if (element.props[key] === void 0) {
|
|
2238
|
+
acc[key] = dataAttributes[key];
|
|
2239
|
+
}
|
|
2240
|
+
return acc;
|
|
2241
|
+
},
|
|
2242
|
+
{}
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
function HighlightItem({
|
|
2246
|
+
ref,
|
|
2247
|
+
as,
|
|
2248
|
+
children,
|
|
2249
|
+
id,
|
|
2250
|
+
value,
|
|
2251
|
+
className,
|
|
2252
|
+
style,
|
|
2253
|
+
transition,
|
|
2254
|
+
disabled = false,
|
|
2255
|
+
activeClassName,
|
|
2256
|
+
exitDelay,
|
|
2257
|
+
asChild = false,
|
|
2258
|
+
forceUpdateBounds,
|
|
2259
|
+
...props
|
|
2260
|
+
}) {
|
|
2261
|
+
const itemId = React18.useId();
|
|
2262
|
+
const {
|
|
2263
|
+
activeValue,
|
|
2264
|
+
setActiveValue,
|
|
2265
|
+
mode,
|
|
2266
|
+
setBounds,
|
|
2267
|
+
clearBounds,
|
|
2268
|
+
hover,
|
|
2269
|
+
click,
|
|
2270
|
+
enabled,
|
|
2271
|
+
className: contextClassName,
|
|
2272
|
+
style: contextStyle,
|
|
2273
|
+
transition: contextTransition,
|
|
2274
|
+
id: contextId,
|
|
2275
|
+
disabled: contextDisabled,
|
|
2276
|
+
exitDelay: contextExitDelay,
|
|
2277
|
+
forceUpdateBounds: contextForceUpdateBounds,
|
|
2278
|
+
setActiveClassName
|
|
2279
|
+
} = useHighlight();
|
|
2280
|
+
const Component = as ?? "div";
|
|
2281
|
+
const element = children;
|
|
2282
|
+
const childValue = id ?? value ?? element.props?.["data-value"] ?? element.props?.id ?? itemId;
|
|
2283
|
+
const isActive = activeValue === childValue;
|
|
2284
|
+
const isDisabled = disabled === void 0 ? contextDisabled : disabled;
|
|
2285
|
+
const itemTransition = transition ?? contextTransition;
|
|
2286
|
+
const localRef = React18.useRef(null);
|
|
2287
|
+
React18.useImperativeHandle(ref, () => localRef.current);
|
|
2288
|
+
const refCallback = React18.useCallback((node) => {
|
|
2289
|
+
localRef.current = node;
|
|
2290
|
+
}, []);
|
|
2291
|
+
React18.useEffect(() => {
|
|
2292
|
+
if (mode !== "parent") return;
|
|
2293
|
+
let rafId;
|
|
2294
|
+
let previousBounds = null;
|
|
2295
|
+
const shouldUpdateBounds = forceUpdateBounds === true || contextForceUpdateBounds && forceUpdateBounds !== false;
|
|
2296
|
+
const updateBounds = () => {
|
|
2297
|
+
if (!localRef.current) return;
|
|
2298
|
+
const bounds = localRef.current.getBoundingClientRect();
|
|
2299
|
+
if (shouldUpdateBounds) {
|
|
2300
|
+
if (previousBounds && previousBounds.top === bounds.top && previousBounds.left === bounds.left && previousBounds.width === bounds.width && previousBounds.height === bounds.height) {
|
|
2301
|
+
rafId = requestAnimationFrame(updateBounds);
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
previousBounds = bounds;
|
|
2305
|
+
rafId = requestAnimationFrame(updateBounds);
|
|
2306
|
+
}
|
|
2307
|
+
setBounds(bounds);
|
|
2308
|
+
};
|
|
2309
|
+
if (isActive) {
|
|
2310
|
+
updateBounds();
|
|
2311
|
+
setActiveClassName(activeClassName ?? "");
|
|
2312
|
+
} else if (!activeValue) clearBounds();
|
|
2313
|
+
if (shouldUpdateBounds) return () => cancelAnimationFrame(rafId);
|
|
2314
|
+
}, [
|
|
2315
|
+
mode,
|
|
2316
|
+
isActive,
|
|
2317
|
+
activeValue,
|
|
2318
|
+
setBounds,
|
|
2319
|
+
clearBounds,
|
|
2320
|
+
activeClassName,
|
|
2321
|
+
setActiveClassName,
|
|
2322
|
+
forceUpdateBounds,
|
|
2323
|
+
contextForceUpdateBounds
|
|
2324
|
+
]);
|
|
2325
|
+
if (!React18.isValidElement(children)) return children;
|
|
2326
|
+
const dataAttributes = {
|
|
2327
|
+
"data-active": isActive ? "true" : "false",
|
|
2328
|
+
"aria-selected": isActive,
|
|
2329
|
+
"data-disabled": isDisabled,
|
|
2330
|
+
"data-value": childValue,
|
|
2331
|
+
"data-highlight": true
|
|
2332
|
+
};
|
|
2333
|
+
const commonHandlers = hover ? {
|
|
2334
|
+
onMouseEnter: (e) => {
|
|
2335
|
+
setActiveValue(childValue);
|
|
2336
|
+
element.props.onMouseEnter?.(e);
|
|
2337
|
+
},
|
|
2338
|
+
onMouseLeave: (e) => {
|
|
2339
|
+
setActiveValue(null);
|
|
2340
|
+
element.props.onMouseLeave?.(e);
|
|
2341
|
+
}
|
|
2342
|
+
} : click ? {
|
|
2343
|
+
onClick: (e) => {
|
|
2344
|
+
setActiveValue(childValue);
|
|
2345
|
+
element.props.onClick?.(e);
|
|
2346
|
+
}
|
|
2347
|
+
} : {};
|
|
2348
|
+
if (asChild) {
|
|
2349
|
+
if (mode === "children") {
|
|
2350
|
+
return React18.cloneElement(
|
|
2351
|
+
element,
|
|
2352
|
+
{
|
|
2353
|
+
key: childValue,
|
|
2354
|
+
ref: refCallback,
|
|
2355
|
+
className: cn("relative", element.props.className),
|
|
2356
|
+
...getNonOverridingDataAttributes(element, {
|
|
2357
|
+
...dataAttributes,
|
|
2358
|
+
"data-slot": "motion-highlight-item-container"
|
|
2359
|
+
}),
|
|
2360
|
+
...commonHandlers,
|
|
2361
|
+
...props
|
|
2362
|
+
},
|
|
2363
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2364
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: isActive && !isDisabled && /* @__PURE__ */ jsx(
|
|
2365
|
+
motion.div,
|
|
2366
|
+
{
|
|
2367
|
+
layoutId: `transition-background-${contextId}`,
|
|
2368
|
+
"data-slot": "motion-highlight",
|
|
2369
|
+
style: {
|
|
2370
|
+
position: "absolute",
|
|
2371
|
+
zIndex: 0,
|
|
2372
|
+
...contextStyle,
|
|
2373
|
+
...style
|
|
2374
|
+
},
|
|
2375
|
+
className: cn(contextClassName, activeClassName),
|
|
2376
|
+
transition: itemTransition,
|
|
2377
|
+
initial: { opacity: 0 },
|
|
2378
|
+
animate: { opacity: 1 },
|
|
2379
|
+
exit: {
|
|
2380
|
+
opacity: 0,
|
|
2381
|
+
transition: {
|
|
2382
|
+
...itemTransition,
|
|
2383
|
+
delay: (itemTransition?.delay ?? 0) + (exitDelay ?? contextExitDelay ?? 0) / 1e3
|
|
2384
|
+
}
|
|
2385
|
+
},
|
|
2386
|
+
...dataAttributes
|
|
2387
|
+
}
|
|
2388
|
+
) }),
|
|
2389
|
+
/* @__PURE__ */ jsx(
|
|
2390
|
+
Component,
|
|
2391
|
+
{
|
|
2392
|
+
"data-slot": "motion-highlight-item",
|
|
2393
|
+
style: { position: "relative", zIndex: 1 },
|
|
2394
|
+
className,
|
|
2395
|
+
...dataAttributes,
|
|
2396
|
+
children
|
|
2397
|
+
}
|
|
2398
|
+
)
|
|
2399
|
+
] })
|
|
2400
|
+
);
|
|
2401
|
+
}
|
|
2402
|
+
return React18.cloneElement(element, {
|
|
2403
|
+
ref: refCallback,
|
|
2404
|
+
...getNonOverridingDataAttributes(element, {
|
|
2405
|
+
...dataAttributes,
|
|
2406
|
+
"data-slot": "motion-highlight-item"
|
|
2407
|
+
}),
|
|
2408
|
+
...commonHandlers
|
|
2409
|
+
});
|
|
2410
|
+
}
|
|
2411
|
+
return enabled ? /* @__PURE__ */ jsxs(
|
|
2412
|
+
Component,
|
|
2413
|
+
{
|
|
2414
|
+
ref: localRef,
|
|
2415
|
+
"data-slot": "motion-highlight-item-container",
|
|
2416
|
+
className: cn(mode === "children" && "relative", className),
|
|
2417
|
+
...dataAttributes,
|
|
2418
|
+
...props,
|
|
2419
|
+
...commonHandlers,
|
|
2420
|
+
children: [
|
|
2421
|
+
mode === "children" && /* @__PURE__ */ jsx(AnimatePresence, { initial: false, mode: "wait", children: isActive && !isDisabled && /* @__PURE__ */ jsx(
|
|
2422
|
+
motion.div,
|
|
2423
|
+
{
|
|
2424
|
+
layoutId: `transition-background-${contextId}`,
|
|
2425
|
+
"data-slot": "motion-highlight",
|
|
2426
|
+
style: {
|
|
2427
|
+
position: "absolute",
|
|
2428
|
+
zIndex: 0,
|
|
2429
|
+
...contextStyle,
|
|
2430
|
+
...style
|
|
2431
|
+
},
|
|
2432
|
+
className: cn(contextClassName, activeClassName),
|
|
2433
|
+
transition: itemTransition,
|
|
2434
|
+
initial: { opacity: 0 },
|
|
2435
|
+
animate: { opacity: 1 },
|
|
2436
|
+
exit: {
|
|
2437
|
+
opacity: 0,
|
|
2438
|
+
transition: {
|
|
2439
|
+
...itemTransition,
|
|
2440
|
+
delay: (itemTransition?.delay ?? 0) + (exitDelay ?? contextExitDelay ?? 0) / 1e3
|
|
2441
|
+
}
|
|
2442
|
+
},
|
|
2443
|
+
...dataAttributes
|
|
2444
|
+
}
|
|
2445
|
+
) }),
|
|
2446
|
+
React18.cloneElement(element, {
|
|
2447
|
+
style: { position: "relative", zIndex: 1 },
|
|
2448
|
+
className: element.props.className,
|
|
2449
|
+
...getNonOverridingDataAttributes(element, {
|
|
2450
|
+
...dataAttributes,
|
|
2451
|
+
"data-slot": "motion-highlight-item"
|
|
2452
|
+
})
|
|
2453
|
+
})
|
|
2454
|
+
]
|
|
2455
|
+
},
|
|
2456
|
+
childValue
|
|
2457
|
+
) : children;
|
|
2458
|
+
}
|
|
2459
|
+
function mergeRefs(...refs) {
|
|
2460
|
+
return (node) => {
|
|
2461
|
+
refs.forEach((ref) => {
|
|
2462
|
+
if (!ref) return;
|
|
2463
|
+
if (typeof ref === "function") {
|
|
2464
|
+
ref(node);
|
|
2465
|
+
} else {
|
|
2466
|
+
ref.current = node;
|
|
2467
|
+
}
|
|
2468
|
+
});
|
|
2469
|
+
};
|
|
2470
|
+
}
|
|
2471
|
+
function mergeProps4(childProps, slotProps) {
|
|
2472
|
+
const merged = { ...childProps, ...slotProps };
|
|
2473
|
+
if (childProps.className || slotProps.className) {
|
|
2474
|
+
merged.className = cn(
|
|
2475
|
+
childProps.className,
|
|
2476
|
+
slotProps.className
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
if (childProps.style || slotProps.style) {
|
|
2480
|
+
merged.style = {
|
|
2481
|
+
...childProps.style,
|
|
2482
|
+
...slotProps.style
|
|
2483
|
+
};
|
|
2484
|
+
}
|
|
2485
|
+
return merged;
|
|
2486
|
+
}
|
|
2487
|
+
function Slot({
|
|
2488
|
+
children,
|
|
2489
|
+
ref,
|
|
2490
|
+
...props
|
|
2491
|
+
}) {
|
|
2492
|
+
const isAlreadyMotion = typeof children.type === "object" && children.type !== null && isMotionComponent(children.type);
|
|
2493
|
+
const Base = React18.useMemo(
|
|
2494
|
+
() => isAlreadyMotion ? children.type : motion.create(children.type),
|
|
2495
|
+
[isAlreadyMotion, children.type]
|
|
2496
|
+
);
|
|
2497
|
+
if (!React18.isValidElement(children)) return null;
|
|
2498
|
+
const { ref: childRef, ...childProps } = children.props;
|
|
2499
|
+
const mergedProps = mergeProps4(childProps, props);
|
|
2500
|
+
return /* @__PURE__ */ jsx(Base, { ...mergedProps, ref: mergeRefs(childRef, ref) });
|
|
2501
|
+
}
|
|
2502
|
+
var [TabsProvider, useTabs] = getStrictContext("TabsContext");
|
|
2503
|
+
function Tabs(props) {
|
|
2504
|
+
const [value, setValue] = useControlledState({
|
|
2505
|
+
value: props.value,
|
|
2506
|
+
defaultValue: props.defaultValue,
|
|
2507
|
+
onChange: props.onValueChange
|
|
2508
|
+
});
|
|
2509
|
+
return /* @__PURE__ */ jsx(TabsProvider, { value: { value, setValue }, children: /* @__PURE__ */ jsx(
|
|
2510
|
+
Tabs$1.Root,
|
|
2511
|
+
{
|
|
2512
|
+
"data-slot": "tabs",
|
|
2513
|
+
...props,
|
|
2514
|
+
onValueChange: setValue
|
|
2515
|
+
}
|
|
2516
|
+
) });
|
|
2517
|
+
}
|
|
2518
|
+
function TabsHighlight({
|
|
2519
|
+
transition = { type: "spring", stiffness: 200, damping: 25 },
|
|
2520
|
+
...props
|
|
2521
|
+
}) {
|
|
2522
|
+
const { value } = useTabs();
|
|
2523
|
+
return /* @__PURE__ */ jsx(
|
|
2524
|
+
Highlight,
|
|
2525
|
+
{
|
|
2526
|
+
"data-slot": "tabs-highlight",
|
|
2527
|
+
controlledItems: true,
|
|
2528
|
+
value,
|
|
2529
|
+
transition,
|
|
2530
|
+
click: false,
|
|
2531
|
+
...props
|
|
2532
|
+
}
|
|
2533
|
+
);
|
|
2534
|
+
}
|
|
2535
|
+
function TabsList(props) {
|
|
2536
|
+
return /* @__PURE__ */ jsx(Tabs$1.List, { "data-slot": "tabs-list", ...props });
|
|
2537
|
+
}
|
|
2538
|
+
function TabsHighlightItem(props) {
|
|
2539
|
+
return /* @__PURE__ */ jsx(HighlightItem, { "data-slot": "tabs-highlight-item", ...props });
|
|
2540
|
+
}
|
|
2541
|
+
function TabsTab(props) {
|
|
2542
|
+
return /* @__PURE__ */ jsx(Tabs$1.Tab, { "data-slot": "tabs-tab", ...props });
|
|
2543
|
+
}
|
|
2544
|
+
function Tabs2({ className, ...props }) {
|
|
2545
|
+
return /* @__PURE__ */ jsx(
|
|
2546
|
+
Tabs,
|
|
2547
|
+
{
|
|
2548
|
+
className: cn("flex flex-col gap-2", className),
|
|
2549
|
+
...props
|
|
2550
|
+
}
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
function TabsList2({ className, ...props }) {
|
|
2554
|
+
return /* @__PURE__ */ jsx(TabsHighlight, { className: "absolute z-0 inset-0 border border-transparent rounded-md bg-background dark:border-input dark:bg-input/30 shadow-sm", children: /* @__PURE__ */ jsx(
|
|
2555
|
+
TabsList,
|
|
2556
|
+
{
|
|
2557
|
+
className: cn(
|
|
2558
|
+
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
|
2559
|
+
className
|
|
2560
|
+
),
|
|
2561
|
+
...props
|
|
2562
|
+
}
|
|
2563
|
+
) });
|
|
2564
|
+
}
|
|
2565
|
+
function TabsTab2({ className, ...props }) {
|
|
2566
|
+
return /* @__PURE__ */ jsx(TabsHighlightItem, { value: props.value, className: "flex-1", children: /* @__PURE__ */ jsx(
|
|
2567
|
+
TabsTab,
|
|
2568
|
+
{
|
|
2569
|
+
className: cn(
|
|
2570
|
+
"data-[selected]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md w-full px-2 py-1 text-sm font-medium whitespace-nowrap transition-colors duration-500 ease-in-out focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
2571
|
+
className
|
|
2572
|
+
),
|
|
2573
|
+
...props
|
|
2574
|
+
}
|
|
2575
|
+
) });
|
|
2576
|
+
}
|
|
2577
|
+
function Aside() {
|
|
2578
|
+
const activeTab = useActiveTab();
|
|
2579
|
+
const setActiveTab = useSetActiveTab();
|
|
2580
|
+
const tabs = [
|
|
2581
|
+
{ value: "insert", icon: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }), label: useMsg("aside.insert") },
|
|
2582
|
+
{ value: "layer", icon: /* @__PURE__ */ jsx(Layers2, { className: "h-4 w-4" }), label: useMsg("aside.layer") },
|
|
2583
|
+
{ value: "image", icon: /* @__PURE__ */ jsx(Image, { className: "h-4 w-4" }), label: useMsg("aside.image") },
|
|
2584
|
+
{ value: "text", icon: /* @__PURE__ */ jsx(Type, { className: "h-4 w-4" }), label: useMsg("aside.text") },
|
|
2585
|
+
{ value: "copilot", icon: /* @__PURE__ */ jsx(Bot, { className: "h-4 w-4" }), label: useMsg("aside.copilot") }
|
|
2586
|
+
];
|
|
2587
|
+
return /* @__PURE__ */ jsx("div", { className: "w-18 h-full py-4 border-r border-neutral-200 dark:border-neutral-800/80", children: /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(Tabs2, { value: activeTab, onValueChange: setActiveTab, className: "w-full flex items-center justify-center", children: /* @__PURE__ */ jsx(TabsList2, { className: "flex-col h-auto bg-transparent gap-2", children: tabs.map(({ value, icon, label }) => /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
2588
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(TabsTab2, { value, className: "p-2", children: icon }) }) }),
|
|
2589
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "right", children: label })
|
|
2590
|
+
] }, value)) }) }) }) });
|
|
2591
|
+
}
|
|
2592
|
+
function AnimatedAsana({
|
|
2593
|
+
trigger = false,
|
|
2594
|
+
useTrigger = true,
|
|
2595
|
+
// Enable hover trigger by default
|
|
2596
|
+
animationDuration = 400,
|
|
2597
|
+
// Default animation duration
|
|
2598
|
+
springConfig = {
|
|
2599
|
+
stiffness: 180,
|
|
2600
|
+
damping: 15,
|
|
2601
|
+
mass: 1
|
|
2602
|
+
},
|
|
2603
|
+
priority = false,
|
|
2604
|
+
// Default non-priority
|
|
2605
|
+
...props
|
|
2606
|
+
}) {
|
|
2607
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
2608
|
+
const [animationPhase, setAnimationPhase] = useState("three-circles");
|
|
2609
|
+
const animationTimerRef = useRef(null);
|
|
2610
|
+
const animationStartedRef = useRef(false);
|
|
2611
|
+
const effectiveTrigger = useMemo(
|
|
2612
|
+
() => trigger || useTrigger && isHovered,
|
|
2613
|
+
[trigger, useTrigger, isHovered]
|
|
2614
|
+
);
|
|
2615
|
+
const springTransition = useMemo(
|
|
2616
|
+
() => ({
|
|
2617
|
+
type: "spring",
|
|
2618
|
+
stiffness: springConfig.stiffness,
|
|
2619
|
+
damping: springConfig.damping,
|
|
2620
|
+
mass: springConfig.mass
|
|
2621
|
+
}),
|
|
2622
|
+
[springConfig.stiffness, springConfig.damping, springConfig.mass]
|
|
2623
|
+
);
|
|
2624
|
+
const handleMouseEnter = useCallback(() => {
|
|
2625
|
+
if (useTrigger) {
|
|
2626
|
+
setIsHovered(true);
|
|
2627
|
+
}
|
|
2628
|
+
}, [useTrigger]);
|
|
2629
|
+
const handleMouseLeave = useCallback(() => {
|
|
2630
|
+
if (useTrigger) {
|
|
2631
|
+
setIsHovered(false);
|
|
2632
|
+
}
|
|
2633
|
+
}, [useTrigger]);
|
|
2634
|
+
useEffect(() => {
|
|
2635
|
+
if (animationTimerRef.current) {
|
|
2636
|
+
clearTimeout(animationTimerRef.current);
|
|
2637
|
+
animationTimerRef.current = null;
|
|
2638
|
+
}
|
|
2639
|
+
if (effectiveTrigger) {
|
|
2640
|
+
animationStartedRef.current = true;
|
|
2641
|
+
setAnimationPhase("one-circle");
|
|
2642
|
+
animationTimerRef.current = setTimeout(() => {
|
|
2643
|
+
setAnimationPhase("three-circles");
|
|
2644
|
+
animationTimerRef.current = null;
|
|
2645
|
+
}, animationDuration);
|
|
2646
|
+
} else if (animationStartedRef.current) {
|
|
2647
|
+
setAnimationPhase("three-circles");
|
|
2648
|
+
animationStartedRef.current = false;
|
|
2649
|
+
}
|
|
2650
|
+
return () => {
|
|
2651
|
+
if (animationTimerRef.current) {
|
|
2652
|
+
clearTimeout(animationTimerRef.current);
|
|
2653
|
+
animationTimerRef.current = null;
|
|
2654
|
+
}
|
|
2655
|
+
};
|
|
2656
|
+
}, [effectiveTrigger, animationDuration]);
|
|
2657
|
+
const centerCircleAnimation = useMemo(
|
|
2658
|
+
() => ({
|
|
2659
|
+
opacity: animationPhase === "one-circle" ? 1 : 0,
|
|
2660
|
+
scale: animationPhase === "one-circle" ? 1 : 0
|
|
2661
|
+
}),
|
|
2662
|
+
[animationPhase]
|
|
2663
|
+
);
|
|
2664
|
+
const topCircleAnimation = useMemo(
|
|
2665
|
+
() => ({
|
|
2666
|
+
opacity: animationPhase === "three-circles" ? 1 : 0,
|
|
2667
|
+
y: animationPhase === "three-circles" ? 0 : 4.5,
|
|
2668
|
+
scale: animationPhase === "three-circles" ? 1 : 0
|
|
2669
|
+
}),
|
|
2670
|
+
[animationPhase]
|
|
2671
|
+
);
|
|
2672
|
+
const leftBottomCircleAnimation = useMemo(
|
|
2673
|
+
() => ({
|
|
2674
|
+
opacity: animationPhase === "three-circles" ? 1 : 0,
|
|
2675
|
+
x: animationPhase === "three-circles" ? 0 : 5,
|
|
2676
|
+
y: animationPhase === "three-circles" ? 0 : -4.5,
|
|
2677
|
+
scale: animationPhase === "three-circles" ? 1 : 0
|
|
2678
|
+
}),
|
|
2679
|
+
[animationPhase]
|
|
2680
|
+
);
|
|
2681
|
+
const rightBottomCircleAnimation = useMemo(
|
|
2682
|
+
() => ({
|
|
2683
|
+
opacity: animationPhase === "three-circles" ? 1 : 0,
|
|
2684
|
+
x: animationPhase === "three-circles" ? 0 : -5,
|
|
2685
|
+
y: animationPhase === "three-circles" ? 0 : -4.5,
|
|
2686
|
+
scale: animationPhase === "three-circles" ? 1 : 0
|
|
2687
|
+
}),
|
|
2688
|
+
[animationPhase]
|
|
2689
|
+
);
|
|
2690
|
+
return /* @__PURE__ */ jsxs(
|
|
2691
|
+
"svg",
|
|
2692
|
+
{
|
|
2693
|
+
width: "1em",
|
|
2694
|
+
height: "1em",
|
|
2695
|
+
strokeWidth: "1.5",
|
|
2696
|
+
viewBox: "0 0 24 24",
|
|
2697
|
+
fill: "none",
|
|
2698
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2699
|
+
color: "currentColor",
|
|
2700
|
+
onMouseEnter: handleMouseEnter,
|
|
2701
|
+
onMouseLeave: handleMouseLeave,
|
|
2702
|
+
role: "img",
|
|
2703
|
+
"aria-label": "Asana logo",
|
|
2704
|
+
style: { touchAction: "none" },
|
|
2705
|
+
"data-testid": "asana-icon",
|
|
2706
|
+
...props,
|
|
2707
|
+
children: [
|
|
2708
|
+
/* @__PURE__ */ jsx(
|
|
2709
|
+
motion.circle,
|
|
2710
|
+
{
|
|
2711
|
+
cx: 12,
|
|
2712
|
+
cy: 12,
|
|
2713
|
+
r: 6,
|
|
2714
|
+
stroke: "currentColor",
|
|
2715
|
+
strokeWidth: "1.5",
|
|
2716
|
+
strokeLinecap: "round",
|
|
2717
|
+
strokeLinejoin: "round",
|
|
2718
|
+
fill: "none",
|
|
2719
|
+
initial: { opacity: 0, scale: 0 },
|
|
2720
|
+
animate: centerCircleAnimation,
|
|
2721
|
+
transition: {
|
|
2722
|
+
opacity: { duration: 0.2 },
|
|
2723
|
+
scale: { ...springTransition, duration: 0.3 }
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
),
|
|
2727
|
+
/* @__PURE__ */ jsx(
|
|
2728
|
+
motion.path,
|
|
2729
|
+
{
|
|
2730
|
+
d: "M12 11.5C14.2091 11.5 16 9.70914 16 7.5C16 5.29086 14.2091 3.5 12 3.5C9.79086 3.5 8 5.29086 8 7.5C8 9.70914 9.79086 11.5 12 11.5Z",
|
|
2731
|
+
stroke: "currentColor",
|
|
2732
|
+
strokeWidth: "1.5",
|
|
2733
|
+
strokeLinecap: "round",
|
|
2734
|
+
strokeLinejoin: "round",
|
|
2735
|
+
fill: "none",
|
|
2736
|
+
initial: { opacity: 1, y: 0, scale: 1 },
|
|
2737
|
+
animate: topCircleAnimation,
|
|
2738
|
+
transition: {
|
|
2739
|
+
...springTransition,
|
|
2740
|
+
delay: animationPhase === "three-circles" ? 0.1 : 0
|
|
2741
|
+
}
|
|
2742
|
+
}
|
|
2743
|
+
),
|
|
2744
|
+
/* @__PURE__ */ jsx(
|
|
2745
|
+
motion.path,
|
|
2746
|
+
{
|
|
2747
|
+
d: "M7 20.5C9.20914 20.5 11 18.7091 11 16.5C11 14.2909 9.20914 12.5 7 12.5C4.79086 12.5 3 14.2909 3 16.5C3 18.7091 4.79086 20.5 7 20.5Z",
|
|
2748
|
+
stroke: "currentColor",
|
|
2749
|
+
strokeWidth: "1.5",
|
|
2750
|
+
strokeLinecap: "round",
|
|
2751
|
+
strokeLinejoin: "round",
|
|
2752
|
+
fill: "none",
|
|
2753
|
+
initial: { opacity: 1, x: 0, y: 0, scale: 1 },
|
|
2754
|
+
animate: leftBottomCircleAnimation,
|
|
2755
|
+
transition: {
|
|
2756
|
+
...springTransition,
|
|
2757
|
+
delay: animationPhase === "three-circles" ? 0.15 : 0.05
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
),
|
|
2761
|
+
/* @__PURE__ */ jsx(
|
|
2762
|
+
motion.path,
|
|
2763
|
+
{
|
|
2764
|
+
d: "M17 20.5C19.2091 20.5 21 18.7091 21 16.5C21 14.2909 19.2091 12.5 17 12.5C14.7909 12.5 13 14.2909 13 16.5C13 18.7091 14.7909 20.5 17 20.5Z",
|
|
2765
|
+
stroke: "currentColor",
|
|
2766
|
+
strokeWidth: "1.5",
|
|
2767
|
+
strokeLinecap: "round",
|
|
2768
|
+
strokeLinejoin: "round",
|
|
2769
|
+
fill: "none",
|
|
2770
|
+
initial: { opacity: 1, x: 0, y: 0, scale: 1 },
|
|
2771
|
+
animate: rightBottomCircleAnimation,
|
|
2772
|
+
transition: {
|
|
2773
|
+
...springTransition,
|
|
2774
|
+
delay: animationPhase === "three-circles" ? 0.2 : 0.1
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
)
|
|
2778
|
+
]
|
|
2779
|
+
}
|
|
2780
|
+
);
|
|
2781
|
+
}
|
|
2782
|
+
React18__default.memo(function TriggerableAsana2(props) {
|
|
2783
|
+
return /* @__PURE__ */ jsx(AnimatedAsana, { useTrigger: true, ...props });
|
|
2784
|
+
});
|
|
2785
|
+
React18__default.memo(function ControlledAsana2(props) {
|
|
2786
|
+
return /* @__PURE__ */ jsx(AnimatedAsana, { useTrigger: false, ...props });
|
|
2787
|
+
});
|
|
2788
|
+
var [GlobalTooltipProvider, useGlobalTooltip] = getStrictContext("GlobalTooltipProvider");
|
|
2789
|
+
var [LocalTooltipProvider, useTooltip] = getStrictContext(
|
|
2790
|
+
"LocalTooltipProvider"
|
|
2791
|
+
);
|
|
2792
|
+
function getResolvedSide(placement) {
|
|
2793
|
+
if (placement.includes("-")) {
|
|
2794
|
+
return placement.split("-")[0];
|
|
2795
|
+
}
|
|
2796
|
+
return placement;
|
|
2797
|
+
}
|
|
2798
|
+
function initialFromSide(side) {
|
|
2799
|
+
if (side === "top") return { y: 15 };
|
|
2800
|
+
if (side === "bottom") return { y: -15 };
|
|
2801
|
+
if (side === "left") return { x: 15 };
|
|
2802
|
+
return { x: -15 };
|
|
2803
|
+
}
|
|
2804
|
+
function TooltipProvider2({
|
|
2805
|
+
children,
|
|
2806
|
+
id,
|
|
2807
|
+
openDelay = 700,
|
|
2808
|
+
closeDelay = 300,
|
|
2809
|
+
transition = { type: "spring", stiffness: 300, damping: 35 }
|
|
2810
|
+
}) {
|
|
2811
|
+
const globalId = React18.useId();
|
|
2812
|
+
const [currentTooltip, setCurrentTooltip] = React18.useState(null);
|
|
2813
|
+
const timeoutRef = React18.useRef(null);
|
|
2814
|
+
const lastCloseTimeRef = React18.useRef(0);
|
|
2815
|
+
const referenceElRef = React18.useRef(null);
|
|
2816
|
+
const showTooltip = React18.useCallback(
|
|
2817
|
+
(data) => {
|
|
2818
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
2819
|
+
if (currentTooltip !== null) {
|
|
2820
|
+
setCurrentTooltip(data);
|
|
2821
|
+
return;
|
|
2822
|
+
}
|
|
2823
|
+
const now = Date.now();
|
|
2824
|
+
const delay = now - lastCloseTimeRef.current < closeDelay ? 0 : openDelay;
|
|
2825
|
+
timeoutRef.current = window.setTimeout(
|
|
2826
|
+
() => setCurrentTooltip(data),
|
|
2827
|
+
delay
|
|
2828
|
+
);
|
|
2829
|
+
},
|
|
2830
|
+
[openDelay, closeDelay, currentTooltip]
|
|
2831
|
+
);
|
|
2832
|
+
const hideTooltip = React18.useCallback(() => {
|
|
2833
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
2834
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
2835
|
+
setCurrentTooltip(null);
|
|
2836
|
+
lastCloseTimeRef.current = Date.now();
|
|
2837
|
+
}, closeDelay);
|
|
2838
|
+
}, [closeDelay]);
|
|
2839
|
+
const hideImmediate = React18.useCallback(() => {
|
|
2840
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
2841
|
+
setCurrentTooltip(null);
|
|
2842
|
+
lastCloseTimeRef.current = Date.now();
|
|
2843
|
+
}, []);
|
|
2844
|
+
const setReferenceEl = React18.useCallback((el) => {
|
|
2845
|
+
referenceElRef.current = el;
|
|
2846
|
+
}, []);
|
|
2847
|
+
React18.useEffect(() => {
|
|
2848
|
+
const onKeyDown = (e) => {
|
|
2849
|
+
if (e.key === "Escape") hideImmediate();
|
|
2850
|
+
};
|
|
2851
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
2852
|
+
window.addEventListener("scroll", hideImmediate, true);
|
|
2853
|
+
window.addEventListener("resize", hideImmediate, true);
|
|
2854
|
+
return () => {
|
|
2855
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
2856
|
+
window.removeEventListener("scroll", hideImmediate, true);
|
|
2857
|
+
window.removeEventListener("resize", hideImmediate, true);
|
|
2858
|
+
};
|
|
2859
|
+
}, [hideImmediate]);
|
|
2860
|
+
return /* @__PURE__ */ jsxs(
|
|
2861
|
+
GlobalTooltipProvider,
|
|
2862
|
+
{
|
|
2863
|
+
value: {
|
|
2864
|
+
showTooltip,
|
|
2865
|
+
hideTooltip,
|
|
2866
|
+
hideImmediate,
|
|
2867
|
+
currentTooltip,
|
|
2868
|
+
transition,
|
|
2869
|
+
globalId: id ?? globalId,
|
|
2870
|
+
setReferenceEl,
|
|
2871
|
+
referenceElRef
|
|
2872
|
+
},
|
|
2873
|
+
children: [
|
|
2874
|
+
/* @__PURE__ */ jsx(LayoutGroup, { children }),
|
|
2875
|
+
/* @__PURE__ */ jsx(TooltipOverlay, {})
|
|
2876
|
+
]
|
|
2877
|
+
}
|
|
2878
|
+
);
|
|
2879
|
+
}
|
|
2880
|
+
var [RenderedTooltipProvider, useRenderedTooltip] = getStrictContext("RenderedTooltipContext");
|
|
2881
|
+
var [FloatingProvider, useFloatingContext] = getStrictContext("FloatingContext");
|
|
2882
|
+
var MotionTooltipArrow = motion.create(FloatingArrow);
|
|
2883
|
+
function TooltipArrow({
|
|
2884
|
+
ref,
|
|
2885
|
+
withTransition = true,
|
|
2886
|
+
...props
|
|
2887
|
+
}) {
|
|
2888
|
+
const { side, align, open } = useRenderedTooltip();
|
|
2889
|
+
const { context, arrowRef } = useFloatingContext();
|
|
2890
|
+
const { transition, globalId } = useGlobalTooltip();
|
|
2891
|
+
React18.useImperativeHandle(ref, () => arrowRef.current);
|
|
2892
|
+
const deg = { top: 0, right: 90, bottom: 180, left: -90 }[side];
|
|
2893
|
+
return /* @__PURE__ */ jsx(
|
|
2894
|
+
MotionTooltipArrow,
|
|
2895
|
+
{
|
|
2896
|
+
ref: arrowRef,
|
|
2897
|
+
context,
|
|
2898
|
+
"data-state": open ? "open" : "closed",
|
|
2899
|
+
"data-side": side,
|
|
2900
|
+
"data-align": align,
|
|
2901
|
+
"data-slot": "tooltip-arrow",
|
|
2902
|
+
style: { rotate: deg },
|
|
2903
|
+
layoutId: withTransition ? `tooltip-arrow-${globalId}` : void 0,
|
|
2904
|
+
transition: withTransition ? transition : void 0,
|
|
2905
|
+
...props
|
|
2906
|
+
}
|
|
2907
|
+
);
|
|
2908
|
+
}
|
|
2909
|
+
function TooltipPortal(props) {
|
|
2910
|
+
return /* @__PURE__ */ jsx(FloatingPortal, { ...props });
|
|
2911
|
+
}
|
|
2912
|
+
function TooltipOverlay() {
|
|
2913
|
+
const { currentTooltip, transition, globalId, referenceElRef } = useGlobalTooltip();
|
|
2914
|
+
const [rendered, setRendered] = React18.useState({ data: null, open: false });
|
|
2915
|
+
const arrowRef = React18.useRef(null);
|
|
2916
|
+
const side = rendered.data?.side ?? "top";
|
|
2917
|
+
const align = rendered.data?.align ?? "center";
|
|
2918
|
+
const { refs, x, y, strategy, context, update } = useFloating({
|
|
2919
|
+
placement: align === "center" ? side : `${side}-${align}`,
|
|
2920
|
+
whileElementsMounted: autoUpdate,
|
|
2921
|
+
middleware: [
|
|
2922
|
+
offset({
|
|
2923
|
+
mainAxis: rendered.data?.sideOffset ?? 0,
|
|
2924
|
+
crossAxis: rendered.data?.alignOffset ?? 0
|
|
2925
|
+
}),
|
|
2926
|
+
flip(),
|
|
2927
|
+
shift({ padding: 8 }),
|
|
2928
|
+
arrow({ element: arrowRef })
|
|
2929
|
+
]
|
|
2930
|
+
});
|
|
2931
|
+
React18.useEffect(() => {
|
|
2932
|
+
if (currentTooltip) {
|
|
2933
|
+
setRendered({ data: currentTooltip, open: true });
|
|
2934
|
+
} else {
|
|
2935
|
+
setRendered((p) => p.data ? { ...p, open: false } : p);
|
|
2936
|
+
}
|
|
2937
|
+
}, [currentTooltip]);
|
|
2938
|
+
React18.useLayoutEffect(() => {
|
|
2939
|
+
if (referenceElRef.current) {
|
|
2940
|
+
refs.setReference(referenceElRef.current);
|
|
2941
|
+
update();
|
|
2942
|
+
}
|
|
2943
|
+
}, [referenceElRef, refs, update, rendered.data]);
|
|
2944
|
+
const ready = x != null && y != null;
|
|
2945
|
+
const Component = rendered.data?.contentAsChild ? Slot : motion.div;
|
|
2946
|
+
const resolvedSide = getResolvedSide(context.placement);
|
|
2947
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: rendered.data && ready && /* @__PURE__ */ jsx(TooltipPortal, { children: /* @__PURE__ */ jsx(
|
|
2948
|
+
"div",
|
|
2949
|
+
{
|
|
2950
|
+
ref: refs.setFloating,
|
|
2951
|
+
"data-slot": "tooltip-overlay",
|
|
2952
|
+
"data-side": resolvedSide,
|
|
2953
|
+
"data-align": rendered.data.align,
|
|
2954
|
+
"data-state": rendered.open ? "open" : "closed",
|
|
2955
|
+
style: {
|
|
2956
|
+
position: strategy,
|
|
2957
|
+
top: 0,
|
|
2958
|
+
left: 0,
|
|
2959
|
+
zIndex: 50,
|
|
2960
|
+
transform: `translate3d(${x}px, ${y}px, 0)`
|
|
2961
|
+
},
|
|
2962
|
+
children: /* @__PURE__ */ jsx(FloatingProvider, { value: { context, arrowRef }, children: /* @__PURE__ */ jsx(
|
|
2963
|
+
RenderedTooltipProvider,
|
|
2964
|
+
{
|
|
2965
|
+
value: {
|
|
2966
|
+
side: resolvedSide,
|
|
2967
|
+
align: rendered.data.align,
|
|
2968
|
+
open: rendered.open
|
|
2969
|
+
},
|
|
2970
|
+
children: /* @__PURE__ */ jsx(
|
|
2971
|
+
Component,
|
|
2972
|
+
{
|
|
2973
|
+
"data-slot": "tooltip-content",
|
|
2974
|
+
"data-side": resolvedSide,
|
|
2975
|
+
"data-align": rendered.data.align,
|
|
2976
|
+
"data-state": rendered.open ? "open" : "closed",
|
|
2977
|
+
layoutId: `tooltip-content-${globalId}`,
|
|
2978
|
+
initial: {
|
|
2979
|
+
opacity: 0,
|
|
2980
|
+
scale: 0,
|
|
2981
|
+
...initialFromSide(rendered.data.side)
|
|
2982
|
+
},
|
|
2983
|
+
animate: rendered.open ? { opacity: 1, scale: 1, x: 0, y: 0 } : {
|
|
2984
|
+
opacity: 0,
|
|
2985
|
+
scale: 0,
|
|
2986
|
+
...initialFromSide(rendered.data.side)
|
|
2987
|
+
},
|
|
2988
|
+
exit: {
|
|
2989
|
+
opacity: 0,
|
|
2990
|
+
scale: 0,
|
|
2991
|
+
...initialFromSide(rendered.data.side)
|
|
2992
|
+
},
|
|
2993
|
+
onAnimationComplete: () => {
|
|
2994
|
+
if (!rendered.open)
|
|
2995
|
+
setRendered({ data: null, open: false });
|
|
2996
|
+
},
|
|
2997
|
+
transition,
|
|
2998
|
+
...rendered.data.contentProps,
|
|
2999
|
+
style: {
|
|
3000
|
+
position: "relative",
|
|
3001
|
+
...rendered.data.contentProps?.style || {}
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
)
|
|
3005
|
+
}
|
|
3006
|
+
) })
|
|
3007
|
+
}
|
|
3008
|
+
) }) });
|
|
3009
|
+
}
|
|
3010
|
+
function Tooltip2({
|
|
3011
|
+
children,
|
|
3012
|
+
side = "top",
|
|
3013
|
+
sideOffset = 0,
|
|
3014
|
+
align = "center",
|
|
3015
|
+
alignOffset = 0
|
|
3016
|
+
}) {
|
|
3017
|
+
const id = React18.useId();
|
|
3018
|
+
const [props, setProps] = React18.useState({});
|
|
3019
|
+
const [asChild, setAsChild] = React18.useState(false);
|
|
3020
|
+
return /* @__PURE__ */ jsx(
|
|
3021
|
+
LocalTooltipProvider,
|
|
3022
|
+
{
|
|
3023
|
+
value: {
|
|
3024
|
+
props,
|
|
3025
|
+
setProps,
|
|
3026
|
+
asChild,
|
|
3027
|
+
setAsChild,
|
|
3028
|
+
side,
|
|
3029
|
+
sideOffset,
|
|
3030
|
+
align,
|
|
3031
|
+
alignOffset,
|
|
3032
|
+
id
|
|
3033
|
+
},
|
|
3034
|
+
children
|
|
3035
|
+
}
|
|
3036
|
+
);
|
|
3037
|
+
}
|
|
3038
|
+
function shallowEqualWithoutChildren(a, b) {
|
|
3039
|
+
if (a === b) return true;
|
|
3040
|
+
if (!a || !b) return false;
|
|
3041
|
+
const keysA = Object.keys(a).filter((k) => k !== "children");
|
|
3042
|
+
const keysB = Object.keys(b).filter((k) => k !== "children");
|
|
3043
|
+
if (keysA.length !== keysB.length) return false;
|
|
3044
|
+
for (const k of keysA) {
|
|
3045
|
+
if (a[k] !== b[k]) return false;
|
|
3046
|
+
}
|
|
3047
|
+
return true;
|
|
3048
|
+
}
|
|
3049
|
+
function TooltipContent2({ asChild = false, ...props }) {
|
|
3050
|
+
const { setProps, setAsChild } = useTooltip();
|
|
3051
|
+
const lastPropsRef = React18.useRef(
|
|
3052
|
+
void 0
|
|
3053
|
+
);
|
|
3054
|
+
React18.useEffect(() => {
|
|
3055
|
+
if (!shallowEqualWithoutChildren(lastPropsRef.current, props)) {
|
|
3056
|
+
lastPropsRef.current = props;
|
|
3057
|
+
setProps(props);
|
|
3058
|
+
}
|
|
3059
|
+
}, [props, setProps]);
|
|
3060
|
+
React18.useEffect(() => {
|
|
3061
|
+
setAsChild(asChild);
|
|
3062
|
+
}, [asChild, setAsChild]);
|
|
3063
|
+
return null;
|
|
3064
|
+
}
|
|
3065
|
+
function TooltipTrigger2({
|
|
3066
|
+
ref,
|
|
3067
|
+
onMouseEnter,
|
|
3068
|
+
onMouseLeave,
|
|
3069
|
+
onFocus,
|
|
3070
|
+
onBlur,
|
|
3071
|
+
onPointerDown,
|
|
3072
|
+
asChild = false,
|
|
3073
|
+
...props
|
|
3074
|
+
}) {
|
|
3075
|
+
const {
|
|
3076
|
+
props: contentProps,
|
|
3077
|
+
asChild: contentAsChild,
|
|
3078
|
+
side,
|
|
3079
|
+
sideOffset,
|
|
3080
|
+
align,
|
|
3081
|
+
alignOffset,
|
|
3082
|
+
id
|
|
3083
|
+
} = useTooltip();
|
|
3084
|
+
const {
|
|
3085
|
+
showTooltip,
|
|
3086
|
+
hideTooltip,
|
|
3087
|
+
hideImmediate,
|
|
3088
|
+
currentTooltip,
|
|
3089
|
+
setReferenceEl
|
|
3090
|
+
} = useGlobalTooltip();
|
|
3091
|
+
const triggerRef = React18.useRef(null);
|
|
3092
|
+
React18.useImperativeHandle(ref, () => triggerRef.current);
|
|
3093
|
+
const suppressNextFocusRef = React18.useRef(false);
|
|
3094
|
+
const handleOpen = React18.useCallback(() => {
|
|
3095
|
+
if (!triggerRef.current) return;
|
|
3096
|
+
setReferenceEl(triggerRef.current);
|
|
3097
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
3098
|
+
showTooltip({
|
|
3099
|
+
contentProps,
|
|
3100
|
+
contentAsChild,
|
|
3101
|
+
rect,
|
|
3102
|
+
side,
|
|
3103
|
+
sideOffset,
|
|
3104
|
+
align,
|
|
3105
|
+
alignOffset,
|
|
3106
|
+
id
|
|
3107
|
+
});
|
|
3108
|
+
}, [
|
|
3109
|
+
showTooltip,
|
|
3110
|
+
setReferenceEl,
|
|
3111
|
+
contentProps,
|
|
3112
|
+
contentAsChild,
|
|
3113
|
+
side,
|
|
3114
|
+
sideOffset,
|
|
3115
|
+
align,
|
|
3116
|
+
alignOffset,
|
|
3117
|
+
id
|
|
3118
|
+
]);
|
|
3119
|
+
const handlePointerDown = React18.useCallback(
|
|
3120
|
+
(e) => {
|
|
3121
|
+
onPointerDown?.(e);
|
|
3122
|
+
if (currentTooltip?.id === id) {
|
|
3123
|
+
suppressNextFocusRef.current = true;
|
|
3124
|
+
hideImmediate();
|
|
3125
|
+
Promise.resolve().then(() => {
|
|
3126
|
+
suppressNextFocusRef.current = false;
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
3129
|
+
},
|
|
3130
|
+
[onPointerDown, currentTooltip?.id, id, hideImmediate]
|
|
3131
|
+
);
|
|
3132
|
+
const handleMouseEnter = React18.useCallback(
|
|
3133
|
+
(e) => {
|
|
3134
|
+
onMouseEnter?.(e);
|
|
3135
|
+
handleOpen();
|
|
3136
|
+
},
|
|
3137
|
+
[handleOpen, onMouseEnter]
|
|
3138
|
+
);
|
|
3139
|
+
const handleMouseLeave = React18.useCallback(
|
|
3140
|
+
(e) => {
|
|
3141
|
+
onMouseLeave?.(e);
|
|
3142
|
+
hideTooltip();
|
|
3143
|
+
},
|
|
3144
|
+
[hideTooltip, onMouseLeave]
|
|
3145
|
+
);
|
|
3146
|
+
const handleFocus = React18.useCallback(
|
|
3147
|
+
(e) => {
|
|
3148
|
+
onFocus?.(e);
|
|
3149
|
+
if (suppressNextFocusRef.current) return;
|
|
3150
|
+
handleOpen();
|
|
3151
|
+
},
|
|
3152
|
+
[handleOpen, onFocus]
|
|
3153
|
+
);
|
|
3154
|
+
const handleBlur = React18.useCallback(
|
|
3155
|
+
(e) => {
|
|
3156
|
+
onBlur?.(e);
|
|
3157
|
+
hideTooltip();
|
|
3158
|
+
},
|
|
3159
|
+
[hideTooltip, onBlur]
|
|
3160
|
+
);
|
|
3161
|
+
const Component = asChild ? Slot : motion.div;
|
|
3162
|
+
return /* @__PURE__ */ jsx(
|
|
3163
|
+
Component,
|
|
3164
|
+
{
|
|
3165
|
+
ref: triggerRef,
|
|
3166
|
+
onPointerDown: handlePointerDown,
|
|
3167
|
+
onMouseEnter: handleMouseEnter,
|
|
3168
|
+
onMouseLeave: handleMouseLeave,
|
|
3169
|
+
onFocus: handleFocus,
|
|
3170
|
+
onBlur: handleBlur,
|
|
3171
|
+
"data-slot": "tooltip-trigger",
|
|
3172
|
+
"data-side": side,
|
|
3173
|
+
"data-align": align,
|
|
3174
|
+
"data-state": currentTooltip?.id === id ? "open" : "closed",
|
|
3175
|
+
...props
|
|
3176
|
+
}
|
|
3177
|
+
);
|
|
3178
|
+
}
|
|
3179
|
+
function AvatarContainer({
|
|
3180
|
+
zIndex,
|
|
3181
|
+
translate,
|
|
3182
|
+
side,
|
|
3183
|
+
sideOffset,
|
|
3184
|
+
align,
|
|
3185
|
+
alignOffset,
|
|
3186
|
+
...props
|
|
3187
|
+
}) {
|
|
3188
|
+
return /* @__PURE__ */ jsx(
|
|
3189
|
+
Tooltip2,
|
|
3190
|
+
{
|
|
3191
|
+
side,
|
|
3192
|
+
sideOffset,
|
|
3193
|
+
align,
|
|
3194
|
+
alignOffset,
|
|
3195
|
+
children: /* @__PURE__ */ jsx(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
3196
|
+
motion.div,
|
|
3197
|
+
{
|
|
3198
|
+
"data-slot": "avatar-container",
|
|
3199
|
+
initial: "initial",
|
|
3200
|
+
whileHover: "hover",
|
|
3201
|
+
whileTap: "hover",
|
|
3202
|
+
style: { position: "relative", zIndex },
|
|
3203
|
+
children: /* @__PURE__ */ jsx(
|
|
3204
|
+
motion.div,
|
|
3205
|
+
{
|
|
3206
|
+
variants: {
|
|
3207
|
+
initial: { y: 0 },
|
|
3208
|
+
hover: { y: translate }
|
|
3209
|
+
},
|
|
3210
|
+
...props
|
|
3211
|
+
}
|
|
3212
|
+
)
|
|
3213
|
+
}
|
|
3214
|
+
) })
|
|
3215
|
+
}
|
|
3216
|
+
);
|
|
3217
|
+
}
|
|
3218
|
+
function AvatarGroup({
|
|
3219
|
+
ref,
|
|
3220
|
+
children,
|
|
3221
|
+
id,
|
|
3222
|
+
transition = { type: "spring", stiffness: 300, damping: 17 },
|
|
3223
|
+
invertOverlap = false,
|
|
3224
|
+
translate = "-30%",
|
|
3225
|
+
openDelay = 0,
|
|
3226
|
+
closeDelay = 0,
|
|
3227
|
+
side = "top",
|
|
3228
|
+
sideOffset = 25,
|
|
3229
|
+
align = "center",
|
|
3230
|
+
alignOffset = 0,
|
|
3231
|
+
tooltipTransition = { type: "spring", stiffness: 300, damping: 35 },
|
|
3232
|
+
style,
|
|
3233
|
+
...props
|
|
3234
|
+
}) {
|
|
3235
|
+
return /* @__PURE__ */ jsx(
|
|
3236
|
+
TooltipProvider2,
|
|
3237
|
+
{
|
|
3238
|
+
id,
|
|
3239
|
+
openDelay,
|
|
3240
|
+
closeDelay,
|
|
3241
|
+
transition: tooltipTransition,
|
|
3242
|
+
children: /* @__PURE__ */ jsx(
|
|
3243
|
+
"div",
|
|
3244
|
+
{
|
|
3245
|
+
ref,
|
|
3246
|
+
"data-slot": "avatar-group",
|
|
3247
|
+
style: {
|
|
3248
|
+
display: "flex",
|
|
3249
|
+
alignItems: "center",
|
|
3250
|
+
...style
|
|
3251
|
+
},
|
|
3252
|
+
...props,
|
|
3253
|
+
children: children?.map((child, index) => /* @__PURE__ */ jsx(
|
|
3254
|
+
AvatarContainer,
|
|
3255
|
+
{
|
|
3256
|
+
zIndex: invertOverlap ? React18.Children.count(children) - index : index,
|
|
3257
|
+
transition,
|
|
3258
|
+
translate,
|
|
3259
|
+
side,
|
|
3260
|
+
sideOffset,
|
|
3261
|
+
align,
|
|
3262
|
+
alignOffset,
|
|
3263
|
+
children: child
|
|
3264
|
+
},
|
|
3265
|
+
index
|
|
3266
|
+
))
|
|
3267
|
+
}
|
|
3268
|
+
)
|
|
3269
|
+
}
|
|
3270
|
+
);
|
|
3271
|
+
}
|
|
3272
|
+
function AvatarGroupTooltip(props) {
|
|
3273
|
+
return /* @__PURE__ */ jsx(TooltipContent2, { ...props });
|
|
3274
|
+
}
|
|
3275
|
+
function AvatarGroupTooltipArrow(props) {
|
|
3276
|
+
return /* @__PURE__ */ jsx(TooltipArrow, { ...props });
|
|
3277
|
+
}
|
|
3278
|
+
function AvatarGroup2({
|
|
3279
|
+
className,
|
|
3280
|
+
invertOverlap = true,
|
|
3281
|
+
...props
|
|
3282
|
+
}) {
|
|
3283
|
+
return /* @__PURE__ */ jsx(
|
|
3284
|
+
AvatarGroup,
|
|
3285
|
+
{
|
|
3286
|
+
className: cn("h-12 -space-x-3", className),
|
|
3287
|
+
invertOverlap,
|
|
3288
|
+
...props
|
|
3289
|
+
}
|
|
3290
|
+
);
|
|
3291
|
+
}
|
|
3292
|
+
function AvatarGroupTooltip2({
|
|
3293
|
+
className,
|
|
3294
|
+
children,
|
|
3295
|
+
layout = "preserve-aspect",
|
|
3296
|
+
...props
|
|
3297
|
+
}) {
|
|
3298
|
+
return /* @__PURE__ */ jsxs(
|
|
3299
|
+
AvatarGroupTooltip,
|
|
3300
|
+
{
|
|
3301
|
+
className: cn(
|
|
3302
|
+
"bg-primary text-primary-foreground z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance",
|
|
3303
|
+
className
|
|
3304
|
+
),
|
|
3305
|
+
...props,
|
|
3306
|
+
children: [
|
|
3307
|
+
/* @__PURE__ */ jsx(motion9.div, { layout, className: "overflow-hidden", children }),
|
|
3308
|
+
/* @__PURE__ */ jsx(
|
|
3309
|
+
AvatarGroupTooltipArrow,
|
|
3310
|
+
{
|
|
3311
|
+
className: "fill-primary size-3 data-[side='bottom']:translate-y-[1px] data-[side='right']:translate-x-[1px] data-[side='left']:translate-x-[-1px] data-[side='top']:translate-y-[-1px]",
|
|
3312
|
+
tipRadius: 2
|
|
3313
|
+
}
|
|
3314
|
+
)
|
|
3315
|
+
]
|
|
3316
|
+
}
|
|
3317
|
+
);
|
|
3318
|
+
}
|
|
3319
|
+
function Avatar({
|
|
3320
|
+
className,
|
|
3321
|
+
size = "default",
|
|
3322
|
+
...props
|
|
3323
|
+
}) {
|
|
3324
|
+
return /* @__PURE__ */ jsx(
|
|
3325
|
+
Avatar$1.Root,
|
|
3326
|
+
{
|
|
3327
|
+
"data-slot": "avatar",
|
|
3328
|
+
"data-size": size,
|
|
3329
|
+
className: cn(
|
|
3330
|
+
"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",
|
|
3331
|
+
className
|
|
3332
|
+
),
|
|
3333
|
+
...props
|
|
3334
|
+
}
|
|
3335
|
+
);
|
|
3336
|
+
}
|
|
3337
|
+
function AvatarImage({ className, ...props }) {
|
|
3338
|
+
return /* @__PURE__ */ jsx(
|
|
3339
|
+
Avatar$1.Image,
|
|
3340
|
+
{
|
|
3341
|
+
"data-slot": "avatar-image",
|
|
3342
|
+
className: cn(
|
|
3343
|
+
"rounded-full aspect-square size-full object-cover",
|
|
3344
|
+
className
|
|
3345
|
+
),
|
|
3346
|
+
...props
|
|
3347
|
+
}
|
|
3348
|
+
);
|
|
3349
|
+
}
|
|
3350
|
+
function AvatarFallback({
|
|
3351
|
+
className,
|
|
3352
|
+
...props
|
|
3353
|
+
}) {
|
|
3354
|
+
return /* @__PURE__ */ jsx(
|
|
3355
|
+
Avatar$1.Fallback,
|
|
3356
|
+
{
|
|
3357
|
+
"data-slot": "avatar-fallback",
|
|
3358
|
+
className: cn(
|
|
3359
|
+
"bg-muted text-muted-foreground rounded-full flex size-full items-center justify-center text-sm group-data-[size=sm]/avatar:text-xs",
|
|
3360
|
+
className
|
|
3361
|
+
),
|
|
3362
|
+
...props
|
|
3363
|
+
}
|
|
3364
|
+
);
|
|
3365
|
+
}
|
|
3366
|
+
var AVATARS = [
|
|
3367
|
+
{
|
|
3368
|
+
src: "https://pbs.twimg.com/profile_images/1534700564810018816/anAuSfkp_400x400.jpg",
|
|
3369
|
+
fallback: "JH",
|
|
3370
|
+
tooltip: "Jhey"
|
|
3371
|
+
},
|
|
3372
|
+
{
|
|
3373
|
+
src: "https://pbs.twimg.com/profile_images/1927474594102784000/Al0g-I6o_400x400.jpg",
|
|
3374
|
+
fallback: "DH",
|
|
3375
|
+
tooltip: "David Haz"
|
|
3376
|
+
}
|
|
3377
|
+
];
|
|
3378
|
+
var Collaborators = () => {
|
|
3379
|
+
return /* @__PURE__ */ jsx(AvatarGroup2, { children: AVATARS.map((avatar, index) => /* @__PURE__ */ jsxs(Avatar, { className: "size-8 border-3 border-background", children: [
|
|
3380
|
+
/* @__PURE__ */ jsx(AvatarImage, { src: avatar.src }),
|
|
3381
|
+
/* @__PURE__ */ jsx(AvatarFallback, { children: avatar.fallback }),
|
|
3382
|
+
/* @__PURE__ */ jsx(AvatarGroupTooltip2, { children: avatar.tooltip })
|
|
3383
|
+
] }, index)) });
|
|
3384
|
+
};
|
|
3385
|
+
var Share = () => {
|
|
3386
|
+
const [access, setAccess] = React18.useState("private");
|
|
3387
|
+
const [copied, setCopied] = React18.useState(false);
|
|
3388
|
+
const shareUrl = typeof window !== "undefined" ? window.location.href : "";
|
|
3389
|
+
const shareButton = useMsg("share.button");
|
|
3390
|
+
const shareTitle = useMsg("share.title");
|
|
3391
|
+
const peopleWithAccess = useMsg("share.people-with-access");
|
|
3392
|
+
const generalAccess = useMsg("share.general-access");
|
|
3393
|
+
const copyLabel = useMsg("share.copy");
|
|
3394
|
+
const copiedLabel = useMsg("share.copied");
|
|
3395
|
+
const ACCESS_OPTIONS = [
|
|
3396
|
+
{
|
|
3397
|
+
value: "private",
|
|
3398
|
+
label: useMsg("share.access.private.label"),
|
|
3399
|
+
description: useMsg("share.access.private.description"),
|
|
3400
|
+
icon: /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4" })
|
|
3401
|
+
},
|
|
3402
|
+
{
|
|
3403
|
+
value: "anyone-view",
|
|
3404
|
+
label: useMsg("share.access.anyone-view.label"),
|
|
3405
|
+
description: useMsg("share.access.anyone-view.description"),
|
|
3406
|
+
icon: /* @__PURE__ */ jsx(Globe, { className: "w-4 h-4" })
|
|
3407
|
+
},
|
|
3408
|
+
{
|
|
3409
|
+
value: "anyone-edit",
|
|
3410
|
+
label: useMsg("share.access.anyone-edit.label"),
|
|
3411
|
+
description: useMsg("share.access.anyone-edit.description"),
|
|
3412
|
+
icon: /* @__PURE__ */ jsx(Users, { className: "w-4 h-4" })
|
|
3413
|
+
}
|
|
3414
|
+
];
|
|
3415
|
+
const handleCopy = () => {
|
|
3416
|
+
navigator.clipboard.writeText(shareUrl).then(() => {
|
|
3417
|
+
setCopied(true);
|
|
3418
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
3419
|
+
});
|
|
3420
|
+
};
|
|
3421
|
+
return /* @__PURE__ */ jsxs(Popover2, { children: [
|
|
3422
|
+
/* @__PURE__ */ jsxs(PopoverTrigger2, { render: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline" }), children: [
|
|
3423
|
+
/* @__PURE__ */ jsx(Link2, { className: "h-4 w-4" }),
|
|
3424
|
+
shareButton
|
|
3425
|
+
] }),
|
|
3426
|
+
/* @__PURE__ */ jsxs(PopoverPanel, { side: "bottom", align: "end", className: "w-80 flex flex-col gap-3", children: [
|
|
3427
|
+
/* @__PURE__ */ jsx(PopoverTitle2, { className: "text-base font-medium", children: shareTitle }),
|
|
3428
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
3429
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: peopleWithAccess }),
|
|
3430
|
+
/* @__PURE__ */ jsx(Collaborators, {})
|
|
3431
|
+
] }),
|
|
3432
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
3433
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
3434
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: generalAccess }),
|
|
3435
|
+
ACCESS_OPTIONS.map((opt) => /* @__PURE__ */ jsxs(
|
|
3436
|
+
"button",
|
|
3437
|
+
{
|
|
3438
|
+
onClick: () => setAccess(opt.value),
|
|
3439
|
+
className: "flex items-center gap-3 rounded-lg px-3 py-2 text-left transition-colors hover:bg-muted",
|
|
3440
|
+
children: [
|
|
3441
|
+
/* @__PURE__ */ jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: opt.icon }),
|
|
3442
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
3443
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-none", children: opt.label }),
|
|
3444
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: opt.description })
|
|
3445
|
+
] }),
|
|
3446
|
+
access === opt.value && /* @__PURE__ */ jsx(Check, { className: "w-4 h-4 text-primary shrink-0" })
|
|
3447
|
+
]
|
|
3448
|
+
},
|
|
3449
|
+
opt.value
|
|
3450
|
+
))
|
|
3451
|
+
] }),
|
|
3452
|
+
/* @__PURE__ */ jsx(Separator, {}),
|
|
3453
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
3454
|
+
/* @__PURE__ */ jsx(Input, { readOnly: true, value: shareUrl, className: "flex-1 text-xs" }),
|
|
3455
|
+
/* @__PURE__ */ jsxs(Button, { size: "sm", variant: "outline", onClick: handleCopy, className: "shrink-0", children: [
|
|
3456
|
+
copied ? /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Link2, { className: "h-4 w-4" }),
|
|
3457
|
+
copied ? copiedLabel : copyLabel
|
|
3458
|
+
] })
|
|
3459
|
+
] })
|
|
3460
|
+
] })
|
|
3461
|
+
] });
|
|
3462
|
+
};
|
|
3463
|
+
var AVATARS2 = [
|
|
3464
|
+
{
|
|
3465
|
+
src: "https://pbs.twimg.com/profile_images/1534700564810018816/anAuSfkp_400x400.jpg",
|
|
3466
|
+
fallback: "JH",
|
|
3467
|
+
name: "Jhey",
|
|
3468
|
+
role: "Editor (you)"
|
|
3469
|
+
},
|
|
3470
|
+
{
|
|
3471
|
+
src: "https://pbs.twimg.com/profile_images/1927474594102784000/Al0g-I6o_400x400.jpg",
|
|
3472
|
+
fallback: "DH",
|
|
3473
|
+
name: "David Haz",
|
|
3474
|
+
role: "Editor"
|
|
3475
|
+
}
|
|
3476
|
+
];
|
|
3477
|
+
var [currentUser, ...others] = AVATARS2;
|
|
3478
|
+
var CollaboratorsPopover = () => {
|
|
3479
|
+
const collaboratorsTitle = useMsg("collaborators.title");
|
|
3480
|
+
return /* @__PURE__ */ jsxs(Popover2, { children: [
|
|
3481
|
+
/* @__PURE__ */ jsx(PopoverTrigger2, { render: /* @__PURE__ */ jsx("div", {}), nativeButton: false, children: /* @__PURE__ */ jsx("button", { className: "rounded-full ring-2 ring-background focus:outline-none focus-visible:ring-primary", children: /* @__PURE__ */ jsxs(Avatar, { className: "size-6", children: [
|
|
3482
|
+
/* @__PURE__ */ jsx(AvatarImage, { src: currentUser.src }),
|
|
3483
|
+
/* @__PURE__ */ jsx(AvatarFallback, { children: currentUser.fallback })
|
|
3484
|
+
] }) }) }),
|
|
3485
|
+
/* @__PURE__ */ jsxs(PopoverPanel, { side: "bottom", align: "end", className: "w-64 flex flex-col gap-3", children: [
|
|
3486
|
+
/* @__PURE__ */ jsx(PopoverTitle2, { className: "text-sm font-medium", children: collaboratorsTitle }),
|
|
3487
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: [currentUser, ...others].map((user) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
3488
|
+
/* @__PURE__ */ jsxs(Avatar, { className: "size-8 shrink-0", children: [
|
|
3489
|
+
/* @__PURE__ */ jsx(AvatarImage, { src: user.src }),
|
|
3490
|
+
/* @__PURE__ */ jsx(AvatarFallback, { children: user.fallback })
|
|
3491
|
+
] }),
|
|
3492
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
3493
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium leading-none truncate", children: user.name }),
|
|
3494
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: user.role })
|
|
3495
|
+
] })
|
|
3496
|
+
] }, user.fallback)) })
|
|
3497
|
+
] })
|
|
3498
|
+
] });
|
|
3499
|
+
};
|
|
3500
|
+
var Header = () => {
|
|
3501
|
+
const { history, appState } = usePuck();
|
|
3502
|
+
const publish = useMsg("header.publish");
|
|
3503
|
+
const undo = useMsg("header.undo");
|
|
3504
|
+
const undoTooltip = useMsg("header.undo.tooltip");
|
|
3505
|
+
const redo = useMsg("header.redo");
|
|
3506
|
+
const redoTooltip = useMsg("header.redo.tooltip");
|
|
3507
|
+
const exportLabel = useMsg("header.export");
|
|
3508
|
+
const exportJson = useMsg("header.export.json");
|
|
3509
|
+
const theme = useTheme();
|
|
3510
|
+
const toggleTheme = useToggleTheme();
|
|
3511
|
+
const themeLightLabel = useMsg("header.theme.light");
|
|
3512
|
+
const themeDarkLabel = useMsg("header.theme.dark");
|
|
3513
|
+
const themeLabel = theme === "dark" ? themeLightLabel : themeDarkLabel;
|
|
3514
|
+
React18.useEffect(() => {
|
|
3515
|
+
document.documentElement.classList.toggle("dark", theme === "dark");
|
|
3516
|
+
}, []);
|
|
3517
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ 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: [
|
|
3518
|
+
/* @__PURE__ */ jsx("div", { className: "w-18 flex items-center justify-center h-full border-r border-neutral-200 dark:border-neutral-800/80", children: /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-10 h-10 bg-primary rounded-full", children: /* @__PURE__ */ jsx(AnimatedAsana, { className: "text-white text-2xl" }) }) }),
|
|
3519
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex flex-1 w-full px-2", children: [
|
|
3520
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", children: /* @__PURE__ */ jsx(ArrowLeft, { className: "h-4 w-4" }) }),
|
|
3521
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none text-sm font-medium", children: appState?.data?.root?.props?.title || "" }),
|
|
3522
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2 h-full ml-auto", children: [
|
|
3523
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
3524
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
3525
|
+
Button,
|
|
3526
|
+
{
|
|
3527
|
+
variant: "ghost",
|
|
3528
|
+
size: "icon",
|
|
3529
|
+
disabled: !history.hasPast,
|
|
3530
|
+
onClick: () => history.back(),
|
|
3531
|
+
"aria-label": undo,
|
|
3532
|
+
children: /* @__PURE__ */ jsx(Undo2, { className: "h-4 w-4" })
|
|
3533
|
+
}
|
|
3534
|
+
) }),
|
|
3535
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: undoTooltip })
|
|
3536
|
+
] }),
|
|
3537
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
3538
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
3539
|
+
Button,
|
|
3540
|
+
{
|
|
3541
|
+
variant: "ghost",
|
|
3542
|
+
size: "icon",
|
|
3543
|
+
disabled: !history.hasFuture,
|
|
3544
|
+
onClick: () => history.forward(),
|
|
3545
|
+
"aria-label": redo,
|
|
3546
|
+
children: /* @__PURE__ */ jsx(Redo2, { className: "h-4 w-4" })
|
|
3547
|
+
}
|
|
3548
|
+
) }),
|
|
3549
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: redoTooltip })
|
|
3550
|
+
] }),
|
|
3551
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
|
|
3552
|
+
/* @__PURE__ */ jsx(CollaboratorsPopover, {}),
|
|
3553
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
|
|
3554
|
+
/* @__PURE__ */ jsx(Share, {}),
|
|
3555
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
|
|
3556
|
+
/* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
3557
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
3558
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { render: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", "aria-label": exportLabel }), children: /* @__PURE__ */ jsx(Download, { className: "h-4 w-4" }) }) }),
|
|
3559
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: exportLabel })
|
|
3560
|
+
] }),
|
|
3561
|
+
/* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsxs(
|
|
3562
|
+
DropdownMenuItem,
|
|
3563
|
+
{
|
|
3564
|
+
onClick: () => {
|
|
3565
|
+
const json = JSON.stringify(appState.data, null, 2);
|
|
3566
|
+
const blob = new Blob([json], { type: "application/json" });
|
|
3567
|
+
const url = URL.createObjectURL(blob);
|
|
3568
|
+
const a = document.createElement("a");
|
|
3569
|
+
a.href = url;
|
|
3570
|
+
a.download = `${appState.data.root?.props?.title || "page"}.json`;
|
|
3571
|
+
a.click();
|
|
3572
|
+
URL.revokeObjectURL(url);
|
|
3573
|
+
},
|
|
3574
|
+
children: [
|
|
3575
|
+
/* @__PURE__ */ jsx(FileDown, { className: "h-4 w-4" }),
|
|
3576
|
+
" ",
|
|
3577
|
+
exportJson
|
|
3578
|
+
]
|
|
3579
|
+
}
|
|
3580
|
+
) })
|
|
3581
|
+
] }),
|
|
3582
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
|
|
3583
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
3584
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", onClick: toggleTheme, "aria-label": themeLabel, children: theme === "dark" ? /* @__PURE__ */ jsx(Sun, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Moon, { className: "h-4 w-4" }) }) }),
|
|
3585
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: themeLabel })
|
|
3586
|
+
] }),
|
|
3587
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
|
|
3588
|
+
/* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
3589
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { size: "sm", "aria-label": publish, children: [
|
|
3590
|
+
/* @__PURE__ */ jsx(Send, { className: "h-4 w-4" }),
|
|
3591
|
+
publish
|
|
3592
|
+
] }) }),
|
|
3593
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: publish })
|
|
3594
|
+
] })
|
|
3595
|
+
] })
|
|
3596
|
+
] })
|
|
3597
|
+
] }) });
|
|
3598
|
+
};
|
|
3599
|
+
var DEFAULT_SEEDS = [
|
|
3600
|
+
"forest",
|
|
3601
|
+
"ocean",
|
|
3602
|
+
"mountain",
|
|
3603
|
+
"city",
|
|
3604
|
+
"food",
|
|
3605
|
+
"travel",
|
|
3606
|
+
"abstract",
|
|
3607
|
+
"people",
|
|
3608
|
+
"architecture",
|
|
3609
|
+
"animals",
|
|
3610
|
+
"technology",
|
|
3611
|
+
"minimal"
|
|
3612
|
+
];
|
|
3613
|
+
function picsumUrl(seed, w = 960, h = 960) {
|
|
3614
|
+
return `https://picsum.photos/seed/${encodeURIComponent(seed)}/${w}/${h}`;
|
|
3615
|
+
}
|
|
3616
|
+
function getDefaultImages(seeds) {
|
|
3617
|
+
return seeds.map((seed, i) => ({
|
|
3618
|
+
src: picsumUrl(seed),
|
|
3619
|
+
alt: seed,
|
|
3620
|
+
id: `${seed}-${i}`
|
|
3621
|
+
}));
|
|
3622
|
+
}
|
|
3623
|
+
function getSearchImages(query) {
|
|
3624
|
+
return Array.from({ length: 12 }, (_, i) => ({
|
|
3625
|
+
src: picsumUrl(`${query}-${i}`),
|
|
3626
|
+
alt: `${query} ${i + 1}`,
|
|
3627
|
+
id: `${query}-${i}`
|
|
3628
|
+
}));
|
|
3629
|
+
}
|
|
3630
|
+
var ghostEl = null;
|
|
3631
|
+
function createGhost(src) {
|
|
3632
|
+
const el = document.createElement("div");
|
|
3633
|
+
el.style.cssText = `
|
|
3634
|
+
position: fixed; top: -9999px; left: -9999px; z-index: 99999;
|
|
3635
|
+
width: 80px; height: 60px; border-radius: 6px; overflow: hidden;
|
|
3636
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.3); pointer-events: none;
|
|
3637
|
+
`;
|
|
3638
|
+
const img = document.createElement("img");
|
|
3639
|
+
img.src = src;
|
|
3640
|
+
img.style.cssText = "width:100%;height:100%;object-fit:cover;";
|
|
3641
|
+
el.appendChild(img);
|
|
3642
|
+
document.body.appendChild(el);
|
|
3643
|
+
return el;
|
|
3644
|
+
}
|
|
3645
|
+
function moveGhost(x, y) {
|
|
3646
|
+
if (!ghostEl) return;
|
|
3647
|
+
ghostEl.style.left = `${x + 12}px`;
|
|
3648
|
+
ghostEl.style.top = `${y + 12}px`;
|
|
3649
|
+
}
|
|
3650
|
+
function removeGhost() {
|
|
3651
|
+
ghostEl?.remove();
|
|
3652
|
+
ghostEl = null;
|
|
3653
|
+
}
|
|
3654
|
+
function ImageLibrary({
|
|
3655
|
+
seeds,
|
|
3656
|
+
items: customImages
|
|
3657
|
+
} = {}) {
|
|
3658
|
+
const effectiveSeeds = seeds ?? DEFAULT_SEEDS;
|
|
3659
|
+
const [query, setQuery] = React18.useState("");
|
|
3660
|
+
const [committed, setCommitted] = React18.useState("");
|
|
3661
|
+
const [items, setItems] = React18.useState(
|
|
3662
|
+
() => customImages ?? getDefaultImages(effectiveSeeds)
|
|
3663
|
+
);
|
|
3664
|
+
const libraryTitle = useMsg("image-library.title");
|
|
3665
|
+
const searchPlaceholder = useMsg("image-library.search.placeholder");
|
|
3666
|
+
React18.useEffect(() => {
|
|
3667
|
+
const t = setTimeout(() => setCommitted(query.trim()), 400);
|
|
3668
|
+
return () => clearTimeout(t);
|
|
3669
|
+
}, [query]);
|
|
3670
|
+
React18.useEffect(() => {
|
|
3671
|
+
if (customImages) return;
|
|
3672
|
+
setItems(
|
|
3673
|
+
committed ? getSearchImages(committed) : getDefaultImages(effectiveSeeds)
|
|
3674
|
+
);
|
|
3675
|
+
}, [committed, customImages, effectiveSeeds]);
|
|
3676
|
+
function handlePointerDown(e, src) {
|
|
3677
|
+
e.stopPropagation();
|
|
3678
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
3679
|
+
ghostEl = createGhost(src);
|
|
3680
|
+
moveGhost(e.clientX, e.clientY);
|
|
3681
|
+
window.dispatchEvent(
|
|
3682
|
+
new CustomEvent("anvilkit:librarydragstart", {
|
|
3683
|
+
detail: { type: "image" }
|
|
3684
|
+
})
|
|
3685
|
+
);
|
|
3686
|
+
function onMove(ev) {
|
|
3687
|
+
moveGhost(ev.clientX, ev.clientY);
|
|
3688
|
+
}
|
|
3689
|
+
function onUp(ev) {
|
|
3690
|
+
removeGhost();
|
|
3691
|
+
window.removeEventListener("pointermove", onMove);
|
|
3692
|
+
window.removeEventListener("pointerup", onUp);
|
|
3693
|
+
window.dispatchEvent(
|
|
3694
|
+
new CustomEvent("anvilkit:imagedrop", {
|
|
3695
|
+
detail: { src, clientX: ev.clientX, clientY: ev.clientY }
|
|
3696
|
+
})
|
|
3697
|
+
);
|
|
3698
|
+
}
|
|
3699
|
+
window.addEventListener("pointermove", onMove);
|
|
3700
|
+
window.addEventListener("pointerup", onUp);
|
|
3701
|
+
}
|
|
3702
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
3703
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: libraryTitle }),
|
|
3704
|
+
/* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
3705
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
3706
|
+
/* @__PURE__ */ jsx(
|
|
3707
|
+
Input,
|
|
3708
|
+
{
|
|
3709
|
+
className: "pl-8",
|
|
3710
|
+
placeholder: searchPlaceholder,
|
|
3711
|
+
value: query,
|
|
3712
|
+
onChange: (e) => setQuery(e.target.value)
|
|
3713
|
+
}
|
|
3714
|
+
)
|
|
3715
|
+
] }) }),
|
|
3716
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-2 grid grid-cols-2 gap-2", children: items.map((item, i) => /* @__PURE__ */ jsxs(
|
|
3717
|
+
"div",
|
|
3718
|
+
{
|
|
3719
|
+
onPointerDown: (e) => handlePointerDown(e, item.src),
|
|
3720
|
+
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",
|
|
3721
|
+
children: [
|
|
3722
|
+
/* @__PURE__ */ jsx(
|
|
3723
|
+
"img",
|
|
3724
|
+
{
|
|
3725
|
+
src: item.src,
|
|
3726
|
+
alt: item.alt,
|
|
3727
|
+
className: "w-full h-20 object-cover pointer-events-none",
|
|
3728
|
+
loading: "lazy"
|
|
3729
|
+
}
|
|
3730
|
+
),
|
|
3731
|
+
/* @__PURE__ */ jsx("div", { className: "px-1.5 py-1 text-xs text-muted-foreground truncate capitalize", children: item.alt })
|
|
3732
|
+
]
|
|
3733
|
+
},
|
|
3734
|
+
`${item.src}-${i}`
|
|
3735
|
+
)) }) })
|
|
3736
|
+
] });
|
|
3737
|
+
}
|
|
3738
|
+
var ghostEl2 = null;
|
|
3739
|
+
function createGhost2(text) {
|
|
3740
|
+
const el = document.createElement("div");
|
|
3741
|
+
el.style.cssText = `
|
|
3742
|
+
position: fixed; top: -9999px; left: -9999px; z-index: 99999;
|
|
3743
|
+
max-width: 200px; padding: 6px 10px; border-radius: 6px;
|
|
3744
|
+
background: #1e1e2e; color: #fff; font-size: 12px; line-height: 1.4;
|
|
3745
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.3); pointer-events: none;
|
|
3746
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
3747
|
+
`;
|
|
3748
|
+
el.textContent = text.length > 40 ? text.slice(0, 40) + "\u2026" : text;
|
|
3749
|
+
document.body.appendChild(el);
|
|
3750
|
+
return el;
|
|
3751
|
+
}
|
|
3752
|
+
function moveGhost2(x, y) {
|
|
3753
|
+
if (!ghostEl2) return;
|
|
3754
|
+
ghostEl2.style.left = `${x + 12}px`;
|
|
3755
|
+
ghostEl2.style.top = `${y + 12}px`;
|
|
3756
|
+
}
|
|
3757
|
+
function removeGhost2() {
|
|
3758
|
+
ghostEl2?.remove();
|
|
3759
|
+
ghostEl2 = null;
|
|
3760
|
+
}
|
|
3761
|
+
var DEFAULT_SNIPPETS = [
|
|
3762
|
+
// Headlines
|
|
3763
|
+
{
|
|
3764
|
+
category: "Headlines",
|
|
3765
|
+
label: "Bold statement",
|
|
3766
|
+
text: "The Future Starts Here"
|
|
3767
|
+
},
|
|
3768
|
+
{
|
|
3769
|
+
category: "Headlines",
|
|
3770
|
+
label: "Question hook",
|
|
3771
|
+
text: "Ready to Transform Your Business?"
|
|
3772
|
+
},
|
|
3773
|
+
{
|
|
3774
|
+
category: "Headlines",
|
|
3775
|
+
label: "Value prop",
|
|
3776
|
+
text: "Simple, Powerful, Built for Teams"
|
|
3777
|
+
},
|
|
3778
|
+
{
|
|
3779
|
+
category: "Headlines",
|
|
3780
|
+
label: "Action-led",
|
|
3781
|
+
text: "Ship Faster. Break Less. Sleep Better."
|
|
3782
|
+
},
|
|
3783
|
+
// Subheadings
|
|
3784
|
+
{
|
|
3785
|
+
category: "Subheadings",
|
|
3786
|
+
label: "Feature intro",
|
|
3787
|
+
text: "Everything you need, nothing you don't."
|
|
3788
|
+
},
|
|
3789
|
+
{
|
|
3790
|
+
category: "Subheadings",
|
|
3791
|
+
label: "Social proof",
|
|
3792
|
+
text: "Trusted by over 10,000 teams worldwide."
|
|
3793
|
+
},
|
|
3794
|
+
{
|
|
3795
|
+
category: "Subheadings",
|
|
3796
|
+
label: "CTA support",
|
|
3797
|
+
text: "Get started in minutes \u2014 no credit card required."
|
|
3798
|
+
},
|
|
3799
|
+
// Body
|
|
3800
|
+
{
|
|
3801
|
+
category: "Body",
|
|
3802
|
+
label: "Product description",
|
|
3803
|
+
text: "Our platform helps teams collaborate in real time, ship products faster, and stay aligned across every stage of the process."
|
|
3804
|
+
},
|
|
3805
|
+
{
|
|
3806
|
+
category: "Body",
|
|
3807
|
+
label: "Feature benefit",
|
|
3808
|
+
text: "With built-in analytics and smart automation, you can focus on what matters most \u2014 building great products."
|
|
3809
|
+
},
|
|
3810
|
+
{
|
|
3811
|
+
category: "Body",
|
|
3812
|
+
label: "About us",
|
|
3813
|
+
text: "We're a small team on a big mission: to make software development feel effortless for everyone."
|
|
3814
|
+
},
|
|
3815
|
+
// CTAs
|
|
3816
|
+
{ category: "CTAs", label: "Primary", text: "Get Started Free" },
|
|
3817
|
+
{ category: "CTAs", label: "Secondary", text: "Learn More" },
|
|
3818
|
+
{ category: "CTAs", label: "Soft sell", text: "See How It Works" },
|
|
3819
|
+
{ category: "CTAs", label: "Urgency", text: "Start Your Free Trial Today" }
|
|
3820
|
+
];
|
|
3821
|
+
function CopyLibrary({
|
|
3822
|
+
items
|
|
3823
|
+
} = {}) {
|
|
3824
|
+
const activeSnippets = items ?? DEFAULT_SNIPPETS;
|
|
3825
|
+
const categories = Array.from(new Set(activeSnippets.map((s) => s.category)));
|
|
3826
|
+
const [query, setQuery] = React18.useState("");
|
|
3827
|
+
const libraryTitle = useMsg("copy-library.title");
|
|
3828
|
+
const searchPlaceholder = useMsg("copy-library.search.placeholder");
|
|
3829
|
+
const filtered = query.trim() ? activeSnippets.filter(
|
|
3830
|
+
(s) => s.text.toLowerCase().includes(query.toLowerCase()) || s.label.toLowerCase().includes(query.toLowerCase()) || s.category.toLowerCase().includes(query.toLowerCase())
|
|
3831
|
+
) : activeSnippets;
|
|
3832
|
+
function handlePointerDown(e, text) {
|
|
3833
|
+
e.stopPropagation();
|
|
3834
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
3835
|
+
ghostEl2 = createGhost2(text);
|
|
3836
|
+
moveGhost2(e.clientX, e.clientY);
|
|
3837
|
+
window.dispatchEvent(
|
|
3838
|
+
new CustomEvent("anvilkit:librarydragstart", {
|
|
3839
|
+
detail: { type: "text" }
|
|
3840
|
+
})
|
|
3841
|
+
);
|
|
3842
|
+
function onMove(ev) {
|
|
3843
|
+
moveGhost2(ev.clientX, ev.clientY);
|
|
3844
|
+
}
|
|
3845
|
+
function onUp(ev) {
|
|
3846
|
+
removeGhost2();
|
|
3847
|
+
window.removeEventListener("pointermove", onMove);
|
|
3848
|
+
window.removeEventListener("pointerup", onUp);
|
|
3849
|
+
window.dispatchEvent(
|
|
3850
|
+
new CustomEvent("anvilkit:textdrop", {
|
|
3851
|
+
detail: { text, clientX: ev.clientX, clientY: ev.clientY }
|
|
3852
|
+
})
|
|
3853
|
+
);
|
|
3854
|
+
}
|
|
3855
|
+
window.addEventListener("pointermove", onMove);
|
|
3856
|
+
window.addEventListener("pointerup", onUp);
|
|
3857
|
+
}
|
|
3858
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
3859
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: libraryTitle }),
|
|
3860
|
+
/* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
3861
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
3862
|
+
/* @__PURE__ */ jsx(
|
|
3863
|
+
Input,
|
|
3864
|
+
{
|
|
3865
|
+
className: "pl-8",
|
|
3866
|
+
placeholder: searchPlaceholder,
|
|
3867
|
+
value: query,
|
|
3868
|
+
onChange: (e) => setQuery(e.target.value)
|
|
3869
|
+
}
|
|
3870
|
+
)
|
|
3871
|
+
] }) }),
|
|
3872
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-2 flex flex-col gap-4", children: (query.trim() ? [null] : categories).map((cat) => {
|
|
3873
|
+
const items2 = cat ? filtered.filter((s) => s.category === cat) : filtered;
|
|
3874
|
+
if (!items2.length) return null;
|
|
3875
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
3876
|
+
cat && /* @__PURE__ */ jsxs("div", { className: "px-1 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider flex items-center gap-1", children: [
|
|
3877
|
+
/* @__PURE__ */ jsx(Type, { className: "h-3 w-3" }),
|
|
3878
|
+
cat
|
|
3879
|
+
] }),
|
|
3880
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", children: items2.map((snippet, i) => /* @__PURE__ */ jsxs(
|
|
3881
|
+
"div",
|
|
3882
|
+
{
|
|
3883
|
+
onPointerDown: (e) => handlePointerDown(e, snippet.text),
|
|
3884
|
+
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",
|
|
3885
|
+
children: [
|
|
3886
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-foreground/70 mb-0.5", children: snippet.label }),
|
|
3887
|
+
/* @__PURE__ */ jsx("div", { className: "text-xs text-foreground leading-snug line-clamp-2", children: snippet.text })
|
|
3888
|
+
]
|
|
3889
|
+
},
|
|
3890
|
+
i
|
|
3891
|
+
)) })
|
|
3892
|
+
] }, cat ?? "results");
|
|
3893
|
+
}) }) })
|
|
3894
|
+
] });
|
|
3895
|
+
}
|
|
3896
|
+
var EditorLayout = ({
|
|
3897
|
+
aiPanel,
|
|
3898
|
+
images,
|
|
3899
|
+
copywritings
|
|
3900
|
+
}) => {
|
|
3901
|
+
const activeTab = useActiveTab();
|
|
3902
|
+
return /* @__PURE__ */ jsxs("div", { className: "max-sm:hidden overflow-hidden h-screen", children: [
|
|
3903
|
+
/* @__PURE__ */ jsx(Header, {}),
|
|
3904
|
+
/* @__PURE__ */ jsxs(motion.div, { className: "relative w-full flex border-r border-neutral-200 dark:border-neutral-800/80 bg-white/60 dark:bg-neutral-950/80 backdrop-blur-md ml-0 h-[calc(100vh-54px)]", children: [
|
|
3905
|
+
/* @__PURE__ */ jsx(Aside, {}),
|
|
3906
|
+
/* @__PURE__ */ jsxs("div", { className: "relative h-full flex flex-col overflow-x-hidden overflow-y-auto border-r border-neutral-200 dark:border-neutral-800/80 w-[240px]", children: [
|
|
3907
|
+
activeTab === "insert" && /* @__PURE__ */ jsx(Puck.Components, {}),
|
|
3908
|
+
activeTab === "layer" && /* @__PURE__ */ jsx(Puck.Outline, {}),
|
|
3909
|
+
activeTab === "image" && /* @__PURE__ */ jsx(ImageLibrary, { ...images }),
|
|
3910
|
+
activeTab === "text" && /* @__PURE__ */ jsx(CopyLibrary, { ...copywritings }),
|
|
3911
|
+
activeTab === "copilot" && aiPanel
|
|
3912
|
+
] }),
|
|
3913
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 h-full overflow-hidden", children: /* @__PURE__ */ jsx(Puck.Preview, {}) }),
|
|
3914
|
+
/* @__PURE__ */ jsx("div", { className: "border-l border-neutral-200 dark:border-neutral-800/80 w-[240px]", children: /* @__PURE__ */ jsx(Puck.Fields, {}) })
|
|
3915
|
+
] })
|
|
3916
|
+
] });
|
|
3917
|
+
};
|
|
3918
|
+
function createEditorUiStore(storeId) {
|
|
3919
|
+
return createStore()(
|
|
3920
|
+
persist(
|
|
3921
|
+
(set) => ({
|
|
3922
|
+
drawerSearch: "",
|
|
3923
|
+
setDrawerSearch: (q) => set({ drawerSearch: q }),
|
|
3924
|
+
drawerCollapsed: {},
|
|
3925
|
+
toggleDrawerGroup: (group) => set((s) => ({
|
|
3926
|
+
drawerCollapsed: { ...s.drawerCollapsed, [group]: !s.drawerCollapsed[group] }
|
|
3927
|
+
})),
|
|
3928
|
+
activeTab: "insert",
|
|
3929
|
+
setActiveTab: (tab) => set({ activeTab: tab }),
|
|
3930
|
+
outlineExpanded: {},
|
|
3931
|
+
toggleOutlineItem: (id) => set((s) => ({
|
|
3932
|
+
outlineExpanded: { ...s.outlineExpanded, [id]: !s.outlineExpanded[id] }
|
|
3933
|
+
})),
|
|
3934
|
+
theme: "light",
|
|
3935
|
+
toggleTheme: () => set((s) => {
|
|
3936
|
+
const next = s.theme === "light" ? "dark" : "light";
|
|
3937
|
+
document.documentElement.classList.toggle("dark", next === "dark");
|
|
3938
|
+
return { theme: next };
|
|
3939
|
+
})
|
|
3940
|
+
}),
|
|
3941
|
+
{
|
|
3942
|
+
name: `anvilkit-ui-${storeId}`,
|
|
3943
|
+
partialize: (s) => ({
|
|
3944
|
+
activeTab: s.activeTab,
|
|
3945
|
+
drawerCollapsed: s.drawerCollapsed,
|
|
3946
|
+
outlineExpanded: s.outlineExpanded,
|
|
3947
|
+
theme: s.theme
|
|
3948
|
+
// drawerSearch intentionally excluded — transient input
|
|
3949
|
+
})
|
|
3950
|
+
}
|
|
3951
|
+
)
|
|
3952
|
+
);
|
|
3953
|
+
}
|
|
3954
|
+
function createEditorI18nStore(initial) {
|
|
3955
|
+
return createStore()(
|
|
3956
|
+
persist(
|
|
3957
|
+
(set) => ({
|
|
3958
|
+
locale: initial.locale,
|
|
3959
|
+
messages: initial.messages,
|
|
3960
|
+
setLocale: (locale, messages) => set({ locale, messages })
|
|
3961
|
+
}),
|
|
3962
|
+
{
|
|
3963
|
+
name: "anvilkit-i18n",
|
|
3964
|
+
// Only persist locale — messages are re-loaded from props on mount
|
|
3965
|
+
partialize: (s) => ({ locale: s.locale })
|
|
3966
|
+
}
|
|
3967
|
+
)
|
|
3968
|
+
);
|
|
3969
|
+
}
|
|
3970
|
+
|
|
3971
|
+
// src/i18n/zh.ts
|
|
3972
|
+
var defaultMessages = {
|
|
3973
|
+
"header.publish": "\u53D1\u5E03",
|
|
3974
|
+
"header.undo": "\u64A4\u9500",
|
|
3975
|
+
"header.undo.tooltip": "\u64A4\u9500 (Ctrl+Z)",
|
|
3976
|
+
"header.redo": "\u91CD\u505A",
|
|
3977
|
+
"header.redo.tooltip": "\u91CD\u505A (Ctrl+Y)",
|
|
3978
|
+
"header.export": "\u5BFC\u51FA",
|
|
3979
|
+
"header.export.json": "\u5BFC\u51FA JSON",
|
|
3980
|
+
"drawer.title": "\u7EC4\u4EF6\u5E93",
|
|
3981
|
+
"drawer.search.placeholder": "\u641C\u7D22\u7EC4\u4EF6...",
|
|
3982
|
+
"aside.insert": "\u63D2\u5165",
|
|
3983
|
+
"aside.layer": "\u56FE\u5C42",
|
|
3984
|
+
"aside.image": "\u56FE\u7247",
|
|
3985
|
+
"aside.text": "\u6587\u672C",
|
|
3986
|
+
"aside.copilot": "AI \u52A9\u624B",
|
|
3987
|
+
"image-library.title": "\u56FE\u7247\u5E93",
|
|
3988
|
+
"image-library.search.placeholder": "\u641C\u7D22\u56FE\u7247...",
|
|
3989
|
+
"copy-library.title": "\u6587\u6848\u5E93",
|
|
3990
|
+
"copy-library.search.placeholder": "\u641C\u7D22\u6587\u6848...",
|
|
3991
|
+
"share.button": "\u5206\u4EAB",
|
|
3992
|
+
"share.title": "\u5206\u4EAB",
|
|
3993
|
+
"share.people-with-access": "\u6709\u6743\u9650\u7684\u4EBA",
|
|
3994
|
+
"share.general-access": "\u901A\u7528\u8BBF\u95EE",
|
|
3995
|
+
"share.copy": "\u590D\u5236",
|
|
3996
|
+
"share.copied": "\u5DF2\u590D\u5236",
|
|
3997
|
+
"share.access.private.label": "\u79C1\u5BC6",
|
|
3998
|
+
"share.access.private.description": "\u4EC5\u53D7\u9080\u4EBA\u5458\u53EF\u8BBF\u95EE",
|
|
3999
|
+
"share.access.anyone-view.label": "\u4EFB\u4F55\u6709\u94FE\u63A5\u7684\u4EBA\u53EF\u67E5\u770B",
|
|
4000
|
+
"share.access.anyone-view.description": "\u4EFB\u4F55\u6709\u94FE\u63A5\u7684\u4EBA\u5747\u53EF\u67E5\u770B",
|
|
4001
|
+
"share.access.anyone-edit.label": "\u4EFB\u4F55\u6709\u94FE\u63A5\u7684\u4EBA\u53EF\u7F16\u8F91",
|
|
4002
|
+
"share.access.anyone-edit.description": "\u4EFB\u4F55\u6709\u94FE\u63A5\u7684\u4EBA\u5747\u53EF\u7F16\u8F91",
|
|
4003
|
+
"collaborators.title": "\u534F\u4F5C\u8005",
|
|
4004
|
+
"collaborators.role.editor": "\u7F16\u8F91\u8005",
|
|
4005
|
+
"collaborators.role.editor-you": "\u7F16\u8F91\u8005\uFF08\u4F60\uFF09",
|
|
4006
|
+
"richtext.bold": "\u52A0\u7C97",
|
|
4007
|
+
"richtext.italic": "\u659C\u4F53",
|
|
4008
|
+
"richtext.link": "\u94FE\u63A5",
|
|
4009
|
+
"richtext.link.prompt": "URL\uFF1A",
|
|
4010
|
+
"header.theme.light": "\u6D45\u8272\u6A21\u5F0F",
|
|
4011
|
+
"header.theme.dark": "\u6DF1\u8272\u6A21\u5F0F"
|
|
4012
|
+
};
|
|
4013
|
+
function Studio({
|
|
4014
|
+
config,
|
|
4015
|
+
data,
|
|
4016
|
+
onPublish,
|
|
4017
|
+
onChange,
|
|
4018
|
+
overrideExtensions,
|
|
4019
|
+
aiHost,
|
|
4020
|
+
className,
|
|
4021
|
+
images,
|
|
4022
|
+
copywritings,
|
|
4023
|
+
storeId,
|
|
4024
|
+
locale,
|
|
4025
|
+
messages
|
|
4026
|
+
}) {
|
|
4027
|
+
const uiStore2 = React18.useRef(createEditorUiStore(storeId ?? "default")).current;
|
|
4028
|
+
const i18nStore = React18.useRef(
|
|
4029
|
+
createEditorI18nStore({
|
|
4030
|
+
locale: locale ?? "zh",
|
|
4031
|
+
messages: messages ?? defaultMessages
|
|
4032
|
+
})
|
|
4033
|
+
).current;
|
|
4034
|
+
const aiPlugin = React18.useMemo(
|
|
4035
|
+
() => createAiPlugin({ host: aiHost }),
|
|
4036
|
+
[aiHost]
|
|
4037
|
+
);
|
|
4038
|
+
const mergedOverrides = React18.useMemo(
|
|
4039
|
+
() => ({ ...aiPlugin.overrides, ...puckOverrides, ...overrideExtensions }),
|
|
4040
|
+
[aiPlugin.overrides, overrideExtensions]
|
|
4041
|
+
);
|
|
4042
|
+
return /* @__PURE__ */ jsx(EditorUiStoreProvider, { value: uiStore2, children: /* @__PURE__ */ jsx(EditorI18nStoreProvider, { value: i18nStore, children: /* @__PURE__ */ jsx("div", { className, children: /* @__PURE__ */ jsx(
|
|
4043
|
+
Puck,
|
|
4044
|
+
{
|
|
4045
|
+
config,
|
|
4046
|
+
data,
|
|
4047
|
+
onPublish,
|
|
4048
|
+
onChange,
|
|
4049
|
+
overrides: mergedOverrides,
|
|
4050
|
+
plugins: [aiPlugin],
|
|
4051
|
+
children: /* @__PURE__ */ jsx(
|
|
4052
|
+
EditorLayout,
|
|
4053
|
+
{
|
|
4054
|
+
aiPanel: aiPlugin.render(),
|
|
4055
|
+
images,
|
|
4056
|
+
copywritings
|
|
4057
|
+
}
|
|
4058
|
+
)
|
|
4059
|
+
}
|
|
4060
|
+
) }) }) });
|
|
4061
|
+
}
|
|
4062
|
+
|
|
4063
|
+
// src/store/index.ts
|
|
4064
|
+
var uiStore = createEditorUiStore("default");
|
|
4065
|
+
|
|
4066
|
+
export { Studio, createEditorI18nStore, createEditorUiStore, puckOverrides, uiStore };
|