@proveanything/smartlinks-utils-ui 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +10 -1
  2. package/dist/chunk-4LHF5JB7.js +54 -0
  3. package/dist/chunk-4LHF5JB7.js.map +1 -0
  4. package/dist/{chunk-GN2P3MOG.js → chunk-7UBXTFZQ.js} +16 -62
  5. package/dist/chunk-7UBXTFZQ.js.map +1 -0
  6. package/dist/{chunk-S6KH3YV4.js → chunk-JQPS5XPJ.js} +2 -2
  7. package/dist/{chunk-S6KH3YV4.js.map → chunk-JQPS5XPJ.js.map} +1 -1
  8. package/dist/chunk-MZ6JSCXO.js +247 -0
  9. package/dist/chunk-MZ6JSCXO.js.map +1 -0
  10. package/dist/{chunk-4Z46C4MJ.js → chunk-OTJV62XV.js} +2 -2
  11. package/dist/{chunk-4Z46C4MJ.js.map → chunk-OTJV62XV.js.map} +1 -1
  12. package/dist/{chunk-XA5J6CZL.js → chunk-UDYVH7QF.js} +212 -23
  13. package/dist/chunk-UDYVH7QF.js.map +1 -0
  14. package/dist/chunk-WFNEZQCD.js +28 -0
  15. package/dist/chunk-WFNEZQCD.js.map +1 -0
  16. package/dist/components/AssetPicker/index.d.ts +27 -1
  17. package/dist/components/AssetPicker/index.js +2 -1
  18. package/dist/components/ConditionsEditor/index.d.ts +5 -130
  19. package/dist/components/ConditionsEditor/index.js +3 -1
  20. package/dist/components/FacetRuleEditor/index.d.ts +42 -0
  21. package/dist/components/FacetRuleEditor/index.js +5 -0
  22. package/dist/components/FacetRuleEditor/index.js.map +1 -0
  23. package/dist/components/FontPicker/index.js +2 -1
  24. package/dist/components/IconPicker/index.js +2 -1
  25. package/dist/components/RecordsAdmin/index.d.ts +220 -30
  26. package/dist/components/RecordsAdmin/index.js +714 -369
  27. package/dist/components/RecordsAdmin/index.js.map +1 -1
  28. package/dist/index.d.ts +5 -2
  29. package/dist/index.js +7 -4
  30. package/dist/types-a2DdgZ2H.d.ts +128 -0
  31. package/dist/{index-BmKyfKiK.d.ts → useAssets-BM1bzzkq.d.ts} +38 -1
  32. package/package.json +17 -4
  33. package/dist/chunk-GN2P3MOG.js.map +0 -1
  34. package/dist/chunk-XA5J6CZL.js.map +0 -1
  35. package/dist/components/RecordsAdmin/index.css +0 -40
  36. package/dist/components/RecordsAdmin/index.css.map +0 -1
  37. package/dist/index.css +0 -1288
  38. package/dist/index.css.map +0 -1
@@ -1,9 +1,51 @@
1
+ import { styleInject } from '../../chunk-WFNEZQCD.js';
1
2
  import { cn } from '../../chunk-L7FQ52F5.js';
2
- import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext } from 'react';
3
- import { Package, Layers, Tag, Box, Rows3, Image, LayoutGrid, List, ChevronRight, ChevronDown, Trash2, Eye, X, HelpCircle, Search, Plus, CornerDownLeft, Circle } from 'lucide-react';
3
+ import { createContext, useMemo, useState, useEffect, useCallback, useRef, useContext, createElement } from 'react';
4
+ import { ChevronDown, Database, Lightbulb, SearchX, Inbox, LayoutGrid, Eye, MoreHorizontal, Download, Upload, Trash2, Copy, Pencil, Plus, CircleDashed, ArrowDownLeft, CheckCircle2, Globe, Tag, Boxes, Layers, Package, Rows3, Image, List, ChevronRight, Eraser, Box, AlertTriangle, Info, X, HelpCircle, Search, CornerDownLeft, Circle } from 'lucide-react';
4
5
  import { useQueryClient, useInfiniteQuery, useQuery } from '@tanstack/react-query';
5
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
7
 
8
+ var DEFAULT_ICONS = {
9
+ scope: { product: Package, variant: Layers, batch: Boxes, facet: Tag, universal: Globe },
10
+ status: { own: CheckCircle2, inherited: ArrowDownLeft, missing: CircleDashed },
11
+ action: {
12
+ add: Plus,
13
+ edit: Pencil,
14
+ duplicate: Copy,
15
+ delete: Trash2,
16
+ import: Upload,
17
+ export: Download,
18
+ more: MoreHorizontal
19
+ },
20
+ preview: { eye: Eye, switch: LayoutGrid },
21
+ empty: { default: Inbox, search: SearchX },
22
+ intro: { info: Lightbulb },
23
+ header: { default: Database, byRecordType: {} },
24
+ group: { chevron: ChevronDown }
25
+ };
26
+ function mergeIcons(override) {
27
+ if (!override) return DEFAULT_ICONS;
28
+ return {
29
+ scope: { ...DEFAULT_ICONS.scope, ...override.scope ?? {} },
30
+ status: { ...DEFAULT_ICONS.status, ...override.status ?? {} },
31
+ action: { ...DEFAULT_ICONS.action, ...override.action ?? {} },
32
+ preview: { ...DEFAULT_ICONS.preview, ...override.preview ?? {} },
33
+ empty: { ...DEFAULT_ICONS.empty, ...override.empty ?? {} },
34
+ intro: { ...DEFAULT_ICONS.intro, ...override.intro ?? {} },
35
+ header: {
36
+ default: override.header?.default ?? DEFAULT_ICONS.header.default,
37
+ byRecordType: { ...DEFAULT_ICONS.header.byRecordType, ...override.header?.byRecordType ?? {} }
38
+ },
39
+ group: { ...DEFAULT_ICONS.group, ...override.group ?? {} }
40
+ };
41
+ }
42
+ function pickHeaderIcon(icons, recordType) {
43
+ if (recordType && icons.header.byRecordType[recordType]) {
44
+ return icons.header.byRecordType[recordType];
45
+ }
46
+ return icons.header.default;
47
+ }
48
+
7
49
  // src/components/RecordsAdmin/types/i18n.ts
8
50
  var DEFAULT_I18N = {
9
51
  emptyTitle: "Nothing here yet",
@@ -160,7 +202,15 @@ var listRecords = async (ctx, params = {}) => {
160
202
  const res = await ctx.SL.app.records.list(
161
203
  ctx.collectionId,
162
204
  ctx.appId,
163
- { recordType: ctx.recordType, limit, offset, ref, refPrefix, q, sort },
205
+ {
206
+ ...ctx.recordType ? { recordType: ctx.recordType } : {},
207
+ limit,
208
+ offset,
209
+ ref,
210
+ refPrefix,
211
+ q,
212
+ sort
213
+ },
164
214
  true
165
215
  );
166
216
  return {
@@ -173,7 +223,7 @@ var getRecordByRef = async (ctx, ref) => {
173
223
  const res = await ctx.SL.app.records.list(
174
224
  ctx.collectionId,
175
225
  ctx.appId,
176
- { recordType: ctx.recordType, ref, limit: 1 },
226
+ { ...ctx.recordType ? { recordType: ctx.recordType } : {}, ref, limit: 1 },
177
227
  true
178
228
  );
179
229
  return res?.data?.[0] ?? null;
@@ -182,7 +232,7 @@ var upsertRecord = async (ctx, write) => {
182
232
  const ref = write.ref ?? deriveRefFromScope(write.scope);
183
233
  const res = await ctx.SL.app.records.upsert(ctx.collectionId, ctx.appId, {
184
234
  ref,
185
- recordType: ctx.recordType,
235
+ ...ctx.recordType ? { recordType: ctx.recordType } : {},
186
236
  scope: write.scope,
187
237
  data: write.data,
188
238
  status: write.status,
@@ -205,7 +255,7 @@ var matchRecords = async (ctx, target, opts = {}) => ctx.SL.app.records.match(
205
255
  ctx.appId,
206
256
  {
207
257
  target,
208
- recordType: ctx.recordType,
258
+ ...ctx.recordType ? { recordType: ctx.recordType } : {},
209
259
  strategy: opts.strategy ?? "all",
210
260
  at: opts.at,
211
261
  includeScheduled: opts.includeScheduled,
@@ -222,7 +272,7 @@ var bulkUpsert = async (ctx, entries) => {
222
272
  const slice = entries.slice(i, i + CHUNK);
223
273
  const items = slice.map((e) => ({
224
274
  ref: e.ref ?? deriveRefFromScope(e.scope),
225
- recordType: ctx.recordType,
275
+ ...ctx.recordType ? { recordType: ctx.recordType } : {},
226
276
  scope: e.scope,
227
277
  data: e.data,
228
278
  status: e.status
@@ -238,7 +288,7 @@ var bulkDelete = async (ctx, input) => {
238
288
  const res = await ctx.SL.app.records.bulkDelete(
239
289
  ctx.collectionId,
240
290
  ctx.appId,
241
- { scope: input.scope, recordType: ctx.recordType }
291
+ { scope: input.scope, ...ctx.recordType ? { recordType: ctx.recordType } : {} }
242
292
  );
243
293
  return { removed: res.deleted ?? 0 };
244
294
  }
@@ -249,7 +299,7 @@ var bulkDelete = async (ctx, input) => {
249
299
  const res = await ctx.SL.app.records.bulkDelete(
250
300
  ctx.collectionId,
251
301
  ctx.appId,
252
- { refs: slice, recordType: ctx.recordType }
302
+ { refs: slice, ...ctx.recordType ? { recordType: ctx.recordType } : {} }
253
303
  );
254
304
  removed += res.deleted ?? 0;
255
305
  }
@@ -405,22 +455,27 @@ var resolveRecord = async (args) => {
405
455
  if (records.length === 0) {
406
456
  return { data: null, source: "empty" };
407
457
  }
408
- const winner = records[0];
458
+ const winnerEntry = records[0];
459
+ const winner = winnerEntry.record;
409
460
  const winnerIsSelf = scopesEqual(winner.scope, editingScope);
410
461
  if (winnerIsSelf) {
411
- const parent = records[1];
462
+ const parent = records[1]?.record;
412
463
  return {
413
464
  data: winner.data,
414
465
  source: "self",
415
466
  sourceRef: winner.ref ?? void 0,
416
- parentValue: args.withParent && parent ? parent.data : void 0
467
+ parentValue: args.withParent && parent ? parent.data : void 0,
468
+ matchedAt: winnerEntry.matchedAt,
469
+ matchedRule: winnerEntry.matchedRule
417
470
  };
418
471
  }
419
472
  return {
420
473
  data: winner.data,
421
474
  source: "inherited",
422
475
  sourceRef: winner.ref ?? void 0,
423
- parentValue: args.withParent ? winner.data : void 0
476
+ parentValue: args.withParent ? winner.data : void 0,
477
+ matchedAt: winnerEntry.matchedAt,
478
+ matchedRule: winnerEntry.matchedRule
424
479
  };
425
480
  };
426
481
 
@@ -431,7 +486,7 @@ var resolvedRecordQueryKey = (args) => [
431
486
  "resolved",
432
487
  args.collectionId,
433
488
  args.appId,
434
- args.recordType,
489
+ args.recordType ?? null,
435
490
  args.productId ?? null,
436
491
  args.variantId ?? null,
437
492
  args.batchId ?? null,
@@ -620,7 +675,8 @@ function useRecordEditor(args) {
620
675
  saveError
621
676
  };
622
677
  }
623
- var lsKey = (appId, recordType) => `ra:intro:${appId}:${recordType}`;
678
+ var RT_KEY = (recordType) => recordType ?? "_default";
679
+ var lsKey = (appId, recordType) => `ra:intro:${appId}:${RT_KEY(recordType)}`;
624
680
  var useIntroDismissed = (SL, collectionId, appId, recordType) => {
625
681
  const [dismissed, setDismissed] = useState(() => {
626
682
  try {
@@ -635,7 +691,7 @@ var useIntroDismissed = (SL, collectionId, appId, recordType) => {
635
691
  try {
636
692
  const cfg = await SL?.appConfiguration?.getConfig?.({ collectionId, appId, admin: true });
637
693
  if (cancelled) return;
638
- const flag = cfg?._meta?.introDismissed?.[recordType];
694
+ const flag = cfg?._meta?.introDismissed?.[RT_KEY(recordType)];
639
695
  if (flag) setDismissed(true);
640
696
  } catch {
641
697
  }
@@ -656,7 +712,7 @@ var useIntroDismissed = (SL, collectionId, appId, recordType) => {
656
712
  ...cfg ?? {},
657
713
  _meta: {
658
714
  ...cfg?._meta ?? {},
659
- introDismissed: { ...cfg?._meta?.introDismissed ?? {}, [recordType]: true }
715
+ introDismissed: { ...cfg?._meta?.introDismissed ?? {}, [RT_KEY(recordType)]: true }
660
716
  }
661
717
  };
662
718
  await SL?.appConfiguration?.setConfig?.({ collectionId, appId, admin: true, config: next });
@@ -700,11 +756,11 @@ var toBrowseItem = (p) => ({
700
756
  sortOrder: p.sortOrder ?? null
701
757
  });
702
758
  var useProductBrowse = (args) => {
703
- const { SL, collectionId, search = "", pageSize = 50, enabled = true } = args;
759
+ const { SL, collectionId, search = "", pageSize = 50, enabled = true, admin = true } = args;
704
760
  const queryClient = useQueryClient();
705
761
  const queryKey = useMemo(
706
- () => [...QK, collectionId, search.trim(), pageSize],
707
- [collectionId, search, pageSize]
762
+ () => [...QK, collectionId, search.trim(), pageSize, admin],
763
+ [collectionId, search, pageSize, admin]
708
764
  );
709
765
  const query = useInfiniteQuery({
710
766
  queryKey,
@@ -716,7 +772,7 @@ var useProductBrowse = (args) => {
716
772
  sort: [{ field: "sortOrder", direction: "asc" }, { field: "name", direction: "asc" }]
717
773
  };
718
774
  if (search.trim()) body.query = { search: search.trim() };
719
- const res = await SL.product.query(collectionId, body);
775
+ const res = await SL.product.query(collectionId, body, admin);
720
776
  const items2 = (res?.items ?? []).map(toBrowseItem);
721
777
  const page = res?.page ?? {};
722
778
  return {
@@ -900,48 +956,44 @@ var useDirtyNavigation = ({
900
956
  );
901
957
  return { runWithGuard };
902
958
  };
903
- var ICONS = {
904
- product: Box,
905
- facet: Tag,
906
- variant: Layers,
907
- batch: Package
908
- };
909
959
  var LABELS = {
910
960
  product: "Products",
911
961
  facet: "Shared",
912
- // Variant/Batch are drill-downs under a product, but kept here for hosts
913
- // that still pass them as top-level scopes. The shell omits them by default.
914
962
  variant: "Variants",
915
963
  batch: "Batches"
916
964
  };
917
- var ScopeTabs = ({ scopes, active, onChange, loading = false }) => /* @__PURE__ */ jsx("div", { role: "tablist", className: "flex gap-1 border-b", style: { borderColor: "hsl(var(--ra-border))" }, children: scopes.map((s) => {
918
- const Icon = ICONS[s];
919
- const isActive = active === s;
920
- return /* @__PURE__ */ jsxs(
921
- "button",
922
- {
923
- type: "button",
924
- role: "tab",
925
- "aria-selected": isActive,
926
- onClick: () => onChange(s),
927
- disabled: loading,
928
- className: cn(
929
- "flex items-center gap-1.5 px-3 py-2 text-xs border-b-2 -mb-px transition-colors",
930
- isActive ? "font-medium" : "opacity-60 hover:opacity-100",
931
- loading && "cursor-wait opacity-40"
932
- ),
933
- style: {
934
- borderColor: isActive ? "hsl(var(--ra-accent))" : "transparent",
935
- color: "hsl(var(--ra-text))"
965
+ var ScopeTabs = ({
966
+ scopes,
967
+ active,
968
+ onChange,
969
+ loading = false,
970
+ counts,
971
+ icons
972
+ }) => {
973
+ const iconMap = icons ?? DEFAULT_ICONS.scope;
974
+ return /* @__PURE__ */ jsx("div", { role: "tablist", className: "ra-tabs", "aria-label": "Record scope", children: scopes.map((s) => {
975
+ const Icon = iconMap[s] ?? DEFAULT_ICONS.scope[s];
976
+ const isActive = active === s;
977
+ const count = counts?.[s];
978
+ return /* @__PURE__ */ jsxs(
979
+ "button",
980
+ {
981
+ type: "button",
982
+ role: "tab",
983
+ "aria-selected": isActive,
984
+ onClick: () => onChange(s),
985
+ disabled: loading,
986
+ className: "ra-tab",
987
+ children: [
988
+ /* @__PURE__ */ jsx(Icon, { className: cn("ra-tab-icon w-3.5 h-3.5", loading && "animate-pulse") }),
989
+ /* @__PURE__ */ jsx("span", { children: LABELS[s] }),
990
+ typeof count === "number" && count > 0 && /* @__PURE__ */ jsx("span", { className: "ra-tab-count", children: count })
991
+ ]
936
992
  },
937
- children: [
938
- /* @__PURE__ */ jsx(Icon, { className: cn("w-3.5 h-3.5", loading && "animate-pulse") }),
939
- LABELS[s]
940
- ]
941
- },
942
- s
943
- );
944
- }) });
993
+ s
994
+ );
995
+ }) });
996
+ };
945
997
  var StatusFilterPills = ({ value, onChange, counts, i18n }) => {
946
998
  const opts = [
947
999
  { key: "all", label: i18n.filterAll, count: counts.all },
@@ -982,34 +1034,23 @@ var StatusDot = ({ source, status, className }) => {
982
1034
  };
983
1035
  var DefaultRecordRow = ({ record, ctx, compact = false }) => {
984
1036
  const { selected, onSelect, isDirty } = ctx;
1037
+ const ScopeIcon = record.scope.kind && record.scope.kind !== "collection" ? DEFAULT_ICONS.scope[record.scope.kind] : DEFAULT_ICONS.scope.product;
985
1038
  return /* @__PURE__ */ jsxs(
986
1039
  "button",
987
1040
  {
988
1041
  type: "button",
989
1042
  onClick: onSelect,
990
- className: cn(
991
- "w-full text-left flex items-center gap-2.5 px-3 transition-colors hover:bg-[hsl(var(--ra-muted))]",
992
- compact ? "py-1.5" : "py-2.5",
993
- selected && "ra-row-active"
994
- ),
1043
+ "data-selected": selected ? "true" : "false",
1044
+ className: cn("ra-row", compact && "ra-row-compact"),
1045
+ style: compact ? { paddingTop: "0.4rem", paddingBottom: "0.4rem" } : void 0,
995
1046
  children: [
996
- !compact && /* @__PURE__ */ jsx(StatusDot, { status: record.status }),
997
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
998
- /* @__PURE__ */ jsx("div", { className: "text-sm truncate", style: { color: "hsl(var(--ra-text))" }, children: record.label }),
999
- !compact && record.subtitle && /* @__PURE__ */ jsx("div", { className: "text-xs truncate", style: { color: "hsl(var(--ra-muted-text))" }, children: record.subtitle })
1047
+ !compact && /* @__PURE__ */ jsx("span", { className: "ra-row-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ScopeIcon, { className: "w-3.5 h-3.5" }) }),
1048
+ /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
1049
+ /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
1050
+ !compact && record.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: record.subtitle })
1000
1051
  ] }),
1001
- record.badges?.slice(0, 2).map((b, i) => /* @__PURE__ */ jsx(
1002
- "span",
1003
- {
1004
- className: "text-[10px] px-1.5 py-0.5 rounded-sm shrink-0",
1005
- style: {
1006
- background: "hsl(var(--ra-muted))",
1007
- color: "hsl(var(--ra-muted-text))"
1008
- },
1009
- children: b.label
1010
- },
1011
- `${b.label}-${i}`
1012
- )),
1052
+ /* @__PURE__ */ jsx(StatusDot, { status: record.status }),
1053
+ record.badges?.slice(0, 1).map((b, i) => /* @__PURE__ */ jsx("span", { className: "ra-chip", "data-tone": "muted", children: b.label }, `${b.label}-${i}`)),
1013
1054
  isDirty && /* @__PURE__ */ jsx(
1014
1055
  "span",
1015
1056
  {
@@ -1032,14 +1073,13 @@ var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
1032
1073
  type: "button",
1033
1074
  onClick: onSelect,
1034
1075
  className: cn(
1035
- "group flex flex-col text-left rounded-md overflow-hidden border transition-colors",
1036
- "hover:bg-[hsl(var(--ra-muted))]",
1076
+ "group flex flex-col text-left rounded-md overflow-hidden border ra-card-hover",
1037
1077
  selected && "ring-2"
1038
1078
  ),
1039
1079
  style: {
1040
- borderColor: "hsl(var(--ra-border))",
1041
- // selected ring
1042
- ...selected ? { boxShadow: "0 0 0 2px hsl(var(--ra-accent, var(--ra-text)))" } : {}
1080
+ background: "hsl(var(--ra-surface))",
1081
+ borderColor: selected ? "var(--ra-row-active-bd)" : "hsl(var(--ra-border))",
1082
+ boxShadow: selected ? `0 0 0 2px hsl(var(--ra-accent) / 0.45), var(--ra-card-shadow)` : "var(--ra-card-shadow)"
1043
1083
  },
1044
1084
  children: [
1045
1085
  /* @__PURE__ */ jsxs(
@@ -1059,8 +1099,8 @@ var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
1059
1099
  ) : /* @__PURE__ */ jsx(
1060
1100
  "span",
1061
1101
  {
1062
- className: "text-2xl font-medium opacity-60",
1063
- style: { color: "hsl(var(--ra-text))" },
1102
+ className: "text-2xl ra-display",
1103
+ style: { color: "hsl(var(--ra-muted-text))" },
1064
1104
  children: initials(record.label)
1065
1105
  }
1066
1106
  ),
@@ -1076,22 +1116,10 @@ var DefaultRecordCard = ({ record, ctx, variant = "grid" }) => {
1076
1116
  ]
1077
1117
  }
1078
1118
  ),
1079
- /* @__PURE__ */ jsxs("div", { className: "p-2 min-w-0", children: [
1080
- /* @__PURE__ */ jsx("div", { className: "text-sm truncate", style: { color: "hsl(var(--ra-text))" }, children: record.label }),
1081
- variant === "gallery" && record.subtitle && /* @__PURE__ */ jsx("div", { className: "text-xs truncate", style: { color: "hsl(var(--ra-muted-text))" }, children: record.subtitle }),
1082
- record.badges && record.badges.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex gap-1 mt-1.5 flex-wrap", children: record.badges.slice(0, 3).map((b, i) => /* @__PURE__ */ jsx(
1083
- "span",
1084
- {
1085
- className: "text-[10px] px-1.5 py-0.5 rounded-sm",
1086
- style: {
1087
- background: "hsl(var(--ra-surface))",
1088
- border: "1px solid hsl(var(--ra-border))",
1089
- color: "hsl(var(--ra-muted-text))"
1090
- },
1091
- children: b.label
1092
- },
1093
- `${b.label}-${i}`
1094
- )) })
1119
+ /* @__PURE__ */ jsxs("div", { className: "p-2.5 min-w-0", children: [
1120
+ /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
1121
+ variant === "gallery" && record.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: record.subtitle }),
1122
+ record.badges && record.badges.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex gap-1 mt-1.5 flex-wrap", children: record.badges.slice(0, 3).map((b, i) => /* @__PURE__ */ jsx("span", { className: "ra-chip", "data-tone": "muted", children: b.label }, `${b.label}-${i}`)) })
1095
1123
  ] })
1096
1124
  ]
1097
1125
  }
@@ -1104,45 +1132,124 @@ var RecordList = ({
1104
1132
  dirtyRef,
1105
1133
  presentation = "list",
1106
1134
  renderListRow,
1107
- renderCard
1135
+ renderCard,
1136
+ groupBy
1108
1137
  }) => {
1109
1138
  const buildCtx = (item) => ({
1110
1139
  selected: item.ref === selectedRef,
1111
1140
  onSelect: () => onSelect(item),
1112
1141
  isDirty: !!dirtyRef && item.ref === dirtyRef
1113
1142
  });
1114
- if (presentation === "grid" || presentation === "gallery") {
1115
- const minColPx = presentation === "gallery" ? 200 : 120;
1116
- return /* @__PURE__ */ jsx(
1117
- "div",
1118
- {
1119
- className: "grid gap-2 p-2",
1120
- style: { gridTemplateColumns: `repeat(auto-fill, minmax(${minColPx}px, 1fr))` },
1121
- children: items.map((item) => {
1122
- const ctx = buildCtx(item);
1123
- return /* @__PURE__ */ jsx("div", { children: renderCard ? renderCard(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordCard, { record: item, ctx, variant: presentation }) }, item.ref);
1124
- })
1143
+ const groups = useMemo(() => {
1144
+ if (!groupBy) return null;
1145
+ const buckets = /* @__PURE__ */ new Map();
1146
+ const orderedKeys = [];
1147
+ for (const item of items) {
1148
+ const g = groupBy(item) ?? { key: "__other", label: "Other" };
1149
+ if (!buckets.has(g.key)) {
1150
+ buckets.set(g.key, { ...g, items: [] });
1151
+ orderedKeys.push(g.key);
1125
1152
  }
1126
- );
1153
+ buckets.get(g.key).items.push(item);
1154
+ }
1155
+ return orderedKeys.map((k) => buckets.get(k));
1156
+ }, [items, groupBy]);
1157
+ const renderItems = (rows) => {
1158
+ if (presentation === "grid" || presentation === "gallery") {
1159
+ const minColPx = presentation === "gallery" ? 200 : 120;
1160
+ return /* @__PURE__ */ jsx(
1161
+ "div",
1162
+ {
1163
+ className: "grid gap-2 p-2",
1164
+ style: { gridTemplateColumns: `repeat(auto-fill, minmax(${minColPx}px, 1fr))` },
1165
+ children: rows.map((item) => {
1166
+ const ctx = buildCtx(item);
1167
+ return /* @__PURE__ */ jsx("div", { children: renderCard ? renderCard(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordCard, { record: item, ctx, variant: presentation }) }, item.ref);
1168
+ })
1169
+ }
1170
+ );
1171
+ }
1172
+ const compact = presentation === "compact";
1173
+ return /* @__PURE__ */ jsx("ul", { children: rows.map((item) => {
1174
+ const ctx = buildCtx(item);
1175
+ return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.ref);
1176
+ }) });
1177
+ };
1178
+ if (groups) {
1179
+ return /* @__PURE__ */ jsx(GroupedList, { groups, renderItems });
1127
1180
  }
1128
- const compact = presentation === "compact";
1129
- return /* @__PURE__ */ jsx("ul", { className: "divide-y", style: { borderColor: "hsl(var(--ra-border))" }, children: items.map((item) => {
1130
- const ctx = buildCtx(item);
1131
- return /* @__PURE__ */ jsx("li", { children: renderListRow ? renderListRow(item, ctx) : /* @__PURE__ */ jsx(DefaultRecordRow, { record: item, ctx, compact }) }, item.ref);
1181
+ return renderItems(items);
1182
+ };
1183
+ var GroupedList = ({
1184
+ groups,
1185
+ renderItems
1186
+ }) => {
1187
+ const Chevron = DEFAULT_ICONS.group.chevron;
1188
+ const [open, setOpen] = useState(
1189
+ () => Object.fromEntries(groups.map((g) => [g.key, true]))
1190
+ );
1191
+ return /* @__PURE__ */ jsx(Fragment, { children: groups.map((g) => {
1192
+ const isOpen = open[g.key] !== false;
1193
+ return /* @__PURE__ */ jsxs("section", { className: "ra-group", "data-open": isOpen ? "true" : "false", children: [
1194
+ /* @__PURE__ */ jsxs(
1195
+ "button",
1196
+ {
1197
+ type: "button",
1198
+ className: "ra-group-summary",
1199
+ onClick: () => setOpen((s) => ({ ...s, [g.key]: !isOpen })),
1200
+ "aria-expanded": isOpen,
1201
+ children: [
1202
+ /* @__PURE__ */ jsx(Chevron, { className: "ra-group-chevron w-3 h-3" }),
1203
+ g.icon,
1204
+ /* @__PURE__ */ jsx("span", { className: "ra-group-name", children: g.label }),
1205
+ /* @__PURE__ */ jsx("span", { className: "ra-group-count", children: g.items.length })
1206
+ ]
1207
+ }
1208
+ ),
1209
+ /* @__PURE__ */ jsx("div", { className: "ra-group-body", children: renderItems(g.items) })
1210
+ ] }, g.key);
1132
1211
  }) });
1133
1212
  };
1134
1213
  var ProductList = RecordList;
1135
1214
  var FacetList = RecordList;
1136
1215
  var VariantList = RecordList;
1137
1216
  var BatchList = RecordList;
1138
- var EmptyState = ({ title, body, action }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center text-center p-8 gap-2", children: [
1139
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", style: { color: "hsl(var(--ra-text))" }, children: title }),
1140
- body && /* @__PURE__ */ jsx("div", { className: "text-xs", style: { color: "hsl(var(--ra-muted-text))" }, children: body }),
1141
- action
1217
+ var EmptyState = ({
1218
+ title,
1219
+ body,
1220
+ action,
1221
+ secondaryAction,
1222
+ icon: Icon = Inbox
1223
+ }) => /* @__PURE__ */ jsxs("div", { className: "ra-empty", children: [
1224
+ /* @__PURE__ */ jsx("div", { className: "ra-empty-icon", children: /* @__PURE__ */ jsx(Icon, { className: "w-6 h-6" }) }),
1225
+ /* @__PURE__ */ jsx("h3", { className: "ra-empty-title", children: title }),
1226
+ body && /* @__PURE__ */ jsx("p", { className: "ra-empty-body", children: body }),
1227
+ (action || secondaryAction) && /* @__PURE__ */ jsxs("div", { className: "ra-empty-actions", children: [
1228
+ action,
1229
+ secondaryAction
1230
+ ] })
1142
1231
  ] });
1143
- var LoadingState = () => /* @__PURE__ */ jsx("div", { className: "p-4 space-y-2", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx("div", { className: "h-10 rounded animate-pulse", style: { background: "hsl(var(--ra-muted))" } }, i)) });
1144
- var ErrorState = ({ error }) => /* @__PURE__ */ jsx("div", { className: "p-4 text-xs", style: { color: "hsl(0 70% 45%)" }, children: error.message || "Something went wrong." });
1145
- var ICONS2 = {
1232
+ var LoadingState = () => /* @__PURE__ */ jsx("div", { className: "p-3 space-y-2", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx(
1233
+ "div",
1234
+ {
1235
+ className: "h-11 rounded-md animate-pulse",
1236
+ style: { background: "hsl(var(--ra-muted))" }
1237
+ },
1238
+ i
1239
+ )) });
1240
+ var ErrorState = ({ error }) => /* @__PURE__ */ jsxs("div", { className: "ra-empty", children: [
1241
+ /* @__PURE__ */ jsx(
1242
+ "div",
1243
+ {
1244
+ className: "ra-empty-icon",
1245
+ style: { background: "hsl(var(--ra-danger) / 0.10)", color: "hsl(var(--ra-danger))" },
1246
+ children: "!"
1247
+ }
1248
+ ),
1249
+ /* @__PURE__ */ jsx("h3", { className: "ra-empty-title", children: "Something went wrong" }),
1250
+ /* @__PURE__ */ jsx("p", { className: "ra-empty-body", children: error.message || "Please try again." })
1251
+ ] });
1252
+ var ICONS = {
1146
1253
  list: List,
1147
1254
  grid: LayoutGrid,
1148
1255
  gallery: Image,
@@ -1170,7 +1277,7 @@ var PresentationSwitcher = ({ options, value, onChange, i18n }) => {
1170
1277
  role: "tablist",
1171
1278
  "aria-label": "View",
1172
1279
  children: options.map((opt) => {
1173
- const Icon = ICONS2[opt];
1280
+ const Icon = ICONS[opt];
1174
1281
  const active = opt === value;
1175
1282
  return /* @__PURE__ */ jsx(
1176
1283
  "button",
@@ -1209,7 +1316,7 @@ var safeWrite = (key, val) => {
1209
1316
  };
1210
1317
  function usePresentationPref(args) {
1211
1318
  const { appId, recordType, options, defaultValue } = args;
1212
- const key = `${KEY_PREFIX}:${appId}:${recordType}`;
1319
+ const key = `${KEY_PREFIX}:${appId}:${recordType ?? "_default"}`;
1213
1320
  const initial = () => {
1214
1321
  const stored = safeRead(key);
1215
1322
  if (stored && options.includes(stored)) return stored;
@@ -1260,11 +1367,11 @@ var BulkActionsMenu = ({
1260
1367
  return () => document.removeEventListener("mousedown", onDocClick);
1261
1368
  }, [open]);
1262
1369
  const items = [
1263
- onApplyToMany && { label: i18n.applyToMany, onClick: onApplyToMany },
1264
- onCopyFrom && { label: i18n.copyFrom, onClick: onCopyFrom },
1265
- onClearMany && { label: i18n.clear, onClick: onClearMany },
1266
- onImportCsv && { label: i18n.importCsv, onClick: onImportCsv },
1267
- onExportCsv && { label: i18n.exportCsv, onClick: onExportCsv }
1370
+ onApplyToMany && { key: "apply", label: i18n.applyToMany, onClick: onApplyToMany, icon: Layers },
1371
+ onCopyFrom && { key: "copy", label: i18n.copyFrom, onClick: onCopyFrom, icon: Copy },
1372
+ onImportCsv && { key: "imp", label: i18n.importCsv, onClick: onImportCsv, icon: Upload, divider: true },
1373
+ onExportCsv && { key: "exp", label: i18n.exportCsv, onClick: onExportCsv, icon: Download },
1374
+ onClearMany && { key: "clear", label: i18n.clear, onClick: onClearMany, icon: Eraser, tone: "danger", divider: true }
1268
1375
  ].filter(Boolean);
1269
1376
  if (items.length === 0) return null;
1270
1377
  return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
@@ -1273,35 +1380,39 @@ var BulkActionsMenu = ({
1273
1380
  {
1274
1381
  type: "button",
1275
1382
  onClick: () => setOpen((v) => !v),
1276
- className: "flex items-center gap-1 px-3 py-1.5 text-xs rounded-md border hover:bg-[hsl(var(--ra-muted))]",
1277
- style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
1383
+ className: "ra-btn",
1384
+ "aria-haspopup": "menu",
1385
+ "aria-expanded": open,
1278
1386
  children: [
1279
1387
  i18n.bulkActions,
1280
- /* @__PURE__ */ jsx(ChevronDown, { className: "w-3 h-3" })
1388
+ /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 opacity-70" })
1281
1389
  ]
1282
1390
  }
1283
1391
  ),
1284
- open && /* @__PURE__ */ jsx(
1285
- "div",
1286
- {
1287
- className: "absolute right-0 mt-1 min-w-[180px] rounded-md border shadow-md py-1 z-10",
1288
- style: { background: "hsl(var(--ra-surface))", borderColor: "hsl(var(--ra-border))" },
1289
- children: items.map((it) => /* @__PURE__ */ jsx(
1392
+ open && /* @__PURE__ */ jsx("div", { className: "absolute right-0 mt-1.5 ra-bulk-menu", role: "menu", children: items.map((it, i) => {
1393
+ const Icon = it.icon;
1394
+ return /* @__PURE__ */ jsxs("div", { children: [
1395
+ it.divider && i > 0 && /* @__PURE__ */ jsx("div", { className: "ra-bulk-divider" }),
1396
+ /* @__PURE__ */ jsxs(
1290
1397
  "button",
1291
1398
  {
1292
1399
  type: "button",
1400
+ role: "menuitem",
1401
+ "data-tone": it.tone,
1293
1402
  onClick: () => {
1294
1403
  setOpen(false);
1295
1404
  it.onClick();
1296
1405
  },
1297
- className: "w-full text-left px-3 py-1.5 text-xs hover:bg-[hsl(var(--ra-muted))]",
1298
- style: { color: "hsl(var(--ra-text))" },
1299
- children: it.label
1300
- },
1301
- it.label
1302
- ))
1303
- }
1304
- )
1406
+ className: "ra-bulk-item",
1407
+ children: [
1408
+ /* @__PURE__ */ jsx(Icon, { className: "w-3.5 h-3.5 opacity-80" }),
1409
+ it.label,
1410
+ it.tone === "danger" && /* @__PURE__ */ jsx(Trash2, { className: "w-3 h-3 ml-auto opacity-50" })
1411
+ ]
1412
+ }
1413
+ )
1414
+ ] }, it.key);
1415
+ }) })
1305
1416
  ] });
1306
1417
  };
1307
1418
  var DeleteButton = ({
@@ -1628,17 +1739,16 @@ var InlinePreview = ({ children, scopePicker, label = "Preview" }) => /* @__PURE
1628
1739
  ] }),
1629
1740
  children
1630
1741
  ] });
1631
- var SidePreview = ({ children, scopePicker, label = "Preview" }) => /* @__PURE__ */ jsxs(
1632
- "div",
1633
- {
1634
- className: "flex flex-col h-full border-l overflow-hidden",
1635
- style: { borderColor: "hsl(var(--ra-border))" },
1636
- children: [
1637
- /* @__PURE__ */ jsx(PreviewHeader, { label, scopePicker }),
1638
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto p-4", children })
1639
- ]
1640
- }
1641
- );
1742
+ var SidePreview = ({ children, scopePicker, label = "Preview" }) => /* @__PURE__ */ jsxs("div", { className: "ra-preview-rail", children: [
1743
+ /* @__PURE__ */ jsxs("header", { className: "ra-preview-rail-header", children: [
1744
+ /* @__PURE__ */ jsxs("div", { className: "ra-preview-rail-title", children: [
1745
+ /* @__PURE__ */ jsx(Eye, { className: "w-3 h-3" }),
1746
+ label
1747
+ ] }),
1748
+ scopePicker && /* @__PURE__ */ jsx("div", { className: "ml-auto", children: scopePicker })
1749
+ ] }),
1750
+ /* @__PURE__ */ jsx("div", { className: "ra-preview-rail-body", children })
1751
+ ] });
1642
1752
  var TabbedPreview = ({
1643
1753
  editor,
1644
1754
  preview,
@@ -1861,48 +1971,114 @@ var PreviewScopePicker = ({
1861
1971
  )
1862
1972
  ] });
1863
1973
  };
1864
- var IntroCard = ({ title, body, onDismiss }) => /* @__PURE__ */ jsxs(
1865
- "div",
1866
- {
1867
- className: "relative rounded-lg border p-4 mb-4",
1868
- style: {
1869
- borderColor: "hsl(var(--ra-accent) / 0.3)",
1870
- background: "hsl(var(--ra-accent) / 0.04)"
1871
- },
1872
- children: [
1873
- /* @__PURE__ */ jsx(
1974
+ var TONE_ICON = {
1975
+ info: Lightbulb,
1976
+ success: CheckCircle2,
1977
+ warning: AlertTriangle
1978
+ };
1979
+ var IntroCard = ({ title, body, onDismiss, tone = "info", action }) => {
1980
+ const Icon = TONE_ICON[tone] ?? Info;
1981
+ return /* @__PURE__ */ jsxs("div", { className: "ra-intro", "data-tone": tone, role: "note", children: [
1982
+ /* @__PURE__ */ jsx("div", { className: "ra-intro-icon", children: /* @__PURE__ */ jsx(Icon, { className: "w-4 h-4" }) }),
1983
+ /* @__PURE__ */ jsxs("div", { className: "ra-intro-body", children: [
1984
+ /* @__PURE__ */ jsx("h4", { className: "ra-intro-title", children: title }),
1985
+ /* @__PURE__ */ jsxs("div", { className: "ra-intro-text", children: [
1986
+ body,
1987
+ action && /* @__PURE__ */ jsx("span", { className: "ml-1.5", children: action })
1988
+ ] })
1989
+ ] }),
1990
+ /* @__PURE__ */ jsx(
1991
+ "button",
1992
+ {
1993
+ type: "button",
1994
+ onClick: onDismiss,
1995
+ "aria-label": "Dismiss",
1996
+ className: "ra-intro-dismiss",
1997
+ children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5" })
1998
+ }
1999
+ )
2000
+ ] });
2001
+ };
2002
+ var UtilityRow = ({ label, introHidden, onShowIntro }) => {
2003
+ if (!introHidden || !onShowIntro) return null;
2004
+ return /* @__PURE__ */ jsx(
2005
+ "div",
2006
+ {
2007
+ className: "flex items-center justify-end gap-2 text-xs",
2008
+ style: { color: "hsl(var(--ra-muted-text))" },
2009
+ children: /* @__PURE__ */ jsxs(
1874
2010
  "button",
1875
2011
  {
1876
2012
  type: "button",
1877
- onClick: onDismiss,
1878
- "aria-label": "Dismiss",
1879
- className: "absolute top-2 right-2 p-1 rounded hover:bg-black/5",
1880
- children: /* @__PURE__ */ jsx(X, { className: "w-3.5 h-3.5 opacity-60" })
2013
+ onClick: onShowIntro,
2014
+ className: "ra-btn",
2015
+ "data-variant": "ghost",
2016
+ style: { padding: "0.25rem 0.55rem", fontSize: "0.7rem" },
2017
+ children: [
2018
+ /* @__PURE__ */ jsx(HelpCircle, { className: "w-3 h-3" }),
2019
+ "How ",
2020
+ label.toLowerCase(),
2021
+ " works"
2022
+ ]
1881
2023
  }
1882
- ),
1883
- /* @__PURE__ */ jsx("div", { className: "text-sm font-medium mb-1.5", style: { color: "hsl(var(--ra-text))" }, children: title }),
1884
- /* @__PURE__ */ jsx("div", { className: "text-xs", style: { color: "hsl(var(--ra-muted-text))" }, children: body })
1885
- ]
2024
+ )
2025
+ }
2026
+ );
2027
+ };
2028
+ function ShellHeader({
2029
+ title,
2030
+ subtitle,
2031
+ headerIcon,
2032
+ headerActions,
2033
+ showStats = false,
2034
+ showHeaderIcon = true,
2035
+ recordType,
2036
+ icons,
2037
+ stats,
2038
+ statsItems
2039
+ }) {
2040
+ let iconNode = null;
2041
+ if (showHeaderIcon) {
2042
+ if (headerIcon) {
2043
+ iconNode = headerIcon;
2044
+ } else {
2045
+ const Icon = pickHeaderIcon(icons, recordType);
2046
+ iconNode = createElement(Icon, { className: "w-4 h-4", "aria-hidden": true });
2047
+ }
1886
2048
  }
1887
- );
1888
- var UtilityRow = ({ label, recordType, introHidden, onShowIntro }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 mb-3 text-xs", style: { color: "hsl(var(--ra-muted-text))" }, children: [
1889
- /* @__PURE__ */ jsx("span", { className: "font-mono opacity-70", children: recordType }),
1890
- introHidden && onShowIntro && /* @__PURE__ */ jsxs(
1891
- "button",
1892
- {
1893
- type: "button",
1894
- onClick: onShowIntro,
1895
- className: "flex items-center gap-1 px-2 py-1 rounded-full border hover:bg-[hsl(var(--ra-muted))]",
1896
- style: { borderColor: "hsl(var(--ra-border))" },
1897
- children: [
1898
- /* @__PURE__ */ jsx(HelpCircle, { className: "w-3 h-3" }),
1899
- "How ",
1900
- label.toLowerCase(),
1901
- " works"
1902
- ]
2049
+ const resolvedItems = (() => {
2050
+ if (!showStats) return [];
2051
+ if (statsItems && statsItems.length > 0) return statsItems;
2052
+ const items = [];
2053
+ if (typeof stats?.shared === "number" && stats.shared > 0) {
2054
+ items.push({ label: "Shared", value: stats.shared });
1903
2055
  }
1904
- )
1905
- ] });
2056
+ if (typeof stats?.products === "number" && stats.products > 0) {
2057
+ items.push({ label: "Products", value: stats.products });
2058
+ }
2059
+ return items;
2060
+ })();
2061
+ const hasStats = resolvedItems.length > 0;
2062
+ return /* @__PURE__ */ jsxs("header", { className: "ra-header", children: [
2063
+ /* @__PURE__ */ jsxs("div", { className: "ra-header__main", children: [
2064
+ iconNode ? /* @__PURE__ */ jsx("div", { className: "ra-header-icon", "aria-hidden": "true", children: iconNode }) : null,
2065
+ /* @__PURE__ */ jsxs("div", { className: "ra-header-text", children: [
2066
+ /* @__PURE__ */ jsx("h1", { className: "ra-header-title", children: title }),
2067
+ subtitle ? /* @__PURE__ */ jsx("p", { className: "ra-header-subtitle", children: subtitle }) : null
2068
+ ] })
2069
+ ] }),
2070
+ /* @__PURE__ */ jsxs("div", { className: "ra-header-aside", children: [
2071
+ hasStats ? /* @__PURE__ */ jsx("div", { className: "ra-header-stats", role: "group", "aria-label": "Record counts", children: resolvedItems.map((item, idx) => /* @__PURE__ */ jsxs("span", { style: { display: "contents" }, children: [
2072
+ idx > 0 && /* @__PURE__ */ jsx("span", { className: "ra-stat-divider", "aria-hidden": "true" }),
2073
+ /* @__PURE__ */ jsxs("span", { className: "ra-stat", children: [
2074
+ /* @__PURE__ */ jsx("span", { className: "ra-stat-value", children: item.value }),
2075
+ /* @__PURE__ */ jsx("span", { className: "ra-stat-label", children: item.label })
2076
+ ] })
2077
+ ] }, `${item.label}-${idx}`)) }) : null,
2078
+ headerActions ? /* @__PURE__ */ jsx("div", { className: "ra-header-actions", children: headerActions }) : null
2079
+ ] })
2080
+ ] });
2081
+ }
1906
2082
 
1907
2083
  // src/components/RecordsAdmin/data/csv.ts
1908
2084
  var escapeCell = (s) => {
@@ -2007,6 +2183,12 @@ var downloadBlob = (blob, filename) => {
2007
2183
  document.body.removeChild(a);
2008
2184
  URL.revokeObjectURL(url);
2009
2185
  };
2186
+
2187
+ // src/components/RecordsAdmin/shell/tokens.css
2188
+ styleInject(':root {\n --ra-status-own: var(--ra-emerald, 142 71% 45%);\n --ra-status-shared: var(--ra-amber, 38 92% 50%);\n --ra-status-missing: var(--muted-foreground, 220 9% 46%);\n --ra-accent: var(--primary, 222 47% 11%);\n --ra-surface: var(--card, 0 0% 100%);\n --ra-border: var(--border, 220 13% 91%);\n --ra-text: var(--foreground, 222 47% 11%);\n --ra-muted: var(--muted, 220 14% 96%);\n --ra-muted-text: var(--muted-foreground, 220 9% 46%);\n --ra-radius: var(--radius, 0.625rem);\n --ra-dot-size: 0.5rem;\n --ra-page-bg: var(--background, 220 14% 98%);\n --ra-card-shadow: 0 1px 2px hsl(var(--ra-accent) / 0.04), 0 4px 12px hsl(var(--ra-accent) / 0.05);\n --ra-card-shadow-hover: 0 2px 4px hsl(var(--ra-accent) / 0.06), 0 8px 24px hsl(var(--ra-accent) / 0.08);\n --ra-row-hover: hsl(var(--ra-accent) / 0.05);\n --ra-row-active-bg: hsl(var(--ra-accent) / 0.10);\n --ra-row-active-bd: hsl(var(--ra-accent) / 0.45);\n --ra-focus-ring: hsl(var(--ra-accent) / 0.35);\n --ra-font-display: var(--font-display, var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif));\n --ra-font-ui: var(--font-sans, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);\n --ra-title-weight: 600;\n --ra-display-weight: 700;\n --ra-info: var(--ra-blue, 214 95% 55%);\n --ra-success: var(--ra-emerald, 142 71% 45%);\n --ra-warning: var(--ra-amber, 38 92% 50%);\n --ra-danger: var(--destructive, 0 72% 51%);\n}\n.ra-status-dot {\n display: inline-block;\n width: var(--ra-dot-size);\n height: var(--ra-dot-size);\n border-radius: 9999px;\n flex-shrink: 0;\n}\n.ra-status-own {\n background: hsl(var(--ra-status-own));\n}\n.ra-status-shared {\n background: hsl(var(--ra-status-shared));\n}\n.ra-status-missing {\n background: hsl(var(--ra-status-missing) / 0.4);\n border: 1px solid hsl(var(--ra-status-missing) / 0.6);\n}\n.ra-row-active {\n background: var(--ra-row-active-bg);\n border-color: var(--ra-row-active-bd) !important;\n}\n');
2189
+
2190
+ // src/components/RecordsAdmin/shell/shell.css
2191
+ styleInject(".ra-shell {\n color: hsl(var(--ra-text));\n background: hsl(var(--ra-page-bg));\n font-family: var(--ra-font-ui);\n}\n.ra-shell *,\n.ra-shell *::before,\n.ra-shell *::after {\n box-sizing: border-box;\n}\n.ra-shell .ra-card {\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: var(--ra-radius);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-card-hover {\n transition:\n box-shadow .18s ease,\n transform .18s ease,\n border-color .18s ease;\n}\n.ra-shell .ra-card-hover:hover {\n box-shadow: var(--ra-card-shadow-hover);\n}\n.ra-shell .ra-display {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-title {\n font-weight: var(--ra-title-weight);\n}\n.ra-shell :where(button, [role=button], input, select, textarea, a):focus-visible {\n outline: none;\n box-shadow: 0 0 0 3px var(--ra-focus-ring);\n border-radius: calc(var(--ra-radius) * 0.6);\n}\n.ra-shell .ra-header {\n position: relative;\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.9rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-accent) / 0.12);\n background:\n linear-gradient(\n 135deg,\n hsl(var(--ra-accent) / 0.08),\n hsl(var(--ra-accent) / 0.02) 60%,\n hsl(var(--ra-surface)) 100%);\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-header__main {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: 0.625rem;\n}\n.ra-shell .ra-header-aside {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-shrink: 0;\n}\n.ra-shell .ra-header-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: calc(var(--ra-radius) * 0.9);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n border: 1px solid hsl(var(--ra-accent) / 0.18);\n}\n.ra-shell .ra-header-text {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-header-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n line-height: 1.2;\n color: hsl(var(--ra-text));\n letter-spacing: -0.01em;\n margin: 0;\n}\n.ra-shell .ra-header-subtitle {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.125rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-header-stats {\n display: flex;\n align-items: stretch;\n gap: 0.15rem;\n padding: 0.15rem 0.4rem;\n border-radius: calc(var(--ra-radius) * 0.75);\n background: hsl(var(--ra-surface) / 0.7);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-stat {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0.15rem 0.45rem;\n min-width: 2.5rem;\n}\n.ra-shell .ra-stat-value {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 0.85rem;\n color: hsl(var(--ra-text));\n line-height: 1;\n}\n.ra-shell .ra-stat-label {\n font-size: 0.6rem;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n}\n.ra-shell .ra-stat-divider {\n width: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-header-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n.ra-shell .ra-tabs {\n display: flex;\n gap: 0.25rem;\n padding: 0.25rem;\n background: hsl(var(--ra-muted));\n border-radius: calc(var(--ra-radius) * 0.85);\n border: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-tab {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.4rem 0.7rem;\n border-radius: calc(var(--ra-radius) * 0.65);\n font-size: 0.78rem;\n font-weight: 500;\n color: hsl(var(--ra-muted-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n transition:\n background .15s ease,\n color .15s ease,\n transform .15s ease;\n white-space: nowrap;\n}\n.ra-shell .ra-tab:hover {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-tab[aria-selected=true] {\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n box-shadow: var(--ra-card-shadow);\n font-weight: var(--ra-title-weight);\n}\n.ra-shell .ra-tab[aria-selected=true] .ra-tab-icon {\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-tab[disabled] {\n opacity: .5;\n cursor: not-allowed;\n}\n.ra-shell .ra-tab-count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 0.35rem;\n height: 1.1rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.12);\n color: hsl(var(--ra-accent));\n font-size: 0.625rem;\n font-weight: 600;\n line-height: 1;\n}\n.ra-shell .ra-tab[aria-selected=false] .ra-tab-count {\n background: hsl(var(--ra-muted-text) / 0.15);\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell[data-density=compact] .ra-row {\n padding-block: 0.4rem;\n}\n.ra-shell[data-density=compact] .ra-header {\n padding: 0.75rem 1rem;\n}\n.ra-shell[data-density=compact] .ra-header-icon {\n width: 2.25rem;\n height: 2.25rem;\n}\n.ra-shell .ra-row {\n display: flex;\n align-items: center;\n gap: 0.65rem;\n width: 100%;\n text-align: left;\n padding: 0.65rem 0.85rem;\n border-left: 3px solid transparent;\n background: transparent;\n border-bottom: 1px solid transparent;\n transition: background .12s ease, border-color .12s ease;\n cursor: pointer;\n color: hsl(var(--ra-text));\n font-family: inherit;\n}\n.ra-shell .ra-row + .ra-row {\n border-top: 1px solid hsl(var(--ra-border) / 0.6);\n}\n.ra-shell .ra-row:hover {\n background: var(--ra-row-hover);\n}\n.ra-shell .ra-row[data-selected=true] {\n background: var(--ra-row-active-bg);\n border-left-color: var(--ra-row-active-bd);\n}\n.ra-shell .ra-row-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n flex-shrink: 0;\n}\n.ra-shell .ra-row[data-selected=true] .ra-row-icon {\n background: hsl(var(--ra-accent) / 0.15);\n color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-row-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-row-title {\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n line-height: 1.25;\n color: hsl(var(--ra-text));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-sub {\n font-size: 0.75rem;\n color: hsl(var(--ra-muted-text));\n margin-top: 0.15rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-row-actions {\n display: inline-flex;\n align-items: center;\n gap: 0.15rem;\n margin-left: auto;\n opacity: 0;\n transition: opacity .15s ease;\n}\n.ra-shell .ra-row:hover .ra-row-actions,\n.ra-shell .ra-row:focus-within .ra-row-actions {\n opacity: 1;\n}\n.ra-shell .ra-row-action {\n width: 1.6rem;\n height: 1.6rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 999px;\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .15s ease, color .15s ease;\n}\n.ra-shell .ra-row-action:hover {\n background: hsl(var(--ra-accent) / 0.10);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-row-action[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.12);\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-chip {\n display: inline-flex;\n align-items: center;\n gap: 0.3rem;\n padding: 0.15rem 0.5rem;\n border-radius: 999px;\n font-size: 0.6875rem;\n font-weight: 500;\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-muted-text));\n border: 1px solid hsl(var(--ra-border));\n white-space: nowrap;\n max-width: 14rem;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.ra-shell .ra-chip[data-tone=success] {\n background: hsl(var(--ra-success) / 0.12);\n color: hsl(var(--ra-success));\n border-color: hsl(var(--ra-success) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=warning] {\n background: hsl(var(--ra-warning) / 0.14);\n color: hsl(var(--ra-warning));\n border-color: hsl(var(--ra-warning) / 0.35);\n}\n.ra-shell .ra-chip[data-tone=info] {\n background: hsl(var(--ra-info) / 0.10);\n color: hsl(var(--ra-info));\n border-color: hsl(var(--ra-info) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=danger] {\n background: hsl(var(--ra-danger) / 0.10);\n color: hsl(var(--ra-danger));\n border-color: hsl(var(--ra-danger) / 0.30);\n}\n.ra-shell .ra-chip[data-tone=muted] {\n background: transparent;\n color: hsl(var(--ra-muted-text));\n border-style: dashed;\n}\n.ra-shell .ra-group {\n border-bottom: 1px solid hsl(var(--ra-border));\n}\n.ra-shell .ra-group:last-child {\n border-bottom: 0;\n}\n.ra-shell .ra-group-summary {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 0.85rem;\n background: hsl(var(--ra-muted) / 0.6);\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: hsl(var(--ra-muted-text));\n border: 0;\n cursor: pointer;\n transition: background .12s ease;\n}\n.ra-shell .ra-group-summary:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-group-summary .ra-group-chevron {\n transition: transform .15s ease;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-chevron {\n transform: rotate(-90deg);\n}\n.ra-shell .ra-group-name {\n flex: 1;\n text-align: left;\n}\n.ra-shell .ra-group-count {\n font-size: 0.65rem;\n font-weight: 600;\n color: hsl(var(--ra-muted-text));\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: 999px;\n padding: 0.05rem 0.4rem;\n}\n.ra-shell .ra-group[data-open=false] .ra-group-body {\n display: none;\n}\n.ra-shell .ra-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n text-align: center;\n padding: 2.5rem 1.5rem;\n gap: 0.75rem;\n}\n.ra-shell .ra-empty-icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 3.25rem;\n height: 3.25rem;\n border-radius: 999px;\n background: hsl(var(--ra-accent) / 0.08);\n color: hsl(var(--ra-accent));\n margin-bottom: 0.25rem;\n}\n.ra-shell .ra-empty-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-display-weight);\n font-size: 1rem;\n color: hsl(var(--ra-text));\n margin: 0;\n letter-spacing: -0.01em;\n}\n.ra-shell .ra-empty-body {\n font-size: 0.8125rem;\n color: hsl(var(--ra-muted-text));\n max-width: 22rem;\n line-height: 1.45;\n}\n.ra-shell .ra-empty-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n margin-top: 0.25rem;\n flex-wrap: wrap;\n justify-content: center;\n}\n.ra-shell .ra-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n padding: 0.45rem 0.85rem;\n border-radius: calc(var(--ra-radius) * 0.7);\n font-size: 0.8125rem;\n font-weight: 500;\n border: 1px solid hsl(var(--ra-border));\n background: hsl(var(--ra-surface));\n color: hsl(var(--ra-text));\n cursor: pointer;\n transition:\n background .15s ease,\n border-color .15s ease,\n box-shadow .15s ease,\n transform .1s ease;\n}\n.ra-shell .ra-btn:hover {\n background: hsl(var(--ra-muted));\n box-shadow: var(--ra-card-shadow);\n}\n.ra-shell .ra-btn:active {\n transform: translateY(1px);\n}\n.ra-shell .ra-btn[data-variant=primary] {\n background: hsl(var(--ra-accent));\n color: hsl(var(--ra-surface));\n border-color: hsl(var(--ra-accent));\n}\n.ra-shell .ra-btn[data-variant=primary]:hover {\n background: hsl(var(--ra-accent) / 0.92);\n}\n.ra-shell .ra-btn[data-variant=ghost] {\n background: transparent;\n border-color: transparent;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-btn[data-variant=ghost]:hover {\n background: hsl(var(--ra-muted));\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-btn[data-variant=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-btn[data-variant=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n border-color: hsl(var(--ra-danger) / 0.40);\n}\n.ra-shell .ra-intro {\n position: relative;\n display: flex;\n gap: 0.85rem;\n padding: 0.9rem 1rem;\n border-radius: var(--ra-radius);\n border: 1px solid hsl(var(--ra-info) / 0.30);\n background: hsl(var(--ra-info) / 0.08);\n margin-bottom: 1rem;\n}\n.ra-shell .ra-intro[data-tone=success] {\n border-color: hsl(var(--ra-success) / 0.30);\n background: hsl(var(--ra-success) / 0.08);\n}\n.ra-shell .ra-intro[data-tone=warning] {\n border-color: hsl(var(--ra-warning) / 0.35);\n background: hsl(var(--ra-warning) / 0.10);\n}\n.ra-shell .ra-intro-icon {\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: hsl(var(--ra-info) / 0.18);\n color: hsl(var(--ra-info));\n}\n.ra-shell .ra-intro[data-tone=success] .ra-intro-icon {\n background: hsl(var(--ra-success) / 0.18);\n color: hsl(var(--ra-success));\n}\n.ra-shell .ra-intro[data-tone=warning] .ra-intro-icon {\n background: hsl(var(--ra-warning) / 0.20);\n color: hsl(var(--ra-warning));\n}\n.ra-shell .ra-intro-body {\n flex: 1;\n min-width: 0;\n}\n.ra-shell .ra-intro-title {\n font-family: var(--ra-font-display);\n font-weight: var(--ra-title-weight);\n font-size: 0.875rem;\n color: hsl(var(--ra-text));\n margin: 0 0 0.2rem 0;\n}\n.ra-shell .ra-intro-text {\n font-size: 0.8125rem;\n color: hsl(var(--ra-text) / 0.85);\n line-height: 1.45;\n}\n.ra-shell .ra-intro-dismiss {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n width: 1.6rem;\n height: 1.6rem;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: transparent;\n border: 0;\n color: hsl(var(--ra-muted-text));\n cursor: pointer;\n}\n.ra-shell .ra-intro-dismiss:hover {\n background: hsl(var(--ra-text) / 0.06);\n color: hsl(var(--ra-text));\n}\n.ra-shell .ra-bulk-menu {\n min-width: 12rem;\n background: hsl(var(--ra-surface));\n border: 1px solid hsl(var(--ra-border));\n border-radius: calc(var(--ra-radius) * 0.85);\n box-shadow: var(--ra-card-shadow-hover);\n padding: 0.3rem;\n z-index: 30;\n}\n.ra-shell .ra-bulk-item {\n display: flex;\n align-items: center;\n gap: 0.55rem;\n width: 100%;\n padding: 0.45rem 0.6rem;\n border-radius: calc(var(--ra-radius) * 0.6);\n font-size: 0.8125rem;\n color: hsl(var(--ra-text));\n background: transparent;\n border: 0;\n cursor: pointer;\n text-align: left;\n transition: background .12s ease, color .12s ease;\n}\n.ra-shell .ra-bulk-item:hover {\n background: hsl(var(--ra-muted));\n}\n.ra-shell .ra-bulk-item[data-tone=danger] {\n color: hsl(var(--ra-danger));\n}\n.ra-shell .ra-bulk-item[data-tone=danger]:hover {\n background: hsl(var(--ra-danger) / 0.10);\n}\n.ra-shell .ra-bulk-divider {\n height: 1px;\n background: hsl(var(--ra-border));\n margin: 0.25rem 0;\n}\n.ra-shell .ra-preview-rail {\n background: hsl(var(--ra-surface));\n border-left: 1px solid hsl(var(--ra-border));\n box-shadow: -4px 0 16px hsl(var(--ra-accent) / 0.04);\n display: flex;\n flex-direction: column;\n height: 100%;\n overflow: hidden;\n}\n.ra-shell .ra-preview-rail-header {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n background:\n linear-gradient(\n 180deg,\n hsl(var(--ra-surface)) 0%,\n hsl(var(--ra-surface) / 0.92) 100%);\n border-bottom: 1px solid hsl(var(--ra-border));\n backdrop-filter: blur(6px);\n}\n.ra-shell .ra-preview-rail-title {\n display: inline-flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.7rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n color: hsl(var(--ra-muted-text));\n}\n.ra-shell .ra-preview-rail-body {\n flex: 1;\n overflow-y: auto;\n padding: 1rem;\n}\n");
2010
2192
  var TOP_LEVEL_SCOPES = ["product", "facet"];
2011
2193
  var defaultItemId = () => {
2012
2194
  const time = Date.now().toString(36);
@@ -2056,9 +2238,21 @@ function RecordsAdminShell(props) {
2056
2238
  renderEmpty,
2057
2239
  cardinality = "singleton",
2058
2240
  itemNoun = "item",
2059
- generateItemId
2241
+ generateItemId,
2242
+ title,
2243
+ subtitle,
2244
+ headerIcon,
2245
+ headerActions,
2246
+ showStats = false,
2247
+ showHeaderIcon = true,
2248
+ statsItems,
2249
+ icons: iconsOverride,
2250
+ groupBy,
2251
+ renderEmptyState,
2252
+ density = "comfortable"
2060
2253
  } = props;
2061
2254
  const i18n = { ...DEFAULT_I18N, ...i18nOverride ?? {} };
2255
+ const icons = useMemo(() => mergeIcons(iconsOverride), [iconsOverride]);
2062
2256
  const [presentation, setPresentation] = usePresentationPref({
2063
2257
  appId,
2064
2258
  recordType,
@@ -2246,8 +2440,9 @@ function RecordsAdminShell(props) {
2246
2440
  });
2247
2441
  const handleExport = () => {
2248
2442
  if (!csvSchema) return;
2443
+ const fileBase = recordType ?? (label.toLowerCase().replace(/\s+/g, "-") || "records");
2249
2444
  const blob = exportCsv(recordList.items, csvSchema);
2250
- downloadBlob(blob, `${recordType}.csv`);
2445
+ downloadBlob(blob, `${fileBase}.csv`);
2251
2446
  onTelemetry?.({ type: "csv.export", recordType, rows: recordList.items.length });
2252
2447
  };
2253
2448
  const handleImport = () => {
@@ -2261,7 +2456,8 @@ function RecordsAdminShell(props) {
2261
2456
  const report = await importCsv(file, csvSchema, ctx);
2262
2457
  onTelemetry?.({ type: "csv.import", recordType, rows: report.total, errors: report.failed });
2263
2458
  if (report.failed > 0) {
2264
- downloadBlob(new Blob([report.annotatedCsv], { type: "text/csv" }), `${recordType}-errors.csv`);
2459
+ const fileBase = recordType ?? (label.toLowerCase().replace(/\s+/g, "-") || "records");
2460
+ downloadBlob(new Blob([report.annotatedCsv], { type: "text/csv" }), `${fileBase}-errors.csv`);
2265
2461
  }
2266
2462
  refetchAll();
2267
2463
  };
@@ -2375,177 +2571,214 @@ function RecordsAdminShell(props) {
2375
2571
  }
2376
2572
  });
2377
2573
  };
2378
- return /* @__PURE__ */ jsxs("div", { className: `ra-shell flex flex-col h-full ${className ?? ""}`, children: [
2379
- /* @__PURE__ */ jsxs("div", { className: "px-4 pt-4", children: [
2380
- intro && !dismissed && /* @__PURE__ */ jsx(
2381
- IntroCard,
2382
- {
2383
- title: intro.title,
2384
- body: intro.body,
2385
- onDismiss: () => {
2386
- dismiss();
2387
- onTelemetry?.({ type: "intro.dismiss", recordType });
2388
- }
2389
- }
2390
- ),
2391
- /* @__PURE__ */ jsx(
2392
- UtilityRow,
2393
- {
2394
- label,
2395
- recordType,
2396
- introHidden: dismissed && !!intro,
2397
- onShowIntro: undismiss
2398
- }
2399
- )
2400
- ] }),
2401
- /* @__PURE__ */ jsxs(
2402
- "div",
2403
- {
2404
- className: "flex-1 grid border-t overflow-hidden",
2405
- style: { gridTemplateColumns: "minmax(260px, 320px) 1fr", borderColor: "hsl(var(--ra-border))" },
2406
- children: [
2407
- /* @__PURE__ */ jsxs("aside", { className: "border-r overflow-hidden flex flex-col", style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" }, children: [
2408
- /* @__PURE__ */ jsx(
2409
- ScopeTabs,
2410
- {
2411
- scopes: topLevelScopes,
2412
- active: activeScope,
2413
- onChange: (s) => {
2414
- void runWithGuard(() => {
2415
- onTelemetry?.({ type: "scope.change", recordType, from: activeScope, to: s });
2416
- setActiveScope(s);
2417
- });
2418
- },
2419
- loading: probe.isLoading
2574
+ return /* @__PURE__ */ jsxs(
2575
+ "div",
2576
+ {
2577
+ className: `ra-shell flex flex-col h-full ${className ?? ""}`,
2578
+ "data-density": density,
2579
+ children: [
2580
+ /* @__PURE__ */ jsxs("div", { className: "px-4 pt-4 space-y-3", children: [
2581
+ intro && !dismissed && /* @__PURE__ */ jsx(
2582
+ IntroCard,
2583
+ {
2584
+ title: intro.title,
2585
+ body: intro.body,
2586
+ onDismiss: () => {
2587
+ dismiss();
2588
+ onTelemetry?.({ type: "intro.dismiss", recordType });
2420
2589
  }
2421
- ),
2422
- /* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2.5 border-b", style: { borderColor: "hsl(var(--ra-border))" }, children: [
2423
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2424
- /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", children: [
2425
- /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 opacity-50" }),
2426
- /* @__PURE__ */ jsx(
2427
- "input",
2590
+ }
2591
+ ),
2592
+ /* @__PURE__ */ jsx(
2593
+ ShellHeader,
2594
+ {
2595
+ title: title ?? label ?? recordType,
2596
+ subtitle,
2597
+ headerIcon,
2598
+ headerActions,
2599
+ showStats,
2600
+ showHeaderIcon,
2601
+ recordType,
2602
+ icons,
2603
+ stats: {
2604
+ products: productBrowse.items.length,
2605
+ shared: recordList.items.length
2606
+ },
2607
+ statsItems
2608
+ }
2609
+ ),
2610
+ /* @__PURE__ */ jsx(
2611
+ UtilityRow,
2612
+ {
2613
+ label,
2614
+ introHidden: dismissed && !!intro,
2615
+ onShowIntro: undismiss
2616
+ }
2617
+ )
2618
+ ] }),
2619
+ /* @__PURE__ */ jsxs(
2620
+ "div",
2621
+ {
2622
+ className: "flex-1 grid border-t overflow-hidden",
2623
+ style: { gridTemplateColumns: "minmax(260px, 320px) 1fr", borderColor: "hsl(var(--ra-border))", marginTop: "0.75rem" },
2624
+ children: [
2625
+ /* @__PURE__ */ jsxs("aside", { className: "border-r overflow-hidden flex flex-col", style: { borderColor: "hsl(var(--ra-border))", background: "hsl(var(--ra-surface))" }, children: [
2626
+ /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
2627
+ ScopeTabs,
2628
+ {
2629
+ scopes: topLevelScopes,
2630
+ active: activeScope,
2631
+ onChange: (s) => {
2632
+ void runWithGuard(() => {
2633
+ onTelemetry?.({ type: "scope.change", recordType, from: activeScope, to: s });
2634
+ setActiveScope(s);
2635
+ });
2636
+ },
2637
+ loading: probe.isLoading,
2638
+ counts: {
2639
+ product: productBrowse.items.length,
2640
+ facet: recordList.items.length
2641
+ },
2642
+ icons: icons.scope
2643
+ }
2644
+ ) }),
2645
+ /* @__PURE__ */ jsxs("div", { className: "p-3 space-y-2.5 border-b", style: { borderColor: "hsl(var(--ra-border))" }, children: [
2646
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2647
+ /* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", children: [
2648
+ /* @__PURE__ */ jsx(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 opacity-50" }),
2649
+ /* @__PURE__ */ jsx(
2650
+ "input",
2651
+ {
2652
+ type: "text",
2653
+ value: search,
2654
+ onChange: (e) => setSearch(e.target.value),
2655
+ placeholder: i18n.searchPlaceholder,
2656
+ className: "w-full pl-8 pr-3 py-1.5 text-xs rounded-md border bg-transparent focus:outline-none focus:ring-1",
2657
+ style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" }
2658
+ }
2659
+ )
2660
+ ] }),
2661
+ /* @__PURE__ */ jsx(
2662
+ PresentationSwitcher,
2663
+ {
2664
+ options: presentations,
2665
+ value: presentation,
2666
+ onChange: onPresentationChange,
2667
+ i18n
2668
+ }
2669
+ )
2670
+ ] }),
2671
+ !isProductTab && /* @__PURE__ */ jsx(StatusFilterPills, { value: filter, onChange: setFilter, counts: recordList.counts, i18n }),
2672
+ cardinality === "collection" && !isProductTab && editingScope && /* @__PURE__ */ jsxs(
2673
+ "button",
2428
2674
  {
2429
- type: "text",
2430
- value: search,
2431
- onChange: (e) => setSearch(e.target.value),
2432
- placeholder: i18n.searchPlaceholder,
2433
- className: "w-full pl-8 pr-3 py-1.5 text-xs rounded-md border bg-transparent focus:outline-none focus:ring-1",
2434
- style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" }
2675
+ type: "button",
2676
+ onClick: () => {
2677
+ void runWithGuard(() => {
2678
+ const id = generateItemId ? generateItemId() : defaultItemId();
2679
+ const baseRef = editingScope.raw;
2680
+ const itemRef = baseRef ? `${baseRef}/item:${id}` : `item:${id}`;
2681
+ setSelectedFacetRef(itemRef);
2682
+ onTelemetry?.({ type: "item.create", recordType, scopeRef: baseRef });
2683
+ });
2684
+ },
2685
+ className: "w-full inline-flex items-center justify-center gap-1.5 text-xs py-1.5 rounded-md border transition-colors hover:bg-[hsl(var(--ra-muted))]",
2686
+ style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
2687
+ children: [
2688
+ /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5" }),
2689
+ i18n.newItem || `New ${itemNoun}`
2690
+ ]
2435
2691
  }
2436
2692
  )
2437
2693
  ] }),
2438
- /* @__PURE__ */ jsx(
2439
- PresentationSwitcher,
2440
- {
2441
- options: presentations,
2442
- value: presentation,
2443
- onChange: onPresentationChange,
2444
- i18n
2445
- }
2446
- )
2694
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
2695
+ leftLoading && /* @__PURE__ */ jsx(LoadingState, {}),
2696
+ !leftLoading && leftError && /* @__PURE__ */ jsx(ErrorState, { error: leftError }),
2697
+ !leftLoading && !leftError && leftItems.length === 0 && (renderEmpty ? renderEmpty({ scope: editingScope }) : renderEmptyState ? renderEmptyState({ scope: activeScope }) : /* @__PURE__ */ jsx(
2698
+ EmptyState,
2699
+ {
2700
+ icon: search ? icons.empty.search : icons.empty.default,
2701
+ title: search ? i18n.noResults : i18n.emptyTitle,
2702
+ body: search ? void 0 : i18n.emptyBody
2703
+ }
2704
+ )),
2705
+ !leftLoading && !leftError && leftItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2706
+ /* @__PURE__ */ jsx(
2707
+ RecordList,
2708
+ {
2709
+ items: leftItems,
2710
+ selectedRef: leftSelectedRef,
2711
+ onSelect: onLeftSelect,
2712
+ dirtyRef: editorCtx.isDirty ? editingScope?.raw : void 0,
2713
+ presentation,
2714
+ renderListRow,
2715
+ renderCard,
2716
+ groupBy
2717
+ }
2718
+ ),
2719
+ isProductTab && !productPinned && productBrowse.hasNextPage && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
2720
+ "button",
2721
+ {
2722
+ type: "button",
2723
+ onClick: () => {
2724
+ void productBrowse.fetchNextPage();
2725
+ },
2726
+ disabled: productBrowse.isFetchingNextPage,
2727
+ className: "w-full text-xs py-2 rounded-md border transition-opacity disabled:opacity-50 hover:bg-[hsl(var(--ra-muted))]",
2728
+ style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
2729
+ children: productBrowse.isFetchingNextPage ? "Loading\u2026" : `Load more (${leftItems.length} shown)`
2730
+ }
2731
+ ) })
2732
+ ] })
2733
+ ] })
2447
2734
  ] }),
2448
- !isProductTab && /* @__PURE__ */ jsx(StatusFilterPills, { value: filter, onChange: setFilter, counts: recordList.counts, i18n }),
2449
- cardinality === "collection" && !isProductTab && editingScope && /* @__PURE__ */ jsxs(
2450
- "button",
2451
- {
2452
- type: "button",
2453
- onClick: () => {
2454
- void runWithGuard(() => {
2455
- const id = generateItemId ? generateItemId() : defaultItemId();
2456
- const baseRef = editingScope.raw;
2457
- const itemRef = baseRef ? `${baseRef}/item:${id}` : `item:${id}`;
2458
- setSelectedFacetRef(itemRef);
2459
- onTelemetry?.({ type: "item.create", recordType, scopeRef: baseRef });
2460
- });
2461
- },
2462
- className: "w-full inline-flex items-center justify-center gap-1.5 text-xs py-1.5 rounded-md border transition-colors hover:bg-[hsl(var(--ra-muted))]",
2463
- style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
2464
- children: [
2465
- /* @__PURE__ */ jsx(Plus, { className: "w-3.5 h-3.5" }),
2466
- i18n.newItem || `New ${itemNoun}`
2467
- ]
2468
- }
2469
- )
2470
- ] }),
2471
- /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto", children: [
2472
- leftLoading && /* @__PURE__ */ jsx(LoadingState, {}),
2473
- !leftLoading && leftError && /* @__PURE__ */ jsx(ErrorState, { error: leftError }),
2474
- !leftLoading && !leftError && leftItems.length === 0 && (renderEmpty ? renderEmpty({ scope: editingScope }) : /* @__PURE__ */ jsx(EmptyState, { title: i18n.noResults, body: search ? void 0 : i18n.emptyBody })),
2475
- !leftLoading && !leftError && leftItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
2476
- /* @__PURE__ */ jsx(
2477
- RecordList,
2478
- {
2479
- items: leftItems,
2480
- selectedRef: leftSelectedRef,
2481
- onSelect: onLeftSelect,
2482
- dirtyRef: editorCtx.isDirty ? editingScope?.raw : void 0,
2483
- presentation,
2484
- renderListRow,
2485
- renderCard
2486
- }
2487
- ),
2488
- isProductTab && !productPinned && productBrowse.hasNextPage && /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
2489
- "button",
2735
+ /* @__PURE__ */ jsxs("main", { className: "overflow-hidden", children: [
2736
+ !editingScope && activeScope === "product" && !selectedProductId && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
2737
+ !editingScope && activeScope === "facet" && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
2738
+ isProductTab && selectedProductId && /* @__PURE__ */ jsx(
2739
+ ProductDrillDown,
2490
2740
  {
2491
- type: "button",
2492
- onClick: () => {
2493
- void productBrowse.fetchNextPage();
2741
+ productLabel: productBrowse.items.find((p) => p.id === selectedProductId)?.name ?? selectedProductId,
2742
+ showVariants: drillVariantsAllowed,
2743
+ showBatches: drillBatchesAllowed,
2744
+ active: drillTab,
2745
+ onChange: (t) => {
2746
+ void runWithGuard(() => {
2747
+ setDrillTab(t);
2748
+ if (t === "product") {
2749
+ setSelectedVariantId(void 0);
2750
+ setSelectedBatchId(void 0);
2751
+ }
2752
+ });
2494
2753
  },
2495
- disabled: productBrowse.isFetchingNextPage,
2496
- className: "w-full text-xs py-2 rounded-md border transition-opacity disabled:opacity-50 hover:bg-[hsl(var(--ra-muted))]",
2497
- style: { borderColor: "hsl(var(--ra-border))", color: "hsl(var(--ra-text))" },
2498
- children: productBrowse.isFetchingNextPage ? "Loading\u2026" : `Load more (${leftItems.length} shown)`
2754
+ selectedChildId: drillTab === "variant" ? selectedVariantId : drillTab === "batch" ? selectedBatchId : void 0,
2755
+ onSelectChild: (id) => {
2756
+ void runWithGuard(() => {
2757
+ if (drillTab === "variant") setSelectedVariantId(id);
2758
+ else if (drillTab === "batch") setSelectedBatchId(id);
2759
+ });
2760
+ },
2761
+ variants: variantChildren.items,
2762
+ batches: batchChildren.items,
2763
+ variantsLoading: variantChildren.isLoading,
2764
+ batchesLoading: batchChildren.isLoading,
2765
+ children: editingScope ? renderEditorWithPreview() : /* @__PURE__ */ jsx(
2766
+ EmptyState,
2767
+ {
2768
+ title: drillTab === "variant" ? "Pick a variant" : "Pick a batch",
2769
+ body: `Select a ${drillTab} on the left to edit its ${recordType ?? label.toLowerCase()}.`
2770
+ }
2771
+ )
2499
2772
  }
2500
- ) })
2773
+ ),
2774
+ !isProductTab && editingScope && renderEditorWithPreview()
2501
2775
  ] })
2502
- ] })
2503
- ] }),
2504
- /* @__PURE__ */ jsxs("main", { className: "overflow-hidden", children: [
2505
- !editingScope && activeScope === "product" && !selectedProductId && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
2506
- !editingScope && activeScope === "facet" && /* @__PURE__ */ jsx(EmptyState, { title: i18n.emptyTitle, body: i18n.emptyBody }),
2507
- isProductTab && selectedProductId && /* @__PURE__ */ jsx(
2508
- ProductDrillDown,
2509
- {
2510
- productLabel: productBrowse.items.find((p) => p.id === selectedProductId)?.name ?? selectedProductId,
2511
- showVariants: drillVariantsAllowed,
2512
- showBatches: drillBatchesAllowed,
2513
- active: drillTab,
2514
- onChange: (t) => {
2515
- void runWithGuard(() => {
2516
- setDrillTab(t);
2517
- if (t === "product") {
2518
- setSelectedVariantId(void 0);
2519
- setSelectedBatchId(void 0);
2520
- }
2521
- });
2522
- },
2523
- selectedChildId: drillTab === "variant" ? selectedVariantId : drillTab === "batch" ? selectedBatchId : void 0,
2524
- onSelectChild: (id) => {
2525
- void runWithGuard(() => {
2526
- if (drillTab === "variant") setSelectedVariantId(id);
2527
- else if (drillTab === "batch") setSelectedBatchId(id);
2528
- });
2529
- },
2530
- variants: variantChildren.items,
2531
- batches: batchChildren.items,
2532
- variantsLoading: variantChildren.isLoading,
2533
- batchesLoading: batchChildren.isLoading,
2534
- children: editingScope ? renderEditorWithPreview() : /* @__PURE__ */ jsx(
2535
- EmptyState,
2536
- {
2537
- title: drillTab === "variant" ? "Pick a variant" : "Pick a batch",
2538
- body: `Select a ${drillTab} on the left to edit its ${recordType}.`
2539
- }
2540
- )
2541
- }
2542
- ),
2543
- !isProductTab && editingScope && renderEditorWithPreview()
2544
- ] })
2545
- ]
2546
- }
2547
- )
2548
- ] });
2776
+ ]
2777
+ }
2778
+ )
2779
+ ]
2780
+ }
2781
+ );
2549
2782
  }
2550
2783
  var RecordBrowser = ({
2551
2784
  scopes,
@@ -2654,6 +2887,112 @@ var ResolvedPreview = ({ children }) => /* @__PURE__ */ jsxs("div", { className:
2654
2887
  /* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wide mb-2", style: { color: "hsl(var(--ra-muted-text))" }, children: "Public preview" }),
2655
2888
  children
2656
2889
  ] });
2890
+ var resolveAllQueryKey = (args) => [
2891
+ "records-admin",
2892
+ "resolve-all",
2893
+ args.collectionId,
2894
+ args.appId,
2895
+ args.recordType ?? null,
2896
+ args.context.productId ?? null,
2897
+ args.context.variantId ?? null,
2898
+ args.context.batchId ?? null,
2899
+ args.context.proofId ?? null,
2900
+ args.context.facets ?? null,
2901
+ args.tiers ?? null,
2902
+ args.limit ?? null,
2903
+ args.at ?? null,
2904
+ args.includeScheduled ?? false,
2905
+ args.includeExpired ?? false,
2906
+ args.admin ?? false
2907
+ ];
2908
+ function useResolveAllRecords(args) {
2909
+ const {
2910
+ SL,
2911
+ collectionId,
2912
+ appId,
2913
+ recordType,
2914
+ context,
2915
+ tiers,
2916
+ limit,
2917
+ at,
2918
+ includeScheduled,
2919
+ includeExpired,
2920
+ admin = false,
2921
+ enabled = true,
2922
+ staleTime = 15e3
2923
+ } = args;
2924
+ const query = useQuery({
2925
+ queryKey: resolveAllQueryKey(args),
2926
+ enabled: enabled && !!collectionId && !!appId,
2927
+ staleTime,
2928
+ queryFn: () => SL.app.records.resolveAll(
2929
+ collectionId,
2930
+ appId,
2931
+ {
2932
+ context,
2933
+ ...recordType ? { recordType } : {},
2934
+ ...tiers ? { tiers } : {},
2935
+ ...limit !== void 0 ? { limit } : {},
2936
+ ...at ? { at } : {},
2937
+ ...includeScheduled !== void 0 ? { includeScheduled } : {},
2938
+ ...includeExpired !== void 0 ? { includeExpired } : {}
2939
+ },
2940
+ admin
2941
+ )
2942
+ });
2943
+ return {
2944
+ records: query.data?.records ?? [],
2945
+ truncated: query.data?.truncated ?? false,
2946
+ isLoading: query.isLoading,
2947
+ error: query.error ?? null,
2948
+ refetch: () => {
2949
+ void query.refetch();
2950
+ }
2951
+ };
2952
+ }
2953
+ var isRuleValid = (rule) => {
2954
+ if (!rule || !Array.isArray(rule.all) || rule.all.length === 0) return false;
2955
+ return rule.all.every(
2956
+ (c) => !!c.facetKey && Array.isArray(c.anyOf) && c.anyOf.length > 0
2957
+ );
2958
+ };
2959
+ function useRulePreview(args) {
2960
+ const {
2961
+ SL,
2962
+ collectionId,
2963
+ appId,
2964
+ rule,
2965
+ limit = 20,
2966
+ debounceMs = 350,
2967
+ enabled = true
2968
+ } = args;
2969
+ const [debouncedRule, setDebouncedRule] = useState(rule);
2970
+ const timer = useRef(null);
2971
+ useEffect(() => {
2972
+ if (timer.current) clearTimeout(timer.current);
2973
+ timer.current = setTimeout(() => setDebouncedRule(rule), debounceMs);
2974
+ return () => {
2975
+ if (timer.current) clearTimeout(timer.current);
2976
+ };
2977
+ }, [rule, debounceMs]);
2978
+ const valid = isRuleValid(debouncedRule);
2979
+ const query = useQuery({
2980
+ queryKey: ["records-admin", "preview-rule", collectionId, appId, debouncedRule, limit],
2981
+ enabled: enabled && !!collectionId && !!appId && valid,
2982
+ staleTime: 3e4,
2983
+ queryFn: () => SL.app.records.previewRule(collectionId, appId, {
2984
+ facetRule: debouncedRule,
2985
+ limit
2986
+ })
2987
+ });
2988
+ return {
2989
+ totalMatches: query.data?.totalMatches ?? null,
2990
+ sampleProductIds: query.data?.sampleProductIds ?? [],
2991
+ isLoading: query.isFetching,
2992
+ isStale: rule !== debouncedRule,
2993
+ error: query.error ?? null
2994
+ };
2995
+ }
2657
2996
  var DEFAULT_SCOPES2 = ["batch", "variant", "product", "facet"];
2658
2997
  var readField = (data, path) => {
2659
2998
  if (data == null || typeof data !== "object") return void 0;
@@ -2694,7 +3033,7 @@ function useCollectedRecords(args) {
2694
3033
  "collected",
2695
3034
  collectionId,
2696
3035
  appId,
2697
- recordType,
3036
+ recordType ?? null,
2698
3037
  productId ?? null,
2699
3038
  variantId ?? null,
2700
3039
  batchId ?? null,
@@ -2716,12 +3055,15 @@ function useCollectedRecords(args) {
2716
3055
  const ctx = { SL, collectionId, appId, recordType };
2717
3056
  const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
2718
3057
  const records = result?.records ?? [];
2719
- const baseList = records.map((rec, i) => ({
2720
- ref: rec.ref ?? "",
2721
- scope: parseRef(rec.ref ?? ""),
2722
- data: rec.data,
2723
- depth: i
2724
- }));
3058
+ const baseList = records.map((entry, i) => {
3059
+ const rec = entry.record;
3060
+ return {
3061
+ ref: rec.ref ?? "",
3062
+ scope: parseRef(rec.ref ?? ""),
3063
+ data: rec.data,
3064
+ depth: i
3065
+ };
3066
+ });
2725
3067
  const sortKind = sort?.kind ?? "specificity";
2726
3068
  const direction = sort?.direction ?? (sortKind === "specificity" ? "desc" : "asc");
2727
3069
  const sign = direction === "desc" ? -1 : 1;
@@ -2784,7 +3126,7 @@ function useMergedRecord(args) {
2784
3126
  "merged",
2785
3127
  collectionId,
2786
3128
  appId,
2787
- recordType,
3129
+ recordType ?? null,
2788
3130
  productId ?? null,
2789
3131
  variantId ?? null,
2790
3132
  batchId ?? null,
@@ -2806,7 +3148,10 @@ function useMergedRecord(args) {
2806
3148
  const result = await matchRecords(ctx, parsedRefToTarget(target), { strategy: "all" }).catch(() => null);
2807
3149
  const records = result?.records ?? [];
2808
3150
  if (records.length === 0) return { data: null, provenance: {}, layers: [] };
2809
- const present = records.map((rec) => ({ ref: rec.ref ?? "", data: rec.data }));
3151
+ const present = records.map((entry) => ({
3152
+ ref: entry.record.ref ?? "",
3153
+ data: entry.record.data
3154
+ }));
2810
3155
  const ordered = [...present].reverse();
2811
3156
  let merged = null;
2812
3157
  const provenance = {};
@@ -2828,6 +3173,6 @@ function useMergedRecord(args) {
2828
3173
  };
2829
3174
  }
2830
3175
 
2831
- export { ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_I18N, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SidePreview, StatusDot, StatusFilterPills, TabbedPreview, UtilityRow, VariantList, buildRef, bulkDelete, bulkUpsert, deleteRecord, downloadBlob, exportCsv, getRecordByRef, importCsv, listRecords, matchRecords, parseRef, parsedRefToScope, parsedRefToTarget, resolutionChain, resolveRecord, restoreRecord, scopesEqual, upsertRecord, useCollectedRecords, useDirtyNavigation, useIntroDismissed, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordEditor, useRecordList, useResolvedRecord, useScopeProbe, useUnsavedGuard };
3176
+ export { ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_I18N, DEFAULT_ICONS, DefaultRecordCard, DefaultRecordRow, DeleteButton, DrawerPreview, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SidePreview, StatusDot, StatusFilterPills, TabbedPreview, UtilityRow, VariantList, buildRef, bulkDelete, bulkUpsert, deleteRecord, downloadBlob, exportCsv, getRecordByRef, importCsv, listRecords, matchRecords, mergeIcons, parseRef, parsedRefToScope, parsedRefToTarget, pickHeaderIcon, resolutionChain, resolveRecord, restoreRecord, scopesEqual, upsertRecord, useCollectedRecords, useDirtyNavigation, useIntroDismissed, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeProbe, useUnsavedGuard };
2832
3177
  //# sourceMappingURL=index.js.map
2833
3178
  //# sourceMappingURL=index.js.map