@proveanything/smartlinks-utils-ui 0.9.4 → 0.9.6

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.
@@ -1805,8 +1805,14 @@ function useShellNavigation(args) {
1805
1805
  onTelemetry,
1806
1806
  onBeforeDelete,
1807
1807
  generateItemId,
1808
- hooks
1808
+ hooks,
1809
+ lastAppliedDLRef
1809
1810
  } = args;
1811
+ const stampEcho = (recordId, scope) => {
1812
+ if (!lastAppliedDLRef) return;
1813
+ const view = deepLinkState.urlState.view ?? "";
1814
+ lastAppliedDLRef.current = `${recordId ?? ""}|${scope ?? ""}|${view}`;
1815
+ };
1810
1816
  const buildItemUrlValue = useCallback((id) => {
1811
1817
  if (!baseScopeRef && id.startsWith("item:")) return id;
1812
1818
  return baseScopeRef ? `${baseScopeRef}/item:${id}` : id;
@@ -1844,6 +1850,7 @@ function useShellNavigation(args) {
1844
1850
  setSelectedItemId(itemId);
1845
1851
  onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId });
1846
1852
  deepLinkState.emit({ recordId: itemId, scope: baseScopeRef || null }, "record.open");
1853
+ stampEcho(itemId, baseScopeRef || null);
1847
1854
  });
1848
1855
  }, [
1849
1856
  isCollection,
@@ -1858,7 +1865,8 @@ function useShellNavigation(args) {
1858
1865
  editingScope,
1859
1866
  setSelectedItemId,
1860
1867
  onTelemetry,
1861
- deepLinkState
1868
+ deepLinkState,
1869
+ lastAppliedDLRef
1862
1870
  ]);
1863
1871
  const onItemCreate = useCallback(() => {
1864
1872
  if (!isCollection) return;
@@ -1867,6 +1875,7 @@ function useShellNavigation(args) {
1867
1875
  setSelectedItemId(id);
1868
1876
  onTelemetry?.({ type: "item.create", recordType, scopeRef: baseScopeRef });
1869
1877
  deepLinkState.emit({ recordId: null, scope: baseScopeRef || null }, "record.open");
1878
+ stampEcho(null, baseScopeRef || null);
1870
1879
  });
1871
1880
  }, [
1872
1881
  isCollection,
@@ -1876,7 +1885,8 @@ function useShellNavigation(args) {
1876
1885
  onTelemetry,
1877
1886
  recordType,
1878
1887
  baseScopeRef,
1879
- deepLinkState
1888
+ deepLinkState,
1889
+ lastAppliedDLRef
1880
1890
  ]);
1881
1891
  const onItemDelete = useCallback(async (itemId) => {
1882
1892
  if (!isCollection) return;
@@ -1918,7 +1928,10 @@ function useShellNavigation(args) {
1918
1928
  await removeRecord2(ctx, itemId);
1919
1929
  onTelemetry?.({ type: "item.delete", recordType, scopeRef: baseScopeRef, itemId });
1920
1930
  if (selectedItemId === itemId) setSelectedItemId(null);
1921
- if (selectedItemId === itemId) deepLinkState.emit({ recordId: null }, "record.close");
1931
+ if (selectedItemId === itemId) {
1932
+ deepLinkState.emit({ recordId: null }, "record.close");
1933
+ stampEcho(null, baseScopeRef || null);
1934
+ }
1922
1935
  collectionItems.refetch();
1923
1936
  if (hooks?.afterDelete) {
1924
1937
  try {
@@ -1942,7 +1955,8 @@ function useShellNavigation(args) {
1942
1955
  deepLinkState,
1943
1956
  editingScope,
1944
1957
  setSelectedItemId,
1945
- hooks
1958
+ hooks,
1959
+ lastAppliedDLRef
1946
1960
  ]);
1947
1961
  const itemViewCtx = useMemo(() => ({
1948
1962
  onOpen: onItemOpen,
@@ -1964,15 +1978,17 @@ function useShellNavigation(args) {
1964
1978
  void runWithGuard(() => {
1965
1979
  setSelectedItemId(null);
1966
1980
  deepLinkState.emit({ recordId: null }, "record.close");
1981
+ stampEcho(null, baseScopeRef || null);
1967
1982
  });
1968
- }, [runWithGuard, deepLinkState, setSelectedItemId]);
1983
+ }, [runWithGuard, deepLinkState, setSelectedItemId, baseScopeRef, lastAppliedDLRef]);
1969
1984
  const stepToItem = useCallback((id) => {
1970
1985
  void runWithGuard(() => {
1971
1986
  setSelectedItemId(id);
1972
1987
  onTelemetry?.({ type: "item.open", recordType, scopeRef: baseScopeRef, itemId: id });
1973
1988
  deepLinkState.emit({ recordId: id, scope: baseScopeRef || null }, "record.step");
1989
+ stampEcho(id, baseScopeRef || null);
1974
1990
  });
1975
- }, [runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, setSelectedItemId]);
1991
+ }, [runWithGuard, onTelemetry, recordType, baseScopeRef, deepLinkState, setSelectedItemId, lastAppliedDLRef]);
1976
1992
  const onItemPrev = useCallback(() => {
1977
1993
  if (!itemPosition || itemPosition.index <= 0) return;
1978
1994
  const next = collectionItems.items[itemPosition.index - 1];
@@ -3405,68 +3421,68 @@ var DefaultRecordRow = ({ record, ctx, compact = false }) => {
3405
3421
  const i18n = ctx.i18n ?? DEFAULT_I18N;
3406
3422
  const subtitle = record.subtitle ?? (isRuleRecord ? null : ruleSummary) ?? (tone === "missing" ? i18n.subtitleEmpty : tone === "own" ? i18n.subtitleConfigured : i18n.subtitleInherited);
3407
3423
  return /* @__PURE__ */ jsxs(
3408
- "button",
3424
+ "div",
3409
3425
  {
3410
- type: "button",
3411
- onClick: onSelect,
3412
3426
  "data-selected": selected ? "true" : "false",
3413
3427
  "data-tone": tone,
3414
3428
  className: cn("ra-row", compact && "ra-row-compact"),
3415
3429
  style: compact ? { paddingTop: "0.4rem", paddingBottom: "0.4rem" } : void 0,
3416
3430
  children: [
3417
- !compact && /* @__PURE__ */ jsx("span", { className: "ra-row-status", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
3418
- StatusIcon,
3419
- {
3420
- status: record.status,
3421
- label: statusToneLabel(tone)
3422
- }
3423
- ) }),
3424
- /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
3425
- /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
3426
- !compact && isRuleRecord && /* @__PURE__ */ jsxs(
3427
- "div",
3431
+ /* @__PURE__ */ jsxs("button", { type: "button", onClick: onSelect, className: "ra-row-hit", children: [
3432
+ !compact && /* @__PURE__ */ jsx("span", { className: "ra-row-status", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
3433
+ StatusIcon,
3428
3434
  {
3429
- className: "ra-row-rule-chips",
3430
- title: ruleSummary ?? void 0,
3431
- "aria-label": ruleSummary ?? void 0,
3432
- children: [
3433
- ruleClauses.slice(0, 4).map((clause, i) => /* @__PURE__ */ jsx("span", { className: "ra-rule-chip", children: clause.label }, `${clause.facetKey}-${i}`)),
3434
- ruleClauses.length > 4 && /* @__PURE__ */ jsxs("span", { className: "ra-rule-chip ra-rule-chip-more", children: [
3435
- "+",
3436
- ruleClauses.length - 4
3437
- ] })
3438
- ]
3435
+ status: record.status,
3436
+ label: statusToneLabel(tone)
3437
+ }
3438
+ ) }),
3439
+ /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
3440
+ /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: record.label }),
3441
+ !compact && isRuleRecord && /* @__PURE__ */ jsxs(
3442
+ "div",
3443
+ {
3444
+ className: "ra-row-rule-chips",
3445
+ title: ruleSummary ?? void 0,
3446
+ "aria-label": ruleSummary ?? void 0,
3447
+ children: [
3448
+ ruleClauses.slice(0, 4).map((clause, i) => /* @__PURE__ */ jsx("span", { className: "ra-rule-chip", children: clause.label }, `${clause.facetKey}-${i}`)),
3449
+ ruleClauses.length > 4 && /* @__PURE__ */ jsxs("span", { className: "ra-rule-chip ra-rule-chip-more", children: [
3450
+ "+",
3451
+ ruleClauses.length - 4
3452
+ ] })
3453
+ ]
3454
+ }
3455
+ ),
3456
+ !compact && !isRuleRecord && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: subtitle })
3457
+ ] }),
3458
+ compact && /* @__PURE__ */ jsx(StatusIcon, { status: record.status, size: "0.85rem" }),
3459
+ !compact && record.scope.kind && record.scope.kind !== "collection" && record.scope.kind !== "rule" && /* @__PURE__ */ jsx("span", { className: "ra-row-scope", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ScopeIcon, { className: "w-3 h-3" }) }),
3460
+ record.badges?.slice(0, 1).map((b, i) => /* @__PURE__ */ jsx("span", { className: "ra-chip", "data-tone": "muted", children: b.label }, `${b.label}-${i}`)),
3461
+ record.facetRule && !compact && !isRuleRecord && /* @__PURE__ */ jsx(
3462
+ "span",
3463
+ {
3464
+ className: "ra-row-rule-pip",
3465
+ title: ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
3466
+ "aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
3467
+ children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "w-3 h-3", "aria-hidden": "true" })
3439
3468
  }
3440
3469
  ),
3441
- !compact && !isRuleRecord && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: subtitle })
3470
+ hasError ? /* @__PURE__ */ jsx(
3471
+ "span",
3472
+ {
3473
+ title: "Save failed",
3474
+ "aria-label": "Save failed",
3475
+ className: "ra-error-pip"
3476
+ }
3477
+ ) : isDirty && /* @__PURE__ */ jsx(
3478
+ "span",
3479
+ {
3480
+ title: "Unsaved changes",
3481
+ "aria-label": "Unsaved changes",
3482
+ className: "ra-dirty-pip"
3483
+ }
3484
+ )
3442
3485
  ] }),
3443
- compact && /* @__PURE__ */ jsx(StatusIcon, { status: record.status, size: "0.85rem" }),
3444
- !compact && record.scope.kind && record.scope.kind !== "collection" && record.scope.kind !== "rule" && /* @__PURE__ */ jsx("span", { className: "ra-row-scope", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ScopeIcon, { className: "w-3 h-3" }) }),
3445
- record.badges?.slice(0, 1).map((b, i) => /* @__PURE__ */ jsx("span", { className: "ra-chip", "data-tone": "muted", children: b.label }, `${b.label}-${i}`)),
3446
- record.facetRule && !compact && !isRuleRecord && /* @__PURE__ */ jsx(
3447
- "span",
3448
- {
3449
- className: "ra-row-rule-pip",
3450
- title: ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
3451
- "aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This record has targeting rules",
3452
- children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "w-3 h-3", "aria-hidden": "true" })
3453
- }
3454
- ),
3455
- hasError ? /* @__PURE__ */ jsx(
3456
- "span",
3457
- {
3458
- title: "Save failed",
3459
- "aria-label": "Save failed",
3460
- className: "ra-error-pip"
3461
- }
3462
- ) : isDirty && /* @__PURE__ */ jsx(
3463
- "span",
3464
- {
3465
- title: "Unsaved changes",
3466
- "aria-label": "Unsaved changes",
3467
- className: "ra-dirty-pip"
3468
- }
3469
- ),
3470
3486
  (onCopy || onPaste) && /* @__PURE__ */ jsx(
3471
3487
  RowContextMenu,
3472
3488
  {
@@ -4010,112 +4026,6 @@ var createDefaultDeepLinkAdapter = (paramNames) => ({
4010
4026
  }
4011
4027
  });
4012
4028
 
4013
- // src/components/RecordsAdmin/data/postMessageDeepLinkAdapter.ts
4014
- var CONTEXT_KEYS = [
4015
- "dark",
4016
- "appId",
4017
- "collectionId",
4018
- "productId",
4019
- "proofId",
4020
- "lang",
4021
- "theme"
4022
- ];
4023
- var getSearchParams2 = (loc) => new URLSearchParams(loc.search.startsWith("?") ? loc.search.slice(1) : loc.search);
4024
- var getHashParams2 = (loc) => {
4025
- const idx = loc.hash.indexOf("?");
4026
- return new URLSearchParams(idx >= 0 ? loc.hash.slice(idx + 1) : "");
4027
- };
4028
- var getReadParams2 = (loc) => {
4029
- if (loc.hash && loc.hash.includes("?")) return getHashParams2(loc);
4030
- return getSearchParams2(loc);
4031
- };
4032
- var getMergedParams = (loc) => {
4033
- const merged = getSearchParams2(loc);
4034
- const hashParams = getHashParams2(loc);
4035
- hashParams.forEach((value, key) => {
4036
- merged.set(key, value);
4037
- });
4038
- return merged;
4039
- };
4040
- var findPath = (loc) => {
4041
- if (loc.hash && loc.hash.startsWith("#")) {
4042
- const hash = loc.hash.slice(1);
4043
- const qIdx = hash.indexOf("?");
4044
- const hashPath = qIdx >= 0 ? hash.slice(0, qIdx) : hash;
4045
- if (hashPath) return hashPath;
4046
- }
4047
- return loc.pathname || "/";
4048
- };
4049
- var isInSmartLinksIframe = () => {
4050
- if (typeof window === "undefined") return false;
4051
- try {
4052
- return window.parent != null && window.parent !== window;
4053
- } catch {
4054
- return true;
4055
- }
4056
- };
4057
- var createPostMessageDeepLinkAdapter = (paramNames) => {
4058
- const lastShellState = {};
4059
- const post = (path) => {
4060
- if (typeof window === "undefined") return;
4061
- const params = getMergedParams(window.location);
4062
- const context = {};
4063
- const state = {};
4064
- params.forEach((value, key) => {
4065
- if (key === "theme") return;
4066
- if (CONTEXT_KEYS.includes(key)) context[key] = value;
4067
- else state[key] = value;
4068
- });
4069
- const overlay = (key, paramKey) => {
4070
- const v = lastShellState[key];
4071
- if (v == null || v === "") delete state[paramKey];
4072
- else state[paramKey] = v;
4073
- };
4074
- overlay("recordId", paramNames.recordId);
4075
- overlay("scope", paramNames.scope);
4076
- overlay("view", paramNames.view);
4077
- try {
4078
- const message = {
4079
- type: "smartlinks-route-change",
4080
- path,
4081
- context,
4082
- state,
4083
- appId: context.appId
4084
- };
4085
- window.parent.postMessage(message, "*");
4086
- } catch {
4087
- }
4088
- };
4089
- return {
4090
- read() {
4091
- if (typeof window === "undefined") return {};
4092
- const params = getReadParams2(window.location);
4093
- return {
4094
- recordId: params.get(paramNames.recordId),
4095
- scope: params.get(paramNames.scope),
4096
- view: params.get(paramNames.view)
4097
- };
4098
- },
4099
- write(partial) {
4100
- if (typeof window === "undefined") return;
4101
- if ("recordId" in partial) lastShellState.recordId = partial.recordId ?? null;
4102
- if ("scope" in partial) lastShellState.scope = partial.scope ?? null;
4103
- if ("view" in partial) lastShellState.view = partial.view ?? null;
4104
- post(findPath(window.location));
4105
- },
4106
- subscribe(listener) {
4107
- if (typeof window === "undefined") return () => {
4108
- };
4109
- window.addEventListener("popstate", listener);
4110
- window.addEventListener("hashchange", listener);
4111
- return () => {
4112
- window.removeEventListener("popstate", listener);
4113
- window.removeEventListener("hashchange", listener);
4114
- };
4115
- }
4116
- };
4117
- };
4118
-
4119
4029
  // src/components/RecordsAdmin/hooks/useDeepLinkState.ts
4120
4030
  var SMART_PUSH = ["record.open", "record.close", "scope"];
4121
4031
  var classify2 = (mode, kind) => {
@@ -4135,8 +4045,7 @@ function useDeepLinkState(options) {
4135
4045
  if (!enabled) return null;
4136
4046
  if (options?.adapter) return options.adapter;
4137
4047
  if (!defaultAdapterRef.current) {
4138
- const inIframe = isInSmartLinksIframe();
4139
- defaultAdapterRef.current = inIframe ? createPostMessageDeepLinkAdapter(paramNames) : createDefaultDeepLinkAdapter(paramNames);
4048
+ defaultAdapterRef.current = createDefaultDeepLinkAdapter(paramNames);
4140
4049
  }
4141
4050
  return defaultAdapterRef.current;
4142
4051
  }, [enabled, options?.adapter, paramNames]);
@@ -4576,6 +4485,7 @@ function RecordTargeting({
4576
4485
  const summary = useMemo(() => summariseRule2(clauses, facets), [clauses, facets]);
4577
4486
  if (!ctx.onFacetRuleChange) return null;
4578
4487
  if (!hasInflightRule) return null;
4488
+ if (hasAnyClause && !isInvalid && !forceOpen) return null;
4579
4489
  const headerTone = isInvalid ? { color: "hsl(var(--ra-danger, 0 70% 45%))" } : { color: "hsl(var(--ra-muted-text))" };
4580
4490
  const setOpenAndNotify = (next) => {
4581
4491
  setOpen(next);
@@ -4681,6 +4591,7 @@ function TargetingPopover({
4681
4591
  const [open, setOpen] = useState(false);
4682
4592
  const triggerRef = useRef(null);
4683
4593
  const [anchor, setAnchor] = useState(null);
4594
+ const ruleLabelLookup = useRuleLabelLookup();
4684
4595
  const currentHash = useMemo(() => ruleHash(ctx.facetRule), [ctx.facetRule]);
4685
4596
  const currentMatchesPreset = !!currentHash && catalogue.some((e) => e.hash === currentHash);
4686
4597
  const sharedCount = useMemo(() => {
@@ -4734,6 +4645,7 @@ function TargetingPopover({
4734
4645
  };
4735
4646
  const triggerLabel = mode === "global" ? "Global" : "Targeted";
4736
4647
  const TriggerIcon = mode === "global" ? Globe2 : Target;
4648
+ const triggerSummary = mode !== "global" && ctx.facetRule && (ctx.facetRule.all?.length ?? 0) > 0 ? summariseRule(ctx.facetRule, ruleLabelLookup) : null;
4737
4649
  const popover = open && anchor ? createPortal(
4738
4650
  /* @__PURE__ */ jsxs(
4739
4651
  "div",
@@ -4851,17 +4763,36 @@ function TargetingPopover({
4851
4763
  ref: triggerRef,
4852
4764
  type: "button",
4853
4765
  onClick: () => setOpen((o) => !o),
4854
- className: "text-[11px] inline-flex items-center gap-1 px-2 py-1 rounded-md border transition-colors hover:bg-[hsl(var(--ra-muted))]",
4766
+ className: "text-[11px] inline-flex items-center gap-1 px-2 py-1 rounded-md border transition-colors hover:bg-[hsl(var(--ra-muted))] max-w-[18rem]",
4855
4767
  style: {
4856
4768
  borderColor: "hsl(var(--ra-border))",
4857
4769
  color: "hsl(var(--ra-text))"
4858
4770
  },
4859
4771
  "aria-haspopup": "dialog",
4860
4772
  "aria-expanded": open,
4861
- title: "Use rules to scope this record to a targeted audience",
4773
+ title: triggerSummary ? `Targeted: ${triggerSummary}` : "Use rules to scope this record to a targeted audience",
4862
4774
  children: [
4863
- /* @__PURE__ */ jsx(TriggerIcon, { className: "w-3 h-3" }),
4864
- triggerLabel,
4775
+ /* @__PURE__ */ jsx(TriggerIcon, { className: "w-3 h-3 shrink-0" }),
4776
+ /* @__PURE__ */ jsx("span", { className: "shrink-0", children: triggerLabel }),
4777
+ triggerSummary && /* @__PURE__ */ jsxs(Fragment, { children: [
4778
+ /* @__PURE__ */ jsx(
4779
+ "span",
4780
+ {
4781
+ className: "shrink-0",
4782
+ style: { color: "hsl(var(--ra-muted-text))" },
4783
+ "aria-hidden": "true",
4784
+ children: "\xB7"
4785
+ }
4786
+ ),
4787
+ /* @__PURE__ */ jsx(
4788
+ "span",
4789
+ {
4790
+ className: "truncate",
4791
+ style: { color: "hsl(var(--ra-muted-text))" },
4792
+ children: triggerSummary
4793
+ }
4794
+ )
4795
+ ] }),
4865
4796
  mode === "preset" && /* @__PURE__ */ jsx(Check, { className: "w-3 h-3", style: { color: "hsl(var(--ra-muted-text))" } })
4866
4797
  ]
4867
4798
  }
@@ -5880,70 +5811,67 @@ function SiblingRail({
5880
5811
  selectedItemId,
5881
5812
  isLoading,
5882
5813
  error,
5883
- onBack,
5884
5814
  onSelect,
5885
5815
  dirtyKeys,
5886
5816
  errorKeys,
5887
5817
  i18n
5888
5818
  }) {
5889
- return /* @__PURE__ */ jsxs("div", { className: "ra-sibling-rail", children: [
5890
- /* @__PURE__ */ jsxs(
5891
- "button",
5892
- {
5893
- type: "button",
5894
- onClick: onBack,
5895
- className: "ra-sibling-back",
5896
- children: [
5897
- /* @__PURE__ */ jsx(ArrowLeft, { className: "w-3.5 h-3.5" }),
5898
- i18n.backToScopes
5899
- ]
5900
- }
5901
- ),
5902
- /* @__PURE__ */ jsx("div", { className: "ra-sibling-heading", children: i18n.siblingsHeading }),
5903
- /* @__PURE__ */ jsxs("div", { className: "ra-sibling-body", children: [
5904
- isLoading && /* @__PURE__ */ jsx(LoadingState, {}),
5905
- !isLoading && error && /* @__PURE__ */ jsx(ErrorState, { error }),
5906
- !isLoading && !error && items.length === 0 && /* @__PURE__ */ jsx(EmptyState, { title: i18n.noItemsTitle, body: i18n.noItemsBody }),
5907
- !isLoading && !error && items.length > 0 && /* @__PURE__ */ jsx("ul", { className: "ra-sibling-list", children: items.map((item, idx) => {
5908
- const id = item.itemId ?? "";
5909
- const key = item.id ?? (id || anchorKey(item.scope) || `pos:${idx}`);
5910
- const akey = anchorKey(item.scope);
5911
- const selected = selectedItemId === id;
5912
- const isDirty = !!(id && dirtyKeys?.has(id) || akey && dirtyKeys?.has(akey));
5913
- const hasError = !!(id && errorKeys?.has(id) || akey && errorKeys?.has(akey));
5914
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
5915
- "button",
5916
- {
5917
- type: "button",
5918
- onClick: () => onSelect(id),
5919
- className: "ra-row",
5920
- "data-selected": selected,
5921
- children: [
5922
- /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
5923
- /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: item.label }),
5924
- item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: item.subtitle })
5925
- ] }),
5926
- hasError ? /* @__PURE__ */ jsx(
5927
- "span",
5928
- {
5929
- className: "ra-error-pip",
5930
- title: "Save failed",
5931
- "aria-label": "Save failed"
5932
- }
5933
- ) : isDirty ? /* @__PURE__ */ jsx(
5934
- "span",
5935
- {
5936
- className: "ra-dirty-pip",
5937
- title: "Unsaved changes",
5938
- "aria-label": "Unsaved changes"
5939
- }
5940
- ) : null
5941
- ]
5942
- }
5943
- ) }, key);
5944
- }) })
5945
- ] })
5946
- ] });
5819
+ const ruleLabelLookup = useRuleLabelLookup();
5820
+ return /* @__PURE__ */ jsx("div", { className: "ra-sibling-rail", children: /* @__PURE__ */ jsxs("div", { className: "ra-sibling-body", children: [
5821
+ isLoading && /* @__PURE__ */ jsx(LoadingState, {}),
5822
+ !isLoading && error && /* @__PURE__ */ jsx(ErrorState, { error }),
5823
+ !isLoading && !error && items.length === 0 && /* @__PURE__ */ jsx(EmptyState, { title: i18n.noItemsTitle, body: i18n.noItemsBody }),
5824
+ !isLoading && !error && items.length > 0 && /* @__PURE__ */ jsx("ul", { className: "ra-sibling-list", children: items.map((item, idx) => {
5825
+ const id = item.itemId ?? "";
5826
+ const key = item.id ?? (id || anchorKey(item.scope) || `pos:${idx}`);
5827
+ const akey = anchorKey(item.scope);
5828
+ const selected = selectedItemId === id;
5829
+ const isDirty = !!(id && dirtyKeys?.has(id) || akey && dirtyKeys?.has(akey));
5830
+ const hasError = !!(id && errorKeys?.has(id) || akey && errorKeys?.has(akey));
5831
+ const ruleClauses = item.facetRule ? summarizeFacetRule(item.facetRule, ruleLabelLookup) : [];
5832
+ const isTargeted = ruleClauses.length > 0;
5833
+ const ruleSummary = isTargeted ? ruleClauses.map((c) => c.label).join(" \xB7 ") : null;
5834
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
5835
+ "button",
5836
+ {
5837
+ type: "button",
5838
+ onClick: () => onSelect(id),
5839
+ className: "ra-row",
5840
+ "data-selected": selected,
5841
+ children: [
5842
+ /* @__PURE__ */ jsxs("div", { className: "ra-row-body", children: [
5843
+ /* @__PURE__ */ jsx("div", { className: "ra-row-title", children: item.label }),
5844
+ item.subtitle && /* @__PURE__ */ jsx("div", { className: "ra-row-sub", children: item.subtitle })
5845
+ ] }),
5846
+ isTargeted && /* @__PURE__ */ jsx(
5847
+ "span",
5848
+ {
5849
+ className: "ra-row-rule-pip",
5850
+ title: ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
5851
+ "aria-label": ruleSummary ? `Targeted: ${ruleSummary}` : "This item has targeting rules",
5852
+ children: /* @__PURE__ */ jsx(SlidersHorizontal, { className: "w-3 h-3", "aria-hidden": "true" })
5853
+ }
5854
+ ),
5855
+ hasError ? /* @__PURE__ */ jsx(
5856
+ "span",
5857
+ {
5858
+ className: "ra-error-pip",
5859
+ title: "Save failed",
5860
+ "aria-label": "Save failed"
5861
+ }
5862
+ ) : isDirty ? /* @__PURE__ */ jsx(
5863
+ "span",
5864
+ {
5865
+ className: "ra-dirty-pip",
5866
+ title: "Unsaved changes",
5867
+ "aria-label": "Unsaved changes"
5868
+ }
5869
+ ) : null
5870
+ ]
5871
+ }
5872
+ ) }, key);
5873
+ }) })
5874
+ ] }) });
5947
5875
  }
5948
5876
  var TONE_ICON = {
5949
5877
  info: Lightbulb,
@@ -6110,14 +6038,7 @@ function ShellHeader({
6110
6038
  const resolvedItems = (() => {
6111
6039
  if (!showStats) return [];
6112
6040
  if (statsItems && statsItems.length > 0) return statsItems;
6113
- const items = [];
6114
- if (typeof stats?.shared === "number" && stats.shared > 0) {
6115
- items.push({ label: "Shared", value: stats.shared });
6116
- }
6117
- if (typeof stats?.products === "number" && stats.products > 0) {
6118
- items.push({ label: "Products", value: stats.products });
6119
- }
6120
- return items;
6041
+ return [];
6121
6042
  })();
6122
6043
  const hasStats = resolvedItems.length > 0;
6123
6044
  const hasStatsHeading = !!(statsTitle || statsIcon);
@@ -7102,7 +7023,6 @@ var EditorPoolBody = ({
7102
7023
  };
7103
7024
  var TOP_LEVEL_SCOPES = ["collection", "rule", "product"];
7104
7025
  var OPT_IN_TOP_LEVEL_SCOPES = ["all"];
7105
- var WARNED_FACET_DEPRECATED = false;
7106
7026
  var DRAFT_ID3 = "__draft__";
7107
7027
  var isDraftId3 = (id) => !!id && (id === DRAFT_ID3 || id.startsWith("draft:"));
7108
7028
  var mintDraftItemId2 = () => {
@@ -7315,14 +7235,6 @@ function RecordsAdminShellInner(props) {
7315
7235
  if (!productPinnedFromContext || contextScopeMode !== "strict") return topLevelScopes;
7316
7236
  return topLevelScopes.filter((s) => s !== "collection" && s !== "rule" && s !== "all");
7317
7237
  }, [productPinnedFromContext, contextScopeMode, topLevelScopes]);
7318
- useEffect(() => {
7319
- if (requestedScopes.includes("facet") && !WARNED_FACET_DEPRECATED) {
7320
- WARNED_FACET_DEPRECATED = true;
7321
- console.warn(
7322
- '[RecordsAdminShell] The "facet" top-level scope was removed in 0.5.0. Use the Rules tab\'s built-in "Browse by facet" filter instead. Drop "facet" (and any `defaultScope: "facet"`) from your `scopes` prop.'
7323
- );
7324
- }
7325
- }, [requestedScopes]);
7326
7238
  const drillVariantsAllowed = useMemo(
7327
7239
  () => requestedScopes.includes("variant") && (probe.isLoading || probe.hasVariants),
7328
7240
  [requestedScopes, probe.isLoading, probe.hasVariants]
@@ -7467,7 +7379,7 @@ function RecordsAdminShellInner(props) {
7467
7379
  }
7468
7380
  setSelectedItemId(null);
7469
7381
  }, [editingScope?.raw]);
7470
- useShellDeepLink({
7382
+ const { lastAppliedDLRef } = useShellDeepLink({
7471
7383
  deepLinkState,
7472
7384
  editingScope,
7473
7385
  selectedItemId,
@@ -7730,7 +7642,8 @@ function RecordsAdminShellInner(props) {
7730
7642
  onTelemetry,
7731
7643
  onBeforeDelete,
7732
7644
  generateItemId,
7733
- hooks: props.hooks
7645
+ hooks: props.hooks,
7646
+ lastAppliedDLRef
7734
7647
  });
7735
7648
  const renderEditorWithPreview = () => {
7736
7649
  if (!editingTargetScope) return null;
@@ -8350,7 +8263,7 @@ function RecordsAdminShellInner(props) {
8350
8263
  i18n
8351
8264
  }
8352
8265
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
8353
- /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
8266
+ /* @__PURE__ */ jsx("div", { className: "px-1.5 py-2", children: /* @__PURE__ */ jsx(
8354
8267
  ScopeTabs,
8355
8268
  {
8356
8269
  scopes: effectiveTopLevelScopes,
@@ -8496,7 +8409,13 @@ function RecordsAdminShellInner(props) {
8496
8409
  errorKeys,
8497
8410
  presentation: effectivePresentation,
8498
8411
  renderListRow,
8499
- groupBy: effectiveGroupBy,
8412
+ groupBy: (
8413
+ // The synthetic "All items" row in collection mode is a
8414
+ // navigational anchor, not a real record — applying the
8415
+ // host's groupBy bucketed it under "Other" (its
8416
+ // data is null). Skip grouping for that single-row rail.
8417
+ (isGlobalTab || isAllTab) && isCollection ? void 0 : effectiveGroupBy
8418
+ ),
8500
8419
  renderGroupActions: renderRuleGroupActions,
8501
8420
  rowClipboard,
8502
8421
  i18n
@@ -9276,6 +9195,142 @@ function useRecordEditor(args) {
9276
9195
  onFacetRuleChange: handleFacetRuleChange
9277
9196
  };
9278
9197
  }
9198
+
9199
+ // src/components/RecordsAdmin/data/routerDeepLinkAdapter.ts
9200
+ var createRouterDeepLinkAdapter = (paramNames, getParams, setParams) => {
9201
+ [paramNames.recordId, paramNames.scope, paramNames.view];
9202
+ return {
9203
+ read() {
9204
+ const params = getParams();
9205
+ return {
9206
+ recordId: params.get(paramNames.recordId),
9207
+ scope: params.get(paramNames.scope),
9208
+ view: params.get(paramNames.view)
9209
+ };
9210
+ },
9211
+ write(partial) {
9212
+ const merged = new URLSearchParams(getParams());
9213
+ const apply = (key, value) => {
9214
+ if (value == null || value === "") merged.delete(key);
9215
+ else merged.set(key, value);
9216
+ };
9217
+ if ("recordId" in partial) apply(paramNames.recordId, partial.recordId);
9218
+ if ("scope" in partial) apply(paramNames.scope, partial.scope);
9219
+ if ("view" in partial) apply(paramNames.view, partial.view);
9220
+ setParams(merged);
9221
+ },
9222
+ subscribe(_listener) {
9223
+ return () => {
9224
+ };
9225
+ }
9226
+ };
9227
+ };
9228
+
9229
+ // src/components/RecordsAdmin/data/postMessageDeepLinkAdapter.ts
9230
+ var CONTEXT_KEYS = [
9231
+ "dark",
9232
+ "appId",
9233
+ "collectionId",
9234
+ "productId",
9235
+ "proofId",
9236
+ "lang",
9237
+ "theme"
9238
+ ];
9239
+ var getSearchParams2 = (loc) => new URLSearchParams(loc.search.startsWith("?") ? loc.search.slice(1) : loc.search);
9240
+ var getHashParams2 = (loc) => {
9241
+ const idx = loc.hash.indexOf("?");
9242
+ return new URLSearchParams(idx >= 0 ? loc.hash.slice(idx + 1) : "");
9243
+ };
9244
+ var getReadParams2 = (loc) => {
9245
+ if (loc.hash && loc.hash.includes("?")) return getHashParams2(loc);
9246
+ return getSearchParams2(loc);
9247
+ };
9248
+ var getMergedParams = (loc) => {
9249
+ const merged = getSearchParams2(loc);
9250
+ const hashParams = getHashParams2(loc);
9251
+ hashParams.forEach((value, key) => {
9252
+ merged.set(key, value);
9253
+ });
9254
+ return merged;
9255
+ };
9256
+ var findPath = (loc) => {
9257
+ if (loc.hash && loc.hash.startsWith("#")) {
9258
+ const hash = loc.hash.slice(1);
9259
+ const qIdx = hash.indexOf("?");
9260
+ const hashPath = qIdx >= 0 ? hash.slice(0, qIdx) : hash;
9261
+ if (hashPath) return hashPath;
9262
+ }
9263
+ return loc.pathname || "/";
9264
+ };
9265
+ var isInSmartLinksIframe = () => {
9266
+ if (typeof window === "undefined") return false;
9267
+ try {
9268
+ return window.parent != null && window.parent !== window;
9269
+ } catch {
9270
+ return true;
9271
+ }
9272
+ };
9273
+ var createPostMessageDeepLinkAdapter = (paramNames) => {
9274
+ const lastShellState = {};
9275
+ const post = (path) => {
9276
+ if (typeof window === "undefined") return;
9277
+ const params = getMergedParams(window.location);
9278
+ const context = {};
9279
+ const state = {};
9280
+ params.forEach((value, key) => {
9281
+ if (key === "theme") return;
9282
+ if (CONTEXT_KEYS.includes(key)) context[key] = value;
9283
+ else state[key] = value;
9284
+ });
9285
+ const overlay = (key, paramKey) => {
9286
+ const v = lastShellState[key];
9287
+ if (v == null || v === "") delete state[paramKey];
9288
+ else state[paramKey] = v;
9289
+ };
9290
+ overlay("recordId", paramNames.recordId);
9291
+ overlay("scope", paramNames.scope);
9292
+ overlay("view", paramNames.view);
9293
+ try {
9294
+ const message = {
9295
+ type: "smartlinks-route-change",
9296
+ path,
9297
+ context,
9298
+ state,
9299
+ appId: context.appId
9300
+ };
9301
+ window.parent.postMessage(message, "*");
9302
+ } catch {
9303
+ }
9304
+ };
9305
+ return {
9306
+ read() {
9307
+ if (typeof window === "undefined") return {};
9308
+ const params = getReadParams2(window.location);
9309
+ return {
9310
+ recordId: params.get(paramNames.recordId),
9311
+ scope: params.get(paramNames.scope),
9312
+ view: params.get(paramNames.view)
9313
+ };
9314
+ },
9315
+ write(partial) {
9316
+ if (typeof window === "undefined") return;
9317
+ if ("recordId" in partial) lastShellState.recordId = partial.recordId ?? null;
9318
+ if ("scope" in partial) lastShellState.scope = partial.scope ?? null;
9319
+ if ("view" in partial) lastShellState.view = partial.view ?? null;
9320
+ post(findPath(window.location));
9321
+ },
9322
+ subscribe(listener) {
9323
+ if (typeof window === "undefined") return () => {
9324
+ };
9325
+ window.addEventListener("popstate", listener);
9326
+ window.addEventListener("hashchange", listener);
9327
+ return () => {
9328
+ window.removeEventListener("popstate", listener);
9329
+ window.removeEventListener("hashchange", listener);
9330
+ };
9331
+ }
9332
+ };
9333
+ };
9279
9334
  var resolveAllQueryKey = (args) => [
9280
9335
  "records-admin",
9281
9336
  "resolve-all",
@@ -9519,6 +9574,6 @@ function useMergedRecord(args) {
9519
9574
  // src/components/RecordsAdmin/index.ts
9520
9575
  assertComponentStylesLoaded("records-admin");
9521
9576
 
9522
- export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DirtyDraftProvider, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList, buildDraftKey, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, createPostMessageDeepLinkAdapter, downloadBlob, exportCsv, importCsv, isInSmartLinksIframe, mergeIcons, normaliseRule, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, ruleHash, rulesEqual, scopeCountsQueryKey, statusToneLabel, summariseRule, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyDraft, useDirtyDraftActions, useDirtyDraftStore, useDirtyDrafts, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeCounts, useScopeProbe, useUnsavedGuard };
9577
+ export { ALL_ITEM_VIEWS, ALL_PRESENTATIONS, BatchList, BulkActionsMenu, DEFAULT_DEEP_LINK_PARAM_NAMES, DEFAULT_I18N, DEFAULT_ICONS, DefaultItemCards, DefaultItemTable, DefaultRecordCard, DefaultRecordRow, DeleteButton, DirtyDraftProvider, DrawerPreview, EditorItemNav, EmptyState, ErrorState, FacetList, InheritanceMarker, InheritanceProvider, InlinePreview, IntroCard, ItemListView, ItemViewSwitcher, LoadingState, PresentationSwitcher, PreviewScopePicker, PreviewToggleButton, ProductDrillDown, ProductList, RecordBrowser, RecordEditor, RecordList, RecordsAdminShell, ResolvedPreview, ScopeBreadcrumb, ScopeTabs, SiblingRail, SidePreview, StatusDot, StatusFilterPills, StatusIcon, TabbedPreview, UtilityRow, VariantList, buildDraftKey, buildRef, checkPasteCompatibility, cloneValue, createDefaultDeepLinkAdapter, createPostMessageDeepLinkAdapter, createRouterDeepLinkAdapter, downloadBlob, exportCsv, importCsv, isInSmartLinksIframe, mergeIcons, normaliseRule, parseRef, pickHeaderIcon, resolutionChain, resolveRecord, ruleHash, rulesEqual, scopeCountsQueryKey, statusToneLabel, summariseRule, useCollectedRecords, useCollectionItems, useDeepLinkState, useDirtyDraft, useDirtyDraftActions, useDirtyDraftStore, useDirtyDrafts, useDirtyNavigation, useFacetBrowse, useIntroDismissed, useItemViewPref, useMergedRecord, usePresentationPref, useProductBrowse, useProductChildren, useRecordClipboard, useRecordEditor, useRecordList, useResolveAllRecords, useResolvedRecord, useRulePreview, useScopeCounts, useScopeProbe, useUnsavedGuard };
9523
9578
  //# sourceMappingURL=index.js.map
9524
9579
  //# sourceMappingURL=index.js.map