@clyrex-digital/clyrex-controls-dev 0.8.1-dev.20260924080906 → 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
  );
@@ -6096,6 +6196,7 @@ var init_Slider = __esm({
6096
6196
  const [isPlaying, setIsPlaying] = (0, import_react60.useState)(autoplay);
6097
6197
  const trackRef = (0, import_react60.useRef)(null);
6098
6198
  console.log("trackRef:", trackRef);
6199
+ const [videoProgress, setVideoProgress] = (0, import_react60.useState)(null);
6099
6200
  (0, import_react60.useEffect)(() => {
6100
6201
  if (typeof initialSlidesToShow === "number") {
6101
6202
  setSlidesToShowState(initialSlidesToShow);
@@ -6120,28 +6221,36 @@ var init_Slider = __esm({
6120
6221
  const videoElement = activeSlideElement?.querySelector("video");
6121
6222
  if (videoElement) {
6122
6223
  videoElement.loop = false;
6224
+ setVideoProgress(0);
6123
6225
  if (videoElement.ended) {
6124
6226
  videoElement.currentTime = 0;
6125
6227
  }
6126
6228
  videoElement.play().catch(() => {
6127
6229
  });
6128
6230
  const handleTimeUpdate = () => {
6129
- if (videoElement.duration && !isNaN(videoElement.duration)) {
6231
+ if (videoElement.duration && !isNaN(videoElement.duration) && videoElement.duration > 0) {
6130
6232
  const pct = videoElement.currentTime / videoElement.duration * 100;
6233
+ setVideoProgress(pct);
6131
6234
  }
6132
6235
  };
6133
6236
  const handleVideoEnded = () => {
6237
+ setVideoProgress(100);
6134
6238
  nextSlide();
6135
6239
  };
6136
6240
  const handleVideoError = () => {
6137
6241
  nextSlide();
6138
6242
  };
6243
+ videoElement.addEventListener("timeupdate", handleTimeUpdate);
6244
+ videoElement.addEventListener("loadedmetadata", handleTimeUpdate);
6139
6245
  videoElement.addEventListener("ended", handleVideoEnded, { once: true });
6140
6246
  videoElement.addEventListener("error", handleVideoError, { once: true });
6141
6247
  return () => {
6248
+ videoElement.removeEventListener("timeupdate", handleTimeUpdate);
6249
+ videoElement.removeEventListener("loadedmetadata", handleTimeUpdate);
6142
6250
  videoElement.removeEventListener("ended", handleVideoEnded);
6143
6251
  videoElement.removeEventListener("error", handleVideoError);
6144
6252
  videoElement.pause();
6253
+ setVideoProgress(null);
6145
6254
  };
6146
6255
  }
6147
6256
  const timer = setInterval(() => {
@@ -6240,7 +6349,8 @@ var init_Slider = __esm({
6240
6349
  activeClassName: dotActiveClassName,
6241
6350
  inactiveClassName: dotInactiveClassName,
6242
6351
  currentSlide,
6243
- totalSlides
6352
+ totalSlides,
6353
+ customProgress: index === currentSlide ? videoProgress : null
6244
6354
  },
6245
6355
  index
6246
6356
  )) }),
@@ -6300,7 +6410,8 @@ var init_Slider = __esm({
6300
6410
  activeClassName: dotActiveClassName,
6301
6411
  inactiveClassName: dotInactiveClassName,
6302
6412
  currentSlide,
6303
- totalSlides
6413
+ totalSlides,
6414
+ customProgress: index === currentSlide ? videoProgress : null
6304
6415
  },
6305
6416
  index
6306
6417
  )) })
@@ -6336,7 +6447,8 @@ var init_Slider = __esm({
6336
6447
  activeClassName = "",
6337
6448
  inactiveClassName = "",
6338
6449
  currentSlide,
6339
- totalSlides
6450
+ totalSlides,
6451
+ customProgress = null
6340
6452
  }) => {
6341
6453
  const [progress, setProgress] = (0, import_react60.useState)(0);
6342
6454
  (0, import_react60.useEffect)(() => {
@@ -6345,7 +6457,7 @@ var init_Slider = __esm({
6345
6457
  }
6346
6458
  }, [active, index]);
6347
6459
  (0, import_react60.useEffect)(() => {
6348
- if (!active || !isPlaying) {
6460
+ if (!active || !isPlaying || customProgress !== null) {
6349
6461
  if (!active) {
6350
6462
  setProgress(0);
6351
6463
  }
@@ -6363,7 +6475,7 @@ var init_Slider = __esm({
6363
6475
  }
6364
6476
  }, 50);
6365
6477
  return () => clearInterval(interval);
6366
- }, [active, isPlaying, duration, index]);
6478
+ }, [active, isPlaying, duration, index, customProgress]);
6367
6479
  const isFilled = index < currentSlide;
6368
6480
  const isActive = index === currentSlide;
6369
6481
  const shouldShowProgress = isActive || style === "cumulative" && isFilled;
@@ -6398,7 +6510,7 @@ var init_Slider = __esm({
6398
6510
  };
6399
6511
  const renderProgressBar = () => {
6400
6512
  if (style === "modern" && isActive || style === "cumulative" && shouldShowProgress) {
6401
- const displayProgress = style === "cumulative" && isFilled ? 100 : progress;
6513
+ const displayProgress = style === "cumulative" && isFilled ? 100 : customProgress !== null && customProgress !== void 0 ? customProgress : progress;
6402
6514
  return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
6403
6515
  "div",
6404
6516
  {
@@ -9377,7 +9489,7 @@ var DivContainer = async (props) => {
9377
9489
  renderedContainer,
9378
9490
  paginationControl
9379
9491
  ] }),
9380
- 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)(
9381
9493
  DataBindingControls2,
9382
9494
  {
9383
9495
  mode: "facets",