@anvilkit/puck-studio 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +195 -176
- package/dist/index.cjs +945 -803
- package/dist/index.d.cts +110 -46
- package/dist/index.d.ts +110 -46
- package/dist/index.js +928 -789
- package/dist/legacy.cjs +54 -0
- package/dist/legacy.js +52 -0
- package/dist/overrides.cjs +2090 -0
- package/dist/overrides.d.cts +212 -0
- package/dist/overrides.d.ts +212 -0
- package/dist/overrides.js +2057 -0
- package/dist/styles.css +88 -0
- package/package.json +109 -65
|
@@ -0,0 +1,2057 @@
|
|
|
1
|
+
import { Search, Info, Plus, Bold, Italic, Link, ChevronRightIcon, Sparkles, ChevronDownIcon, CheckIcon, GripVertical, Copy, Trash2, SearchIcon, ChevronUpIcon } from 'lucide-react';
|
|
2
|
+
import { useStore } from 'zustand';
|
|
3
|
+
import * as React6 from 'react';
|
|
4
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
import { ScrollArea as ScrollArea$1 } from '@base-ui/react/scroll-area';
|
|
6
|
+
import { clsx } from 'clsx';
|
|
7
|
+
import { twMerge } from 'tailwind-merge';
|
|
8
|
+
import { Input as Input$1 } from '@base-ui/react/input';
|
|
9
|
+
import { usePuck, useGetPuck, AutoField } from '@puckeditor/core';
|
|
10
|
+
import { Separator as Separator$1 } from '@base-ui/react/separator';
|
|
11
|
+
import { Tooltip as Tooltip$1 } from '@base-ui/react/tooltip';
|
|
12
|
+
import { mergeProps } from '@base-ui/react/merge-props';
|
|
13
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
14
|
+
import { Button as Button$1 } from '@base-ui/react/button';
|
|
15
|
+
import { cva } from 'class-variance-authority';
|
|
16
|
+
import { Select as Select$1 } from '@base-ui/react/select';
|
|
17
|
+
import { useSensors, useSensor, PointerSensor, DndContext, closestCenter } from '@dnd-kit/core';
|
|
18
|
+
import { SortableContext, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
|
|
19
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
20
|
+
import { Popover as Popover$1 } from '@base-ui/react/popover';
|
|
21
|
+
import { AnimatePresence, motion } from 'motion/react';
|
|
22
|
+
import { Toggle as Toggle$1 } from '@base-ui/react/toggle';
|
|
23
|
+
import { Command as Command$1 } from 'cmdk';
|
|
24
|
+
|
|
25
|
+
// src/core/overrides/layout/EditorDrawer.tsx
|
|
26
|
+
function getStrictContext(name) {
|
|
27
|
+
const Context = React6.createContext(void 0);
|
|
28
|
+
const Provider = ({
|
|
29
|
+
value,
|
|
30
|
+
children
|
|
31
|
+
}) => /* @__PURE__ */ jsx(Context.Provider, { value, children });
|
|
32
|
+
const useSafeContext = () => {
|
|
33
|
+
const ctx = React6.useContext(Context);
|
|
34
|
+
if (ctx === void 0) {
|
|
35
|
+
throw new Error(`useContext must be used within ${name ?? "a Provider"}`);
|
|
36
|
+
}
|
|
37
|
+
return ctx;
|
|
38
|
+
};
|
|
39
|
+
return [Provider, useSafeContext];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/store/ui-context.ts
|
|
43
|
+
var [EditorUiStoreProvider, useEditorUiStoreApi] = getStrictContext("EditorUiStoreProvider");
|
|
44
|
+
|
|
45
|
+
// src/store/i18n-context.ts
|
|
46
|
+
var [EditorI18nStoreProvider, useEditorI18nStoreApi] = getStrictContext("EditorI18nStoreProvider");
|
|
47
|
+
|
|
48
|
+
// src/store/hooks.ts
|
|
49
|
+
function useDrawerSearch() {
|
|
50
|
+
return useStore(useEditorUiStoreApi(), (s) => s.drawerSearch);
|
|
51
|
+
}
|
|
52
|
+
function useSetDrawerSearch() {
|
|
53
|
+
return useStore(useEditorUiStoreApi(), (s) => s.setDrawerSearch);
|
|
54
|
+
}
|
|
55
|
+
function useTheme() {
|
|
56
|
+
return useStore(useEditorUiStoreApi(), (s) => s.theme);
|
|
57
|
+
}
|
|
58
|
+
function useMsg(key) {
|
|
59
|
+
return useStore(useEditorI18nStoreApi(), (s) => s.messages[key] ?? key);
|
|
60
|
+
}
|
|
61
|
+
function cn(...inputs) {
|
|
62
|
+
return twMerge(clsx(inputs));
|
|
63
|
+
}
|
|
64
|
+
function ScrollArea({
|
|
65
|
+
className,
|
|
66
|
+
children,
|
|
67
|
+
...props
|
|
68
|
+
}) {
|
|
69
|
+
return /* @__PURE__ */ jsxs(
|
|
70
|
+
ScrollArea$1.Root,
|
|
71
|
+
{
|
|
72
|
+
"data-slot": "scroll-area",
|
|
73
|
+
className: cn("relative", className),
|
|
74
|
+
...props,
|
|
75
|
+
children: [
|
|
76
|
+
/* @__PURE__ */ jsx(
|
|
77
|
+
ScrollArea$1.Viewport,
|
|
78
|
+
{
|
|
79
|
+
"data-slot": "scroll-area-viewport",
|
|
80
|
+
className: "size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1",
|
|
81
|
+
children
|
|
82
|
+
}
|
|
83
|
+
),
|
|
84
|
+
/* @__PURE__ */ jsx(ScrollBar, {}),
|
|
85
|
+
/* @__PURE__ */ jsx(ScrollArea$1.Corner, {})
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
function ScrollBar({
|
|
91
|
+
className,
|
|
92
|
+
orientation = "vertical",
|
|
93
|
+
...props
|
|
94
|
+
}) {
|
|
95
|
+
return /* @__PURE__ */ jsx(
|
|
96
|
+
ScrollArea$1.Scrollbar,
|
|
97
|
+
{
|
|
98
|
+
"data-slot": "scroll-area-scrollbar",
|
|
99
|
+
"data-orientation": orientation,
|
|
100
|
+
orientation,
|
|
101
|
+
className: cn(
|
|
102
|
+
"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",
|
|
103
|
+
className
|
|
104
|
+
),
|
|
105
|
+
...props,
|
|
106
|
+
children: /* @__PURE__ */ jsx(
|
|
107
|
+
ScrollArea$1.Thumb,
|
|
108
|
+
{
|
|
109
|
+
"data-slot": "scroll-area-thumb",
|
|
110
|
+
className: "relative flex-1 rounded-full bg-border"
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
function Input({ className, type, ...props }) {
|
|
117
|
+
return /* @__PURE__ */ jsx(
|
|
118
|
+
Input$1,
|
|
119
|
+
{
|
|
120
|
+
type,
|
|
121
|
+
"data-slot": "input",
|
|
122
|
+
className: cn(
|
|
123
|
+
"h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-2.5 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
124
|
+
className
|
|
125
|
+
),
|
|
126
|
+
...props
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
function EditorDrawer({
|
|
131
|
+
children
|
|
132
|
+
}) {
|
|
133
|
+
const search = useDrawerSearch();
|
|
134
|
+
const setSearch = useSetDrawerSearch();
|
|
135
|
+
const drawerTitle = useMsg("drawer.title");
|
|
136
|
+
const searchPlaceholder = useMsg("drawer.search.placeholder");
|
|
137
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
138
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 pt-3 pb-1 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: drawerTitle }),
|
|
139
|
+
/* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
140
|
+
/* @__PURE__ */ jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
|
|
141
|
+
/* @__PURE__ */ jsx(
|
|
142
|
+
Input,
|
|
143
|
+
{
|
|
144
|
+
className: "pl-8",
|
|
145
|
+
placeholder: searchPlaceholder,
|
|
146
|
+
value: search,
|
|
147
|
+
onChange: (e) => setSearch(e.target.value)
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
] }) }),
|
|
151
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children })
|
|
152
|
+
] });
|
|
153
|
+
}
|
|
154
|
+
function EditorComponents({
|
|
155
|
+
children
|
|
156
|
+
}) {
|
|
157
|
+
return /* @__PURE__ */ jsxs("div", { "data-puck-components-grid": true, className: "p-2", children: [
|
|
158
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
159
|
+
[data-puck-components-grid] [data-puck-drawer] {
|
|
160
|
+
display: grid;
|
|
161
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
162
|
+
gap: 6px;
|
|
163
|
+
}
|
|
164
|
+
/* flatten item wrapper and draggable wrapper */
|
|
165
|
+
[data-puck-components-grid] [data-puck-drawer] > div,
|
|
166
|
+
[data-puck-components-grid] [data-puck-drawer] > div > div {
|
|
167
|
+
display: contents;
|
|
168
|
+
}
|
|
169
|
+
/* hide the ghost/bg copy */
|
|
170
|
+
[data-puck-components-grid] [data-puck-drawer] > div > div > div:first-child {
|
|
171
|
+
display: none;
|
|
172
|
+
}
|
|
173
|
+
/* flatten the real draggable wrapper */
|
|
174
|
+
[data-puck-components-grid] [data-puck-drawer] > div > div > div:last-child {
|
|
175
|
+
display: contents;
|
|
176
|
+
}
|
|
177
|
+
` }),
|
|
178
|
+
children
|
|
179
|
+
] });
|
|
180
|
+
}
|
|
181
|
+
function getPlaceholderUrl(name) {
|
|
182
|
+
return `https://picsum.photos/seed/${encodeURIComponent(name)}/120/80`;
|
|
183
|
+
}
|
|
184
|
+
function DrawerItem({
|
|
185
|
+
children,
|
|
186
|
+
name
|
|
187
|
+
}) {
|
|
188
|
+
const { config } = usePuck();
|
|
189
|
+
const componentConfig = config.components?.[name];
|
|
190
|
+
const thumbnail = typeof componentConfig?.metadata?.thumbnail === "string" ? componentConfig.metadata.thumbnail : void 0;
|
|
191
|
+
const src = thumbnail ?? getPlaceholderUrl(name);
|
|
192
|
+
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: [
|
|
193
|
+
/* @__PURE__ */ jsx("div", { className: "w-full h-16 bg-muted overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
194
|
+
"img",
|
|
195
|
+
{
|
|
196
|
+
src,
|
|
197
|
+
alt: name,
|
|
198
|
+
className: "w-full h-full object-cover",
|
|
199
|
+
onError: (e) => {
|
|
200
|
+
e.currentTarget.style.display = "none";
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
) }),
|
|
204
|
+
/* @__PURE__ */ jsx("div", { className: "px-2 py-1.5 text-xs font-medium truncate", children: name ?? children })
|
|
205
|
+
] });
|
|
206
|
+
}
|
|
207
|
+
function Separator({
|
|
208
|
+
className,
|
|
209
|
+
orientation = "horizontal",
|
|
210
|
+
...props
|
|
211
|
+
}) {
|
|
212
|
+
return /* @__PURE__ */ jsx(
|
|
213
|
+
Separator$1,
|
|
214
|
+
{
|
|
215
|
+
"data-slot": "separator",
|
|
216
|
+
orientation,
|
|
217
|
+
className: cn(
|
|
218
|
+
"shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
|
|
219
|
+
className
|
|
220
|
+
),
|
|
221
|
+
...props
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
function EditorOutline({
|
|
226
|
+
children
|
|
227
|
+
}) {
|
|
228
|
+
const { selectedItem } = usePuck();
|
|
229
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
|
|
230
|
+
/* @__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" }) }),
|
|
231
|
+
selectedItem && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
232
|
+
/* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 text-xs text-muted-foreground truncate", children: [
|
|
233
|
+
"Selected:",
|
|
234
|
+
" ",
|
|
235
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: typeof selectedItem.type === "string" ? selectedItem.type : String(selectedItem.type) })
|
|
236
|
+
] }),
|
|
237
|
+
/* @__PURE__ */ jsx(Separator, {})
|
|
238
|
+
] }),
|
|
239
|
+
/* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-2 text-sm", children }) })
|
|
240
|
+
] });
|
|
241
|
+
}
|
|
242
|
+
var CANVAS_CSS = `
|
|
243
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
244
|
+
:root {
|
|
245
|
+
--background: 0 0% 100%;
|
|
246
|
+
--foreground: 222.2 84% 4.9%;
|
|
247
|
+
--primary: 222.2 47.4% 11.2%;
|
|
248
|
+
--primary-foreground: 210 40% 98%;
|
|
249
|
+
--secondary: 210 40% 96.1%;
|
|
250
|
+
--muted: 210 40% 96.1%;
|
|
251
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
252
|
+
--border: 214.3 31.8% 91.4%;
|
|
253
|
+
--radius: 0.5rem;
|
|
254
|
+
}
|
|
255
|
+
.dark {
|
|
256
|
+
--background: 222.2 84% 4.9%;
|
|
257
|
+
--foreground: 210 40% 98%;
|
|
258
|
+
--primary: 210 40% 98%;
|
|
259
|
+
--primary-foreground: 222.2 47.4% 11.2%;
|
|
260
|
+
--secondary: 217.2 32.6% 17.5%;
|
|
261
|
+
--muted: 217.2 32.6% 17.5%;
|
|
262
|
+
--muted-foreground: 215 20.2% 65.1%;
|
|
263
|
+
--border: 217.2 32.6% 17.5%;
|
|
264
|
+
}
|
|
265
|
+
body { margin: 0; font-family: system-ui, sans-serif; }
|
|
266
|
+
`;
|
|
267
|
+
var CANVAS_STYLE_ID = "__anvilkit_styles__";
|
|
268
|
+
function resolveDocument(target) {
|
|
269
|
+
if (target) return target;
|
|
270
|
+
if (typeof document === "undefined") return void 0;
|
|
271
|
+
return document;
|
|
272
|
+
}
|
|
273
|
+
function useThemeSync({
|
|
274
|
+
document: targetDocument,
|
|
275
|
+
injectCanvasCss = false
|
|
276
|
+
} = {}) {
|
|
277
|
+
const theme = useTheme();
|
|
278
|
+
React6.useEffect(() => {
|
|
279
|
+
const resolvedDocument = resolveDocument(targetDocument);
|
|
280
|
+
if (!resolvedDocument || !injectCanvasCss) return;
|
|
281
|
+
const existing = resolvedDocument.getElementById(CANVAS_STYLE_ID);
|
|
282
|
+
if (existing) existing.remove();
|
|
283
|
+
const style = resolvedDocument.createElement("style");
|
|
284
|
+
style.id = CANVAS_STYLE_ID;
|
|
285
|
+
style.textContent = CANVAS_CSS;
|
|
286
|
+
resolvedDocument.head.appendChild(style);
|
|
287
|
+
}, [targetDocument, injectCanvasCss]);
|
|
288
|
+
React6.useEffect(() => {
|
|
289
|
+
const resolvedDocument = resolveDocument(targetDocument);
|
|
290
|
+
if (!resolvedDocument) return;
|
|
291
|
+
resolvedDocument.documentElement.classList.toggle("dark", theme === "dark");
|
|
292
|
+
}, [targetDocument, theme]);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/features/library-dnd/drop-contract.ts
|
|
296
|
+
var LIBRARY_DRAG_START = "anvilkit:librarydragstart";
|
|
297
|
+
var IMAGE_DROP = "anvilkit:imagedrop";
|
|
298
|
+
var TEXT_DROP = "anvilkit:textdrop";
|
|
299
|
+
function addLibraryDragEventListener(type, listener, target = window) {
|
|
300
|
+
const wrapped = (event) => {
|
|
301
|
+
listener(event);
|
|
302
|
+
};
|
|
303
|
+
target.addEventListener(type, wrapped);
|
|
304
|
+
return () => {
|
|
305
|
+
target.removeEventListener(type, wrapped);
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// src/features/library-dnd/replace-props.ts
|
|
310
|
+
function isImageUrl(val) {
|
|
311
|
+
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/");
|
|
312
|
+
}
|
|
313
|
+
function replaceImageInProps(props, newSrc) {
|
|
314
|
+
const result = {};
|
|
315
|
+
for (const key of Object.keys(props)) {
|
|
316
|
+
const val = props[key];
|
|
317
|
+
if (typeof val === "string" && isImageUrl(val)) {
|
|
318
|
+
result[key] = newSrc;
|
|
319
|
+
} else if (Array.isArray(val)) {
|
|
320
|
+
result[key] = val.map(
|
|
321
|
+
(item) => item && typeof item === "object" ? replaceImageInProps(item, newSrc) : item
|
|
322
|
+
);
|
|
323
|
+
} else if (val && typeof val === "object") {
|
|
324
|
+
result[key] = replaceImageInProps(val, newSrc);
|
|
325
|
+
} else {
|
|
326
|
+
result[key] = val;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
function replaceTextInProps(props, newText, targetText) {
|
|
332
|
+
for (const key of Object.keys(props)) {
|
|
333
|
+
if (key === "id") continue;
|
|
334
|
+
const val = props[key];
|
|
335
|
+
if (typeof val === "string" && val === targetText && !isImageUrl(val)) {
|
|
336
|
+
return { result: { ...props, [key]: newText }, replaced: true };
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
for (const key of Object.keys(props)) {
|
|
340
|
+
if (key === "id") continue;
|
|
341
|
+
const val = props[key];
|
|
342
|
+
if (typeof val === "string" && !isImageUrl(val) && val.length > 0) {
|
|
343
|
+
return { result: { ...props, [key]: newText }, replaced: true };
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return { result: props, replaced: false };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// src/core/overrides/canvas/drop-targets.ts
|
|
350
|
+
var TEXT_TAGS = /* @__PURE__ */ new Set([
|
|
351
|
+
"P",
|
|
352
|
+
"H1",
|
|
353
|
+
"H2",
|
|
354
|
+
"H3",
|
|
355
|
+
"H4",
|
|
356
|
+
"H5",
|
|
357
|
+
"H6",
|
|
358
|
+
"SPAN",
|
|
359
|
+
"A",
|
|
360
|
+
"LI",
|
|
361
|
+
"BUTTON",
|
|
362
|
+
"LABEL"
|
|
363
|
+
]);
|
|
364
|
+
function getIframeCoords(iframeEl, clientX, clientY) {
|
|
365
|
+
const rect = iframeEl.getBoundingClientRect();
|
|
366
|
+
const x = clientX - rect.left;
|
|
367
|
+
const y = clientY - rect.top;
|
|
368
|
+
if (x < 0 || y < 0 || x > rect.width || y > rect.height) {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
return { x, y };
|
|
372
|
+
}
|
|
373
|
+
function getComponentElAt(iframeDoc, iframeEl, clientX, clientY) {
|
|
374
|
+
const coords = getIframeCoords(iframeEl, clientX, clientY);
|
|
375
|
+
if (!coords) return null;
|
|
376
|
+
const element = iframeDoc.elementFromPoint(coords.x, coords.y);
|
|
377
|
+
if (!element) return null;
|
|
378
|
+
return element.closest("[data-puck-component]");
|
|
379
|
+
}
|
|
380
|
+
function getImageElInComponent(compEl, iframeEl, clientX, clientY) {
|
|
381
|
+
const images = Array.from(compEl.querySelectorAll("img"));
|
|
382
|
+
if (!images.length) return null;
|
|
383
|
+
if (images.length === 1) return images[0];
|
|
384
|
+
const rect = iframeEl.getBoundingClientRect();
|
|
385
|
+
const x = clientX - rect.left;
|
|
386
|
+
const y = clientY - rect.top;
|
|
387
|
+
let closest = null;
|
|
388
|
+
let minDistance = Infinity;
|
|
389
|
+
for (const image of images) {
|
|
390
|
+
const imageRect = image.getBoundingClientRect();
|
|
391
|
+
const centerX = imageRect.left + imageRect.width / 2;
|
|
392
|
+
const centerY = imageRect.top + imageRect.height / 2;
|
|
393
|
+
const distance = Math.hypot(centerX - x, centerY - y);
|
|
394
|
+
if (distance < minDistance) {
|
|
395
|
+
minDistance = distance;
|
|
396
|
+
closest = image;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return closest;
|
|
400
|
+
}
|
|
401
|
+
function getTextElInComponent(iframeDoc, iframeEl, compEl, clientX, clientY) {
|
|
402
|
+
const coords = getIframeCoords(iframeEl, clientX, clientY);
|
|
403
|
+
if (!coords) return null;
|
|
404
|
+
const element = iframeDoc.elementFromPoint(coords.x, coords.y);
|
|
405
|
+
if (element && compEl.contains(element)) {
|
|
406
|
+
let current = element;
|
|
407
|
+
while (current && current !== iframeDoc.body) {
|
|
408
|
+
if (TEXT_TAGS.has(current.tagName) && current.textContent?.trim()) {
|
|
409
|
+
return current;
|
|
410
|
+
}
|
|
411
|
+
current = current.parentElement;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
for (const tag of TEXT_TAGS) {
|
|
415
|
+
const candidate = compEl.querySelector(tag.toLowerCase());
|
|
416
|
+
if (candidate?.textContent?.trim()) {
|
|
417
|
+
return candidate;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// src/core/overrides/canvas/highlight.ts
|
|
424
|
+
function createElementHighlighter() {
|
|
425
|
+
let highlightedEl = null;
|
|
426
|
+
function set(el, color) {
|
|
427
|
+
if (highlightedEl && highlightedEl !== el) {
|
|
428
|
+
highlightedEl.style.outline = "";
|
|
429
|
+
highlightedEl.style.outlineOffset = "";
|
|
430
|
+
}
|
|
431
|
+
if (el) {
|
|
432
|
+
el.style.outline = `2px solid ${color}`;
|
|
433
|
+
el.style.outlineOffset = "2px";
|
|
434
|
+
}
|
|
435
|
+
highlightedEl = el;
|
|
436
|
+
}
|
|
437
|
+
function clear() {
|
|
438
|
+
set(null, "");
|
|
439
|
+
}
|
|
440
|
+
return { set, clear };
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// src/core/overrides/canvas/useLibraryDropBridge.ts
|
|
444
|
+
function useLibraryDropBridge(iframeDoc) {
|
|
445
|
+
const getPuck = useGetPuck();
|
|
446
|
+
React6.useEffect(() => {
|
|
447
|
+
if (!iframeDoc) return;
|
|
448
|
+
const iframeEl = iframeDoc.defaultView?.frameElement;
|
|
449
|
+
if (!iframeEl) return;
|
|
450
|
+
const iframeDocument = iframeDoc;
|
|
451
|
+
const frameElement = iframeEl;
|
|
452
|
+
let activeLibrary = null;
|
|
453
|
+
const highlighter = createElementHighlighter();
|
|
454
|
+
function dispatchReplace(componentId, updatedProps) {
|
|
455
|
+
const { dispatch, getItemById, getSelectorForId } = getPuck();
|
|
456
|
+
const item = getItemById(componentId);
|
|
457
|
+
const selector = getSelectorForId(componentId);
|
|
458
|
+
if (!item || !selector) return false;
|
|
459
|
+
dispatch({
|
|
460
|
+
type: "replace",
|
|
461
|
+
destinationIndex: selector.index,
|
|
462
|
+
destinationZone: selector.zone,
|
|
463
|
+
data: {
|
|
464
|
+
...item,
|
|
465
|
+
props: { ...item.props, ...updatedProps }
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
function onLibraryDragStart(type) {
|
|
471
|
+
activeLibrary = type;
|
|
472
|
+
}
|
|
473
|
+
function onPointerMove(e) {
|
|
474
|
+
if (!activeLibrary) return;
|
|
475
|
+
const compEl = getComponentElAt(iframeDocument, frameElement, e.clientX, e.clientY);
|
|
476
|
+
if (!compEl) {
|
|
477
|
+
highlighter.clear();
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (activeLibrary === "image") {
|
|
481
|
+
highlighter.set(
|
|
482
|
+
getImageElInComponent(compEl, frameElement, e.clientX, e.clientY),
|
|
483
|
+
"#6366f1"
|
|
484
|
+
);
|
|
485
|
+
} else {
|
|
486
|
+
highlighter.set(
|
|
487
|
+
getTextElInComponent(iframeDocument, frameElement, compEl, e.clientX, e.clientY),
|
|
488
|
+
"#f59e0b"
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function onPointerUp() {
|
|
493
|
+
activeLibrary = null;
|
|
494
|
+
highlighter.clear();
|
|
495
|
+
}
|
|
496
|
+
function onImageDrop(src, clientX, clientY) {
|
|
497
|
+
highlighter.clear();
|
|
498
|
+
activeLibrary = null;
|
|
499
|
+
if (!src) return;
|
|
500
|
+
const compEl = getComponentElAt(iframeDocument, frameElement, clientX, clientY);
|
|
501
|
+
if (!compEl) return;
|
|
502
|
+
const componentId = compEl.dataset.puckComponent;
|
|
503
|
+
if (!componentId) return;
|
|
504
|
+
const item = getPuck().getItemById(componentId);
|
|
505
|
+
if (!item) return;
|
|
506
|
+
const updatedProps = replaceImageInProps(
|
|
507
|
+
item.props,
|
|
508
|
+
src
|
|
509
|
+
);
|
|
510
|
+
dispatchReplace(componentId, updatedProps);
|
|
511
|
+
}
|
|
512
|
+
function onTextDrop(text, clientX, clientY) {
|
|
513
|
+
highlighter.clear();
|
|
514
|
+
activeLibrary = null;
|
|
515
|
+
if (!text) return;
|
|
516
|
+
const compEl = getComponentElAt(iframeDocument, frameElement, clientX, clientY);
|
|
517
|
+
if (!compEl) return;
|
|
518
|
+
const componentId = compEl.dataset.puckComponent;
|
|
519
|
+
if (!componentId) return;
|
|
520
|
+
const textEl = getTextElInComponent(
|
|
521
|
+
iframeDocument,
|
|
522
|
+
frameElement,
|
|
523
|
+
compEl,
|
|
524
|
+
clientX,
|
|
525
|
+
clientY
|
|
526
|
+
);
|
|
527
|
+
const targetText = textEl?.textContent?.trim() ?? "";
|
|
528
|
+
const item = getPuck().getItemById(componentId);
|
|
529
|
+
if (!item) return;
|
|
530
|
+
const { result: updatedProps, replaced } = replaceTextInProps(
|
|
531
|
+
item.props,
|
|
532
|
+
text,
|
|
533
|
+
targetText
|
|
534
|
+
);
|
|
535
|
+
if (replaced) dispatchReplace(componentId, updatedProps);
|
|
536
|
+
}
|
|
537
|
+
const removeLibraryDragStart = addLibraryDragEventListener(
|
|
538
|
+
LIBRARY_DRAG_START,
|
|
539
|
+
(event) => {
|
|
540
|
+
onLibraryDragStart(event.detail.type);
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
544
|
+
window.addEventListener("pointerup", onPointerUp);
|
|
545
|
+
const removeImageDrop = addLibraryDragEventListener(IMAGE_DROP, (event) => {
|
|
546
|
+
const { src, clientX, clientY } = event.detail;
|
|
547
|
+
onImageDrop(src, clientX, clientY);
|
|
548
|
+
});
|
|
549
|
+
const removeTextDrop = addLibraryDragEventListener(TEXT_DROP, (event) => {
|
|
550
|
+
const { text, clientX, clientY } = event.detail;
|
|
551
|
+
onTextDrop(text, clientX, clientY);
|
|
552
|
+
});
|
|
553
|
+
return () => {
|
|
554
|
+
removeLibraryDragStart();
|
|
555
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
556
|
+
window.removeEventListener("pointerup", onPointerUp);
|
|
557
|
+
removeImageDrop();
|
|
558
|
+
removeTextDrop();
|
|
559
|
+
highlighter.clear();
|
|
560
|
+
};
|
|
561
|
+
}, [iframeDoc, getPuck]);
|
|
562
|
+
}
|
|
563
|
+
function CanvasIframe({
|
|
564
|
+
children,
|
|
565
|
+
document: iframeDoc
|
|
566
|
+
}) {
|
|
567
|
+
useThemeSync({ document: iframeDoc, injectCanvasCss: true });
|
|
568
|
+
useLibraryDropBridge(iframeDoc);
|
|
569
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
570
|
+
}
|
|
571
|
+
function CanvasPreview({
|
|
572
|
+
children
|
|
573
|
+
}) {
|
|
574
|
+
return /* @__PURE__ */ jsx("div", { className: "w-full h-full px-3 py-2 text-sm font-medium text-foreground", children });
|
|
575
|
+
}
|
|
576
|
+
function ComponentOverlay({
|
|
577
|
+
children,
|
|
578
|
+
hover,
|
|
579
|
+
isSelected
|
|
580
|
+
}) {
|
|
581
|
+
return /* @__PURE__ */ jsx(
|
|
582
|
+
"div",
|
|
583
|
+
{
|
|
584
|
+
className: [
|
|
585
|
+
"absolute inset-0 rounded-sm pointer-events-none z-10 transition-colors",
|
|
586
|
+
isSelected ? "border-2 border-primary/80" : hover ? "border-2 border-primary/40" : ""
|
|
587
|
+
].filter(Boolean).join(" "),
|
|
588
|
+
children
|
|
589
|
+
}
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
function TooltipProvider({
|
|
593
|
+
delay = 0,
|
|
594
|
+
...props
|
|
595
|
+
}) {
|
|
596
|
+
return /* @__PURE__ */ jsx(
|
|
597
|
+
Tooltip$1.Provider,
|
|
598
|
+
{
|
|
599
|
+
"data-slot": "tooltip-provider",
|
|
600
|
+
delay,
|
|
601
|
+
...props
|
|
602
|
+
}
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
function Tooltip({ ...props }) {
|
|
606
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Root, { "data-slot": "tooltip", ...props });
|
|
607
|
+
}
|
|
608
|
+
function TooltipTrigger({ ...props }) {
|
|
609
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { "data-slot": "tooltip-trigger", ...props });
|
|
610
|
+
}
|
|
611
|
+
function TooltipContent({
|
|
612
|
+
className,
|
|
613
|
+
side = "top",
|
|
614
|
+
sideOffset = 4,
|
|
615
|
+
align = "center",
|
|
616
|
+
alignOffset = 0,
|
|
617
|
+
children,
|
|
618
|
+
...props
|
|
619
|
+
}) {
|
|
620
|
+
return /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsx(
|
|
621
|
+
Tooltip$1.Positioner,
|
|
622
|
+
{
|
|
623
|
+
align,
|
|
624
|
+
alignOffset,
|
|
625
|
+
side,
|
|
626
|
+
sideOffset,
|
|
627
|
+
className: "isolate z-50",
|
|
628
|
+
children: /* @__PURE__ */ jsxs(
|
|
629
|
+
Tooltip$1.Popup,
|
|
630
|
+
{
|
|
631
|
+
"data-slot": "tooltip-content",
|
|
632
|
+
className: cn(
|
|
633
|
+
"z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-md bg-foreground px-3 py-1.5 text-xs text-background has-data-[slot=kbd]:pr-1.5 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
634
|
+
className
|
|
635
|
+
),
|
|
636
|
+
...props,
|
|
637
|
+
children: [
|
|
638
|
+
children,
|
|
639
|
+
/* @__PURE__ */ jsx(Tooltip$1.Arrow, { className: "z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=inline-end]:top-1/2! data-[side=inline-end]:-left-1 data-[side=inline-end]:-translate-y-1/2 data-[side=inline-start]:top-1/2! data-[side=inline-start]:-right-1 data-[side=inline-start]:-translate-y-1/2 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5" })
|
|
640
|
+
]
|
|
641
|
+
}
|
|
642
|
+
)
|
|
643
|
+
}
|
|
644
|
+
) });
|
|
645
|
+
}
|
|
646
|
+
function ActionBar({
|
|
647
|
+
children,
|
|
648
|
+
label,
|
|
649
|
+
parentAction
|
|
650
|
+
}) {
|
|
651
|
+
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: [
|
|
652
|
+
label && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
653
|
+
/* @__PURE__ */ jsx("span", { className: "px-2 text-xs font-medium text-muted-foreground truncate max-w-[120px]", children: label }),
|
|
654
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5" })
|
|
655
|
+
] }),
|
|
656
|
+
parentAction && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
657
|
+
parentAction,
|
|
658
|
+
/* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5" })
|
|
659
|
+
] }),
|
|
660
|
+
children
|
|
661
|
+
] }) });
|
|
662
|
+
}
|
|
663
|
+
function Label({ className, ...props }) {
|
|
664
|
+
return /* @__PURE__ */ jsx(
|
|
665
|
+
"label",
|
|
666
|
+
{
|
|
667
|
+
"data-slot": "label",
|
|
668
|
+
className: cn(
|
|
669
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
670
|
+
className
|
|
671
|
+
),
|
|
672
|
+
...props
|
|
673
|
+
}
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
function Breadcrumb({ className, ...props }) {
|
|
677
|
+
return /* @__PURE__ */ jsx(
|
|
678
|
+
"nav",
|
|
679
|
+
{
|
|
680
|
+
"aria-label": "breadcrumb",
|
|
681
|
+
"data-slot": "breadcrumb",
|
|
682
|
+
className: cn(className),
|
|
683
|
+
...props
|
|
684
|
+
}
|
|
685
|
+
);
|
|
686
|
+
}
|
|
687
|
+
function BreadcrumbList({ className, ...props }) {
|
|
688
|
+
return /* @__PURE__ */ jsx(
|
|
689
|
+
"ol",
|
|
690
|
+
{
|
|
691
|
+
"data-slot": "breadcrumb-list",
|
|
692
|
+
className: cn(
|
|
693
|
+
"flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground sm:gap-2.5",
|
|
694
|
+
className
|
|
695
|
+
),
|
|
696
|
+
...props
|
|
697
|
+
}
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
function BreadcrumbItem({ className, ...props }) {
|
|
701
|
+
return /* @__PURE__ */ jsx(
|
|
702
|
+
"li",
|
|
703
|
+
{
|
|
704
|
+
"data-slot": "breadcrumb-item",
|
|
705
|
+
className: cn("inline-flex items-center gap-1.5", className),
|
|
706
|
+
...props
|
|
707
|
+
}
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
function BreadcrumbLink({
|
|
711
|
+
className,
|
|
712
|
+
render,
|
|
713
|
+
...props
|
|
714
|
+
}) {
|
|
715
|
+
return useRender({
|
|
716
|
+
defaultTagName: "a",
|
|
717
|
+
props: mergeProps(
|
|
718
|
+
{
|
|
719
|
+
className: cn("transition-colors hover:text-foreground", className)
|
|
720
|
+
},
|
|
721
|
+
props
|
|
722
|
+
),
|
|
723
|
+
render,
|
|
724
|
+
state: {
|
|
725
|
+
slot: "breadcrumb-link"
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
function BreadcrumbPage({ className, ...props }) {
|
|
730
|
+
return /* @__PURE__ */ jsx(
|
|
731
|
+
"span",
|
|
732
|
+
{
|
|
733
|
+
"data-slot": "breadcrumb-page",
|
|
734
|
+
role: "link",
|
|
735
|
+
"aria-disabled": "true",
|
|
736
|
+
"aria-current": "page",
|
|
737
|
+
className: cn("font-normal text-foreground", className),
|
|
738
|
+
...props
|
|
739
|
+
}
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
function BreadcrumbSeparator({
|
|
743
|
+
children,
|
|
744
|
+
className,
|
|
745
|
+
...props
|
|
746
|
+
}) {
|
|
747
|
+
return /* @__PURE__ */ jsx(
|
|
748
|
+
"li",
|
|
749
|
+
{
|
|
750
|
+
"data-slot": "breadcrumb-separator",
|
|
751
|
+
role: "presentation",
|
|
752
|
+
"aria-hidden": "true",
|
|
753
|
+
className: cn("[&>svg]:size-3.5", className),
|
|
754
|
+
...props,
|
|
755
|
+
children: children ?? /* @__PURE__ */ jsx(ChevronRightIcon, {})
|
|
756
|
+
}
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
function getComponentTypeLabel(item) {
|
|
760
|
+
if (!item) return "Component";
|
|
761
|
+
return typeof item.type === "string" ? item.type : String(item.type);
|
|
762
|
+
}
|
|
763
|
+
function getComponentId(item) {
|
|
764
|
+
const id = item?.props?.id;
|
|
765
|
+
return typeof id === "string" ? id : null;
|
|
766
|
+
}
|
|
767
|
+
function useBreadcrumbs() {
|
|
768
|
+
const { appState, dispatch, selectedItem, getParentById } = usePuck();
|
|
769
|
+
const { itemSelector } = appState.ui;
|
|
770
|
+
const selectRoot = () => dispatch({ type: "setUi", ui: { itemSelector: null } });
|
|
771
|
+
if (!itemSelector || !selectedItem) {
|
|
772
|
+
return [{ label: "Page" }];
|
|
773
|
+
}
|
|
774
|
+
const selectedType = getComponentTypeLabel(selectedItem);
|
|
775
|
+
const parentId = getComponentId(selectedItem);
|
|
776
|
+
const parent = parentId ? getParentById(parentId) : void 0;
|
|
777
|
+
if (!parent) {
|
|
778
|
+
return [{ label: "Page", onSelect: selectRoot }, { label: selectedType }];
|
|
779
|
+
}
|
|
780
|
+
const parentType = getComponentTypeLabel(parent);
|
|
781
|
+
return [
|
|
782
|
+
{ label: "Page", onSelect: selectRoot },
|
|
783
|
+
{ label: parentType },
|
|
784
|
+
{ label: selectedType }
|
|
785
|
+
];
|
|
786
|
+
}
|
|
787
|
+
function FieldWrapper({
|
|
788
|
+
children
|
|
789
|
+
}) {
|
|
790
|
+
const crumbs = useBreadcrumbs();
|
|
791
|
+
return /* @__PURE__ */ jsx(ScrollArea, { className: "h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0", children: [
|
|
792
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-b", children: /* @__PURE__ */ jsx(Breadcrumb, { children: /* @__PURE__ */ jsx(BreadcrumbList, { children: crumbs.map((crumb, i) => {
|
|
793
|
+
const isLast = i === crumbs.length - 1;
|
|
794
|
+
return /* @__PURE__ */ jsxs(React6.Fragment, { children: [
|
|
795
|
+
i > 0 && /* @__PURE__ */ jsx(BreadcrumbSeparator, {}),
|
|
796
|
+
/* @__PURE__ */ jsx(BreadcrumbItem, { children: isLast ? /* @__PURE__ */ jsx(BreadcrumbPage, { children: crumb.label }) : /* @__PURE__ */ jsx(
|
|
797
|
+
BreadcrumbLink,
|
|
798
|
+
{
|
|
799
|
+
className: "cursor-pointer",
|
|
800
|
+
onClick: crumb.onSelect,
|
|
801
|
+
children: crumb.label
|
|
802
|
+
}
|
|
803
|
+
) })
|
|
804
|
+
] }, i);
|
|
805
|
+
}) }) }) }),
|
|
806
|
+
children
|
|
807
|
+
] }) });
|
|
808
|
+
}
|
|
809
|
+
function FieldLabel({
|
|
810
|
+
children,
|
|
811
|
+
label,
|
|
812
|
+
icon,
|
|
813
|
+
labelIcon,
|
|
814
|
+
el,
|
|
815
|
+
readOnly,
|
|
816
|
+
className
|
|
817
|
+
}) {
|
|
818
|
+
const El = el ?? "div";
|
|
819
|
+
const labelAdornment = icon ?? labelIcon;
|
|
820
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(El, { className: `flex flex-col gap-1.5 ${className ?? ""}`, children: [
|
|
821
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
822
|
+
labelAdornment && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: labelAdornment }),
|
|
823
|
+
/* @__PURE__ */ jsx(Label, { className: "text-xs font-medium text-muted-foreground", children: label }),
|
|
824
|
+
label && /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
825
|
+
/* @__PURE__ */ jsx(
|
|
826
|
+
TooltipTrigger,
|
|
827
|
+
{
|
|
828
|
+
"aria-label": label,
|
|
829
|
+
render: /* @__PURE__ */ jsx(
|
|
830
|
+
"button",
|
|
831
|
+
{
|
|
832
|
+
type: "button",
|
|
833
|
+
className: "inline-flex cursor-help items-center justify-center text-muted-foreground/60 transition-colors hover:text-muted-foreground"
|
|
834
|
+
}
|
|
835
|
+
),
|
|
836
|
+
children: /* @__PURE__ */ jsx(Info, { className: "h-3 w-3 text-muted-foreground/60 cursor-help" })
|
|
837
|
+
}
|
|
838
|
+
),
|
|
839
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "right", children: label })
|
|
840
|
+
] }),
|
|
841
|
+
readOnly && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-muted-foreground/50", children: "Read only" })
|
|
842
|
+
] }),
|
|
843
|
+
children
|
|
844
|
+
] }) });
|
|
845
|
+
}
|
|
846
|
+
var buttonVariants = cva(
|
|
847
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
848
|
+
{
|
|
849
|
+
variants: {
|
|
850
|
+
variant: {
|
|
851
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
|
852
|
+
outline: "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
853
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
854
|
+
ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
855
|
+
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",
|
|
856
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
857
|
+
},
|
|
858
|
+
size: {
|
|
859
|
+
default: "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
860
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
861
|
+
sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
|
|
862
|
+
lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
|
863
|
+
icon: "size-9",
|
|
864
|
+
"icon-xs": "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
|
|
865
|
+
"icon-sm": "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
|
|
866
|
+
"icon-lg": "size-10"
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
defaultVariants: {
|
|
870
|
+
variant: "default",
|
|
871
|
+
size: "default"
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
);
|
|
875
|
+
function Button({
|
|
876
|
+
className,
|
|
877
|
+
variant = "default",
|
|
878
|
+
size = "default",
|
|
879
|
+
...props
|
|
880
|
+
}) {
|
|
881
|
+
return /* @__PURE__ */ jsx(
|
|
882
|
+
Button$1,
|
|
883
|
+
{
|
|
884
|
+
"data-slot": "button",
|
|
885
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
886
|
+
...props
|
|
887
|
+
}
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
var MOCK_VALUES = {
|
|
891
|
+
default: ["AI-generated content", "Smart suggestion", "Generated text"]
|
|
892
|
+
};
|
|
893
|
+
function getMock(instructions) {
|
|
894
|
+
if (instructions?.toLowerCase().includes("caps")) {
|
|
895
|
+
return "AI GENERATED TITLE";
|
|
896
|
+
}
|
|
897
|
+
const pool = MOCK_VALUES.default;
|
|
898
|
+
return pool[Math.floor(Math.random() * pool.length)];
|
|
899
|
+
}
|
|
900
|
+
function AiButton({ ai, onGenerate }) {
|
|
901
|
+
const [loading, setLoading] = React6.useState(false);
|
|
902
|
+
const handleClick = () => {
|
|
903
|
+
setLoading(true);
|
|
904
|
+
setTimeout(() => {
|
|
905
|
+
onGenerate(getMock(ai.instructions));
|
|
906
|
+
setLoading(false);
|
|
907
|
+
}, 600);
|
|
908
|
+
};
|
|
909
|
+
return /* @__PURE__ */ jsx(
|
|
910
|
+
Button,
|
|
911
|
+
{
|
|
912
|
+
type: "button",
|
|
913
|
+
variant: "outline",
|
|
914
|
+
size: "icon",
|
|
915
|
+
className: "h-8 w-8 shrink-0 text-muted-foreground hover:text-primary",
|
|
916
|
+
onClick: handleClick,
|
|
917
|
+
disabled: loading,
|
|
918
|
+
"aria-label": "Generate with AI",
|
|
919
|
+
children: /* @__PURE__ */ jsx(Sparkles, { className: `h-3.5 w-3.5 ${loading ? "animate-pulse" : ""}` })
|
|
920
|
+
}
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
function TextField({
|
|
924
|
+
field,
|
|
925
|
+
value,
|
|
926
|
+
onChange,
|
|
927
|
+
readOnly,
|
|
928
|
+
placeholder,
|
|
929
|
+
label,
|
|
930
|
+
labelIcon
|
|
931
|
+
}) {
|
|
932
|
+
const [local, setLocal] = React6.useState(value ?? "");
|
|
933
|
+
const onChangeRef = React6.useRef(onChange);
|
|
934
|
+
const lastCommittedValueRef = React6.useRef(value ?? "");
|
|
935
|
+
React6.useEffect(() => {
|
|
936
|
+
onChangeRef.current = onChange;
|
|
937
|
+
}, [onChange]);
|
|
938
|
+
React6.useEffect(() => {
|
|
939
|
+
lastCommittedValueRef.current = value ?? "";
|
|
940
|
+
setLocal(value ?? "");
|
|
941
|
+
}, [value]);
|
|
942
|
+
React6.useEffect(() => {
|
|
943
|
+
const timer = setTimeout(() => {
|
|
944
|
+
if (local !== lastCommittedValueRef.current) {
|
|
945
|
+
onChangeRef.current(local);
|
|
946
|
+
lastCommittedValueRef.current = local;
|
|
947
|
+
}
|
|
948
|
+
}, 200);
|
|
949
|
+
return () => clearTimeout(timer);
|
|
950
|
+
}, [local]);
|
|
951
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", labelIcon, readOnly, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
952
|
+
/* @__PURE__ */ jsx(
|
|
953
|
+
Input,
|
|
954
|
+
{
|
|
955
|
+
value: local,
|
|
956
|
+
onChange: (e) => setLocal(e.target.value),
|
|
957
|
+
readOnly,
|
|
958
|
+
placeholder,
|
|
959
|
+
className: "h-8 text-sm flex-1"
|
|
960
|
+
}
|
|
961
|
+
),
|
|
962
|
+
field?.ai && /* @__PURE__ */ jsx(
|
|
963
|
+
AiButton,
|
|
964
|
+
{
|
|
965
|
+
ai: field.ai,
|
|
966
|
+
onGenerate: (nextValue) => {
|
|
967
|
+
lastCommittedValueRef.current = nextValue;
|
|
968
|
+
setLocal(nextValue);
|
|
969
|
+
onChangeRef.current(nextValue);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
)
|
|
973
|
+
] }) });
|
|
974
|
+
}
|
|
975
|
+
function Textarea({ className, ...props }) {
|
|
976
|
+
return /* @__PURE__ */ jsx(
|
|
977
|
+
"textarea",
|
|
978
|
+
{
|
|
979
|
+
"data-slot": "textarea",
|
|
980
|
+
className: cn(
|
|
981
|
+
"flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-transparent px-2.5 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
|
|
982
|
+
className
|
|
983
|
+
),
|
|
984
|
+
...props
|
|
985
|
+
}
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
function TextareaField({ value, onChange, readOnly, placeholder, label }) {
|
|
989
|
+
const [local, setLocal] = React6.useState(value ?? "");
|
|
990
|
+
React6.useEffect(() => {
|
|
991
|
+
setLocal(value ?? "");
|
|
992
|
+
}, [value]);
|
|
993
|
+
React6.useEffect(() => {
|
|
994
|
+
const timer = setTimeout(() => {
|
|
995
|
+
if (local !== value) onChange(local);
|
|
996
|
+
}, 200);
|
|
997
|
+
return () => clearTimeout(timer);
|
|
998
|
+
}, [local]);
|
|
999
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsx(
|
|
1000
|
+
Textarea,
|
|
1001
|
+
{
|
|
1002
|
+
value: local,
|
|
1003
|
+
onChange: (e) => setLocal(e.target.value),
|
|
1004
|
+
readOnly,
|
|
1005
|
+
placeholder,
|
|
1006
|
+
className: "min-h-[80px] text-sm resize-y"
|
|
1007
|
+
}
|
|
1008
|
+
) });
|
|
1009
|
+
}
|
|
1010
|
+
function NumberField({ value, onChange, readOnly, min, max, step, label }) {
|
|
1011
|
+
const [local, setLocal] = React6.useState(String(value ?? ""));
|
|
1012
|
+
React6.useEffect(() => {
|
|
1013
|
+
setLocal(String(value ?? ""));
|
|
1014
|
+
}, [value]);
|
|
1015
|
+
React6.useEffect(() => {
|
|
1016
|
+
const parsed = parseFloat(local);
|
|
1017
|
+
if (!isNaN(parsed) && parsed !== value) {
|
|
1018
|
+
const timer = setTimeout(() => onChange(parsed), 200);
|
|
1019
|
+
return () => clearTimeout(timer);
|
|
1020
|
+
}
|
|
1021
|
+
}, [local]);
|
|
1022
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsx(
|
|
1023
|
+
Input,
|
|
1024
|
+
{
|
|
1025
|
+
type: "number",
|
|
1026
|
+
value: local,
|
|
1027
|
+
onChange: (e) => setLocal(e.target.value),
|
|
1028
|
+
readOnly,
|
|
1029
|
+
min,
|
|
1030
|
+
max,
|
|
1031
|
+
step,
|
|
1032
|
+
className: "h-8 text-sm"
|
|
1033
|
+
}
|
|
1034
|
+
) });
|
|
1035
|
+
}
|
|
1036
|
+
var Select = Select$1.Root;
|
|
1037
|
+
function SelectGroup({ className, ...props }) {
|
|
1038
|
+
return /* @__PURE__ */ jsx(
|
|
1039
|
+
Select$1.Group,
|
|
1040
|
+
{
|
|
1041
|
+
"data-slot": "select-group",
|
|
1042
|
+
className: cn("scroll-my-1 p-1", className),
|
|
1043
|
+
...props
|
|
1044
|
+
}
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
function SelectValue({ className, ...props }) {
|
|
1048
|
+
return /* @__PURE__ */ jsx(
|
|
1049
|
+
Select$1.Value,
|
|
1050
|
+
{
|
|
1051
|
+
"data-slot": "select-value",
|
|
1052
|
+
className: cn("flex flex-1 text-left", className),
|
|
1053
|
+
...props
|
|
1054
|
+
}
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
function SelectTrigger({
|
|
1058
|
+
className,
|
|
1059
|
+
size = "default",
|
|
1060
|
+
children,
|
|
1061
|
+
...props
|
|
1062
|
+
}) {
|
|
1063
|
+
return /* @__PURE__ */ jsxs(
|
|
1064
|
+
Select$1.Trigger,
|
|
1065
|
+
{
|
|
1066
|
+
"data-slot": "select-trigger",
|
|
1067
|
+
"data-size": size,
|
|
1068
|
+
className: cn(
|
|
1069
|
+
"flex w-fit items-center justify-between gap-1.5 rounded-md border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1070
|
+
className
|
|
1071
|
+
),
|
|
1072
|
+
...props,
|
|
1073
|
+
children: [
|
|
1074
|
+
children,
|
|
1075
|
+
/* @__PURE__ */ jsx(
|
|
1076
|
+
Select$1.Icon,
|
|
1077
|
+
{
|
|
1078
|
+
render: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "pointer-events-none size-4 text-muted-foreground" })
|
|
1079
|
+
}
|
|
1080
|
+
)
|
|
1081
|
+
]
|
|
1082
|
+
}
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
function SelectContent({
|
|
1086
|
+
className,
|
|
1087
|
+
children,
|
|
1088
|
+
side = "bottom",
|
|
1089
|
+
sideOffset = 4,
|
|
1090
|
+
align = "center",
|
|
1091
|
+
alignOffset = 0,
|
|
1092
|
+
alignItemWithTrigger = true,
|
|
1093
|
+
...props
|
|
1094
|
+
}) {
|
|
1095
|
+
return /* @__PURE__ */ jsx(Select$1.Portal, { children: /* @__PURE__ */ jsx(
|
|
1096
|
+
Select$1.Positioner,
|
|
1097
|
+
{
|
|
1098
|
+
side,
|
|
1099
|
+
sideOffset,
|
|
1100
|
+
align,
|
|
1101
|
+
alignOffset,
|
|
1102
|
+
alignItemWithTrigger,
|
|
1103
|
+
className: "isolate z-50",
|
|
1104
|
+
children: /* @__PURE__ */ jsxs(
|
|
1105
|
+
Select$1.Popup,
|
|
1106
|
+
{
|
|
1107
|
+
"data-slot": "select-content",
|
|
1108
|
+
"data-align-trigger": alignItemWithTrigger,
|
|
1109
|
+
className: cn("relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-md bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className),
|
|
1110
|
+
...props,
|
|
1111
|
+
children: [
|
|
1112
|
+
/* @__PURE__ */ jsx(SelectScrollUpButton, {}),
|
|
1113
|
+
/* @__PURE__ */ jsx(Select$1.List, { children }),
|
|
1114
|
+
/* @__PURE__ */ jsx(SelectScrollDownButton, {})
|
|
1115
|
+
]
|
|
1116
|
+
}
|
|
1117
|
+
)
|
|
1118
|
+
}
|
|
1119
|
+
) });
|
|
1120
|
+
}
|
|
1121
|
+
function SelectItem({
|
|
1122
|
+
className,
|
|
1123
|
+
children,
|
|
1124
|
+
...props
|
|
1125
|
+
}) {
|
|
1126
|
+
return /* @__PURE__ */ jsxs(
|
|
1127
|
+
Select$1.Item,
|
|
1128
|
+
{
|
|
1129
|
+
"data-slot": "select-item",
|
|
1130
|
+
className: cn(
|
|
1131
|
+
"relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
1132
|
+
className
|
|
1133
|
+
),
|
|
1134
|
+
...props,
|
|
1135
|
+
children: [
|
|
1136
|
+
/* @__PURE__ */ jsx(Select$1.ItemText, { className: "flex flex-1 shrink-0 gap-2 whitespace-nowrap", children }),
|
|
1137
|
+
/* @__PURE__ */ jsx(
|
|
1138
|
+
Select$1.ItemIndicator,
|
|
1139
|
+
{
|
|
1140
|
+
render: /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center" }),
|
|
1141
|
+
children: /* @__PURE__ */ jsx(CheckIcon, { className: "pointer-events-none" })
|
|
1142
|
+
}
|
|
1143
|
+
)
|
|
1144
|
+
]
|
|
1145
|
+
}
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
function SelectScrollUpButton({
|
|
1149
|
+
className,
|
|
1150
|
+
...props
|
|
1151
|
+
}) {
|
|
1152
|
+
return /* @__PURE__ */ jsx(
|
|
1153
|
+
Select$1.ScrollUpArrow,
|
|
1154
|
+
{
|
|
1155
|
+
"data-slot": "select-scroll-up-button",
|
|
1156
|
+
className: cn(
|
|
1157
|
+
"top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
|
|
1158
|
+
className
|
|
1159
|
+
),
|
|
1160
|
+
...props,
|
|
1161
|
+
children: /* @__PURE__ */ jsx(
|
|
1162
|
+
ChevronUpIcon,
|
|
1163
|
+
{}
|
|
1164
|
+
)
|
|
1165
|
+
}
|
|
1166
|
+
);
|
|
1167
|
+
}
|
|
1168
|
+
function SelectScrollDownButton({
|
|
1169
|
+
className,
|
|
1170
|
+
...props
|
|
1171
|
+
}) {
|
|
1172
|
+
return /* @__PURE__ */ jsx(
|
|
1173
|
+
Select$1.ScrollDownArrow,
|
|
1174
|
+
{
|
|
1175
|
+
"data-slot": "select-scroll-down-button",
|
|
1176
|
+
className: cn(
|
|
1177
|
+
"bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
|
|
1178
|
+
className
|
|
1179
|
+
),
|
|
1180
|
+
...props,
|
|
1181
|
+
children: /* @__PURE__ */ jsx(
|
|
1182
|
+
ChevronDownIcon,
|
|
1183
|
+
{}
|
|
1184
|
+
)
|
|
1185
|
+
}
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
function SelectField({ field, value, onChange, id, readOnly, label }) {
|
|
1189
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsxs(
|
|
1190
|
+
Select,
|
|
1191
|
+
{
|
|
1192
|
+
value: String(value ?? ""),
|
|
1193
|
+
onValueChange: (v) => {
|
|
1194
|
+
if (v === null) return;
|
|
1195
|
+
const match = field.options.find((o) => String(o.value) === v);
|
|
1196
|
+
onChange(match ? match.value : v);
|
|
1197
|
+
},
|
|
1198
|
+
children: [
|
|
1199
|
+
/* @__PURE__ */ jsx(SelectTrigger, { id, className: "h-8 text-sm w-full", disabled: readOnly, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select..." }) }),
|
|
1200
|
+
/* @__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))) }) })
|
|
1201
|
+
]
|
|
1202
|
+
}
|
|
1203
|
+
) });
|
|
1204
|
+
}
|
|
1205
|
+
var buttonGroupVariants = cva(
|
|
1206
|
+
"flex w-fit items-stretch *:focus-visible:relative *:focus-visible:z-10 has-[>[data-slot=button-group]]:gap-2 has-[select[aria-hidden=true]:last-child]:[&>[data-slot=select-trigger]:last-of-type]:rounded-r-md [&>[data-slot=select-trigger]:not([class*='w-'])]:w-fit [&>input]:flex-1",
|
|
1207
|
+
{
|
|
1208
|
+
variants: {
|
|
1209
|
+
orientation: {
|
|
1210
|
+
horizontal: "*:data-slot:rounded-r-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-r-md! [&>[data-slot]~[data-slot]]:rounded-l-none [&>[data-slot]~[data-slot]]:border-l-0",
|
|
1211
|
+
vertical: "flex-col *:data-slot:rounded-b-none [&>[data-slot]:not(:has(~[data-slot]))]:rounded-b-md! [&>[data-slot]~[data-slot]]:rounded-t-none [&>[data-slot]~[data-slot]]:border-t-0"
|
|
1212
|
+
}
|
|
1213
|
+
},
|
|
1214
|
+
defaultVariants: {
|
|
1215
|
+
orientation: "horizontal"
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
);
|
|
1219
|
+
function ButtonGroup({
|
|
1220
|
+
className,
|
|
1221
|
+
orientation,
|
|
1222
|
+
...props
|
|
1223
|
+
}) {
|
|
1224
|
+
return /* @__PURE__ */ jsx(
|
|
1225
|
+
"div",
|
|
1226
|
+
{
|
|
1227
|
+
role: "group",
|
|
1228
|
+
"data-slot": "button-group",
|
|
1229
|
+
"data-orientation": orientation,
|
|
1230
|
+
className: cn(buttonGroupVariants({ orientation }), className),
|
|
1231
|
+
...props
|
|
1232
|
+
}
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
function RadioField({ field, value, onChange, readOnly, label }) {
|
|
1236
|
+
const options = field.options ?? [];
|
|
1237
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, el: "div", children: /* @__PURE__ */ jsx(ButtonGroup, { className: "w-full", children: options.map((opt) => {
|
|
1238
|
+
const selected = String(opt.value) === String(value ?? "");
|
|
1239
|
+
return /* @__PURE__ */ jsx(
|
|
1240
|
+
Button,
|
|
1241
|
+
{
|
|
1242
|
+
type: "button",
|
|
1243
|
+
variant: selected ? "default" : "outline",
|
|
1244
|
+
size: "sm",
|
|
1245
|
+
className: "flex-1 text-xs",
|
|
1246
|
+
disabled: readOnly,
|
|
1247
|
+
onClick: () => onChange(opt.value),
|
|
1248
|
+
children: opt.label
|
|
1249
|
+
},
|
|
1250
|
+
String(opt.value)
|
|
1251
|
+
);
|
|
1252
|
+
}) }) });
|
|
1253
|
+
}
|
|
1254
|
+
function ItemGroup({ className, ...props }) {
|
|
1255
|
+
return /* @__PURE__ */ jsx(
|
|
1256
|
+
"div",
|
|
1257
|
+
{
|
|
1258
|
+
role: "list",
|
|
1259
|
+
"data-slot": "item-group",
|
|
1260
|
+
className: cn(
|
|
1261
|
+
"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
|
|
1262
|
+
className
|
|
1263
|
+
),
|
|
1264
|
+
...props
|
|
1265
|
+
}
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
var itemVariants = cva(
|
|
1269
|
+
"group/item flex w-full flex-wrap items-center rounded-md border text-sm transition-colors duration-100 outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 [a]:transition-colors [a]:hover:bg-muted",
|
|
1270
|
+
{
|
|
1271
|
+
variants: {
|
|
1272
|
+
variant: {
|
|
1273
|
+
default: "border-transparent",
|
|
1274
|
+
outline: "border-border",
|
|
1275
|
+
muted: "border-transparent bg-muted/50"
|
|
1276
|
+
},
|
|
1277
|
+
size: {
|
|
1278
|
+
default: "gap-3.5 px-4 py-3.5",
|
|
1279
|
+
sm: "gap-2.5 px-3 py-2.5",
|
|
1280
|
+
xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0"
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1283
|
+
defaultVariants: {
|
|
1284
|
+
variant: "default",
|
|
1285
|
+
size: "default"
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
);
|
|
1289
|
+
function Item({
|
|
1290
|
+
className,
|
|
1291
|
+
variant = "default",
|
|
1292
|
+
size = "default",
|
|
1293
|
+
render,
|
|
1294
|
+
...props
|
|
1295
|
+
}) {
|
|
1296
|
+
return useRender({
|
|
1297
|
+
defaultTagName: "div",
|
|
1298
|
+
props: mergeProps(
|
|
1299
|
+
{
|
|
1300
|
+
className: cn(itemVariants({ variant, size, className }))
|
|
1301
|
+
},
|
|
1302
|
+
props
|
|
1303
|
+
),
|
|
1304
|
+
render,
|
|
1305
|
+
state: {
|
|
1306
|
+
slot: "item",
|
|
1307
|
+
variant,
|
|
1308
|
+
size
|
|
1309
|
+
}
|
|
1310
|
+
});
|
|
1311
|
+
}
|
|
1312
|
+
cva(
|
|
1313
|
+
"flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
|
|
1314
|
+
{
|
|
1315
|
+
variants: {
|
|
1316
|
+
variant: {
|
|
1317
|
+
default: "bg-transparent",
|
|
1318
|
+
icon: "[&_svg:not([class*='size-'])]:size-4",
|
|
1319
|
+
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"
|
|
1320
|
+
}
|
|
1321
|
+
},
|
|
1322
|
+
defaultVariants: {
|
|
1323
|
+
variant: "default"
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
);
|
|
1327
|
+
function ItemContent({ className, ...props }) {
|
|
1328
|
+
return /* @__PURE__ */ jsx(
|
|
1329
|
+
"div",
|
|
1330
|
+
{
|
|
1331
|
+
"data-slot": "item-content",
|
|
1332
|
+
className: cn(
|
|
1333
|
+
"flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
|
|
1334
|
+
className
|
|
1335
|
+
),
|
|
1336
|
+
...props
|
|
1337
|
+
}
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
function ItemTitle({ className, ...props }) {
|
|
1341
|
+
return /* @__PURE__ */ jsx(
|
|
1342
|
+
"div",
|
|
1343
|
+
{
|
|
1344
|
+
"data-slot": "item-title",
|
|
1345
|
+
className: cn(
|
|
1346
|
+
"line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
|
|
1347
|
+
className
|
|
1348
|
+
),
|
|
1349
|
+
...props
|
|
1350
|
+
}
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
function ItemActions({ className, ...props }) {
|
|
1354
|
+
return /* @__PURE__ */ jsx(
|
|
1355
|
+
"div",
|
|
1356
|
+
{
|
|
1357
|
+
"data-slot": "item-actions",
|
|
1358
|
+
className: cn("flex items-center gap-2", className),
|
|
1359
|
+
...props
|
|
1360
|
+
}
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
function useControlledState(props) {
|
|
1364
|
+
const { value, defaultValue, onChange } = props;
|
|
1365
|
+
const [state, setInternalState] = React6.useState(
|
|
1366
|
+
value !== void 0 ? value : defaultValue
|
|
1367
|
+
);
|
|
1368
|
+
React6.useEffect(() => {
|
|
1369
|
+
if (value !== void 0) setInternalState(value);
|
|
1370
|
+
}, [value]);
|
|
1371
|
+
const setState = React6.useCallback(
|
|
1372
|
+
(next, ...args) => {
|
|
1373
|
+
setInternalState(next);
|
|
1374
|
+
onChange?.(next, ...args);
|
|
1375
|
+
},
|
|
1376
|
+
[onChange]
|
|
1377
|
+
);
|
|
1378
|
+
return [state, setState];
|
|
1379
|
+
}
|
|
1380
|
+
var [PopoverProvider, usePopover] = getStrictContext("PopoverContext");
|
|
1381
|
+
function Popover(props) {
|
|
1382
|
+
const [isOpen, setIsOpen] = useControlledState({
|
|
1383
|
+
value: props?.open,
|
|
1384
|
+
defaultValue: props?.defaultOpen,
|
|
1385
|
+
onChange: props?.onOpenChange
|
|
1386
|
+
});
|
|
1387
|
+
return /* @__PURE__ */ jsx(PopoverProvider, { value: { isOpen, setIsOpen }, children: /* @__PURE__ */ jsx(
|
|
1388
|
+
Popover$1.Root,
|
|
1389
|
+
{
|
|
1390
|
+
"data-slot": "popover",
|
|
1391
|
+
...props,
|
|
1392
|
+
onOpenChange: setIsOpen
|
|
1393
|
+
}
|
|
1394
|
+
) });
|
|
1395
|
+
}
|
|
1396
|
+
function PopoverTrigger(props) {
|
|
1397
|
+
return /* @__PURE__ */ jsx(Popover$1.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
1398
|
+
}
|
|
1399
|
+
function PopoverPortal(props) {
|
|
1400
|
+
const { isOpen } = usePopover();
|
|
1401
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(
|
|
1402
|
+
Popover$1.Portal,
|
|
1403
|
+
{
|
|
1404
|
+
keepMounted: true,
|
|
1405
|
+
"data-slot": "popover-portal",
|
|
1406
|
+
...props
|
|
1407
|
+
}
|
|
1408
|
+
) });
|
|
1409
|
+
}
|
|
1410
|
+
function PopoverPositioner(props) {
|
|
1411
|
+
return /* @__PURE__ */ jsx(Popover$1.Positioner, { "data-slot": "popover-positioner", ...props });
|
|
1412
|
+
}
|
|
1413
|
+
function PopoverPopup({
|
|
1414
|
+
initialFocus,
|
|
1415
|
+
finalFocus,
|
|
1416
|
+
transition = { type: "spring", stiffness: 300, damping: 25 },
|
|
1417
|
+
...props
|
|
1418
|
+
}) {
|
|
1419
|
+
return /* @__PURE__ */ jsx(
|
|
1420
|
+
Popover$1.Popup,
|
|
1421
|
+
{
|
|
1422
|
+
initialFocus,
|
|
1423
|
+
finalFocus,
|
|
1424
|
+
render: /* @__PURE__ */ jsx(
|
|
1425
|
+
motion.div,
|
|
1426
|
+
{
|
|
1427
|
+
"data-slot": "popover-popup",
|
|
1428
|
+
initial: { opacity: 0, scale: 0.5 },
|
|
1429
|
+
animate: { opacity: 1, scale: 1 },
|
|
1430
|
+
exit: { opacity: 0, scale: 0.5 },
|
|
1431
|
+
transition,
|
|
1432
|
+
...props
|
|
1433
|
+
},
|
|
1434
|
+
"popover-popup"
|
|
1435
|
+
)
|
|
1436
|
+
}
|
|
1437
|
+
);
|
|
1438
|
+
}
|
|
1439
|
+
function Popover2(props) {
|
|
1440
|
+
return /* @__PURE__ */ jsx(Popover, { ...props });
|
|
1441
|
+
}
|
|
1442
|
+
function PopoverTrigger2(props) {
|
|
1443
|
+
return /* @__PURE__ */ jsx(PopoverTrigger, { ...props });
|
|
1444
|
+
}
|
|
1445
|
+
function PopoverPanel({
|
|
1446
|
+
className,
|
|
1447
|
+
align = "center",
|
|
1448
|
+
sideOffset = 4,
|
|
1449
|
+
initialFocus,
|
|
1450
|
+
finalFocus,
|
|
1451
|
+
style,
|
|
1452
|
+
children,
|
|
1453
|
+
...props
|
|
1454
|
+
}) {
|
|
1455
|
+
return /* @__PURE__ */ jsx(PopoverPortal, { children: /* @__PURE__ */ jsx(
|
|
1456
|
+
PopoverPositioner,
|
|
1457
|
+
{
|
|
1458
|
+
align,
|
|
1459
|
+
sideOffset,
|
|
1460
|
+
className: "z-50",
|
|
1461
|
+
...props,
|
|
1462
|
+
children: /* @__PURE__ */ jsx(
|
|
1463
|
+
PopoverPopup,
|
|
1464
|
+
{
|
|
1465
|
+
initialFocus,
|
|
1466
|
+
finalFocus,
|
|
1467
|
+
className: cn(
|
|
1468
|
+
"bg-popover text-popover-foreground w-72 rounded-md border p-4 shadow-md outline-hidden origin-(--transform-origin)",
|
|
1469
|
+
className
|
|
1470
|
+
),
|
|
1471
|
+
style,
|
|
1472
|
+
children
|
|
1473
|
+
}
|
|
1474
|
+
)
|
|
1475
|
+
}
|
|
1476
|
+
) });
|
|
1477
|
+
}
|
|
1478
|
+
function getArraySubField(subName, subField) {
|
|
1479
|
+
return { ...subField, label: subField.label ?? subName };
|
|
1480
|
+
}
|
|
1481
|
+
function SortableItem({
|
|
1482
|
+
id,
|
|
1483
|
+
index,
|
|
1484
|
+
item,
|
|
1485
|
+
field,
|
|
1486
|
+
readOnly,
|
|
1487
|
+
atMax,
|
|
1488
|
+
atMin,
|
|
1489
|
+
fieldId,
|
|
1490
|
+
open,
|
|
1491
|
+
onOpenChange,
|
|
1492
|
+
onDuplicate,
|
|
1493
|
+
onRemove,
|
|
1494
|
+
onUpdate,
|
|
1495
|
+
getSummary
|
|
1496
|
+
}) {
|
|
1497
|
+
const {
|
|
1498
|
+
attributes,
|
|
1499
|
+
listeners,
|
|
1500
|
+
setNodeRef,
|
|
1501
|
+
transform,
|
|
1502
|
+
transition,
|
|
1503
|
+
isDragging
|
|
1504
|
+
} = useSortable({ id });
|
|
1505
|
+
const style = {
|
|
1506
|
+
transform: CSS.Transform.toString(transform),
|
|
1507
|
+
transition,
|
|
1508
|
+
opacity: isDragging ? 0.5 : 1
|
|
1509
|
+
};
|
|
1510
|
+
return /* @__PURE__ */ jsx("div", { ref: setNodeRef, style, children: /* @__PURE__ */ jsxs(Popover2, { open, onOpenChange, children: [
|
|
1511
|
+
/* @__PURE__ */ jsxs(Item, { variant: "outline", size: "sm", className: "cursor-pointer", children: [
|
|
1512
|
+
/* @__PURE__ */ jsx(
|
|
1513
|
+
"button",
|
|
1514
|
+
{
|
|
1515
|
+
type: "button",
|
|
1516
|
+
className: "cursor-grab active:cursor-grabbing touch-none p-0.5 text-muted-foreground/40 hover:text-muted-foreground",
|
|
1517
|
+
...attributes,
|
|
1518
|
+
...listeners,
|
|
1519
|
+
children: /* @__PURE__ */ jsx(GripVertical, { className: "h-3.5 w-3.5 shrink-0" })
|
|
1520
|
+
}
|
|
1521
|
+
),
|
|
1522
|
+
/* @__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) }) }) }),
|
|
1523
|
+
!readOnly && /* @__PURE__ */ jsxs(ItemActions, { children: [
|
|
1524
|
+
/* @__PURE__ */ jsx(
|
|
1525
|
+
Button,
|
|
1526
|
+
{
|
|
1527
|
+
variant: "ghost",
|
|
1528
|
+
size: "icon",
|
|
1529
|
+
className: "h-5 w-5",
|
|
1530
|
+
disabled: atMax,
|
|
1531
|
+
onClick: (e) => {
|
|
1532
|
+
e.stopPropagation();
|
|
1533
|
+
onDuplicate(index);
|
|
1534
|
+
},
|
|
1535
|
+
title: "Duplicate",
|
|
1536
|
+
children: /* @__PURE__ */ jsx(Copy, { className: "h-3 w-3" })
|
|
1537
|
+
}
|
|
1538
|
+
),
|
|
1539
|
+
/* @__PURE__ */ jsx(
|
|
1540
|
+
Button,
|
|
1541
|
+
{
|
|
1542
|
+
variant: "ghost",
|
|
1543
|
+
size: "icon",
|
|
1544
|
+
className: "h-5 w-5 text-destructive hover:text-destructive",
|
|
1545
|
+
disabled: atMin,
|
|
1546
|
+
onClick: (e) => {
|
|
1547
|
+
e.stopPropagation();
|
|
1548
|
+
onRemove(index);
|
|
1549
|
+
},
|
|
1550
|
+
title: "Delete",
|
|
1551
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-3 w-3" })
|
|
1552
|
+
}
|
|
1553
|
+
)
|
|
1554
|
+
] })
|
|
1555
|
+
] }),
|
|
1556
|
+
/* @__PURE__ */ jsx(
|
|
1557
|
+
PopoverPanel,
|
|
1558
|
+
{
|
|
1559
|
+
side: "left",
|
|
1560
|
+
sideOffset: 60,
|
|
1561
|
+
align: "start",
|
|
1562
|
+
alignOffset: -14,
|
|
1563
|
+
className: "w-56 p-3 flex flex-col gap-2",
|
|
1564
|
+
children: Object.entries(field.arrayFields).map(([subName, subField]) => /* @__PURE__ */ jsx(
|
|
1565
|
+
AutoField,
|
|
1566
|
+
{
|
|
1567
|
+
field: getArraySubField(subName, subField),
|
|
1568
|
+
value: item[subName],
|
|
1569
|
+
onChange: (val) => onUpdate(index, subName, val),
|
|
1570
|
+
readOnly,
|
|
1571
|
+
id: `${fieldId}-${index}-${subName}`
|
|
1572
|
+
},
|
|
1573
|
+
subName
|
|
1574
|
+
))
|
|
1575
|
+
}
|
|
1576
|
+
)
|
|
1577
|
+
] }) });
|
|
1578
|
+
}
|
|
1579
|
+
function ArrayField({
|
|
1580
|
+
field,
|
|
1581
|
+
value = [],
|
|
1582
|
+
onChange,
|
|
1583
|
+
readOnly,
|
|
1584
|
+
label,
|
|
1585
|
+
id = ""
|
|
1586
|
+
}) {
|
|
1587
|
+
const [openIndex, setOpenIndex] = React6.useState(null);
|
|
1588
|
+
const stableValue = React6.useMemo(() => {
|
|
1589
|
+
const needsId = value.some((item) => !item._id);
|
|
1590
|
+
if (!needsId) return value;
|
|
1591
|
+
return value.map(
|
|
1592
|
+
(item) => item._id ? item : { ...item, _id: `${id}-${Math.random().toString(36).slice(2)}` }
|
|
1593
|
+
);
|
|
1594
|
+
}, [value, id]);
|
|
1595
|
+
const itemIds = stableValue.map((item) => item._id);
|
|
1596
|
+
const atMax = field.max !== void 0 && stableValue.length >= field.max;
|
|
1597
|
+
const atMin = field.min !== void 0 && stableValue.length <= field.min;
|
|
1598
|
+
const sensors = useSensors(useSensor(PointerSensor));
|
|
1599
|
+
const handleDragEnd = (event) => {
|
|
1600
|
+
const { active, over } = event;
|
|
1601
|
+
if (!over || active.id === over.id) return;
|
|
1602
|
+
const from = itemIds.indexOf(active.id);
|
|
1603
|
+
const to = itemIds.indexOf(over.id);
|
|
1604
|
+
if (from === -1 || to === -1) return;
|
|
1605
|
+
onChange(arrayMove(stableValue, from, to));
|
|
1606
|
+
};
|
|
1607
|
+
const defaultItem = () => {
|
|
1608
|
+
if (!field.defaultItemProps) return {};
|
|
1609
|
+
return typeof field.defaultItemProps === "function" ? field.defaultItemProps(value.length) : { ...field.defaultItemProps };
|
|
1610
|
+
};
|
|
1611
|
+
const addItem = () => {
|
|
1612
|
+
if (atMax || readOnly) return;
|
|
1613
|
+
const newIndex = stableValue.length;
|
|
1614
|
+
onChange([...stableValue, defaultItem()]);
|
|
1615
|
+
setOpenIndex(newIndex);
|
|
1616
|
+
};
|
|
1617
|
+
const removeItem = (i) => {
|
|
1618
|
+
if (atMin || readOnly) return;
|
|
1619
|
+
const next = [...stableValue];
|
|
1620
|
+
next.splice(i, 1);
|
|
1621
|
+
onChange(next);
|
|
1622
|
+
};
|
|
1623
|
+
const duplicateItem = (i) => {
|
|
1624
|
+
if (atMax || readOnly) return;
|
|
1625
|
+
const next = [...stableValue];
|
|
1626
|
+
next.splice(i + 1, 0, { ...stableValue[i] });
|
|
1627
|
+
onChange(next);
|
|
1628
|
+
};
|
|
1629
|
+
const updateItem = (i, subName, val) => {
|
|
1630
|
+
onChange(
|
|
1631
|
+
stableValue.map(
|
|
1632
|
+
(item, idx) => idx === i ? { ...item, [subName]: val } : item
|
|
1633
|
+
)
|
|
1634
|
+
);
|
|
1635
|
+
};
|
|
1636
|
+
const getSummary = (item, i) => {
|
|
1637
|
+
if (field.getItemSummary) return field.getItemSummary(item, i);
|
|
1638
|
+
const first = Object.entries(item).find(
|
|
1639
|
+
(entry) => entry[0] !== "_id" && typeof entry[1] === "string" && entry[1].length > 0
|
|
1640
|
+
);
|
|
1641
|
+
return first?.[1] ?? `Item ${i + 1}`;
|
|
1642
|
+
};
|
|
1643
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? field.label ?? "", readOnly, el: "div", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
1644
|
+
/* @__PURE__ */ jsx(
|
|
1645
|
+
DndContext,
|
|
1646
|
+
{
|
|
1647
|
+
sensors,
|
|
1648
|
+
collisionDetection: closestCenter,
|
|
1649
|
+
onDragEnd: handleDragEnd,
|
|
1650
|
+
children: /* @__PURE__ */ jsx(
|
|
1651
|
+
SortableContext,
|
|
1652
|
+
{
|
|
1653
|
+
items: itemIds,
|
|
1654
|
+
strategy: verticalListSortingStrategy,
|
|
1655
|
+
children: /* @__PURE__ */ jsx(ItemGroup, { children: stableValue.map((item, i) => /* @__PURE__ */ jsx(
|
|
1656
|
+
SortableItem,
|
|
1657
|
+
{
|
|
1658
|
+
id: itemIds[i],
|
|
1659
|
+
index: i,
|
|
1660
|
+
item,
|
|
1661
|
+
field,
|
|
1662
|
+
readOnly,
|
|
1663
|
+
atMax,
|
|
1664
|
+
atMin,
|
|
1665
|
+
fieldId: id,
|
|
1666
|
+
open: openIndex === i,
|
|
1667
|
+
onOpenChange: (o) => setOpenIndex(o ? i : null),
|
|
1668
|
+
onDuplicate: duplicateItem,
|
|
1669
|
+
onRemove: removeItem,
|
|
1670
|
+
onUpdate: updateItem,
|
|
1671
|
+
getSummary
|
|
1672
|
+
},
|
|
1673
|
+
itemIds[i]
|
|
1674
|
+
)) })
|
|
1675
|
+
}
|
|
1676
|
+
)
|
|
1677
|
+
}
|
|
1678
|
+
),
|
|
1679
|
+
!readOnly && !atMax && /* @__PURE__ */ jsxs(
|
|
1680
|
+
Button,
|
|
1681
|
+
{
|
|
1682
|
+
variant: "outline",
|
|
1683
|
+
size: "sm",
|
|
1684
|
+
onClick: addItem,
|
|
1685
|
+
className: "w-full gap-1.5 mt-0.5",
|
|
1686
|
+
children: [
|
|
1687
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }),
|
|
1688
|
+
"Add item"
|
|
1689
|
+
]
|
|
1690
|
+
}
|
|
1691
|
+
)
|
|
1692
|
+
] }) });
|
|
1693
|
+
}
|
|
1694
|
+
function ObjectField({ children, name, readOnly }) {
|
|
1695
|
+
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 }) });
|
|
1696
|
+
}
|
|
1697
|
+
function Card({
|
|
1698
|
+
className,
|
|
1699
|
+
size = "default",
|
|
1700
|
+
...props
|
|
1701
|
+
}) {
|
|
1702
|
+
return /* @__PURE__ */ jsx(
|
|
1703
|
+
"div",
|
|
1704
|
+
{
|
|
1705
|
+
"data-slot": "card",
|
|
1706
|
+
"data-size": size,
|
|
1707
|
+
className: cn(
|
|
1708
|
+
"group/card flex flex-col gap-6 overflow-hidden rounded-xl bg-card py-6 text-sm text-card-foreground shadow-xs ring-1 ring-foreground/10 has-[>img:first-child]:pt-0 data-[size=sm]:gap-4 data-[size=sm]:py-4 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
|
1709
|
+
className
|
|
1710
|
+
),
|
|
1711
|
+
...props
|
|
1712
|
+
}
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1715
|
+
function CardContent({ className, ...props }) {
|
|
1716
|
+
return /* @__PURE__ */ jsx(
|
|
1717
|
+
"div",
|
|
1718
|
+
{
|
|
1719
|
+
"data-slot": "card-content",
|
|
1720
|
+
className: cn("px-6 group-data-[size=sm]/card:px-4", className),
|
|
1721
|
+
...props
|
|
1722
|
+
}
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
function SlotField({ children, label }) {
|
|
1726
|
+
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." }) }) }) });
|
|
1727
|
+
}
|
|
1728
|
+
function CustomField({ children, label }) {
|
|
1729
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", el: "div", children: /* @__PURE__ */ jsx("div", { className: "rounded-md border border-border/60 p-3", children }) });
|
|
1730
|
+
}
|
|
1731
|
+
var toggleVariants = cva(
|
|
1732
|
+
"group/toggle inline-flex items-center justify-center gap-1 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1733
|
+
{
|
|
1734
|
+
variants: {
|
|
1735
|
+
variant: {
|
|
1736
|
+
default: "bg-transparent",
|
|
1737
|
+
outline: "border border-input bg-transparent shadow-xs hover:bg-muted"
|
|
1738
|
+
},
|
|
1739
|
+
size: {
|
|
1740
|
+
default: "h-9 min-w-9 px-2",
|
|
1741
|
+
sm: "h-8 min-w-8 px-1.5",
|
|
1742
|
+
lg: "h-10 min-w-10 px-2.5"
|
|
1743
|
+
}
|
|
1744
|
+
},
|
|
1745
|
+
defaultVariants: {
|
|
1746
|
+
variant: "default",
|
|
1747
|
+
size: "default"
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
);
|
|
1751
|
+
function Toggle({
|
|
1752
|
+
className,
|
|
1753
|
+
variant = "default",
|
|
1754
|
+
size = "default",
|
|
1755
|
+
...props
|
|
1756
|
+
}) {
|
|
1757
|
+
return /* @__PURE__ */ jsx(
|
|
1758
|
+
Toggle$1,
|
|
1759
|
+
{
|
|
1760
|
+
"data-slot": "toggle",
|
|
1761
|
+
className: cn(toggleVariants({ variant, size, className })),
|
|
1762
|
+
...props
|
|
1763
|
+
}
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
function RichtextField({ value, onChange, readOnly, label }) {
|
|
1767
|
+
const ref = React6.useRef(null);
|
|
1768
|
+
const boldLabel = useMsg("richtext.bold");
|
|
1769
|
+
const italicLabel = useMsg("richtext.italic");
|
|
1770
|
+
const linkLabel = useMsg("richtext.link");
|
|
1771
|
+
const linkPrompt = useMsg("richtext.link.prompt");
|
|
1772
|
+
React6.useEffect(() => {
|
|
1773
|
+
if (ref.current && ref.current.innerHTML !== value) {
|
|
1774
|
+
ref.current.innerHTML = value ?? "";
|
|
1775
|
+
}
|
|
1776
|
+
}, [value]);
|
|
1777
|
+
const exec = (cmd, val) => {
|
|
1778
|
+
document.execCommand(cmd, false, val);
|
|
1779
|
+
if (ref.current) onChange(ref.current.innerHTML);
|
|
1780
|
+
};
|
|
1781
|
+
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: [
|
|
1782
|
+
!readOnly && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 border-b px-1 py-0.5 bg-muted/30", children: [
|
|
1783
|
+
/* @__PURE__ */ jsx(Toggle, { size: "sm", onPressedChange: () => exec("bold"), "aria-label": boldLabel, children: /* @__PURE__ */ jsx(Bold, { className: "h-3.5 w-3.5" }) }),
|
|
1784
|
+
/* @__PURE__ */ jsx(Toggle, { size: "sm", onPressedChange: () => exec("italic"), "aria-label": italicLabel, children: /* @__PURE__ */ jsx(Italic, { className: "h-3.5 w-3.5" }) }),
|
|
1785
|
+
/* @__PURE__ */ jsx(
|
|
1786
|
+
Toggle,
|
|
1787
|
+
{
|
|
1788
|
+
size: "sm",
|
|
1789
|
+
onPressedChange: () => {
|
|
1790
|
+
const url = window.prompt(linkPrompt);
|
|
1791
|
+
if (url) exec("createLink", url);
|
|
1792
|
+
},
|
|
1793
|
+
"aria-label": linkLabel,
|
|
1794
|
+
children: /* @__PURE__ */ jsx(Link, { className: "h-3.5 w-3.5" })
|
|
1795
|
+
}
|
|
1796
|
+
)
|
|
1797
|
+
] }),
|
|
1798
|
+
/* @__PURE__ */ jsx(
|
|
1799
|
+
"div",
|
|
1800
|
+
{
|
|
1801
|
+
ref,
|
|
1802
|
+
contentEditable: !readOnly,
|
|
1803
|
+
suppressContentEditableWarning: true,
|
|
1804
|
+
onInput: () => {
|
|
1805
|
+
if (ref.current) onChange(ref.current.innerHTML);
|
|
1806
|
+
},
|
|
1807
|
+
className: "min-h-[60px] px-3 py-2 text-sm outline-none"
|
|
1808
|
+
}
|
|
1809
|
+
)
|
|
1810
|
+
] }) });
|
|
1811
|
+
}
|
|
1812
|
+
function InputGroup({ className, ...props }) {
|
|
1813
|
+
return /* @__PURE__ */ jsx(
|
|
1814
|
+
"div",
|
|
1815
|
+
{
|
|
1816
|
+
"data-slot": "input-group",
|
|
1817
|
+
role: "group",
|
|
1818
|
+
className: cn(
|
|
1819
|
+
"group/input-group relative flex h-9 w-full min-w-0 items-center rounded-md border border-input shadow-xs transition-[color,box-shadow] outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
|
|
1820
|
+
className
|
|
1821
|
+
),
|
|
1822
|
+
...props
|
|
1823
|
+
}
|
|
1824
|
+
);
|
|
1825
|
+
}
|
|
1826
|
+
var inputGroupAddonVariants = cva(
|
|
1827
|
+
"flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
|
|
1828
|
+
{
|
|
1829
|
+
variants: {
|
|
1830
|
+
align: {
|
|
1831
|
+
"inline-start": "order-first pl-2 has-[>button]:-ml-1 has-[>kbd]:ml-[-0.15rem]",
|
|
1832
|
+
"inline-end": "order-last pr-2 has-[>button]:-mr-1 has-[>kbd]:mr-[-0.15rem]",
|
|
1833
|
+
"block-start": "order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2",
|
|
1834
|
+
"block-end": "order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2"
|
|
1835
|
+
}
|
|
1836
|
+
},
|
|
1837
|
+
defaultVariants: {
|
|
1838
|
+
align: "inline-start"
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
);
|
|
1842
|
+
function InputGroupAddon({
|
|
1843
|
+
className,
|
|
1844
|
+
align = "inline-start",
|
|
1845
|
+
...props
|
|
1846
|
+
}) {
|
|
1847
|
+
return /* @__PURE__ */ jsx(
|
|
1848
|
+
"div",
|
|
1849
|
+
{
|
|
1850
|
+
role: "group",
|
|
1851
|
+
"data-slot": "input-group-addon",
|
|
1852
|
+
"data-align": align,
|
|
1853
|
+
className: cn(inputGroupAddonVariants({ align }), className),
|
|
1854
|
+
onClick: (e) => {
|
|
1855
|
+
if (e.target.closest("button")) {
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
e.currentTarget.parentElement?.querySelector("input")?.focus();
|
|
1859
|
+
},
|
|
1860
|
+
...props
|
|
1861
|
+
}
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
cva(
|
|
1865
|
+
"flex items-center gap-2 text-sm shadow-none",
|
|
1866
|
+
{
|
|
1867
|
+
variants: {
|
|
1868
|
+
size: {
|
|
1869
|
+
xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
|
|
1870
|
+
sm: "",
|
|
1871
|
+
"icon-xs": "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
|
|
1872
|
+
"icon-sm": "size-8 p-0 has-[>svg]:p-0"
|
|
1873
|
+
}
|
|
1874
|
+
},
|
|
1875
|
+
defaultVariants: {
|
|
1876
|
+
size: "xs"
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
);
|
|
1880
|
+
function Command({
|
|
1881
|
+
className,
|
|
1882
|
+
...props
|
|
1883
|
+
}) {
|
|
1884
|
+
return /* @__PURE__ */ jsx(
|
|
1885
|
+
Command$1,
|
|
1886
|
+
{
|
|
1887
|
+
"data-slot": "command",
|
|
1888
|
+
className: cn(
|
|
1889
|
+
"flex size-full flex-col overflow-hidden rounded-xl! bg-popover p-1 text-popover-foreground",
|
|
1890
|
+
className
|
|
1891
|
+
),
|
|
1892
|
+
...props
|
|
1893
|
+
}
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
function CommandInput({
|
|
1897
|
+
className,
|
|
1898
|
+
...props
|
|
1899
|
+
}) {
|
|
1900
|
+
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: [
|
|
1901
|
+
/* @__PURE__ */ jsx(
|
|
1902
|
+
Command$1.Input,
|
|
1903
|
+
{
|
|
1904
|
+
"data-slot": "command-input",
|
|
1905
|
+
className: cn(
|
|
1906
|
+
"w-full text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
|
|
1907
|
+
className
|
|
1908
|
+
),
|
|
1909
|
+
...props
|
|
1910
|
+
}
|
|
1911
|
+
),
|
|
1912
|
+
/* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(SearchIcon, { className: "size-4 shrink-0 opacity-50" }) })
|
|
1913
|
+
] }) });
|
|
1914
|
+
}
|
|
1915
|
+
function CommandList({
|
|
1916
|
+
className,
|
|
1917
|
+
...props
|
|
1918
|
+
}) {
|
|
1919
|
+
return /* @__PURE__ */ jsx(
|
|
1920
|
+
Command$1.List,
|
|
1921
|
+
{
|
|
1922
|
+
"data-slot": "command-list",
|
|
1923
|
+
className: cn(
|
|
1924
|
+
"no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none",
|
|
1925
|
+
className
|
|
1926
|
+
),
|
|
1927
|
+
...props
|
|
1928
|
+
}
|
|
1929
|
+
);
|
|
1930
|
+
}
|
|
1931
|
+
function CommandEmpty({
|
|
1932
|
+
className,
|
|
1933
|
+
...props
|
|
1934
|
+
}) {
|
|
1935
|
+
return /* @__PURE__ */ jsx(
|
|
1936
|
+
Command$1.Empty,
|
|
1937
|
+
{
|
|
1938
|
+
"data-slot": "command-empty",
|
|
1939
|
+
className: cn("py-6 text-center text-sm", className),
|
|
1940
|
+
...props
|
|
1941
|
+
}
|
|
1942
|
+
);
|
|
1943
|
+
}
|
|
1944
|
+
function CommandItem({
|
|
1945
|
+
className,
|
|
1946
|
+
children,
|
|
1947
|
+
...props
|
|
1948
|
+
}) {
|
|
1949
|
+
return /* @__PURE__ */ jsxs(
|
|
1950
|
+
Command$1.Item,
|
|
1951
|
+
{
|
|
1952
|
+
"data-slot": "command-item",
|
|
1953
|
+
className: cn(
|
|
1954
|
+
"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",
|
|
1955
|
+
className
|
|
1956
|
+
),
|
|
1957
|
+
...props,
|
|
1958
|
+
children: [
|
|
1959
|
+
children,
|
|
1960
|
+
/* @__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" })
|
|
1961
|
+
]
|
|
1962
|
+
}
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
function Skeleton({ className, ...props }) {
|
|
1966
|
+
return /* @__PURE__ */ jsx(
|
|
1967
|
+
"div",
|
|
1968
|
+
{
|
|
1969
|
+
"data-slot": "skeleton",
|
|
1970
|
+
className: cn("animate-pulse rounded-md bg-muted", className),
|
|
1971
|
+
...props
|
|
1972
|
+
}
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
function ExternalField({ value, onChange, fetchList, readOnly, label }) {
|
|
1976
|
+
const [query, setQuery] = React6.useState("");
|
|
1977
|
+
const [results, setResults] = React6.useState([]);
|
|
1978
|
+
const [loading, setLoading] = React6.useState(false);
|
|
1979
|
+
React6.useEffect(() => {
|
|
1980
|
+
if (!fetchList) return;
|
|
1981
|
+
setLoading(true);
|
|
1982
|
+
const timer = setTimeout(async () => {
|
|
1983
|
+
try {
|
|
1984
|
+
const data = await fetchList(query);
|
|
1985
|
+
setResults(data);
|
|
1986
|
+
} catch {
|
|
1987
|
+
setResults([]);
|
|
1988
|
+
} finally {
|
|
1989
|
+
setLoading(false);
|
|
1990
|
+
}
|
|
1991
|
+
}, 300);
|
|
1992
|
+
return () => clearTimeout(timer);
|
|
1993
|
+
}, [query, fetchList]);
|
|
1994
|
+
const selectedLabel = results.find((r) => r.value === value)?.label ?? String(value ?? "");
|
|
1995
|
+
return /* @__PURE__ */ jsx(FieldLabel, { label: label ?? "", readOnly, children: /* @__PURE__ */ jsxs(Command, { className: "rounded-md border border-input", children: [
|
|
1996
|
+
/* @__PURE__ */ jsx(
|
|
1997
|
+
CommandInput,
|
|
1998
|
+
{
|
|
1999
|
+
placeholder: "Search...",
|
|
2000
|
+
value: query,
|
|
2001
|
+
onValueChange: setQuery,
|
|
2002
|
+
disabled: readOnly
|
|
2003
|
+
}
|
|
2004
|
+
),
|
|
2005
|
+
/* @__PURE__ */ jsx(CommandList, { children: loading ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 p-2", children: [
|
|
2006
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-full" }),
|
|
2007
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-3/4" }),
|
|
2008
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-1/2" })
|
|
2009
|
+
] }) : results.length === 0 ? /* @__PURE__ */ jsx(CommandEmpty, { children: "No results found." }) : results.map((r, i) => /* @__PURE__ */ jsx(
|
|
2010
|
+
CommandItem,
|
|
2011
|
+
{
|
|
2012
|
+
"data-checked": r.value === value,
|
|
2013
|
+
onSelect: () => onChange(r.value),
|
|
2014
|
+
children: r.label
|
|
2015
|
+
},
|
|
2016
|
+
i
|
|
2017
|
+
)) }),
|
|
2018
|
+
value != null && /* @__PURE__ */ jsxs("div", { className: "border-t px-3 py-1.5 text-xs text-muted-foreground truncate", children: [
|
|
2019
|
+
"Selected: ",
|
|
2020
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: selectedLabel })
|
|
2021
|
+
] })
|
|
2022
|
+
] }) });
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
// src/core/overrides/fields/FieldTypesRegistry.ts
|
|
2026
|
+
var fieldTypesRegistry = {
|
|
2027
|
+
text: TextField,
|
|
2028
|
+
textarea: TextareaField,
|
|
2029
|
+
number: NumberField,
|
|
2030
|
+
select: SelectField,
|
|
2031
|
+
radio: RadioField,
|
|
2032
|
+
array: ArrayField,
|
|
2033
|
+
object: ObjectField,
|
|
2034
|
+
slot: SlotField,
|
|
2035
|
+
custom: CustomField,
|
|
2036
|
+
richtext: RichtextField,
|
|
2037
|
+
external: ExternalField
|
|
2038
|
+
};
|
|
2039
|
+
function PuckRoot({ children }) {
|
|
2040
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
2041
|
+
}
|
|
2042
|
+
var puckOverrides = {
|
|
2043
|
+
drawer: EditorDrawer,
|
|
2044
|
+
components: EditorComponents,
|
|
2045
|
+
drawerItem: DrawerItem,
|
|
2046
|
+
componentItem: DrawerItem,
|
|
2047
|
+
outline: EditorOutline,
|
|
2048
|
+
iframe: CanvasIframe,
|
|
2049
|
+
preview: CanvasPreview,
|
|
2050
|
+
componentOverlay: ComponentOverlay,
|
|
2051
|
+
actionBar: ActionBar,
|
|
2052
|
+
fields: FieldWrapper,
|
|
2053
|
+
fieldTypes: fieldTypesRegistry,
|
|
2054
|
+
puck: PuckRoot
|
|
2055
|
+
};
|
|
2056
|
+
|
|
2057
|
+
export { ActionBar, CanvasIframe, CanvasPreview, ComponentOverlay, DrawerItem, EditorComponents, EditorDrawer, EditorOutline, FieldLabel, FieldWrapper, fieldTypesRegistry, puckOverrides };
|