@jbpark/live-editor 3.0.1 → 3.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.
Files changed (43) hide show
  1. package/README.ko.md +3 -2
  2. package/README.md +3 -2
  3. package/dist/{ast-D6R-dsk0.js → ast-CIe-mhh_.js} +416 -177
  4. package/dist/ast-CIe-mhh_.js.map +1 -0
  5. package/dist/{boundary-BF7iZp6e.js → boundary-BTP1nfG6.js} +2 -2
  6. package/dist/{boundary-BF7iZp6e.js.map → boundary-BTP1nfG6.js.map} +1 -1
  7. package/dist/{context-DH70wj9d.js → context-649REFsj.js} +2 -2
  8. package/dist/{context-DH70wj9d.js.map → context-649REFsj.js.map} +1 -1
  9. package/dist/core-D3q5rpuz.js +77 -0
  10. package/dist/core-D3q5rpuz.js.map +1 -0
  11. package/dist/dnd/index.d.ts +2 -2
  12. package/dist/dnd/index.js +2 -2
  13. package/dist/{dnd-CZJjzuTC.js → dnd-BnXoytb5.js} +385 -398
  14. package/dist/dnd-BnXoytb5.js.map +1 -0
  15. package/dist/editor/index.d.ts +1 -1
  16. package/dist/editor/index.js +2 -2
  17. package/dist/{editor-Ct9wuhLm.js → editor-DQSoTCe8.js} +2 -2
  18. package/dist/{editor-Ct9wuhLm.js.map → editor-DQSoTCe8.js.map} +1 -1
  19. package/dist/error/index.js +2 -2
  20. package/dist/{error-lsJey-it.js → error-CO0EbMlA.js} +2 -2
  21. package/dist/{error-lsJey-it.js.map → error-CO0EbMlA.js.map} +1 -1
  22. package/dist/{index-C4TBkJBG.d.ts → index-Ck3akHag.d.ts} +2 -2
  23. package/dist/{index-Bqc5kUAG.d.ts → index-DswWDEXZ.d.ts} +27 -3
  24. package/dist/{index-GuEiafMN.d.ts → index-DxbG789f.d.ts} +25 -2
  25. package/dist/index.d.ts +3 -3
  26. package/dist/index.js +5 -5
  27. package/dist/preview/index.js +1 -1
  28. package/dist/{preview-CNVXyDgY.js → preview-DFH-z_JL.js} +4 -4
  29. package/dist/{preview-CNVXyDgY.js.map → preview-DFH-z_JL.js.map} +1 -1
  30. package/dist/provider/index.js +1 -1
  31. package/dist/style.css +105 -123
  32. package/dist/{use-dynamic-tailwind-C0Onss1A.js → use-dynamic-tailwind-DqqQu2de.js} +2 -2
  33. package/dist/{use-dynamic-tailwind-C0Onss1A.js.map → use-dynamic-tailwind-DqqQu2de.js.map} +1 -1
  34. package/dist/utils/ast/index.d.ts +2 -2
  35. package/dist/utils/ast/index.js +2 -2
  36. package/dist/utils/index.js +1 -1
  37. package/dist/{utils-BwEgY5pe.js → utils-WyxPYZGh.js} +12 -10
  38. package/dist/{utils-BwEgY5pe.js.map → utils-WyxPYZGh.js.map} +1 -1
  39. package/package.json +2 -2
  40. package/dist/ast-D6R-dsk0.js.map +0 -1
  41. package/dist/core-CbuS_p_d.js +0 -123
  42. package/dist/core-CbuS_p_d.js.map +0 -1
  43. package/dist/dnd-CZJjzuTC.js.map +0 -1
@@ -1,10 +1,10 @@
1
1
  import { C as __toESM, b as DRAGGABLE_ITEMS, f as nanoid, g as BINDING_PROP, m as require_lib, n as createSectionPreviewCache, r as fillSectionIds, y as DEFAULT_TEMPLATE } from "./document-C6bNHl7l.js";
2
- import { d as replaceSections, o as extractSections, r as cn, s as generateSection, u as preloadScripts } from "./utils-BwEgY5pe.js";
2
+ import { d as replaceSections, o as extractSections, r as cn, s as generateSection, u as preloadScripts } from "./utils-WyxPYZGh.js";
3
3
  import { i as usePreview } from "./states-Ci1AvoQ9.js";
4
- import { A as parseValue, D as extractObjectProperties, E as extractNodeValue, M as generateCode, S as parseBinding, _ as moveSelectedIndices, a as extract, b as getCurrentValue, c as moveArrayItem, d as removeArrayItems, f as updateArrayItemProperty, g as replaceIds, h as fillIds, k as parseArrayExpression, l as moveArrayItems, o as appendArrayItem, p as updateArrayItemValue, r as update, s as duplicateArrayItems, t as validateBindingValue, v as removeIndices, x as getStructuredValue, y as findEditableChildren } from "./ast-D6R-dsk0.js";
5
- import { n as useCompiledModule, r as Frame, t as useDynamicTailwind } from "./use-dynamic-tailwind-C0Onss1A.js";
6
- import { t as Core } from "./core-CbuS_p_d.js";
7
- import { n as Error$1, t as ErrorBoundary } from "./boundary-BF7iZp6e.js";
4
+ import { E as extractObjectProperties, O as parseArrayExpression, T as extractNodeValue, _ as updateArrayItemValue, b as getStructuredValue, d as duplicateArrayItems, f as moveArrayItem, g as updateArrayItemProperty, h as removeArrayItems, i as replaceIds, k as parseValue, l as extract, o as update, p as moveArrayItems, r as fillIds, s as getChildrenSignatures, t as validateBindingValue, u as appendArrayItem, v as findEditableChildren, x as parseBinding, y as getCurrentValue } from "./ast-CIe-mhh_.js";
5
+ import { n as useCompiledModule, r as Frame, t as useDynamicTailwind } from "./use-dynamic-tailwind-DqqQu2de.js";
6
+ import { t as Core } from "./core-D3q5rpuz.js";
7
+ import { n as Error$1, t as ErrorBoundary } from "./boundary-BTP1nfG6.js";
8
8
  import { Children, createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
9
9
  import { Button, Card, Checkbox, ColorPicker, DatePicker, Drawer, Input, RichTextEditor, Select, Space, Splitter, Toast, Typography, Upload } from "@jbpark/ui-kit";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -78,6 +78,332 @@ const useDndPalette = () => useDndRegions("useDndPalette()").palette;
78
78
  const useDndPanel = () => useDndRegions("useDndPanel()").panel;
79
79
  const useDndLayout = () => useDndRegions("useDndLayout()");
80
80
  //#endregion
81
+ //#region src/components/dnd/panel/bulk-actions-bar.tsx
82
+ const BulkActionsBar = ({ count, onDuplicate, onMoveUp, onMoveDown, onDelete, onClear }) => {
83
+ if (count === 0) return null;
84
+ return /* @__PURE__ */ jsxs("div", {
85
+ className: "flex items-center justify-between rounded border\n border-blue-200 bg-blue-50 p-2",
86
+ children: [/* @__PURE__ */ jsxs("div", {
87
+ className: "text-xs font-medium text-blue-700",
88
+ children: [count, " selected"]
89
+ }), /* @__PURE__ */ jsxs("div", {
90
+ className: "flex items-center space-x-1",
91
+ children: [
92
+ /* @__PURE__ */ jsx(Button, {
93
+ size: "small",
94
+ icon: /* @__PURE__ */ jsx(Copy, {}),
95
+ title: "Duplicate selected",
96
+ onClick: onDuplicate
97
+ }),
98
+ /* @__PURE__ */ jsx(Button, {
99
+ size: "small",
100
+ icon: /* @__PURE__ */ jsx(ArrowUp, {}),
101
+ title: "Move selected up",
102
+ onClick: onMoveUp
103
+ }),
104
+ /* @__PURE__ */ jsx(Button, {
105
+ size: "small",
106
+ icon: /* @__PURE__ */ jsx(ArrowDown, {}),
107
+ title: "Move selected down",
108
+ onClick: onMoveDown
109
+ }),
110
+ /* @__PURE__ */ jsx(Button, {
111
+ danger: true,
112
+ size: "small",
113
+ icon: /* @__PURE__ */ jsx(X, {}),
114
+ title: "Delete selected",
115
+ onClick: onDelete
116
+ }),
117
+ /* @__PURE__ */ jsx(Button, {
118
+ size: "small",
119
+ onClick: onClear,
120
+ children: "Clear"
121
+ })
122
+ ]
123
+ })]
124
+ });
125
+ };
126
+ //#endregion
127
+ //#region src/components/dnd/panel/node.tsx
128
+ const Node = ({ data, onChange }) => {
129
+ const idAttr = data.dataAttributes.find((a) => a.name === "data-id");
130
+ const bindingAttr = data.dataAttributes.find((a) => a.name === "data-binding");
131
+ if (!idAttr?.value || !bindingAttr?.value) return null;
132
+ const dataId = idAttr.value;
133
+ const bindings = data.bindings || parseBinding(bindingAttr.value);
134
+ if (!bindings.length) return null;
135
+ return /* @__PURE__ */ jsx("div", {
136
+ className: "space-y-2 rounded",
137
+ children: /* @__PURE__ */ jsx("div", {
138
+ className: "space-y-1",
139
+ children: bindings.map((binding) => {
140
+ const currentValue = getCurrentValue(data, binding.property);
141
+ const structuredValue = getStructuredValue(data, binding.property, binding.type);
142
+ return /* @__PURE__ */ jsxs("div", {
143
+ className: "space-y-1",
144
+ children: [/* @__PURE__ */ jsxs("label", {
145
+ className: "block text-xs font-semibold text-gray-700",
146
+ children: [binding.label, /* @__PURE__ */ jsxs("span", {
147
+ className: "ml-1 text-gray-400",
148
+ children: [
149
+ "(",
150
+ binding.property,
151
+ ")"
152
+ ]
153
+ })]
154
+ }), /* @__PURE__ */ jsx(Field, {
155
+ binding: {
156
+ id: dataId,
157
+ label: binding.label,
158
+ property: binding.property,
159
+ type: binding.type,
160
+ widget: binding.widget,
161
+ options: binding.options,
162
+ render: binding.render,
163
+ min: binding.min,
164
+ max: binding.max,
165
+ pattern: binding.pattern,
166
+ required: binding.required,
167
+ meta: binding.meta,
168
+ value: structuredValue,
169
+ rawValue: currentValue,
170
+ onChange: (next) => onChange?.({
171
+ id: dataId,
172
+ label: binding.label,
173
+ property: binding.property,
174
+ value: next
175
+ })
176
+ },
177
+ onNodeChange: onChange
178
+ })]
179
+ }, binding.label);
180
+ })
181
+ })
182
+ });
183
+ };
184
+ //#endregion
185
+ //#region src/components/dnd/panel/use-children-editor.ts
186
+ const useChildrenEditor = (items, { onChange } = {}) => {
187
+ const selection = useMultiSelect(items.length);
188
+ const expected = useMemo(() => getChildrenSignatures(items), [items]);
189
+ const revision = JSON.stringify(expected);
190
+ const clear = selection.clear;
191
+ useEffect(() => {
192
+ clear();
193
+ }, [revision, clear]);
194
+ const commit = (action) => {
195
+ onChange?.(JSON.stringify({
196
+ kind: "children-edit",
197
+ expected,
198
+ action
199
+ }));
200
+ };
201
+ return {
202
+ items,
203
+ selection,
204
+ actions: {
205
+ move: (from, to) => commit({
206
+ type: "move",
207
+ from,
208
+ to
209
+ }),
210
+ remove: (index) => commit({
211
+ type: "remove",
212
+ indices: [index]
213
+ }),
214
+ add: () => commit({ type: "append" }),
215
+ duplicateSelected: () => commit({
216
+ type: "duplicate",
217
+ indices: [...selection.selected]
218
+ }),
219
+ moveSelected: (direction) => commit({
220
+ type: "move-selected",
221
+ indices: [...selection.selected],
222
+ direction
223
+ }),
224
+ removeSelected: () => commit({
225
+ type: "remove",
226
+ indices: [...selection.selected]
227
+ })
228
+ }
229
+ };
230
+ };
231
+ //#endregion
232
+ //#region src/components/dnd/panel/children.tsx
233
+ const Children$1 = ({ value, onChange, onNodeChange }) => {
234
+ const items = useMemo(() => Array.isArray(value) ? value : [], [value]);
235
+ const { selection, actions } = useChildrenEditor(items, { onChange });
236
+ const editableChildrenMap = useMemo(() => {
237
+ const map = /* @__PURE__ */ new Map();
238
+ items.forEach((item, index) => {
239
+ const editableNodes = findEditableChildren(item);
240
+ if (editableNodes.length > 0) map.set(index, editableNodes);
241
+ });
242
+ return map;
243
+ }, [items]);
244
+ return /* @__PURE__ */ jsxs("div", {
245
+ className: "space-y-3",
246
+ children: [
247
+ /* @__PURE__ */ jsxs("div", {
248
+ className: "flex items-center justify-between",
249
+ children: [/* @__PURE__ */ jsxs("div", {
250
+ className: "text-sm font-semibold text-green-700",
251
+ children: [
252
+ "Children Items (",
253
+ items.length,
254
+ ")"
255
+ ]
256
+ }), /* @__PURE__ */ jsx(Button, {
257
+ size: "small",
258
+ color: "green",
259
+ icon: /* @__PURE__ */ jsx(Plus, {}),
260
+ onClick: actions.add,
261
+ children: "Add Child"
262
+ })]
263
+ }),
264
+ /* @__PURE__ */ jsx(BulkActionsBar, {
265
+ count: selection.selected.size,
266
+ onDuplicate: actions.duplicateSelected,
267
+ onMoveUp: () => actions.moveSelected("up"),
268
+ onMoveDown: () => actions.moveSelected("down"),
269
+ onDelete: actions.removeSelected,
270
+ onClear: selection.clear
271
+ }),
272
+ items.map((item, itemIndex) => /* @__PURE__ */ jsxs("div", {
273
+ className: "space-y-2 rounded border border-green-200 bg-green-50 p-3",
274
+ children: [
275
+ /* @__PURE__ */ jsxs("div", {
276
+ className: "flex items-center justify-between",
277
+ children: [/* @__PURE__ */ jsxs("div", {
278
+ className: "flex items-center space-x-2",
279
+ children: [/* @__PURE__ */ jsx("div", {
280
+ onClick: (e) => selection.toggle(itemIndex, e.shiftKey),
281
+ className: "inline-flex",
282
+ children: /* @__PURE__ */ jsx(Checkbox, {
283
+ checked: selection.isSelected(itemIndex),
284
+ onChange: () => {}
285
+ })
286
+ }), /* @__PURE__ */ jsxs("div", {
287
+ className: "text-xs font-medium text-green-800",
288
+ children: [
289
+ "Child ",
290
+ itemIndex + 1,
291
+ " (",
292
+ item.tagName || "fragment",
293
+ ")"
294
+ ]
295
+ })]
296
+ }), /* @__PURE__ */ jsxs("div", {
297
+ className: "flex space-x-1",
298
+ children: [
299
+ /* @__PURE__ */ jsx(Button, {
300
+ size: "small",
301
+ icon: /* @__PURE__ */ jsx(ArrowUp, {}),
302
+ disabled: itemIndex === 0,
303
+ onClick: () => actions.move(itemIndex, itemIndex - 1)
304
+ }),
305
+ /* @__PURE__ */ jsx(Button, {
306
+ size: "small",
307
+ icon: /* @__PURE__ */ jsx(ArrowDown, {}),
308
+ disabled: itemIndex === items.length - 1,
309
+ onClick: () => actions.move(itemIndex, itemIndex + 1)
310
+ }),
311
+ /* @__PURE__ */ jsx(Button, {
312
+ title: "Delete item",
313
+ danger: true,
314
+ size: "small",
315
+ icon: /* @__PURE__ */ jsx(X, {}),
316
+ onClick: () => actions.remove(itemIndex)
317
+ })
318
+ ]
319
+ })]
320
+ }),
321
+ editableChildrenMap.has(itemIndex) && /* @__PURE__ */ jsxs("div", {
322
+ className: "space-y-2",
323
+ children: [/* @__PURE__ */ jsx("div", {
324
+ className: "text-xs font-medium text-green-700",
325
+ children: "Editable Bindings:"
326
+ }), editableChildrenMap.get(itemIndex).map((editableNode, idx) => {
327
+ const nodeId = editableNode.dataAttributes.find((a) => a.name === "data-id")?.value;
328
+ return /* @__PURE__ */ jsxs("div", {
329
+ className: "rounded border border-green-100 bg-white p-2",
330
+ children: [/* @__PURE__ */ jsx("div", {
331
+ className: "mb-1 text-xs text-green-600",
332
+ children: editableNode.tagName
333
+ }), /* @__PURE__ */ jsx(Node, {
334
+ data: editableNode,
335
+ onChange: onNodeChange
336
+ })]
337
+ }, `editable-${nodeId || idx}`);
338
+ })]
339
+ }),
340
+ !!item.children && !editableChildrenMap.has(itemIndex) && /* @__PURE__ */ jsxs("div", {
341
+ className: "space-y-1",
342
+ children: [/* @__PURE__ */ jsx("div", {
343
+ className: "text-xs font-medium text-green-700",
344
+ children: "Child Nodes:"
345
+ }), item.children.map((node, nodeIndex) => /* @__PURE__ */ jsx("div", {
346
+ className: "ml-2 rounded border border-green-100 bg-white p-2",
347
+ children: /* @__PURE__ */ jsx(Node, {
348
+ data: node,
349
+ onChange: onNodeChange
350
+ })
351
+ }, `node-${itemIndex}-${nodeIndex}`))]
352
+ })
353
+ ]
354
+ }, item.id || itemIndex))
355
+ ]
356
+ });
357
+ };
358
+ //#endregion
359
+ //#region src/components/dnd/panel/icon-map.tsx
360
+ const ICON_MAP = {
361
+ AlertCircle,
362
+ ArrowDown,
363
+ ArrowLeft,
364
+ ArrowRight,
365
+ ArrowUp,
366
+ Bell,
367
+ Bookmark,
368
+ Calendar,
369
+ Camera,
370
+ Check,
371
+ ChevronDown,
372
+ ChevronRight,
373
+ Clock,
374
+ Download,
375
+ Edit,
376
+ Eye,
377
+ Filter,
378
+ Heart,
379
+ Home,
380
+ Image,
381
+ Info,
382
+ Link,
383
+ Mail,
384
+ Map: Map$1,
385
+ Menu,
386
+ MessageCircle,
387
+ Phone,
388
+ Plus,
389
+ Search,
390
+ Settings,
391
+ Share,
392
+ ShoppingCart,
393
+ Star,
394
+ Trash,
395
+ Upload: Upload$1,
396
+ User,
397
+ X
398
+ };
399
+ const ICON_OPTIONS = Object.entries(ICON_MAP).map(([name, Icon]) => ({
400
+ label: /* @__PURE__ */ jsxs("span", {
401
+ className: "flex items-center gap-2",
402
+ children: [/* @__PURE__ */ jsx(Icon, { size: 14 }), name]
403
+ }),
404
+ value: name
405
+ }));
406
+ //#endregion
81
407
  //#region src/components/dnd/panel/use-items-editor.ts
82
408
  const resolveLeaf = (render, key) => {
83
409
  const leaf = render?.[key];
@@ -87,8 +413,8 @@ const resolveMap = (render, key) => {
87
413
  const leaf = render?.[key];
88
414
  return leaf && !("type" in leaf) ? leaf : void 0;
89
415
  };
90
- const bindingsInJSX = (node) => {
91
- const nodes = extract(generateCode(node));
416
+ const bindingsInJSX = (source) => {
417
+ const nodes = extract(source);
92
418
  const container = nodes.find((n) => n.bindings?.some((b) => b.property === "children"));
93
419
  if (container) return [container];
94
420
  const bindings = [];
@@ -107,7 +433,8 @@ const parseSource = (value) => {
107
433
  };
108
434
  const objectItems = [];
109
435
  const primitiveItems = [];
110
- ast.elements.filter((element) => Boolean(element)).forEach((element, elementIndex) => {
436
+ ast.elements.forEach((element, elementIndex) => {
437
+ if (!import_lib.isExpression(element)) return;
111
438
  if (!import_lib.isObjectExpression(element)) {
112
439
  const extracted = extractNodeValue(element);
113
440
  primitiveItems.push({
@@ -125,18 +452,20 @@ const parseSource = (value) => {
125
452
  if (!import_lib.isObjectProperty(prop) || !import_lib.isIdentifier(prop.key) || !(import_lib.isJSXElement(prop.value) || import_lib.isJSXFragment(prop.value))) return;
126
453
  const propertyName = prop.key.name;
127
454
  try {
128
- const found = bindingsInJSX(prop.value);
455
+ const found = bindingsInJSX(value.slice(prop.value.start, prop.value.end));
129
456
  if (found.length > 0) jsxBindings[propertyName] = found;
130
- else jsxFallbacks[propertyName] = generateCode(prop.value);
457
+ else jsxFallbacks[propertyName] = value.slice(prop.value.start, prop.value.end);
131
458
  } catch (error) {
132
459
  console.error(`Failed to parse JSX in property '${propertyName}':`, error);
133
460
  }
134
461
  });
462
+ const editableProperties = extractObjectProperties(element);
463
+ for (const property of Object.values(editableProperties)) if (property.type === "array" || property.type === "object") property.value = value.slice(property.astNode.start, property.astNode.end);
135
464
  objectItems.push({
136
465
  id: nanoid(6),
137
466
  index: objectItems.length,
138
467
  elementIndex,
139
- editableProperties: extractObjectProperties(element),
468
+ editableProperties,
140
469
  jsxBindings,
141
470
  jsxFallbacks
142
471
  });
@@ -157,10 +486,11 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
157
486
  const selection = useMultiSelect(isPrimitive ? primitiveItems.length : objectItems.length);
158
487
  const commit = (next) => {
159
488
  if (next === null) {
160
- Toast.error("Failed to update this item", { description: "Check the console for details." });
161
- return;
489
+ Toast.error("Failed to update this item", { description: "The source was preserved. Structural edits require a dense array without spreads; use the code editor for unsupported syntax." });
490
+ return false;
162
491
  }
163
492
  onChange?.(next);
493
+ return true;
164
494
  };
165
495
  const elementIndicesOf = (indices) => {
166
496
  return new Set((isPrimitive ? primitiveItems : objectItems).filter((item) => indices.has(item.index)).map((item) => item.elementIndex));
@@ -257,81 +587,35 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
257
587
  }),
258
588
  selection,
259
589
  actions: {
260
- add: () => commit(appendArrayItem(value, kind)),
261
- move: (elementIndex, toIndex) => {
262
- const target = (isPrimitive ? primitiveItems : objectItems).find((item) => item.index === toIndex);
263
- if (!target) return;
264
- commit(moveArrayItem(value, elementIndex, target.elementIndex));
265
- selection.clear();
266
- },
267
- remove: (elementIndex) => {
268
- commit(removeArrayItems(value, /* @__PURE__ */ new Set([elementIndex]), kind));
269
- selection.clear();
270
- },
271
- duplicateSelected: () => commit(duplicateArrayItems(value, elementIndicesOf(selection.selected))),
272
- moveSelected: (direction) => {
273
- const result = moveArrayItems(value, elementIndicesOf(selection.selected), direction);
274
- if (!result) {
275
- commit(null);
276
- return;
277
- }
278
- selection.replace(result.indices);
279
- commit(result.code);
280
- },
281
- removeSelected: () => {
282
- commit(removeArrayItems(value, elementIndicesOf(selection.selected), kind));
283
- selection.clear();
284
- }
285
- },
286
- parseError
287
- };
288
- };
289
- //#endregion
290
- //#region src/components/dnd/panel/items.tsx
291
- const BulkActionsBar = ({ count, onDuplicate, onMoveUp, onMoveDown, onDelete, onClear }) => {
292
- if (count === 0) return null;
293
- return /* @__PURE__ */ jsxs("div", {
294
- className: "flex items-center justify-between rounded border\n border-blue-200 bg-blue-50 p-2",
295
- children: [/* @__PURE__ */ jsxs("div", {
296
- className: "text-xs font-medium text-blue-700",
297
- children: [count, " selected"]
298
- }), /* @__PURE__ */ jsxs("div", {
299
- className: "flex items-center space-x-1",
300
- children: [
301
- /* @__PURE__ */ jsx(Button, {
302
- size: "small",
303
- icon: /* @__PURE__ */ jsx(Copy, {}),
304
- title: "Duplicate selected",
305
- onClick: onDuplicate
306
- }),
307
- /* @__PURE__ */ jsx(Button, {
308
- size: "small",
309
- icon: /* @__PURE__ */ jsx(ArrowUp, {}),
310
- title: "Move selected up",
311
- onClick: onMoveUp
312
- }),
313
- /* @__PURE__ */ jsx(Button, {
314
- size: "small",
315
- icon: /* @__PURE__ */ jsx(ArrowDown, {}),
316
- title: "Move selected down",
317
- onClick: onMoveDown
318
- }),
319
- /* @__PURE__ */ jsx(Button, {
320
- danger: true,
321
- size: "small",
322
- icon: /* @__PURE__ */ jsx(X, {}),
323
- title: "Delete selected",
324
- onClick: onDelete
325
- }),
326
- /* @__PURE__ */ jsx(Button, {
327
- size: "small",
328
- onClick: onClear,
329
- children: "Clear"
330
- })
331
- ]
332
- })]
333
- });
590
+ add: () => commit(appendArrayItem(value, kind)),
591
+ move: (elementIndex, toIndex) => {
592
+ const target = (isPrimitive ? primitiveItems : objectItems).find((item) => item.index === toIndex);
593
+ if (!target) return;
594
+ if (commit(moveArrayItem(value, elementIndex, target.elementIndex))) selection.clear();
595
+ },
596
+ remove: (elementIndex) => {
597
+ if (commit(removeArrayItems(value, /* @__PURE__ */ new Set([elementIndex]), kind))) selection.clear();
598
+ },
599
+ duplicateSelected: () => commit(duplicateArrayItems(value, elementIndicesOf(selection.selected))),
600
+ moveSelected: (direction) => {
601
+ const result = moveArrayItems(value, elementIndicesOf(selection.selected), direction);
602
+ if (!result) {
603
+ commit(null);
604
+ return;
605
+ }
606
+ const visible = parseArrayExpression(result.code)?.elements.flatMap((node, index) => import_lib.isExpression(node) && import_lib.isObjectExpression(node) === !isPrimitive ? [index] : []) ?? [];
607
+ selection.replace(new Set(visible.flatMap((position, index) => result.indices.has(position) ? [index] : [])));
608
+ commit(result.code);
609
+ },
610
+ removeSelected: () => {
611
+ if (commit(removeArrayItems(value, elementIndicesOf(selection.selected), kind))) selection.clear();
612
+ }
613
+ },
614
+ parseError
615
+ };
334
616
  };
617
+ //#endregion
618
+ //#region src/components/dnd/panel/items.tsx
335
619
  const NestedGroup = ({ group, onNodeChange }) => {
336
620
  if (group.fallback) return /* @__PURE__ */ jsxs("div", {
337
621
  className: "space-y-2",
@@ -546,305 +830,6 @@ const Items = ({ value, render, onChange, onChildChange }) => {
546
830
  });
547
831
  };
548
832
  //#endregion
549
- //#region src/components/dnd/panel/node.tsx
550
- const Node = ({ data, onChange }) => {
551
- const idAttr = data.dataAttributes.find((a) => a.name === "data-id");
552
- const bindingAttr = data.dataAttributes.find((a) => a.name === "data-binding");
553
- if (!idAttr?.value || !bindingAttr?.value) return null;
554
- const dataId = idAttr.value;
555
- const bindings = data.bindings || parseBinding(bindingAttr.value);
556
- if (!bindings.length) return null;
557
- return /* @__PURE__ */ jsx("div", {
558
- className: "space-y-2 rounded",
559
- children: /* @__PURE__ */ jsx("div", {
560
- className: "space-y-1",
561
- children: bindings.map((binding) => {
562
- const currentValue = getCurrentValue(data, binding.property);
563
- const structuredValue = getStructuredValue(data, binding.property, binding.type);
564
- return /* @__PURE__ */ jsxs("div", {
565
- className: "space-y-1",
566
- children: [/* @__PURE__ */ jsxs("label", {
567
- className: "block text-xs font-semibold text-gray-700",
568
- children: [binding.label, /* @__PURE__ */ jsxs("span", {
569
- className: "ml-1 text-gray-400",
570
- children: [
571
- "(",
572
- binding.property,
573
- ")"
574
- ]
575
- })]
576
- }), /* @__PURE__ */ jsx(Field, {
577
- binding: {
578
- id: dataId,
579
- label: binding.label,
580
- property: binding.property,
581
- type: binding.type,
582
- widget: binding.widget,
583
- options: binding.options,
584
- render: binding.render,
585
- min: binding.min,
586
- max: binding.max,
587
- pattern: binding.pattern,
588
- required: binding.required,
589
- meta: binding.meta,
590
- value: structuredValue,
591
- rawValue: currentValue,
592
- onChange: (next) => onChange?.({
593
- id: dataId,
594
- label: binding.label,
595
- property: binding.property,
596
- value: next
597
- })
598
- },
599
- onNodeChange: onChange
600
- })]
601
- }, binding.label);
602
- })
603
- })
604
- });
605
- };
606
- //#endregion
607
- //#region src/components/dnd/panel/children.tsx
608
- const Children$1 = ({ value, onChange, onNodeChange }) => {
609
- const items = useMemo(() => Array.isArray(value) ? value : [], [value]);
610
- const selection = useMultiSelect(items.length);
611
- const editableChildrenMap = useMemo(() => {
612
- const map = /* @__PURE__ */ new Map();
613
- items.forEach((item, index) => {
614
- const editableNodes = findEditableChildren(item);
615
- if (editableNodes.length > 0) map.set(index, editableNodes);
616
- });
617
- return map;
618
- }, [items]);
619
- const moveItem = (fromIndex, toIndex) => {
620
- const nextItems = [...items];
621
- const [movedItem] = nextItems.splice(fromIndex, 1);
622
- nextItems.splice(toIndex, 0, movedItem);
623
- onChange?.(JSON.stringify(nextItems));
624
- };
625
- const moveSelectedItems = (indices, direction) => {
626
- const { items: nextItems, indices: nextIndices } = moveSelectedIndices(items, indices, direction);
627
- selection.replace(nextIndices);
628
- onChange?.(JSON.stringify(nextItems));
629
- };
630
- const deleteSelectedItems = (indices) => {
631
- if (items.length - indices.size < 1) return;
632
- const nextItems = removeIndices(items, indices);
633
- onChange?.(JSON.stringify(nextItems));
634
- };
635
- const deleteItem = (index) => deleteSelectedItems(/* @__PURE__ */ new Set([index]));
636
- const addItem = () => {
637
- const template = items[0] || createDefaultItem();
638
- const newItem = cloneDataAttrNode(template);
639
- const nextItems = [...items, newItem];
640
- onChange?.(JSON.stringify(nextItems));
641
- };
642
- const duplicateSelectedItems = (indices) => {
643
- const sources = [...indices].sort((a, b) => a - b).map((index) => items[index]).filter((item) => Boolean(item));
644
- if (sources.length === 0) return;
645
- const clones = sources.map(cloneDataAttrNode);
646
- onChange?.(JSON.stringify([...items, ...clones]));
647
- };
648
- const createDefaultItem = () => ({
649
- id: nanoid(6),
650
- tagName: "div",
651
- attributes: [{
652
- name: "data-id",
653
- value: nanoid(6)
654
- }, {
655
- name: "data-item",
656
- value: "true"
657
- }],
658
- dataAttributes: [{
659
- name: "data-id",
660
- value: nanoid(6)
661
- }, {
662
- name: "data-item",
663
- value: "true"
664
- }],
665
- textContent: "",
666
- children: []
667
- });
668
- const cloneDataAttrNode = (node) => ({
669
- ...node,
670
- id: nanoid(6),
671
- attributes: node.attributes.map((attr) => ({
672
- ...attr,
673
- value: attr.name === "data-id" ? nanoid(6) : attr.value
674
- })),
675
- dataAttributes: node.dataAttributes.map((attr) => ({
676
- ...attr,
677
- value: attr.name === "data-id" ? nanoid(6) : attr.value
678
- })),
679
- children: node.children?.map(cloneDataAttrNode)
680
- });
681
- return /* @__PURE__ */ jsxs("div", {
682
- className: "space-y-3",
683
- children: [
684
- /* @__PURE__ */ jsxs("div", {
685
- className: "flex items-center justify-between",
686
- children: [/* @__PURE__ */ jsxs("div", {
687
- className: "text-sm font-semibold text-green-700",
688
- children: [
689
- "Children Items (",
690
- items.length,
691
- ")"
692
- ]
693
- }), /* @__PURE__ */ jsx(Button, {
694
- size: "small",
695
- color: "green",
696
- icon: /* @__PURE__ */ jsx(Plus, {}),
697
- onClick: addItem,
698
- children: "Add Child"
699
- })]
700
- }),
701
- /* @__PURE__ */ jsx(BulkActionsBar, {
702
- count: selection.selected.size,
703
- onDuplicate: () => duplicateSelectedItems(selection.selected),
704
- onMoveUp: () => moveSelectedItems(selection.selected, "up"),
705
- onMoveDown: () => moveSelectedItems(selection.selected, "down"),
706
- onDelete: () => {
707
- deleteSelectedItems(selection.selected);
708
- selection.clear();
709
- },
710
- onClear: selection.clear
711
- }),
712
- items.map((item, itemIndex) => /* @__PURE__ */ jsxs("div", {
713
- className: "space-y-2 rounded border border-green-200 bg-green-50 p-3",
714
- children: [
715
- /* @__PURE__ */ jsxs("div", {
716
- className: "flex items-center justify-between",
717
- children: [/* @__PURE__ */ jsxs("div", {
718
- className: "flex items-center space-x-2",
719
- children: [/* @__PURE__ */ jsx("div", {
720
- onClick: (e) => selection.toggle(itemIndex, e.shiftKey),
721
- className: "inline-flex",
722
- children: /* @__PURE__ */ jsx(Checkbox, {
723
- checked: selection.isSelected(itemIndex),
724
- onChange: () => {}
725
- })
726
- }), /* @__PURE__ */ jsxs("div", {
727
- className: "text-xs font-medium text-green-800",
728
- children: [
729
- "Child ",
730
- itemIndex + 1,
731
- " (",
732
- item.tagName || "fragment",
733
- ")"
734
- ]
735
- })]
736
- }), /* @__PURE__ */ jsxs("div", {
737
- className: "flex space-x-1",
738
- children: [
739
- /* @__PURE__ */ jsx(Button, {
740
- size: "small",
741
- icon: /* @__PURE__ */ jsx(ArrowUp, {}),
742
- disabled: itemIndex === 0,
743
- onClick: () => moveItem(itemIndex, itemIndex - 1)
744
- }),
745
- /* @__PURE__ */ jsx(Button, {
746
- size: "small",
747
- icon: /* @__PURE__ */ jsx(ArrowDown, {}),
748
- disabled: itemIndex === items.length - 1,
749
- onClick: () => moveItem(itemIndex, itemIndex + 1)
750
- }),
751
- /* @__PURE__ */ jsx(Button, {
752
- title: items.length <= 1 ? "At least 1 item is required" : "Delete item",
753
- danger: true,
754
- size: "small",
755
- icon: /* @__PURE__ */ jsx(X, {}),
756
- disabled: items.length <= 1,
757
- onClick: () => deleteItem(itemIndex)
758
- })
759
- ]
760
- })]
761
- }),
762
- editableChildrenMap.has(itemIndex) && /* @__PURE__ */ jsxs("div", {
763
- className: "space-y-2",
764
- children: [/* @__PURE__ */ jsx("div", {
765
- className: "text-xs font-medium text-green-700",
766
- children: "Editable Bindings:"
767
- }), editableChildrenMap.get(itemIndex).map((editableNode, idx) => {
768
- const nodeId = editableNode.dataAttributes.find((a) => a.name === "data-id")?.value;
769
- return /* @__PURE__ */ jsxs("div", {
770
- className: "rounded border border-green-100 bg-white p-2",
771
- children: [/* @__PURE__ */ jsx("div", {
772
- className: "mb-1 text-xs text-green-600",
773
- children: editableNode.tagName
774
- }), /* @__PURE__ */ jsx(Node, {
775
- data: editableNode,
776
- onChange: onNodeChange
777
- })]
778
- }, `editable-${itemIndex}-${nodeId || idx}`);
779
- })]
780
- }),
781
- !!item.children && !editableChildrenMap.has(itemIndex) && /* @__PURE__ */ jsxs("div", {
782
- className: "space-y-1",
783
- children: [/* @__PURE__ */ jsx("div", {
784
- className: "text-xs font-medium text-green-700",
785
- children: "Child Nodes:"
786
- }), item.children.map((node, nodeIndex) => /* @__PURE__ */ jsx("div", {
787
- className: "ml-2 rounded border border-green-100 bg-white p-2",
788
- children: /* @__PURE__ */ jsx(Node, {
789
- data: node,
790
- onChange: onNodeChange
791
- })
792
- }, `node-${itemIndex}-${nodeIndex}`))]
793
- })
794
- ]
795
- }, item.id || itemIndex))
796
- ]
797
- });
798
- };
799
- //#endregion
800
- //#region src/components/dnd/panel/icon-map.tsx
801
- const ICON_MAP = {
802
- AlertCircle,
803
- ArrowDown,
804
- ArrowLeft,
805
- ArrowRight,
806
- ArrowUp,
807
- Bell,
808
- Bookmark,
809
- Calendar,
810
- Camera,
811
- Check,
812
- ChevronDown,
813
- ChevronRight,
814
- Clock,
815
- Download,
816
- Edit,
817
- Eye,
818
- Filter,
819
- Heart,
820
- Home,
821
- Image,
822
- Info,
823
- Link,
824
- Mail,
825
- Map: Map$1,
826
- Menu,
827
- MessageCircle,
828
- Phone,
829
- Plus,
830
- Search,
831
- Settings,
832
- Share,
833
- ShoppingCart,
834
- Star,
835
- Trash,
836
- Upload: Upload$1,
837
- User,
838
- X
839
- };
840
- const ICON_OPTIONS = Object.entries(ICON_MAP).map(([name, Icon]) => ({
841
- label: /* @__PURE__ */ jsxs("span", {
842
- className: "flex items-center gap-2",
843
- children: [/* @__PURE__ */ jsx(Icon, { size: 14 }), name]
844
- }),
845
- value: name
846
- }));
847
- //#endregion
848
833
  //#region src/components/dnd/panel/field.tsx
849
834
  const isColorProperty = (propertyName) => {
850
835
  return propertyName.toLowerCase().includes("color");
@@ -1161,7 +1146,7 @@ const groupBindingsById = (bindings) => {
1161
1146
  return [...groups.values()];
1162
1147
  };
1163
1148
  const Panel$1 = ({ item, onDelete, onMoveUp, onMoveDown, canMoveUp = false, canMoveDown = false, bindings, onNodeChange }) => {
1164
- const groups = useMemo(() => groupBindingsById(bindings), [bindings]);
1149
+ const groups = groupBindingsById(bindings);
1165
1150
  if (!item) return /* @__PURE__ */ jsx(Typography.Paragraph, {
1166
1151
  className: cn("p-4 text-sm text-gray-500"),
1167
1152
  children: "Please select a section."
@@ -1524,7 +1509,7 @@ const describeUpdateFailure = (failure, label) => {
1524
1509
  };
1525
1510
  case "parse-error": return {
1526
1511
  title: `Failed to update "${label}"`,
1527
- description: "Check the console for details."
1512
+ description: failure.error instanceof Error ? failure.error.message : "Check the console for details."
1528
1513
  };
1529
1514
  default: return { title: `Failed to update "${label}"` };
1530
1515
  }
@@ -1617,16 +1602,18 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
1617
1602
  required: binding.required,
1618
1603
  meta: binding.meta,
1619
1604
  value: getStructuredValue(node, binding.property, binding.type),
1620
- rawValue: getCurrentValue(node, binding.property),
1621
- onChange: (value) => onFieldChange({
1622
- id: dataId,
1623
- label: binding.label,
1624
- property: binding.property,
1625
- value
1626
- })
1605
+ rawValue: getCurrentValue(node, binding.property)
1627
1606
  }));
1628
1607
  });
1629
- }, [fields]);
1608
+ }, [fields]).map((field) => ({
1609
+ ...field,
1610
+ onChange: (value) => onFieldChange({
1611
+ id: field.id,
1612
+ label: field.label,
1613
+ property: field.property,
1614
+ value
1615
+ })
1616
+ }));
1630
1617
  useEffect(() => {
1631
1618
  if (frame?.scripts?.length) preloadScripts(frame.scripts);
1632
1619
  }, [frame?.scripts]);
@@ -1723,6 +1710,6 @@ Dnd.Canvas = Canvas;
1723
1710
  Dnd.Panel = Panel;
1724
1711
  Dnd.Layout = Layout;
1725
1712
  //#endregion
1726
- export { Panel as a, ICON_OPTIONS as c, useDndPalette as d, useDndPanel as f, Palette as i, useItemsEditor as l, Canvas as n, Field as o, DraggableItem as p, Layout as r, ICON_MAP as s, Dnd as t, useDndLayout as u };
1713
+ export { Panel as a, ICON_MAP as c, useDndLayout as d, useDndPalette as f, Palette as i, ICON_OPTIONS as l, DraggableItem as m, Canvas as n, Field as o, useDndPanel as p, Layout as r, useItemsEditor as s, Dnd as t, useChildrenEditor as u };
1727
1714
 
1728
- //# sourceMappingURL=dnd-CZJjzuTC.js.map
1715
+ //# sourceMappingURL=dnd-BnXoytb5.js.map