@aduptive/strapi-blockscene 1.0.0-alpha.9 → 2.0.0-alpha.10

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.mjs CHANGED
@@ -143,8 +143,8 @@ var require_groups = __commonJS({
143
143
  }
144
144
  function layoutColumns2(row, layout, schema) {
145
145
  const max = layout.maxColumns || MAX_COLUMNS;
146
- const read2 = (name) => Math.min(max, parseColumns(row?.[name]) ?? parseColumns(schema?.attributes?.[name]?.default) ?? 1);
147
- return { desktop: read2(layout.columnsField), mobile: layout.mobileColumnsField ? read2(layout.mobileColumnsField) : null };
146
+ const read3 = (name) => Math.min(max, parseColumns(row?.[name]) ?? parseColumns(schema?.attributes?.[name]?.default) ?? 1);
147
+ return { desktop: read3(layout.columnsField), mobile: layout.mobileColumnsField ? read3(layout.mobileColumnsField) : null };
148
148
  }
149
149
  module.exports = {
150
150
  safeGroups: safeGroups2,
@@ -166,33 +166,129 @@ var require_groups = __commonJS({
166
166
  }
167
167
  });
168
168
 
169
- // admin/strapi4.tsx
170
- import * as React12 from "react";
169
+ // server/diff.js
170
+ var require_diff = __commonJS({
171
+ "server/diff.js"(exports, module) {
172
+ "use strict";
173
+ var IGNORED = ["id", "documentId", "locale", "localizations", "createdAt", "updatedAt", "publishedAt", "firstPublishedAt", "createdBy", "updatedBy", "strapi_stage", "strapi_assignee", "__temp_key__", "__pivot"];
174
+ var morph = (attr) => String(attr?.relation || "").toLowerCase().includes("morph");
175
+ var kept2 = (name, attr) => attr && !IGNORED.includes(name) && attr.type !== "password" && !(attr.type === "relation" && (morph(attr) || attr.visible === false));
176
+ var empty = (value) => value === null || value === void 0 || value === "";
177
+ function snapshotPopulate(uid, schemaOf, stack = []) {
178
+ const schema = schemaOf(uid);
179
+ if (!schema || stack.includes(uid)) return {};
180
+ const scalars = (component) => Object.entries(schemaOf(component)?.attributes || {}).filter(([name, attr]) => kept2(name, attr) && !["relation", "media", "component", "dynamiczone"].includes(attr.type)).map(([name]) => name);
181
+ const nested = (component) => ({ select: scalars(component).length ? scalars(component) : ["id"], populate: snapshotPopulate(component, schemaOf, [...stack, uid]) });
182
+ const out = {};
183
+ for (const [name, attr] of Object.entries(schema.attributes || {})) {
184
+ if (!kept2(name, attr)) continue;
185
+ if (attr.type === "relation") out[name] = { select: ["documentId", "locale"] };
186
+ else if (attr.type === "media") out[name] = { select: ["id"] };
187
+ else if (attr.type === "component") out[name] = nested(attr.component);
188
+ else if (attr.type === "dynamiczone") out[name] = { on: Object.fromEntries((attr.components || []).map((component) => [component, nested(component)])) };
189
+ }
190
+ return out;
191
+ }
192
+ function canonical2(data, schema, schemaOf, { relations = true } = {}, depth = 0) {
193
+ const out = {};
194
+ if (!data || typeof data !== "object" || depth > 20) return out;
195
+ const idOf = (file) => file && typeof file === "object" ? file.id : file;
196
+ const ref = (item) => item && typeof item === "object" && item.documentId ? { documentId: item.documentId, ...item.locale && { locale: item.locale } } : null;
197
+ for (const [name, attr] of Object.entries(schema?.attributes || {})) {
198
+ const value = data[name];
199
+ if (!kept2(name, attr) || empty(value)) continue;
200
+ if (attr.type === "relation") {
201
+ if (!relations) continue;
202
+ const refs = (Array.isArray(value) ? value : [value]).map(ref).filter(Boolean);
203
+ if (refs.length) out[name] = Array.isArray(value) ? refs : refs[0];
204
+ } else if (attr.type === "media") {
205
+ const ids = (Array.isArray(value) ? value : [value]).map(idOf).filter((id) => !empty(id));
206
+ if (ids.length) out[name] = attr.multiple ? ids : ids[0];
207
+ } else if (attr.type === "component") {
208
+ const child = schemaOf(attr.component);
209
+ if (attr.repeatable) {
210
+ if (Array.isArray(value) && value.length) out[name] = value.map((item) => canonical2(item, child, schemaOf, { relations }, depth + 1));
211
+ } else out[name] = canonical2(value, child, schemaOf, { relations }, depth + 1);
212
+ } else if (attr.type === "dynamiczone") {
213
+ if (Array.isArray(value) && value.length) out[name] = value.filter((row) => row && typeof row.__component === "string").map((row) => ({ __component: row.__component, ...canonical2(row, schemaOf(row.__component), schemaOf, { relations }, depth + 1) }));
214
+ } else out[name] = value;
215
+ }
216
+ return out;
217
+ }
218
+ var stable = (value) => JSON.stringify(value, (_, v) => v && typeof v === "object" && !Array.isArray(v) ? Object.fromEntries(Object.keys(v).sort().map((k) => [k, v[k]])) : v);
219
+ var same2 = (a, b) => stable(a ?? null) === stable(b ?? null);
220
+ function diffRows2(before = [], after = []) {
221
+ const a = before.map(stable), b = after.map(stable);
222
+ const n = a.length, m = b.length;
223
+ if (n * m > 25e4) return after.map((row, to) => ({ op: a[to] === b[to] ? "same" : "changed", from: to < n ? to : void 0, to, uid: row.__component }));
224
+ const lcs = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
225
+ for (let i2 = n - 1; i2 >= 0; i2--) for (let j2 = m - 1; j2 >= 0; j2--) lcs[i2][j2] = a[i2] === b[j2] ? lcs[i2 + 1][j2 + 1] + 1 : Math.max(lcs[i2 + 1][j2], lcs[i2][j2 + 1]);
226
+ const out = [];
227
+ const gap = (fromRows2, toRows2) => {
228
+ const removed = [...fromRows2];
229
+ for (const to of toRows2) {
230
+ const k = removed.findIndex((from) => before[from].__component === after[to].__component);
231
+ if (k === -1) out.push({ op: "added", to, uid: after[to].__component });
232
+ else out.push({ op: "changed", from: removed.splice(k, 1)[0], to, uid: after[to].__component });
233
+ }
234
+ for (const from of removed) out.push({ op: "removed", from, uid: before[from].__component });
235
+ };
236
+ let i = 0, j = 0, fromRows = [], toRows = [];
237
+ while (i < n || j < m) {
238
+ if (i < n && j < m && a[i] === b[j]) {
239
+ gap(fromRows, toRows);
240
+ fromRows = [];
241
+ toRows = [];
242
+ out.push({ op: "same", from: i, to: j, uid: after[j].__component });
243
+ i++;
244
+ j++;
245
+ } else if (j < m && (i >= n || lcs[i][j + 1] >= lcs[i + 1][j])) toRows.push(j++);
246
+ else fromRows.push(i++);
247
+ }
248
+ gap(fromRows, toRows);
249
+ return out;
250
+ }
251
+ function summarize(before, after, schema) {
252
+ const zones = Object.entries(schema?.attributes || {}).filter(([, attr]) => attr?.type === "dynamiczone").map(([name]) => name);
253
+ const blocks = { added: 0, removed: 0, changed: 0 };
254
+ if (!before) return { initial: true, fields: [], blocks };
255
+ const names = [.../* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after || {})])];
256
+ const fields = names.filter((name) => !zones.includes(name) && !same2(before[name], after?.[name])).sort();
257
+ for (const name of zones) for (const { op } of diffRows2(before[name], after?.[name])) if (op !== "same") blocks[op]++;
258
+ return { fields, blocks };
259
+ }
260
+ module.exports = { IGNORED, kept: kept2, snapshotPopulate, canonical: canonical2, stable, same: same2, diffRows: diffRows2, summarize };
261
+ }
262
+ });
263
+
264
+ // admin/strapi5.tsx
265
+ import * as React16 from "react";
171
266
  import {
172
- Button as Button5,
267
+ Box as Box8,
268
+ Modal as Dialog2,
173
269
  MenuItem as MenuItem2,
174
270
  SimpleMenu as SimpleMenu2,
175
- ModalLayout,
176
- ModalHeader,
177
- ModalBody,
178
- Typography as Typography6,
179
- Status,
180
- Switch,
181
- Flex as Flex6,
182
- SingleSelect,
183
- SingleSelectOption,
184
- TextInput
271
+ Switch as Switch2,
272
+ Flex as Flex10,
273
+ Typography as Typography10,
274
+ Field as Field3,
275
+ SingleSelect as SingleSelect2,
276
+ SingleSelectOption as SingleSelectOption2,
277
+ TextInput as TextInput2
185
278
  } from "@strapi/design-system";
186
279
  import {
187
- useCMEditViewDataManager,
188
- useFetchClient,
189
- useLibrary,
190
- useRBAC,
191
- useNotification,
192
- auth,
280
+ useFetchClient as useFetchClient3,
281
+ useRBAC as useRBAC3,
282
+ useStrapiApp as useStrapiApp2,
283
+ useAuth,
284
+ useForm as useForm3,
285
+ useNotification as useNotification3,
193
286
  getFetchClient
194
- } from "@strapi/helper-plugin";
195
- import { useIntl as useIntl2 } from "react-intl";
287
+ } from "@strapi/strapi/admin";
288
+ import {
289
+ unstable_useContentManagerContext as useContext2,
290
+ useDocumentRBAC as useDocumentRBAC2
291
+ } from "@strapi/content-manager/strapi-admin";
196
292
 
197
293
  // admin/Gallery.tsx
198
294
  import * as React6 from "react";
@@ -271,9 +367,9 @@ function canInsert(zone, uid, values, components, count = 1) {
271
367
  zone?.components.includes(uid) && components[uid] && (Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0) + count <= (zone.max ?? Infinity)
272
368
  );
273
369
  }
274
- function candidatesFor(uid, meta = {}, config = {}) {
275
- const version = config.previewVersion ? `?v=${encodeURIComponent(config.previewVersion)}` : "";
276
- const base = (config.previewBaseUrl || "/block-previews").replace(/\/$/, "");
370
+ function candidatesFor(uid, meta = {}, config2 = {}) {
371
+ const version = config2.previewVersion ? `?v=${encodeURIComponent(config2.previewVersion)}` : "";
372
+ const base = (config2.previewBaseUrl || "/block-previews").replace(/\/$/, "");
277
373
  return [
278
374
  meta.manualImage,
279
375
  meta.image,
@@ -308,12 +404,12 @@ var fieldsOf = (schema) => Object.entries(schema?.attributes || {}).filter(([nam
308
404
  var TYPOLOGIES = ["hero", "text", "media", "listing", "cards", "cta", "form", "layout"];
309
405
  var FACETS = { media: ["image", "video", "gallery"], content: ["richtext", "list", "dynamic", "form"] };
310
406
  var typologyRank = (t) => TYPOLOGIES.indexOf(t) + 1 || 99;
311
- var pickable = (zone, config) => {
312
- const closers = Object.values(config.groups || {});
407
+ var pickable = (zone, config2) => {
408
+ const closers = Object.values(config2.groups || {});
313
409
  return zone.components.filter((uid) => !closers.includes(uid));
314
410
  };
315
- function entryOf(uid, schema, config) {
316
- const meta = config.components?.[uid] || {};
411
+ function entryOf(uid, schema, config2) {
412
+ const meta = config2.components?.[uid] || {};
317
413
  return {
318
414
  uid,
319
415
  label: meta.label || schema.info?.displayName || uid,
@@ -323,27 +419,27 @@ function entryOf(uid, schema, config) {
323
419
  tags: meta.tags || [],
324
420
  keywords: meta.keywords || "",
325
421
  fields: fieldsOf(schema),
326
- candidates: candidatesFor(uid, meta, config),
422
+ candidates: candidatesFor(uid, meta, config2),
327
423
  template: meta.template || "generic",
328
424
  // Insert variants from the code config ({ id, label, values }); the first is what a quick insert uses.
329
425
  variants: Array.isArray(meta.variants) ? meta.variants : []
330
426
  };
331
427
  }
332
- var allEntries = (zone, components, config) => pickable(zone, config).flatMap((uid) => components[uid] ? [entryOf(uid, components[uid], config)] : []);
333
- function entriesFor(zone, components, config, query, filter = {}) {
334
- const needle = query.trim().toLocaleLowerCase();
428
+ var allEntries = (zone, components, config2) => pickable(zone, config2).flatMap((uid) => components[uid] ? [entryOf(uid, components[uid], config2)] : []);
429
+ function entriesFor(zone, components, config2, query2, filter = {}) {
430
+ const needle = query2.trim().toLocaleLowerCase();
335
431
  const any = (picked, values) => !picked?.length || picked.some((value) => values.includes(value));
336
- return allEntries(zone, components, config).filter(
432
+ return allEntries(zone, components, config2).filter(
337
433
  (entry) => (!filter.typology || entry.typology === filter.typology) && (!filter.uids || filter.uids.includes(entry.uid)) && any(filter.tags, entry.tags) && any(filter.media, entry.facets) && any(filter.content, entry.facets) && `${entry.label} ${entry.description} ${entry.typology} ${entry.tags.join(" ")} ${entry.uid} ${entry.keywords}`.toLocaleLowerCase().includes(needle)
338
434
  ).sort((a, b) => typologyRank(a.typology) - typologyRank(b.typology) || a.label.localeCompare(b.label));
339
435
  }
340
- function optionsFor(zone, components, config) {
436
+ function optionsFor(zone, components, config2) {
341
437
  const count = (values) => {
342
438
  const counts = /* @__PURE__ */ new Map();
343
439
  for (const value of values) counts.set(value, (counts.get(value) || 0) + 1);
344
440
  return [...counts.entries()];
345
441
  };
346
- const entries = allEntries(zone, components, config);
442
+ const entries = allEntries(zone, components, config2);
347
443
  const facets = entries.flatMap((entry) => entry.facets);
348
444
  return {
349
445
  total: entries.length,
@@ -388,9 +484,9 @@ function initialState(editor, remembered) {
388
484
  return "closed";
389
485
  }
390
486
  var withoutField = (rows, name) => rows.map((row) => row.filter((field) => field?.name !== name)).filter((row) => row.length);
391
- function dropField4(layout, name) {
487
+ function dropField(layout, name) {
392
488
  if (!name || !layout?.components) return layout;
393
- return { ...layout, components: Object.fromEntries(Object.entries(layout.components).map(([uid, component]) => [uid, Array.isArray(component?.layouts?.edit) ? { ...component, layouts: { ...component.layouts, edit: withoutField(component.layouts.edit, name) } } : component])) };
489
+ return { ...layout, components: Object.fromEntries(Object.entries(layout.components).map(([uid, component]) => [uid, Array.isArray(component?.layout) ? { ...component, layout: withoutField(component.layout, name) } : component])) };
394
490
  }
395
491
  function humanize(name) {
396
492
  const text = String(name || "").replace(/[_\-\s]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").trim().split(" ").filter(Boolean).map((word) => /^[A-Z0-9]{2,}$/.test(word) && /[A-Z]/.test(word) ? word : word.toLowerCase()).join(" ");
@@ -421,23 +517,33 @@ function fieldText(fields, owner, name, label, locale, on) {
421
517
  }
422
518
  return Object.keys(out).length ? out : null;
423
519
  }
520
+ function layoutType(layout, types = {}) {
521
+ const names = (layout?.layout || []).flat(2).map((field) => field?.name);
522
+ const found = Object.entries(types || {}).filter(([, [displayName, ...attributes]]) => displayName === layout?.settings?.displayName && names.every((name) => attributes.includes(name)));
523
+ return found.length === 1 ? found[0][0] : found.length ? false : null;
524
+ }
424
525
  var labelsOff = (catalog) => !catalog?.editor?.enabled || !catalog.editor.friendlyLabels && !Object.keys(catalog.fields || {}).length;
425
526
  var withHelp = (description, help) => description ? `${description} ${help}` : help;
426
- function labelEditLayout4(layout, catalog, locale) {
427
- const uid = layout?.contentType?.uid;
428
- if (labelsOff(catalog) || !uid || catalog.contentTypes?.[uid]?.enabled === false) return layout;
527
+ function labelEditLayout(layout, catalog, locale, helpAction2) {
528
+ if (labelsOff(catalog) || !Array.isArray(layout?.layout) || !layout.layout.length) return layout;
529
+ const uid = layoutType(layout, catalog.types);
530
+ if (uid === false || uid && catalog.contentTypes?.[uid]?.enabled === false) return layout;
429
531
  const fix = (owner) => (field) => {
430
- const text = field?.metadatas && fieldText(catalog.fields, owner, field.name, field.metadatas.label, locale, catalog.editor.friendlyLabels);
532
+ const text = field && fieldText(catalog.fields, owner, field.name, field.label, locale, catalog.editor.friendlyLabels);
431
533
  if (!text) return field;
432
- const { help, ...rest } = text;
433
- const metadatas = { ...field.metadatas, ...rest };
434
- return { ...field, metadatas: help === void 0 ? metadatas : { ...metadatas, description: withHelp(metadatas.description, help) } };
534
+ const { description, help, ...rest } = text;
535
+ const hint = description ?? field.hint;
536
+ return {
537
+ ...field,
538
+ ...rest,
539
+ ...description !== void 0 && { hint },
540
+ ...help !== void 0 && (helpAction2 ? { labelAction: helpAction2(help, field.labelAction) } : { hint: withHelp(hint, help) })
541
+ };
435
542
  };
436
- const rows = (target, owner) => Array.isArray(target?.layouts?.edit) ? { ...target, layouts: { ...target.layouts, edit: target.layouts.edit.map((row) => row.map(fix(owner))) } } : target;
437
543
  return {
438
544
  ...layout,
439
- contentType: rows(layout.contentType, uid),
440
- components: Object.fromEntries(Object.entries(layout.components || {}).map(([cuid, component]) => [cuid, rows(component, cuid)]))
545
+ layout: layout.layout.map((panel) => panel.map((row) => row.map(fix(uid)))),
546
+ components: Object.fromEntries(Object.entries(layout.components || {}).map(([cuid, component]) => [cuid, Array.isArray(component?.layout) ? { ...component, layout: component.layout.map((row) => row.map(fix(cuid))) } : component]))
441
547
  };
442
548
  }
443
549
 
@@ -591,18 +697,18 @@ var stageBackground = (theme) => {
591
697
 
592
698
  // admin/accordions.mjs
593
699
  function zoneLists(root = document) {
594
- return [...root.querySelectorAll("ol[aria-describedby]")].filter((list) => list.querySelector(":scope > li button[aria-expanded]"));
700
+ return [...root.querySelectorAll("ol[aria-describedby]")].filter((list2) => list2.querySelector(":scope > li button[aria-expanded]"));
595
701
  }
596
702
  function findZoneList(label, root = document) {
597
703
  const lists = zoneLists(root);
598
- const text = (list) => (list.parentElement?.textContent || "").trim().toLocaleLowerCase();
599
- return lists.find((list) => text(list).startsWith(String(label).toLocaleLowerCase())) || (lists.length === 1 ? lists[0] : null);
704
+ const text = (list2) => (list2.parentElement?.textContent || "").trim().toLocaleLowerCase();
705
+ return lists.find((list2) => text(list2).startsWith(String(label).toLocaleLowerCase())) || (lists.length === 1 ? lists[0] : null);
600
706
  }
601
- function toggles(list) {
602
- return [...list.querySelectorAll(":scope > li")].map((item) => item.querySelector("button[aria-expanded]")).filter(Boolean);
707
+ function toggles(list2) {
708
+ return [...list2.querySelectorAll(":scope > li")].map((item) => item.querySelector("button[aria-expanded]")).filter(Boolean);
603
709
  }
604
710
  var FOLDED = "data-blockscene-folded";
605
- var shownToggles = (list) => toggles(list).filter((button) => !button.closest(`li[${FOLDED}]`));
711
+ var shownToggles = (list2) => toggles(list2).filter((button) => !button.closest(`li[${FOLDED}]`));
606
712
  function planRows(rects, view, margin = 0) {
607
713
  const now = [], later = [];
608
714
  const gap = (r) => Math.max(view.top - margin - r.bottom, r.top - view.bottom - margin, 0);
@@ -625,9 +731,9 @@ function stopAll() {
625
731
  var PER_FRAME = 3;
626
732
  var idle = (run) => typeof requestIdleCallback === "function" ? requestIdleCallback(run, { timeout: 300 }) : setTimeout(() => run({ timeRemaining: () => 8 }), 16);
627
733
  var frame = (run) => typeof requestAnimationFrame === "function" ? requestAnimationFrame(run) : setTimeout(run, 16);
628
- function setAll(list, open, batch = (run) => run()) {
629
- jobs.get(list)?.();
630
- jobs.delete(list);
734
+ function setAll(list2, open, batch = (run) => run()) {
735
+ jobs.get(list2)?.();
736
+ jobs.delete(list2);
631
737
  const header = (li) => li.querySelector("button[aria-expanded]");
632
738
  const differs = (li) => {
633
739
  const b = li.isConnected && header(li);
@@ -640,9 +746,9 @@ function setAll(list, open, batch = (run) => run()) {
640
746
  });
641
747
  return buttons.length;
642
748
  };
643
- const rows = [...list.querySelectorAll(":scope > li")].filter((li) => !li.hasAttribute(FOLDED) && differs(li));
749
+ const rows = [...list2.querySelectorAll(":scope > li")].filter((li) => !li.hasAttribute(FOLDED) && differs(li));
644
750
  if (!rows.length) return 0;
645
- const root = scroller(list);
751
+ const root = scroller(list2);
646
752
  const view = () => root ? root.getBoundingClientRect() : { top: 0, bottom: window.innerHeight };
647
753
  const height = view().bottom - view().top;
648
754
  const { now, later } = planRows(rows.map((li) => li.getBoundingClientRect()), view(), open ? height : 0);
@@ -673,7 +779,7 @@ function setAll(list, open, batch = (run) => run()) {
673
779
  if (queue.size && !handle && !stopped) handle = frame(flush);
674
780
  }, { root, rootMargin: `${Math.round(height)}px 0px` });
675
781
  later.forEach((i) => observer.observe(rows[i]));
676
- jobs.set(list, () => {
782
+ jobs.set(list2, () => {
677
783
  stopped = true;
678
784
  observer.disconnect();
679
785
  });
@@ -687,10 +793,10 @@ function setAll(list, open, batch = (run) => run()) {
687
793
  if (stopped) return;
688
794
  click(pending2.splice(0, deadline.timeRemaining() > 10 ? PER_FRAME : 1));
689
795
  if (pending2.length) idle(slice);
690
- else jobs.delete(list);
796
+ else jobs.delete(list2);
691
797
  };
692
798
  idle(slice);
693
- jobs.set(list, () => {
799
+ jobs.set(list2, () => {
694
800
  stopped = true;
695
801
  });
696
802
  return changed;
@@ -4151,9 +4257,9 @@ function useAnchors(zones, onOpen) {
4151
4257
  sync.current = () => {
4152
4258
  const next = [];
4153
4259
  for (const zone of latest.current) {
4154
- const list = zone.uids?.length ? findZoneList(zone.label) : null;
4155
- if (!list) continue;
4156
- toggles(list).forEach((button, index) => {
4260
+ const list2 = zone.uids?.length ? findZoneList(zone.label) : null;
4261
+ if (!list2) continue;
4262
+ toggles(list2).forEach((button, index) => {
4157
4263
  const uid = zone.uids[index];
4158
4264
  if (!uid) return;
4159
4265
  let el = button.querySelector(
@@ -4213,7 +4319,7 @@ function useAnchors(zones, onOpen) {
4213
4319
  }, []);
4214
4320
  return anchors;
4215
4321
  }
4216
- function RowPreviews({ zones, components, catalog, Modal: Modal2 }) {
4322
+ function RowPreviews({ zones, components, catalog, Modal: Modal3 }) {
4217
4323
  const t = useMessages();
4218
4324
  const [resolved, setResolved] = React2.useState({});
4219
4325
  const [open, setOpen] = React2.useState(null);
@@ -4262,7 +4368,7 @@ function RowPreviews({ zones, components, catalog, Modal: Modal2 }) {
4262
4368
  )
4263
4369
  ),
4264
4370
  open && srcOf(open) && /* @__PURE__ */ jsx2(
4265
- Modal2,
4371
+ Modal3,
4266
4372
  {
4267
4373
  open: true,
4268
4374
  onOpenChange: (value) => {
@@ -4333,9 +4439,52 @@ function cloneRow(row, components, { relation } = {}) {
4333
4439
  };
4334
4440
  return walk(row, components?.[row?.__component], []);
4335
4441
  }
4336
- function integerKeys(rows, n) {
4337
- const max = Math.max(-1, ...rows.map((row) => Number(row?.__temp_key__)).filter(Number.isFinite));
4338
- return Array.from({ length: n }, (_, i) => max + 1 + i);
4442
+ function relationSlots(row, components) {
4443
+ const slots = [];
4444
+ const walk = (value, uid, path) => {
4445
+ const schema = components?.[uid];
4446
+ if (!value || !schema) return;
4447
+ for (const [key, attr] of Object.entries(schema.attributes || {})) {
4448
+ if (attr?.type === "relation" && value.id != null)
4449
+ slots.push({ path: [...path, key].join("."), uid, id: value.id, field: key, target: attr.targetModel || attr.target });
4450
+ else if (attr?.type === "component" && value[key]) {
4451
+ if (attr.repeatable) (Array.isArray(value[key]) ? value[key] : []).forEach((entry, i) => walk(entry, attr.component, [...path, key, i]));
4452
+ else walk(value[key], attr.component, [...path, key]);
4453
+ }
4454
+ }
4455
+ };
4456
+ walk(row, row?.__component, []);
4457
+ return slots;
4458
+ }
4459
+ var plain = (r) => ({ id: r.id ?? r.apiData?.id, documentId: r.documentId ?? r.apiData?.documentId, locale: r.locale ?? r.apiData?.locale ?? null, status: r.status });
4460
+ function currentRelations(server, value) {
4461
+ const gone = new Set((value?.disconnect || []).map((r) => plain(r).id));
4462
+ const out = (server || []).map(plain).filter((r) => !gone.has(r.id));
4463
+ for (const r of (value?.connect || []).map(plain)) if (!out.some((o) => o.id === r.id)) out.push(r);
4464
+ return out;
4465
+ }
4466
+ function toConnect(relations, target) {
4467
+ const keys = relations.length ? generateNKeysBetween2(null, null, relations.length) : [];
4468
+ return {
4469
+ connect: relations.map((r, i) => ({
4470
+ id: r.id,
4471
+ apiData: { id: r.id, documentId: r.documentId, locale: r.locale, isTemporary: true },
4472
+ status: r.status,
4473
+ label: r.label ?? r.documentId,
4474
+ href: `../collection-types/${target}/${r.documentId}${r.locale ? `?plugins[i18n][locale]=${r.locale}` : ""}`,
4475
+ __temp_key__: keys[i]
4476
+ })),
4477
+ disconnect: []
4478
+ };
4479
+ }
4480
+ function fractionalKeys(rows, at, n) {
4481
+ const key = (row) => typeof row?.__temp_key__ === "string" ? row.__temp_key__ : null;
4482
+ try {
4483
+ return generateNKeysBetween2(key(rows[at - 1]), key(rows[at]), n);
4484
+ } catch {
4485
+ const max = rows.map(key).filter(Boolean).sort().pop() ?? null;
4486
+ return generateNKeysBetween2(max, null, n);
4487
+ }
4339
4488
  }
4340
4489
  var insertRows = (rows, at, items2, keys) => [
4341
4490
  ...rows.slice(0, at),
@@ -4402,13 +4551,13 @@ function movedRow(prev, next, actor) {
4402
4551
  if (i === n) return null;
4403
4552
  let j = n - 1;
4404
4553
  while (k[j] === m[j]) j--;
4405
- const same = (a, b) => (0, import_groups2.blockKey)(a) === (0, import_groups2.blockKey)(b) || a?.id == null && b?.id == null && a?.__component === b?.__component;
4554
+ const same2 = (a, b) => (0, import_groups2.blockKey)(a) === (0, import_groups2.blockKey)(b) || a?.id == null && b?.id == null && a?.__component === b?.__component;
4406
4555
  const shifted = (from, to, by) => {
4407
4556
  for (let x = from; x <= to; x++) if (m[x] !== k[x + by]) return false;
4408
4557
  return true;
4409
4558
  };
4410
- const down = same(prev[i], next[j]) && shifted(i, j - 1, 1);
4411
- const up = same(prev[j], next[i]) && shifted(i + 1, j, -1);
4559
+ const down = same2(prev[i], next[j]) && shifted(i, j - 1, 1);
4560
+ const up = same2(prev[j], next[i]) && shifted(i + 1, j, -1);
4412
4561
  if (down && up) return actor === k[i] ? { from: i, to: j } : actor === k[j] ? { from: j, to: i } : null;
4413
4562
  return down ? { from: i, to: j } : up ? { from: j, to: i } : null;
4414
4563
  }
@@ -4775,7 +4924,7 @@ var set = (el, name, value) => {
4775
4924
  if (value === null) el.hasAttribute(name) && el.removeAttribute(name);
4776
4925
  else if (el.getAttribute(name) !== value) el.setAttribute(name, value);
4777
4926
  };
4778
- var items = (list) => [...list.querySelectorAll(":scope > li")];
4927
+ var items = (list2) => [...list2.querySelectorAll(":scope > li")];
4779
4928
  var Fold = styled3.span`
4780
4929
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 28px; height: 28px; margin-left: 8px;
4781
4930
  border-radius: 4px; cursor: pointer; color: ${({ theme }) => theme.colors.primary600};
@@ -4830,8 +4979,8 @@ function GroupRows({ zones, form, groups, docKey, labelOf, layouts = null, compo
4830
4979
  const li = !target?.closest?.(`[${GRID_BOX}]`) && target?.closest?.("ol[aria-describedby] > li");
4831
4980
  if (!li) return null;
4832
4981
  for (const zone of latest.current.zones) {
4833
- const list2 = findZoneList(zone.label);
4834
- if (li.parentElement === list2) return blockKey(latest.current.form.rows(zone.name)[items(list2).indexOf(li)]) || null;
4982
+ const list3 = findZoneList(zone.label);
4983
+ if (li.parentElement === list3) return blockKey(latest.current.form.rows(zone.name)[items(list3).indexOf(li)]) || null;
4835
4984
  }
4836
4985
  return null;
4837
4986
  };
@@ -4861,8 +5010,8 @@ function GroupRows({ zones, form, groups, docKey, labelOf, layouts = null, compo
4861
5010
  const { zones: zones2, form: form2, docKey: docKey2, labelOf: labelOf2, layouts: layouts2 } = latest.current;
4862
5011
  if (dragging.current) {
4863
5012
  const placeholder = zones2.some((zone) => {
4864
- const list2 = findZoneList(zone.label);
4865
- return list2 && items(list2).some((li) => !li.querySelector("button[aria-expanded]"));
5013
+ const list3 = findZoneList(zone.label);
5014
+ return list3 && items(list3).some((li) => !li.querySelector("button[aria-expanded]"));
4866
5015
  });
4867
5016
  if (placeholder) previewed.current = true;
4868
5017
  else if (previewed.current) end();
@@ -4872,10 +5021,10 @@ function GroupRows({ zones, form, groups, docKey, labelOf, layouts = null, compo
4872
5021
  const seen = /* @__PURE__ */ new Set();
4873
5022
  if (on)
4874
5023
  for (const zone of zones2) {
4875
- const list2 = zone.count ? findZoneList(zone.label) : null;
5024
+ const list3 = zone.count ? findZoneList(zone.label) : null;
4876
5025
  const rows = form2.rows(zone.name);
4877
- const lis = list2 ? items(list2) : [];
4878
- if (!list2 || lis.length !== rows.length) continue;
5026
+ const lis = list3 ? items(list3) : [];
5027
+ if (!list3 || lis.length !== rows.length) continue;
4879
5028
  const outline = groupOutline(rows, groups);
4880
5029
  const idOf = (i) => `${docKey2}|${zone.name}|${blockKey(rows[i])}`;
4881
5030
  const unfold = [...form2.errorRows?.(zone.name) || []];
@@ -4954,16 +5103,16 @@ function GroupRows({ zones, form, groups, docKey, labelOf, layouts = null, compo
4954
5103
  sync.current();
4955
5104
  };
4956
5105
  const line = theme?.colors?.primary600 || "#4945ff";
4957
- const list = "ol[aria-describedby] > li";
5106
+ const list2 = "ol[aria-describedby] > li";
4958
5107
  return /* @__PURE__ */ jsxs3(Fragment2, { children: [
4959
5108
  /* @__PURE__ */ jsx5("style", { children: `
4960
- ${list}[${DEPTH}] { padding-left: calc(var(--bs-depth) * ${STEP}); background: repeating-linear-gradient(to right, ${line} 0 2px, transparent 2px ${STEP}) 1.1rem 0 / calc(var(--bs-depth) * ${STEP}) 100% no-repeat; }
4961
- ${list}[${FOLDED}]:not([data-bp-block-modal]) { display: none !important; }
4962
- ${list}[data-bp-block-modal] { padding-left: 0 !important; background-image: none !important; }
4963
- ${list}[${KIND}="close"] [data-handler-id] { display: none !important; }
4964
- ${list}[${KIND}="close"] button[aria-expanded]:first-of-type { min-height: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important; opacity: 0.7; }
4965
- ${list}[${KIND}="close"] button[aria-expanded]:first-of-type + * { padding-top: 0 !important; padding-bottom: 0 !important; }
4966
- ${list}[${KIND}="close"] button[aria-expanded] [data-blockscene-row-thumb] { display: none; }` }),
5109
+ ${list2}[${DEPTH}] { padding-left: calc(var(--bs-depth) * ${STEP}); background: repeating-linear-gradient(to right, ${line} 0 2px, transparent 2px ${STEP}) 1.1rem 0 / calc(var(--bs-depth) * ${STEP}) 100% no-repeat; }
5110
+ ${list2}[${FOLDED}]:not([data-bp-block-modal]) { display: none !important; }
5111
+ ${list2}[data-bp-block-modal] { padding-left: 0 !important; background-image: none !important; }
5112
+ ${list2}[${KIND}="close"] [data-handler-id] { display: none !important; }
5113
+ ${list2}[${KIND}="close"] button[aria-expanded]:first-of-type { min-height: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important; opacity: 0.7; }
5114
+ ${list2}[${KIND}="close"] button[aria-expanded]:first-of-type + * { padding-top: 0 !important; padding-bottom: 0 !important; }
5115
+ ${list2}[${KIND}="close"] button[aria-expanded] [data-blockscene-row-thumb] { display: none; }` }),
4967
5116
  anchors.map(
4968
5117
  (a) => createPortal2(
4969
5118
  /* @__PURE__ */ jsx5(
@@ -5110,9 +5259,9 @@ function useAnchors2(zones, enabled, selecting) {
5110
5259
  const next = [];
5111
5260
  if (enabled)
5112
5261
  for (const zone of latest.current.zones) {
5113
- const list = zone.count ? findZoneList(zone.label) : null;
5114
- if (!list) continue;
5115
- toggles(list).forEach((toggle, index) => {
5262
+ const list2 = zone.count ? findZoneList(zone.label) : null;
5263
+ if (!list2) continue;
5264
+ toggles(list2).forEach((toggle, index) => {
5116
5265
  const trash = trashOf(toggle);
5117
5266
  if (!trash || index >= zone.count) return;
5118
5267
  const holder = trash.parentElement !== actionsOf(toggle) && trash.parentElement?.children.length === 1 ? trash.parentElement : trash;
@@ -5237,7 +5386,7 @@ var HiddenBadge = styled4.span`
5237
5386
  text-transform: uppercase; letter-spacing: 0.04em;
5238
5387
  color: ${({ theme }) => theme.colors.warning700}; background: ${({ theme }) => theme.colors.warning100};
5239
5388
  `;
5240
- function RowActions({ zones, actions, Modal: Modal2 }) {
5389
+ function RowActions({ zones, actions, Modal: Modal3 }) {
5241
5390
  const a = actions;
5242
5391
  const e = a?.editor || {};
5243
5392
  const anchors = useAnchors2(zones, Boolean(a) && Boolean(a.hiddenName || e.duplicate !== false || e.clipboard !== false || a.selection), a?.selection?.zone || null);
@@ -5251,9 +5400,9 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
5251
5400
  const button = event.target?.closest?.("button");
5252
5401
  if (!button || bypass.current) return;
5253
5402
  for (const zone of latest.current.zones) {
5254
- const list = findZoneList(zone.label);
5255
- if (!list?.contains(button)) continue;
5256
- const headers = toggles(list);
5403
+ const list2 = findZoneList(zone.label);
5404
+ if (!list2?.contains(button)) continue;
5405
+ const headers = toggles(list2);
5257
5406
  const index = headers.findIndex((toggle) => trashOf(toggle) === button);
5258
5407
  if (index < 0) return;
5259
5408
  event.preventDefault();
@@ -5366,7 +5515,7 @@ ol[aria-describedby] > li button[data-strapi-accordion-toggle] > span:last-child
5366
5515
  `${zone}:${index}`
5367
5516
  );
5368
5517
  }),
5369
- confirm && /* @__PURE__ */ jsx6(Modal2, { open: true, width: "48rem", onOpenChange: (open) => !open && setConfirm(null), trigger: null, title: t.confirmDeleteTitle, children: /* @__PURE__ */ jsxs4(Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-confirm-delete", children: [
5518
+ confirm && /* @__PURE__ */ jsx6(Modal3, { open: true, width: "48rem", onOpenChange: (open) => !open && setConfirm(null), trigger: null, title: t.confirmDeleteTitle, children: /* @__PURE__ */ jsxs4(Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-confirm-delete", children: [
5370
5519
  /* @__PURE__ */ jsx6(Typography, { children: t.f("confirmDelete", { name: confirm.label }) }),
5371
5520
  confirm.marker && /* @__PURE__ */ jsx6(Typography, { variant: "pi", textColor: "neutral600", children: t.confirmDeleteMarker }),
5372
5521
  /* @__PURE__ */ jsxs4(Flex, { gap: 2, justifyContent: "flex-end", children: [
@@ -5758,7 +5907,7 @@ var readCollapsed = () => {
5758
5907
  };
5759
5908
  var TYPE_ICONS2 = { hero: "hero", text: "text", media: "image", listing: "list", cards: "cards", cta: "link", form: "form", layout: "layout" };
5760
5909
  var FILTER_MENUS = ["tags", "media", "content"];
5761
- var toggled = (list, value) => list.includes(value) ? list.filter((item) => item !== value) : [...list, value];
5910
+ var toggled = (list2, value) => list2.includes(value) ? list2.filter((item) => item !== value) : [...list2, value];
5762
5911
  function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
5763
5912
  const [open, setOpen] = React6.useState(false);
5764
5913
  const ref = React6.useRef(null);
@@ -5988,10 +6137,10 @@ var flip = (panel, scrim, card, back) => {
5988
6137
  return panel.animate(back ? frames.reverse() : frames, timing);
5989
6138
  };
5990
6139
  var newChannel = () => crypto.randomUUID?.() || `${Date.now()}-${Math.random().toString(36).slice(2)}`;
5991
- function useLiveSource(entry, config, get, contentType, locale, variant) {
5992
- const editor = config?.editor || {};
6140
+ function useLiveSource(entry, config2, get, contentType, locale, variant) {
6141
+ const editor = config2?.editor || {};
5993
6142
  const [native, setNative] = React6.useState(null);
5994
- const plain = editor.blockPreviewUrl ? blockPreviewSrc(editor.blockPreviewUrl, entry.uid, { variant, locale: locale || "" }) : null;
6143
+ const plain2 = editor.blockPreviewUrl ? blockPreviewSrc(editor.blockPreviewUrl, entry.uid, { variant, locale: locale || "" }) : null;
5995
6144
  React6.useEffect(() => {
5996
6145
  if (editor.blockPreviewUrl || editor.previewUrl || !contentType || !get) return;
5997
6146
  let active = true;
@@ -6004,7 +6153,7 @@ function useLiveSource(entry, config, get, contentType, locale, variant) {
6004
6153
  };
6005
6154
  }, [editor.blockPreviewUrl, editor.previewUrl, contentType, locale, get]);
6006
6155
  const channel = React6.useMemo(newChannel, []);
6007
- if (editor.blockPreviewUrl) return plain ? { kind: "plain", src: plain, origin: "", channel } : null;
6156
+ if (editor.blockPreviewUrl) return plain2 ? { kind: "plain", src: plain2, origin: "", channel } : null;
6008
6157
  const base = editor.previewUrl || native;
6009
6158
  if (!base) return null;
6010
6159
  try {
@@ -6016,7 +6165,7 @@ function useLiveSource(entry, config, get, contentType, locale, variant) {
6016
6165
  }
6017
6166
  }
6018
6167
  var LIVE_TIMEOUT = 8e3;
6019
- function Magnify({ entry, palette, config, components, get, contentType, locale, starred, onStar, onInsert, onClose, cardOf }) {
6168
+ function Magnify({ entry, palette, config: config2, components, get, contentType, locale, starred, onStar, onInsert, onClose, cardOf }) {
6020
6169
  const t = useMessages();
6021
6170
  const panel = React6.useRef(null);
6022
6171
  const scrim = React6.useRef(null);
@@ -6030,7 +6179,7 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
6030
6179
  const [state, setState] = React6.useState("loading");
6031
6180
  const [variantId, setVariantId] = React6.useState(entry.variants[0]?.id);
6032
6181
  const variant = entry.variants.find((item) => item.id === variantId);
6033
- const live = useLiveSource(entry, config, get, contentType, locale, variantId);
6182
+ const live = useLiveSource(entry, config2, get, contentType, locale, variantId);
6034
6183
  const send = () => {
6035
6184
  let blocks = [];
6036
6185
  try {
@@ -6175,7 +6324,7 @@ function PickerModal({
6175
6324
  open,
6176
6325
  onOpenChange,
6177
6326
  onSelect,
6178
- Modal: Modal2,
6327
+ Modal: Modal3,
6179
6328
  Toggle,
6180
6329
  get,
6181
6330
  put,
@@ -6187,7 +6336,7 @@ function PickerModal({
6187
6336
  {
6188
6337
  zone,
6189
6338
  components,
6190
- Modal: Modal2,
6339
+ Modal: Modal3,
6191
6340
  Toggle,
6192
6341
  get,
6193
6342
  put,
@@ -6202,7 +6351,7 @@ function ZoneGallery({
6202
6351
  zone,
6203
6352
  components,
6204
6353
  add,
6205
- Modal: Modal2,
6354
+ Modal: Modal3,
6206
6355
  Toggle,
6207
6356
  get,
6208
6357
  put,
@@ -6216,7 +6365,7 @@ function ZoneGallery({
6216
6365
  const [ownOpen, setOwnOpen] = React6.useState(false);
6217
6366
  const open = controlled ? controlled.open : ownOpen;
6218
6367
  const setOpen = controlled ? controlled.onOpenChange : setOwnOpen;
6219
- const [query, setQuery] = React6.useState("");
6368
+ const [query2, setQuery] = React6.useState("");
6220
6369
  const [view, setView] = React6.useState("all");
6221
6370
  const [picked, setPicked] = React6.useState(NO_FILTERS);
6222
6371
  const [detail, setDetail] = React6.useState(null);
@@ -6224,7 +6373,7 @@ function ZoneGallery({
6224
6373
  const [prefs, setPrefs] = React6.useState({ starred: [], recent: [] });
6225
6374
  const [showFields, setShowFields] = React6.useState(readShowFields);
6226
6375
  const [columns, setColumns] = React6.useState(readColumns);
6227
- const [config, setConfig] = React6.useState(null);
6376
+ const [config2, setConfig] = React6.useState(null);
6228
6377
  const [error, setError] = React6.useState("");
6229
6378
  React6.useEffect(() => {
6230
6379
  if (controlled) return;
@@ -6263,18 +6412,18 @@ function ZoneGallery({
6263
6412
  });
6264
6413
  };
6265
6414
  const star = (uid) => savePrefs({ ...prefs, starred: toggled(prefs.starred, uid) });
6266
- const options = config ? optionsFor(zone, components, config) : null;
6267
- const inZone = (list) => options ? list.filter((uid) => options.uids.includes(uid)) : [];
6415
+ const options = config2 ? optionsFor(zone, components, config2) : null;
6416
+ const inZone = (list2) => options ? list2.filter((uid) => options.uids.includes(uid)) : [];
6268
6417
  const filter = {
6269
6418
  ...picked,
6270
6419
  typology: TYPOLOGIES.includes(view) ? view : void 0,
6271
6420
  uids: view === "recent" ? prefs.recent : view === "starred" ? prefs.starred : void 0
6272
6421
  };
6273
- let entries = config ? entriesFor(zone, components, config, query, filter) : [];
6422
+ let entries = config2 ? entriesFor(zone, components, config2, query2, filter) : [];
6274
6423
  if (view === "recent") entries = [...entries].sort((a, b) => prefs.recent.indexOf(a.uid) - prefs.recent.indexOf(b.uid));
6275
6424
  const chosen = entries.find((entry) => entry.uid === detail);
6276
6425
  const chips = FILTER_MENUS.flatMap((menu) => picked[menu].map((value) => ({ menu, value })));
6277
- const filtering = query.trim() !== "" || view !== "all" || chips.length > 0;
6426
+ const filtering = query2.trim() !== "" || view !== "all" || chips.length > 0;
6278
6427
  const reset = () => {
6279
6428
  setQuery("");
6280
6429
  setView("all");
@@ -6327,7 +6476,7 @@ function ZoneGallery({
6327
6476
  key
6328
6477
  );
6329
6478
  return /* @__PURE__ */ jsx7(
6330
- Modal2,
6479
+ Modal3,
6331
6480
  {
6332
6481
  open,
6333
6482
  onOpenChange: setOpen,
@@ -6372,7 +6521,7 @@ function ZoneGallery({
6372
6521
  Searchbar,
6373
6522
  {
6374
6523
  name: `block-search-${zone.name}`,
6375
- value: query,
6524
+ value: query2,
6376
6525
  placeholder: t.search,
6377
6526
  clearLabel: t.clear,
6378
6527
  onClear: () => setQuery(""),
@@ -6437,7 +6586,7 @@ function ZoneGallery({
6437
6586
  /* @__PURE__ */ jsx7(Button2, { variant: "tertiary", size: "S", onClick: () => setPicked(NO_FILTERS), "data-testid": "gallery-clear-all", children: t.clearAll })
6438
6587
  ] }),
6439
6588
  /* @__PURE__ */ jsx7(Typography2, { variant: "pi", textColor: "neutral600", children: t.example }),
6440
- error ? /* @__PURE__ */ jsx7(Typography2, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ jsx7(Typography2, { children: t.loading }) : entries.length ? /* @__PURE__ */ jsxs5("div", { ref: grid, style: { position: "relative", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
6589
+ error ? /* @__PURE__ */ jsx7(Typography2, { role: "alert", textColor: "danger600", children: error }) : !config2 ? /* @__PURE__ */ jsx7(Typography2, { children: t.loading }) : entries.length ? /* @__PURE__ */ jsxs5("div", { ref: grid, style: { position: "relative", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
6441
6590
  /* @__PURE__ */ jsx7(
6442
6591
  Flex2,
6443
6592
  {
@@ -6452,7 +6601,7 @@ function ZoneGallery({
6452
6601
  Card,
6453
6602
  {
6454
6603
  entry,
6455
- palette: config.palette,
6604
+ palette: config2.palette,
6456
6605
  showFields,
6457
6606
  starred: prefs.starred.includes(entry.uid),
6458
6607
  active: detail === entry.uid,
@@ -6469,8 +6618,8 @@ function ZoneGallery({
6469
6618
  Magnify,
6470
6619
  {
6471
6620
  entry: chosen,
6472
- palette: config.palette,
6473
- config,
6621
+ palette: config2.palette,
6622
+ config: config2,
6474
6623
  components,
6475
6624
  get,
6476
6625
  contentType,
@@ -6534,14 +6683,14 @@ function useInitialAccordions({
6534
6683
  const timer = setInterval(() => {
6535
6684
  const pending2 = latest.current.filter((zone) => zone.count > 0);
6536
6685
  const ready = pending2.length > 0 && pending2.every((zone) => {
6537
- const list = findZoneList(zone.label);
6538
- return list && toggles(list).length >= zone.count;
6686
+ const list2 = findZoneList(zone.label);
6687
+ return list2 && toggles(list2).length >= zone.count;
6539
6688
  }) && (editor.initialState !== "remember" || user.current);
6540
6689
  if (!ready && ++tries < 25) return;
6541
6690
  stop();
6542
6691
  for (const zone of pending2) {
6543
- const list = findZoneList(zone.label);
6544
- if (!list) continue;
6692
+ const list2 = findZoneList(zone.label);
6693
+ if (!list2) continue;
6545
6694
  const key = memoryKey({
6546
6695
  base: memoryBase(),
6547
6696
  userId: user.current,
@@ -6549,7 +6698,7 @@ function useInitialAccordions({
6549
6698
  zone: zone.name
6550
6699
  });
6551
6700
  setAll(
6552
- list,
6701
+ list2,
6553
6702
  initialState(editor, readMemory(storage2(), key)) === "open",
6554
6703
  unstable_batchedUpdates
6555
6704
  );
@@ -6568,8 +6717,8 @@ function useZoneAnchor(zone, enabled) {
6568
6717
  const sync = () => {
6569
6718
  let host = null, after = null;
6570
6719
  if (filled) {
6571
- const list = findZoneList(zone.label);
6572
- host = list && [...list.parentElement?.children || []].find((child) => child !== list && child.textContent?.trim()) || null;
6720
+ const list2 = findZoneList(zone.label);
6721
+ host = list2 && [...list2.parentElement?.children || []].find((child) => child !== list2 && child.textContent?.trim()) || null;
6573
6722
  } else {
6574
6723
  after = [...document.querySelectorAll("button")].find((button) => isNativeAddButton(button, zone)) || null;
6575
6724
  host = after?.parentElement || null;
@@ -6609,16 +6758,16 @@ function useRowStates(zone, enabled) {
6609
6758
  React6.useEffect(() => {
6610
6759
  if (!enabled) return;
6611
6760
  let frame2 = 0;
6612
- const read2 = () => {
6761
+ const read3 = () => {
6613
6762
  frame2 = 0;
6614
- const list = findZoneList(zone.label);
6615
- const values = list ? shownToggles(list).map((button) => button.getAttribute("aria-expanded") === "true") : [];
6763
+ const list2 = findZoneList(zone.label);
6764
+ const values = list2 ? shownToggles(list2).map((button) => button.getAttribute("aria-expanded") === "true") : [];
6616
6765
  const closed = values.includes(false), open = values.includes(true);
6617
6766
  setState((prev) => prev.closed === closed && prev.open === open ? prev : { closed, open });
6618
6767
  };
6619
- read2();
6768
+ read3();
6620
6769
  const observer = new MutationObserver(() => {
6621
- if (!frame2) frame2 = requestAnimationFrame(read2);
6770
+ if (!frame2) frame2 = requestAnimationFrame(read3);
6622
6771
  });
6623
6772
  observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["aria-expanded", FOLDED] });
6624
6773
  return () => {
@@ -6638,8 +6787,8 @@ function ZoneControls({ zone, editor, contentType, userId, actions, extra, Menu:
6638
6787
  if (!anchor) return null;
6639
6788
  const toggle = toggleShown && accordionToggle(rows.closed, rows.open, editor);
6640
6789
  const apply = (open) => {
6641
- const list = findZoneList(zone.label);
6642
- if (list) setAll(list, open, unstable_batchedUpdates);
6790
+ const list2 = findZoneList(zone.label);
6791
+ if (list2) setAll(list2, open, unstable_batchedUpdates);
6643
6792
  writeMemory(
6644
6793
  storage2(),
6645
6794
  memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }),
@@ -6734,14 +6883,14 @@ import { Box as Box4, Button as Button3, Flex as Flex3, MenuItem, SimpleMenu, Ty
6734
6883
  // admin/pane.mjs
6735
6884
  var TOOLBAR = ["modes", "history", "devices", "status", "actions"];
6736
6885
  var RIGHT = ["status", "actions"];
6737
- function toolbarLayout(list) {
6738
- const ids = Array.isArray(list) ? list.filter((id, i) => TOOLBAR.includes(id) && list.indexOf(id) === i) : TOOLBAR;
6886
+ function toolbarLayout(list2) {
6887
+ const ids = Array.isArray(list2) ? list2.filter((id, i) => TOOLBAR.includes(id) && list2.indexOf(id) === i) : TOOLBAR;
6739
6888
  const at = ids.findIndex((id) => RIGHT.includes(id));
6740
6889
  return at < 0 ? { before: ids, right: [], after: [] } : { before: ids.slice(0, at), right: ids.filter((id) => RIGHT.includes(id)), after: ids.slice(at).filter((id) => !RIGHT.includes(id)) };
6741
6890
  }
6742
- function deviceEntries(list, devices) {
6743
- const valid = Array.isArray(list) && list.length > 0 && list.every((item) => item in devices || item && typeof item === "object" && typeof item.label === "string" && Number.isInteger(item.width) && item.width > 0);
6744
- return (valid ? list : Object.keys(devices)).map((item) => typeof item === "string" ? { id: item, name: item, width: devices[item], icon: item } : { id: `px-${item.width}`, label: item.label, width: item.width, icon: item.width < 600 ? "mobile" : item.width < 1100 ? "tablet" : "desktop" });
6891
+ function deviceEntries(list2, devices) {
6892
+ const valid = Array.isArray(list2) && list2.length > 0 && list2.every((item) => item in devices || item && typeof item === "object" && typeof item.label === "string" && Number.isInteger(item.width) && item.width > 0);
6893
+ return (valid ? list2 : Object.keys(devices)).map((item) => typeof item === "string" ? { id: item, name: item, width: devices[item], icon: item } : { id: `px-${item.width}`, label: item.label, width: item.width, icon: item.width < 600 ? "mobile" : item.width < 1100 ? "tablet" : "desktop" });
6745
6894
  }
6746
6895
  var panels = [];
6747
6896
  var PANEL_ID = /^[A-Za-z0-9][\w-]{0,39}$/;
@@ -7147,6 +7296,34 @@ function ZoneBarTools({ state }) {
7147
7296
  ) })
7148
7297
  ] });
7149
7298
  }
7299
+ function GroupDiagnostics({ scope, groups, problems }) {
7300
+ const t = useMessages();
7301
+ const insertClose = (error) => {
7302
+ const end = (0, import_groups.groupRange)(scope.latest.current, error.index, groups)[1];
7303
+ scope.insertRows(end + 1, { __component: error.expected });
7304
+ };
7305
+ return /* @__PURE__ */ jsx9(Box4, { role: "alert", "data-testid": "page-preview-diagnostics", padding: 2, background: "danger100", hasRadius: true, children: /* @__PURE__ */ jsxs6("details", { children: [
7306
+ /* @__PURE__ */ jsx9("summary", { style: { cursor: "pointer" }, children: /* @__PURE__ */ jsx9(Typography4, { variant: "pi", fontWeight: "bold", textColor: "danger700", children: t.f("diagSummary", { count: problems.length }) }) }),
7307
+ /* @__PURE__ */ jsx9("ul", { style: { margin: "6px 0 0 16px", padding: 0 }, children: problems.map((error) => /* @__PURE__ */ jsxs6("li", { style: { marginBottom: 8 }, children: [
7308
+ /* @__PURE__ */ jsx9(Typography4, { variant: "pi", textColor: "neutral800", ...tagProps(scope.host.ds, "p"), children: t.f(
7309
+ error.code === "closeBeforeOpen" ? "diagCloseBeforeOpen" : error.code === "mismatch" ? "diagMismatch" : "diagUnclosed",
7310
+ { n: error.index + 1, uid: error.uid, open: error.open || "", expected: error.expected || "" }
7311
+ ) }),
7312
+ error.code === "unclosed" && scope.canEdit && /* @__PURE__ */ jsx9(Box4, { paddingTop: 1, children: /* @__PURE__ */ jsx9(
7313
+ Button3,
7314
+ {
7315
+ size: "S",
7316
+ variant: "danger-light",
7317
+ "data-testid": `diag-insert-close-${error.index}`,
7318
+ onClick: () => insertClose(error),
7319
+ style: { height: "auto", minHeight: 32, whiteSpace: "normal", textAlign: "left", paddingTop: 6, paddingBottom: 6 },
7320
+ children: t.f("diagInsertClose", { n: error.index + 1, expected: error.expected })
7321
+ }
7322
+ ) }),
7323
+ error.code === "closeBeforeOpen" && /* @__PURE__ */ jsx9(Typography4, { variant: "pi", textColor: "neutral600", ...tagProps(scope.host.ds, "p"), style: { marginTop: 2 }, children: t.diagStrayHint })
7324
+ ] }, `${error.code}-${error.index}`)) })
7325
+ ] }) });
7326
+ }
7150
7327
  function PagePreview({
7151
7328
  editor,
7152
7329
  state,
@@ -7154,13 +7331,13 @@ function PagePreview({
7154
7331
  groups = null,
7155
7332
  hiddenAttribute = null,
7156
7333
  form = null,
7157
- Modal: Modal2,
7334
+ Modal: Modal3,
7158
7335
  Toggle
7159
7336
  }) {
7160
7337
  const t = useMessages();
7161
- const { values, zone, zoneLabel: zoneLabel2, canEdit, latest, insertRows: insertRows2 } = usePreviewZone(host);
7338
+ const { values, zone, zoneLabel, canEdit, latest, insertRows: insertRows2 } = usePreviewZone(host);
7162
7339
  const { history, mode, setMode, block: blockModal, setBlock: setBlockModal, inserting, setInserting } = state;
7163
- const { onChange, get, put, notify, MediaLibrary: MediaLibraryDialog, Actions, ds } = host;
7340
+ const { onChange, get, put, notify, MediaLibrary: MediaLibraryDialog, Actions: Actions2, ds } = host;
7164
7341
  const deviceList = deviceEntries(editor?.previewDevices, DEVICES);
7165
7342
  const [deviceId, setDeviceState] = React8.useState(() => read(DEVICE_KEY));
7166
7343
  const device = deviceList.find((entry) => entry.id === deviceId) || deviceList[0];
@@ -7236,7 +7413,7 @@ function PagePreview({
7236
7413
  const live = React8.useRef({
7237
7414
  mode,
7238
7415
  canEdit,
7239
- zoneLabel: zoneLabel2,
7416
+ zoneLabel,
7240
7417
  components: host.components,
7241
7418
  setMode,
7242
7419
  onChange,
@@ -7246,7 +7423,7 @@ function PagePreview({
7246
7423
  live.current = {
7247
7424
  mode,
7248
7425
  canEdit,
7249
- zoneLabel: zoneLabel2,
7426
+ zoneLabel,
7250
7427
  components: host.components,
7251
7428
  setMode,
7252
7429
  onChange,
@@ -7439,7 +7616,7 @@ function PagePreview({
7439
7616
  channel,
7440
7617
  type
7441
7618
  );
7442
- const { mode: mode2, canEdit: canEdit2, zoneLabel: zoneLabel3, components, setMode: setMode2, onChange: onChange2 } = live.current;
7619
+ const { mode: mode2, canEdit: canEdit2, zoneLabel: zoneLabel2, components, setMode: setMode2, onChange: onChange2 } = live.current;
7443
7620
  if (is("ready")) {
7444
7621
  clearTimeout(timeout);
7445
7622
  setReady(true);
@@ -7518,9 +7695,9 @@ function PagePreview({
7518
7695
  const uid = index >= 0 ? latest.current[index]?.__component : "";
7519
7696
  if (index < 0) return;
7520
7697
  if (is("select")) {
7521
- const list = findZoneList(zoneLabel3);
7522
- const item = list?.querySelectorAll(":scope > li")[index];
7523
- const header = list ? toggles(list)[index] : null;
7698
+ const list2 = findZoneList(zoneLabel2);
7699
+ const item = list2?.querySelectorAll(":scope > li")[index];
7700
+ const header = list2 ? toggles(list2)[index] : null;
7524
7701
  if (header?.getAttribute("aria-expanded") === "false") header.click();
7525
7702
  item?.scrollIntoView({ block: "center", behavior: "smooth" });
7526
7703
  if (item) {
@@ -7581,9 +7758,9 @@ function PagePreview({
7581
7758
  iframe.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel, type: "hover", key }, origin);
7582
7759
  };
7583
7760
  const onOver = (event) => {
7584
- const list = findZoneList(live.current.zoneLabel);
7761
+ const list2 = findZoneList(live.current.zoneLabel);
7585
7762
  const target = event.target;
7586
- const index = list?.contains(target) ? [...list.querySelectorAll(":scope > li")].findIndex((li) => li.contains(target)) : -1;
7763
+ const index = list2?.contains(target) ? [...list2.querySelectorAll(":scope > li")].findIndex((li) => li.contains(target)) : -1;
7587
7764
  post(index >= 0 ? blockKey(latest.current[index]) : null);
7588
7765
  };
7589
7766
  const onOut = (event) => {
@@ -7759,7 +7936,7 @@ ${/* Strapi 4's scrolled header is fixed to the viewport's right edge: beside th
7759
7936
  children: [
7760
7937
  !ready && /* @__PURE__ */ jsx9(Typography4, { variant: "pi", role: "status", textColor: "neutral600", children: failed ? t.previewFailed : t.previewLoading }),
7761
7938
  failed && /* @__PURE__ */ jsx9(Button3, { size: "S", variant: "secondary", onClick: retry, children: t.retry }),
7762
- layout.right.length > 0 && /* @__PURE__ */ jsx9(Actions, { parts: layout.right })
7939
+ layout.right.length > 0 && /* @__PURE__ */ jsx9(Actions2, { parts: layout.right })
7763
7940
  ]
7764
7941
  }
7765
7942
  ),
@@ -7838,7 +8015,7 @@ ${/* Strapi 4's scrolled header is fixed to the viewport's right edge: beside th
7838
8015
  max: insertAttr.max
7839
8016
  },
7840
8017
  components: host.components,
7841
- Modal: Modal2,
8018
+ Modal: Modal3,
7842
8019
  Toggle,
7843
8020
  get,
7844
8021
  put,
@@ -7999,11 +8176,441 @@ ${/* Strapi 4's scrolled header is fixed to the viewport's right edge: beside th
7999
8176
  );
8000
8177
  }
8001
8178
 
8002
- // admin/Settings.tsx
8179
+ // admin/host5.tsx
8003
8180
  import * as React9 from "react";
8004
- import { Box as Box5, Button as Button4, Flex as Flex4, Searchbar as Searchbar2, Typography as Typography5 } from "@strapi/design-system";
8181
+ import { Button as Button4, Flex as Flex4, Status, Typography as Typography5 } from "@strapi/design-system";
8182
+ import { useIntl as useIntl2 } from "react-intl";
8183
+ import {
8184
+ DescriptionComponentRenderer,
8185
+ useFetchClient,
8186
+ useForm,
8187
+ useNotification,
8188
+ useQueryParams,
8189
+ useStrapiApp
8190
+ } from "@strapi/strapi/admin";
8191
+ import {
8192
+ unstable_useContentManagerContext as useContext,
8193
+ unstable_useDocument as useDocument,
8194
+ useDocumentRBAC
8195
+ } from "@strapi/content-manager/strapi-admin";
8196
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
8197
+ function usePreviewHost5() {
8198
+ const c = useContext();
8199
+ const rbac = useDocumentRBAC("BlockscenePagePreview", (state) => state);
8200
+ const values = useForm("BlockscenePagePreview", (state) => state.values);
8201
+ const initialValues = useForm("BlockscenePagePreview", (state) => state.initialValues);
8202
+ const setValues = useForm("BlockscenePagePreview", (state) => state.setValues);
8203
+ const onChange = useForm("BlockscenePagePreview", (state) => state.onChange);
8204
+ const addFieldRow = useForm("BlockscenePagePreview", (state) => state.addFieldRow);
8205
+ const moveFieldRow = useForm("BlockscenePagePreview", (state) => state.moveFieldRow);
8206
+ const { get, put } = useFetchClient();
8207
+ const { toggleNotification } = useNotification();
8208
+ const components = useStrapiApp("BlockscenePagePreview", (state) => state.components);
8209
+ const fields = c.layout?.edit?.layout?.flat(3) || [];
8210
+ const latest = React9.useRef(values);
8211
+ latest.current = values;
8212
+ const readable = React9.useCallback(
8213
+ (name) => c.isCreatingEntry || (rbac.canReadFields || []).includes(name),
8214
+ [c.isCreatingEntry, rbac.canReadFields]
8215
+ );
8216
+ return {
8217
+ ds: 2,
8218
+ model: c.model,
8219
+ documentId: c.id,
8220
+ locale: c.form?.initialValues?.locale,
8221
+ creating: Boolean(c.isCreatingEntry),
8222
+ loading: Boolean(c.isLoading),
8223
+ disabled: Boolean(c.form?.disabled),
8224
+ contentType: c.contentType,
8225
+ components: c.components,
8226
+ values,
8227
+ history: typeof setValues === "function" ? { epoch: initialValues, setValues } : null,
8228
+ readable,
8229
+ editable: (name) => ((c.isCreatingEntry ? rbac.canCreateFields : rbac.canUpdateFields) || []).includes(name) && fields.find((f) => f.name === name)?.disabled !== true && typeof addFieldRow === "function",
8230
+ fieldLabel: (name) => fields.find((f) => f.name === name)?.label || name,
8231
+ onChange,
8232
+ // Append then move: Strapi < 5.8.1 addFieldRow(field, value, index) overwrites the row at index instead of inserting.
8233
+ insertRows: (zone, at, items2) => {
8234
+ const length = Array.isArray(latest.current?.[zone]) ? latest.current[zone].length : 0;
8235
+ items2.forEach((item, i) => {
8236
+ addFieldRow(zone, item);
8237
+ if (at + i < length + i) moveFieldRow(zone, length + i, at + i);
8238
+ });
8239
+ },
8240
+ get,
8241
+ put,
8242
+ notify: (type, message) => toggleNotification({ type, message }),
8243
+ MediaLibrary: components?.["media-library"],
8244
+ useNativeBase,
8245
+ Actions
8246
+ };
8247
+ }
8248
+ function useNativeBase(skip, model, documentId, locale) {
8249
+ const { get } = useFetchClient();
8250
+ const [native, setNative] = React9.useState(null);
8251
+ React9.useEffect(() => {
8252
+ if (skip || !model) return;
8253
+ let active = true;
8254
+ const query2 = new URLSearchParams({
8255
+ status: "draft",
8256
+ ...documentId ? { documentId: String(documentId) } : {},
8257
+ ...locale ? { locale } : {}
8258
+ });
8259
+ get(`/content-manager/preview/url/${model}?${query2}`).then(({ data }) => {
8260
+ if (active && typeof data?.data?.url === "string")
8261
+ setNative(`${new URL(data.data.url).origin}/block-preview/page`);
8262
+ }).catch(() => {
8263
+ if (active) setNative(null);
8264
+ });
8265
+ return () => {
8266
+ active = false;
8267
+ };
8268
+ }, [get, model, documentId, locale, skip]);
8269
+ return skip ? null : native;
8270
+ }
8271
+ function Actions({ parts }) {
8272
+ const c = useContext();
8273
+ return /* @__PURE__ */ jsx10(
8274
+ ToolbarActions,
8275
+ {
8276
+ model: c.model,
8277
+ collectionType: c.collectionType,
8278
+ documentId: c.isCreatingEntry ? void 0 : c.id,
8279
+ locale: c.form?.initialValues?.locale,
8280
+ parts
8281
+ }
8282
+ );
8283
+ }
8284
+ var ACTION_TYPES = ["update", "publish"];
8285
+ var nativeButtons = () => document.querySelectorAll(
8286
+ '#main-content button:not([data-testid="page-preview-pane"] button)'
8287
+ );
8288
+ function ToolbarActions({ model, collectionType, documentId, locale, parts }) {
8289
+ const plugins = useStrapiApp(
8290
+ "BlocksceneToolbar",
8291
+ (state) => state.plugins
8292
+ );
8293
+ const [{ query: query2 }] = useQueryParams();
8294
+ const { document: doc, meta } = useDocument(
8295
+ { model, collectionType, documentId, params: { locale } },
8296
+ { skip: !documentId }
8297
+ );
8298
+ const { toggleNotification } = useNotification();
8299
+ const t = useMessages();
8300
+ const { formatMessage } = useIntl2();
8301
+ const modified = useForm("BlocksceneToolbar", (state) => state.modified);
8302
+ const status = documentId ? doc?.status : void 0;
8303
+ const descriptions = (plugins["content-manager"]?.apis?.getDocumentActions?.("panel") || []).filter((d) => ACTION_TYPES.includes(d.type));
8304
+ const props = {
8305
+ activeTab: query2.status || "draft",
8306
+ model,
8307
+ documentId,
8308
+ document: doc,
8309
+ meta,
8310
+ collectionType
8311
+ };
8312
+ const run = async (action, event) => {
8313
+ const native = [...nativeButtons()].find(
8314
+ (b) => b.textContent?.trim() === action.label
8315
+ );
8316
+ if (native) {
8317
+ native.click();
8318
+ return;
8319
+ }
8320
+ const mute = await action.onClick?.(event);
8321
+ if (action.dialog && !mute && action.dialog.type === "notification")
8322
+ toggleNotification({
8323
+ title: action.dialog.title,
8324
+ message: action.dialog.content,
8325
+ type: action.dialog.status
8326
+ });
8327
+ };
8328
+ const typeOf = (action) => action.type || descriptions.find(
8329
+ (d) => typeof action.id === "string" && action.id.startsWith(`${d.name || d.displayName}-`)
8330
+ )?.type;
8331
+ return /* @__PURE__ */ jsx10(DescriptionComponentRenderer, { props, descriptions, children: (actions) => /* @__PURE__ */ jsxs7(Flex4, { gap: 2, alignItems: "center", "data-testid": "page-preview-actions", children: [
8332
+ parts.includes("status") && (status || modified) && /* @__PURE__ */ jsxs7(Flex4, { gap: 2, alignItems: "center", style: { order: parts.indexOf("status") }, children: [
8333
+ status && /* @__PURE__ */ jsx10(
8334
+ Status,
8335
+ {
8336
+ size: "S",
8337
+ role: "status",
8338
+ "data-testid": "page-preview-status",
8339
+ variant: status === "draft" ? "secondary" : status === "published" ? "success" : "alternative",
8340
+ children: /* @__PURE__ */ jsx10(Typography5, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({ id: `content-manager.containers.List.${status}`, defaultMessage: status.charAt(0).toUpperCase() + status.slice(1) }) })
8341
+ }
8342
+ ),
8343
+ modified && /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.unsaved })
8344
+ ] }),
8345
+ parts.includes("actions") && [...actions].sort(
8346
+ (a, b) => ACTION_TYPES.indexOf(typeOf(a)) - ACTION_TYPES.indexOf(typeOf(b))
8347
+ ).map((action) => {
8348
+ const reason = action.disabled ? typeOf(action) === "publish" ? t.publishDisabledHint : t.saveDisabledHint : void 0;
8349
+ return /* @__PURE__ */ jsx10("span", { title: reason, style: { order: parts.indexOf("actions") }, children: /* @__PURE__ */ jsx10(
8350
+ Button4,
8351
+ {
8352
+ size: "S",
8353
+ variant: typeOf(action) === "publish" ? "default" : "secondary",
8354
+ disabled: action.disabled,
8355
+ loading: action.loading,
8356
+ "aria-description": reason,
8357
+ onClick: (e) => run(action, e),
8358
+ children: action.label
8359
+ }
8360
+ ) }, action.id);
8361
+ })
8362
+ ] }) });
8363
+ }
8364
+
8365
+ // admin/History.tsx
8366
+ import * as React10 from "react";
8367
+ import { Box as Box5, Button as Button5, Flex as Flex5, Typography as Typography6 } from "@strapi/design-system";
8368
+ import { useForm as useForm2, useQueryParams as useQueryParams2, useRBAC } from "@strapi/strapi/admin";
8369
+
8370
+ // admin/versions.mjs
8371
+ var import_diff = __toESM(require_diff(), 1);
8372
+ import { generateNKeysBetween as generateNKeysBetween3 } from "fractional-indexing";
8373
+ var targetOf = (attr) => attr.targetModel || attr.target;
8374
+ var list = (value) => Array.isArray(value) ? value : value == null ? [] : [value];
8375
+ var withKeys = (rows) => {
8376
+ const keys = rows.length ? generateNKeysBetween3(null, null, rows.length) : [];
8377
+ return rows.map((row, i) => ({ ...row, __temp_key__: keys[i] }));
8378
+ };
8379
+ function formDiff(snapshot, formValues, schema, components) {
8380
+ const schemaOf = (uid) => components?.[uid];
8381
+ const version = (0, import_diff.canonical)(snapshot, schema, schemaOf, { relations: false });
8382
+ const form = (0, import_diff.canonical)(formValues, schema, schemaOf, { relations: false });
8383
+ const zones = [];
8384
+ const fields = [];
8385
+ for (const [name, attr] of Object.entries(schema?.attributes || {})) {
8386
+ if (!(0, import_diff.kept)(name, attr) || attr.type === "relation") continue;
8387
+ if (attr.type === "dynamiczone") {
8388
+ const ops = (0, import_diff.diffRows)(form[name] || [], version[name] || []).filter((op) => op.op !== "same");
8389
+ if (ops.length) zones.push({ name, ops });
8390
+ } else if (!(0, import_diff.same)(form[name], version[name])) fields.push(name);
8391
+ }
8392
+ return { fields, zones };
8393
+ }
8394
+ function loadVersion(snapshot, { schema, components, current = {}, media = {}, relations = {}, server = {}, editable = () => true }) {
8395
+ const schemaOf = (uid) => components?.[uid];
8396
+ const report = { left: [], removed: [], blocks: 0, media: 0, relations: 0 };
8397
+ const file = (id) => media[id] || (report.media++, null);
8398
+ const resolve = (attr, refs) => {
8399
+ const targets = relations[targetOf(attr)] || [];
8400
+ const found = [];
8401
+ for (const ref of refs) {
8402
+ const hit = targets.find((r) => r.documentId === ref.documentId && (r.locale || null) === (ref.locale || null)) || targets.find((r) => r.documentId === ref.documentId);
8403
+ if (hit) found.push(hit);
8404
+ else report.relations++;
8405
+ }
8406
+ return found;
8407
+ };
8408
+ const build = (data, schema2) => {
8409
+ const out = {};
8410
+ for (const [name, attr] of Object.entries(schema2?.attributes || {})) {
8411
+ const value = data?.[name];
8412
+ if (!(0, import_diff.kept)(name, attr)) continue;
8413
+ if (attr.type === "relation") out[name] = toConnect(resolve(attr, list(value)), targetOf(attr));
8414
+ else if (value === void 0 || value === null) continue;
8415
+ else if (attr.type === "media") {
8416
+ if (attr.multiple) out[name] = list(value).map(file).filter(Boolean);
8417
+ else out[name] = file(value);
8418
+ } else if (attr.type === "component") {
8419
+ const child = schemaOf(attr.component);
8420
+ out[name] = attr.repeatable ? withKeys(list(value).map((item) => build(item, child))) : build(value, child);
8421
+ } else if (attr.type === "dynamiczone") out[name] = zone(attr, value);
8422
+ else out[name] = structuredClone(value);
8423
+ }
8424
+ return out;
8425
+ };
8426
+ const zone = (attr, rows) => withKeys(list(rows).filter((row) => {
8427
+ const ok = row && attr.components?.includes(row.__component) && schemaOf(row.__component);
8428
+ if (!ok) report.blocks++;
8429
+ return ok;
8430
+ }).map((row) => ({ ...build(row, schemaOf(row.__component)), __component: row.__component })));
8431
+ const values = { ...current };
8432
+ for (const name of Object.keys(snapshot || {})) if (!schema?.attributes?.[name]) report.removed.push(name);
8433
+ for (const [name, attr] of Object.entries(schema?.attributes || {})) {
8434
+ if (!(0, import_diff.kept)(name, attr)) continue;
8435
+ const value = snapshot?.[name];
8436
+ const empty = value === void 0 || value === null;
8437
+ if (!editable(name)) {
8438
+ if (!empty || current[name] != null) report.left.push(name);
8439
+ continue;
8440
+ }
8441
+ if (attr.type === "relation") {
8442
+ if (!Array.isArray(server[name])) {
8443
+ report.left.push(name);
8444
+ continue;
8445
+ }
8446
+ const wanted = resolve(attr, list(value));
8447
+ const has = new Set(server[name].map((r) => r.documentId));
8448
+ const keep = new Set(wanted.map((r) => r.documentId));
8449
+ values[name] = {
8450
+ connect: toConnect(wanted.filter((r) => !has.has(r.documentId)), targetOf(attr)).connect,
8451
+ disconnect: server[name].filter((r) => !keep.has(r.documentId)).map((r) => ({ id: r.id, status: r.status, apiData: { id: r.id, documentId: r.documentId, locale: r.locale } }))
8452
+ };
8453
+ } else if (attr.type === "component" || attr.type === "dynamiczone") {
8454
+ if (attr.type === "dynamiczone") values[name] = zone(attr, value);
8455
+ else if (attr.repeatable) values[name] = withKeys(list(value).map((item) => build(item, schemaOf(attr.component))));
8456
+ else values[name] = empty ? null : build(value, schemaOf(attr.component));
8457
+ } else if (attr.type === "media") {
8458
+ values[name] = attr.multiple ? list(value).map(file).filter(Boolean) : empty ? null : file(value);
8459
+ } else if (!empty) values[name] = structuredClone(value);
8460
+ else if (current[name] != null && current[name] !== "") values[name] = null;
8461
+ }
8462
+ return { values, report };
8463
+ }
8464
+
8465
+ // admin/History.tsx
8466
+ import { Fragment as Fragment8, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
8467
+ var HISTORY_READ = [{ action: "plugin::blockscene.history.read", subject: null }];
8468
+ var PAGE = 10;
8469
+ function summaryText(t, s) {
8470
+ if (!s) return "";
8471
+ if (s.missing) return t.historyMissing;
8472
+ if (s.initial) return t.historyInitial;
8473
+ const parts = [];
8474
+ const b = s.blocks || {};
8475
+ if (b.added || b.removed || b.changed) parts.push(t.f("historyBlocksSummary", { added: b.added || 0, removed: b.removed || 0, changed: b.changed || 0 }));
8476
+ if (s.fields?.length) parts.push(t.f("historyFieldsSummary", { fields: s.fields.join(", ") }));
8477
+ return parts.join(" \xB7 ") || t.historyNoChange;
8478
+ }
8479
+ function History({ model, documentId, schema, components, editable, disabled, get, relationsOf: relationsOf2 }) {
8480
+ const t = useMessages();
8481
+ const { allowedActions, isLoading } = useRBAC(HISTORY_READ);
8482
+ const [{ query: query2 }] = useQueryParams2();
8483
+ const locale = typeof query2?.plugins?.i18n?.locale === "string" ? query2.plugins.i18n.locale : "";
8484
+ const values = useForm2("BlocksceneVersions", (state) => state.values);
8485
+ const initialValues = useForm2("BlocksceneVersions", (state) => state.initialValues);
8486
+ const setValues = useForm2("BlocksceneVersions", (state) => state.setValues);
8487
+ const [events, setEvents] = React10.useState(null);
8488
+ const [failed, setFailed] = React10.useState(false);
8489
+ const [shown, setShown] = React10.useState(PAGE);
8490
+ const [open, setOpen] = React10.useState(null);
8491
+ const [report, setReport] = React10.useState(null);
8492
+ const [loading, setLoading] = React10.useState(false);
8493
+ const [refresh, reload] = React10.useReducer((n) => n + 1, 0);
8494
+ const allowed = Boolean(allowedActions?.canRead);
8495
+ React10.useEffect(() => {
8496
+ if (!allowed || !documentId) return;
8497
+ let active = true;
8498
+ setFailed(false);
8499
+ get(`/blockscene/history/${encodeURIComponent(model)}/${encodeURIComponent(documentId)}${locale ? `?locale=${encodeURIComponent(locale)}` : ""}`).then(({ data }) => active && setEvents(Array.isArray(data?.results) ? data.results : [])).catch(() => active && setFailed(true));
8500
+ return () => {
8501
+ active = false;
8502
+ };
8503
+ }, [allowed, get, model, documentId, locale, initialValues, refresh]);
8504
+ React10.useEffect(() => {
8505
+ setOpen(null);
8506
+ setReport(null);
8507
+ setShown(PAGE);
8508
+ }, [model, documentId, locale]);
8509
+ if (isLoading || !allowed || !documentId) return null;
8510
+ const name = (uid) => components?.[uid]?.info?.displayName || uid;
8511
+ const when2 = (at) => {
8512
+ try {
8513
+ return new Date(at).toLocaleString(t.locale, { dateStyle: "medium", timeStyle: "short" });
8514
+ } catch {
8515
+ return at;
8516
+ }
8517
+ };
8518
+ const summary = (s) => summaryText(t, s);
8519
+ const select = async (event) => {
8520
+ setReport(null);
8521
+ if (open?.event?.id === event.id) return setOpen(null);
8522
+ setOpen({ event, loading: true });
8523
+ try {
8524
+ const { data } = await get(`/blockscene/history-events/${event.id}`);
8525
+ setOpen({ event, ...data });
8526
+ } catch {
8527
+ setOpen({ event, failed: true });
8528
+ }
8529
+ };
8530
+ const load2 = async () => {
8531
+ if (!open?.snapshot || typeof setValues !== "function" || disabled) return;
8532
+ setLoading(true);
8533
+ setReport(null);
8534
+ try {
8535
+ const server = {};
8536
+ for (const [field, attr] of Object.entries(schema?.attributes || {}))
8537
+ if (attr?.type === "relation" && editable(field)) server[field] = await relationsOf2(get, { uid: model, id: documentId, field }, locale).catch(() => void 0);
8538
+ const { values: next, report: report2 } = loadVersion(open.snapshot, { schema, components, current: values, media: open.media, relations: open.relations, server, editable });
8539
+ setValues(next);
8540
+ setReport(report2);
8541
+ } catch {
8542
+ setReport({ failed: true });
8543
+ } finally {
8544
+ setLoading(false);
8545
+ }
8546
+ };
8547
+ const diff = open?.snapshot ? formDiff(open.snapshot, values, schema, components) : null;
8548
+ const same2 = diff && !diff.fields.length && !diff.zones.length;
8549
+ return /* @__PURE__ */ jsxs8(Flex5, { direction: "column", alignItems: "stretch", gap: 2, "data-testid": "blockscene-versions", children: [
8550
+ /* @__PURE__ */ jsxs8(Flex5, { justifyContent: "space-between", alignItems: "center", children: [
8551
+ /* @__PURE__ */ jsx11(Typography6, { variant: "sigma", tag: "h3", textColor: "neutral600", children: t.historyTitle }),
8552
+ /* @__PURE__ */ jsx11(Button5, { variant: "tertiary", size: "S", onClick: reload, children: t.historyRefresh })
8553
+ ] }),
8554
+ failed ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", role: "alert", textColor: "danger600", children: t.historyFailed }) : !events ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "neutral600", children: t.historyLoading }) : !events.length ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "neutral600", children: t.historyEmpty }) : /* @__PURE__ */ jsxs8(Flex5, { tag: "ol", direction: "column", alignItems: "stretch", gap: 1, style: { listStyle: "none", margin: 0, padding: 0 }, children: [
8555
+ events.slice(0, shown).map((event) => {
8556
+ const active = open?.event?.id === event.id;
8557
+ return /* @__PURE__ */ jsxs8("li", { "data-testid": `history-event-${event.id}`, children: [
8558
+ /* @__PURE__ */ jsx11(
8559
+ Box5,
8560
+ {
8561
+ tag: "button",
8562
+ type: "button",
8563
+ onClick: () => select(event),
8564
+ "aria-expanded": active,
8565
+ padding: 2,
8566
+ hasRadius: true,
8567
+ width: "100%",
8568
+ background: active ? "primary100" : "neutral0",
8569
+ borderColor: active ? "primary200" : "neutral150",
8570
+ style: { textAlign: "left", cursor: "pointer", borderStyle: "solid", borderWidth: 1 },
8571
+ children: /* @__PURE__ */ jsxs8(Flex5, { direction: "column", alignItems: "flex-start", gap: 1, children: [
8572
+ /* @__PURE__ */ jsx11(Typography6, { variant: "omega", fontWeight: "bold", children: t.historyActions[event.action] || event.action }),
8573
+ /* @__PURE__ */ jsxs8(Typography6, { variant: "pi", textColor: "neutral600", children: [
8574
+ event.actorName || (event.actor === "system" ? t.historySystem : event.actor),
8575
+ " \xB7 ",
8576
+ when2(event.at)
8577
+ ] }),
8578
+ /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: event.summary?.missing ? "warning700" : "neutral700", children: summary(event.summary) })
8579
+ ] })
8580
+ }
8581
+ ),
8582
+ active && /* @__PURE__ */ jsx11(Box5, { padding: 3, background: "neutral100", hasRadius: true, marginTop: 1, children: open.loading ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", children: t.historyLoading }) : open.failed ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", role: "alert", textColor: "danger600", children: t.historyLoadFailed }) : !open.snapshot ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "neutral600", children: t.historyNotKept }) : /* @__PURE__ */ jsxs8(Flex5, { direction: "column", alignItems: "stretch", gap: 2, children: [
8583
+ /* @__PURE__ */ jsx11(Typography6, { variant: "pi", fontWeight: "bold", children: t.historyCompare }),
8584
+ same2 ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "neutral600", children: t.historySame }) : /* @__PURE__ */ jsxs8(Fragment8, { children: [
8585
+ diff.fields.length > 0 && /* @__PURE__ */ jsx11(Typography6, { variant: "pi", children: t.f("historyDiffFields", { fields: diff.fields.join(", ") }) }),
8586
+ diff.zones.map((zone) => /* @__PURE__ */ jsx11(Flex5, { tag: "ul", direction: "column", alignItems: "stretch", gap: 1, style: { margin: 0, paddingLeft: 16 }, "data-testid": `history-diff-${zone.name}`, children: zone.ops.map((op, i) => /* @__PURE__ */ jsx11("li", { children: /* @__PURE__ */ jsxs8(Typography6, { variant: "pi", textColor: op.op === "added" ? "success700" : op.op === "removed" ? "danger700" : "warning700", children: [
8587
+ t.diffOps[op.op],
8588
+ ": ",
8589
+ name(op.uid),
8590
+ op.to !== void 0 ? ` (#${op.to + 1})` : op.from !== void 0 ? ` (#${op.from + 1})` : ""
8591
+ ] }) }, i)) }, zone.name))
8592
+ ] }),
8593
+ /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "neutral600", children: t.historyDiffNote }),
8594
+ /* @__PURE__ */ jsx11(Flex5, { children: /* @__PURE__ */ jsx11(Button5, { size: "S", onClick: load2, loading, disabled: disabled || loading, "data-testid": "history-load", children: t.historyLoad }) }),
8595
+ report && /* @__PURE__ */ jsx11(Box5, { role: "status", padding: 2, background: report.failed ? "danger100" : "success100", hasRadius: true, children: report.failed ? /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "danger700", children: t.historyLoadFailed }) : /* @__PURE__ */ jsxs8(Flex5, { direction: "column", alignItems: "flex-start", gap: 1, children: [
8596
+ /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "success700", children: t.historyLoaded }),
8597
+ report.left.length > 0 && /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "warning700", "data-testid": "history-left", children: t.f("historyLeft", { fields: report.left.join(", ") }) }),
8598
+ report.removed.length > 0 && /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "warning700", children: t.f("historyRemovedFields", { fields: report.removed.join(", ") }) }),
8599
+ (report.media || report.relations || report.blocks) > 0 && /* @__PURE__ */ jsx11(Typography6, { variant: "pi", textColor: "warning700", children: t.f("historyMissingItems", { media: report.media, relations: report.relations, blocks: report.blocks }) })
8600
+ ] }) })
8601
+ ] }) })
8602
+ ] }, event.id);
8603
+ }),
8604
+ events.length > shown && /* @__PURE__ */ jsx11(Flex5, { children: /* @__PURE__ */ jsx11(Button5, { variant: "tertiary", size: "S", onClick: () => setShown(shown + PAGE), children: t.historyShowMore }) })
8605
+ ] })
8606
+ ] });
8607
+ }
8608
+
8609
+ // admin/Settings.tsx
8610
+ import * as React11 from "react";
8611
+ import { Box as Box6, Button as Button6, Flex as Flex6, Searchbar as Searchbar2, Typography as Typography7 } from "@strapi/design-system";
8005
8612
  import styled7 from "styled-components";
8006
- import { Fragment as Fragment8, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
8613
+ import { Fragment as Fragment9, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
8007
8614
  var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
8008
8615
  var Grid2 = styled7.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
8009
8616
  var Card2 = styled7.div`
@@ -8016,17 +8623,17 @@ var Bar = styled7.div`
8016
8623
  box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
8017
8624
  `;
8018
8625
  function useMainRect2(anchor) {
8019
- const [rect, setRect] = React9.useState({ left: 0, width: 0 });
8020
- React9.useEffect(() => {
8021
- const read2 = () => {
8626
+ const [rect, setRect] = React11.useState({ left: 0, width: 0 });
8627
+ React11.useEffect(() => {
8628
+ const read3 = () => {
8022
8629
  let host = document.getElementById("main-content");
8023
8630
  for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
8024
8631
  const r = (host || document.querySelector("main"))?.getBoundingClientRect();
8025
8632
  if (r) setRect({ left: Math.round(r.left), width: Math.round(r.width) });
8026
8633
  };
8027
- read2();
8028
- window.addEventListener("resize", read2);
8029
- return () => window.removeEventListener("resize", read2);
8634
+ read3();
8635
+ window.addEventListener("resize", read3);
8636
+ return () => window.removeEventListener("resize", read3);
8030
8637
  });
8031
8638
  return rect;
8032
8639
  }
@@ -8034,11 +8641,11 @@ var Swatches = styled7.div` display: grid; grid-template-columns: repeat(auto-fi
8034
8641
  var Label = styled7.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
8035
8642
  function ColorField({ name, label, value, onChange, disabled }) {
8036
8643
  const valid = COLOR2.test(value);
8037
- return /* @__PURE__ */ jsxs7(Label, { children: [
8038
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
8039
- /* @__PURE__ */ jsxs7(Flex4, { gap: 2, children: [
8040
- /* @__PURE__ */ jsx10("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" } }),
8041
- /* @__PURE__ */ jsx10(
8644
+ return /* @__PURE__ */ jsxs9(Label, { children: [
8645
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
8646
+ /* @__PURE__ */ jsxs9(Flex6, { gap: 2, children: [
8647
+ /* @__PURE__ */ jsx12("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" } }),
8648
+ /* @__PURE__ */ jsx12(
8042
8649
  "input",
8043
8650
  {
8044
8651
  name,
@@ -8054,14 +8661,14 @@ function ColorField({ name, label, value, onChange, disabled }) {
8054
8661
  ] });
8055
8662
  }
8056
8663
  function TagsField({ name, label, hint, value, onChange, disabled }) {
8057
- const [text, setText] = React9.useState(value.join(", "));
8058
- return /* @__PURE__ */ jsxs7(Label, { children: [
8059
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
8060
- /* @__PURE__ */ jsx10("input", { name, value: text, disabled, onChange: (e) => {
8664
+ const [text, setText] = React11.useState(value.join(", "));
8665
+ return /* @__PURE__ */ jsxs9(Label, { children: [
8666
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
8667
+ /* @__PURE__ */ jsx12("input", { name, value: text, disabled, onChange: (e) => {
8061
8668
  setText(e.target.value);
8062
8669
  onChange([...new Set(e.target.value.split(",").map((tag) => tag.replace(/[<>]/g, "").trim().slice(0, 24)).filter(Boolean))].slice(0, 10));
8063
8670
  }, style: { padding: "6px 8px", border: "1px solid #dcdce4", borderRadius: 4, fontSize: 13 } }),
8064
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: hint })
8671
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: hint })
8065
8672
  ] });
8066
8673
  }
8067
8674
  var FIELD_UID = /^(plugin|global)::[\w.-]+$/;
@@ -8069,11 +8676,11 @@ var LAZY_MAX = 20;
8069
8676
  var parseUids = (text) => [...new Set(text.split(/[\s,]+/).filter(Boolean))];
8070
8677
  var badUids = (uids = []) => uids.length > LAZY_MAX || uids.some((uid) => !FIELD_UID.test(uid));
8071
8678
  function UidListField({ TextField: TextField2, value, onChange, ...props }) {
8072
- const [text, setText] = React9.useState(value.join(", "));
8073
- React9.useEffect(() => {
8679
+ const [text, setText] = React11.useState(value.join(", "));
8680
+ React11.useEffect(() => {
8074
8681
  if (parseUids(text).join() !== value.join()) setText(value.join(", "));
8075
8682
  }, [value.join()]);
8076
- return /* @__PURE__ */ jsx10(TextField2, { ...props, value: text, onChange: (v) => {
8683
+ return /* @__PURE__ */ jsx12(TextField2, { ...props, value: text, onChange: (v) => {
8077
8684
  setText(v);
8078
8685
  onChange(parseUids(v));
8079
8686
  } });
@@ -8095,50 +8702,50 @@ var Checks = styled7.fieldset`
8095
8702
  var TOOLBAR2 = ["modes", "history", "devices", "status", "actions"];
8096
8703
  var DEVICE_NAMES = ["fit", "mobile", "tablet", "desktop"];
8097
8704
  var DEVICE_LABEL = /^[^<>]{1,24}$/;
8098
- var badDevices = (list = []) => list.length < 1 || list.length > 8 || list.some((item) => typeof item !== "string" && (!DEVICE_LABEL.test(String(item.label || "").trim()) || !(Number.isInteger(item.width) && item.width >= 240 && item.width <= 3840))) || new Set(list.map((item) => typeof item === "string" ? item : item.width)).size !== list.length;
8705
+ var badDevices = (list2 = []) => list2.length < 1 || list2.length > 8 || list2.some((item) => typeof item !== "string" && (!DEVICE_LABEL.test(String(item.label || "").trim()) || !(Number.isInteger(item.width) && item.width >= 240 && item.width <= 3840))) || new Set(list2.map((item) => typeof item === "string" ? item : item.width)).size !== list2.length;
8099
8706
  var Row = styled7.div` display: flex; align-items: center; gap: 8px; min-height: 36px; font-size: 13px; color: ${({ theme }) => theme.colors.neutral800}; `;
8100
8707
  function PaneEditor({ id, toolbar, devices, set: set2, t, disabled, TextField: TextField2 }) {
8101
- const move = (list, index, by) => {
8102
- const next = [...list];
8708
+ const move = (list2, index, by) => {
8709
+ const next = [...list2];
8103
8710
  [next[index], next[index + by]] = [next[index + by], next[index]];
8104
8711
  return next;
8105
8712
  };
8106
- const arrows = (list, index, key) => /* @__PURE__ */ jsxs7(Fragment8, { children: [
8107
- /* @__PURE__ */ jsx10(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index < 0 || index === 0, onClick: () => set2(key, move(list, index, -1)) }),
8108
- /* @__PURE__ */ jsx10(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index < 0 || index === list.length - 1, onClick: () => set2(key, move(list, index, 1)) })
8713
+ const arrows = (list2, index, key) => /* @__PURE__ */ jsxs9(Fragment9, { children: [
8714
+ /* @__PURE__ */ jsx12(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index < 0 || index === 0, onClick: () => set2(key, move(list2, index, -1)) }),
8715
+ /* @__PURE__ */ jsx12(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index < 0 || index === list2.length - 1, onClick: () => set2(key, move(list2, index, 1)) })
8109
8716
  ] });
8110
- const check = (list, item, key) => /* @__PURE__ */ jsx10(
8717
+ const check = (list2, item, key) => /* @__PURE__ */ jsx12(
8111
8718
  "input",
8112
8719
  {
8113
8720
  type: "checkbox",
8114
8721
  name: `${id}-${key}-${item}`,
8115
- checked: list.includes(item),
8722
+ checked: list2.includes(item),
8116
8723
  disabled,
8117
- onChange: (e) => set2(key, e.target.checked ? [...list, item] : list.filter((entry) => entry !== item))
8724
+ onChange: (e) => set2(key, e.target.checked ? [...list2, item] : list2.filter((entry) => entry !== item))
8118
8725
  }
8119
8726
  );
8120
8727
  const width = (index, patch) => set2("previewDevices", devices.map((item, i) => i === index ? { ...item, ...patch } : item));
8121
- return /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 3, "data-testid": `pane-editor-${id}`, children: [
8122
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.paneHelp }),
8123
- /* @__PURE__ */ jsx10(Box5, { children: [...toolbar, ...TOOLBAR2.filter((item) => !toolbar.includes(item))].map((item) => /* @__PURE__ */ jsxs7(Row, { "data-testid": `${id}-toolbar-${item}`, children: [
8728
+ return /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 3, "data-testid": `pane-editor-${id}`, children: [
8729
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.paneHelp }),
8730
+ /* @__PURE__ */ jsx12(Box6, { children: [...toolbar, ...TOOLBAR2.filter((item) => !toolbar.includes(item))].map((item) => /* @__PURE__ */ jsxs9(Row, { "data-testid": `${id}-toolbar-${item}`, children: [
8124
8731
  arrows(toolbar, toolbar.indexOf(item), "previewToolbar"),
8125
- /* @__PURE__ */ jsxs7("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
8732
+ /* @__PURE__ */ jsxs9("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
8126
8733
  check(toolbar, item, "previewToolbar"),
8127
8734
  t.toolbar[item]
8128
8735
  ] })
8129
8736
  ] }, item)) }),
8130
- /* @__PURE__ */ jsx10(Typography5, { variant: "delta", tag: "h3", children: t.paneDevices }),
8131
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.paneDevicesHelp }),
8132
- /* @__PURE__ */ jsx10(Box5, { children: [...devices, ...DEVICE_NAMES.filter((item) => !devices.includes(item))].map((item) => {
8737
+ /* @__PURE__ */ jsx12(Typography7, { variant: "delta", tag: "h3", children: t.paneDevices }),
8738
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.paneDevicesHelp }),
8739
+ /* @__PURE__ */ jsx12(Box6, { children: [...devices, ...DEVICE_NAMES.filter((item) => !devices.includes(item))].map((item) => {
8133
8740
  const index = devices.indexOf(item);
8134
- return /* @__PURE__ */ jsxs7(Row, { "data-testid": `${id}-device-${typeof item === "string" ? item : index}`, children: [
8741
+ return /* @__PURE__ */ jsxs9(Row, { "data-testid": `${id}-device-${typeof item === "string" ? item : index}`, children: [
8135
8742
  arrows(devices, index, "previewDevices"),
8136
- typeof item === "string" ? /* @__PURE__ */ jsxs7("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
8743
+ typeof item === "string" ? /* @__PURE__ */ jsxs9("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
8137
8744
  check(devices, item, "previewDevices"),
8138
8745
  t.device[item]
8139
- ] }) : /* @__PURE__ */ jsxs7(Fragment8, { children: [
8140
- /* @__PURE__ */ jsx10(Box5, { style: { flex: "1 1 160px" }, children: /* @__PURE__ */ jsx10(TextField2, { name: `${id}-device-label-${index}`, label: t.paneWidthLabel, value: item.label, disabled, onChange: (v) => width(index, { label: v }) }) }),
8141
- /* @__PURE__ */ jsx10(Box5, { style: { width: 140 }, children: /* @__PURE__ */ jsx10(
8746
+ ] }) : /* @__PURE__ */ jsxs9(Fragment9, { children: [
8747
+ /* @__PURE__ */ jsx12(Box6, { style: { flex: "1 1 160px" }, children: /* @__PURE__ */ jsx12(TextField2, { name: `${id}-device-label-${index}`, label: t.paneWidthLabel, value: item.label, disabled, onChange: (v) => width(index, { label: v }) }) }),
8748
+ /* @__PURE__ */ jsx12(Box6, { style: { width: 140 }, children: /* @__PURE__ */ jsx12(
8142
8749
  TextField2,
8143
8750
  {
8144
8751
  name: `${id}-device-width-${index}`,
@@ -8148,12 +8755,12 @@ function PaneEditor({ id, toolbar, devices, set: set2, t, disabled, TextField: T
8148
8755
  onChange: (v) => width(index, { width: /^\d{1,4}$/.test(v.trim()) ? Number(v.trim()) : NaN })
8149
8756
  }
8150
8757
  ) }),
8151
- /* @__PURE__ */ jsx10(Tool, { icon: "close", label: t.paneRemoveWidth, disabled, onClick: () => set2("previewDevices", devices.filter((_, i) => i !== index)) })
8758
+ /* @__PURE__ */ jsx12(Tool, { icon: "close", label: t.paneRemoveWidth, disabled, onClick: () => set2("previewDevices", devices.filter((_, i) => i !== index)) })
8152
8759
  ] })
8153
8760
  ] }, typeof item === "string" ? item : `px-${index}`);
8154
8761
  }) }),
8155
- /* @__PURE__ */ jsx10(Flex4, { children: /* @__PURE__ */ jsx10(
8156
- Button4,
8762
+ /* @__PURE__ */ jsx12(Flex6, { children: /* @__PURE__ */ jsx12(
8763
+ Button6,
8157
8764
  {
8158
8765
  variant: "secondary",
8159
8766
  size: "S",
@@ -8163,15 +8770,15 @@ function PaneEditor({ id, toolbar, devices, set: set2, t, disabled, TextField: T
8163
8770
  children: t.paneAddWidth
8164
8771
  }
8165
8772
  ) }),
8166
- badDevices(devices) && /* @__PURE__ */ jsx10(Typography5, { role: "alert", variant: "pi", textColor: "danger600", children: t.paneInvalid })
8773
+ badDevices(devices) && /* @__PURE__ */ jsx12(Typography7, { role: "alert", variant: "pi", textColor: "danger600", children: t.paneInvalid })
8167
8774
  ] });
8168
8775
  }
8169
8776
  var DAYS = (n) => Number.isInteger(n) && n >= 1 && n <= 3650;
8170
8777
  var badRetention = (h) => !h || !DAYS(h.retentionDays) || !DAYS(h.eventDays) || !DAYS(h.trashDays) || h.eventDays < h.retentionDays || !(Number.isInteger(h.maxSnapshots) && h.maxSnapshots >= 1 && h.maxSnapshots <= 1e3);
8171
8778
  function HistorySettings({ types, history, set: set2, t, disabled, ToggleField: ToggleField2, TextField: TextField2 }) {
8172
8779
  const all = history.contentTypes === "all";
8173
- const list = all ? [] : history.contentTypes;
8174
- const number = (key) => /* @__PURE__ */ jsx10(Box5, { style: { minWidth: 200 }, children: /* @__PURE__ */ jsx10(
8780
+ const list2 = all ? [] : history.contentTypes;
8781
+ const number = (key) => /* @__PURE__ */ jsx12(Box6, { style: { minWidth: 200 }, children: /* @__PURE__ */ jsx12(
8175
8782
  TextField2,
8176
8783
  {
8177
8784
  name: `history-${key}`,
@@ -8181,33 +8788,33 @@ function HistorySettings({ types, history, set: set2, t, disabled, ToggleField:
8181
8788
  onChange: (v) => set2(key, /^\d{1,5}$/.test(v.trim()) ? Number(v.trim()) : NaN)
8182
8789
  }
8183
8790
  ) });
8184
- return /* @__PURE__ */ jsx10(Box5, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "history-settings", children: [
8185
- /* @__PURE__ */ jsx10(Typography5, { variant: "beta", tag: "h2", children: t.historySettings }),
8186
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.historySettingsHelp }),
8187
- /* @__PURE__ */ jsx10(ToggleField2, { name: "history-enabled", label: t.historyEnabled, value: history.enabled, disabled, onChange: (v) => set2("enabled", v) }),
8188
- /* @__PURE__ */ jsx10(ToggleField2, { name: "history-all", label: t.historyAll, value: all, disabled: disabled || !history.enabled, onChange: (v) => set2("contentTypes", v ? "all" : types.map((type) => type.uid)) }),
8189
- !all && /* @__PURE__ */ jsxs7(Checks, { disabled: disabled || !history.enabled, children: [
8190
- /* @__PURE__ */ jsx10("legend", { children: t.historyTypes }),
8191
- types.map((type) => /* @__PURE__ */ jsxs7("label", { children: [
8192
- /* @__PURE__ */ jsx10(
8791
+ return /* @__PURE__ */ jsx12(Box6, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "history-settings", children: [
8792
+ /* @__PURE__ */ jsx12(Typography7, { variant: "beta", tag: "h2", children: t.historySettings }),
8793
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.historySettingsHelp }),
8794
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "history-enabled", label: t.historyEnabled, value: history.enabled, disabled, onChange: (v) => set2("enabled", v) }),
8795
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "history-all", label: t.historyAll, value: all, disabled: disabled || !history.enabled, onChange: (v) => set2("contentTypes", v ? "all" : types.map((type) => type.uid)) }),
8796
+ !all && /* @__PURE__ */ jsxs9(Checks, { disabled: disabled || !history.enabled, children: [
8797
+ /* @__PURE__ */ jsx12("legend", { children: t.historyTypes }),
8798
+ types.map((type) => /* @__PURE__ */ jsxs9("label", { children: [
8799
+ /* @__PURE__ */ jsx12(
8193
8800
  "input",
8194
8801
  {
8195
8802
  type: "checkbox",
8196
8803
  name: `history-type-${type.uid}`,
8197
- checked: list.includes(type.uid),
8198
- onChange: (e) => set2("contentTypes", e.target.checked ? [...list, type.uid] : list.filter((uid) => uid !== type.uid))
8804
+ checked: list2.includes(type.uid),
8805
+ onChange: (e) => set2("contentTypes", e.target.checked ? [...list2, type.uid] : list2.filter((uid) => uid !== type.uid))
8199
8806
  }
8200
8807
  ),
8201
8808
  type.displayName
8202
8809
  ] }, type.uid))
8203
8810
  ] }),
8204
- /* @__PURE__ */ jsxs7(Flex4, { gap: 4, wrap: "wrap", alignItems: "flex-end", children: [
8811
+ /* @__PURE__ */ jsxs9(Flex6, { gap: 4, wrap: "wrap", alignItems: "flex-end", children: [
8205
8812
  number("retentionDays"),
8206
8813
  number("maxSnapshots"),
8207
8814
  number("eventDays"),
8208
8815
  number("trashDays")
8209
8816
  ] }),
8210
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: badRetention(history) ? "danger600" : "neutral600", role: badRetention(history) ? "alert" : void 0, children: badRetention(history) ? t.historyInvalid : `${t.historyRetentionHelp} ${t.trashDaysHelp}` })
8817
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: badRetention(history) ? "danger600" : "neutral600", role: badRetention(history) ? "alert" : void 0, children: badRetention(history) ? t.historyInvalid : `${t.historyRetentionHelp} ${t.trashDaysHelp}` })
8211
8818
  ] }) });
8212
8819
  }
8213
8820
  function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: SelectField2, TextField: TextField2 }) {
@@ -8221,10 +8828,10 @@ function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: Selec
8221
8828
  };
8222
8829
  const fields = (type.attributes || []).filter((attr) => !SYSTEM_FIELDS2.includes(attr.name));
8223
8830
  const id = (name, index) => `sidebar-${name}-${type.uid}${index === void 0 ? "" : `-${index}`}`;
8224
- return /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, "data-testid": `sidebar-editor-${type.uid}`, children: [
8225
- /* @__PURE__ */ jsx10(Typography5, { variant: "delta", tag: "h3", children: t.f("sidebarTitle", { name: type.displayName }) }),
8226
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.sidebarHelp }),
8227
- /* @__PURE__ */ jsx10(Box5, { style: { maxWidth: 240 }, children: /* @__PURE__ */ jsx10(
8831
+ return /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, "data-testid": `sidebar-editor-${type.uid}`, children: [
8832
+ /* @__PURE__ */ jsx12(Typography7, { variant: "delta", tag: "h3", children: t.f("sidebarTitle", { name: type.displayName }) }),
8833
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.sidebarHelp }),
8834
+ /* @__PURE__ */ jsx12(Box6, { style: { maxWidth: 240 }, children: /* @__PURE__ */ jsx12(
8228
8835
  SelectField2,
8229
8836
  {
8230
8837
  name: id("position"),
@@ -8235,21 +8842,21 @@ function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: Selec
8235
8842
  onChange: (v) => set2("sidebarPosition", v, "left")
8236
8843
  }
8237
8844
  ) }),
8238
- items2.map((item, index) => /* @__PURE__ */ jsxs7(Item, { "data-testid": id("item", index), children: [
8239
- /* @__PURE__ */ jsxs7(Flex4, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
8240
- /* @__PURE__ */ jsx10(Box5, { style: { flex: "1 1 200px" }, children: /* @__PURE__ */ jsx10(TextField2, { name: id("label", index), label: t.sidebarItemLabel, value: item.label, disabled, onChange: (v) => edit(index, { label: v }) }) }),
8241
- /* @__PURE__ */ jsx10(Box5, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx10(
8845
+ items2.map((item, index) => /* @__PURE__ */ jsxs9(Item, { "data-testid": id("item", index), children: [
8846
+ /* @__PURE__ */ jsxs9(Flex6, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
8847
+ /* @__PURE__ */ jsx12(Box6, { style: { flex: "1 1 200px" }, children: /* @__PURE__ */ jsx12(TextField2, { name: id("label", index), label: t.sidebarItemLabel, value: item.label, disabled, onChange: (v) => edit(index, { label: v }) }) }),
8848
+ /* @__PURE__ */ jsx12(Box6, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx12(
8242
8849
  SelectField2,
8243
8850
  {
8244
8851
  name: id("icon", index),
8245
8852
  label: t.sidebarIcon,
8246
8853
  value: item.icon || "none",
8247
8854
  disabled,
8248
- options: [{ value: "none", label: t.noIcon }, ...SIDEBAR_ICONS.map((value) => ({ value, label: t.icons[value], icon: /* @__PURE__ */ jsx10(Icon, { name: value, size: 16 }) }))],
8855
+ options: [{ value: "none", label: t.noIcon }, ...SIDEBAR_ICONS.map((value) => ({ value, label: t.icons[value], icon: /* @__PURE__ */ jsx12(Icon, { name: value, size: 16 }) }))],
8249
8856
  onChange: (v) => edit(index, { icon: v === "none" ? void 0 : v })
8250
8857
  }
8251
8858
  ) }),
8252
- /* @__PURE__ */ jsx10(Box5, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsx10(
8859
+ /* @__PURE__ */ jsx12(Box6, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsx12(
8253
8860
  SelectField2,
8254
8861
  {
8255
8862
  name: id("open", index),
@@ -8260,16 +8867,16 @@ function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: Selec
8260
8867
  onChange: (v) => edit(index, { open: v })
8261
8868
  }
8262
8869
  ) }),
8263
- /* @__PURE__ */ jsxs7(Flex4, { gap: 1, paddingBottom: 1, children: [
8264
- /* @__PURE__ */ jsx10(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index === 0, onClick: () => move(index, -1) }),
8265
- /* @__PURE__ */ jsx10(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index === items2.length - 1, onClick: () => move(index, 1) }),
8266
- /* @__PURE__ */ jsx10(Tool, { icon: "close", label: t.sidebarRemove, disabled, onClick: () => save(items2.filter((_, i) => i !== index)) })
8870
+ /* @__PURE__ */ jsxs9(Flex6, { gap: 1, paddingBottom: 1, children: [
8871
+ /* @__PURE__ */ jsx12(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index === 0, onClick: () => move(index, -1) }),
8872
+ /* @__PURE__ */ jsx12(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index === items2.length - 1, onClick: () => move(index, 1) }),
8873
+ /* @__PURE__ */ jsx12(Tool, { icon: "close", label: t.sidebarRemove, disabled, onClick: () => save(items2.filter((_, i) => i !== index)) })
8267
8874
  ] })
8268
8875
  ] }),
8269
- /* @__PURE__ */ jsxs7(Checks, { disabled, children: [
8270
- /* @__PURE__ */ jsx10("legend", { children: t.sidebarFields }),
8271
- fields.map((attr) => /* @__PURE__ */ jsxs7("label", { children: [
8272
- /* @__PURE__ */ jsx10(
8876
+ /* @__PURE__ */ jsxs9(Checks, { disabled, children: [
8877
+ /* @__PURE__ */ jsx12("legend", { children: t.sidebarFields }),
8878
+ fields.map((attr) => /* @__PURE__ */ jsxs9("label", { children: [
8879
+ /* @__PURE__ */ jsx12(
8273
8880
  "input",
8274
8881
  {
8275
8882
  type: "checkbox",
@@ -8281,11 +8888,11 @@ function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: Selec
8281
8888
  attr.name
8282
8889
  ] }, attr.name))
8283
8890
  ] }),
8284
- badItem(item) && /* @__PURE__ */ jsx10(Typography5, { role: "alert", variant: "pi", textColor: "danger600", children: t.sidebarInvalid })
8891
+ badItem(item) && /* @__PURE__ */ jsx12(Typography7, { role: "alert", variant: "pi", textColor: "danger600", children: t.sidebarInvalid })
8285
8892
  ] }, index)),
8286
- /* @__PURE__ */ jsxs7(Flex4, { gap: 2, alignItems: "center", children: [
8287
- /* @__PURE__ */ jsx10(
8288
- Button4,
8893
+ /* @__PURE__ */ jsxs9(Flex6, { gap: 2, alignItems: "center", children: [
8894
+ /* @__PURE__ */ jsx12(
8895
+ Button6,
8289
8896
  {
8290
8897
  variant: "secondary",
8291
8898
  size: "S",
@@ -8295,7 +8902,7 @@ function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: Selec
8295
8902
  children: t.sidebarAdd
8296
8903
  }
8297
8904
  ),
8298
- items2.length >= SIDEBAR_MAX && /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.f("sidebarLimit", { max: SIDEBAR_MAX }) })
8905
+ items2.length >= SIDEBAR_MAX && /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.f("sidebarLimit", { max: SIDEBAR_MAX }) })
8299
8906
  ] })
8300
8907
  ] });
8301
8908
  }
@@ -8304,18 +8911,18 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8304
8911
  const t = useMessages();
8305
8912
  const { get, put, del } = useClient();
8306
8913
  const { canRead, canUpdate, isLoading } = usePermissions2();
8307
- const [data, setData] = React9.useState(null);
8308
- const [catalog, setCatalog] = React9.useState(null);
8309
- const [settings, setSettings] = React9.useState(null);
8310
- const [media, setMedia] = React9.useState({});
8311
- const [sources, setSources] = React9.useState({});
8312
- const [dirty, setDirty] = React9.useState(false);
8313
- const [saving, setSaving] = React9.useState(false);
8314
- const [status, setStatus] = React9.useState("");
8315
- const [failed, setFailed] = React9.useState(false);
8316
- const [filter, setFilter] = React9.useState("");
8317
- const [picking, setPicking] = React9.useState(null);
8318
- React9.useEffect(() => {
8914
+ const [data, setData] = React11.useState(null);
8915
+ const [catalog, setCatalog] = React11.useState(null);
8916
+ const [settings, setSettings] = React11.useState(null);
8917
+ const [media, setMedia] = React11.useState({});
8918
+ const [sources, setSources] = React11.useState({});
8919
+ const [dirty, setDirty] = React11.useState(false);
8920
+ const [saving, setSaving] = React11.useState(false);
8921
+ const [status, setStatus] = React11.useState("");
8922
+ const [failed, setFailed] = React11.useState(false);
8923
+ const [filter, setFilter] = React11.useState("");
8924
+ const [picking, setPicking] = React11.useState(null);
8925
+ React11.useEffect(() => {
8319
8926
  if (!canRead || isLoading) return;
8320
8927
  let active = true;
8321
8928
  Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
@@ -8393,36 +9000,36 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8393
9000
  return index === 0 && manual ? t.manual : t.automatic;
8394
9001
  };
8395
9002
  const ready = !isLoading && canRead && !failed && settings && catalog;
8396
- const header = React9.useRef(null);
8397
- const [floating, setFloating] = React9.useState(false);
9003
+ const header = React11.useRef(null);
9004
+ const [floating, setFloating] = React11.useState(false);
8398
9005
  const main = useMainRect2(header);
8399
- React9.useEffect(() => {
9006
+ React11.useEffect(() => {
8400
9007
  const el = header.current;
8401
9008
  if (!el || typeof IntersectionObserver === "undefined") return;
8402
9009
  const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
8403
9010
  observer.observe(el);
8404
9011
  return () => observer.disconnect();
8405
9012
  }, [ready]);
8406
- const controls = (suffix) => ready && /* @__PURE__ */ jsxs7(Flex4, { gap: 3, alignItems: "center", wrap: "wrap", children: [
8407
- /* @__PURE__ */ jsx10(Typography5, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
8408
- !suffix && /* @__PURE__ */ jsx10(Button4, { variant: "tertiary", onClick: restore, disabled: !canUpdate || saving, "data-testid": "restore-blockscene-settings", children: data.projectDefaults ? t.restoreProject : t.resetAll }),
8409
- /* @__PURE__ */ jsx10(Button4, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
9013
+ const controls = (suffix) => ready && /* @__PURE__ */ jsxs9(Flex6, { gap: 3, alignItems: "center", wrap: "wrap", children: [
9014
+ /* @__PURE__ */ jsx12(Typography7, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
9015
+ !suffix && /* @__PURE__ */ jsx12(Button6, { variant: "tertiary", onClick: restore, disabled: !canUpdate || saving, "data-testid": "restore-blockscene-settings", children: data.projectDefaults ? t.restoreProject : t.resetAll }),
9016
+ /* @__PURE__ */ jsx12(Button6, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
8410
9017
  ] });
8411
- return /* @__PURE__ */ jsx10(Box5, { padding: 8, background: "neutral100", children: /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 5, children: [
8412
- /* @__PURE__ */ jsx10("div", { ref: header, children: /* @__PURE__ */ jsxs7(Flex4, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
8413
- /* @__PURE__ */ jsx10(Typography5, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
9018
+ return /* @__PURE__ */ jsx12(Box6, { padding: 8, background: "neutral100", children: /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 5, children: [
9019
+ /* @__PURE__ */ jsx12("div", { ref: header, children: /* @__PURE__ */ jsxs9(Flex6, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
9020
+ /* @__PURE__ */ jsx12(Typography7, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
8414
9021
  controls("")
8415
9022
  ] }) }),
8416
- floating && main.width > 0 && /* @__PURE__ */ jsx10(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ jsxs7(Flex4, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
8417
- /* @__PURE__ */ jsx10(Typography5, { variant: "beta", tag: "p", children: t.settingsTitle }),
9023
+ floating && main.width > 0 && /* @__PURE__ */ jsx12(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ jsxs9(Flex6, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
9024
+ /* @__PURE__ */ jsx12(Typography7, { variant: "beta", tag: "p", children: t.settingsTitle }),
8418
9025
  controls("-floating")
8419
9026
  ] }) }),
8420
- /* @__PURE__ */ jsx10(Typography5, { textColor: "neutral600", children: t.settingsIntro }),
8421
- isLoading ? /* @__PURE__ */ jsx10(Typography5, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ jsx10(Typography5, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ jsx10(Typography5, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ jsx10(Typography5, { children: t.loading }) : /* @__PURE__ */ jsxs7(Fragment8, { children: [
8422
- data.disabled && /* @__PURE__ */ jsx10(Box5, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ jsx10(Typography5, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
8423
- /* @__PURE__ */ jsx10(Box5, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 4, children: [
8424
- /* @__PURE__ */ jsx10(Typography5, { variant: "beta", tag: "h2", children: t.palette }),
8425
- /* @__PURE__ */ jsx10(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ jsx10(
9027
+ /* @__PURE__ */ jsx12(Typography7, { textColor: "neutral600", children: t.settingsIntro }),
9028
+ isLoading ? /* @__PURE__ */ jsx12(Typography7, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ jsx12(Typography7, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ jsx12(Typography7, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ jsx12(Typography7, { children: t.loading }) : /* @__PURE__ */ jsxs9(Fragment9, { children: [
9029
+ data.disabled && /* @__PURE__ */ jsx12(Box6, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ jsx12(Typography7, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
9030
+ /* @__PURE__ */ jsx12(Box6, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 4, children: [
9031
+ /* @__PURE__ */ jsx12(Typography7, { variant: "beta", tag: "h2", children: t.palette }),
9032
+ /* @__PURE__ */ jsx12(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ jsx12(
8426
9033
  ColorField,
8427
9034
  {
8428
9035
  name: `palette-${key}`,
@@ -8436,43 +9043,43 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8436
9043
  },
8437
9044
  key
8438
9045
  )) }),
8439
- badColor && /* @__PURE__ */ jsx10(Typography5, { role: "alert", textColor: "danger600", children: t.invalidColor }),
8440
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
8441
- /* @__PURE__ */ jsx10(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ jsxs7(Flex4, { direction: "column", gap: 1, children: [
8442
- /* @__PURE__ */ jsx10(Box5, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ jsx10(Wireframe, { template, palette: settings.palette }) }),
8443
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
9046
+ badColor && /* @__PURE__ */ jsx12(Typography7, { role: "alert", textColor: "danger600", children: t.invalidColor }),
9047
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
9048
+ /* @__PURE__ */ jsx12(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ jsxs9(Flex6, { direction: "column", gap: 1, children: [
9049
+ /* @__PURE__ */ jsx12(Box6, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ jsx12(Wireframe, { template, palette: settings.palette }) }),
9050
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
8444
9051
  ] }, template)) }),
8445
- /* @__PURE__ */ jsx10(Flex4, { children: /* @__PURE__ */ jsx10(Button4, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
9052
+ /* @__PURE__ */ jsx12(Flex6, { children: /* @__PURE__ */ jsx12(Button6, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
8446
9053
  s.palette = { ...DEFAULT_PALETTE };
8447
9054
  return s;
8448
9055
  }), children: t.resetPalette }) })
8449
9056
  ] }) }),
8450
- /* @__PURE__ */ jsx10(Box5, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 4, children: [
8451
- /* @__PURE__ */ jsx10(Typography5, { variant: "beta", tag: "h2", children: t.editor }),
8452
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9057
+ /* @__PURE__ */ jsx12(Box6, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 4, children: [
9058
+ /* @__PURE__ */ jsx12(Typography7, { variant: "beta", tag: "h2", children: t.editor }),
9059
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8453
9060
  s.editor.enabled = v;
8454
9061
  return s;
8455
9062
  }) }),
8456
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
8457
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9063
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
9064
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8458
9065
  s.editor.showOpenAll = v;
8459
9066
  return s;
8460
9067
  }) }),
8461
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9068
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8462
9069
  s.editor.showCloseAll = v;
8463
9070
  return s;
8464
9071
  }) }),
8465
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.toggleHelp }),
8466
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-showRowThumbnails", label: t.showRowThumbnails, value: editor.showRowThumbnails !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9072
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.toggleHelp }),
9073
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-showRowThumbnails", label: t.showRowThumbnails, value: editor.showRowThumbnails !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8467
9074
  s.editor.showRowThumbnails = v;
8468
9075
  return s;
8469
9076
  }) }),
8470
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-friendlyLabels", label: t.friendlyLabels, value: editor.friendlyLabels !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9077
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-friendlyLabels", label: t.friendlyLabels, value: editor.friendlyLabels !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8471
9078
  s.editor.friendlyLabels = v;
8472
9079
  return s;
8473
9080
  }) }),
8474
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.friendlyLabelsHelp }),
8475
- /* @__PURE__ */ jsx10(
9081
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.friendlyLabelsHelp }),
9082
+ /* @__PURE__ */ jsx12(
8476
9083
  SelectField2,
8477
9084
  {
8478
9085
  name: "editor-initialState",
@@ -8486,8 +9093,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8486
9093
  })
8487
9094
  }
8488
9095
  ),
8489
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
8490
- /* @__PURE__ */ jsx10(
9096
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
9097
+ /* @__PURE__ */ jsx12(
8491
9098
  TextField2,
8492
9099
  {
8493
9100
  name: "editor-blockPreviewUrl",
@@ -8501,8 +9108,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8501
9108
  })
8502
9109
  }
8503
9110
  ),
8504
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.blockPreviewUrlHelp }),
8505
- /* @__PURE__ */ jsx10(
9111
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.blockPreviewUrlHelp }),
9112
+ /* @__PURE__ */ jsx12(
8506
9113
  TextField2,
8507
9114
  {
8508
9115
  name: "editor-previewUrl",
@@ -8516,9 +9123,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8516
9123
  })
8517
9124
  }
8518
9125
  ),
8519
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
8520
- !editor.previewUrl && /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "warning700", "data-testid": "preview-url-empty", children: t.previewUrlEmpty }),
8521
- /* @__PURE__ */ jsx10(
9126
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
9127
+ !editor.previewUrl && /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "warning700", "data-testid": "preview-url-empty", children: t.previewUrlEmpty }),
9128
+ /* @__PURE__ */ jsx12(
8522
9129
  SelectField2,
8523
9130
  {
8524
9131
  name: "editor-previewMode",
@@ -8532,9 +9139,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8532
9139
  })
8533
9140
  }
8534
9141
  ),
8535
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
8536
- /* @__PURE__ */ jsx10(Typography5, { variant: "delta", tag: "h3", children: t.paneTitle }),
8537
- /* @__PURE__ */ jsx10(
9142
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
9143
+ /* @__PURE__ */ jsx12(Typography7, { variant: "delta", tag: "h3", children: t.paneTitle }),
9144
+ /* @__PURE__ */ jsx12(
8538
9145
  PaneEditor,
8539
9146
  {
8540
9147
  id: "editor",
@@ -8549,12 +9156,12 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8549
9156
  })
8550
9157
  }
8551
9158
  ),
8552
- lazyEditors && /* @__PURE__ */ jsxs7(Fragment8, { children: [
8553
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-lazyEditors", label: t.lazyEditors, value: editor.lazyEditors !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9159
+ lazyEditors && /* @__PURE__ */ jsxs9(Fragment9, { children: [
9160
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-lazyEditors", label: t.lazyEditors, value: editor.lazyEditors !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8554
9161
  s.editor.lazyEditors = v;
8555
9162
  return s;
8556
9163
  }) }),
8557
- /* @__PURE__ */ jsx10(
9164
+ /* @__PURE__ */ jsx12(
8558
9165
  UidListField,
8559
9166
  {
8560
9167
  TextField: TextField2,
@@ -8569,31 +9176,31 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8569
9176
  })
8570
9177
  }
8571
9178
  ),
8572
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: badLazy ? "danger600" : "neutral600", role: badLazy ? "alert" : void 0, children: badLazy ? t.f("lazyFieldsInvalid", { max: LAZY_MAX }) : t.lazyEditorsHelp }),
8573
- data.blockPreviewAvailable && /* @__PURE__ */ jsxs7(Fragment8, { children: [
8574
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9179
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: badLazy ? "danger600" : "neutral600", role: badLazy ? "alert" : void 0, children: badLazy ? t.f("lazyFieldsInvalid", { max: LAZY_MAX }) : t.lazyEditorsHelp }),
9180
+ data.blockPreviewAvailable && /* @__PURE__ */ jsxs9(Fragment9, { children: [
9181
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8575
9182
  s.editor.blockPreviewInForm = v;
8576
9183
  return s;
8577
9184
  }) }),
8578
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
9185
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
8579
9186
  ] })
8580
9187
  ] })
8581
9188
  ] }) }),
8582
- /* @__PURE__ */ jsx10(Box5, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-actions-settings", children: [
8583
- /* @__PURE__ */ jsx10(Typography5, { variant: "beta", tag: "h2", children: t.rowActionsTitle }),
8584
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-confirmDelete", label: t.confirmDeleteOption, value: editor.confirmDelete !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9189
+ /* @__PURE__ */ jsx12(Box6, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-actions-settings", children: [
9190
+ /* @__PURE__ */ jsx12(Typography7, { variant: "beta", tag: "h2", children: t.rowActionsTitle }),
9191
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-confirmDelete", label: t.confirmDeleteOption, value: editor.confirmDelete !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8585
9192
  s.editor.confirmDelete = v;
8586
9193
  return s;
8587
9194
  }) }),
8588
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-duplicate", label: t.duplicateOption, value: editor.duplicate !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9195
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-duplicate", label: t.duplicateOption, value: editor.duplicate !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8589
9196
  s.editor.duplicate = v;
8590
9197
  return s;
8591
9198
  }) }),
8592
- /* @__PURE__ */ jsx10(ToggleField2, { name: "editor-clipboard", label: t.clipboardOption, value: editor.clipboard !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
9199
+ /* @__PURE__ */ jsx12(ToggleField2, { name: "editor-clipboard", label: t.clipboardOption, value: editor.clipboard !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
8593
9200
  s.editor.clipboard = v;
8594
9201
  return s;
8595
9202
  }) }),
8596
- /* @__PURE__ */ jsx10(
9203
+ /* @__PURE__ */ jsx12(
8597
9204
  SelectField2,
8598
9205
  {
8599
9206
  name: "editor-hiddenBlocks",
@@ -8607,9 +9214,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8607
9214
  })
8608
9215
  }
8609
9216
  ),
8610
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: data.hiddenAttribute ? t.hiddenBlocksHelp : t.hiddenAttributeOff })
9217
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: data.hiddenAttribute ? t.hiddenBlocksHelp : t.hiddenAttributeOff })
8611
9218
  ] }) }),
8612
- data.historyTypes && settings.history && /* @__PURE__ */ jsx10(
9219
+ data.historyTypes && settings.history && /* @__PURE__ */ jsx12(
8613
9220
  HistorySettings,
8614
9221
  {
8615
9222
  types: data.historyTypes,
@@ -8624,9 +9231,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8624
9231
  })
8625
9232
  }
8626
9233
  ),
8627
- (data.contentTypes || []).length > 0 && /* @__PURE__ */ jsx10(Box5, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "content-types", children: [
8628
- /* @__PURE__ */ jsx10(Typography5, { variant: "beta", tag: "h2", children: t.contentTypes }),
8629
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: t.contentTypesHelp }),
9234
+ (data.contentTypes || []).length > 0 && /* @__PURE__ */ jsx12(Box6, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "content-types", children: [
9235
+ /* @__PURE__ */ jsx12(Typography7, { variant: "beta", tag: "h2", children: t.contentTypes }),
9236
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: t.contentTypesHelp }),
8630
9237
  data.contentTypes.map((type) => {
8631
9238
  const entry = settings.contentTypes?.[type.uid] || {};
8632
9239
  const set2 = (key, value, fallback) => update((s) => {
@@ -8638,9 +9245,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8638
9245
  else delete s.contentTypes[type.uid];
8639
9246
  return s;
8640
9247
  });
8641
- return /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 4, children: [
8642
- /* @__PURE__ */ jsxs7(Flex4, { gap: 6, alignItems: "flex-end", wrap: "wrap", "data-testid": `content-type-${type.uid}`, children: [
8643
- /* @__PURE__ */ jsx10(Box5, { style: { minWidth: 220 }, children: /* @__PURE__ */ jsx10(
9248
+ return /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 4, children: [
9249
+ /* @__PURE__ */ jsxs9(Flex6, { gap: 6, alignItems: "flex-end", wrap: "wrap", "data-testid": `content-type-${type.uid}`, children: [
9250
+ /* @__PURE__ */ jsx12(Box6, { style: { minWidth: 220 }, children: /* @__PURE__ */ jsx12(
8644
9251
  ToggleField2,
8645
9252
  {
8646
9253
  name: `type-enabled-${type.uid}`,
@@ -8650,7 +9257,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8650
9257
  onChange: (v) => set2("enabled", v, true)
8651
9258
  }
8652
9259
  ) }),
8653
- /* @__PURE__ */ jsx10(Box5, { style: { minWidth: 240 }, children: /* @__PURE__ */ jsx10(
9260
+ /* @__PURE__ */ jsx12(Box6, { style: { minWidth: 240 }, children: /* @__PURE__ */ jsx12(
8654
9261
  SelectField2,
8655
9262
  {
8656
9263
  name: `type-mode-${type.uid}`,
@@ -8662,9 +9269,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8662
9269
  }
8663
9270
  ) })
8664
9271
  ] }),
8665
- entry.enabled !== false && /* @__PURE__ */ jsx10(SidebarEditor, { type, entry, set: set2, t, disabled: !canUpdate || saving, SelectField: SelectField2, TextField: TextField2 }),
8666
- entry.enabled !== false && /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, children: [
8667
- /* @__PURE__ */ jsx10(
9272
+ entry.enabled !== false && /* @__PURE__ */ jsx12(SidebarEditor, { type, entry, set: set2, t, disabled: !canUpdate || saving, SelectField: SelectField2, TextField: TextField2 }),
9273
+ entry.enabled !== false && /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, children: [
9274
+ /* @__PURE__ */ jsx12(
8668
9275
  ToggleField2,
8669
9276
  {
8670
9277
  name: `type-pane-${type.uid}`,
@@ -8677,7 +9284,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8677
9284
  }
8678
9285
  }
8679
9286
  ),
8680
- (entry.previewToolbar || entry.previewDevices) && /* @__PURE__ */ jsx10(
9287
+ (entry.previewToolbar || entry.previewDevices) && /* @__PURE__ */ jsx12(
8681
9288
  PaneEditor,
8682
9289
  {
8683
9290
  id: `type-${type.uid}`,
@@ -8692,18 +9299,18 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8692
9299
  ] })
8693
9300
  ] }, type.uid);
8694
9301
  }),
8695
- badSidebar && /* @__PURE__ */ jsx10(Typography5, { role: "alert", textColor: "danger600", children: t.sidebarInvalidSave })
9302
+ badSidebar && /* @__PURE__ */ jsx12(Typography7, { role: "alert", textColor: "danger600", children: t.sidebarInvalidSave })
8696
9303
  ] }) }),
8697
- /* @__PURE__ */ jsx10(Box5, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 4, children: [
8698
- /* @__PURE__ */ jsx10(Typography5, { variant: "beta", tag: "h2", children: t.components }),
8699
- /* @__PURE__ */ jsx10(Searchbar2, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
8700
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
8701
- /* @__PURE__ */ jsx10(Grid2, { "data-testid": "components-grid", children: components.map((component) => {
9304
+ /* @__PURE__ */ jsx12(Box6, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 4, children: [
9305
+ /* @__PURE__ */ jsx12(Typography7, { variant: "beta", tag: "h2", children: t.components }),
9306
+ /* @__PURE__ */ jsx12(Searchbar2, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
9307
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
9308
+ /* @__PURE__ */ jsx12(Grid2, { "data-testid": "components-grid", children: components.map((component) => {
8702
9309
  const entry = settings.components[component.uid] || {};
8703
9310
  const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
8704
9311
  const candidates = candidatesFor(component.uid, meta, catalog);
8705
- return /* @__PURE__ */ jsxs7(Card2, { "data-testid": `settings-${component.uid}`, children: [
8706
- /* @__PURE__ */ jsx10(
9312
+ return /* @__PURE__ */ jsxs9(Card2, { "data-testid": `settings-${component.uid}`, children: [
9313
+ /* @__PURE__ */ jsx12(
8707
9314
  Thumb,
8708
9315
  {
8709
9316
  candidates,
@@ -8714,23 +9321,23 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8714
9321
  onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
8715
9322
  }
8716
9323
  ),
8717
- /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "flex-start", gap: 2, children: [
8718
- /* @__PURE__ */ jsx10(Typography5, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
8719
- /* @__PURE__ */ jsxs7(Typography5, { variant: "pi", textColor: "neutral600", children: [
9324
+ /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "flex-start", gap: 2, children: [
9325
+ /* @__PURE__ */ jsx12(Typography7, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
9326
+ /* @__PURE__ */ jsxs9(Typography7, { variant: "pi", textColor: "neutral600", children: [
8720
9327
  component.uid,
8721
9328
  " \xB7 ",
8722
9329
  component.category
8723
9330
  ] }),
8724
- /* @__PURE__ */ jsxs7(Typography5, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
9331
+ /* @__PURE__ */ jsxs9(Typography7, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
8725
9332
  t.source,
8726
9333
  ": ",
8727
9334
  sourceOf(component.uid, Boolean(meta.manualImage)),
8728
9335
  meta.manualName ? ` (${meta.manualName})` : ""
8729
9336
  ] }),
8730
- meta.manualMissing && /* @__PURE__ */ jsx10(Typography5, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
8731
- /* @__PURE__ */ jsxs7(Flex4, { gap: 2, wrap: "wrap", children: [
8732
- /* @__PURE__ */ jsx10(Button4, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
8733
- entry.mediaId && /* @__PURE__ */ jsx10(Button4, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
9337
+ meta.manualMissing && /* @__PURE__ */ jsx12(Typography7, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
9338
+ /* @__PURE__ */ jsxs9(Flex6, { gap: 2, wrap: "wrap", children: [
9339
+ /* @__PURE__ */ jsx12(Button6, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
9340
+ entry.mediaId && /* @__PURE__ */ jsx12(Button6, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
8734
9341
  update((s) => {
8735
9342
  delete s.components[component.uid]?.mediaId;
8736
9343
  if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
@@ -8743,7 +9350,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8743
9350
  });
8744
9351
  }, children: t.useAutomatic })
8745
9352
  ] }),
8746
- /* @__PURE__ */ jsx10(
9353
+ /* @__PURE__ */ jsx12(
8747
9354
  SelectField2,
8748
9355
  {
8749
9356
  name: `template-${component.uid}`,
@@ -8757,7 +9364,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8757
9364
  })
8758
9365
  }
8759
9366
  ),
8760
- /* @__PURE__ */ jsx10(
9367
+ /* @__PURE__ */ jsx12(
8761
9368
  SelectField2,
8762
9369
  {
8763
9370
  name: `typology-${component.uid}`,
@@ -8768,7 +9375,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8768
9375
  onChange: (v) => setComponent(component.uid, "typology", v === "auto" ? void 0 : v)
8769
9376
  }
8770
9377
  ),
8771
- /* @__PURE__ */ jsx10(
9378
+ /* @__PURE__ */ jsx12(
8772
9379
  TagsField,
8773
9380
  {
8774
9381
  name: `tags-${component.uid}`,
@@ -8779,12 +9386,12 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8779
9386
  onChange: (tags) => setComponent(component.uid, "tags", tags.length ? tags : void 0)
8780
9387
  }
8781
9388
  ),
8782
- meta.variants?.length > 0 && /* @__PURE__ */ jsxs7(Typography5, { variant: "pi", textColor: "neutral600", "data-testid": `variants-${component.uid}`, children: [
9389
+ meta.variants?.length > 0 && /* @__PURE__ */ jsxs9(Typography7, { variant: "pi", textColor: "neutral600", "data-testid": `variants-${component.uid}`, children: [
8783
9390
  t.variantsFromCode,
8784
9391
  ": ",
8785
9392
  meta.variants.map((item) => localized(item.label, t.locale) || item.id).join(", ")
8786
9393
  ] }),
8787
- catalog.groups?.[component.uid] && /* @__PURE__ */ jsx10(
9394
+ catalog.groups?.[component.uid] && /* @__PURE__ */ jsx12(
8788
9395
  LayoutFields,
8789
9396
  {
8790
9397
  component,
@@ -8799,7 +9406,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8799
9406
  ] }, component.uid);
8800
9407
  }) })
8801
9408
  ] }) }),
8802
- picking && /* @__PURE__ */ jsx10(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
9409
+ picking && /* @__PURE__ */ jsx12(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
8803
9410
  const uid = picking;
8804
9411
  setPicking(null);
8805
9412
  if (!asset?.id) return;
@@ -8815,8 +9422,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
8815
9422
  function LayoutFields({ component, layout, set: set2, t, disabled, SelectField: SelectField2 }) {
8816
9423
  const fields = (component.layoutFields || []).map((name) => ({ value: name, label: name }));
8817
9424
  const change = (key, value) => set2(key === "columnsField" && value === "none" ? void 0 : Object.fromEntries(Object.entries({ ...layout, [key]: value }).filter(([, v]) => v !== "none" && v !== void 0)));
8818
- return /* @__PURE__ */ jsxs7(Flex4, { direction: "column", alignItems: "stretch", gap: 2, "data-testid": `layout-${component.uid}`, style: { width: "100%" }, children: [
8819
- /* @__PURE__ */ jsx10(
9425
+ return /* @__PURE__ */ jsxs9(Flex6, { direction: "column", alignItems: "stretch", gap: 2, "data-testid": `layout-${component.uid}`, style: { width: "100%" }, children: [
9426
+ /* @__PURE__ */ jsx12(
8820
9427
  SelectField2,
8821
9428
  {
8822
9429
  name: `layout-columns-${component.uid}`,
@@ -8827,8 +9434,8 @@ function LayoutFields({ component, layout, set: set2, t, disabled, SelectField:
8827
9434
  onChange: (v) => change("columnsField", v)
8828
9435
  }
8829
9436
  ),
8830
- layout?.columnsField && /* @__PURE__ */ jsxs7(Fragment8, { children: [
8831
- /* @__PURE__ */ jsx10(
9437
+ layout?.columnsField && /* @__PURE__ */ jsxs9(Fragment9, { children: [
9438
+ /* @__PURE__ */ jsx12(
8832
9439
  SelectField2,
8833
9440
  {
8834
9441
  name: `layout-mobile-${component.uid}`,
@@ -8839,7 +9446,7 @@ function LayoutFields({ component, layout, set: set2, t, disabled, SelectField:
8839
9446
  onChange: (v) => change("mobileColumnsField", v)
8840
9447
  }
8841
9448
  ),
8842
- /* @__PURE__ */ jsx10(
9449
+ /* @__PURE__ */ jsx12(
8843
9450
  SelectField2,
8844
9451
  {
8845
9452
  name: `layout-max-${component.uid}`,
@@ -8851,7 +9458,7 @@ function LayoutFields({ component, layout, set: set2, t, disabled, SelectField:
8851
9458
  }
8852
9459
  )
8853
9460
  ] }),
8854
- /* @__PURE__ */ jsx10(Typography5, { variant: "pi", textColor: "neutral600", children: fields.length ? t.layoutHelp : t.layoutNoFields })
9461
+ /* @__PURE__ */ jsx12(Typography7, { variant: "pi", textColor: "neutral600", children: fields.length ? t.layoutHelp : t.layoutNoFields })
8855
9462
  ] });
8856
9463
  }
8857
9464
  function register(app, Component2, to) {
@@ -8870,13 +9477,13 @@ function register(app, Component2, to) {
8870
9477
  }
8871
9478
 
8872
9479
  // admin/catalog.ts
8873
- import * as React11 from "react";
9480
+ import * as React13 from "react";
8874
9481
 
8875
9482
  // admin/FieldHelp.tsx
8876
- import * as React10 from "react";
9483
+ import * as React12 from "react";
8877
9484
  import styled8 from "styled-components";
8878
- import { Flex as Flex5, Tooltip } from "@strapi/design-system";
8879
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
9485
+ import { Flex as Flex7, Tooltip } from "@strapi/design-system";
9486
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
8880
9487
  var HelpButton = styled8.button`
8881
9488
  display: inline-flex; padding: 0; border: 0; border-radius: 50%; background: none; cursor: help; color: inherit;
8882
9489
  &:hover, &:focus-visible { color: ${({ theme }) => theme.colors.primary600}; }
@@ -8884,13 +9491,13 @@ var HelpButton = styled8.button`
8884
9491
  `;
8885
9492
  function FieldHelp({ text, previous, title }) {
8886
9493
  const m = useMessages();
8887
- const kept = React10.isValidElement(previous) && previous.props.title ? React10.cloneElement(previous, { title }) : previous;
8888
- return /* @__PURE__ */ jsxs8(Flex5, { gap: 1, alignItems: "center", children: [
8889
- kept,
8890
- /* @__PURE__ */ jsx11(Tooltip, { label: text, style: { maxWidth: 320 }, children: /* @__PURE__ */ jsx11(HelpButton, { type: "button", "aria-label": m.fieldHelp, children: /* @__PURE__ */ jsx11(Icon, { name: "info", size: 14 }) }) })
9494
+ const kept2 = React12.isValidElement(previous) && previous.props.title ? React12.cloneElement(previous, { title }) : previous;
9495
+ return /* @__PURE__ */ jsxs10(Flex7, { gap: 1, alignItems: "center", children: [
9496
+ kept2,
9497
+ /* @__PURE__ */ jsx13(Tooltip, { label: text, style: { maxWidth: 320 }, children: /* @__PURE__ */ jsx13(HelpButton, { type: "button", "aria-label": m.fieldHelp, children: /* @__PURE__ */ jsx13(Icon, { name: "info", size: 14 }) }) })
8891
9498
  ] });
8892
9499
  }
8893
- var helpAction = (text, previous) => /* @__PURE__ */ jsx11(FieldHelp, { text, previous, title: React10.isValidElement(previous) && previous.props.title || { id: "blockscene.fieldHelp" } });
9500
+ var helpAction = (text, previous) => /* @__PURE__ */ jsx13(FieldHelp, { text, previous, title: React12.isValidElement(previous) && previous.props.title || { id: "blockscene.fieldHelp" } });
8894
9501
 
8895
9502
  // admin/catalog.ts
8896
9503
  var cached = null;
@@ -8903,8 +9510,8 @@ var load = (get) => flight || (flight = get("/blockscene/catalog").then(({ data
8903
9510
  flight = null;
8904
9511
  }));
8905
9512
  function useCatalog(get) {
8906
- const [catalog, setCatalog] = React11.useState(null);
8907
- React11.useEffect(() => {
9513
+ const [catalog, setCatalog] = React13.useState(null);
9514
+ React13.useEffect(() => {
8908
9515
  let active = true;
8909
9516
  load(get).then((data) => {
8910
9517
  if (active) setCatalog(data);
@@ -8939,83 +9546,644 @@ var labelsHook = (get, relabel, drop) => (args) => {
8939
9546
  }
8940
9547
  };
8941
9548
 
8942
- // admin/strapi4.tsx
8943
- import { Fragment as Fragment9, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
8944
- function Modal({ open, onOpenChange, trigger, title, children, width = "80vw" }) {
8945
- const id = React12.useId();
8946
- return /* @__PURE__ */ jsxs9(Fragment9, { children: [
8947
- trigger,
8948
- open && /* @__PURE__ */ jsxs9(ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, width, children: [
8949
- /* @__PURE__ */ jsx12(ModalHeader, { children: /* @__PURE__ */ jsx12(Typography6, { id, variant: "beta", children: title }) }),
8950
- /* @__PURE__ */ jsx12(ModalBody, { children })
9549
+ // admin/LazyInput.tsx
9550
+ import * as React14 from "react";
9551
+ import { Field, Flex as Flex8, Typography as Typography8 } from "@strapi/design-system";
9552
+ import styled9 from "styled-components";
9553
+
9554
+ // admin/sanitize.mjs
9555
+ var DROP = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "IFRAME", "FRAME", "OBJECT", "EMBED", "LINK", "META", "BASE", "FORM", "TEMPLATE", "NOSCRIPT"]);
9556
+ var URL_ATTRS = /* @__PURE__ */ new Set(["href", "src", "xlink:href", "action", "formaction", "srcset", "poster", "background"]);
9557
+ var unsafeUrl = (value) => /^(javascript|vbscript|data:text\/html)/i.test(String(value).replace(/[\u0000- ]/g, ""));
9558
+ var STYLE_PROPS = /* @__PURE__ */ new Set([
9559
+ "color",
9560
+ "background-color",
9561
+ "text-align",
9562
+ "font-size",
9563
+ "font-weight",
9564
+ "font-style",
9565
+ "font-family",
9566
+ "text-decoration",
9567
+ "text-transform",
9568
+ "line-height",
9569
+ "letter-spacing",
9570
+ "vertical-align",
9571
+ "width",
9572
+ "height",
9573
+ "border-color"
9574
+ ]);
9575
+ function safeStyle(value) {
9576
+ return String(value).split(";").map((part) => part.split(":")).filter(([prop, ...rest]) => {
9577
+ const name = prop?.trim().toLowerCase();
9578
+ const val = rest.join(":").trim();
9579
+ return STYLE_PROPS.has(name) && val && !/url\s*\(|expression|[\\<>]|@import/i.test(val);
9580
+ }).map(([prop, ...rest]) => `${prop.trim().toLowerCase()}: ${rest.join(":").trim()}`).join("; ");
9581
+ }
9582
+ function cleanTree(root) {
9583
+ for (const el of [...root.children]) {
9584
+ if (DROP.has(String(el.tagName).toUpperCase())) {
9585
+ el.remove();
9586
+ continue;
9587
+ }
9588
+ for (const { name, value } of [...el.attributes]) {
9589
+ const key = name.toLowerCase();
9590
+ if (key === "style") {
9591
+ const kept2 = safeStyle(value);
9592
+ if (kept2) el.setAttribute(name, kept2);
9593
+ else el.removeAttribute(name);
9594
+ } else if (key.startsWith("on") || key === "srcdoc" || URL_ATTRS.has(key) && unsafeUrl(value)) el.removeAttribute(name);
9595
+ }
9596
+ cleanTree(el);
9597
+ }
9598
+ return root;
9599
+ }
9600
+ function sanitizeHtml(html) {
9601
+ if (typeof html !== "string" || !html.trim() || typeof DOMParser === "undefined") return "";
9602
+ return cleanTree(new DOMParser().parseFromString(html, "text/html").body).innerHTML;
9603
+ }
9604
+
9605
+ // admin/LazyInput.tsx
9606
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
9607
+ var config = { on: false, fields: [] };
9608
+ var listeners = /* @__PURE__ */ new Set();
9609
+ function setLazyConfig(next) {
9610
+ if (next.on === config.on && next.fields.join() === config.fields.join()) return;
9611
+ config = next;
9612
+ listeners.forEach((run) => run());
9613
+ }
9614
+ var subscribe = (run) => {
9615
+ listeners.add(run);
9616
+ return () => {
9617
+ listeners.delete(run);
9618
+ };
9619
+ };
9620
+ var read2 = () => config;
9621
+ var lazyFor = (uid) => config.on && config.fields.includes(uid);
9622
+ var Preview = styled9.div`
9623
+ min-height: 240px; border: 1px solid ${({ theme }) => theme.colors.neutral200}; border-radius: 4px; overflow: hidden;
9624
+ background: ${({ theme, $disabled }) => $disabled ? theme.colors.neutral150 : theme.colors.neutral0};
9625
+ color: ${({ theme }) => theme.colors.neutral800}; font-size: 1.4rem; line-height: 1.5;
9626
+ cursor: ${({ $disabled }) => $disabled ? "default" : "text"};
9627
+ &:hover { border-color: ${({ theme, $disabled }) => $disabled ? theme.colors.neutral200 : theme.colors.primary600}; }
9628
+ &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: 2px; }
9629
+ /* Stands in for the editor toolbar, so mounting the editor barely moves the page. */
9630
+ & > [data-bar] { height: 40px; display: flex; align-items: center; padding: 0 12px; border-bottom: 1px solid ${({ theme }) => theme.colors.neutral200}; }
9631
+ & > [data-body] { padding: 8px 12px; overflow-wrap: anywhere; }
9632
+ & [data-body] img { max-width: 100%; height: auto; }
9633
+ & [data-body] :is(ul, ol) { padding-left: 2.4rem; list-style: revert; }
9634
+ & [data-body] :is(h1, h2, h3, h4, h5, h6) { font-weight: 600; margin: 0.6em 0 0.3em; }
9635
+ & [data-body] h1 { font-size: 2.4rem; } & [data-body] h2 { font-size: 2rem; } & [data-body] h3 { font-size: 1.8rem; } & [data-body] h4 { font-size: 1.6rem; }
9636
+ & [data-body] p { margin: 0.4em 0; }
9637
+ & [data-body] a { color: ${({ theme }) => theme.colors.primary600}; text-decoration: underline; }
9638
+ `;
9639
+ function Placeholder({ name, label, hint, error, required, labelAction, placeholder, value, disabled, onActivate }) {
9640
+ const t = useMessages();
9641
+ const html = React14.useMemo(() => typeof value === "string" ? sanitizeHtml(value) : value == null ? "" : null, [value]);
9642
+ const activate = disabled ? void 0 : (event) => {
9643
+ event.preventDefault();
9644
+ onActivate();
9645
+ };
9646
+ return /* @__PURE__ */ jsx14(Field.Root, { id: name, name, error, hint, required, children: /* @__PURE__ */ jsxs11(Flex8, { direction: "column", alignItems: "stretch", gap: 1, children: [
9647
+ /* @__PURE__ */ jsx14(Field.Label, { action: labelAction, children: label }),
9648
+ /* @__PURE__ */ jsxs11(
9649
+ Preview,
9650
+ {
9651
+ id: name,
9652
+ "data-blockscene-lazy": name,
9653
+ $disabled: Boolean(disabled),
9654
+ role: disabled ? void 0 : "button",
9655
+ tabIndex: disabled ? void 0 : 0,
9656
+ "aria-disabled": disabled || void 0,
9657
+ "aria-label": disabled ? void 0 : `${label || name}: ${t.lazyEdit}`,
9658
+ onClick: activate,
9659
+ onFocus: activate,
9660
+ onKeyDown: disabled ? void 0 : (e) => {
9661
+ if (e.key === "Enter" || e.key === " ") activate?.(e);
9662
+ },
9663
+ children: [
9664
+ /* @__PURE__ */ jsx14("div", { "data-bar": true, children: /* @__PURE__ */ jsx14(Typography8, { variant: "pi", textColor: "neutral500", children: disabled ? "" : t.lazyEdit }) }),
9665
+ html === null ? /* @__PURE__ */ jsx14("div", { "data-body": true, children: JSON.stringify(value) }) : html ? /* @__PURE__ */ jsx14("div", { "data-body": true, dangerouslySetInnerHTML: { __html: html } }) : /* @__PURE__ */ jsx14("div", { "data-body": true, children: /* @__PURE__ */ jsx14(Typography8, { textColor: "neutral500", children: placeholder || "" }) })
9666
+ ]
9667
+ }
9668
+ ),
9669
+ /* @__PURE__ */ jsx14(Field.Hint, {}),
9670
+ /* @__PURE__ */ jsx14(Field.Error, {})
9671
+ ] }) });
9672
+ }
9673
+ function lazyInput(uid, Real) {
9674
+ const Lazy = React14.forwardRef((props, ref) => {
9675
+ React14.useSyncExternalStore(subscribe, read2);
9676
+ const [active, setActive] = React14.useState(() => !lazyFor(uid));
9677
+ const box = React14.useRef(null);
9678
+ const focus = React14.useRef(false);
9679
+ React14.useEffect(() => {
9680
+ if (!active || !focus.current) return;
9681
+ focus.current = false;
9682
+ let frame2 = 0;
9683
+ const started = performance.now();
9684
+ const poll = () => {
9685
+ const editable = box.current?.querySelector(".ck-editor__editable");
9686
+ if (editable?.isContentEditable) return editable.focus();
9687
+ if (performance.now() - started < 5e3) frame2 = requestAnimationFrame(poll);
9688
+ };
9689
+ poll();
9690
+ return () => cancelAnimationFrame(frame2);
9691
+ }, [active]);
9692
+ return /* @__PURE__ */ jsx14("div", { ref: box, style: { display: "contents" }, children: active || !lazyFor(uid) ? /* @__PURE__ */ jsx14(Real, { ...props, ref }) : /* @__PURE__ */ jsx14(Placeholder, { ...props, onActivate: () => {
9693
+ focus.current = true;
9694
+ setActive(true);
9695
+ } }) });
9696
+ });
9697
+ Lazy.displayName = `BlocksceneLazy(${uid})`;
9698
+ return Lazy;
9699
+ }
9700
+ function wrapCustomFields(app) {
9701
+ const all = app?.customFields?.getAll?.() || {};
9702
+ for (const [uid, field] of Object.entries(all)) {
9703
+ const load2 = field?.components?.Input;
9704
+ if (typeof load2 !== "function" || load2.blockscene) continue;
9705
+ const wrapped = () => Promise.resolve(load2()).then((mod) => lazyFor(uid) ? { ...mod, default: lazyInput(uid, mod?.default ?? mod) } : mod);
9706
+ wrapped.blockscene = true;
9707
+ field.components.Input = wrapped;
9708
+ }
9709
+ }
9710
+
9711
+ // admin/Activity.tsx
9712
+ import * as React15 from "react";
9713
+ import {
9714
+ Box as Box7,
9715
+ Button as Button7,
9716
+ Dialog,
9717
+ Field as Field2,
9718
+ Flex as Flex9,
9719
+ Link,
9720
+ Modal,
9721
+ SingleSelect,
9722
+ SingleSelectOption,
9723
+ Switch,
9724
+ Table,
9725
+ Tabs,
9726
+ Tbody,
9727
+ Td,
9728
+ TextInput,
9729
+ Th,
9730
+ Thead,
9731
+ Tr,
9732
+ Typography as Typography9
9733
+ } from "@strapi/design-system";
9734
+ import { Layouts, Page, useFetchClient as useFetchClient2, useNotification as useNotification2, useRBAC as useRBAC2 } from "@strapi/strapi/admin";
9735
+ import { Fragment as Fragment11, jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
9736
+ var ACTIVITY = [{ action: "plugin::blockscene.activity.read", subject: null }];
9737
+ var TRASH = ["read", "restore", "purge"].map((name) => ({ action: `plugin::blockscene.trash.${name}`, subject: null }));
9738
+ var ACTIONS = ["create", "update", "publish", "unpublish", "discard", "delete", "restore", "purge"];
9739
+ var DAY = 24 * 60 * 60 * 1e3;
9740
+ var contentMenuLink = (Component2) => ({
9741
+ to: "plugins/blockscene",
9742
+ icon: () => /* @__PURE__ */ jsx15(Icon, { name: "clock", size: 20 }),
9743
+ intlLabel: { id: "blockscene.contentMenu", defaultMessage: "Activity and trash" },
9744
+ permissions: [...ACTIVITY, TRASH[0]],
9745
+ // Not an `async` function: Strapi 5 warns on AsyncFunction loaders.
9746
+ Component: () => Promise.resolve({ default: Component2 })
9747
+ });
9748
+ var when = (t, at) => {
9749
+ try {
9750
+ return new Date(at).toLocaleString(t.locale, { dateStyle: "medium", timeStyle: "short" });
9751
+ } catch {
9752
+ return at;
9753
+ }
9754
+ };
9755
+ var editUrl = (type, documentId, locale) => {
9756
+ const base = window.location.pathname.split("/plugins/blockscene")[0];
9757
+ const kind = type?.kind === "singleType" ? "single-types" : "collection-types";
9758
+ return `${base}/content-manager/${kind}/${type.uid}${kind === "single-types" ? "" : `/${encodeURIComponent(documentId)}`}${locale ? `?plugins[i18n][locale]=${encodeURIComponent(locale)}` : ""}`;
9759
+ };
9760
+ var query = (params) => new URLSearchParams(Object.entries(params).filter(([, v]) => v !== "" && v != null).map(([k, v]) => [k, String(v)])).toString();
9761
+ var Select = ({ label, value, onChange, options, name }) => /* @__PURE__ */ jsx15(Box7, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsxs12(Field2.Root, { name, children: [
9762
+ /* @__PURE__ */ jsx15(Field2.Label, { children: label }),
9763
+ /* @__PURE__ */ jsx15(SingleSelect, { value, onChange: (v) => onChange(String(v)), children: options.map((o) => /* @__PURE__ */ jsx15(SingleSelectOption, { value: o.value, children: o.label }, o.value)) })
9764
+ ] }) });
9765
+ var Input = ({ label, value, onChange, name, type = "text" }) => /* @__PURE__ */ jsx15(Box7, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsxs12(Field2.Root, { name, children: [
9766
+ /* @__PURE__ */ jsx15(Field2.Label, { children: label }),
9767
+ /* @__PURE__ */ jsx15(TextInput, { name, type, value, onChange: (e) => onChange(e.target.value) })
9768
+ ] }) });
9769
+ function Pager({ t, pagination, setPage }) {
9770
+ if (!pagination?.total) return null;
9771
+ const { page, pageCount, total } = pagination;
9772
+ return /* @__PURE__ */ jsxs12(Flex9, { justifyContent: "space-between", alignItems: "center", paddingTop: 4, children: [
9773
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", textColor: "neutral600", children: t.f("contentPage", { page, pages: Math.max(pageCount, 1), total }) }),
9774
+ /* @__PURE__ */ jsxs12(Flex9, { gap: 2, children: [
9775
+ /* @__PURE__ */ jsx15(Button7, { variant: "tertiary", size: "S", disabled: page <= 1, onClick: () => setPage(page - 1), children: t.contentPrevious }),
9776
+ /* @__PURE__ */ jsx15(Button7, { variant: "tertiary", size: "S", disabled: page >= pageCount, onClick: () => setPage(page + 1), children: t.contentNext })
8951
9777
  ] })
8952
9778
  ] });
8953
9779
  }
8954
- var Menu2 = ({ label, testid, items: items2 }) => /* @__PURE__ */ jsx12("div", { "data-testid": testid, children: /* @__PURE__ */ jsx12(SimpleMenu2, { variant: "tertiary", size: "S", "aria-label": label, title: label, endIcon: null, label: /* @__PURE__ */ jsx12(Icon, { name: "more", size: 16 }), children: items2.map((item) => /* @__PURE__ */ jsx12(MenuItem2, { onClick: item.onSelect, "data-testid": item.testid, children: /* @__PURE__ */ jsxs9(Flex6, { as: "span", gap: 2, alignItems: "center", children: [
8955
- /* @__PURE__ */ jsx12(Icon, { name: item.icon, size: 16 }),
8956
- item.label
8957
- ] }) }, item.testid)) }) });
8958
- function overlayVariant(c, components, zone, at, uid, values) {
8959
- const row = variantRow(components[uid], components, values, (n) => [...Array(n).keys()]);
8960
- for (const name of Object.keys(values)) if (name in row) c.onChange({ target: { name: `${zone}.${at}.${name}`, value: row[name] } });
8961
- }
8962
- function useRowForm(c, components) {
8963
- const toggleNotification = useNotification();
8964
- const latest = React12.useRef(c.modifiedData);
8965
- latest.current = c.modifiedData;
8966
- if (typeof c.onChange !== "function") return null;
9780
+ function useList(get, path, params, refresh = 0) {
9781
+ const [state, setState] = React15.useState({ data: null, failed: false });
9782
+ const key = `${path}?${query(params)}`;
9783
+ React15.useEffect(() => {
9784
+ let active = true;
9785
+ setState((s) => ({ data: s.data, failed: false, loading: true }));
9786
+ get(`/blockscene${key}`).then(({ data }) => active && setState({ data, failed: false })).catch(() => active && setState({ data: null, failed: true }));
9787
+ return () => {
9788
+ active = false;
9789
+ };
9790
+ }, [get, key, refresh]);
9791
+ return state;
9792
+ }
9793
+ var Doc = ({ t, type, row, documentId, locale }) => {
9794
+ const title = row.title || t.contentUntitled;
9795
+ return /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "flex-start", gap: 1, children: [
9796
+ row.exists && type ? /* @__PURE__ */ jsx15(Link, { href: editUrl(type, documentId, locale), children: title }) : /* @__PURE__ */ jsx15(Typography9, { fontWeight: "bold", children: title }),
9797
+ /* @__PURE__ */ jsxs12(Typography9, { variant: "pi", textColor: "neutral600", children: [
9798
+ type?.displayName || row.contentType,
9799
+ locale ? ` \xB7 ${locale}` : "",
9800
+ row.exists === false ? ` \xB7 ${t.contentGone}` : ""
9801
+ ] })
9802
+ ] });
9803
+ };
9804
+ function ActivityTab({ t, get }) {
9805
+ const [filters, setFilters] = React15.useState({ actor: "", contentType: "", action: "", from: "", to: "", q: "" });
9806
+ const [search, setSearch] = React15.useState("");
9807
+ const [page, setPage] = React15.useState(1);
9808
+ const set2 = (key, value) => {
9809
+ setFilters((f) => ({ ...f, [key]: value }));
9810
+ setPage(1);
9811
+ };
9812
+ const day = (value, end) => {
9813
+ if (!value) return "";
9814
+ const d = /* @__PURE__ */ new Date(`${value}T${end ? "23:59:59.999" : "00:00:00"}`);
9815
+ return Number.isFinite(d.getTime()) ? d.toISOString() : "";
9816
+ };
9817
+ const { data, failed } = useList(get, "/activity", { ...filters, from: day(filters.from, false), to: day(filters.to, true), page, pageSize: 25 });
9818
+ const types = new Map((data?.types || []).map((type) => [type.uid, type]));
9819
+ return /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "stretch", gap: 4, children: [
9820
+ data && !data.enabled && /* @__PURE__ */ jsx15(Box7, { padding: 3, background: "warning100", hasRadius: true, children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", textColor: "warning700", children: t.contentOff }) }),
9821
+ /* @__PURE__ */ jsxs12(Flex9, { tag: "form", gap: 3, wrap: "wrap", alignItems: "flex-end", onSubmit: (e) => {
9822
+ e.preventDefault();
9823
+ set2("q", search.trim());
9824
+ }, children: [
9825
+ /* @__PURE__ */ jsx15(
9826
+ Select,
9827
+ {
9828
+ name: "actor",
9829
+ label: t.activityPerson,
9830
+ value: filters.actor,
9831
+ onChange: (v) => set2("actor", v),
9832
+ options: [{ value: "", label: t.activityAnyone }, ...(data?.actors || []).map((a) => ({ value: a.actor, label: a.actorName || (a.actor === "system" ? t.historySystem : a.actor) }))]
9833
+ }
9834
+ ),
9835
+ /* @__PURE__ */ jsx15(
9836
+ Select,
9837
+ {
9838
+ name: "contentType",
9839
+ label: t.activityType,
9840
+ value: filters.contentType,
9841
+ onChange: (v) => set2("contentType", v),
9842
+ options: [{ value: "", label: t.activityAnyType }, ...(data?.types || []).map((type) => ({ value: type.uid, label: type.displayName }))]
9843
+ }
9844
+ ),
9845
+ /* @__PURE__ */ jsx15(
9846
+ Select,
9847
+ {
9848
+ name: "action",
9849
+ label: t.activityAction,
9850
+ value: filters.action,
9851
+ onChange: (v) => set2("action", v),
9852
+ options: [{ value: "", label: t.activityAnyAction }, ...ACTIONS.map((a) => ({ value: a, label: t.historyActions[a] || a }))]
9853
+ }
9854
+ ),
9855
+ /* @__PURE__ */ jsx15(Input, { name: "from", type: "date", label: t.activityFrom, value: filters.from, onChange: (v) => set2("from", v) }),
9856
+ /* @__PURE__ */ jsx15(Input, { name: "to", type: "date", label: t.activityTo, value: filters.to, onChange: (v) => set2("to", v) }),
9857
+ /* @__PURE__ */ jsx15(Input, { name: "q", label: t.activitySearch, value: search, onChange: setSearch }),
9858
+ /* @__PURE__ */ jsx15(Button7, { type: "submit", variant: "secondary", children: t.activitySearchButton }),
9859
+ /* @__PURE__ */ jsx15(Button7, { type: "button", variant: "tertiary", onClick: () => {
9860
+ setSearch("");
9861
+ setFilters({ actor: "", contentType: "", action: "", from: "", to: "", q: "" });
9862
+ setPage(1);
9863
+ }, children: t.contentClear })
9864
+ ] }),
9865
+ failed ? /* @__PURE__ */ jsx15(Typography9, { role: "alert", textColor: "danger600", children: t.activityFailed }) : !data ? /* @__PURE__ */ jsx15(Typography9, { textColor: "neutral600", children: t.contentLoading }) : !data.results.length ? /* @__PURE__ */ jsx15(Typography9, { textColor: "neutral600", children: t.activityEmpty }) : /* @__PURE__ */ jsxs12(Box7, { children: [
9866
+ /* @__PURE__ */ jsxs12(Table, { colCount: 4, rowCount: data.results.length + 1, "data-testid": "blockscene-activity", children: [
9867
+ /* @__PURE__ */ jsx15(Thead, { children: /* @__PURE__ */ jsxs12(Tr, { children: [
9868
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: t.activityWhen }) }),
9869
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: t.activityDocument }) }),
9870
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: t.activityWho }) }),
9871
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: t.activityWhat }) })
9872
+ ] }) }),
9873
+ /* @__PURE__ */ jsx15(Tbody, { children: data.results.map((event) => /* @__PURE__ */ jsxs12(Tr, { "data-testid": `activity-${event.id}`, children: [
9874
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: when(t, event.at) }) }),
9875
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsx15(Doc, { t, type: types.get(event.contentType), row: event, documentId: event.relatedDocumentId, locale: event.locale }) }),
9876
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: event.actorName || (event.actor === "system" ? t.historySystem : event.actor) }) }),
9877
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "flex-start", gap: 1, children: [
9878
+ /* @__PURE__ */ jsx15(Typography9, { variant: "omega", fontWeight: "bold", children: t.historyActions[event.action] || event.action }),
9879
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", textColor: event.summary?.missing ? "warning700" : "neutral700", children: ["delete", "purge"].includes(event.action) ? "" : [event.summary?.restoredFrom ? t.activityRestoredFrom : "", summaryText(t, event.summary)].filter(Boolean).join(" \xB7 ") })
9880
+ ] }) })
9881
+ ] }, event.id)) })
9882
+ ] }),
9883
+ /* @__PURE__ */ jsx15(Pager, { t, pagination: data.pagination, setPage })
9884
+ ] })
9885
+ ] });
9886
+ }
9887
+ function Report({ t, report }) {
9888
+ const locale = (value) => value ?? t.contentNone;
9889
+ const line = (item) => item.code === "incoming" ? t.f("report.incoming", item) : t.f(`report.${item.code}`, { ...item, locale: locale(item.locale), locales: (item.locales || []).map(locale).join(", "), fields: (item.fields || []).join(", ") });
9890
+ const incoming = report.incoming && (report.incoming.reconnect || report.incoming.gone || report.incoming.replaced || report.incoming.published) ? [{ code: "incoming", ...report.incoming }] : [];
9891
+ const warnings = [...report.warnings || [], ...incoming];
9892
+ return /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "stretch", gap: 2, "data-testid": "restore-report", children: [
9893
+ report.blocking?.length > 0 && /* @__PURE__ */ jsxs12(Box7, { padding: 3, background: "danger100", hasRadius: true, children: [
9894
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", fontWeight: "bold", textColor: "danger700", children: t.restoreBlocked }),
9895
+ /* @__PURE__ */ jsx15("ul", { style: { margin: "4px 0 0", paddingLeft: 16 }, children: report.blocking.map((item, i) => /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", textColor: "danger700", children: line(item) }) }, i)) })
9896
+ ] }),
9897
+ warnings.length > 0 && /* @__PURE__ */ jsxs12(Box7, { padding: 3, background: "warning100", hasRadius: true, children: [
9898
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", fontWeight: "bold", textColor: "warning700", children: t.restoreWarnings }),
9899
+ /* @__PURE__ */ jsx15("ul", { style: { margin: "4px 0 0", paddingLeft: 16 }, children: warnings.map((item, i) => /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", textColor: "warning700", children: line(item) }) }, i)) })
9900
+ ] })
9901
+ ] });
9902
+ }
9903
+ function Preview2({ t, id, get, onClose }) {
9904
+ const [row, setRow] = React15.useState(null);
9905
+ const [failed, setFailed] = React15.useState(false);
9906
+ React15.useEffect(() => {
9907
+ get(`/blockscene/trash/${id}`).then(({ data }) => setRow(data)).catch(() => setFailed(true));
9908
+ }, [get, id]);
9909
+ return /* @__PURE__ */ jsx15(Modal.Root, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs12(Modal.Content, { style: { width: "min(900px, 92vw)" }, children: [
9910
+ /* @__PURE__ */ jsx15(Modal.Header, { children: /* @__PURE__ */ jsx15(Modal.Title, { children: row?.title || t.trashPreview }) }),
9911
+ /* @__PURE__ */ jsx15(Modal.Body, { children: failed ? /* @__PURE__ */ jsx15(Typography9, { role: "alert", textColor: "danger600", children: t.trashFailed }) : !row ? /* @__PURE__ */ jsx15(Typography9, { children: t.contentLoading }) : /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "stretch", gap: 5, "data-testid": "trash-preview", children: [
9912
+ row.incoming > 0 && /* @__PURE__ */ jsx15(Typography9, { variant: "pi", textColor: "neutral600", children: t.f("trashIncoming", { count: row.incoming }) }),
9913
+ row.entries.map((entry, i) => /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "stretch", gap: 2, children: [
9914
+ /* @__PURE__ */ jsxs12(Typography9, { variant: "delta", tag: "h3", children: [
9915
+ entry.locale || t.contentNone,
9916
+ entry.status ? ` \xB7 ${entry.status === "published" ? t.trashPublished : t.trashDraft}` : ""
9917
+ ] }),
9918
+ /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", textColor: "neutral600", children: t.trashFields }),
9919
+ /* @__PURE__ */ jsx15("dl", { style: { display: "grid", gridTemplateColumns: "minmax(120px, max-content) 1fr", gap: "4px 16px", margin: 0 }, children: entry.fields.map((field) => /* @__PURE__ */ jsxs12(React15.Fragment, { children: [
9920
+ /* @__PURE__ */ jsx15("dt", { children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", fontWeight: "bold", children: field.name }) }),
9921
+ /* @__PURE__ */ jsx15("dd", { style: { margin: 0, wordBreak: "break-word" }, children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: field.count !== void 0 ? t.f("trashItems", { count: field.count }) : field.value }) })
9922
+ ] }, field.name)) }),
9923
+ entry.blocks.length > 0 && /* @__PURE__ */ jsxs12(Fragment11, { children: [
9924
+ /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", textColor: "neutral600", children: t.trashBlocks }),
9925
+ /* @__PURE__ */ jsx15("ol", { style: { margin: 0, paddingLeft: 20 }, children: entry.blocks.map((block, j) => /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: block.name }) }, j)) })
9926
+ ] })
9927
+ ] }, i))
9928
+ ] }) }),
9929
+ /* @__PURE__ */ jsx15(Modal.Footer, { children: /* @__PURE__ */ jsx15(Modal.Close, { children: /* @__PURE__ */ jsx15(Button7, { variant: "tertiary", children: t.trashClose }) }) })
9930
+ ] }) });
9931
+ }
9932
+ function TrashTab({ t, get, post, del, can }) {
9933
+ const { toggleNotification } = useNotification2();
9934
+ const [contentType, setType] = React15.useState("");
9935
+ const [restored, setRestored] = React15.useState(false);
9936
+ const [page, setPage] = React15.useState(1);
9937
+ const [refresh, reload] = React15.useReducer((n) => n + 1, 0);
9938
+ const { data, failed } = useList(get, "/trash", { contentType, status: restored ? "restored" : "trashed", page, pageSize: 20 }, refresh);
9939
+ const [preview, setPreview] = React15.useState(null);
9940
+ const [restore, setRestore] = React15.useState(null);
9941
+ const [remove, setRemove] = React15.useState(null);
9942
+ const [busy, setBusy] = React15.useState(false);
9943
+ const types = new Map((data?.types || []).map((type) => [type.uid, type]));
9944
+ const title = (row) => row.title || t.contentUntitled;
9945
+ const check = async (row) => {
9946
+ setRestore({ row, report: null });
9947
+ try {
9948
+ const { data: data2 } = await get(`/blockscene/trash/${row.id}/check`);
9949
+ setRestore({ row, report: data2 });
9950
+ } catch {
9951
+ setRestore({ row, report: { blocking: [], warnings: [] }, failed: true });
9952
+ }
9953
+ };
9954
+ const confirmRestore = async () => {
9955
+ setBusy(true);
9956
+ try {
9957
+ const { data: result } = await post(`/blockscene/trash/${restore.row.id}/restore`, {});
9958
+ setRestore({ ...restore, done: result });
9959
+ reload();
9960
+ } catch (error) {
9961
+ const details = error?.response?.data?.error?.details;
9962
+ if (details) setRestore({ ...restore, report: details });
9963
+ else {
9964
+ setRestore(null);
9965
+ toggleNotification({ type: "danger", message: t.restoreFailed });
9966
+ }
9967
+ } finally {
9968
+ setBusy(false);
9969
+ }
9970
+ };
9971
+ const confirmRemove = async () => {
9972
+ setBusy(true);
9973
+ try {
9974
+ await del(`/blockscene/trash/${remove.id}`);
9975
+ toggleNotification({ type: "success", message: t.trashDeleted });
9976
+ reload();
9977
+ } catch {
9978
+ toggleNotification({ type: "danger", message: t.trashDeleteFailed });
9979
+ } finally {
9980
+ setBusy(false);
9981
+ setRemove(null);
9982
+ }
9983
+ };
9984
+ const expires = (at) => {
9985
+ const days = Math.floor((new Date(at).getTime() - Date.now()) / DAY);
9986
+ return days < 1 ? t.trashExpiresToday : t.f("trashExpiresIn", { days });
9987
+ };
9988
+ return /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "stretch", gap: 4, children: [
9989
+ /* @__PURE__ */ jsxs12(Flex9, { gap: 4, wrap: "wrap", alignItems: "flex-end", children: [
9990
+ /* @__PURE__ */ jsx15(
9991
+ Select,
9992
+ {
9993
+ name: "trash-type",
9994
+ label: t.activityType,
9995
+ value: contentType,
9996
+ onChange: (v) => {
9997
+ setType(v);
9998
+ setPage(1);
9999
+ },
10000
+ options: [{ value: "", label: t.activityAnyType }, ...(data?.types || []).map((type) => ({ value: type.uid, label: type.displayName }))]
10001
+ }
10002
+ ),
10003
+ /* @__PURE__ */ jsxs12(Flex9, { gap: 2, paddingBottom: 2, children: [
10004
+ /* @__PURE__ */ jsx15(Switch, { "aria-label": t.trashShowRestored, checked: restored, onCheckedChange: (v) => {
10005
+ setRestored(v);
10006
+ setPage(1);
10007
+ } }),
10008
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: t.trashShowRestored })
10009
+ ] })
10010
+ ] }),
10011
+ failed ? /* @__PURE__ */ jsx15(Typography9, { role: "alert", textColor: "danger600", children: t.trashFailed }) : !data ? /* @__PURE__ */ jsx15(Typography9, { textColor: "neutral600", children: t.contentLoading }) : !data.results.length ? /* @__PURE__ */ jsx15(Typography9, { textColor: "neutral600", children: t.trashEmpty }) : /* @__PURE__ */ jsxs12(Box7, { children: [
10012
+ /* @__PURE__ */ jsxs12(Table, { colCount: 5, rowCount: data.results.length + 1, "data-testid": "blockscene-trash", children: [
10013
+ /* @__PURE__ */ jsx15(Thead, { children: /* @__PURE__ */ jsxs12(Tr, { children: [
10014
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: t.activityDocument }) }),
10015
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: t.trashLocales }) }),
10016
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: t.trashDeletedBy }) }),
10017
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: restored ? t.trashRestoredAs : t.trashExpires }) }),
10018
+ /* @__PURE__ */ jsx15(Th, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "sigma", children: " " }) })
10019
+ ] }) }),
10020
+ /* @__PURE__ */ jsx15(Tbody, { children: data.results.map((row) => /* @__PURE__ */ jsxs12(Tr, { "data-testid": `trash-${row.id}`, children: [
10021
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsx15(Doc, { t, type: types.get(row.contentType), row: { ...row, exists: void 0 }, documentId: row.relatedDocumentId, locale: null }) }),
10022
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: (row.locales || []).map((l) => l ?? t.contentNone).join(", ") }) }),
10023
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "flex-start", children: [
10024
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: row.actorName || (row.actor === "system" ? t.historySystem : row.actor) }),
10025
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", textColor: "neutral600", children: when(t, row.deletedAt) })
10026
+ ] }) }),
10027
+ /* @__PURE__ */ jsxs12(Td, { children: [
10028
+ /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: restored ? row.restoredAt ? when(t, row.restoredAt) : "" : expires(row.expiresAt) }),
10029
+ restored && row.restoredAs && types.get(row.contentType) && /* @__PURE__ */ jsx15(Box7, { children: /* @__PURE__ */ jsx15(Link, { href: editUrl(types.get(row.contentType), row.restoredAs, null), children: t.contentOpen }) })
10030
+ ] }),
10031
+ /* @__PURE__ */ jsx15(Td, { children: /* @__PURE__ */ jsxs12(Flex9, { gap: 2, justifyContent: "flex-end", children: [
10032
+ /* @__PURE__ */ jsx15(Button7, { variant: "tertiary", size: "S", onClick: () => setPreview(row.id), children: t.trashPreview }),
10033
+ !restored && can.canRestore && /* @__PURE__ */ jsx15(Button7, { variant: "secondary", size: "S", onClick: () => check(row), "data-testid": `trash-restore-${row.id}`, children: t.trashRestore }),
10034
+ can.canPurge && /* @__PURE__ */ jsx15(Button7, { variant: "danger-light", size: "S", onClick: () => setRemove(row), "data-testid": `trash-delete-${row.id}`, children: t.trashDelete })
10035
+ ] }) })
10036
+ ] }, row.id)) })
10037
+ ] }),
10038
+ /* @__PURE__ */ jsx15(Pager, { t, pagination: data.pagination, setPage })
10039
+ ] }),
10040
+ preview !== null && /* @__PURE__ */ jsx15(Preview2, { t, id: preview, get, onClose: () => setPreview(null) }),
10041
+ restore && /* @__PURE__ */ jsx15(Dialog.Root, { open: true, onOpenChange: (open) => !open && !busy && setRestore(null), children: /* @__PURE__ */ jsxs12(Dialog.Content, { children: [
10042
+ /* @__PURE__ */ jsx15(Dialog.Header, { children: t.f("restoreTitle", { title: title(restore.row) }) }),
10043
+ /* @__PURE__ */ jsx15(Dialog.Body, { children: /* @__PURE__ */ jsx15(Flex9, { direction: "column", alignItems: "stretch", gap: 3, width: "100%", children: restore.done ? /* @__PURE__ */ jsxs12(Flex9, { direction: "column", alignItems: "flex-start", gap: 2, role: "status", "data-testid": "restore-done", children: [
10044
+ /* @__PURE__ */ jsx15(Typography9, { textColor: "success700", children: restore.done.already ? t.restoreAlready : t.restoreDone }),
10045
+ restore.done.documentId && types.get(restore.row.contentType) && /* @__PURE__ */ jsx15(Link, { href: editUrl(types.get(restore.row.contentType), restore.done.documentId, restore.done.locales?.[0] ?? null), children: t.restoreOpen }),
10046
+ !restore.done.already && /* @__PURE__ */ jsx15(Report, { t, report: { warnings: restore.done.warnings, incoming: restore.done.incoming && { ...restore.done.incoming, reconnect: restore.done.incoming.reconnected } } })
10047
+ ] }) : !restore.report ? /* @__PURE__ */ jsx15(Typography9, { children: t.restoreChecking }) : restore.failed ? /* @__PURE__ */ jsx15(Typography9, { role: "alert", textColor: "danger600", children: t.restoreFailed }) : /* @__PURE__ */ jsxs12(Fragment11, { children: [
10048
+ /* @__PURE__ */ jsxs12(Typography9, { variant: "pi", children: [
10049
+ t.restoreIntro,
10050
+ " ",
10051
+ restore.report.documentId ? t.restoreInto : t.restoreNew
10052
+ ] }),
10053
+ restore.report.locales?.length > 0 && restore.report.locales[0] !== null && /* @__PURE__ */ jsx15(Typography9, { variant: "pi", children: t.f("restoreLocales", { locales: restore.report.locales.join(", ") }) }),
10054
+ /* @__PURE__ */ jsx15(Report, { t, report: restore.report })
10055
+ ] }) }) }),
10056
+ /* @__PURE__ */ jsxs12(Dialog.Footer, { children: [
10057
+ /* @__PURE__ */ jsx15(Dialog.Cancel, { children: /* @__PURE__ */ jsx15(Button7, { variant: "tertiary", disabled: busy, children: restore.done ? t.trashClose : t.restoreCancel }) }),
10058
+ !restore.done && /* @__PURE__ */ jsx15(Button7, { onClick: confirmRestore, loading: busy, disabled: busy || !restore.report || restore.failed || restore.report.blocking?.length > 0, "data-testid": "restore-confirm", children: t.restoreConfirm })
10059
+ ] })
10060
+ ] }) }),
10061
+ remove && /* @__PURE__ */ jsx15(Dialog.Root, { open: true, onOpenChange: (open) => !open && !busy && setRemove(null), children: /* @__PURE__ */ jsxs12(Dialog.Content, { children: [
10062
+ /* @__PURE__ */ jsx15(Dialog.Header, { children: t.trashDeleteTitle }),
10063
+ /* @__PURE__ */ jsx15(Dialog.Body, { children: /* @__PURE__ */ jsx15(Typography9, { children: t.f("trashDeleteConfirm", { title: title(remove) }) }) }),
10064
+ /* @__PURE__ */ jsxs12(Dialog.Footer, { children: [
10065
+ /* @__PURE__ */ jsx15(Dialog.Cancel, { children: /* @__PURE__ */ jsx15(Button7, { variant: "tertiary", disabled: busy, children: t.restoreCancel }) }),
10066
+ /* @__PURE__ */ jsx15(Button7, { variant: "danger", onClick: confirmRemove, loading: busy, disabled: busy, "data-testid": "delete-confirm", children: t.trashDelete })
10067
+ ] })
10068
+ ] }) })
10069
+ ] });
10070
+ }
10071
+ function ContentPage() {
10072
+ const t = useMessages();
10073
+ const { get, post, del } = useFetchClient2();
10074
+ const activity = useRBAC2(ACTIVITY);
10075
+ const trash = useRBAC2(TRASH);
10076
+ const [tab, setTab] = React15.useState(null);
10077
+ if (activity.isLoading || trash.isLoading) return /* @__PURE__ */ jsx15(Page.Loading, {});
10078
+ const canActivity = Boolean(activity.allowedActions?.canRead), canTrash = Boolean(trash.allowedActions?.canRead);
10079
+ if (!canActivity && !canTrash) return /* @__PURE__ */ jsx15(Page.NoPermissions, {});
10080
+ const current = tab || (canActivity ? "activity" : "trash");
10081
+ return /* @__PURE__ */ jsxs12(Page.Main, { children: [
10082
+ /* @__PURE__ */ jsx15(Page.Title, { children: t.contentTitle }),
10083
+ /* @__PURE__ */ jsx15(Layouts.Header, { title: t.contentTitle, subtitle: t.contentSubtitle }),
10084
+ /* @__PURE__ */ jsx15(Layouts.Content, { children: /* @__PURE__ */ jsxs12(Tabs.Root, { value: current, onValueChange: setTab, children: [
10085
+ /* @__PURE__ */ jsxs12(Tabs.List, { "aria-label": t.contentTitle, children: [
10086
+ canActivity && /* @__PURE__ */ jsx15(Tabs.Trigger, { value: "activity", children: t.activityTab }),
10087
+ canTrash && /* @__PURE__ */ jsx15(Tabs.Trigger, { value: "trash", children: t.trashTab })
10088
+ ] }),
10089
+ /* @__PURE__ */ jsxs12(Box7, { paddingTop: 6, paddingBottom: 6, background: "neutral0", hasRadius: true, paddingLeft: 6, paddingRight: 6, marginTop: 4, children: [
10090
+ canActivity && /* @__PURE__ */ jsx15(Tabs.Content, { value: "activity", children: /* @__PURE__ */ jsx15(ActivityTab, { t, get }) }),
10091
+ canTrash && /* @__PURE__ */ jsx15(Tabs.Content, { value: "trash", children: /* @__PURE__ */ jsx15(TrashTab, { t, get, post, del, can: trash.allowedActions }) })
10092
+ ] })
10093
+ ] }) })
10094
+ ] });
10095
+ }
10096
+
10097
+ // admin/strapi5.tsx
10098
+ import { Fragment as Fragment12, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
10099
+ function Modal2({ open, onOpenChange, trigger, title, children, width = "80vw" }) {
10100
+ return /* @__PURE__ */ jsxs13(Dialog2.Root, { open, onOpenChange, children: [
10101
+ trigger && /* @__PURE__ */ jsx16(Dialog2.Trigger, { children: trigger }),
10102
+ /* @__PURE__ */ jsxs13(Dialog2.Content, { style: { width, maxWidth: "92vw" }, children: [
10103
+ /* @__PURE__ */ jsx16(Dialog2.Header, { children: /* @__PURE__ */ jsx16(Dialog2.Title, { children: title }) }),
10104
+ /* @__PURE__ */ jsx16(Dialog2.Body, { children })
10105
+ ] })
10106
+ ] });
10107
+ }
10108
+ async function relationsOf(get, { uid, id, field }, locale) {
10109
+ const out = [];
10110
+ for (let page = 1; page <= 20; page++) {
10111
+ const query2 = new URLSearchParams({ page: String(page), pageSize: "100", ...locale ? { locale } : {} });
10112
+ const { data } = await get(`/content-manager/relations/${uid}/${id}/${field}?${query2}`);
10113
+ out.push(...data?.results || []);
10114
+ if (page >= (data?.pagination?.pageCount || 1)) break;
10115
+ }
10116
+ return out.reverse();
10117
+ }
10118
+ function useRowForm(c, values, get) {
10119
+ const onChange = useForm3("Blockscene", (state) => state.onChange);
10120
+ const errors = useForm3("Blockscene", (state) => state.errors);
10121
+ const { toggleNotification } = useNotification3();
10122
+ const latest = React16.useRef(values);
10123
+ latest.current = values;
10124
+ const locale = c.form?.initialValues?.locale || void 0;
10125
+ if (typeof onChange !== "function") return null;
8967
10126
  return {
8968
- model: c.slug,
8969
- locale: c.initialData?.locale || void 0,
10127
+ model: c.model,
10128
+ locale,
8970
10129
  rows: (zone) => Array.isArray(latest.current?.[zone]) ? latest.current[zone] : [],
8971
- setRows: (zone, rows) => c.onChange({ target: { name: zone, value: rows } }),
8972
- errorRows: (zone) => errorRows(c.formErrors, zone),
8973
- keys: (rows, _at, n) => integerKeys(rows, n),
10130
+ setRows: (zone, rows) => onChange(zone, rows),
10131
+ errorRows: (zone) => errorRows(errors, zone),
10132
+ keys: fractionalKeys,
8974
10133
  notify: (type, message) => toggleNotification({ type, message }),
8975
- prepare: async (rows) => rows.map((row) => cloneRow(row, components))
10134
+ prepare: (rows) => Promise.all(rows.map(async (row) => {
10135
+ const server = /* @__PURE__ */ new Map();
10136
+ for (const slot of relationSlots(row, c.components)) server.set(slot.path, await relationsOf(get, slot, locale));
10137
+ return cloneRow(row, c.components, {
10138
+ relation: (value, attr, path) => toConnect(currentRelations(server.get(path.join(".")) || [], value), attr.targetModel || attr.target)
10139
+ });
10140
+ }))
8976
10141
  };
8977
10142
  }
8978
- function Picker() {
8979
- const c = useCMEditViewDataManager();
8980
- const { get, put } = useFetchClient();
10143
+ function useScope() {
10144
+ const c = useContext2();
10145
+ const rbac = useDocumentRBAC2("Blockscene", (state) => state);
10146
+ const { get, put } = useFetchClient3();
10147
+ const formValues = useForm3("Blockscene", (state) => state.values);
8981
10148
  const catalog = useCatalog(get);
8982
- const components = c.allLayoutData?.components || {};
8983
- const form = useRowForm(c, components);
8984
- const schema = c.layout || c.allLayoutData?.contentType;
8985
- const allowed = (c.isCreatingEntry ? c.createActionAllowedFields : c.updateActionAllowedFields) || [];
10149
+ const creating = !c.id && !c.form?.initialValues?.id && !c.form?.initialValues?.documentId;
10150
+ const allowed = (creating ? rbac.canCreateFields : rbac.canUpdateFields) || [];
10151
+ const fields = c.layout?.edit?.layout?.flat(3) || [];
8986
10152
  const zones = editableZones(
8987
- schema,
8988
- c.modifiedData,
8989
- (name) => allowed.includes(name) && schema?.metadatas?.[name]?.edit?.editable !== false,
8990
- !c.addComponentToDynamicZone
8991
- ).map((zone) => ({ ...zone, label: zoneLabel(schema, zone.name) }));
8992
- const add = (zone, uid, values) => {
8993
- const close = catalog?.groups?.[uid];
8994
- if (!canInsert(zone, uid, c.modifiedData, components, close ? 2 : 1) || close && !zone.components.includes(close))
8995
- return false;
8996
- const at = Array.isArray(c.modifiedData?.[zone.name]) ? c.modifiedData[zone.name].length : 0;
8997
- c.addComponentToDynamicZone(
8998
- zone.name,
8999
- components[uid],
9000
- components,
9001
- Boolean(c.formErrors?.[zone.name])
9002
- );
9003
- if (values) overlayVariant(c, components, zone.name, at, uid, values);
9004
- if (close)
9005
- c.addComponentToDynamicZone(
9006
- zone.name,
9007
- components[close],
9008
- components,
9009
- Boolean(c.formErrors?.[zone.name])
9010
- );
9011
- return true;
9012
- };
9013
- if (!catalog?.editor?.enabled || catalog.contentTypes?.[c.slug]?.enabled === false) return null;
9014
- const docKey = `${c.slug}:${c.isCreatingEntry ? "new" : c.initialData?.id}:${c.initialData?.locale || ""}`;
9015
- return /* @__PURE__ */ jsx12("div", { hidden: true, "data-blockscene-editor": "", children: /* @__PURE__ */ jsx12(Workspace, { c, schema, zones, components, add, catalog, docKey, form, get, put }) });
10153
+ c.contentType,
10154
+ formValues ?? c.form?.values,
10155
+ (name) => allowed.includes(name) && (creating || (rbac.canReadFields || []).includes(name)) && fields.find((field) => field.name === name)?.disabled !== true,
10156
+ c.isLoading || c.form?.disabled || !c.form?.addFieldRow
10157
+ ).map((zone) => ({
10158
+ ...zone,
10159
+ label: fields.find((field) => field.name === zone.name)?.label || zone.name
10160
+ }));
10161
+ const typeSettings = catalog?.contentTypes?.[c.model] || {};
10162
+ const gallery = zones.length > 0 && Boolean(catalog?.editor?.enabled) && typeSettings.enabled !== false;
10163
+ const history = !creating && Boolean(c.id) && Boolean(catalog?.history?.contentTypes?.includes(c.model));
10164
+ return { c, rbac, get, put, formValues, catalog, creating, zones, typeSettings, gallery, history };
9016
10165
  }
9017
- function Workspace({ c, schema, zones, components, add, catalog, docKey, form, get, put }) {
9018
- const typeSettings = catalog.contentTypes?.[c.slug] || {};
10166
+ var Menu2 = ({ label, testid, items: items2 }) => /* @__PURE__ */ jsx16(Box8, { "data-testid": testid, children: /* @__PURE__ */ jsx16(SimpleMenu2, { variant: "tertiary", size: "S", "aria-label": label, title: label, endIcon: null, label: /* @__PURE__ */ jsx16(Icon, { name: "more", size: 16 }), children: items2.map((item) => /* @__PURE__ */ jsx16(MenuItem2, { onSelect: item.onSelect, "data-testid": item.testid, children: /* @__PURE__ */ jsxs13(Flex10, { gap: 2, alignItems: "center", children: [
10167
+ /* @__PURE__ */ jsx16(Icon, { name: item.icon, size: 16 }),
10168
+ item.label
10169
+ ] }) }, item.testid)) }) });
10170
+ function Editor() {
10171
+ const scope = useScope();
10172
+ const { catalog, typeSettings, gallery } = scope;
10173
+ const lazy = Boolean(catalog?.editor?.enabled && catalog.editor.lazyEditors !== false && typeSettings.enabled !== false);
10174
+ const lazyFields = (catalog?.editor?.lazyFields || []).join(",");
10175
+ React16.useEffect(() => {
10176
+ if (catalog) setLazyConfig({ on: lazy, fields: lazyFields ? lazyFields.split(",") : [] });
10177
+ }, [catalog, lazy, lazyFields]);
10178
+ const kept2 = React16.useRef(false);
10179
+ if (!scope.c.isLoading) kept2.current = gallery;
10180
+ if (!kept2.current) return null;
10181
+ return /* @__PURE__ */ jsx16(Guard, { children: /* @__PURE__ */ jsx16("div", { hidden: true, "data-blockscene-editor": "", children: /* @__PURE__ */ jsx16(Workspace, { scope }) }) });
10182
+ }
10183
+ function Workspace({ scope }) {
10184
+ const { c, get, put, formValues, catalog, creating, zones, typeSettings } = scope;
10185
+ const user = useAuth("Blockscene", (state2) => state2.user);
10186
+ const form = useRowForm(c, formValues ?? c.form?.values, get);
9019
10187
  const editor = {
9020
10188
  ...catalog.editor,
9021
10189
  previewMode: typeSettings.previewMode || catalog.editor.previewMode,
@@ -9024,32 +10192,49 @@ function Workspace({ c, schema, zones, components, add, catalog, docKey, form, g
9024
10192
  previewToolbar: typeSettings.previewToolbar || catalog.editor.previewToolbar,
9025
10193
  previewDevices: typeSettings.previewDevices || catalog.editor.previewDevices
9026
10194
  };
9027
- const host = usePreviewHost4(c, schema, components, get, put);
10195
+ const host = usePreviewHost5();
9028
10196
  const state = useEditorState(editor, host);
9029
- return /* @__PURE__ */ jsxs9(Fragment9, { children: [
9030
- /* @__PURE__ */ jsx12(
10197
+ const add = (zone, uid, preset) => {
10198
+ const values = formValues ?? c.form.values;
10199
+ const close = catalog?.groups?.[uid];
10200
+ if (c.form.disabled || !canInsert(zone, uid, values, c.components, close ? 2 : 1) || close && !zone.components.includes(close))
10201
+ return false;
10202
+ const at = Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0;
10203
+ c.form.addFieldRow(
10204
+ zone.name,
10205
+ {
10206
+ ...variantRow(c.components[uid], c.components, preset),
10207
+ __component: uid
10208
+ },
10209
+ at
10210
+ );
10211
+ if (close) c.form.addFieldRow(zone.name, { __component: close }, at + 1);
10212
+ return true;
10213
+ };
10214
+ return /* @__PURE__ */ jsxs13(Fragment12, { children: [
10215
+ /* @__PURE__ */ jsx16(
9031
10216
  Gallery,
9032
10217
  {
9033
10218
  zones,
9034
- components,
10219
+ components: c.components,
9035
10220
  add,
9036
- Modal,
10221
+ Modal: Modal2,
9037
10222
  Toggle: ToggleField,
10223
+ Menu: Menu2,
9038
10224
  get,
9039
10225
  put,
9040
10226
  editor: catalog.editor,
9041
10227
  catalog,
9042
- docKey,
9043
- contentType: c.slug,
9044
- userId: auth.getUserInfo?.()?.id,
10228
+ docKey: `${c.model}:${creating ? "new" : c.id}:${c.form?.initialValues?.locale || ""}`,
10229
+ contentType: c.model,
10230
+ userId: user?.id,
9045
10231
  form,
9046
- Menu: Menu2,
9047
- zoneTools: state.preview.base ? /* @__PURE__ */ jsx12(ZoneBarTools, { state }) : null,
10232
+ zoneTools: /* @__PURE__ */ jsx16(ZoneBarTools, { state }),
9048
10233
  openBlock: state.openBlock,
9049
10234
  openInsert: state.openInsert
9050
10235
  }
9051
10236
  ),
9052
- /* @__PURE__ */ jsx12(
10237
+ /* @__PURE__ */ jsx16(
9053
10238
  PagePreview,
9054
10239
  {
9055
10240
  editor,
@@ -9058,102 +10243,73 @@ function Workspace({ c, schema, zones, components, add, catalog, docKey, form, g
9058
10243
  groups: catalog.groups || null,
9059
10244
  hiddenAttribute: catalog.editor.hiddenBlocks !== "off" ? catalog.hiddenAttribute : null,
9060
10245
  form,
9061
- Modal,
10246
+ Modal: Modal2,
9062
10247
  Toggle: ToggleField
9063
10248
  }
9064
10249
  )
9065
10250
  ] });
9066
10251
  }
9067
- function usePreviewHost4(c, schema, components, get, put) {
9068
- const toggleNotification = useNotification();
9069
- const { components: library } = useLibrary();
9070
- const creating = Boolean(c.isCreatingEntry);
9071
- const readable = React12.useCallback(
9072
- (name) => creating || (c.readActionAllowedFields || []).includes(name),
9073
- [creating, c.readActionAllowedFields]
9074
- );
10252
+ function Panel2() {
10253
+ const { c, rbac, get, catalog, gallery, history } = useScope();
10254
+ const canReadHistory = Boolean(useRBAC3(HISTORY_READ).allowedActions?.canRead);
10255
+ const preview = usePreviewZone(usePreviewHost5());
10256
+ const groups = gallery ? catalog?.groups : null;
10257
+ const problems = groups && preview.zone ? (0, import_groups.validateGroups)(preview.rows, groups) : [];
10258
+ const versions = history && canReadHistory;
10259
+ if (!versions && !problems.length) return null;
9075
10260
  return {
9076
- ds: 1,
9077
- model: c.slug,
9078
- documentId: creating ? void 0 : c.initialData?.id,
9079
- locale: c.initialData?.locale || void 0,
9080
- creating,
9081
- loading: false,
9082
- disabled: false,
9083
- contentType: schema,
9084
- components,
9085
- values: c.modifiedData,
9086
- history: null,
9087
- readable,
9088
- editable: (name) => ((creating ? c.createActionAllowedFields : c.updateActionAllowedFields) || []).includes(name) && schema?.metadatas?.[name]?.edit?.editable !== false && typeof c.addComponentToDynamicZone === "function" && typeof c.onChange === "function",
9089
- fieldLabel: (name) => zoneLabel(schema, name),
9090
- onChange: (name, value) => c.onChange({ target: { name, value } }),
9091
- // Native insertion at a position (4.11+): the edit view's own default data structure, relations emptied.
9092
- // An insert variant's values are overlaid on the first row as in the gallery insert (Picker `add`).
9093
- insertRows: (zone, at, items2, values) => {
9094
- items2.forEach((item, i) => c.addComponentToDynamicZone(zone, components[item.__component], components, Boolean(c.formErrors?.[zone]), at + i));
9095
- if (values && items2[0]) overlayVariant(c, components, zone, at, items2[0].__component, values);
9096
- },
9097
- get,
9098
- put,
9099
- notify: (type, message) => toggleNotification({ type, message }),
9100
- MediaLibrary: library?.["media-library"],
9101
- useNativeBase: () => null,
9102
- Actions: Actions4
10261
+ title: "Blockscene",
10262
+ content: /* @__PURE__ */ jsx16(Guard, { children: /* @__PURE__ */ jsxs13(Flex10, { direction: "column", alignItems: "stretch", gap: 4, children: [
10263
+ problems.length > 0 && /* @__PURE__ */ jsx16(GroupDiagnostics, { scope: preview, groups, problems }),
10264
+ versions && /* @__PURE__ */ jsx16(
10265
+ History,
10266
+ {
10267
+ model: c.model,
10268
+ documentId: c.id,
10269
+ schema: c.contentType,
10270
+ components: c.components,
10271
+ editable: (name) => (rbac.canUpdateFields || []).some((field) => field === name || field.startsWith(`${name}.`)),
10272
+ disabled: Boolean(c.form?.disabled),
10273
+ get,
10274
+ relationsOf
10275
+ }
10276
+ )
10277
+ ] }) })
9103
10278
  };
9104
10279
  }
9105
- var zoneLabel = (schema, name) => schema?.layouts?.edit?.flat().find((field) => field?.name === name)?.metadatas?.label || schema?.metadatas?.[name]?.edit?.label || name;
9106
- function Actions4({ parts }) {
9107
- const c = useCMEditViewDataManager();
9108
- const t = useMessages();
9109
- const { formatMessage } = useIntl2();
9110
- const dirty = React12.useMemo(
9111
- () => c.isCreatingEntry ? Object.keys(c.modifiedData || {}).length > 0 : JSON.stringify(c.initialData) !== JSON.stringify(c.modifiedData),
9112
- [c.initialData, c.modifiedData, c.isCreatingEntry]
9113
- );
9114
- const published = typeof c.initialData?.publishedAt === "string";
9115
- const status = c.hasDraftAndPublish && !c.isCreatingEntry ? published ? "published" : "draft" : void 0;
9116
- const save = formatMessage({ id: "content-manager.containers.Edit.submit", defaultMessage: "Save" });
9117
- const publish = formatMessage(published ? { id: "app.utils.unpublish", defaultMessage: "Unpublish" } : { id: "app.utils.publish", defaultMessage: "Publish" });
9118
- const native = (label) => [...document.querySelectorAll("#main-content button")].find((b) => b.textContent?.trim() === label);
9119
- const actions = [
9120
- // Publish is the primary action, Save the secondary one (as in the Strapi 5 pane toolbar).
9121
- { label: save, variant: "secondary", disabled: !dirty, loading: c.status === "submit-pending", reason: t.saveDisabledHint },
9122
- ...c.hasDraftAndPublish && !c.isCreatingEntry ? [{ label: publish, variant: "default", disabled: dirty, loading: c.status === (published ? "unpublish-pending" : "publish-pending"), reason: t.publishDisabledHint }] : []
9123
- ].filter((action) => native(action.label));
9124
- return /* @__PURE__ */ jsxs9(Flex6, { gap: 2, alignItems: "center", "data-testid": "page-preview-actions", children: [
9125
- parts.includes("status") && (status || dirty) && /* @__PURE__ */ jsxs9(Flex6, { gap: 2, alignItems: "center", style: { order: parts.indexOf("status") }, children: [
9126
- status && /* @__PURE__ */ jsx12(Status, { size: "S", showBullet: false, role: "status", "data-testid": "page-preview-status", variant: published ? "success" : "secondary", children: /* @__PURE__ */ jsx12(Typography6, { as: "span", variant: "omega", fontWeight: "bold", children: formatMessage({ id: `content-manager.containers.List.${status}`, defaultMessage: status === "published" ? "Published" : "Draft" }) }) }),
9127
- dirty && /* @__PURE__ */ jsx12(Typography6, { variant: "pi", textColor: "neutral600", children: t.unsaved })
9128
- ] }),
9129
- parts.includes("actions") && actions.map((action) => /* @__PURE__ */ jsx12("span", { title: action.disabled ? action.reason : void 0, style: { order: parts.indexOf("actions") }, children: /* @__PURE__ */ jsx12(
9130
- Button5,
9131
- {
9132
- size: "S",
9133
- variant: action.variant,
9134
- disabled: action.disabled,
9135
- loading: action.loading,
9136
- "aria-description": action.disabled ? action.reason : void 0,
9137
- onClick: () => native(action.label)?.click(),
9138
- children: action.label
9139
- }
9140
- ) }, action.label))
9141
- ] });
9142
- }
9143
- var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ jsxs9(Flex6, { gap: 3, children: [
9144
- /* @__PURE__ */ jsx12(
9145
- Switch,
10280
+ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ jsxs13(Flex10, { gap: 3, children: [
10281
+ /* @__PURE__ */ jsx16(
10282
+ Switch2,
9146
10283
  {
9147
10284
  name,
9148
10285
  "aria-label": label,
9149
- selected: Boolean(value),
10286
+ checked: Boolean(value),
9150
10287
  disabled,
9151
- onChange: () => onChange(!value)
10288
+ onCheckedChange: onChange
9152
10289
  }
9153
10290
  ),
9154
- /* @__PURE__ */ jsx12(Typography6, { children: label })
10291
+ /* @__PURE__ */ jsx16(Typography10, { children: label })
10292
+ ] });
10293
+ var TextField = ({
10294
+ name,
10295
+ label,
10296
+ value,
10297
+ onChange,
10298
+ disabled,
10299
+ placeholder
10300
+ }) => /* @__PURE__ */ jsxs13(Field3.Root, { name, children: [
10301
+ /* @__PURE__ */ jsx16(Field3.Label, { children: label }),
10302
+ /* @__PURE__ */ jsx16(
10303
+ TextInput2,
10304
+ {
10305
+ name,
10306
+ value,
10307
+ disabled,
10308
+ placeholder,
10309
+ onChange: (e) => onChange(e.target.value)
10310
+ }
10311
+ )
9155
10312
  ] });
9156
- var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ jsx12(TextInput, { name, label, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) });
9157
10313
  var SelectField = ({
9158
10314
  name,
9159
10315
  label,
@@ -9161,66 +10317,77 @@ var SelectField = ({
9161
10317
  onChange,
9162
10318
  disabled,
9163
10319
  options
9164
- }) => /* @__PURE__ */ jsx12(
9165
- SingleSelect,
9166
- {
9167
- name,
9168
- label,
9169
- value,
9170
- disabled,
9171
- onChange: (v) => onChange(String(v)),
9172
- children: options.map((o) => /* @__PURE__ */ jsx12(SingleSelectOption, { value: o.value, children: o.label }, o.value))
9173
- }
9174
- );
10320
+ }) => /* @__PURE__ */ jsxs13(Field3.Root, { name, children: [
10321
+ /* @__PURE__ */ jsx16(Field3.Label, { children: label }),
10322
+ /* @__PURE__ */ jsx16(
10323
+ SingleSelect2,
10324
+ {
10325
+ value,
10326
+ disabled,
10327
+ startIcon: options.find((o) => o.value === value)?.icon,
10328
+ onChange: (v) => onChange(String(v)),
10329
+ children: options.map((o) => /* @__PURE__ */ jsx16(SingleSelectOption2, { value: o.value, startIcon: o.icon, children: o.label }, o.value))
10330
+ }
10331
+ )
10332
+ ] });
9175
10333
  function MediaPicker({ onClose, onSelect }) {
9176
- const { components } = useLibrary();
9177
- const Dialog = components?.["media-library"];
9178
- if (!Dialog) {
9179
- onClose();
9180
- return null;
9181
- }
9182
- return /* @__PURE__ */ jsx12(
9183
- Dialog,
10334
+ const components = useStrapiApp2(
10335
+ "Blockscene",
10336
+ (state) => state.components
10337
+ );
10338
+ const Dialog3 = components?.["media-library"];
10339
+ React16.useEffect(() => {
10340
+ if (!Dialog3) onClose();
10341
+ }, [Dialog3, onClose]);
10342
+ if (!Dialog3) return null;
10343
+ return /* @__PURE__ */ jsx16(
10344
+ Dialog3,
9184
10345
  {
9185
10346
  onClose,
9186
10347
  allowedTypes: ["images"],
10348
+ multiple: false,
9187
10349
  onSelectAssets: (assets) => onSelect(assets?.[0])
9188
10350
  }
9189
10351
  );
9190
10352
  }
9191
10353
  function usePermissions() {
9192
- const { allowedActions, isLoading } = useRBAC(permissions);
10354
+ const { allowedActions, isLoading } = useRBAC3(
10355
+ Object.values(permissions).flat()
10356
+ );
9193
10357
  return {
9194
10358
  canRead: allowedActions.canRead,
9195
10359
  canUpdate: allowedActions.canUpdate,
9196
10360
  isLoading
9197
10361
  };
9198
10362
  }
9199
- var SettingsPage = () => /* @__PURE__ */ jsx12(Guard, { children: /* @__PURE__ */ jsx12(
10363
+ var SettingsPage = () => /* @__PURE__ */ jsx16(Guard, { children: /* @__PURE__ */ jsx16(
9200
10364
  Settings,
9201
10365
  {
9202
- useClient: useFetchClient,
10366
+ useClient: useFetchClient3,
9203
10367
  usePermissions,
9204
10368
  MediaPicker,
9205
10369
  ToggleField,
9206
10370
  SelectField,
9207
- TextField
10371
+ TextField,
10372
+ lazyEditors: true
9208
10373
  }
9209
10374
  ) });
9210
- var strapi4_default = {
10375
+ var strapiApp = null;
10376
+ var strapi5_default = {
9211
10377
  register(app) {
9212
- register(app, SettingsPage, "/settings/blockscene");
10378
+ strapiApp = app;
10379
+ register(app, SettingsPage, "blockscene");
9213
10380
  app.registerPlugin({ id: "blockscene", name: "Blockscene", apis: { registerPanel: (panel) => registerPanel(panel, ICON_NAMES) } });
10381
+ app.addMenuLink(contentMenuLink(() => /* @__PURE__ */ jsx16(Guard, { children: /* @__PURE__ */ jsx16(ContentPage, {}) })));
9214
10382
  },
9215
10383
  registerTrads,
9216
10384
  bootstrap(app) {
9217
- app.registerHook("Admin/CM/pages/EditView/mutate-edit-view-layout", labelsHook(() => getFetchClient().get, labelEditLayout4, dropField4));
9218
- app.injectContentManagerComponent("editView", "right-links", {
9219
- name: "blockscene",
9220
- Component: () => /* @__PURE__ */ jsx12(Guard, { children: /* @__PURE__ */ jsx12(Picker, {}) })
9221
- });
10385
+ app.getPlugin("content-manager").apis.addEditViewSidePanel([Panel2]);
10386
+ app.getPlugin("content-manager").injectComponent("editView", "right-links", { name: "blockscene", Component: Editor });
10387
+ app.registerHook("Admin/CM/pages/EditView/mutate-edit-view-layout", labelsHook(() => getFetchClient().get, labelEditLayout, dropField));
10388
+ wrapCustomFields(strapiApp);
9222
10389
  }
9223
10390
  };
9224
10391
  export {
9225
- strapi4_default as default
10392
+ strapi5_default as default
9226
10393
  };