@proveanything/smartlinks-utils-ui 0.10.2 → 0.10.3

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.
@@ -2055,6 +2055,15 @@ declare const useProductBrowse: (args: UseProductBrowseArgs) => {
2055
2055
  refetch: () => Promise<void>;
2056
2056
  };
2057
2057
 
2058
+ interface FacetValueShape {
2059
+ key?: string;
2060
+ name?: string;
2061
+ }
2062
+ interface FacetShape {
2063
+ key?: string;
2064
+ name?: string;
2065
+ values?: FacetValueShape[];
2066
+ }
2058
2067
  interface UseFacetBrowseArgs {
2059
2068
  SL: SmartLinksSDK;
2060
2069
  collectionId: string;
@@ -2075,6 +2084,12 @@ declare const useFacetBrowse: ({ SL, collectionId, existing, search, filter, ena
2075
2084
  isLoading: boolean;
2076
2085
  error: Error | null;
2077
2086
  refetch: () => void;
2087
+ /** Raw canonical facet vocabulary as returned by the SDK. Use this
2088
+ * (NOT `items`) when you need the authoritative list of facets and
2089
+ * their values — `items` is the record-merged list and may include
2090
+ * rows whose scope's `facetId` doesn't match a canonical key, which
2091
+ * would otherwise show up as duplicate facet groups. */
2092
+ vocabulary: FacetShape[];
2078
2093
  };
2079
2094
 
2080
2095
  interface CollectedRecord<T = unknown> {
@@ -817,7 +817,13 @@ var useFacetBrowse = ({
817
817
  counts,
818
818
  isLoading: query.isLoading,
819
819
  error: query.error ?? null,
820
- refetch
820
+ refetch,
821
+ /** Raw canonical facet vocabulary as returned by the SDK. Use this
822
+ * (NOT `items`) when you need the authoritative list of facets and
823
+ * their values — `items` is the record-merged list and may include
824
+ * rows whose scope's `facetId` doesn't match a canonical key, which
825
+ * would otherwise show up as duplicate facet groups. */
826
+ vocabulary: query.data ?? []
821
827
  };
822
828
  };
823
829
  var QK2 = ["records-admin", "product-browse"];
@@ -3697,6 +3703,8 @@ var FacetList = RecordList;
3697
3703
  var VariantList = RecordList;
3698
3704
  var BatchList = RecordList;
3699
3705
  var COLLAPSED_FACET_CAP = 6;
3706
+ var COLLAPSED_VALUE_CAP = 12;
3707
+ var VALUE_SEARCH_THRESHOLD = 12;
3700
3708
  function FacetBrowseFilter({
3701
3709
  facets,
3702
3710
  value,
@@ -3710,12 +3718,33 @@ function FacetBrowseFilter({
3710
3718
  );
3711
3719
  const [openKey, setOpenKey] = useState(value?.facetKey ?? firstUsable ?? null);
3712
3720
  const [allExpanded, setAllExpanded] = useState(false);
3721
+ const [valuesExpanded, setValuesExpanded] = useState({});
3722
+ const [valueSearch, setValueSearch] = useState({});
3713
3723
  const effectiveOpen = value?.facetKey ?? openKey ?? firstUsable ?? null;
3714
3724
  if (isLoading) {
3715
3725
  return /* @__PURE__ */ jsx("div", { className: "ra-rule-filters", "aria-busy": "true", children: /* @__PURE__ */ jsx("div", { className: "ra-rule-filters-row", children: /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip", "data-active": "false", children: "Loading facets\u2026" }) }) });
3716
3726
  }
3717
3727
  if (!facets.length) return null;
3718
3728
  const openFacet = facets.find((f) => f.key === effectiveOpen) ?? null;
3729
+ const openValuesExpanded = openFacet ? !!valuesExpanded[openFacet.key] : false;
3730
+ const openValueSearch = openFacet ? valueSearch[openFacet.key] ?? "" : "";
3731
+ const openValuesFiltered = useMemo(() => {
3732
+ if (!openFacet) return [];
3733
+ const q = openValueSearch.trim().toLowerCase();
3734
+ if (!q) return openFacet.values;
3735
+ return openFacet.values.filter(
3736
+ (v) => `${v.label ?? ""} ${v.key}`.toLowerCase().includes(q)
3737
+ );
3738
+ }, [openFacet, openValueSearch]);
3739
+ const valueOverflow = openFacet ? openValuesFiltered.length - COLLAPSED_VALUE_CAP : 0;
3740
+ const visibleValues = openFacet ? openValuesExpanded || valueOverflow <= 0 ? openValuesFiltered : (() => {
3741
+ const head = openValuesFiltered.slice(0, COLLAPSED_VALUE_CAP);
3742
+ const activeVal = value && value.facetKey === openFacet.key ? openFacet.values.find((v) => v.key === value.facetValue) : null;
3743
+ if (activeVal && !head.includes(activeVal)) {
3744
+ return [...head.slice(0, COLLAPSED_VALUE_CAP - 1), activeVal];
3745
+ }
3746
+ return head;
3747
+ })() : [];
3719
3748
  const overflow = facets.length - COLLAPSED_FACET_CAP;
3720
3749
  let visibleFacets = facets;
3721
3750
  if (!allExpanded && overflow > 0) {
@@ -3764,30 +3793,57 @@ function FacetBrowseFilter({
3764
3793
  }
3765
3794
  )
3766
3795
  ] }),
3767
- openFacet && openFacet.values.length > 0 && /* @__PURE__ */ jsx(
3796
+ openFacet && openFacet.values.length > 0 && /* @__PURE__ */ jsxs(
3768
3797
  "div",
3769
3798
  {
3770
3799
  className: "ra-rule-filters-row",
3771
3800
  role: "group",
3772
3801
  "aria-label": `Pick a ${openFacet.label ?? openFacet.key} value`,
3773
- style: { paddingLeft: "0.25rem" },
3774
- children: openFacet.values.map((v) => {
3775
- const active = value?.facetKey === openFacet.key && value?.facetValue === v.key;
3776
- return /* @__PURE__ */ jsx(
3802
+ style: { paddingLeft: "0.25rem", maxHeight: "8.5rem", overflowY: "auto" },
3803
+ children: [
3804
+ openFacet.values.length > VALUE_SEARCH_THRESHOLD && /* @__PURE__ */ jsx(
3805
+ "input",
3806
+ {
3807
+ type: "search",
3808
+ value: openValueSearch,
3809
+ onChange: (e) => setValueSearch((s) => ({ ...s, [openFacet.key]: e.target.value })),
3810
+ placeholder: `Search ${openFacet.label ?? openFacet.key}\u2026`,
3811
+ "aria-label": `Search ${openFacet.label ?? openFacet.key} values`,
3812
+ className: "ra-rule-filter-chip",
3813
+ style: { minWidth: "8rem", writingMode: "horizontal-tb" }
3814
+ }
3815
+ ),
3816
+ visibleValues.map((v) => {
3817
+ const active = value?.facetKey === openFacet.key && value?.facetValue === v.key;
3818
+ return /* @__PURE__ */ jsx(
3819
+ "button",
3820
+ {
3821
+ type: "button",
3822
+ className: "ra-rule-filter-chip",
3823
+ "data-tone": "complexity",
3824
+ "data-active": active ? "true" : "false",
3825
+ "aria-pressed": active,
3826
+ onClick: () => onChange(active ? null : { facetKey: openFacet.key, facetValue: v.key }),
3827
+ title: `Filter to ${openFacet.label ?? openFacet.key} = ${v.label ?? v.key}`,
3828
+ children: /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-label", children: v.label ?? v.key })
3829
+ },
3830
+ v.key
3831
+ );
3832
+ }),
3833
+ valueOverflow > 0 && /* @__PURE__ */ jsx(
3777
3834
  "button",
3778
3835
  {
3779
3836
  type: "button",
3837
+ onClick: () => setValuesExpanded((s) => ({ ...s, [openFacet.key]: !openValuesExpanded })),
3780
3838
  className: "ra-rule-filter-chip",
3781
- "data-tone": "complexity",
3782
- "data-active": active ? "true" : "false",
3783
- "aria-pressed": active,
3784
- onClick: () => onChange(active ? null : { facetKey: openFacet.key, facetValue: v.key }),
3785
- title: `Filter to ${openFacet.label ?? openFacet.key} = ${v.label ?? v.key}`,
3786
- children: /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-label", children: v.label ?? v.key })
3787
- },
3788
- v.key
3789
- );
3790
- })
3839
+ "data-active": "false",
3840
+ "aria-expanded": openValuesExpanded,
3841
+ title: openValuesExpanded ? "Show fewer values" : `Show all ${openValuesFiltered.length} values`,
3842
+ children: /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-chip-label", children: openValuesExpanded ? "Show fewer" : `Show all (${openValuesFiltered.length})` })
3843
+ }
3844
+ ),
3845
+ openValuesFiltered.length === 0 && /* @__PURE__ */ jsx("span", { className: "ra-rule-filter-clear", style: { cursor: "default", textDecoration: "none" }, children: "No values match." })
3846
+ ]
3791
3847
  }
3792
3848
  ),
3793
3849
  value && /* @__PURE__ */ jsx(
@@ -8292,25 +8348,18 @@ function RecordsAdminShellInner(props) {
8292
8348
  [facetBrowseFilter]
8293
8349
  );
8294
8350
  const facetBrowseFacets = useMemo(() => {
8295
- if (!facetBrowse.items.length) return [];
8296
- const byKey = /* @__PURE__ */ new Map();
8297
- for (const it of facetBrowse.items) {
8298
- const key = it.scope.facetId;
8299
- const value = it.scope.facetValue;
8300
- if (!key || !value) continue;
8301
- const facetLabel = it.subtitle ?? key;
8302
- const valueLabel = it.label ?? value;
8303
- const existing = byKey.get(key);
8304
- if (existing) {
8305
- if (!existing.values.some((v) => v.key === value)) {
8306
- existing.values.push({ key: value, label: valueLabel });
8307
- }
8308
- } else {
8309
- byKey.set(key, { key, label: facetLabel, values: [{ key: value, label: valueLabel }] });
8310
- }
8351
+ const vocab = facetBrowse.vocabulary ?? [];
8352
+ if (!vocab.length) return [];
8353
+ const out = [];
8354
+ for (const facet of vocab) {
8355
+ const key = facet.key;
8356
+ if (!key) continue;
8357
+ const values = (facet.values ?? []).filter((v) => !!v.key).map((v) => ({ key: v.key, label: v.name ?? v.key }));
8358
+ if (!values.length) continue;
8359
+ out.push({ key, label: facet.name ?? key, values });
8311
8360
  }
8312
- return Array.from(byKey.values());
8313
- }, [facetBrowse.items]);
8361
+ return out;
8362
+ }, [facetBrowse.vocabulary]);
8314
8363
  const collectionGlobalAllRow = useMemo(
8315
8364
  () => ({
8316
8365
  id: null,