@jbpark/live-editor 3.2.1 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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-D3q5rpuz.js.map → core-Co8Nlq16.js.map} +1 -1
- package/dist/dnd/index.d.ts +2 -2
- package/dist/dnd/index.js +2 -2
- package/dist/{dnd-D90jLjLH.js → dnd-_0jfnnVB.js} +419 -338
- package/dist/dnd-_0jfnnVB.js.map +1 -0
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.js +2 -2
- package/dist/editor-aNRx7hRY.js +66 -0
- package/dist/editor-aNRx7hRY.js.map +1 -0
- 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-BQdZ6LrR.d.ts → index-13BDSrQc.d.ts} +2 -2
- 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 +8 -8
- 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 +4 -2
- 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/dnd-D90jLjLH.js.map +0 -1
- package/dist/document-C6bNHl7l.js.map +0 -1
- package/dist/editor-LzqHe_-F.js +0 -51
- package/dist/editor-LzqHe_-F.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,77 +202,92 @@ 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
|
};
|
|
184
231
|
//#endregion
|
|
232
|
+
//#region src/components/dnd/panel/use-structural-selection.ts
|
|
233
|
+
const selectionAfter = (command, selected, count) => {
|
|
234
|
+
switch (command.type) {
|
|
235
|
+
case "append":
|
|
236
|
+
case "duplicate": return new Set(selected);
|
|
237
|
+
case "move-selected": return moveSelectedIndices(Array.from({ length: count }, (_, index) => index), new Set(command.indices), command.direction).indices;
|
|
238
|
+
default: return /* @__PURE__ */ new Set();
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const useStructuralSelection = (count, revision) => {
|
|
242
|
+
const selection = useMultiSelect(count);
|
|
243
|
+
const [seen, setSeen] = useState(revision);
|
|
244
|
+
const [pending, setPending] = useState(null);
|
|
245
|
+
if (revision !== seen) {
|
|
246
|
+
setSeen(revision);
|
|
247
|
+
setPending(null);
|
|
248
|
+
if (pending?.matches(revision) && pending.selection.size > 0) selection.replace(pending.selection);
|
|
249
|
+
else selection.clear();
|
|
250
|
+
}
|
|
251
|
+
const record = (next, matches, { now = false } = {}) => {
|
|
252
|
+
setPending({
|
|
253
|
+
matches,
|
|
254
|
+
selection: next
|
|
255
|
+
});
|
|
256
|
+
if (!now) return;
|
|
257
|
+
if (next.size > 0) selection.replace(next);
|
|
258
|
+
else selection.clear();
|
|
259
|
+
};
|
|
260
|
+
return {
|
|
261
|
+
selection,
|
|
262
|
+
record
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
//#endregion
|
|
185
266
|
//#region src/components/dnd/panel/use-children-editor.ts
|
|
267
|
+
const producedBy = (expected, action) => {
|
|
268
|
+
if (action.type === "move-selected") {
|
|
269
|
+
const moved = JSON.stringify(moveSelectedIndices(expected, new Set(action.indices), action.direction).items);
|
|
270
|
+
return (revision) => revision === moved;
|
|
271
|
+
}
|
|
272
|
+
const added = action.type === "append" ? 1 : action.type === "duplicate" ? action.indices.length : 0;
|
|
273
|
+
return (revision) => {
|
|
274
|
+
const next = JSON.parse(revision);
|
|
275
|
+
return next.length === expected.length + added && expected.every((signature, index) => next[index] === signature);
|
|
276
|
+
};
|
|
277
|
+
};
|
|
186
278
|
const useChildrenEditor = (items, { onChange } = {}) => {
|
|
187
|
-
const selection = useMultiSelect(items.length);
|
|
188
279
|
const expected = useMemo(() => getChildrenSignatures(items), [items]);
|
|
189
280
|
const revision = JSON.stringify(expected);
|
|
190
|
-
const
|
|
191
|
-
useEffect(() => {
|
|
192
|
-
clear();
|
|
193
|
-
}, [revision, clear]);
|
|
281
|
+
const { selection, record } = useStructuralSelection(items.length, revision);
|
|
194
282
|
const commit = (action) => {
|
|
195
|
-
|
|
283
|
+
const edit = {
|
|
196
284
|
kind: "children-edit",
|
|
197
285
|
expected,
|
|
198
286
|
action
|
|
199
|
-
}
|
|
287
|
+
};
|
|
288
|
+
const next = selectionAfter(action, selection.selected, items.length);
|
|
289
|
+
if (next.size > 0) record(next, producedBy(expected, action));
|
|
290
|
+
onChange?.(JSON.stringify(edit));
|
|
200
291
|
};
|
|
201
292
|
return {
|
|
202
293
|
items,
|
|
@@ -356,63 +447,7 @@ const Children$1 = ({ value, onChange, onNodeChange }) => {
|
|
|
356
447
|
});
|
|
357
448
|
};
|
|
358
449
|
//#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
450
|
//#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
451
|
const bindingsInJSX = (source) => {
|
|
417
452
|
const nodes = extract(source);
|
|
418
453
|
const container = nodes.find((n) => n.bindings?.some((b) => b.property === "children"));
|
|
@@ -512,8 +547,19 @@ const removeIds = (ids, indices) => {
|
|
|
512
547
|
};
|
|
513
548
|
const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
514
549
|
const { objectItems, primitiveItems, parseError } = useMemo(() => parseSource(value), [value]);
|
|
550
|
+
const canEditStructure = useMemo(() => canStructurallyEditArray(value), [value]);
|
|
551
|
+
const { reportError } = useDndEditOptions();
|
|
552
|
+
const reportErrorRef = useRef(reportError);
|
|
553
|
+
useEffect(() => {
|
|
554
|
+
reportErrorRef.current = reportError;
|
|
555
|
+
});
|
|
515
556
|
useEffect(() => {
|
|
516
|
-
if (parseError)
|
|
557
|
+
if (parseError) reportErrorRef.current({
|
|
558
|
+
type: "parse",
|
|
559
|
+
target: "items",
|
|
560
|
+
title: "Failed to parse items",
|
|
561
|
+
description: "Check the console for details."
|
|
562
|
+
});
|
|
517
563
|
}, [parseError]);
|
|
518
564
|
const kind = primitiveItems.length > 0 && objectItems.length === 0 ? "primitive" : "object";
|
|
519
565
|
const isPrimitive = kind === "primitive";
|
|
@@ -525,16 +571,21 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
525
571
|
rawItems,
|
|
526
572
|
value
|
|
527
573
|
]);
|
|
528
|
-
const selection =
|
|
529
|
-
const commit = (next, nextIds) => {
|
|
574
|
+
const { selection, record } = useStructuralSelection(isPrimitive ? primitiveItems.length : objectItems.length, value);
|
|
575
|
+
const commit = (next, nextIds, nextSelection) => {
|
|
530
576
|
if (next === null) {
|
|
531
|
-
|
|
577
|
+
reportError({
|
|
578
|
+
type: "items",
|
|
579
|
+
title: "Failed to update this item",
|
|
580
|
+
description: "The source was preserved. Structural edits require a dense array without spreads; use the code editor for unsupported syntax."
|
|
581
|
+
});
|
|
532
582
|
return false;
|
|
533
583
|
}
|
|
534
584
|
const parsed = parseSource(next);
|
|
535
585
|
const nextItems = kind === "primitive" ? parsed.primitiveItems : parsed.objectItems;
|
|
536
586
|
if (nextIds) setIdentityState(createIdentityState(next, kind, nextItems, nextIds));
|
|
537
587
|
else setIdentityState(createIdentityState(next, kind, nextItems, identity.ids));
|
|
588
|
+
record(nextSelection, (revision) => revision === next, { now: true });
|
|
538
589
|
onChange?.(next);
|
|
539
590
|
return true;
|
|
540
591
|
};
|
|
@@ -542,7 +593,7 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
542
593
|
return new Set((isPrimitive ? primitiveItems : objectItems).filter((item) => indices.has(item.index)).map((item) => item.elementIndex));
|
|
543
594
|
};
|
|
544
595
|
const updateProperty = (elementIndex, propertyKey, next) => {
|
|
545
|
-
commit(updateArrayItemProperty(value, elementIndex, propertyKey, next, render));
|
|
596
|
+
commit(updateArrayItemProperty(value, elementIndex, propertyKey, next, render), void 0, new Set(selection.selected));
|
|
546
597
|
};
|
|
547
598
|
return {
|
|
548
599
|
kind,
|
|
@@ -557,58 +608,37 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
557
608
|
label: `item-${item.index}`,
|
|
558
609
|
property: item.type,
|
|
559
610
|
value: item.value ?? "",
|
|
560
|
-
rawValue: String(item.value ?? ""),
|
|
561
|
-
|
|
611
|
+
rawValue: item.type === "unknown" ? item.source : String(item.value ?? ""),
|
|
612
|
+
canEditValue: canLosslesslyEvaluateSource(item.source),
|
|
613
|
+
onChange: (next) => commit(updateArrayItemValue(value, item.elementIndex, next), void 0, new Set(selection.selected))
|
|
562
614
|
}
|
|
563
615
|
})) : objectItems.map((item) => {
|
|
564
616
|
const id = identity.ids[item.index] ?? item.id;
|
|
565
617
|
const properties = Object.entries(item.editableProperties).map(([key, prop]) => {
|
|
566
|
-
const
|
|
618
|
+
const binding = resolveRenderEntry(render, key);
|
|
619
|
+
const propertySource = value.slice(prop.astNode.start, prop.astNode.end);
|
|
567
620
|
return {
|
|
621
|
+
...toBindingFields(binding),
|
|
568
622
|
id: `item-${id}-${key}`,
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
623
|
+
meta: {
|
|
624
|
+
...binding.meta,
|
|
625
|
+
valueType: prop.type
|
|
626
|
+
},
|
|
573
627
|
value: parseValue(String(prop.value)),
|
|
574
|
-
rawValue: String(prop.value),
|
|
575
|
-
|
|
628
|
+
rawValue: prop.type === "unknown" ? propertySource : String(prop.value),
|
|
629
|
+
canEditValue: canLosslesslyEvaluateSource(propertySource),
|
|
576
630
|
onChange: (next) => updateProperty(item.elementIndex, key, next)
|
|
577
631
|
};
|
|
578
632
|
});
|
|
579
633
|
const nested = [...Object.entries(item.jsxBindings).map(([property, nodes]) => ({
|
|
580
634
|
property,
|
|
581
635
|
elements: nodes.flatMap((node) => {
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
if (!id || !attr) return [];
|
|
585
|
-
const parsed = node.bindings ?? parseBinding(attr);
|
|
586
|
-
if (!parsed.length) return [];
|
|
636
|
+
const source = resolvePanelBindings(node);
|
|
637
|
+
if (!source) return [];
|
|
587
638
|
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
|
-
}))
|
|
639
|
+
id: source.id,
|
|
640
|
+
tagName: source.tagName,
|
|
641
|
+
bindings: withPanelCommit(source.bindings, onNodeChange)
|
|
612
642
|
}];
|
|
613
643
|
})
|
|
614
644
|
})), ...Object.entries(item.jsxFallbacks).map(([property, code]) => ({
|
|
@@ -621,6 +651,7 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
621
651
|
type: "jsx",
|
|
622
652
|
value: code,
|
|
623
653
|
rawValue: code,
|
|
654
|
+
canEditValue: true,
|
|
624
655
|
onChange: (next) => updateProperty(item.elementIndex, property, next)
|
|
625
656
|
}
|
|
626
657
|
}))];
|
|
@@ -636,40 +667,43 @@ const useItemsEditor = (value, { render, onChange, onNodeChange } = {}) => {
|
|
|
636
667
|
actions: {
|
|
637
668
|
add: () => {
|
|
638
669
|
const next = appendArrayItem(value, kind);
|
|
639
|
-
commit(next, next ? [...identity.ids, nanoid(6)] : void 0);
|
|
670
|
+
commit(next, next ? [...identity.ids, nanoid(6)] : void 0, selectionAfter({ type: "append" }, selection.selected, rawItems.length));
|
|
640
671
|
},
|
|
641
672
|
move: (elementIndex, toIndex) => {
|
|
642
673
|
const items = isPrimitive ? primitiveItems : objectItems;
|
|
643
674
|
const from = items.find((item) => item.elementIndex === elementIndex);
|
|
644
675
|
const target = items.find((item) => item.index === toIndex);
|
|
645
676
|
if (!from || !target) return;
|
|
646
|
-
|
|
677
|
+
commit(moveArrayItem(value, elementIndex, target.elementIndex), moveId(identity.ids, from.index, target.index), /* @__PURE__ */ new Set());
|
|
647
678
|
},
|
|
648
679
|
remove: (elementIndex) => {
|
|
649
680
|
const removed = (isPrimitive ? primitiveItems : objectItems).find((item) => item.elementIndex === elementIndex);
|
|
650
|
-
|
|
681
|
+
commit(removeArrayItems(value, /* @__PURE__ */ new Set([elementIndex]), kind), removed ? removeIds(identity.ids, /* @__PURE__ */ new Set([removed.index])) : void 0, /* @__PURE__ */ new Set());
|
|
651
682
|
},
|
|
652
683
|
duplicateSelected: () => {
|
|
653
684
|
const selected = elementIndicesOf(selection.selected);
|
|
654
685
|
const next = duplicateArrayItems(value, selected);
|
|
655
686
|
const copied = rawItems.filter((item) => selected.has(item.elementIndex)).sort((a, b) => a.elementIndex - b.elementIndex).map(() => nanoid(6));
|
|
656
|
-
commit(next, next ? [...identity.ids, ...copied] : void 0
|
|
687
|
+
commit(next, next ? [...identity.ids, ...copied] : void 0, selectionAfter({
|
|
688
|
+
type: "duplicate",
|
|
689
|
+
indices: [...selection.selected]
|
|
690
|
+
}, selection.selected, rawItems.length));
|
|
657
691
|
},
|
|
658
692
|
moveSelected: (direction) => {
|
|
659
693
|
const nextIdentity = moveSelectedIndices(identity.ids, selection.selected, direction);
|
|
660
694
|
const result = moveArrayItems(value, elementIndicesOf(selection.selected), direction);
|
|
661
695
|
if (!result) {
|
|
662
|
-
commit(null);
|
|
696
|
+
commit(null, void 0, selection.selected);
|
|
663
697
|
return;
|
|
664
698
|
}
|
|
665
699
|
const visible = parseArrayExpression(result.code)?.elements.flatMap((node, index) => import_lib.isExpression(node) && import_lib.isObjectExpression(node) === !isPrimitive ? [index] : []) ?? [];
|
|
666
|
-
|
|
667
|
-
commit(result.code, nextIdentity.items);
|
|
700
|
+
commit(result.code, nextIdentity.items, new Set(visible.flatMap((position, index) => result.indices.has(position) ? [index] : [])));
|
|
668
701
|
},
|
|
669
702
|
removeSelected: () => {
|
|
670
|
-
|
|
703
|
+
commit(removeArrayItems(value, elementIndicesOf(selection.selected), kind), removeIds(identity.ids, selection.selected), /* @__PURE__ */ new Set());
|
|
671
704
|
}
|
|
672
705
|
},
|
|
706
|
+
canEditStructure,
|
|
673
707
|
parseError
|
|
674
708
|
};
|
|
675
709
|
};
|
|
@@ -732,7 +766,7 @@ const NestedGroup = ({ group, onNodeChange }) => {
|
|
|
732
766
|
});
|
|
733
767
|
};
|
|
734
768
|
const Items = ({ value, render, onChange, onChildChange }) => {
|
|
735
|
-
const { kind, items, selection, actions, parseError } = useItemsEditor(value, {
|
|
769
|
+
const { kind, items, selection, actions, canEditStructure, parseError } = useItemsEditor(value, {
|
|
736
770
|
render,
|
|
737
771
|
onChange,
|
|
738
772
|
onNodeChange: onChildChange
|
|
@@ -746,7 +780,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
746
780
|
items.length,
|
|
747
781
|
")"
|
|
748
782
|
]
|
|
749
|
-
}), items.length > 0 && /* @__PURE__ */ jsx(Button, {
|
|
783
|
+
}), items.length > 0 && canEditStructure && /* @__PURE__ */ jsx(Button, {
|
|
750
784
|
size: "small",
|
|
751
785
|
icon: /* @__PURE__ */ jsx(Plus, {}),
|
|
752
786
|
variant: "solid",
|
|
@@ -771,6 +805,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
771
805
|
});
|
|
772
806
|
const bulkBar = /* @__PURE__ */ jsx(BulkActionsBar, {
|
|
773
807
|
count: selection.selected.size,
|
|
808
|
+
disabled: !canEditStructure,
|
|
774
809
|
onDuplicate: actions.duplicateSelected,
|
|
775
810
|
onMoveUp: () => actions.moveSelected("up"),
|
|
776
811
|
onMoveDown: () => actions.moveSelected("down"),
|
|
@@ -783,20 +818,20 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
783
818
|
/* @__PURE__ */ jsx(Button, {
|
|
784
819
|
size: "small",
|
|
785
820
|
icon: /* @__PURE__ */ jsx(ArrowUp, {}),
|
|
786
|
-
disabled: item.index === 0,
|
|
821
|
+
disabled: !canEditStructure || item.index === 0,
|
|
787
822
|
onClick: () => actions.move(item.elementIndex, item.index - 1)
|
|
788
823
|
}),
|
|
789
824
|
/* @__PURE__ */ jsx(Button, {
|
|
790
825
|
size: "small",
|
|
791
826
|
icon: /* @__PURE__ */ jsx(ArrowDown, {}),
|
|
792
|
-
disabled: item.index === items.length - 1,
|
|
827
|
+
disabled: !canEditStructure || item.index === items.length - 1,
|
|
793
828
|
onClick: () => actions.move(item.elementIndex, item.index + 1)
|
|
794
829
|
}),
|
|
795
830
|
/* @__PURE__ */ jsx(Button, {
|
|
796
831
|
danger: true,
|
|
797
832
|
size: "small",
|
|
798
833
|
icon: /* @__PURE__ */ jsx(X, {}),
|
|
799
|
-
disabled: items.length <= 1,
|
|
834
|
+
disabled: !canEditStructure || items.length <= 1,
|
|
800
835
|
onClick: () => actions.remove(item.elementIndex)
|
|
801
836
|
})
|
|
802
837
|
]
|
|
@@ -806,15 +841,20 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
806
841
|
children: [
|
|
807
842
|
header,
|
|
808
843
|
bulkBar,
|
|
844
|
+
!canEditStructure && /* @__PURE__ */ jsx("div", {
|
|
845
|
+
className: "rounded border border-dashed border-amber-200 p-3 text-xs\n text-amber-700",
|
|
846
|
+
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."
|
|
847
|
+
}),
|
|
809
848
|
items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
810
849
|
className: "space-y-2 rounded border border-gray-100 bg-gray-50 p-2",
|
|
811
850
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
812
851
|
className: "flex items-center justify-between space-x-1",
|
|
813
852
|
children: [/* @__PURE__ */ jsx("div", {
|
|
814
|
-
onClick: (e) => selection.toggle(item.index, e.shiftKey),
|
|
853
|
+
onClick: (e) => canEditStructure && selection.toggle(item.index, e.shiftKey),
|
|
815
854
|
className: "inline-flex",
|
|
816
855
|
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
817
856
|
checked: selection.isSelected(item.index),
|
|
857
|
+
disabled: !canEditStructure,
|
|
818
858
|
onChange: () => {}
|
|
819
859
|
})
|
|
820
860
|
}), itemControls(item)]
|
|
@@ -830,6 +870,10 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
830
870
|
children: [
|
|
831
871
|
header,
|
|
832
872
|
bulkBar,
|
|
873
|
+
!canEditStructure && /* @__PURE__ */ jsx("div", {
|
|
874
|
+
className: "rounded border border-dashed border-amber-200 p-3 text-xs\n text-amber-700",
|
|
875
|
+
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."
|
|
876
|
+
}),
|
|
833
877
|
items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
834
878
|
className: "space-y-3 rounded border bg-gray-50 p-3",
|
|
835
879
|
children: [
|
|
@@ -838,10 +882,11 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
838
882
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
839
883
|
className: "flex items-center space-x-2",
|
|
840
884
|
children: [/* @__PURE__ */ jsx("div", {
|
|
841
|
-
onClick: (e) => selection.toggle(item.index, e.shiftKey),
|
|
885
|
+
onClick: (e) => canEditStructure && selection.toggle(item.index, e.shiftKey),
|
|
842
886
|
className: "inline-flex",
|
|
843
887
|
children: /* @__PURE__ */ jsx(Checkbox, {
|
|
844
888
|
checked: selection.isSelected(item.index),
|
|
889
|
+
disabled: !canEditStructure,
|
|
845
890
|
onChange: () => {}
|
|
846
891
|
})
|
|
847
892
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -976,7 +1021,7 @@ const ColorPickerField = ({ value, onChange }) => {
|
|
|
976
1021
|
}
|
|
977
1022
|
});
|
|
978
1023
|
};
|
|
979
|
-
const
|
|
1024
|
+
const BuiltinField = ({ binding, onNodeChange }) => {
|
|
980
1025
|
const { id, value, rawValue, onChange } = binding;
|
|
981
1026
|
const [validationError, setValidationError] = useState(null);
|
|
982
1027
|
const [text, setText] = useState(rawValue);
|
|
@@ -985,6 +1030,17 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
985
1030
|
setPrevRawValue(rawValue);
|
|
986
1031
|
setText(rawValue);
|
|
987
1032
|
}
|
|
1033
|
+
if (binding.canEditValue === false) return /* @__PURE__ */ jsxs("div", {
|
|
1034
|
+
className: "space-y-1 rounded border border-dashed border-amber-200 p-3\n text-xs text-amber-700",
|
|
1035
|
+
children: [
|
|
1036
|
+
/* @__PURE__ */ jsx("div", { children: "This expression is preserved but is not editable here." }),
|
|
1037
|
+
/* @__PURE__ */ jsx("code", {
|
|
1038
|
+
className: "block overflow-x-auto text-amber-800",
|
|
1039
|
+
children: rawValue
|
|
1040
|
+
}),
|
|
1041
|
+
/* @__PURE__ */ jsx("div", { children: "Use the code editor to change it." })
|
|
1042
|
+
]
|
|
1043
|
+
});
|
|
988
1044
|
const commitIfChanged = (next) => {
|
|
989
1045
|
if (next !== (typeof next === "string" ? rawValue : value)) onChange(next);
|
|
990
1046
|
};
|
|
@@ -1016,30 +1072,30 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
1016
1072
|
const objectValue = value;
|
|
1017
1073
|
return /* @__PURE__ */ jsx("div", {
|
|
1018
1074
|
className: "space-y-2 rounded border border-gray-200 bg-gray-50 p-2",
|
|
1019
|
-
children: Object.entries(objectValue).map(([key, val]) =>
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
className: "
|
|
1023
|
-
children:
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
})
|
|
1042
|
-
}
|
|
1075
|
+
children: Object.entries(objectValue).map(([key, val]) => {
|
|
1076
|
+
const nested = resolveRenderEntry(binding.render, key);
|
|
1077
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1078
|
+
className: "space-y-1",
|
|
1079
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
1080
|
+
className: "block text-xs font-medium text-gray-600",
|
|
1081
|
+
children: nested.label
|
|
1082
|
+
}), /* @__PURE__ */ jsx(Field, {
|
|
1083
|
+
binding: {
|
|
1084
|
+
...toBindingFields(nested),
|
|
1085
|
+
id,
|
|
1086
|
+
value: val,
|
|
1087
|
+
rawValue: typeof val === "object" && val !== null ? JSON.stringify(val) : String(val),
|
|
1088
|
+
onChange: (next) => {
|
|
1089
|
+
onChange({
|
|
1090
|
+
...objectValue,
|
|
1091
|
+
[key]: next
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
},
|
|
1095
|
+
onNodeChange
|
|
1096
|
+
})]
|
|
1097
|
+
}, key);
|
|
1098
|
+
})
|
|
1043
1099
|
});
|
|
1044
1100
|
}
|
|
1045
1101
|
if (binding.type === "boolean" || typeof value === "boolean") return /* @__PURE__ */ jsx(Checkbox, {
|
|
@@ -1093,61 +1149,6 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
1093
1149
|
className: "mt-1 text-xs text-red-500",
|
|
1094
1150
|
children: validationError
|
|
1095
1151
|
})] });
|
|
1096
|
-
if (binding.widget === "icon-picker" || binding.type === "icon-picker") {
|
|
1097
|
-
const SelectedIcon = ICON_MAP[stringValue];
|
|
1098
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1099
|
-
className: "flex items-center gap-2",
|
|
1100
|
-
children: [/* @__PURE__ */ jsx(Select, {
|
|
1101
|
-
value: stringValue,
|
|
1102
|
-
options: ICON_OPTIONS,
|
|
1103
|
-
onChange: commitIfChanged
|
|
1104
|
-
}), SelectedIcon && /* @__PURE__ */ jsx(SelectedIcon, {
|
|
1105
|
-
size: 18,
|
|
1106
|
-
className: "shrink-0"
|
|
1107
|
-
})]
|
|
1108
|
-
});
|
|
1109
|
-
}
|
|
1110
|
-
if (binding.widget === "asset-picker" || binding.type === "asset-picker") {
|
|
1111
|
-
const defaultUploadValue = stringValue ? [{
|
|
1112
|
-
uid: "current",
|
|
1113
|
-
name: stringValue.split("/").pop() || "asset",
|
|
1114
|
-
url: stringValue
|
|
1115
|
-
}] : [];
|
|
1116
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1117
|
-
className: "space-y-2",
|
|
1118
|
-
children: [
|
|
1119
|
-
/* @__PURE__ */ jsx(Input, {
|
|
1120
|
-
value: text,
|
|
1121
|
-
onChange: (e) => setText(e.target.value),
|
|
1122
|
-
placeholder: "Enter an image URL",
|
|
1123
|
-
onBlur: (e) => {
|
|
1124
|
-
const next = e.target.value.trim();
|
|
1125
|
-
const result = validateBindingValue(binding, next);
|
|
1126
|
-
if (!result.valid) {
|
|
1127
|
-
setValidationError(result.message ?? "Invalid value.");
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
setValidationError(null);
|
|
1131
|
-
commitIfChanged(next);
|
|
1132
|
-
}
|
|
1133
|
-
}),
|
|
1134
|
-
/* @__PURE__ */ jsx(Upload, {
|
|
1135
|
-
multiple: false,
|
|
1136
|
-
maxCount: 1,
|
|
1137
|
-
accept: "image/*",
|
|
1138
|
-
defaultValue: defaultUploadValue,
|
|
1139
|
-
onChange: (files) => {
|
|
1140
|
-
const next = files[0]?.url ?? "";
|
|
1141
|
-
commitIfChanged(next);
|
|
1142
|
-
}
|
|
1143
|
-
}),
|
|
1144
|
-
validationError && /* @__PURE__ */ jsx("p", {
|
|
1145
|
-
className: "mt-1 text-xs text-red-500",
|
|
1146
|
-
children: validationError
|
|
1147
|
-
})
|
|
1148
|
-
]
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
1152
|
if (binding.type === "number" || typeof value === "number") return /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Input, {
|
|
1152
1153
|
type: "number",
|
|
1153
1154
|
value: text,
|
|
@@ -1188,6 +1189,13 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
1188
1189
|
children: validationError
|
|
1189
1190
|
})] });
|
|
1190
1191
|
};
|
|
1192
|
+
const Field = (props) => {
|
|
1193
|
+
const { renderField } = useDndEditOptions();
|
|
1194
|
+
const builtin = /* @__PURE__ */ jsx(BuiltinField, { ...props });
|
|
1195
|
+
if (!renderField) return builtin;
|
|
1196
|
+
const custom = renderField(props, builtin);
|
|
1197
|
+
return custom === void 0 ? builtin : /* @__PURE__ */ jsx(Fragment, { children: custom });
|
|
1198
|
+
};
|
|
1191
1199
|
//#endregion
|
|
1192
1200
|
//#region src/components/dnd/panel/field-group.tsx
|
|
1193
1201
|
const FieldGroup = ({ bindings, onNodeChange }) => /* @__PURE__ */ jsx("div", {
|
|
@@ -1379,16 +1387,59 @@ const Layout = ({ palette, panel }) => {
|
|
|
1379
1387
|
] });
|
|
1380
1388
|
};
|
|
1381
1389
|
//#endregion
|
|
1390
|
+
//#region src/components/dnd/section-fallback-context.ts
|
|
1391
|
+
const SectionFallbackContext = createContext(void 0);
|
|
1392
|
+
//#endregion
|
|
1393
|
+
//#region src/components/dnd/section-fallback.tsx
|
|
1394
|
+
const ConsumerFallback = ({ render, args, builtin }) => {
|
|
1395
|
+
const node = render(args);
|
|
1396
|
+
return node === void 0 ? builtin : /* @__PURE__ */ jsx(Fragment, { children: node });
|
|
1397
|
+
};
|
|
1398
|
+
const SectionFallback = ({ args, builtin }) => {
|
|
1399
|
+
const render = useContext(SectionFallbackContext);
|
|
1400
|
+
if (!render) return builtin;
|
|
1401
|
+
return /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
1402
|
+
fallback: () => builtin,
|
|
1403
|
+
children: /* @__PURE__ */ jsx(ConsumerFallback, {
|
|
1404
|
+
render,
|
|
1405
|
+
args,
|
|
1406
|
+
builtin
|
|
1407
|
+
})
|
|
1408
|
+
});
|
|
1409
|
+
};
|
|
1410
|
+
//#endregion
|
|
1382
1411
|
//#region src/components/dnd/renderer.tsx
|
|
1383
|
-
const Renderer = ({ preview, headers, modules, frame, dynamicTailwind = false, provider }) => {
|
|
1384
|
-
const module = useCompiledModule(preview, modules);
|
|
1385
|
-
const
|
|
1412
|
+
const Renderer = ({ preview, sectionId = "", sectionName = "", sectionCode = preview, forceFallback = false, headers, modules, frame, dynamicTailwind = false, provider }) => {
|
|
1413
|
+
const module = useCompiledModule(forceFallback ? "" : preview, modules);
|
|
1414
|
+
const section = {
|
|
1415
|
+
id: sectionId,
|
|
1416
|
+
name: sectionName,
|
|
1417
|
+
code: sectionCode
|
|
1418
|
+
};
|
|
1419
|
+
const { ref: wrapperRef, css: dynamicCSS } = useDynamicTailwind(preview, dynamicTailwind && !forceFallback);
|
|
1386
1420
|
const renderProvider = (component) => {
|
|
1387
1421
|
return provider ? provider(component) : component;
|
|
1388
1422
|
};
|
|
1389
|
-
if (
|
|
1390
|
-
|
|
1391
|
-
|
|
1423
|
+
if (forceFallback) return /* @__PURE__ */ jsx(SectionFallback, {
|
|
1424
|
+
args: {
|
|
1425
|
+
section,
|
|
1426
|
+
reason: "forced"
|
|
1427
|
+
},
|
|
1428
|
+
builtin: /* @__PURE__ */ jsx(Error$1, {
|
|
1429
|
+
message: "This section is not rendered in this editor.",
|
|
1430
|
+
title: "Section Unavailable"
|
|
1431
|
+
})
|
|
1432
|
+
});
|
|
1433
|
+
if (module?.error) return /* @__PURE__ */ jsx(SectionFallback, {
|
|
1434
|
+
args: {
|
|
1435
|
+
section,
|
|
1436
|
+
reason: "compile",
|
|
1437
|
+
message: module.error
|
|
1438
|
+
},
|
|
1439
|
+
builtin: /* @__PURE__ */ jsx(Error$1, {
|
|
1440
|
+
message: module.error,
|
|
1441
|
+
title: "Compile Error"
|
|
1442
|
+
})
|
|
1392
1443
|
});
|
|
1393
1444
|
const Component = module?.exports?.default;
|
|
1394
1445
|
if (!Component) return null;
|
|
@@ -1401,6 +1452,18 @@ const Renderer = ({ preview, headers, modules, frame, dynamicTailwind = false, p
|
|
|
1401
1452
|
"data-editor-mode": true,
|
|
1402
1453
|
children: /* @__PURE__ */ jsx(ErrorBoundary, {
|
|
1403
1454
|
resetKeys: [preview],
|
|
1455
|
+
fallback: (message, reset) => /* @__PURE__ */ jsx(SectionFallback, {
|
|
1456
|
+
args: {
|
|
1457
|
+
section,
|
|
1458
|
+
reason: "runtime",
|
|
1459
|
+
message
|
|
1460
|
+
},
|
|
1461
|
+
builtin: /* @__PURE__ */ jsx(Error$1, {
|
|
1462
|
+
message,
|
|
1463
|
+
onReset: reset,
|
|
1464
|
+
title: "Rendering Error"
|
|
1465
|
+
})
|
|
1466
|
+
}),
|
|
1404
1467
|
children: renderProvider(/* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Component, {
|
|
1405
1468
|
headers,
|
|
1406
1469
|
container
|
|
@@ -1455,7 +1518,7 @@ const Sortable = ({ id, children, selected, onClick, onDelete: _onDelete, onCopy
|
|
|
1455
1518
|
};
|
|
1456
1519
|
//#endregion
|
|
1457
1520
|
//#region src/components/dnd/overlay.tsx
|
|
1458
|
-
const Overlay = ({ sections, renderProps }) => {
|
|
1521
|
+
const Overlay = ({ sections, isForced, renderProps }) => {
|
|
1459
1522
|
const { active } = useDndContext();
|
|
1460
1523
|
if (!active) return null;
|
|
1461
1524
|
if (active.data.current?.type === "new-item") {
|
|
@@ -1470,6 +1533,10 @@ const Overlay = ({ sections, renderProps }) => {
|
|
|
1470
1533
|
name: section.name,
|
|
1471
1534
|
children: /* @__PURE__ */ jsx(renderer_default, {
|
|
1472
1535
|
preview,
|
|
1536
|
+
sectionId: section.id,
|
|
1537
|
+
sectionName: section.name,
|
|
1538
|
+
sectionCode: section.code,
|
|
1539
|
+
forceFallback: isForced?.(section) ?? false,
|
|
1473
1540
|
modules: renderProps.modules,
|
|
1474
1541
|
frame: renderProps.frame,
|
|
1475
1542
|
dynamicTailwind: renderProps.dynamicTailwind
|
|
@@ -1586,6 +1653,10 @@ const describeUpdateFailure = (failure, label) => {
|
|
|
1586
1653
|
title: `Failed to update "${label}"`,
|
|
1587
1654
|
description: "The target element could not be found in this section."
|
|
1588
1655
|
};
|
|
1656
|
+
case "unsupported-syntax": return {
|
|
1657
|
+
title: `Cannot edit "${label}" in the panel`,
|
|
1658
|
+
description: `The "${failure.property}" expression was preserved. Change it in the code editor instead.`
|
|
1659
|
+
};
|
|
1589
1660
|
case "parse-error": return {
|
|
1590
1661
|
title: `Failed to update "${label}"`,
|
|
1591
1662
|
description: failure.error instanceof Error ? failure.error.message : "Check the console for details."
|
|
@@ -1598,11 +1669,19 @@ const conditionalModifiers = (args) => {
|
|
|
1598
1669
|
if (active?.data.current?.type === "new-item") return args.transform;
|
|
1599
1670
|
return restrictToVerticalAxis(args);
|
|
1600
1671
|
};
|
|
1601
|
-
const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, className, items = [], frame, dynamicTailwind = false, provider, children, ...restProps }) => {
|
|
1672
|
+
const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, className, items = [], frame, dynamicTailwind = false, provider, renderField, onEditError, renderSectionFallback, shouldForceSectionFallback, children, ...restProps }) => {
|
|
1602
1673
|
const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);
|
|
1603
1674
|
const { breakpoint } = useResponsiveSize();
|
|
1604
1675
|
const isMobile = breakpoint.current === "xs" || breakpoint.current === "sm";
|
|
1605
1676
|
const { code } = usePreview();
|
|
1677
|
+
const isForced = (section) => {
|
|
1678
|
+
try {
|
|
1679
|
+
return shouldForceSectionFallback?.(section) === true;
|
|
1680
|
+
} catch (error) {
|
|
1681
|
+
console.error("shouldForceSectionFallback threw", error);
|
|
1682
|
+
return false;
|
|
1683
|
+
}
|
|
1684
|
+
};
|
|
1606
1685
|
const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 10 } }));
|
|
1607
1686
|
const value = _value === void 0 ? code : _value;
|
|
1608
1687
|
const { sections, previews, selectedId, selectedItem, selectedIndex, select, clearSelection, add: addItem, remove: onDelete, copy: onCopy, move: moveSection, reorder, patch } = useSectionDocument(value, _onChange);
|
|
@@ -1629,32 +1708,49 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1629
1708
|
if (!selectedCode) return {
|
|
1630
1709
|
fields: [],
|
|
1631
1710
|
updatedCode: "",
|
|
1632
|
-
parseError:
|
|
1711
|
+
parseError: null
|
|
1633
1712
|
};
|
|
1634
1713
|
try {
|
|
1635
1714
|
const updated = fillIds(selectedCode);
|
|
1636
1715
|
return {
|
|
1637
1716
|
fields: extract(updated).filter((node) => node.tagName !== "section"),
|
|
1638
1717
|
updatedCode: updated !== selectedCode ? updated : selectedCode,
|
|
1639
|
-
parseError:
|
|
1718
|
+
parseError: null
|
|
1640
1719
|
};
|
|
1641
1720
|
} catch (e) {
|
|
1642
1721
|
console.warn("⚠️ Parsing error", e);
|
|
1643
1722
|
return {
|
|
1644
1723
|
fields: [],
|
|
1645
1724
|
updatedCode: "",
|
|
1646
|
-
parseError:
|
|
1725
|
+
parseError: { error: e }
|
|
1647
1726
|
};
|
|
1648
1727
|
}
|
|
1649
1728
|
}, [selectedCode]);
|
|
1729
|
+
const reportError = onEditError ?? toastEditError;
|
|
1730
|
+
const reportErrorRef = useRef(reportError);
|
|
1650
1731
|
useEffect(() => {
|
|
1651
|
-
|
|
1732
|
+
reportErrorRef.current = reportError;
|
|
1733
|
+
});
|
|
1734
|
+
useEffect(() => {
|
|
1735
|
+
if (parseError) reportErrorRef.current({
|
|
1736
|
+
type: "parse",
|
|
1737
|
+
target: "section",
|
|
1738
|
+
error: parseError.error,
|
|
1739
|
+
title: "Failed to parse this section",
|
|
1740
|
+
description: "Check the console for details."
|
|
1741
|
+
});
|
|
1652
1742
|
}, [parseError]);
|
|
1653
1743
|
const onFieldChange = ({ id, label, property, value: fieldValue }) => {
|
|
1654
1744
|
const result = update(updatedCode, id, label, fieldValue, property);
|
|
1655
1745
|
if (!result.success) {
|
|
1656
|
-
|
|
1657
|
-
|
|
1746
|
+
reportError({
|
|
1747
|
+
type: "update",
|
|
1748
|
+
id,
|
|
1749
|
+
label,
|
|
1750
|
+
property,
|
|
1751
|
+
failure: result.failure,
|
|
1752
|
+
...describeUpdateFailure(result.failure, label)
|
|
1753
|
+
});
|
|
1658
1754
|
return;
|
|
1659
1755
|
}
|
|
1660
1756
|
if (selectedItem) onChange({
|
|
@@ -1662,37 +1758,8 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1662
1758
|
code: result.code
|
|
1663
1759
|
});
|
|
1664
1760
|
};
|
|
1665
|
-
const
|
|
1666
|
-
|
|
1667
|
-
const dataId = node.dataAttributes.find((a) => a.name === "data-id")?.value;
|
|
1668
|
-
const bindingAttr = node.dataAttributes.find((a) => a.name === "data-binding")?.value;
|
|
1669
|
-
if (!dataId || !bindingAttr) return [];
|
|
1670
|
-
return (node.bindings ?? parseBinding(bindingAttr)).map((binding) => ({
|
|
1671
|
-
id: dataId,
|
|
1672
|
-
label: binding.label,
|
|
1673
|
-
property: binding.property,
|
|
1674
|
-
type: binding.type,
|
|
1675
|
-
widget: binding.widget,
|
|
1676
|
-
options: binding.options,
|
|
1677
|
-
render: binding.render,
|
|
1678
|
-
min: binding.min,
|
|
1679
|
-
max: binding.max,
|
|
1680
|
-
pattern: binding.pattern,
|
|
1681
|
-
required: binding.required,
|
|
1682
|
-
meta: binding.meta,
|
|
1683
|
-
value: getStructuredValue(node, binding.property, binding.type),
|
|
1684
|
-
rawValue: getCurrentValue(node, binding.property)
|
|
1685
|
-
}));
|
|
1686
|
-
});
|
|
1687
|
-
}, [fields]).map((field) => ({
|
|
1688
|
-
...field,
|
|
1689
|
-
onChange: (value) => onFieldChange({
|
|
1690
|
-
id: field.id,
|
|
1691
|
-
label: field.label,
|
|
1692
|
-
property: field.property,
|
|
1693
|
-
value
|
|
1694
|
-
})
|
|
1695
|
-
}));
|
|
1761
|
+
const bindingFields = useMemo(() => fields.flatMap((node) => resolvePanelBindings(node)?.bindings ?? []), [fields]);
|
|
1762
|
+
const bindings = withPanelCommit(bindingFields, onFieldChange);
|
|
1696
1763
|
useEffect(() => {
|
|
1697
1764
|
if (frame?.scripts?.length) preloadScripts(frame.scripts);
|
|
1698
1765
|
}, [frame?.scripts]);
|
|
@@ -1735,6 +1802,10 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1735
1802
|
onCopy,
|
|
1736
1803
|
children: /* @__PURE__ */ jsx(renderer_default, {
|
|
1737
1804
|
preview: previews[index],
|
|
1805
|
+
sectionId: section.id,
|
|
1806
|
+
sectionName: section.name,
|
|
1807
|
+
sectionCode: section.code,
|
|
1808
|
+
forceFallback: isForced(section),
|
|
1738
1809
|
modules,
|
|
1739
1810
|
frame,
|
|
1740
1811
|
dynamicTailwind,
|
|
@@ -1744,40 +1815,50 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1744
1815
|
}, section.id))
|
|
1745
1816
|
})
|
|
1746
1817
|
}) });
|
|
1747
|
-
return /* @__PURE__ */ jsx(
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
}
|
|
1779
|
-
|
|
1780
|
-
|
|
1818
|
+
return /* @__PURE__ */ jsx(SectionFallbackContext.Provider, {
|
|
1819
|
+
value: renderSectionFallback,
|
|
1820
|
+
children: /* @__PURE__ */ jsxs(DndContext, {
|
|
1821
|
+
sensors,
|
|
1822
|
+
collisionDetection: closestCenter,
|
|
1823
|
+
modifiers: [conditionalModifiers],
|
|
1824
|
+
onDragStart,
|
|
1825
|
+
onDragOver,
|
|
1826
|
+
onDragEnd,
|
|
1827
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1828
|
+
className: cn("relative flex h-full w-full", className),
|
|
1829
|
+
...restProps,
|
|
1830
|
+
children: /* @__PURE__ */ jsx(DndEditOptionsContext.Provider, {
|
|
1831
|
+
value: {
|
|
1832
|
+
renderField,
|
|
1833
|
+
reportError
|
|
1834
|
+
},
|
|
1835
|
+
children: /* @__PURE__ */ jsx(DndRegionContext.Provider, {
|
|
1836
|
+
value: {
|
|
1837
|
+
palette,
|
|
1838
|
+
panel,
|
|
1839
|
+
canvas,
|
|
1840
|
+
isMobile,
|
|
1841
|
+
selectedId,
|
|
1842
|
+
clearSelection,
|
|
1843
|
+
paletteOpen: mobilePaletteOpen,
|
|
1844
|
+
setPaletteOpen: setMobilePaletteOpen
|
|
1845
|
+
},
|
|
1846
|
+
children: Children.toArray(children).length ? children : /* @__PURE__ */ jsx(Layout, {})
|
|
1847
|
+
})
|
|
1848
|
+
})
|
|
1849
|
+
}), /* @__PURE__ */ jsx(DragOverlay, { children: /* @__PURE__ */ jsx(Overlay, {
|
|
1850
|
+
sections,
|
|
1851
|
+
isForced,
|
|
1852
|
+
renderProps: {
|
|
1853
|
+
fullCode: value,
|
|
1854
|
+
modules,
|
|
1855
|
+
frame,
|
|
1856
|
+
dynamicTailwind,
|
|
1857
|
+
...props
|
|
1858
|
+
}
|
|
1859
|
+
}) })]
|
|
1860
|
+
})
|
|
1861
|
+
});
|
|
1781
1862
|
};
|
|
1782
1863
|
//#endregion
|
|
1783
1864
|
//#region src/components/dnd/index.ts
|
|
@@ -1789,6 +1870,6 @@ Dnd.Canvas = Canvas;
|
|
|
1789
1870
|
Dnd.Panel = Panel;
|
|
1790
1871
|
Dnd.Layout = Layout;
|
|
1791
1872
|
//#endregion
|
|
1792
|
-
export { Panel as a,
|
|
1873
|
+
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 };
|
|
1793
1874
|
|
|
1794
|
-
//# sourceMappingURL=dnd-
|
|
1875
|
+
//# sourceMappingURL=dnd-_0jfnnVB.js.map
|