@clyrex-digital/clyrex-controls-dev 0.8.1-dev.20260924103055 → 0.8.1-dev.20260925110206
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/DataBindingControls-25UC5W3R.mjs +502 -0
- package/dist/DataBindingControls-6IS5F3QX.mjs +498 -0
- package/dist/index.js +283 -162
- package/dist/index.mjs +2 -2
- package/dist/server.js +283 -162
- package/dist/server.mjs +2 -2
- package/package.json +1 -1
- package/dist/DataBindingControls-SLNZLI3I.mjs +0 -377
- package/dist/DataBindingControls-UDRT7JFF.mjs +0 -381
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
InputControlType_default
|
|
4
|
+
} from "./chunk-HRDHAIZF.mjs";
|
|
5
|
+
import {
|
|
6
|
+
Button_default
|
|
7
|
+
} from "./chunk-4WMSS6CE.mjs";
|
|
8
|
+
import "./chunk-56HSDML5.mjs";
|
|
9
|
+
|
|
10
|
+
// src/components/pageRenderingEngine/nodes/DataBindingControls.tsx
|
|
11
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
12
|
+
import { useRouter, useSearchParams } from "next/navigation";
|
|
13
|
+
|
|
14
|
+
// src/components/controls/edit/InputControl.tsx
|
|
15
|
+
import dynamic from "next/dynamic";
|
|
16
|
+
var InputControl = dynamic(() => import("./InputControlClient-NHXG4QBU.mjs"), {
|
|
17
|
+
ssr: false
|
|
18
|
+
});
|
|
19
|
+
var InputControl_default = InputControl;
|
|
20
|
+
|
|
21
|
+
// src/components/pageRenderingEngine/nodes/DataBindingControls.tsx
|
|
22
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
23
|
+
var humanize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
|
|
24
|
+
var escapeODataString = (value) => value.replace(/'/g, "''");
|
|
25
|
+
var parseFacetSelections = (filter) => {
|
|
26
|
+
const selections = /* @__PURE__ */ new Map();
|
|
27
|
+
if (!filter || !filter.trim()) return selections;
|
|
28
|
+
const expression = /(?:^|[\s()]+(?:and[\s()]+)?)([\w./-]+)\s+eq\s+'((?:''|[^'])*)'/gi;
|
|
29
|
+
for (const match of filter.matchAll(expression)) {
|
|
30
|
+
if (match[1] && match[2] !== void 0) {
|
|
31
|
+
selections.set(match[1].trim(), match[2].replace(/''/g, "'"));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return selections;
|
|
35
|
+
};
|
|
36
|
+
var buildFacetFilter = (selections) => Array.from(selections.entries()).map(([field, value]) => `${field} eq '${escapeODataString(value)}'`).join(" and ");
|
|
37
|
+
var parseODataSearch = (value) => {
|
|
38
|
+
if (!value) return "";
|
|
39
|
+
const trimmedValue = value.trim();
|
|
40
|
+
if (trimmedValue.startsWith("'") && trimmedValue.endsWith("'")) {
|
|
41
|
+
return trimmedValue.slice(1, -1).replace(/''/g, "'");
|
|
42
|
+
}
|
|
43
|
+
return trimmedValue;
|
|
44
|
+
};
|
|
45
|
+
var SearchIcon = ({ className = "" }) => /* @__PURE__ */ jsxs(
|
|
46
|
+
"svg",
|
|
47
|
+
{
|
|
48
|
+
"aria-hidden": "true",
|
|
49
|
+
className,
|
|
50
|
+
fill: "none",
|
|
51
|
+
viewBox: "0 0 24 24",
|
|
52
|
+
stroke: "currentColor",
|
|
53
|
+
strokeWidth: "2",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
56
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "m20 20-4-4" })
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
var ResetIcon = ({ className = "" }) => /* @__PURE__ */ jsxs(
|
|
61
|
+
"svg",
|
|
62
|
+
{
|
|
63
|
+
"aria-hidden": "true",
|
|
64
|
+
className,
|
|
65
|
+
fill: "none",
|
|
66
|
+
viewBox: "0 0 24 24",
|
|
67
|
+
stroke: "currentColor",
|
|
68
|
+
strokeWidth: "2",
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 4v6h6" }),
|
|
71
|
+
/* @__PURE__ */ jsx(
|
|
72
|
+
"path",
|
|
73
|
+
{
|
|
74
|
+
strokeLinecap: "round",
|
|
75
|
+
strokeLinejoin: "round",
|
|
76
|
+
d: "M5.5 15a8 8 0 1 0 .6-7.8L4 10"
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
var FilterSlidersIcon = ({ className = "" }) => /* @__PURE__ */ jsxs(
|
|
83
|
+
"svg",
|
|
84
|
+
{
|
|
85
|
+
"aria-hidden": "true",
|
|
86
|
+
className,
|
|
87
|
+
fill: "none",
|
|
88
|
+
viewBox: "0 0 24 24",
|
|
89
|
+
stroke: "currentColor",
|
|
90
|
+
strokeWidth: "2",
|
|
91
|
+
children: [
|
|
92
|
+
/* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 4h18M3 12h18M3 20h18" }),
|
|
93
|
+
/* @__PURE__ */ jsx("circle", { cx: "8", cy: "4", r: "2", fill: "currentColor" }),
|
|
94
|
+
/* @__PURE__ */ jsx("circle", { cx: "16", cy: "12", r: "2", fill: "currentColor" }),
|
|
95
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "20", r: "2", fill: "currentColor" })
|
|
96
|
+
]
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
var ChevronDownIcon = ({ className = "" }) => /* @__PURE__ */ jsx(
|
|
100
|
+
"svg",
|
|
101
|
+
{
|
|
102
|
+
"aria-hidden": "true",
|
|
103
|
+
className,
|
|
104
|
+
fill: "none",
|
|
105
|
+
viewBox: "0 0 24 24",
|
|
106
|
+
stroke: "currentColor",
|
|
107
|
+
strokeWidth: "2",
|
|
108
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "m19 9-7 7-7-7" })
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
var CheckIcon = ({ className = "" }) => /* @__PURE__ */ jsx(
|
|
112
|
+
"svg",
|
|
113
|
+
{
|
|
114
|
+
"aria-hidden": "true",
|
|
115
|
+
className,
|
|
116
|
+
fill: "none",
|
|
117
|
+
viewBox: "0 0 24 24",
|
|
118
|
+
stroke: "currentColor",
|
|
119
|
+
strokeWidth: "2.5",
|
|
120
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" })
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
var CloseIcon = ({ className = "" }) => /* @__PURE__ */ jsx(
|
|
124
|
+
"svg",
|
|
125
|
+
{
|
|
126
|
+
"aria-hidden": "true",
|
|
127
|
+
className,
|
|
128
|
+
fill: "none",
|
|
129
|
+
viewBox: "0 0 24 24",
|
|
130
|
+
stroke: "currentColor",
|
|
131
|
+
strokeWidth: "2",
|
|
132
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 18L18 6M6 6l12 12" })
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
var normalizeSortOption = (option) => {
|
|
136
|
+
const direction = option.direction.trim();
|
|
137
|
+
const title = option.title || humanize(option.name);
|
|
138
|
+
return {
|
|
139
|
+
label: title,
|
|
140
|
+
value: [option.name, direction].filter(Boolean).join(" ")
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
var DataBindingControls = ({
|
|
144
|
+
path,
|
|
145
|
+
query,
|
|
146
|
+
facets,
|
|
147
|
+
sortOptions,
|
|
148
|
+
showFacets,
|
|
149
|
+
showSortOptions,
|
|
150
|
+
showSearchBar,
|
|
151
|
+
mode = "toolbar"
|
|
152
|
+
}) => {
|
|
153
|
+
const router = useRouter();
|
|
154
|
+
const searchParams = useSearchParams();
|
|
155
|
+
const [collapsedCategories, setCollapsedCategories] = useState({});
|
|
156
|
+
const [isSortOpen, setIsSortOpen] = useState(false);
|
|
157
|
+
const sortDropdownRef = useRef(null);
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
const handleClickOutside = (event) => {
|
|
160
|
+
if (sortDropdownRef.current && !sortDropdownRef.current.contains(event.target)) {
|
|
161
|
+
setIsSortOpen(false);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
165
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
166
|
+
}, []);
|
|
167
|
+
const toggleCategory = (field) => {
|
|
168
|
+
setCollapsedCategories((prev) => ({
|
|
169
|
+
...prev,
|
|
170
|
+
[field]: !prev[field]
|
|
171
|
+
}));
|
|
172
|
+
};
|
|
173
|
+
const searchParamsFilter = searchParams?.get("$filter") ?? searchParams?.get("filter");
|
|
174
|
+
const searchParamsSort = searchParams?.get("$orderby") ?? searchParams?.get("orderBy");
|
|
175
|
+
const searchParamsSearch = searchParams?.get("$search");
|
|
176
|
+
const currentFilter = searchParamsFilter !== void 0 && searchParamsFilter !== null ? searchParamsFilter : query?.["$filter"] ?? query?.filter ?? "";
|
|
177
|
+
const currentSort = searchParamsSort !== void 0 && searchParamsSort !== null ? searchParamsSort : query?.["$orderby"] ?? query?.orderBy ?? "";
|
|
178
|
+
const currentSearch = parseODataSearch(
|
|
179
|
+
searchParamsSearch !== void 0 && searchParamsSearch !== null ? searchParamsSearch : query?.["$search"]
|
|
180
|
+
);
|
|
181
|
+
const [searchText, setSearchText] = useState(currentSearch);
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
setSearchText(currentSearch);
|
|
184
|
+
}, [currentSearch]);
|
|
185
|
+
const selectedFacetValues = useMemo(
|
|
186
|
+
() => parseFacetSelections(currentFilter),
|
|
187
|
+
[currentFilter]
|
|
188
|
+
);
|
|
189
|
+
const activeFacets = useMemo(() => {
|
|
190
|
+
if (!facets) return [];
|
|
191
|
+
return Object.entries(facets).map(([field, values]) => {
|
|
192
|
+
if (!Array.isArray(values)) return null;
|
|
193
|
+
const filteredValues = values.filter(
|
|
194
|
+
(item) => item.count > 0 || selectedFacetValues.get(field) === item.value
|
|
195
|
+
);
|
|
196
|
+
if (filteredValues.length === 0) return null;
|
|
197
|
+
return [field, filteredValues];
|
|
198
|
+
}).filter((group) => group !== null);
|
|
199
|
+
}, [facets, selectedFacetValues]);
|
|
200
|
+
const normalizedSortOptions = (sortOptions ?? []).filter((option) => option?.name && option?.direction).map(normalizeSortOption).filter((option) => option.value);
|
|
201
|
+
const selectedSortOption = normalizedSortOptions.find((opt) => opt.value === currentSort) || normalizedSortOptions[0];
|
|
202
|
+
const selectedSortLabel = selectedSortOption?.label || "";
|
|
203
|
+
const getQueryUrl = useCallback(
|
|
204
|
+
(updates) => {
|
|
205
|
+
const initialParams = searchParams ? searchParams.toString() : "";
|
|
206
|
+
const params = new URLSearchParams(initialParams || query || {});
|
|
207
|
+
Object.entries(updates).forEach(([key, value]) => {
|
|
208
|
+
if (value) {
|
|
209
|
+
params.set(key, value);
|
|
210
|
+
} else {
|
|
211
|
+
params.delete(key);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
params.delete("$skip");
|
|
215
|
+
params.delete("skip");
|
|
216
|
+
const queryString = Array.from(params.entries()).map(
|
|
217
|
+
([key, value]) => key === "$filter" || key === "filter" ? `${key}=${encodeURIComponent(value)}` : `${key}=${value}`
|
|
218
|
+
).join("&");
|
|
219
|
+
return queryString ? `${path}?${queryString}` : path;
|
|
220
|
+
},
|
|
221
|
+
[path, query, searchParams]
|
|
222
|
+
);
|
|
223
|
+
const navigateWithoutReload = useCallback(
|
|
224
|
+
(url) => {
|
|
225
|
+
if (typeof window !== "undefined") {
|
|
226
|
+
const targetUrl = new URL(url, window.location.origin);
|
|
227
|
+
if (targetUrl.pathname === window.location.pathname && targetUrl.search === window.location.search) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
router.push(url, { scroll: false });
|
|
232
|
+
},
|
|
233
|
+
[router]
|
|
234
|
+
);
|
|
235
|
+
const getFacetUrl = (field, value) => {
|
|
236
|
+
const updatedSelections = new Map(selectedFacetValues);
|
|
237
|
+
if (value) {
|
|
238
|
+
if (updatedSelections.get(field) === value) {
|
|
239
|
+
updatedSelections.delete(field);
|
|
240
|
+
} else {
|
|
241
|
+
updatedSelections.set(field, value);
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
updatedSelections.delete(field);
|
|
245
|
+
}
|
|
246
|
+
const updatedFilter = buildFacetFilter(updatedSelections);
|
|
247
|
+
return getQueryUrl({
|
|
248
|
+
$filter: updatedFilter || void 0,
|
|
249
|
+
filter: void 0
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
const clearFacetField = (field) => {
|
|
253
|
+
const updatedSelections = new Map(selectedFacetValues);
|
|
254
|
+
updatedSelections.delete(field);
|
|
255
|
+
const updatedFilter = buildFacetFilter(updatedSelections);
|
|
256
|
+
navigateWithoutReload(
|
|
257
|
+
getQueryUrl({
|
|
258
|
+
$filter: updatedFilter || void 0,
|
|
259
|
+
filter: void 0
|
|
260
|
+
})
|
|
261
|
+
);
|
|
262
|
+
};
|
|
263
|
+
const handleSearch = useCallback(async () => {
|
|
264
|
+
const trimmedSearchText = searchText.trim();
|
|
265
|
+
if (trimmedSearchText === currentSearch.trim()) {
|
|
266
|
+
return { isSuccessful: true };
|
|
267
|
+
}
|
|
268
|
+
navigateWithoutReload(
|
|
269
|
+
getQueryUrl({
|
|
270
|
+
"$search": trimmedSearchText || void 0
|
|
271
|
+
})
|
|
272
|
+
);
|
|
273
|
+
return { isSuccessful: true };
|
|
274
|
+
}, [currentSearch, getQueryUrl, navigateWithoutReload, searchText]);
|
|
275
|
+
const handleClearAll = useCallback(async () => {
|
|
276
|
+
navigateWithoutReload(
|
|
277
|
+
getQueryUrl({
|
|
278
|
+
$filter: void 0,
|
|
279
|
+
filter: void 0,
|
|
280
|
+
$orderby: void 0,
|
|
281
|
+
orderBy: void 0
|
|
282
|
+
})
|
|
283
|
+
);
|
|
284
|
+
return { isSuccessful: true };
|
|
285
|
+
}, [getQueryUrl, navigateWithoutReload]);
|
|
286
|
+
const hasFacetControls = showFacets && activeFacets.length > 0;
|
|
287
|
+
const hasSortControls = showSortOptions && normalizedSortOptions.length > 0;
|
|
288
|
+
const hasActiveFiltersOrSort = Boolean(
|
|
289
|
+
currentFilter.trim() || currentSort.trim()
|
|
290
|
+
);
|
|
291
|
+
const selectedFacetCount = selectedFacetValues.size;
|
|
292
|
+
const shouldShowToolbarClearAll = hasActiveFiltersOrSort && !hasFacetControls;
|
|
293
|
+
const shouldShowToolbar = mode === "toolbar" && (showSearchBar || hasSortControls || shouldShowToolbarClearAll);
|
|
294
|
+
const shouldShowFacets = mode === "facets" && hasFacetControls;
|
|
295
|
+
if (!shouldShowToolbar && !shouldShowFacets) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
const renderFacetItems = (field, values) => /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1 pt-1 pb-1", children: values.map((facet) => {
|
|
299
|
+
const isSelected = selectedFacetValues.get(field) === facet.value;
|
|
300
|
+
return /* @__PURE__ */ jsxs(
|
|
301
|
+
"button",
|
|
302
|
+
{
|
|
303
|
+
type: "button",
|
|
304
|
+
onClick: () => navigateWithoutReload(getFacetUrl(field, facet.value)),
|
|
305
|
+
"aria-pressed": isSelected,
|
|
306
|
+
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"}`,
|
|
307
|
+
children: [
|
|
308
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [
|
|
309
|
+
/* @__PURE__ */ jsx(
|
|
310
|
+
"span",
|
|
311
|
+
{
|
|
312
|
+
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"}`,
|
|
313
|
+
children: isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-3 w-3" })
|
|
314
|
+
}
|
|
315
|
+
),
|
|
316
|
+
/* @__PURE__ */ jsx("span", { className: "leading-snug break-words", children: facet.value })
|
|
317
|
+
] }),
|
|
318
|
+
/* @__PURE__ */ jsx(
|
|
319
|
+
"span",
|
|
320
|
+
{
|
|
321
|
+
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"}`,
|
|
322
|
+
children: facet.count
|
|
323
|
+
}
|
|
324
|
+
)
|
|
325
|
+
]
|
|
326
|
+
},
|
|
327
|
+
`${field}-${facet.value}`
|
|
328
|
+
);
|
|
329
|
+
}) });
|
|
330
|
+
return /* @__PURE__ */ jsxs(
|
|
331
|
+
"div",
|
|
332
|
+
{
|
|
333
|
+
className: mode === "toolbar" ? "my-6" : "flex flex-col rounded-md border bg-default p-3.5 shadow-sm",
|
|
334
|
+
children: [
|
|
335
|
+
shouldShowToolbar && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between", children: [
|
|
336
|
+
showSearchBar && /* @__PURE__ */ jsxs(
|
|
337
|
+
"form",
|
|
338
|
+
{
|
|
339
|
+
role: "search",
|
|
340
|
+
className: "flex w-full items-center gap-2 sm:flex-row md:min-w-0 md:flex-1",
|
|
341
|
+
onSubmit: (event) => {
|
|
342
|
+
event.preventDefault();
|
|
343
|
+
void handleSearch();
|
|
344
|
+
},
|
|
345
|
+
children: [
|
|
346
|
+
/* @__PURE__ */ jsxs("div", { className: "relative min-w-0 flex-1", children: [
|
|
347
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "pointer-events-none absolute left-3.5 top-1/2 z-10 h-4 w-4 -translate-y-1/2 opacity-60" }),
|
|
348
|
+
/* @__PURE__ */ jsx(
|
|
349
|
+
InputControl_default,
|
|
350
|
+
{
|
|
351
|
+
name: "searchText",
|
|
352
|
+
controlType: InputControlType_default.lineTextInput,
|
|
353
|
+
value: searchText,
|
|
354
|
+
callback: (updatedValues) => setSearchText(updatedValues.value),
|
|
355
|
+
attributes: {
|
|
356
|
+
placeholder: "Search discussions, topics, or keywords..."
|
|
357
|
+
},
|
|
358
|
+
inputClasses: "!mt-0 !h-10 !rounded-md !border-neutral-soft !bg-default !py-2 !pl-10 !pr-4 !shadow-sm !text-sm focus:!border-primary-base focus:!ring-primary-base"
|
|
359
|
+
}
|
|
360
|
+
)
|
|
361
|
+
] }),
|
|
362
|
+
/* @__PURE__ */ jsxs(
|
|
363
|
+
Button_default,
|
|
364
|
+
{
|
|
365
|
+
ButtonType: "Primary" /* Solid */,
|
|
366
|
+
onClick: handleSearch,
|
|
367
|
+
className: "!h-10 !rounded-md !px-5 !py-0 flex items-center justify-center gap-1.5 shrink-0",
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsx(SearchIcon, { className: "h-4 w-4" }),
|
|
370
|
+
/* @__PURE__ */ jsx("span", { children: "Search" })
|
|
371
|
+
]
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
]
|
|
375
|
+
}
|
|
376
|
+
),
|
|
377
|
+
hasSortControls && /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", ref: sortDropdownRef, children: [
|
|
378
|
+
/* @__PURE__ */ jsxs(
|
|
379
|
+
"button",
|
|
380
|
+
{
|
|
381
|
+
type: "button",
|
|
382
|
+
onClick: () => setIsSortOpen((prev) => !prev),
|
|
383
|
+
"aria-expanded": isSortOpen,
|
|
384
|
+
className: "inline-flex h-10 items-center justify-between gap-2.5 rounded-md border bg-default px-3.5 text-sm font-normal shadow-sm transition-all hover:bg-neutral-weak focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-base cursor-pointer whitespace-nowrap",
|
|
385
|
+
children: [
|
|
386
|
+
/* @__PURE__ */ jsxs("span", { className: "whitespace-nowrap", children: [
|
|
387
|
+
/* @__PURE__ */ jsx("span", { className: "opacity-70", children: "Sort by: " }),
|
|
388
|
+
/* @__PURE__ */ jsx("span", { className: "font-semibold", children: selectedSortLabel })
|
|
389
|
+
] }),
|
|
390
|
+
/* @__PURE__ */ jsx(
|
|
391
|
+
ChevronDownIcon,
|
|
392
|
+
{
|
|
393
|
+
className: `h-4 w-4 shrink-0 transition-transform duration-200 ${isSortOpen ? "rotate-180" : ""}`
|
|
394
|
+
}
|
|
395
|
+
)
|
|
396
|
+
]
|
|
397
|
+
}
|
|
398
|
+
),
|
|
399
|
+
isSortOpen && /* @__PURE__ */ jsx("div", { className: "absolute right-0 z-50 mt-1.5 w-max min-w-full max-h-80 overflow-y-auto rounded-lg border border-neutral-soft bg-default p-1 shadow-lg", children: normalizedSortOptions.map((option) => {
|
|
400
|
+
const isSelected = currentSort ? option.value === currentSort : option.value === normalizedSortOptions[0]?.value;
|
|
401
|
+
return /* @__PURE__ */ jsxs(
|
|
402
|
+
"button",
|
|
403
|
+
{
|
|
404
|
+
type: "button",
|
|
405
|
+
onClick: () => {
|
|
406
|
+
setIsSortOpen(false);
|
|
407
|
+
navigateWithoutReload(
|
|
408
|
+
getQueryUrl({
|
|
409
|
+
$orderby: option.value || void 0,
|
|
410
|
+
orderBy: void 0
|
|
411
|
+
})
|
|
412
|
+
);
|
|
413
|
+
},
|
|
414
|
+
className: `flex w-full items-center justify-between gap-4 rounded-md px-3 py-1.5 text-left text-sm transition-colors cursor-pointer whitespace-nowrap ${isSelected ? "bg-primary-base font-semibold" : "hover:bg-neutral-soft font-normal"}`,
|
|
415
|
+
children: [
|
|
416
|
+
/* @__PURE__ */ jsx("span", { className: "whitespace-nowrap", children: option.label }),
|
|
417
|
+
isSelected && /* @__PURE__ */ jsx(CheckIcon, { className: "h-4 w-4 shrink-0" })
|
|
418
|
+
]
|
|
419
|
+
},
|
|
420
|
+
option.value
|
|
421
|
+
);
|
|
422
|
+
}) })
|
|
423
|
+
] })
|
|
424
|
+
] }),
|
|
425
|
+
shouldShowFacets && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
426
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b pb-3", children: [
|
|
427
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
428
|
+
/* @__PURE__ */ jsx(FilterSlidersIcon, { className: "h-4 w-4" }),
|
|
429
|
+
/* @__PURE__ */ jsx("h2", { className: "text-base font-semibold tracking-tight", children: "Filters" }),
|
|
430
|
+
selectedFacetCount > 0 && /* @__PURE__ */ jsx("span", { className: "flex h-5 items-center justify-center rounded-full bg-primary-base px-2 text-xs font-semibold", children: selectedFacetCount })
|
|
431
|
+
] }),
|
|
432
|
+
hasActiveFiltersOrSort && /* @__PURE__ */ jsxs(
|
|
433
|
+
"button",
|
|
434
|
+
{
|
|
435
|
+
type: "button",
|
|
436
|
+
onClick: () => void handleClearAll(),
|
|
437
|
+
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",
|
|
438
|
+
"aria-label": "Clear all filters and sorting",
|
|
439
|
+
children: [
|
|
440
|
+
/* @__PURE__ */ jsx(ResetIcon, { className: "h-3.5 w-3.5 transition-transform duration-200 group-hover:-rotate-45" }),
|
|
441
|
+
/* @__PURE__ */ jsx("span", { children: "Clear all" })
|
|
442
|
+
]
|
|
443
|
+
}
|
|
444
|
+
)
|
|
445
|
+
] }),
|
|
446
|
+
selectedFacetCount > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5 pb-2.5 border-b ", children: Array.from(selectedFacetValues.entries()).map(([field, value]) => /* @__PURE__ */ jsxs(
|
|
447
|
+
"button",
|
|
448
|
+
{
|
|
449
|
+
type: "button",
|
|
450
|
+
onClick: () => clearFacetField(field),
|
|
451
|
+
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",
|
|
452
|
+
title: `Remove filter: ${value}`,
|
|
453
|
+
children: [
|
|
454
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium truncate max-w-[150px]", children: value }),
|
|
455
|
+
/* @__PURE__ */ jsx(CloseIcon, { className: "h-3.5 w-3.5 shrink-0 opacity-60 group-hover:opacity-100" })
|
|
456
|
+
]
|
|
457
|
+
},
|
|
458
|
+
`chip-${field}`
|
|
459
|
+
)) }),
|
|
460
|
+
activeFacets.length === 1 && /* @__PURE__ */ jsx("nav", { "aria-label": `${humanize(activeFacets[0][0])} filters`, children: /* @__PURE__ */ jsxs("div", { className: "py-1", children: [
|
|
461
|
+
/* @__PURE__ */ jsx("div", { className: "px-1 pb-2 font-medium text-sm", children: humanize(activeFacets[0][0]) }),
|
|
462
|
+
renderFacetItems(activeFacets[0][0], activeFacets[0][1])
|
|
463
|
+
] }) }),
|
|
464
|
+
activeFacets.length > 1 && /* @__PURE__ */ jsx("div", { className: "flex flex-col divide-y divide-neutral-soft", children: activeFacets.map(([field, values]) => {
|
|
465
|
+
const isOpen = !collapsedCategories[field];
|
|
466
|
+
return /* @__PURE__ */ jsxs(
|
|
467
|
+
"div",
|
|
468
|
+
{
|
|
469
|
+
className: "py-2 first:pt-0 last:pb-0",
|
|
470
|
+
children: [
|
|
471
|
+
/* @__PURE__ */ jsxs(
|
|
472
|
+
"button",
|
|
473
|
+
{
|
|
474
|
+
type: "button",
|
|
475
|
+
onClick: () => toggleCategory(field),
|
|
476
|
+
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",
|
|
477
|
+
children: [
|
|
478
|
+
/* @__PURE__ */ jsx("span", { children: humanize(field) }),
|
|
479
|
+
/* @__PURE__ */ jsx(
|
|
480
|
+
ChevronDownIcon,
|
|
481
|
+
{
|
|
482
|
+
className: `h-4 w-4 transition-transform duration-200 ease-out ${isOpen ? "rotate-180" : ""}`
|
|
483
|
+
}
|
|
484
|
+
)
|
|
485
|
+
]
|
|
486
|
+
}
|
|
487
|
+
),
|
|
488
|
+
isOpen && /* @__PURE__ */ jsx("div", { className: "pt-1", children: renderFacetItems(field, values) })
|
|
489
|
+
]
|
|
490
|
+
},
|
|
491
|
+
field
|
|
492
|
+
);
|
|
493
|
+
}) })
|
|
494
|
+
] })
|
|
495
|
+
]
|
|
496
|
+
}
|
|
497
|
+
);
|
|
498
|
+
};
|
|
499
|
+
var DataBindingControls_default = DataBindingControls;
|
|
500
|
+
export {
|
|
501
|
+
DataBindingControls_default as default
|
|
502
|
+
};
|