@clyrex-digital/clyrex-controls-dev 0.8.1-dev.20260924103055 → 0.8.1-dev.20260924115534

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -5684,7 +5684,7 @@ var DataBindingControls_exports = {};
5684
5684
  __export(DataBindingControls_exports, {
5685
5685
  default: () => DataBindingControls_default
5686
5686
  });
5687
- var import_react59, import_navigation, import_jsx_runtime86, ACTIVE_QUERY_CONTROLS_EVENT, humanize, escapeODataString, parseFacetSelections, buildFacetFilter, parseODataSearch, SearchIcon, ResetIcon, normalizeSortOption, DataBindingControls, DataBindingControls_default;
5687
+ var import_react59, import_navigation, import_jsx_runtime86, humanize, escapeODataString, parseFacetSelections, buildFacetFilter, parseODataSearch, SearchIcon, ResetIcon, FilterSlidersIcon, ChevronDownIcon, CheckIcon, CloseIcon, normalizeSortOption, DataBindingControls, DataBindingControls_default;
5688
5688
  var init_DataBindingControls = __esm({
5689
5689
  "src/components/pageRenderingEngine/nodes/DataBindingControls.tsx"() {
5690
5690
  "use strict";
@@ -5696,22 +5696,15 @@ var init_DataBindingControls = __esm({
5696
5696
  init_InputControlType();
5697
5697
  init_StyleTypes();
5698
5698
  import_jsx_runtime86 = require("react/jsx-runtime");
5699
- ACTIVE_QUERY_CONTROLS_EVENT = "data-binding-active-query-controls";
5700
5699
  humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
5701
5700
  escapeODataString = (value) => value.replace(/'/g, "''");
5702
5701
  parseFacetSelections = (filter) => {
5703
5702
  const selections = /* @__PURE__ */ new Map();
5704
- const groupedExpression = /\(\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*\)/gi;
5705
- for (const match of filter.matchAll(groupedExpression)) {
5706
- selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
5707
- }
5708
- if (selections.size === 0) {
5709
- const ungroupedExpression = /(?:^|\s+and\s+)\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*(?=\s+and\s+|$)/gi;
5710
- for (const match of filter.matchAll(ungroupedExpression)) {
5711
- selections.set(
5712
- match[1].trim(),
5713
- match[2].replace(/''/g, "'")
5714
- );
5703
+ if (!filter || !filter.trim()) return selections;
5704
+ const expression = /(?:^|[\s()]+(?:and[\s()]+)?)([\w./-]+)\s+eq\s+'((?:''|[^'])*)'/gi;
5705
+ for (const match of filter.matchAll(expression)) {
5706
+ if (match[1] && match[2] !== void 0) {
5707
+ selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
5715
5708
  }
5716
5709
  }
5717
5710
  return selections;
@@ -5762,6 +5755,59 @@ var init_DataBindingControls = __esm({
5762
5755
  ]
5763
5756
  }
5764
5757
  );
5758
+ FilterSlidersIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5759
+ "svg",
5760
+ {
5761
+ "aria-hidden": "true",
5762
+ className,
5763
+ fill: "none",
5764
+ viewBox: "0 0 24 24",
5765
+ stroke: "currentColor",
5766
+ strokeWidth: "2",
5767
+ children: [
5768
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 4h18M3 12h18M3 20h18" }),
5769
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("circle", { cx: "8", cy: "4", r: "2", fill: "currentColor" }),
5770
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("circle", { cx: "16", cy: "12", r: "2", fill: "currentColor" }),
5771
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("circle", { cx: "10", cy: "20", r: "2", fill: "currentColor" })
5772
+ ]
5773
+ }
5774
+ );
5775
+ ChevronDownIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5776
+ "svg",
5777
+ {
5778
+ "aria-hidden": "true",
5779
+ className,
5780
+ fill: "none",
5781
+ viewBox: "0 0 24 24",
5782
+ stroke: "currentColor",
5783
+ strokeWidth: "2",
5784
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m19 9-7 7-7-7" })
5785
+ }
5786
+ );
5787
+ CheckIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5788
+ "svg",
5789
+ {
5790
+ "aria-hidden": "true",
5791
+ className,
5792
+ fill: "none",
5793
+ viewBox: "0 0 24 24",
5794
+ stroke: "currentColor",
5795
+ strokeWidth: "2.5",
5796
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" })
5797
+ }
5798
+ );
5799
+ CloseIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5800
+ "svg",
5801
+ {
5802
+ "aria-hidden": "true",
5803
+ className,
5804
+ fill: "none",
5805
+ viewBox: "0 0 24 24",
5806
+ stroke: "currentColor",
5807
+ strokeWidth: "2",
5808
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
5809
+ }
5810
+ );
5765
5811
  normalizeSortOption = (option) => {
5766
5812
  const direction = option.direction.trim();
5767
5813
  return {
@@ -5780,59 +5826,46 @@ var init_DataBindingControls = __esm({
5780
5826
  mode = "toolbar"
5781
5827
  }) => {
5782
5828
  const router = (0, import_navigation.useRouter)();
5783
- const facetGroups = Object.entries(facets ?? {}).filter(
5784
- ([, values]) => Array.isArray(values) && values.length > 0
5829
+ const searchParams = (0, import_navigation.useSearchParams)();
5830
+ const [collapsedCategories, setCollapsedCategories] = (0, import_react59.useState)({});
5831
+ const toggleCategory = (field) => {
5832
+ setCollapsedCategories((prev) => ({
5833
+ ...prev,
5834
+ [field]: !prev[field]
5835
+ }));
5836
+ };
5837
+ const searchParamsFilter = searchParams?.get("$filter") ?? searchParams?.get("filter");
5838
+ const searchParamsSort = searchParams?.get("$orderby") ?? searchParams?.get("orderBy");
5839
+ const searchParamsSearch = searchParams?.get("$search");
5840
+ const currentFilter = searchParamsFilter !== void 0 && searchParamsFilter !== null ? searchParamsFilter : query?.["$filter"] ?? query?.filter ?? "";
5841
+ const currentSort = searchParamsSort !== void 0 && searchParamsSort !== null ? searchParamsSort : query?.["$orderby"] ?? query?.orderBy ?? "";
5842
+ const currentSearch = parseODataSearch(
5843
+ searchParamsSearch !== void 0 && searchParamsSearch !== null ? searchParamsSearch : query?.["$search"]
5785
5844
  );
5786
- const normalizedSortOptions = (sortOptions ?? []).filter((option) => option?.name && option?.direction).map(normalizeSortOption).filter((option) => option.value);
5787
- const queryFilter = query?.["$filter"] ?? query?.filter ?? "";
5788
- const querySort = query?.["$orderby"] ?? query?.orderBy ?? "";
5789
- const [currentFilter, setCurrentFilter] = (0, import_react59.useState)(queryFilter);
5790
- const [currentSort, setCurrentSort] = (0, import_react59.useState)(querySort);
5791
- const selectedFacetValues = parseFacetSelections(currentFilter);
5792
- const currentSearch = parseODataSearch(query?.["$search"]);
5793
5845
  const [searchText, setSearchText] = (0, import_react59.useState)(currentSearch);
5794
- const lastNavigationUrl = (0, import_react59.useRef)(null);
5795
5846
  (0, import_react59.useEffect)(() => {
5796
5847
  setSearchText(currentSearch);
5797
5848
  }, [currentSearch]);
5798
- (0, import_react59.useEffect)(() => {
5799
- setCurrentFilter(queryFilter);
5800
- }, [queryFilter]);
5801
- (0, import_react59.useEffect)(() => {
5802
- setCurrentSort(querySort);
5803
- }, [querySort]);
5804
- (0, import_react59.useEffect)(() => {
5805
- const syncActiveQueryControls2 = (event) => {
5806
- const { filter, sort } = event.detail;
5807
- if (filter !== void 0) {
5808
- setCurrentFilter(filter);
5809
- }
5810
- if (sort !== void 0) {
5811
- setCurrentSort(sort);
5812
- }
5813
- };
5814
- window.addEventListener(
5815
- ACTIVE_QUERY_CONTROLS_EVENT,
5816
- syncActiveQueryControls2
5817
- );
5818
- return () => window.removeEventListener(
5819
- ACTIVE_QUERY_CONTROLS_EVENT,
5820
- syncActiveQueryControls2
5821
- );
5822
- }, []);
5823
- const syncActiveQueryControls = (0, import_react59.useCallback)(
5824
- (updates) => {
5825
- window.dispatchEvent(
5826
- new CustomEvent(ACTIVE_QUERY_CONTROLS_EVENT, {
5827
- detail: updates
5828
- })
5829
- );
5830
- },
5831
- []
5849
+ const selectedFacetValues = (0, import_react59.useMemo)(
5850
+ () => parseFacetSelections(currentFilter),
5851
+ [currentFilter]
5832
5852
  );
5853
+ const activeFacets = (0, import_react59.useMemo)(() => {
5854
+ if (!facets) return [];
5855
+ return Object.entries(facets).map(([field, values]) => {
5856
+ if (!Array.isArray(values)) return null;
5857
+ const filteredValues = values.filter(
5858
+ (item) => item.count > 0 || selectedFacetValues.get(field) === item.value
5859
+ );
5860
+ if (filteredValues.length === 0) return null;
5861
+ return [field, filteredValues];
5862
+ }).filter((group) => group !== null);
5863
+ }, [facets, selectedFacetValues]);
5864
+ const normalizedSortOptions = (sortOptions ?? []).filter((option) => option?.name && option?.direction).map(normalizeSortOption).filter((option) => option.value);
5833
5865
  const getQueryUrl = (0, import_react59.useCallback)(
5834
5866
  (updates) => {
5835
- const params = new URLSearchParams(query ?? {});
5867
+ const initialParams = searchParams ? searchParams.toString() : "";
5868
+ const params = new URLSearchParams(initialParams || query || {});
5836
5869
  Object.entries(updates).forEach(([key, value]) => {
5837
5870
  if (value) {
5838
5871
  params.set(key, value);
@@ -5847,38 +5880,48 @@ var init_DataBindingControls = __esm({
5847
5880
  ).join("&");
5848
5881
  return queryString ? `${path}?${queryString}` : path;
5849
5882
  },
5850
- [path, query]
5883
+ [path, query, searchParams]
5851
5884
  );
5852
- const getFacetUrl = (field, value) => {
5853
- const updatedSelections = new Map(selectedFacetValues);
5854
- if (value) {
5855
- updatedSelections.set(field, value);
5856
- } else {
5857
- updatedSelections.delete(field);
5858
- }
5859
- const updatedFilter = buildFacetFilter(updatedSelections);
5860
- syncActiveQueryControls({ filter: updatedFilter });
5861
- return getQueryUrl({
5862
- $filter: updatedFilter || void 0,
5863
- filter: void 0
5864
- });
5865
- };
5866
5885
  const navigateWithoutReload = (0, import_react59.useCallback)(
5867
5886
  (url) => {
5868
- if (lastNavigationUrl.current === url) {
5869
- return;
5870
- }
5871
5887
  if (typeof window !== "undefined") {
5872
5888
  const targetUrl = new URL(url, window.location.origin);
5873
5889
  if (targetUrl.pathname === window.location.pathname && targetUrl.search === window.location.search) {
5874
5890
  return;
5875
5891
  }
5876
5892
  }
5877
- lastNavigationUrl.current = url;
5878
5893
  router.push(url, { scroll: false });
5879
5894
  },
5880
5895
  [router]
5881
5896
  );
5897
+ const getFacetUrl = (field, value) => {
5898
+ const updatedSelections = new Map(selectedFacetValues);
5899
+ if (value) {
5900
+ if (updatedSelections.get(field) === value) {
5901
+ updatedSelections.delete(field);
5902
+ } else {
5903
+ updatedSelections.set(field, value);
5904
+ }
5905
+ } else {
5906
+ updatedSelections.delete(field);
5907
+ }
5908
+ const updatedFilter = buildFacetFilter(updatedSelections);
5909
+ return getQueryUrl({
5910
+ $filter: updatedFilter || void 0,
5911
+ filter: void 0
5912
+ });
5913
+ };
5914
+ const clearFacetField = (field) => {
5915
+ const updatedSelections = new Map(selectedFacetValues);
5916
+ updatedSelections.delete(field);
5917
+ const updatedFilter = buildFacetFilter(updatedSelections);
5918
+ navigateWithoutReload(
5919
+ getQueryUrl({
5920
+ $filter: updatedFilter || void 0,
5921
+ filter: void 0
5922
+ })
5923
+ );
5924
+ };
5882
5925
  const handleSearch = (0, import_react59.useCallback)(async () => {
5883
5926
  const trimmedSearchText = searchText.trim();
5884
5927
  if (trimmedSearchText === currentSearch.trim()) {
@@ -5892,7 +5935,6 @@ var init_DataBindingControls = __esm({
5892
5935
  return { isSuccessful: true };
5893
5936
  }, [currentSearch, getQueryUrl, navigateWithoutReload, searchText]);
5894
5937
  const handleClearAll = (0, import_react59.useCallback)(async () => {
5895
- syncActiveQueryControls({ filter: "", sort: "" });
5896
5938
  navigateWithoutReload(
5897
5939
  getQueryUrl({
5898
5940
  $filter: void 0,
@@ -5902,66 +5944,76 @@ var init_DataBindingControls = __esm({
5902
5944
  })
5903
5945
  );
5904
5946
  return { isSuccessful: true };
5905
- }, [getQueryUrl, navigateWithoutReload, syncActiveQueryControls]);
5906
- const hasFacetControls = showFacets && facetGroups.length > 0;
5947
+ }, [getQueryUrl, navigateWithoutReload]);
5948
+ const hasFacetControls = showFacets && activeFacets.length > 0;
5907
5949
  const hasSortControls = showSortOptions && normalizedSortOptions.length > 0;
5908
5950
  const hasActiveFiltersOrSort = Boolean(
5909
5951
  currentFilter.trim() || currentSort.trim()
5910
5952
  );
5953
+ const selectedFacetCount = selectedFacetValues.size;
5911
5954
  const shouldShowToolbarClearAll = hasActiveFiltersOrSort && !hasFacetControls;
5912
5955
  const shouldShowToolbar = mode === "toolbar" && (showSearchBar || hasSortControls || shouldShowToolbarClearAll);
5913
5956
  const shouldShowFacets = mode === "facets" && hasFacetControls;
5914
5957
  if (!shouldShowToolbar && !shouldShowFacets) {
5915
5958
  return null;
5916
5959
  }
5917
- const renderFacetLinks = (field, values, stacked = false) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: stacked ? "flex flex-col gap-0.5" : "flex flex-wrap gap-1.5", children: [
5918
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5960
+ const renderFacetItems = (field, values) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "flex flex-col gap-1 pt-1 pb-1", children: values.map((facet) => {
5961
+ const isSelected = selectedFacetValues.get(field) === facet.value;
5962
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5919
5963
  "button",
5920
5964
  {
5921
5965
  type: "button",
5922
- onClick: () => navigateWithoutReload(getFacetUrl(field)),
5923
- "aria-pressed": !selectedFacetValues.has(field),
5924
- className: `cursor-pointer px-3 py-1.5 text-left text-sm transition-all duration-150 ease-out hover:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${stacked ? "w-full" : "border"} ${selectedFacetValues.has(field) ? "hover:bg-info-soft" : "bg-primary-base font-semibold hover:brightness-95"}`,
5925
- children: "All"
5926
- }
5927
- ),
5928
- values.map((facet) => {
5929
- const isSelected = selectedFacetValues.get(field) === facet.value;
5930
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5931
- "button",
5932
- {
5933
- type: "button",
5934
- onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
5935
- "aria-pressed": isSelected,
5936
- className: `cursor-pointer px-3 py-1.5 text-left text-sm transition-all duration-150 ease-out hover:shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary ${stacked ? "w-full" : "border"} ${isSelected ? "bg-primary-base font-semibold hover:brightness-95" : "hover:bg-info-soft"}`,
5937
- children: [
5938
- facet.value,
5939
- " (",
5940
- facet.count,
5941
- ")"
5942
- ]
5943
- },
5944
- `${field}-${facet.value}`
5945
- );
5946
- })
5947
- ] });
5966
+ onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
5967
+ "aria-pressed": isSelected,
5968
+ className: `group flex w-full cursor-pointer items-center justify-between gap-2.5 rounded-md px-2 py-1.5 text-left text-sm transition-all duration-150 ease-out focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary-base ${isSelected ? "bg-neutral-soft font-medium border " : "hover:bg-neutral-weak border border-transparent"}`,
5969
+ children: [
5970
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex min-w-0 items-center gap-2.5", children: [
5971
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5972
+ "span",
5973
+ {
5974
+ className: `flex h-4 w-4 shrink-0 items-center justify-center rounded-[3px] border transition-colors duration-150 ${isSelected ? "bg-primary-base border-primary-base" : " group-hover:border-neutral-strong bg-default"}`,
5975
+ children: isSelected && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CheckIcon, { className: "h-3 w-3" })
5976
+ }
5977
+ ),
5978
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "leading-snug break-words", children: facet.value })
5979
+ ] }),
5980
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5981
+ "span",
5982
+ {
5983
+ className: `shrink-0 rounded px-1.5 py-0.5 text-xs transition-colors ml-2 ${isSelected ? "bg-neutral-weak font-semibold" : "bg-neutral-weak font-normal"}`,
5984
+ children: facet.count
5985
+ }
5986
+ )
5987
+ ]
5988
+ },
5989
+ `${field}-${facet.value}`
5990
+ );
5991
+ }) });
5948
5992
  return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5949
5993
  "div",
5950
5994
  {
5951
- className: mode === "toolbar" ? "my-6" : "flex flex-col gap-2 border bg-default rounded-[5px] p-3",
5995
+ className: mode === "toolbar" ? "my-6" : "flex flex-col rounded-md border bg-default p-3.5 shadow-sm",
5952
5996
  children: [
5953
5997
  shouldShowToolbar && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
5954
- showSearchBar && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5998
+ showSearchBar && // <form
5999
+ // role="search"
6000
+ // className="flex w-full flex-col gap-3 rounded-md border border-info bg-info-soft p-3 sm:flex-row sm:items-center md:min-w-0 md:flex-1"
6001
+ // onSubmit={(event) => {
6002
+ // event.preventDefault();
6003
+ // void handleSearch();
6004
+ // }}
6005
+ // >
6006
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5955
6007
  "form",
5956
6008
  {
5957
6009
  role: "search",
5958
- className: "flex w-full flex-col gap-3 rounded-xl border border-info bg-info-soft p-3 sm:flex-row sm:items-center md:min-w-0 md:flex-1",
6010
+ className: "flex w-full flex-col gap-3 rounded-md sm:flex-row sm:items-center md:min-w-0 md:flex-1",
5959
6011
  onSubmit: (event) => {
5960
6012
  event.preventDefault();
5961
6013
  void handleSearch();
5962
6014
  },
5963
6015
  children: [
5964
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "relative bg-default rounded-xl min-w-0 flex-1", children: [
6016
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "relative bg-default rounded-md min-w-0 flex-1", children: [
5965
6017
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(SearchIcon, { className: "pointer-events-none absolute left-4 top-1/2 z-10 h-5 w-5 -translate-y-1/2" }),
5966
6018
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5967
6019
  InputControl_default,
@@ -5973,7 +6025,7 @@ var init_DataBindingControls = __esm({
5973
6025
  attributes: {
5974
6026
  placeholder: "Search discussions, topics, or keywords..."
5975
6027
  },
5976
- inputClasses: "!mt-0 !rounded-xl !py-3 !pl-11 !pr-4 !shadow-sm"
6028
+ inputClasses: "!mt-0 !rounded-md !py-3 !pl-11 !pr-4 !shadow-sm"
5977
6029
  }
5978
6030
  )
5979
6031
  ] }),
@@ -5982,7 +6034,7 @@ var init_DataBindingControls = __esm({
5982
6034
  {
5983
6035
  ButtonType: "Primary" /* Solid */,
5984
6036
  onClick: handleSearch,
5985
- className: "!rounded-xl !px-6 !py-3 sm:self-stretch",
6037
+ className: "!rounded-md !px-6 !py-3 sm:self-stretch",
5986
6038
  children: [
5987
6039
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(SearchIcon, { className: "h-5 w-5" }),
5988
6040
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: "Search" })
@@ -5992,7 +6044,7 @@ var init_DataBindingControls = __esm({
5992
6044
  ]
5993
6045
  }
5994
6046
  ),
5995
- hasSortControls && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex w-full items-center gap-3 rounded-2xl border border-info bg-info-soft p-3 text-sm md:ml-auto md:w-auto md:min-w-72 md:self-stretch", children: [
6047
+ hasSortControls && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex w-full items-center gap-3 rounded-md border border-info bg-info-soft p-3 text-sm md:ml-auto md:w-auto md:min-w-72 md:self-stretch", children: [
5996
6048
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5997
6049
  "label",
5998
6050
  {
@@ -6001,7 +6053,7 @@ var init_DataBindingControls = __esm({
6001
6053
  children: "Sort by"
6002
6054
  }
6003
6055
  ),
6004
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "min-w-0 flex-1 rounded-xl bg-default md:min-w-48", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
6056
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "min-w-0 flex-1 rounded-md bg-default md:min-w-48", children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
6005
6057
  InputControl_default,
6006
6058
  {
6007
6059
  name: "sortOptions",
@@ -6012,7 +6064,6 @@ var init_DataBindingControls = __esm({
6012
6064
  dataTextFieldName: "label",
6013
6065
  callback: (updatedValues) => {
6014
6066
  const updatedSort = updatedValues.value || "";
6015
- syncActiveQueryControls({ sort: updatedSort });
6016
6067
  navigateWithoutReload(
6017
6068
  getQueryUrl({
6018
6069
  $orderby: updatedSort || void 0,
@@ -6021,32 +6072,81 @@ var init_DataBindingControls = __esm({
6021
6072
  );
6022
6073
  },
6023
6074
  attributes: { placeholder: "Default" },
6024
- inputClasses: "!mt-0 !rounded-xl !border-info !bg-default !px-4 !py-3 !text-body !shadow-sm focus:!border-primary focus:!ring-primary-base"
6075
+ inputClasses: "!mt-0 !rounded-md !border-info !bg-default !px-4 !py-3 !shadow-sm focus:!border-primary focus:!ring-primary-base"
6025
6076
  }
6026
6077
  ) })
6027
6078
  ] })
6028
6079
  ] }),
6029
- shouldShowFacets && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex items-center justify-between gap-2 border-b pb-2", children: [
6030
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-lg font-semibold", children: "Filters" }),
6031
- hasActiveFiltersOrSort && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6080
+ shouldShowFacets && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex flex-col gap-3", children: [
6081
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex items-center justify-between border-b pb-3", children: [
6082
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex items-center gap-2", children: [
6083
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(FilterSlidersIcon, { className: "h-4 w-4" }),
6084
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-base font-semibold tracking-tight", children: "Filters" }),
6085
+ selectedFacetCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "flex h-5 items-center justify-center rounded-full bg-primary-base px-2 text-xs font-semibold", children: selectedFacetCount })
6086
+ ] }),
6087
+ hasActiveFiltersOrSort && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6088
+ "button",
6089
+ {
6090
+ type: "button",
6091
+ onClick: () => void handleClearAll(),
6092
+ className: "group inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium transition-colors duration-150 hover:bg-neutral-soft focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary-base",
6093
+ "aria-label": "Clear all filters and sorting",
6094
+ children: [
6095
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(ResetIcon, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:-rotate-45" }),
6096
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: "Clear all" })
6097
+ ]
6098
+ }
6099
+ )
6100
+ ] }),
6101
+ selectedFacetCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "flex flex-wrap gap-1.5 pb-2.5 border-b ", children: Array.from(selectedFacetValues.entries()).map(([field, value]) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6032
6102
  "button",
6033
6103
  {
6034
6104
  type: "button",
6035
- onClick: () => void handleClearAll(),
6036
- className: "group inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-primary transition-colors duration-150 hover:bg-info-soft hover:text-primary-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
6037
- "aria-label": "Clear all filters and sorting",
6105
+ onClick: () => clearFacetField(field),
6106
+ className: "group inline-flex max-w-full cursor-pointer items-center gap-1.5 rounded-md border bg-neutral-weak px-2.5 py-1 text-xs transition-colors hover:bg-neutral-soft",
6107
+ title: `Remove filter: ${value}`,
6038
6108
  children: [
6039
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(ResetIcon, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:-rotate-45" }),
6040
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: "Clear all" })
6109
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "font-medium truncate max-w-[150px]", children: value }),
6110
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CloseIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-60 group-hover:opacity-100" })
6041
6111
  ]
6042
- }
6043
- )
6044
- ] }),
6045
- shouldShowFacets && facetGroups.length === 1 && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("nav", { "aria-label": `${humanize(facetGroups[0][0])} filters`, children: renderFacetLinks(facetGroups[0][0], facetGroups[0][1]) }),
6046
- shouldShowFacets && facetGroups.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "flex flex-col", children: facetGroups.map(([field, values]) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("details", { className: "border-b py-1 last:border-b-0", open: true, children: [
6047
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("summary", { className: "cursor-pointer rounded-md px-2 py-1.5 font-semibold transition-colors duration-150 hover:bg-info-soft focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary", children: humanize(field) }),
6048
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "px-1 pb-1 pt-0.5", children: renderFacetLinks(field, values, true) })
6049
- ] }, field)) })
6112
+ },
6113
+ `chip-${field}`
6114
+ )) }),
6115
+ activeFacets.length === 1 && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("nav", { "aria-label": `${humanize(activeFacets[0][0])} filters`, children: /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "py-1", children: [
6116
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "px-1 pb-2 font-medium text-sm", children: humanize(activeFacets[0][0]) }),
6117
+ renderFacetItems(activeFacets[0][0], activeFacets[0][1])
6118
+ ] }) }),
6119
+ activeFacets.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "flex flex-col divide-y divide-neutral-soft", children: activeFacets.map(([field, values]) => {
6120
+ const isOpen = !collapsedCategories[field];
6121
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6122
+ "div",
6123
+ {
6124
+ className: "py-2 first:pt-0 last:pb-0",
6125
+ children: [
6126
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6127
+ "button",
6128
+ {
6129
+ type: "button",
6130
+ onClick: () => toggleCategory(field),
6131
+ className: "flex w-full cursor-pointer items-center justify-between rounded-md px-1.5 py-1.5 text-sm font-semibold transition-colors duration-150 hover:bg-neutral-weak focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary-base",
6132
+ children: [
6133
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: humanize(field) }),
6134
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
6135
+ ChevronDownIcon,
6136
+ {
6137
+ className: `h-4 w-4 transition-transform duration-200 ease-out ${isOpen ? "rotate-180" : ""}`
6138
+ }
6139
+ )
6140
+ ]
6141
+ }
6142
+ ),
6143
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "pt-1", children: renderFacetItems(field, values) })
6144
+ ]
6145
+ },
6146
+ field
6147
+ );
6148
+ }) })
6149
+ ] })
6050
6150
  ]
6051
6151
  }
6052
6152
  );
@@ -9389,7 +9489,7 @@ var DivContainer = async (props) => {
9389
9489
  renderedContainer,
9390
9490
  paginationControl
9391
9491
  ] }),
9392
- dataBindingProperties?.showFacets && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("aside", { className: " lg:sticky lg:top-[90px] lg:self-start", children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
9492
+ dataBindingProperties?.showFacets && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("aside", { children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
9393
9493
  DataBindingControls2,
9394
9494
  {
9395
9495
  mode: "facets",
package/dist/server.mjs CHANGED
@@ -2388,7 +2388,7 @@ var GoogleMapNode_default = GoogleMapNode;
2388
2388
  // src/components/pageRenderingEngine/nodes/DivContainer.tsx
2389
2389
  import { jsx as jsx37, jsxs as jsxs15 } from "react/jsx-runtime";
2390
2390
  var Pagination = dynamic13(() => import("./Pagination-V53JCR6P.mjs"), { ssr: true });
2391
- var DataBindingControls = dynamic13(() => import("./DataBindingControls-UDRT7JFF.mjs"), {
2391
+ var DataBindingControls = dynamic13(() => import("./DataBindingControls-G5TRSVEU.mjs"), {
2392
2392
  ssr: true
2393
2393
  });
2394
2394
  var Slider = dynamic13(() => import("./Slider-UNNVADVP.mjs"), {
@@ -2929,7 +2929,7 @@ var DivContainer = async (props) => {
2929
2929
  renderedContainer,
2930
2930
  paginationControl
2931
2931
  ] }),
2932
- dataBindingProperties?.showFacets && /* @__PURE__ */ jsx37("aside", { className: " lg:sticky lg:top-[90px] lg:self-start", children: /* @__PURE__ */ jsx37(
2932
+ dataBindingProperties?.showFacets && /* @__PURE__ */ jsx37("aside", { children: /* @__PURE__ */ jsx37(
2933
2933
  DataBindingControls,
2934
2934
  {
2935
2935
  mode: "facets",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clyrex-digital/clyrex-controls-dev",
3
- "version": "0.8.1-dev.20260924103055",
3
+ "version": "0.8.1-dev.20260924115534",
4
4
  "description": "Reusable React components",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",