@aduptive/strapi-blockscene 1.0.0-alpha.1 → 1.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.
package/dist/admin.cjs CHANGED
@@ -32,13 +32,13 @@ __export(strapi4_exports, {
32
32
  default: () => strapi4_default
33
33
  });
34
34
  module.exports = __toCommonJS(strapi4_exports);
35
- var React4 = __toESM(require("react"));
35
+ var React5 = __toESM(require("react"));
36
36
  var import_design_system3 = require("@strapi/design-system");
37
37
  var import_helper_plugin = require("@strapi/helper-plugin");
38
38
 
39
39
  // admin/Gallery.tsx
40
- var React = __toESM(require("react"));
41
- var import_react_dom = require("react-dom");
40
+ var React2 = __toESM(require("react"));
41
+ var import_react_dom2 = require("react-dom");
42
42
  var import_design_system = require("@strapi/design-system");
43
43
  var import_styled_components = __toESM(require("styled-components"));
44
44
 
@@ -46,27 +46,58 @@ var import_styled_components = __toESM(require("styled-components"));
46
46
  var import_fractional_indexing = require("fractional-indexing");
47
47
  function editableZones(schema, values, canEdit, disabled = false) {
48
48
  if (disabled) return [];
49
- return Object.entries(schema?.attributes || {}).filter(([name, attr]) => attr.type === "dynamiczone" && !attr.conditions && canEdit(name)).map(([name, attr]) => {
50
- const count = Array.isArray(values?.[name]) ? values[name].length : 0;
51
- return { name, components: attr.components || [], max: attr.max, count, full: count >= (attr.max ?? Infinity) };
49
+ return Object.entries(schema?.attributes || {}).filter(
50
+ ([name, attr]) => attr.type === "dynamiczone" && !attr.conditions && canEdit(name)
51
+ ).map(([name, attr]) => {
52
+ const rows = Array.isArray(values?.[name]) ? values[name] : [];
53
+ return {
54
+ name,
55
+ components: attr.components || [],
56
+ max: attr.max,
57
+ count: rows.length,
58
+ uids: rows.map(
59
+ (row) => row && typeof row.__component === "string" ? row.__component : ""
60
+ ),
61
+ full: rows.length >= (attr.max ?? Infinity)
62
+ };
52
63
  });
53
64
  }
54
65
  function canInsert(zone, uid, values, components, count = 1) {
55
- return Boolean(zone?.components.includes(uid) && components[uid] && (Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0) + count <= (zone.max ?? Infinity));
66
+ return Boolean(
67
+ zone?.components.includes(uid) && components[uid] && (Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0) + count <= (zone.max ?? Infinity)
68
+ );
56
69
  }
57
70
  function candidatesFor(uid, meta = {}, config = {}) {
58
71
  const version = config.previewVersion ? `?v=${encodeURIComponent(config.previewVersion)}` : "";
59
72
  const base = (config.previewBaseUrl || "/block-previews").replace(/\/$/, "");
60
- return [meta.manualImage, meta.image, `${base}/${encodeURIComponent(uid)}.webp${version}`].filter(Boolean);
73
+ return [
74
+ meta.manualImage,
75
+ meta.image,
76
+ `${base}/${encodeURIComponent(uid)}.webp${version}`
77
+ ].filter(Boolean);
61
78
  }
62
- var SYSTEM_FIELDS = ["id", "documentId", "createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "locale", "localizations"];
79
+ var SYSTEM_FIELDS = [
80
+ "id",
81
+ "documentId",
82
+ "createdAt",
83
+ "updatedAt",
84
+ "publishedAt",
85
+ "createdBy",
86
+ "updatedBy",
87
+ "locale",
88
+ "localizations"
89
+ ];
63
90
  var fieldType = (attr) => attr?.type === "customField" ? String(attr.customField || "").includes("CKEditor") ? "richtext" : "customField" : attr?.type || "unknown";
64
91
  var fieldsOf = (schema) => Object.entries(schema?.attributes || {}).filter(([name]) => !SYSTEM_FIELDS.includes(name)).map(([name, attr]) => ({ name, type: fieldType(attr) }));
65
92
  var categoryOf = (uid, schema, meta = {}) => meta.category || schema?.category || uid.split(".")[0];
66
93
  var byCategory = (a, b) => (a === "admin" ? 1 : 0) - (b === "admin" ? 1 : 0) || a.localeCompare(b);
94
+ var pickable = (zone, config) => {
95
+ const closers = Object.values(config.groups || {});
96
+ return zone.components.filter((uid) => !closers.includes(uid));
97
+ };
67
98
  function entriesFor(zone, components, config, query, category = "all") {
68
99
  const needle = query.trim().toLocaleLowerCase();
69
- return zone.components.flatMap((uid) => {
100
+ return pickable(zone, config).flatMap((uid) => {
70
101
  const schema = components[uid];
71
102
  if (!schema) return [];
72
103
  const meta = config.components?.[uid] || {};
@@ -81,11 +112,13 @@ function entriesFor(zone, components, config, query, category = "all") {
81
112
  };
82
113
  if (category !== "all" && entry.category !== category) return [];
83
114
  return `${entry.label} ${entry.description} ${entry.category} ${uid} ${meta.keywords || ""}`.toLocaleLowerCase().includes(needle) ? [entry] : [];
84
- }).sort((a, b) => byCategory(a.category, b.category) || a.label.localeCompare(b.label));
115
+ }).sort(
116
+ (a, b) => byCategory(a.category, b.category) || a.label.localeCompare(b.label)
117
+ );
85
118
  }
86
119
  function categoriesFor(zone, components, config) {
87
120
  const counts = /* @__PURE__ */ new Map();
88
- for (const uid of zone.components) {
121
+ for (const uid of pickable(zone, config)) {
89
122
  const schema = components[uid];
90
123
  if (!schema) continue;
91
124
  const c = categoryOf(uid, schema, config.components?.[uid] || {});
@@ -95,8 +128,12 @@ function categoriesFor(zone, components, config) {
95
128
  }
96
129
  function groupEntries(entries) {
97
130
  const map = /* @__PURE__ */ new Map();
98
- for (const entry of entries) map.set(entry.category, [...map.get(entry.category) || [], entry]);
99
- return [...map.entries()].map(([category, items]) => ({ category, entries: items }));
131
+ for (const entry of entries)
132
+ map.set(entry.category, [...map.get(entry.category) || [], entry]);
133
+ return [...map.entries()].map(([category, items]) => ({
134
+ category,
135
+ entries: items
136
+ }));
100
137
  }
101
138
  function memoryKey({ base = "", userId, contentType, zone }) {
102
139
  if (!userId || !contentType || !zone) return null;
@@ -112,7 +149,8 @@ function readMemory(storage2, key) {
112
149
  }
113
150
  function writeMemory(storage2, key, value) {
114
151
  try {
115
- if (key && (value === "open" || value === "closed")) storage2?.setItem(key, value);
152
+ if (key && (value === "open" || value === "closed"))
153
+ storage2?.setItem(key, value);
116
154
  } catch {
117
155
  }
118
156
  }
@@ -198,6 +236,10 @@ function Wireframe({ template, palette, className, noPreview }) {
198
236
  );
199
237
  }
200
238
 
239
+ // admin/RowPreviews.tsx
240
+ var React = __toESM(require("react"));
241
+ var import_react_dom = require("react-dom");
242
+
201
243
  // admin/messages.ts
202
244
  var import_react_intl = require("react-intl");
203
245
 
@@ -312,7 +354,8 @@ var en_default = {
312
354
  columns: "Columns",
313
355
  noPreview: "no preview",
314
356
  "templates.none": "No preview",
315
- noChanges: "No unsaved changes"
357
+ noChanges: "No unsaved changes",
358
+ rowPreview: "Open the {label} preview"
316
359
  };
317
360
 
318
361
  // admin/translations/pt-BR.json
@@ -426,7 +469,8 @@ var pt_BR_default = {
426
469
  columns: "Colunas",
427
470
  noPreview: "sem preview",
428
471
  "templates.none": "Sem preview",
429
- noChanges: "Sem altera\xE7\xF5es pendentes"
472
+ noChanges: "Sem altera\xE7\xF5es pendentes",
473
+ rowPreview: "Abrir a pr\xE9via de {label}"
430
474
  };
431
475
 
432
476
  // admin/translations/pt.json
@@ -540,7 +584,8 @@ var pt_default = {
540
584
  columns: "Colunas",
541
585
  noPreview: "sem pr\xE9-visualiza\xE7\xE3o",
542
586
  "templates.none": "Sem pr\xE9-visualiza\xE7\xE3o",
543
- noChanges: "Sem altera\xE7\xF5es pendentes"
587
+ noChanges: "Sem altera\xE7\xF5es pendentes",
588
+ rowPreview: "Abrir a pr\xE9-visualiza\xE7\xE3o de {label}"
544
589
  };
545
590
 
546
591
  // admin/translations/fr.json
@@ -654,7 +699,8 @@ var fr_default = {
654
699
  columns: "Colonnes",
655
700
  noPreview: "pas d\u2019aper\xE7u",
656
701
  "templates.none": "Pas d\u2019aper\xE7u",
657
- noChanges: "Aucune modification en attente"
702
+ noChanges: "Aucune modification en attente",
703
+ rowPreview: "Ouvrir l\u2019aper\xE7u de {label}"
658
704
  };
659
705
 
660
706
  // admin/translations/es.json
@@ -768,7 +814,8 @@ var es_default = {
768
814
  columns: "Columnas",
769
815
  noPreview: "sin vista previa",
770
816
  "templates.none": "Sin vista previa",
771
- noChanges: "Sin cambios pendientes"
817
+ noChanges: "Sin cambios pendientes",
818
+ rowPreview: "Abrir la vista previa de {label}"
772
819
  };
773
820
 
774
821
  // admin/translations/de.json
@@ -882,7 +929,8 @@ var de_default = {
882
929
  columns: "Spalten",
883
930
  noPreview: "keine Vorschau",
884
931
  "templates.none": "Keine Vorschau",
885
- noChanges: "Keine ungespeicherten \xC4nderungen"
932
+ noChanges: "Keine ungespeicherten \xC4nderungen",
933
+ rowPreview: "Vorschau von {label} \xF6ffnen"
886
934
  };
887
935
 
888
936
  // admin/translations/it.json
@@ -996,7 +1044,8 @@ var it_default = {
996
1044
  columns: "Colonne",
997
1045
  noPreview: "nessuna anteprima",
998
1046
  "templates.none": "Nessuna anteprima",
999
- noChanges: "Nessuna modifica in sospeso"
1047
+ noChanges: "Nessuna modifica in sospeso",
1048
+ rowPreview: "Apri l\u2019anteprima di {label}"
1000
1049
  };
1001
1050
 
1002
1051
  // admin/translations/nl.json
@@ -1110,7 +1159,8 @@ var nl_default = {
1110
1159
  columns: "Kolommen",
1111
1160
  noPreview: "geen voorbeeld",
1112
1161
  "templates.none": "Geen voorbeeld",
1113
- noChanges: "Geen niet-opgeslagen wijzigingen"
1162
+ noChanges: "Geen niet-opgeslagen wijzigingen",
1163
+ rowPreview: "Voorbeeld van {label} openen"
1114
1164
  };
1115
1165
 
1116
1166
  // admin/messages.ts
@@ -1130,26 +1180,224 @@ function useMessages() {
1130
1180
  return out;
1131
1181
  }
1132
1182
 
1133
- // admin/Gallery.tsx
1183
+ // admin/RowPreviews.tsx
1134
1184
  var import_jsx_runtime2 = require("react/jsx-runtime");
1185
+ var ATTR = "data-blockscene-row-thumb";
1186
+ function useAnchors(zones, onOpen) {
1187
+ const [anchors, setAnchors] = React.useState([]);
1188
+ const open = React.useRef(onOpen);
1189
+ open.current = onOpen;
1190
+ const latest = React.useRef(zones);
1191
+ latest.current = zones;
1192
+ const sync = React.useRef(() => {
1193
+ });
1194
+ sync.current = () => {
1195
+ const next = [];
1196
+ for (const zone of latest.current) {
1197
+ const list = zone.uids?.length ? findZoneList(zone.label) : null;
1198
+ if (!list) continue;
1199
+ toggles(list).forEach((button, index) => {
1200
+ const uid = zone.uids[index];
1201
+ if (!uid) return;
1202
+ let el = button.querySelector(
1203
+ `:scope > [${ATTR}]`
1204
+ );
1205
+ if (!el) {
1206
+ el = document.createElement("span");
1207
+ el.setAttribute(ATTR, "");
1208
+ el.style.cssText = "display:inline-flex;align-items:center";
1209
+ const activate = (event) => {
1210
+ if (!event.currentTarget.getAttribute("role"))
1211
+ return;
1212
+ event.preventDefault();
1213
+ event.stopPropagation();
1214
+ open.current(
1215
+ String(event.currentTarget.dataset.uid || "")
1216
+ );
1217
+ };
1218
+ el.addEventListener("click", activate, true);
1219
+ el.addEventListener(
1220
+ "keydown",
1221
+ (event) => {
1222
+ if (event.key === "Enter" || event.key === " ") activate(event);
1223
+ },
1224
+ true
1225
+ );
1226
+ button.insertBefore(el, button.firstChild);
1227
+ }
1228
+ el.dataset.uid = uid;
1229
+ next.push({ el, uid, zone: zone.name, index });
1230
+ });
1231
+ }
1232
+ for (const el of document.querySelectorAll(`[${ATTR}]`))
1233
+ if (!next.some((a) => a.el === el)) el.remove();
1234
+ setAnchors(
1235
+ (prev) => prev.length === next.length && prev.every((a, i) => a.el === next[i].el && a.uid === next[i].uid) ? prev : next
1236
+ );
1237
+ };
1238
+ React.useEffect(() => {
1239
+ sync.current();
1240
+ });
1241
+ React.useEffect(() => {
1242
+ let frame = 0;
1243
+ const observer = new MutationObserver(() => {
1244
+ if (frame) return;
1245
+ frame = requestAnimationFrame(() => {
1246
+ frame = 0;
1247
+ sync.current();
1248
+ });
1249
+ });
1250
+ observer.observe(document.body, { childList: true, subtree: true });
1251
+ return () => {
1252
+ observer.disconnect();
1253
+ cancelAnimationFrame(frame);
1254
+ for (const el of document.querySelectorAll(`[${ATTR}]`)) el.remove();
1255
+ };
1256
+ }, []);
1257
+ return anchors;
1258
+ }
1259
+ function RowPreviews({ zones, components, catalog, Modal: Modal2 }) {
1260
+ const t = useMessages();
1261
+ const [resolved, setResolved] = React.useState({});
1262
+ const [open, setOpen] = React.useState(null);
1263
+ const anchors = useAnchors(zones, (uid) => setOpen(uid));
1264
+ const candidates = (uid) => candidatesFor(uid, catalog?.components?.[uid] || {}, catalog || {});
1265
+ const label = (uid) => catalog?.components?.[uid]?.label || components?.[uid]?.info?.displayName || uid;
1266
+ const srcOf = (uid) => candidates(uid)[resolved[uid] ?? -1] || "";
1267
+ React.useEffect(() => {
1268
+ for (const { el, uid } of anchors) {
1269
+ if (srcOf(uid)) {
1270
+ el.setAttribute("role", "button");
1271
+ el.setAttribute("tabindex", "0");
1272
+ el.setAttribute("aria-label", t.f("rowPreview", { label: label(uid) }));
1273
+ el.style.cursor = "zoom-in";
1274
+ } else
1275
+ for (const name of ["role", "tabindex", "aria-label"])
1276
+ el.removeAttribute(name);
1277
+ }
1278
+ });
1279
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1280
+ anchors.map(
1281
+ (a) => (0, import_react_dom.createPortal)(
1282
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1283
+ "span",
1284
+ {
1285
+ style: {
1286
+ display: "block",
1287
+ width: "6.4rem",
1288
+ marginRight: "8px",
1289
+ flex: "0 0 auto"
1290
+ },
1291
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1292
+ Thumb,
1293
+ {
1294
+ candidates: candidates(a.uid),
1295
+ blank: true,
1296
+ onResolved: (index) => setResolved(
1297
+ (prev) => prev[a.uid] === index ? prev : { ...prev, [a.uid]: index }
1298
+ )
1299
+ }
1300
+ )
1301
+ }
1302
+ ),
1303
+ a.el,
1304
+ `${a.zone}:${a.index}`
1305
+ )
1306
+ ),
1307
+ open && srcOf(open) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1308
+ Modal2,
1309
+ {
1310
+ open: true,
1311
+ onOpenChange: (value) => {
1312
+ if (!value) setOpen(null);
1313
+ },
1314
+ trigger: null,
1315
+ title: label(open),
1316
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1317
+ "img",
1318
+ {
1319
+ src: srcOf(open),
1320
+ alt: "",
1321
+ style: {
1322
+ display: "block",
1323
+ margin: "0 auto",
1324
+ maxWidth: "100%",
1325
+ maxHeight: "75vh",
1326
+ objectFit: "contain"
1327
+ }
1328
+ }
1329
+ )
1330
+ }
1331
+ )
1332
+ ] });
1333
+ }
1334
+
1335
+ // admin/Gallery.tsx
1336
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1135
1337
  var Columns = import_styled_components.default.div`
1136
- column-count: ${({ $columns }) => $columns}; column-gap: 12px;
1137
- > * { break-inside: avoid; -webkit-column-break-inside: avoid; margin-bottom: 12px; }
1338
+ column-count: ${({ $columns }) => $columns};
1339
+ column-gap: 12px;
1340
+ > * {
1341
+ break-inside: avoid;
1342
+ -webkit-column-break-inside: avoid;
1343
+ margin-bottom: 12px;
1344
+ }
1138
1345
  `;
1139
1346
  var Tile = import_styled_components.default.button`
1140
- display: flex; flex-direction: column; gap: 8px; text-align: left; width: 100%;
1141
- padding: 8px; border: 1px solid ${({ theme }) => theme.colors.neutral200};
1142
- border-radius: 4px; background: ${({ theme }) => theme.colors.neutral0}; cursor: pointer;
1143
- &:hover { border-color: ${({ theme }) => theme.colors.primary600}; }
1144
- &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: 2px; }
1347
+ display: flex;
1348
+ flex-direction: column;
1349
+ gap: 8px;
1350
+ text-align: left;
1351
+ width: 100%;
1352
+ padding: 8px;
1353
+ border: 1px solid ${({ theme }) => theme.colors.neutral200};
1354
+ border-radius: 4px;
1355
+ background: ${({ theme }) => theme.colors.neutral0};
1356
+ cursor: pointer;
1357
+ &:hover {
1358
+ border-color: ${({ theme }) => theme.colors.primary600};
1359
+ }
1360
+ &:focus-visible {
1361
+ outline: 2px solid ${({ theme }) => theme.colors.primary600};
1362
+ outline-offset: 2px;
1363
+ }
1364
+ `;
1365
+ var Clamp = (0, import_styled_components.default)(import_design_system.Typography)`
1366
+ display: -webkit-box;
1367
+ -webkit-line-clamp: 2;
1368
+ -webkit-box-orient: vertical;
1369
+ overflow: hidden;
1145
1370
  `;
1146
- var Clamp = (0, import_styled_components.default)(import_design_system.Typography)` display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; `;
1147
1371
  var Slider = import_styled_components.default.input`
1148
- appearance: none; -webkit-appearance: none; width: 8rem; height: 0.4rem; border-radius: 0.4rem; cursor: pointer;
1372
+ appearance: none;
1373
+ -webkit-appearance: none;
1374
+ width: 8rem;
1375
+ height: 0.4rem;
1376
+ border-radius: 0.4rem;
1377
+ cursor: pointer;
1149
1378
  background: ${({ theme, $percent }) => `linear-gradient(to right, ${theme.colors.primary600} ${$percent}%, ${theme.colors.neutral200} ${$percent}%)`};
1150
- &::-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; }
1151
- &::-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; }
1152
- &:focus-visible { outline: 0.2rem solid ${({ theme }) => theme.colors.primary600}; outline-offset: 0.2rem; }
1379
+ &::-webkit-slider-thumb {
1380
+ appearance: none;
1381
+ -webkit-appearance: none;
1382
+ width: 1.6rem;
1383
+ height: 1.6rem;
1384
+ border-radius: 50%;
1385
+ background: ${({ theme }) => theme.colors.neutral0};
1386
+ border: 0.2rem solid ${({ theme }) => theme.colors.primary600};
1387
+ cursor: pointer;
1388
+ }
1389
+ &::-moz-range-thumb {
1390
+ width: 1.6rem;
1391
+ height: 1.6rem;
1392
+ border-radius: 50%;
1393
+ background: ${({ theme }) => theme.colors.neutral0};
1394
+ border: 0.2rem solid ${({ theme }) => theme.colors.primary600};
1395
+ cursor: pointer;
1396
+ }
1397
+ &:focus-visible {
1398
+ outline: 0.2rem solid ${({ theme }) => theme.colors.primary600};
1399
+ outline-offset: 0.2rem;
1400
+ }
1153
1401
  `;
1154
1402
  var COLUMNS = { key: "blockscene:columns", min: 1, max: 5, initial: 3 };
1155
1403
  var SHOW_FIELDS_KEY = "blockscene:show-fields";
@@ -1175,16 +1423,31 @@ var remember = (key, value) => {
1175
1423
  }
1176
1424
  };
1177
1425
  var Frame = import_styled_components.default.div`
1178
- width: 100%; overflow: hidden; border-radius: 4px; line-height: 0;
1426
+ width: 100%;
1427
+ overflow: hidden;
1428
+ border-radius: 4px;
1429
+ line-height: 0;
1179
1430
  aspect-ratio: ${({ $fixed }) => $fixed ? "16 / 9" : "auto"};
1180
1431
  background: ${({ theme }) => theme.colors.neutral100};
1181
- img { width: 100%; height: auto; display: block; }
1432
+ img {
1433
+ width: 100%;
1434
+ height: auto;
1435
+ display: block;
1436
+ }
1182
1437
  `;
1183
- function Thumb({ candidates, template, palette, onResolved, noPreview, eager }) {
1438
+ function Thumb({
1439
+ candidates,
1440
+ template,
1441
+ palette,
1442
+ onResolved,
1443
+ noPreview,
1444
+ eager,
1445
+ blank
1446
+ }) {
1184
1447
  const key = candidates.join("|");
1185
- const [state, setState] = React.useState({ key, index: 0 });
1448
+ const [state, setState] = React2.useState({ key, index: 0 });
1186
1449
  const index = state.key === key ? state.index : 0;
1187
- const resolved = React.useRef("");
1450
+ const resolved = React2.useRef("");
1188
1451
  const report = (value) => {
1189
1452
  const tag = `${key}:${value}`;
1190
1453
  if (resolved.current !== tag) {
@@ -1192,11 +1455,19 @@ function Thumb({ candidates, template, palette, onResolved, noPreview, eager })
1192
1455
  onResolved?.(value);
1193
1456
  }
1194
1457
  };
1195
- React.useEffect(() => {
1458
+ React2.useEffect(() => {
1196
1459
  if (index >= candidates.length) report(-1);
1197
1460
  });
1198
- 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 }) });
1199
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1461
+ if (index >= candidates.length)
1462
+ return blank ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1463
+ Wireframe,
1464
+ {
1465
+ template,
1466
+ palette,
1467
+ noPreview
1468
+ }
1469
+ ) });
1470
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1200
1471
  "img",
1201
1472
  {
1202
1473
  src: candidates[index],
@@ -1210,25 +1481,68 @@ function Thumb({ candidates, template, palette, onResolved, noPreview, eager })
1210
1481
  }
1211
1482
  function Card({ entry, palette, showFields, onSelect }) {
1212
1483
  const t = useMessages();
1213
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Tile, { type: "button", onClick: onSelect, title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
1214
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview }),
1215
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
1216
- entry.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
1217
- showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral500", style: { fontStyle: "italic" }, "data-testid": "block-fields", children: entry.fields.map((f) => `${f.name} (${f.type})`).join(", ") })
1218
- ] });
1484
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1485
+ Tile,
1486
+ {
1487
+ type: "button",
1488
+ onClick: onSelect,
1489
+ title: entry.uid,
1490
+ "data-testid": `blockscene-${entry.uid}`,
1491
+ children: [
1492
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1493
+ Thumb,
1494
+ {
1495
+ candidates: entry.candidates,
1496
+ template: entry.template,
1497
+ palette,
1498
+ noPreview: t.noPreview
1499
+ }
1500
+ ),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1502
+ import_design_system.Typography,
1503
+ {
1504
+ variant: "pi",
1505
+ fontWeight: "bold",
1506
+ textColor: "neutral800",
1507
+ ellipsis: true,
1508
+ children: entry.label
1509
+ }
1510
+ ),
1511
+ entry.description && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
1512
+ showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1513
+ import_design_system.Typography,
1514
+ {
1515
+ variant: "pi",
1516
+ textColor: "neutral500",
1517
+ style: { fontStyle: "italic" },
1518
+ "data-testid": "block-fields",
1519
+ children: entry.fields.map((f) => `${f.name} (${f.type})`).join(", ")
1520
+ }
1521
+ )
1522
+ ]
1523
+ }
1524
+ );
1219
1525
  }
1220
- function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, controlled }) {
1526
+ function ZoneGallery({
1527
+ zone,
1528
+ components,
1529
+ add,
1530
+ Modal: Modal2,
1531
+ Toggle,
1532
+ get,
1533
+ controlled
1534
+ }) {
1221
1535
  const t = useMessages();
1222
- const [ownOpen, setOwnOpen] = React.useState(false);
1536
+ const [ownOpen, setOwnOpen] = React2.useState(false);
1223
1537
  const open = controlled ? controlled.open : ownOpen;
1224
1538
  const setOpen = controlled ? controlled.onOpenChange : setOwnOpen;
1225
- const [query, setQuery] = React.useState("");
1226
- const [category, setCategory] = React.useState("all");
1227
- const [showFields, setShowFields] = React.useState(readShowFields);
1228
- const [columns, setColumns] = React.useState(readColumns);
1229
- const [config, setConfig] = React.useState(null);
1230
- const [error, setError] = React.useState("");
1231
- React.useEffect(() => {
1539
+ const [query, setQuery] = React2.useState("");
1540
+ const [category, setCategory] = React2.useState("all");
1541
+ const [showFields, setShowFields] = React2.useState(readShowFields);
1542
+ const [columns, setColumns] = React2.useState(readColumns);
1543
+ const [config, setConfig] = React2.useState(null);
1544
+ const [error, setError] = React2.useState("");
1545
+ React2.useEffect(() => {
1232
1546
  if (controlled) return;
1233
1547
  const onClick = (event) => {
1234
1548
  const button = event.target?.closest?.("button");
@@ -1240,7 +1554,7 @@ function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, contro
1240
1554
  document.addEventListener("click", onClick, true);
1241
1555
  return () => document.removeEventListener("click", onClick, true);
1242
1556
  }, [controlled, zone.name, zone.label]);
1243
- React.useEffect(() => {
1557
+ React2.useEffect(() => {
1244
1558
  if (!open) return;
1245
1559
  let active = true;
1246
1560
  setError("");
@@ -1256,7 +1570,10 @@ function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, contro
1256
1570
  }, [open, get, t.failed]);
1257
1571
  const entries = config ? entriesFor(zone, components, config, query, category) : [];
1258
1572
  const categories = config ? categoriesFor(zone, components, config) : [];
1259
- const total = categories.reduce((sum, [, count]) => sum + count, 0);
1573
+ const total = categories.reduce(
1574
+ (sum, [, count]) => sum + count,
1575
+ 0
1576
+ );
1260
1577
  const filtering = query.trim() !== "" || category !== "all";
1261
1578
  const reset = () => {
1262
1579
  setQuery("");
@@ -1280,21 +1597,41 @@ function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, contro
1280
1597
  setShowFields(value);
1281
1598
  remember(SHOW_FIELDS_KEY, String(value));
1282
1599
  };
1283
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1600
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1284
1601
  Modal2,
1285
1602
  {
1286
1603
  open,
1287
1604
  onOpenChange: setOpen,
1288
1605
  title: t.gallery,
1289
- 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: [
1290
- t.add,
1291
- ": ",
1292
- zone.name
1293
- ] }),
1294
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
1295
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
1296
- /* @__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 }) }),
1297
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1606
+ trigger: controlled ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1607
+ import_design_system.Button,
1608
+ {
1609
+ variant: "secondary",
1610
+ fullWidth: true,
1611
+ onClick: () => setOpen(true),
1612
+ "data-testid": `open-gallery-${zone.name}`,
1613
+ children: [
1614
+ t.add,
1615
+ ": ",
1616
+ zone.name
1617
+ ]
1618
+ }
1619
+ ),
1620
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
1621
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
1622
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1623
+ import_design_system.Typography,
1624
+ {
1625
+ variant: "omega",
1626
+ fontWeight: "bold",
1627
+ textColor: "neutral800",
1628
+ style: { whiteSpace: "nowrap" },
1629
+ "data-testid": `block-count-${zone.name}`,
1630
+ "aria-live": "polite",
1631
+ children: filtering ? t.f("countFiltered", { shown: entries.length, total }) : t.f("countAll", { count: total })
1632
+ }
1633
+ ),
1634
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1298
1635
  import_design_system.Searchbar,
1299
1636
  {
1300
1637
  name: `block-search-${zone.name}`,
@@ -1306,14 +1643,54 @@ function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, contro
1306
1643
  children: t.search
1307
1644
  }
1308
1645
  ) }),
1309
- 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: [
1310
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.SingleSelectOption, { value: "all", children: t.allCategories }),
1311
- categories.map(([name, count]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.SingleSelectOption, { value: name, children: `${name} (${count})` }, name))
1312
- ] }) }),
1313
- Toggle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Toggle, { name: `block-fields-${zone.name}`, label: t.showFields, hint: t.showFieldsHint, value: showFields, onChange: changeShowFields }),
1314
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 2, alignItems: "center", children: [
1315
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
1316
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1646
+ categories.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1647
+ import_design_system.Box,
1648
+ {
1649
+ style: { width: "14rem" },
1650
+ "data-testid": `block-category-${zone.name}`,
1651
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1652
+ import_design_system.SingleSelect,
1653
+ {
1654
+ "aria-label": t.filterCategory,
1655
+ size: "S",
1656
+ value: category,
1657
+ onChange: (value) => setCategory(String(value)),
1658
+ children: [
1659
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.SingleSelectOption, { value: "all", children: t.allCategories }),
1660
+ categories.map(([name, count]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1661
+ import_design_system.SingleSelectOption,
1662
+ {
1663
+ value: name,
1664
+ children: `${name} (${count})`
1665
+ },
1666
+ name
1667
+ ))
1668
+ ]
1669
+ }
1670
+ )
1671
+ }
1672
+ ),
1673
+ Toggle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1674
+ Toggle,
1675
+ {
1676
+ name: `block-fields-${zone.name}`,
1677
+ label: t.showFields,
1678
+ hint: t.showFieldsHint,
1679
+ value: showFields,
1680
+ onChange: changeShowFields
1681
+ }
1682
+ ),
1683
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { gap: 2, alignItems: "center", children: [
1684
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1685
+ import_design_system.Typography,
1686
+ {
1687
+ variant: "pi",
1688
+ textColor: "neutral600",
1689
+ id: `block-columns-${zone.name}`,
1690
+ children: t.columns
1691
+ }
1692
+ ),
1693
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1317
1694
  Slider,
1318
1695
  {
1319
1696
  type: "range",
@@ -1326,16 +1703,52 @@ function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, contro
1326
1703
  onChange: (e) => changeColumns(Number(e.target.value))
1327
1704
  }
1328
1705
  ),
1329
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", children: columns })
1706
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", children: columns })
1330
1707
  ] })
1331
1708
  ] }),
1332
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
1333
- 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: [
1334
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${name}`, children: `${name} (${items.length})` }),
1335
- /* @__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)) })
1336
- ] }, name)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", children: [
1337
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { children: t.empty }),
1338
- filtering && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
1709
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
1710
+ 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)(
1711
+ import_design_system.Flex,
1712
+ {
1713
+ direction: "column",
1714
+ alignItems: "stretch",
1715
+ gap: 4,
1716
+ style: { overflowY: "auto", maxHeight: "60vh", padding: "4px" },
1717
+ children: groupEntries(entries).map(
1718
+ ({ category: name, entries: items }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1719
+ import_design_system.Flex,
1720
+ {
1721
+ direction: "column",
1722
+ alignItems: "stretch",
1723
+ gap: 2,
1724
+ children: [
1725
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1726
+ import_design_system.Typography,
1727
+ {
1728
+ variant: "sigma",
1729
+ textColor: "neutral600",
1730
+ "data-testid": `block-group-${name}`,
1731
+ children: `${name} (${items.length})`
1732
+ }
1733
+ ),
1734
+ /* @__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)(
1735
+ Card,
1736
+ {
1737
+ entry,
1738
+ palette: config.palette,
1739
+ showFields,
1740
+ onSelect: () => select(entry.uid)
1741
+ }
1742
+ ) }, entry.uid)) })
1743
+ ]
1744
+ },
1745
+ name
1746
+ )
1747
+ )
1748
+ }
1749
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", children: [
1750
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { children: t.empty }),
1751
+ filtering && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
1339
1752
  ] })
1340
1753
  ] })
1341
1754
  }
@@ -1349,13 +1762,19 @@ var storage = () => {
1349
1762
  }
1350
1763
  };
1351
1764
  var memoryBase = () => `${window.location.origin}${window.location.pathname.split("/content-manager")[0]}`;
1352
- function useInitialAccordions({ zones, editor, docKey, contentType, userId }) {
1353
- const applied = React.useRef("");
1354
- const user = React.useRef(userId);
1765
+ function useInitialAccordions({
1766
+ zones,
1767
+ editor,
1768
+ docKey,
1769
+ contentType,
1770
+ userId
1771
+ }) {
1772
+ const applied = React2.useRef("");
1773
+ const user = React2.useRef(userId);
1355
1774
  user.current = userId;
1356
- const latest = React.useRef(zones);
1775
+ const latest = React2.useRef(zones);
1357
1776
  latest.current = zones;
1358
- React.useEffect(() => {
1777
+ React2.useEffect(() => {
1359
1778
  if (!editor?.enabled || !docKey || applied.current === docKey) return;
1360
1779
  if (applied.current.startsWith(`${contentType}:new`) && docKey.startsWith(`${contentType}:`)) {
1361
1780
  applied.current = docKey;
@@ -1364,7 +1783,10 @@ function useInitialAccordions({ zones, editor, docKey, contentType, userId }) {
1364
1783
  applied.current = docKey;
1365
1784
  let tries = 0;
1366
1785
  const cancel = (event) => {
1367
- if (event.target?.closest?.('button[aria-expanded], [data-testid^="block-accordion-controls-"]')) stop();
1786
+ if (event.target?.closest?.(
1787
+ 'button[aria-expanded], [data-testid^="block-accordion-controls-"]'
1788
+ ))
1789
+ stop();
1368
1790
  };
1369
1791
  const stop = () => {
1370
1792
  clearInterval(timer);
@@ -1382,8 +1804,17 @@ function useInitialAccordions({ zones, editor, docKey, contentType, userId }) {
1382
1804
  for (const zone of pending) {
1383
1805
  const list = findZoneList(zone.label);
1384
1806
  if (!list) continue;
1385
- const key = memoryKey({ base: memoryBase(), userId: user.current, contentType, zone: zone.name });
1386
- setAll(list, initialState(editor, readMemory(storage(), key)) === "open", import_react_dom.unstable_batchedUpdates);
1807
+ const key = memoryKey({
1808
+ base: memoryBase(),
1809
+ userId: user.current,
1810
+ contentType,
1811
+ zone: zone.name
1812
+ });
1813
+ setAll(
1814
+ list,
1815
+ initialState(editor, readMemory(storage(), key)) === "open",
1816
+ import_react_dom2.unstable_batchedUpdates
1817
+ );
1387
1818
  }
1388
1819
  }, 200);
1389
1820
  return stop;
@@ -1394,27 +1825,84 @@ function ZoneControls({ zone, editor, contentType, userId }) {
1394
1825
  if (!zone.count || !(editor.showOpenAll || editor.showCloseAll)) return null;
1395
1826
  const apply = (open) => {
1396
1827
  const list = findZoneList(zone.label);
1397
- if (list) setAll(list, open, import_react_dom.unstable_batchedUpdates);
1398
- writeMemory(storage(), memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }), open ? "open" : "closed");
1828
+ if (list) setAll(list, open, import_react_dom2.unstable_batchedUpdates);
1829
+ writeMemory(
1830
+ storage(),
1831
+ memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }),
1832
+ open ? "open" : "closed"
1833
+ );
1399
1834
  };
1400
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 2, wrap: "wrap", "data-testid": `block-accordion-controls-${zone.name}`, children: [
1401
- editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { type: "button", variant: "tertiary", size: "S", onClick: () => apply(true), children: t.openAll }),
1402
- editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { type: "button", variant: "tertiary", size: "S", onClick: () => apply(false), children: t.closeAll })
1403
- ] });
1835
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1836
+ import_design_system.Flex,
1837
+ {
1838
+ gap: 2,
1839
+ wrap: "wrap",
1840
+ "data-testid": `block-accordion-controls-${zone.name}`,
1841
+ children: [
1842
+ editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1843
+ import_design_system.Button,
1844
+ {
1845
+ type: "button",
1846
+ variant: "tertiary",
1847
+ size: "S",
1848
+ onClick: () => apply(true),
1849
+ children: t.openAll
1850
+ }
1851
+ ),
1852
+ editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1853
+ import_design_system.Button,
1854
+ {
1855
+ type: "button",
1856
+ variant: "tertiary",
1857
+ size: "S",
1858
+ onClick: () => apply(false),
1859
+ children: t.closeAll
1860
+ }
1861
+ )
1862
+ ]
1863
+ }
1864
+ );
1404
1865
  }
1405
- function Gallery({ zones, editor, docKey, contentType, userId, ...props }) {
1866
+ function Gallery({
1867
+ zones,
1868
+ editor,
1869
+ docKey,
1870
+ contentType,
1871
+ userId,
1872
+ catalog,
1873
+ ...props
1874
+ }) {
1406
1875
  useInitialAccordions({ zones, editor, docKey, contentType, userId });
1407
- 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: [
1408
- !zone.full && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoneGallery, { zone, ...props }),
1409
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoneControls, { zone, editor, contentType, userId })
1410
- ] }, zone.name)) });
1876
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
1877
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1878
+ RowPreviews,
1879
+ {
1880
+ zones,
1881
+ components: props.components,
1882
+ catalog,
1883
+ Modal: props.Modal
1884
+ }
1885
+ ),
1886
+ zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
1887
+ !zone.full && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ZoneGallery, { zone, ...props }),
1888
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1889
+ ZoneControls,
1890
+ {
1891
+ zone,
1892
+ editor,
1893
+ contentType,
1894
+ userId
1895
+ }
1896
+ )
1897
+ ] }, zone.name))
1898
+ ] });
1411
1899
  }
1412
1900
 
1413
1901
  // admin/Settings.tsx
1414
- var React2 = __toESM(require("react"));
1902
+ var React3 = __toESM(require("react"));
1415
1903
  var import_design_system2 = require("@strapi/design-system");
1416
1904
  var import_styled_components2 = __toESM(require("styled-components"));
1417
- var import_jsx_runtime3 = require("react/jsx-runtime");
1905
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1418
1906
  var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
1419
1907
  var Grid = import_styled_components2.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
1420
1908
  var Card2 = import_styled_components2.default.div`
@@ -1427,8 +1915,8 @@ var Bar = import_styled_components2.default.div`
1427
1915
  box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
1428
1916
  `;
1429
1917
  function useMainRect(anchor) {
1430
- const [rect, setRect] = React2.useState({ left: 0, width: 0 });
1431
- React2.useEffect(() => {
1918
+ const [rect, setRect] = React3.useState({ left: 0, width: 0 });
1919
+ React3.useEffect(() => {
1432
1920
  const read = () => {
1433
1921
  let host = document.getElementById("main-content");
1434
1922
  for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
@@ -1445,11 +1933,11 @@ var Swatches = import_styled_components2.default.div` display: grid; grid-templa
1445
1933
  var Label = import_styled_components2.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
1446
1934
  function ColorField({ name, label, value, onChange, disabled }) {
1447
1935
  const valid = COLOR2.test(value);
1448
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Label, { children: [
1449
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
1450
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 2, children: [
1451
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "color", "aria-label": label, value: valid ? value : "#000000", disabled, onChange: (e) => onChange(e.target.value.toUpperCase()), style: { width: 40, height: 32, padding: 0, border: 0, background: "none" } }),
1452
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1936
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Label, { children: [
1937
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
1938
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { gap: 2, children: [
1939
+ /* @__PURE__ */ (0, import_jsx_runtime4.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" } }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1453
1941
  "input",
1454
1942
  {
1455
1943
  name,
@@ -1469,18 +1957,18 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1469
1957
  const t = useMessages();
1470
1958
  const { get, put } = useClient();
1471
1959
  const { canRead, canUpdate, isLoading } = usePermissions2();
1472
- const [data, setData] = React2.useState(null);
1473
- const [catalog, setCatalog] = React2.useState(null);
1474
- const [settings, setSettings] = React2.useState(null);
1475
- const [media, setMedia] = React2.useState({});
1476
- const [sources, setSources] = React2.useState({});
1477
- const [dirty, setDirty] = React2.useState(false);
1478
- const [saving, setSaving] = React2.useState(false);
1479
- const [status, setStatus] = React2.useState("");
1480
- const [failed, setFailed] = React2.useState(false);
1481
- const [filter, setFilter] = React2.useState("");
1482
- const [picking, setPicking] = React2.useState(null);
1483
- React2.useEffect(() => {
1960
+ const [data, setData] = React3.useState(null);
1961
+ const [catalog, setCatalog] = React3.useState(null);
1962
+ const [settings, setSettings] = React3.useState(null);
1963
+ const [media, setMedia] = React3.useState({});
1964
+ const [sources, setSources] = React3.useState({});
1965
+ const [dirty, setDirty] = React3.useState(false);
1966
+ const [saving, setSaving] = React3.useState(false);
1967
+ const [status, setStatus] = React3.useState("");
1968
+ const [failed, setFailed] = React3.useState(false);
1969
+ const [filter, setFilter] = React3.useState("");
1970
+ const [picking, setPicking] = React3.useState(null);
1971
+ React3.useEffect(() => {
1484
1972
  if (!canRead || isLoading) return;
1485
1973
  let active = true;
1486
1974
  Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
@@ -1528,35 +2016,35 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1528
2016
  return index === 0 && manual ? t.manual : t.automatic;
1529
2017
  };
1530
2018
  const ready = !isLoading && canRead && !failed && settings && catalog;
1531
- const header = React2.useRef(null);
1532
- const [floating, setFloating] = React2.useState(false);
2019
+ const header = React3.useRef(null);
2020
+ const [floating, setFloating] = React3.useState(false);
1533
2021
  const main = useMainRect(header);
1534
- React2.useEffect(() => {
2022
+ React3.useEffect(() => {
1535
2023
  const el = header.current;
1536
2024
  if (!el || typeof IntersectionObserver === "undefined") return;
1537
2025
  const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
1538
2026
  observer.observe(el);
1539
2027
  return () => observer.disconnect();
1540
2028
  }, [ready]);
1541
- const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
1542
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
1543
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
2029
+ const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
2030
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
2031
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
1544
2032
  ] });
1545
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
1546
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
1547
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
2033
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
2034
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
2035
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
1548
2036
  controls("")
1549
2037
  ] }) }),
1550
- floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
1551
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
2038
+ floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
2039
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
1552
2040
  controls("-floating")
1553
2041
  ] }) }),
1554
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { textColor: "neutral600", children: t.settingsIntro }),
1555
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1556
- data.disabled && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
1557
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
1558
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.palette }),
1559
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2042
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { textColor: "neutral600", children: t.settingsIntro }),
2043
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2044
+ data.disabled && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
2045
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2046
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.palette }),
2047
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1560
2048
  ColorField,
1561
2049
  {
1562
2050
  name: `palette-${key}`,
@@ -1570,33 +2058,33 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1570
2058
  },
1571
2059
  key
1572
2060
  )) }),
1573
- invalid && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
1574
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
1575
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", gap: 1, children: [
1576
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wireframe, { template, palette: settings.palette }) }),
1577
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
2061
+ invalid && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
2062
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
2063
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { direction: "column", gap: 1, children: [
2064
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Wireframe, { template, palette: settings.palette }) }),
2065
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
1578
2066
  ] }, template)) }),
1579
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
2067
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
1580
2068
  s.palette = { ...DEFAULT_PALETTE };
1581
2069
  return s;
1582
2070
  }), children: t.resetPalette }) })
1583
2071
  ] }) }),
1584
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
1585
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.editor }),
1586
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2072
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2073
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.editor }),
2074
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1587
2075
  s.editor.enabled = v;
1588
2076
  return s;
1589
2077
  }) }),
1590
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
1591
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2078
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
2079
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1592
2080
  s.editor.showOpenAll = v;
1593
2081
  return s;
1594
2082
  }) }),
1595
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2083
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1596
2084
  s.editor.showCloseAll = v;
1597
2085
  return s;
1598
2086
  }) }),
1599
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2087
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1600
2088
  SelectField2,
1601
2089
  {
1602
2090
  name: "editor-initialState",
@@ -1610,9 +2098,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1610
2098
  })
1611
2099
  }
1612
2100
  ),
1613
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
1614
- previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1615
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2101
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
2102
+ previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2103
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1616
2104
  TextField,
1617
2105
  {
1618
2106
  name: "editor-previewUrl",
@@ -1626,8 +2114,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1626
2114
  })
1627
2115
  }
1628
2116
  ),
1629
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
1630
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2117
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
2118
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1631
2119
  SelectField2,
1632
2120
  {
1633
2121
  name: "editor-previewMode",
@@ -1641,26 +2129,26 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1641
2129
  })
1642
2130
  }
1643
2131
  ),
1644
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
1645
- data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1646
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
2132
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
2133
+ data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2134
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
1647
2135
  s.editor.blockPreviewInForm = v;
1648
2136
  return s;
1649
2137
  }) }),
1650
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
2138
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
1651
2139
  ] })
1652
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
2140
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
1653
2141
  ] }) }),
1654
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
1655
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.components }),
1656
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
1657
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
1658
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
2142
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
2143
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.components }),
2144
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
2145
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
2146
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
1659
2147
  const entry = settings.components[component.uid] || {};
1660
2148
  const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
1661
2149
  const candidates = candidatesFor(component.uid, meta, catalog);
1662
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
1663
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2150
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
2151
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1664
2152
  Thumb,
1665
2153
  {
1666
2154
  candidates,
@@ -1671,23 +2159,23 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1671
2159
  onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
1672
2160
  }
1673
2161
  ),
1674
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
1675
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
1676
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: [
2162
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
2163
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
2164
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: [
1677
2165
  component.uid,
1678
2166
  " \xB7 ",
1679
2167
  component.category
1680
2168
  ] }),
1681
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
2169
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
1682
2170
  t.source,
1683
2171
  ": ",
1684
2172
  sourceOf(component.uid, Boolean(meta.manualImage)),
1685
2173
  meta.manualName ? ` (${meta.manualName})` : ""
1686
2174
  ] }),
1687
- meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
1688
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 2, wrap: "wrap", children: [
1689
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
1690
- entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
2175
+ meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
2176
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system2.Flex, { gap: 2, wrap: "wrap", children: [
2177
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
2178
+ entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
1691
2179
  update((s) => {
1692
2180
  delete s.components[component.uid]?.mediaId;
1693
2181
  if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
@@ -1700,7 +2188,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1700
2188
  });
1701
2189
  }, children: t.useAutomatic })
1702
2190
  ] }),
1703
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2191
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1704
2192
  SelectField2,
1705
2193
  {
1706
2194
  name: `template-${component.uid}`,
@@ -1718,7 +2206,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1718
2206
  ] }, component.uid);
1719
2207
  }) })
1720
2208
  ] }) }),
1721
- picking && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
2209
+ picking && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
1722
2210
  const uid = picking;
1723
2211
  setPicking(null);
1724
2212
  if (!asset?.id) return;
@@ -1731,24 +2219,26 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
1731
2219
  ] })
1732
2220
  ] }) });
1733
2221
  }
1734
- function register(app, Component) {
2222
+ function register(app, Component, to) {
1735
2223
  app.createSettingSection(
1736
2224
  { id: "blockscene", intlLabel: { id: "blockscene.title", defaultMessage: "Blockscene" } },
1737
2225
  [{
1738
2226
  id: "blockscene-settings",
1739
- to: "/settings/blockscene",
2227
+ to,
1740
2228
  intlLabel: { id: "blockscene.settings", defaultMessage: "Gallery" },
1741
- Component: async () => Component,
2229
+ // Module shape: older Strapi 4 (e.g. 4.11) only reads `.default` from the loader result.
2230
+ // Not an `async` function: Strapi 5 warns on AsyncFunction loaders.
2231
+ Component: () => Promise.resolve({ default: Component }),
1742
2232
  permissions: permissions.read
1743
2233
  }]
1744
2234
  );
1745
2235
  }
1746
2236
 
1747
2237
  // admin/catalog.ts
1748
- var React3 = __toESM(require("react"));
2238
+ var React4 = __toESM(require("react"));
1749
2239
  function useCatalog(get) {
1750
- const [catalog, setCatalog] = React3.useState(null);
1751
- React3.useEffect(() => {
2240
+ const [catalog, setCatalog] = React4.useState(null);
2241
+ React4.useEffect(() => {
1752
2242
  let active = true;
1753
2243
  get("/blockscene/catalog").then(({ data }) => {
1754
2244
  if (active) setCatalog(data);
@@ -1763,14 +2253,14 @@ function useCatalog(get) {
1763
2253
  }
1764
2254
 
1765
2255
  // admin/strapi4.tsx
1766
- var import_jsx_runtime4 = require("react/jsx-runtime");
2256
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1767
2257
  function Modal({ open, onOpenChange, trigger, title, children }) {
1768
- const id = React4.useId();
1769
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2258
+ const id = React5.useId();
2259
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1770
2260
  trigger,
1771
- open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, children: [
1772
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { id, variant: "beta", children: title }) }),
1773
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.ModalBody, { children })
2261
+ open && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system3.ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, children: [
2262
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Typography, { id, variant: "beta", children: title }) }),
2263
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.ModalBody, { children })
1774
2264
  ] })
1775
2265
  ] });
1776
2266
  }
@@ -1781,17 +2271,37 @@ function Picker() {
1781
2271
  const components = c.allLayoutData?.components || {};
1782
2272
  const schema = c.layout || c.allLayoutData?.contentType;
1783
2273
  const allowed = (c.isCreatingEntry ? c.createActionAllowedFields : c.updateActionAllowedFields) || [];
1784
- const zones = editableZones(schema, c.modifiedData, (name) => allowed.includes(name) && schema?.metadatas?.[name]?.edit?.editable !== false, !c.addComponentToDynamicZone).map((zone) => ({ ...zone, label: schema?.metadatas?.[zone.name]?.edit?.label || zone.name }));
2274
+ const zones = editableZones(
2275
+ schema,
2276
+ c.modifiedData,
2277
+ (name) => allowed.includes(name) && schema?.metadatas?.[name]?.edit?.editable !== false,
2278
+ !c.addComponentToDynamicZone
2279
+ ).map((zone) => ({
2280
+ ...zone,
2281
+ label: schema?.metadatas?.[zone.name]?.edit?.label || zone.name
2282
+ }));
1785
2283
  const add = (zone, uid) => {
1786
2284
  const close = catalog?.groups?.[uid];
1787
- if (!canInsert(zone, uid, c.modifiedData, components, close ? 2 : 1) || close && !zone.components.includes(close)) return false;
1788
- c.addComponentToDynamicZone(zone.name, components[uid], components, Boolean(c.formErrors?.[zone.name]));
1789
- if (close) c.addComponentToDynamicZone(zone.name, components[close], components, Boolean(c.formErrors?.[zone.name]));
2285
+ if (!canInsert(zone, uid, c.modifiedData, components, close ? 2 : 1) || close && !zone.components.includes(close))
2286
+ return false;
2287
+ c.addComponentToDynamicZone(
2288
+ zone.name,
2289
+ components[uid],
2290
+ components,
2291
+ Boolean(c.formErrors?.[zone.name])
2292
+ );
2293
+ if (close)
2294
+ c.addComponentToDynamicZone(
2295
+ zone.name,
2296
+ components[close],
2297
+ components,
2298
+ Boolean(c.formErrors?.[zone.name])
2299
+ );
1790
2300
  return true;
1791
2301
  };
1792
2302
  if (!catalog?.editor?.enabled) return null;
1793
2303
  const docKey = `${c.slug}:${c.isCreatingEntry ? "new" : c.initialData?.id}:${c.initialData?.locale || ""}`;
1794
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2304
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1795
2305
  Gallery,
1796
2306
  {
1797
2307
  zones,
@@ -1801,17 +2311,44 @@ function Picker() {
1801
2311
  Toggle: ToggleField,
1802
2312
  get,
1803
2313
  editor: catalog.editor,
2314
+ catalog,
1804
2315
  docKey,
1805
2316
  contentType: c.slug,
1806
2317
  userId: import_helper_plugin.auth.getUserInfo?.()?.id
1807
2318
  }
1808
2319
  );
1809
2320
  }
1810
- var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { gap: 3, children: [
1811
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Switch, { name, "aria-label": label, selected: Boolean(value), disabled, onChange: () => onChange(!value) }),
1812
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { children: label })
2321
+ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system3.Flex, { gap: 3, children: [
2322
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2323
+ import_design_system3.Switch,
2324
+ {
2325
+ name,
2326
+ "aria-label": label,
2327
+ selected: Boolean(value),
2328
+ disabled,
2329
+ onChange: () => onChange(!value)
2330
+ }
2331
+ ),
2332
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.Typography, { children: label })
1813
2333
  ] });
1814
- var SelectField = ({ name, label, value, onChange, disabled, options }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.SingleSelect, { name, label, value, disabled, onChange: (v) => onChange(String(v)), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.SingleSelectOption, { value: o.value, children: o.label }, o.value)) });
2334
+ var SelectField = ({
2335
+ name,
2336
+ label,
2337
+ value,
2338
+ onChange,
2339
+ disabled,
2340
+ options
2341
+ }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2342
+ import_design_system3.SingleSelect,
2343
+ {
2344
+ name,
2345
+ label,
2346
+ value,
2347
+ disabled,
2348
+ onChange: (v) => onChange(String(v)),
2349
+ children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system3.SingleSelectOption, { value: o.value, children: o.label }, o.value))
2350
+ }
2351
+ );
1815
2352
  function MediaPicker({ onClose, onSelect }) {
1816
2353
  const { components } = (0, import_helper_plugin.useLibrary)();
1817
2354
  const Dialog = components?.["media-library"];
@@ -1819,20 +2356,44 @@ function MediaPicker({ onClose, onSelect }) {
1819
2356
  onClose();
1820
2357
  return null;
1821
2358
  }
1822
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog, { onClose, allowedTypes: ["images"], onSelectAssets: (assets) => onSelect(assets?.[0]) });
2359
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2360
+ Dialog,
2361
+ {
2362
+ onClose,
2363
+ allowedTypes: ["images"],
2364
+ onSelectAssets: (assets) => onSelect(assets?.[0])
2365
+ }
2366
+ );
1823
2367
  }
1824
2368
  function usePermissions() {
1825
2369
  const { allowedActions, isLoading } = (0, import_helper_plugin.useRBAC)(permissions);
1826
- return { canRead: allowedActions.canRead, canUpdate: allowedActions.canUpdate, isLoading };
2370
+ return {
2371
+ canRead: allowedActions.canRead,
2372
+ canUpdate: allowedActions.canUpdate,
2373
+ isLoading
2374
+ };
1827
2375
  }
1828
- var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Settings, { useClient: import_helper_plugin.useFetchClient, usePermissions, MediaPicker, ToggleField, SelectField, previewSupported: false });
2376
+ var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2377
+ Settings,
2378
+ {
2379
+ useClient: import_helper_plugin.useFetchClient,
2380
+ usePermissions,
2381
+ MediaPicker,
2382
+ ToggleField,
2383
+ SelectField,
2384
+ previewSupported: false
2385
+ }
2386
+ );
1829
2387
  var strapi4_default = {
1830
2388
  register(app) {
1831
- register(app, SettingsPage);
2389
+ register(app, SettingsPage, "/settings/blockscene");
1832
2390
  app.registerPlugin({ id: "blockscene", name: "Blockscene" });
1833
2391
  },
1834
2392
  registerTrads,
1835
2393
  bootstrap(app) {
1836
- app.injectContentManagerComponent("editView", "right-links", { name: "blockscene", Component: Picker });
2394
+ app.injectContentManagerComponent("editView", "right-links", {
2395
+ name: "blockscene",
2396
+ Component: Picker
2397
+ });
1837
2398
  }
1838
2399
  };