@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/dist/client.js CHANGED
@@ -39,6 +39,133 @@ function MediaPicker({ label, required, value, onChange }) {
39
39
  "x"
40
40
  ))) : /* @__PURE__ */ React.createElement(ListDrawerToggler, { className: "bdf-upload-btn" }, "Choose from Media Library")), /* @__PURE__ */ React.createElement(ListDrawer, { onSelect: handleSelect }));
41
41
  }
42
+ function toRelDoc(v) {
43
+ if (!v) return null;
44
+ if (typeof v === "object") {
45
+ const o = v;
46
+ if (!o.id) return null;
47
+ return { id: o.id, title: o.title ? String(o.title) : null };
48
+ }
49
+ if (typeof v === "string" || typeof v === "number") return { id: v, title: null };
50
+ return null;
51
+ }
52
+ function RelationshipPicker({ label, required, collection, hasMany = false, value, onChange }) {
53
+ const changeRef = useRef(onChange);
54
+ const closeRef = useRef(() => {
55
+ });
56
+ useEffect(() => {
57
+ changeRef.current = onChange;
58
+ });
59
+ const items = hasMany ? Array.isArray(value) ? value.map(toRelDoc).filter(Boolean) : [] : (() => {
60
+ const d = toRelDoc(value);
61
+ return d ? [d] : [];
62
+ })();
63
+ const itemsRef = useRef(items);
64
+ useEffect(() => {
65
+ itemsRef.current = items;
66
+ });
67
+ const handleSelect = useCallback(
68
+ ({ docID, doc }) => {
69
+ const title = String(doc?.title ?? doc?.name ?? doc?.slug ?? "") || null;
70
+ const entry = { id: docID, title };
71
+ if (hasMany) {
72
+ const alreadyExists = itemsRef.current.some((i) => String(i.id) === String(docID));
73
+ if (!alreadyExists) changeRef.current([...itemsRef.current, entry]);
74
+ } else {
75
+ changeRef.current(entry);
76
+ closeRef.current();
77
+ }
78
+ },
79
+ [hasMany]
80
+ );
81
+ const [ListDrawer, ListDrawerToggler, { closeDrawer, openDrawer }] = useListDrawer({
82
+ collectionSlugs: [collection]
83
+ });
84
+ closeRef.current = closeDrawer;
85
+ const [fetchedTitles, setFetchedTitles] = useState({});
86
+ const fetchingRef = useRef(/* @__PURE__ */ new Set());
87
+ useEffect(() => {
88
+ const missing = items.filter(
89
+ (i) => !i.title && !fetchedTitles[String(i.id)] && !fetchingRef.current.has(String(i.id))
90
+ );
91
+ if (missing.length === 0) return;
92
+ missing.forEach((item) => {
93
+ const idStr = String(item.id);
94
+ fetchingRef.current.add(idStr);
95
+ fetch(`/api/${collection}/${idStr}?depth=0`, { credentials: "same-origin" }).then((r) => r.ok ? r.json() : null).then((doc) => {
96
+ if (doc) {
97
+ const t = doc.title ?? doc.name ?? doc.slug ?? null;
98
+ if (t) setFetchedTitles((prev) => ({ ...prev, [idStr]: String(t) }));
99
+ }
100
+ }).catch(() => {
101
+ fetchingRef.current.delete(idStr);
102
+ });
103
+ });
104
+ }, [items, collection]);
105
+ function getTitle(item) {
106
+ return item.title ?? fetchedTitles[String(item.id)] ?? `ID: ${String(item.id)}`;
107
+ }
108
+ function clearOne(e, id) {
109
+ e.stopPropagation();
110
+ if (hasMany) onChange(items.filter((i) => String(i.id) !== String(id)));
111
+ else onChange(null);
112
+ }
113
+ return /* @__PURE__ */ React.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ React.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ React.createElement("span", { className: "bdf-required" }, "*")), /* @__PURE__ */ React.createElement("div", { className: `bdf-rel${hasMany ? " bdf-rel--multi" : ""}` }, /* @__PURE__ */ React.createElement(
114
+ "div",
115
+ {
116
+ role: "button",
117
+ tabIndex: 0,
118
+ className: "bdf-rel__control",
119
+ onClick: openDrawer,
120
+ onKeyDown: (e) => {
121
+ if (e.key === "Enter" || e.key === " ") openDrawer();
122
+ }
123
+ },
124
+ /* @__PURE__ */ React.createElement("div", { className: "bdf-rel__values" }, items.length === 0 && /* @__PURE__ */ React.createElement("span", { className: "bdf-rel__placeholder" }, "Select a value..."), !hasMany && items.length > 0 && /* @__PURE__ */ React.createElement("span", { className: "bdf-rel__single" }, getTitle(items[0])), hasMany && items.map((item) => /* @__PURE__ */ React.createElement("span", { key: String(item.id), className: "bdf-rel__chip" }, /* @__PURE__ */ React.createElement("span", { className: "bdf-rel__chip-label" }, getTitle(item)), /* @__PURE__ */ React.createElement(
125
+ "button",
126
+ {
127
+ type: "button",
128
+ className: "bdf-rel__chip-remove",
129
+ onClick: (e) => clearOne(e, item.id),
130
+ "aria-label": `Remove ${getTitle(item)}`
131
+ },
132
+ /* @__PURE__ */ React.createElement("svg", { height: "12", width: "12", viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", fill: "currentColor" }, /* @__PURE__ */ React.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" }))
133
+ )))),
134
+ /* @__PURE__ */ React.createElement("div", { className: "bdf-rel__indicators" }, !hasMany && items.length > 0 && /* @__PURE__ */ React.createElement(
135
+ "button",
136
+ {
137
+ type: "button",
138
+ className: "bdf-rel__clear",
139
+ onClick: (e) => clearOne(e, items[0].id),
140
+ "aria-label": "Clear"
141
+ },
142
+ /* @__PURE__ */ React.createElement("svg", { height: "16", width: "16", viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", fill: "currentColor" }, /* @__PURE__ */ React.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" }))
143
+ ), /* @__PURE__ */ React.createElement("span", { className: "bdf-rel__sep" }), /* @__PURE__ */ React.createElement("span", { className: "bdf-rel__chevron" }, /* @__PURE__ */ React.createElement("svg", { height: "16", width: "16", viewBox: "0 0 20 20", "aria-hidden": "true", focusable: "false", fill: "currentColor" }, /* @__PURE__ */ React.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" }))))
144
+ ), hasMany && /* @__PURE__ */ React.createElement(ListDrawerToggler, { className: "bdf-rel__add", onClick: (e) => e.stopPropagation() }, "+")), /* @__PURE__ */ React.createElement("span", { className: "bdf-rel__hint" }, collection, hasMany ? " \xB7 multiple" : ""), /* @__PURE__ */ React.createElement(ListDrawer, { onSelect: handleSelect }));
145
+ }
146
+ function JsonField({ label, required, value, onChange }) {
147
+ const [text, setText] = useState(
148
+ () => value !== void 0 ? JSON.stringify(value, null, 2) : ""
149
+ );
150
+ const [hasError, setHasError] = useState(false);
151
+ return /* @__PURE__ */ React.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ React.createElement("label", { className: "bdf-label" }, label, required && /* @__PURE__ */ React.createElement("span", { className: "bdf-required" }, "*"), /* @__PURE__ */ React.createElement("span", { style: { marginLeft: 6, fontSize: 11, color: "var(--theme-elevation-400)", fontWeight: 400 } }, "(JSON)")), /* @__PURE__ */ React.createElement(
152
+ "textarea",
153
+ {
154
+ className: "bdf-input bdf-textarea bdf-mono",
155
+ value: text,
156
+ rows: 4,
157
+ onChange: (e) => {
158
+ setText(e.target.value);
159
+ try {
160
+ onChange(JSON.parse(e.target.value));
161
+ setHasError(false);
162
+ } catch {
163
+ setHasError(true);
164
+ }
165
+ }
166
+ }
167
+ ), hasError && /* @__PURE__ */ React.createElement("div", { className: "bdf-error", style: { marginTop: 4 } }, "Invalid JSON \u2014 changes not saved until fixed."));
168
+ }
42
169
  function SchemaForm({ schema, value, onChange }) {
43
170
  const set = useCallback(
44
171
  (key, val) => onChange({ ...value, [key]: val }),
@@ -64,7 +191,7 @@ function FieldInput({ field, value, onChange }) {
64
191
  "input",
65
192
  {
66
193
  className: "bdf-input",
67
- type: field.type === "email" ? "email" : "text",
194
+ type: field.type === "email" ? "email" : field.type === "url" ? "url" : "text",
68
195
  value: value ?? "",
69
196
  onChange: (e) => onChange(e.target.value)
70
197
  }
@@ -117,7 +244,7 @@ function FieldInput({ field, value, onChange }) {
117
244
  className: "bdf-input",
118
245
  type: "number",
119
246
  value: numVal,
120
- onChange: (e) => onChange(e.target.value === "" ? void 0 : e.target.valueAsNumber)
247
+ onChange: (e) => onChange(e.target.value === "" ? null : e.target.valueAsNumber)
121
248
  }
122
249
  ));
123
250
  }
@@ -176,32 +303,25 @@ function FieldInput({ field, value, onChange }) {
176
303
  onChange
177
304
  }
178
305
  );
179
- case "relationship":
180
- return /* @__PURE__ */ React.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ React.createElement("label", { className: "bdf-label" }, label, field.required && /* @__PURE__ */ React.createElement("span", { className: "bdf-required" }, "*"), field.collection && /* @__PURE__ */ React.createElement("span", { style: { marginLeft: 6, fontSize: 11, color: "var(--theme-elevation-400)", fontWeight: 400 } }, "(", field.collection, ")")), /* @__PURE__ */ React.createElement(
181
- "input",
306
+ case "relationship": {
307
+ const relField = field;
308
+ if (!relField.collection) {
309
+ return /* @__PURE__ */ React.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ React.createElement("label", { className: "bdf-label" }, label), /* @__PURE__ */ React.createElement("div", { className: "bdf-error" }, "Relationship field ", /* @__PURE__ */ React.createElement("strong", null, field.name), " has no ", /* @__PURE__ */ React.createElement("code", null, "collection"), " defined in its schema."));
310
+ }
311
+ return /* @__PURE__ */ React.createElement(
312
+ RelationshipPicker,
182
313
  {
183
- className: "bdf-input",
184
- type: "text",
185
- value: value ?? "",
186
- onChange: (e) => onChange(e.target.value),
187
- placeholder: "Enter document ID"
314
+ label,
315
+ required: field.required,
316
+ collection: relField.collection,
317
+ hasMany: relField.hasMany ?? false,
318
+ value,
319
+ onChange
188
320
  }
189
- ));
321
+ );
322
+ }
190
323
  case "json":
191
- return /* @__PURE__ */ React.createElement("div", { className: "bdf-field" }, /* @__PURE__ */ React.createElement("label", { className: "bdf-label" }, label, field.required && /* @__PURE__ */ React.createElement("span", { className: "bdf-required" }, "*"), /* @__PURE__ */ React.createElement("span", { style: { marginLeft: 6, fontSize: 11, color: "var(--theme-elevation-400)", fontWeight: 400 } }, "(JSON)")), /* @__PURE__ */ React.createElement(
192
- "textarea",
193
- {
194
- className: "bdf-input bdf-textarea bdf-mono",
195
- value: value !== void 0 ? JSON.stringify(value, null, 2) : "",
196
- rows: 4,
197
- onChange: (e) => {
198
- try {
199
- onChange(JSON.parse(e.target.value));
200
- } catch {
201
- }
202
- }
203
- }
204
- ));
324
+ return /* @__PURE__ */ React.createElement(JsonField, { label, required: field.required, value, onChange });
205
325
  case "array": {
206
326
  const rows = Array.isArray(value) ? value : [];
207
327
  const subFields = field.fields ?? [];
@@ -297,9 +417,37 @@ function BlockDataField({ path }) {
297
417
  )));
298
418
  }
299
419
 
420
+ // src/components/BlockVersionSync/index.tsx
421
+ import { useEffect as useEffect2, useRef as useRef2 } from "react";
422
+ import { useField as useField2, useFormFields as useFormFields2 } from "@payloadcms/ui";
423
+ function BlockVersionSync({ path }) {
424
+ const blockVersionPath = path.replace(/\.blockDefinition$/, ".blockVersion");
425
+ const { setValue: setVersion } = useField2({ path: blockVersionPath });
426
+ const blockDefValue = useFormFields2(([fields]) => fields[path]?.value);
427
+ const prevDefIdRef = useRef2(null);
428
+ useEffect2(() => {
429
+ const defId = blockDefValue && typeof blockDefValue === "object" ? blockDefValue.id : typeof blockDefValue === "string" || typeof blockDefValue === "number" ? blockDefValue : null;
430
+ if (defId === prevDefIdRef.current) return;
431
+ prevDefIdRef.current = defId;
432
+ if (!defId) {
433
+ setVersion(null);
434
+ return;
435
+ }
436
+ fetch(`/api/block-definitions/${String(defId)}?depth=1`, { credentials: "same-origin" }).then((r) => r.ok ? r.json() : null).then((doc) => {
437
+ if (!doc) return;
438
+ const currentVersion = doc.currentVersion;
439
+ if (!currentVersion) return;
440
+ const versionId = typeof currentVersion === "object" ? currentVersion.id : currentVersion;
441
+ if (versionId) setVersion(versionId);
442
+ }).catch(() => {
443
+ });
444
+ }, [blockDefValue, setVersion]);
445
+ return null;
446
+ }
447
+
300
448
  // src/components/SchemaBuilderField/index.tsx
301
- import React5, { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
302
- import { useField as useField2 } from "@payloadcms/ui";
449
+ import React5, { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
450
+ import { useField as useField3 } from "@payloadcms/ui";
303
451
 
304
452
  // src/components/SchemaBuilderField/FieldRow.tsx
305
453
  import React4, { useState as useState2 } from "react";
@@ -873,22 +1021,22 @@ function parseSchema(raw) {
873
1021
  return [];
874
1022
  }
875
1023
  function SchemaBuilderField({ path, readOnly }) {
876
- const { value, setValue } = useField2({ path });
877
- const setValueRef = useRef2(setValue);
878
- useEffect2(() => {
1024
+ const { value, setValue } = useField3({ path });
1025
+ const setValueRef = useRef3(setValue);
1026
+ useEffect3(() => {
879
1027
  setValueRef.current = setValue;
880
1028
  });
881
1029
  const [fields, setFields] = useState3(() => parseSchema(value));
882
1030
  const hasExistingValue = value !== void 0 && value !== null;
883
1031
  const [hydrated, setHydrated] = useState3(!hasExistingValue);
884
- useEffect2(() => {
1032
+ useEffect3(() => {
885
1033
  if (hydrated) return;
886
1034
  if (value !== void 0 && value !== null) {
887
1035
  setFields(parseSchema(value));
888
1036
  setHydrated(true);
889
1037
  }
890
1038
  }, [value, hydrated]);
891
- useEffect2(() => {
1039
+ useEffect3(() => {
892
1040
  if (!hydrated) return;
893
1041
  setValueRef.current({ fields });
894
1042
  }, [fields, hydrated]);
@@ -945,10 +1093,10 @@ function SchemaBuilderField({ path, readOnly }) {
945
1093
  // src/components/EditInBuilderButton/index.tsx
946
1094
  import React6 from "react";
947
1095
  import { useDocumentInfo } from "@payloadcms/ui";
948
- import { useField as useField3 } from "@payloadcms/ui";
1096
+ import { useField as useField4 } from "@payloadcms/ui";
949
1097
  function EditInBuilderButton() {
950
1098
  const { id } = useDocumentInfo();
951
- const { value: slug } = useField3({ path: "slug" });
1099
+ const { value: slug } = useField4({ path: "slug" });
952
1100
  if (!id || !slug) return null;
953
1101
  return /* @__PURE__ */ React6.createElement("div", { style: { marginTop: "1rem" } }, /* @__PURE__ */ React6.createElement(
954
1102
  "a",
@@ -976,7 +1124,7 @@ function EditInBuilderButton() {
976
1124
  }
977
1125
 
978
1126
  // src/block-builder/components/canvas/BuilderShell.tsx
979
- import React16, { useCallback as useCallback5, useEffect as useEffect5, useState as useState8 } from "react";
1127
+ import React16, { useCallback as useCallback5, useEffect as useEffect6, useState as useState8 } from "react";
980
1128
 
981
1129
  // src/block-builder/store/builder.store.ts
982
1130
  import { create } from "zustand";
@@ -1133,7 +1281,8 @@ var useBuilderStore = create()(
1133
1281
  );
1134
1282
 
1135
1283
  // src/block-builder/components/canvas/TopBar.tsx
1136
- import React7, { useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
1284
+ import React7, { useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
1285
+ import { Blocks, ChevronDown, X } from "lucide-react";
1137
1286
 
1138
1287
  // src/block-builder/lib/mapToSaveRequest.ts
1139
1288
  var TYPE_MAP = {
@@ -1287,7 +1436,7 @@ function generateIndexFile(blocks) {
1287
1436
  }
1288
1437
 
1289
1438
  // src/block-builder/components/canvas/TopBar.tsx
1290
- function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersionId, onVersionSelect, onRestoreVersion, onAfterPublish }) {
1439
+ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersionId, onVersionSelect, onRestoreVersion, onAfterPublish, notification, onSetNotification }) {
1291
1440
  const blocks = useBuilderStore((s) => s.blocks);
1292
1441
  const activeBlockId = useBuilderStore((s) => s.activeBlockId);
1293
1442
  const activeBlock = blocks.find((b) => b.id === activeBlockId);
@@ -1295,21 +1444,21 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1295
1444
  const isDirty = useBuilderStore((s) => s.isDirty);
1296
1445
  const isReadOnly = useBuilderStore((s) => s.isReadOnly);
1297
1446
  const setVersionMeta = useBuilderStore((s) => s.setVersionMeta);
1298
- const [notification, setNotification] = useState4(null);
1447
+ const setNotification = onSetNotification;
1299
1448
  const [versionDropdownOpen, setVersionDropdownOpen] = useState4(false);
1300
1449
  const [blockPickerOpen, setBlockPickerOpen] = useState4(false);
1301
- const dropdownRef = useRef3(null);
1302
- const blockPickerRef = useRef3(null);
1450
+ const dropdownRef = useRef4(null);
1451
+ const blockPickerRef = useRef4(null);
1303
1452
  const selectedVersion = versions.find((v) => v.id === selectedVersionId);
1304
1453
  const currentVersion = versions.find((v) => v.isCurrent);
1305
1454
  const activeBlockDef = blockDefs.find((b) => b.slug === activeSlug);
1306
- useEffect3(() => {
1455
+ useEffect4(() => {
1307
1456
  if (notification?.status === "success") {
1308
1457
  const t = setTimeout(() => setNotification(null), 3e3);
1309
1458
  return () => clearTimeout(t);
1310
1459
  }
1311
1460
  }, [notification]);
1312
- useEffect3(() => {
1461
+ useEffect4(() => {
1313
1462
  function handleClick(e) {
1314
1463
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
1315
1464
  setVersionDropdownOpen(false);
@@ -1322,7 +1471,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1322
1471
  return () => document.removeEventListener("mousedown", handleClick);
1323
1472
  }, []);
1324
1473
  async function handlePublish() {
1325
- if (!activeBlock || isReadOnly) return;
1474
+ if (!activeBlock || isReadOnly) return false;
1326
1475
  setNotification({ status: "publishing" });
1327
1476
  try {
1328
1477
  const req = mapToSaveRequest(activeBlock);
@@ -1339,13 +1488,15 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1339
1488
  status: "success",
1340
1489
  msg: `v${json.versionNumber ?? "?"} published successfully!`
1341
1490
  });
1342
- await onAfterPublish();
1491
+ onAfterPublish();
1492
+ return true;
1343
1493
  } else {
1344
1494
  setNotification({
1345
1495
  status: "error",
1346
1496
  title: "Failed to publish block",
1347
1497
  errors: json.errors ?? ["An unknown error occurred."]
1348
1498
  });
1499
+ return false;
1349
1500
  }
1350
1501
  } catch (err) {
1351
1502
  setNotification({
@@ -1353,6 +1504,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1353
1504
  title: "Network error",
1354
1505
  errors: [err instanceof Error ? err.message : "Could not reach the server."]
1355
1506
  });
1507
+ return false;
1356
1508
  }
1357
1509
  }
1358
1510
  function handleExport() {
@@ -1380,9 +1532,9 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1380
1532
  className: "bb-block-picker__trigger",
1381
1533
  onClick: () => setBlockPickerOpen((o) => !o)
1382
1534
  },
1383
- /* @__PURE__ */ React7.createElement("span", { className: "bb-block-picker__icon" }, "B"),
1535
+ /* @__PURE__ */ React7.createElement(Blocks, { size: 14, strokeWidth: 1.75, className: "bb-block-picker__icon" }),
1384
1536
  /* @__PURE__ */ React7.createElement("span", null, activeBlockDef?.name ?? activeSlug ?? "Select a block"),
1385
- /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__chevron" }, "v")
1537
+ /* @__PURE__ */ React7.createElement(ChevronDown, { size: 14, strokeWidth: 1.75, className: "bb-version-selector__chevron" })
1386
1538
  ), blockPickerOpen && /* @__PURE__ */ React7.createElement("div", { className: "bb-block-picker__dropdown" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-version-dropdown__header" }, "Block Definitions"), blockDefs.map((b) => /* @__PURE__ */ React7.createElement(
1387
1539
  "button",
1388
1540
  {
@@ -1406,7 +1558,7 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1406
1558
  /* @__PURE__ */ React7.createElement("span", { className: `bb-version-selector__dot${selectedVersion?.isCurrent ? " bb-version-selector__dot--current" : " bb-version-selector__dot--old"}` }),
1407
1559
  /* @__PURE__ */ React7.createElement("span", null, selectedVersion?.label ?? `v${selectedVersion?.versionNumber ?? "?"}`),
1408
1560
  selectedVersion?.isCurrent && /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__badge" }, "current"),
1409
- /* @__PURE__ */ React7.createElement("span", { className: "bb-version-selector__chevron" }, "v")
1561
+ /* @__PURE__ */ React7.createElement(ChevronDown, { size: 14, strokeWidth: 1.75, className: "bb-version-selector__chevron" })
1410
1562
  ), versionDropdownOpen && /* @__PURE__ */ React7.createElement("div", { className: "bb-version-dropdown" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-version-dropdown__header" }, "Version History"), versions.map((v) => /* @__PURE__ */ React7.createElement(
1411
1563
  "button",
1412
1564
  {
@@ -1447,9 +1599,8 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1447
1599
  {
1448
1600
  type: "button",
1449
1601
  onClick: async () => {
1450
- await handlePublish();
1451
- setVersionMeta(null, false);
1452
- onRestoreVersion();
1602
+ const success = await handlePublish();
1603
+ if (success) onRestoreVersion();
1453
1604
  },
1454
1605
  disabled: notification?.status === "publishing" || !activeBlock,
1455
1606
  className: "bb-btn bb-btn--warning"
@@ -1464,19 +1615,38 @@ function TopBar({ blockDefs, activeSlug, onBlockSelect, versions, selectedVersio
1464
1615
  className: "bb-btn bb-btn--primary"
1465
1616
  },
1466
1617
  notification?.status === "publishing" ? "Publishing..." : "Publish to Payload"
1467
- ))), notification?.status === "publishing" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--publishing" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__spinner" }), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, isReadOnly ? "Restoring version..." : "Publishing to Payload..."), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Validating schema and saving block definition.")))), notification?.status === "success" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--success" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "OK"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.msg), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "The block definition and version have been saved.")), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "x"))), notification?.status === "error" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--error" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "!"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.title), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Fix the following errors before publishing:"), /* @__PURE__ */ React7.createElement("ul", { className: "bb-notify__error-list" }, notification.errors.map((e, i) => /* @__PURE__ */ React7.createElement("li", { key: i }, e)))), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, "x"))));
1618
+ ))), notification?.status === "publishing" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--publishing" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__spinner" }), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, isReadOnly ? "Restoring version..." : "Publishing to Payload..."), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Validating schema and saving block definition.")))), notification?.status === "success" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--success" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "OK"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.msg), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "The block definition and version have been saved.")), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, /* @__PURE__ */ React7.createElement(X, { size: 12, strokeWidth: 2 })))), notification?.status === "error" && /* @__PURE__ */ React7.createElement("div", { className: "bb-notify bb-notify--error" }, /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__box" }, /* @__PURE__ */ React7.createElement("span", { className: "bb-notify__icon" }, "!"), /* @__PURE__ */ React7.createElement("div", { className: "bb-notify__body" }, /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__title" }, notification.title), /* @__PURE__ */ React7.createElement("p", { className: "bb-notify__sub" }, "Fix the following errors before publishing:"), /* @__PURE__ */ React7.createElement("ul", { className: "bb-notify__error-list" }, notification.errors.map((e, i) => /* @__PURE__ */ React7.createElement("li", { key: i }, e)))), /* @__PURE__ */ React7.createElement("button", { className: "bb-notify__close", onClick: () => setNotification(null) }, /* @__PURE__ */ React7.createElement(X, { size: 12, strokeWidth: 2 })))));
1468
1619
  }
1469
1620
 
1470
1621
  // src/block-builder/components/canvas/BlockList.tsx
1471
1622
  import React8 from "react";
1472
- function BlockList() {
1623
+ import { Copy, Trash2, Plus } from "lucide-react";
1624
+ function BlockList({ blockDefs = [], activeSlug, onBlockSelect }) {
1473
1625
  const blocks = useBuilderStore((s) => s.blocks);
1474
1626
  const activeBlockId = useBuilderStore((s) => s.activeBlockId);
1475
1627
  const addBlock = useBuilderStore((s) => s.addBlock);
1476
1628
  const removeBlock = useBuilderStore((s) => s.removeBlock);
1477
1629
  const duplicateBlock = useBuilderStore((s) => s.duplicateBlock);
1478
1630
  const setActiveBlock = useBuilderStore((s) => s.setActiveBlock);
1479
- return /* @__PURE__ */ React8.createElement("div", { className: "bb-sidebar bb-sidebar--200 bb-sidebar--blocks" }, /* @__PURE__ */ React8.createElement("div", { className: "bb-sidebar__header" }, /* @__PURE__ */ React8.createElement("span", { className: "bb-sidebar__title" }, "Blocks"), /* @__PURE__ */ React8.createElement("button", { type: "button", onClick: addBlock, title: "Add block", className: "bb-sidebar__add" }, "+")), /* @__PURE__ */ React8.createElement("div", { className: "bb-sidebar__body" }, blocks.length === 0 && /* @__PURE__ */ React8.createElement("div", { className: "bb-block-empty" }, "No blocks yet.", /* @__PURE__ */ React8.createElement("br", null), "Click + to create one."), blocks.map((block) => {
1631
+ const useApiNav = blockDefs.length > 0;
1632
+ const loadedBlock = useApiNav ? blocks.find((b) => b.slug === activeSlug) : null;
1633
+ const localOnlyBlocks = blocks.filter(
1634
+ (b) => !blockDefs.some((d) => d.slug === b.slug)
1635
+ );
1636
+ return /* @__PURE__ */ React8.createElement("div", { className: "bb-sidebar bb-sidebar--200 bb-sidebar--blocks" }, /* @__PURE__ */ React8.createElement("div", { className: "bb-sidebar__header" }, /* @__PURE__ */ React8.createElement("span", { className: "bb-sidebar__title" }, "Blocks"), /* @__PURE__ */ React8.createElement("button", { type: "button", onClick: addBlock, title: "Add block", className: "bb-sidebar__add" }, /* @__PURE__ */ React8.createElement(Plus, { size: 14, strokeWidth: 2 }))), /* @__PURE__ */ React8.createElement("div", { className: "bb-sidebar__body" }, useApiNav && blockDefs.map((def) => {
1637
+ const isActive = def.slug === activeSlug;
1638
+ const fieldCount = isActive && loadedBlock ? loadedBlock.fields.length : null;
1639
+ return /* @__PURE__ */ React8.createElement(
1640
+ "div",
1641
+ {
1642
+ key: def.id,
1643
+ onClick: () => onBlockSelect?.(def.slug),
1644
+ className: `bb-block-item${isActive ? " bb-block-item--active" : ""}`
1645
+ },
1646
+ /* @__PURE__ */ React8.createElement("div", { className: "bb-block-item__slug" }, def.slug),
1647
+ /* @__PURE__ */ React8.createElement("div", { className: "bb-block-item__meta" }, fieldCount !== null ? `${fieldCount} field${fieldCount !== 1 ? "s" : ""}` : def.name)
1648
+ );
1649
+ }), localOnlyBlocks.map((block) => {
1480
1650
  const isActive = block.id === activeBlockId;
1481
1651
  return /* @__PURE__ */ React8.createElement(
1482
1652
  "div",
@@ -1501,7 +1671,7 @@ function BlockList() {
1501
1671
  className: "bb-block-action",
1502
1672
  title: "Duplicate"
1503
1673
  },
1504
- "="
1674
+ /* @__PURE__ */ React8.createElement(Copy, { size: 12, strokeWidth: 1.75 })
1505
1675
  ),
1506
1676
  /* @__PURE__ */ React8.createElement(
1507
1677
  "button",
@@ -1511,11 +1681,11 @@ function BlockList() {
1511
1681
  className: "bb-block-action bb-block-action--danger",
1512
1682
  title: "Delete"
1513
1683
  },
1514
- "x"
1684
+ /* @__PURE__ */ React8.createElement(Trash2, { size: 12, strokeWidth: 1.75 })
1515
1685
  )
1516
1686
  )
1517
1687
  );
1518
- })));
1688
+ }), !useApiNav && blocks.length === 0 && /* @__PURE__ */ React8.createElement("div", { className: "bb-block-empty" }, "No blocks yet.", /* @__PURE__ */ React8.createElement("br", null), "Click + to create one.")));
1519
1689
  }
1520
1690
 
1521
1691
  // src/block-builder/components/canvas/BuilderCanvas.tsx
@@ -1539,24 +1709,32 @@ import { restrictToVerticalAxis, restrictToParentElement } from "@dnd-kit/modifi
1539
1709
  import React9 from "react";
1540
1710
  import { useSortable } from "@dnd-kit/sortable";
1541
1711
  import { CSS } from "@dnd-kit/utilities";
1712
+ import {
1713
+ Type,
1714
+ AlignLeft,
1715
+ Hash,
1716
+ Mail,
1717
+ Calendar,
1718
+ CheckSquare,
1719
+ ChevronDown as ChevronDown2,
1720
+ Circle,
1721
+ Upload,
1722
+ Link,
1723
+ Braces,
1724
+ X as X2
1725
+ } from "lucide-react";
1542
1726
  var ICON_MAP = {
1543
- text: "T",
1544
- textarea: "Tx",
1545
- richText: "RT",
1546
- number: "#",
1547
- checkbox: "[x]",
1548
- select: "v",
1549
- radio: "(o)",
1550
- date: "D",
1551
- upload: "^",
1552
- email: "@",
1553
- code: "<>",
1554
- point: "P",
1555
- relationship: "->>",
1556
- array: "[]",
1557
- group: "{ }",
1558
- json: "{ }",
1559
- ui: "UI"
1727
+ text: Type,
1728
+ textarea: AlignLeft,
1729
+ number: Hash,
1730
+ email: Mail,
1731
+ date: Calendar,
1732
+ checkbox: CheckSquare,
1733
+ select: ChevronDown2,
1734
+ radio: Circle,
1735
+ upload: Upload,
1736
+ relationship: Link,
1737
+ json: Braces
1560
1738
  };
1561
1739
  function SortableFieldCard({ field, blockId, index }) {
1562
1740
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
@@ -1565,6 +1743,7 @@ function SortableFieldCard({ field, blockId, index }) {
1565
1743
  const activeFieldId = useBuilderStore((s) => s.activeFieldId);
1566
1744
  const setActiveField = useBuilderStore((s) => s.setActiveField);
1567
1745
  const removeField = useBuilderStore((s) => s.removeField);
1746
+ const isReadOnly = useBuilderStore((s) => s.isReadOnly);
1568
1747
  const isActive = activeFieldId === field.id;
1569
1748
  const wrapStyle = {
1570
1749
  transform: CSS.Transform.toString(transform),
@@ -1585,10 +1764,10 @@ function SortableFieldCard({ field, blockId, index }) {
1585
1764
  className: `bb-field-card${isActive ? " bb-field-card--active" : ""}`,
1586
1765
  onClick: () => setActiveField(isActive ? null : field.id)
1587
1766
  },
1588
- /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__icon" }, ICON_MAP[field.type] ?? "?"),
1767
+ /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__icon" }, /* @__PURE__ */ React9.createElement(FieldIcon, { type: field.type })),
1589
1768
  /* @__PURE__ */ React9.createElement("div", { className: "bb-field-card__body" }, /* @__PURE__ */ React9.createElement("div", { className: "bb-field-card__name" }, field.name || /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__name--empty" }, "unnamed")), /* @__PURE__ */ React9.createElement("div", { className: "bb-field-card__type" }, field.type, field.required && /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__required" }, "*"))),
1590
1769
  /* @__PURE__ */ React9.createElement("span", { className: "bb-field-card__index" }, "#", index + 1),
1591
- /* @__PURE__ */ React9.createElement(
1770
+ !isReadOnly && /* @__PURE__ */ React9.createElement(
1592
1771
  "button",
1593
1772
  {
1594
1773
  type: "button",
@@ -1600,11 +1779,15 @@ function SortableFieldCard({ field, blockId, index }) {
1600
1779
  className: "bb-field-card__delete",
1601
1780
  title: "Remove field"
1602
1781
  },
1603
- "x"
1782
+ /* @__PURE__ */ React9.createElement(X2, { size: 12, strokeWidth: 2 })
1604
1783
  )
1605
1784
  )
1606
1785
  );
1607
1786
  }
1787
+ function FieldIcon({ type }) {
1788
+ const Icon = ICON_MAP[type];
1789
+ return Icon ? /* @__PURE__ */ React9.createElement(Icon, { size: 13, strokeWidth: 1.75 }) : null;
1790
+ }
1608
1791
 
1609
1792
  // src/block-builder/components/canvas/BuilderCanvas.tsx
1610
1793
  function BuilderCanvas() {
@@ -1721,21 +1904,15 @@ import React12 from "react";
1721
1904
  var ALL_TYPES = [
1722
1905
  "text",
1723
1906
  "textarea",
1724
- "richText",
1725
1907
  "number",
1908
+ "email",
1909
+ "date",
1726
1910
  "checkbox",
1727
1911
  "select",
1728
1912
  "radio",
1729
- "date",
1730
1913
  "upload",
1731
- "email",
1732
- "code",
1733
- "point",
1734
1914
  "relationship",
1735
- "array",
1736
- "group",
1737
- "json",
1738
- "ui"
1915
+ "json"
1739
1916
  ];
1740
1917
  function FieldConfig() {
1741
1918
  const activeBlockId = useBuilderStore((s) => s.activeBlockId);
@@ -1908,19 +2085,20 @@ function ConfigPanel() {
1908
2085
  // src/block-builder/components/sidebar/FieldPalette.tsx
1909
2086
  import React14, { useState as useState6 } from "react";
1910
2087
  import {
1911
- Type,
1912
- AlignLeft,
1913
- Hash,
1914
- Mail,
1915
- Calendar,
1916
- CheckSquare,
1917
- ChevronDown,
1918
- Circle,
1919
- Upload,
1920
- Link,
2088
+ Type as Type2,
2089
+ AlignLeft as AlignLeft2,
2090
+ AlignJustify,
2091
+ Hash as Hash2,
2092
+ Mail as Mail2,
2093
+ Calendar as Calendar2,
2094
+ CheckSquare as CheckSquare2,
2095
+ ChevronDown as ChevronDown3,
2096
+ Circle as Circle2,
2097
+ Upload as Upload2,
2098
+ Link as Link2,
1921
2099
  List,
1922
2100
  Folder,
1923
- Braces
2101
+ Braces as Braces2
1924
2102
  } from "lucide-react";
1925
2103
 
1926
2104
  // src/block-builder/lib/field-palette.ts
@@ -1955,19 +2133,20 @@ function getFieldMeta(type) {
1955
2133
 
1956
2134
  // src/block-builder/components/sidebar/FieldPalette.tsx
1957
2135
  var ICON_MAP2 = {
1958
- Type,
1959
- AlignLeft,
1960
- Hash,
1961
- Mail,
1962
- Calendar,
1963
- CheckSquare,
1964
- ChevronDown,
1965
- Circle,
1966
- Upload,
1967
- Link,
2136
+ Type: Type2,
2137
+ AlignLeft: AlignLeft2,
2138
+ AlignJustify,
2139
+ Hash: Hash2,
2140
+ Mail: Mail2,
2141
+ Calendar: Calendar2,
2142
+ CheckSquare: CheckSquare2,
2143
+ ChevronDown: ChevronDown3,
2144
+ Circle: Circle2,
2145
+ Upload: Upload2,
2146
+ Link: Link2,
1968
2147
  List,
1969
2148
  Folder,
1970
- Braces
2149
+ Braces: Braces2
1971
2150
  };
1972
2151
  function FieldPalette() {
1973
2152
  const [search, setSearch] = useState6("");
@@ -2040,7 +2219,7 @@ function FieldButton({
2040
2219
  }
2041
2220
 
2042
2221
  // src/block-builder/components/canvas/CodePreview.tsx
2043
- import React15, { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef4, useState as useState7 } from "react";
2222
+ import React15, { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef5, useState as useState7 } from "react";
2044
2223
  var KEYWORDS = /* @__PURE__ */ new Set([
2045
2224
  "import",
2046
2225
  "export",
@@ -2135,8 +2314,8 @@ function CodePreview() {
2135
2314
  const [fileMap, setFileMap] = useState7({});
2136
2315
  const [activeFile, setActiveFile] = useState7(null);
2137
2316
  const [copied, setCopied] = useState7(false);
2138
- const timerRef = useRef4(null);
2139
- const copyTimerRef = useRef4(null);
2317
+ const timerRef = useRef5(null);
2318
+ const copyTimerRef = useRef5(null);
2140
2319
  const regenerate = useCallback4(() => {
2141
2320
  if (blocks.length === 0) {
2142
2321
  setFileMap({});
@@ -2154,7 +2333,7 @@ function CodePreview() {
2154
2333
  return prev && keys.includes(prev) ? prev : keys[0] ?? null;
2155
2334
  });
2156
2335
  }, [blocks]);
2157
- useEffect4(() => {
2336
+ useEffect5(() => {
2158
2337
  if (timerRef.current) clearTimeout(timerRef.current);
2159
2338
  timerRef.current = setTimeout(regenerate, 300);
2160
2339
  return () => {
@@ -2309,18 +2488,20 @@ function BuilderShell({ loadSlug }) {
2309
2488
  const isReadOnly = useBuilderStore((s) => s.isReadOnly);
2310
2489
  const [activeSlug, setActiveSlug] = useState8(loadSlug ?? null);
2311
2490
  const [loading, setLoading] = useState8(!!loadSlug);
2312
- const [loadError, setLoadError] = useState8(null);
2491
+ const [notification, setNotification] = useState8(null);
2313
2492
  const [showCodePreview, setShowCodePreview] = useState8(false);
2314
2493
  const [versions, setVersions] = useState8([]);
2315
2494
  const [selectedVersionId, setSelectedVersionId] = useState8(null);
2316
2495
  const [blockDefs, setBlockDefs] = useState8([]);
2317
2496
  const [mobilePanelTab, setMobilePanelTab] = useState8("blocks");
2318
- useEffect5(() => {
2497
+ useEffect6(() => {
2319
2498
  fetch("/api/block-definitions?limit=200&depth=0").then((r) => r.json()).then((json) => {
2320
2499
  setBlockDefs(
2321
2500
  (json.docs ?? []).map((d) => ({ id: String(d.id), slug: d.slug, name: d.name }))
2322
2501
  );
2323
- }).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."] });
2324
2505
  });
2325
2506
  }, []);
2326
2507
  const loadVersionsForSlug = useCallback5(async (slug) => {
@@ -2334,7 +2515,7 @@ function BuilderShell({ loadSlug }) {
2334
2515
  }, []);
2335
2516
  const loadVersion = useCallback5(async (slug, versionId) => {
2336
2517
  setLoading(true);
2337
- setLoadError(null);
2518
+ setNotification(null);
2338
2519
  const url = versionId ? `/api/block-builder/load/${encodeURIComponent(slug)}?versionId=${encodeURIComponent(versionId)}` : `/api/block-builder/load/${encodeURIComponent(slug)}`;
2339
2520
  try {
2340
2521
  const res = await fetch(url);
@@ -2344,10 +2525,10 @@ function BuilderShell({ loadSlug }) {
2344
2525
  setVersionMeta(json.versionId ?? null, !(json.isCurrent ?? true));
2345
2526
  setSelectedVersionId(json.versionId ?? null);
2346
2527
  } else {
2347
- setLoadError(json.error ?? "Failed to load block");
2528
+ setNotification({ status: "error", title: "Failed to load block", errors: [json.error ?? "Unknown error"] });
2348
2529
  }
2349
2530
  } catch (err) {
2350
- setLoadError(err instanceof Error ? err.message : "Network error");
2531
+ setNotification({ status: "error", title: "Network error", errors: [err instanceof Error ? err.message : "Could not reach the server."] });
2351
2532
  } finally {
2352
2533
  setLoading(false);
2353
2534
  }
@@ -2357,7 +2538,7 @@ function BuilderShell({ loadSlug }) {
2357
2538
  setBlockSlug(slug);
2358
2539
  setVersions([]);
2359
2540
  setSelectedVersionId(null);
2360
- setLoadError(null);
2541
+ setNotification(null);
2361
2542
  setMobilePanelTab("canvas");
2362
2543
  await loadVersion(slug);
2363
2544
  const list = await loadVersionsForSlug(slug);
@@ -2365,7 +2546,7 @@ function BuilderShell({ loadSlug }) {
2365
2546
  const current = list.find((v) => v.isCurrent) ?? list[0];
2366
2547
  if (current) setSelectedVersionId(current.id);
2367
2548
  }, [loadVersion, loadVersionsForSlug, setBlockSlug]);
2368
- useEffect5(() => {
2549
+ useEffect6(() => {
2369
2550
  if (!loadSlug) return;
2370
2551
  loadBlockBySlug(loadSlug);
2371
2552
  }, [loadSlug]);
@@ -2398,9 +2579,11 @@ function BuilderShell({ loadSlug }) {
2398
2579
  selectedVersionId,
2399
2580
  onVersionSelect: handleVersionSelect,
2400
2581
  onRestoreVersion: handleRestoreVersion,
2401
- onAfterPublish: handleAfterPublish
2582
+ onAfterPublish: handleAfterPublish,
2583
+ notification,
2584
+ onSetNotification: setNotification
2402
2585
  }
2403
- ), loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-loading-bar" }, "Loading..."), loadError && /* @__PURE__ */ React16.createElement("div", { className: "bb-error-bar" }, "Error: ", loadError), isReadOnly && !loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-readonly-banner" }, /* @__PURE__ */ React16.createElement("span", { className: "bb-readonly-banner__icon" }, "[i]"), /* @__PURE__ */ React16.createElement("span", null, "You are viewing a previous version - read only.", /* @__PURE__ */ React16.createElement(
2586
+ ), loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-loading-bar" }, "Loading..."), isReadOnly && !loading && /* @__PURE__ */ React16.createElement("div", { className: "bb-readonly-banner" }, /* @__PURE__ */ React16.createElement("span", { className: "bb-readonly-banner__icon" }, "[i]"), /* @__PURE__ */ React16.createElement("span", null, "You are viewing a previous version - read only.", /* @__PURE__ */ React16.createElement(
2404
2587
  "button",
2405
2588
  {
2406
2589
  type: "button",
@@ -2408,7 +2591,7 @@ function BuilderShell({ loadSlug }) {
2408
2591
  onClick: handleRestoreVersion
2409
2592
  },
2410
2593
  "Switch to latest"
2411
- ))), /* @__PURE__ */ React16.createElement("div", { className: "bb-main", "data-mobile-panel": mobilePanelTab }, /* @__PURE__ */ React16.createElement(BlockList, null), /* @__PURE__ */ React16.createElement("div", { className: "bb-main__center" }, /* @__PURE__ */ React16.createElement(FieldPalette, null), /* @__PURE__ */ React16.createElement(BuilderCanvas, null)), /* @__PURE__ */ React16.createElement(ConfigPanel, null)), /* @__PURE__ */ React16.createElement("div", { className: "bb-footer" }, /* @__PURE__ */ React16.createElement(
2594
+ ))), /* @__PURE__ */ React16.createElement("div", { className: "bb-main", "data-mobile-panel": mobilePanelTab }, /* @__PURE__ */ React16.createElement(BlockList, { blockDefs, activeSlug, onBlockSelect: loadBlockBySlug }), /* @__PURE__ */ React16.createElement("div", { className: "bb-main__center" }, /* @__PURE__ */ React16.createElement(FieldPalette, null), /* @__PURE__ */ React16.createElement(BuilderCanvas, null)), /* @__PURE__ */ React16.createElement(ConfigPanel, null)), /* @__PURE__ */ React16.createElement("div", { className: "bb-footer" }, /* @__PURE__ */ React16.createElement(
2412
2595
  "button",
2413
2596
  {
2414
2597
  type: "button",
@@ -2437,10 +2620,10 @@ function BuilderShell({ loadSlug }) {
2437
2620
 
2438
2621
  // src/components/BlockBuilderNavLink/index.tsx
2439
2622
  import React17 from "react";
2440
- import Link2 from "next/link";
2623
+ import Link3 from "next/link";
2441
2624
  function BlockBuilderNavLink() {
2442
2625
  return /* @__PURE__ */ React17.createElement("div", { style: { padding: "0 16px", marginTop: "8px" } }, /* @__PURE__ */ React17.createElement(
2443
- Link2,
2626
+ Link3,
2444
2627
  {
2445
2628
  href: "/block-builder",
2446
2629
  target: "_blank",
@@ -2465,6 +2648,7 @@ function BlockBuilderNavLink() {
2465
2648
  export {
2466
2649
  BlockBuilderNavLink,
2467
2650
  BlockDataField,
2651
+ BlockVersionSync,
2468
2652
  BuilderShell,
2469
2653
  EditInBuilderButton,
2470
2654
  SchemaBuilderField