@aduptive/strapi-blockscene 1.0.0-alpha.3 → 2.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/admin.cjs +960 -156
  2. package/dist/admin.mjs +982 -155
  3. package/package.json +8 -9
package/dist/admin.cjs CHANGED
@@ -4,6 +4,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __getProtoOf = Object.getPrototypeOf;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
7
10
  var __export = (target, all) => {
8
11
  for (var name in all)
9
12
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -26,15 +29,122 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
26
29
  ));
27
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
31
 
29
- // admin/strapi4.tsx
30
- var strapi4_exports = {};
31
- __export(strapi4_exports, {
32
- default: () => strapi4_default
32
+ // server/groups.js
33
+ var require_groups = __commonJS({
34
+ "server/groups.js"(exports, module2) {
35
+ "use strict";
36
+ var UID = /^[a-z0-9-]+\.[a-z0-9-]+$/;
37
+ function safeGroups2(value, knownUids) {
38
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
39
+ const out = {};
40
+ for (const [open, close] of Object.entries(value)) {
41
+ if (!UID.test(open) || typeof close !== "string" || !UID.test(close) || open === close) continue;
42
+ if (knownUids && (!knownUids.includes(open) || !knownUids.includes(close))) continue;
43
+ out[open] = close;
44
+ }
45
+ for (const close of Object.values(out)) if (out[close]) return null;
46
+ return Object.keys(out).length ? out : null;
47
+ }
48
+ var uidOf = (row) => typeof row?.__component === "string" ? row.__component : "";
49
+ var isOpener = (row, g) => Boolean(g) && Object.prototype.hasOwnProperty.call(g, uidOf(row));
50
+ var isClose = (row, g) => Boolean(g) && Object.values(g).includes(uidOf(row));
51
+ var blockKey2 = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
52
+ function validateGroups2(rows, g) {
53
+ const errors = [];
54
+ if (!g || !Array.isArray(rows)) return errors;
55
+ const stack = [];
56
+ rows.forEach((row, index) => {
57
+ const uid = uidOf(row);
58
+ if (isOpener(row, g)) {
59
+ stack.push({ index, uid, close: g[uid] });
60
+ return;
61
+ }
62
+ if (!isClose(row, g)) return;
63
+ const top = stack[stack.length - 1];
64
+ if (!top) errors.push({ code: "closeBeforeOpen", index, uid });
65
+ else if (top.close !== uid) errors.push({ code: "mismatch", index, uid, expected: top.close, open: top.uid, openIndex: top.index });
66
+ else stack.pop();
67
+ });
68
+ for (const open of stack) errors.push({ code: "unclosed", index: open.index, uid: open.uid, expected: open.close });
69
+ return errors;
70
+ }
71
+ function groupRange2(rows, start, g) {
72
+ const stack = [g[uidOf(rows[start])]];
73
+ for (let i = start + 1; i < rows.length; i++) {
74
+ const row = rows[i];
75
+ if (isOpener(row, g)) stack.push(g[uidOf(row)]);
76
+ else if (isClose(row, g) && uidOf(row) === stack[stack.length - 1]) {
77
+ stack.pop();
78
+ if (!stack.length) return [start, i];
79
+ }
80
+ }
81
+ return [start, rows.length - 1];
82
+ }
83
+ function groupRows2(rows, g, depth = 0, offset = 0) {
84
+ const out = [];
85
+ let i = 0;
86
+ while (i < rows.length) {
87
+ const row = rows[i];
88
+ if (isOpener(row, g)) {
89
+ const [, end] = groupRange2(rows, i, g);
90
+ const closed = uidOf(rows[end]) === g[uidOf(row)] && end > i;
91
+ out.push({
92
+ type: "group",
93
+ key: blockKey2(row),
94
+ closeKey: closed ? blockKey2(rows[end]) : null,
95
+ row,
96
+ index: offset + i,
97
+ depth,
98
+ children: groupRows2(rows.slice(i + 1, closed ? end : end + 1), g, depth + 1, offset + i + 1)
99
+ });
100
+ i = end + 1;
101
+ continue;
102
+ }
103
+ out.push({ type: "block", key: blockKey2(row), row, index: offset + i, depth, stray: isClose(row, g) });
104
+ i++;
105
+ }
106
+ return out;
107
+ }
108
+ function topLevelRanges2(rows, g) {
109
+ const ranges = [];
110
+ let i = 0;
111
+ while (i < rows.length) {
112
+ const end = isOpener(rows[i], g) ? groupRange2(rows, i, g)[1] : i;
113
+ ranges.push([i, end]);
114
+ i = end + 1;
115
+ }
116
+ return ranges;
117
+ }
118
+ function moveGroup2(rows, key, direction, g) {
119
+ if (!g) return null;
120
+ const ranges = topLevelRanges2(rows, g);
121
+ const at = ranges.findIndex(([s]) => blockKey2(rows[s]) === String(key));
122
+ const to = at + (direction === "up" ? -1 : 1);
123
+ if (at < 0 || to < 0 || to >= ranges.length) return null;
124
+ const [a, b] = direction === "up" ? [ranges[to], ranges[at]] : [ranges[at], ranges[to]];
125
+ return [...rows.slice(0, a[0]), ...rows.slice(b[0], b[1] + 1), ...rows.slice(a[0], a[1] + 1), ...rows.slice(b[1] + 1)];
126
+ }
127
+ function removeGroup2(rows, key, g) {
128
+ if (!g) return null;
129
+ const start = rows.findIndex((row) => blockKey2(row) === String(key));
130
+ if (start < 0 || !isOpener(rows[start], g)) return null;
131
+ const [, end] = groupRange2(rows, start, g);
132
+ return [...rows.slice(0, start), ...rows.slice(end + 1)];
133
+ }
134
+ module2.exports = { safeGroups: safeGroups2, validateGroups: validateGroups2, groupRange: groupRange2, groupRows: groupRows2, topLevelRanges: topLevelRanges2, moveGroup: moveGroup2, removeGroup: removeGroup2, blockKey: blockKey2, isOpener, isClose };
135
+ }
136
+ });
137
+
138
+ // admin/strapi5.tsx
139
+ var strapi5_exports = {};
140
+ __export(strapi5_exports, {
141
+ default: () => strapi5_default
33
142
  });
34
- module.exports = __toCommonJS(strapi4_exports);
35
- var React4 = __toESM(require("react"));
36
- var import_design_system3 = require("@strapi/design-system");
37
- var import_helper_plugin = require("@strapi/helper-plugin");
143
+ module.exports = __toCommonJS(strapi5_exports);
144
+ var React6 = __toESM(require("react"));
145
+ var import_design_system6 = require("@strapi/design-system");
146
+ var import_admin3 = require("@strapi/strapi/admin");
147
+ var import_strapi_admin2 = require("@strapi/content-manager/strapi-admin");
38
148
 
39
149
  // admin/Gallery.tsx
40
150
  var React = __toESM(require("react"));
@@ -44,6 +154,25 @@ var import_styled_components = __toESM(require("styled-components"));
44
154
 
45
155
  // admin/model.mjs
46
156
  var import_fractional_indexing = require("fractional-indexing");
157
+ function componentDefaults(schema, components, stack = []) {
158
+ if (!schema || stack.includes(schema)) throw new Error("Invalid recursive component defaults");
159
+ const row = {};
160
+ for (const [name, attr] of Object.entries(schema.attributes || {})) {
161
+ if (Object.hasOwn(attr, "default")) {
162
+ const value = structuredClone(attr.default);
163
+ if (attr.type === "password") row[name] = "";
164
+ else if (attr.type === "relation") row[name] = { connect: [], disconnect: [] };
165
+ else if (value !== null || attr.type === "boolean") row[name] = value;
166
+ } else if (attr.type === "component" && attr.required) {
167
+ const create = () => componentDefaults(components[attr.component], components, [...stack, schema]);
168
+ if (attr.repeatable) {
169
+ const keys = (0, import_fractional_indexing.generateNKeysBetween)(null, null, attr.min || 0);
170
+ row[name] = keys.map((key) => ({ ...create(), __temp_key__: key }));
171
+ } else row[name] = create();
172
+ } else if (attr.type === "dynamiczone" && attr.required) row[name] = [];
173
+ }
174
+ return row;
175
+ }
47
176
  function editableZones(schema, values, canEdit, disabled = false) {
48
177
  if (disabled) return [];
49
178
  return Object.entries(schema?.attributes || {}).filter(([name, attr]) => attr.type === "dynamiczone" && !attr.conditions && canEdit(name)).map(([name, attr]) => {
@@ -1217,7 +1346,10 @@ function Card({ entry, palette, showFields, onSelect }) {
1217
1346
  showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral500", style: { fontStyle: "italic" }, "data-testid": "block-fields", children: entry.fields.map((f) => `${f.name} (${f.type})`).join(", ") })
1218
1347
  ] });
1219
1348
  }
1220
- function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, controlled }) {
1349
+ function PickerModal({ zone, components, open, onOpenChange, onSelect, Modal: Modal3, Toggle, get }) {
1350
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoneGallery, { zone, components, Modal: Modal3, Toggle, get, controlled: { open, onOpenChange, onSelect } });
1351
+ }
1352
+ function ZoneGallery({ zone, components, add, Modal: Modal3, Toggle, get, controlled }) {
1221
1353
  const t = useMessages();
1222
1354
  const [ownOpen, setOwnOpen] = React.useState(false);
1223
1355
  const open = controlled ? controlled.open : ownOpen;
@@ -1281,7 +1413,7 @@ function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, contro
1281
1413
  remember(SHOW_FIELDS_KEY, String(value));
1282
1414
  };
1283
1415
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1284
- Modal2,
1416
+ Modal3,
1285
1417
  {
1286
1418
  open,
1287
1419
  onOpenChange: setOpen,
@@ -1410,46 +1542,712 @@ function Gallery({ zones, editor, docKey, contentType, userId, ...props }) {
1410
1542
  ] }, zone.name)) });
1411
1543
  }
1412
1544
 
1413
- // admin/Settings.tsx
1545
+ // admin/PagePreview.tsx
1546
+ var React3 = __toESM(require("react"));
1547
+ var import_react_dom2 = require("react-dom");
1548
+ var import_styled_components2 = __toESM(require("styled-components"));
1549
+ var import_design_system3 = require("@strapi/design-system");
1550
+ var import_admin2 = require("@strapi/strapi/admin");
1551
+ var import_design_system4 = require("@strapi/design-system");
1552
+ var import_strapi_admin = require("@strapi/content-manager/strapi-admin");
1553
+
1554
+ // admin/FieldEditorModal.tsx
1414
1555
  var React2 = __toESM(require("react"));
1556
+ var import_admin = require("@strapi/strapi/admin");
1415
1557
  var import_design_system2 = require("@strapi/design-system");
1416
- var import_styled_components2 = __toESM(require("styled-components"));
1417
1558
  var import_jsx_runtime3 = require("react/jsx-runtime");
1559
+ var Actions = ({ onApply, onCancel }) => {
1560
+ const t = useMessages();
1561
+ const value = (0, import_admin.useForm)("BlocksceneFieldEditor", (state) => state.values.value);
1562
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 2, justifyContent: "flex-end", children: [
1563
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", onClick: onCancel, children: t.cancel }),
1564
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { onClick: () => onApply(value ?? null), "data-testid": "field-editor-apply", children: t.apply })
1565
+ ] });
1566
+ };
1567
+ function FieldEditorModal({ label, attribute, value, onApply, onCancel }) {
1568
+ const t = useMessages();
1569
+ const customFields = (0, import_admin.useStrapiApp)("BlocksceneFieldEditor", (state) => state.customFields);
1570
+ const [Input, setInput] = React2.useState(void 0);
1571
+ const isCustom = Boolean(attribute?.customField);
1572
+ const isText = attribute?.type === "string" || attribute?.type === "text";
1573
+ React2.useEffect(() => {
1574
+ let active = true;
1575
+ if (!isCustom) {
1576
+ setInput(null);
1577
+ return;
1578
+ }
1579
+ const field = customFields?.get?.(attribute.customField);
1580
+ if (!field?.components?.Input) {
1581
+ setInput(null);
1582
+ return;
1583
+ }
1584
+ Promise.resolve(field.components.Input()).then((mod) => {
1585
+ if (active) setInput(() => mod.default || mod);
1586
+ }).catch(() => {
1587
+ if (active) setInput(null);
1588
+ });
1589
+ return () => {
1590
+ active = false;
1591
+ };
1592
+ }, [attribute, customFields, isCustom]);
1593
+ const supported = isText || isCustom && Input;
1594
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Modal.Root, { open: true, onOpenChange: (open) => {
1595
+ if (!open) onCancel();
1596
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Modal.Content, { "aria-label": `${t.editText} ${label}`, children: [
1597
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Modal.Header, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Modal.Title, { children: [
1598
+ t.editText,
1599
+ " \xB7 ",
1600
+ label
1601
+ ] }) }),
1602
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_admin.Form, { initialValues: { value: value ?? (isText ? "" : null) }, method: "PUT", onSubmit: () => {
1603
+ }, children: [
1604
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Modal.Body, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "field-editor-modal", children: [
1605
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.editHelp }),
1606
+ isCustom && Input === void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { children: t.loading }),
1607
+ isCustom && Input && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Input, { name: "value", attribute, label, type: attribute.type }),
1608
+ isText && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_admin.InputRenderer, { type: attribute.type === "text" ? "text" : "string", name: "value", label }),
1609
+ (isCustom && Input === null || !isCustom && !isText) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: t.editUnsupported })
1610
+ ] }) }),
1611
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Modal.Footer, { children: supported ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Actions, { onApply, onCancel }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", onClick: onCancel, children: t.close }) })
1612
+ ] })
1613
+ ] }) });
1614
+ }
1615
+
1616
+ // admin/preview.mjs
1617
+ var import_groups = __toESM(require_groups(), 1);
1618
+ var PROTOCOL = "blockscene:page-preview:v1";
1619
+ var TEXT_TYPES = ["string", "text"];
1620
+ var RICH_TYPES = ["richtext", "blocks", "customField"];
1621
+ var EDITABLE_TYPES = [...TEXT_TYPES, ...RICH_TYPES];
1622
+ var SCALAR = ["string", "text", "richtext", "email", "enumeration", "integer", "biginteger", "float", "decimal", "boolean", "date", "datetime", "time", "json", "blocks", "uid", "customField"];
1623
+ var blockKey = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
1624
+ function projectRow(row, schema, components, cmsOrigin, depth = 0) {
1625
+ if (!row || !schema || depth > 3) return null;
1626
+ const out = {};
1627
+ for (const [name, attr] of Object.entries(schema.attributes || {})) {
1628
+ const value = row[name];
1629
+ if (attr.type === "password" || attr.type === "relation" || attr.private) continue;
1630
+ if (SCALAR.includes(attr.type)) {
1631
+ if (value !== void 0) out[name] = typeof value === "string" ? value.slice(0, 2e5) : value;
1632
+ } else if (attr.type === "media") {
1633
+ const files = (attr.multiple ? Array.isArray(value) ? value : [] : value ? [value] : []).map((file) => projectMedia(file, cmsOrigin)).filter(Boolean);
1634
+ out[name] = attr.multiple ? files : files[0] || null;
1635
+ } else if (attr.type === "component") {
1636
+ const child = components?.[attr.component];
1637
+ out[name] = attr.repeatable ? (Array.isArray(value) ? value : []).slice(0, 100).map((item, i) => ({ ...projectRow(item, child, components, cmsOrigin, depth + 1), __key: blockKey(item) ?? String(i) })) : projectRow(value, child, components, cmsOrigin, depth + 1);
1638
+ }
1639
+ }
1640
+ return out;
1641
+ }
1642
+ function projectMedia(file, cmsOrigin) {
1643
+ if (!file || typeof file.url !== "string") return null;
1644
+ try {
1645
+ const url = new URL(file.url, cmsOrigin);
1646
+ if (!["http:", "https:"].includes(url.protocol)) return null;
1647
+ return { url: url.href, alternativeText: String(file.alternativeText || ""), caption: String(file.caption || ""), width: Number(file.width) || 0, height: Number(file.height) || 0, mime: String(file.mime || "") };
1648
+ } catch {
1649
+ return null;
1650
+ }
1651
+ }
1652
+ function resolveField(uid, field, components) {
1653
+ if (typeof field !== "string" || field.length > 200) return null;
1654
+ let schema = components?.[uid];
1655
+ const parts = field.split(".");
1656
+ for (let i = 0; i < parts.length; i++) {
1657
+ const attr = schema?.attributes?.[parts[i]];
1658
+ if (!attr || attr.private === true) return null;
1659
+ if (i === parts.length - 1) return attr;
1660
+ if (attr.type !== "component") return null;
1661
+ if (attr.repeatable) {
1662
+ if (!/^\d{1,3}$/.test(parts[i + 1] || "")) return null;
1663
+ i++;
1664
+ }
1665
+ schema = components?.[attr.component];
1666
+ }
1667
+ return null;
1668
+ }
1669
+ function editableFields(uid, row, components) {
1670
+ const schema = components?.[uid];
1671
+ const out = [];
1672
+ const SYSTEM = ["id", "documentId", "locale", "createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "localizations", "__component", "__temp_key__"];
1673
+ const push = (name, attr, label) => {
1674
+ if (!SYSTEM.includes(name.split(".").pop()) && attr?.private !== true && EDITABLE_TYPES.includes(attr?.type)) out.push({ name, type: attr.type, label });
1675
+ };
1676
+ for (const [name, attr] of Object.entries(schema?.attributes || {})) {
1677
+ if (attr.type === "component" && attr.repeatable) {
1678
+ (Array.isArray(row?.[name]) ? row[name] : []).slice(0, 50).forEach((_, i) => {
1679
+ for (const [child, childAttr] of Object.entries(components?.[attr.component]?.attributes || {})) push(`${name}.${i}.${child}`, childAttr, `${name} ${i + 1} \xB7 ${child}`);
1680
+ });
1681
+ } else push(name, attr, name);
1682
+ }
1683
+ return out;
1684
+ }
1685
+ function mediaFields(uid, row, components) {
1686
+ const media = {};
1687
+ for (const [name, attr] of Object.entries(components?.[uid]?.attributes || {})) {
1688
+ if (attr.type === "media" && attr.private !== true) media[name] = { required: attr.required === true, multiple: attr.multiple === true, present: attr.multiple ? Array.isArray(row?.[name]) && row[name].length > 0 : Boolean(row?.[name]) };
1689
+ }
1690
+ return media;
1691
+ }
1692
+ function projectPage(rows, components, cmsOrigin) {
1693
+ return (Array.isArray(rows) ? rows : []).slice(0, 200).flatMap((row, index) => {
1694
+ const uid = row?.__component;
1695
+ const key = blockKey(row);
1696
+ const schema = components?.[uid];
1697
+ if (!uid || key == null || !schema) return [];
1698
+ return [{
1699
+ key,
1700
+ index,
1701
+ uid,
1702
+ label: schema.info?.displayName || uid,
1703
+ data: projectRow(row, schema, components, cmsOrigin),
1704
+ fields: editableFields(uid, row, components),
1705
+ media: mediaFields(uid, row, components)
1706
+ }];
1707
+ });
1708
+ }
1709
+ var validateFocus = (uid, field, components) => {
1710
+ const attr = resolveField(uid, field, components);
1711
+ return attr && EDITABLE_TYPES.includes(attr.type) ? attr : null;
1712
+ };
1713
+ function validateEdit(uid, field, value, components) {
1714
+ if (typeof value !== "string" || value.length > 5e3) return null;
1715
+ const attr = resolveField(uid, field, components);
1716
+ return attr && TEXT_TYPES.includes(attr.type) ? value.replace(/[\r\n]+/g, " ") : null;
1717
+ }
1718
+ var mediaAttribute = (uid, field, components) => {
1719
+ const attr = resolveField(uid, field, components);
1720
+ return attr?.type === "media" ? attr : null;
1721
+ };
1722
+ function isPreviewMessage(event, origin, source, channel, type) {
1723
+ return event.origin === origin && event.source === source && event.data?.protocol === PROTOCOL && event.data?.channel === channel && event.data?.type === type;
1724
+ }
1725
+ function insertIndex(rows, after) {
1726
+ if (after === null || after === void 0) return 0;
1727
+ const index = (Array.isArray(rows) ? rows : []).findIndex((row) => blockKey(row) === String(after));
1728
+ return index < 0 ? -1 : index + 1;
1729
+ }
1730
+
1731
+ // admin/PagePreview.tsx
1732
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1733
+ var MODE_KEY = "blockscene:page-mode";
1734
+ var RATIO_KEY = "blockscene:page-split-ratio";
1735
+ var MIN_PANE = 360;
1736
+ var MIN_FORM = 520;
1737
+ var NARROW = 960;
1738
+ var KEY_STEP = 32;
1739
+ var MODAL_TYPES = ["customField", "string", "text"];
1740
+ var read = (key) => {
1741
+ try {
1742
+ return localStorage.getItem(key);
1743
+ } catch {
1744
+ return null;
1745
+ }
1746
+ };
1747
+ var write = (key, value) => {
1748
+ try {
1749
+ localStorage.setItem(key, value);
1750
+ } catch {
1751
+ }
1752
+ };
1753
+ var clampWidth = (width, vw) => Math.round(Math.min(Math.max(width, MIN_PANE), Math.max(MIN_PANE, vw - MIN_FORM)));
1754
+ var getIn = (object, path) => path.split(".").reduce((acc, part) => acc == null ? acc : acc[part], object);
1755
+ var Pane = import_styled_components2.default.aside`
1756
+ position: fixed; top: 0; bottom: 0; z-index: 2; display: flex; flex-direction: column;
1757
+ background: ${({ theme }) => theme.colors.neutral0}; border-left: 1px solid ${({ theme }) => theme.colors.neutral200};
1758
+ box-shadow: ${({ theme }) => theme.shadows.popupShadow};
1759
+ `;
1760
+ function useMainRect() {
1761
+ const [rect, setRect] = React3.useState(() => ({ left: 0, width: window.innerWidth }));
1762
+ React3.useEffect(() => {
1763
+ const main = document.getElementById("main-content");
1764
+ const measure = () => {
1765
+ const r = main?.getBoundingClientRect();
1766
+ setRect(r && r.width > 0 ? { left: Math.round(r.left), width: Math.round(r.width) } : { left: 0, width: window.innerWidth });
1767
+ };
1768
+ measure();
1769
+ const observer = main && "ResizeObserver" in window ? new ResizeObserver(measure) : null;
1770
+ if (main) observer?.observe(main);
1771
+ window.addEventListener("resize", measure);
1772
+ return () => {
1773
+ observer?.disconnect();
1774
+ window.removeEventListener("resize", measure);
1775
+ };
1776
+ }, []);
1777
+ return rect;
1778
+ }
1779
+ var Handle = import_styled_components2.default.div`
1780
+ position: absolute; top: 0; bottom: 0; left: -5px; width: 10px; cursor: col-resize; z-index: 3; touch-action: none;
1781
+ &::after { content: ''; position: absolute; top: 0; bottom: 0; left: 4px; width: 2px; }
1782
+ &:hover::after, &[data-dragging='true']::after, &:focus-visible::after { background: ${({ theme }) => theme.colors.primary600}; }
1783
+ &:focus-visible { outline: none; }
1784
+ `;
1785
+ var Frame2 = import_styled_components2.default.iframe` flex: 1; width: 100%; border: 0; background: white; `;
1786
+ var SPLIT_STYLE = `
1787
+ body.bp-split #main-content { padding-right: calc(var(--bp-pane, 50vw) + 1.6rem) !important; }
1788
+ body.bp-split [data-bp-grid] { display: flex !important; flex-direction: column-reverse; gap: 1.6rem; }
1789
+ body.bp-split [data-bp-panels] { width: 100%; }
1790
+ body.bp-split [data-bp-panels] > div { flex-direction: row; flex-wrap: wrap; align-items: flex-start; gap: 1.2rem; }
1791
+ body.bp-split [data-bp-panels] > div > * { flex: 1 1 24rem; }`;
1792
+ var markLayout = (anchor) => {
1793
+ let item = anchor;
1794
+ while (item?.parentElement && getComputedStyle(item.parentElement).display !== "grid") item = item.parentElement;
1795
+ if (!item?.parentElement) return;
1796
+ item.dataset.bpPanels = "";
1797
+ item.parentElement.dataset.bpGrid = "";
1798
+ };
1799
+ function usePreviewBase(override, model, documentId, locale) {
1800
+ const { get } = (0, import_admin2.useFetchClient)();
1801
+ const [native, setNative] = React3.useState(null);
1802
+ React3.useEffect(() => {
1803
+ if (override || !model) return;
1804
+ let active = true;
1805
+ const query = new URLSearchParams({ status: "draft", ...documentId ? { documentId } : {}, ...locale ? { locale } : {} });
1806
+ get(`/content-manager/preview/url/${model}?${query}`).then(({ data }) => {
1807
+ if (active && typeof data?.data?.url === "string") setNative(`${new URL(data.data.url).origin}/block-preview/page`);
1808
+ }).catch(() => {
1809
+ if (active) setNative(null);
1810
+ });
1811
+ return () => {
1812
+ active = false;
1813
+ };
1814
+ }, [get, model, documentId, locale, override]);
1815
+ return override ? { base: override, source: "custom" } : native ? { base: native, source: "native" } : { base: null, source: "none" };
1816
+ }
1817
+ function PickerDialog({ open, onOpenChange, trigger, title, children }) {
1818
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system4.Modal.Root, { open, onOpenChange, children: [
1819
+ trigger && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system4.Modal.Trigger, { children: trigger }),
1820
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system4.Modal.Content, { children: [
1821
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system4.Modal.Header, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system4.Modal.Title, { children: title }) }),
1822
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system4.Modal.Body, { children })
1823
+ ] })
1824
+ ] });
1825
+ }
1826
+ var ACTION_TYPES = ["update", "publish"];
1827
+ var nativeButtons = () => document.querySelectorAll('#main-content button:not([data-testid="page-preview-pane"] button)');
1828
+ function ToolbarActions({ model, collectionType, documentId, locale }) {
1829
+ const plugins = (0, import_admin2.useStrapiApp)("BlocksceneToolbar", (state) => state.plugins);
1830
+ const [{ query }] = (0, import_admin2.useQueryParams)();
1831
+ const { document: doc, meta } = (0, import_strapi_admin.unstable_useDocument)({ model, collectionType, documentId, params: { locale } }, { skip: !documentId });
1832
+ const { toggleNotification } = (0, import_admin2.useNotification)();
1833
+ const t = useMessages();
1834
+ const descriptions = (plugins["content-manager"]?.apis?.getDocumentActions?.("panel") || []).filter((d) => ACTION_TYPES.includes(d.type));
1835
+ const props = { activeTab: query.status || "draft", model, documentId, document: doc, meta, collectionType };
1836
+ const run = async (action, event) => {
1837
+ const native = [...nativeButtons()].find((b) => b.textContent?.trim() === action.label);
1838
+ if (native) {
1839
+ native.click();
1840
+ return;
1841
+ }
1842
+ const mute = await action.onClick?.(event);
1843
+ if (action.dialog && !mute && action.dialog.type === "notification") toggleNotification({ title: action.dialog.title, message: action.dialog.content, type: action.dialog.status });
1844
+ };
1845
+ const typeOf = (action) => action.type || descriptions.find((d) => typeof action.id === "string" && action.id.startsWith(`${d.name || d.displayName}-`))?.type;
1846
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_admin2.DescriptionComponentRenderer, { props, descriptions, children: (actions) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Flex, { gap: 1, "data-testid": "page-preview-actions", children: [...actions].sort((a, b) => ACTION_TYPES.indexOf(typeOf(a)) - ACTION_TYPES.indexOf(typeOf(b))).map((action) => {
1847
+ const reason = action.disabled ? typeOf(action) === "publish" ? t.publishDisabledHint : t.saveDisabledHint : void 0;
1848
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { title: reason, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Button, { size: "S", variant: action.variant || "default", disabled: action.disabled, loading: action.loading, "aria-description": reason, onClick: (e) => run(action, e), children: action.label }) }, action.id);
1849
+ }) }) });
1850
+ }
1851
+ function PagePreview({ editor, groups = null, Toggle }) {
1852
+ const t = useMessages();
1853
+ const c = (0, import_strapi_admin.unstable_useContentManagerContext)();
1854
+ const rbac = (0, import_strapi_admin.useDocumentRBAC)("BlockscenePagePreview", (state) => state);
1855
+ const values = (0, import_admin2.useForm)("BlockscenePagePreview", (state) => state.values);
1856
+ const onChange = (0, import_admin2.useForm)("BlockscenePagePreview", (state) => state.onChange);
1857
+ const components = (0, import_admin2.useStrapiApp)("BlockscenePagePreview", (state) => state.components);
1858
+ const MediaLibraryDialog = components?.["media-library"];
1859
+ const addFieldRow = (0, import_admin2.useForm)("BlockscenePagePreview", (state) => state.addFieldRow);
1860
+ const moveFieldRow = (0, import_admin2.useForm)("BlockscenePagePreview", (state) => state.moveFieldRow);
1861
+ const fields = c.layout?.edit?.layout?.flat(3) || [];
1862
+ const readable = (name) => c.isCreatingEntry || (rbac.canReadFields || []).includes(name);
1863
+ const zone = React3.useMemo(() => editableZones(c.contentType, values, readable, c.isLoading)[0]?.name, [c.contentType, values, c.isLoading, rbac.canReadFields, c.isCreatingEntry]);
1864
+ const zoneLabel = fields.find((field) => field.name === zone)?.label || zone || "";
1865
+ const canEdit = Boolean(zone && ((c.isCreatingEntry ? rbac.canCreateFields : rbac.canUpdateFields) || []).includes(zone) && fields.find((field) => field.name === zone)?.disabled !== true && !c.form?.disabled && typeof addFieldRow === "function");
1866
+ const [mode, setModeState] = React3.useState(() => {
1867
+ const v = read(MODE_KEY);
1868
+ return v === "split" || v === "preview" ? v : editor?.previewMode || "form";
1869
+ });
1870
+ const setMode = (next) => {
1871
+ setModeState(next);
1872
+ write(MODE_KEY, next);
1873
+ };
1874
+ const [ratio, setRatio] = React3.useState(() => {
1875
+ const v = Number(read(RATIO_KEY));
1876
+ return v > 0 && v < 1 ? v : 0.5;
1877
+ });
1878
+ const main = useMainRect();
1879
+ const vw = main.width;
1880
+ const [dragging, setDragging] = React3.useState(false);
1881
+ const [ready, setReady] = React3.useState(false);
1882
+ const [failed, setFailed] = React3.useState(false);
1883
+ const [attempt, retry] = React3.useReducer((n) => n + 1, 0);
1884
+ const [picking, setPicking] = React3.useState(null);
1885
+ React3.useEffect(() => {
1886
+ setEditing(null);
1887
+ setPicking(null);
1888
+ setInserting(null);
1889
+ }, [c.id, c.form?.initialValues?.locale]);
1890
+ const [editing, setEditing] = React3.useState(null);
1891
+ const [inserting, setInserting] = React3.useState(null);
1892
+ const { get } = (0, import_admin2.useFetchClient)();
1893
+ const { toggleNotification } = (0, import_admin2.useNotification)();
1894
+ const zoneAttr = zone ? c.contentType?.attributes?.[zone] : null;
1895
+ const iframe = React3.useRef(null);
1896
+ const loaded = React3.useRef(false);
1897
+ const anchor = React3.useRef(null);
1898
+ const channel = React3.useMemo(() => crypto.randomUUID(), []);
1899
+ const { base, source } = usePreviewBase(editor?.previewUrl || "", c.model, c.isCreatingEntry ? void 0 : c.id, c.form?.initialValues?.locale);
1900
+ const url = base ? new URL(base) : null;
1901
+ url?.searchParams.set("channel", channel);
1902
+ const origin = url?.origin || "";
1903
+ const narrow = vw < NARROW;
1904
+ const paneWidth = clampWidth(ratio * vw, vw);
1905
+ const resizable = mode === "split" && !narrow;
1906
+ const active = mode !== "form" && Boolean(url) && Boolean(zone);
1907
+ const rows = zone && Array.isArray(values?.[zone]) ? values[zone] : [];
1908
+ const latest = React3.useRef(rows);
1909
+ latest.current = rows;
1910
+ const insertRows = (at, ...items) => items.forEach((item, i) => {
1911
+ const from = latest.current.length + i;
1912
+ addFieldRow(zone, item);
1913
+ if (at + i < from) moveFieldRow(zone, from, at + i);
1914
+ });
1915
+ const live = React3.useRef({ mode, canEdit, zoneLabel, components: c.components, setMode, onChange });
1916
+ live.current = { mode, canEdit, zoneLabel, components: c.components, setMode, onChange };
1917
+ const send = React3.useCallback(() => {
1918
+ iframe.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel, type: "update-page", blocks: projectPage(latest.current, live.current.components, window.location.origin), groups, locale: t.locale, mode: live.current.mode }, origin);
1919
+ }, [channel, origin]);
1920
+ const indexOf = (key) => latest.current.findIndex((row) => blockKey(row) === key);
1921
+ const path = (key, field) => `${zone}.${indexOf(key)}.${field}`;
1922
+ React3.useEffect(() => {
1923
+ if (resizable) markLayout(anchor.current);
1924
+ document.body.classList.toggle("bp-split", resizable);
1925
+ document.documentElement.style.setProperty("--bp-pane", `${paneWidth}px`);
1926
+ return () => document.body.classList.remove("bp-split");
1927
+ }, [resizable, paneWidth]);
1928
+ const applyWidth = (width, persist) => {
1929
+ const next = clampWidth(width, vw) / vw;
1930
+ setRatio(next);
1931
+ if (persist) write(RATIO_KEY, String(next));
1932
+ };
1933
+ const focusField = (index, field) => {
1934
+ const item = findZoneList(live.current.zoneLabel)?.querySelectorAll(":scope > li")[index];
1935
+ if (!item) return;
1936
+ const header = toggles(item.parentElement)[index];
1937
+ if (header?.getAttribute("aria-expanded") === "false") header.click();
1938
+ const parts = field.split(".");
1939
+ const escaped = CSS.escape(`${zone}.${index}.${field}`);
1940
+ let tries = 0;
1941
+ const timer = setInterval(() => {
1942
+ if (++tries > 40) return clearInterval(timer);
1943
+ let scope = item;
1944
+ for (let i = 0; i + 1 < parts.length; i += 2) {
1945
+ const nested = [...scope.querySelectorAll("button[aria-expanded][data-radix-collection-item]")].filter((b) => b !== header);
1946
+ const row = nested[Number(parts[i + 1])];
1947
+ if (!row) return;
1948
+ if (row.getAttribute("aria-expanded") === "false") row.click();
1949
+ scope = row.closest("li, div") || scope;
1950
+ }
1951
+ const target = document.querySelector(`[name="${escaped}"], label[for="${escaped}"]`);
1952
+ if (!target) return;
1953
+ const INPUT = '.ck-editor__editable, textarea, input:not([type="hidden"]), select';
1954
+ let container = target.matches(INPUT) ? target : target.parentElement;
1955
+ for (let depth = 0; container && depth < 4 && !container.matches(INPUT) && !container.querySelector(INPUT); depth++) container = container.parentElement;
1956
+ const editable = container?.matches(INPUT) ? container : container?.querySelector(INPUT);
1957
+ if (!editable) return;
1958
+ if (editable.classList.contains("ck-editor__editable") && !editable.isContentEditable) return;
1959
+ editable.focus();
1960
+ if (document.activeElement !== editable) return;
1961
+ clearInterval(timer);
1962
+ editable.scrollIntoView({ block: "center", behavior: "smooth" });
1963
+ }, 150);
1964
+ };
1965
+ React3.useEffect(() => {
1966
+ if (!active) return;
1967
+ setReady(false);
1968
+ setFailed(false);
1969
+ const timeout = setTimeout(() => setFailed(true), 15e3);
1970
+ const receive = (event) => {
1971
+ const is = (type) => isPreviewMessage(event, origin, iframe.current?.contentWindow, channel, type);
1972
+ const { mode: mode2, canEdit: canEdit2, zoneLabel: zoneLabel2, components: components2, setMode: setMode2, onChange: onChange2 } = live.current;
1973
+ if (is("ready")) {
1974
+ clearTimeout(timeout);
1975
+ setReady(true);
1976
+ setFailed(false);
1977
+ send();
1978
+ return;
1979
+ }
1980
+ if (is("insert") && canEdit2) {
1981
+ const after = event.data.after === null || event.data.after === void 0 ? null : String(event.data.after);
1982
+ if (after !== null && insertIndex(latest.current, after) < 0) return;
1983
+ if (latest.current.length >= (zoneAttr?.max ?? Infinity)) {
1984
+ toggleNotification({ type: "info", message: t.zoneFull });
1985
+ return;
1986
+ }
1987
+ setInserting({ after });
1988
+ return;
1989
+ }
1990
+ if (is("move-group") && canEdit2 && groups) {
1991
+ const next = (0, import_groups.moveGroup)(latest.current, String(event.data.key), event.data.direction === "up" ? "up" : "down", groups);
1992
+ if (next) onChange2(zone, next);
1993
+ return;
1994
+ }
1995
+ if (is("delete-group") && canEdit2 && groups) {
1996
+ const next = (0, import_groups.removeGroup)(latest.current, String(event.data.key), groups);
1997
+ if (next) onChange2(zone, next);
1998
+ return;
1999
+ }
2000
+ if (is("insert-group") && canEdit2 && groups) {
2001
+ const after = event.data.after === null || event.data.after === void 0 ? null : String(event.data.after);
2002
+ const index2 = insertIndex(latest.current, after);
2003
+ const uid2 = String(event.data.uid || "");
2004
+ const close = groups[uid2];
2005
+ const allowed = zoneAttr?.components || [];
2006
+ if (index2 < 0 || !close || !allowed.includes(uid2) || !allowed.includes(close)) return;
2007
+ if (latest.current.length + 2 > (zoneAttr?.max ?? Infinity)) {
2008
+ toggleNotification({ type: "info", message: t.zoneFull });
2009
+ return;
2010
+ }
2011
+ insertRows(index2, { ...componentDefaults(components2[uid2], components2), __component: uid2 }, { __component: close });
2012
+ return;
2013
+ }
2014
+ const key = typeof event.data?.key === "string" ? event.data.key : "";
2015
+ const index = key ? indexOf(key) : -1;
2016
+ const uid = index >= 0 ? latest.current[index]?.__component : "";
2017
+ if (index < 0) return;
2018
+ if (is("select")) {
2019
+ const list = findZoneList(zoneLabel2);
2020
+ const item = list?.querySelectorAll(":scope > li")[index];
2021
+ const header = list ? toggles(list)[index] : null;
2022
+ if (header?.getAttribute("aria-expanded") === "false") header.click();
2023
+ item?.scrollIntoView({ block: "center", behavior: "smooth" });
2024
+ if (item) {
2025
+ item.style.outline = "2px solid #4945ff";
2026
+ setTimeout(() => {
2027
+ item.style.outline = "";
2028
+ }, 1500);
2029
+ }
2030
+ if (mode2 === "preview") setMode2("split");
2031
+ iframe.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel, type: "highlight", key }, origin);
2032
+ } else if (is("focus")) {
2033
+ const attr = validateFocus(uid, event.data.field, components2);
2034
+ if (!attr) return;
2035
+ if (mode2 === "preview" && canEdit2 && (attr.customField || MODAL_TYPES.includes(attr.type))) setEditing({ key, field: event.data.field, attr, label: `${components2[uid]?.info?.displayName || uid} \xB7 ${event.data.field}`, value: getIn(latest.current[index], event.data.field) });
2036
+ else focusField(index, event.data.field);
2037
+ } else if (is("media") && canEdit2) {
2038
+ const attr = mediaAttribute(uid, event.data.field, components2);
2039
+ if (attr) setPicking({ key, field: event.data.field, attr });
2040
+ } else if (is("media-remove") && canEdit2) {
2041
+ const attr = mediaAttribute(uid, event.data.field, components2);
2042
+ if (attr && !attr.required) onChange2(path(key, event.data.field), null);
2043
+ } else if (is("edit") && canEdit2) {
2044
+ const value = validateEdit(uid, event.data.field, event.data.value, components2);
2045
+ if (value !== null) onChange2(path(key, event.data.field), value);
2046
+ }
2047
+ };
2048
+ window.addEventListener("message", receive);
2049
+ if (loaded.current) iframe.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel, type: "ping" }, origin);
2050
+ return () => {
2051
+ clearTimeout(timeout);
2052
+ window.removeEventListener("message", receive);
2053
+ };
2054
+ }, [active, attempt, channel, origin, groups]);
2055
+ React3.useEffect(() => {
2056
+ if (!ready || !active) return;
2057
+ const timer = setTimeout(send, 120);
2058
+ return () => clearTimeout(timer);
2059
+ }, [values, c.components, ready, active, send, mode]);
2060
+ if (!zone) return null;
2061
+ const modes = [["form", t.modeForm], ["split", t.modeSplit], ["preview", t.modePreview]];
2062
+ const switcher = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Flex, { gap: 1, wrap: "wrap", "data-testid": "page-preview-modes", role: "group", "aria-label": t.modeGroup, children: modes.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Button, { type: "button", size: "S", variant: mode === value ? "default" : "tertiary", "aria-pressed": mode === value, onClick: () => setMode(value), disabled: !url && value !== "form", children: label }, value)) });
2063
+ const onKey = (event) => {
2064
+ const map = { ArrowLeft: paneWidth + KEY_STEP, ArrowRight: paneWidth - KEY_STEP, Home: MIN_PANE, End: vw - MIN_FORM };
2065
+ if (event.key in map) {
2066
+ event.preventDefault();
2067
+ applyWidth(map[event.key], true);
2068
+ }
2069
+ };
2070
+ const problems = groups ? (0, import_groups.validateGroups)(rows, groups) : [];
2071
+ const insertClose = (error) => {
2072
+ const end = (0, import_groups.groupRange)(latest.current, error.index, groups)[1];
2073
+ insertRows(end + 1, { __component: error.expected });
2074
+ };
2075
+ const diagnostics = problems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Box, { role: "alert", "data-testid": "page-preview-diagnostics", padding: 2, background: "danger100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("details", { children: [
2076
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("summary", { style: { cursor: "pointer" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "danger700", children: t.f("diagSummary", { count: problems.length }) }) }),
2077
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { style: { margin: "6px 0 0 16px", padding: 0 }, children: problems.map((error) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { style: { marginBottom: 6 }, children: [
2078
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "danger700", children: t.f(error.code === "closeBeforeOpen" ? "diagCloseBeforeOpen" : error.code === "mismatch" ? "diagMismatch" : "diagUnclosed", { n: error.index + 1, uid: error.uid, open: error.open || "", expected: error.expected || "" }) }),
2079
+ error.code === "unclosed" && canEdit && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Box, { paddingTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Button, { size: "S", variant: "danger-light", "data-testid": `diag-insert-close-${error.index}`, onClick: () => insertClose(error), children: t.f("diagInsertClose", { n: error.index + 1, expected: error.expected }) }) }),
2080
+ error.code === "closeBeforeOpen" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.diagStrayHint })
2081
+ ] }, `${error.code}-${error.index}`)) })
2082
+ ] }) });
2083
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 2, ref: anchor, children: [
2084
+ switcher,
2085
+ diagnostics,
2086
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: url ? t.previewHelp : t.previewNoUrl }),
2087
+ active && (0, import_react_dom2.createPortal)(
2088
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2089
+ Pane,
2090
+ {
2091
+ "data-testid": "page-preview-pane",
2092
+ "aria-label": t.previewPane,
2093
+ style: { left: mode === "preview" || narrow ? main.left : main.left + main.width - paneWidth, width: mode === "preview" || narrow ? main.width : paneWidth, userSelect: dragging ? "none" : void 0 },
2094
+ children: [
2095
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: SPLIT_STYLE }),
2096
+ resizable && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2097
+ Handle,
2098
+ {
2099
+ role: "separator",
2100
+ "aria-orientation": "vertical",
2101
+ "aria-label": t.resize,
2102
+ tabIndex: 0,
2103
+ "aria-valuemin": MIN_PANE,
2104
+ "aria-valuemax": Math.max(MIN_PANE, vw - MIN_FORM),
2105
+ "aria-valuenow": paneWidth,
2106
+ "data-testid": "page-preview-resizer",
2107
+ "data-dragging": dragging,
2108
+ onPointerDown: (e) => {
2109
+ e.preventDefault();
2110
+ e.currentTarget.setPointerCapture(e.pointerId);
2111
+ setDragging(true);
2112
+ },
2113
+ onPointerMove: (e) => {
2114
+ if (dragging) applyWidth(main.left + main.width - e.clientX, false);
2115
+ },
2116
+ onPointerUp: (e) => {
2117
+ if (!dragging) return;
2118
+ setDragging(false);
2119
+ e.currentTarget.releasePointerCapture(e.pointerId);
2120
+ applyWidth(main.left + main.width - e.clientX, true);
2121
+ },
2122
+ onPointerCancel: () => setDragging(false),
2123
+ onKeyDown: onKey
2124
+ }
2125
+ ),
2126
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { padding: 2, gap: 2, justifyContent: "space-between", alignItems: "center", background: "neutral100", wrap: "wrap", style: { position: "sticky", top: 0, zIndex: 2 }, children: [
2127
+ switcher,
2128
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { gap: 2, alignItems: "center", wrap: "wrap", style: { marginLeft: "auto" }, children: [
2129
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { variant: "pi", role: "status", textColor: "neutral600", children: failed ? t.previewFailed : ready ? t.previewReady : t.previewLoading }),
2130
+ failed && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Button, { size: "S", variant: "secondary", onClick: retry, children: t.retry }),
2131
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToolbarActions, { model: c.model, collectionType: c.collectionType, documentId: c.isCreatingEntry ? void 0 : c.id, locale: c.form?.initialValues?.locale })
2132
+ ] })
2133
+ ] }),
2134
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2135
+ Frame2,
2136
+ {
2137
+ ref: iframe,
2138
+ title: t.previewPane,
2139
+ src: url.href,
2140
+ sandbox: "allow-scripts allow-same-origin",
2141
+ referrerPolicy: "no-referrer",
2142
+ onLoad: () => {
2143
+ loaded.current = true;
2144
+ },
2145
+ style: dragging ? { pointerEvents: "none" } : void 0
2146
+ },
2147
+ attempt
2148
+ )
2149
+ ]
2150
+ }
2151
+ ),
2152
+ document.body
2153
+ ),
2154
+ inserting && zoneAttr && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2155
+ PickerModal,
2156
+ {
2157
+ zone: { name: zone, components: zoneAttr.components || [], max: zoneAttr.max },
2158
+ components: c.components,
2159
+ Modal: PickerDialog,
2160
+ Toggle,
2161
+ get,
2162
+ open: true,
2163
+ onOpenChange: (open) => {
2164
+ if (!open) setInserting(null);
2165
+ },
2166
+ onSelect: (uid) => {
2167
+ const index = insertIndex(latest.current, inserting.after);
2168
+ setInserting(null);
2169
+ const close = groups?.[uid];
2170
+ if (index < 0 || !(zoneAttr.components || []).includes(uid) || close && !(zoneAttr.components || []).includes(close) || latest.current.length + (close ? 2 : 1) > (zoneAttr.max ?? Infinity)) {
2171
+ toggleNotification({ type: "warning", message: close ? t.zoneFull : t.insertMoved });
2172
+ return;
2173
+ }
2174
+ insertRows(index, { ...componentDefaults(c.components[uid], c.components), __component: uid }, ...close ? [{ __component: close }] : []);
2175
+ }
2176
+ }
2177
+ ),
2178
+ editing && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2179
+ FieldEditorModal,
2180
+ {
2181
+ label: editing.label,
2182
+ attribute: editing.attr,
2183
+ value: editing.value,
2184
+ onCancel: () => setEditing(null),
2185
+ onApply: (value) => {
2186
+ const index = indexOf(editing.key);
2187
+ setEditing(null);
2188
+ if (index >= 0) onChange(`${zone}.${index}.${editing.field}`, value);
2189
+ }
2190
+ }
2191
+ ),
2192
+ picking && MediaLibraryDialog && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2193
+ MediaLibraryDialog,
2194
+ {
2195
+ allowedTypes: picking.attr.allowedTypes || ["images"],
2196
+ multiple: picking.attr.multiple === true,
2197
+ onClose: () => setPicking(null),
2198
+ onSelectAssets: (assets) => {
2199
+ const index = indexOf(picking.key);
2200
+ setPicking(null);
2201
+ if (index < 0 || !assets?.length) return;
2202
+ const current = getIn(latest.current[index], picking.field);
2203
+ onChange(`${zone}.${index}.${picking.field}`, picking.attr.multiple ? [...Array.isArray(current) ? current : [], ...assets] : assets[0]);
2204
+ }
2205
+ }
2206
+ ),
2207
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Box, { hidden: true, "data-testid": "page-preview-state", "data-mode": mode, "data-ready": ready, "data-failed": failed, "data-pane-width": paneWidth, "data-narrow": narrow, "data-preview-source": source, "data-editing": editing ? editing.field : "" })
2208
+ ] });
2209
+ }
2210
+
2211
+ // admin/Settings.tsx
2212
+ var React4 = __toESM(require("react"));
2213
+ var import_design_system5 = require("@strapi/design-system");
2214
+ var import_styled_components3 = __toESM(require("styled-components"));
2215
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1418
2216
  var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
1419
- var Grid = import_styled_components2.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
1420
- var Card2 = import_styled_components2.default.div`
2217
+ var Grid = import_styled_components3.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
2218
+ var Card2 = import_styled_components3.default.div`
1421
2219
  display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
1422
2220
  border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral0};
1423
2221
  `;
1424
- var Bar = import_styled_components2.default.div`
2222
+ var Bar = import_styled_components3.default.div`
1425
2223
  position: fixed; top: 0; z-index: 4; padding: 12px 32px;
1426
2224
  background: ${({ theme }) => theme.colors.neutral100}; border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};
1427
2225
  box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
1428
2226
  `;
1429
- function useMainRect(anchor) {
1430
- const [rect, setRect] = React2.useState({ left: 0, width: 0 });
1431
- React2.useEffect(() => {
1432
- const read = () => {
2227
+ function useMainRect2(anchor) {
2228
+ const [rect, setRect] = React4.useState({ left: 0, width: 0 });
2229
+ React4.useEffect(() => {
2230
+ const read2 = () => {
1433
2231
  let host = document.getElementById("main-content");
1434
2232
  for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
1435
2233
  const r = (host || document.querySelector("main"))?.getBoundingClientRect();
1436
2234
  if (r) setRect({ left: Math.round(r.left), width: Math.round(r.width) });
1437
2235
  };
1438
- read();
1439
- window.addEventListener("resize", read);
1440
- return () => window.removeEventListener("resize", read);
2236
+ read2();
2237
+ window.addEventListener("resize", read2);
2238
+ return () => window.removeEventListener("resize", read2);
1441
2239
  });
1442
2240
  return rect;
1443
2241
  }
1444
- var Swatches = import_styled_components2.default.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
1445
- var Label = import_styled_components2.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
2242
+ var Swatches = import_styled_components3.default.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
2243
+ var Label = import_styled_components3.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
1446
2244
  function ColorField({ name, label, value, onChange, disabled }) {
1447
2245
  const valid = COLOR2.test(value);
1448
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Label, { children: [
1449
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
1450
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 2, children: [
1451
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "color", "aria-label": label, value: valid ? value : "#000000", disabled, onChange: (e) => onChange(e.target.value.toUpperCase()), style: { width: 40, height: 32, padding: 0, border: 0, background: "none" } }),
1452
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2246
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Label, { children: [
2247
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
2248
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 2, children: [
2249
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { type: "color", "aria-label": label, value: valid ? value : "#000000", disabled, onChange: (e) => onChange(e.target.value.toUpperCase()), style: { width: 40, height: 32, padding: 0, border: 0, background: "none" } }),
2250
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1453
2251
  "input",
1454
2252
  {
1455
2253
  name,
@@ -1465,22 +2263,22 @@ function ColorField({ name, label, value, onChange, disabled }) {
1465
2263
  ] });
1466
2264
  }
1467
2265
  var permissions = { read: [{ action: "plugin::blockscene.settings.read", subject: null }], update: [{ action: "plugin::blockscene.settings.update", subject: null }] };
1468
- function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: MediaPicker2, ToggleField: ToggleField2, SelectField: SelectField2, TextField, previewSupported = false }) {
2266
+ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: MediaPicker2, ToggleField: ToggleField2, SelectField: SelectField2, TextField: TextField2, previewSupported = false }) {
1469
2267
  const t = useMessages();
1470
2268
  const { get, put } = useClient();
1471
2269
  const { canRead, canUpdate, isLoading } = usePermissions2();
1472
- const [data, setData] = React2.useState(null);
1473
- const [catalog, setCatalog] = React2.useState(null);
1474
- const [settings, setSettings] = React2.useState(null);
1475
- const [media, setMedia] = React2.useState({});
1476
- const [sources, setSources] = React2.useState({});
1477
- const [dirty, setDirty] = React2.useState(false);
1478
- const [saving, setSaving] = React2.useState(false);
1479
- const [status, setStatus] = React2.useState("");
1480
- const [failed, setFailed] = React2.useState(false);
1481
- const [filter, setFilter] = React2.useState("");
1482
- const [picking, setPicking] = React2.useState(null);
1483
- React2.useEffect(() => {
2270
+ const [data, setData] = React4.useState(null);
2271
+ const [catalog, setCatalog] = React4.useState(null);
2272
+ const [settings, setSettings] = React4.useState(null);
2273
+ const [media, setMedia] = React4.useState({});
2274
+ const [sources, setSources] = React4.useState({});
2275
+ const [dirty, setDirty] = React4.useState(false);
2276
+ const [saving, setSaving] = React4.useState(false);
2277
+ const [status, setStatus] = React4.useState("");
2278
+ const [failed, setFailed] = React4.useState(false);
2279
+ const [filter, setFilter] = React4.useState("");
2280
+ const [picking, setPicking] = React4.useState(null);
2281
+ React4.useEffect(() => {
1484
2282
  if (!canRead || isLoading) return;
1485
2283
  let active = true;
1486
2284
  Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
@@ -1528,35 +2326,35 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1528
2326
  return index === 0 && manual ? t.manual : t.automatic;
1529
2327
  };
1530
2328
  const ready = !isLoading && canRead && !failed && settings && catalog;
1531
- const header = React2.useRef(null);
1532
- const [floating, setFloating] = React2.useState(false);
1533
- const main = useMainRect(header);
1534
- React2.useEffect(() => {
2329
+ const header = React4.useRef(null);
2330
+ const [floating, setFloating] = React4.useState(false);
2331
+ const main = useMainRect2(header);
2332
+ React4.useEffect(() => {
1535
2333
  const el = header.current;
1536
2334
  if (!el || typeof IntersectionObserver === "undefined") return;
1537
2335
  const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
1538
2336
  observer.observe(el);
1539
2337
  return () => observer.disconnect();
1540
2338
  }, [ready]);
1541
- const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
1542
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
1543
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
2339
+ const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
2340
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
2341
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
1544
2342
  ] });
1545
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
1546
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
1547
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
2343
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
2344
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
2345
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
1548
2346
  controls("")
1549
2347
  ] }) }),
1550
- floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
1551
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
2348
+ floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
2349
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
1552
2350
  controls("-floating")
1553
2351
  ] }) }),
1554
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { textColor: "neutral600", children: t.settingsIntro }),
1555
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1556
- data.disabled && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
1557
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
1558
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.palette }),
1559
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2352
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { textColor: "neutral600", children: t.settingsIntro }),
2353
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2354
+ data.disabled && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
2355
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2356
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "h2", children: t.palette }),
2357
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1560
2358
  ColorField,
1561
2359
  {
1562
2360
  name: `palette-${key}`,
@@ -1570,33 +2368,33 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1570
2368
  },
1571
2369
  key
1572
2370
  )) }),
1573
- invalid && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
1574
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
1575
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", gap: 1, children: [
1576
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wireframe, { template, palette: settings.palette }) }),
1577
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
2371
+ invalid && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
2372
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
2373
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { direction: "column", gap: 1, children: [
2374
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Wireframe, { template, palette: settings.palette }) }),
2375
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
1578
2376
  ] }, template)) }),
1579
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
2377
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
1580
2378
  s.palette = { ...DEFAULT_PALETTE };
1581
2379
  return s;
1582
2380
  }), children: t.resetPalette }) })
1583
2381
  ] }) }),
1584
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
1585
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.editor }),
1586
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2382
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2383
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "h2", children: t.editor }),
2384
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1587
2385
  s.editor.enabled = v;
1588
2386
  return s;
1589
2387
  }) }),
1590
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
1591
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2388
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
2389
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1592
2390
  s.editor.showOpenAll = v;
1593
2391
  return s;
1594
2392
  }) }),
1595
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2393
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1596
2394
  s.editor.showCloseAll = v;
1597
2395
  return s;
1598
2396
  }) }),
1599
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2397
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1600
2398
  SelectField2,
1601
2399
  {
1602
2400
  name: "editor-initialState",
@@ -1610,10 +2408,10 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1610
2408
  })
1611
2409
  }
1612
2410
  ),
1613
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
1614
- previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1615
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1616
- TextField,
2411
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
2412
+ previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2413
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2414
+ TextField2,
1617
2415
  {
1618
2416
  name: "editor-previewUrl",
1619
2417
  label: t.previewUrl,
@@ -1626,8 +2424,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1626
2424
  })
1627
2425
  }
1628
2426
  ),
1629
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
1630
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2427
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
2428
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1631
2429
  SelectField2,
1632
2430
  {
1633
2431
  name: "editor-previewMode",
@@ -1641,26 +2439,26 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1641
2439
  })
1642
2440
  }
1643
2441
  ),
1644
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
1645
- data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1646
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2442
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
2443
+ data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2444
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1647
2445
  s.editor.blockPreviewInForm = v;
1648
2446
  return s;
1649
2447
  }) }),
1650
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
2448
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
1651
2449
  ] })
1652
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
2450
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
1653
2451
  ] }) }),
1654
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
1655
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.components }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
1657
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
1658
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
2452
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2453
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "h2", children: t.components }),
2454
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
2455
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
2456
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
1659
2457
  const entry = settings.components[component.uid] || {};
1660
2458
  const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
1661
2459
  const candidates = candidatesFor(component.uid, meta, catalog);
1662
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
1663
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2460
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
2461
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1664
2462
  Thumb,
1665
2463
  {
1666
2464
  candidates,
@@ -1671,23 +2469,23 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1671
2469
  onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
1672
2470
  }
1673
2471
  ),
1674
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
1675
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
1676
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: [
2472
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
2473
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
2474
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: [
1677
2475
  component.uid,
1678
2476
  " \xB7 ",
1679
2477
  component.category
1680
2478
  ] }),
1681
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
2479
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
1682
2480
  t.source,
1683
2481
  ": ",
1684
2482
  sourceOf(component.uid, Boolean(meta.manualImage)),
1685
2483
  meta.manualName ? ` (${meta.manualName})` : ""
1686
2484
  ] }),
1687
- meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
1688
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 2, wrap: "wrap", children: [
1689
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
1690
- entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
2485
+ meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
2486
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 2, wrap: "wrap", children: [
2487
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
2488
+ entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
1691
2489
  update((s) => {
1692
2490
  delete s.components[component.uid]?.mediaId;
1693
2491
  if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
@@ -1700,7 +2498,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1700
2498
  });
1701
2499
  }, children: t.useAutomatic })
1702
2500
  ] }),
1703
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2501
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1704
2502
  SelectField2,
1705
2503
  {
1706
2504
  name: `template-${component.uid}`,
@@ -1718,7 +2516,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1718
2516
  ] }, component.uid);
1719
2517
  }) })
1720
2518
  ] }) }),
1721
- picking && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
2519
+ picking && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
1722
2520
  const uid = picking;
1723
2521
  setPicking(null);
1724
2522
  if (!asset?.id) return;
@@ -1747,10 +2545,10 @@ function register(app, Component, to) {
1747
2545
  }
1748
2546
 
1749
2547
  // admin/catalog.ts
1750
- var React3 = __toESM(require("react"));
2548
+ var React5 = __toESM(require("react"));
1751
2549
  function useCatalog(get) {
1752
- const [catalog, setCatalog] = React3.useState(null);
1753
- React3.useEffect(() => {
2550
+ const [catalog, setCatalog] = React5.useState(null);
2551
+ React5.useEffect(() => {
1754
2552
  let active = true;
1755
2553
  get("/blockscene/catalog").then(({ data }) => {
1756
2554
  if (active) setCatalog(data);
@@ -1764,77 +2562,83 @@ function useCatalog(get) {
1764
2562
  return catalog;
1765
2563
  }
1766
2564
 
1767
- // admin/strapi4.tsx
1768
- var import_jsx_runtime4 = require("react/jsx-runtime");
1769
- function Modal({ open, onOpenChange, trigger, title, children }) {
1770
- const id = React4.useId();
1771
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1772
- trigger,
1773
- open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, children: [
1774
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { id, variant: "beta", children: title }) }),
1775
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.ModalBody, { children })
2565
+ // admin/strapi5.tsx
2566
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2567
+ function Modal2({ open, onOpenChange, trigger, title, children }) {
2568
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Modal.Root, { open, onOpenChange, children: [
2569
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Modal.Trigger, { children: trigger }),
2570
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Modal.Content, { style: { width: "80vw", maxWidth: "80vw" }, children: [
2571
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Modal.Header, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Modal.Title, { children: title }) }),
2572
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Modal.Body, { children })
1776
2573
  ] })
1777
2574
  ] });
1778
2575
  }
1779
- function Picker() {
1780
- const c = (0, import_helper_plugin.useCMEditViewDataManager)();
1781
- const { get } = (0, import_helper_plugin.useFetchClient)();
2576
+ function Panel() {
2577
+ const c = (0, import_strapi_admin2.unstable_useContentManagerContext)();
2578
+ const rbac = (0, import_strapi_admin2.useDocumentRBAC)("Blockscene", (state) => state);
2579
+ const { get } = (0, import_admin3.useFetchClient)();
2580
+ const t = useMessages();
2581
+ const user = (0, import_admin3.useAuth)("Blockscene", (state) => state.user);
2582
+ const formValues = (0, import_admin3.useForm)("Blockscene", (state) => state.values);
1782
2583
  const catalog = useCatalog(get);
1783
- const components = c.allLayoutData?.components || {};
1784
- const schema = c.layout || c.allLayoutData?.contentType;
1785
- const allowed = (c.isCreatingEntry ? c.createActionAllowedFields : c.updateActionAllowedFields) || [];
1786
- const zones = editableZones(schema, c.modifiedData, (name) => allowed.includes(name) && schema?.metadatas?.[name]?.edit?.editable !== false, !c.addComponentToDynamicZone).map((zone) => ({ ...zone, label: schema?.metadatas?.[zone.name]?.edit?.label || zone.name }));
2584
+ const creating = !c.id && !c.form?.initialValues?.id && !c.form?.initialValues?.documentId;
2585
+ const allowed = (creating ? rbac.canCreateFields : rbac.canUpdateFields) || [];
2586
+ const fields = c.layout?.edit?.layout?.flat(3) || [];
2587
+ const zones = editableZones(
2588
+ c.contentType,
2589
+ formValues ?? c.form?.values,
2590
+ (name) => allowed.includes(name) && (creating || (rbac.canReadFields || []).includes(name)) && fields.find((field) => field.name === name)?.disabled !== true,
2591
+ c.isLoading || c.form?.disabled || !c.form?.addFieldRow
2592
+ ).map((zone) => ({ ...zone, label: fields.find((field) => field.name === zone.name)?.label || zone.name }));
1787
2593
  const add = (zone, uid) => {
2594
+ const values = formValues ?? c.form.values;
1788
2595
  const close = catalog?.groups?.[uid];
1789
- if (!canInsert(zone, uid, c.modifiedData, components, close ? 2 : 1) || close && !zone.components.includes(close)) return false;
1790
- c.addComponentToDynamicZone(zone.name, components[uid], components, Boolean(c.formErrors?.[zone.name]));
1791
- if (close) c.addComponentToDynamicZone(zone.name, components[close], components, Boolean(c.formErrors?.[zone.name]));
2596
+ if (c.form.disabled || !canInsert(zone, uid, values, c.components, close ? 2 : 1) || close && !zone.components.includes(close)) return false;
2597
+ const at = Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0;
2598
+ c.form.addFieldRow(zone.name, { ...componentDefaults(c.components[uid], c.components), __component: uid }, at);
2599
+ if (close) c.form.addFieldRow(zone.name, { __component: close }, at + 1);
1792
2600
  return true;
1793
2601
  };
1794
- if (!catalog?.editor?.enabled) return null;
1795
- const docKey = `${c.slug}:${c.isCreatingEntry ? "new" : c.initialData?.id}:${c.initialData?.locale || ""}`;
1796
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1797
- Gallery,
1798
- {
1799
- zones,
1800
- components,
1801
- add,
1802
- Modal,
1803
- Toggle: ToggleField,
1804
- get,
1805
- editor: catalog.editor,
1806
- docKey,
1807
- contentType: c.slug,
1808
- userId: import_helper_plugin.auth.getUserInfo?.()?.id
1809
- }
1810
- );
2602
+ if (!zones.length || !catalog?.editor?.enabled) return null;
2603
+ const docKey = `${c.model}:${creating ? "new" : c.id}:${c.form?.initialValues?.locale || ""}`;
2604
+ return { title: t.gallery, content: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2605
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Gallery, { zones, components: c.components, add, Modal: Modal2, Toggle: ToggleField, get, editor: catalog.editor, docKey, contentType: c.model, userId: user?.id }),
2606
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PagePreview, { editor: catalog.editor, groups: catalog.groups || null, Toggle: ToggleField })
2607
+ ] }) };
1811
2608
  }
1812
- var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { gap: 3, children: [
1813
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Switch, { name, "aria-label": label, selected: Boolean(value), disabled, onChange: () => onChange(!value) }),
1814
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { children: label })
2609
+ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Flex, { gap: 3, children: [
2610
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Switch, { name, "aria-label": label, checked: Boolean(value), disabled, onCheckedChange: onChange }),
2611
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Typography, { children: label })
2612
+ ] });
2613
+ var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Field.Root, { name, children: [
2614
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Field.Label, { children: label }),
2615
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.TextInput, { name, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) })
2616
+ ] });
2617
+ var SelectField = ({ name, label, value, onChange, disabled, options }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Field.Root, { name, children: [
2618
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Field.Label, { children: label }),
2619
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.SingleSelect, { value, disabled, onChange: (v) => onChange(String(v)), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.SingleSelectOption, { value: o.value, children: o.label }, o.value)) })
1815
2620
  ] });
1816
- var SelectField = ({ name, label, value, onChange, disabled, options }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.SingleSelect, { name, label, value, disabled, onChange: (v) => onChange(String(v)), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.SingleSelectOption, { value: o.value, children: o.label }, o.value)) });
1817
2621
  function MediaPicker({ onClose, onSelect }) {
1818
- const { components } = (0, import_helper_plugin.useLibrary)();
1819
- const Dialog = components?.["media-library"];
1820
- if (!Dialog) {
1821
- onClose();
1822
- return null;
1823
- }
1824
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog, { onClose, allowedTypes: ["images"], onSelectAssets: (assets) => onSelect(assets?.[0]) });
2622
+ const components = (0, import_admin3.useStrapiApp)("Blockscene", (state) => state.components);
2623
+ const Dialog3 = components?.["media-library"];
2624
+ React6.useEffect(() => {
2625
+ if (!Dialog3) onClose();
2626
+ }, [Dialog3, onClose]);
2627
+ if (!Dialog3) return null;
2628
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dialog3, { onClose, allowedTypes: ["images"], multiple: false, onSelectAssets: (assets) => onSelect(assets?.[0]) });
1825
2629
  }
1826
2630
  function usePermissions() {
1827
- const { allowedActions, isLoading } = (0, import_helper_plugin.useRBAC)(permissions);
2631
+ const { allowedActions, isLoading } = (0, import_admin3.useRBAC)(Object.values(permissions).flat());
1828
2632
  return { canRead: allowedActions.canRead, canUpdate: allowedActions.canUpdate, isLoading };
1829
2633
  }
1830
- var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Settings, { useClient: import_helper_plugin.useFetchClient, usePermissions, MediaPicker, ToggleField, SelectField, previewSupported: false });
1831
- var strapi4_default = {
2634
+ var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Settings, { useClient: import_admin3.useFetchClient, usePermissions, MediaPicker, ToggleField, SelectField, TextField, previewSupported: true });
2635
+ var strapi5_default = {
1832
2636
  register(app) {
1833
- register(app, SettingsPage, "/settings/blockscene");
2637
+ register(app, SettingsPage, "blockscene");
1834
2638
  app.registerPlugin({ id: "blockscene", name: "Blockscene" });
1835
2639
  },
1836
2640
  registerTrads,
1837
2641
  bootstrap(app) {
1838
- app.injectContentManagerComponent("editView", "right-links", { name: "blockscene", Component: Picker });
2642
+ app.getPlugin("content-manager").apis.addEditViewSidePanel([Panel]);
1839
2643
  }
1840
2644
  };