@nextbridgehq/payload-block-builder 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +250 -39
- package/dist/bin/init.js +79 -25
- package/dist/client.cjs +473 -302
- package/dist/client.d.cts +5 -1
- package/dist/client.d.ts +5 -1
- package/dist/client.js +308 -124
- package/dist/index.cjs +45 -15
- package/dist/index.js +45 -15
- package/package.json +2 -2
- package/src/components/BlockDataField/BlockDataField.css +170 -0
package/dist/client.cjs
CHANGED
|
@@ -32,6 +32,7 @@ var client_exports = {};
|
|
|
32
32
|
__export(client_exports, {
|
|
33
33
|
BlockBuilderNavLink: () => BlockBuilderNavLink,
|
|
34
34
|
BlockDataField: () => BlockDataField,
|
|
35
|
+
BlockVersionSync: () => BlockVersionSync,
|
|
35
36
|
BuilderShell: () => BuilderShell,
|
|
36
37
|
EditInBuilderButton: () => EditInBuilderButton,
|
|
37
38
|
SchemaBuilderField: () => SchemaBuilderField
|
|
@@ -77,6 +78,133 @@ function MediaPicker({ label, required, value, onChange }) {
|
|
|
77
78
|
"x"
|
|
78
79
|
))) : /* @__PURE__ */ import_react.default.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Choose from Media Library")), /* @__PURE__ */ import_react.default.createElement(ListDrawer, { onSelect: handleSelect }));
|
|
79
80
|
}
|
|
81
|
+
function toRelDoc(v) {
|
|
82
|
+
if (!v) return null;
|
|
83
|
+
if (typeof v === "object") {
|
|
84
|
+
const o = v;
|
|
85
|
+
if (!o.id) return null;
|
|
86
|
+
return { id: o.id, title: o.title ? String(o.title) : null };
|
|
87
|
+
}
|
|
88
|
+
if (typeof v === "string" || typeof v === "number") return { id: v, title: null };
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
function RelationshipPicker({ label, required, collection, hasMany = false, value, onChange }) {
|
|
92
|
+
const changeRef = (0, import_react.useRef)(onChange);
|
|
93
|
+
const closeRef = (0, import_react.useRef)(() => {
|
|
94
|
+
});
|
|
95
|
+
(0, import_react.useEffect)(() => {
|
|
96
|
+
changeRef.current = onChange;
|
|
97
|
+
});
|
|
98
|
+
const items = hasMany ? Array.isArray(value) ? value.map(toRelDoc).filter(Boolean) : [] : (() => {
|
|
99
|
+
const d = toRelDoc(value);
|
|
100
|
+
return d ? [d] : [];
|
|
101
|
+
})();
|
|
102
|
+
const itemsRef = (0, import_react.useRef)(items);
|
|
103
|
+
(0, import_react.useEffect)(() => {
|
|
104
|
+
itemsRef.current = items;
|
|
105
|
+
});
|
|
106
|
+
const handleSelect = (0, import_react.useCallback)(
|
|
107
|
+
({ docID, doc }) => {
|
|
108
|
+
const title = String(doc?.title ?? doc?.name ?? doc?.slug ?? "") || null;
|
|
109
|
+
const entry = { id: docID, title };
|
|
110
|
+
if (hasMany) {
|
|
111
|
+
const alreadyExists = itemsRef.current.some((i) => String(i.id) === String(docID));
|
|
112
|
+
if (!alreadyExists) changeRef.current([...itemsRef.current, entry]);
|
|
113
|
+
} else {
|
|
114
|
+
changeRef.current(entry);
|
|
115
|
+
closeRef.current();
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
[hasMany]
|
|
119
|
+
);
|
|
120
|
+
const [ListDrawer, ListDrawerToggler, { closeDrawer, openDrawer }] = (0, import_ui.useListDrawer)({
|
|
121
|
+
collectionSlugs: [collection]
|
|
122
|
+
});
|
|
123
|
+
closeRef.current = closeDrawer;
|
|
124
|
+
const [fetchedTitles, setFetchedTitles] = (0, import_react.useState)({});
|
|
125
|
+
const fetchingRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
126
|
+
(0, import_react.useEffect)(() => {
|
|
127
|
+
const missing = items.filter(
|
|
128
|
+
(i) => !i.title && !fetchedTitles[String(i.id)] && !fetchingRef.current.has(String(i.id))
|
|
129
|
+
);
|
|
130
|
+
if (missing.length === 0) return;
|
|
131
|
+
missing.forEach((item) => {
|
|
132
|
+
const idStr = String(item.id);
|
|
133
|
+
fetchingRef.current.add(idStr);
|
|
134
|
+
fetch(`/api/${collection}/${idStr}?depth=0`, { credentials: "same-origin" }).then((r) => r.ok ? r.json() : null).then((doc) => {
|
|
135
|
+
if (doc) {
|
|
136
|
+
const t = doc.title ?? doc.name ?? doc.slug ?? null;
|
|
137
|
+
if (t) setFetchedTitles((prev) => ({ ...prev, [idStr]: String(t) }));
|
|
138
|
+
}
|
|
139
|
+
}).catch(() => {
|
|
140
|
+
fetchingRef.current.delete(idStr);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
}, [items, collection]);
|
|
144
|
+
function getTitle(item) {
|
|
145
|
+
return item.title ?? fetchedTitles[String(item.id)] ?? `ID: ${String(item.id)}`;
|
|
146
|
+
}
|
|
147
|
+
function clearOne(e, id) {
|
|
148
|
+
e.stopPropagation();
|
|
149
|
+
if (hasMany) onChange(items.filter((i) => String(i.id) !== String(id)));
|
|
150
|
+
else onChange(null);
|
|
151
|
+
}
|
|
152
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-required" }, "*")), /* @__PURE__ */ import_react.default.createElement("div", { className: `bdf-rel${hasMany ? " bdf-rel--multi" : ""}` }, /* @__PURE__ */ import_react.default.createElement(
|
|
153
|
+
"div",
|
|
154
|
+
{
|
|
155
|
+
role: "button",
|
|
156
|
+
tabIndex: 0,
|
|
157
|
+
className: "bdf-rel__control",
|
|
158
|
+
onClick: openDrawer,
|
|
159
|
+
onKeyDown: (e) => {
|
|
160
|
+
if (e.key === "Enter" || e.key === " ") openDrawer();
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
/* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-rel__values" }, items.length === 0 && /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-rel__placeholder" }, "Select a value..."), !hasMany && items.length > 0 && /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-rel__single" }, getTitle(items[0])), hasMany && items.map((item) => /* @__PURE__ */ import_react.default.createElement("span", { key: String(item.id), className: "bdf-rel__chip" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-rel__chip-label" }, getTitle(item)), /* @__PURE__ */ import_react.default.createElement(
|
|
164
|
+
"button",
|
|
165
|
+
{
|
|
166
|
+
type: "button",
|
|
167
|
+
className: "bdf-rel__chip-remove",
|
|
168
|
+
onClick: (e) => clearOne(e, item.id),
|
|
169
|
+
"aria-label": `Remove ${getTitle(item)}`
|
|
170
|
+
},
|
|
171
|
+
/* @__PURE__ */ import_react.default.createElement("svg", { height: "12", width: "12", viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", fill: "currentColor" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" }))
|
|
172
|
+
)))),
|
|
173
|
+
/* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-rel__indicators" }, !hasMany && items.length > 0 && /* @__PURE__ */ import_react.default.createElement(
|
|
174
|
+
"button",
|
|
175
|
+
{
|
|
176
|
+
type: "button",
|
|
177
|
+
className: "bdf-rel__clear",
|
|
178
|
+
onClick: (e) => clearOne(e, items[0].id),
|
|
179
|
+
"aria-label": "Clear"
|
|
180
|
+
},
|
|
181
|
+
/* @__PURE__ */ import_react.default.createElement("svg", { height: "16", width: "16", viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", fill: "currentColor" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z" }))
|
|
182
|
+
), /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-rel__sep" }), /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-rel__chevron" }, /* @__PURE__ */ import_react.default.createElement("svg", { height: "16", width: "16", viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", fill: "currentColor" }, /* @__PURE__ */ import_react.default.createElement("path", { d: "M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z" }))))
|
|
183
|
+
), hasMany && /* @__PURE__ */ import_react.default.createElement(ListDrawerToggler, { className: "bdf-rel__add", onClick: (e) => e.stopPropagation() }, "+")), /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-rel__hint" }, collection, hasMany ? " \xB7 multiple" : ""), /* @__PURE__ */ import_react.default.createElement(ListDrawer, { onSelect: handleSelect }));
|
|
184
|
+
}
|
|
185
|
+
function JsonField({ label, required, value, onChange }) {
|
|
186
|
+
const [text, setText] = (0, import_react.useState)(
|
|
187
|
+
() => value !== void 0 ? JSON.stringify(value, null, 2) : ""
|
|
188
|
+
);
|
|
189
|
+
const [hasError, setHasError] = (0, import_react.useState)(false);
|
|
190
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ import_react.default.createElement("span", { className: "bdf-required" }, "*"), /* @__PURE__ */ import_react.default.createElement("span", { style: { marginLeft: 6, fontSize: 11, color: "var(--theme-elevation-400)", fontWeight: 400 } }, "(JSON)")), /* @__PURE__ */ import_react.default.createElement(
|
|
191
|
+
"textarea",
|
|
192
|
+
{
|
|
193
|
+
className: "bdf-input bdf-textarea bdf-mono",
|
|
194
|
+
value: text,
|
|
195
|
+
rows: 4,
|
|
196
|
+
onChange: (e) => {
|
|
197
|
+
setText(e.target.value);
|
|
198
|
+
try {
|
|
199
|
+
onChange(JSON.parse(e.target.value));
|
|
200
|
+
setHasError(false);
|
|
201
|
+
} catch {
|
|
202
|
+
setHasError(true);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
), hasError && /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-error", style: { marginTop: 4 } }, "Invalid JSON \u2014 changes not saved until fixed."));
|
|
207
|
+
}
|
|
80
208
|
function SchemaForm({ schema, value, onChange }) {
|
|
81
209
|
const set = (0, import_react.useCallback)(
|
|
82
210
|
(key, val) => onChange({ ...value, [key]: val }),
|
|
@@ -102,7 +230,7 @@ function FieldInput({ field, value, onChange }) {
|
|
|
102
230
|
"input",
|
|
103
231
|
{
|
|
104
232
|
className: "bdf-input",
|
|
105
|
-
type: field.type === "email" ? "email" : "text",
|
|
233
|
+
type: field.type === "email" ? "email" : field.type === "url" ? "url" : "text",
|
|
106
234
|
value: value ?? "",
|
|
107
235
|
onChange: (e) => onChange(e.target.value)
|
|
108
236
|
}
|
|
@@ -155,7 +283,7 @@ function FieldInput({ field, value, onChange }) {
|
|
|
155
283
|
className: "bdf-input",
|
|
156
284
|
type: "number",
|
|
157
285
|
value: numVal,
|
|
158
|
-
onChange: (e) => onChange(e.target.value === "" ?
|
|
286
|
+
onChange: (e) => onChange(e.target.value === "" ? null : e.target.valueAsNumber)
|
|
159
287
|
}
|
|
160
288
|
));
|
|
161
289
|
}
|
|
@@ -214,32 +342,25 @@ function FieldInput({ field, value, onChange }) {
|
|
|
214
342
|
onChange
|
|
215
343
|
}
|
|
216
344
|
);
|
|
217
|
-
case "relationship":
|
|
218
|
-
|
|
219
|
-
|
|
345
|
+
case "relationship": {
|
|
346
|
+
const relField = field;
|
|
347
|
+
if (!relField.collection) {
|
|
348
|
+
return /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "bdf-label" }, label), /* @__PURE__ */ import_react.default.createElement("div", { className: "bdf-error" }, "Relationship field ", /* @__PURE__ */ import_react.default.createElement("strong", null, field.name), " has no ", /* @__PURE__ */ import_react.default.createElement("code", null, "collection"), " defined in its schema."));
|
|
349
|
+
}
|
|
350
|
+
return /* @__PURE__ */ import_react.default.createElement(
|
|
351
|
+
RelationshipPicker,
|
|
220
352
|
{
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
353
|
+
label,
|
|
354
|
+
required: field.required,
|
|
355
|
+
collection: relField.collection,
|
|
356
|
+
hasMany: relField.hasMany ?? false,
|
|
357
|
+
value,
|
|
358
|
+
onChange
|
|
226
359
|
}
|
|
227
|
-
)
|
|
360
|
+
);
|
|
361
|
+
}
|
|
228
362
|
case "json":
|
|
229
|
-
return /* @__PURE__ */ import_react.default.createElement(
|
|
230
|
-
"textarea",
|
|
231
|
-
{
|
|
232
|
-
className: "bdf-input bdf-textarea bdf-mono",
|
|
233
|
-
value: value !== void 0 ? JSON.stringify(value, null, 2) : "",
|
|
234
|
-
rows: 4,
|
|
235
|
-
onChange: (e) => {
|
|
236
|
-
try {
|
|
237
|
-
onChange(JSON.parse(e.target.value));
|
|
238
|
-
} catch {
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
));
|
|
363
|
+
return /* @__PURE__ */ import_react.default.createElement(JsonField, { label, required: field.required, value, onChange });
|
|
243
364
|
case "array": {
|
|
244
365
|
const rows = Array.isArray(value) ? value : [];
|
|
245
366
|
const subFields = field.fields ?? [];
|
|
@@ -335,15 +456,43 @@ function BlockDataField({ path }) {
|
|
|
335
456
|
)));
|
|
336
457
|
}
|
|
337
458
|
|
|
338
|
-
// src/components/
|
|
339
|
-
var
|
|
459
|
+
// src/components/BlockVersionSync/index.tsx
|
|
460
|
+
var import_react2 = require("react");
|
|
340
461
|
var import_ui2 = require("@payloadcms/ui");
|
|
462
|
+
function BlockVersionSync({ path }) {
|
|
463
|
+
const blockVersionPath = path.replace(/\.blockDefinition$/, ".blockVersion");
|
|
464
|
+
const { setValue: setVersion } = (0, import_ui2.useField)({ path: blockVersionPath });
|
|
465
|
+
const blockDefValue = (0, import_ui2.useFormFields)(([fields]) => fields[path]?.value);
|
|
466
|
+
const prevDefIdRef = (0, import_react2.useRef)(null);
|
|
467
|
+
(0, import_react2.useEffect)(() => {
|
|
468
|
+
const defId = blockDefValue && typeof blockDefValue === "object" ? blockDefValue.id : typeof blockDefValue === "string" || typeof blockDefValue === "number" ? blockDefValue : null;
|
|
469
|
+
if (defId === prevDefIdRef.current) return;
|
|
470
|
+
prevDefIdRef.current = defId;
|
|
471
|
+
if (!defId) {
|
|
472
|
+
setVersion(null);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
fetch(`/api/block-definitions/${String(defId)}?depth=1`, { credentials: "same-origin" }).then((r) => r.ok ? r.json() : null).then((doc) => {
|
|
476
|
+
if (!doc) return;
|
|
477
|
+
const currentVersion = doc.currentVersion;
|
|
478
|
+
if (!currentVersion) return;
|
|
479
|
+
const versionId = typeof currentVersion === "object" ? currentVersion.id : currentVersion;
|
|
480
|
+
if (versionId) setVersion(versionId);
|
|
481
|
+
}).catch(() => {
|
|
482
|
+
});
|
|
483
|
+
}, [blockDefValue, setVersion]);
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// src/components/SchemaBuilderField/index.tsx
|
|
488
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
489
|
+
var import_ui3 = require("@payloadcms/ui");
|
|
341
490
|
|
|
342
491
|
// src/components/SchemaBuilderField/FieldRow.tsx
|
|
343
|
-
var
|
|
492
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
344
493
|
|
|
345
494
|
// src/components/SchemaBuilderField/OptionsEditor.tsx
|
|
346
|
-
var
|
|
495
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
347
496
|
function OptionsEditor({ options, onChange, readOnly }) {
|
|
348
497
|
function addOption() {
|
|
349
498
|
onChange([...options, { label: "", value: "" }]);
|
|
@@ -354,7 +503,7 @@ function OptionsEditor({ options, onChange, readOnly }) {
|
|
|
354
503
|
function removeOption(index) {
|
|
355
504
|
onChange(options.filter((_, i) => i !== index));
|
|
356
505
|
}
|
|
357
|
-
return /* @__PURE__ */
|
|
506
|
+
return /* @__PURE__ */ import_react3.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, /* @__PURE__ */ import_react3.default.createElement(
|
|
358
507
|
"span",
|
|
359
508
|
{
|
|
360
509
|
style: {
|
|
@@ -369,8 +518,8 @@ function OptionsEditor({ options, onChange, readOnly }) {
|
|
|
369
518
|
}
|
|
370
519
|
},
|
|
371
520
|
"Options",
|
|
372
|
-
options.length > 0 && /* @__PURE__ */
|
|
373
|
-
), options.length === 0 && /* @__PURE__ */
|
|
521
|
+
options.length > 0 && /* @__PURE__ */ import_react3.default.createElement("span", { style: { marginLeft: 6, fontSize: 11, color: "var(--theme-elevation-400)", fontWeight: 400 } }, "(", options.length, ")")
|
|
522
|
+
), options.length === 0 && /* @__PURE__ */ import_react3.default.createElement(
|
|
374
523
|
"p",
|
|
375
524
|
{
|
|
376
525
|
style: {
|
|
@@ -382,7 +531,7 @@ function OptionsEditor({ options, onChange, readOnly }) {
|
|
|
382
531
|
}
|
|
383
532
|
},
|
|
384
533
|
"No options yet."
|
|
385
|
-
), options.map((opt, i) => /* @__PURE__ */
|
|
534
|
+
), options.map((opt, i) => /* @__PURE__ */ import_react3.default.createElement("div", { key: i, className: "sbf-options-row" }, /* @__PURE__ */ import_react3.default.createElement(
|
|
386
535
|
"input",
|
|
387
536
|
{
|
|
388
537
|
className: "sbf-input",
|
|
@@ -392,7 +541,7 @@ function OptionsEditor({ options, onChange, readOnly }) {
|
|
|
392
541
|
disabled: readOnly,
|
|
393
542
|
onChange: (e) => updateOption(i, "label", e.target.value)
|
|
394
543
|
}
|
|
395
|
-
), /* @__PURE__ */
|
|
544
|
+
), /* @__PURE__ */ import_react3.default.createElement(
|
|
396
545
|
"input",
|
|
397
546
|
{
|
|
398
547
|
className: "sbf-input",
|
|
@@ -402,7 +551,7 @@ function OptionsEditor({ options, onChange, readOnly }) {
|
|
|
402
551
|
disabled: readOnly,
|
|
403
552
|
onChange: (e) => updateOption(i, "value", e.target.value)
|
|
404
553
|
}
|
|
405
|
-
), !readOnly && /* @__PURE__ */
|
|
554
|
+
), !readOnly && /* @__PURE__ */ import_react3.default.createElement(
|
|
406
555
|
"button",
|
|
407
556
|
{
|
|
408
557
|
type: "button",
|
|
@@ -411,37 +560,37 @@ function OptionsEditor({ options, onChange, readOnly }) {
|
|
|
411
560
|
onClick: () => removeOption(i)
|
|
412
561
|
},
|
|
413
562
|
"x"
|
|
414
|
-
))), !readOnly && /* @__PURE__ */
|
|
563
|
+
))), !readOnly && /* @__PURE__ */ import_react3.default.createElement(
|
|
415
564
|
"button",
|
|
416
565
|
{
|
|
417
566
|
type: "button",
|
|
418
567
|
className: "sbf-add-btn sbf-add-btn--small",
|
|
419
568
|
onClick: addOption
|
|
420
569
|
},
|
|
421
|
-
/* @__PURE__ */
|
|
570
|
+
/* @__PURE__ */ import_react3.default.createElement("span", { className: "sbf-add-btn__icon" }, "+"),
|
|
422
571
|
"Add Option"
|
|
423
572
|
));
|
|
424
573
|
}
|
|
425
574
|
|
|
426
575
|
// src/components/SchemaBuilderField/NestedFieldsEditor.tsx
|
|
427
|
-
var
|
|
576
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
428
577
|
function NestedFieldsEditor({ fields, onChange, readOnly, depth = 1 }) {
|
|
429
|
-
const addField = (0,
|
|
578
|
+
const addField = (0, import_react4.useCallback)(() => {
|
|
430
579
|
onChange([...fields, { name: "", type: "text", label: "", required: false }]);
|
|
431
580
|
}, [fields, onChange]);
|
|
432
|
-
const updateField = (0,
|
|
581
|
+
const updateField = (0, import_react4.useCallback)(
|
|
433
582
|
(index, updated) => {
|
|
434
583
|
onChange(fields.map((f, i) => i === index ? updated : f));
|
|
435
584
|
},
|
|
436
585
|
[fields, onChange]
|
|
437
586
|
);
|
|
438
|
-
const removeField = (0,
|
|
587
|
+
const removeField = (0, import_react4.useCallback)(
|
|
439
588
|
(index) => {
|
|
440
589
|
onChange(fields.filter((_, i) => i !== index));
|
|
441
590
|
},
|
|
442
591
|
[fields, onChange]
|
|
443
592
|
);
|
|
444
|
-
const moveField = (0,
|
|
593
|
+
const moveField = (0, import_react4.useCallback)(
|
|
445
594
|
(index, dir) => {
|
|
446
595
|
const next = [...fields];
|
|
447
596
|
const target = index + dir;
|
|
@@ -451,7 +600,7 @@ function NestedFieldsEditor({ fields, onChange, readOnly, depth = 1 }) {
|
|
|
451
600
|
},
|
|
452
601
|
[fields, onChange]
|
|
453
602
|
);
|
|
454
|
-
return /* @__PURE__ */
|
|
603
|
+
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "sbf-nested" }, /* @__PURE__ */ import_react4.default.createElement(
|
|
455
604
|
"span",
|
|
456
605
|
{
|
|
457
606
|
style: {
|
|
@@ -466,8 +615,8 @@ function NestedFieldsEditor({ fields, onChange, readOnly, depth = 1 }) {
|
|
|
466
615
|
}
|
|
467
616
|
},
|
|
468
617
|
"Nested fields",
|
|
469
|
-
fields.length > 0 && /* @__PURE__ */
|
|
470
|
-
), fields.length === 0 && /* @__PURE__ */
|
|
618
|
+
fields.length > 0 && /* @__PURE__ */ import_react4.default.createElement("span", { style: { marginLeft: 6, fontSize: 11, color: "var(--theme-elevation-400)", fontWeight: 400 } }, "(", fields.length, ")")
|
|
619
|
+
), fields.length === 0 && /* @__PURE__ */ import_react4.default.createElement(
|
|
471
620
|
"p",
|
|
472
621
|
{
|
|
473
622
|
style: {
|
|
@@ -479,7 +628,7 @@ function NestedFieldsEditor({ fields, onChange, readOnly, depth = 1 }) {
|
|
|
479
628
|
}
|
|
480
629
|
},
|
|
481
630
|
"No nested fields yet."
|
|
482
|
-
), fields.length > 0 && /* @__PURE__ */
|
|
631
|
+
), fields.length > 0 && /* @__PURE__ */ import_react4.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "calc(var(--base, 16px) / 2)" } }, fields.map((field, i) => /* @__PURE__ */ import_react4.default.createElement(
|
|
483
632
|
FieldRow,
|
|
484
633
|
{
|
|
485
634
|
key: i,
|
|
@@ -493,14 +642,14 @@ function NestedFieldsEditor({ fields, onChange, readOnly, depth = 1 }) {
|
|
|
493
642
|
readOnly,
|
|
494
643
|
depth
|
|
495
644
|
}
|
|
496
|
-
))), !readOnly && /* @__PURE__ */
|
|
645
|
+
))), !readOnly && /* @__PURE__ */ import_react4.default.createElement("div", { style: { marginTop: "calc(var(--base, 16px) / 2)" } }, /* @__PURE__ */ import_react4.default.createElement(
|
|
497
646
|
"button",
|
|
498
647
|
{
|
|
499
648
|
type: "button",
|
|
500
649
|
className: "sbf-add-btn sbf-add-btn--small",
|
|
501
650
|
onClick: addField
|
|
502
651
|
},
|
|
503
|
-
/* @__PURE__ */
|
|
652
|
+
/* @__PURE__ */ import_react4.default.createElement("span", { className: "sbf-add-btn__icon" }, "+"),
|
|
504
653
|
"Add Nested Field"
|
|
505
654
|
)));
|
|
506
655
|
}
|
|
@@ -547,10 +696,10 @@ var TYPE_BADGE_COLORS = {
|
|
|
547
696
|
blocks: "var(--theme-elevation-150)"
|
|
548
697
|
};
|
|
549
698
|
function FieldLabel({ children, required }) {
|
|
550
|
-
return /* @__PURE__ */
|
|
699
|
+
return /* @__PURE__ */ import_react5.default.createElement("label", { className: `sbf-label${required ? " sbf-label--required" : ""}` }, children);
|
|
551
700
|
}
|
|
552
701
|
function FieldWrap({ children }) {
|
|
553
|
-
return /* @__PURE__ */
|
|
702
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { style: { display: "flex", flexDirection: "column" } }, children);
|
|
554
703
|
}
|
|
555
704
|
function FieldRow({
|
|
556
705
|
index,
|
|
@@ -562,9 +711,9 @@ function FieldRow({
|
|
|
562
711
|
readOnly,
|
|
563
712
|
depth = 0
|
|
564
713
|
}) {
|
|
565
|
-
const [expanded, setExpanded] = (0,
|
|
566
|
-
const [showAdmin, setShowAdmin] = (0,
|
|
567
|
-
const [showConditions, setShowConditions] = (0,
|
|
714
|
+
const [expanded, setExpanded] = (0, import_react5.useState)(false);
|
|
715
|
+
const [showAdmin, setShowAdmin] = (0, import_react5.useState)(false);
|
|
716
|
+
const [showConditions, setShowConditions] = (0, import_react5.useState)(false);
|
|
568
717
|
const maxDepth = 3;
|
|
569
718
|
const canNest = depth < maxDepth;
|
|
570
719
|
const needsOptions = field.type === "select" || field.type === "multiselect";
|
|
@@ -573,7 +722,7 @@ function FieldRow({
|
|
|
573
722
|
onChange({ ...field, [key]: val });
|
|
574
723
|
}
|
|
575
724
|
const badgeBg = TYPE_BADGE_COLORS[field.type] ?? "var(--theme-elevation-150)";
|
|
576
|
-
return /* @__PURE__ */
|
|
725
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: `sbf-row${expanded ? "" : " sbf-row--collapsed"}` }, /* @__PURE__ */ import_react5.default.createElement(
|
|
577
726
|
"div",
|
|
578
727
|
{
|
|
579
728
|
className: "sbf-row__header",
|
|
@@ -581,7 +730,7 @@ function FieldRow({
|
|
|
581
730
|
"aria-expanded": expanded,
|
|
582
731
|
onClick: () => setExpanded((p) => !p)
|
|
583
732
|
},
|
|
584
|
-
/* @__PURE__ */
|
|
733
|
+
/* @__PURE__ */ import_react5.default.createElement(
|
|
585
734
|
"span",
|
|
586
735
|
{
|
|
587
736
|
style: {
|
|
@@ -598,9 +747,9 @@ function FieldRow({
|
|
|
598
747
|
},
|
|
599
748
|
">"
|
|
600
749
|
),
|
|
601
|
-
/* @__PURE__ */
|
|
602
|
-
field.required && /* @__PURE__ */
|
|
603
|
-
/* @__PURE__ */
|
|
750
|
+
/* @__PURE__ */ import_react5.default.createElement("span", { className: `sbf-row__label${!field.name ? " sbf-row__label--empty" : ""}` }, field.name || "unnamed field"),
|
|
751
|
+
field.required && /* @__PURE__ */ import_react5.default.createElement("span", { style: { color: "var(--theme-error-500, #ef4444)", fontSize: 16, lineHeight: 1, flexShrink: 0 } }, "*"),
|
|
752
|
+
/* @__PURE__ */ import_react5.default.createElement(
|
|
604
753
|
"span",
|
|
605
754
|
{
|
|
606
755
|
className: "sbf-type-badge",
|
|
@@ -608,15 +757,15 @@ function FieldRow({
|
|
|
608
757
|
},
|
|
609
758
|
field.type
|
|
610
759
|
),
|
|
611
|
-
!readOnly && /* @__PURE__ */
|
|
760
|
+
!readOnly && /* @__PURE__ */ import_react5.default.createElement(
|
|
612
761
|
"div",
|
|
613
762
|
{
|
|
614
763
|
style: { display: "flex", gap: 2, flexShrink: 0, alignItems: "center" },
|
|
615
764
|
onClick: (e) => e.stopPropagation()
|
|
616
765
|
},
|
|
617
|
-
onMoveUp && /* @__PURE__ */
|
|
618
|
-
onMoveDown && /* @__PURE__ */
|
|
619
|
-
/* @__PURE__ */
|
|
766
|
+
onMoveUp && /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveUp, title: "Move up" }, "^"),
|
|
767
|
+
onMoveDown && /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", className: "sbf-icon-btn", onClick: onMoveDown, title: "Move down" }, "v"),
|
|
768
|
+
/* @__PURE__ */ import_react5.default.createElement(
|
|
620
769
|
"button",
|
|
621
770
|
{
|
|
622
771
|
type: "button",
|
|
@@ -627,7 +776,7 @@ function FieldRow({
|
|
|
627
776
|
"x"
|
|
628
777
|
)
|
|
629
778
|
)
|
|
630
|
-
), expanded && /* @__PURE__ */
|
|
779
|
+
), expanded && /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-row__content" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-grid-2" }, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, { required: true }, "Field Name"), /* @__PURE__ */ import_react5.default.createElement(
|
|
631
780
|
"input",
|
|
632
781
|
{
|
|
633
782
|
className: "sbf-input",
|
|
@@ -637,7 +786,7 @@ function FieldRow({
|
|
|
637
786
|
disabled: readOnly,
|
|
638
787
|
onChange: (e) => set("name", e.target.value)
|
|
639
788
|
}
|
|
640
|
-
)), /* @__PURE__ */
|
|
789
|
+
)), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, { required: true }, "Type"), /* @__PURE__ */ import_react5.default.createElement(
|
|
641
790
|
"select",
|
|
642
791
|
{
|
|
643
792
|
className: "sbf-input sbf-select",
|
|
@@ -645,8 +794,8 @@ function FieldRow({
|
|
|
645
794
|
disabled: readOnly,
|
|
646
795
|
onChange: (e) => set("type", e.target.value)
|
|
647
796
|
},
|
|
648
|
-
ALL_FIELD_TYPES.map((t) => /* @__PURE__ */
|
|
649
|
-
))), /* @__PURE__ */
|
|
797
|
+
ALL_FIELD_TYPES.map((t) => /* @__PURE__ */ import_react5.default.createElement("option", { key: t, value: t }, t))
|
|
798
|
+
))), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Label"), /* @__PURE__ */ import_react5.default.createElement(
|
|
650
799
|
"input",
|
|
651
800
|
{
|
|
652
801
|
className: "sbf-input",
|
|
@@ -656,7 +805,7 @@ function FieldRow({
|
|
|
656
805
|
disabled: readOnly,
|
|
657
806
|
onChange: (e) => set("label", e.target.value)
|
|
658
807
|
}
|
|
659
|
-
)), /* @__PURE__ */
|
|
808
|
+
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-flags-row" }, /* @__PURE__ */ import_react5.default.createElement("label", { className: "sbf-checkbox-wrap" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
660
809
|
"input",
|
|
661
810
|
{
|
|
662
811
|
type: "checkbox",
|
|
@@ -664,7 +813,7 @@ function FieldRow({
|
|
|
664
813
|
disabled: readOnly,
|
|
665
814
|
onChange: (e) => set("required", e.target.checked)
|
|
666
815
|
}
|
|
667
|
-
), /* @__PURE__ */
|
|
816
|
+
), /* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-checkbox-label" }, "Required"))), field.type === "number" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-grid-2" }, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Min"), /* @__PURE__ */ import_react5.default.createElement(
|
|
668
817
|
"input",
|
|
669
818
|
{
|
|
670
819
|
className: "sbf-input",
|
|
@@ -673,7 +822,7 @@ function FieldRow({
|
|
|
673
822
|
disabled: readOnly,
|
|
674
823
|
onChange: (e) => set("min", e.target.value === "" ? void 0 : e.target.valueAsNumber)
|
|
675
824
|
}
|
|
676
|
-
)), /* @__PURE__ */
|
|
825
|
+
)), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Max"), /* @__PURE__ */ import_react5.default.createElement(
|
|
677
826
|
"input",
|
|
678
827
|
{
|
|
679
828
|
className: "sbf-input",
|
|
@@ -682,7 +831,7 @@ function FieldRow({
|
|
|
682
831
|
disabled: readOnly,
|
|
683
832
|
onChange: (e) => set("max", e.target.value === "" ? void 0 : e.target.valueAsNumber)
|
|
684
833
|
}
|
|
685
|
-
))), (field.type === "text" || field.type === "textarea") && /* @__PURE__ */
|
|
834
|
+
))), (field.type === "text" || field.type === "textarea") && /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-grid-2" }, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Min Length"), /* @__PURE__ */ import_react5.default.createElement(
|
|
686
835
|
"input",
|
|
687
836
|
{
|
|
688
837
|
className: "sbf-input",
|
|
@@ -691,7 +840,7 @@ function FieldRow({
|
|
|
691
840
|
disabled: readOnly,
|
|
692
841
|
onChange: (e) => set("minLength", e.target.value === "" ? void 0 : e.target.valueAsNumber)
|
|
693
842
|
}
|
|
694
|
-
)), /* @__PURE__ */
|
|
843
|
+
)), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Max Length"), /* @__PURE__ */ import_react5.default.createElement(
|
|
695
844
|
"input",
|
|
696
845
|
{
|
|
697
846
|
className: "sbf-input",
|
|
@@ -700,7 +849,7 @@ function FieldRow({
|
|
|
700
849
|
disabled: readOnly,
|
|
701
850
|
onChange: (e) => set("maxLength", e.target.value === "" ? void 0 : e.target.valueAsNumber)
|
|
702
851
|
}
|
|
703
|
-
))), field.type === "array" && /* @__PURE__ */
|
|
852
|
+
))), field.type === "array" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-grid-2" }, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Min Rows"), /* @__PURE__ */ import_react5.default.createElement(
|
|
704
853
|
"input",
|
|
705
854
|
{
|
|
706
855
|
className: "sbf-input",
|
|
@@ -709,7 +858,7 @@ function FieldRow({
|
|
|
709
858
|
disabled: readOnly,
|
|
710
859
|
onChange: (e) => set("minRows", e.target.value === "" ? void 0 : e.target.valueAsNumber)
|
|
711
860
|
}
|
|
712
|
-
)), /* @__PURE__ */
|
|
861
|
+
)), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Max Rows"), /* @__PURE__ */ import_react5.default.createElement(
|
|
713
862
|
"input",
|
|
714
863
|
{
|
|
715
864
|
className: "sbf-input",
|
|
@@ -718,7 +867,7 @@ function FieldRow({
|
|
|
718
867
|
disabled: readOnly,
|
|
719
868
|
onChange: (e) => set("maxRows", e.target.value === "" ? void 0 : e.target.valueAsNumber)
|
|
720
869
|
}
|
|
721
|
-
))), field.type === "relationship" && /* @__PURE__ */
|
|
870
|
+
))), field.type === "relationship" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, { required: true }, "Collection slug"), /* @__PURE__ */ import_react5.default.createElement(
|
|
722
871
|
"input",
|
|
723
872
|
{
|
|
724
873
|
className: "sbf-input",
|
|
@@ -728,7 +877,7 @@ function FieldRow({
|
|
|
728
877
|
disabled: readOnly,
|
|
729
878
|
onChange: (e) => set("collection", e.target.value)
|
|
730
879
|
}
|
|
731
|
-
)), /* @__PURE__ */
|
|
880
|
+
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-flags-row" }, /* @__PURE__ */ import_react5.default.createElement("label", { className: "sbf-checkbox-wrap" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
732
881
|
"input",
|
|
733
882
|
{
|
|
734
883
|
type: "checkbox",
|
|
@@ -736,14 +885,14 @@ function FieldRow({
|
|
|
736
885
|
disabled: readOnly,
|
|
737
886
|
onChange: (e) => set("hasMany", e.target.checked)
|
|
738
887
|
}
|
|
739
|
-
), /* @__PURE__ */
|
|
888
|
+
), /* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-checkbox-label" }, "Has Many")))), needsOptions && /* @__PURE__ */ import_react5.default.createElement(
|
|
740
889
|
OptionsEditor,
|
|
741
890
|
{
|
|
742
891
|
options: field.options ?? [],
|
|
743
892
|
onChange: (opts) => set("options", opts),
|
|
744
893
|
readOnly
|
|
745
894
|
}
|
|
746
|
-
), needsNested && canNest && /* @__PURE__ */
|
|
895
|
+
), needsNested && canNest && /* @__PURE__ */ import_react5.default.createElement(
|
|
747
896
|
NestedFieldsEditor,
|
|
748
897
|
{
|
|
749
898
|
fields: field.fields ?? [],
|
|
@@ -751,7 +900,7 @@ function FieldRow({
|
|
|
751
900
|
readOnly,
|
|
752
901
|
depth: depth + 1
|
|
753
902
|
}
|
|
754
|
-
), needsNested && !canNest && /* @__PURE__ */
|
|
903
|
+
), needsNested && !canNest && /* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-description" }, "Maximum nesting depth (", depth, ") reached."), /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-section" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
755
904
|
"button",
|
|
756
905
|
{
|
|
757
906
|
type: "button",
|
|
@@ -759,8 +908,8 @@ function FieldRow({
|
|
|
759
908
|
onClick: () => setShowAdmin((p) => !p)
|
|
760
909
|
},
|
|
761
910
|
"Admin & UI settings",
|
|
762
|
-
/* @__PURE__ */
|
|
763
|
-
), showAdmin && /* @__PURE__ */
|
|
911
|
+
/* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-section__toggle-icon" }, ">")
|
|
912
|
+
), showAdmin && /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-section__body" }, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Description"), /* @__PURE__ */ import_react5.default.createElement(
|
|
764
913
|
"input",
|
|
765
914
|
{
|
|
766
915
|
className: "sbf-input",
|
|
@@ -770,7 +919,7 @@ function FieldRow({
|
|
|
770
919
|
disabled: readOnly,
|
|
771
920
|
onChange: (e) => set("admin", { ...field.admin, description: e.target.value })
|
|
772
921
|
}
|
|
773
|
-
)), /* @__PURE__ */
|
|
922
|
+
)), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Placeholder"), /* @__PURE__ */ import_react5.default.createElement(
|
|
774
923
|
"input",
|
|
775
924
|
{
|
|
776
925
|
className: "sbf-input",
|
|
@@ -780,7 +929,7 @@ function FieldRow({
|
|
|
780
929
|
disabled: readOnly,
|
|
781
930
|
onChange: (e) => set("admin", { ...field.admin, placeholder: e.target.value })
|
|
782
931
|
}
|
|
783
|
-
)), /* @__PURE__ */
|
|
932
|
+
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-flags-row" }, /* @__PURE__ */ import_react5.default.createElement("label", { className: "sbf-checkbox-wrap" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
784
933
|
"input",
|
|
785
934
|
{
|
|
786
935
|
type: "checkbox",
|
|
@@ -788,7 +937,7 @@ function FieldRow({
|
|
|
788
937
|
disabled: readOnly,
|
|
789
938
|
onChange: (e) => set("admin", { ...field.admin, readOnly: e.target.checked })
|
|
790
939
|
}
|
|
791
|
-
), /* @__PURE__ */
|
|
940
|
+
), /* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-checkbox-label" }, "Read Only")), /* @__PURE__ */ import_react5.default.createElement("label", { className: "sbf-checkbox-wrap" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
792
941
|
"input",
|
|
793
942
|
{
|
|
794
943
|
type: "checkbox",
|
|
@@ -796,7 +945,7 @@ function FieldRow({
|
|
|
796
945
|
disabled: readOnly,
|
|
797
946
|
onChange: (e) => set("admin", { ...field.admin, hidden: e.target.checked })
|
|
798
947
|
}
|
|
799
|
-
), /* @__PURE__ */
|
|
948
|
+
), /* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-checkbox-label" }, "Hidden"))))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-section" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
800
949
|
"button",
|
|
801
950
|
{
|
|
802
951
|
type: "button",
|
|
@@ -804,7 +953,7 @@ function FieldRow({
|
|
|
804
953
|
onClick: () => setShowConditions((p) => !p)
|
|
805
954
|
},
|
|
806
955
|
"Conditional logic",
|
|
807
|
-
(field.conditions?.length ?? 0) > 0 && /* @__PURE__ */
|
|
956
|
+
(field.conditions?.length ?? 0) > 0 && /* @__PURE__ */ import_react5.default.createElement(
|
|
808
957
|
"span",
|
|
809
958
|
{
|
|
810
959
|
style: {
|
|
@@ -818,8 +967,8 @@ function FieldRow({
|
|
|
818
967
|
" rule",
|
|
819
968
|
field.conditions.length !== 1 ? "s" : ""
|
|
820
969
|
),
|
|
821
|
-
/* @__PURE__ */
|
|
822
|
-
), showConditions && /* @__PURE__ */
|
|
970
|
+
/* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-section__toggle-icon" }, ">")
|
|
971
|
+
), showConditions && /* @__PURE__ */ import_react5.default.createElement("div", { className: "sbf-section__body" }, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Condition Mode"), /* @__PURE__ */ import_react5.default.createElement(
|
|
823
972
|
"select",
|
|
824
973
|
{
|
|
825
974
|
className: "sbf-input sbf-select",
|
|
@@ -828,9 +977,9 @@ function FieldRow({
|
|
|
828
977
|
onChange: (e) => set("conditionMode", e.target.value),
|
|
829
978
|
style: { width: "auto", minWidth: 240 }
|
|
830
979
|
},
|
|
831
|
-
/* @__PURE__ */
|
|
832
|
-
/* @__PURE__ */
|
|
833
|
-
)), (field.conditions ?? []).map((cond, ci) => /* @__PURE__ */
|
|
980
|
+
/* @__PURE__ */ import_react5.default.createElement("option", { value: "AND" }, "AND - all conditions must match"),
|
|
981
|
+
/* @__PURE__ */ import_react5.default.createElement("option", { value: "OR" }, "OR - any condition must match")
|
|
982
|
+
)), (field.conditions ?? []).map((cond, ci) => /* @__PURE__ */ import_react5.default.createElement("div", { key: ci, className: "sbf-conditions-grid" }, /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Field"), /* @__PURE__ */ import_react5.default.createElement(
|
|
834
983
|
"input",
|
|
835
984
|
{
|
|
836
985
|
className: "sbf-input",
|
|
@@ -844,7 +993,7 @@ function FieldRow({
|
|
|
844
993
|
set("conditions", next);
|
|
845
994
|
}
|
|
846
995
|
}
|
|
847
|
-
)), /* @__PURE__ */
|
|
996
|
+
)), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Operator"), /* @__PURE__ */ import_react5.default.createElement(
|
|
848
997
|
"select",
|
|
849
998
|
{
|
|
850
999
|
className: "sbf-input sbf-select",
|
|
@@ -856,8 +1005,8 @@ function FieldRow({
|
|
|
856
1005
|
set("conditions", next);
|
|
857
1006
|
}
|
|
858
1007
|
},
|
|
859
|
-
["equals", "not_equals", "contains", "not_contains", "greater_than", "less_than", "in", "not_in", "exists", "empty"].map((op) => /* @__PURE__ */
|
|
860
|
-
)), /* @__PURE__ */
|
|
1008
|
+
["equals", "not_equals", "contains", "not_contains", "greater_than", "less_than", "in", "not_in", "exists", "empty"].map((op) => /* @__PURE__ */ import_react5.default.createElement("option", { key: op, value: op }, op.replace(/_/g, " ")))
|
|
1009
|
+
)), /* @__PURE__ */ import_react5.default.createElement(FieldWrap, null, /* @__PURE__ */ import_react5.default.createElement(FieldLabel, null, "Value"), /* @__PURE__ */ import_react5.default.createElement(
|
|
861
1010
|
"input",
|
|
862
1011
|
{
|
|
863
1012
|
className: "sbf-input",
|
|
@@ -870,7 +1019,7 @@ function FieldRow({
|
|
|
870
1019
|
set("conditions", next);
|
|
871
1020
|
}
|
|
872
1021
|
}
|
|
873
|
-
)), !readOnly && /* @__PURE__ */
|
|
1022
|
+
)), !readOnly && /* @__PURE__ */ import_react5.default.createElement(
|
|
874
1023
|
"button",
|
|
875
1024
|
{
|
|
876
1025
|
type: "button",
|
|
@@ -882,7 +1031,7 @@ function FieldRow({
|
|
|
882
1031
|
}
|
|
883
1032
|
},
|
|
884
1033
|
"x"
|
|
885
|
-
))), !readOnly && /* @__PURE__ */
|
|
1034
|
+
))), !readOnly && /* @__PURE__ */ import_react5.default.createElement(
|
|
886
1035
|
"button",
|
|
887
1036
|
{
|
|
888
1037
|
type: "button",
|
|
@@ -894,7 +1043,7 @@ function FieldRow({
|
|
|
894
1043
|
]);
|
|
895
1044
|
}
|
|
896
1045
|
},
|
|
897
|
-
/* @__PURE__ */
|
|
1046
|
+
/* @__PURE__ */ import_react5.default.createElement("span", { className: "sbf-add-btn__icon" }, "+"),
|
|
898
1047
|
"Add Condition"
|
|
899
1048
|
)))));
|
|
900
1049
|
}
|
|
@@ -911,38 +1060,38 @@ function parseSchema(raw) {
|
|
|
911
1060
|
return [];
|
|
912
1061
|
}
|
|
913
1062
|
function SchemaBuilderField({ path, readOnly }) {
|
|
914
|
-
const { value, setValue } = (0,
|
|
915
|
-
const setValueRef = (0,
|
|
916
|
-
(0,
|
|
1063
|
+
const { value, setValue } = (0, import_ui3.useField)({ path });
|
|
1064
|
+
const setValueRef = (0, import_react6.useRef)(setValue);
|
|
1065
|
+
(0, import_react6.useEffect)(() => {
|
|
917
1066
|
setValueRef.current = setValue;
|
|
918
1067
|
});
|
|
919
|
-
const [fields, setFields] = (0,
|
|
1068
|
+
const [fields, setFields] = (0, import_react6.useState)(() => parseSchema(value));
|
|
920
1069
|
const hasExistingValue = value !== void 0 && value !== null;
|
|
921
|
-
const [hydrated, setHydrated] = (0,
|
|
922
|
-
(0,
|
|
1070
|
+
const [hydrated, setHydrated] = (0, import_react6.useState)(!hasExistingValue);
|
|
1071
|
+
(0, import_react6.useEffect)(() => {
|
|
923
1072
|
if (hydrated) return;
|
|
924
1073
|
if (value !== void 0 && value !== null) {
|
|
925
1074
|
setFields(parseSchema(value));
|
|
926
1075
|
setHydrated(true);
|
|
927
1076
|
}
|
|
928
1077
|
}, [value, hydrated]);
|
|
929
|
-
(0,
|
|
1078
|
+
(0, import_react6.useEffect)(() => {
|
|
930
1079
|
if (!hydrated) return;
|
|
931
1080
|
setValueRef.current({ fields });
|
|
932
1081
|
}, [fields, hydrated]);
|
|
933
|
-
const addField = (0,
|
|
1082
|
+
const addField = (0, import_react6.useCallback)(() => {
|
|
934
1083
|
setFields((prev) => [
|
|
935
1084
|
...prev,
|
|
936
1085
|
{ name: "", type: "text", label: "", required: false }
|
|
937
1086
|
]);
|
|
938
1087
|
}, []);
|
|
939
|
-
const updateField = (0,
|
|
1088
|
+
const updateField = (0, import_react6.useCallback)((index, updated) => {
|
|
940
1089
|
setFields((prev) => prev.map((f, i) => i === index ? updated : f));
|
|
941
1090
|
}, []);
|
|
942
|
-
const removeField = (0,
|
|
1091
|
+
const removeField = (0, import_react6.useCallback)((index) => {
|
|
943
1092
|
setFields((prev) => prev.filter((_, i) => i !== index));
|
|
944
1093
|
}, []);
|
|
945
|
-
const moveField = (0,
|
|
1094
|
+
const moveField = (0, import_react6.useCallback)((index, dir) => {
|
|
946
1095
|
setFields((prev) => {
|
|
947
1096
|
const next = [...prev];
|
|
948
1097
|
const target = index + dir;
|
|
@@ -951,7 +1100,7 @@ function SchemaBuilderField({ path, readOnly }) {
|
|
|
951
1100
|
return next;
|
|
952
1101
|
});
|
|
953
1102
|
}, []);
|
|
954
|
-
return /* @__PURE__ */
|
|
1103
|
+
return /* @__PURE__ */ import_react6.default.createElement("div", null, /* @__PURE__ */ import_react6.default.createElement("div", { className: "sbf-section-heading" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "sbf-section-label" }, "Fields", fields.length > 0 && /* @__PURE__ */ import_react6.default.createElement(
|
|
955
1104
|
"span",
|
|
956
1105
|
{
|
|
957
1106
|
style: {
|
|
@@ -964,7 +1113,7 @@ function SchemaBuilderField({ path, readOnly }) {
|
|
|
964
1113
|
"(",
|
|
965
1114
|
fields.length,
|
|
966
1115
|
")"
|
|
967
|
-
))), fields.length === 0 ? /* @__PURE__ */
|
|
1116
|
+
))), fields.length === 0 ? /* @__PURE__ */ import_react6.default.createElement("div", { className: "sbf-empty" }, "No fields defined. Click \u201CAdd Field\u201D below to add the first field to this block schema.") : /* @__PURE__ */ import_react6.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: "calc(var(--base, 16px) / 2)" } }, fields.map((field, i) => /* @__PURE__ */ import_react6.default.createElement(
|
|
968
1117
|
FieldRow,
|
|
969
1118
|
{
|
|
970
1119
|
key: i,
|
|
@@ -977,18 +1126,18 @@ function SchemaBuilderField({ path, readOnly }) {
|
|
|
977
1126
|
onMoveDown: i < fields.length - 1 ? () => moveField(i, 1) : void 0,
|
|
978
1127
|
readOnly
|
|
979
1128
|
}
|
|
980
|
-
))), !readOnly && /* @__PURE__ */
|
|
1129
|
+
))), !readOnly && /* @__PURE__ */ import_react6.default.createElement("div", { style: { marginTop: "calc(var(--base, 16px) / 2)", marginBottom: "calc(var(--base, 16px) / 2)" } }, /* @__PURE__ */ import_react6.default.createElement("button", { type: "button", className: "sbf-add-btn", onClick: addField }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "sbf-add-btn__icon" }, "+"), "Add Field")));
|
|
981
1130
|
}
|
|
982
1131
|
|
|
983
1132
|
// src/components/EditInBuilderButton/index.tsx
|
|
984
|
-
var
|
|
985
|
-
var import_ui3 = require("@payloadcms/ui");
|
|
1133
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
986
1134
|
var import_ui4 = require("@payloadcms/ui");
|
|
1135
|
+
var import_ui5 = require("@payloadcms/ui");
|
|
987
1136
|
function EditInBuilderButton() {
|
|
988
|
-
const { id } = (0,
|
|
989
|
-
const { value: slug } = (0,
|
|
1137
|
+
const { id } = (0, import_ui4.useDocumentInfo)();
|
|
1138
|
+
const { value: slug } = (0, import_ui5.useField)({ path: "slug" });
|
|
990
1139
|
if (!id || !slug) return null;
|
|
991
|
-
return /* @__PURE__ */
|
|
1140
|
+
return /* @__PURE__ */ import_react7.default.createElement("div", { style: { marginTop: "1rem" } }, /* @__PURE__ */ import_react7.default.createElement(
|
|
992
1141
|
"a",
|
|
993
1142
|
{
|
|
994
1143
|
href: `/block-builder?load=${slug}`,
|
|
@@ -1014,7 +1163,7 @@ function EditInBuilderButton() {
|
|
|
1014
1163
|
}
|
|
1015
1164
|
|
|
1016
1165
|
// src/block-builder/components/canvas/BuilderShell.tsx
|
|
1017
|
-
var
|
|
1166
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
1018
1167
|
|
|
1019
1168
|
// src/block-builder/store/builder.store.ts
|
|
1020
1169
|
var import_zustand = require("zustand");
|
|
@@ -1171,7 +1320,8 @@ var useBuilderStore = (0, import_zustand.create)()(
|
|
|
1171
1320
|
);
|
|
1172
1321
|
|
|
1173
1322
|
// src/block-builder/components/canvas/TopBar.tsx
|
|
1174
|
-
var
|
|
1323
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
1324
|
+
var import_lucide_react = require("lucide-react");
|
|
1175
1325
|
|
|
1176
1326
|
// src/block-builder/lib/mapToSaveRequest.ts
|
|
1177
1327
|
var TYPE_MAP = {
|
|
@@ -1325,7 +1475,7 @@ function generateIndexFile(blocks) {
|
|
|
1325
1475
|
}
|
|
1326
1476
|
|
|
1327
1477
|
// src/block-builder/components/canvas/TopBar.tsx
|
|
1328
|
-
function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersionId, onVersionSelect, onRestoreVersion, onAfterPublish }) {
|
|
1478
|
+
function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersionId, onVersionSelect, onRestoreVersion, onAfterPublish, notification, onSetNotification }) {
|
|
1329
1479
|
const blocks = useBuilderStore((s) => s.blocks);
|
|
1330
1480
|
const activeBlockId = useBuilderStore((s) => s.activeBlockId);
|
|
1331
1481
|
const activeBlock = blocks.find((b) => b.id === activeBlockId);
|
|
@@ -1333,21 +1483,21 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1333
1483
|
const isDirty = useBuilderStore((s) => s.isDirty);
|
|
1334
1484
|
const isReadOnly = useBuilderStore((s) => s.isReadOnly);
|
|
1335
1485
|
const setVersionMeta = useBuilderStore((s) => s.setVersionMeta);
|
|
1336
|
-
const
|
|
1337
|
-
const [versionDropdownOpen, setVersionDropdownOpen] = (0,
|
|
1338
|
-
const [blockPickerOpen, setBlockPickerOpen] = (0,
|
|
1339
|
-
const dropdownRef = (0,
|
|
1340
|
-
const blockPickerRef = (0,
|
|
1486
|
+
const setNotification = onSetNotification;
|
|
1487
|
+
const [versionDropdownOpen, setVersionDropdownOpen] = (0, import_react8.useState)(false);
|
|
1488
|
+
const [blockPickerOpen, setBlockPickerOpen] = (0, import_react8.useState)(false);
|
|
1489
|
+
const dropdownRef = (0, import_react8.useRef)(null);
|
|
1490
|
+
const blockPickerRef = (0, import_react8.useRef)(null);
|
|
1341
1491
|
const selectedVersion = versions.find((v) => v.id === selectedVersionId);
|
|
1342
1492
|
const currentVersion = versions.find((v) => v.isCurrent);
|
|
1343
1493
|
const activeBlockDef = blockDefs.find((b) => b.slug === activeSlug);
|
|
1344
|
-
(0,
|
|
1494
|
+
(0, import_react8.useEffect)(() => {
|
|
1345
1495
|
if (notification?.status === "success") {
|
|
1346
1496
|
const t = setTimeout(() => setNotification(null), 3e3);
|
|
1347
1497
|
return () => clearTimeout(t);
|
|
1348
1498
|
}
|
|
1349
1499
|
}, [notification]);
|
|
1350
|
-
(0,
|
|
1500
|
+
(0, import_react8.useEffect)(() => {
|
|
1351
1501
|
function handleClick(e) {
|
|
1352
1502
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
1353
1503
|
setVersionDropdownOpen(false);
|
|
@@ -1360,7 +1510,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1360
1510
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
1361
1511
|
}, []);
|
|
1362
1512
|
async function handlePublish() {
|
|
1363
|
-
if (!activeBlock || isReadOnly) return;
|
|
1513
|
+
if (!activeBlock || isReadOnly) return false;
|
|
1364
1514
|
setNotification({ status: "publishing" });
|
|
1365
1515
|
try {
|
|
1366
1516
|
const req = mapToSaveRequest(activeBlock);
|
|
@@ -1377,13 +1527,15 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1377
1527
|
status: "success",
|
|
1378
1528
|
msg: `v${json.versionNumber ?? "?"} published successfully!`
|
|
1379
1529
|
});
|
|
1380
|
-
|
|
1530
|
+
onAfterPublish();
|
|
1531
|
+
return true;
|
|
1381
1532
|
} else {
|
|
1382
1533
|
setNotification({
|
|
1383
1534
|
status: "error",
|
|
1384
1535
|
title: "Failed to publish block",
|
|
1385
1536
|
errors: json.errors ?? ["An unknown error occurred."]
|
|
1386
1537
|
});
|
|
1538
|
+
return false;
|
|
1387
1539
|
}
|
|
1388
1540
|
} catch (err) {
|
|
1389
1541
|
setNotification({
|
|
@@ -1391,6 +1543,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1391
1543
|
title: "Network error",
|
|
1392
1544
|
errors: [err instanceof Error ? err.message : "Could not reach the server."]
|
|
1393
1545
|
});
|
|
1546
|
+
return false;
|
|
1394
1547
|
}
|
|
1395
1548
|
}
|
|
1396
1549
|
function handleExport() {
|
|
@@ -1411,17 +1564,17 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1411
1564
|
function formatDate(iso) {
|
|
1412
1565
|
return new Date(iso).toLocaleDateString(void 0, { month: "short", day: "numeric" });
|
|
1413
1566
|
}
|
|
1414
|
-
return /* @__PURE__ */
|
|
1567
|
+
return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-topbar" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-topbar__brand" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-topbar__title" }, "Block Builder"), isDirty && !isReadOnly && /* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-topbar__dirty" }, "* unsaved")), /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-topbar__selectors" }, blockDefs.length > 0 && /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-block-picker", ref: blockPickerRef }, /* @__PURE__ */ import_react8.default.createElement(
|
|
1415
1568
|
"button",
|
|
1416
1569
|
{
|
|
1417
1570
|
type: "button",
|
|
1418
1571
|
className: "bb-block-picker__trigger",
|
|
1419
1572
|
onClick: () => setBlockPickerOpen((o) => !o)
|
|
1420
1573
|
},
|
|
1421
|
-
/* @__PURE__ */
|
|
1422
|
-
/* @__PURE__ */
|
|
1423
|
-
/* @__PURE__ */
|
|
1424
|
-
), blockPickerOpen && /* @__PURE__ */
|
|
1574
|
+
/* @__PURE__ */ import_react8.default.createElement(import_lucide_react.Blocks, { size: 14, strokeWidth: 1.75, className: "bb-block-picker__icon" }),
|
|
1575
|
+
/* @__PURE__ */ import_react8.default.createElement("span", null, activeBlockDef?.name ?? activeSlug ?? "Select a block"),
|
|
1576
|
+
/* @__PURE__ */ import_react8.default.createElement(import_lucide_react.ChevronDown, { size: 14, strokeWidth: 1.75, className: "bb-version-selector__chevron" })
|
|
1577
|
+
), blockPickerOpen && /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-block-picker__dropdown" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-version-dropdown__header" }, "Block Definitions"), blockDefs.map((b) => /* @__PURE__ */ import_react8.default.createElement(
|
|
1425
1578
|
"button",
|
|
1426
1579
|
{
|
|
1427
1580
|
key: b.id,
|
|
@@ -1432,20 +1585,20 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1432
1585
|
onBlockSelect(b.slug);
|
|
1433
1586
|
}
|
|
1434
1587
|
},
|
|
1435
|
-
/* @__PURE__ */
|
|
1436
|
-
/* @__PURE__ */
|
|
1437
|
-
)))), versions.length > 0 && /* @__PURE__ */
|
|
1588
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-block-picker__item-name" }, b.name),
|
|
1589
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-version-dropdown__meta" }, b.slug)
|
|
1590
|
+
)))), versions.length > 0 && /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-version-selector", ref: dropdownRef }, /* @__PURE__ */ import_react8.default.createElement(
|
|
1438
1591
|
"button",
|
|
1439
1592
|
{
|
|
1440
1593
|
type: "button",
|
|
1441
1594
|
className: `bb-version-selector__trigger${isReadOnly ? " bb-version-selector__trigger--readonly" : ""}`,
|
|
1442
1595
|
onClick: () => setVersionDropdownOpen((o) => !o)
|
|
1443
1596
|
},
|
|
1444
|
-
/* @__PURE__ */
|
|
1445
|
-
/* @__PURE__ */
|
|
1446
|
-
selectedVersion?.isCurrent && /* @__PURE__ */
|
|
1447
|
-
/* @__PURE__ */
|
|
1448
|
-
), versionDropdownOpen && /* @__PURE__ */
|
|
1597
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: `bb-version-selector__dot${selectedVersion?.isCurrent ? " bb-version-selector__dot--current" : " bb-version-selector__dot--old"}` }),
|
|
1598
|
+
/* @__PURE__ */ import_react8.default.createElement("span", null, selectedVersion?.label ?? `v${selectedVersion?.versionNumber ?? "?"}`),
|
|
1599
|
+
selectedVersion?.isCurrent && /* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-version-selector__badge" }, "current"),
|
|
1600
|
+
/* @__PURE__ */ import_react8.default.createElement(import_lucide_react.ChevronDown, { size: 14, strokeWidth: 1.75, className: "bb-version-selector__chevron" })
|
|
1601
|
+
), versionDropdownOpen && /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-version-dropdown" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-version-dropdown__header" }, "Version History"), versions.map((v) => /* @__PURE__ */ import_react8.default.createElement(
|
|
1449
1602
|
"button",
|
|
1450
1603
|
{
|
|
1451
1604
|
key: v.id,
|
|
@@ -1456,10 +1609,10 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1456
1609
|
onVersionSelect(v.id);
|
|
1457
1610
|
}
|
|
1458
1611
|
},
|
|
1459
|
-
/* @__PURE__ */
|
|
1460
|
-
/* @__PURE__ */
|
|
1461
|
-
/* @__PURE__ */
|
|
1462
|
-
))))), /* @__PURE__ */
|
|
1612
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: `bb-version-selector__dot${v.isCurrent ? " bb-version-selector__dot--current" : " bb-version-selector__dot--old"}` }),
|
|
1613
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-version-dropdown__label" }, v.label, v.isCurrent && /* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-version-selector__badge" }, "current")),
|
|
1614
|
+
/* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-version-dropdown__meta" }, v.changelog ? `${v.changelog.slice(0, 32)}${v.changelog.length > 32 ? "..." : ""}` : formatDate(v.createdAt))
|
|
1615
|
+
))))), /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-topbar__actions" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
1463
1616
|
"button",
|
|
1464
1617
|
{
|
|
1465
1618
|
type: "button",
|
|
@@ -1469,7 +1622,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1469
1622
|
style: { display: "none" }
|
|
1470
1623
|
},
|
|
1471
1624
|
"Export .ts"
|
|
1472
|
-
), isReadOnly ? /* @__PURE__ */
|
|
1625
|
+
), isReadOnly ? /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(
|
|
1473
1626
|
"button",
|
|
1474
1627
|
{
|
|
1475
1628
|
type: "button",
|
|
@@ -1480,20 +1633,19 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1480
1633
|
disabled: !currentVersion
|
|
1481
1634
|
},
|
|
1482
1635
|
"Back to current"
|
|
1483
|
-
), /* @__PURE__ */
|
|
1636
|
+
), /* @__PURE__ */ import_react8.default.createElement(
|
|
1484
1637
|
"button",
|
|
1485
1638
|
{
|
|
1486
1639
|
type: "button",
|
|
1487
1640
|
onClick: async () => {
|
|
1488
|
-
await handlePublish();
|
|
1489
|
-
|
|
1490
|
-
onRestoreVersion();
|
|
1641
|
+
const success = await handlePublish();
|
|
1642
|
+
if (success) onRestoreVersion();
|
|
1491
1643
|
},
|
|
1492
1644
|
disabled: notification?.status === "publishing" || !activeBlock,
|
|
1493
1645
|
className: "bb-btn bb-btn--warning"
|
|
1494
1646
|
},
|
|
1495
1647
|
notification?.status === "publishing" ? "Restoring..." : "Restore as new version"
|
|
1496
|
-
)) : /* @__PURE__ */
|
|
1648
|
+
)) : /* @__PURE__ */ import_react8.default.createElement(
|
|
1497
1649
|
"button",
|
|
1498
1650
|
{
|
|
1499
1651
|
type: "button",
|
|
@@ -1502,36 +1654,55 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
|
|
|
1502
1654
|
className: "bb-btn bb-btn--primary"
|
|
1503
1655
|
},
|
|
1504
1656
|
notification?.status === "publishing" ? "Publishing..." : "Publish to Payload"
|
|
1505
|
-
))), notification?.status === "publishing" && /* @__PURE__ */
|
|
1657
|
+
))), notification?.status === "publishing" && /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify bb-notify--publishing" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify__spinner" }), /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react8.default.createElement("p", { className: "bb-notify__title" }, isReadOnly ? "Restoring version..." : "Publishing to Payload..."), /* @__PURE__ */ import_react8.default.createElement("p", { className: "bb-notify__sub" }, "Validating schema and saving block definition.")))), notification?.status === "success" && /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify bb-notify--success" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-notify__icon" }, "OK"), /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react8.default.createElement("p", { className: "bb-notify__title" }, notification.msg), /* @__PURE__ */ import_react8.default.createElement("p", { className: "bb-notify__sub" }, "The block definition and version have been saved.")), /* @__PURE__ */ import_react8.default.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, /* @__PURE__ */ import_react8.default.createElement(import_lucide_react.X, { size: 12, strokeWidth: 2 })))), notification?.status === "error" && /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify bb-notify--error" }, /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ import_react8.default.createElement("span", { className: "bb-notify__icon" }, "!"), /* @__PURE__ */ import_react8.default.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ import_react8.default.createElement("p", { className: "bb-notify__title" }, notification.title), /* @__PURE__ */ import_react8.default.createElement("p", { className: "bb-notify__sub" }, "Fix the following errors before publishing:"), /* @__PURE__ */ import_react8.default.createElement("ul", { className: "bb-notify__error-list" }, notification.errors.map((e, i) => /* @__PURE__ */ import_react8.default.createElement("li", { key: i }, e)))), /* @__PURE__ */ import_react8.default.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, /* @__PURE__ */ import_react8.default.createElement(import_lucide_react.X, { size: 12, strokeWidth: 2 })))));
|
|
1506
1658
|
}
|
|
1507
1659
|
|
|
1508
1660
|
// src/block-builder/components/canvas/BlockList.tsx
|
|
1509
|
-
var
|
|
1510
|
-
|
|
1661
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
1662
|
+
var import_lucide_react2 = require("lucide-react");
|
|
1663
|
+
function BlockList({ blockDefs = [], activeSlug, onBlockSelect }) {
|
|
1511
1664
|
const blocks = useBuilderStore((s) => s.blocks);
|
|
1512
1665
|
const activeBlockId = useBuilderStore((s) => s.activeBlockId);
|
|
1513
1666
|
const addBlock = useBuilderStore((s) => s.addBlock);
|
|
1514
1667
|
const removeBlock = useBuilderStore((s) => s.removeBlock);
|
|
1515
1668
|
const duplicateBlock = useBuilderStore((s) => s.duplicateBlock);
|
|
1516
1669
|
const setActiveBlock = useBuilderStore((s) => s.setActiveBlock);
|
|
1517
|
-
|
|
1670
|
+
const useApiNav = blockDefs.length > 0;
|
|
1671
|
+
const loadedBlock = useApiNav ? blocks.find((b) => b.slug === activeSlug) : null;
|
|
1672
|
+
const localOnlyBlocks = blocks.filter(
|
|
1673
|
+
(b) => !blockDefs.some((d) => d.slug === b.slug)
|
|
1674
|
+
);
|
|
1675
|
+
return /* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-sidebar bb-sidebar--200 bb-sidebar--blocks" }, /* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-sidebar__header" }, /* @__PURE__ */ import_react9.default.createElement("span", { className: "bb-sidebar__title" }, "Blocks"), /* @__PURE__ */ import_react9.default.createElement("button", { type: "button", onClick: addBlock, title: "Add block", className: "bb-sidebar__add" }, /* @__PURE__ */ import_react9.default.createElement(import_lucide_react2.Plus, { size: 14, strokeWidth: 2 }))), /* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-sidebar__body" }, useApiNav && blockDefs.map((def) => {
|
|
1676
|
+
const isActive = def.slug === activeSlug;
|
|
1677
|
+
const fieldCount = isActive && loadedBlock ? loadedBlock.fields.length : null;
|
|
1678
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1679
|
+
"div",
|
|
1680
|
+
{
|
|
1681
|
+
key: def.id,
|
|
1682
|
+
onClick: () => onBlockSelect?.(def.slug),
|
|
1683
|
+
className: `bb-block-item${isActive ? " bb-block-item--active" : ""}`
|
|
1684
|
+
},
|
|
1685
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-block-item__slug" }, def.slug),
|
|
1686
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-block-item__meta" }, fieldCount !== null ? `${fieldCount} field${fieldCount !== 1 ? "s" : ""}` : def.name)
|
|
1687
|
+
);
|
|
1688
|
+
}), localOnlyBlocks.map((block) => {
|
|
1518
1689
|
const isActive = block.id === activeBlockId;
|
|
1519
|
-
return /* @__PURE__ */
|
|
1690
|
+
return /* @__PURE__ */ import_react9.default.createElement(
|
|
1520
1691
|
"div",
|
|
1521
1692
|
{
|
|
1522
1693
|
key: block.id,
|
|
1523
1694
|
onClick: () => setActiveBlock(block.id),
|
|
1524
1695
|
className: `bb-block-item${isActive ? " bb-block-item--active" : ""}`
|
|
1525
1696
|
},
|
|
1526
|
-
/* @__PURE__ */
|
|
1527
|
-
/* @__PURE__ */
|
|
1528
|
-
/* @__PURE__ */
|
|
1697
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-block-item__slug" }, block.slug),
|
|
1698
|
+
/* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-block-item__meta" }, block.fields.length, " field", block.fields.length !== 1 ? "s" : ""),
|
|
1699
|
+
/* @__PURE__ */ import_react9.default.createElement(
|
|
1529
1700
|
"div",
|
|
1530
1701
|
{
|
|
1531
1702
|
className: "bb-block-item__actions",
|
|
1532
1703
|
onClick: (e) => e.stopPropagation()
|
|
1533
1704
|
},
|
|
1534
|
-
/* @__PURE__ */
|
|
1705
|
+
/* @__PURE__ */ import_react9.default.createElement(
|
|
1535
1706
|
"button",
|
|
1536
1707
|
{
|
|
1537
1708
|
type: "button",
|
|
@@ -1539,9 +1710,9 @@ function BlockList() {
|
|
|
1539
1710
|
className: "bb-block-action",
|
|
1540
1711
|
title: "Duplicate"
|
|
1541
1712
|
},
|
|
1542
|
-
|
|
1713
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react2.Copy, { size: 12, strokeWidth: 1.75 })
|
|
1543
1714
|
),
|
|
1544
|
-
/* @__PURE__ */
|
|
1715
|
+
/* @__PURE__ */ import_react9.default.createElement(
|
|
1545
1716
|
"button",
|
|
1546
1717
|
{
|
|
1547
1718
|
type: "button",
|
|
@@ -1549,41 +1720,36 @@ function BlockList() {
|
|
|
1549
1720
|
className: "bb-block-action bb-block-action--danger",
|
|
1550
1721
|
title: "Delete"
|
|
1551
1722
|
},
|
|
1552
|
-
|
|
1723
|
+
/* @__PURE__ */ import_react9.default.createElement(import_lucide_react2.Trash2, { size: 12, strokeWidth: 1.75 })
|
|
1553
1724
|
)
|
|
1554
1725
|
)
|
|
1555
1726
|
);
|
|
1556
|
-
})));
|
|
1727
|
+
}), !useApiNav && blocks.length === 0 && /* @__PURE__ */ import_react9.default.createElement("div", { className: "bb-block-empty" }, "No blocks yet.", /* @__PURE__ */ import_react9.default.createElement("br", null), "Click + to create one.")));
|
|
1557
1728
|
}
|
|
1558
1729
|
|
|
1559
1730
|
// src/block-builder/components/canvas/BuilderCanvas.tsx
|
|
1560
|
-
var
|
|
1731
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
1561
1732
|
var import_core = require("@dnd-kit/core");
|
|
1562
1733
|
var import_sortable2 = require("@dnd-kit/sortable");
|
|
1563
1734
|
var import_modifiers = require("@dnd-kit/modifiers");
|
|
1564
1735
|
|
|
1565
1736
|
// src/block-builder/components/canvas/SortableFieldCard.tsx
|
|
1566
|
-
var
|
|
1737
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
1567
1738
|
var import_sortable = require("@dnd-kit/sortable");
|
|
1568
1739
|
var import_utilities = require("@dnd-kit/utilities");
|
|
1740
|
+
var import_lucide_react3 = require("lucide-react");
|
|
1569
1741
|
var ICON_MAP = {
|
|
1570
|
-
text:
|
|
1571
|
-
textarea:
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
upload:
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
point: "P",
|
|
1582
|
-
relationship: "->>",
|
|
1583
|
-
array: "[]",
|
|
1584
|
-
group: "{ }",
|
|
1585
|
-
json: "{ }",
|
|
1586
|
-
ui: "UI"
|
|
1742
|
+
text: import_lucide_react3.Type,
|
|
1743
|
+
textarea: import_lucide_react3.AlignLeft,
|
|
1744
|
+
number: import_lucide_react3.Hash,
|
|
1745
|
+
email: import_lucide_react3.Mail,
|
|
1746
|
+
date: import_lucide_react3.Calendar,
|
|
1747
|
+
checkbox: import_lucide_react3.CheckSquare,
|
|
1748
|
+
select: import_lucide_react3.ChevronDown,
|
|
1749
|
+
radio: import_lucide_react3.Circle,
|
|
1750
|
+
upload: import_lucide_react3.Upload,
|
|
1751
|
+
relationship: import_lucide_react3.Link,
|
|
1752
|
+
json: import_lucide_react3.Braces
|
|
1587
1753
|
};
|
|
1588
1754
|
function SortableFieldCard({ field, blockId, index }) {
|
|
1589
1755
|
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = (0, import_sortable.useSortable)({
|
|
@@ -1592,12 +1758,13 @@ function SortableFieldCard({ field, blockId, index }) {
|
|
|
1592
1758
|
const activeFieldId = useBuilderStore((s) => s.activeFieldId);
|
|
1593
1759
|
const setActiveField = useBuilderStore((s) => s.setActiveField);
|
|
1594
1760
|
const removeField = useBuilderStore((s) => s.removeField);
|
|
1761
|
+
const isReadOnly = useBuilderStore((s) => s.isReadOnly);
|
|
1595
1762
|
const isActive = activeFieldId === field.id;
|
|
1596
1763
|
const wrapStyle = {
|
|
1597
1764
|
transform: import_utilities.CSS.Transform.toString(transform),
|
|
1598
1765
|
transition
|
|
1599
1766
|
};
|
|
1600
|
-
return /* @__PURE__ */
|
|
1767
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
1601
1768
|
"div",
|
|
1602
1769
|
{
|
|
1603
1770
|
ref: setNodeRef,
|
|
@@ -1606,16 +1773,16 @@ function SortableFieldCard({ field, blockId, index }) {
|
|
|
1606
1773
|
...attributes,
|
|
1607
1774
|
...listeners
|
|
1608
1775
|
},
|
|
1609
|
-
/* @__PURE__ */
|
|
1776
|
+
/* @__PURE__ */ import_react10.default.createElement(
|
|
1610
1777
|
"div",
|
|
1611
1778
|
{
|
|
1612
1779
|
className: `bb-field-card${isActive ? " bb-field-card--active" : ""}`,
|
|
1613
1780
|
onClick: () => setActiveField(isActive ? null : field.id)
|
|
1614
1781
|
},
|
|
1615
|
-
/* @__PURE__ */
|
|
1616
|
-
/* @__PURE__ */
|
|
1617
|
-
/* @__PURE__ */
|
|
1618
|
-
/* @__PURE__ */
|
|
1782
|
+
/* @__PURE__ */ import_react10.default.createElement("span", { className: "bb-field-card__icon" }, /* @__PURE__ */ import_react10.default.createElement(FieldIcon, { type: field.type })),
|
|
1783
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-field-card__body" }, /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-field-card__name" }, field.name || /* @__PURE__ */ import_react10.default.createElement("span", { className: "bb-field-card__name--empty" }, "unnamed")), /* @__PURE__ */ import_react10.default.createElement("div", { className: "bb-field-card__type" }, field.type, field.required && /* @__PURE__ */ import_react10.default.createElement("span", { className: "bb-field-card__required" }, "*"))),
|
|
1784
|
+
/* @__PURE__ */ import_react10.default.createElement("span", { className: "bb-field-card__index" }, "#", index + 1),
|
|
1785
|
+
!isReadOnly && /* @__PURE__ */ import_react10.default.createElement(
|
|
1619
1786
|
"button",
|
|
1620
1787
|
{
|
|
1621
1788
|
type: "button",
|
|
@@ -1627,11 +1794,15 @@ function SortableFieldCard({ field, blockId, index }) {
|
|
|
1627
1794
|
className: "bb-field-card__delete",
|
|
1628
1795
|
title: "Remove field"
|
|
1629
1796
|
},
|
|
1630
|
-
|
|
1797
|
+
/* @__PURE__ */ import_react10.default.createElement(import_lucide_react3.X, { size: 12, strokeWidth: 2 })
|
|
1631
1798
|
)
|
|
1632
1799
|
)
|
|
1633
1800
|
);
|
|
1634
1801
|
}
|
|
1802
|
+
function FieldIcon({ type }) {
|
|
1803
|
+
const Icon = ICON_MAP[type];
|
|
1804
|
+
return Icon ? /* @__PURE__ */ import_react10.default.createElement(Icon, { size: 13, strokeWidth: 1.75 }) : null;
|
|
1805
|
+
}
|
|
1635
1806
|
|
|
1636
1807
|
// src/block-builder/components/canvas/BuilderCanvas.tsx
|
|
1637
1808
|
function BuilderCanvas() {
|
|
@@ -1654,9 +1825,9 @@ function BuilderCanvas() {
|
|
|
1654
1825
|
}
|
|
1655
1826
|
}
|
|
1656
1827
|
if (!block) {
|
|
1657
|
-
return /* @__PURE__ */
|
|
1828
|
+
return /* @__PURE__ */ import_react11.default.createElement("div", { className: "bb-canvas", style: { display: "flex", alignItems: "center", justifyContent: "center" } }, /* @__PURE__ */ import_react11.default.createElement("span", { className: "bb-canvas__no-block" }, "Select or create a block from the left panel."));
|
|
1658
1829
|
}
|
|
1659
|
-
return /* @__PURE__ */
|
|
1830
|
+
return /* @__PURE__ */ import_react11.default.createElement("div", { className: `bb-canvas${isReadOnly ? " bb-canvas--readonly" : ""}` }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "bb-canvas__inner" }, /* @__PURE__ */ import_react11.default.createElement("div", { className: "bb-canvas__header" }, block.slug, " - ", block.fields.length, " field", block.fields.length !== 1 ? "s" : ""), block.fields.length === 0 ? /* @__PURE__ */ import_react11.default.createElement("div", { className: "bb-canvas__empty" }, "Add fields from the palette on the left") : /* @__PURE__ */ import_react11.default.createElement(
|
|
1660
1831
|
import_core.DndContext,
|
|
1661
1832
|
{
|
|
1662
1833
|
sensors,
|
|
@@ -1664,13 +1835,13 @@ function BuilderCanvas() {
|
|
|
1664
1835
|
modifiers: [import_modifiers.restrictToVerticalAxis, import_modifiers.restrictToParentElement],
|
|
1665
1836
|
onDragEnd: handleDragEnd
|
|
1666
1837
|
},
|
|
1667
|
-
/* @__PURE__ */
|
|
1838
|
+
/* @__PURE__ */ import_react11.default.createElement(
|
|
1668
1839
|
import_sortable2.SortableContext,
|
|
1669
1840
|
{
|
|
1670
1841
|
items: block.fields.map((f) => f.id),
|
|
1671
1842
|
strategy: import_sortable2.verticalListSortingStrategy
|
|
1672
1843
|
},
|
|
1673
|
-
/* @__PURE__ */
|
|
1844
|
+
/* @__PURE__ */ import_react11.default.createElement("div", { className: "bb-canvas__field-list" }, block.fields.map((field, i) => /* @__PURE__ */ import_react11.default.createElement(
|
|
1674
1845
|
SortableFieldCard,
|
|
1675
1846
|
{
|
|
1676
1847
|
key: field.id,
|
|
@@ -1684,18 +1855,18 @@ function BuilderCanvas() {
|
|
|
1684
1855
|
}
|
|
1685
1856
|
|
|
1686
1857
|
// src/block-builder/components/canvas/ConfigPanel.tsx
|
|
1687
|
-
var
|
|
1858
|
+
var import_react14 = __toESM(require("react"), 1);
|
|
1688
1859
|
|
|
1689
1860
|
// src/block-builder/components/config/BlockConfig.tsx
|
|
1690
|
-
var
|
|
1861
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
1691
1862
|
function BlockConfig() {
|
|
1692
1863
|
const activeBlockId = useBuilderStore((s) => s.activeBlockId);
|
|
1693
1864
|
const block = useBuilderStore((s) => s.blocks.find((b) => b.id === activeBlockId));
|
|
1694
1865
|
const updateBlock = useBuilderStore((s) => s.updateBlock);
|
|
1695
1866
|
if (!block) {
|
|
1696
|
-
return /* @__PURE__ */
|
|
1867
|
+
return /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-form__empty" }, "No block selected.");
|
|
1697
1868
|
}
|
|
1698
|
-
return /* @__PURE__ */
|
|
1869
|
+
return /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-form" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react12.default.createElement("label", { className: "bb-form__label" }, "Slug *"), /* @__PURE__ */ import_react12.default.createElement(
|
|
1699
1870
|
"input",
|
|
1700
1871
|
{
|
|
1701
1872
|
type: "text",
|
|
@@ -1704,7 +1875,7 @@ function BlockConfig() {
|
|
|
1704
1875
|
placeholder: "myBlock",
|
|
1705
1876
|
className: "bb-input"
|
|
1706
1877
|
}
|
|
1707
|
-
), /* @__PURE__ */
|
|
1878
|
+
), /* @__PURE__ */ import_react12.default.createElement("span", { className: "bb-form__hint" }, "Unique identifier used in code and database")), /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react12.default.createElement("label", { className: "bb-form__label" }, "Interface Name"), /* @__PURE__ */ import_react12.default.createElement(
|
|
1708
1879
|
"input",
|
|
1709
1880
|
{
|
|
1710
1881
|
type: "text",
|
|
@@ -1713,7 +1884,7 @@ function BlockConfig() {
|
|
|
1713
1884
|
placeholder: "MyBlock",
|
|
1714
1885
|
className: "bb-input"
|
|
1715
1886
|
}
|
|
1716
|
-
)), /* @__PURE__ */
|
|
1887
|
+
)), /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-grid-2" }, /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react12.default.createElement("label", { className: "bb-form__label" }, "Singular Label"), /* @__PURE__ */ import_react12.default.createElement(
|
|
1717
1888
|
"input",
|
|
1718
1889
|
{
|
|
1719
1890
|
type: "text",
|
|
@@ -1722,7 +1893,7 @@ function BlockConfig() {
|
|
|
1722
1893
|
placeholder: "My Block",
|
|
1723
1894
|
className: "bb-input"
|
|
1724
1895
|
}
|
|
1725
|
-
)), /* @__PURE__ */
|
|
1896
|
+
)), /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react12.default.createElement("label", { className: "bb-form__label" }, "Plural Label"), /* @__PURE__ */ import_react12.default.createElement(
|
|
1726
1897
|
"input",
|
|
1727
1898
|
{
|
|
1728
1899
|
type: "text",
|
|
@@ -1731,7 +1902,7 @@ function BlockConfig() {
|
|
|
1731
1902
|
placeholder: "My Blocks",
|
|
1732
1903
|
className: "bb-input"
|
|
1733
1904
|
}
|
|
1734
|
-
))), /* @__PURE__ */
|
|
1905
|
+
))), /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react12.default.createElement("label", { className: "bb-form__label" }, "Image URL"), /* @__PURE__ */ import_react12.default.createElement(
|
|
1735
1906
|
"input",
|
|
1736
1907
|
{
|
|
1737
1908
|
type: "text",
|
|
@@ -1740,29 +1911,23 @@ function BlockConfig() {
|
|
|
1740
1911
|
placeholder: "https://...",
|
|
1741
1912
|
className: "bb-input"
|
|
1742
1913
|
}
|
|
1743
|
-
)), /* @__PURE__ */
|
|
1914
|
+
)), /* @__PURE__ */ import_react12.default.createElement("div", { className: "bb-stat-box" }, /* @__PURE__ */ import_react12.default.createElement("strong", null, block.fields.length), " field", block.fields.length !== 1 ? "s" : "", " defined"));
|
|
1744
1915
|
}
|
|
1745
1916
|
|
|
1746
1917
|
// src/block-builder/components/config/FieldConfig.tsx
|
|
1747
|
-
var
|
|
1918
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
1748
1919
|
var ALL_TYPES = [
|
|
1749
1920
|
"text",
|
|
1750
1921
|
"textarea",
|
|
1751
|
-
"richText",
|
|
1752
1922
|
"number",
|
|
1923
|
+
"email",
|
|
1924
|
+
"date",
|
|
1753
1925
|
"checkbox",
|
|
1754
1926
|
"select",
|
|
1755
1927
|
"radio",
|
|
1756
|
-
"date",
|
|
1757
1928
|
"upload",
|
|
1758
|
-
"email",
|
|
1759
|
-
"code",
|
|
1760
|
-
"point",
|
|
1761
1929
|
"relationship",
|
|
1762
|
-
"
|
|
1763
|
-
"group",
|
|
1764
|
-
"json",
|
|
1765
|
-
"ui"
|
|
1930
|
+
"json"
|
|
1766
1931
|
];
|
|
1767
1932
|
function FieldConfig() {
|
|
1768
1933
|
const activeBlockId = useBuilderStore((s) => s.activeBlockId);
|
|
@@ -1771,13 +1936,13 @@ function FieldConfig() {
|
|
|
1771
1936
|
const field = block?.fields.find((f) => f.id === activeFieldId);
|
|
1772
1937
|
const updateField = useBuilderStore((s) => s.updateField);
|
|
1773
1938
|
if (!activeBlockId || !activeFieldId || !field) {
|
|
1774
|
-
return /* @__PURE__ */
|
|
1939
|
+
return /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__empty" }, "Select a field to configure it.");
|
|
1775
1940
|
}
|
|
1776
1941
|
function upd(updates) {
|
|
1777
1942
|
updateField(activeBlockId, activeFieldId, updates);
|
|
1778
1943
|
}
|
|
1779
1944
|
const needsOptions = field.type === "select" || field.type === "radio";
|
|
1780
|
-
return /* @__PURE__ */
|
|
1945
|
+
return /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-grid-2" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-form__label" }, "Field Name *"), /* @__PURE__ */ import_react13.default.createElement(
|
|
1781
1946
|
"input",
|
|
1782
1947
|
{
|
|
1783
1948
|
type: "text",
|
|
@@ -1786,15 +1951,15 @@ function FieldConfig() {
|
|
|
1786
1951
|
placeholder: "fieldName",
|
|
1787
1952
|
className: "bb-input"
|
|
1788
1953
|
}
|
|
1789
|
-
)), /* @__PURE__ */
|
|
1954
|
+
)), /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-form__label" }, "Type *"), /* @__PURE__ */ import_react13.default.createElement(
|
|
1790
1955
|
"select",
|
|
1791
1956
|
{
|
|
1792
1957
|
value: field.type,
|
|
1793
1958
|
onChange: (e) => upd({ type: e.target.value }),
|
|
1794
1959
|
className: "bb-input bb-select"
|
|
1795
1960
|
},
|
|
1796
|
-
ALL_TYPES.map((t) => /* @__PURE__ */
|
|
1797
|
-
))), /* @__PURE__ */
|
|
1961
|
+
ALL_TYPES.map((t) => /* @__PURE__ */ import_react13.default.createElement("option", { key: t, value: t }, t))
|
|
1962
|
+
))), /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-form__label" }, "Label"), /* @__PURE__ */ import_react13.default.createElement(
|
|
1798
1963
|
"input",
|
|
1799
1964
|
{
|
|
1800
1965
|
type: "text",
|
|
@@ -1803,28 +1968,28 @@ function FieldConfig() {
|
|
|
1803
1968
|
placeholder: "Human-readable label",
|
|
1804
1969
|
className: "bb-input"
|
|
1805
1970
|
}
|
|
1806
|
-
)), /* @__PURE__ */
|
|
1971
|
+
)), /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-flags-row" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-checkbox-row" }, /* @__PURE__ */ import_react13.default.createElement(
|
|
1807
1972
|
"input",
|
|
1808
1973
|
{
|
|
1809
1974
|
type: "checkbox",
|
|
1810
1975
|
checked: field.required ?? false,
|
|
1811
1976
|
onChange: (e) => upd({ required: e.target.checked })
|
|
1812
1977
|
}
|
|
1813
|
-
), "Required"), /* @__PURE__ */
|
|
1978
|
+
), "Required"), /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-checkbox-row" }, /* @__PURE__ */ import_react13.default.createElement(
|
|
1814
1979
|
"input",
|
|
1815
1980
|
{
|
|
1816
1981
|
type: "checkbox",
|
|
1817
1982
|
checked: field.unique ?? false,
|
|
1818
1983
|
onChange: (e) => upd({ unique: e.target.checked })
|
|
1819
1984
|
}
|
|
1820
|
-
), "Unique"), /* @__PURE__ */
|
|
1985
|
+
), "Unique"), /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-checkbox-row" }, /* @__PURE__ */ import_react13.default.createElement(
|
|
1821
1986
|
"input",
|
|
1822
1987
|
{
|
|
1823
1988
|
type: "checkbox",
|
|
1824
1989
|
checked: field.localized ?? false,
|
|
1825
1990
|
onChange: (e) => upd({ localized: e.target.checked })
|
|
1826
1991
|
}
|
|
1827
|
-
), "Localized")), /* @__PURE__ */
|
|
1992
|
+
), "Localized")), /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-form__label" }, "Default Value"), /* @__PURE__ */ import_react13.default.createElement(
|
|
1828
1993
|
"input",
|
|
1829
1994
|
{
|
|
1830
1995
|
type: "text",
|
|
@@ -1833,7 +1998,7 @@ function FieldConfig() {
|
|
|
1833
1998
|
placeholder: "Default value",
|
|
1834
1999
|
className: "bb-input"
|
|
1835
2000
|
}
|
|
1836
|
-
)), field.type === "relationship" && /* @__PURE__ */
|
|
2001
|
+
)), field.type === "relationship" && /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, null, /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-form__label" }, "Relation To (collection slug)"), /* @__PURE__ */ import_react13.default.createElement(
|
|
1837
2002
|
"input",
|
|
1838
2003
|
{
|
|
1839
2004
|
type: "text",
|
|
@@ -1842,14 +2007,14 @@ function FieldConfig() {
|
|
|
1842
2007
|
placeholder: "pages",
|
|
1843
2008
|
className: "bb-input"
|
|
1844
2009
|
}
|
|
1845
|
-
)), /* @__PURE__ */
|
|
2010
|
+
)), /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-checkbox-row" }, /* @__PURE__ */ import_react13.default.createElement(
|
|
1846
2011
|
"input",
|
|
1847
2012
|
{
|
|
1848
2013
|
type: "checkbox",
|
|
1849
2014
|
checked: field.hasMany ?? false,
|
|
1850
2015
|
onChange: (e) => upd({ hasMany: e.target.checked })
|
|
1851
2016
|
}
|
|
1852
|
-
), "Has Many")), field.type === "array" && /* @__PURE__ */
|
|
2017
|
+
), "Has Many")), field.type === "array" && /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-grid-2" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-form__label" }, "Min Rows"), /* @__PURE__ */ import_react13.default.createElement(
|
|
1853
2018
|
"input",
|
|
1854
2019
|
{
|
|
1855
2020
|
type: "number",
|
|
@@ -1857,7 +2022,7 @@ function FieldConfig() {
|
|
|
1857
2022
|
onChange: (e) => upd({ minRows: e.target.value === "" ? void 0 : e.target.valueAsNumber }),
|
|
1858
2023
|
className: "bb-input"
|
|
1859
2024
|
}
|
|
1860
|
-
)), /* @__PURE__ */
|
|
2025
|
+
)), /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("label", { className: "bb-form__label" }, "Max Rows"), /* @__PURE__ */ import_react13.default.createElement(
|
|
1861
2026
|
"input",
|
|
1862
2027
|
{
|
|
1863
2028
|
type: "number",
|
|
@@ -1865,7 +2030,7 @@ function FieldConfig() {
|
|
|
1865
2030
|
onChange: (e) => upd({ maxRows: e.target.value === "" ? void 0 : e.target.valueAsNumber }),
|
|
1866
2031
|
className: "bb-input"
|
|
1867
2032
|
}
|
|
1868
|
-
))), needsOptions && /* @__PURE__ */
|
|
2033
|
+
))), needsOptions && /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-form__section" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "bb-options-label" }, "Options"), (field.options ?? []).map((opt, i) => /* @__PURE__ */ import_react13.default.createElement("div", { key: i, className: "bb-option-row" }, /* @__PURE__ */ import_react13.default.createElement(
|
|
1869
2034
|
"input",
|
|
1870
2035
|
{
|
|
1871
2036
|
type: "text",
|
|
@@ -1878,7 +2043,7 @@ function FieldConfig() {
|
|
|
1878
2043
|
},
|
|
1879
2044
|
className: "bb-input"
|
|
1880
2045
|
}
|
|
1881
|
-
), /* @__PURE__ */
|
|
2046
|
+
), /* @__PURE__ */ import_react13.default.createElement(
|
|
1882
2047
|
"input",
|
|
1883
2048
|
{
|
|
1884
2049
|
type: "text",
|
|
@@ -1891,7 +2056,7 @@ function FieldConfig() {
|
|
|
1891
2056
|
},
|
|
1892
2057
|
className: "bb-input"
|
|
1893
2058
|
}
|
|
1894
|
-
), /* @__PURE__ */
|
|
2059
|
+
), /* @__PURE__ */ import_react13.default.createElement(
|
|
1895
2060
|
"button",
|
|
1896
2061
|
{
|
|
1897
2062
|
type: "button",
|
|
@@ -1903,7 +2068,7 @@ function FieldConfig() {
|
|
|
1903
2068
|
title: "Remove option"
|
|
1904
2069
|
},
|
|
1905
2070
|
"x"
|
|
1906
|
-
))), /* @__PURE__ */
|
|
2071
|
+
))), /* @__PURE__ */ import_react13.default.createElement(
|
|
1907
2072
|
"button",
|
|
1908
2073
|
{
|
|
1909
2074
|
type: "button",
|
|
@@ -1916,11 +2081,11 @@ function FieldConfig() {
|
|
|
1916
2081
|
|
|
1917
2082
|
// src/block-builder/components/canvas/ConfigPanel.tsx
|
|
1918
2083
|
function ConfigPanel() {
|
|
1919
|
-
const [tab, setTab] = (0,
|
|
2084
|
+
const [tab, setTab] = (0, import_react14.useState)("block");
|
|
1920
2085
|
const activeFieldId = useBuilderStore((s) => s.activeFieldId);
|
|
1921
2086
|
const isReadOnly = useBuilderStore((s) => s.isReadOnly);
|
|
1922
2087
|
const activeTab = activeFieldId ? "field" : tab;
|
|
1923
|
-
return /* @__PURE__ */
|
|
2088
|
+
return /* @__PURE__ */ import_react14.default.createElement("div", { className: `bb-config${isReadOnly ? " bb-config--readonly" : ""}` }, /* @__PURE__ */ import_react14.default.createElement("div", { className: "bb-config__tabs" }, ["block", "field"].map((t) => /* @__PURE__ */ import_react14.default.createElement(
|
|
1924
2089
|
"button",
|
|
1925
2090
|
{
|
|
1926
2091
|
key: t,
|
|
@@ -1929,12 +2094,12 @@ function ConfigPanel() {
|
|
|
1929
2094
|
className: `bb-config__tab${activeTab === t ? " bb-config__tab--active" : ""}`
|
|
1930
2095
|
},
|
|
1931
2096
|
t
|
|
1932
|
-
))), /* @__PURE__ */
|
|
2097
|
+
))), /* @__PURE__ */ import_react14.default.createElement("div", { className: "bb-config__body" }, activeTab === "block" ? /* @__PURE__ */ import_react14.default.createElement(BlockConfig, null) : /* @__PURE__ */ import_react14.default.createElement(FieldConfig, null)), isReadOnly && /* @__PURE__ */ import_react14.default.createElement("div", { className: "bb-config__readonly-overlay" }, /* @__PURE__ */ import_react14.default.createElement("span", { className: "bb-config__readonly-label" }, "Read only")));
|
|
1933
2098
|
}
|
|
1934
2099
|
|
|
1935
2100
|
// src/block-builder/components/sidebar/FieldPalette.tsx
|
|
1936
|
-
var
|
|
1937
|
-
var
|
|
2101
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
2102
|
+
var import_lucide_react4 = require("lucide-react");
|
|
1938
2103
|
|
|
1939
2104
|
// src/block-builder/lib/field-palette.ts
|
|
1940
2105
|
var FIELD_PALETTE = [
|
|
@@ -1968,22 +2133,23 @@ function getFieldMeta(type) {
|
|
|
1968
2133
|
|
|
1969
2134
|
// src/block-builder/components/sidebar/FieldPalette.tsx
|
|
1970
2135
|
var ICON_MAP2 = {
|
|
1971
|
-
Type:
|
|
1972
|
-
AlignLeft:
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2136
|
+
Type: import_lucide_react4.Type,
|
|
2137
|
+
AlignLeft: import_lucide_react4.AlignLeft,
|
|
2138
|
+
AlignJustify: import_lucide_react4.AlignJustify,
|
|
2139
|
+
Hash: import_lucide_react4.Hash,
|
|
2140
|
+
Mail: import_lucide_react4.Mail,
|
|
2141
|
+
Calendar: import_lucide_react4.Calendar,
|
|
2142
|
+
CheckSquare: import_lucide_react4.CheckSquare,
|
|
2143
|
+
ChevronDown: import_lucide_react4.ChevronDown,
|
|
2144
|
+
Circle: import_lucide_react4.Circle,
|
|
2145
|
+
Upload: import_lucide_react4.Upload,
|
|
2146
|
+
Link: import_lucide_react4.Link,
|
|
2147
|
+
List: import_lucide_react4.List,
|
|
2148
|
+
Folder: import_lucide_react4.Folder,
|
|
2149
|
+
Braces: import_lucide_react4.Braces
|
|
1984
2150
|
};
|
|
1985
2151
|
function FieldPalette() {
|
|
1986
|
-
const [search, setSearch] = (0,
|
|
2152
|
+
const [search, setSearch] = (0, import_react15.useState)("");
|
|
1987
2153
|
const activeBlockId = useBuilderStore((s) => s.activeBlockId);
|
|
1988
2154
|
const addField = useBuilderStore((s) => s.addField);
|
|
1989
2155
|
const isReadOnly = useBuilderStore((s) => s.isReadOnly);
|
|
@@ -1994,7 +2160,7 @@ function FieldPalette() {
|
|
|
1994
2160
|
if (!activeBlockId || isReadOnly) return;
|
|
1995
2161
|
addField(activeBlockId, type);
|
|
1996
2162
|
}
|
|
1997
|
-
return /* @__PURE__ */
|
|
2163
|
+
return /* @__PURE__ */ import_react15.default.createElement("div", { className: `bb-sidebar bb-sidebar--200 bb-sidebar--palette${isReadOnly ? " bb-sidebar--readonly" : ""}` }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "bb-sidebar__header" }, /* @__PURE__ */ import_react15.default.createElement("span", { className: "bb-sidebar__title" }, "Fields")), /* @__PURE__ */ import_react15.default.createElement("div", { className: "bb-palette__search-wrap" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
1998
2164
|
"input",
|
|
1999
2165
|
{
|
|
2000
2166
|
type: "text",
|
|
@@ -2003,7 +2169,7 @@ function FieldPalette() {
|
|
|
2003
2169
|
placeholder: "Search...",
|
|
2004
2170
|
className: "bb-palette__search"
|
|
2005
2171
|
}
|
|
2006
|
-
)), /* @__PURE__ */
|
|
2172
|
+
)), /* @__PURE__ */ import_react15.default.createElement("div", { className: "bb-sidebar__body" }, search.trim() ? /* @__PURE__ */ import_react15.default.createElement("div", { className: "bb-palette__items" }, filtered.map((item) => /* @__PURE__ */ import_react15.default.createElement(
|
|
2007
2173
|
FieldButton,
|
|
2008
2174
|
{
|
|
2009
2175
|
key: item.type,
|
|
@@ -2015,7 +2181,7 @@ function FieldPalette() {
|
|
|
2015
2181
|
}
|
|
2016
2182
|
))) : FIELD_CATEGORIES.map((cat) => {
|
|
2017
2183
|
const items = FIELD_PALETTE.filter((f) => f.category === cat.id);
|
|
2018
|
-
return /* @__PURE__ */
|
|
2184
|
+
return /* @__PURE__ */ import_react15.default.createElement("div", { key: cat.id, style: { marginTop: 6 } }, /* @__PURE__ */ import_react15.default.createElement("div", { className: "bb-palette__cat-label" }, cat.label), /* @__PURE__ */ import_react15.default.createElement("div", { className: "bb-palette__items" }, items.map((item) => /* @__PURE__ */ import_react15.default.createElement(
|
|
2019
2185
|
FieldButton,
|
|
2020
2186
|
{
|
|
2021
2187
|
key: item.type,
|
|
@@ -2026,7 +2192,7 @@ function FieldPalette() {
|
|
|
2026
2192
|
disabled: !activeBlockId || isReadOnly
|
|
2027
2193
|
}
|
|
2028
2194
|
))));
|
|
2029
|
-
})), !activeBlockId && /* @__PURE__ */
|
|
2195
|
+
})), !activeBlockId && /* @__PURE__ */ import_react15.default.createElement("div", { className: "bb-sidebar__footer" }, "Select a block first"));
|
|
2030
2196
|
}
|
|
2031
2197
|
function FieldButton({
|
|
2032
2198
|
type,
|
|
@@ -2037,7 +2203,7 @@ function FieldButton({
|
|
|
2037
2203
|
}) {
|
|
2038
2204
|
const meta = getFieldMeta(type);
|
|
2039
2205
|
const Icon = ICON_MAP2[icon];
|
|
2040
|
-
return /* @__PURE__ */
|
|
2206
|
+
return /* @__PURE__ */ import_react15.default.createElement(
|
|
2041
2207
|
"button",
|
|
2042
2208
|
{
|
|
2043
2209
|
type: "button",
|
|
@@ -2046,14 +2212,14 @@ function FieldButton({
|
|
|
2046
2212
|
title: meta?.description,
|
|
2047
2213
|
className: "bb-palette__item"
|
|
2048
2214
|
},
|
|
2049
|
-
/* @__PURE__ */
|
|
2050
|
-
/* @__PURE__ */
|
|
2051
|
-
/* @__PURE__ */
|
|
2215
|
+
/* @__PURE__ */ import_react15.default.createElement("span", { className: "bb-palette__item__icon" }, Icon ? /* @__PURE__ */ import_react15.default.createElement(Icon, { size: 13, strokeWidth: 1.75 }) : null),
|
|
2216
|
+
/* @__PURE__ */ import_react15.default.createElement("span", { className: "bb-palette__item__label" }, label),
|
|
2217
|
+
/* @__PURE__ */ import_react15.default.createElement("span", { className: "bb-palette__item__type" }, type)
|
|
2052
2218
|
);
|
|
2053
2219
|
}
|
|
2054
2220
|
|
|
2055
2221
|
// src/block-builder/components/canvas/CodePreview.tsx
|
|
2056
|
-
var
|
|
2222
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
2057
2223
|
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
2058
2224
|
"import",
|
|
2059
2225
|
"export",
|
|
@@ -2141,16 +2307,16 @@ var TOKEN_COLORS = {
|
|
|
2141
2307
|
};
|
|
2142
2308
|
function HighlightedCode({ code }) {
|
|
2143
2309
|
const tokens = tokenise(code);
|
|
2144
|
-
return /* @__PURE__ */
|
|
2310
|
+
return /* @__PURE__ */ import_react16.default.createElement("code", { style: { fontFamily: "inherit" } }, tokens.map((tok, i) => /* @__PURE__ */ import_react16.default.createElement("span", { key: i, style: { color: TOKEN_COLORS[tok.kind] } }, tok.text)));
|
|
2145
2311
|
}
|
|
2146
2312
|
function CodePreview() {
|
|
2147
2313
|
const blocks = useBuilderStore((s) => s.blocks);
|
|
2148
|
-
const [fileMap, setFileMap] = (0,
|
|
2149
|
-
const [activeFile, setActiveFile] = (0,
|
|
2150
|
-
const [copied, setCopied] = (0,
|
|
2151
|
-
const timerRef = (0,
|
|
2152
|
-
const copyTimerRef = (0,
|
|
2153
|
-
const regenerate = (0,
|
|
2314
|
+
const [fileMap, setFileMap] = (0, import_react16.useState)({});
|
|
2315
|
+
const [activeFile, setActiveFile] = (0, import_react16.useState)(null);
|
|
2316
|
+
const [copied, setCopied] = (0, import_react16.useState)(false);
|
|
2317
|
+
const timerRef = (0, import_react16.useRef)(null);
|
|
2318
|
+
const copyTimerRef = (0, import_react16.useRef)(null);
|
|
2319
|
+
const regenerate = (0, import_react16.useCallback)(() => {
|
|
2154
2320
|
if (blocks.length === 0) {
|
|
2155
2321
|
setFileMap({});
|
|
2156
2322
|
setActiveFile(null);
|
|
@@ -2167,7 +2333,7 @@ function CodePreview() {
|
|
|
2167
2333
|
return prev && keys.includes(prev) ? prev : keys[0] ?? null;
|
|
2168
2334
|
});
|
|
2169
2335
|
}, [blocks]);
|
|
2170
|
-
(0,
|
|
2336
|
+
(0, import_react16.useEffect)(() => {
|
|
2171
2337
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
2172
2338
|
timerRef.current = setTimeout(regenerate, 300);
|
|
2173
2339
|
return () => {
|
|
@@ -2186,7 +2352,7 @@ function CodePreview() {
|
|
|
2186
2352
|
const activeCode = activeFile ? fileMap[activeFile] ?? "" : "";
|
|
2187
2353
|
const lineCount = activeCode ? activeCode.split("\n").length : 0;
|
|
2188
2354
|
if (fileNames.length === 0) {
|
|
2189
|
-
return /* @__PURE__ */
|
|
2355
|
+
return /* @__PURE__ */ import_react16.default.createElement(
|
|
2190
2356
|
"div",
|
|
2191
2357
|
{
|
|
2192
2358
|
className: "code-preview",
|
|
@@ -2203,7 +2369,7 @@ function CodePreview() {
|
|
|
2203
2369
|
"Add a block to see generated TypeScript code"
|
|
2204
2370
|
);
|
|
2205
2371
|
}
|
|
2206
|
-
return /* @__PURE__ */
|
|
2372
|
+
return /* @__PURE__ */ import_react16.default.createElement("div", { className: "code-preview", style: { height: "100%", display: "flex", flexDirection: "column", overflow: "hidden" } }, /* @__PURE__ */ import_react16.default.createElement(
|
|
2207
2373
|
"div",
|
|
2208
2374
|
{
|
|
2209
2375
|
style: {
|
|
@@ -2217,7 +2383,7 @@ function CodePreview() {
|
|
|
2217
2383
|
},
|
|
2218
2384
|
fileNames.map((name) => {
|
|
2219
2385
|
const isActive = activeFile === name;
|
|
2220
|
-
return /* @__PURE__ */
|
|
2386
|
+
return /* @__PURE__ */ import_react16.default.createElement(
|
|
2221
2387
|
"button",
|
|
2222
2388
|
{
|
|
2223
2389
|
key: name,
|
|
@@ -2240,8 +2406,8 @@ function CodePreview() {
|
|
|
2240
2406
|
name
|
|
2241
2407
|
);
|
|
2242
2408
|
}),
|
|
2243
|
-
/* @__PURE__ */
|
|
2244
|
-
lineCount > 0 && /* @__PURE__ */
|
|
2409
|
+
/* @__PURE__ */ import_react16.default.createElement("div", { style: { flex: 1 } }),
|
|
2410
|
+
lineCount > 0 && /* @__PURE__ */ import_react16.default.createElement(
|
|
2245
2411
|
"span",
|
|
2246
2412
|
{
|
|
2247
2413
|
style: {
|
|
@@ -2254,7 +2420,7 @@ function CodePreview() {
|
|
|
2254
2420
|
lineCount,
|
|
2255
2421
|
" lines"
|
|
2256
2422
|
),
|
|
2257
|
-
/* @__PURE__ */
|
|
2423
|
+
/* @__PURE__ */ import_react16.default.createElement(
|
|
2258
2424
|
"button",
|
|
2259
2425
|
{
|
|
2260
2426
|
type: "button",
|
|
@@ -2277,7 +2443,7 @@ function CodePreview() {
|
|
|
2277
2443
|
},
|
|
2278
2444
|
copied ? "Copied" : "Copy"
|
|
2279
2445
|
)
|
|
2280
|
-
), /* @__PURE__ */
|
|
2446
|
+
), /* @__PURE__ */ import_react16.default.createElement("div", { style: { flex: 1, overflow: "auto", display: "flex" } }, /* @__PURE__ */ import_react16.default.createElement(
|
|
2281
2447
|
"div",
|
|
2282
2448
|
{
|
|
2283
2449
|
style: {
|
|
@@ -2294,8 +2460,8 @@ function CodePreview() {
|
|
|
2294
2460
|
},
|
|
2295
2461
|
"aria-hidden": "true"
|
|
2296
2462
|
},
|
|
2297
|
-
activeCode.split("\n").map((_, i) => /* @__PURE__ */
|
|
2298
|
-
), /* @__PURE__ */
|
|
2463
|
+
activeCode.split("\n").map((_, i) => /* @__PURE__ */ import_react16.default.createElement("div", { key: i }, i + 1))
|
|
2464
|
+
), /* @__PURE__ */ import_react16.default.createElement(
|
|
2299
2465
|
"pre",
|
|
2300
2466
|
{
|
|
2301
2467
|
style: {
|
|
@@ -2310,7 +2476,7 @@ function CodePreview() {
|
|
|
2310
2476
|
whiteSpace: "pre"
|
|
2311
2477
|
}
|
|
2312
2478
|
},
|
|
2313
|
-
/* @__PURE__ */
|
|
2479
|
+
/* @__PURE__ */ import_react16.default.createElement(HighlightedCode, { code: activeCode })
|
|
2314
2480
|
)));
|
|
2315
2481
|
}
|
|
2316
2482
|
|
|
@@ -2320,23 +2486,25 @@ function BuilderShell({ loadSlug }) {
|
|
|
2320
2486
|
const setVersionMeta = useBuilderStore((s) => s.setVersionMeta);
|
|
2321
2487
|
const setBlockSlug = useBuilderStore((s) => s.setBlockSlug);
|
|
2322
2488
|
const isReadOnly = useBuilderStore((s) => s.isReadOnly);
|
|
2323
|
-
const [activeSlug, setActiveSlug] = (0,
|
|
2324
|
-
const [loading, setLoading] = (0,
|
|
2325
|
-
const [
|
|
2326
|
-
const [showCodePreview, setShowCodePreview] = (0,
|
|
2327
|
-
const [versions, setVersions] = (0,
|
|
2328
|
-
const [selectedVersionId, setSelectedVersionId] = (0,
|
|
2329
|
-
const [blockDefs, setBlockDefs] = (0,
|
|
2330
|
-
const [mobilePanelTab, setMobilePanelTab] = (0,
|
|
2331
|
-
(0,
|
|
2489
|
+
const [activeSlug, setActiveSlug] = (0, import_react17.useState)(loadSlug ?? null);
|
|
2490
|
+
const [loading, setLoading] = (0, import_react17.useState)(!!loadSlug);
|
|
2491
|
+
const [notification, setNotification] = (0, import_react17.useState)(null);
|
|
2492
|
+
const [showCodePreview, setShowCodePreview] = (0, import_react17.useState)(false);
|
|
2493
|
+
const [versions, setVersions] = (0, import_react17.useState)([]);
|
|
2494
|
+
const [selectedVersionId, setSelectedVersionId] = (0, import_react17.useState)(null);
|
|
2495
|
+
const [blockDefs, setBlockDefs] = (0, import_react17.useState)([]);
|
|
2496
|
+
const [mobilePanelTab, setMobilePanelTab] = (0, import_react17.useState)("blocks");
|
|
2497
|
+
(0, import_react17.useEffect)(() => {
|
|
2332
2498
|
fetch("/api/block-definitions?limit=200&depth=0").then((r) => r.json()).then((json) => {
|
|
2333
2499
|
setBlockDefs(
|
|
2334
2500
|
(json.docs ?? []).map((d) => ({ id: String(d.id), slug: d.slug, name: d.name }))
|
|
2335
2501
|
);
|
|
2336
|
-
}).catch(() => {
|
|
2502
|
+
}).catch((err) => {
|
|
2503
|
+
console.error("[block-builder] Failed to load block definitions:", err);
|
|
2504
|
+
setNotification({ status: "error", title: "Failed to load block definitions", errors: ["Could not load block definitions. Please refresh the page."] });
|
|
2337
2505
|
});
|
|
2338
2506
|
}, []);
|
|
2339
|
-
const loadVersionsForSlug = (0,
|
|
2507
|
+
const loadVersionsForSlug = (0, import_react17.useCallback)(async (slug) => {
|
|
2340
2508
|
try {
|
|
2341
2509
|
const res = await fetch(`/api/block-builder/versions/${encodeURIComponent(slug)}`);
|
|
2342
2510
|
const json = await res.json();
|
|
@@ -2345,9 +2513,9 @@ function BuilderShell({ loadSlug }) {
|
|
|
2345
2513
|
return [];
|
|
2346
2514
|
}
|
|
2347
2515
|
}, []);
|
|
2348
|
-
const loadVersion = (0,
|
|
2516
|
+
const loadVersion = (0, import_react17.useCallback)(async (slug, versionId) => {
|
|
2349
2517
|
setLoading(true);
|
|
2350
|
-
|
|
2518
|
+
setNotification(null);
|
|
2351
2519
|
const url = versionId ? `/api/block-builder/load/${encodeURIComponent(slug)}?versionId=${encodeURIComponent(versionId)}` : `/api/block-builder/load/${encodeURIComponent(slug)}`;
|
|
2352
2520
|
try {
|
|
2353
2521
|
const res = await fetch(url);
|
|
@@ -2357,20 +2525,20 @@ function BuilderShell({ loadSlug }) {
|
|
|
2357
2525
|
setVersionMeta(json.versionId ?? null, !(json.isCurrent ?? true));
|
|
2358
2526
|
setSelectedVersionId(json.versionId ?? null);
|
|
2359
2527
|
} else {
|
|
2360
|
-
|
|
2528
|
+
setNotification({ status: "error", title: "Failed to load block", errors: [json.error ?? "Unknown error"] });
|
|
2361
2529
|
}
|
|
2362
2530
|
} catch (err) {
|
|
2363
|
-
|
|
2531
|
+
setNotification({ status: "error", title: "Network error", errors: [err instanceof Error ? err.message : "Could not reach the server."] });
|
|
2364
2532
|
} finally {
|
|
2365
2533
|
setLoading(false);
|
|
2366
2534
|
}
|
|
2367
2535
|
}, [loadBlock, setVersionMeta]);
|
|
2368
|
-
const loadBlockBySlug = (0,
|
|
2536
|
+
const loadBlockBySlug = (0, import_react17.useCallback)(async (slug) => {
|
|
2369
2537
|
setActiveSlug(slug);
|
|
2370
2538
|
setBlockSlug(slug);
|
|
2371
2539
|
setVersions([]);
|
|
2372
2540
|
setSelectedVersionId(null);
|
|
2373
|
-
|
|
2541
|
+
setNotification(null);
|
|
2374
2542
|
setMobilePanelTab("canvas");
|
|
2375
2543
|
await loadVersion(slug);
|
|
2376
2544
|
const list = await loadVersionsForSlug(slug);
|
|
@@ -2378,7 +2546,7 @@ function BuilderShell({ loadSlug }) {
|
|
|
2378
2546
|
const current = list.find((v) => v.isCurrent) ?? list[0];
|
|
2379
2547
|
if (current) setSelectedVersionId(current.id);
|
|
2380
2548
|
}, [loadVersion, loadVersionsForSlug, setBlockSlug]);
|
|
2381
|
-
(0,
|
|
2549
|
+
(0, import_react17.useEffect)(() => {
|
|
2382
2550
|
if (!loadSlug) return;
|
|
2383
2551
|
loadBlockBySlug(loadSlug);
|
|
2384
2552
|
}, [loadSlug]);
|
|
@@ -2401,7 +2569,7 @@ function BuilderShell({ loadSlug }) {
|
|
|
2401
2569
|
const current = list.find((v) => v.isCurrent) ?? list[0];
|
|
2402
2570
|
if (current) setSelectedVersionId(current.id);
|
|
2403
2571
|
}
|
|
2404
|
-
return /* @__PURE__ */
|
|
2572
|
+
return /* @__PURE__ */ import_react17.default.createElement("div", { className: "bb-shell" }, /* @__PURE__ */ import_react17.default.createElement(
|
|
2405
2573
|
TopBar,
|
|
2406
2574
|
{
|
|
2407
2575
|
blockDefs,
|
|
@@ -2411,9 +2579,11 @@ function BuilderShell({ loadSlug }) {
|
|
|
2411
2579
|
selectedVersionId,
|
|
2412
2580
|
onVersionSelect: handleVersionSelect,
|
|
2413
2581
|
onRestoreVersion: handleRestoreVersion,
|
|
2414
|
-
onAfterPublish: handleAfterPublish
|
|
2582
|
+
onAfterPublish: handleAfterPublish,
|
|
2583
|
+
notification,
|
|
2584
|
+
onSetNotification: setNotification
|
|
2415
2585
|
}
|
|
2416
|
-
), loading && /* @__PURE__ */
|
|
2586
|
+
), loading && /* @__PURE__ */ import_react17.default.createElement("div", { className: "bb-loading-bar" }, "Loading..."), isReadOnly && !loading && /* @__PURE__ */ import_react17.default.createElement("div", { className: "bb-readonly-banner" }, /* @__PURE__ */ import_react17.default.createElement("span", { className: "bb-readonly-banner__icon" }, "[i]"), /* @__PURE__ */ import_react17.default.createElement("span", null, "You are viewing a previous version - read only.", /* @__PURE__ */ import_react17.default.createElement(
|
|
2417
2587
|
"button",
|
|
2418
2588
|
{
|
|
2419
2589
|
type: "button",
|
|
@@ -2421,7 +2591,7 @@ function BuilderShell({ loadSlug }) {
|
|
|
2421
2591
|
onClick: handleRestoreVersion
|
|
2422
2592
|
},
|
|
2423
2593
|
"Switch to latest"
|
|
2424
|
-
))), /* @__PURE__ */
|
|
2594
|
+
))), /* @__PURE__ */ import_react17.default.createElement("div", { className: "bb-main", "data-mobile-panel": mobilePanelTab }, /* @__PURE__ */ import_react17.default.createElement(BlockList, { blockDefs, activeSlug, onBlockSelect: loadBlockBySlug }), /* @__PURE__ */ import_react17.default.createElement("div", { className: "bb-main__center" }, /* @__PURE__ */ import_react17.default.createElement(FieldPalette, null), /* @__PURE__ */ import_react17.default.createElement(BuilderCanvas, null)), /* @__PURE__ */ import_react17.default.createElement(ConfigPanel, null)), /* @__PURE__ */ import_react17.default.createElement("div", { className: "bb-footer" }, /* @__PURE__ */ import_react17.default.createElement(
|
|
2425
2595
|
"button",
|
|
2426
2596
|
{
|
|
2427
2597
|
type: "button",
|
|
@@ -2430,12 +2600,12 @@ function BuilderShell({ loadSlug }) {
|
|
|
2430
2600
|
},
|
|
2431
2601
|
showCodePreview ? "v" : ">",
|
|
2432
2602
|
" Code Preview"
|
|
2433
|
-
), showCodePreview && /* @__PURE__ */
|
|
2603
|
+
), showCodePreview && /* @__PURE__ */ import_react17.default.createElement("div", { className: "bb-footer__content" }, /* @__PURE__ */ import_react17.default.createElement(CodePreview, null))), /* @__PURE__ */ import_react17.default.createElement("nav", { className: "bb-mobile-nav", "aria-label": "Panel navigation" }, [
|
|
2434
2604
|
{ id: "blocks", icon: "B", label: "Blocks" },
|
|
2435
2605
|
{ id: "canvas", icon: "[]", label: "Canvas" },
|
|
2436
2606
|
{ id: "palette", icon: "+", label: "Fields" },
|
|
2437
2607
|
{ id: "config", icon: "*", label: "Config" }
|
|
2438
|
-
].map(({ id, icon, label }) => /* @__PURE__ */
|
|
2608
|
+
].map(({ id, icon, label }) => /* @__PURE__ */ import_react17.default.createElement(
|
|
2439
2609
|
"button",
|
|
2440
2610
|
{
|
|
2441
2611
|
key: id,
|
|
@@ -2443,16 +2613,16 @@ function BuilderShell({ loadSlug }) {
|
|
|
2443
2613
|
className: `bb-mobile-nav__tab${mobilePanelTab === id ? " bb-mobile-nav__tab--active" : ""}`,
|
|
2444
2614
|
onClick: () => setMobilePanelTab(id)
|
|
2445
2615
|
},
|
|
2446
|
-
/* @__PURE__ */
|
|
2616
|
+
/* @__PURE__ */ import_react17.default.createElement("span", { className: "bb-mobile-nav__icon" }, icon),
|
|
2447
2617
|
label
|
|
2448
2618
|
))));
|
|
2449
2619
|
}
|
|
2450
2620
|
|
|
2451
2621
|
// src/components/BlockBuilderNavLink/index.tsx
|
|
2452
|
-
var
|
|
2622
|
+
var import_react18 = __toESM(require("react"), 1);
|
|
2453
2623
|
var import_link = __toESM(require("next/link"), 1);
|
|
2454
2624
|
function BlockBuilderNavLink() {
|
|
2455
|
-
return /* @__PURE__ */
|
|
2625
|
+
return /* @__PURE__ */ import_react18.default.createElement("div", { style: { padding: "0 16px", marginTop: "8px" } }, /* @__PURE__ */ import_react18.default.createElement(
|
|
2456
2626
|
import_link.default,
|
|
2457
2627
|
{
|
|
2458
2628
|
href: "/block-builder",
|
|
@@ -2479,6 +2649,7 @@ function BlockBuilderNavLink() {
|
|
|
2479
2649
|
0 && (module.exports = {
|
|
2480
2650
|
BlockBuilderNavLink,
|
|
2481
2651
|
BlockDataField,
|
|
2652
|
+
BlockVersionSync,
|
|
2482
2653
|
BuilderShell,
|
|
2483
2654
|
EditInBuilderButton,
|
|
2484
2655
|
SchemaBuilderField
|