@aduptive/strapi-blockscene 2.0.0-alpha.1 → 2.0.0-alpha.4

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 (4) hide show
  1. package/README.md +17 -5
  2. package/dist/admin.cjs +1307 -372
  3. package/dist/admin.mjs +1346 -374
  4. package/package.json +3 -5
package/dist/admin.cjs CHANGED
@@ -141,30 +141,35 @@ __export(strapi5_exports, {
141
141
  default: () => strapi5_default
142
142
  });
143
143
  module.exports = __toCommonJS(strapi5_exports);
144
- var React6 = __toESM(require("react"));
145
- var import_design_system6 = require("@strapi/design-system");
144
+ var React7 = __toESM(require("react"));
145
+ var import_design_system5 = require("@strapi/design-system");
146
146
  var import_admin3 = require("@strapi/strapi/admin");
147
147
  var import_strapi_admin2 = require("@strapi/content-manager/strapi-admin");
148
148
 
149
149
  // admin/Gallery.tsx
150
- var React = __toESM(require("react"));
151
- var import_react_dom = require("react-dom");
150
+ var React2 = __toESM(require("react"));
151
+ var import_react_dom2 = require("react-dom");
152
152
  var import_design_system = require("@strapi/design-system");
153
153
  var import_styled_components = __toESM(require("styled-components"));
154
154
 
155
155
  // admin/model.mjs
156
156
  var import_fractional_indexing = require("fractional-indexing");
157
157
  function componentDefaults(schema, components, stack = []) {
158
- if (!schema || stack.includes(schema)) throw new Error("Invalid recursive component defaults");
158
+ if (!schema || stack.includes(schema))
159
+ throw new Error("Invalid recursive component defaults");
159
160
  const row = {};
160
161
  for (const [name, attr] of Object.entries(schema.attributes || {})) {
161
162
  if (Object.hasOwn(attr, "default")) {
162
163
  const value = structuredClone(attr.default);
163
164
  if (attr.type === "password") row[name] = "";
164
- else if (attr.type === "relation") row[name] = { connect: [], disconnect: [] };
165
+ else if (attr.type === "relation")
166
+ row[name] = { connect: [], disconnect: [] };
165
167
  else if (value !== null || attr.type === "boolean") row[name] = value;
166
168
  } else if (attr.type === "component" && attr.required) {
167
- const create = () => componentDefaults(components[attr.component], components, [...stack, schema]);
169
+ const create = () => componentDefaults(components[attr.component], components, [
170
+ ...stack,
171
+ schema
172
+ ]);
168
173
  if (attr.repeatable) {
169
174
  const keys = (0, import_fractional_indexing.generateNKeysBetween)(null, null, attr.min || 0);
170
175
  row[name] = keys.map((key) => ({ ...create(), __temp_key__: key }));
@@ -175,27 +180,58 @@ function componentDefaults(schema, components, stack = []) {
175
180
  }
176
181
  function editableZones(schema, values, canEdit, disabled = false) {
177
182
  if (disabled) return [];
178
- return Object.entries(schema?.attributes || {}).filter(([name, attr]) => attr.type === "dynamiczone" && !attr.conditions && canEdit(name)).map(([name, attr]) => {
179
- const count = Array.isArray(values?.[name]) ? values[name].length : 0;
180
- return { name, components: attr.components || [], max: attr.max, count, full: count >= (attr.max ?? Infinity) };
183
+ return Object.entries(schema?.attributes || {}).filter(
184
+ ([name, attr]) => attr.type === "dynamiczone" && !attr.conditions && canEdit(name)
185
+ ).map(([name, attr]) => {
186
+ const rows = Array.isArray(values?.[name]) ? values[name] : [];
187
+ return {
188
+ name,
189
+ components: attr.components || [],
190
+ max: attr.max,
191
+ count: rows.length,
192
+ uids: rows.map(
193
+ (row) => row && typeof row.__component === "string" ? row.__component : ""
194
+ ),
195
+ full: rows.length >= (attr.max ?? Infinity)
196
+ };
181
197
  });
182
198
  }
183
199
  function canInsert(zone, uid, values, components, count = 1) {
184
- return Boolean(zone?.components.includes(uid) && components[uid] && (Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0) + count <= (zone.max ?? Infinity));
200
+ return Boolean(
201
+ zone?.components.includes(uid) && components[uid] && (Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0) + count <= (zone.max ?? Infinity)
202
+ );
185
203
  }
186
204
  function candidatesFor(uid, meta = {}, config = {}) {
187
205
  const version = config.previewVersion ? `?v=${encodeURIComponent(config.previewVersion)}` : "";
188
206
  const base = (config.previewBaseUrl || "/block-previews").replace(/\/$/, "");
189
- return [meta.manualImage, meta.image, `${base}/${encodeURIComponent(uid)}.webp${version}`].filter(Boolean);
207
+ return [
208
+ meta.manualImage,
209
+ meta.image,
210
+ `${base}/${encodeURIComponent(uid)}.webp${version}`
211
+ ].filter(Boolean);
190
212
  }
191
- var SYSTEM_FIELDS = ["id", "documentId", "createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "locale", "localizations"];
213
+ var SYSTEM_FIELDS = [
214
+ "id",
215
+ "documentId",
216
+ "createdAt",
217
+ "updatedAt",
218
+ "publishedAt",
219
+ "createdBy",
220
+ "updatedBy",
221
+ "locale",
222
+ "localizations"
223
+ ];
192
224
  var fieldType = (attr) => attr?.type === "customField" ? String(attr.customField || "").includes("CKEditor") ? "richtext" : "customField" : attr?.type || "unknown";
193
225
  var fieldsOf = (schema) => Object.entries(schema?.attributes || {}).filter(([name]) => !SYSTEM_FIELDS.includes(name)).map(([name, attr]) => ({ name, type: fieldType(attr) }));
194
226
  var categoryOf = (uid, schema, meta = {}) => meta.category || schema?.category || uid.split(".")[0];
195
227
  var byCategory = (a, b) => (a === "admin" ? 1 : 0) - (b === "admin" ? 1 : 0) || a.localeCompare(b);
228
+ var pickable = (zone, config) => {
229
+ const closers = Object.values(config.groups || {});
230
+ return zone.components.filter((uid) => !closers.includes(uid));
231
+ };
196
232
  function entriesFor(zone, components, config, query, category = "all") {
197
233
  const needle = query.trim().toLocaleLowerCase();
198
- return zone.components.flatMap((uid) => {
234
+ return pickable(zone, config).flatMap((uid) => {
199
235
  const schema = components[uid];
200
236
  if (!schema) return [];
201
237
  const meta = config.components?.[uid] || {};
@@ -210,11 +246,13 @@ function entriesFor(zone, components, config, query, category = "all") {
210
246
  };
211
247
  if (category !== "all" && entry.category !== category) return [];
212
248
  return `${entry.label} ${entry.description} ${entry.category} ${uid} ${meta.keywords || ""}`.toLocaleLowerCase().includes(needle) ? [entry] : [];
213
- }).sort((a, b) => byCategory(a.category, b.category) || a.label.localeCompare(b.label));
249
+ }).sort(
250
+ (a, b) => byCategory(a.category, b.category) || a.label.localeCompare(b.label)
251
+ );
214
252
  }
215
253
  function categoriesFor(zone, components, config) {
216
254
  const counts = /* @__PURE__ */ new Map();
217
- for (const uid of zone.components) {
255
+ for (const uid of pickable(zone, config)) {
218
256
  const schema = components[uid];
219
257
  if (!schema) continue;
220
258
  const c = categoryOf(uid, schema, config.components?.[uid] || {});
@@ -224,8 +262,12 @@ function categoriesFor(zone, components, config) {
224
262
  }
225
263
  function groupEntries(entries) {
226
264
  const map = /* @__PURE__ */ new Map();
227
- for (const entry of entries) map.set(entry.category, [...map.get(entry.category) || [], entry]);
228
- return [...map.entries()].map(([category, items]) => ({ category, entries: items }));
265
+ for (const entry of entries)
266
+ map.set(entry.category, [...map.get(entry.category) || [], entry]);
267
+ return [...map.entries()].map(([category, items]) => ({
268
+ category,
269
+ entries: items
270
+ }));
229
271
  }
230
272
  function memoryKey({ base = "", userId, contentType, zone }) {
231
273
  if (!userId || !contentType || !zone) return null;
@@ -241,7 +283,8 @@ function readMemory(storage2, key) {
241
283
  }
242
284
  function writeMemory(storage2, key, value) {
243
285
  try {
244
- if (key && (value === "open" || value === "closed")) storage2?.setItem(key, value);
286
+ if (key && (value === "open" || value === "closed"))
287
+ storage2?.setItem(key, value);
245
288
  } catch {
246
289
  }
247
290
  }
@@ -327,6 +370,10 @@ function Wireframe({ template, palette, className, noPreview }) {
327
370
  );
328
371
  }
329
372
 
373
+ // admin/RowPreviews.tsx
374
+ var React = __toESM(require("react"));
375
+ var import_react_dom = require("react-dom");
376
+
330
377
  // admin/messages.ts
331
378
  var import_react_intl = require("react-intl");
332
379
 
@@ -441,7 +488,8 @@ var en_default = {
441
488
  columns: "Columns",
442
489
  noPreview: "no preview",
443
490
  "templates.none": "No preview",
444
- noChanges: "No unsaved changes"
491
+ noChanges: "No unsaved changes",
492
+ rowPreview: "Open the {label} preview"
445
493
  };
446
494
 
447
495
  // admin/translations/pt-BR.json
@@ -555,7 +603,8 @@ var pt_BR_default = {
555
603
  columns: "Colunas",
556
604
  noPreview: "sem preview",
557
605
  "templates.none": "Sem preview",
558
- noChanges: "Sem altera\xE7\xF5es pendentes"
606
+ noChanges: "Sem altera\xE7\xF5es pendentes",
607
+ rowPreview: "Abrir a pr\xE9via de {label}"
559
608
  };
560
609
 
561
610
  // admin/translations/pt.json
@@ -669,7 +718,8 @@ var pt_default = {
669
718
  columns: "Colunas",
670
719
  noPreview: "sem pr\xE9-visualiza\xE7\xE3o",
671
720
  "templates.none": "Sem pr\xE9-visualiza\xE7\xE3o",
672
- noChanges: "Sem altera\xE7\xF5es pendentes"
721
+ noChanges: "Sem altera\xE7\xF5es pendentes",
722
+ rowPreview: "Abrir a pr\xE9-visualiza\xE7\xE3o de {label}"
673
723
  };
674
724
 
675
725
  // admin/translations/fr.json
@@ -783,7 +833,8 @@ var fr_default = {
783
833
  columns: "Colonnes",
784
834
  noPreview: "pas d\u2019aper\xE7u",
785
835
  "templates.none": "Pas d\u2019aper\xE7u",
786
- noChanges: "Aucune modification en attente"
836
+ noChanges: "Aucune modification en attente",
837
+ rowPreview: "Ouvrir l\u2019aper\xE7u de {label}"
787
838
  };
788
839
 
789
840
  // admin/translations/es.json
@@ -897,7 +948,8 @@ var es_default = {
897
948
  columns: "Columnas",
898
949
  noPreview: "sin vista previa",
899
950
  "templates.none": "Sin vista previa",
900
- noChanges: "Sin cambios pendientes"
951
+ noChanges: "Sin cambios pendientes",
952
+ rowPreview: "Abrir la vista previa de {label}"
901
953
  };
902
954
 
903
955
  // admin/translations/de.json
@@ -1011,7 +1063,8 @@ var de_default = {
1011
1063
  columns: "Spalten",
1012
1064
  noPreview: "keine Vorschau",
1013
1065
  "templates.none": "Keine Vorschau",
1014
- noChanges: "Keine ungespeicherten \xC4nderungen"
1066
+ noChanges: "Keine ungespeicherten \xC4nderungen",
1067
+ rowPreview: "Vorschau von {label} \xF6ffnen"
1015
1068
  };
1016
1069
 
1017
1070
  // admin/translations/it.json
@@ -1125,7 +1178,8 @@ var it_default = {
1125
1178
  columns: "Colonne",
1126
1179
  noPreview: "nessuna anteprima",
1127
1180
  "templates.none": "Nessuna anteprima",
1128
- noChanges: "Nessuna modifica in sospeso"
1181
+ noChanges: "Nessuna modifica in sospeso",
1182
+ rowPreview: "Apri l\u2019anteprima di {label}"
1129
1183
  };
1130
1184
 
1131
1185
  // admin/translations/nl.json
@@ -1239,7 +1293,8 @@ var nl_default = {
1239
1293
  columns: "Kolommen",
1240
1294
  noPreview: "geen voorbeeld",
1241
1295
  "templates.none": "Geen voorbeeld",
1242
- noChanges: "Geen niet-opgeslagen wijzigingen"
1296
+ noChanges: "Geen niet-opgeslagen wijzigingen",
1297
+ rowPreview: "Voorbeeld van {label} openen"
1243
1298
  };
1244
1299
 
1245
1300
  // admin/messages.ts
@@ -1259,26 +1314,224 @@ function useMessages() {
1259
1314
  return out;
1260
1315
  }
1261
1316
 
1262
- // admin/Gallery.tsx
1317
+ // admin/RowPreviews.tsx
1263
1318
  var import_jsx_runtime2 = require("react/jsx-runtime");
1319
+ var ATTR = "data-blockscene-row-thumb";
1320
+ function useAnchors(zones, onOpen) {
1321
+ const [anchors, setAnchors] = React.useState([]);
1322
+ const open = React.useRef(onOpen);
1323
+ open.current = onOpen;
1324
+ const latest = React.useRef(zones);
1325
+ latest.current = zones;
1326
+ const sync = React.useRef(() => {
1327
+ });
1328
+ sync.current = () => {
1329
+ const next = [];
1330
+ for (const zone of latest.current) {
1331
+ const list = zone.uids?.length ? findZoneList(zone.label) : null;
1332
+ if (!list) continue;
1333
+ toggles(list).forEach((button, index) => {
1334
+ const uid = zone.uids[index];
1335
+ if (!uid) return;
1336
+ let el = button.querySelector(
1337
+ `:scope > [${ATTR}]`
1338
+ );
1339
+ if (!el) {
1340
+ el = document.createElement("span");
1341
+ el.setAttribute(ATTR, "");
1342
+ el.style.cssText = "display:inline-flex;align-items:center";
1343
+ const activate = (event) => {
1344
+ if (!event.currentTarget.getAttribute("role"))
1345
+ return;
1346
+ event.preventDefault();
1347
+ event.stopPropagation();
1348
+ open.current(
1349
+ String(event.currentTarget.dataset.uid || "")
1350
+ );
1351
+ };
1352
+ el.addEventListener("click", activate, true);
1353
+ el.addEventListener(
1354
+ "keydown",
1355
+ (event) => {
1356
+ if (event.key === "Enter" || event.key === " ") activate(event);
1357
+ },
1358
+ true
1359
+ );
1360
+ button.insertBefore(el, button.firstChild);
1361
+ }
1362
+ el.dataset.uid = uid;
1363
+ next.push({ el, uid, zone: zone.name, index });
1364
+ });
1365
+ }
1366
+ for (const el of document.querySelectorAll(`[${ATTR}]`))
1367
+ if (!next.some((a) => a.el === el)) el.remove();
1368
+ setAnchors(
1369
+ (prev) => prev.length === next.length && prev.every((a, i) => a.el === next[i].el && a.uid === next[i].uid) ? prev : next
1370
+ );
1371
+ };
1372
+ React.useEffect(() => {
1373
+ sync.current();
1374
+ });
1375
+ React.useEffect(() => {
1376
+ let frame = 0;
1377
+ const observer = new MutationObserver(() => {
1378
+ if (frame) return;
1379
+ frame = requestAnimationFrame(() => {
1380
+ frame = 0;
1381
+ sync.current();
1382
+ });
1383
+ });
1384
+ observer.observe(document.body, { childList: true, subtree: true });
1385
+ return () => {
1386
+ observer.disconnect();
1387
+ cancelAnimationFrame(frame);
1388
+ for (const el of document.querySelectorAll(`[${ATTR}]`)) el.remove();
1389
+ };
1390
+ }, []);
1391
+ return anchors;
1392
+ }
1393
+ function RowPreviews({ zones, components, catalog, Modal: Modal3 }) {
1394
+ const t = useMessages();
1395
+ const [resolved, setResolved] = React.useState({});
1396
+ const [open, setOpen] = React.useState(null);
1397
+ const anchors = useAnchors(zones, (uid) => setOpen(uid));
1398
+ const candidates = (uid) => candidatesFor(uid, catalog?.components?.[uid] || {}, catalog || {});
1399
+ const label = (uid) => catalog?.components?.[uid]?.label || components?.[uid]?.info?.displayName || uid;
1400
+ const srcOf = (uid) => candidates(uid)[resolved[uid] ?? -1] || "";
1401
+ React.useEffect(() => {
1402
+ for (const { el, uid } of anchors) {
1403
+ if (srcOf(uid)) {
1404
+ el.setAttribute("role", "button");
1405
+ el.setAttribute("tabindex", "0");
1406
+ el.setAttribute("aria-label", t.f("rowPreview", { label: label(uid) }));
1407
+ el.style.cursor = "zoom-in";
1408
+ } else
1409
+ for (const name of ["role", "tabindex", "aria-label"])
1410
+ el.removeAttribute(name);
1411
+ }
1412
+ });
1413
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1414
+ anchors.map(
1415
+ (a) => (0, import_react_dom.createPortal)(
1416
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1417
+ "span",
1418
+ {
1419
+ style: {
1420
+ display: "block",
1421
+ width: "6.4rem",
1422
+ marginRight: "8px",
1423
+ flex: "0 0 auto"
1424
+ },
1425
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1426
+ Thumb,
1427
+ {
1428
+ candidates: candidates(a.uid),
1429
+ blank: true,
1430
+ onResolved: (index) => setResolved(
1431
+ (prev) => prev[a.uid] === index ? prev : { ...prev, [a.uid]: index }
1432
+ )
1433
+ }
1434
+ )
1435
+ }
1436
+ ),
1437
+ a.el,
1438
+ `${a.zone}:${a.index}`
1439
+ )
1440
+ ),
1441
+ open && srcOf(open) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1442
+ Modal3,
1443
+ {
1444
+ open: true,
1445
+ onOpenChange: (value) => {
1446
+ if (!value) setOpen(null);
1447
+ },
1448
+ trigger: null,
1449
+ title: label(open),
1450
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1451
+ "img",
1452
+ {
1453
+ src: srcOf(open),
1454
+ alt: "",
1455
+ style: {
1456
+ display: "block",
1457
+ margin: "0 auto",
1458
+ maxWidth: "100%",
1459
+ maxHeight: "75vh",
1460
+ objectFit: "contain"
1461
+ }
1462
+ }
1463
+ )
1464
+ }
1465
+ )
1466
+ ] });
1467
+ }
1468
+
1469
+ // admin/Gallery.tsx
1470
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1264
1471
  var Columns = import_styled_components.default.div`
1265
- column-count: ${({ $columns }) => $columns}; column-gap: 12px;
1266
- > * { break-inside: avoid; -webkit-column-break-inside: avoid; margin-bottom: 12px; }
1472
+ column-count: ${({ $columns }) => $columns};
1473
+ column-gap: 12px;
1474
+ > * {
1475
+ break-inside: avoid;
1476
+ -webkit-column-break-inside: avoid;
1477
+ margin-bottom: 12px;
1478
+ }
1267
1479
  `;
1268
1480
  var Tile = import_styled_components.default.button`
1269
- display: flex; flex-direction: column; gap: 8px; text-align: left; width: 100%;
1270
- padding: 8px; border: 1px solid ${({ theme }) => theme.colors.neutral200};
1271
- border-radius: 4px; background: ${({ theme }) => theme.colors.neutral0}; cursor: pointer;
1272
- &:hover { border-color: ${({ theme }) => theme.colors.primary600}; }
1273
- &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: 2px; }
1481
+ display: flex;
1482
+ flex-direction: column;
1483
+ gap: 8px;
1484
+ text-align: left;
1485
+ width: 100%;
1486
+ padding: 8px;
1487
+ border: 1px solid ${({ theme }) => theme.colors.neutral200};
1488
+ border-radius: 4px;
1489
+ background: ${({ theme }) => theme.colors.neutral0};
1490
+ cursor: pointer;
1491
+ &:hover {
1492
+ border-color: ${({ theme }) => theme.colors.primary600};
1493
+ }
1494
+ &:focus-visible {
1495
+ outline: 2px solid ${({ theme }) => theme.colors.primary600};
1496
+ outline-offset: 2px;
1497
+ }
1498
+ `;
1499
+ var Clamp = (0, import_styled_components.default)(import_design_system.Typography)`
1500
+ display: -webkit-box;
1501
+ -webkit-line-clamp: 2;
1502
+ -webkit-box-orient: vertical;
1503
+ overflow: hidden;
1274
1504
  `;
1275
- var Clamp = (0, import_styled_components.default)(import_design_system.Typography)` display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; `;
1276
1505
  var Slider = import_styled_components.default.input`
1277
- appearance: none; -webkit-appearance: none; width: 8rem; height: 0.4rem; border-radius: 0.4rem; cursor: pointer;
1506
+ appearance: none;
1507
+ -webkit-appearance: none;
1508
+ width: 8rem;
1509
+ height: 0.4rem;
1510
+ border-radius: 0.4rem;
1511
+ cursor: pointer;
1278
1512
  background: ${({ theme, $percent }) => `linear-gradient(to right, ${theme.colors.primary600} ${$percent}%, ${theme.colors.neutral200} ${$percent}%)`};
1279
- &::-webkit-slider-thumb { appearance: none; -webkit-appearance: none; width: 1.6rem; height: 1.6rem; border-radius: 50%; background: ${({ theme }) => theme.colors.neutral0}; border: 0.2rem solid ${({ theme }) => theme.colors.primary600}; cursor: pointer; }
1280
- &::-moz-range-thumb { width: 1.6rem; height: 1.6rem; border-radius: 50%; background: ${({ theme }) => theme.colors.neutral0}; border: 0.2rem solid ${({ theme }) => theme.colors.primary600}; cursor: pointer; }
1281
- &:focus-visible { outline: 0.2rem solid ${({ theme }) => theme.colors.primary600}; outline-offset: 0.2rem; }
1513
+ &::-webkit-slider-thumb {
1514
+ appearance: none;
1515
+ -webkit-appearance: none;
1516
+ width: 1.6rem;
1517
+ height: 1.6rem;
1518
+ border-radius: 50%;
1519
+ background: ${({ theme }) => theme.colors.neutral0};
1520
+ border: 0.2rem solid ${({ theme }) => theme.colors.primary600};
1521
+ cursor: pointer;
1522
+ }
1523
+ &::-moz-range-thumb {
1524
+ width: 1.6rem;
1525
+ height: 1.6rem;
1526
+ border-radius: 50%;
1527
+ background: ${({ theme }) => theme.colors.neutral0};
1528
+ border: 0.2rem solid ${({ theme }) => theme.colors.primary600};
1529
+ cursor: pointer;
1530
+ }
1531
+ &:focus-visible {
1532
+ outline: 0.2rem solid ${({ theme }) => theme.colors.primary600};
1533
+ outline-offset: 0.2rem;
1534
+ }
1282
1535
  `;
1283
1536
  var COLUMNS = { key: "blockscene:columns", min: 1, max: 5, initial: 3 };
1284
1537
  var SHOW_FIELDS_KEY = "blockscene:show-fields";
@@ -1304,16 +1557,31 @@ var remember = (key, value) => {
1304
1557
  }
1305
1558
  };
1306
1559
  var Frame = import_styled_components.default.div`
1307
- width: 100%; overflow: hidden; border-radius: 4px; line-height: 0;
1560
+ width: 100%;
1561
+ overflow: hidden;
1562
+ border-radius: 4px;
1563
+ line-height: 0;
1308
1564
  aspect-ratio: ${({ $fixed }) => $fixed ? "16 / 9" : "auto"};
1309
1565
  background: ${({ theme }) => theme.colors.neutral100};
1310
- img { width: 100%; height: auto; display: block; }
1566
+ img {
1567
+ width: 100%;
1568
+ height: auto;
1569
+ display: block;
1570
+ }
1311
1571
  `;
1312
- function Thumb({ candidates, template, palette, onResolved, noPreview, eager }) {
1572
+ function Thumb({
1573
+ candidates,
1574
+ template,
1575
+ palette,
1576
+ onResolved,
1577
+ noPreview,
1578
+ eager,
1579
+ blank
1580
+ }) {
1313
1581
  const key = candidates.join("|");
1314
- const [state, setState] = React.useState({ key, index: 0 });
1582
+ const [state, setState] = React2.useState({ key, index: 0 });
1315
1583
  const index = state.key === key ? state.index : 0;
1316
- const resolved = React.useRef("");
1584
+ const resolved = React2.useRef("");
1317
1585
  const report = (value) => {
1318
1586
  const tag = `${key}:${value}`;
1319
1587
  if (resolved.current !== tag) {
@@ -1321,11 +1589,19 @@ function Thumb({ candidates, template, palette, onResolved, noPreview, eager })
1321
1589
  onResolved?.(value);
1322
1590
  }
1323
1591
  };
1324
- React.useEffect(() => {
1592
+ React2.useEffect(() => {
1325
1593
  if (index >= candidates.length) report(-1);
1326
1594
  });
1327
- if (index >= candidates.length) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Wireframe, { template, palette, noPreview }) });
1328
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1595
+ if (index >= candidates.length)
1596
+ return blank ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1597
+ Wireframe,
1598
+ {
1599
+ template,
1600
+ palette,
1601
+ noPreview
1602
+ }
1603
+ ) });
1604
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1329
1605
  "img",
1330
1606
  {
1331
1607
  src: candidates[index],
@@ -1339,28 +1615,90 @@ function Thumb({ candidates, template, palette, onResolved, noPreview, eager })
1339
1615
  }
1340
1616
  function Card({ entry, palette, showFields, onSelect }) {
1341
1617
  const t = useMessages();
1342
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Tile, { type: "button", onClick: onSelect, title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
1343
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview }),
1344
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
1345
- entry.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
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(", ") })
1347
- ] });
1618
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1619
+ Tile,
1620
+ {
1621
+ type: "button",
1622
+ onClick: onSelect,
1623
+ title: entry.uid,
1624
+ "data-testid": `blockscene-${entry.uid}`,
1625
+ children: [
1626
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1627
+ Thumb,
1628
+ {
1629
+ candidates: entry.candidates,
1630
+ template: entry.template,
1631
+ palette,
1632
+ noPreview: t.noPreview
1633
+ }
1634
+ ),
1635
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1636
+ import_design_system.Typography,
1637
+ {
1638
+ variant: "pi",
1639
+ fontWeight: "bold",
1640
+ textColor: "neutral800",
1641
+ ellipsis: true,
1642
+ children: entry.label
1643
+ }
1644
+ ),
1645
+ entry.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
1646
+ showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1647
+ import_design_system.Typography,
1648
+ {
1649
+ variant: "pi",
1650
+ textColor: "neutral500",
1651
+ style: { fontStyle: "italic" },
1652
+ "data-testid": "block-fields",
1653
+ children: entry.fields.map((f) => `${f.name} (${f.type})`).join(", ")
1654
+ }
1655
+ )
1656
+ ]
1657
+ }
1658
+ );
1348
1659
  }
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 } });
1660
+ function PickerModal({
1661
+ zone,
1662
+ components,
1663
+ open,
1664
+ onOpenChange,
1665
+ onSelect,
1666
+ Modal: Modal3,
1667
+ Toggle,
1668
+ get
1669
+ }) {
1670
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1671
+ ZoneGallery,
1672
+ {
1673
+ zone,
1674
+ components,
1675
+ Modal: Modal3,
1676
+ Toggle,
1677
+ get,
1678
+ controlled: { open, onOpenChange, onSelect }
1679
+ }
1680
+ );
1351
1681
  }
1352
- function ZoneGallery({ zone, components, add, Modal: Modal3, Toggle, get, controlled }) {
1682
+ function ZoneGallery({
1683
+ zone,
1684
+ components,
1685
+ add,
1686
+ Modal: Modal3,
1687
+ Toggle,
1688
+ get,
1689
+ controlled
1690
+ }) {
1353
1691
  const t = useMessages();
1354
- const [ownOpen, setOwnOpen] = React.useState(false);
1692
+ const [ownOpen, setOwnOpen] = React2.useState(false);
1355
1693
  const open = controlled ? controlled.open : ownOpen;
1356
1694
  const setOpen = controlled ? controlled.onOpenChange : setOwnOpen;
1357
- const [query, setQuery] = React.useState("");
1358
- const [category, setCategory] = React.useState("all");
1359
- const [showFields, setShowFields] = React.useState(readShowFields);
1360
- const [columns, setColumns] = React.useState(readColumns);
1361
- const [config, setConfig] = React.useState(null);
1362
- const [error, setError] = React.useState("");
1363
- React.useEffect(() => {
1695
+ const [query, setQuery] = React2.useState("");
1696
+ const [category, setCategory] = React2.useState("all");
1697
+ const [showFields, setShowFields] = React2.useState(readShowFields);
1698
+ const [columns, setColumns] = React2.useState(readColumns);
1699
+ const [config, setConfig] = React2.useState(null);
1700
+ const [error, setError] = React2.useState("");
1701
+ React2.useEffect(() => {
1364
1702
  if (controlled) return;
1365
1703
  const onClick = (event) => {
1366
1704
  const button = event.target?.closest?.("button");
@@ -1372,7 +1710,7 @@ function ZoneGallery({ zone, components, add, Modal: Modal3, Toggle, get, contro
1372
1710
  document.addEventListener("click", onClick, true);
1373
1711
  return () => document.removeEventListener("click", onClick, true);
1374
1712
  }, [controlled, zone.name, zone.label]);
1375
- React.useEffect(() => {
1713
+ React2.useEffect(() => {
1376
1714
  if (!open) return;
1377
1715
  let active = true;
1378
1716
  setError("");
@@ -1388,7 +1726,10 @@ function ZoneGallery({ zone, components, add, Modal: Modal3, Toggle, get, contro
1388
1726
  }, [open, get, t.failed]);
1389
1727
  const entries = config ? entriesFor(zone, components, config, query, category) : [];
1390
1728
  const categories = config ? categoriesFor(zone, components, config) : [];
1391
- const total = categories.reduce((sum, [, count]) => sum + count, 0);
1729
+ const total = categories.reduce(
1730
+ (sum, [, count]) => sum + count,
1731
+ 0
1732
+ );
1392
1733
  const filtering = query.trim() !== "" || category !== "all";
1393
1734
  const reset = () => {
1394
1735
  setQuery("");
@@ -1412,21 +1753,41 @@ function ZoneGallery({ zone, components, add, Modal: Modal3, Toggle, get, contro
1412
1753
  setShowFields(value);
1413
1754
  remember(SHOW_FIELDS_KEY, String(value));
1414
1755
  };
1415
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1756
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1416
1757
  Modal3,
1417
1758
  {
1418
1759
  open,
1419
1760
  onOpenChange: setOpen,
1420
1761
  title: t.gallery,
1421
- trigger: controlled ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Button, { variant: "secondary", fullWidth: true, onClick: () => setOpen(true), "data-testid": `open-gallery-${zone.name}`, children: [
1422
- t.add,
1423
- ": ",
1424
- zone.name
1425
- ] }),
1426
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
1427
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
1428
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "omega", fontWeight: "bold", textColor: "neutral800", style: { whiteSpace: "nowrap" }, "data-testid": `block-count-${zone.name}`, "aria-live": "polite", children: filtering ? t.f("countFiltered", { shown: entries.length, total }) : t.f("countAll", { count: total }) }),
1429
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1762
+ trigger: controlled ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1763
+ import_design_system.Button,
1764
+ {
1765
+ variant: "secondary",
1766
+ fullWidth: true,
1767
+ onClick: () => setOpen(true),
1768
+ "data-testid": `open-gallery-${zone.name}`,
1769
+ children: [
1770
+ t.add,
1771
+ ": ",
1772
+ zone.name
1773
+ ]
1774
+ }
1775
+ ),
1776
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
1777
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
1778
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1779
+ import_design_system.Typography,
1780
+ {
1781
+ variant: "omega",
1782
+ fontWeight: "bold",
1783
+ textColor: "neutral800",
1784
+ style: { whiteSpace: "nowrap" },
1785
+ "data-testid": `block-count-${zone.name}`,
1786
+ "aria-live": "polite",
1787
+ children: filtering ? t.f("countFiltered", { shown: entries.length, total }) : t.f("countAll", { count: total })
1788
+ }
1789
+ ),
1790
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1430
1791
  import_design_system.Searchbar,
1431
1792
  {
1432
1793
  name: `block-search-${zone.name}`,
@@ -1438,14 +1799,54 @@ function ZoneGallery({ zone, components, add, Modal: Modal3, Toggle, get, contro
1438
1799
  children: t.search
1439
1800
  }
1440
1801
  ) }),
1441
- categories.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Box, { style: { width: "14rem" }, "data-testid": `block-category-${zone.name}`, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.SingleSelect, { "aria-label": t.filterCategory, size: "S", value: category, onChange: (value) => setCategory(String(value)), children: [
1442
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.SingleSelectOption, { value: "all", children: t.allCategories }),
1443
- categories.map(([name, count]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.SingleSelectOption, { value: name, children: `${name} (${count})` }, name))
1444
- ] }) }),
1445
- Toggle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Toggle, { name: `block-fields-${zone.name}`, label: t.showFields, hint: t.showFieldsHint, value: showFields, onChange: changeShowFields }),
1446
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 2, alignItems: "center", children: [
1447
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
1448
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1802
+ categories.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1803
+ import_design_system.Box,
1804
+ {
1805
+ style: { width: "14rem" },
1806
+ "data-testid": `block-category-${zone.name}`,
1807
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1808
+ import_design_system.SingleSelect,
1809
+ {
1810
+ "aria-label": t.filterCategory,
1811
+ size: "S",
1812
+ value: category,
1813
+ onChange: (value) => setCategory(String(value)),
1814
+ children: [
1815
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.SingleSelectOption, { value: "all", children: t.allCategories }),
1816
+ categories.map(([name, count]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1817
+ import_design_system.SingleSelectOption,
1818
+ {
1819
+ value: name,
1820
+ children: `${name} (${count})`
1821
+ },
1822
+ name
1823
+ ))
1824
+ ]
1825
+ }
1826
+ )
1827
+ }
1828
+ ),
1829
+ Toggle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1830
+ Toggle,
1831
+ {
1832
+ name: `block-fields-${zone.name}`,
1833
+ label: t.showFields,
1834
+ hint: t.showFieldsHint,
1835
+ value: showFields,
1836
+ onChange: changeShowFields
1837
+ }
1838
+ ),
1839
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { gap: 2, alignItems: "center", children: [
1840
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1841
+ import_design_system.Typography,
1842
+ {
1843
+ variant: "pi",
1844
+ textColor: "neutral600",
1845
+ id: `block-columns-${zone.name}`,
1846
+ children: t.columns
1847
+ }
1848
+ ),
1849
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1449
1850
  Slider,
1450
1851
  {
1451
1852
  type: "range",
@@ -1458,16 +1859,52 @@ function ZoneGallery({ zone, components, add, Modal: Modal3, Toggle, get, contro
1458
1859
  onChange: (e) => changeColumns(Number(e.target.value))
1459
1860
  }
1460
1861
  ),
1461
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", children: columns })
1862
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", children: columns })
1462
1863
  ] })
1463
1864
  ] }),
1464
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
1465
- error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { children: t.loading }) : entries.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 4, style: { overflowY: "auto", maxHeight: "60vh", padding: "4px" }, children: groupEntries(entries).map(({ category: name, entries: items }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1466
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${name}`, children: `${name} (${items.length})` }),
1467
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Columns, { $columns: columns, children: items.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { entry, palette: config.palette, showFields, onSelect: () => select(entry.uid) }) }, entry.uid)) })
1468
- ] }, name)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", children: [
1469
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { children: t.empty }),
1470
- filtering && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
1865
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
1866
+ error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { children: t.loading }) : entries.length ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1867
+ import_design_system.Flex,
1868
+ {
1869
+ direction: "column",
1870
+ alignItems: "stretch",
1871
+ gap: 4,
1872
+ style: { overflowY: "auto", maxHeight: "60vh", padding: "4px" },
1873
+ children: groupEntries(entries).map(
1874
+ ({ category: name, entries: items }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1875
+ import_design_system.Flex,
1876
+ {
1877
+ direction: "column",
1878
+ alignItems: "stretch",
1879
+ gap: 2,
1880
+ children: [
1881
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1882
+ import_design_system.Typography,
1883
+ {
1884
+ variant: "sigma",
1885
+ textColor: "neutral600",
1886
+ "data-testid": `block-group-${name}`,
1887
+ children: `${name} (${items.length})`
1888
+ }
1889
+ ),
1890
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Columns, { $columns: columns, children: items.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1891
+ Card,
1892
+ {
1893
+ entry,
1894
+ palette: config.palette,
1895
+ showFields,
1896
+ onSelect: () => select(entry.uid)
1897
+ }
1898
+ ) }, entry.uid)) })
1899
+ ]
1900
+ },
1901
+ name
1902
+ )
1903
+ )
1904
+ }
1905
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", children: [
1906
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { children: t.empty }),
1907
+ filtering && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
1471
1908
  ] })
1472
1909
  ] })
1473
1910
  }
@@ -1481,13 +1918,19 @@ var storage = () => {
1481
1918
  }
1482
1919
  };
1483
1920
  var memoryBase = () => `${window.location.origin}${window.location.pathname.split("/content-manager")[0]}`;
1484
- function useInitialAccordions({ zones, editor, docKey, contentType, userId }) {
1485
- const applied = React.useRef("");
1486
- const user = React.useRef(userId);
1921
+ function useInitialAccordions({
1922
+ zones,
1923
+ editor,
1924
+ docKey,
1925
+ contentType,
1926
+ userId
1927
+ }) {
1928
+ const applied = React2.useRef("");
1929
+ const user = React2.useRef(userId);
1487
1930
  user.current = userId;
1488
- const latest = React.useRef(zones);
1931
+ const latest = React2.useRef(zones);
1489
1932
  latest.current = zones;
1490
- React.useEffect(() => {
1933
+ React2.useEffect(() => {
1491
1934
  if (!editor?.enabled || !docKey || applied.current === docKey) return;
1492
1935
  if (applied.current.startsWith(`${contentType}:new`) && docKey.startsWith(`${contentType}:`)) {
1493
1936
  applied.current = docKey;
@@ -1496,7 +1939,10 @@ function useInitialAccordions({ zones, editor, docKey, contentType, userId }) {
1496
1939
  applied.current = docKey;
1497
1940
  let tries = 0;
1498
1941
  const cancel = (event) => {
1499
- if (event.target?.closest?.('button[aria-expanded], [data-testid^="block-accordion-controls-"]')) stop();
1942
+ if (event.target?.closest?.(
1943
+ 'button[aria-expanded], [data-testid^="block-accordion-controls-"]'
1944
+ ))
1945
+ stop();
1500
1946
  };
1501
1947
  const stop = () => {
1502
1948
  clearInterval(timer);
@@ -1514,8 +1960,17 @@ function useInitialAccordions({ zones, editor, docKey, contentType, userId }) {
1514
1960
  for (const zone of pending) {
1515
1961
  const list = findZoneList(zone.label);
1516
1962
  if (!list) continue;
1517
- const key = memoryKey({ base: memoryBase(), userId: user.current, contentType, zone: zone.name });
1518
- setAll(list, initialState(editor, readMemory(storage(), key)) === "open", import_react_dom.unstable_batchedUpdates);
1963
+ const key = memoryKey({
1964
+ base: memoryBase(),
1965
+ userId: user.current,
1966
+ contentType,
1967
+ zone: zone.name
1968
+ });
1969
+ setAll(
1970
+ list,
1971
+ initialState(editor, readMemory(storage(), key)) === "open",
1972
+ import_react_dom2.unstable_batchedUpdates
1973
+ );
1519
1974
  }
1520
1975
  }, 200);
1521
1976
  return stop;
@@ -1526,51 +1981,107 @@ function ZoneControls({ zone, editor, contentType, userId }) {
1526
1981
  if (!zone.count || !(editor.showOpenAll || editor.showCloseAll)) return null;
1527
1982
  const apply = (open) => {
1528
1983
  const list = findZoneList(zone.label);
1529
- if (list) setAll(list, open, import_react_dom.unstable_batchedUpdates);
1530
- writeMemory(storage(), memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }), open ? "open" : "closed");
1984
+ if (list) setAll(list, open, import_react_dom2.unstable_batchedUpdates);
1985
+ writeMemory(
1986
+ storage(),
1987
+ memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }),
1988
+ open ? "open" : "closed"
1989
+ );
1531
1990
  };
1532
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 2, wrap: "wrap", "data-testid": `block-accordion-controls-${zone.name}`, children: [
1533
- editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { type: "button", variant: "tertiary", size: "S", onClick: () => apply(true), children: t.openAll }),
1534
- editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { type: "button", variant: "tertiary", size: "S", onClick: () => apply(false), children: t.closeAll })
1535
- ] });
1991
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1992
+ import_design_system.Flex,
1993
+ {
1994
+ gap: 2,
1995
+ wrap: "wrap",
1996
+ "data-testid": `block-accordion-controls-${zone.name}`,
1997
+ children: [
1998
+ editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1999
+ import_design_system.Button,
2000
+ {
2001
+ type: "button",
2002
+ variant: "tertiary",
2003
+ size: "S",
2004
+ onClick: () => apply(true),
2005
+ children: t.openAll
2006
+ }
2007
+ ),
2008
+ editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2009
+ import_design_system.Button,
2010
+ {
2011
+ type: "button",
2012
+ variant: "tertiary",
2013
+ size: "S",
2014
+ onClick: () => apply(false),
2015
+ children: t.closeAll
2016
+ }
2017
+ )
2018
+ ]
2019
+ }
2020
+ );
1536
2021
  }
1537
- function Gallery({ zones, editor, docKey, contentType, userId, ...props }) {
2022
+ function Gallery({
2023
+ zones,
2024
+ editor,
2025
+ docKey,
2026
+ contentType,
2027
+ userId,
2028
+ catalog,
2029
+ ...props
2030
+ }) {
1538
2031
  useInitialAccordions({ zones, editor, docKey, contentType, userId });
1539
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1540
- !zone.full && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoneGallery, { zone, ...props }),
1541
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoneControls, { zone, editor, contentType, userId })
1542
- ] }, zone.name)) });
2032
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
2033
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2034
+ RowPreviews,
2035
+ {
2036
+ zones,
2037
+ components: props.components,
2038
+ catalog,
2039
+ Modal: props.Modal
2040
+ }
2041
+ ),
2042
+ zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2043
+ !zone.full && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ZoneGallery, { zone, ...props }),
2044
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2045
+ ZoneControls,
2046
+ {
2047
+ zone,
2048
+ editor,
2049
+ contentType,
2050
+ userId
2051
+ }
2052
+ )
2053
+ ] }, zone.name))
2054
+ ] });
1543
2055
  }
1544
2056
 
1545
2057
  // admin/PagePreview.tsx
1546
- var React3 = __toESM(require("react"));
1547
- var import_react_dom2 = require("react-dom");
2058
+ var React4 = __toESM(require("react"));
2059
+ var import_react_dom3 = require("react-dom");
1548
2060
  var import_styled_components2 = __toESM(require("styled-components"));
1549
2061
  var import_design_system3 = require("@strapi/design-system");
1550
2062
  var import_admin2 = require("@strapi/strapi/admin");
1551
- var import_design_system4 = require("@strapi/design-system");
1552
2063
  var import_strapi_admin = require("@strapi/content-manager/strapi-admin");
1553
2064
 
1554
2065
  // admin/FieldEditorModal.tsx
1555
- var React2 = __toESM(require("react"));
2066
+ var React3 = __toESM(require("react"));
1556
2067
  var import_admin = require("@strapi/strapi/admin");
1557
2068
  var import_design_system2 = require("@strapi/design-system");
1558
- var import_jsx_runtime3 = require("react/jsx-runtime");
2069
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1559
2070
  var Actions = ({ onApply, onCancel }) => {
1560
2071
  const t = useMessages();
1561
2072
  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 })
2073
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { gap: 2, justifyContent: "flex-end", children: [
2074
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Button, { variant: "tertiary", onClick: onCancel, children: t.cancel }),
2075
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Button, { onClick: () => onApply(value ?? null), "data-testid": "field-editor-apply", children: t.apply })
1565
2076
  ] });
1566
2077
  };
1567
2078
  function FieldEditorModal({ label, attribute, value, onApply, onCancel }) {
1568
2079
  const t = useMessages();
1569
2080
  const customFields = (0, import_admin.useStrapiApp)("BlocksceneFieldEditor", (state) => state.customFields);
1570
- const [Input, setInput] = React2.useState(void 0);
2081
+ const [Input, setInput] = React3.useState(void 0);
1571
2082
  const isCustom = Boolean(attribute?.customField);
1572
2083
  const isText = attribute?.type === "string" || attribute?.type === "text";
1573
- React2.useEffect(() => {
2084
+ React3.useEffect(() => {
1574
2085
  let active = true;
1575
2086
  if (!isCustom) {
1576
2087
  setInput(null);
@@ -1591,24 +2102,24 @@ function FieldEditorModal({ label, attribute, value, onApply, onCancel }) {
1591
2102
  };
1592
2103
  }, [attribute, customFields, isCustom]);
1593
2104
  const supported = isText || isCustom && Input;
1594
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Modal.Root, { open: true, onOpenChange: (open) => {
2105
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Modal.Root, { open: true, onOpenChange: (open) => {
1595
2106
  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: [
2107
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Modal.Content, { "aria-label": `${t.editText} ${label}`, children: [
2108
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Modal.Header, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Modal.Title, { children: [
1598
2109
  t.editText,
1599
2110
  " \xB7 ",
1600
2111
  label
1601
2112
  ] }) }),
1602
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_admin.Form, { initialValues: { value: value ?? (isText ? "" : null) }, method: "PUT", onSubmit: () => {
2113
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_admin.Form, { initialValues: { value: value ?? (isText ? "" : null) }, method: "PUT", onSubmit: () => {
1603
2114
  }, 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 })
2115
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Modal.Body, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "field-editor-modal", children: [
2116
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.editHelp }),
2117
+ isCustom && Input === void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { children: t.loading }),
2118
+ isCustom && Input && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Input, { name: "value", attribute, label, type: attribute.type }),
2119
+ isText && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_admin.InputRenderer, { type: attribute.type === "text" ? "text" : "string", name: "value", label }),
2120
+ (isCustom && Input === null || !isCustom && !isText) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: t.editUnsupported })
1610
2121
  ] }) }),
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 }) })
2122
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Modal.Footer, { children: supported ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Actions, { onApply, onCancel }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Button, { variant: "tertiary", onClick: onCancel, children: t.close }) })
1612
2123
  ] })
1613
2124
  ] }) });
1614
2125
  }
@@ -1719,6 +2230,7 @@ var mediaAttribute = (uid, field, components) => {
1719
2230
  const attr = resolveField(uid, field, components);
1720
2231
  return attr?.type === "media" ? attr : null;
1721
2232
  };
2233
+ var getIn = (row, path) => String(path).split(".").reduce((value, key) => value == null ? void 0 : value[key], row);
1722
2234
  function isPreviewMessage(event, origin, source, channel, type) {
1723
2235
  return event.origin === origin && event.source === source && event.data?.protocol === PROTOCOL && event.data?.channel === channel && event.data?.type === type;
1724
2236
  }
@@ -1729,7 +2241,7 @@ function insertIndex(rows, after) {
1729
2241
  }
1730
2242
 
1731
2243
  // admin/PagePreview.tsx
1732
- var import_jsx_runtime4 = require("react/jsx-runtime");
2244
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1733
2245
  var MODE_KEY = "blockscene:page-mode";
1734
2246
  var RATIO_KEY = "blockscene:page-split-ratio";
1735
2247
  var MIN_PANE = 360;
@@ -1750,20 +2262,32 @@ var write = (key, value) => {
1750
2262
  } catch {
1751
2263
  }
1752
2264
  };
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);
2265
+ var clampWidth = (width, vw) => Math.round(
2266
+ Math.min(Math.max(width, MIN_PANE), Math.max(MIN_PANE, vw - MIN_FORM))
2267
+ );
1755
2268
  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};
2269
+ position: fixed;
2270
+ top: 0;
2271
+ bottom: 0;
2272
+ z-index: 2;
2273
+ display: flex;
2274
+ flex-direction: column;
2275
+ background: ${({ theme }) => theme.colors.neutral0};
2276
+ border-left: 1px solid ${({ theme }) => theme.colors.neutral200};
1758
2277
  box-shadow: ${({ theme }) => theme.shadows.popupShadow};
1759
2278
  `;
1760
2279
  function useMainRect() {
1761
- const [rect, setRect] = React3.useState(() => ({ left: 0, width: window.innerWidth }));
1762
- React3.useEffect(() => {
2280
+ const [rect, setRect] = React4.useState(() => ({
2281
+ left: 0,
2282
+ width: window.innerWidth
2283
+ }));
2284
+ React4.useEffect(() => {
1763
2285
  const main = document.getElementById("main-content");
1764
2286
  const measure = () => {
1765
2287
  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 });
2288
+ setRect(
2289
+ r && r.width > 0 ? { left: Math.round(r.left), width: Math.round(r.width) } : { left: 0, width: window.innerWidth }
2290
+ );
1767
2291
  };
1768
2292
  measure();
1769
2293
  const observer = main && "ResizeObserver" in window ? new ResizeObserver(measure) : null;
@@ -1777,12 +2301,37 @@ function useMainRect() {
1777
2301
  return rect;
1778
2302
  }
1779
2303
  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; }
2304
+ position: absolute;
2305
+ top: 0;
2306
+ bottom: 0;
2307
+ left: -5px;
2308
+ width: 10px;
2309
+ cursor: col-resize;
2310
+ z-index: 3;
2311
+ touch-action: none;
2312
+ &::after {
2313
+ content: "";
2314
+ position: absolute;
2315
+ top: 0;
2316
+ bottom: 0;
2317
+ left: 4px;
2318
+ width: 2px;
2319
+ }
2320
+ &:hover::after,
2321
+ &[data-dragging="true"]::after,
2322
+ &:focus-visible::after {
2323
+ background: ${({ theme }) => theme.colors.primary600};
2324
+ }
2325
+ &:focus-visible {
2326
+ outline: none;
2327
+ }
2328
+ `;
2329
+ var Frame2 = import_styled_components2.default.iframe`
2330
+ flex: 1;
2331
+ width: 100%;
2332
+ border: 0;
2333
+ background: white;
1784
2334
  `;
1785
- var Frame2 = import_styled_components2.default.iframe` flex: 1; width: 100%; border: 0; background: white; `;
1786
2335
  var SPLIT_STYLE = `
1787
2336
  body.bp-split #main-content { padding-right: calc(var(--bp-pane, 50vw) + 1.6rem) !important; }
1788
2337
  body.bp-split [data-bp-grid] { display: flex !important; flex-direction: column-reverse; gap: 1.6rem; }
@@ -1791,20 +2340,26 @@ body.bp-split [data-bp-panels] > div { flex-direction: row; flex-wrap: wrap; ali
1791
2340
  body.bp-split [data-bp-panels] > div > * { flex: 1 1 24rem; }`;
1792
2341
  var markLayout = (anchor) => {
1793
2342
  let item = anchor;
1794
- while (item?.parentElement && getComputedStyle(item.parentElement).display !== "grid") item = item.parentElement;
2343
+ while (item?.parentElement && getComputedStyle(item.parentElement).display !== "grid")
2344
+ item = item.parentElement;
1795
2345
  if (!item?.parentElement) return;
1796
2346
  item.dataset.bpPanels = "";
1797
2347
  item.parentElement.dataset.bpGrid = "";
1798
2348
  };
1799
2349
  function usePreviewBase(override, model, documentId, locale) {
1800
2350
  const { get } = (0, import_admin2.useFetchClient)();
1801
- const [native, setNative] = React3.useState(null);
1802
- React3.useEffect(() => {
2351
+ const [native, setNative] = React4.useState(null);
2352
+ React4.useEffect(() => {
1803
2353
  if (override || !model) return;
1804
2354
  let active = true;
1805
- const query = new URLSearchParams({ status: "draft", ...documentId ? { documentId } : {}, ...locale ? { locale } : {} });
2355
+ const query = new URLSearchParams({
2356
+ status: "draft",
2357
+ ...documentId ? { documentId } : {},
2358
+ ...locale ? { locale } : {}
2359
+ });
1806
2360
  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`);
2361
+ if (active && typeof data?.data?.url === "string")
2362
+ setNative(`${new URL(data.data.url).origin}/block-preview/page`);
1808
2363
  }).catch(() => {
1809
2364
  if (active) setNative(null);
1810
2365
  });
@@ -1814,55 +2369,109 @@ function usePreviewBase(override, model, documentId, locale) {
1814
2369
  }, [get, model, documentId, locale, override]);
1815
2370
  return override ? { base: override, source: "custom" } : native ? { base: native, source: "native" } : { base: null, source: "none" };
1816
2371
  }
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
2372
  var ACTION_TYPES = ["update", "publish"];
1827
- var nativeButtons = () => document.querySelectorAll('#main-content button:not([data-testid="page-preview-pane"] button)');
2373
+ var nativeButtons = () => document.querySelectorAll(
2374
+ '#main-content button:not([data-testid="page-preview-pane"] button)'
2375
+ );
1828
2376
  function ToolbarActions({ model, collectionType, documentId, locale }) {
1829
- const plugins = (0, import_admin2.useStrapiApp)("BlocksceneToolbar", (state) => state.plugins);
2377
+ const plugins = (0, import_admin2.useStrapiApp)(
2378
+ "BlocksceneToolbar",
2379
+ (state) => state.plugins
2380
+ );
1830
2381
  const [{ query }] = (0, import_admin2.useQueryParams)();
1831
- const { document: doc, meta } = (0, import_strapi_admin.unstable_useDocument)({ model, collectionType, documentId, params: { locale } }, { skip: !documentId });
2382
+ const { document: doc, meta } = (0, import_strapi_admin.unstable_useDocument)(
2383
+ { model, collectionType, documentId, params: { locale } },
2384
+ { skip: !documentId }
2385
+ );
1832
2386
  const { toggleNotification } = (0, import_admin2.useNotification)();
1833
2387
  const t = useMessages();
1834
2388
  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 };
2389
+ const props = {
2390
+ activeTab: query.status || "draft",
2391
+ model,
2392
+ documentId,
2393
+ document: doc,
2394
+ meta,
2395
+ collectionType
2396
+ };
1836
2397
  const run = async (action, event) => {
1837
- const native = [...nativeButtons()].find((b) => b.textContent?.trim() === action.label);
2398
+ const native = [...nativeButtons()].find(
2399
+ (b) => b.textContent?.trim() === action.label
2400
+ );
1838
2401
  if (native) {
1839
2402
  native.click();
1840
2403
  return;
1841
2404
  }
1842
2405
  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 });
2406
+ if (action.dialog && !mute && action.dialog.type === "notification")
2407
+ toggleNotification({
2408
+ title: action.dialog.title,
2409
+ message: action.dialog.content,
2410
+ type: action.dialog.status
2411
+ });
1844
2412
  };
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) => {
2413
+ const typeOf = (action) => action.type || descriptions.find(
2414
+ (d) => typeof action.id === "string" && action.id.startsWith(`${d.name || d.displayName}-`)
2415
+ )?.type;
2416
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_admin2.DescriptionComponentRenderer, { props, descriptions, children: (actions) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Flex, { gap: 1, "data-testid": "page-preview-actions", children: [...actions].sort(
2417
+ (a, b) => ACTION_TYPES.indexOf(typeOf(a)) - ACTION_TYPES.indexOf(typeOf(b))
2418
+ ).map((action) => {
1847
2419
  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);
2420
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { title: reason, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2421
+ import_design_system3.Button,
2422
+ {
2423
+ size: "S",
2424
+ variant: action.variant || "default",
2425
+ disabled: action.disabled,
2426
+ loading: action.loading,
2427
+ "aria-description": reason,
2428
+ onClick: (e) => run(action, e),
2429
+ children: action.label
2430
+ }
2431
+ ) }, action.id);
1849
2432
  }) }) });
1850
2433
  }
1851
- function PagePreview({ editor, groups = null, Toggle }) {
2434
+ function PagePreview({
2435
+ editor,
2436
+ groups = null,
2437
+ Modal: Modal3,
2438
+ Toggle
2439
+ }) {
1852
2440
  const t = useMessages();
1853
2441
  const c = (0, import_strapi_admin.unstable_useContentManagerContext)();
1854
- const rbac = (0, import_strapi_admin.useDocumentRBAC)("BlockscenePagePreview", (state) => state);
2442
+ const rbac = (0, import_strapi_admin.useDocumentRBAC)(
2443
+ "BlockscenePagePreview",
2444
+ (state) => state
2445
+ );
1855
2446
  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);
2447
+ const onChange = (0, import_admin2.useForm)(
2448
+ "BlockscenePagePreview",
2449
+ (state) => state.onChange
2450
+ );
2451
+ const components = (0, import_admin2.useStrapiApp)(
2452
+ "BlockscenePagePreview",
2453
+ (state) => state.components
2454
+ );
1858
2455
  const MediaLibraryDialog = components?.["media-library"];
1859
- const addFieldRow = (0, import_admin2.useForm)("BlockscenePagePreview", (state) => state.addFieldRow);
2456
+ const addFieldRow = (0, import_admin2.useForm)(
2457
+ "BlockscenePagePreview",
2458
+ (state) => state.addFieldRow
2459
+ );
2460
+ const moveFieldRow = (0, import_admin2.useForm)(
2461
+ "BlockscenePagePreview",
2462
+ (state) => state.moveFieldRow
2463
+ );
1860
2464
  const fields = c.layout?.edit?.layout?.flat(3) || [];
1861
2465
  const readable = (name) => c.isCreatingEntry || (rbac.canReadFields || []).includes(name);
1862
- const zone = React3.useMemo(() => editableZones(c.contentType, values, readable, c.isLoading)[0]?.name, [c.contentType, values, c.isLoading, rbac.canReadFields, c.isCreatingEntry]);
2466
+ const zone = React4.useMemo(
2467
+ () => editableZones(c.contentType, values, readable, c.isLoading)[0]?.name,
2468
+ [c.contentType, values, c.isLoading, rbac.canReadFields, c.isCreatingEntry]
2469
+ );
1863
2470
  const zoneLabel = fields.find((field) => field.name === zone)?.label || zone || "";
1864
- 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");
1865
- const [mode, setModeState] = React3.useState(() => {
2471
+ const canEdit = Boolean(
2472
+ zone && ((c.isCreatingEntry ? rbac.canCreateFields : rbac.canUpdateFields) || []).includes(zone) && fields.find((field) => field.name === zone)?.disabled !== true && !c.form?.disabled && typeof addFieldRow === "function"
2473
+ );
2474
+ const [mode, setModeState] = React4.useState(() => {
1866
2475
  const v = read(MODE_KEY);
1867
2476
  return v === "split" || v === "preview" ? v : editor?.previewMode || "form";
1868
2477
  });
@@ -1870,32 +2479,37 @@ function PagePreview({ editor, groups = null, Toggle }) {
1870
2479
  setModeState(next);
1871
2480
  write(MODE_KEY, next);
1872
2481
  };
1873
- const [ratio, setRatio] = React3.useState(() => {
2482
+ const [ratio, setRatio] = React4.useState(() => {
1874
2483
  const v = Number(read(RATIO_KEY));
1875
2484
  return v > 0 && v < 1 ? v : 0.5;
1876
2485
  });
1877
2486
  const main = useMainRect();
1878
2487
  const vw = main.width;
1879
- const [dragging, setDragging] = React3.useState(false);
1880
- const [ready, setReady] = React3.useState(false);
1881
- const [failed, setFailed] = React3.useState(false);
1882
- const [attempt, retry] = React3.useReducer((n) => n + 1, 0);
1883
- const [picking, setPicking] = React3.useState(null);
1884
- React3.useEffect(() => {
2488
+ const [dragging, setDragging] = React4.useState(false);
2489
+ const [ready, setReady] = React4.useState(false);
2490
+ const [failed, setFailed] = React4.useState(false);
2491
+ const [attempt, retry] = React4.useReducer((n) => n + 1, 0);
2492
+ const [picking, setPicking] = React4.useState(null);
2493
+ React4.useEffect(() => {
1885
2494
  setEditing(null);
1886
2495
  setPicking(null);
1887
2496
  setInserting(null);
1888
2497
  }, [c.id, c.form?.initialValues?.locale]);
1889
- const [editing, setEditing] = React3.useState(null);
1890
- const [inserting, setInserting] = React3.useState(null);
2498
+ const [editing, setEditing] = React4.useState(null);
2499
+ const [inserting, setInserting] = React4.useState(null);
1891
2500
  const { get } = (0, import_admin2.useFetchClient)();
1892
2501
  const { toggleNotification } = (0, import_admin2.useNotification)();
1893
2502
  const zoneAttr = zone ? c.contentType?.attributes?.[zone] : null;
1894
- const iframe = React3.useRef(null);
1895
- const loaded = React3.useRef(false);
1896
- const anchor = React3.useRef(null);
1897
- const channel = React3.useMemo(() => crypto.randomUUID(), []);
1898
- const { base, source } = usePreviewBase(editor?.previewUrl || "", c.model, c.isCreatingEntry ? void 0 : c.id, c.form?.initialValues?.locale);
2503
+ const iframe = React4.useRef(null);
2504
+ const loaded = React4.useRef(false);
2505
+ const anchor = React4.useRef(null);
2506
+ const channel = React4.useMemo(() => crypto.randomUUID(), []);
2507
+ const { base, source } = usePreviewBase(
2508
+ editor?.previewUrl || "",
2509
+ c.model,
2510
+ c.isCreatingEntry ? void 0 : c.id,
2511
+ c.form?.initialValues?.locale
2512
+ );
1899
2513
  const url = base ? new URL(base) : null;
1900
2514
  url?.searchParams.set("channel", channel);
1901
2515
  const origin = url?.origin || "";
@@ -1904,16 +2518,50 @@ function PagePreview({ editor, groups = null, Toggle }) {
1904
2518
  const resizable = mode === "split" && !narrow;
1905
2519
  const active = mode !== "form" && Boolean(url) && Boolean(zone);
1906
2520
  const rows = zone && Array.isArray(values?.[zone]) ? values[zone] : [];
1907
- const latest = React3.useRef(rows);
2521
+ const latest = React4.useRef(rows);
1908
2522
  latest.current = rows;
1909
- const live = React3.useRef({ mode, canEdit, zoneLabel, components: c.components, setMode, onChange });
1910
- live.current = { mode, canEdit, zoneLabel, components: c.components, setMode, onChange };
1911
- const send = React3.useCallback(() => {
1912
- 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);
2523
+ const insertRows = (at, ...items) => items.forEach((item, i) => {
2524
+ const from = latest.current.length + i;
2525
+ addFieldRow(zone, item);
2526
+ if (at + i < from) moveFieldRow(zone, from, at + i);
2527
+ });
2528
+ const live = React4.useRef({
2529
+ mode,
2530
+ canEdit,
2531
+ zoneLabel,
2532
+ components: c.components,
2533
+ setMode,
2534
+ onChange
2535
+ });
2536
+ live.current = {
2537
+ mode,
2538
+ canEdit,
2539
+ zoneLabel,
2540
+ components: c.components,
2541
+ setMode,
2542
+ onChange
2543
+ };
2544
+ const send = React4.useCallback(() => {
2545
+ iframe.current?.contentWindow?.postMessage(
2546
+ {
2547
+ protocol: PROTOCOL,
2548
+ channel,
2549
+ type: "update-page",
2550
+ blocks: projectPage(
2551
+ latest.current,
2552
+ live.current.components,
2553
+ window.location.origin
2554
+ ),
2555
+ groups,
2556
+ locale: t.locale,
2557
+ mode: live.current.mode
2558
+ },
2559
+ origin
2560
+ );
1913
2561
  }, [channel, origin]);
1914
2562
  const indexOf = (key) => latest.current.findIndex((row) => blockKey(row) === key);
1915
2563
  const path = (key, field) => `${zone}.${indexOf(key)}.${field}`;
1916
- React3.useEffect(() => {
2564
+ React4.useEffect(() => {
1917
2565
  if (resizable) markLayout(anchor.current);
1918
2566
  document.body.classList.toggle("bp-split", resizable);
1919
2567
  document.documentElement.style.setProperty("--bp-pane", `${paneWidth}px`);
@@ -1925,7 +2573,9 @@ function PagePreview({ editor, groups = null, Toggle }) {
1925
2573
  if (persist) write(RATIO_KEY, String(next));
1926
2574
  };
1927
2575
  const focusField = (index, field) => {
1928
- const item = findZoneList(live.current.zoneLabel)?.querySelectorAll(":scope > li")[index];
2576
+ const item = findZoneList(live.current.zoneLabel)?.querySelectorAll(
2577
+ ":scope > li"
2578
+ )[index];
1929
2579
  if (!item) return;
1930
2580
  const header = toggles(item.parentElement)[index];
1931
2581
  if (header?.getAttribute("aria-expanded") === "false") header.click();
@@ -1936,33 +2586,47 @@ function PagePreview({ editor, groups = null, Toggle }) {
1936
2586
  if (++tries > 40) return clearInterval(timer);
1937
2587
  let scope = item;
1938
2588
  for (let i = 0; i + 1 < parts.length; i += 2) {
1939
- const nested = [...scope.querySelectorAll("button[aria-expanded][data-radix-collection-item]")].filter((b) => b !== header);
2589
+ const nested = [
2590
+ ...scope.querySelectorAll(
2591
+ "button[aria-expanded][data-radix-collection-item]"
2592
+ )
2593
+ ].filter((b) => b !== header);
1940
2594
  const row = nested[Number(parts[i + 1])];
1941
2595
  if (!row) return;
1942
2596
  if (row.getAttribute("aria-expanded") === "false") row.click();
1943
2597
  scope = row.closest("li, div") || scope;
1944
2598
  }
1945
- const target = document.querySelector(`[name="${escaped}"], label[for="${escaped}"]`);
2599
+ const target = document.querySelector(
2600
+ `[name="${escaped}"], label[for="${escaped}"]`
2601
+ );
1946
2602
  if (!target) return;
1947
2603
  const INPUT = '.ck-editor__editable, textarea, input:not([type="hidden"]), select';
1948
2604
  let container = target.matches(INPUT) ? target : target.parentElement;
1949
- for (let depth = 0; container && depth < 4 && !container.matches(INPUT) && !container.querySelector(INPUT); depth++) container = container.parentElement;
2605
+ for (let depth = 0; container && depth < 4 && !container.matches(INPUT) && !container.querySelector(INPUT); depth++)
2606
+ container = container.parentElement;
1950
2607
  const editable = container?.matches(INPUT) ? container : container?.querySelector(INPUT);
1951
2608
  if (!editable) return;
1952
- if (editable.classList.contains("ck-editor__editable") && !editable.isContentEditable) return;
2609
+ if (editable.classList.contains("ck-editor__editable") && !editable.isContentEditable)
2610
+ return;
1953
2611
  editable.focus();
1954
2612
  if (document.activeElement !== editable) return;
1955
2613
  clearInterval(timer);
1956
2614
  editable.scrollIntoView({ block: "center", behavior: "smooth" });
1957
2615
  }, 150);
1958
2616
  };
1959
- React3.useEffect(() => {
2617
+ React4.useEffect(() => {
1960
2618
  if (!active) return;
1961
2619
  setReady(false);
1962
2620
  setFailed(false);
1963
2621
  const timeout = setTimeout(() => setFailed(true), 15e3);
1964
2622
  const receive = (event) => {
1965
- const is = (type) => isPreviewMessage(event, origin, iframe.current?.contentWindow, channel, type);
2623
+ const is = (type) => isPreviewMessage(
2624
+ event,
2625
+ origin,
2626
+ iframe.current?.contentWindow,
2627
+ channel,
2628
+ type
2629
+ );
1966
2630
  const { mode: mode2, canEdit: canEdit2, zoneLabel: zoneLabel2, components: components2, setMode: setMode2, onChange: onChange2 } = live.current;
1967
2631
  if (is("ready")) {
1968
2632
  clearTimeout(timeout);
@@ -1982,12 +2646,21 @@ function PagePreview({ editor, groups = null, Toggle }) {
1982
2646
  return;
1983
2647
  }
1984
2648
  if (is("move-group") && canEdit2 && groups) {
1985
- const next = (0, import_groups.moveGroup)(latest.current, String(event.data.key), event.data.direction === "up" ? "up" : "down", groups);
2649
+ const next = (0, import_groups.moveGroup)(
2650
+ latest.current,
2651
+ String(event.data.key),
2652
+ event.data.direction === "up" ? "up" : "down",
2653
+ groups
2654
+ );
1986
2655
  if (next) onChange2(zone, next);
1987
2656
  return;
1988
2657
  }
1989
2658
  if (is("delete-group") && canEdit2 && groups) {
1990
- const next = (0, import_groups.removeGroup)(latest.current, String(event.data.key), groups);
2659
+ const next = (0, import_groups.removeGroup)(
2660
+ latest.current,
2661
+ String(event.data.key),
2662
+ groups
2663
+ );
1991
2664
  if (next) onChange2(zone, next);
1992
2665
  return;
1993
2666
  }
@@ -1997,13 +2670,20 @@ function PagePreview({ editor, groups = null, Toggle }) {
1997
2670
  const uid2 = String(event.data.uid || "");
1998
2671
  const close = groups[uid2];
1999
2672
  const allowed = zoneAttr?.components || [];
2000
- if (index2 < 0 || !close || !allowed.includes(uid2) || !allowed.includes(close)) return;
2673
+ if (index2 < 0 || !close || !allowed.includes(uid2) || !allowed.includes(close))
2674
+ return;
2001
2675
  if (latest.current.length + 2 > (zoneAttr?.max ?? Infinity)) {
2002
2676
  toggleNotification({ type: "info", message: t.zoneFull });
2003
2677
  return;
2004
2678
  }
2005
- addFieldRow(zone, { ...componentDefaults(components2[uid2], components2), __component: uid2 }, index2);
2006
- addFieldRow(zone, { __component: close }, index2 + 1);
2679
+ insertRows(
2680
+ index2,
2681
+ {
2682
+ ...componentDefaults(components2[uid2], components2),
2683
+ __component: uid2
2684
+ },
2685
+ { __component: close }
2686
+ );
2007
2687
  return;
2008
2688
  }
2009
2689
  const key = typeof event.data?.key === "string" ? event.data.key : "";
@@ -2023,11 +2703,21 @@ function PagePreview({ editor, groups = null, Toggle }) {
2023
2703
  }, 1500);
2024
2704
  }
2025
2705
  if (mode2 === "preview") setMode2("split");
2026
- iframe.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel, type: "highlight", key }, origin);
2706
+ iframe.current?.contentWindow?.postMessage(
2707
+ { protocol: PROTOCOL, channel, type: "highlight", key },
2708
+ origin
2709
+ );
2027
2710
  } else if (is("focus")) {
2028
2711
  const attr = validateFocus(uid, event.data.field, components2);
2029
2712
  if (!attr) return;
2030
- 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) });
2713
+ if (mode2 === "preview" && canEdit2 && (attr.customField || MODAL_TYPES.includes(attr.type)))
2714
+ setEditing({
2715
+ key,
2716
+ field: event.data.field,
2717
+ attr,
2718
+ label: `${components2[uid]?.info?.displayName || uid} \xB7 ${event.data.field}`,
2719
+ value: getIn(latest.current[index], event.data.field)
2720
+ });
2031
2721
  else focusField(index, event.data.field);
2032
2722
  } else if (is("media") && canEdit2) {
2033
2723
  const attr = mediaAttribute(uid, event.data.field, components2);
@@ -2036,27 +2726,67 @@ function PagePreview({ editor, groups = null, Toggle }) {
2036
2726
  const attr = mediaAttribute(uid, event.data.field, components2);
2037
2727
  if (attr && !attr.required) onChange2(path(key, event.data.field), null);
2038
2728
  } else if (is("edit") && canEdit2) {
2039
- const value = validateEdit(uid, event.data.field, event.data.value, components2);
2729
+ const value = validateEdit(
2730
+ uid,
2731
+ event.data.field,
2732
+ event.data.value,
2733
+ components2
2734
+ );
2040
2735
  if (value !== null) onChange2(path(key, event.data.field), value);
2041
2736
  }
2042
2737
  };
2043
2738
  window.addEventListener("message", receive);
2044
- if (loaded.current) iframe.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel, type: "ping" }, origin);
2739
+ if (loaded.current)
2740
+ iframe.current?.contentWindow?.postMessage(
2741
+ { protocol: PROTOCOL, channel, type: "ping" },
2742
+ origin
2743
+ );
2045
2744
  return () => {
2046
2745
  clearTimeout(timeout);
2047
2746
  window.removeEventListener("message", receive);
2048
2747
  };
2049
2748
  }, [active, attempt, channel, origin, groups]);
2050
- React3.useEffect(() => {
2749
+ React4.useEffect(() => {
2051
2750
  if (!ready || !active) return;
2052
2751
  const timer = setTimeout(send, 120);
2053
2752
  return () => clearTimeout(timer);
2054
2753
  }, [values, c.components, ready, active, send, mode]);
2055
2754
  if (!zone) return null;
2056
- const modes = [["form", t.modeForm], ["split", t.modeSplit], ["preview", t.modePreview]];
2057
- 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)) });
2755
+ const modes = [
2756
+ ["form", t.modeForm],
2757
+ ["split", t.modeSplit],
2758
+ ["preview", t.modePreview]
2759
+ ];
2760
+ const switcher = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2761
+ import_design_system3.Flex,
2762
+ {
2763
+ gap: 1,
2764
+ wrap: "wrap",
2765
+ "data-testid": "page-preview-modes",
2766
+ role: "group",
2767
+ "aria-label": t.modeGroup,
2768
+ children: modes.map(([value, label]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2769
+ import_design_system3.Button,
2770
+ {
2771
+ type: "button",
2772
+ size: "S",
2773
+ variant: mode === value ? "default" : "tertiary",
2774
+ "aria-pressed": mode === value,
2775
+ onClick: () => setMode(value),
2776
+ disabled: !url && value !== "form",
2777
+ children: label
2778
+ },
2779
+ value
2780
+ ))
2781
+ }
2782
+ );
2058
2783
  const onKey = (event) => {
2059
- const map = { ArrowLeft: paneWidth + KEY_STEP, ArrowRight: paneWidth - KEY_STEP, Home: MIN_PANE, End: vw - MIN_FORM };
2784
+ const map = {
2785
+ ArrowLeft: paneWidth + KEY_STEP,
2786
+ ArrowRight: paneWidth - KEY_STEP,
2787
+ Home: MIN_PANE,
2788
+ End: vw - MIN_FORM
2789
+ };
2060
2790
  if (event.key in map) {
2061
2791
  event.preventDefault();
2062
2792
  applyWidth(map[event.key], true);
@@ -2065,30 +2795,71 @@ function PagePreview({ editor, groups = null, Toggle }) {
2065
2795
  const problems = groups ? (0, import_groups.validateGroups)(rows, groups) : [];
2066
2796
  const insertClose = (error) => {
2067
2797
  const end = (0, import_groups.groupRange)(latest.current, error.index, groups)[1];
2068
- addFieldRow(zone, { __component: error.expected }, end + 1);
2798
+ insertRows(end + 1, { __component: error.expected });
2069
2799
  };
2070
- 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: [
2071
- /* @__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 }) }) }),
2072
- /* @__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: [
2073
- /* @__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 || "" }) }),
2074
- 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 }) }) }),
2075
- error.code === "closeBeforeOpen" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.diagStrayHint })
2076
- ] }, `${error.code}-${error.index}`)) })
2077
- ] }) });
2078
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 2, ref: anchor, children: [
2800
+ const diagnostics = problems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2801
+ import_design_system3.Box,
2802
+ {
2803
+ role: "alert",
2804
+ "data-testid": "page-preview-diagnostics",
2805
+ padding: 2,
2806
+ background: "danger100",
2807
+ hasRadius: true,
2808
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("details", { children: [
2809
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("summary", { style: { cursor: "pointer" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "danger700", children: t.f("diagSummary", { count: problems.length }) }) }),
2810
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { style: { margin: "6px 0 0 16px", padding: 0 }, children: problems.map((error) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2811
+ "li",
2812
+ {
2813
+ style: { marginBottom: 6 },
2814
+ children: [
2815
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "danger700", children: t.f(
2816
+ error.code === "closeBeforeOpen" ? "diagCloseBeforeOpen" : error.code === "mismatch" ? "diagMismatch" : "diagUnclosed",
2817
+ {
2818
+ n: error.index + 1,
2819
+ uid: error.uid,
2820
+ open: error.open || "",
2821
+ expected: error.expected || ""
2822
+ }
2823
+ ) }),
2824
+ error.code === "unclosed" && canEdit && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Box, { paddingTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2825
+ import_design_system3.Button,
2826
+ {
2827
+ size: "S",
2828
+ variant: "danger-light",
2829
+ "data-testid": `diag-insert-close-${error.index}`,
2830
+ onClick: () => insertClose(error),
2831
+ children: t.f("diagInsertClose", {
2832
+ n: error.index + 1,
2833
+ expected: error.expected
2834
+ })
2835
+ }
2836
+ ) }),
2837
+ error.code === "closeBeforeOpen" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.diagStrayHint })
2838
+ ]
2839
+ },
2840
+ `${error.code}-${error.index}`
2841
+ )) })
2842
+ ] })
2843
+ }
2844
+ );
2845
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 2, ref: anchor, children: [
2079
2846
  switcher,
2080
2847
  diagnostics,
2081
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: url ? t.previewHelp : t.previewNoUrl }),
2082
- active && (0, import_react_dom2.createPortal)(
2083
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2848
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: url ? t.previewHelp : t.previewNoUrl }),
2849
+ active && (0, import_react_dom3.createPortal)(
2850
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2084
2851
  Pane,
2085
2852
  {
2086
2853
  "data-testid": "page-preview-pane",
2087
2854
  "aria-label": t.previewPane,
2088
- style: { left: mode === "preview" || narrow ? main.left : main.left + main.width - paneWidth, width: mode === "preview" || narrow ? main.width : paneWidth, userSelect: dragging ? "none" : void 0 },
2855
+ style: {
2856
+ left: mode === "preview" || narrow ? main.left : main.left + main.width - paneWidth,
2857
+ width: mode === "preview" || narrow ? main.width : paneWidth,
2858
+ userSelect: dragging ? "none" : void 0
2859
+ },
2089
2860
  children: [
2090
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: SPLIT_STYLE }),
2091
- resizable && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2861
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: SPLIT_STYLE }),
2862
+ resizable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2092
2863
  Handle,
2093
2864
  {
2094
2865
  role: "separator",
@@ -2106,7 +2877,8 @@ function PagePreview({ editor, groups = null, Toggle }) {
2106
2877
  setDragging(true);
2107
2878
  },
2108
2879
  onPointerMove: (e) => {
2109
- if (dragging) applyWidth(main.left + main.width - e.clientX, false);
2880
+ if (dragging)
2881
+ applyWidth(main.left + main.width - e.clientX, false);
2110
2882
  },
2111
2883
  onPointerUp: (e) => {
2112
2884
  if (!dragging) return;
@@ -2118,15 +2890,44 @@ function PagePreview({ editor, groups = null, Toggle }) {
2118
2890
  onKeyDown: onKey
2119
2891
  }
2120
2892
  ),
2121
- /* @__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: [
2122
- switcher,
2123
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { gap: 2, alignItems: "center", wrap: "wrap", style: { marginLeft: "auto" }, children: [
2124
- /* @__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 }),
2125
- failed && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Button, { size: "S", variant: "secondary", onClick: retry, children: t.retry }),
2126
- /* @__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 })
2127
- ] })
2128
- ] }),
2129
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2893
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2894
+ import_design_system3.Flex,
2895
+ {
2896
+ padding: 2,
2897
+ gap: 2,
2898
+ justifyContent: "space-between",
2899
+ alignItems: "center",
2900
+ background: "neutral100",
2901
+ wrap: "wrap",
2902
+ style: { position: "sticky", top: 0, zIndex: 2 },
2903
+ children: [
2904
+ switcher,
2905
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2906
+ import_design_system3.Flex,
2907
+ {
2908
+ gap: 2,
2909
+ alignItems: "center",
2910
+ wrap: "wrap",
2911
+ style: { marginLeft: "auto" },
2912
+ children: [
2913
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Typography, { variant: "pi", role: "status", textColor: "neutral600", children: failed ? t.previewFailed : ready ? t.previewReady : t.previewLoading }),
2914
+ failed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Button, { size: "S", variant: "secondary", onClick: retry, children: t.retry }),
2915
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2916
+ ToolbarActions,
2917
+ {
2918
+ model: c.model,
2919
+ collectionType: c.collectionType,
2920
+ documentId: c.isCreatingEntry ? void 0 : c.id,
2921
+ locale: c.form?.initialValues?.locale
2922
+ }
2923
+ )
2924
+ ]
2925
+ }
2926
+ )
2927
+ ]
2928
+ }
2929
+ ),
2930
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2130
2931
  Frame2,
2131
2932
  {
2132
2933
  ref: iframe,
@@ -2146,12 +2947,16 @@ function PagePreview({ editor, groups = null, Toggle }) {
2146
2947
  ),
2147
2948
  document.body
2148
2949
  ),
2149
- inserting && zoneAttr && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2950
+ inserting && zoneAttr && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2150
2951
  PickerModal,
2151
2952
  {
2152
- zone: { name: zone, components: zoneAttr.components || [], max: zoneAttr.max },
2953
+ zone: {
2954
+ name: zone,
2955
+ components: zoneAttr.components || [],
2956
+ max: zoneAttr.max
2957
+ },
2153
2958
  components: c.components,
2154
- Modal: PickerDialog,
2959
+ Modal: Modal3,
2155
2960
  Toggle,
2156
2961
  get,
2157
2962
  open: true,
@@ -2163,15 +2968,24 @@ function PagePreview({ editor, groups = null, Toggle }) {
2163
2968
  setInserting(null);
2164
2969
  const close = groups?.[uid];
2165
2970
  if (index < 0 || !(zoneAttr.components || []).includes(uid) || close && !(zoneAttr.components || []).includes(close) || latest.current.length + (close ? 2 : 1) > (zoneAttr.max ?? Infinity)) {
2166
- toggleNotification({ type: "warning", message: close ? t.zoneFull : t.insertMoved });
2971
+ toggleNotification({
2972
+ type: "warning",
2973
+ message: close ? t.zoneFull : t.insertMoved
2974
+ });
2167
2975
  return;
2168
2976
  }
2169
- addFieldRow(zone, { ...componentDefaults(c.components[uid], c.components), __component: uid }, index);
2170
- if (close) addFieldRow(zone, { __component: close }, index + 1);
2977
+ insertRows(
2978
+ index,
2979
+ {
2980
+ ...componentDefaults(c.components[uid], c.components),
2981
+ __component: uid
2982
+ },
2983
+ ...close ? [{ __component: close }] : []
2984
+ );
2171
2985
  }
2172
2986
  }
2173
2987
  ),
2174
- editing && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2988
+ editing && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2175
2989
  FieldEditorModal,
2176
2990
  {
2177
2991
  label: editing.label,
@@ -2181,11 +2995,12 @@ function PagePreview({ editor, groups = null, Toggle }) {
2181
2995
  onApply: (value) => {
2182
2996
  const index = indexOf(editing.key);
2183
2997
  setEditing(null);
2184
- if (index >= 0) onChange(`${zone}.${index}.${editing.field}`, value);
2998
+ if (index >= 0)
2999
+ onChange(`${zone}.${index}.${editing.field}`, value);
2185
3000
  }
2186
3001
  }
2187
3002
  ),
2188
- picking && MediaLibraryDialog && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3003
+ picking && MediaLibraryDialog && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2189
3004
  MediaLibraryDialog,
2190
3005
  {
2191
3006
  allowedTypes: picking.attr.allowedTypes || ["images"],
@@ -2196,19 +3011,32 @@ function PagePreview({ editor, groups = null, Toggle }) {
2196
3011
  setPicking(null);
2197
3012
  if (index < 0 || !assets?.length) return;
2198
3013
  const current = getIn(latest.current[index], picking.field);
2199
- onChange(`${zone}.${index}.${picking.field}`, picking.attr.multiple ? [...Array.isArray(current) ? current : [], ...assets] : assets[0]);
3014
+ onChange(
3015
+ `${zone}.${index}.${picking.field}`,
3016
+ picking.attr.multiple ? [...Array.isArray(current) ? current : [], ...assets] : assets[0]
3017
+ );
2200
3018
  }
2201
3019
  }
2202
3020
  ),
2203
- /* @__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 : "" })
3021
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3022
+ import_design_system3.Box,
3023
+ {
3024
+ hidden: true,
3025
+ "data-testid": "page-preview-state",
3026
+ "data-mode": mode,
3027
+ "data-ready": ready,
3028
+ "data-failed": failed,
3029
+ "data-preview-source": source
3030
+ }
3031
+ )
2204
3032
  ] });
2205
3033
  }
2206
3034
 
2207
3035
  // admin/Settings.tsx
2208
- var React4 = __toESM(require("react"));
2209
- var import_design_system5 = require("@strapi/design-system");
3036
+ var React5 = __toESM(require("react"));
3037
+ var import_design_system4 = require("@strapi/design-system");
2210
3038
  var import_styled_components3 = __toESM(require("styled-components"));
2211
- var import_jsx_runtime5 = require("react/jsx-runtime");
3039
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2212
3040
  var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
2213
3041
  var Grid = import_styled_components3.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
2214
3042
  var Card2 = import_styled_components3.default.div`
@@ -2221,8 +3049,8 @@ var Bar = import_styled_components3.default.div`
2221
3049
  box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
2222
3050
  `;
2223
3051
  function useMainRect2(anchor) {
2224
- const [rect, setRect] = React4.useState({ left: 0, width: 0 });
2225
- React4.useEffect(() => {
3052
+ const [rect, setRect] = React5.useState({ left: 0, width: 0 });
3053
+ React5.useEffect(() => {
2226
3054
  const read2 = () => {
2227
3055
  let host = document.getElementById("main-content");
2228
3056
  for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
@@ -2239,11 +3067,11 @@ var Swatches = import_styled_components3.default.div` display: grid; grid-templa
2239
3067
  var Label = import_styled_components3.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
2240
3068
  function ColorField({ name, label, value, onChange, disabled }) {
2241
3069
  const valid = COLOR2.test(value);
2242
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Label, { children: [
2243
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
2244
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 2, children: [
2245
- /* @__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" } }),
2246
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3070
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Label, { children: [
3071
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
3072
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { gap: 2, children: [
3073
+ /* @__PURE__ */ (0, import_jsx_runtime6.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" } }),
3074
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2247
3075
  "input",
2248
3076
  {
2249
3077
  name,
@@ -2263,18 +3091,18 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2263
3091
  const t = useMessages();
2264
3092
  const { get, put } = useClient();
2265
3093
  const { canRead, canUpdate, isLoading } = usePermissions2();
2266
- const [data, setData] = React4.useState(null);
2267
- const [catalog, setCatalog] = React4.useState(null);
2268
- const [settings, setSettings] = React4.useState(null);
2269
- const [media, setMedia] = React4.useState({});
2270
- const [sources, setSources] = React4.useState({});
2271
- const [dirty, setDirty] = React4.useState(false);
2272
- const [saving, setSaving] = React4.useState(false);
2273
- const [status, setStatus] = React4.useState("");
2274
- const [failed, setFailed] = React4.useState(false);
2275
- const [filter, setFilter] = React4.useState("");
2276
- const [picking, setPicking] = React4.useState(null);
2277
- React4.useEffect(() => {
3094
+ const [data, setData] = React5.useState(null);
3095
+ const [catalog, setCatalog] = React5.useState(null);
3096
+ const [settings, setSettings] = React5.useState(null);
3097
+ const [media, setMedia] = React5.useState({});
3098
+ const [sources, setSources] = React5.useState({});
3099
+ const [dirty, setDirty] = React5.useState(false);
3100
+ const [saving, setSaving] = React5.useState(false);
3101
+ const [status, setStatus] = React5.useState("");
3102
+ const [failed, setFailed] = React5.useState(false);
3103
+ const [filter, setFilter] = React5.useState("");
3104
+ const [picking, setPicking] = React5.useState(null);
3105
+ React5.useEffect(() => {
2278
3106
  if (!canRead || isLoading) return;
2279
3107
  let active = true;
2280
3108
  Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
@@ -2322,35 +3150,35 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2322
3150
  return index === 0 && manual ? t.manual : t.automatic;
2323
3151
  };
2324
3152
  const ready = !isLoading && canRead && !failed && settings && catalog;
2325
- const header = React4.useRef(null);
2326
- const [floating, setFloating] = React4.useState(false);
3153
+ const header = React5.useRef(null);
3154
+ const [floating, setFloating] = React5.useState(false);
2327
3155
  const main = useMainRect2(header);
2328
- React4.useEffect(() => {
3156
+ React5.useEffect(() => {
2329
3157
  const el = header.current;
2330
3158
  if (!el || typeof IntersectionObserver === "undefined") return;
2331
3159
  const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
2332
3160
  observer.observe(el);
2333
3161
  return () => observer.disconnect();
2334
3162
  }, [ready]);
2335
- const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
2336
- /* @__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 }),
2337
- /* @__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 })
3163
+ const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
3164
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.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 }),
3165
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
2338
3166
  ] });
2339
- 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: [
2340
- /* @__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: [
2341
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
3167
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
3168
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
3169
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
2342
3170
  controls("")
2343
3171
  ] }) }),
2344
- 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: [
2345
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
3172
+ floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
3173
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
2346
3174
  controls("-floating")
2347
3175
  ] }) }),
2348
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { textColor: "neutral600", children: t.settingsIntro }),
2349
- 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: [
2350
- 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 }) }),
2351
- /* @__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: [
2352
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "h2", children: t.palette }),
2353
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3176
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { textColor: "neutral600", children: t.settingsIntro }),
3177
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3178
+ data.disabled && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
3179
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
3180
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "beta", tag: "h2", children: t.palette }),
3181
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2354
3182
  ColorField,
2355
3183
  {
2356
3184
  name: `palette-${key}`,
@@ -2364,33 +3192,33 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2364
3192
  },
2365
3193
  key
2366
3194
  )) }),
2367
- invalid && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
2368
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
2369
- /* @__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: [
2370
- /* @__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 }) }),
2371
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
3195
+ invalid && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
3196
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
3197
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { direction: "column", gap: 1, children: [
3198
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Wireframe, { template, palette: settings.palette }) }),
3199
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
2372
3200
  ] }, template)) }),
2373
- /* @__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) => {
3201
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
2374
3202
  s.palette = { ...DEFAULT_PALETTE };
2375
3203
  return s;
2376
3204
  }), children: t.resetPalette }) })
2377
3205
  ] }) }),
2378
- /* @__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: [
2379
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "h2", children: t.editor }),
2380
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
3206
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
3207
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "beta", tag: "h2", children: t.editor }),
3208
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2381
3209
  s.editor.enabled = v;
2382
3210
  return s;
2383
3211
  }) }),
2384
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
2385
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
3212
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
3213
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2386
3214
  s.editor.showOpenAll = v;
2387
3215
  return s;
2388
3216
  }) }),
2389
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
3217
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2390
3218
  s.editor.showCloseAll = v;
2391
3219
  return s;
2392
3220
  }) }),
2393
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3221
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2394
3222
  SelectField2,
2395
3223
  {
2396
3224
  name: "editor-initialState",
@@ -2404,9 +3232,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2404
3232
  })
2405
3233
  }
2406
3234
  ),
2407
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
2408
- previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2409
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3235
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
3236
+ previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3237
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2410
3238
  TextField2,
2411
3239
  {
2412
3240
  name: "editor-previewUrl",
@@ -2420,8 +3248,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2420
3248
  })
2421
3249
  }
2422
3250
  ),
2423
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
2424
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3251
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
3252
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2425
3253
  SelectField2,
2426
3254
  {
2427
3255
  name: "editor-previewMode",
@@ -2435,26 +3263,26 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2435
3263
  })
2436
3264
  }
2437
3265
  ),
2438
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
2439
- data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
2440
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
3266
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
3267
+ data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
3268
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2441
3269
  s.editor.blockPreviewInForm = v;
2442
3270
  return s;
2443
3271
  }) }),
2444
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
3272
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
2445
3273
  ] })
2446
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
3274
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
2447
3275
  ] }) }),
2448
- /* @__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: [
2449
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "beta", tag: "h2", children: t.components }),
2450
- /* @__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 }),
2451
- /* @__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 }) }),
2452
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
3276
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
3277
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "beta", tag: "h2", children: t.components }),
3278
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
3279
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
3280
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
2453
3281
  const entry = settings.components[component.uid] || {};
2454
3282
  const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
2455
3283
  const candidates = candidatesFor(component.uid, meta, catalog);
2456
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
2457
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3284
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
3285
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2458
3286
  Thumb,
2459
3287
  {
2460
3288
  candidates,
@@ -2465,23 +3293,23 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2465
3293
  onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
2466
3294
  }
2467
3295
  ),
2468
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
2469
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
2470
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Typography, { variant: "pi", textColor: "neutral600", children: [
3296
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
3297
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
3298
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Typography, { variant: "pi", textColor: "neutral600", children: [
2471
3299
  component.uid,
2472
3300
  " \xB7 ",
2473
3301
  component.category
2474
3302
  ] }),
2475
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
3303
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
2476
3304
  t.source,
2477
3305
  ": ",
2478
3306
  sourceOf(component.uid, Boolean(meta.manualImage)),
2479
3307
  meta.manualName ? ` (${meta.manualName})` : ""
2480
3308
  ] }),
2481
- meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
2482
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system5.Flex, { gap: 2, wrap: "wrap", children: [
2483
- /* @__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 }),
2484
- entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system5.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
3309
+ meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
3310
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system4.Flex, { gap: 2, wrap: "wrap", children: [
3311
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
3312
+ entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system4.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
2485
3313
  update((s) => {
2486
3314
  delete s.components[component.uid]?.mediaId;
2487
3315
  if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
@@ -2494,7 +3322,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2494
3322
  });
2495
3323
  }, children: t.useAutomatic })
2496
3324
  ] }),
2497
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3325
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2498
3326
  SelectField2,
2499
3327
  {
2500
3328
  name: `template-${component.uid}`,
@@ -2512,7 +3340,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2512
3340
  ] }, component.uid);
2513
3341
  }) })
2514
3342
  ] }) }),
2515
- picking && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
3343
+ picking && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
2516
3344
  const uid = picking;
2517
3345
  setPicking(null);
2518
3346
  if (!asset?.id) return;
@@ -2525,24 +3353,26 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
2525
3353
  ] })
2526
3354
  ] }) });
2527
3355
  }
2528
- function register(app, Component) {
3356
+ function register(app, Component, to) {
2529
3357
  app.createSettingSection(
2530
3358
  { id: "blockscene", intlLabel: { id: "blockscene.title", defaultMessage: "Blockscene" } },
2531
3359
  [{
2532
3360
  id: "blockscene-settings",
2533
- to: "/settings/blockscene",
3361
+ to,
2534
3362
  intlLabel: { id: "blockscene.settings", defaultMessage: "Gallery" },
2535
- Component: async () => Component,
3363
+ // Module shape: older Strapi 4 (e.g. 4.11) only reads `.default` from the loader result.
3364
+ // Not an `async` function: Strapi 5 warns on AsyncFunction loaders.
3365
+ Component: () => Promise.resolve({ default: Component }),
2536
3366
  permissions: permissions.read
2537
3367
  }]
2538
3368
  );
2539
3369
  }
2540
3370
 
2541
3371
  // admin/catalog.ts
2542
- var React5 = __toESM(require("react"));
3372
+ var React6 = __toESM(require("react"));
2543
3373
  function useCatalog(get) {
2544
- const [catalog, setCatalog] = React5.useState(null);
2545
- React5.useEffect(() => {
3374
+ const [catalog, setCatalog] = React6.useState(null);
3375
+ React6.useEffect(() => {
2546
3376
  let active = true;
2547
3377
  get("/blockscene/catalog").then(({ data }) => {
2548
3378
  if (active) setCatalog(data);
@@ -2557,13 +3387,13 @@ function useCatalog(get) {
2557
3387
  }
2558
3388
 
2559
3389
  // admin/strapi5.tsx
2560
- var import_jsx_runtime6 = require("react/jsx-runtime");
3390
+ var import_jsx_runtime7 = require("react/jsx-runtime");
2561
3391
  function Modal2({ open, onOpenChange, trigger, title, children }) {
2562
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Modal.Root, { open, onOpenChange, children: [
2563
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Modal.Trigger, { children: trigger }),
2564
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Modal.Content, { style: { width: "80vw", maxWidth: "80vw" }, children: [
2565
- /* @__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 }) }),
2566
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Modal.Body, { children })
3392
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system5.Modal.Root, { open, onOpenChange, children: [
3393
+ trigger && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.Modal.Trigger, { children: trigger }),
3394
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system5.Modal.Content, { style: { width: "80vw", maxWidth: "80vw" }, children: [
3395
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.Modal.Header, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.Modal.Title, { children: title }) }),
3396
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.Modal.Body, { children })
2567
3397
  ] })
2568
3398
  ] });
2569
3399
  }
@@ -2583,52 +3413,157 @@ function Panel() {
2583
3413
  formValues ?? c.form?.values,
2584
3414
  (name) => allowed.includes(name) && (creating || (rbac.canReadFields || []).includes(name)) && fields.find((field) => field.name === name)?.disabled !== true,
2585
3415
  c.isLoading || c.form?.disabled || !c.form?.addFieldRow
2586
- ).map((zone) => ({ ...zone, label: fields.find((field) => field.name === zone.name)?.label || zone.name }));
3416
+ ).map((zone) => ({
3417
+ ...zone,
3418
+ label: fields.find((field) => field.name === zone.name)?.label || zone.name
3419
+ }));
2587
3420
  const add = (zone, uid) => {
2588
3421
  const values = formValues ?? c.form.values;
2589
3422
  const close = catalog?.groups?.[uid];
2590
- if (c.form.disabled || !canInsert(zone, uid, values, c.components, close ? 2 : 1) || close && !zone.components.includes(close)) return false;
3423
+ if (c.form.disabled || !canInsert(zone, uid, values, c.components, close ? 2 : 1) || close && !zone.components.includes(close))
3424
+ return false;
2591
3425
  const at = Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0;
2592
- c.form.addFieldRow(zone.name, { ...componentDefaults(c.components[uid], c.components), __component: uid }, at);
3426
+ c.form.addFieldRow(
3427
+ zone.name,
3428
+ {
3429
+ ...componentDefaults(c.components[uid], c.components),
3430
+ __component: uid
3431
+ },
3432
+ at
3433
+ );
2593
3434
  if (close) c.form.addFieldRow(zone.name, { __component: close }, at + 1);
2594
3435
  return true;
2595
3436
  };
2596
3437
  if (!zones.length || !catalog?.editor?.enabled) return null;
2597
3438
  const docKey = `${c.model}:${creating ? "new" : c.id}:${c.form?.initialValues?.locale || ""}`;
2598
- return { title: t.gallery, content: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2599
- /* @__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 }),
2600
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PagePreview, { editor: catalog.editor, groups: catalog.groups || null, Toggle: ToggleField })
2601
- ] }) };
3439
+ return {
3440
+ title: t.gallery,
3441
+ content: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system5.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
3442
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3443
+ Gallery,
3444
+ {
3445
+ zones,
3446
+ components: c.components,
3447
+ add,
3448
+ Modal: Modal2,
3449
+ Toggle: ToggleField,
3450
+ get,
3451
+ editor: catalog.editor,
3452
+ catalog,
3453
+ docKey,
3454
+ contentType: c.model,
3455
+ userId: user?.id
3456
+ }
3457
+ ),
3458
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3459
+ PagePreview,
3460
+ {
3461
+ editor: catalog.editor,
3462
+ groups: catalog.groups || null,
3463
+ Modal: Modal2,
3464
+ Toggle: ToggleField
3465
+ }
3466
+ )
3467
+ ] })
3468
+ };
2602
3469
  }
2603
- var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Flex, { gap: 3, children: [
2604
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Switch, { name, "aria-label": label, checked: Boolean(value), disabled, onCheckedChange: onChange }),
2605
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Typography, { children: label })
3470
+ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system5.Flex, { gap: 3, children: [
3471
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3472
+ import_design_system5.Switch,
3473
+ {
3474
+ name,
3475
+ "aria-label": label,
3476
+ checked: Boolean(value),
3477
+ disabled,
3478
+ onCheckedChange: onChange
3479
+ }
3480
+ ),
3481
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.Typography, { children: label })
2606
3482
  ] });
2607
- var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Field.Root, { name, children: [
2608
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Field.Label, { children: label }),
2609
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.TextInput, { name, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) })
3483
+ var TextField = ({
3484
+ name,
3485
+ label,
3486
+ value,
3487
+ onChange,
3488
+ disabled,
3489
+ placeholder
3490
+ }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system5.Field.Root, { name, children: [
3491
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.Field.Label, { children: label }),
3492
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3493
+ import_design_system5.TextInput,
3494
+ {
3495
+ name,
3496
+ value,
3497
+ disabled,
3498
+ placeholder,
3499
+ onChange: (e) => onChange(e.target.value)
3500
+ }
3501
+ )
2610
3502
  ] });
2611
- var SelectField = ({ name, label, value, onChange, disabled, options }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system6.Field.Root, { name, children: [
2612
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system6.Field.Label, { children: label }),
2613
- /* @__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)) })
3503
+ var SelectField = ({
3504
+ name,
3505
+ label,
3506
+ value,
3507
+ onChange,
3508
+ disabled,
3509
+ options
3510
+ }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system5.Field.Root, { name, children: [
3511
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.Field.Label, { children: label }),
3512
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3513
+ import_design_system5.SingleSelect,
3514
+ {
3515
+ value,
3516
+ disabled,
3517
+ onChange: (v) => onChange(String(v)),
3518
+ children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system5.SingleSelectOption, { value: o.value, children: o.label }, o.value))
3519
+ }
3520
+ )
2614
3521
  ] });
2615
3522
  function MediaPicker({ onClose, onSelect }) {
2616
- const components = (0, import_admin3.useStrapiApp)("Blockscene", (state) => state.components);
2617
- const Dialog3 = components?.["media-library"];
2618
- React6.useEffect(() => {
2619
- if (!Dialog3) onClose();
2620
- }, [Dialog3, onClose]);
2621
- if (!Dialog3) return null;
2622
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Dialog3, { onClose, allowedTypes: ["images"], multiple: false, onSelectAssets: (assets) => onSelect(assets?.[0]) });
3523
+ const components = (0, import_admin3.useStrapiApp)(
3524
+ "Blockscene",
3525
+ (state) => state.components
3526
+ );
3527
+ const Dialog2 = components?.["media-library"];
3528
+ React7.useEffect(() => {
3529
+ if (!Dialog2) onClose();
3530
+ }, [Dialog2, onClose]);
3531
+ if (!Dialog2) return null;
3532
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3533
+ Dialog2,
3534
+ {
3535
+ onClose,
3536
+ allowedTypes: ["images"],
3537
+ multiple: false,
3538
+ onSelectAssets: (assets) => onSelect(assets?.[0])
3539
+ }
3540
+ );
2623
3541
  }
2624
3542
  function usePermissions() {
2625
- const { allowedActions, isLoading } = (0, import_admin3.useRBAC)(permissions);
2626
- return { canRead: allowedActions.canRead, canUpdate: allowedActions.canUpdate, isLoading };
3543
+ const { allowedActions, isLoading } = (0, import_admin3.useRBAC)(
3544
+ Object.values(permissions).flat()
3545
+ );
3546
+ return {
3547
+ canRead: allowedActions.canRead,
3548
+ canUpdate: allowedActions.canUpdate,
3549
+ isLoading
3550
+ };
2627
3551
  }
2628
- var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Settings, { useClient: import_admin3.useFetchClient, usePermissions, MediaPicker, ToggleField, SelectField, TextField, previewSupported: true });
3552
+ var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3553
+ Settings,
3554
+ {
3555
+ useClient: import_admin3.useFetchClient,
3556
+ usePermissions,
3557
+ MediaPicker,
3558
+ ToggleField,
3559
+ SelectField,
3560
+ TextField,
3561
+ previewSupported: true
3562
+ }
3563
+ );
2629
3564
  var strapi5_default = {
2630
3565
  register(app) {
2631
- register(app, SettingsPage);
3566
+ register(app, SettingsPage, "blockscene");
2632
3567
  app.registerPlugin({ id: "blockscene", name: "Blockscene" });
2633
3568
  },
2634
3569
  registerTrads,