@turtleclub/core 0.1.0-beta.100

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.cjs ADDED
@@ -0,0 +1,1179 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ActiveFilterBadges: () => ActiveFilterBadges,
24
+ BooleanFilter: () => BooleanFilter,
25
+ ChainSelector: () => ChainSelector,
26
+ ChainsSelector: () => ChainsSelector,
27
+ Filter: () => Filter,
28
+ FiltersGrid: () => FiltersGrid,
29
+ FiltersPopover: () => FiltersPopover,
30
+ FiltersWrapper: () => FiltersWrapper,
31
+ MultiSelectFilter: () => MultiSelectFilter,
32
+ OpportunitiesSelector: () => OpportunitiesSelector,
33
+ OpportunitySelector: () => OpportunitySelector,
34
+ ProductSelector: () => ProductSelector,
35
+ ProductsSelector: () => ProductsSelector,
36
+ RangeSliderFilter: () => RangeSliderFilter,
37
+ TokenSelector: () => TokenSelector,
38
+ TokensSelector: () => TokensSelector,
39
+ usePagination: () => usePagination,
40
+ useSorting: () => useSorting
41
+ });
42
+ module.exports = __toCommonJS(index_exports);
43
+
44
+ // src/filters/RangeSliderFilter.tsx
45
+ var import_react = require("react");
46
+ var import_ui = require("@turtleclub/ui");
47
+ var import_nuqs = require("nuqs");
48
+ var import_jsx_runtime = require("react/jsx-runtime");
49
+ var defaultFormatter = (value) => {
50
+ return value.toLocaleString();
51
+ };
52
+ function RangeSliderFilter({
53
+ minQueryKey = "min",
54
+ maxQueryKey = "max",
55
+ min = 0,
56
+ max = 100,
57
+ step = 1,
58
+ disabled = false,
59
+ label = "Range",
60
+ showValues = true,
61
+ formatValue = defaultFormatter,
62
+ className = "",
63
+ usePopover = false
64
+ }) {
65
+ const [minValue, setMinValue] = (0, import_nuqs.useQueryState)(minQueryKey, import_nuqs.parseAsInteger.withDefault(min));
66
+ const [maxValue, setMaxValue] = (0, import_nuqs.useQueryState)(maxQueryKey, import_nuqs.parseAsInteger.withDefault(max));
67
+ const [localRange, setLocalRange] = (0, import_react.useState)([minValue, maxValue]);
68
+ const [minInputValue, setMinInputValue] = (0, import_react.useState)(minValue.toString());
69
+ const [maxInputValue, setMaxInputValue] = (0, import_react.useState)(maxValue.toString());
70
+ (0, import_react.useEffect)(() => {
71
+ setLocalRange([minValue, maxValue]);
72
+ setMinInputValue(minValue.toString());
73
+ setMaxInputValue(maxValue.toString());
74
+ }, [minValue, maxValue]);
75
+ const handleRangeChange = (values) => {
76
+ setLocalRange(values);
77
+ };
78
+ const handleRangeCommit = (values) => {
79
+ const [newMin, newMax] = values;
80
+ if (newMin !== minValue) {
81
+ setMinValue(newMin === min ? null : newMin);
82
+ }
83
+ if (newMax !== maxValue) {
84
+ setMaxValue(newMax === max ? null : newMax);
85
+ }
86
+ };
87
+ const handleMinInputChange = (e) => {
88
+ setMinInputValue(e.target.value);
89
+ };
90
+ const handleMaxInputChange = (e) => {
91
+ setMaxInputValue(e.target.value);
92
+ };
93
+ const handleMinInputBlur = () => {
94
+ const numValue = parseInt(minInputValue, 10);
95
+ if (!isNaN(numValue)) {
96
+ const clampedValue = Math.max(min, Math.min(numValue, localRange[1]));
97
+ setLocalRange([clampedValue, localRange[1]]);
98
+ handleRangeCommit([clampedValue, localRange[1]]);
99
+ setMinInputValue(clampedValue.toString());
100
+ } else {
101
+ setMinInputValue(localRange[0].toString());
102
+ }
103
+ };
104
+ const handleMaxInputBlur = () => {
105
+ const numValue = parseInt(maxInputValue, 10);
106
+ if (!isNaN(numValue)) {
107
+ const clampedValue = Math.min(max, Math.max(numValue, localRange[0]));
108
+ setLocalRange([localRange[0], clampedValue]);
109
+ handleRangeCommit([localRange[0], clampedValue]);
110
+ setMaxInputValue(clampedValue.toString());
111
+ } else {
112
+ setMaxInputValue(localRange[1].toString());
113
+ }
114
+ };
115
+ const handleMinInputKeyDown = (e) => {
116
+ if (e.key === "Enter") {
117
+ handleMinInputBlur();
118
+ }
119
+ };
120
+ const handleMaxInputKeyDown = (e) => {
121
+ if (e.key === "Enter") {
122
+ handleMaxInputBlur();
123
+ }
124
+ };
125
+ const isDefaultRange = localRange[0] === min && localRange[1] === max;
126
+ const filterContent = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "space-y-3", children: [
127
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center justify-between", children: [
128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ui.Label, { className: "text-sm font-medium", children: label }),
129
+ showValues && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
130
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: formatValue(localRange[0]) }),
131
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "-" }),
132
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: formatValue(localRange[1]) })
133
+ ] })
134
+ ] }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "px-2", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
136
+ import_ui.Slider,
137
+ {
138
+ value: localRange,
139
+ onValueChange: handleRangeChange,
140
+ onValueCommit: handleRangeCommit,
141
+ min,
142
+ max,
143
+ step,
144
+ disabled,
145
+ className: "w-full"
146
+ }
147
+ ) }),
148
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex justify-between gap-2", children: [
149
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1 flex-1", children: [
150
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ui.Label, { htmlFor: "min-input", className: "text-xs text-muted-foreground", children: "Min" }),
151
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
152
+ import_ui.Input,
153
+ {
154
+ id: "min-input",
155
+ type: "number",
156
+ value: minInputValue,
157
+ onChange: handleMinInputChange,
158
+ onBlur: handleMinInputBlur,
159
+ onKeyDown: handleMinInputKeyDown,
160
+ min,
161
+ max: localRange[1],
162
+ step,
163
+ disabled,
164
+ className: "h-7 text-xs [appearance:textfield] [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:[-webkit-appearance:none] [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:[-webkit-appearance:none]"
165
+ }
166
+ )
167
+ ] }),
168
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex flex-col gap-1 flex-1", children: [
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ui.Label, { htmlFor: "max-input", className: "text-xs text-muted-foreground text-right", children: "Max" }),
170
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
171
+ import_ui.Input,
172
+ {
173
+ id: "max-input",
174
+ type: "number",
175
+ value: maxInputValue,
176
+ onChange: handleMaxInputChange,
177
+ onBlur: handleMaxInputBlur,
178
+ onKeyDown: handleMaxInputKeyDown,
179
+ min: localRange[0],
180
+ max,
181
+ step,
182
+ disabled,
183
+ className: "h-7 text-xs [appearance:textfield] [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:[-webkit-appearance:none] [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:[-webkit-appearance:none]"
184
+ }
185
+ )
186
+ ] })
187
+ ] }),
188
+ !isDefaultRange && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
189
+ "button",
190
+ {
191
+ onClick: () => {
192
+ setLocalRange([min, max]);
193
+ setMinInputValue(min.toString());
194
+ setMaxInputValue(max.toString());
195
+ handleRangeCommit([min, max]);
196
+ },
197
+ className: "text-xs text-muted-foreground hover:text-foreground transition-colors",
198
+ disabled,
199
+ children: "Reset"
200
+ }
201
+ ) })
202
+ ] });
203
+ if (usePopover) {
204
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ui.Popover, { children: [
205
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
206
+ import_ui.PopoverTrigger,
207
+ {
208
+ className: (0, import_ui.cn)(
209
+ (0, import_ui.buttonVariants)({
210
+ variant: "default",
211
+ size: "default",
212
+ border: "bordered"
213
+ }),
214
+ "!bg-neutral-alpha-2",
215
+ className
216
+ ),
217
+ disabled,
218
+ children: [
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-medium", children: [
220
+ label,
221
+ ":"
222
+ ] }),
223
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-muted-foreground", children: showValues && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
224
+ "[",
225
+ formatValue(localRange[0]),
226
+ " - ",
227
+ formatValue(localRange[1]),
228
+ "]"
229
+ ] }) })
230
+ ]
231
+ }
232
+ ),
233
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ui.PopoverContent, { className: "min-w-96", children: filterContent })
234
+ ] });
235
+ }
236
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className, children: filterContent });
237
+ }
238
+
239
+ // src/filters/BooleanFilter.tsx
240
+ var import_ui2 = require("@turtleclub/ui");
241
+ var import_nuqs2 = require("nuqs");
242
+ var import_jsx_runtime2 = require("react/jsx-runtime");
243
+ function BooleanFilter({
244
+ queryKey = "enabled",
245
+ defaultValue = false,
246
+ disabled = false,
247
+ label,
248
+ description,
249
+ className = ""
250
+ }) {
251
+ const [value, setValue] = (0, import_nuqs2.useQueryState)(queryKey, import_nuqs2.parseAsBoolean.withDefault(defaultValue));
252
+ const handleToggle = (checked) => {
253
+ setValue(checked === defaultValue ? null : checked);
254
+ };
255
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `flex items-center justify-between space-x-2 ${className}`, children: [
256
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-0.5", children: [
257
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui2.Label, { className: "text-sm font-medium", children: label }),
258
+ description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-muted-foreground", children: description })
259
+ ] }),
260
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ui2.Switch, { checked: value, onCheckedChange: handleToggle, disabled })
261
+ ] });
262
+ }
263
+
264
+ // src/filters/Filter.tsx
265
+ var import_nuqs3 = require("nuqs");
266
+ var import_jsx_runtime3 = require("react/jsx-runtime");
267
+ function Filter({ queryKey, children, onValueChange }) {
268
+ const [value, setValue] = (0, import_nuqs3.useQueryState)(queryKey, import_nuqs3.parseAsString.withDefault(""));
269
+ const handleValueChange = (newValue) => {
270
+ setValue(newValue || null);
271
+ onValueChange?.(newValue);
272
+ };
273
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children: children({ value, onValueChange: handleValueChange }) });
274
+ }
275
+
276
+ // src/filters/MultiSelectFilter.tsx
277
+ var import_nuqs4 = require("nuqs");
278
+ var import_jsx_runtime4 = require("react/jsx-runtime");
279
+ function MultiSelectFilter({ queryKey, children, onValueChange }) {
280
+ const [value, setValue] = (0, import_nuqs4.useQueryState)(queryKey, (0, import_nuqs4.parseAsArrayOf)(import_nuqs4.parseAsString).withDefault([]));
281
+ const handleValueChange = (newValue) => {
282
+ setValue(newValue.length > 0 ? newValue : null);
283
+ onValueChange?.(newValue);
284
+ };
285
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: children({ value, onValueChange: handleValueChange }) });
286
+ }
287
+
288
+ // src/wrappers/FiltersGrid.tsx
289
+ var import_ui3 = require("@turtleclub/ui");
290
+ var import_jsx_runtime5 = require("react/jsx-runtime");
291
+ function FiltersGrid({
292
+ filters,
293
+ columns = 3,
294
+ className,
295
+ sectionClassName
296
+ }) {
297
+ const enabledFilters = filters.filter((filter) => filter.enabled);
298
+ if (enabledFilters.length === 0) {
299
+ return null;
300
+ }
301
+ const sections = enabledFilters.reduce(
302
+ (acc, filter) => {
303
+ const sectionName = filter.section || "default";
304
+ if (!acc[sectionName]) {
305
+ acc[sectionName] = [];
306
+ }
307
+ acc[sectionName].push(filter);
308
+ return acc;
309
+ },
310
+ {}
311
+ );
312
+ const sectionNames = Object.keys(sections);
313
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: (0, import_ui3.cn)("space-y-4", className), children: sectionNames.map((sectionName, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
314
+ sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "border-t border-border mb-4" }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
316
+ "div",
317
+ {
318
+ className: (0, import_ui3.cn)("grid gap-2", sectionClassName),
319
+ style: {
320
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`
321
+ },
322
+ children: sections[sectionName].map((filter) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "flex flex-col gap-2", children: filter.component }, filter.key))
323
+ }
324
+ )
325
+ ] }, sectionName)) });
326
+ }
327
+
328
+ // src/wrappers/FiltersPopover.tsx
329
+ var import_ui4 = require("@turtleclub/ui");
330
+ var import_jsx_runtime6 = require("react/jsx-runtime");
331
+ function FiltersPopover({
332
+ filters,
333
+ triggerLabel = "Filters",
334
+ columns = 2,
335
+ className,
336
+ popoverClassName,
337
+ sectionClassName,
338
+ align = "start",
339
+ onClearAll
340
+ }) {
341
+ const enabledFilters = filters.filter((filter) => filter.enabled);
342
+ if (enabledFilters.length === 0) {
343
+ return null;
344
+ }
345
+ const sections = enabledFilters.reduce(
346
+ (acc, filter) => {
347
+ const sectionName = filter.section || "default";
348
+ if (!acc[sectionName]) {
349
+ acc[sectionName] = [];
350
+ }
351
+ acc[sectionName].push(filter);
352
+ return acc;
353
+ },
354
+ {}
355
+ );
356
+ const sectionNames = Object.keys(sections);
357
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_ui4.Popover, { children: [
358
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
359
+ import_ui4.PopoverTrigger,
360
+ {
361
+ className: (0, import_ui4.cn)(
362
+ (0, import_ui4.buttonVariants)({
363
+ variant: "default",
364
+ size: "default",
365
+ border: "bordered"
366
+ }),
367
+ "!bg-neutral-alpha-2",
368
+ className
369
+ ),
370
+ children: triggerLabel
371
+ }
372
+ ),
373
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
374
+ import_ui4.PopoverContent,
375
+ {
376
+ className: (0, import_ui4.cn)("w-auto min-w-[400px] max-w-[600px]", popoverClassName),
377
+ align,
378
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "space-y-4", children: [
379
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center justify-between", children: [
380
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h4", { className: "font-medium text-sm", children: "Filters" }),
381
+ onClearAll && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
382
+ "button",
383
+ {
384
+ onClick: onClearAll,
385
+ className: "text-xs text-muted-foreground hover:text-foreground transition-colors",
386
+ children: "Reset all"
387
+ }
388
+ )
389
+ ] }),
390
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "space-y-4", children: sectionNames.map((sectionName, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
391
+ sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "border-t border-border mb-4" }),
392
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
393
+ "div",
394
+ {
395
+ className: (0, import_ui4.cn)("grid gap-2", sectionClassName),
396
+ style: {
397
+ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`
398
+ },
399
+ children: sections[sectionName].map((filter) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-col gap-2", children: filter.component }, filter.key))
400
+ }
401
+ )
402
+ ] }, sectionName)) })
403
+ ] })
404
+ }
405
+ )
406
+ ] });
407
+ }
408
+
409
+ // src/wrappers/ActiveFilterBadges.tsx
410
+ var import_react2 = require("react");
411
+ var import_ui5 = require("@turtleclub/ui");
412
+ var import_lucide_react = require("lucide-react");
413
+ var import_jsx_runtime7 = require("react/jsx-runtime");
414
+ function ActiveFilterBadges({
415
+ filters,
416
+ className,
417
+ clearAllLabel = "Clear All",
418
+ showClearAll = true,
419
+ renderBadge,
420
+ onClearFilter,
421
+ onClearAll
422
+ }) {
423
+ const activeFilters = (0, import_react2.useMemo)(() => {
424
+ return filters.filter((filter) => filter.isActive && filter.value);
425
+ }, [filters]);
426
+ const clearAll = () => {
427
+ const allQueryKeys = activeFilters.map((filter) => filter.queryKeys);
428
+ onClearAll(allQueryKeys);
429
+ };
430
+ if (activeFilters.length === 0) {
431
+ return null;
432
+ }
433
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: (0, import_ui5.cn)("flex flex-wrap items-center gap-2", className), children: [
434
+ activeFilters.map((filter) => {
435
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
436
+ FilterBadge,
437
+ {
438
+ filter,
439
+ renderBadge,
440
+ onClearFilter
441
+ },
442
+ filter.key
443
+ );
444
+ }),
445
+ showClearAll && activeFilters.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ui5.Button, { variant: "ghost", size: "sm", onClick: clearAll, className: "h-7 px-2 text-xs", children: clearAllLabel })
446
+ ] });
447
+ }
448
+ function FilterBadge({ filter, renderBadge, onClearFilter }) {
449
+ const clearFilter = () => {
450
+ onClearFilter(filter.queryKeys);
451
+ };
452
+ if (renderBadge) {
453
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: renderBadge(filter, clearFilter) });
454
+ }
455
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ui5.Badge, { className: "flex items-center gap-1 pr-1 border-border border", children: [
456
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "text-xs", children: [
457
+ filter.label,
458
+ ": ",
459
+ filter.value
460
+ ] }),
461
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
462
+ "button",
463
+ {
464
+ onClick: clearFilter,
465
+ className: "ml-1 rounded-full p-0.5 hover:bg-black/10 focus:bg-black/10 focus:outline-none",
466
+ "aria-label": `Clear ${filter.label} filter`,
467
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_lucide_react.X, { className: "h-3 w-3" })
468
+ }
469
+ )
470
+ ] });
471
+ }
472
+
473
+ // src/wrappers/FiltersWrapper.tsx
474
+ var import_ui6 = require("@turtleclub/ui");
475
+ var import_jsx_runtime8 = require("react/jsx-runtime");
476
+ function FiltersWrapper({
477
+ filters,
478
+ activeFilters,
479
+ layout,
480
+ className,
481
+ badgesClassName,
482
+ slotClassName,
483
+ leftSlot,
484
+ rightSlot,
485
+ columns = 3,
486
+ triggerLabel = "Filters",
487
+ popoverColumns = 2,
488
+ popoverClassName,
489
+ popoverContentClassName,
490
+ align = "start",
491
+ clearAllLabel = "Clear All",
492
+ showClearAll = true,
493
+ renderBadge,
494
+ showActiveBadges = true,
495
+ onClearFilter,
496
+ onClearAll
497
+ }) {
498
+ const hasActiveFilters = activeFilters.some((filter) => filter.isActive && filter.value);
499
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: (0, import_ui6.cn)("space-y-3", className), children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: (0, import_ui6.cn)("flex items-center gap-2", slotClassName), children: [
501
+ leftSlot,
502
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: layout === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FiltersGrid, { filters, columns, className: popoverClassName }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
503
+ FiltersPopover,
504
+ {
505
+ filters,
506
+ triggerLabel,
507
+ columns: popoverColumns,
508
+ className: popoverClassName,
509
+ popoverClassName: popoverContentClassName,
510
+ align,
511
+ onClearAll: () => {
512
+ const allQueryKeys = activeFilters.map((filter) => filter.queryKeys).filter((keys) => keys !== void 0);
513
+ onClearAll(allQueryKeys);
514
+ }
515
+ }
516
+ ) }),
517
+ rightSlot
518
+ ] }),
519
+ showActiveBadges && hasActiveFilters && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
520
+ ActiveFilterBadges,
521
+ {
522
+ filters: activeFilters,
523
+ className: badgesClassName,
524
+ clearAllLabel,
525
+ showClearAll,
526
+ renderBadge,
527
+ onClearFilter,
528
+ onClearAll
529
+ }
530
+ )
531
+ ] });
532
+ }
533
+
534
+ // src/helpers/usePagination.ts
535
+ var import_nuqs5 = require("nuqs");
536
+ var import_react3 = require("react");
537
+ function usePagination(options = {}) {
538
+ const {
539
+ defaultPageSize = 10,
540
+ defaultPageIndex = 0,
541
+ pageIndexKey = "page",
542
+ pageSizeKey = "pageSize"
543
+ } = options;
544
+ const [rawPageIndex, setRawPageIndex] = (0, import_nuqs5.useQueryState)(
545
+ pageIndexKey,
546
+ import_nuqs5.parseAsInteger.withDefault(defaultPageIndex)
547
+ );
548
+ const [rawPageSize, setRawPageSize] = (0, import_nuqs5.useQueryState)(
549
+ pageSizeKey,
550
+ import_nuqs5.parseAsInteger.withDefault(defaultPageSize)
551
+ );
552
+ const pageIndex = (0, import_react3.useMemo)(() => Math.max(0, rawPageIndex), [rawPageIndex]);
553
+ const pageSize = rawPageSize;
554
+ const pagination = (0, import_react3.useMemo)(
555
+ () => ({
556
+ pageIndex,
557
+ pageSize
558
+ }),
559
+ [pageIndex, pageSize]
560
+ );
561
+ const setPagination = (0, import_react3.useCallback)(
562
+ (updater) => {
563
+ const newPagination = typeof updater === "function" ? updater(pagination) : updater;
564
+ if (newPagination.pageIndex !== pageIndex) {
565
+ setRawPageIndex(Math.max(0, newPagination.pageIndex));
566
+ }
567
+ if (newPagination.pageSize !== pageSize) {
568
+ setRawPageSize(newPagination.pageSize);
569
+ }
570
+ },
571
+ [pagination, pageIndex, pageSize, setRawPageIndex, setRawPageSize]
572
+ );
573
+ const setPageIndex = (0, import_react3.useCallback)(
574
+ (newPageIndex) => {
575
+ setRawPageIndex(Math.max(0, newPageIndex));
576
+ },
577
+ [setRawPageIndex]
578
+ );
579
+ const setPageSize = (0, import_react3.useCallback)(
580
+ (newPageSize) => {
581
+ setRawPageSize(newPageSize);
582
+ setRawPageIndex(0);
583
+ },
584
+ [setRawPageSize, setRawPageIndex]
585
+ );
586
+ const nextPage = (0, import_react3.useCallback)(
587
+ (totalPages) => {
588
+ const nextPageIndex = pageIndex + 1;
589
+ if (!totalPages || nextPageIndex < totalPages) {
590
+ setPageIndex(nextPageIndex);
591
+ }
592
+ },
593
+ [pageIndex, setPageIndex]
594
+ );
595
+ const previousPage = (0, import_react3.useCallback)(() => {
596
+ if (pageIndex > 0) {
597
+ setPageIndex(pageIndex - 1);
598
+ }
599
+ }, [pageIndex, setPageIndex]);
600
+ const firstPage = (0, import_react3.useCallback)(() => {
601
+ setPageIndex(0);
602
+ }, [setPageIndex]);
603
+ const lastPage = (0, import_react3.useCallback)(
604
+ (totalPages) => {
605
+ setPageIndex(Math.max(0, totalPages - 1));
606
+ },
607
+ [setPageIndex]
608
+ );
609
+ const reset = (0, import_react3.useCallback)(() => {
610
+ setRawPageIndex(defaultPageIndex);
611
+ setRawPageSize(defaultPageSize);
612
+ }, [setRawPageIndex, setRawPageSize, defaultPageIndex, defaultPageSize]);
613
+ const canPreviousPage = pageIndex > 0;
614
+ const canNextPage = (0, import_react3.useCallback)(
615
+ (totalPages) => {
616
+ if (!totalPages) return true;
617
+ return pageIndex < totalPages - 1;
618
+ },
619
+ [pageIndex]
620
+ );
621
+ return {
622
+ pagination,
623
+ setPagination,
624
+ pageIndex,
625
+ pageSize,
626
+ setPageIndex,
627
+ setPageSize,
628
+ nextPage,
629
+ previousPage,
630
+ firstPage,
631
+ lastPage,
632
+ reset,
633
+ canNextPage,
634
+ canPreviousPage
635
+ };
636
+ }
637
+
638
+ // src/helpers/useSorting.ts
639
+ var import_nuqs6 = require("nuqs");
640
+ var import_react4 = require("react");
641
+ function useSorting(options = {}) {
642
+ const {
643
+ defaultSortBy,
644
+ defaultSortOrder = "asc",
645
+ sortByKey = "sortBy",
646
+ sortOrderKey = "sortOrder"
647
+ } = options;
648
+ const [sortBy, setSortBy] = (0, import_nuqs6.useQueryState)(
649
+ sortByKey,
650
+ import_nuqs6.parseAsString.withDefault(defaultSortBy || "")
651
+ );
652
+ const [sortOrder, setSortOrder] = (0, import_nuqs6.useQueryState)(
653
+ sortOrderKey,
654
+ import_nuqs6.parseAsString.withDefault(defaultSortOrder)
655
+ );
656
+ const validSortOrder = (0, import_react4.useMemo)(() => {
657
+ return sortOrder === "desc" ? "desc" : "asc";
658
+ }, [sortOrder]);
659
+ const sorting = (0, import_react4.useMemo)(() => {
660
+ if (!sortBy || sortBy.trim() === "") {
661
+ return [];
662
+ }
663
+ return [
664
+ {
665
+ id: sortBy,
666
+ desc: validSortOrder === "desc"
667
+ }
668
+ ];
669
+ }, [sortBy, validSortOrder]);
670
+ const setSorting = (0, import_react4.useCallback)(
671
+ (updater) => {
672
+ const newSorting = typeof updater === "function" ? updater(sorting) : updater;
673
+ if (newSorting.length === 0) {
674
+ setSortBy("");
675
+ } else {
676
+ const firstSort = newSorting[0];
677
+ setSortBy(firstSort.id);
678
+ setSortOrder(firstSort.desc ? "desc" : "asc");
679
+ }
680
+ },
681
+ [sorting, setSortBy, setSortOrder]
682
+ );
683
+ const setSort = (0, import_react4.useCallback)(
684
+ (column, order = "asc") => {
685
+ setSortBy(column);
686
+ setSortOrder(order);
687
+ },
688
+ [setSortBy, setSortOrder]
689
+ );
690
+ const clearSort = (0, import_react4.useCallback)(() => {
691
+ setSortBy(null);
692
+ }, [setSortBy]);
693
+ const toggleSort = (0, import_react4.useCallback)(
694
+ (column) => {
695
+ if (sortBy === column) {
696
+ setSortOrder(validSortOrder === "asc" ? "desc" : "asc");
697
+ } else {
698
+ setSortBy(column);
699
+ setSortOrder("asc");
700
+ }
701
+ },
702
+ [sortBy, validSortOrder, setSortBy, setSortOrder]
703
+ );
704
+ const isSorted = (0, import_react4.useCallback)(
705
+ (column) => {
706
+ return sortBy === column;
707
+ },
708
+ [sortBy]
709
+ );
710
+ const getSortOrder = (0, import_react4.useCallback)(
711
+ (column) => {
712
+ return sortBy === column ? validSortOrder : void 0;
713
+ },
714
+ [sortBy, validSortOrder]
715
+ );
716
+ return {
717
+ sorting,
718
+ setSorting,
719
+ sortBy: sortBy || void 0,
720
+ sortOrder: validSortOrder,
721
+ setSort,
722
+ clearSort,
723
+ toggleSort,
724
+ isSorted,
725
+ getSortOrder
726
+ };
727
+ }
728
+
729
+ // src/selectors/ChainsSelector.tsx
730
+ var import_react5 = require("react");
731
+ var import_ui7 = require("@turtleclub/ui");
732
+ var import_hooks = require("@turtleclub/hooks");
733
+ var import_jsx_runtime9 = require("react/jsx-runtime");
734
+ function ChainsSelector({
735
+ value,
736
+ onValueChange,
737
+ placeholder = "Select chains",
738
+ disabled = false,
739
+ className,
740
+ maxCount = 1,
741
+ closeOnSelect = true,
742
+ searchable = true
743
+ }) {
744
+ const { chains, isLoading } = (0, import_hooks.useSupportedChains)({
745
+ page: 1,
746
+ limit: 100
747
+ // High limit to fetch all chains
748
+ });
749
+ const chainOptions = (0, import_react5.useMemo)(() => {
750
+ if (!chains || chains.length === 0) return [];
751
+ const filteredChains = chains.filter((chain) => chain.status === "active");
752
+ return filteredChains.map((chain) => ({
753
+ label: chain.name,
754
+ value: chain?.id ?? "",
755
+ icon: chain.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
756
+ "img",
757
+ {
758
+ src: chain.logoUrl,
759
+ alt: chain.name,
760
+ width: 16,
761
+ height: 16,
762
+ className: "size-4 rounded-full"
763
+ }
764
+ ) : void 0
765
+ }));
766
+ }, [chains]);
767
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
768
+ import_ui7.MultiSelect,
769
+ {
770
+ searchable,
771
+ options: chainOptions,
772
+ value,
773
+ onValueChange,
774
+ disabled: disabled || isLoading,
775
+ placeholder: isLoading ? "Loading chains..." : placeholder,
776
+ closeOnSelect,
777
+ maxCount,
778
+ className
779
+ }
780
+ );
781
+ }
782
+
783
+ // src/selectors/TokensSelector.tsx
784
+ var import_react6 = require("react");
785
+ var import_ui8 = require("@turtleclub/ui");
786
+ var import_hooks2 = require("@turtleclub/hooks");
787
+ var import_jsx_runtime10 = require("react/jsx-runtime");
788
+ function TokensSelector({
789
+ value,
790
+ onValueChange,
791
+ chainId,
792
+ placeholder = "Select tokens",
793
+ disabled = false,
794
+ className,
795
+ maxCount = 1,
796
+ closeOnSelect = true,
797
+ searchable = true
798
+ }) {
799
+ const isChainSelected = !!chainId && chainId.trim() !== "";
800
+ const { tokens, isLoading } = (0, import_hooks2.useSupportedTokens)({
801
+ chainId: isChainSelected ? chainId : "",
802
+ limit: 9e3,
803
+ enabled: isChainSelected
804
+ });
805
+ const tokenOptions = (0, import_react6.useMemo)(() => {
806
+ if (!tokens) return [];
807
+ return tokens.map((token) => ({
808
+ label: `${token.symbol} - ${token.name}`,
809
+ value: token?.id || "",
810
+ icon: token.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
811
+ "img",
812
+ {
813
+ src: token.logoUrl,
814
+ alt: token.name,
815
+ width: 16,
816
+ height: 16,
817
+ className: "size-4 rounded-full"
818
+ }
819
+ ) : void 0
820
+ }));
821
+ }, [tokens]);
822
+ (0, import_react6.useEffect)(() => {
823
+ if (!isChainSelected && value.length > 0) {
824
+ onValueChange([]);
825
+ }
826
+ }, [isChainSelected, value, onValueChange]);
827
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
828
+ import_ui8.MultiSelect,
829
+ {
830
+ searchable,
831
+ options: tokenOptions,
832
+ value,
833
+ onValueChange,
834
+ disabled: disabled || isLoading || !isChainSelected,
835
+ placeholder: !isChainSelected ? "Select a chain first" : isLoading ? "Loading tokens..." : placeholder,
836
+ closeOnSelect,
837
+ maxCount,
838
+ className
839
+ }
840
+ );
841
+ }
842
+
843
+ // src/selectors/ProductsSelector.tsx
844
+ var import_react7 = require("react");
845
+ var import_ui9 = require("@turtleclub/ui");
846
+ var import_hooks3 = require("@turtleclub/hooks");
847
+ var import_jsx_runtime11 = require("react/jsx-runtime");
848
+ function ProductsSelector({
849
+ value,
850
+ onValueChange,
851
+ placeholder = "Select products",
852
+ disabled = false,
853
+ className,
854
+ maxCount = 1,
855
+ closeOnSelect = true,
856
+ searchable = true
857
+ }) {
858
+ const { data: productsData, isLoading } = (0, import_hooks3.useProducts)({});
859
+ const products = (0, import_react7.useMemo)(() => productsData?.products ?? [], [productsData?.products]);
860
+ const productOptions = (0, import_react7.useMemo)(() => {
861
+ if (!products || products.length === 0) return [];
862
+ return products.map((product) => ({
863
+ label: product.name,
864
+ value: product.id,
865
+ icon: product.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
866
+ "img",
867
+ {
868
+ src: product.logoUrl,
869
+ alt: product.name,
870
+ width: 16,
871
+ height: 16,
872
+ className: "size-4 rounded-full"
873
+ }
874
+ ) : void 0
875
+ }));
876
+ }, [products]);
877
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
878
+ import_ui9.MultiSelect,
879
+ {
880
+ searchable,
881
+ options: productOptions,
882
+ value,
883
+ onValueChange,
884
+ disabled: disabled || isLoading,
885
+ placeholder: isLoading ? "Loading products..." : placeholder,
886
+ closeOnSelect,
887
+ maxCount,
888
+ className
889
+ }
890
+ );
891
+ }
892
+
893
+ // src/selectors/OpportunitiesSelector.tsx
894
+ var import_react8 = require("react");
895
+ var import_ui10 = require("@turtleclub/ui");
896
+ var import_hooks4 = require("@turtleclub/hooks");
897
+ var import_jsx_runtime12 = require("react/jsx-runtime");
898
+ function OpportunitiesSelector({
899
+ value,
900
+ onValueChange,
901
+ placeholder = "Select opportunities",
902
+ disabled = false,
903
+ className,
904
+ maxCount = 1,
905
+ closeOnSelect = true,
906
+ searchable = true
907
+ }) {
908
+ const { data: opportunitiesData, isLoading } = (0, import_hooks4.useOpportunities)();
909
+ const opportunities = (0, import_react8.useMemo)(
910
+ () => opportunitiesData?.opportunities ?? [],
911
+ [opportunitiesData?.opportunities]
912
+ );
913
+ const opportunityOptions = (0, import_react8.useMemo)(() => {
914
+ if (!opportunities || opportunities.length === 0) return [];
915
+ const filteredOpportunities = opportunities.filter((opp) => opp.status === "active");
916
+ return filteredOpportunities.map((opportunity) => ({
917
+ label: opportunity.name || opportunity.shortName,
918
+ value: opportunity.id,
919
+ description: opportunity.shortName !== opportunity.name ? opportunity.shortName : void 0,
920
+ icon: opportunity.depositTokens?.[0]?.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
921
+ "img",
922
+ {
923
+ src: opportunity.depositTokens[0].logoUrl,
924
+ alt: opportunity.name,
925
+ width: 16,
926
+ height: 16,
927
+ className: "size-4 rounded-full"
928
+ }
929
+ ) : void 0
930
+ }));
931
+ }, [opportunities]);
932
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
933
+ import_ui10.MultiSelect,
934
+ {
935
+ searchable,
936
+ options: opportunityOptions,
937
+ value,
938
+ onValueChange,
939
+ disabled: disabled || isLoading,
940
+ placeholder: isLoading ? "Loading opportunities..." : placeholder,
941
+ closeOnSelect,
942
+ maxCount,
943
+ className
944
+ }
945
+ );
946
+ }
947
+
948
+ // src/selectors/ChainSelector.tsx
949
+ var import_react9 = require("react");
950
+ var import_ui11 = require("@turtleclub/ui");
951
+ var import_hooks5 = require("@turtleclub/hooks");
952
+ var import_jsx_runtime13 = require("react/jsx-runtime");
953
+ function ChainSelector({
954
+ value,
955
+ onValueChange,
956
+ placeholder = "Select chain",
957
+ disabled = false,
958
+ className,
959
+ closeOnSelect = true,
960
+ searchable = true
961
+ }) {
962
+ const { chains, isLoading } = (0, import_hooks5.useSupportedChains)({
963
+ page: 1,
964
+ limit: 100
965
+ // High limit to fetch all chains
966
+ });
967
+ const chainOptions = (0, import_react9.useMemo)(() => {
968
+ if (!chains || chains.length === 0) return [];
969
+ const filteredChains = chains.filter((chain) => chain.status === "active");
970
+ return filteredChains.map((chain) => ({
971
+ label: chain.name,
972
+ value: chain?.id ?? "",
973
+ icon: chain.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
974
+ "img",
975
+ {
976
+ src: chain.logoUrl,
977
+ alt: chain.name,
978
+ width: 16,
979
+ height: 16,
980
+ className: "size-4 rounded-full"
981
+ }
982
+ ) : void 0
983
+ }));
984
+ }, [chains]);
985
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
986
+ import_ui11.Combobox,
987
+ {
988
+ searchable,
989
+ options: chainOptions,
990
+ value,
991
+ onValueChange,
992
+ disabled: disabled || isLoading,
993
+ placeholder: isLoading ? "Loading chains..." : placeholder,
994
+ closeOnSelect,
995
+ className
996
+ }
997
+ );
998
+ }
999
+
1000
+ // src/selectors/TokenSelector.tsx
1001
+ var import_react10 = require("react");
1002
+ var import_ui12 = require("@turtleclub/ui");
1003
+ var import_hooks6 = require("@turtleclub/hooks");
1004
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1005
+ function TokenSelector({
1006
+ value,
1007
+ onValueChange,
1008
+ chainId,
1009
+ placeholder = "Select token",
1010
+ disabled = false,
1011
+ className,
1012
+ closeOnSelect = true,
1013
+ searchable = true
1014
+ }) {
1015
+ const isChainSelected = !!chainId && chainId.trim() !== "";
1016
+ const { tokens, isLoading } = (0, import_hooks6.useSupportedTokens)({
1017
+ chainId: isChainSelected ? chainId : "",
1018
+ limit: 9e3,
1019
+ enabled: isChainSelected
1020
+ });
1021
+ const tokenOptions = (0, import_react10.useMemo)(() => {
1022
+ if (!tokens) return [];
1023
+ return tokens.map((token) => ({
1024
+ label: `${token.symbol} - ${token.name}`,
1025
+ value: token?.id || "",
1026
+ icon: token.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1027
+ "img",
1028
+ {
1029
+ src: token.logoUrl,
1030
+ alt: token.name,
1031
+ width: 16,
1032
+ height: 16,
1033
+ className: "size-4 rounded-full"
1034
+ }
1035
+ ) : void 0
1036
+ }));
1037
+ }, [tokens]);
1038
+ (0, import_react10.useEffect)(() => {
1039
+ if (!isChainSelected && value) {
1040
+ onValueChange("");
1041
+ }
1042
+ }, [isChainSelected, value, onValueChange]);
1043
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1044
+ import_ui12.Combobox,
1045
+ {
1046
+ searchable,
1047
+ options: tokenOptions,
1048
+ value,
1049
+ onValueChange,
1050
+ disabled: disabled || isLoading || !isChainSelected,
1051
+ placeholder: !isChainSelected ? "Select a chain first" : isLoading ? "Loading tokens..." : placeholder,
1052
+ closeOnSelect,
1053
+ className
1054
+ }
1055
+ );
1056
+ }
1057
+
1058
+ // src/selectors/ProductSelector.tsx
1059
+ var import_react11 = require("react");
1060
+ var import_ui13 = require("@turtleclub/ui");
1061
+ var import_hooks7 = require("@turtleclub/hooks");
1062
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1063
+ function ProductSelector({
1064
+ value,
1065
+ onValueChange,
1066
+ placeholder = "Select product",
1067
+ disabled = false,
1068
+ className,
1069
+ closeOnSelect = true,
1070
+ searchable = true
1071
+ }) {
1072
+ const { data: productsData, isLoading } = (0, import_hooks7.useProducts)({});
1073
+ const products = (0, import_react11.useMemo)(() => productsData?.products ?? [], [productsData?.products]);
1074
+ const productOptions = (0, import_react11.useMemo)(() => {
1075
+ if (!products || products.length === 0) return [];
1076
+ return products.map((product) => ({
1077
+ label: product.name,
1078
+ value: product.id,
1079
+ icon: product.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1080
+ "img",
1081
+ {
1082
+ src: product.logoUrl,
1083
+ alt: product.name,
1084
+ width: 16,
1085
+ height: 16,
1086
+ className: "size-4 rounded-full"
1087
+ }
1088
+ ) : void 0
1089
+ }));
1090
+ }, [products]);
1091
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1092
+ import_ui13.Combobox,
1093
+ {
1094
+ searchable,
1095
+ options: productOptions,
1096
+ value,
1097
+ onValueChange,
1098
+ disabled: disabled || isLoading,
1099
+ placeholder: isLoading ? "Loading products..." : placeholder,
1100
+ closeOnSelect,
1101
+ className
1102
+ }
1103
+ );
1104
+ }
1105
+
1106
+ // src/selectors/OpportunitySelector.tsx
1107
+ var import_react12 = require("react");
1108
+ var import_ui14 = require("@turtleclub/ui");
1109
+ var import_hooks8 = require("@turtleclub/hooks");
1110
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1111
+ function OpportunitySelector({
1112
+ value,
1113
+ onValueChange,
1114
+ placeholder = "Select opportunity",
1115
+ disabled = false,
1116
+ className,
1117
+ closeOnSelect = true,
1118
+ searchable = true
1119
+ }) {
1120
+ const { data: opportunitiesData, isLoading } = (0, import_hooks8.useOpportunities)();
1121
+ const opportunities = (0, import_react12.useMemo)(
1122
+ () => opportunitiesData?.opportunities ?? [],
1123
+ [opportunitiesData?.opportunities]
1124
+ );
1125
+ const opportunityOptions = (0, import_react12.useMemo)(() => {
1126
+ if (!opportunities || opportunities.length === 0) return [];
1127
+ const filteredOpportunities = opportunities.filter((opp) => opp.status === "active");
1128
+ return filteredOpportunities.map((opportunity) => ({
1129
+ label: opportunity.name || opportunity.shortName,
1130
+ value: opportunity.id,
1131
+ description: opportunity.shortName !== opportunity.name ? opportunity.shortName : void 0,
1132
+ icon: opportunity.depositTokens?.[0]?.logoUrl ? () => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1133
+ "img",
1134
+ {
1135
+ src: opportunity.depositTokens[0].logoUrl,
1136
+ alt: opportunity.name,
1137
+ width: 16,
1138
+ height: 16,
1139
+ className: "size-4 rounded-full"
1140
+ }
1141
+ ) : void 0
1142
+ }));
1143
+ }, [opportunities]);
1144
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1145
+ import_ui14.Combobox,
1146
+ {
1147
+ searchable,
1148
+ options: opportunityOptions,
1149
+ value,
1150
+ onValueChange,
1151
+ disabled: disabled || isLoading,
1152
+ placeholder: isLoading ? "Loading opportunities..." : placeholder,
1153
+ closeOnSelect,
1154
+ className
1155
+ }
1156
+ );
1157
+ }
1158
+ // Annotate the CommonJS export names for ESM import in node:
1159
+ 0 && (module.exports = {
1160
+ ActiveFilterBadges,
1161
+ BooleanFilter,
1162
+ ChainSelector,
1163
+ ChainsSelector,
1164
+ Filter,
1165
+ FiltersGrid,
1166
+ FiltersPopover,
1167
+ FiltersWrapper,
1168
+ MultiSelectFilter,
1169
+ OpportunitiesSelector,
1170
+ OpportunitySelector,
1171
+ ProductSelector,
1172
+ ProductsSelector,
1173
+ RangeSliderFilter,
1174
+ TokenSelector,
1175
+ TokensSelector,
1176
+ usePagination,
1177
+ useSorting
1178
+ });
1179
+ //# sourceMappingURL=index.cjs.map