@jbpark/live-editor 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/context-DrqO0VVu.js +38 -0
  2. package/dist/context-DrqO0VVu.js.map +1 -0
  3. package/dist/core-B7igZRDs.js +11195 -0
  4. package/dist/core-B7igZRDs.js.map +1 -0
  5. package/dist/dnd/index.d.ts +2 -0
  6. package/dist/dnd/index.js +2 -0
  7. package/dist/dnd-BdNgmgYB.js +1717 -0
  8. package/dist/dnd-BdNgmgYB.js.map +1 -0
  9. package/dist/editor/index.d.ts +2 -0
  10. package/dist/editor/index.js +3 -0
  11. package/dist/editor-DmgTeTcG.js +51 -0
  12. package/dist/editor-DmgTeTcG.js.map +1 -0
  13. package/dist/error/index.d.ts +2 -0
  14. package/dist/error/index.js +2 -0
  15. package/dist/error-DRMGumEj.js +168 -0
  16. package/dist/error-DRMGumEj.js.map +1 -0
  17. package/dist/frame-C11nuIBH.js +357 -0
  18. package/dist/frame-C11nuIBH.js.map +1 -0
  19. package/dist/index-BnncHZTt.d.ts +63 -0
  20. package/dist/index-C4TBkJBG.d.ts +37 -0
  21. package/dist/index-CCynrS6c.d.ts +52 -0
  22. package/dist/index-DpDU1IAw.d.ts +23 -0
  23. package/dist/index-lgHdCda5.d.ts +17 -0
  24. package/dist/index.d.ts +13 -185
  25. package/dist/index.js +8 -13614
  26. package/dist/index.js.map +1 -1
  27. package/dist/preview/index.d.ts +2 -0
  28. package/dist/preview/index.js +2 -0
  29. package/dist/preview-DkLLqgKE.js +113 -0
  30. package/dist/preview-DkLLqgKE.js.map +1 -0
  31. package/dist/provider/index.d.ts +8 -0
  32. package/dist/provider/index.js +2 -0
  33. package/dist/states-Ci1AvoQ9.js +18 -0
  34. package/dist/states-Ci1AvoQ9.js.map +1 -0
  35. package/dist/style.css +3830 -3
  36. package/dist/tailwind-CbjdLyVX.js +28 -0
  37. package/dist/tailwind-CbjdLyVX.js.map +1 -0
  38. package/dist/utils/index.d.ts +1 -1
  39. package/dist/utils/index.js +1 -1
  40. package/dist/utils/tailwind/index.d.ts +2 -2
  41. package/dist/utils/tailwind/index.js +2 -2
  42. package/dist/{utils-B11t9ZYd.js → utils-BzfDKU6y.js} +10 -23
  43. package/dist/{utils-B11t9ZYd.js.map → utils-BzfDKU6y.js.map} +1 -1
  44. package/package.json +26 -12
  45. package/dist/tailwind-CzPhj3D9.js +0 -36
  46. package/dist/tailwind-CzPhj3D9.js.map +0 -1
@@ -0,0 +1,1717 @@
1
+ import { _ as DEFAULT_TEMPLATE, f as require_lib$1, m as BINDING_PROP, n as createSectionPreviewCache, p as require_lib, v as DRAGGABLE_ITEMS, x as __toESM } from "./document-CSIscFpL.js";
2
+ import { d as replaceSections, i as compile, o as extractSections, r as cn, s as generateSection, t as baseModules, u as preloadScripts } from "./utils-BzfDKU6y.js";
3
+ import { i as usePreview } from "./states-Ci1AvoQ9.js";
4
+ import { _ as parseArrayExpression, c as extract, d as getCurrentValue, f as parseBinding, g as extractObjectProperties, h as extractNodeValue, i as replaceIds, l as nanoid, m as createNodeFromValue, n as clone, o as update, p as arrayExpressionToCode, r as fillIds, t as validateBindingValue, u as findEditableChildren, v as parseValue, y as generateCode } from "./ast-Dq1EfxA5.js";
5
+ import { t as Frame } from "./frame-C11nuIBH.js";
6
+ import { t as generateTailwindCSSFromDOM } from "./tailwind-CbjdLyVX.js";
7
+ import { t as Core } from "./core-B7igZRDs.js";
8
+ import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
9
+ import { Button, Card, Checkbox, ColorPicker, DatePicker, Drawer, Input, Select, Space, Toast, Typography, Upload } from "@jbpark/ui-kit";
10
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
+ import { DndContext, DragOverlay, PointerSensor, closestCenter, useDndContext, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
12
+ import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
13
+ import { SortableContext, arrayMove, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
14
+ import { useDebounce, useMultiSelect, useResponsiveSize } from "@jbpark/use-hooks";
15
+ import { AlertCircle, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Bell, Bookmark, Calendar, Camera, Check, ChevronDown, ChevronRight, ChevronUp, Clock, Copy, Download, Edit, Eye, Filter, Heart, Home, Image, Info, LayoutGrid, Link, Mail, Map as Map$1, Menu, MessageCircle, Phone, Plus, Search, Settings, Share, ShoppingCart, Star, Trash, Upload as Upload$1, User, X } from "lucide-react";
16
+ import { v4 } from "uuid";
17
+ import { CSS } from "@dnd-kit/utilities";
18
+ import Placeholder from "@tiptap/extension-placeholder";
19
+ import { EditorContent, useEditor } from "@tiptap/react";
20
+ import StarterKit from "@tiptap/starter-kit";
21
+ //#region src/components/dnd/draggable.tsx
22
+ var import_lib = require_lib();
23
+ var import_lib$1 = /* @__PURE__ */ __toESM(require_lib$1(), 1);
24
+ const DraggableItem = ({ item, children }) => {
25
+ const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
26
+ id: item.id,
27
+ data: {
28
+ type: "new-item",
29
+ item
30
+ }
31
+ });
32
+ return children({
33
+ ref: setNodeRef,
34
+ dragProps: {
35
+ ...listeners,
36
+ ...attributes
37
+ },
38
+ isDragging
39
+ });
40
+ };
41
+ const DefaultDraggableItem = ({ item, onAdd, tapToAdd = false }) => /* @__PURE__ */ jsx(DraggableItem, {
42
+ item,
43
+ children: ({ ref, dragProps, isDragging }) => /* @__PURE__ */ jsx(Card, {
44
+ ref,
45
+ style: { opacity: isDragging ? .5 : 1 },
46
+ ...dragProps,
47
+ className: cn("cursor-grab", "outline-none", "hover:border-blue-300 hover:shadow-md", isDragging && "opacity-50"),
48
+ onClick: tapToAdd && onAdd ? () => onAdd(item) : void 0,
49
+ onDoubleClick: onAdd ? () => onAdd(item) : void 0,
50
+ children: item.name
51
+ })
52
+ });
53
+ //#endregion
54
+ //#region src/components/dnd/droppable.tsx
55
+ const Droppable = ({ children, className }) => {
56
+ const { setNodeRef, isOver, active } = useDroppable({ id: "sortable-area" });
57
+ const { setNodeRef: setBottomRef, isOver: isBottomOver } = useDroppable({ id: "sortable-area-bottom" });
58
+ const isNewItemDragging = active?.data.current?.type === "new-item";
59
+ const shouldHighlight = isOver && isNewItemDragging;
60
+ const shouldHighlightBottom = isBottomOver && isNewItemDragging;
61
+ return /* @__PURE__ */ jsxs("div", {
62
+ ref: setNodeRef,
63
+ className: cn("min-h-full", "border-2 border-dashed p-1", shouldHighlight ? "border-blue-300 bg-blue-50" : "border-gray-200", className),
64
+ children: [children, isNewItemDragging && /* @__PURE__ */ jsx("div", {
65
+ ref: setBottomRef,
66
+ className: cn("mt-2 min-h-24", "rounded-lg border-2 border-dashed", "transition-all duration-200", "flex items-center justify-center", shouldHighlightBottom ? "border-blue-400 bg-blue-100" : "border-gray-300 bg-gray-50"),
67
+ children: /* @__PURE__ */ jsx(Typography.Text, {
68
+ className: "text-sm text-gray-500",
69
+ children: shouldHighlightBottom ? "Drop here" : "Drag here to add at bottom"
70
+ })
71
+ })]
72
+ });
73
+ };
74
+ //#endregion
75
+ //#region src/components/dnd/renderer.tsx
76
+ const Renderer = ({ preview, headers, modules, frame, dynamicTailwind = false, provider }) => {
77
+ const memoizedModules = useMemo(() => ({
78
+ ...baseModules,
79
+ ...modules
80
+ }), [modules]);
81
+ const module = useMemo(() => {
82
+ try {
83
+ return compile(preview, memoizedModules);
84
+ } catch (e) {
85
+ return {
86
+ exports: {},
87
+ error: e instanceof Error ? e.message : "Module transformation error"
88
+ };
89
+ }
90
+ }, [preview, memoizedModules]);
91
+ const [dynamicCSS, setDynamicCSS] = useState("");
92
+ const [wrapperEl, setWrapperEl] = useState(null);
93
+ const wrapperRef = useCallback((el) => {
94
+ setWrapperEl(el);
95
+ }, []);
96
+ useEffect(() => {
97
+ if (!preview || !dynamicTailwind || !wrapperEl) return;
98
+ let cancelled = false;
99
+ generateTailwindCSSFromDOM(wrapperEl).then((css) => {
100
+ if (!cancelled) setDynamicCSS(css);
101
+ });
102
+ return () => {
103
+ cancelled = true;
104
+ };
105
+ }, [
106
+ preview,
107
+ dynamicTailwind,
108
+ wrapperEl
109
+ ]);
110
+ const renderProvider = (component) => {
111
+ return provider ? provider(component) : component;
112
+ };
113
+ const Component = module.exports.default;
114
+ if (!Component) return null;
115
+ return /* @__PURE__ */ jsx(Frame, {
116
+ ...frame,
117
+ autoHeight: true,
118
+ children: (container) => /* @__PURE__ */ jsx("div", {
119
+ ref: wrapperRef,
120
+ className: "w-full overflow-x-hidden",
121
+ "data-editor-mode": true,
122
+ children: renderProvider(/* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Component, {
123
+ headers,
124
+ container
125
+ }), dynamicTailwind && dynamicCSS && /* @__PURE__ */ jsx("style", { children: dynamicCSS })] }))
126
+ })
127
+ });
128
+ };
129
+ var renderer_default = memo(Renderer);
130
+ //#endregion
131
+ //#region src/components/dnd/sortable.tsx
132
+ const Sortable = ({ id, children, selected, onClick, onDelete: _onDelete, onCopy: _onCopy }) => {
133
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging, isOver, active } = useSortable({ id });
134
+ const style = {
135
+ transform: CSS.Transform.toString(transform),
136
+ transition,
137
+ opacity: isDragging ? .5 : 1,
138
+ cursor: "grab"
139
+ };
140
+ const isNewItemOver = isOver && active?.data.current?.type === "new-item";
141
+ const onDelete = (e) => {
142
+ e.stopPropagation();
143
+ _onDelete?.(id);
144
+ };
145
+ const onCopy = (e) => {
146
+ e.stopPropagation();
147
+ _onCopy?.(id);
148
+ };
149
+ return /* @__PURE__ */ jsxs("div", {
150
+ ref: setNodeRef,
151
+ style,
152
+ ...attributes,
153
+ ...listeners,
154
+ onClick,
155
+ className: cn("relative", selected && "z-10 outline-2 outline-offset-2 outline-blue-500", isNewItemOver && "border-t-4 border-t-green-500"),
156
+ children: [
157
+ /* @__PURE__ */ jsx("div", { className: cn("absolute inset-0 z-50") }),
158
+ children,
159
+ selected && /* @__PURE__ */ jsxs(Space, {
160
+ className: cn("absolute top-1 right-1 z-60"),
161
+ children: [/* @__PURE__ */ jsx(Button, {
162
+ icon: /* @__PURE__ */ jsx(Copy, {}),
163
+ onClick: onCopy
164
+ }), /* @__PURE__ */ jsx(Button, {
165
+ danger: true,
166
+ icon: /* @__PURE__ */ jsx(Trash, {}),
167
+ onClick: onDelete
168
+ })]
169
+ })
170
+ ]
171
+ });
172
+ };
173
+ //#endregion
174
+ //#region src/components/dnd/overlay.tsx
175
+ const Overlay = ({ sections, renderProps }) => {
176
+ const { active } = useDndContext();
177
+ if (!active) return null;
178
+ if (active.data.current?.type === "new-item") {
179
+ const item = active.data.current.item;
180
+ return /* @__PURE__ */ jsx(DefaultDraggableItem, { item });
181
+ }
182
+ const section = sections.find((s) => s.id === active.id);
183
+ if (section) {
184
+ const preview = generateSection(section.code, renderProps.fullCode);
185
+ return /* @__PURE__ */ jsx(Sortable, {
186
+ id: section.id,
187
+ name: section.name,
188
+ children: /* @__PURE__ */ jsx(renderer_default, {
189
+ preview,
190
+ modules: renderProps.modules,
191
+ frame: renderProps.frame,
192
+ dynamicTailwind: renderProps.dynamicTailwind
193
+ })
194
+ });
195
+ }
196
+ return null;
197
+ };
198
+ //#endregion
199
+ //#region src/components/editor/tiptap.tsx
200
+ const Tiptap = ({ value = "", placeholder = "Enter text...", className, onChange }) => {
201
+ const editor = useEditor({
202
+ extensions: [StarterKit, Placeholder.configure({ placeholder })],
203
+ content: value,
204
+ onBlur: ({ editor: e }) => {
205
+ onChange?.(e.getHTML());
206
+ }
207
+ });
208
+ useEffect(() => {
209
+ if (!editor) return;
210
+ if (editor.getHTML() !== value) editor.commands.setContent(value, { emitUpdate: false });
211
+ }, [value, editor]);
212
+ return /* @__PURE__ */ jsx(EditorContent, {
213
+ editor,
214
+ className: cn(`tiptap-editor min-h-20 rounded border border-gray-200 bg-white px-3
215
+ py-2`, "prose prose-sm max-w-none text-sm text-gray-800", "[&_.tiptap]:outline-none", "[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none", "[&_.tiptap_p.is-editor-empty:first-child::before]:float-left", "[&_.tiptap_p.is-editor-empty:first-child::before]:h-0", "[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400", "[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]", className)
216
+ });
217
+ };
218
+ //#endregion
219
+ //#region src/components/dnd/panel/selection.ts
220
+ const removeIndices = (items, indices) => {
221
+ return items.filter((_, index) => !indices.has(index));
222
+ };
223
+ /**
224
+ * Shifts every selected index up/down by one step as a block, preserving
225
+ * relative order — scattered selections stop moving individually once they
226
+ * hit an unselected neighbor, so the whole group slides together instead of
227
+ * items passing through each other.
228
+ */
229
+ const moveSelectedIndices = (items, indices, direction) => {
230
+ const next = [...items];
231
+ const nextIndices = new Set(indices);
232
+ const ordered = [...indices].sort((a, b) => direction === "up" ? a - b : b - a);
233
+ for (const index of ordered) {
234
+ const target = direction === "up" ? index - 1 : index + 1;
235
+ if (target < 0 || target >= next.length || nextIndices.has(target)) continue;
236
+ [next[index], next[target]] = [next[target], next[index]];
237
+ nextIndices.delete(index);
238
+ nextIndices.add(target);
239
+ }
240
+ return {
241
+ items: next,
242
+ indices: nextIndices
243
+ };
244
+ };
245
+ //#endregion
246
+ //#region src/components/dnd/panel/items.tsx
247
+ const BulkActionsBar = ({ count, onDuplicate, onMoveUp, onMoveDown, onDelete, onClear }) => {
248
+ if (count === 0) return null;
249
+ return /* @__PURE__ */ jsxs("div", {
250
+ className: "flex items-center justify-between rounded border\n border-blue-200 bg-blue-50 p-2",
251
+ children: [/* @__PURE__ */ jsxs("div", {
252
+ className: "text-xs font-medium text-blue-700",
253
+ children: [count, " selected"]
254
+ }), /* @__PURE__ */ jsxs("div", {
255
+ className: "flex items-center space-x-1",
256
+ children: [
257
+ /* @__PURE__ */ jsx(Button, {
258
+ size: "small",
259
+ icon: /* @__PURE__ */ jsx(Copy, {}),
260
+ title: "Duplicate selected",
261
+ onClick: onDuplicate
262
+ }),
263
+ /* @__PURE__ */ jsx(Button, {
264
+ size: "small",
265
+ icon: /* @__PURE__ */ jsx(ArrowUp, {}),
266
+ title: "Move selected up",
267
+ onClick: onMoveUp
268
+ }),
269
+ /* @__PURE__ */ jsx(Button, {
270
+ size: "small",
271
+ icon: /* @__PURE__ */ jsx(ArrowDown, {}),
272
+ title: "Move selected down",
273
+ onClick: onMoveDown
274
+ }),
275
+ /* @__PURE__ */ jsx(Button, {
276
+ danger: true,
277
+ size: "small",
278
+ icon: /* @__PURE__ */ jsx(X, {}),
279
+ title: "Delete selected",
280
+ onClick: onDelete
281
+ }),
282
+ /* @__PURE__ */ jsx(Button, {
283
+ size: "small",
284
+ onClick: onClear,
285
+ children: "Clear"
286
+ })
287
+ ]
288
+ })]
289
+ });
290
+ };
291
+ const Items = ({ value, render, onChange, onChildChange }) => {
292
+ const { objectItems, primitiveItems, allElements, parseError } = useMemo(() => {
293
+ const ast = parseArrayExpression(value);
294
+ if (!ast) return {
295
+ objectItems: [],
296
+ primitiveItems: [],
297
+ allElements: [],
298
+ parseError: true
299
+ };
300
+ const objectItems = [];
301
+ const primitiveItems = [];
302
+ const allElements = ast.elements.filter(Boolean);
303
+ ast.elements.forEach((element) => {
304
+ if (!element) return;
305
+ if (!import_lib$1.isObjectExpression(element)) {
306
+ const extracted = extractNodeValue(element);
307
+ primitiveItems.push({
308
+ id: nanoid(6),
309
+ index: primitiveItems.length,
310
+ value: extracted.value,
311
+ type: extracted.type,
312
+ astNode: element
313
+ });
314
+ return;
315
+ }
316
+ const jsxBindings = {};
317
+ element.properties.forEach((prop) => {
318
+ if (!import_lib$1.isObjectProperty(prop) || !import_lib$1.isIdentifier(prop.key) || !import_lib$1.isJSXElement(prop.value)) return;
319
+ const propertyName = prop.key.name;
320
+ try {
321
+ const jsxCode = generateCode(prop.value);
322
+ const nodes = extract(jsxCode);
323
+ const bindings = [];
324
+ const bindingContainer = nodes.find((node) => node.bindings?.some((b) => b.property === "children"));
325
+ if (bindingContainer) bindings.push(bindingContainer);
326
+ else nodes.forEach((node) => {
327
+ if (node.bindings && node.bindings.length > 0 && node.dataAttributes.some((a) => a.name === "data-id")) bindings.push(node);
328
+ const editableChildren = findEditableChildren(node);
329
+ bindings.push(...editableChildren);
330
+ });
331
+ if (bindings.length > 0) jsxBindings[propertyName] = bindings;
332
+ } catch (error) {
333
+ console.error(`Failed to parse JSX in property '${propertyName}':`, error);
334
+ }
335
+ });
336
+ objectItems.push({
337
+ id: nanoid(6),
338
+ index: objectItems.length,
339
+ editableProperties: extractObjectProperties(element),
340
+ originalElement: element,
341
+ jsxBindings
342
+ });
343
+ });
344
+ return {
345
+ objectItems,
346
+ primitiveItems,
347
+ allElements,
348
+ parseError: false
349
+ };
350
+ }, [value]);
351
+ useEffect(() => {
352
+ if (parseError) Toast.error("Failed to parse items", { description: "Check the console for details." });
353
+ }, [parseError]);
354
+ const isPrimitive = primitiveItems.length > 0 && objectItems.length === 0;
355
+ const selection = useMultiSelect(isPrimitive ? primitiveItems.length : objectItems.length);
356
+ const updatePrimitive = (index, next) => {
357
+ const ast = parseArrayExpression(value);
358
+ if (!ast) {
359
+ Toast.error("Failed to update this item", { description: "Check the console for details." });
360
+ return;
361
+ }
362
+ const elements = ast.elements.filter(Boolean);
363
+ const item = primitiveItems.find((p) => p.index === index);
364
+ if (!item) return;
365
+ const newNode = createNodeFromValue(item.type, parseValue(next));
366
+ if (!newNode) return;
367
+ elements[index] = newNode;
368
+ onChange?.(generateCode(import_lib$1.arrayExpression(elements)));
369
+ };
370
+ const movePrimitive = (fromIndex, toIndex) => {
371
+ const nextElements = [...allElements];
372
+ const [moved] = nextElements.splice(fromIndex, 1);
373
+ nextElements.splice(toIndex, 0, moved);
374
+ onChange?.(generateCode(import_lib$1.arrayExpression(nextElements)));
375
+ };
376
+ const deleteSelectedPrimitives = (indices) => {
377
+ if (allElements.length - indices.size < 1) return;
378
+ const nextElements = removeIndices(allElements, indices);
379
+ onChange?.(generateCode(import_lib$1.arrayExpression(nextElements)));
380
+ };
381
+ const deletePrimitive = (index) => deleteSelectedPrimitives(/* @__PURE__ */ new Set([index]));
382
+ const addPrimitive = () => {
383
+ const first = primitiveItems[0];
384
+ if (!first) return;
385
+ const newNode = createNodeFromValue(first.type, first.value);
386
+ if (!newNode) return;
387
+ onChange?.(generateCode(import_lib$1.arrayExpression([...allElements, newNode])));
388
+ };
389
+ const duplicateSelectedPrimitives = (indices) => {
390
+ const clones = [...indices].sort((a, b) => a - b).map((index) => allElements[index]).filter((node) => Boolean(node)).map((node) => clone(node));
391
+ if (clones.length === 0) return;
392
+ onChange?.(generateCode(import_lib$1.arrayExpression([...allElements, ...clones])));
393
+ };
394
+ const moveSelectedPrimitives = (indices, direction) => {
395
+ const { items: nextElements, indices: nextIndices } = moveSelectedIndices(allElements, indices, direction);
396
+ selection.replace(nextIndices);
397
+ onChange?.(generateCode(import_lib$1.arrayExpression(nextElements)));
398
+ };
399
+ const moveItem = (fromIndex, toIndex) => {
400
+ const nextItems = [...objectItems];
401
+ const [movedItem] = nextItems.splice(fromIndex, 1);
402
+ nextItems.splice(toIndex, 0, movedItem);
403
+ const nextValue = arrayExpressionToCode(nextItems.map((item) => item.originalElement));
404
+ onChange?.(nextValue);
405
+ };
406
+ const updateProperty = (itemIndex, propertyKey, value) => {
407
+ const item = objectItems[itemIndex];
408
+ const property = item.editableProperties[propertyKey];
409
+ const renderLeaf = render?.[propertyKey] && "type" in render[propertyKey] ? render[propertyKey] : null;
410
+ const isJsx = renderLeaf?.type === "jsx";
411
+ const isInnerHTML = renderLeaf?.property === BINDING_PROP.INNER_HTML;
412
+ let nextAstValue = null;
413
+ if (isInnerHTML) {
414
+ const str = String(value);
415
+ nextAstValue = import_lib$1.templateLiteral([import_lib$1.templateElement({
416
+ raw: str,
417
+ cooked: str
418
+ }, true)], []);
419
+ } else if (property.type === "array" || property.type === "object") try {
420
+ nextAstValue = (0, import_lib.parseExpression)(String(value), { plugins: ["jsx", "typescript"] });
421
+ } catch {
422
+ return;
423
+ }
424
+ else if (!isJsx) nextAstValue = createNodeFromValue(property.type, value);
425
+ if (!isJsx && !nextAstValue) return;
426
+ const targetProperty = item.originalElement.properties.find((prop) => import_lib$1.isObjectProperty(prop) && import_lib$1.isIdentifier(prop.key) && prop.key.name === propertyKey);
427
+ const jsxPlaceholders = /* @__PURE__ */ new Map();
428
+ const originalValues = /* @__PURE__ */ new Map();
429
+ if (isJsx && targetProperty) {
430
+ const trimmed = String(value).trim();
431
+ if (trimmed.startsWith("<")) {
432
+ const placeholder = `__JSX_${nanoid(6)}__`;
433
+ jsxPlaceholders.set(placeholder, trimmed);
434
+ targetProperty.value = import_lib$1.identifier(placeholder);
435
+ } else targetProperty.value = import_lib$1.stringLiteral(trimmed);
436
+ } else if (targetProperty && nextAstValue) targetProperty.value = nextAstValue;
437
+ objectItems.forEach((obj) => {
438
+ obj.originalElement.properties.forEach((prop) => {
439
+ if (!import_lib$1.isObjectProperty(prop) || !import_lib$1.isIdentifier(prop.key)) return;
440
+ if (import_lib$1.isJSXElement(prop.value) || import_lib$1.isJSXFragment(prop.value)) {
441
+ const placeholder = `__JSX_${nanoid(6)}__`;
442
+ jsxPlaceholders.set(placeholder, generateCode(prop.value));
443
+ originalValues.set(prop, prop.value);
444
+ prop.value = import_lib$1.identifier(placeholder);
445
+ }
446
+ });
447
+ });
448
+ let nextValue = arrayExpressionToCode(objectItems.map((item) => item.originalElement));
449
+ for (const [prop, original] of originalValues) prop.value = original;
450
+ for (const [placeholder, code] of jsxPlaceholders) nextValue = nextValue.replace(placeholder, () => code);
451
+ onChange?.(nextValue);
452
+ };
453
+ const deleteSelectedItems = (indices) => {
454
+ if (objectItems.length - indices.size < 1) return;
455
+ const nextItems = removeIndices(objectItems, indices);
456
+ const nextValue = arrayExpressionToCode(nextItems.map((item) => item.originalElement));
457
+ onChange?.(nextValue);
458
+ };
459
+ const deleteItem = (index) => deleteSelectedItems(/* @__PURE__ */ new Set([index]));
460
+ const cloneObjectItemElement = (source) => {
461
+ const clonedElement = clone(source.originalElement);
462
+ clonedElement.properties.forEach((prop) => {
463
+ if (import_lib$1.isObjectProperty(prop) && import_lib$1.isIdentifier(prop.key)) {
464
+ const key = prop.key.name;
465
+ const editableProp = source.editableProperties[key];
466
+ if (key === "key" && import_lib$1.isStringLiteral(prop.value)) {
467
+ const uniqueKey = `${prop.value.value}-${nanoid(6)}`;
468
+ prop.value = import_lib$1.stringLiteral(uniqueKey);
469
+ return;
470
+ }
471
+ if (editableProp) {
472
+ const nextValue = createNodeFromValue(editableProp.type, editableProp.value);
473
+ if (nextValue) prop.value = nextValue;
474
+ }
475
+ }
476
+ });
477
+ return clonedElement;
478
+ };
479
+ const addItem = () => {
480
+ const firstItem = objectItems[0];
481
+ if (!firstItem) return;
482
+ const clonedElement = cloneObjectItemElement(firstItem);
483
+ const editableProperties = extractObjectProperties(clonedElement);
484
+ const nextItems = [...objectItems];
485
+ const newItemData = {
486
+ id: nanoid(6),
487
+ index: nextItems.length,
488
+ editableProperties,
489
+ originalElement: clonedElement,
490
+ jsxBindings: {}
491
+ };
492
+ nextItems.push(newItemData);
493
+ const nextValue = arrayExpressionToCode(nextItems.map((item) => item.originalElement));
494
+ onChange?.(nextValue);
495
+ };
496
+ const duplicateSelectedItems = (indices) => {
497
+ const sources = [...indices].sort((a, b) => a - b).map((index) => objectItems[index]).filter((item) => Boolean(item));
498
+ if (sources.length === 0) return;
499
+ const clonedElements = sources.map(cloneObjectItemElement);
500
+ const nextValue = arrayExpressionToCode([...objectItems.map((item) => item.originalElement), ...clonedElements]);
501
+ onChange?.(nextValue);
502
+ };
503
+ const moveSelectedItems = (indices, direction) => {
504
+ const { items: nextItems, indices: nextIndices } = moveSelectedIndices(objectItems, indices, direction);
505
+ selection.replace(nextIndices);
506
+ const nextValue = arrayExpressionToCode(nextItems.map((item) => item.originalElement));
507
+ onChange?.(nextValue);
508
+ };
509
+ if (isPrimitive) return /* @__PURE__ */ jsxs("div", {
510
+ className: "space-y-4",
511
+ children: [
512
+ /* @__PURE__ */ jsxs("div", {
513
+ className: "flex items-center justify-between",
514
+ children: [/* @__PURE__ */ jsxs("div", {
515
+ className: "text-sm font-semibold",
516
+ children: [
517
+ "Items (",
518
+ primitiveItems.length,
519
+ ")"
520
+ ]
521
+ }), /* @__PURE__ */ jsx(Button, {
522
+ size: "small",
523
+ icon: /* @__PURE__ */ jsx(Plus, {}),
524
+ variant: "solid",
525
+ color: "green",
526
+ onClick: addPrimitive,
527
+ children: "Add Item"
528
+ })]
529
+ }),
530
+ /* @__PURE__ */ jsx(BulkActionsBar, {
531
+ count: selection.selected.size,
532
+ onDuplicate: () => duplicateSelectedPrimitives(selection.selected),
533
+ onMoveUp: () => moveSelectedPrimitives(selection.selected, "up"),
534
+ onMoveDown: () => moveSelectedPrimitives(selection.selected, "down"),
535
+ onDelete: () => {
536
+ deleteSelectedPrimitives(selection.selected);
537
+ selection.clear();
538
+ },
539
+ onClear: selection.clear
540
+ }),
541
+ primitiveItems.map((item, i) => /* @__PURE__ */ jsxs("div", {
542
+ className: "space-y-2 rounded border border-gray-100 bg-gray-50 p-2",
543
+ children: [/* @__PURE__ */ jsxs("div", {
544
+ className: "flex items-center justify-between space-x-1",
545
+ children: [/* @__PURE__ */ jsx("div", {
546
+ onClick: (e) => selection.toggle(item.index, e.shiftKey),
547
+ className: "inline-flex",
548
+ children: /* @__PURE__ */ jsx(Checkbox, {
549
+ checked: selection.isSelected(item.index),
550
+ onChange: () => {}
551
+ })
552
+ }), /* @__PURE__ */ jsxs("div", {
553
+ className: "flex space-x-1",
554
+ children: [
555
+ /* @__PURE__ */ jsx(Button, {
556
+ size: "small",
557
+ icon: /* @__PURE__ */ jsx(ArrowUp, {}),
558
+ disabled: i === 0,
559
+ onClick: () => movePrimitive(item.index, item.index - 1)
560
+ }),
561
+ /* @__PURE__ */ jsx(Button, {
562
+ size: "small",
563
+ icon: /* @__PURE__ */ jsx(ArrowDown, {}),
564
+ disabled: i === primitiveItems.length - 1,
565
+ onClick: () => movePrimitive(item.index, item.index + 1)
566
+ }),
567
+ /* @__PURE__ */ jsx(Button, {
568
+ danger: true,
569
+ size: "small",
570
+ icon: /* @__PURE__ */ jsx(X, {}),
571
+ disabled: primitiveItems.length <= 1,
572
+ onClick: () => deletePrimitive(item.index)
573
+ })
574
+ ]
575
+ })]
576
+ }), /* @__PURE__ */ jsx(Field, {
577
+ binding: {
578
+ label: `item-${i}`,
579
+ property: item.type
580
+ },
581
+ id: `primitive-${item.id}`,
582
+ value: String(item.value ?? ""),
583
+ onChange: ({ value: next }) => updatePrimitive(item.index, next)
584
+ })]
585
+ }, item.id))
586
+ ]
587
+ });
588
+ return /* @__PURE__ */ jsxs("div", {
589
+ className: "space-y-4",
590
+ children: [
591
+ /* @__PURE__ */ jsxs("div", {
592
+ className: "flex items-center justify-between",
593
+ children: [/* @__PURE__ */ jsxs("div", {
594
+ className: "text-sm font-semibold",
595
+ children: [
596
+ "Items (",
597
+ objectItems.length,
598
+ ")"
599
+ ]
600
+ }), /* @__PURE__ */ jsx(Button, {
601
+ size: "small",
602
+ icon: /* @__PURE__ */ jsx(Plus, {}),
603
+ variant: "solid",
604
+ color: "green",
605
+ disabled: objectItems.length === 0,
606
+ onClick: addItem,
607
+ children: "Add Item"
608
+ })]
609
+ }),
610
+ /* @__PURE__ */ jsx(BulkActionsBar, {
611
+ count: selection.selected.size,
612
+ onDuplicate: () => duplicateSelectedItems(selection.selected),
613
+ onMoveUp: () => moveSelectedItems(selection.selected, "up"),
614
+ onMoveDown: () => moveSelectedItems(selection.selected, "down"),
615
+ onDelete: () => {
616
+ deleteSelectedItems(selection.selected);
617
+ selection.clear();
618
+ },
619
+ onClear: selection.clear
620
+ }),
621
+ objectItems.map((item) => /* @__PURE__ */ jsxs("div", {
622
+ className: "space-y-3 rounded border bg-gray-50 p-3",
623
+ children: [
624
+ /* @__PURE__ */ jsxs("div", {
625
+ className: "flex items-center justify-between",
626
+ children: [/* @__PURE__ */ jsxs("div", {
627
+ className: "flex items-center space-x-2",
628
+ children: [/* @__PURE__ */ jsx("div", {
629
+ onClick: (e) => selection.toggle(item.index, e.shiftKey),
630
+ className: "inline-flex",
631
+ children: /* @__PURE__ */ jsx(Checkbox, {
632
+ checked: selection.isSelected(item.index),
633
+ onChange: () => {}
634
+ })
635
+ }), /* @__PURE__ */ jsxs("div", {
636
+ className: "text-xs font-medium",
637
+ children: ["Item ", item.index + 1]
638
+ })]
639
+ }), /* @__PURE__ */ jsxs("div", {
640
+ className: "flex space-x-1",
641
+ children: [
642
+ /* @__PURE__ */ jsx(Button, {
643
+ size: "small",
644
+ icon: /* @__PURE__ */ jsx(ArrowUp, {}),
645
+ disabled: item.index === 0,
646
+ onClick: () => moveItem(item.index, item.index - 1)
647
+ }),
648
+ /* @__PURE__ */ jsx(Button, {
649
+ size: "small",
650
+ icon: /* @__PURE__ */ jsx(ArrowDown, {}),
651
+ disabled: item.index === objectItems.length - 1,
652
+ onClick: () => moveItem(item.index, item.index + 1)
653
+ }),
654
+ /* @__PURE__ */ jsx(Button, {
655
+ danger: true,
656
+ size: "small",
657
+ icon: /* @__PURE__ */ jsx(X, {}),
658
+ disabled: objectItems.length <= 1,
659
+ onClick: () => deleteItem(item.index)
660
+ })
661
+ ]
662
+ })]
663
+ }),
664
+ /* @__PURE__ */ jsx("div", {
665
+ className: "space-y-2",
666
+ children: Object.entries(item.editableProperties).map(([key, prop]) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("div", {
667
+ className: "flex flex-col space-y-2",
668
+ children: [/* @__PURE__ */ jsx("label", {
669
+ className: "w-20 shrink-0 text-xs font-medium",
670
+ children: key
671
+ }), /* @__PURE__ */ jsx(Field, {
672
+ binding: {
673
+ label: key,
674
+ property: render?.[key] && "type" in render[key] ? render[key].property ?? render[key].type : key,
675
+ type: render?.[key] && "type" in render[key] ? render[key].type : void 0,
676
+ render: render?.[key] && "type" in render[key] ? render[key].render : render?.[key] && !("type" in render[key]) ? render[key] : void 0
677
+ },
678
+ id: `item-${item.id}-${key}`,
679
+ value: String(prop.value),
680
+ onChange: ({ value: next }) => updateProperty(item.index, key, parseValue(next))
681
+ })]
682
+ }), /* @__PURE__ */ jsxs("span", {
683
+ className: "text-right text-xs text-gray-500",
684
+ children: [
685
+ "(",
686
+ prop.type,
687
+ ")"
688
+ ]
689
+ })] }, `${item.id}-${key}`))
690
+ }),
691
+ /* @__PURE__ */ jsx("div", {
692
+ className: "space-y-3 border-t pt-2",
693
+ children: Object.entries(item.jsxBindings).length > 0 ? Object.entries(item.jsxBindings).map(([propertyName, bindings]) => /* @__PURE__ */ jsxs("div", {
694
+ className: "space-y-2",
695
+ children: [/* @__PURE__ */ jsxs("div", {
696
+ className: "text-xs font-medium text-blue-700",
697
+ children: [
698
+ propertyName,
699
+ " Bindings (",
700
+ bindings.length,
701
+ "):"
702
+ ]
703
+ }), bindings.map((bindingNode, idx) => {
704
+ const nodeId = bindingNode.dataAttributes.find((a) => a.name === "data-id")?.value;
705
+ return /* @__PURE__ */ jsxs("div", {
706
+ className: "rounded border border-blue-100 bg-blue-50\n p-2",
707
+ children: [/* @__PURE__ */ jsxs("div", {
708
+ className: "mb-1 text-xs text-blue-600",
709
+ children: [
710
+ "<",
711
+ bindingNode.tagName || "element",
712
+ ">"
713
+ ]
714
+ }), /* @__PURE__ */ jsx(Node, {
715
+ data: bindingNode,
716
+ onChange: onChildChange
717
+ })]
718
+ }, `binding-${item.id}-${propertyName}-${nodeId || idx}`);
719
+ })]
720
+ }, propertyName)) : /* @__PURE__ */ jsx("div", {
721
+ className: "text-xs text-gray-500",
722
+ children: "✓ No JSX bindings found"
723
+ })
724
+ })
725
+ ]
726
+ }, item.id))
727
+ ]
728
+ });
729
+ };
730
+ //#endregion
731
+ //#region src/components/dnd/panel/children.tsx
732
+ const Children = ({ value, onChange, onNodeChange }) => {
733
+ const items = useMemo(() => Array.isArray(value) ? value : [], [value]);
734
+ const selection = useMultiSelect(items.length);
735
+ const editableChildrenMap = useMemo(() => {
736
+ const map = /* @__PURE__ */ new Map();
737
+ items.forEach((item, index) => {
738
+ const editableNodes = findEditableChildren(item);
739
+ if (editableNodes.length > 0) map.set(index, editableNodes);
740
+ });
741
+ return map;
742
+ }, [items]);
743
+ const moveItem = (fromIndex, toIndex) => {
744
+ const nextItems = [...items];
745
+ const [movedItem] = nextItems.splice(fromIndex, 1);
746
+ nextItems.splice(toIndex, 0, movedItem);
747
+ onChange?.(JSON.stringify(nextItems));
748
+ };
749
+ const moveSelectedItems = (indices, direction) => {
750
+ const { items: nextItems, indices: nextIndices } = moveSelectedIndices(items, indices, direction);
751
+ selection.replace(nextIndices);
752
+ onChange?.(JSON.stringify(nextItems));
753
+ };
754
+ const deleteSelectedItems = (indices) => {
755
+ if (items.length - indices.size < 1) return;
756
+ const nextItems = removeIndices(items, indices);
757
+ onChange?.(JSON.stringify(nextItems));
758
+ };
759
+ const deleteItem = (index) => deleteSelectedItems(/* @__PURE__ */ new Set([index]));
760
+ const addItem = () => {
761
+ const template = items[0] || createDefaultItem();
762
+ const newItem = cloneDataAttrNode(template);
763
+ const nextItems = [...items, newItem];
764
+ onChange?.(JSON.stringify(nextItems));
765
+ };
766
+ const duplicateSelectedItems = (indices) => {
767
+ const sources = [...indices].sort((a, b) => a - b).map((index) => items[index]).filter((item) => Boolean(item));
768
+ if (sources.length === 0) return;
769
+ const clones = sources.map(cloneDataAttrNode);
770
+ onChange?.(JSON.stringify([...items, ...clones]));
771
+ };
772
+ const createDefaultItem = () => ({
773
+ id: nanoid(6),
774
+ tagName: "div",
775
+ attributes: [{
776
+ name: "data-id",
777
+ value: nanoid(6)
778
+ }, {
779
+ name: "data-item",
780
+ value: "true"
781
+ }],
782
+ dataAttributes: [{
783
+ name: "data-id",
784
+ value: nanoid(6)
785
+ }, {
786
+ name: "data-item",
787
+ value: "true"
788
+ }],
789
+ textContent: "",
790
+ children: []
791
+ });
792
+ const cloneDataAttrNode = (node) => ({
793
+ ...node,
794
+ id: nanoid(6),
795
+ attributes: node.attributes.map((attr) => ({
796
+ ...attr,
797
+ value: attr.name === "data-id" ? nanoid(6) : attr.value
798
+ })),
799
+ dataAttributes: node.dataAttributes.map((attr) => ({
800
+ ...attr,
801
+ value: attr.name === "data-id" ? nanoid(6) : attr.value
802
+ })),
803
+ children: node.children?.map(cloneDataAttrNode)
804
+ });
805
+ return /* @__PURE__ */ jsxs("div", {
806
+ className: "space-y-3",
807
+ children: [
808
+ /* @__PURE__ */ jsxs("div", {
809
+ className: "flex items-center justify-between",
810
+ children: [/* @__PURE__ */ jsxs("div", {
811
+ className: "text-sm font-semibold text-green-700",
812
+ children: [
813
+ "Children Items (",
814
+ items.length,
815
+ ")"
816
+ ]
817
+ }), /* @__PURE__ */ jsx(Button, {
818
+ size: "small",
819
+ color: "green",
820
+ icon: /* @__PURE__ */ jsx(Plus, {}),
821
+ onClick: addItem,
822
+ children: "Add Child"
823
+ })]
824
+ }),
825
+ /* @__PURE__ */ jsx(BulkActionsBar, {
826
+ count: selection.selected.size,
827
+ onDuplicate: () => duplicateSelectedItems(selection.selected),
828
+ onMoveUp: () => moveSelectedItems(selection.selected, "up"),
829
+ onMoveDown: () => moveSelectedItems(selection.selected, "down"),
830
+ onDelete: () => {
831
+ deleteSelectedItems(selection.selected);
832
+ selection.clear();
833
+ },
834
+ onClear: selection.clear
835
+ }),
836
+ items.map((item, itemIndex) => /* @__PURE__ */ jsxs("div", {
837
+ className: "space-y-2 rounded border border-green-200 bg-green-50 p-3",
838
+ children: [
839
+ /* @__PURE__ */ jsxs("div", {
840
+ className: "flex items-center justify-between",
841
+ children: [/* @__PURE__ */ jsxs("div", {
842
+ className: "flex items-center space-x-2",
843
+ children: [/* @__PURE__ */ jsx("div", {
844
+ onClick: (e) => selection.toggle(itemIndex, e.shiftKey),
845
+ className: "inline-flex",
846
+ children: /* @__PURE__ */ jsx(Checkbox, {
847
+ checked: selection.isSelected(itemIndex),
848
+ onChange: () => {}
849
+ })
850
+ }), /* @__PURE__ */ jsxs("div", {
851
+ className: "text-xs font-medium text-green-800",
852
+ children: [
853
+ "Child ",
854
+ itemIndex + 1,
855
+ " (",
856
+ item.tagName || "fragment",
857
+ ")"
858
+ ]
859
+ })]
860
+ }), /* @__PURE__ */ jsxs("div", {
861
+ className: "flex space-x-1",
862
+ children: [
863
+ /* @__PURE__ */ jsx(Button, {
864
+ size: "small",
865
+ icon: /* @__PURE__ */ jsx(ArrowUp, {}),
866
+ disabled: itemIndex === 0,
867
+ onClick: () => moveItem(itemIndex, itemIndex - 1)
868
+ }),
869
+ /* @__PURE__ */ jsx(Button, {
870
+ size: "small",
871
+ icon: /* @__PURE__ */ jsx(ArrowDown, {}),
872
+ disabled: itemIndex === items.length - 1,
873
+ onClick: () => moveItem(itemIndex, itemIndex + 1)
874
+ }),
875
+ /* @__PURE__ */ jsx(Button, {
876
+ title: items.length <= 1 ? "At least 1 item is required" : "Delete item",
877
+ danger: true,
878
+ size: "small",
879
+ icon: /* @__PURE__ */ jsx(X, {}),
880
+ disabled: items.length <= 1,
881
+ onClick: () => deleteItem(itemIndex)
882
+ })
883
+ ]
884
+ })]
885
+ }),
886
+ editableChildrenMap.has(itemIndex) && /* @__PURE__ */ jsxs("div", {
887
+ className: "space-y-2",
888
+ children: [/* @__PURE__ */ jsx("div", {
889
+ className: "text-xs font-medium text-green-700",
890
+ children: "Editable Bindings:"
891
+ }), editableChildrenMap.get(itemIndex).map((editableNode, idx) => {
892
+ const nodeId = editableNode.dataAttributes.find((a) => a.name === "data-id")?.value;
893
+ return /* @__PURE__ */ jsxs("div", {
894
+ className: "rounded border border-green-100 bg-white p-2",
895
+ children: [/* @__PURE__ */ jsx("div", {
896
+ className: "mb-1 text-xs text-green-600",
897
+ children: editableNode.tagName
898
+ }), /* @__PURE__ */ jsx(Node, {
899
+ data: editableNode,
900
+ onChange: onNodeChange
901
+ })]
902
+ }, `editable-${itemIndex}-${nodeId || idx}`);
903
+ })]
904
+ }),
905
+ !!item.children && !editableChildrenMap.has(itemIndex) && /* @__PURE__ */ jsxs("div", {
906
+ className: "space-y-1",
907
+ children: [/* @__PURE__ */ jsx("div", {
908
+ className: "text-xs font-medium text-green-700",
909
+ children: "Child Nodes:"
910
+ }), item.children.map((node, nodeIndex) => /* @__PURE__ */ jsx("div", {
911
+ className: "ml-2 rounded border border-green-100 bg-white p-2",
912
+ children: /* @__PURE__ */ jsx(Node, {
913
+ data: node,
914
+ onChange: onNodeChange
915
+ })
916
+ }, `node-${itemIndex}-${nodeIndex}`))]
917
+ })
918
+ ]
919
+ }, item.id || itemIndex))
920
+ ]
921
+ });
922
+ };
923
+ //#endregion
924
+ //#region src/components/dnd/panel/icon-map.ts
925
+ const ICON_MAP = {
926
+ AlertCircle,
927
+ ArrowDown,
928
+ ArrowLeft,
929
+ ArrowRight,
930
+ ArrowUp,
931
+ Bell,
932
+ Bookmark,
933
+ Calendar,
934
+ Camera,
935
+ Check,
936
+ ChevronDown,
937
+ ChevronRight,
938
+ Clock,
939
+ Download,
940
+ Edit,
941
+ Eye,
942
+ Filter,
943
+ Heart,
944
+ Home,
945
+ Image,
946
+ Info,
947
+ Link,
948
+ Mail,
949
+ Map: Map$1,
950
+ Menu,
951
+ MessageCircle,
952
+ Phone,
953
+ Plus,
954
+ Search,
955
+ Settings,
956
+ Share,
957
+ ShoppingCart,
958
+ Star,
959
+ Trash,
960
+ Upload: Upload$1,
961
+ User,
962
+ X
963
+ };
964
+ //#endregion
965
+ //#region src/components/dnd/panel/field.tsx
966
+ const isColorProperty = (propertyName) => {
967
+ return propertyName.toLowerCase().includes("color");
968
+ };
969
+ const normalizeToHex = (value) => {
970
+ const trimmed = value.trim();
971
+ if (/^#([0-9A-Fa-f]{3}){1,2}$/.test(trimmed)) return trimmed;
972
+ return "#000000";
973
+ };
974
+ const parseDateValue = (value) => {
975
+ const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value.trim());
976
+ if (!match) return;
977
+ const [, year, month, day] = match;
978
+ const date = new Date(Number(year), Number(month) - 1, Number(day));
979
+ return Number.isNaN(date.getTime()) ? void 0 : date;
980
+ };
981
+ const formatDateValue = (date) => {
982
+ return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
983
+ };
984
+ const COLOR_COMMIT_DELAY = 75;
985
+ const ColorPickerField = ({ id, label, value, onChange }) => {
986
+ const [liveValue, setLiveValue] = useState(value);
987
+ const [prevValue, setPrevValue] = useState(value);
988
+ const lastCommittedRef = useRef(value);
989
+ if (value !== prevValue) {
990
+ setPrevValue(value);
991
+ setLiveValue(value);
992
+ }
993
+ useEffect(() => {
994
+ lastCommittedRef.current = value;
995
+ }, [value]);
996
+ const commit = (next) => {
997
+ if (next === lastCommittedRef.current) return;
998
+ lastCommittedRef.current = next;
999
+ onChange?.({
1000
+ id,
1001
+ label,
1002
+ value: next
1003
+ });
1004
+ };
1005
+ const debouncedCommit = useDebounce(() => commit(liveValue), {
1006
+ delay: COLOR_COMMIT_DELAY,
1007
+ autoInvoke: false
1008
+ });
1009
+ return /* @__PURE__ */ jsx(ColorPicker, {
1010
+ showText: true,
1011
+ value: liveValue,
1012
+ onChange: (next) => {
1013
+ setLiveValue(next);
1014
+ debouncedCommit();
1015
+ },
1016
+ onOpenChange: (open) => {
1017
+ if (!open) commit(liveValue);
1018
+ }
1019
+ });
1020
+ };
1021
+ const ICON_OPTIONS = Object.entries(ICON_MAP).map(([name, Icon]) => ({
1022
+ label: /* @__PURE__ */ jsxs("span", {
1023
+ className: "flex items-center gap-2",
1024
+ children: [/* @__PURE__ */ jsx(Icon, { size: 14 }), name]
1025
+ }),
1026
+ value: name
1027
+ }));
1028
+ const Field = ({ binding, id, value, onChange }) => {
1029
+ const parsedValue = useMemo(() => {
1030
+ return parseValue(value);
1031
+ }, [value]);
1032
+ const [validationError, setValidationError] = useState(null);
1033
+ if (binding.property === "items" || binding.property === "data" || binding.type === "array") return /* @__PURE__ */ jsx(Items, {
1034
+ value,
1035
+ render: binding.render,
1036
+ onChange: (next) => {
1037
+ onChange?.({
1038
+ id,
1039
+ label: binding.label,
1040
+ value: next
1041
+ });
1042
+ },
1043
+ onChildChange: onChange
1044
+ });
1045
+ if (binding.type === "richtext") return /* @__PURE__ */ jsx(Tiptap, {
1046
+ value,
1047
+ onChange: (next) => {
1048
+ if (next !== value) onChange?.({
1049
+ id,
1050
+ label: binding.label,
1051
+ value: next
1052
+ });
1053
+ }
1054
+ });
1055
+ if (binding.property === BINDING_PROP.INNER_HTML || binding.type === "jsx") {
1056
+ const isHTML = binding.property === BINDING_PROP.INNER_HTML;
1057
+ return /* @__PURE__ */ jsx(Core, {
1058
+ value,
1059
+ height: "150px",
1060
+ fragment: !isHTML,
1061
+ raw: isHTML,
1062
+ onSave: (next) => {
1063
+ if (next !== value) onChange?.({
1064
+ id,
1065
+ label: binding.label,
1066
+ value: next
1067
+ });
1068
+ }
1069
+ });
1070
+ }
1071
+ if (binding.property === "children" && Array.isArray(parsedValue)) return /* @__PURE__ */ jsx(Children, {
1072
+ value: parsedValue,
1073
+ onChange: (next) => {
1074
+ onChange?.({
1075
+ id,
1076
+ label: binding.label,
1077
+ value: next
1078
+ });
1079
+ },
1080
+ onNodeChange: onChange
1081
+ });
1082
+ if (typeof parsedValue === "object" && parsedValue !== null && !Array.isArray(parsedValue)) return /* @__PURE__ */ jsx("div", {
1083
+ className: "space-y-2 rounded border border-gray-200 bg-gray-50 p-2",
1084
+ children: Object.entries(parsedValue).map(([key, val]) => /* @__PURE__ */ jsxs("div", {
1085
+ className: "space-y-1",
1086
+ children: [/* @__PURE__ */ jsx("label", {
1087
+ className: "block text-xs font-medium text-gray-600",
1088
+ children: key
1089
+ }), /* @__PURE__ */ jsx(Field, {
1090
+ binding: {
1091
+ label: key,
1092
+ property: binding.render?.[key] && "type" in binding.render[key] ? binding.render[key].type : key,
1093
+ type: binding.render?.[key] && "type" in binding.render[key] ? binding.render[key].type : void 0,
1094
+ render: binding.render?.[key] && !("type" in binding.render[key]) ? binding.render[key] : void 0
1095
+ },
1096
+ id,
1097
+ value: typeof val === "object" ? JSON.stringify(val) : String(val),
1098
+ onChange: ({ value: next }) => {
1099
+ const convertedValue = parseValue(next);
1100
+ const updated = {
1101
+ ...parsedValue,
1102
+ [key]: convertedValue
1103
+ };
1104
+ onChange?.({
1105
+ id,
1106
+ label: binding.label,
1107
+ value: JSON.stringify(updated)
1108
+ });
1109
+ }
1110
+ })]
1111
+ }, key))
1112
+ });
1113
+ if (binding.type === "boolean" || typeof parsedValue === "boolean") return /* @__PURE__ */ jsx(Checkbox, {
1114
+ checked: parsedValue === true || parsedValue === "true",
1115
+ onChange: (checked) => {
1116
+ onChange?.({
1117
+ id,
1118
+ label: binding.label,
1119
+ value: checked.toString()
1120
+ });
1121
+ }
1122
+ });
1123
+ const stringValue = String(value);
1124
+ if (binding.options && Array.isArray(binding.options)) return /* @__PURE__ */ jsx(Select, {
1125
+ value: stringValue,
1126
+ options: binding.options,
1127
+ onChange: (next) => {
1128
+ if (next !== value) onChange?.({
1129
+ id,
1130
+ label: binding.label,
1131
+ value: next
1132
+ });
1133
+ }
1134
+ });
1135
+ if (binding.type === "color" || isColorProperty(binding.property)) return /* @__PURE__ */ jsx(ColorPickerField, {
1136
+ id,
1137
+ label: binding.label,
1138
+ value: normalizeToHex(stringValue),
1139
+ onChange
1140
+ });
1141
+ if (binding.type === "date") return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(DatePicker, {
1142
+ defaultValue: parseDateValue(stringValue),
1143
+ onChange: (date) => {
1144
+ const next = date ? formatDateValue(date) : "";
1145
+ const result = validateBindingValue(binding, next);
1146
+ if (!result.valid) {
1147
+ setValidationError(result.message ?? "Invalid value.");
1148
+ return;
1149
+ }
1150
+ setValidationError(null);
1151
+ if (next !== value) onChange?.({
1152
+ id,
1153
+ label: binding.label,
1154
+ value: next
1155
+ });
1156
+ }
1157
+ }), validationError && /* @__PURE__ */ jsx("p", {
1158
+ className: "mt-1 text-xs text-red-500",
1159
+ children: validationError
1160
+ })] });
1161
+ if (binding.type === "url") return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Input, {
1162
+ type: "url",
1163
+ defaultValue: stringValue,
1164
+ placeholder: "https://example.com",
1165
+ onBlur: (e) => {
1166
+ const next = e.target.value.trim();
1167
+ const result = validateBindingValue(binding, next);
1168
+ if (!result.valid) {
1169
+ setValidationError(result.message ?? "Invalid value.");
1170
+ return;
1171
+ }
1172
+ setValidationError(null);
1173
+ if (next !== value) onChange?.({
1174
+ id,
1175
+ label: binding.label,
1176
+ value: next
1177
+ });
1178
+ }
1179
+ }), validationError && /* @__PURE__ */ jsx("p", {
1180
+ className: "mt-1 text-xs text-red-500",
1181
+ children: validationError
1182
+ })] });
1183
+ if (binding.type === "icon-picker") {
1184
+ const SelectedIcon = ICON_MAP[stringValue];
1185
+ return /* @__PURE__ */ jsxs("div", {
1186
+ className: "flex items-center gap-2",
1187
+ children: [/* @__PURE__ */ jsx(Select, {
1188
+ value: stringValue,
1189
+ options: ICON_OPTIONS,
1190
+ onChange: (next) => {
1191
+ if (next !== value) onChange?.({
1192
+ id,
1193
+ label: binding.label,
1194
+ value: next
1195
+ });
1196
+ }
1197
+ }), SelectedIcon && /* @__PURE__ */ jsx(SelectedIcon, {
1198
+ size: 18,
1199
+ className: "shrink-0"
1200
+ })]
1201
+ });
1202
+ }
1203
+ if (binding.type === "asset-picker") {
1204
+ const defaultUploadValue = stringValue ? [{
1205
+ uid: "current",
1206
+ name: stringValue.split("/").pop() || "asset",
1207
+ url: stringValue
1208
+ }] : [];
1209
+ return /* @__PURE__ */ jsxs("div", {
1210
+ className: "space-y-2",
1211
+ children: [
1212
+ /* @__PURE__ */ jsx(Input, {
1213
+ defaultValue: stringValue,
1214
+ placeholder: "Enter an image URL",
1215
+ onBlur: (e) => {
1216
+ const next = e.target.value.trim();
1217
+ const result = validateBindingValue(binding, next);
1218
+ if (!result.valid) {
1219
+ setValidationError(result.message ?? "Invalid value.");
1220
+ return;
1221
+ }
1222
+ setValidationError(null);
1223
+ if (next !== value) onChange?.({
1224
+ id,
1225
+ label: binding.label,
1226
+ value: next
1227
+ });
1228
+ }
1229
+ }),
1230
+ /* @__PURE__ */ jsx(Upload, {
1231
+ multiple: false,
1232
+ maxCount: 1,
1233
+ accept: "image/*",
1234
+ defaultValue: defaultUploadValue,
1235
+ onChange: (files) => {
1236
+ const next = files[0]?.url ?? "";
1237
+ if (next !== value) onChange?.({
1238
+ id,
1239
+ label: binding.label,
1240
+ value: next
1241
+ });
1242
+ }
1243
+ }),
1244
+ validationError && /* @__PURE__ */ jsx("p", {
1245
+ className: "mt-1 text-xs text-red-500",
1246
+ children: validationError
1247
+ })
1248
+ ]
1249
+ });
1250
+ }
1251
+ if (typeof parsedValue === "number") return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Input, {
1252
+ type: "number",
1253
+ defaultValue: stringValue,
1254
+ placeholder: "Enter a numeric value",
1255
+ onBlur: (e) => {
1256
+ const next = e.target.value.trim();
1257
+ const result = validateBindingValue(binding, next ? Number(next) : "");
1258
+ if (!result.valid) {
1259
+ setValidationError(result.message ?? "Invalid value.");
1260
+ return;
1261
+ }
1262
+ setValidationError(null);
1263
+ if (next !== value) onChange?.({
1264
+ id,
1265
+ label: binding.label,
1266
+ value: next
1267
+ });
1268
+ }
1269
+ }), validationError && /* @__PURE__ */ jsx("p", {
1270
+ className: "mt-1 text-xs text-red-500",
1271
+ children: validationError
1272
+ })] });
1273
+ return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Input.TextArea, {
1274
+ defaultValue: value,
1275
+ placeholder: "Enter a value",
1276
+ onBlur: (e) => {
1277
+ const next = e.target.value.trim();
1278
+ const result = validateBindingValue(binding, next);
1279
+ if (!result.valid) {
1280
+ setValidationError(result.message ?? "Invalid value.");
1281
+ return;
1282
+ }
1283
+ setValidationError(null);
1284
+ if (next !== value) onChange?.({
1285
+ id,
1286
+ label: binding.label,
1287
+ value: next
1288
+ });
1289
+ }
1290
+ }), validationError && /* @__PURE__ */ jsx("p", {
1291
+ className: "mt-1 text-xs text-red-500",
1292
+ children: validationError
1293
+ })] });
1294
+ };
1295
+ //#endregion
1296
+ //#region src/components/dnd/panel/node.tsx
1297
+ const Node = ({ data, onChange }) => {
1298
+ const idAttr = data.dataAttributes.find((a) => a.name === "data-id");
1299
+ const bindingAttr = data.dataAttributes.find((a) => a.name === "data-binding");
1300
+ if (!idAttr?.value || !bindingAttr?.value) return null;
1301
+ const dataId = idAttr.value;
1302
+ const bindings = data.bindings || parseBinding(bindingAttr.value);
1303
+ if (!bindings.length) return null;
1304
+ return /* @__PURE__ */ jsx("div", {
1305
+ className: "space-y-2 rounded",
1306
+ children: /* @__PURE__ */ jsx("div", {
1307
+ className: "space-y-1",
1308
+ children: bindings.map((binding) => {
1309
+ const currentValue = getCurrentValue(data, binding.property);
1310
+ return /* @__PURE__ */ jsxs("div", {
1311
+ className: "space-y-1",
1312
+ children: [/* @__PURE__ */ jsxs("label", {
1313
+ className: "block text-xs font-semibold text-gray-700",
1314
+ children: [binding.label, /* @__PURE__ */ jsxs("span", {
1315
+ className: "ml-1 text-gray-400",
1316
+ children: [
1317
+ "(",
1318
+ binding.property,
1319
+ ")"
1320
+ ]
1321
+ })]
1322
+ }), /* @__PURE__ */ jsx(Field, {
1323
+ id: dataId,
1324
+ binding,
1325
+ value: currentValue,
1326
+ onChange
1327
+ })]
1328
+ }, binding.label);
1329
+ })
1330
+ })
1331
+ });
1332
+ };
1333
+ //#endregion
1334
+ //#region src/components/dnd/panel/panel.tsx
1335
+ const Panel = ({ item, onDelete, onMoveUp, onMoveDown, canMoveUp = false, canMoveDown = false, fields, onFieldChange }) => {
1336
+ if (!item) return /* @__PURE__ */ jsx(Typography.Paragraph, {
1337
+ className: cn("p-4 text-sm text-gray-500"),
1338
+ children: "Please select a section."
1339
+ });
1340
+ return /* @__PURE__ */ jsxs("div", {
1341
+ className: cn("h-full space-y-4 p-4", "overflow-x-hidden overflow-y-auto"),
1342
+ children: [
1343
+ /* @__PURE__ */ jsxs("div", {
1344
+ className: "flex items-center justify-between",
1345
+ children: [/* @__PURE__ */ jsx(Typography.Title, {
1346
+ className: "text-lg font-semibold",
1347
+ children: item.name
1348
+ }), /* @__PURE__ */ jsxs("div", {
1349
+ className: "flex items-center gap-1",
1350
+ children: [
1351
+ onMoveUp && /* @__PURE__ */ jsx(Button, {
1352
+ icon: /* @__PURE__ */ jsx(ChevronUp, {}),
1353
+ disabled: !canMoveUp,
1354
+ onClick: onMoveUp,
1355
+ "aria-label": "Move section up"
1356
+ }),
1357
+ onMoveDown && /* @__PURE__ */ jsx(Button, {
1358
+ icon: /* @__PURE__ */ jsx(ChevronDown, {}),
1359
+ disabled: !canMoveDown,
1360
+ onClick: onMoveDown,
1361
+ "aria-label": "Move section down"
1362
+ }),
1363
+ onDelete && /* @__PURE__ */ jsx(Button, {
1364
+ danger: true,
1365
+ icon: /* @__PURE__ */ jsx(Trash, {}),
1366
+ onClick: () => onDelete(item.id),
1367
+ "aria-label": "Delete section"
1368
+ })
1369
+ ]
1370
+ })]
1371
+ }),
1372
+ !fields.length && /* @__PURE__ */ jsx(Typography.Text, {
1373
+ className: "text-xs text-gray-400",
1374
+ children: "No editable elements."
1375
+ }),
1376
+ fields.map((node, index) => /* @__PURE__ */ jsx(Node, {
1377
+ data: node,
1378
+ onChange: onFieldChange
1379
+ }, `${item.id}-${index}`))
1380
+ ]
1381
+ });
1382
+ };
1383
+ //#endregion
1384
+ //#region src/components/dnd/dnd.tsx
1385
+ const conditionalModifiers = (args) => {
1386
+ const { active } = args;
1387
+ if (active?.data.current?.type === "new-item") return args.transform;
1388
+ return restrictToVerticalAxis(args);
1389
+ };
1390
+ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, className, items = [], frame, dynamicTailwind = false, provider, renderPalette, renderPanel, ...restProps }) => {
1391
+ const [selectedId, setSelectedId] = useState(null);
1392
+ const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);
1393
+ const { breakpoint } = useResponsiveSize();
1394
+ const isMobile = breakpoint.current === "xs" || breakpoint.current === "sm";
1395
+ const { setCode } = usePreview();
1396
+ const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 10 } }));
1397
+ const value = _value || DEFAULT_TEMPLATE;
1398
+ const sections = useMemo(() => extractSections(value), [value]);
1399
+ const selectedItem = useMemo(() => sections.find((s) => s.id === selectedId), [sections, selectedId]);
1400
+ const [previewCache] = useState(() => createSectionPreviewCache());
1401
+ const previews = useMemo(() => previewCache.compute(value, sections), [
1402
+ previewCache,
1403
+ sections,
1404
+ value
1405
+ ]);
1406
+ const onDragStart = (_) => {};
1407
+ const onDragOver = (_e) => {};
1408
+ const onDragEnd = (event) => {
1409
+ const { active, over } = event;
1410
+ if (!over) return;
1411
+ if (active.data.current?.type === "new-item") {
1412
+ const newItem = active.data.current.item;
1413
+ const newSection = {
1414
+ id: v4(),
1415
+ name: newItem.name,
1416
+ code: newItem.code
1417
+ };
1418
+ let nextSections;
1419
+ if (over.id === "sortable-area" || over.id === "sortable-area-bottom") nextSections = [...sections, newSection];
1420
+ else {
1421
+ const overIndex = sections.findIndex((s) => s.id === over.id);
1422
+ if (overIndex >= 0) nextSections = [
1423
+ ...sections.slice(0, overIndex),
1424
+ newSection,
1425
+ ...sections.slice(overIndex)
1426
+ ];
1427
+ else nextSections = [...sections, newSection];
1428
+ }
1429
+ const nextCode = replaceSections(value, nextSections.map((s) => s.code));
1430
+ _onChange?.(nextCode);
1431
+ setCode(nextCode);
1432
+ return;
1433
+ }
1434
+ if (active.id !== over.id && sections.some((s) => s.id === active.id)) {
1435
+ const prevIndex = sections.findIndex((s) => s.id === active.id);
1436
+ const nextIndex = sections.findIndex((s) => s.id === over.id);
1437
+ if (prevIndex >= 0 && nextIndex >= 0) {
1438
+ const nextSections = arrayMove(sections, prevIndex, nextIndex);
1439
+ const nextCode = replaceSections(value, nextSections.map((s) => s.code));
1440
+ _onChange?.(nextCode);
1441
+ setCode(nextCode);
1442
+ }
1443
+ }
1444
+ };
1445
+ const addItem = (item) => {
1446
+ const newSection = {
1447
+ id: v4(),
1448
+ name: item.name,
1449
+ code: item.code
1450
+ };
1451
+ const nextSections = [...sections, newSection];
1452
+ const nextCode = replaceSections(value, nextSections.map((s) => s.code));
1453
+ _onChange?.(nextCode);
1454
+ setCode(nextCode);
1455
+ };
1456
+ const onDelete = (id) => {
1457
+ const nextSections = sections.filter((s) => s.id !== id);
1458
+ setSelectedId(null);
1459
+ const nextCode = replaceSections(value, nextSections.map((s) => s.code));
1460
+ _onChange?.(nextCode);
1461
+ setCode(nextCode);
1462
+ };
1463
+ const moveSection = (id, direction) => {
1464
+ const index = sections.findIndex((s) => s.id === id);
1465
+ const targetIndex = direction === "up" ? index - 1 : index + 1;
1466
+ if (index < 0 || targetIndex < 0 || targetIndex >= sections.length) return;
1467
+ const nextSections = arrayMove(sections, index, targetIndex);
1468
+ const nextCode = replaceSections(value, nextSections.map((s) => s.code));
1469
+ _onChange?.(nextCode);
1470
+ setCode(nextCode);
1471
+ setSelectedId(String(targetIndex));
1472
+ };
1473
+ const onCopy = (id) => {
1474
+ const sectionIndex = sections.findIndex((s) => s.id === id);
1475
+ const sectionToCopy = sections[sectionIndex];
1476
+ if (sectionToCopy) {
1477
+ const nextId = v4();
1478
+ const nextSection = {
1479
+ id: nextId,
1480
+ code: replaceIds(sectionToCopy.code),
1481
+ name: sectionToCopy.name
1482
+ };
1483
+ const nextSections = [
1484
+ ...sections.slice(0, sectionIndex + 1),
1485
+ nextSection,
1486
+ ...sections.slice(sectionIndex + 1)
1487
+ ];
1488
+ setSelectedId(nextId);
1489
+ const nextCode = replaceSections(value, nextSections.map((s) => s.code));
1490
+ _onChange?.(nextCode);
1491
+ setCode(nextCode);
1492
+ }
1493
+ };
1494
+ const onSelect = (id) => {
1495
+ setSelectedId((prev) => prev === id ? null : id);
1496
+ };
1497
+ const onChange = (next) => {
1498
+ const nextSections = sections.map((s) => s.id === next.id ? {
1499
+ ...s,
1500
+ ...next
1501
+ } : s);
1502
+ const nextCode = replaceSections(value, nextSections.map((s) => s.code));
1503
+ _onChange?.(nextCode);
1504
+ setCode(nextCode);
1505
+ };
1506
+ const selectedCode = selectedItem?.code;
1507
+ const { fields, updatedCode, parseError } = useMemo(() => {
1508
+ if (!selectedCode) return {
1509
+ fields: [],
1510
+ updatedCode: "",
1511
+ parseError: false
1512
+ };
1513
+ try {
1514
+ const updated = fillIds(selectedCode);
1515
+ return {
1516
+ fields: extract(updated).filter((node) => node.tagName !== "section"),
1517
+ updatedCode: updated !== selectedCode ? updated : selectedCode,
1518
+ parseError: false
1519
+ };
1520
+ } catch (e) {
1521
+ console.warn("⚠️ Parsing error", e);
1522
+ return {
1523
+ fields: [],
1524
+ updatedCode: "",
1525
+ parseError: true
1526
+ };
1527
+ }
1528
+ }, [selectedCode]);
1529
+ useEffect(() => {
1530
+ if (parseError) Toast.error("Failed to parse this section", { description: "Check the console for details." });
1531
+ }, [parseError]);
1532
+ const onFieldChange = ({ id, label, value: fieldValue }) => {
1533
+ const result = update(updatedCode, id, label, fieldValue);
1534
+ if (!result.success) {
1535
+ Toast.error("Failed to update this field", { description: "Check the console for details." });
1536
+ return;
1537
+ }
1538
+ if (selectedItem) onChange({
1539
+ ...selectedItem,
1540
+ code: result.code
1541
+ });
1542
+ };
1543
+ const bindings = useMemo(() => {
1544
+ return fields.flatMap((node) => {
1545
+ const dataId = node.dataAttributes.find((a) => a.name === "data-id")?.value;
1546
+ const bindingAttr = node.dataAttributes.find((a) => a.name === "data-binding")?.value;
1547
+ if (!dataId || !bindingAttr) return [];
1548
+ return (node.bindings ?? parseBinding(bindingAttr)).map((binding) => ({
1549
+ id: dataId,
1550
+ label: binding.label,
1551
+ property: binding.property,
1552
+ type: binding.type,
1553
+ options: binding.options,
1554
+ value: getCurrentValue(node, binding.property),
1555
+ onChange: (value) => onFieldChange({
1556
+ id: dataId,
1557
+ label: binding.label,
1558
+ value
1559
+ })
1560
+ }));
1561
+ });
1562
+ }, [fields]);
1563
+ useEffect(() => {
1564
+ if (frame?.scripts?.length) preloadScripts(frame.scripts);
1565
+ }, [frame?.scripts]);
1566
+ const renderPaletteItems = (onAdd, forMobileDrawer = false) => {
1567
+ const paletteItems = items?.length ? items : DRAGGABLE_ITEMS;
1568
+ if (renderPalette) return renderPalette({
1569
+ items: paletteItems,
1570
+ onAdd,
1571
+ DraggableItem,
1572
+ isMobile: forMobileDrawer
1573
+ });
1574
+ return /* @__PURE__ */ jsx(Space, {
1575
+ orientation: "vertical",
1576
+ align: "start",
1577
+ children: paletteItems.map((item) => /* @__PURE__ */ jsx(DefaultDraggableItem, {
1578
+ item,
1579
+ onAdd,
1580
+ tapToAdd: forMobileDrawer
1581
+ }, item.id))
1582
+ });
1583
+ };
1584
+ const renderPanelContent = () => {
1585
+ const selectedIndex = sections.findIndex((s) => s.id === selectedId);
1586
+ const canMoveUp = selectedIndex > 0;
1587
+ const canMoveDown = selectedIndex >= 0 && selectedIndex < sections.length - 1;
1588
+ if (renderPanel) return renderPanel({
1589
+ item: selectedItem,
1590
+ onChange,
1591
+ onDelete,
1592
+ onMoveUp: () => moveSection(selectedId, "up"),
1593
+ onMoveDown: () => moveSection(selectedId, "down"),
1594
+ canMoveUp,
1595
+ canMoveDown,
1596
+ bindings
1597
+ });
1598
+ return /* @__PURE__ */ jsx(Panel, {
1599
+ item: selectedItem,
1600
+ onDelete,
1601
+ onMoveUp: () => moveSection(selectedId, "up"),
1602
+ onMoveDown: () => moveSection(selectedId, "down"),
1603
+ canMoveUp,
1604
+ canMoveDown,
1605
+ fields,
1606
+ onFieldChange
1607
+ });
1608
+ };
1609
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(DndContext, {
1610
+ sensors,
1611
+ collisionDetection: closestCenter,
1612
+ modifiers: [conditionalModifiers],
1613
+ onDragStart,
1614
+ onDragOver,
1615
+ onDragEnd,
1616
+ children: [/* @__PURE__ */ jsxs("div", {
1617
+ className: cn("relative flex w-full", className),
1618
+ ...restProps,
1619
+ children: [
1620
+ /* @__PURE__ */ jsx("div", {
1621
+ className: "hidden w-1/5 overflow-y-auto md:block",
1622
+ children: /* @__PURE__ */ jsx("div", {
1623
+ className: "h-full bg-gray-50 p-4",
1624
+ children: renderPaletteItems(addItem)
1625
+ })
1626
+ }),
1627
+ /* @__PURE__ */ jsx("div", {
1628
+ className: cn("relative", "h-full w-full md:w-3/5", "overflow-y-auto"),
1629
+ "data-frame-container": true,
1630
+ style: {
1631
+ isolation: "isolate",
1632
+ contain: "layout style",
1633
+ transform: "translateZ(0)"
1634
+ },
1635
+ children: /* @__PURE__ */ jsx(Droppable, {
1636
+ className: cn(!sections.length && "h-full"),
1637
+ children: !sections.length ? /* @__PURE__ */ jsx("div", {
1638
+ className: cn("flex items-center justify-center", "h-full", "text-gray-500"),
1639
+ children: /* @__PURE__ */ jsxs(Space, {
1640
+ orientation: "vertical",
1641
+ align: "center",
1642
+ children: [/* @__PURE__ */ jsx(Typography.Paragraph, { children: "No sections available" }), /* @__PURE__ */ jsx(Typography.Text, { children: "Drag a component from the left to add it" })]
1643
+ })
1644
+ }) : /* @__PURE__ */ jsx(SortableContext, {
1645
+ items: sections.map((s) => s.id),
1646
+ strategy: verticalListSortingStrategy,
1647
+ children: sections.map((section, index) => /* @__PURE__ */ jsx(Sortable, {
1648
+ id: section.id,
1649
+ name: section.name,
1650
+ selected: selectedId === section.id,
1651
+ onClick: () => onSelect(section.id),
1652
+ onDelete,
1653
+ onCopy,
1654
+ children: /* @__PURE__ */ jsx(renderer_default, {
1655
+ preview: previews[index],
1656
+ modules,
1657
+ frame,
1658
+ dynamicTailwind,
1659
+ provider,
1660
+ ...props
1661
+ })
1662
+ }, section.id))
1663
+ })
1664
+ })
1665
+ }),
1666
+ /* @__PURE__ */ jsx("div", {
1667
+ className: "hidden w-1/5 md:block",
1668
+ children: renderPanelContent()
1669
+ }),
1670
+ /* @__PURE__ */ jsx(Button, {
1671
+ type: "primary",
1672
+ shape: "circle",
1673
+ icon: /* @__PURE__ */ jsx(LayoutGrid, {}),
1674
+ "aria-label": "Components",
1675
+ className: "fixed right-4 bottom-4 z-20 md:hidden",
1676
+ onClick: () => setMobilePaletteOpen(true)
1677
+ }),
1678
+ /* @__PURE__ */ jsx(Drawer, {
1679
+ open: isMobile && mobilePaletteOpen,
1680
+ onClose: () => setMobilePaletteOpen(false),
1681
+ direction: "bottom",
1682
+ size: "large",
1683
+ title: "Components",
1684
+ children: renderPaletteItems((item) => {
1685
+ addItem(item);
1686
+ setMobilePaletteOpen(false);
1687
+ }, true)
1688
+ }),
1689
+ /* @__PURE__ */ jsx(Drawer, {
1690
+ open: isMobile && Boolean(selectedId),
1691
+ onClose: () => setSelectedId(null),
1692
+ direction: "bottom",
1693
+ size: "large",
1694
+ title: "Properties",
1695
+ children: renderPanelContent()
1696
+ })
1697
+ ]
1698
+ }), /* @__PURE__ */ jsx(DragOverlay, { children: /* @__PURE__ */ jsx(Overlay, {
1699
+ sections,
1700
+ renderProps: {
1701
+ fullCode: value,
1702
+ modules,
1703
+ frame,
1704
+ dynamicTailwind,
1705
+ ...props
1706
+ }
1707
+ }) })]
1708
+ }) });
1709
+ };
1710
+ //#endregion
1711
+ //#region src/components/dnd/index.ts
1712
+ const Dnd = Dnd$1;
1713
+ Dnd.DraggableItem = DraggableItem;
1714
+ //#endregion
1715
+ export { DraggableItem as n, Dnd as t };
1716
+
1717
+ //# sourceMappingURL=dnd-BdNgmgYB.js.map