@clyrex-digital/clyrex-controls-dev 0.8.1-dev.20260824072352 → 0.8.1-dev.20260824103828

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.
@@ -18,6 +18,36 @@ var InputControl_default = InputControl;
18
18
  import { jsx, jsxs } from "react/jsx-runtime";
19
19
  var humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
20
20
  var escapeODataString = (value) => value.replace(/'/g, "''");
21
+ var parseFacetSelections = (filter) => {
22
+ const selections = /* @__PURE__ */ new Map();
23
+ const groupedExpression = /\(\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*\)/gi;
24
+ for (const match of filter.matchAll(groupedExpression)) {
25
+ selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
26
+ }
27
+ if (selections.size === 0) {
28
+ const singleExpression = filter.match(
29
+ /^\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*$/i
30
+ );
31
+ if (singleExpression) {
32
+ selections.set(
33
+ singleExpression[1].trim(),
34
+ singleExpression[2].replace(/''/g, "'")
35
+ );
36
+ }
37
+ }
38
+ return selections;
39
+ };
40
+ var buildFacetFilter = (selections) => Array.from(selections.entries()).map(
41
+ ([field, value]) => `(${field} eq '${escapeODataString(value)}')`
42
+ ).join(" and ");
43
+ var parseODataSearch = (value) => {
44
+ if (!value) return "";
45
+ const trimmedValue = value.trim();
46
+ if (trimmedValue.startsWith("'") && trimmedValue.endsWith("'")) {
47
+ return trimmedValue.slice(1, -1).replace(/''/g, "'");
48
+ }
49
+ return trimmedValue;
50
+ };
21
51
  var normalizeSortOption = (option) => {
22
52
  const direction = option.direction.trim();
23
53
  return {
@@ -63,8 +93,9 @@ var DataBindingControls = ({
63
93
  const resolvedSortOptions = apiSortOptions.length > 0 ? apiSortOptions : DUMMY_SORT_OPTIONS;
64
94
  const normalizedSortOptions = resolvedSortOptions.map(normalizeSortOption).filter((option) => option.value);
65
95
  const currentFilter = query?.["$filter"] ?? query?.filter ?? "";
96
+ const selectedFacetValues = parseFacetSelections(currentFilter);
66
97
  const currentSort = query?.["$orderby"] ?? query?.orderBy ?? "";
67
- const currentSearch = query?.searchTerm ?? query?.searchText ?? "";
98
+ const currentSearch = parseODataSearch(query?.["$Search"]);
68
99
  const [searchText, setSearchText] = useState(currentSearch);
69
100
  const lastNavigationUrl = useRef(null);
70
101
  useEffect(() => {
@@ -82,15 +113,24 @@ var DataBindingControls = ({
82
113
  });
83
114
  params.delete("$skip");
84
115
  params.delete("skip");
85
- const queryString = params.toString();
116
+ const queryString = Array.from(params.entries()).map(([key, value]) => `${key}=${value}`).join("&");
86
117
  return queryString ? `${path}?${queryString}` : path;
87
118
  },
88
119
  [path, query]
89
120
  );
90
- const getFacetUrl = (field, value) => getQueryUrl({
91
- $filter: value ? `${field} eq '${escapeODataString(value)}'` : void 0,
92
- filter: void 0
93
- });
121
+ const getFacetUrl = (field, value) => {
122
+ const updatedSelections = new Map(selectedFacetValues);
123
+ if (value) {
124
+ updatedSelections.set(field, value);
125
+ } else {
126
+ updatedSelections.delete(field);
127
+ }
128
+ const updatedFilter = buildFacetFilter(updatedSelections);
129
+ return getQueryUrl({
130
+ $filter: updatedFilter || void 0,
131
+ filter: void 0
132
+ });
133
+ };
94
134
  const navigateWithoutReload = useCallback(
95
135
  (url) => {
96
136
  if (lastNavigationUrl.current === url) {
@@ -115,8 +155,7 @@ var DataBindingControls = ({
115
155
  const timeout = window.setTimeout(() => {
116
156
  navigateWithoutReload(
117
157
  getQueryUrl({
118
- searchTerm: trimmedSearchText || void 0,
119
- searchText: void 0
158
+ "$Search": trimmedSearchText ? `'${escapeODataString(trimmedSearchText)}'` : void 0
120
159
  })
121
160
  );
122
161
  }, 500);
@@ -135,20 +174,20 @@ var DataBindingControls = ({
135
174
  {
136
175
  type: "button",
137
176
  onClick: () => navigateWithoutReload(getFacetUrl(field)),
138
- "aria-pressed": !currentFilter,
139
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter ? "" : "bg-primary-base font-semibold"}`,
177
+ "aria-pressed": !selectedFacetValues.has(field),
178
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${selectedFacetValues.has(field) ? "" : "bg-primary-base font-semibold"}`,
140
179
  children: "All"
141
180
  }
142
181
  ),
143
182
  values.map((facet) => {
144
- const filter = `${field} eq '${escapeODataString(facet.value)}'`;
183
+ const isSelected = selectedFacetValues.get(field) === facet.value;
145
184
  return /* @__PURE__ */ jsxs(
146
185
  "button",
147
186
  {
148
187
  type: "button",
149
188
  onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
150
- "aria-pressed": currentFilter === filter,
151
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter === filter ? "bg-primary-base font-semibold" : ""}`,
189
+ "aria-pressed": isSelected,
190
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${isSelected ? "bg-primary-base font-semibold" : ""}`,
152
191
  children: [
153
192
  facet.value,
154
193
  " (",
@@ -14,6 +14,36 @@ import { useRouter } from "next/navigation";
14
14
  import { jsx, jsxs } from "react/jsx-runtime";
15
15
  var humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
16
16
  var escapeODataString = (value) => value.replace(/'/g, "''");
17
+ var parseFacetSelections = (filter) => {
18
+ const selections = /* @__PURE__ */ new Map();
19
+ const groupedExpression = /\(\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*\)/gi;
20
+ for (const match of filter.matchAll(groupedExpression)) {
21
+ selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
22
+ }
23
+ if (selections.size === 0) {
24
+ const singleExpression = filter.match(
25
+ /^\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*$/i
26
+ );
27
+ if (singleExpression) {
28
+ selections.set(
29
+ singleExpression[1].trim(),
30
+ singleExpression[2].replace(/''/g, "'")
31
+ );
32
+ }
33
+ }
34
+ return selections;
35
+ };
36
+ var buildFacetFilter = (selections) => Array.from(selections.entries()).map(
37
+ ([field, value]) => `(${field} eq '${escapeODataString(value)}')`
38
+ ).join(" and ");
39
+ var parseODataSearch = (value) => {
40
+ if (!value) return "";
41
+ const trimmedValue = value.trim();
42
+ if (trimmedValue.startsWith("'") && trimmedValue.endsWith("'")) {
43
+ return trimmedValue.slice(1, -1).replace(/''/g, "'");
44
+ }
45
+ return trimmedValue;
46
+ };
17
47
  var normalizeSortOption = (option) => {
18
48
  const direction = option.direction.trim();
19
49
  return {
@@ -59,8 +89,9 @@ var DataBindingControls = ({
59
89
  const resolvedSortOptions = apiSortOptions.length > 0 ? apiSortOptions : DUMMY_SORT_OPTIONS;
60
90
  const normalizedSortOptions = resolvedSortOptions.map(normalizeSortOption).filter((option) => option.value);
61
91
  const currentFilter = query?.["$filter"] ?? query?.filter ?? "";
92
+ const selectedFacetValues = parseFacetSelections(currentFilter);
62
93
  const currentSort = query?.["$orderby"] ?? query?.orderBy ?? "";
63
- const currentSearch = query?.searchTerm ?? query?.searchText ?? "";
94
+ const currentSearch = parseODataSearch(query?.["$Search"]);
64
95
  const [searchText, setSearchText] = useState(currentSearch);
65
96
  const lastNavigationUrl = useRef(null);
66
97
  useEffect(() => {
@@ -78,15 +109,24 @@ var DataBindingControls = ({
78
109
  });
79
110
  params.delete("$skip");
80
111
  params.delete("skip");
81
- const queryString = params.toString();
112
+ const queryString = Array.from(params.entries()).map(([key, value]) => `${key}=${value}`).join("&");
82
113
  return queryString ? `${path}?${queryString}` : path;
83
114
  },
84
115
  [path, query]
85
116
  );
86
- const getFacetUrl = (field, value) => getQueryUrl({
87
- $filter: value ? `${field} eq '${escapeODataString(value)}'` : void 0,
88
- filter: void 0
89
- });
117
+ const getFacetUrl = (field, value) => {
118
+ const updatedSelections = new Map(selectedFacetValues);
119
+ if (value) {
120
+ updatedSelections.set(field, value);
121
+ } else {
122
+ updatedSelections.delete(field);
123
+ }
124
+ const updatedFilter = buildFacetFilter(updatedSelections);
125
+ return getQueryUrl({
126
+ $filter: updatedFilter || void 0,
127
+ filter: void 0
128
+ });
129
+ };
90
130
  const navigateWithoutReload = useCallback(
91
131
  (url) => {
92
132
  if (lastNavigationUrl.current === url) {
@@ -111,8 +151,7 @@ var DataBindingControls = ({
111
151
  const timeout = window.setTimeout(() => {
112
152
  navigateWithoutReload(
113
153
  getQueryUrl({
114
- searchTerm: trimmedSearchText || void 0,
115
- searchText: void 0
154
+ "$Search": trimmedSearchText ? `'${escapeODataString(trimmedSearchText)}'` : void 0
116
155
  })
117
156
  );
118
157
  }, 500);
@@ -131,20 +170,20 @@ var DataBindingControls = ({
131
170
  {
132
171
  type: "button",
133
172
  onClick: () => navigateWithoutReload(getFacetUrl(field)),
134
- "aria-pressed": !currentFilter,
135
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter ? "" : "bg-primary-base font-semibold"}`,
173
+ "aria-pressed": !selectedFacetValues.has(field),
174
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${selectedFacetValues.has(field) ? "" : "bg-primary-base font-semibold"}`,
136
175
  children: "All"
137
176
  }
138
177
  ),
139
178
  values.map((facet) => {
140
- const filter = `${field} eq '${escapeODataString(facet.value)}'`;
179
+ const isSelected = selectedFacetValues.get(field) === facet.value;
141
180
  return /* @__PURE__ */ jsxs(
142
181
  "button",
143
182
  {
144
183
  type: "button",
145
184
  onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
146
- "aria-pressed": currentFilter === filter,
147
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter === filter ? "bg-primary-base font-semibold" : ""}`,
185
+ "aria-pressed": isSelected,
186
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${isSelected ? "bg-primary-base font-semibold" : ""}`,
148
187
  children: [
149
188
  facet.value,
150
189
  " (",
@@ -3,7 +3,7 @@
3
3
  "use client";
4
4
  import {
5
5
  OdataBuilder
6
- } from "./chunk-4P4HO663.mjs";
6
+ } from "./chunk-TKJDEJSU.mjs";
7
7
  import {
8
8
  Hyperlink,
9
9
  Icon_default
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-6PW2RLUJ.mjs";
5
5
  import {
6
6
  OdataBuilder
7
- } from "./chunk-Q46GMD3P.mjs";
7
+ } from "./chunk-4OH67SPF.mjs";
8
8
  import {
9
9
  Hyperlink
10
10
  } from "./chunk-2R26M6CK.mjs";
@@ -38,6 +38,9 @@ var OdataBuilder = class {
38
38
  if (key == "searchCols") {
39
39
  this.searchCols = odata[key];
40
40
  }
41
+ if (key == "$Search") {
42
+ this.search = odata[key];
43
+ }
41
44
  if (key == "filter") {
42
45
  this.apiFilter = odata[key];
43
46
  }
@@ -70,6 +73,9 @@ var OdataBuilder = class {
70
73
  if (obj?.["searchCols"] && obj["searchCols"].trim() !== "") {
71
74
  queryString += `&searchCols=${encodeURIComponent(obj["searchCols"])}`;
72
75
  }
76
+ if (obj?.["$Search"] && obj["$Search"].trim() !== "") {
77
+ queryString += `&$Search=${obj["$Search"]}`;
78
+ }
73
79
  if (obj?.["filter"] && obj["filter"].trim() !== "") {
74
80
  queryString += `&filter=${encodeURIComponent(obj["filter"])}`;
75
81
  }
@@ -124,8 +130,8 @@ var OdataBuilder = class {
124
130
  return pageNumber;
125
131
  }
126
132
  appendApiQueryParameters(url) {
127
- if (this.searchTerm) {
128
- url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
133
+ if (this.search) {
134
+ url += `&$Search=${this.search}`;
129
135
  }
130
136
  if (this.apiFilter) {
131
137
  url += `&filter=${encodeURIComponent(this.apiFilter)}`;
@@ -211,6 +217,12 @@ var OdataBuilder = class {
211
217
  if (this.orderBy !== null && this.orderBy !== "") {
212
218
  url = url + `&$orderby=${encodeURIComponent(this.orderBy)}`;
213
219
  }
220
+ if (this.searchTerm) {
221
+ url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
222
+ }
223
+ if (this.searchCols) {
224
+ url += `&searchCols=${encodeURIComponent(this.searchCols)}`;
225
+ }
214
226
  return this.appendApiQueryParameters(url);
215
227
  }
216
228
  getOrderBy() {
@@ -40,6 +40,9 @@ var OdataBuilder = class {
40
40
  if (key == "searchCols") {
41
41
  this.searchCols = odata[key];
42
42
  }
43
+ if (key == "$Search") {
44
+ this.search = odata[key];
45
+ }
43
46
  if (key == "filter") {
44
47
  this.apiFilter = odata[key];
45
48
  }
@@ -72,6 +75,9 @@ var OdataBuilder = class {
72
75
  if (obj?.["searchCols"] && obj["searchCols"].trim() !== "") {
73
76
  queryString += `&searchCols=${encodeURIComponent(obj["searchCols"])}`;
74
77
  }
78
+ if (obj?.["$Search"] && obj["$Search"].trim() !== "") {
79
+ queryString += `&$Search=${obj["$Search"]}`;
80
+ }
75
81
  if (obj?.["filter"] && obj["filter"].trim() !== "") {
76
82
  queryString += `&filter=${encodeURIComponent(obj["filter"])}`;
77
83
  }
@@ -126,8 +132,8 @@ var OdataBuilder = class {
126
132
  return pageNumber;
127
133
  }
128
134
  appendApiQueryParameters(url) {
129
- if (this.searchTerm) {
130
- url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
135
+ if (this.search) {
136
+ url += `&$Search=${this.search}`;
131
137
  }
132
138
  if (this.apiFilter) {
133
139
  url += `&filter=${encodeURIComponent(this.apiFilter)}`;
@@ -213,6 +219,12 @@ var OdataBuilder = class {
213
219
  if (this.orderBy !== null && this.orderBy !== "") {
214
220
  url = url + `&$orderby=${encodeURIComponent(this.orderBy)}`;
215
221
  }
222
+ if (this.searchTerm) {
223
+ url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
224
+ }
225
+ if (this.searchCols) {
226
+ url += `&searchCols=${encodeURIComponent(this.searchCols)}`;
227
+ }
216
228
  return this.appendApiQueryParameters(url);
217
229
  }
218
230
  getOrderBy() {
package/dist/index.js CHANGED
@@ -4123,6 +4123,9 @@ var init_OdataBuilder = __esm({
4123
4123
  if (key == "searchCols") {
4124
4124
  this.searchCols = odata[key];
4125
4125
  }
4126
+ if (key == "$Search") {
4127
+ this.search = odata[key];
4128
+ }
4126
4129
  if (key == "filter") {
4127
4130
  this.apiFilter = odata[key];
4128
4131
  }
@@ -4155,6 +4158,9 @@ var init_OdataBuilder = __esm({
4155
4158
  if (obj?.["searchCols"] && obj["searchCols"].trim() !== "") {
4156
4159
  queryString += `&searchCols=${encodeURIComponent(obj["searchCols"])}`;
4157
4160
  }
4161
+ if (obj?.["$Search"] && obj["$Search"].trim() !== "") {
4162
+ queryString += `&$Search=${obj["$Search"]}`;
4163
+ }
4158
4164
  if (obj?.["filter"] && obj["filter"].trim() !== "") {
4159
4165
  queryString += `&filter=${encodeURIComponent(obj["filter"])}`;
4160
4166
  }
@@ -4209,8 +4215,8 @@ var init_OdataBuilder = __esm({
4209
4215
  return pageNumber;
4210
4216
  }
4211
4217
  appendApiQueryParameters(url) {
4212
- if (this.searchTerm) {
4213
- url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
4218
+ if (this.search) {
4219
+ url += `&$Search=${this.search}`;
4214
4220
  }
4215
4221
  if (this.apiFilter) {
4216
4222
  url += `&filter=${encodeURIComponent(this.apiFilter)}`;
@@ -4296,6 +4302,12 @@ var init_OdataBuilder = __esm({
4296
4302
  if (this.orderBy !== null && this.orderBy !== "") {
4297
4303
  url = url + `&$orderby=${encodeURIComponent(this.orderBy)}`;
4298
4304
  }
4305
+ if (this.searchTerm) {
4306
+ url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
4307
+ }
4308
+ if (this.searchCols) {
4309
+ url += `&searchCols=${encodeURIComponent(this.searchCols)}`;
4310
+ }
4299
4311
  return this.appendApiQueryParameters(url);
4300
4312
  }
4301
4313
  getOrderBy() {
@@ -4494,7 +4506,7 @@ var DataBindingControls_exports = {};
4494
4506
  __export(DataBindingControls_exports, {
4495
4507
  default: () => DataBindingControls_default
4496
4508
  });
4497
- var import_react55, import_navigation, import_jsx_runtime77, humanize, escapeODataString, normalizeSortOption, DUMMY_FACETS, DUMMY_SORT_OPTIONS, DataBindingControls, DataBindingControls_default;
4509
+ var import_react55, import_navigation, import_jsx_runtime77, humanize, escapeODataString, parseFacetSelections, buildFacetFilter, parseODataSearch, normalizeSortOption, DUMMY_FACETS, DUMMY_SORT_OPTIONS, DataBindingControls, DataBindingControls_default;
4498
4510
  var init_DataBindingControls = __esm({
4499
4511
  "src/components/pageRenderingEngine/nodes/DataBindingControls.tsx"() {
4500
4512
  "use strict";
@@ -4506,6 +4518,36 @@ var init_DataBindingControls = __esm({
4506
4518
  import_jsx_runtime77 = require("react/jsx-runtime");
4507
4519
  humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
4508
4520
  escapeODataString = (value) => value.replace(/'/g, "''");
4521
+ parseFacetSelections = (filter) => {
4522
+ const selections = /* @__PURE__ */ new Map();
4523
+ const groupedExpression = /\(\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*\)/gi;
4524
+ for (const match of filter.matchAll(groupedExpression)) {
4525
+ selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
4526
+ }
4527
+ if (selections.size === 0) {
4528
+ const singleExpression = filter.match(
4529
+ /^\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*$/i
4530
+ );
4531
+ if (singleExpression) {
4532
+ selections.set(
4533
+ singleExpression[1].trim(),
4534
+ singleExpression[2].replace(/''/g, "'")
4535
+ );
4536
+ }
4537
+ }
4538
+ return selections;
4539
+ };
4540
+ buildFacetFilter = (selections) => Array.from(selections.entries()).map(
4541
+ ([field, value]) => `(${field} eq '${escapeODataString(value)}')`
4542
+ ).join(" and ");
4543
+ parseODataSearch = (value) => {
4544
+ if (!value) return "";
4545
+ const trimmedValue = value.trim();
4546
+ if (trimmedValue.startsWith("'") && trimmedValue.endsWith("'")) {
4547
+ return trimmedValue.slice(1, -1).replace(/''/g, "'");
4548
+ }
4549
+ return trimmedValue;
4550
+ };
4509
4551
  normalizeSortOption = (option) => {
4510
4552
  const direction = option.direction.trim();
4511
4553
  return {
@@ -4551,8 +4593,9 @@ var init_DataBindingControls = __esm({
4551
4593
  const resolvedSortOptions = apiSortOptions.length > 0 ? apiSortOptions : DUMMY_SORT_OPTIONS;
4552
4594
  const normalizedSortOptions = resolvedSortOptions.map(normalizeSortOption).filter((option) => option.value);
4553
4595
  const currentFilter = query?.["$filter"] ?? query?.filter ?? "";
4596
+ const selectedFacetValues = parseFacetSelections(currentFilter);
4554
4597
  const currentSort = query?.["$orderby"] ?? query?.orderBy ?? "";
4555
- const currentSearch = query?.searchTerm ?? query?.searchText ?? "";
4598
+ const currentSearch = parseODataSearch(query?.["$Search"]);
4556
4599
  const [searchText, setSearchText] = (0, import_react55.useState)(currentSearch);
4557
4600
  const lastNavigationUrl = (0, import_react55.useRef)(null);
4558
4601
  (0, import_react55.useEffect)(() => {
@@ -4570,15 +4613,24 @@ var init_DataBindingControls = __esm({
4570
4613
  });
4571
4614
  params.delete("$skip");
4572
4615
  params.delete("skip");
4573
- const queryString = params.toString();
4616
+ const queryString = Array.from(params.entries()).map(([key, value]) => `${key}=${value}`).join("&");
4574
4617
  return queryString ? `${path}?${queryString}` : path;
4575
4618
  },
4576
4619
  [path, query]
4577
4620
  );
4578
- const getFacetUrl = (field, value) => getQueryUrl({
4579
- $filter: value ? `${field} eq '${escapeODataString(value)}'` : void 0,
4580
- filter: void 0
4581
- });
4621
+ const getFacetUrl = (field, value) => {
4622
+ const updatedSelections = new Map(selectedFacetValues);
4623
+ if (value) {
4624
+ updatedSelections.set(field, value);
4625
+ } else {
4626
+ updatedSelections.delete(field);
4627
+ }
4628
+ const updatedFilter = buildFacetFilter(updatedSelections);
4629
+ return getQueryUrl({
4630
+ $filter: updatedFilter || void 0,
4631
+ filter: void 0
4632
+ });
4633
+ };
4582
4634
  const navigateWithoutReload = (0, import_react55.useCallback)(
4583
4635
  (url) => {
4584
4636
  if (lastNavigationUrl.current === url) {
@@ -4603,8 +4655,7 @@ var init_DataBindingControls = __esm({
4603
4655
  const timeout = window.setTimeout(() => {
4604
4656
  navigateWithoutReload(
4605
4657
  getQueryUrl({
4606
- searchTerm: trimmedSearchText || void 0,
4607
- searchText: void 0
4658
+ "$Search": trimmedSearchText ? `'${escapeODataString(trimmedSearchText)}'` : void 0
4608
4659
  })
4609
4660
  );
4610
4661
  }, 500);
@@ -4623,20 +4674,20 @@ var init_DataBindingControls = __esm({
4623
4674
  {
4624
4675
  type: "button",
4625
4676
  onClick: () => navigateWithoutReload(getFacetUrl(field)),
4626
- "aria-pressed": !currentFilter,
4627
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter ? "" : "bg-primary-base font-semibold"}`,
4677
+ "aria-pressed": !selectedFacetValues.has(field),
4678
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${selectedFacetValues.has(field) ? "" : "bg-primary-base font-semibold"}`,
4628
4679
  children: "All"
4629
4680
  }
4630
4681
  ),
4631
4682
  values.map((facet) => {
4632
- const filter = `${field} eq '${escapeODataString(facet.value)}'`;
4683
+ const isSelected = selectedFacetValues.get(field) === facet.value;
4633
4684
  return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
4634
4685
  "button",
4635
4686
  {
4636
4687
  type: "button",
4637
4688
  onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
4638
- "aria-pressed": currentFilter === filter,
4639
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter === filter ? "bg-primary-base font-semibold" : ""}`,
4689
+ "aria-pressed": isSelected,
4690
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${isSelected ? "bg-primary-base font-semibold" : ""}`,
4640
4691
  children: [
4641
4692
  facet.value,
4642
4693
  " (",
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  OdataBuilder
5
- } from "./chunk-4P4HO663.mjs";
5
+ } from "./chunk-TKJDEJSU.mjs";
6
6
  import {
7
7
  InputControl_default
8
8
  } from "./chunk-GKI42H4B.mjs";
@@ -2295,8 +2295,8 @@ var GoogleMapNode_default = GoogleMapNode;
2295
2295
 
2296
2296
  // src/components/pageRenderingEngine/nodes/DivContainer.tsx
2297
2297
  import { jsx as jsx35, jsxs as jsxs13 } from "react/jsx-runtime";
2298
- var Pagination = dynamic11(() => import("./Pagination-GL6B4MNO.mjs"), { ssr: true });
2299
- var DataBindingControls = dynamic11(() => import("./DataBindingControls-QZ7ES2AS.mjs"), {
2298
+ var Pagination = dynamic11(() => import("./Pagination-2KVND6JU.mjs"), { ssr: true });
2299
+ var DataBindingControls = dynamic11(() => import("./DataBindingControls-VTCI7X5Y.mjs"), {
2300
2300
  ssr: true
2301
2301
  });
2302
2302
  var Slider = dynamic11(() => import("./Slider-554BKC7N.mjs"), {
package/dist/server.js CHANGED
@@ -1945,6 +1945,9 @@ var init_OdataBuilder = __esm({
1945
1945
  if (key == "searchCols") {
1946
1946
  this.searchCols = odata[key];
1947
1947
  }
1948
+ if (key == "$Search") {
1949
+ this.search = odata[key];
1950
+ }
1948
1951
  if (key == "filter") {
1949
1952
  this.apiFilter = odata[key];
1950
1953
  }
@@ -1977,6 +1980,9 @@ var init_OdataBuilder = __esm({
1977
1980
  if (obj?.["searchCols"] && obj["searchCols"].trim() !== "") {
1978
1981
  queryString += `&searchCols=${encodeURIComponent(obj["searchCols"])}`;
1979
1982
  }
1983
+ if (obj?.["$Search"] && obj["$Search"].trim() !== "") {
1984
+ queryString += `&$Search=${obj["$Search"]}`;
1985
+ }
1980
1986
  if (obj?.["filter"] && obj["filter"].trim() !== "") {
1981
1987
  queryString += `&filter=${encodeURIComponent(obj["filter"])}`;
1982
1988
  }
@@ -2031,8 +2037,8 @@ var init_OdataBuilder = __esm({
2031
2037
  return pageNumber;
2032
2038
  }
2033
2039
  appendApiQueryParameters(url) {
2034
- if (this.searchTerm) {
2035
- url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
2040
+ if (this.search) {
2041
+ url += `&$Search=${this.search}`;
2036
2042
  }
2037
2043
  if (this.apiFilter) {
2038
2044
  url += `&filter=${encodeURIComponent(this.apiFilter)}`;
@@ -2118,6 +2124,12 @@ var init_OdataBuilder = __esm({
2118
2124
  if (this.orderBy !== null && this.orderBy !== "") {
2119
2125
  url = url + `&$orderby=${encodeURIComponent(this.orderBy)}`;
2120
2126
  }
2127
+ if (this.searchTerm) {
2128
+ url += `&searchTerm=${encodeURIComponent(this.searchTerm)}`;
2129
+ }
2130
+ if (this.searchCols) {
2131
+ url += `&searchCols=${encodeURIComponent(this.searchCols)}`;
2132
+ }
2121
2133
  return this.appendApiQueryParameters(url);
2122
2134
  }
2123
2135
  getOrderBy() {
@@ -4492,7 +4504,7 @@ var DataBindingControls_exports = {};
4492
4504
  __export(DataBindingControls_exports, {
4493
4505
  default: () => DataBindingControls_default
4494
4506
  });
4495
- var import_react55, import_navigation, import_jsx_runtime77, humanize, escapeODataString, normalizeSortOption, DUMMY_FACETS, DUMMY_SORT_OPTIONS, DataBindingControls, DataBindingControls_default;
4507
+ var import_react55, import_navigation, import_jsx_runtime77, humanize, escapeODataString, parseFacetSelections, buildFacetFilter, parseODataSearch, normalizeSortOption, DUMMY_FACETS, DUMMY_SORT_OPTIONS, DataBindingControls, DataBindingControls_default;
4496
4508
  var init_DataBindingControls = __esm({
4497
4509
  "src/components/pageRenderingEngine/nodes/DataBindingControls.tsx"() {
4498
4510
  "use strict";
@@ -4504,6 +4516,36 @@ var init_DataBindingControls = __esm({
4504
4516
  import_jsx_runtime77 = require("react/jsx-runtime");
4505
4517
  humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
4506
4518
  escapeODataString = (value) => value.replace(/'/g, "''");
4519
+ parseFacetSelections = (filter) => {
4520
+ const selections = /* @__PURE__ */ new Map();
4521
+ const groupedExpression = /\(\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*\)/gi;
4522
+ for (const match of filter.matchAll(groupedExpression)) {
4523
+ selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
4524
+ }
4525
+ if (selections.size === 0) {
4526
+ const singleExpression = filter.match(
4527
+ /^\s*([^()]+?)\s+eq\s+'((?:''|[^'])*)'\s*$/i
4528
+ );
4529
+ if (singleExpression) {
4530
+ selections.set(
4531
+ singleExpression[1].trim(),
4532
+ singleExpression[2].replace(/''/g, "'")
4533
+ );
4534
+ }
4535
+ }
4536
+ return selections;
4537
+ };
4538
+ buildFacetFilter = (selections) => Array.from(selections.entries()).map(
4539
+ ([field, value]) => `(${field} eq '${escapeODataString(value)}')`
4540
+ ).join(" and ");
4541
+ parseODataSearch = (value) => {
4542
+ if (!value) return "";
4543
+ const trimmedValue = value.trim();
4544
+ if (trimmedValue.startsWith("'") && trimmedValue.endsWith("'")) {
4545
+ return trimmedValue.slice(1, -1).replace(/''/g, "'");
4546
+ }
4547
+ return trimmedValue;
4548
+ };
4507
4549
  normalizeSortOption = (option) => {
4508
4550
  const direction = option.direction.trim();
4509
4551
  return {
@@ -4549,8 +4591,9 @@ var init_DataBindingControls = __esm({
4549
4591
  const resolvedSortOptions = apiSortOptions.length > 0 ? apiSortOptions : DUMMY_SORT_OPTIONS;
4550
4592
  const normalizedSortOptions = resolvedSortOptions.map(normalizeSortOption).filter((option) => option.value);
4551
4593
  const currentFilter = query?.["$filter"] ?? query?.filter ?? "";
4594
+ const selectedFacetValues = parseFacetSelections(currentFilter);
4552
4595
  const currentSort = query?.["$orderby"] ?? query?.orderBy ?? "";
4553
- const currentSearch = query?.searchTerm ?? query?.searchText ?? "";
4596
+ const currentSearch = parseODataSearch(query?.["$Search"]);
4554
4597
  const [searchText, setSearchText] = (0, import_react55.useState)(currentSearch);
4555
4598
  const lastNavigationUrl = (0, import_react55.useRef)(null);
4556
4599
  (0, import_react55.useEffect)(() => {
@@ -4568,15 +4611,24 @@ var init_DataBindingControls = __esm({
4568
4611
  });
4569
4612
  params.delete("$skip");
4570
4613
  params.delete("skip");
4571
- const queryString = params.toString();
4614
+ const queryString = Array.from(params.entries()).map(([key, value]) => `${key}=${value}`).join("&");
4572
4615
  return queryString ? `${path}?${queryString}` : path;
4573
4616
  },
4574
4617
  [path, query]
4575
4618
  );
4576
- const getFacetUrl = (field, value) => getQueryUrl({
4577
- $filter: value ? `${field} eq '${escapeODataString(value)}'` : void 0,
4578
- filter: void 0
4579
- });
4619
+ const getFacetUrl = (field, value) => {
4620
+ const updatedSelections = new Map(selectedFacetValues);
4621
+ if (value) {
4622
+ updatedSelections.set(field, value);
4623
+ } else {
4624
+ updatedSelections.delete(field);
4625
+ }
4626
+ const updatedFilter = buildFacetFilter(updatedSelections);
4627
+ return getQueryUrl({
4628
+ $filter: updatedFilter || void 0,
4629
+ filter: void 0
4630
+ });
4631
+ };
4580
4632
  const navigateWithoutReload = (0, import_react55.useCallback)(
4581
4633
  (url) => {
4582
4634
  if (lastNavigationUrl.current === url) {
@@ -4601,8 +4653,7 @@ var init_DataBindingControls = __esm({
4601
4653
  const timeout = window.setTimeout(() => {
4602
4654
  navigateWithoutReload(
4603
4655
  getQueryUrl({
4604
- searchTerm: trimmedSearchText || void 0,
4605
- searchText: void 0
4656
+ "$Search": trimmedSearchText ? `'${escapeODataString(trimmedSearchText)}'` : void 0
4606
4657
  })
4607
4658
  );
4608
4659
  }, 500);
@@ -4621,20 +4672,20 @@ var init_DataBindingControls = __esm({
4621
4672
  {
4622
4673
  type: "button",
4623
4674
  onClick: () => navigateWithoutReload(getFacetUrl(field)),
4624
- "aria-pressed": !currentFilter,
4625
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter ? "" : "bg-primary-base font-semibold"}`,
4675
+ "aria-pressed": !selectedFacetValues.has(field),
4676
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${selectedFacetValues.has(field) ? "" : "bg-primary-base font-semibold"}`,
4626
4677
  children: "All"
4627
4678
  }
4628
4679
  ),
4629
4680
  values.map((facet) => {
4630
- const filter = `${field} eq '${escapeODataString(facet.value)}'`;
4681
+ const isSelected = selectedFacetValues.get(field) === facet.value;
4631
4682
  return /* @__PURE__ */ (0, import_jsx_runtime77.jsxs)(
4632
4683
  "button",
4633
4684
  {
4634
4685
  type: "button",
4635
4686
  onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
4636
- "aria-pressed": currentFilter === filter,
4637
- className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${currentFilter === filter ? "bg-primary-base font-semibold" : ""}`,
4687
+ "aria-pressed": isSelected,
4688
+ className: `px-3 py-2 text-left text-sm ${stacked ? "w-full" : "border"} ${isSelected ? "bg-primary-base font-semibold" : ""}`,
4638
4689
  children: [
4639
4690
  facet.value,
4640
4691
  " (",
package/dist/server.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OdataBuilder
3
- } from "./chunk-Q46GMD3P.mjs";
3
+ } from "./chunk-4OH67SPF.mjs";
4
4
  import {
5
5
  AssetUtility_default
6
6
  } from "./chunk-TQ6BXQ3A.mjs";
@@ -2263,8 +2263,8 @@ var GoogleMapNode_default = GoogleMapNode;
2263
2263
 
2264
2264
  // src/components/pageRenderingEngine/nodes/DivContainer.tsx
2265
2265
  import { jsx as jsx35, jsxs as jsxs13 } from "react/jsx-runtime";
2266
- var Pagination = dynamic11(() => import("./Pagination-ZQO3EUKB.mjs"), { ssr: true });
2267
- var DataBindingControls = dynamic11(() => import("./DataBindingControls-XCAIDMDC.mjs"), {
2266
+ var Pagination = dynamic11(() => import("./Pagination-PDU7V3HY.mjs"), { ssr: true });
2267
+ var DataBindingControls = dynamic11(() => import("./DataBindingControls-2LHGICW3.mjs"), {
2268
2268
  ssr: true
2269
2269
  });
2270
2270
  var Slider = dynamic11(() => import("./Slider-PEIVH6A5.mjs"), {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clyrex-digital/clyrex-controls-dev",
3
- "version": "0.8.1-dev.20260824072352",
3
+ "version": "0.8.1-dev.20260824103828",
4
4
  "description": "Reusable React components",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",