@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/index.js CHANGED
@@ -5686,7 +5686,7 @@ var DataBindingControls_exports = {};
5686
5686
  __export(DataBindingControls_exports, {
5687
5687
  default: () => DataBindingControls_default
5688
5688
  });
5689
- var import_react59, import_navigation, import_jsx_runtime86, ACTIVE_QUERY_CONTROLS_EVENT, humanize, escapeODataString, parseFacetSelections, buildFacetFilter, parseODataSearch, SearchIcon, ResetIcon, normalizeSortOption, DataBindingControls, DataBindingControls_default;
5689
+ var import_react59, import_navigation, import_jsx_runtime86, humanize, escapeODataString, parseFacetSelections, buildFacetFilter, parseODataSearch, SearchIcon, ResetIcon, FilterSlidersIcon, ChevronDownIcon, CheckIcon, CloseIcon, normalizeSortOption, DataBindingControls, DataBindingControls_default;
5690
5690
  var init_DataBindingControls = __esm({
5691
5691
  "src/components/pageRenderingEngine/nodes/DataBindingControls.tsx"() {
5692
5692
  "use strict";
@@ -5698,22 +5698,15 @@ var init_DataBindingControls = __esm({
5698
5698
  init_InputControlType();
5699
5699
  init_StyleTypes();
5700
5700
  import_jsx_runtime86 = require("react/jsx-runtime");
5701
- ACTIVE_QUERY_CONTROLS_EVENT = "data-binding-active-query-controls";
5702
5701
  humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
5703
5702
  escapeODataString = (value) => value.replace(/'/g, "''");
5704
5703
  parseFacetSelections = (filter) => {
5705
5704
  const selections = /* @__PURE__ */ new Map();
5706
- const groupedExpression = /\(\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*\)/gi;
5707
- for (const match of filter.matchAll(groupedExpression)) {
5708
- selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
5709
- }
5710
- if (selections.size === 0) {
5711
- const ungroupedExpression = /(?:^|\s+and\s+)\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*(?=\s+and\s+|$)/gi;
5712
- for (const match of filter.matchAll(ungroupedExpression)) {
5713
- selections.set(
5714
- match[1].trim(),
5715
- match[2].replace(/''/g, "'")
5716
- );
5705
+ if (!filter || !filter.trim()) return selections;
5706
+ const expression = /(?:^|[\s()]+(?:and[\s()]+)?)([\w./-]+)\s+eq\s+'((?:''|[^'])*)'/gi;
5707
+ for (const match of filter.matchAll(expression)) {
5708
+ if (match[1] && match[2] !== void 0) {
5709
+ selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
5717
5710
  }
5718
5711
  }
5719
5712
  return selections;
@@ -5764,6 +5757,59 @@ var init_DataBindingControls = __esm({
5764
5757
  ]
5765
5758
  }
5766
5759
  );
5760
+ FilterSlidersIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5761
+ "svg",
5762
+ {
5763
+ "aria-hidden": "true",
5764
+ className,
5765
+ fill: "none",
5766
+ viewBox: "0 0 24 24",
5767
+ stroke: "currentColor",
5768
+ strokeWidth: "2",
5769
+ children: [
5770
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 4h18M3 12h18M3 20h18" }),
5771
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("circle", { cx: "8", cy: "4", r: "2", fill: "currentColor" }),
5772
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("circle", { cx: "16", cy: "12", r: "2", fill: "currentColor" }),
5773
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("circle", { cx: "10", cy: "20", r: "2", fill: "currentColor" })
5774
+ ]
5775
+ }
5776
+ );
5777
+ ChevronDownIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5778
+ "svg",
5779
+ {
5780
+ "aria-hidden": "true",
5781
+ className,
5782
+ fill: "none",
5783
+ viewBox: "0 0 24 24",
5784
+ stroke: "currentColor",
5785
+ strokeWidth: "2",
5786
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m19 9-7 7-7-7" })
5787
+ }
5788
+ );
5789
+ CheckIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5790
+ "svg",
5791
+ {
5792
+ "aria-hidden": "true",
5793
+ className,
5794
+ fill: "none",
5795
+ viewBox: "0 0 24 24",
5796
+ stroke: "currentColor",
5797
+ strokeWidth: "2.5",
5798
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" })
5799
+ }
5800
+ );
5801
+ CloseIcon = ({ className = "" }) => /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5802
+ "svg",
5803
+ {
5804
+ "aria-hidden": "true",
5805
+ className,
5806
+ fill: "none",
5807
+ viewBox: "0 0 24 24",
5808
+ stroke: "currentColor",
5809
+ strokeWidth: "2",
5810
+ children: /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
5811
+ }
5812
+ );
5767
5813
  normalizeSortOption = (option) => {
5768
5814
  const direction = option.direction.trim();
5769
5815
  return {
@@ -5782,59 +5828,46 @@ var init_DataBindingControls = __esm({
5782
5828
  mode = "toolbar"
5783
5829
  }) => {
5784
5830
  const router = (0, import_navigation.useRouter)();
5785
- const facetGroups = Object.entries(facets ?? {}).filter(
5786
- ([, values]) => Array.isArray(values) && values.length > 0
5831
+ const searchParams = (0, import_navigation.useSearchParams)();
5832
+ const [collapsedCategories, setCollapsedCategories] = (0, import_react59.useState)({});
5833
+ const toggleCategory = (field) => {
5834
+ setCollapsedCategories((prev) => ({
5835
+ ...prev,
5836
+ [field]: !prev[field]
5837
+ }));
5838
+ };
5839
+ const searchParamsFilter = searchParams?.get("$filter") ?? searchParams?.get("filter");
5840
+ const searchParamsSort = searchParams?.get("$orderby") ?? searchParams?.get("orderBy");
5841
+ const searchParamsSearch = searchParams?.get("$search");
5842
+ const currentFilter = searchParamsFilter !== void 0 && searchParamsFilter !== null ? searchParamsFilter : query?.["$filter"] ?? query?.filter ?? "";
5843
+ const currentSort = searchParamsSort !== void 0 && searchParamsSort !== null ? searchParamsSort : query?.["$orderby"] ?? query?.orderBy ?? "";
5844
+ const currentSearch = parseODataSearch(
5845
+ searchParamsSearch !== void 0 && searchParamsSearch !== null ? searchParamsSearch : query?.["$search"]
5787
5846
  );
5788
- const normalizedSortOptions = (sortOptions ?? []).filter((option) => option?.name && option?.direction).map(normalizeSortOption).filter((option) => option.value);
5789
- const queryFilter = query?.["$filter"] ?? query?.filter ?? "";
5790
- const querySort = query?.["$orderby"] ?? query?.orderBy ?? "";
5791
- const [currentFilter, setCurrentFilter] = (0, import_react59.useState)(queryFilter);
5792
- const [currentSort, setCurrentSort] = (0, import_react59.useState)(querySort);
5793
- const selectedFacetValues = parseFacetSelections(currentFilter);
5794
- const currentSearch = parseODataSearch(query?.["$search"]);
5795
5847
  const [searchText, setSearchText] = (0, import_react59.useState)(currentSearch);
5796
- const lastNavigationUrl = (0, import_react59.useRef)(null);
5797
5848
  (0, import_react59.useEffect)(() => {
5798
5849
  setSearchText(currentSearch);
5799
5850
  }, [currentSearch]);
5800
- (0, import_react59.useEffect)(() => {
5801
- setCurrentFilter(queryFilter);
5802
- }, [queryFilter]);
5803
- (0, import_react59.useEffect)(() => {
5804
- setCurrentSort(querySort);
5805
- }, [querySort]);
5806
- (0, import_react59.useEffect)(() => {
5807
- const syncActiveQueryControls2 = (event) => {
5808
- const { filter, sort } = event.detail;
5809
- if (filter !== void 0) {
5810
- setCurrentFilter(filter);
5811
- }
5812
- if (sort !== void 0) {
5813
- setCurrentSort(sort);
5814
- }
5815
- };
5816
- window.addEventListener(
5817
- ACTIVE_QUERY_CONTROLS_EVENT,
5818
- syncActiveQueryControls2
5819
- );
5820
- return () => window.removeEventListener(
5821
- ACTIVE_QUERY_CONTROLS_EVENT,
5822
- syncActiveQueryControls2
5823
- );
5824
- }, []);
5825
- const syncActiveQueryControls = (0, import_react59.useCallback)(
5826
- (updates) => {
5827
- window.dispatchEvent(
5828
- new CustomEvent(ACTIVE_QUERY_CONTROLS_EVENT, {
5829
- detail: updates
5830
- })
5831
- );
5832
- },
5833
- []
5851
+ const selectedFacetValues = (0, import_react59.useMemo)(
5852
+ () => parseFacetSelections(currentFilter),
5853
+ [currentFilter]
5834
5854
  );
5855
+ const activeFacets = (0, import_react59.useMemo)(() => {
5856
+ if (!facets) return [];
5857
+ return Object.entries(facets).map(([field, values]) => {
5858
+ if (!Array.isArray(values)) return null;
5859
+ const filteredValues = values.filter(
5860
+ (item) => item.count > 0 || selectedFacetValues.get(field) === item.value
5861
+ );
5862
+ if (filteredValues.length === 0) return null;
5863
+ return [field, filteredValues];
5864
+ }).filter((group) => group !== null);
5865
+ }, [facets, selectedFacetValues]);
5866
+ const normalizedSortOptions = (sortOptions ?? []).filter((option) => option?.name && option?.direction).map(normalizeSortOption).filter((option) => option.value);
5835
5867
  const getQueryUrl = (0, import_react59.useCallback)(
5836
5868
  (updates) => {
5837
- const params = new URLSearchParams(query ?? {});
5869
+ const initialParams = searchParams ? searchParams.toString() : "";
5870
+ const params = new URLSearchParams(initialParams || query || {});
5838
5871
  Object.entries(updates).forEach(([key, value]) => {
5839
5872
  if (value) {
5840
5873
  params.set(key, value);
@@ -5849,38 +5882,48 @@ var init_DataBindingControls = __esm({
5849
5882
  ).join("&");
5850
5883
  return queryString ? `${path}?${queryString}` : path;
5851
5884
  },
5852
- [path, query]
5885
+ [path, query, searchParams]
5853
5886
  );
5854
- const getFacetUrl = (field, value) => {
5855
- const updatedSelections = new Map(selectedFacetValues);
5856
- if (value) {
5857
- updatedSelections.set(field, value);
5858
- } else {
5859
- updatedSelections.delete(field);
5860
- }
5861
- const updatedFilter = buildFacetFilter(updatedSelections);
5862
- syncActiveQueryControls({ filter: updatedFilter });
5863
- return getQueryUrl({
5864
- $filter: updatedFilter || void 0,
5865
- filter: void 0
5866
- });
5867
- };
5868
5887
  const navigateWithoutReload = (0, import_react59.useCallback)(
5869
5888
  (url) => {
5870
- if (lastNavigationUrl.current === url) {
5871
- return;
5872
- }
5873
5889
  if (typeof window !== "undefined") {
5874
5890
  const targetUrl = new URL(url, window.location.origin);
5875
5891
  if (targetUrl.pathname === window.location.pathname && targetUrl.search === window.location.search) {
5876
5892
  return;
5877
5893
  }
5878
5894
  }
5879
- lastNavigationUrl.current = url;
5880
5895
  router.push(url, { scroll: false });
5881
5896
  },
5882
5897
  [router]
5883
5898
  );
5899
+ const getFacetUrl = (field, value) => {
5900
+ const updatedSelections = new Map(selectedFacetValues);
5901
+ if (value) {
5902
+ if (updatedSelections.get(field) === value) {
5903
+ updatedSelections.delete(field);
5904
+ } else {
5905
+ updatedSelections.set(field, value);
5906
+ }
5907
+ } else {
5908
+ updatedSelections.delete(field);
5909
+ }
5910
+ const updatedFilter = buildFacetFilter(updatedSelections);
5911
+ return getQueryUrl({
5912
+ $filter: updatedFilter || void 0,
5913
+ filter: void 0
5914
+ });
5915
+ };
5916
+ const clearFacetField = (field) => {
5917
+ const updatedSelections = new Map(selectedFacetValues);
5918
+ updatedSelections.delete(field);
5919
+ const updatedFilter = buildFacetFilter(updatedSelections);
5920
+ navigateWithoutReload(
5921
+ getQueryUrl({
5922
+ $filter: updatedFilter || void 0,
5923
+ filter: void 0
5924
+ })
5925
+ );
5926
+ };
5884
5927
  const handleSearch = (0, import_react59.useCallback)(async () => {
5885
5928
  const trimmedSearchText = searchText.trim();
5886
5929
  if (trimmedSearchText === currentSearch.trim()) {
@@ -5894,7 +5937,6 @@ var init_DataBindingControls = __esm({
5894
5937
  return { isSuccessful: true };
5895
5938
  }, [currentSearch, getQueryUrl, navigateWithoutReload, searchText]);
5896
5939
  const handleClearAll = (0, import_react59.useCallback)(async () => {
5897
- syncActiveQueryControls({ filter: "", sort: "" });
5898
5940
  navigateWithoutReload(
5899
5941
  getQueryUrl({
5900
5942
  $filter: void 0,
@@ -5904,66 +5946,76 @@ var init_DataBindingControls = __esm({
5904
5946
  })
5905
5947
  );
5906
5948
  return { isSuccessful: true };
5907
- }, [getQueryUrl, navigateWithoutReload, syncActiveQueryControls]);
5908
- const hasFacetControls = showFacets && facetGroups.length > 0;
5949
+ }, [getQueryUrl, navigateWithoutReload]);
5950
+ const hasFacetControls = showFacets && activeFacets.length > 0;
5909
5951
  const hasSortControls = showSortOptions && normalizedSortOptions.length > 0;
5910
5952
  const hasActiveFiltersOrSort = Boolean(
5911
5953
  currentFilter.trim() || currentSort.trim()
5912
5954
  );
5955
+ const selectedFacetCount = selectedFacetValues.size;
5913
5956
  const shouldShowToolbarClearAll = hasActiveFiltersOrSort && !hasFacetControls;
5914
5957
  const shouldShowToolbar = mode === "toolbar" && (showSearchBar || hasSortControls || shouldShowToolbarClearAll);
5915
5958
  const shouldShowFacets = mode === "facets" && hasFacetControls;
5916
5959
  if (!shouldShowToolbar && !shouldShowFacets) {
5917
5960
  return null;
5918
5961
  }
5919
- 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: [
5920
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5962
+ 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) => {
5963
+ const isSelected = selectedFacetValues.get(field) === facet.value;
5964
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5921
5965
  "button",
5922
5966
  {
5923
5967
  type: "button",
5924
- onClick: () => navigateWithoutReload(getFacetUrl(field)),
5925
- "aria-pressed": !selectedFacetValues.has(field),
5926
- 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"}`,
5927
- children: "All"
5928
- }
5929
- ),
5930
- values.map((facet) => {
5931
- const isSelected = selectedFacetValues.get(field) === facet.value;
5932
- return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5933
- "button",
5934
- {
5935
- type: "button",
5936
- onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
5937
- "aria-pressed": isSelected,
5938
- 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"}`,
5939
- children: [
5940
- facet.value,
5941
- " (",
5942
- facet.count,
5943
- ")"
5944
- ]
5945
- },
5946
- `${field}-${facet.value}`
5947
- );
5948
- })
5949
- ] });
5968
+ onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
5969
+ "aria-pressed": isSelected,
5970
+ 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"}`,
5971
+ children: [
5972
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex min-w-0 items-center gap-2.5", children: [
5973
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5974
+ "span",
5975
+ {
5976
+ 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"}`,
5977
+ children: isSelected && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CheckIcon, { className: "h-3 w-3" })
5978
+ }
5979
+ ),
5980
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "leading-snug break-words", children: facet.value })
5981
+ ] }),
5982
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5983
+ "span",
5984
+ {
5985
+ 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"}`,
5986
+ children: facet.count
5987
+ }
5988
+ )
5989
+ ]
5990
+ },
5991
+ `${field}-${facet.value}`
5992
+ );
5993
+ }) });
5950
5994
  return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5951
5995
  "div",
5952
5996
  {
5953
- className: mode === "toolbar" ? "my-6" : "flex flex-col gap-2 border bg-default rounded-[5px] p-3",
5997
+ className: mode === "toolbar" ? "my-6" : "flex flex-col rounded-md border bg-default p-3.5 shadow-sm",
5954
5998
  children: [
5955
5999
  shouldShowToolbar && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
5956
- showSearchBar && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6000
+ showSearchBar && // <form
6001
+ // role="search"
6002
+ // 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"
6003
+ // onSubmit={(event) => {
6004
+ // event.preventDefault();
6005
+ // void handleSearch();
6006
+ // }}
6007
+ // >
6008
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
5957
6009
  "form",
5958
6010
  {
5959
6011
  role: "search",
5960
- 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",
6012
+ className: "flex w-full flex-col gap-3 rounded-md sm:flex-row sm:items-center md:min-w-0 md:flex-1",
5961
6013
  onSubmit: (event) => {
5962
6014
  event.preventDefault();
5963
6015
  void handleSearch();
5964
6016
  },
5965
6017
  children: [
5966
- /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "relative bg-default rounded-xl min-w-0 flex-1", children: [
6018
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "relative bg-default rounded-md min-w-0 flex-1", children: [
5967
6019
  /* @__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" }),
5968
6020
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5969
6021
  InputControl_default,
@@ -5975,7 +6027,7 @@ var init_DataBindingControls = __esm({
5975
6027
  attributes: {
5976
6028
  placeholder: "Search discussions, topics, or keywords..."
5977
6029
  },
5978
- inputClasses: "!mt-0 !rounded-xl !py-3 !pl-11 !pr-4 !shadow-sm"
6030
+ inputClasses: "!mt-0 !rounded-md !py-3 !pl-11 !pr-4 !shadow-sm"
5979
6031
  }
5980
6032
  )
5981
6033
  ] }),
@@ -5984,7 +6036,7 @@ var init_DataBindingControls = __esm({
5984
6036
  {
5985
6037
  ButtonType: "Primary" /* Solid */,
5986
6038
  onClick: handleSearch,
5987
- className: "!rounded-xl !px-6 !py-3 sm:self-stretch",
6039
+ className: "!rounded-md !px-6 !py-3 sm:self-stretch",
5988
6040
  children: [
5989
6041
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(SearchIcon, { className: "h-5 w-5" }),
5990
6042
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: "Search" })
@@ -5994,7 +6046,7 @@ var init_DataBindingControls = __esm({
5994
6046
  ]
5995
6047
  }
5996
6048
  ),
5997
- 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: [
6049
+ 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: [
5998
6050
  /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
5999
6051
  "label",
6000
6052
  {
@@ -6003,7 +6055,7 @@ var init_DataBindingControls = __esm({
6003
6055
  children: "Sort by"
6004
6056
  }
6005
6057
  ),
6006
- /* @__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)(
6058
+ /* @__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)(
6007
6059
  InputControl_default,
6008
6060
  {
6009
6061
  name: "sortOptions",
@@ -6014,7 +6066,6 @@ var init_DataBindingControls = __esm({
6014
6066
  dataTextFieldName: "label",
6015
6067
  callback: (updatedValues) => {
6016
6068
  const updatedSort = updatedValues.value || "";
6017
- syncActiveQueryControls({ sort: updatedSort });
6018
6069
  navigateWithoutReload(
6019
6070
  getQueryUrl({
6020
6071
  $orderby: updatedSort || void 0,
@@ -6023,32 +6074,81 @@ var init_DataBindingControls = __esm({
6023
6074
  );
6024
6075
  },
6025
6076
  attributes: { placeholder: "Default" },
6026
- inputClasses: "!mt-0 !rounded-xl !border-info !bg-default !px-4 !py-3 !text-body !shadow-sm focus:!border-primary focus:!ring-primary-base"
6077
+ inputClasses: "!mt-0 !rounded-md !border-info !bg-default !px-4 !py-3 !shadow-sm focus:!border-primary focus:!ring-primary-base"
6027
6078
  }
6028
6079
  ) })
6029
6080
  ] })
6030
6081
  ] }),
6031
- shouldShowFacets && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex items-center justify-between gap-2 border-b pb-2", children: [
6032
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-lg font-semibold", children: "Filters" }),
6033
- hasActiveFiltersOrSort && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6082
+ shouldShowFacets && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex flex-col gap-3", children: [
6083
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex items-center justify-between border-b pb-3", children: [
6084
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)("div", { className: "flex items-center gap-2", children: [
6085
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(FilterSlidersIcon, { className: "h-4 w-4" }),
6086
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("h2", { className: "text-base font-semibold tracking-tight", children: "Filters" }),
6087
+ 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 })
6088
+ ] }),
6089
+ hasActiveFiltersOrSort && /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6090
+ "button",
6091
+ {
6092
+ type: "button",
6093
+ onClick: () => void handleClearAll(),
6094
+ 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",
6095
+ "aria-label": "Clear all filters and sorting",
6096
+ children: [
6097
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(ResetIcon, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:-rotate-45" }),
6098
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: "Clear all" })
6099
+ ]
6100
+ }
6101
+ )
6102
+ ] }),
6103
+ 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)(
6034
6104
  "button",
6035
6105
  {
6036
6106
  type: "button",
6037
- onClick: () => void handleClearAll(),
6038
- 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",
6039
- "aria-label": "Clear all filters and sorting",
6107
+ onClick: () => clearFacetField(field),
6108
+ 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",
6109
+ title: `Remove filter: ${value}`,
6040
6110
  children: [
6041
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(ResetIcon, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:-rotate-45" }),
6042
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: "Clear all" })
6111
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { className: "font-medium truncate max-w-[150px]", children: value }),
6112
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(CloseIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-60 group-hover:opacity-100" })
6043
6113
  ]
6044
- }
6045
- )
6046
- ] }),
6047
- 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]) }),
6048
- 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: [
6049
- /* @__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) }),
6050
- /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "px-1 pb-1 pt-0.5", children: renderFacetLinks(field, values, true) })
6051
- ] }, field)) })
6114
+ },
6115
+ `chip-${field}`
6116
+ )) }),
6117
+ 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: [
6118
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "px-1 pb-2 font-medium text-sm", children: humanize(activeFacets[0][0]) }),
6119
+ renderFacetItems(activeFacets[0][0], activeFacets[0][1])
6120
+ ] }) }),
6121
+ activeFacets.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "flex flex-col divide-y divide-neutral-soft", children: activeFacets.map(([field, values]) => {
6122
+ const isOpen = !collapsedCategories[field];
6123
+ return /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6124
+ "div",
6125
+ {
6126
+ className: "py-2 first:pt-0 last:pb-0",
6127
+ children: [
6128
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsxs)(
6129
+ "button",
6130
+ {
6131
+ type: "button",
6132
+ onClick: () => toggleCategory(field),
6133
+ 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",
6134
+ children: [
6135
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("span", { children: humanize(field) }),
6136
+ /* @__PURE__ */ (0, import_jsx_runtime86.jsx)(
6137
+ ChevronDownIcon,
6138
+ {
6139
+ className: `h-4 w-4 transition-transform duration-200 ease-out ${isOpen ? "rotate-180" : ""}`
6140
+ }
6141
+ )
6142
+ ]
6143
+ }
6144
+ ),
6145
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime86.jsx)("div", { className: "pt-1", children: renderFacetItems(field, values) })
6146
+ ]
6147
+ },
6148
+ field
6149
+ );
6150
+ }) })
6151
+ ] })
6052
6152
  ]
6053
6153
  }
6054
6154
  );
@@ -6098,6 +6198,7 @@ var init_Slider = __esm({
6098
6198
  const [isPlaying, setIsPlaying] = (0, import_react60.useState)(autoplay);
6099
6199
  const trackRef = (0, import_react60.useRef)(null);
6100
6200
  console.log("trackRef:", trackRef);
6201
+ const [videoProgress, setVideoProgress] = (0, import_react60.useState)(null);
6101
6202
  (0, import_react60.useEffect)(() => {
6102
6203
  if (typeof initialSlidesToShow === "number") {
6103
6204
  setSlidesToShowState(initialSlidesToShow);
@@ -6122,28 +6223,36 @@ var init_Slider = __esm({
6122
6223
  const videoElement = activeSlideElement?.querySelector("video");
6123
6224
  if (videoElement) {
6124
6225
  videoElement.loop = false;
6226
+ setVideoProgress(0);
6125
6227
  if (videoElement.ended) {
6126
6228
  videoElement.currentTime = 0;
6127
6229
  }
6128
6230
  videoElement.play().catch(() => {
6129
6231
  });
6130
6232
  const handleTimeUpdate = () => {
6131
- if (videoElement.duration && !isNaN(videoElement.duration)) {
6233
+ if (videoElement.duration && !isNaN(videoElement.duration) && videoElement.duration > 0) {
6132
6234
  const pct = videoElement.currentTime / videoElement.duration * 100;
6235
+ setVideoProgress(pct);
6133
6236
  }
6134
6237
  };
6135
6238
  const handleVideoEnded = () => {
6239
+ setVideoProgress(100);
6136
6240
  nextSlide();
6137
6241
  };
6138
6242
  const handleVideoError = () => {
6139
6243
  nextSlide();
6140
6244
  };
6245
+ videoElement.addEventListener("timeupdate", handleTimeUpdate);
6246
+ videoElement.addEventListener("loadedmetadata", handleTimeUpdate);
6141
6247
  videoElement.addEventListener("ended", handleVideoEnded, { once: true });
6142
6248
  videoElement.addEventListener("error", handleVideoError, { once: true });
6143
6249
  return () => {
6250
+ videoElement.removeEventListener("timeupdate", handleTimeUpdate);
6251
+ videoElement.removeEventListener("loadedmetadata", handleTimeUpdate);
6144
6252
  videoElement.removeEventListener("ended", handleVideoEnded);
6145
6253
  videoElement.removeEventListener("error", handleVideoError);
6146
6254
  videoElement.pause();
6255
+ setVideoProgress(null);
6147
6256
  };
6148
6257
  }
6149
6258
  const timer = setInterval(() => {
@@ -6242,7 +6351,8 @@ var init_Slider = __esm({
6242
6351
  activeClassName: dotActiveClassName,
6243
6352
  inactiveClassName: dotInactiveClassName,
6244
6353
  currentSlide,
6245
- totalSlides
6354
+ totalSlides,
6355
+ customProgress: index === currentSlide ? videoProgress : null
6246
6356
  },
6247
6357
  index
6248
6358
  )) }),
@@ -6302,7 +6412,8 @@ var init_Slider = __esm({
6302
6412
  activeClassName: dotActiveClassName,
6303
6413
  inactiveClassName: dotInactiveClassName,
6304
6414
  currentSlide,
6305
- totalSlides
6415
+ totalSlides,
6416
+ customProgress: index === currentSlide ? videoProgress : null
6306
6417
  },
6307
6418
  index
6308
6419
  )) })
@@ -6338,7 +6449,8 @@ var init_Slider = __esm({
6338
6449
  activeClassName = "",
6339
6450
  inactiveClassName = "",
6340
6451
  currentSlide,
6341
- totalSlides
6452
+ totalSlides,
6453
+ customProgress = null
6342
6454
  }) => {
6343
6455
  const [progress, setProgress] = (0, import_react60.useState)(0);
6344
6456
  (0, import_react60.useEffect)(() => {
@@ -6347,7 +6459,7 @@ var init_Slider = __esm({
6347
6459
  }
6348
6460
  }, [active, index]);
6349
6461
  (0, import_react60.useEffect)(() => {
6350
- if (!active || !isPlaying) {
6462
+ if (!active || !isPlaying || customProgress !== null) {
6351
6463
  if (!active) {
6352
6464
  setProgress(0);
6353
6465
  }
@@ -6365,7 +6477,7 @@ var init_Slider = __esm({
6365
6477
  }
6366
6478
  }, 50);
6367
6479
  return () => clearInterval(interval);
6368
- }, [active, isPlaying, duration, index]);
6480
+ }, [active, isPlaying, duration, index, customProgress]);
6369
6481
  const isFilled = index < currentSlide;
6370
6482
  const isActive = index === currentSlide;
6371
6483
  const shouldShowProgress = isActive || style === "cumulative" && isFilled;
@@ -6400,7 +6512,7 @@ var init_Slider = __esm({
6400
6512
  };
6401
6513
  const renderProgressBar = () => {
6402
6514
  if (style === "modern" && isActive || style === "cumulative" && shouldShowProgress) {
6403
- const displayProgress = style === "cumulative" && isFilled ? 100 : progress;
6515
+ const displayProgress = style === "cumulative" && isFilled ? 100 : customProgress !== null && customProgress !== void 0 ? customProgress : progress;
6404
6516
  return /* @__PURE__ */ (0, import_jsx_runtime87.jsx)(
6405
6517
  "div",
6406
6518
  {
@@ -9408,7 +9520,7 @@ var DivContainer = async (props) => {
9408
9520
  renderedContainer,
9409
9521
  paginationControl
9410
9522
  ] }),
9411
- 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)(
9523
+ dataBindingProperties?.showFacets && /* @__PURE__ */ (0, import_jsx_runtime88.jsx)("aside", { children: /* @__PURE__ */ (0, import_jsx_runtime88.jsx)(
9412
9524
  DataBindingControls2,
9413
9525
  {
9414
9526
  mode: "facets",