@jbpark/live-editor 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ast-CZwpVrJv.js +851 -0
- package/dist/ast-CZwpVrJv.js.map +1 -0
- package/dist/{boundary-BTP1nfG6.js → boundary-C90q3YsT.js} +8 -7
- package/dist/boundary-C90q3YsT.js.map +1 -0
- package/dist/{context-649REFsj.js → context-Y-M9fViD.js} +4 -8
- package/dist/context-Y-M9fViD.js.map +1 -0
- package/dist/{core-D3q5rpuz.js → core-Co8Nlq16.js} +2 -2
- package/dist/core-Co8Nlq16.js.map +1 -0
- package/dist/dnd/index.d.ts +2 -2
- package/dist/dnd/index.js +2 -2
- package/dist/{dnd-DTT37EbA.js → dnd-ClnGRNaY.js} +386 -324
- package/dist/dnd-ClnGRNaY.js.map +1 -0
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.js +2 -2
- package/dist/{editor-LzqHe_-F.js → editor-COKGtmfE.js} +3 -3
- package/dist/{editor-LzqHe_-F.js.map → editor-COKGtmfE.js.map} +1 -1
- package/dist/error/index.d.ts +1 -1
- package/dist/error/index.js +2 -2
- package/dist/{error-CO0EbMlA.js → error-o0SBwtTv.js} +2 -2
- package/dist/{error-CO0EbMlA.js.map → error-o0SBwtTv.js.map} +1 -1
- package/dist/{document-C6bNHl7l.js → extract-abHYmNsu.js} +927 -42
- package/dist/extract-abHYmNsu.js.map +1 -0
- package/dist/{index-Ba8jGXSM.d.ts → index-BQdZ6LrR.d.ts} +5 -1
- package/dist/{index-DxbG789f.d.ts → index-B_p74BRM.d.ts} +29 -14
- package/dist/{index-CCynrS6c.d.ts → index-DNNj_0ba.d.ts} +3 -2
- package/dist/{index-lgHdCda5.d.ts → index-DQkL37eL.d.ts} +10 -2
- package/dist/{index-DswWDEXZ.d.ts → index-Doh4VTXr.d.ts} +65 -35
- package/dist/index.d.ts +7 -7
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/preview/index.d.ts +2 -2
- package/dist/preview/index.js +3 -2
- package/dist/{preview-CWT0lgwq.js → preview-DKyKKcu7.js} +4 -4
- package/dist/{preview-CWT0lgwq.js.map → preview-DKyKKcu7.js.map} +1 -1
- package/dist/provider/index.js +1 -1
- package/dist/{use-dynamic-tailwind-DAhKGsY4.js → use-dynamic-tailwind-BF8TQ3Yy.js} +83 -27
- package/dist/use-dynamic-tailwind-BF8TQ3Yy.js.map +1 -0
- package/dist/utils/ast/index.d.ts +2 -2
- package/dist/utils/ast/index.js +3 -3
- package/dist/utils/index.d.ts +4 -7
- package/dist/utils/index.js +3 -3
- package/dist/{utils-WyxPYZGh.js → utils-BQ7WL7Jh.js} +33 -16
- package/dist/{utils-WyxPYZGh.js.map → utils-BQ7WL7Jh.js.map} +1 -1
- package/package.json +3 -1
- package/dist/ast-Bx2Avo4d.js +0 -1530
- package/dist/ast-Bx2Avo4d.js.map +0 -1
- package/dist/boundary-BTP1nfG6.js.map +0 -1
- package/dist/context-649REFsj.js.map +0 -1
- package/dist/core-D3q5rpuz.js.map +0 -1
- package/dist/dnd-DTT37EbA.js.map +0 -1
- package/dist/document-C6bNHl7l.js.map +0 -1
- package/dist/use-dynamic-tailwind-DAhKGsY4.js.map +0 -1
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { D as fillSectionIds, E as createSectionPreviewCache, I as nanoid, K as __toESM, L as require_lib, U as DRAGGABLE_ITEMS, _ as parseArrayExpression, a as findEditableChildren, c as parseBinding, d as canLosslesslyEvaluateSource, m as extractObjectProperties, n as extract, o as getCurrentValue, p as extractNodeValue, s as getStructuredValue, v as parseValue, z as BINDING_PROP } from "./extract-abHYmNsu.js";
|
|
2
|
+
import { c as generateSection, d as preloadScripts, i as cn, p as replaceSections, s as extractSections } from "./utils-BQ7WL7Jh.js";
|
|
3
3
|
import { i as usePreview } from "./states-Ci1AvoQ9.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { t as Core } from "./core-
|
|
7
|
-
import { n as Error$1, t as ErrorBoundary } from "./boundary-
|
|
4
|
+
import { _ as moveSelectedIndices, c as appendArrayItem, d as moveArrayItems, g as canStructurallyEditArray, h as updateArrayItemValue, i as replaceIds, l as duplicateArrayItems, m as updateArrayItemProperty, o as update, p as removeArrayItems, r as fillIds, s as getChildrenSignatures, t as validateBindingValue, u as moveArrayItem } from "./ast-CZwpVrJv.js";
|
|
5
|
+
import { i as Frame, n as useCompiledModule, t as useDynamicTailwind } from "./use-dynamic-tailwind-BF8TQ3Yy.js";
|
|
6
|
+
import { t as Core } from "./core-Co8Nlq16.js";
|
|
7
|
+
import { n as Error$1, t as ErrorBoundary } from "./boundary-C90q3YsT.js";
|
|
8
8
|
import { Children, createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
9
|
-
import { Button, Card, Checkbox, ColorPicker, DatePicker, Drawer, Input, RichTextEditor, Select, Space, Splitter, Toast, Typography, Upload } from "@jbpark/ui-kit";
|
|
10
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
10
|
import { DndContext, DragOverlay, PointerSensor, closestCenter, useDndContext, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
|
|
12
11
|
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
13
12
|
import { SortableContext, arrayMove, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
13
|
+
import { Button, Card, Checkbox, ColorPicker, DatePicker, Drawer, Input, RichTextEditor, Select, Space, Splitter, Toast, Typography } from "@jbpark/ui-kit";
|
|
14
14
|
import { useDebounce, useMultiSelect, useResponsiveSize } from "@jbpark/use-hooks";
|
|
15
|
-
import {
|
|
15
|
+
import { ArrowDown, ArrowUp, ChevronDown, ChevronUp, Copy, LayoutGrid, Plus, Trash, X } from "lucide-react";
|
|
16
16
|
import { CSS } from "@dnd-kit/utilities";
|
|
17
17
|
//#region src/components/dnd/droppable.tsx
|
|
18
18
|
var import_lib = /* @__PURE__ */ __toESM(require_lib(), 1);
|
|
@@ -36,6 +36,13 @@ const Droppable = ({ children, className }) => {
|
|
|
36
36
|
});
|
|
37
37
|
};
|
|
38
38
|
//#endregion
|
|
39
|
+
//#region src/components/dnd/edit-options.ts
|
|
40
|
+
const toastEditError = (error) => {
|
|
41
|
+
Toast.error(error.title, error.description ? { description: error.description } : void 0);
|
|
42
|
+
};
|
|
43
|
+
const DndEditOptionsContext = createContext({ reportError: toastEditError });
|
|
44
|
+
const useDndEditOptions = () => useContext(DndEditOptionsContext);
|
|
45
|
+
//#endregion
|
|
39
46
|
//#region src/components/dnd/draggable.tsx
|
|
40
47
|
const DraggableItem = ({ item, children }) => {
|
|
41
48
|
const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
|
|
@@ -78,8 +85,73 @@ const useDndPalette = () => useDndRegions("useDndPalette()").palette;
|
|
|
78
85
|
const useDndPanel = () => useDndRegions("useDndPanel()").panel;
|
|
79
86
|
const useDndLayout = () => useDndRegions("useDndLayout()");
|
|
80
87
|
//#endregion
|
|
88
|
+
//#region src/components/dnd/panel-binding.ts
|
|
89
|
+
const readAttribute = (node, name) => node.dataAttributes.find((attribute) => attribute.name === name)?.value;
|
|
90
|
+
const canEditBindingValue = (node, binding) => {
|
|
91
|
+
if (binding.property === "children" || binding.property === "innerText" || binding.property === "innerHTML" || binding.property === "items" || binding.property === "data" || binding.type === "array" || binding.type === "jsx" || binding.type === "richtext") return true;
|
|
92
|
+
const attribute = node.attributes.find((candidate) => candidate.name === binding.property);
|
|
93
|
+
return attribute?.isStringLiteral === true || canLosslesslyEvaluateSource(attribute?.value ?? "");
|
|
94
|
+
};
|
|
95
|
+
const toBindingFields = (binding) => ({
|
|
96
|
+
label: binding.label,
|
|
97
|
+
property: binding.property,
|
|
98
|
+
type: binding.type,
|
|
99
|
+
widget: binding.widget,
|
|
100
|
+
options: binding.options,
|
|
101
|
+
render: binding.render,
|
|
102
|
+
min: binding.min,
|
|
103
|
+
max: binding.max,
|
|
104
|
+
pattern: binding.pattern,
|
|
105
|
+
required: binding.required,
|
|
106
|
+
meta: binding.meta
|
|
107
|
+
});
|
|
108
|
+
const resolveRenderEntry = (render, key) => {
|
|
109
|
+
const entry = render?.[key];
|
|
110
|
+
if (entry && "type" in entry) {
|
|
111
|
+
const leaf = entry;
|
|
112
|
+
return {
|
|
113
|
+
...leaf,
|
|
114
|
+
label: leaf.label ?? key,
|
|
115
|
+
property: leaf.property ?? key
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
label: key,
|
|
120
|
+
property: key,
|
|
121
|
+
render: entry
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
const toPanelBindingData = (node, id, binding) => ({
|
|
125
|
+
...toBindingFields(binding),
|
|
126
|
+
id,
|
|
127
|
+
value: getStructuredValue(node, binding.property, binding.type),
|
|
128
|
+
rawValue: getCurrentValue(node, binding.property),
|
|
129
|
+
...!canEditBindingValue(node, binding) && { canEditValue: false }
|
|
130
|
+
});
|
|
131
|
+
const resolvePanelBindings = (node) => {
|
|
132
|
+
const id = readAttribute(node, "data-id");
|
|
133
|
+
const bindingAttr = readAttribute(node, "data-binding");
|
|
134
|
+
if (!id || !bindingAttr) return null;
|
|
135
|
+
const parsed = node.bindings ?? parseBinding(bindingAttr);
|
|
136
|
+
if (!parsed.length) return null;
|
|
137
|
+
return {
|
|
138
|
+
id,
|
|
139
|
+
tagName: node.tagName || "element",
|
|
140
|
+
bindings: parsed.map((binding) => toPanelBindingData(node, id, binding))
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
const withPanelCommit = (bindings, commit) => bindings.map((binding) => ({
|
|
144
|
+
...binding,
|
|
145
|
+
onChange: (value) => commit?.({
|
|
146
|
+
id: binding.id,
|
|
147
|
+
label: binding.label,
|
|
148
|
+
property: binding.property,
|
|
149
|
+
value
|
|
150
|
+
})
|
|
151
|
+
}));
|
|
152
|
+
//#endregion
|
|
81
153
|
//#region src/components/dnd/panel/bulk-actions-bar.tsx
|
|
82
|
-
const BulkActionsBar = ({ count, onDuplicate, onMoveUp, onMoveDown, onDelete, onClear }) => {
|
|
154
|
+
const BulkActionsBar = ({ count, disabled = false, onDuplicate, onMoveUp, onMoveDown, onDelete, onClear }) => {
|
|
83
155
|
if (count === 0) return null;
|
|
84
156
|
return /* @__PURE__ */ jsxs("div", {
|
|
85
157
|
className: "flex items-center justify-between rounded border\n border-blue-200 bg-blue-50 p-2",
|
|
@@ -93,18 +165,21 @@ const BulkActionsBar = ({ count, onDuplicate, onMoveUp, onMoveDown, onDelete, on
|
|
|
93
165
|
size: "small",
|
|
94
166
|
icon: /* @__PURE__ */ jsx(Copy, {}),
|
|
95
167
|
title: "Duplicate selected",
|
|
168
|
+
disabled,
|
|
96
169
|
onClick: onDuplicate
|
|
97
170
|
}),
|
|
98
171
|
/* @__PURE__ */ jsx(Button, {
|
|
99
172
|
size: "small",
|
|
100
173
|
icon: /* @__PURE__ */ jsx(ArrowUp, {}),
|
|
101
174
|
title: "Move selected up",
|
|
175
|
+
disabled,
|
|
102
176
|
onClick: onMoveUp
|
|
103
177
|
}),
|
|
104
178
|
/* @__PURE__ */ jsx(Button, {
|
|
105
179
|
size: "small",
|
|
106
180
|
icon: /* @__PURE__ */ jsx(ArrowDown, {}),
|
|
107
181
|
title: "Move selected down",
|
|
182
|
+
disabled,
|
|
108
183
|
onClick: onMoveDown
|
|
109
184
|
}),
|
|
110
185
|
/* @__PURE__ */ jsx(Button, {
|
|
@@ -112,6 +187,7 @@ const BulkActionsBar = ({ count, onDuplicate, onMoveUp, onMoveDown, onDelete, on
|
|
|
112
187
|
size: "small",
|
|
113
188
|
icon: /* @__PURE__ */ jsx(X, {}),
|
|
114
189
|
title: "Delete selected",
|
|
190
|
+
disabled,
|
|
115
191
|
onClick: onDelete
|
|
116
192
|
}),
|
|
117
193
|
/* @__PURE__ */ jsx(Button, {
|
|
@@ -126,58 +202,29 @@ const BulkActionsBar = ({ count, onDuplicate, onMoveUp, onMoveDown, onDelete, on
|
|
|
126
202
|
//#endregion
|
|
127
203
|
//#region src/components/dnd/panel/node.tsx
|
|
128
204
|
const Node = ({ data, onChange }) => {
|
|
129
|
-
const
|
|
130
|
-
|
|
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;
|
|
205
|
+
const source = resolvePanelBindings(data);
|
|
206
|
+
if (!source) return null;
|
|
135
207
|
return /* @__PURE__ */ jsx("div", {
|
|
136
208
|
className: "space-y-2 rounded",
|
|
137
209
|
children: /* @__PURE__ */ jsx("div", {
|
|
138
210
|
className: "space-y-1",
|
|
139
|
-
children: bindings.map((binding) => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
|
211
|
+
children: withPanelCommit(source.bindings, onChange).map((binding) => /* @__PURE__ */ jsxs("div", {
|
|
212
|
+
className: "space-y-1",
|
|
213
|
+
children: [/* @__PURE__ */ jsxs("label", {
|
|
214
|
+
className: "block text-xs font-semibold text-gray-700",
|
|
215
|
+
children: [binding.label, /* @__PURE__ */ jsxs("span", {
|
|
216
|
+
className: "ml-1 text-gray-400",
|
|
217
|
+
children: [
|
|
218
|
+
"(",
|
|
219
|
+
binding.property,
|
|
220
|
+
")"
|
|
221
|
+
]
|
|
178
222
|
})]
|
|
179
|
-
},
|
|
180
|
-
|
|
223
|
+
}), /* @__PURE__ */ jsx(Field, {
|
|
224
|
+
binding,
|
|
225
|
+
onNodeChange: onChange
|
|
226
|
+
})]
|
|
227
|
+
}, `${binding.id}-${binding.property}`))
|
|
181
228
|
})
|
|
182
229
|
});
|
|
183
230
|
};
|
|
@@ -356,63 +403,7 @@ const Children$1 = ({ value, onChange, onNodeChange }) => {
|
|
|
356
403
|
});
|
|
357
404
|
};
|
|
358
405
|
//#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
|
|
407
406
|
//#region src/components/dnd/panel/use-items-editor.ts
|
|
408
|
-
const resolveLeaf = (render, key) => {
|
|
409
|
-
const leaf = render?.[key];
|
|
410
|
-
return leaf && "type" in leaf ? leaf : null;
|
|
411
|
-
};
|
|
412
|
-
const resolveMap = (render, key) => {
|
|
413
|
-
const leaf = render?.[key];
|
|
414
|
-
return leaf && !("type" in leaf) ? leaf : void 0;
|
|
415
|
-
};
|
|
416
407
|
const bindingsInJSX = (source) => {
|
|
417
408
|
const nodes = extract(source);
|
|
418
409
|
const container = nodes.find((n) => n.bindings?.some((b) => b.property === "children"));
|
|
@@ -512,8 +503,19 @@ const removeIds = (ids, indices) => {
|
|
|
512
503
|
};
|
|
513
504
|
const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
514
505
|
const { objectItems, primitiveItems, parseError } = useMemo(() => parseSource(value), [value]);
|
|
506
|
+
const canEditStructure = useMemo(() => canStructurallyEditArray(value), [value]);
|
|
507
|
+
const { reportError } = useDndEditOptions();
|
|
508
|
+
const reportErrorRef = useRef(reportError);
|
|
509
|
+
useEffect(() => {
|
|
510
|
+
reportErrorRef.current = reportError;
|
|
511
|
+
});
|
|
515
512
|
useEffect(() => {
|
|
516
|
-
if (parseError)
|
|
513
|
+
if (parseError) reportErrorRef.current({
|
|
514
|
+
type: "parse",
|
|
515
|
+
target: "items",
|
|
516
|
+
title: "Failed to parse items",
|
|
517
|
+
description: "Check the console for details."
|
|
518
|
+
});
|
|
517
519
|
}, [parseError]);
|
|
518
520
|
const kind = primitiveItems.length > 0 && objectItems.length === 0 ? "primitive" : "object";
|
|
519
521
|
const isPrimitive = kind === "primitive";
|
|
@@ -528,7 +530,11 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
528
530
|
const selection = useMultiSelect(isPrimitive ? primitiveItems.length : objectItems.length);
|
|
529
531
|
const commit = (next, nextIds) => {
|
|
530
532
|
if (next === null) {
|
|
531
|
-
|
|
533
|
+
reportError({
|
|
534
|
+
type: "items",
|
|
535
|
+
title: "Failed to update this item",
|
|
536
|
+
description: "The source was preserved. Structural edits require a dense array without spreads; use the code editor for unsupported syntax."
|
|
537
|
+
});
|
|
532
538
|
return false;
|
|
533
539
|
}
|
|
534
540
|
const parsed = parseSource(next);
|
|
@@ -557,70 +563,50 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
557
563
|
label: `item-${item.index}`,
|
|
558
564
|
property: item.type,
|
|
559
565
|
value: item.value ?? "",
|
|
560
|
-
rawValue: String(item.value ?? ""),
|
|
566
|
+
rawValue: item.type === "unknown" ? item.source : String(item.value ?? ""),
|
|
567
|
+
canEditValue: canLosslesslyEvaluateSource(item.source),
|
|
561
568
|
onChange: (next) => commit(updateArrayItemValue(value, item.elementIndex, next))
|
|
562
569
|
}
|
|
563
570
|
})) : objectItems.map((item) => {
|
|
564
571
|
const id = identity.ids[item.index] ?? item.id;
|
|
565
572
|
const properties = Object.entries(item.editableProperties).map(([key, prop]) => {
|
|
566
|
-
const
|
|
573
|
+
const binding = resolveRenderEntry(render, key);
|
|
574
|
+
const propertySource = value.slice(prop.astNode.start, prop.astNode.end);
|
|
567
575
|
return {
|
|
576
|
+
...toBindingFields(binding),
|
|
568
577
|
id: `item-${id}-${key}`,
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
578
|
+
meta: {
|
|
579
|
+
...binding.meta,
|
|
580
|
+
valueType: prop.type
|
|
581
|
+
},
|
|
573
582
|
value: parseValue(String(prop.value)),
|
|
574
|
-
rawValue: String(prop.value),
|
|
575
|
-
|
|
583
|
+
rawValue: prop.type === "unknown" ? propertySource : String(prop.value),
|
|
584
|
+
canEditValue: canLosslesslyEvaluateSource(propertySource),
|
|
576
585
|
onChange: (next) => updateProperty(item.elementIndex, key, next)
|
|
577
586
|
};
|
|
578
587
|
});
|
|
579
588
|
const nested = [...Object.entries(item.jsxBindings).map(([property, nodes]) => ({
|
|
580
589
|
property,
|
|
581
590
|
elements: nodes.flatMap((node) => {
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
if (!id || !attr) return [];
|
|
585
|
-
const parsed = node.bindings ?? parseBinding(attr);
|
|
586
|
-
if (!parsed.length) return [];
|
|
591
|
+
const source = resolvePanelBindings(node);
|
|
592
|
+
if (!source) return [];
|
|
587
593
|
return [{
|
|
588
|
-
id,
|
|
589
|
-
tagName:
|
|
590
|
-
bindings:
|
|
591
|
-
id,
|
|
592
|
-
label: binding.label,
|
|
593
|
-
property: binding.property,
|
|
594
|
-
type: binding.type,
|
|
595
|
-
widget: binding.widget,
|
|
596
|
-
options: binding.options,
|
|
597
|
-
render: binding.render,
|
|
598
|
-
min: binding.min,
|
|
599
|
-
max: binding.max,
|
|
600
|
-
pattern: binding.pattern,
|
|
601
|
-
required: binding.required,
|
|
602
|
-
meta: binding.meta,
|
|
603
|
-
value: getStructuredValue(node, binding.property, binding.type),
|
|
604
|
-
rawValue: getCurrentValue(node, binding.property),
|
|
605
|
-
onChange: (next) => onNodeChange?.({
|
|
606
|
-
id,
|
|
607
|
-
label: binding.label,
|
|
608
|
-
property: binding.property,
|
|
609
|
-
value: next
|
|
610
|
-
})
|
|
611
|
-
}))
|
|
594
|
+
id: source.id,
|
|
595
|
+
tagName: source.tagName,
|
|
596
|
+
bindings: withPanelCommit(source.bindings, onNodeChange)
|
|
612
597
|
}];
|
|
613
598
|
})
|
|
614
599
|
})), ...Object.entries(item.jsxFallbacks).map(([property, code]) => ({
|
|
615
600
|
property,
|
|
616
601
|
elements: [],
|
|
617
602
|
fallback: {
|
|
618
|
-
id: `item-${
|
|
603
|
+
id: `item-${id}-${property}-jsx`,
|
|
619
604
|
label: property,
|
|
620
605
|
property,
|
|
621
606
|
type: "jsx",
|
|
622
607
|
value: code,
|
|
623
608
|
rawValue: code,
|
|
609
|
+
canEditValue: true,
|
|
624
610
|
onChange: (next) => updateProperty(item.elementIndex, property, next)
|
|
625
611
|
}
|
|
626
612
|
}))];
|
|
@@ -670,6 +656,7 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
670
656
|
if (commit(removeArrayItems(value, elementIndicesOf(selection.selected), kind), removeIds(identity.ids, selection.selected))) selection.clear();
|
|
671
657
|
}
|
|
672
658
|
},
|
|
659
|
+
canEditStructure,
|
|
673
660
|
parseError
|
|
674
661
|
};
|
|
675
662
|
};
|
|
@@ -732,7 +719,7 @@ const NestedGroup = ({ group, onNodeChange }) => {
|
|
|
732
719
|
});
|
|
733
720
|
};
|
|
734
721
|
const Items = ({ value, render, onChange, onChildChange }) => {
|
|
735
|
-
const { kind, items, selection, actions, parseError } = useItemsEditor(value, {
|
|
722
|
+
const { kind, items, selection, actions, canEditStructure, parseError } = useItemsEditor(value, {
|
|
736
723
|
render,
|
|
737
724
|
onChange,
|
|
738
725
|
onNodeChange: onChildChange
|
|
@@ -746,7 +733,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
746
733
|
items.length,
|
|
747
734
|
")"
|
|
748
735
|
]
|
|
749
|
-
}), items.length > 0 && /* @__PURE__ */ jsx(Button, {
|
|
736
|
+
}), items.length > 0 && canEditStructure && /* @__PURE__ */ jsx(Button, {
|
|
750
737
|
size: "small",
|
|
751
738
|
icon: /* @__PURE__ */ jsx(Plus, {}),
|
|
752
739
|
variant: "solid",
|
|
@@ -771,6 +758,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
771
758
|
});
|
|
772
759
|
const bulkBar = /* @__PURE__ */ jsx(BulkActionsBar, {
|
|
773
760
|
count: selection.selected.size,
|
|
761
|
+
disabled: !canEditStructure,
|
|
774
762
|
onDuplicate: actions.duplicateSelected,
|
|
775
763
|
onMoveUp: () => actions.moveSelected("up"),
|
|
776
764
|
onMoveDown: () => actions.moveSelected("down"),
|
|
@@ -783,20 +771,20 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
783
771
|
/* @__PURE__ */ jsx(Button, {
|
|
784
772
|
size: "small",
|
|
785
773
|
icon: /* @__PURE__ */ jsx(ArrowUp, {}),
|
|
786
|
-
disabled: item.index === 0,
|
|
774
|
+
disabled: !canEditStructure || item.index === 0,
|
|
787
775
|
onClick: () => actions.move(item.elementIndex, item.index - 1)
|
|
788
776
|
}),
|
|
789
777
|
/* @__PURE__ */ jsx(Button, {
|
|
790
778
|
size: "small",
|
|
791
779
|
icon: /* @__PURE__ */ jsx(ArrowDown, {}),
|
|
792
|
-
disabled: item.index === items.length - 1,
|
|
780
|
+
disabled: !canEditStructure || item.index === items.length - 1,
|
|
793
781
|
onClick: () => actions.move(item.elementIndex, item.index + 1)
|
|
794
782
|
}),
|
|
795
783
|
/* @__PURE__ */ jsx(Button, {
|
|
796
784
|
danger: true,
|
|
797
785
|
size: "small",
|
|
798
786
|
icon: /* @__PURE__ */ jsx(X, {}),
|
|
799
|
-
disabled: items.length <= 1,
|
|
787
|
+
disabled: !canEditStructure || items.length <= 1,
|
|
800
788
|
onClick: () => actions.remove(item.elementIndex)
|
|
801
789
|
})
|
|
802
790
|
]
|
|
@@ -806,15 +794,20 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
806
794
|
children: [
|
|
807
795
|
header,
|
|
808
796
|
bulkBar,
|
|
797
|
+
!canEditStructure && /* @__PURE__ */ jsx("div", {
|
|
798
|
+
className: "rounded border border-dashed border-amber-200 p-3 text-xs\n text-amber-700",
|
|
799
|
+
children: "Values remain editable, but moving, copying, adding, and deleting require a dense array without spreads or parenthesized top-level items. Use the code editor for those structural changes."
|
|
800
|
+
}),
|
|
809
801
|
items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
810
802
|
className: "space-y-2 rounded border border-gray-100 bg-gray-50 p-2",
|
|
811
803
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
812
804
|
className: "flex items-center justify-between space-x-1",
|
|
813
805
|
children: [/* @__PURE__ */ jsx("div", {
|
|
814
|
-
onClick: (e) => selection.toggle(item.index, e.shiftKey),
|
|
806
|
+
onClick: (e) => canEditStructure && selection.toggle(item.index, e.shiftKey),
|
|
815
807
|
className: "inline-flex",
|
|
816
808
|
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
817
809
|
checked: selection.isSelected(item.index),
|
|
810
|
+
disabled: !canEditStructure,
|
|
818
811
|
onChange: () => {}
|
|
819
812
|
})
|
|
820
813
|
}), itemControls(item)]
|
|
@@ -830,6 +823,10 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
830
823
|
children: [
|
|
831
824
|
header,
|
|
832
825
|
bulkBar,
|
|
826
|
+
!canEditStructure && /* @__PURE__ */ jsx("div", {
|
|
827
|
+
className: "rounded border border-dashed border-amber-200 p-3 text-xs\n text-amber-700",
|
|
828
|
+
children: "Values remain editable, but moving, copying, adding, and deleting require a dense array without spreads or parenthesized top-level items. Use the code editor for those structural changes."
|
|
829
|
+
}),
|
|
833
830
|
items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
834
831
|
className: "space-y-3 rounded border bg-gray-50 p-3",
|
|
835
832
|
children: [
|
|
@@ -838,10 +835,11 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
838
835
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
839
836
|
className: "flex items-center space-x-2",
|
|
840
837
|
children: [/* @__PURE__ */ jsx("div", {
|
|
841
|
-
onClick: (e) => selection.toggle(item.index, e.shiftKey),
|
|
838
|
+
onClick: (e) => canEditStructure && selection.toggle(item.index, e.shiftKey),
|
|
842
839
|
className: "inline-flex",
|
|
843
840
|
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
844
841
|
checked: selection.isSelected(item.index),
|
|
842
|
+
disabled: !canEditStructure,
|
|
845
843
|
onChange: () => {}
|
|
846
844
|
})
|
|
847
845
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -914,6 +912,36 @@ const RICHTEXT_TOOLBAR = [
|
|
|
914
912
|
"orderedList",
|
|
915
913
|
"link"
|
|
916
914
|
];
|
|
915
|
+
const JSXEditorField = ({ value, isHTML, onSave }) => {
|
|
916
|
+
const selectionRef = useRef(null);
|
|
917
|
+
const focusedRef = useRef(false);
|
|
918
|
+
const handleUpdate = useCallback((update) => {
|
|
919
|
+
selectionRef.current = update.state.selection;
|
|
920
|
+
}, []);
|
|
921
|
+
const handleCreateEditor = useCallback((view) => {
|
|
922
|
+
if (selectionRef.current) view.dispatch({ selection: selectionRef.current });
|
|
923
|
+
if (focusedRef.current) view.focus();
|
|
924
|
+
}, []);
|
|
925
|
+
const handleFocus = useCallback(() => {
|
|
926
|
+
focusedRef.current = true;
|
|
927
|
+
}, []);
|
|
928
|
+
const handleBlur = useCallback((event) => {
|
|
929
|
+
if (event.relatedTarget && !event.currentTarget.contains(event.relatedTarget)) focusedRef.current = false;
|
|
930
|
+
}, []);
|
|
931
|
+
return /* @__PURE__ */ jsx("div", {
|
|
932
|
+
onFocusCapture: handleFocus,
|
|
933
|
+
onBlurCapture: handleBlur,
|
|
934
|
+
children: /* @__PURE__ */ jsx(Core, {
|
|
935
|
+
value,
|
|
936
|
+
height: "150px",
|
|
937
|
+
fragment: !isHTML,
|
|
938
|
+
raw: isHTML,
|
|
939
|
+
onSave,
|
|
940
|
+
onUpdate: handleUpdate,
|
|
941
|
+
onCreateEditor: handleCreateEditor
|
|
942
|
+
})
|
|
943
|
+
});
|
|
944
|
+
};
|
|
917
945
|
const ColorPickerField = ({ value, onChange }) => {
|
|
918
946
|
const [liveValue, setLiveValue] = useState(value);
|
|
919
947
|
const [prevValue, setPrevValue] = useState(value);
|
|
@@ -946,7 +974,7 @@ const ColorPickerField = ({ value, onChange }) => {
|
|
|
946
974
|
}
|
|
947
975
|
});
|
|
948
976
|
};
|
|
949
|
-
const
|
|
977
|
+
const BuiltinField = ({ binding, onNodeChange }) => {
|
|
950
978
|
const { id, value, rawValue, onChange } = binding;
|
|
951
979
|
const [validationError, setValidationError] = useState(null);
|
|
952
980
|
const [text, setText] = useState(rawValue);
|
|
@@ -955,6 +983,17 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
955
983
|
setPrevRawValue(rawValue);
|
|
956
984
|
setText(rawValue);
|
|
957
985
|
}
|
|
986
|
+
if (binding.canEditValue === false) return /* @__PURE__ */ jsxs("div", {
|
|
987
|
+
className: "space-y-1 rounded border border-dashed border-amber-200 p-3\n text-xs text-amber-700",
|
|
988
|
+
children: [
|
|
989
|
+
/* @__PURE__ */ jsx("div", { children: "This expression is preserved but is not editable here." }),
|
|
990
|
+
/* @__PURE__ */ jsx("code", {
|
|
991
|
+
className: "block overflow-x-auto text-amber-800",
|
|
992
|
+
children: rawValue
|
|
993
|
+
}),
|
|
994
|
+
/* @__PURE__ */ jsx("div", { children: "Use the code editor to change it." })
|
|
995
|
+
]
|
|
996
|
+
});
|
|
958
997
|
const commitIfChanged = (next) => {
|
|
959
998
|
if (next !== (typeof next === "string" ? rawValue : value)) onChange(next);
|
|
960
999
|
};
|
|
@@ -971,11 +1010,9 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
971
1010
|
});
|
|
972
1011
|
if (binding.property === BINDING_PROP.INNER_HTML || binding.type === "jsx") {
|
|
973
1012
|
const isHTML = binding.property === BINDING_PROP.INNER_HTML;
|
|
974
|
-
return /* @__PURE__ */ jsx(
|
|
1013
|
+
return /* @__PURE__ */ jsx(JSXEditorField, {
|
|
975
1014
|
value: rawValue,
|
|
976
|
-
|
|
977
|
-
fragment: !isHTML,
|
|
978
|
-
raw: isHTML,
|
|
1015
|
+
isHTML,
|
|
979
1016
|
onSave: commitIfChanged
|
|
980
1017
|
});
|
|
981
1018
|
}
|
|
@@ -988,30 +1025,30 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
988
1025
|
const objectValue = value;
|
|
989
1026
|
return /* @__PURE__ */ jsx("div", {
|
|
990
1027
|
className: "space-y-2 rounded border border-gray-200 bg-gray-50 p-2",
|
|
991
|
-
children: Object.entries(objectValue).map(([key, val]) =>
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
className: "
|
|
995
|
-
children:
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
})
|
|
1014
|
-
}
|
|
1028
|
+
children: Object.entries(objectValue).map(([key, val]) => {
|
|
1029
|
+
const nested = resolveRenderEntry(binding.render, key);
|
|
1030
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1031
|
+
className: "space-y-1",
|
|
1032
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
1033
|
+
className: "block text-xs font-medium text-gray-600",
|
|
1034
|
+
children: nested.label
|
|
1035
|
+
}), /* @__PURE__ */ jsx(Field, {
|
|
1036
|
+
binding: {
|
|
1037
|
+
...toBindingFields(nested),
|
|
1038
|
+
id,
|
|
1039
|
+
value: val,
|
|
1040
|
+
rawValue: typeof val === "object" && val !== null ? JSON.stringify(val) : String(val),
|
|
1041
|
+
onChange: (next) => {
|
|
1042
|
+
onChange({
|
|
1043
|
+
...objectValue,
|
|
1044
|
+
[key]: next
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
},
|
|
1048
|
+
onNodeChange
|
|
1049
|
+
})]
|
|
1050
|
+
}, key);
|
|
1051
|
+
})
|
|
1015
1052
|
});
|
|
1016
1053
|
}
|
|
1017
1054
|
if (binding.type === "boolean" || typeof value === "boolean") return /* @__PURE__ */ jsx(Checkbox, {
|
|
@@ -1065,61 +1102,6 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
1065
1102
|
className: "mt-1 text-xs text-red-500",
|
|
1066
1103
|
children: validationError
|
|
1067
1104
|
})] });
|
|
1068
|
-
if (binding.widget === "icon-picker" || binding.type === "icon-picker") {
|
|
1069
|
-
const SelectedIcon = ICON_MAP[stringValue];
|
|
1070
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1071
|
-
className: "flex items-center gap-2",
|
|
1072
|
-
children: [/* @__PURE__ */ jsx(Select, {
|
|
1073
|
-
value: stringValue,
|
|
1074
|
-
options: ICON_OPTIONS,
|
|
1075
|
-
onChange: commitIfChanged
|
|
1076
|
-
}), SelectedIcon && /* @__PURE__ */ jsx(SelectedIcon, {
|
|
1077
|
-
size: 18,
|
|
1078
|
-
className: "shrink-0"
|
|
1079
|
-
})]
|
|
1080
|
-
});
|
|
1081
|
-
}
|
|
1082
|
-
if (binding.widget === "asset-picker" || binding.type === "asset-picker") {
|
|
1083
|
-
const defaultUploadValue = stringValue ? [{
|
|
1084
|
-
uid: "current",
|
|
1085
|
-
name: stringValue.split("/").pop() || "asset",
|
|
1086
|
-
url: stringValue
|
|
1087
|
-
}] : [];
|
|
1088
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1089
|
-
className: "space-y-2",
|
|
1090
|
-
children: [
|
|
1091
|
-
/* @__PURE__ */ jsx(Input, {
|
|
1092
|
-
value: text,
|
|
1093
|
-
onChange: (e) => setText(e.target.value),
|
|
1094
|
-
placeholder: "Enter an image URL",
|
|
1095
|
-
onBlur: (e) => {
|
|
1096
|
-
const next = e.target.value.trim();
|
|
1097
|
-
const result = validateBindingValue(binding, next);
|
|
1098
|
-
if (!result.valid) {
|
|
1099
|
-
setValidationError(result.message ?? "Invalid value.");
|
|
1100
|
-
return;
|
|
1101
|
-
}
|
|
1102
|
-
setValidationError(null);
|
|
1103
|
-
commitIfChanged(next);
|
|
1104
|
-
}
|
|
1105
|
-
}),
|
|
1106
|
-
/* @__PURE__ */ jsx(Upload, {
|
|
1107
|
-
multiple: false,
|
|
1108
|
-
maxCount: 1,
|
|
1109
|
-
accept: "image/*",
|
|
1110
|
-
defaultValue: defaultUploadValue,
|
|
1111
|
-
onChange: (files) => {
|
|
1112
|
-
const next = files[0]?.url ?? "";
|
|
1113
|
-
commitIfChanged(next);
|
|
1114
|
-
}
|
|
1115
|
-
}),
|
|
1116
|
-
validationError && /* @__PURE__ */ jsx("p", {
|
|
1117
|
-
className: "mt-1 text-xs text-red-500",
|
|
1118
|
-
children: validationError
|
|
1119
|
-
})
|
|
1120
|
-
]
|
|
1121
|
-
});
|
|
1122
|
-
}
|
|
1123
1105
|
if (binding.type === "number" || typeof value === "number") return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Input, {
|
|
1124
1106
|
type: "number",
|
|
1125
1107
|
value: text,
|
|
@@ -1160,6 +1142,13 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
1160
1142
|
children: validationError
|
|
1161
1143
|
})] });
|
|
1162
1144
|
};
|
|
1145
|
+
const Field = (props) => {
|
|
1146
|
+
const { renderField } = useDndEditOptions();
|
|
1147
|
+
const builtin = /* @__PURE__ */ jsx(BuiltinField, { ...props });
|
|
1148
|
+
if (!renderField) return builtin;
|
|
1149
|
+
const custom = renderField(props, builtin);
|
|
1150
|
+
return custom === void 0 ? builtin : /* @__PURE__ */ jsx(Fragment, { children: custom });
|
|
1151
|
+
};
|
|
1163
1152
|
//#endregion
|
|
1164
1153
|
//#region src/components/dnd/panel/field-group.tsx
|
|
1165
1154
|
const FieldGroup = ({ bindings, onNodeChange }) => /* @__PURE__ */ jsx("div", {
|
|
@@ -1351,16 +1340,59 @@ const Layout = ({ palette, panel }) => {
|
|
|
1351
1340
|
] });
|
|
1352
1341
|
};
|
|
1353
1342
|
//#endregion
|
|
1343
|
+
//#region src/components/dnd/section-fallback-context.ts
|
|
1344
|
+
const SectionFallbackContext = createContext(void 0);
|
|
1345
|
+
//#endregion
|
|
1346
|
+
//#region src/components/dnd/section-fallback.tsx
|
|
1347
|
+
const ConsumerFallback = ({ render, args, builtin }) => {
|
|
1348
|
+
const node = render(args);
|
|
1349
|
+
return node === void 0 ? builtin : /* @__PURE__ */ jsx(Fragment, { children: node });
|
|
1350
|
+
};
|
|
1351
|
+
const SectionFallback = ({ args, builtin }) => {
|
|
1352
|
+
const render = useContext(SectionFallbackContext);
|
|
1353
|
+
if (!render) return builtin;
|
|
1354
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
1355
|
+
fallback: () => builtin,
|
|
1356
|
+
children: /* @__PURE__ */ jsx(ConsumerFallback, {
|
|
1357
|
+
render,
|
|
1358
|
+
args,
|
|
1359
|
+
builtin
|
|
1360
|
+
})
|
|
1361
|
+
});
|
|
1362
|
+
};
|
|
1363
|
+
//#endregion
|
|
1354
1364
|
//#region src/components/dnd/renderer.tsx
|
|
1355
|
-
const Renderer = ({ preview, headers, modules, frame, dynamicTailwind = false, provider }) => {
|
|
1356
|
-
const module = useCompiledModule(preview, modules);
|
|
1357
|
-
const
|
|
1365
|
+
const Renderer = ({ preview, sectionId = "", sectionName = "", sectionCode = preview, forceFallback = false, headers, modules, frame, dynamicTailwind = false, provider }) => {
|
|
1366
|
+
const module = useCompiledModule(forceFallback ? "" : preview, modules);
|
|
1367
|
+
const section = {
|
|
1368
|
+
id: sectionId,
|
|
1369
|
+
name: sectionName,
|
|
1370
|
+
code: sectionCode
|
|
1371
|
+
};
|
|
1372
|
+
const { ref: wrapperRef, css: dynamicCSS } = useDynamicTailwind(preview, dynamicTailwind && !forceFallback);
|
|
1358
1373
|
const renderProvider = (component) => {
|
|
1359
1374
|
return provider ? provider(component) : component;
|
|
1360
1375
|
};
|
|
1361
|
-
if (
|
|
1362
|
-
|
|
1363
|
-
|
|
1376
|
+
if (forceFallback) return /* @__PURE__ */ jsx(SectionFallback, {
|
|
1377
|
+
args: {
|
|
1378
|
+
section,
|
|
1379
|
+
reason: "forced"
|
|
1380
|
+
},
|
|
1381
|
+
builtin: /* @__PURE__ */ jsx(Error$1, {
|
|
1382
|
+
message: "This section is not rendered in this editor.",
|
|
1383
|
+
title: "Section Unavailable"
|
|
1384
|
+
})
|
|
1385
|
+
});
|
|
1386
|
+
if (module?.error) return /* @__PURE__ */ jsx(SectionFallback, {
|
|
1387
|
+
args: {
|
|
1388
|
+
section,
|
|
1389
|
+
reason: "compile",
|
|
1390
|
+
message: module.error
|
|
1391
|
+
},
|
|
1392
|
+
builtin: /* @__PURE__ */ jsx(Error$1, {
|
|
1393
|
+
message: module.error,
|
|
1394
|
+
title: "Compile Error"
|
|
1395
|
+
})
|
|
1364
1396
|
});
|
|
1365
1397
|
const Component = module?.exports?.default;
|
|
1366
1398
|
if (!Component) return null;
|
|
@@ -1373,6 +1405,18 @@ const Renderer = ({ preview, headers, modules, frame, dynamicTailwind = false, p
|
|
|
1373
1405
|
"data-editor-mode": true,
|
|
1374
1406
|
children: /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
1375
1407
|
resetKeys: [preview],
|
|
1408
|
+
fallback: (message, reset) => /* @__PURE__ */ jsx(SectionFallback, {
|
|
1409
|
+
args: {
|
|
1410
|
+
section,
|
|
1411
|
+
reason: "runtime",
|
|
1412
|
+
message
|
|
1413
|
+
},
|
|
1414
|
+
builtin: /* @__PURE__ */ jsx(Error$1, {
|
|
1415
|
+
message,
|
|
1416
|
+
onReset: reset,
|
|
1417
|
+
title: "Rendering Error"
|
|
1418
|
+
})
|
|
1419
|
+
}),
|
|
1376
1420
|
children: renderProvider(/* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Component, {
|
|
1377
1421
|
headers,
|
|
1378
1422
|
container
|
|
@@ -1427,7 +1471,7 @@ const Sortable = ({ id, children, selected, onClick, onDelete: _onDelete, onCopy
|
|
|
1427
1471
|
};
|
|
1428
1472
|
//#endregion
|
|
1429
1473
|
//#region src/components/dnd/overlay.tsx
|
|
1430
|
-
const Overlay = ({ sections, renderProps }) => {
|
|
1474
|
+
const Overlay = ({ sections, isForced, renderProps }) => {
|
|
1431
1475
|
const { active } = useDndContext();
|
|
1432
1476
|
if (!active) return null;
|
|
1433
1477
|
if (active.data.current?.type === "new-item") {
|
|
@@ -1442,6 +1486,10 @@ const Overlay = ({ sections, renderProps }) => {
|
|
|
1442
1486
|
name: section.name,
|
|
1443
1487
|
children: /* @__PURE__ */ jsx(renderer_default, {
|
|
1444
1488
|
preview,
|
|
1489
|
+
sectionId: section.id,
|
|
1490
|
+
sectionName: section.name,
|
|
1491
|
+
sectionCode: section.code,
|
|
1492
|
+
forceFallback: isForced?.(section) ?? false,
|
|
1445
1493
|
modules: renderProps.modules,
|
|
1446
1494
|
frame: renderProps.frame,
|
|
1447
1495
|
dynamicTailwind: renderProps.dynamicTailwind
|
|
@@ -1558,6 +1606,10 @@ const describeUpdateFailure = (failure, label) => {
|
|
|
1558
1606
|
title: `Failed to update "${label}"`,
|
|
1559
1607
|
description: "The target element could not be found in this section."
|
|
1560
1608
|
};
|
|
1609
|
+
case "unsupported-syntax": return {
|
|
1610
|
+
title: `Cannot edit "${label}" in the panel`,
|
|
1611
|
+
description: `The "${failure.property}" expression was preserved. Change it in the code editor instead.`
|
|
1612
|
+
};
|
|
1561
1613
|
case "parse-error": return {
|
|
1562
1614
|
title: `Failed to update "${label}"`,
|
|
1563
1615
|
description: failure.error instanceof Error ? failure.error.message : "Check the console for details."
|
|
@@ -1570,11 +1622,19 @@ const conditionalModifiers = (args) => {
|
|
|
1570
1622
|
if (active?.data.current?.type === "new-item") return args.transform;
|
|
1571
1623
|
return restrictToVerticalAxis(args);
|
|
1572
1624
|
};
|
|
1573
|
-
const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, className, items = [], frame, dynamicTailwind = false, provider, children, ...restProps }) => {
|
|
1625
|
+
const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, className, items = [], frame, dynamicTailwind = false, provider, renderField, onEditError, renderSectionFallback, shouldForceSectionFallback, children, ...restProps }) => {
|
|
1574
1626
|
const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);
|
|
1575
1627
|
const { breakpoint } = useResponsiveSize();
|
|
1576
1628
|
const isMobile = breakpoint.current === "xs" || breakpoint.current === "sm";
|
|
1577
1629
|
const { code } = usePreview();
|
|
1630
|
+
const isForced = (section) => {
|
|
1631
|
+
try {
|
|
1632
|
+
return shouldForceSectionFallback?.(section) === true;
|
|
1633
|
+
} catch (error) {
|
|
1634
|
+
console.error("shouldForceSectionFallback threw", error);
|
|
1635
|
+
return false;
|
|
1636
|
+
}
|
|
1637
|
+
};
|
|
1578
1638
|
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 10 } }));
|
|
1579
1639
|
const value = _value === void 0 ? code : _value;
|
|
1580
1640
|
const { sections, previews, selectedId, selectedItem, selectedIndex, select, clearSelection, add: addItem, remove: onDelete, copy: onCopy, move: moveSection, reorder, patch } = useSectionDocument(value, _onChange);
|
|
@@ -1601,32 +1661,49 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1601
1661
|
if (!selectedCode) return {
|
|
1602
1662
|
fields: [],
|
|
1603
1663
|
updatedCode: "",
|
|
1604
|
-
parseError:
|
|
1664
|
+
parseError: null
|
|
1605
1665
|
};
|
|
1606
1666
|
try {
|
|
1607
1667
|
const updated = fillIds(selectedCode);
|
|
1608
1668
|
return {
|
|
1609
1669
|
fields: extract(updated).filter((node) => node.tagName !== "section"),
|
|
1610
1670
|
updatedCode: updated !== selectedCode ? updated : selectedCode,
|
|
1611
|
-
parseError:
|
|
1671
|
+
parseError: null
|
|
1612
1672
|
};
|
|
1613
1673
|
} catch (e) {
|
|
1614
1674
|
console.warn("⚠️ Parsing error", e);
|
|
1615
1675
|
return {
|
|
1616
1676
|
fields: [],
|
|
1617
1677
|
updatedCode: "",
|
|
1618
|
-
parseError:
|
|
1678
|
+
parseError: { error: e }
|
|
1619
1679
|
};
|
|
1620
1680
|
}
|
|
1621
1681
|
}, [selectedCode]);
|
|
1682
|
+
const reportError = onEditError ?? toastEditError;
|
|
1683
|
+
const reportErrorRef = useRef(reportError);
|
|
1684
|
+
useEffect(() => {
|
|
1685
|
+
reportErrorRef.current = reportError;
|
|
1686
|
+
});
|
|
1622
1687
|
useEffect(() => {
|
|
1623
|
-
if (parseError)
|
|
1688
|
+
if (parseError) reportErrorRef.current({
|
|
1689
|
+
type: "parse",
|
|
1690
|
+
target: "section",
|
|
1691
|
+
error: parseError.error,
|
|
1692
|
+
title: "Failed to parse this section",
|
|
1693
|
+
description: "Check the console for details."
|
|
1694
|
+
});
|
|
1624
1695
|
}, [parseError]);
|
|
1625
1696
|
const onFieldChange = ({ id, label, property, value: fieldValue }) => {
|
|
1626
1697
|
const result = update(updatedCode, id, label, fieldValue, property);
|
|
1627
1698
|
if (!result.success) {
|
|
1628
|
-
|
|
1629
|
-
|
|
1699
|
+
reportError({
|
|
1700
|
+
type: "update",
|
|
1701
|
+
id,
|
|
1702
|
+
label,
|
|
1703
|
+
property,
|
|
1704
|
+
failure: result.failure,
|
|
1705
|
+
...describeUpdateFailure(result.failure, label)
|
|
1706
|
+
});
|
|
1630
1707
|
return;
|
|
1631
1708
|
}
|
|
1632
1709
|
if (selectedItem) onChange({
|
|
@@ -1634,37 +1711,8 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1634
1711
|
code: result.code
|
|
1635
1712
|
});
|
|
1636
1713
|
};
|
|
1637
|
-
const
|
|
1638
|
-
|
|
1639
|
-
const dataId = node.dataAttributes.find((a) => a.name === "data-id")?.value;
|
|
1640
|
-
const bindingAttr = node.dataAttributes.find((a) => a.name === "data-binding")?.value;
|
|
1641
|
-
if (!dataId || !bindingAttr) return [];
|
|
1642
|
-
return (node.bindings ?? parseBinding(bindingAttr)).map((binding) => ({
|
|
1643
|
-
id: dataId,
|
|
1644
|
-
label: binding.label,
|
|
1645
|
-
property: binding.property,
|
|
1646
|
-
type: binding.type,
|
|
1647
|
-
widget: binding.widget,
|
|
1648
|
-
options: binding.options,
|
|
1649
|
-
render: binding.render,
|
|
1650
|
-
min: binding.min,
|
|
1651
|
-
max: binding.max,
|
|
1652
|
-
pattern: binding.pattern,
|
|
1653
|
-
required: binding.required,
|
|
1654
|
-
meta: binding.meta,
|
|
1655
|
-
value: getStructuredValue(node, binding.property, binding.type),
|
|
1656
|
-
rawValue: getCurrentValue(node, binding.property)
|
|
1657
|
-
}));
|
|
1658
|
-
});
|
|
1659
|
-
}, [fields]).map((field) => ({
|
|
1660
|
-
...field,
|
|
1661
|
-
onChange: (value) => onFieldChange({
|
|
1662
|
-
id: field.id,
|
|
1663
|
-
label: field.label,
|
|
1664
|
-
property: field.property,
|
|
1665
|
-
value
|
|
1666
|
-
})
|
|
1667
|
-
}));
|
|
1714
|
+
const bindingFields = useMemo(() => fields.flatMap((node) => resolvePanelBindings(node)?.bindings ?? []), [fields]);
|
|
1715
|
+
const bindings = withPanelCommit(bindingFields, onFieldChange);
|
|
1668
1716
|
useEffect(() => {
|
|
1669
1717
|
if (frame?.scripts?.length) preloadScripts(frame.scripts);
|
|
1670
1718
|
}, [frame?.scripts]);
|
|
@@ -1707,6 +1755,10 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1707
1755
|
onCopy,
|
|
1708
1756
|
children: /* @__PURE__ */ jsx(renderer_default, {
|
|
1709
1757
|
preview: previews[index],
|
|
1758
|
+
sectionId: section.id,
|
|
1759
|
+
sectionName: section.name,
|
|
1760
|
+
sectionCode: section.code,
|
|
1761
|
+
forceFallback: isForced(section),
|
|
1710
1762
|
modules,
|
|
1711
1763
|
frame,
|
|
1712
1764
|
dynamicTailwind,
|
|
@@ -1716,40 +1768,50 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1716
1768
|
}, section.id))
|
|
1717
1769
|
})
|
|
1718
1770
|
}) });
|
|
1719
|
-
return /* @__PURE__ */ jsx(
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
|
-
|
|
1771
|
+
return /* @__PURE__ */ jsx(SectionFallbackContext.Provider, {
|
|
1772
|
+
value: renderSectionFallback,
|
|
1773
|
+
children: /* @__PURE__ */ jsxs(DndContext, {
|
|
1774
|
+
sensors,
|
|
1775
|
+
collisionDetection: closestCenter,
|
|
1776
|
+
modifiers: [conditionalModifiers],
|
|
1777
|
+
onDragStart,
|
|
1778
|
+
onDragOver,
|
|
1779
|
+
onDragEnd,
|
|
1780
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1781
|
+
className: cn("relative flex h-full w-full", className),
|
|
1782
|
+
...restProps,
|
|
1783
|
+
children: /* @__PURE__ */ jsx(DndEditOptionsContext.Provider, {
|
|
1784
|
+
value: {
|
|
1785
|
+
renderField,
|
|
1786
|
+
reportError
|
|
1787
|
+
},
|
|
1788
|
+
children: /* @__PURE__ */ jsx(DndRegionContext.Provider, {
|
|
1789
|
+
value: {
|
|
1790
|
+
palette,
|
|
1791
|
+
panel,
|
|
1792
|
+
canvas,
|
|
1793
|
+
isMobile,
|
|
1794
|
+
selectedId,
|
|
1795
|
+
clearSelection,
|
|
1796
|
+
paletteOpen: mobilePaletteOpen,
|
|
1797
|
+
setPaletteOpen: setMobilePaletteOpen
|
|
1798
|
+
},
|
|
1799
|
+
children: Children.toArray(children).length ? children : /* @__PURE__ */ jsx(Layout, {})
|
|
1800
|
+
})
|
|
1801
|
+
})
|
|
1802
|
+
}), /* @__PURE__ */ jsx(DragOverlay, { children: /* @__PURE__ */ jsx(Overlay, {
|
|
1803
|
+
sections,
|
|
1804
|
+
isForced,
|
|
1805
|
+
renderProps: {
|
|
1806
|
+
fullCode: value,
|
|
1807
|
+
modules,
|
|
1808
|
+
frame,
|
|
1809
|
+
dynamicTailwind,
|
|
1810
|
+
...props
|
|
1811
|
+
}
|
|
1812
|
+
}) })]
|
|
1813
|
+
})
|
|
1814
|
+
});
|
|
1753
1815
|
};
|
|
1754
1816
|
//#endregion
|
|
1755
1817
|
//#region src/components/dnd/index.ts
|
|
@@ -1761,6 +1823,6 @@ Dnd.Canvas = Canvas;
|
|
|
1761
1823
|
Dnd.Panel = Panel;
|
|
1762
1824
|
Dnd.Layout = Layout;
|
|
1763
1825
|
//#endregion
|
|
1764
|
-
export { Panel as a,
|
|
1826
|
+
export { Panel as a, useChildrenEditor as c, useDndPanel as d, DraggableItem as f, Palette as i, useDndLayout as l, Canvas as n, Field as o, Layout as r, useItemsEditor as s, Dnd as t, useDndPalette as u };
|
|
1765
1827
|
|
|
1766
|
-
//# sourceMappingURL=dnd-
|
|
1828
|
+
//# sourceMappingURL=dnd-ClnGRNaY.js.map
|