@turtleclub/core 0.1.0-beta.15 → 0.1.0-beta.16
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 +6 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -6
- package/dist/index.d.ts +2 -6
- package/dist/index.js +10 -34
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/selectors/OpportunitiesSelector.tsx +4 -27
- package/src/selectors/OpportunitySelector.tsx +4 -27
package/dist/index.cjs
CHANGED
|
@@ -744,7 +744,6 @@ var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
|
744
744
|
function OpportunitiesSelector({
|
|
745
745
|
value,
|
|
746
746
|
onValueChange,
|
|
747
|
-
productId,
|
|
748
747
|
placeholder = "Select opportunities",
|
|
749
748
|
disabled = false,
|
|
750
749
|
className,
|
|
@@ -752,13 +751,7 @@ function OpportunitiesSelector({
|
|
|
752
751
|
closeOnSelect = true,
|
|
753
752
|
searchable = true
|
|
754
753
|
}) {
|
|
755
|
-
const
|
|
756
|
-
const { data: opportunitiesData, isLoading } = (0, import_hooks4.useOpportunities)({
|
|
757
|
-
filters: {
|
|
758
|
-
productId
|
|
759
|
-
},
|
|
760
|
-
enabled: isProductSelected
|
|
761
|
-
});
|
|
754
|
+
const { data: opportunitiesData, isLoading } = (0, import_hooks4.useOpportunities)();
|
|
762
755
|
const opportunities = (0, import_react8.useMemo)(
|
|
763
756
|
() => opportunitiesData?.opportunities ?? [],
|
|
764
757
|
[opportunitiesData?.opportunities]
|
|
@@ -782,11 +775,6 @@ function OpportunitiesSelector({
|
|
|
782
775
|
) : void 0
|
|
783
776
|
}));
|
|
784
777
|
}, [opportunities]);
|
|
785
|
-
(0, import_react8.useEffect)(() => {
|
|
786
|
-
if (!isProductSelected && value.length > 0) {
|
|
787
|
-
onValueChange([]);
|
|
788
|
-
}
|
|
789
|
-
}, [isProductSelected, value, onValueChange]);
|
|
790
778
|
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
791
779
|
import_ui10.MultiSelect,
|
|
792
780
|
{
|
|
@@ -794,8 +782,8 @@ function OpportunitiesSelector({
|
|
|
794
782
|
options: opportunityOptions,
|
|
795
783
|
value,
|
|
796
784
|
onValueChange,
|
|
797
|
-
disabled: disabled || isLoading
|
|
798
|
-
placeholder:
|
|
785
|
+
disabled: disabled || isLoading,
|
|
786
|
+
placeholder: isLoading ? "Loading opportunities..." : placeholder,
|
|
799
787
|
closeOnSelect,
|
|
800
788
|
maxCount,
|
|
801
789
|
className
|
|
@@ -965,20 +953,13 @@ var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
|
965
953
|
function OpportunitySelector({
|
|
966
954
|
value,
|
|
967
955
|
onValueChange,
|
|
968
|
-
productId,
|
|
969
956
|
placeholder = "Select opportunity",
|
|
970
957
|
disabled = false,
|
|
971
958
|
className,
|
|
972
959
|
closeOnSelect = true,
|
|
973
960
|
searchable = true
|
|
974
961
|
}) {
|
|
975
|
-
const
|
|
976
|
-
const { data: opportunitiesData, isLoading } = (0, import_hooks8.useOpportunities)({
|
|
977
|
-
filters: {
|
|
978
|
-
productId
|
|
979
|
-
},
|
|
980
|
-
enabled: isProductSelected
|
|
981
|
-
});
|
|
962
|
+
const { data: opportunitiesData, isLoading } = (0, import_hooks8.useOpportunities)();
|
|
982
963
|
const opportunities = (0, import_react12.useMemo)(
|
|
983
964
|
() => opportunitiesData?.opportunities ?? [],
|
|
984
965
|
[opportunitiesData?.opportunities]
|
|
@@ -1002,11 +983,6 @@ function OpportunitySelector({
|
|
|
1002
983
|
) : void 0
|
|
1003
984
|
}));
|
|
1004
985
|
}, [opportunities]);
|
|
1005
|
-
(0, import_react12.useEffect)(() => {
|
|
1006
|
-
if (!isProductSelected && value) {
|
|
1007
|
-
onValueChange("");
|
|
1008
|
-
}
|
|
1009
|
-
}, [isProductSelected, value, onValueChange]);
|
|
1010
986
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
1011
987
|
import_ui14.Combobox,
|
|
1012
988
|
{
|
|
@@ -1014,8 +990,8 @@ function OpportunitySelector({
|
|
|
1014
990
|
options: opportunityOptions,
|
|
1015
991
|
value,
|
|
1016
992
|
onValueChange,
|
|
1017
|
-
disabled: disabled || isLoading
|
|
1018
|
-
placeholder:
|
|
993
|
+
disabled: disabled || isLoading,
|
|
994
|
+
placeholder: isLoading ? "Loading opportunities..." : placeholder,
|
|
1019
995
|
closeOnSelect,
|
|
1020
996
|
className
|
|
1021
997
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/filters/RangeSliderFilter.tsx","../src/filters/BooleanFilter.tsx","../src/filters/Filter.tsx","../src/filters/MultiSelectFilter.tsx","../src/wrappers/FiltersGrid.tsx","../src/wrappers/FiltersPopover.tsx","../src/wrappers/ActiveFilterBadges.tsx","../src/wrappers/FiltersWrapper.tsx","../src/helpers/usePagination.ts","../src/helpers/useSorting.ts","../src/selectors/ChainsSelector.tsx","../src/selectors/TokensSelector.tsx","../src/selectors/ProductsSelector.tsx","../src/selectors/OpportunitiesSelector.tsx","../src/selectors/ChainSelector.tsx","../src/selectors/TokenSelector.tsx","../src/selectors/ProductSelector.tsx","../src/selectors/OpportunitySelector.tsx"],"sourcesContent":["export * from \"./filters\";\nexport * from \"./wrappers\";\nexport * from \"./helpers\";\nexport * from \"./selectors\";\n","\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport { Slider, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsInteger } from \"nuqs\";\n\ninterface RangeSliderFilterProps {\n /** Query key for minimum value (default: 'min') */\n minQueryKey?: string;\n /** Query key for maximum value (default: 'max') */\n maxQueryKey?: string;\n /** Minimum value (default: 0) */\n min?: number;\n /** Maximum value (default: 100) */\n max?: number;\n /** Step value for slider (default: 1) */\n step?: number;\n /** Whether the filter is disabled */\n disabled?: boolean;\n /** Custom label for the filter */\n label: string;\n /** Whether to show values (default: true) */\n showValues?: boolean;\n /** Value formatter function */\n formatValue?: (value: number) => string;\n /** Custom className for the container */\n className?: string;\n}\n\nconst defaultFormatter = (value: number): string => {\n return value.toLocaleString();\n};\n\nexport function RangeSliderFilter({\n minQueryKey = \"min\",\n maxQueryKey = \"max\",\n min = 0,\n max = 100,\n step = 1,\n disabled = false,\n label = \"Range\",\n showValues = true,\n formatValue = defaultFormatter,\n className = \"\",\n}: RangeSliderFilterProps) {\n const [minValue, setMinValue] = useQueryState(minQueryKey, parseAsInteger.withDefault(min));\n\n const [maxValue, setMaxValue] = useQueryState(maxQueryKey, parseAsInteger.withDefault(max));\n\n // Local state for slider values (to avoid excessive URL updates)\n const [localRange, setLocalRange] = useState([minValue, maxValue]);\n\n // Update local state when query params change\n useEffect(() => {\n setLocalRange([minValue, maxValue]);\n }, [minValue, maxValue]);\n\n const handleRangeChange = (values: number[]) => {\n setLocalRange(values);\n };\n\n const handleRangeCommit = (values: number[]) => {\n const [newMin, newMax] = values;\n if (newMin !== minValue) {\n setMinValue(newMin === min ? null : newMin);\n }\n if (newMax !== maxValue) {\n setMaxValue(newMax === max ? null : newMax);\n }\n };\n\n const isDefaultRange = localRange[0] === min && localRange[1] === max;\n\n return (\n <div className={`space-y-3 ${className}`}>\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {showValues && (\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <span>{formatValue(localRange[0])}</span>\n <span>-</span>\n <span>{formatValue(localRange[1])}</span>\n </div>\n )}\n </div>\n\n <div className=\"px-2\">\n <Slider\n value={localRange}\n onValueChange={handleRangeChange}\n onValueCommit={handleRangeCommit}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n className=\"w-full\"\n />\n </div>\n\n {showValues && (\n <div className=\"flex justify-between text-xs text-muted-foreground\">\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n )}\n\n {!isDefaultRange && (\n <div className=\"flex justify-end\">\n <button\n onClick={() => {\n setLocalRange([min, max]);\n handleRangeCommit([min, max]);\n }}\n className=\"text-xs text-muted-foreground hover:text-foreground transition-colors\"\n disabled={disabled}\n >\n Reset\n </button>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Switch, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsBoolean } from \"nuqs\";\n\ninterface BooleanSwitchFilterProps {\n /** Query key for the boolean value (default: 'enabled') */\n queryKey?: string;\n /** Default value when not set (default: false) */\n defaultValue?: boolean;\n /** Whether the switch is disabled */\n disabled?: boolean;\n /** Label for the switch */\n label: string;\n /** Description text (optional) */\n description?: string;\n /** Custom className for the container */\n className?: string;\n}\n\nexport function BooleanFilter({\n queryKey = \"enabled\",\n defaultValue = false,\n disabled = false,\n label,\n description,\n className = \"\",\n}: BooleanSwitchFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsBoolean.withDefault(defaultValue));\n\n const handleToggle = (checked: boolean) => {\n // If the value is the same as default, remove from URL\n setValue(checked === defaultValue ? null : checked);\n };\n\n return (\n <div className={`flex items-center justify-between space-x-2 ${className}`}>\n <div className=\"space-y-0.5\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {description && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n </div>\n <Switch checked={value} onCheckedChange={handleToggle} disabled={disabled} />\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsString } from \"nuqs\";\n\ninterface FilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: { value: string; onValueChange: (value: string) => void }) => React.ReactNode;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Generic Filter component that handles nuqs URL state management for single values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example Basic Single Selection\n * ```tsx\n * // Single chain selection - persists to URL as ?chainId=ethereum\n * <Filter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chain\"\n * />\n * )}\n * </Filter>\n * ```\n */\nexport function Filter({ queryKey, children, onValueChange }: FilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsString.withDefault(\"\"));\n\n const handleValueChange = (newValue: string) => {\n setValue(newValue || null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsArrayOf, parseAsString } from \"nuqs\";\n\ninterface MultiSelectFilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: {\n value: string[];\n onValueChange: (values: string[]) => void;\n }) => React.ReactNode;\n /** Callback when values change */\n onValueChange?: (values: string[]) => void;\n}\n\n/**\n * Generic MultiSelectFilter component that handles nuqs URL state management for array values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example\n * ```tsx\n * <MultiSelectFilter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainsSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chains\"\n * />\n * )}\n * </MultiSelectFilter>\n * ```\n */\nexport function MultiSelectFilter({ queryKey, children, onValueChange }: MultiSelectFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsArrayOf(parseAsString).withDefault([]));\n\n const handleValueChange = (newValue: string[]) => {\n setValue(newValue.length > 0 ? newValue : null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn, Label } from \"@turtleclub/ui\";\n\nexport interface FilterConfig {\n key: string;\n label: string;\n component: React.ReactNode;\n enabled: boolean;\n section?: string;\n}\n\nexport interface FiltersGridProps {\n filters: FilterConfig[];\n columns?: number;\n className?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersGrid({\n filters,\n columns = 3,\n className,\n sectionClassName,\n}: FiltersGridProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <div className={cn(\"space-y-4\", className)}>\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger, Button, cn, Label, Badge } from \"@turtleclub/ui\";\nimport { SlidersHorizontal } from \"lucide-react\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersPopoverProps {\n filters: FilterConfig[];\n triggerLabel?: string;\n columns?: number;\n className?: string;\n popoverClassName?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersPopover({\n filters,\n triggerLabel = \"Filters\",\n columns = 2,\n className,\n popoverClassName,\n sectionClassName,\n}: FiltersPopoverProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className={cn(className)}>\n <SlidersHorizontal className=\"mr-2 h-4 w-4\" />\n {triggerLabel}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n className={cn(\"w-auto min-w-[400px] max-w-[600px]\", popoverClassName)}\n align=\"start\"\n >\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"font-medium text-sm\">Filters</h4>\n </div>\n <div className=\"space-y-4\">\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\nimport React, { useMemo } from \"react\";\nimport { Badge, Button, cn } from \"@turtleclub/ui\";\nimport { X } from \"lucide-react\";\n\nexport interface ActiveFilterConfig {\n /** Unique key for the filter */\n key: string;\n /** Display label for the filter */\n label: string;\n /** Current filter value to display */\n value: string;\n /** Query parameter key(s) this filter uses */\n queryKeys: string | string[];\n /** Whether this filter is currently active */\n isActive: boolean;\n}\n\nexport interface ActiveFilterBadgesProps {\n /** Array of filter configurations */\n filters: ActiveFilterConfig[];\n /** Custom className for the container */\n className?: string;\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Component that displays active filter badges with individual clear buttons\n * and an optional \"clear all\" button.\n *\n * @example\n * ```tsx\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * {\n * key: 'sorting',\n * label: 'Sort',\n * value: 'Name (A-Z)',\n * queryKeys: ['sortBy', 'sortOrder'],\n * isActive: true,\n * },\n * ];\n *\n * <ActiveFilterBadges filters={activeFilters} />\n * ```\n */\nexport function ActiveFilterBadges({\n filters,\n className,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n onClearFilter,\n onClearAll,\n}: ActiveFilterBadgesProps) {\n // Get only active filters\n const activeFilters = useMemo(() => {\n return filters.filter((filter) => filter.isActive && filter.value);\n }, [filters]);\n\n // Clear all function\n const clearAll = () => {\n const allQueryKeys = activeFilters.map((filter) => filter.queryKeys);\n onClearAll(allQueryKeys);\n };\n\n // Don't render if no active filters\n if (activeFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {activeFilters.map((filter) => {\n return (\n <FilterBadge\n key={filter.key}\n filter={filter}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n />\n );\n })}\n\n {showClearAll && activeFilters.length > 1 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearAll} className=\"h-7 px-2 text-xs\">\n {clearAllLabel}\n </Button>\n )}\n </div>\n );\n}\n\ninterface FilterBadgeProps {\n filter: ActiveFilterConfig;\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n onClearFilter: (queryKeys: string | string[]) => void;\n}\n\nfunction FilterBadge({ filter, renderBadge, onClearFilter }: FilterBadgeProps) {\n const clearFilter = () => {\n onClearFilter(filter.queryKeys);\n };\n\n if (renderBadge) {\n return <>{renderBadge(filter, clearFilter)}</>;\n }\n\n return (\n <Badge className=\"flex items-center gap-1 pr-1 border-border border\">\n <span className=\"text-xs\">\n {filter.label}: {filter.value}\n </span>\n <button\n onClick={clearFilter}\n className=\"ml-1 rounded-full p-0.5 hover:bg-black/10 focus:bg-black/10 focus:outline-none\"\n aria-label={`Clear ${filter.label} filter`}\n >\n <X className=\"h-3 w-3\" />\n </button>\n </Badge>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@turtleclub/ui\";\nimport { FiltersGrid } from \"./FiltersGrid\";\nimport { FiltersPopover } from \"./FiltersPopover\";\nimport { ActiveFilterBadges, ActiveFilterConfig } from \"./ActiveFilterBadges\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersWrapperProps {\n /** Array of filter configurations */\n filters: FilterConfig[];\n /** Array of active filter configurations for badges */\n activeFilters: ActiveFilterConfig[];\n /** Layout type: 'grid' or 'popover' */\n layout: \"grid\" | \"popover\";\n /** Custom className for the wrapper */\n className?: string;\n /** Custom className for the active badges section */\n badgesClassName?: string;\n\n // Grid-specific props\n /** Number of columns for grid layout (default: 3) */\n columns?: number;\n\n // Popover-specific props\n /** Button label for popover trigger (default: \"Filters\") */\n triggerLabel?: string;\n /** Number of columns in popover (default: 2) */\n popoverColumns?: number;\n /** Custom className for popover trigger button */\n popoverClassName?: string;\n /** Custom className for popover content */\n popoverContentClassName?: string;\n\n // Active badges props\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Whether to show active filter badges (default: true) */\n showActiveBadges?: boolean;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Unified wrapper component that combines filter controls with active filter badges.\n *\n * Supports both grid and popover layouts, automatically displays active filter badges\n * below the filter controls with individual and bulk clear functionality.\n *\n * @example\n * ```tsx\n * const filters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * component: <ChainFilter />,\n * enabled: true,\n * },\n * ];\n *\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * ];\n *\n * <FiltersWrapper\n * layout=\"grid\"\n * filters={filters}\n * activeFilters={activeFilters}\n * />\n * ```\n */\nexport function FiltersWrapper({\n filters,\n activeFilters,\n layout,\n className,\n badgesClassName,\n columns = 3,\n triggerLabel = \"Filters\",\n popoverColumns = 2,\n popoverClassName,\n popoverContentClassName,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n showActiveBadges = true,\n onClearFilter,\n onClearAll,\n}: FiltersWrapperProps) {\n const hasActiveFilters = activeFilters.some((filter) => filter.isActive && filter.value);\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n {/* Filter Controls */}\n {layout === \"grid\" ? (\n <FiltersGrid filters={filters} columns={columns} className={popoverClassName} />\n ) : (\n <FiltersPopover\n filters={filters}\n triggerLabel={triggerLabel}\n columns={popoverColumns}\n className={popoverClassName}\n popoverClassName={popoverContentClassName}\n />\n )}\n\n {/* Active Filter Badges */}\n {showActiveBadges && hasActiveFilters && (\n <ActiveFilterBadges\n filters={activeFilters}\n className={badgesClassName}\n clearAllLabel={clearAllLabel}\n showClearAll={showClearAll}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n onClearAll={onClearAll}\n />\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useQueryState, parseAsInteger } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { PaginationState } from \"@tanstack/react-table\";\n\nexport interface UsePaginationOptions {\n /** Default page size (default: 10) */\n defaultPageSize?: number;\n /** Default page index (default: 0) */\n defaultPageIndex?: number;\n /** Query param key for page index (default: 'page') */\n pageIndexKey?: string;\n /** Query param key for page size (default: 'pageSize') */\n pageSizeKey?: string;\n}\n\nexport interface UsePaginationReturn {\n /** Current pagination state for TanStack Table */\n pagination: PaginationState;\n /** Function to update pagination state */\n setPagination: (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => void;\n /** Current page index (0-based) */\n pageIndex: number;\n /** Current page size */\n pageSize: number;\n /** Set page index directly */\n setPageIndex: (pageIndex: number) => void;\n /** Set page size directly */\n setPageSize: (pageSize: number) => void;\n /** Go to next page */\n nextPage: (totalPages?: number) => void;\n /** Go to previous page */\n previousPage: () => void;\n /** Go to first page */\n firstPage: () => void;\n /** Go to last page */\n lastPage: (totalPages: number) => void;\n /** Reset pagination to defaults */\n reset: () => void;\n /** Check if can go to next page */\n canNextPage: (totalPages?: number) => boolean;\n /** Check if can go to previous page */\n canPreviousPage: boolean;\n}\n\n/**\n * Hook for managing server-side pagination state using nuqs.\n *\n * This hook synchronizes pagination state with URL query parameters,\n * making it perfect for server-side pagination where the URL should\n * reflect the current page and page size.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * pagination,\n * setPagination,\n * pageIndex,\n * pageSize,\n * setPageIndex,\n * setPageSize\n * } = usePagination({\n * defaultPageSize: 20,\n * pageIndexKey: 'page',\n * pageSizeKey: 'limit'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualPagination: true,\n * pagination,\n * onPaginationChange: setPagination,\n * pageCount: Math.ceil(totalCount / pageSize),\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function usePagination(options: UsePaginationOptions = {}): UsePaginationReturn {\n const {\n defaultPageSize = 10,\n defaultPageIndex = 0,\n pageIndexKey = \"page\",\n pageSizeKey = \"pageSize\",\n } = options;\n\n // Use nuqs to manage query state\n const [rawPageIndex, setRawPageIndex] = useQueryState(\n pageIndexKey,\n parseAsInteger.withDefault(defaultPageIndex)\n );\n\n const [rawPageSize, setRawPageSize] = useQueryState(\n pageSizeKey,\n parseAsInteger.withDefault(defaultPageSize)\n );\n\n // Ensure page index is never negative\n const pageIndex = useMemo(() => Math.max(0, rawPageIndex), [rawPageIndex]);\n\n // Use page size directly from query state\n const pageSize = rawPageSize;\n\n // Create pagination state for TanStack Table\n const pagination = useMemo<PaginationState>(\n () => ({\n pageIndex,\n pageSize,\n }),\n [pageIndex, pageSize]\n );\n\n // Set pagination function that handles both object and function updates\n const setPagination = useCallback(\n (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => {\n const newPagination = typeof updater === \"function\" ? updater(pagination) : updater;\n\n if (newPagination.pageIndex !== pageIndex) {\n setRawPageIndex(Math.max(0, newPagination.pageIndex));\n }\n\n if (newPagination.pageSize !== pageSize) {\n setRawPageSize(newPagination.pageSize);\n }\n },\n [pagination, pageIndex, pageSize, setRawPageIndex, setRawPageSize]\n );\n\n // Individual setters\n const setPageIndex = useCallback(\n (newPageIndex: number) => {\n setRawPageIndex(Math.max(0, newPageIndex));\n },\n [setRawPageIndex]\n );\n\n const setPageSize = useCallback(\n (newPageSize: number) => {\n setRawPageSize(newPageSize);\n // Reset to first page when page size changes\n setRawPageIndex(0);\n },\n [setRawPageSize, setRawPageIndex]\n );\n\n // Navigation functions\n const nextPage = useCallback(\n (totalPages?: number) => {\n const nextPageIndex = pageIndex + 1;\n if (!totalPages || nextPageIndex < totalPages) {\n setPageIndex(nextPageIndex);\n }\n },\n [pageIndex, setPageIndex]\n );\n\n const previousPage = useCallback(() => {\n if (pageIndex > 0) {\n setPageIndex(pageIndex - 1);\n }\n }, [pageIndex, setPageIndex]);\n\n const firstPage = useCallback(() => {\n setPageIndex(0);\n }, [setPageIndex]);\n\n const lastPage = useCallback(\n (totalPages: number) => {\n setPageIndex(Math.max(0, totalPages - 1));\n },\n [setPageIndex]\n );\n\n // Reset function\n const reset = useCallback(() => {\n setRawPageIndex(defaultPageIndex);\n setRawPageSize(defaultPageSize);\n }, [setRawPageIndex, setRawPageSize, defaultPageIndex, defaultPageSize]);\n\n // Navigation state\n const canPreviousPage = pageIndex > 0;\n const canNextPage = useCallback(\n (totalPages?: number) => {\n if (!totalPages) return true; // Assume we can go next if total pages unknown\n return pageIndex < totalPages - 1;\n },\n [pageIndex]\n );\n\n return {\n pagination,\n setPagination,\n pageIndex,\n pageSize,\n setPageIndex,\n setPageSize,\n nextPage,\n previousPage,\n firstPage,\n lastPage,\n reset,\n canNextPage,\n canPreviousPage,\n };\n}\n","\"use client\";\n\nimport { useQueryState, parseAsString } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { SortingState } from \"@tanstack/react-table\";\n\nexport interface UseSortingOptions {\n /** Default sort column (default: undefined - no sorting) */\n defaultSortBy?: string;\n /** Default sort order (default: 'asc') */\n defaultSortOrder?: \"asc\" | \"desc\";\n /** Query param key for sort column (default: 'sortBy') */\n sortByKey?: string;\n /** Query param key for sort order (default: 'sortOrder') */\n sortOrderKey?: string;\n}\n\nexport interface UseSortingReturn {\n /** Current sorting state for TanStack Table */\n sorting: SortingState;\n /** Function to update sorting state */\n setSorting: (updater: SortingState | ((prev: SortingState) => SortingState)) => void;\n /** Current sort column (undefined if no sorting) */\n sortBy: string | undefined;\n /** Current sort order */\n sortOrder: \"asc\" | \"desc\";\n /** Set sort column and order directly */\n setSort: (column: string, order?: \"asc\" | \"desc\") => void;\n /** Clear all sorting */\n clearSort: () => void;\n /** Toggle sort order for a column */\n toggleSort: (column: string) => void;\n /** Check if a column is currently sorted */\n isSorted: (column: string) => boolean;\n /** Get sort order for a column */\n getSortOrder: (column: string) => \"asc\" | \"desc\" | undefined;\n}\n\n/**\n * Hook for managing server-side sorting state using nuqs.\n *\n * This hook synchronizes sorting state with URL query parameters,\n * making it perfect for server-side sorting where the URL should\n * reflect the current sort state.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * sorting,\n * setSorting,\n * sortBy,\n * sortOrder,\n * setSort,\n * toggleSort\n * } = useSorting({\n * defaultSortBy: 'name',\n * defaultSortOrder: 'asc'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualSorting: true,\n * sorting,\n * onSortingChange: setSorting,\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function useSorting(options: UseSortingOptions = {}): UseSortingReturn {\n const {\n defaultSortBy,\n defaultSortOrder = \"asc\",\n sortByKey = \"sortBy\",\n sortOrderKey = \"sortOrder\",\n } = options;\n\n // Use nuqs to manage query state\n const [sortBy, setSortBy] = useQueryState(\n sortByKey,\n parseAsString.withDefault(defaultSortBy || \"\")\n );\n\n const [sortOrder, setSortOrder] = useQueryState(\n sortOrderKey,\n parseAsString.withDefault(defaultSortOrder)\n );\n\n // Ensure sort order is valid\n const validSortOrder = useMemo(() => {\n return sortOrder === \"desc\" ? \"desc\" : \"asc\";\n }, [sortOrder]);\n\n // Create sorting state for TanStack Table\n const sorting = useMemo<SortingState>(() => {\n if (!sortBy || sortBy.trim() === \"\") {\n return [];\n }\n return [\n {\n id: sortBy,\n desc: validSortOrder === \"desc\",\n },\n ];\n }, [sortBy, validSortOrder]);\n\n // Set sorting function that handles both object and function updates\n const setSorting = useCallback(\n (updater: SortingState | ((prev: SortingState) => SortingState)) => {\n const newSorting = typeof updater === \"function\" ? updater(sorting) : updater;\n\n if (newSorting.length === 0) {\n // Clear sorting\n setSortBy(\"\");\n } else {\n // Set first sort (TanStack Table typically only has one sort at a time)\n const firstSort = newSorting[0];\n setSortBy(firstSort.id);\n setSortOrder(firstSort.desc ? \"desc\" : \"asc\");\n }\n },\n [sorting, setSortBy, setSortOrder]\n );\n\n // Set sort column and order directly\n const setSort = useCallback(\n (column: string, order: \"asc\" | \"desc\" = \"asc\") => {\n setSortBy(column);\n setSortOrder(order);\n },\n [setSortBy, setSortOrder]\n );\n\n // Clear all sorting\n const clearSort = useCallback(() => {\n setSortBy(null);\n }, [setSortBy]);\n\n // Toggle sort order for a column\n const toggleSort = useCallback(\n (column: string) => {\n if (sortBy === column) {\n // Same column, toggle order\n setSortOrder(validSortOrder === \"asc\" ? \"desc\" : \"asc\");\n } else {\n // Different column, set new column with asc\n setSortBy(column);\n setSortOrder(\"asc\");\n }\n },\n [sortBy, validSortOrder, setSortBy, setSortOrder]\n );\n\n // Check if a column is currently sorted\n const isSorted = useCallback(\n (column: string) => {\n return sortBy === column;\n },\n [sortBy]\n );\n\n // Get sort order for a column\n const getSortOrder = useCallback(\n (column: string) => {\n return sortBy === column ? validSortOrder : undefined;\n },\n [sortBy, validSortOrder]\n );\n\n return {\n sorting,\n setSorting,\n sortBy: sortBy || undefined,\n sortOrder: validSortOrder,\n setSort,\n clearSort,\n toggleSort,\n isSorted,\n getSortOrder,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainsSelector({\n value,\n onValueChange,\n placeholder = \"Select chains\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokensSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select tokens\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value.length > 0) {\n onValueChange([]);\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductsSelector({\n value,\n onValueChange,\n placeholder = \"Select products\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo, useEffect } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Selected product ID to filter opportunities */\n productId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitiesSelector({\n value,\n onValueChange,\n productId,\n placeholder = \"Select opportunities\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const isProductSelected = !!productId && productId.trim() !== \"\";\n\n const { data: opportunitiesData, isLoading } = useOpportunities({\n filters: {\n productId,\n },\n enabled: isProductSelected,\n });\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n // Clear selection when product changes\n useEffect(() => {\n if (!isProductSelected && value.length > 0) {\n onValueChange([]);\n }\n }, [isProductSelected, value, onValueChange]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isProductSelected}\n placeholder={\n !isProductSelected\n ? \"Select a product first\"\n : isLoading\n ? \"Loading opportunities...\"\n : placeholder\n }\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainSelector({\n value,\n onValueChange,\n placeholder = \"Select chain\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <Combobox\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokenSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select token\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value) {\n onValueChange(\"\");\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <Combobox\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductSelector({\n value,\n onValueChange,\n placeholder = \"Select product\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <Combobox\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo, useEffect } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Selected product ID to filter opportunities */\n productId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitySelector({\n value,\n onValueChange,\n productId,\n placeholder = \"Select opportunity\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const isProductSelected = !!productId && productId.trim() !== \"\";\n\n const { data: opportunitiesData, isLoading } = useOpportunities({\n filters: {\n productId,\n },\n enabled: isProductSelected,\n });\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n // Clear selection when product changes\n useEffect(() => {\n if (!isProductSelected && value) {\n onValueChange(\"\");\n }\n }, [isProductSelected, value, onValueChange]);\n\n return (\n <Combobox\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isProductSelected}\n placeholder={\n !isProductSelected\n ? \"Select a product first\"\n : isLoading\n ? \"Loading opportunities...\"\n : placeholder\n }\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n"],"mappings":"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","names":["import_ui","import_nuqs","import_jsx_runtime","import_nuqs","import_jsx_runtime","import_nuqs","import_jsx_runtime","import_ui","import_jsx_runtime","import_ui","import_jsx_runtime","import_react","import_ui","import_lucide_react","import_jsx_runtime","import_ui","import_jsx_runtime","import_nuqs","import_react","import_nuqs","import_react","import_react","import_ui","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/filters/RangeSliderFilter.tsx","../src/filters/BooleanFilter.tsx","../src/filters/Filter.tsx","../src/filters/MultiSelectFilter.tsx","../src/wrappers/FiltersGrid.tsx","../src/wrappers/FiltersPopover.tsx","../src/wrappers/ActiveFilterBadges.tsx","../src/wrappers/FiltersWrapper.tsx","../src/helpers/usePagination.ts","../src/helpers/useSorting.ts","../src/selectors/ChainsSelector.tsx","../src/selectors/TokensSelector.tsx","../src/selectors/ProductsSelector.tsx","../src/selectors/OpportunitiesSelector.tsx","../src/selectors/ChainSelector.tsx","../src/selectors/TokenSelector.tsx","../src/selectors/ProductSelector.tsx","../src/selectors/OpportunitySelector.tsx"],"sourcesContent":["export * from \"./filters\";\nexport * from \"./wrappers\";\nexport * from \"./helpers\";\nexport * from \"./selectors\";\n","\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport { Slider, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsInteger } from \"nuqs\";\n\ninterface RangeSliderFilterProps {\n /** Query key for minimum value (default: 'min') */\n minQueryKey?: string;\n /** Query key for maximum value (default: 'max') */\n maxQueryKey?: string;\n /** Minimum value (default: 0) */\n min?: number;\n /** Maximum value (default: 100) */\n max?: number;\n /** Step value for slider (default: 1) */\n step?: number;\n /** Whether the filter is disabled */\n disabled?: boolean;\n /** Custom label for the filter */\n label: string;\n /** Whether to show values (default: true) */\n showValues?: boolean;\n /** Value formatter function */\n formatValue?: (value: number) => string;\n /** Custom className for the container */\n className?: string;\n}\n\nconst defaultFormatter = (value: number): string => {\n return value.toLocaleString();\n};\n\nexport function RangeSliderFilter({\n minQueryKey = \"min\",\n maxQueryKey = \"max\",\n min = 0,\n max = 100,\n step = 1,\n disabled = false,\n label = \"Range\",\n showValues = true,\n formatValue = defaultFormatter,\n className = \"\",\n}: RangeSliderFilterProps) {\n const [minValue, setMinValue] = useQueryState(minQueryKey, parseAsInteger.withDefault(min));\n\n const [maxValue, setMaxValue] = useQueryState(maxQueryKey, parseAsInteger.withDefault(max));\n\n // Local state for slider values (to avoid excessive URL updates)\n const [localRange, setLocalRange] = useState([minValue, maxValue]);\n\n // Update local state when query params change\n useEffect(() => {\n setLocalRange([minValue, maxValue]);\n }, [minValue, maxValue]);\n\n const handleRangeChange = (values: number[]) => {\n setLocalRange(values);\n };\n\n const handleRangeCommit = (values: number[]) => {\n const [newMin, newMax] = values;\n if (newMin !== minValue) {\n setMinValue(newMin === min ? null : newMin);\n }\n if (newMax !== maxValue) {\n setMaxValue(newMax === max ? null : newMax);\n }\n };\n\n const isDefaultRange = localRange[0] === min && localRange[1] === max;\n\n return (\n <div className={`space-y-3 ${className}`}>\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {showValues && (\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <span>{formatValue(localRange[0])}</span>\n <span>-</span>\n <span>{formatValue(localRange[1])}</span>\n </div>\n )}\n </div>\n\n <div className=\"px-2\">\n <Slider\n value={localRange}\n onValueChange={handleRangeChange}\n onValueCommit={handleRangeCommit}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n className=\"w-full\"\n />\n </div>\n\n {showValues && (\n <div className=\"flex justify-between text-xs text-muted-foreground\">\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n )}\n\n {!isDefaultRange && (\n <div className=\"flex justify-end\">\n <button\n onClick={() => {\n setLocalRange([min, max]);\n handleRangeCommit([min, max]);\n }}\n className=\"text-xs text-muted-foreground hover:text-foreground transition-colors\"\n disabled={disabled}\n >\n Reset\n </button>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Switch, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsBoolean } from \"nuqs\";\n\ninterface BooleanSwitchFilterProps {\n /** Query key for the boolean value (default: 'enabled') */\n queryKey?: string;\n /** Default value when not set (default: false) */\n defaultValue?: boolean;\n /** Whether the switch is disabled */\n disabled?: boolean;\n /** Label for the switch */\n label: string;\n /** Description text (optional) */\n description?: string;\n /** Custom className for the container */\n className?: string;\n}\n\nexport function BooleanFilter({\n queryKey = \"enabled\",\n defaultValue = false,\n disabled = false,\n label,\n description,\n className = \"\",\n}: BooleanSwitchFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsBoolean.withDefault(defaultValue));\n\n const handleToggle = (checked: boolean) => {\n // If the value is the same as default, remove from URL\n setValue(checked === defaultValue ? null : checked);\n };\n\n return (\n <div className={`flex items-center justify-between space-x-2 ${className}`}>\n <div className=\"space-y-0.5\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {description && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n </div>\n <Switch checked={value} onCheckedChange={handleToggle} disabled={disabled} />\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsString } from \"nuqs\";\n\ninterface FilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: { value: string; onValueChange: (value: string) => void }) => React.ReactNode;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Generic Filter component that handles nuqs URL state management for single values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example Basic Single Selection\n * ```tsx\n * // Single chain selection - persists to URL as ?chainId=ethereum\n * <Filter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chain\"\n * />\n * )}\n * </Filter>\n * ```\n */\nexport function Filter({ queryKey, children, onValueChange }: FilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsString.withDefault(\"\"));\n\n const handleValueChange = (newValue: string) => {\n setValue(newValue || null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsArrayOf, parseAsString } from \"nuqs\";\n\ninterface MultiSelectFilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: {\n value: string[];\n onValueChange: (values: string[]) => void;\n }) => React.ReactNode;\n /** Callback when values change */\n onValueChange?: (values: string[]) => void;\n}\n\n/**\n * Generic MultiSelectFilter component that handles nuqs URL state management for array values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example\n * ```tsx\n * <MultiSelectFilter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainsSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chains\"\n * />\n * )}\n * </MultiSelectFilter>\n * ```\n */\nexport function MultiSelectFilter({ queryKey, children, onValueChange }: MultiSelectFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsArrayOf(parseAsString).withDefault([]));\n\n const handleValueChange = (newValue: string[]) => {\n setValue(newValue.length > 0 ? newValue : null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn, Label } from \"@turtleclub/ui\";\n\nexport interface FilterConfig {\n key: string;\n label: string;\n component: React.ReactNode;\n enabled: boolean;\n section?: string;\n}\n\nexport interface FiltersGridProps {\n filters: FilterConfig[];\n columns?: number;\n className?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersGrid({\n filters,\n columns = 3,\n className,\n sectionClassName,\n}: FiltersGridProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <div className={cn(\"space-y-4\", className)}>\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger, Button, cn, Label, Badge } from \"@turtleclub/ui\";\nimport { SlidersHorizontal } from \"lucide-react\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersPopoverProps {\n filters: FilterConfig[];\n triggerLabel?: string;\n columns?: number;\n className?: string;\n popoverClassName?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersPopover({\n filters,\n triggerLabel = \"Filters\",\n columns = 2,\n className,\n popoverClassName,\n sectionClassName,\n}: FiltersPopoverProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className={cn(className)}>\n <SlidersHorizontal className=\"mr-2 h-4 w-4\" />\n {triggerLabel}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n className={cn(\"w-auto min-w-[400px] max-w-[600px]\", popoverClassName)}\n align=\"start\"\n >\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"font-medium text-sm\">Filters</h4>\n </div>\n <div className=\"space-y-4\">\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\nimport React, { useMemo } from \"react\";\nimport { Badge, Button, cn } from \"@turtleclub/ui\";\nimport { X } from \"lucide-react\";\n\nexport interface ActiveFilterConfig {\n /** Unique key for the filter */\n key: string;\n /** Display label for the filter */\n label: string;\n /** Current filter value to display */\n value: string;\n /** Query parameter key(s) this filter uses */\n queryKeys: string | string[];\n /** Whether this filter is currently active */\n isActive: boolean;\n}\n\nexport interface ActiveFilterBadgesProps {\n /** Array of filter configurations */\n filters: ActiveFilterConfig[];\n /** Custom className for the container */\n className?: string;\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Component that displays active filter badges with individual clear buttons\n * and an optional \"clear all\" button.\n *\n * @example\n * ```tsx\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * {\n * key: 'sorting',\n * label: 'Sort',\n * value: 'Name (A-Z)',\n * queryKeys: ['sortBy', 'sortOrder'],\n * isActive: true,\n * },\n * ];\n *\n * <ActiveFilterBadges filters={activeFilters} />\n * ```\n */\nexport function ActiveFilterBadges({\n filters,\n className,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n onClearFilter,\n onClearAll,\n}: ActiveFilterBadgesProps) {\n // Get only active filters\n const activeFilters = useMemo(() => {\n return filters.filter((filter) => filter.isActive && filter.value);\n }, [filters]);\n\n // Clear all function\n const clearAll = () => {\n const allQueryKeys = activeFilters.map((filter) => filter.queryKeys);\n onClearAll(allQueryKeys);\n };\n\n // Don't render if no active filters\n if (activeFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {activeFilters.map((filter) => {\n return (\n <FilterBadge\n key={filter.key}\n filter={filter}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n />\n );\n })}\n\n {showClearAll && activeFilters.length > 1 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearAll} className=\"h-7 px-2 text-xs\">\n {clearAllLabel}\n </Button>\n )}\n </div>\n );\n}\n\ninterface FilterBadgeProps {\n filter: ActiveFilterConfig;\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n onClearFilter: (queryKeys: string | string[]) => void;\n}\n\nfunction FilterBadge({ filter, renderBadge, onClearFilter }: FilterBadgeProps) {\n const clearFilter = () => {\n onClearFilter(filter.queryKeys);\n };\n\n if (renderBadge) {\n return <>{renderBadge(filter, clearFilter)}</>;\n }\n\n return (\n <Badge className=\"flex items-center gap-1 pr-1 border-border border\">\n <span className=\"text-xs\">\n {filter.label}: {filter.value}\n </span>\n <button\n onClick={clearFilter}\n className=\"ml-1 rounded-full p-0.5 hover:bg-black/10 focus:bg-black/10 focus:outline-none\"\n aria-label={`Clear ${filter.label} filter`}\n >\n <X className=\"h-3 w-3\" />\n </button>\n </Badge>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@turtleclub/ui\";\nimport { FiltersGrid } from \"./FiltersGrid\";\nimport { FiltersPopover } from \"./FiltersPopover\";\nimport { ActiveFilterBadges, ActiveFilterConfig } from \"./ActiveFilterBadges\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersWrapperProps {\n /** Array of filter configurations */\n filters: FilterConfig[];\n /** Array of active filter configurations for badges */\n activeFilters: ActiveFilterConfig[];\n /** Layout type: 'grid' or 'popover' */\n layout: \"grid\" | \"popover\";\n /** Custom className for the wrapper */\n className?: string;\n /** Custom className for the active badges section */\n badgesClassName?: string;\n\n // Grid-specific props\n /** Number of columns for grid layout (default: 3) */\n columns?: number;\n\n // Popover-specific props\n /** Button label for popover trigger (default: \"Filters\") */\n triggerLabel?: string;\n /** Number of columns in popover (default: 2) */\n popoverColumns?: number;\n /** Custom className for popover trigger button */\n popoverClassName?: string;\n /** Custom className for popover content */\n popoverContentClassName?: string;\n\n // Active badges props\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Whether to show active filter badges (default: true) */\n showActiveBadges?: boolean;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Unified wrapper component that combines filter controls with active filter badges.\n *\n * Supports both grid and popover layouts, automatically displays active filter badges\n * below the filter controls with individual and bulk clear functionality.\n *\n * @example\n * ```tsx\n * const filters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * component: <ChainFilter />,\n * enabled: true,\n * },\n * ];\n *\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * ];\n *\n * <FiltersWrapper\n * layout=\"grid\"\n * filters={filters}\n * activeFilters={activeFilters}\n * />\n * ```\n */\nexport function FiltersWrapper({\n filters,\n activeFilters,\n layout,\n className,\n badgesClassName,\n columns = 3,\n triggerLabel = \"Filters\",\n popoverColumns = 2,\n popoverClassName,\n popoverContentClassName,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n showActiveBadges = true,\n onClearFilter,\n onClearAll,\n}: FiltersWrapperProps) {\n const hasActiveFilters = activeFilters.some((filter) => filter.isActive && filter.value);\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n {/* Filter Controls */}\n {layout === \"grid\" ? (\n <FiltersGrid filters={filters} columns={columns} className={popoverClassName} />\n ) : (\n <FiltersPopover\n filters={filters}\n triggerLabel={triggerLabel}\n columns={popoverColumns}\n className={popoverClassName}\n popoverClassName={popoverContentClassName}\n />\n )}\n\n {/* Active Filter Badges */}\n {showActiveBadges && hasActiveFilters && (\n <ActiveFilterBadges\n filters={activeFilters}\n className={badgesClassName}\n clearAllLabel={clearAllLabel}\n showClearAll={showClearAll}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n onClearAll={onClearAll}\n />\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useQueryState, parseAsInteger } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { PaginationState } from \"@tanstack/react-table\";\n\nexport interface UsePaginationOptions {\n /** Default page size (default: 10) */\n defaultPageSize?: number;\n /** Default page index (default: 0) */\n defaultPageIndex?: number;\n /** Query param key for page index (default: 'page') */\n pageIndexKey?: string;\n /** Query param key for page size (default: 'pageSize') */\n pageSizeKey?: string;\n}\n\nexport interface UsePaginationReturn {\n /** Current pagination state for TanStack Table */\n pagination: PaginationState;\n /** Function to update pagination state */\n setPagination: (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => void;\n /** Current page index (0-based) */\n pageIndex: number;\n /** Current page size */\n pageSize: number;\n /** Set page index directly */\n setPageIndex: (pageIndex: number) => void;\n /** Set page size directly */\n setPageSize: (pageSize: number) => void;\n /** Go to next page */\n nextPage: (totalPages?: number) => void;\n /** Go to previous page */\n previousPage: () => void;\n /** Go to first page */\n firstPage: () => void;\n /** Go to last page */\n lastPage: (totalPages: number) => void;\n /** Reset pagination to defaults */\n reset: () => void;\n /** Check if can go to next page */\n canNextPage: (totalPages?: number) => boolean;\n /** Check if can go to previous page */\n canPreviousPage: boolean;\n}\n\n/**\n * Hook for managing server-side pagination state using nuqs.\n *\n * This hook synchronizes pagination state with URL query parameters,\n * making it perfect for server-side pagination where the URL should\n * reflect the current page and page size.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * pagination,\n * setPagination,\n * pageIndex,\n * pageSize,\n * setPageIndex,\n * setPageSize\n * } = usePagination({\n * defaultPageSize: 20,\n * pageIndexKey: 'page',\n * pageSizeKey: 'limit'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualPagination: true,\n * pagination,\n * onPaginationChange: setPagination,\n * pageCount: Math.ceil(totalCount / pageSize),\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function usePagination(options: UsePaginationOptions = {}): UsePaginationReturn {\n const {\n defaultPageSize = 10,\n defaultPageIndex = 0,\n pageIndexKey = \"page\",\n pageSizeKey = \"pageSize\",\n } = options;\n\n // Use nuqs to manage query state\n const [rawPageIndex, setRawPageIndex] = useQueryState(\n pageIndexKey,\n parseAsInteger.withDefault(defaultPageIndex)\n );\n\n const [rawPageSize, setRawPageSize] = useQueryState(\n pageSizeKey,\n parseAsInteger.withDefault(defaultPageSize)\n );\n\n // Ensure page index is never negative\n const pageIndex = useMemo(() => Math.max(0, rawPageIndex), [rawPageIndex]);\n\n // Use page size directly from query state\n const pageSize = rawPageSize;\n\n // Create pagination state for TanStack Table\n const pagination = useMemo<PaginationState>(\n () => ({\n pageIndex,\n pageSize,\n }),\n [pageIndex, pageSize]\n );\n\n // Set pagination function that handles both object and function updates\n const setPagination = useCallback(\n (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => {\n const newPagination = typeof updater === \"function\" ? updater(pagination) : updater;\n\n if (newPagination.pageIndex !== pageIndex) {\n setRawPageIndex(Math.max(0, newPagination.pageIndex));\n }\n\n if (newPagination.pageSize !== pageSize) {\n setRawPageSize(newPagination.pageSize);\n }\n },\n [pagination, pageIndex, pageSize, setRawPageIndex, setRawPageSize]\n );\n\n // Individual setters\n const setPageIndex = useCallback(\n (newPageIndex: number) => {\n setRawPageIndex(Math.max(0, newPageIndex));\n },\n [setRawPageIndex]\n );\n\n const setPageSize = useCallback(\n (newPageSize: number) => {\n setRawPageSize(newPageSize);\n // Reset to first page when page size changes\n setRawPageIndex(0);\n },\n [setRawPageSize, setRawPageIndex]\n );\n\n // Navigation functions\n const nextPage = useCallback(\n (totalPages?: number) => {\n const nextPageIndex = pageIndex + 1;\n if (!totalPages || nextPageIndex < totalPages) {\n setPageIndex(nextPageIndex);\n }\n },\n [pageIndex, setPageIndex]\n );\n\n const previousPage = useCallback(() => {\n if (pageIndex > 0) {\n setPageIndex(pageIndex - 1);\n }\n }, [pageIndex, setPageIndex]);\n\n const firstPage = useCallback(() => {\n setPageIndex(0);\n }, [setPageIndex]);\n\n const lastPage = useCallback(\n (totalPages: number) => {\n setPageIndex(Math.max(0, totalPages - 1));\n },\n [setPageIndex]\n );\n\n // Reset function\n const reset = useCallback(() => {\n setRawPageIndex(defaultPageIndex);\n setRawPageSize(defaultPageSize);\n }, [setRawPageIndex, setRawPageSize, defaultPageIndex, defaultPageSize]);\n\n // Navigation state\n const canPreviousPage = pageIndex > 0;\n const canNextPage = useCallback(\n (totalPages?: number) => {\n if (!totalPages) return true; // Assume we can go next if total pages unknown\n return pageIndex < totalPages - 1;\n },\n [pageIndex]\n );\n\n return {\n pagination,\n setPagination,\n pageIndex,\n pageSize,\n setPageIndex,\n setPageSize,\n nextPage,\n previousPage,\n firstPage,\n lastPage,\n reset,\n canNextPage,\n canPreviousPage,\n };\n}\n","\"use client\";\n\nimport { useQueryState, parseAsString } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { SortingState } from \"@tanstack/react-table\";\n\nexport interface UseSortingOptions {\n /** Default sort column (default: undefined - no sorting) */\n defaultSortBy?: string;\n /** Default sort order (default: 'asc') */\n defaultSortOrder?: \"asc\" | \"desc\";\n /** Query param key for sort column (default: 'sortBy') */\n sortByKey?: string;\n /** Query param key for sort order (default: 'sortOrder') */\n sortOrderKey?: string;\n}\n\nexport interface UseSortingReturn {\n /** Current sorting state for TanStack Table */\n sorting: SortingState;\n /** Function to update sorting state */\n setSorting: (updater: SortingState | ((prev: SortingState) => SortingState)) => void;\n /** Current sort column (undefined if no sorting) */\n sortBy: string | undefined;\n /** Current sort order */\n sortOrder: \"asc\" | \"desc\";\n /** Set sort column and order directly */\n setSort: (column: string, order?: \"asc\" | \"desc\") => void;\n /** Clear all sorting */\n clearSort: () => void;\n /** Toggle sort order for a column */\n toggleSort: (column: string) => void;\n /** Check if a column is currently sorted */\n isSorted: (column: string) => boolean;\n /** Get sort order for a column */\n getSortOrder: (column: string) => \"asc\" | \"desc\" | undefined;\n}\n\n/**\n * Hook for managing server-side sorting state using nuqs.\n *\n * This hook synchronizes sorting state with URL query parameters,\n * making it perfect for server-side sorting where the URL should\n * reflect the current sort state.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * sorting,\n * setSorting,\n * sortBy,\n * sortOrder,\n * setSort,\n * toggleSort\n * } = useSorting({\n * defaultSortBy: 'name',\n * defaultSortOrder: 'asc'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualSorting: true,\n * sorting,\n * onSortingChange: setSorting,\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function useSorting(options: UseSortingOptions = {}): UseSortingReturn {\n const {\n defaultSortBy,\n defaultSortOrder = \"asc\",\n sortByKey = \"sortBy\",\n sortOrderKey = \"sortOrder\",\n } = options;\n\n // Use nuqs to manage query state\n const [sortBy, setSortBy] = useQueryState(\n sortByKey,\n parseAsString.withDefault(defaultSortBy || \"\")\n );\n\n const [sortOrder, setSortOrder] = useQueryState(\n sortOrderKey,\n parseAsString.withDefault(defaultSortOrder)\n );\n\n // Ensure sort order is valid\n const validSortOrder = useMemo(() => {\n return sortOrder === \"desc\" ? \"desc\" : \"asc\";\n }, [sortOrder]);\n\n // Create sorting state for TanStack Table\n const sorting = useMemo<SortingState>(() => {\n if (!sortBy || sortBy.trim() === \"\") {\n return [];\n }\n return [\n {\n id: sortBy,\n desc: validSortOrder === \"desc\",\n },\n ];\n }, [sortBy, validSortOrder]);\n\n // Set sorting function that handles both object and function updates\n const setSorting = useCallback(\n (updater: SortingState | ((prev: SortingState) => SortingState)) => {\n const newSorting = typeof updater === \"function\" ? updater(sorting) : updater;\n\n if (newSorting.length === 0) {\n // Clear sorting\n setSortBy(\"\");\n } else {\n // Set first sort (TanStack Table typically only has one sort at a time)\n const firstSort = newSorting[0];\n setSortBy(firstSort.id);\n setSortOrder(firstSort.desc ? \"desc\" : \"asc\");\n }\n },\n [sorting, setSortBy, setSortOrder]\n );\n\n // Set sort column and order directly\n const setSort = useCallback(\n (column: string, order: \"asc\" | \"desc\" = \"asc\") => {\n setSortBy(column);\n setSortOrder(order);\n },\n [setSortBy, setSortOrder]\n );\n\n // Clear all sorting\n const clearSort = useCallback(() => {\n setSortBy(null);\n }, [setSortBy]);\n\n // Toggle sort order for a column\n const toggleSort = useCallback(\n (column: string) => {\n if (sortBy === column) {\n // Same column, toggle order\n setSortOrder(validSortOrder === \"asc\" ? \"desc\" : \"asc\");\n } else {\n // Different column, set new column with asc\n setSortBy(column);\n setSortOrder(\"asc\");\n }\n },\n [sortBy, validSortOrder, setSortBy, setSortOrder]\n );\n\n // Check if a column is currently sorted\n const isSorted = useCallback(\n (column: string) => {\n return sortBy === column;\n },\n [sortBy]\n );\n\n // Get sort order for a column\n const getSortOrder = useCallback(\n (column: string) => {\n return sortBy === column ? validSortOrder : undefined;\n },\n [sortBy, validSortOrder]\n );\n\n return {\n sorting,\n setSorting,\n sortBy: sortBy || undefined,\n sortOrder: validSortOrder,\n setSort,\n clearSort,\n toggleSort,\n isSorted,\n getSortOrder,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainsSelector({\n value,\n onValueChange,\n placeholder = \"Select chains\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokensSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select tokens\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value.length > 0) {\n onValueChange([]);\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductsSelector({\n value,\n onValueChange,\n placeholder = \"Select products\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitiesSelector({\n value,\n onValueChange,\n placeholder = \"Select opportunities\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const { data: opportunitiesData, isLoading } = useOpportunities();\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading opportunities...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainSelector({\n value,\n onValueChange,\n placeholder = \"Select chain\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <Combobox\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokenSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select token\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value) {\n onValueChange(\"\");\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <Combobox\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductSelector({\n value,\n onValueChange,\n placeholder = \"Select product\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <Combobox\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitySelector({\n value,\n onValueChange,\n placeholder = \"Select opportunity\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const { data: opportunitiesData, isLoading } = useOpportunities();\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n return (\n <Combobox\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading opportunities...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n"],"mappings":"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","names":["import_ui","import_nuqs","import_jsx_runtime","import_nuqs","import_jsx_runtime","import_nuqs","import_jsx_runtime","import_ui","import_jsx_runtime","import_ui","import_jsx_runtime","import_react","import_ui","import_lucide_react","import_jsx_runtime","import_ui","import_jsx_runtime","import_nuqs","import_react","import_nuqs","import_react","import_react","import_ui","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime","import_react","import_ui","import_hooks","import_jsx_runtime"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -469,8 +469,6 @@ interface OpportunitySelectorProps$1 {
|
|
|
469
469
|
value: string[];
|
|
470
470
|
/** Callback when selection changes */
|
|
471
471
|
onValueChange: (values: string[]) => void;
|
|
472
|
-
/** Selected product ID to filter opportunities */
|
|
473
|
-
productId?: string;
|
|
474
472
|
/** Placeholder text */
|
|
475
473
|
placeholder?: string;
|
|
476
474
|
/** Whether the selector is disabled */
|
|
@@ -484,7 +482,7 @@ interface OpportunitySelectorProps$1 {
|
|
|
484
482
|
/** Whether to show search */
|
|
485
483
|
searchable?: boolean;
|
|
486
484
|
}
|
|
487
|
-
declare function OpportunitiesSelector({ value, onValueChange,
|
|
485
|
+
declare function OpportunitiesSelector({ value, onValueChange, placeholder, disabled, className, maxCount, closeOnSelect, searchable, }: OpportunitySelectorProps$1): react_jsx_runtime.JSX.Element;
|
|
488
486
|
|
|
489
487
|
interface ChainSelectorProps {
|
|
490
488
|
/** Selected chain ID */
|
|
@@ -547,8 +545,6 @@ interface OpportunitySelectorProps {
|
|
|
547
545
|
value: string;
|
|
548
546
|
/** Callback when selection changes */
|
|
549
547
|
onValueChange: (value: string) => void;
|
|
550
|
-
/** Selected product ID to filter opportunities */
|
|
551
|
-
productId?: string;
|
|
552
548
|
/** Placeholder text */
|
|
553
549
|
placeholder?: string;
|
|
554
550
|
/** Whether the selector is disabled */
|
|
@@ -560,6 +556,6 @@ interface OpportunitySelectorProps {
|
|
|
560
556
|
/** Whether to show search */
|
|
561
557
|
searchable?: boolean;
|
|
562
558
|
}
|
|
563
|
-
declare function OpportunitySelector({ value, onValueChange,
|
|
559
|
+
declare function OpportunitySelector({ value, onValueChange, placeholder, disabled, className, closeOnSelect, searchable, }: OpportunitySelectorProps): react_jsx_runtime.JSX.Element;
|
|
564
560
|
|
|
565
561
|
export { ActiveFilterBadges, type ActiveFilterBadgesProps, type ActiveFilterConfig, BooleanFilter, ChainSelector, ChainsSelector, Filter, type FilterConfig, FiltersGrid, type FiltersGridProps, FiltersPopover, type FiltersPopoverProps, FiltersWrapper, type FiltersWrapperProps, MultiSelectFilter, OpportunitiesSelector, OpportunitySelector, ProductSelector, ProductsSelector, RangeSliderFilter, TokenSelector, TokensSelector, type UsePaginationOptions, type UsePaginationReturn, type UseSortingOptions, type UseSortingReturn, usePagination, useSorting };
|
package/dist/index.d.ts
CHANGED
|
@@ -469,8 +469,6 @@ interface OpportunitySelectorProps$1 {
|
|
|
469
469
|
value: string[];
|
|
470
470
|
/** Callback when selection changes */
|
|
471
471
|
onValueChange: (values: string[]) => void;
|
|
472
|
-
/** Selected product ID to filter opportunities */
|
|
473
|
-
productId?: string;
|
|
474
472
|
/** Placeholder text */
|
|
475
473
|
placeholder?: string;
|
|
476
474
|
/** Whether the selector is disabled */
|
|
@@ -484,7 +482,7 @@ interface OpportunitySelectorProps$1 {
|
|
|
484
482
|
/** Whether to show search */
|
|
485
483
|
searchable?: boolean;
|
|
486
484
|
}
|
|
487
|
-
declare function OpportunitiesSelector({ value, onValueChange,
|
|
485
|
+
declare function OpportunitiesSelector({ value, onValueChange, placeholder, disabled, className, maxCount, closeOnSelect, searchable, }: OpportunitySelectorProps$1): react_jsx_runtime.JSX.Element;
|
|
488
486
|
|
|
489
487
|
interface ChainSelectorProps {
|
|
490
488
|
/** Selected chain ID */
|
|
@@ -547,8 +545,6 @@ interface OpportunitySelectorProps {
|
|
|
547
545
|
value: string;
|
|
548
546
|
/** Callback when selection changes */
|
|
549
547
|
onValueChange: (value: string) => void;
|
|
550
|
-
/** Selected product ID to filter opportunities */
|
|
551
|
-
productId?: string;
|
|
552
548
|
/** Placeholder text */
|
|
553
549
|
placeholder?: string;
|
|
554
550
|
/** Whether the selector is disabled */
|
|
@@ -560,6 +556,6 @@ interface OpportunitySelectorProps {
|
|
|
560
556
|
/** Whether to show search */
|
|
561
557
|
searchable?: boolean;
|
|
562
558
|
}
|
|
563
|
-
declare function OpportunitySelector({ value, onValueChange,
|
|
559
|
+
declare function OpportunitySelector({ value, onValueChange, placeholder, disabled, className, closeOnSelect, searchable, }: OpportunitySelectorProps): react_jsx_runtime.JSX.Element;
|
|
564
560
|
|
|
565
561
|
export { ActiveFilterBadges, type ActiveFilterBadgesProps, type ActiveFilterConfig, BooleanFilter, ChainSelector, ChainsSelector, Filter, type FilterConfig, FiltersGrid, type FiltersGridProps, FiltersPopover, type FiltersPopoverProps, FiltersWrapper, type FiltersWrapperProps, MultiSelectFilter, OpportunitiesSelector, OpportunitySelector, ProductSelector, ProductsSelector, RangeSliderFilter, TokenSelector, TokensSelector, type UsePaginationOptions, type UsePaginationReturn, type UseSortingOptions, type UseSortingReturn, usePagination, useSorting };
|
package/dist/index.js
CHANGED
|
@@ -694,14 +694,13 @@ function ProductsSelector({
|
|
|
694
694
|
}
|
|
695
695
|
|
|
696
696
|
// src/selectors/OpportunitiesSelector.tsx
|
|
697
|
-
import { useMemo as useMemo7
|
|
697
|
+
import { useMemo as useMemo7 } from "react";
|
|
698
698
|
import { MultiSelect as MultiSelect4 } from "@turtleclub/ui";
|
|
699
699
|
import { useOpportunities } from "@turtleclub/hooks";
|
|
700
700
|
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
701
701
|
function OpportunitiesSelector({
|
|
702
702
|
value,
|
|
703
703
|
onValueChange,
|
|
704
|
-
productId,
|
|
705
704
|
placeholder = "Select opportunities",
|
|
706
705
|
disabled = false,
|
|
707
706
|
className,
|
|
@@ -709,13 +708,7 @@ function OpportunitiesSelector({
|
|
|
709
708
|
closeOnSelect = true,
|
|
710
709
|
searchable = true
|
|
711
710
|
}) {
|
|
712
|
-
const
|
|
713
|
-
const { data: opportunitiesData, isLoading } = useOpportunities({
|
|
714
|
-
filters: {
|
|
715
|
-
productId
|
|
716
|
-
},
|
|
717
|
-
enabled: isProductSelected
|
|
718
|
-
});
|
|
711
|
+
const { data: opportunitiesData, isLoading } = useOpportunities();
|
|
719
712
|
const opportunities = useMemo7(
|
|
720
713
|
() => opportunitiesData?.opportunities ?? [],
|
|
721
714
|
[opportunitiesData?.opportunities]
|
|
@@ -739,11 +732,6 @@ function OpportunitiesSelector({
|
|
|
739
732
|
) : void 0
|
|
740
733
|
}));
|
|
741
734
|
}, [opportunities]);
|
|
742
|
-
useEffect3(() => {
|
|
743
|
-
if (!isProductSelected && value.length > 0) {
|
|
744
|
-
onValueChange([]);
|
|
745
|
-
}
|
|
746
|
-
}, [isProductSelected, value, onValueChange]);
|
|
747
735
|
return /* @__PURE__ */ jsx12(
|
|
748
736
|
MultiSelect4,
|
|
749
737
|
{
|
|
@@ -751,8 +739,8 @@ function OpportunitiesSelector({
|
|
|
751
739
|
options: opportunityOptions,
|
|
752
740
|
value,
|
|
753
741
|
onValueChange,
|
|
754
|
-
disabled: disabled || isLoading
|
|
755
|
-
placeholder:
|
|
742
|
+
disabled: disabled || isLoading,
|
|
743
|
+
placeholder: isLoading ? "Loading opportunities..." : placeholder,
|
|
756
744
|
closeOnSelect,
|
|
757
745
|
maxCount,
|
|
758
746
|
className
|
|
@@ -809,7 +797,7 @@ function ChainSelector({
|
|
|
809
797
|
}
|
|
810
798
|
|
|
811
799
|
// src/selectors/TokenSelector.tsx
|
|
812
|
-
import { useEffect as
|
|
800
|
+
import { useEffect as useEffect3, useMemo as useMemo9 } from "react";
|
|
813
801
|
import { Combobox as Combobox2 } from "@turtleclub/ui";
|
|
814
802
|
import { useSupportedTokens as useSupportedTokens2 } from "@turtleclub/hooks";
|
|
815
803
|
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
@@ -846,7 +834,7 @@ function TokenSelector({
|
|
|
846
834
|
) : void 0
|
|
847
835
|
}));
|
|
848
836
|
}, [tokens]);
|
|
849
|
-
|
|
837
|
+
useEffect3(() => {
|
|
850
838
|
if (!isChainSelected && value) {
|
|
851
839
|
onValueChange("");
|
|
852
840
|
}
|
|
@@ -915,27 +903,20 @@ function ProductSelector({
|
|
|
915
903
|
}
|
|
916
904
|
|
|
917
905
|
// src/selectors/OpportunitySelector.tsx
|
|
918
|
-
import { useMemo as useMemo11
|
|
906
|
+
import { useMemo as useMemo11 } from "react";
|
|
919
907
|
import { Combobox as Combobox4 } from "@turtleclub/ui";
|
|
920
908
|
import { useOpportunities as useOpportunities2 } from "@turtleclub/hooks";
|
|
921
909
|
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
922
910
|
function OpportunitySelector({
|
|
923
911
|
value,
|
|
924
912
|
onValueChange,
|
|
925
|
-
productId,
|
|
926
913
|
placeholder = "Select opportunity",
|
|
927
914
|
disabled = false,
|
|
928
915
|
className,
|
|
929
916
|
closeOnSelect = true,
|
|
930
917
|
searchable = true
|
|
931
918
|
}) {
|
|
932
|
-
const
|
|
933
|
-
const { data: opportunitiesData, isLoading } = useOpportunities2({
|
|
934
|
-
filters: {
|
|
935
|
-
productId
|
|
936
|
-
},
|
|
937
|
-
enabled: isProductSelected
|
|
938
|
-
});
|
|
919
|
+
const { data: opportunitiesData, isLoading } = useOpportunities2();
|
|
939
920
|
const opportunities = useMemo11(
|
|
940
921
|
() => opportunitiesData?.opportunities ?? [],
|
|
941
922
|
[opportunitiesData?.opportunities]
|
|
@@ -959,11 +940,6 @@ function OpportunitySelector({
|
|
|
959
940
|
) : void 0
|
|
960
941
|
}));
|
|
961
942
|
}, [opportunities]);
|
|
962
|
-
useEffect5(() => {
|
|
963
|
-
if (!isProductSelected && value) {
|
|
964
|
-
onValueChange("");
|
|
965
|
-
}
|
|
966
|
-
}, [isProductSelected, value, onValueChange]);
|
|
967
943
|
return /* @__PURE__ */ jsx16(
|
|
968
944
|
Combobox4,
|
|
969
945
|
{
|
|
@@ -971,8 +947,8 @@ function OpportunitySelector({
|
|
|
971
947
|
options: opportunityOptions,
|
|
972
948
|
value,
|
|
973
949
|
onValueChange,
|
|
974
|
-
disabled: disabled || isLoading
|
|
975
|
-
placeholder:
|
|
950
|
+
disabled: disabled || isLoading,
|
|
951
|
+
placeholder: isLoading ? "Loading opportunities..." : placeholder,
|
|
976
952
|
closeOnSelect,
|
|
977
953
|
className
|
|
978
954
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/filters/RangeSliderFilter.tsx","../src/filters/BooleanFilter.tsx","../src/filters/Filter.tsx","../src/filters/MultiSelectFilter.tsx","../src/wrappers/FiltersGrid.tsx","../src/wrappers/FiltersPopover.tsx","../src/wrappers/ActiveFilterBadges.tsx","../src/wrappers/FiltersWrapper.tsx","../src/helpers/usePagination.ts","../src/helpers/useSorting.ts","../src/selectors/ChainsSelector.tsx","../src/selectors/TokensSelector.tsx","../src/selectors/ProductsSelector.tsx","../src/selectors/OpportunitiesSelector.tsx","../src/selectors/ChainSelector.tsx","../src/selectors/TokenSelector.tsx","../src/selectors/ProductSelector.tsx","../src/selectors/OpportunitySelector.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport { Slider, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsInteger } from \"nuqs\";\n\ninterface RangeSliderFilterProps {\n /** Query key for minimum value (default: 'min') */\n minQueryKey?: string;\n /** Query key for maximum value (default: 'max') */\n maxQueryKey?: string;\n /** Minimum value (default: 0) */\n min?: number;\n /** Maximum value (default: 100) */\n max?: number;\n /** Step value for slider (default: 1) */\n step?: number;\n /** Whether the filter is disabled */\n disabled?: boolean;\n /** Custom label for the filter */\n label: string;\n /** Whether to show values (default: true) */\n showValues?: boolean;\n /** Value formatter function */\n formatValue?: (value: number) => string;\n /** Custom className for the container */\n className?: string;\n}\n\nconst defaultFormatter = (value: number): string => {\n return value.toLocaleString();\n};\n\nexport function RangeSliderFilter({\n minQueryKey = \"min\",\n maxQueryKey = \"max\",\n min = 0,\n max = 100,\n step = 1,\n disabled = false,\n label = \"Range\",\n showValues = true,\n formatValue = defaultFormatter,\n className = \"\",\n}: RangeSliderFilterProps) {\n const [minValue, setMinValue] = useQueryState(minQueryKey, parseAsInteger.withDefault(min));\n\n const [maxValue, setMaxValue] = useQueryState(maxQueryKey, parseAsInteger.withDefault(max));\n\n // Local state for slider values (to avoid excessive URL updates)\n const [localRange, setLocalRange] = useState([minValue, maxValue]);\n\n // Update local state when query params change\n useEffect(() => {\n setLocalRange([minValue, maxValue]);\n }, [minValue, maxValue]);\n\n const handleRangeChange = (values: number[]) => {\n setLocalRange(values);\n };\n\n const handleRangeCommit = (values: number[]) => {\n const [newMin, newMax] = values;\n if (newMin !== minValue) {\n setMinValue(newMin === min ? null : newMin);\n }\n if (newMax !== maxValue) {\n setMaxValue(newMax === max ? null : newMax);\n }\n };\n\n const isDefaultRange = localRange[0] === min && localRange[1] === max;\n\n return (\n <div className={`space-y-3 ${className}`}>\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {showValues && (\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <span>{formatValue(localRange[0])}</span>\n <span>-</span>\n <span>{formatValue(localRange[1])}</span>\n </div>\n )}\n </div>\n\n <div className=\"px-2\">\n <Slider\n value={localRange}\n onValueChange={handleRangeChange}\n onValueCommit={handleRangeCommit}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n className=\"w-full\"\n />\n </div>\n\n {showValues && (\n <div className=\"flex justify-between text-xs text-muted-foreground\">\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n )}\n\n {!isDefaultRange && (\n <div className=\"flex justify-end\">\n <button\n onClick={() => {\n setLocalRange([min, max]);\n handleRangeCommit([min, max]);\n }}\n className=\"text-xs text-muted-foreground hover:text-foreground transition-colors\"\n disabled={disabled}\n >\n Reset\n </button>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Switch, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsBoolean } from \"nuqs\";\n\ninterface BooleanSwitchFilterProps {\n /** Query key for the boolean value (default: 'enabled') */\n queryKey?: string;\n /** Default value when not set (default: false) */\n defaultValue?: boolean;\n /** Whether the switch is disabled */\n disabled?: boolean;\n /** Label for the switch */\n label: string;\n /** Description text (optional) */\n description?: string;\n /** Custom className for the container */\n className?: string;\n}\n\nexport function BooleanFilter({\n queryKey = \"enabled\",\n defaultValue = false,\n disabled = false,\n label,\n description,\n className = \"\",\n}: BooleanSwitchFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsBoolean.withDefault(defaultValue));\n\n const handleToggle = (checked: boolean) => {\n // If the value is the same as default, remove from URL\n setValue(checked === defaultValue ? null : checked);\n };\n\n return (\n <div className={`flex items-center justify-between space-x-2 ${className}`}>\n <div className=\"space-y-0.5\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {description && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n </div>\n <Switch checked={value} onCheckedChange={handleToggle} disabled={disabled} />\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsString } from \"nuqs\";\n\ninterface FilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: { value: string; onValueChange: (value: string) => void }) => React.ReactNode;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Generic Filter component that handles nuqs URL state management for single values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example Basic Single Selection\n * ```tsx\n * // Single chain selection - persists to URL as ?chainId=ethereum\n * <Filter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chain\"\n * />\n * )}\n * </Filter>\n * ```\n */\nexport function Filter({ queryKey, children, onValueChange }: FilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsString.withDefault(\"\"));\n\n const handleValueChange = (newValue: string) => {\n setValue(newValue || null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsArrayOf, parseAsString } from \"nuqs\";\n\ninterface MultiSelectFilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: {\n value: string[];\n onValueChange: (values: string[]) => void;\n }) => React.ReactNode;\n /** Callback when values change */\n onValueChange?: (values: string[]) => void;\n}\n\n/**\n * Generic MultiSelectFilter component that handles nuqs URL state management for array values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example\n * ```tsx\n * <MultiSelectFilter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainsSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chains\"\n * />\n * )}\n * </MultiSelectFilter>\n * ```\n */\nexport function MultiSelectFilter({ queryKey, children, onValueChange }: MultiSelectFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsArrayOf(parseAsString).withDefault([]));\n\n const handleValueChange = (newValue: string[]) => {\n setValue(newValue.length > 0 ? newValue : null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn, Label } from \"@turtleclub/ui\";\n\nexport interface FilterConfig {\n key: string;\n label: string;\n component: React.ReactNode;\n enabled: boolean;\n section?: string;\n}\n\nexport interface FiltersGridProps {\n filters: FilterConfig[];\n columns?: number;\n className?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersGrid({\n filters,\n columns = 3,\n className,\n sectionClassName,\n}: FiltersGridProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <div className={cn(\"space-y-4\", className)}>\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger, Button, cn, Label, Badge } from \"@turtleclub/ui\";\nimport { SlidersHorizontal } from \"lucide-react\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersPopoverProps {\n filters: FilterConfig[];\n triggerLabel?: string;\n columns?: number;\n className?: string;\n popoverClassName?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersPopover({\n filters,\n triggerLabel = \"Filters\",\n columns = 2,\n className,\n popoverClassName,\n sectionClassName,\n}: FiltersPopoverProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className={cn(className)}>\n <SlidersHorizontal className=\"mr-2 h-4 w-4\" />\n {triggerLabel}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n className={cn(\"w-auto min-w-[400px] max-w-[600px]\", popoverClassName)}\n align=\"start\"\n >\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"font-medium text-sm\">Filters</h4>\n </div>\n <div className=\"space-y-4\">\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\nimport React, { useMemo } from \"react\";\nimport { Badge, Button, cn } from \"@turtleclub/ui\";\nimport { X } from \"lucide-react\";\n\nexport interface ActiveFilterConfig {\n /** Unique key for the filter */\n key: string;\n /** Display label for the filter */\n label: string;\n /** Current filter value to display */\n value: string;\n /** Query parameter key(s) this filter uses */\n queryKeys: string | string[];\n /** Whether this filter is currently active */\n isActive: boolean;\n}\n\nexport interface ActiveFilterBadgesProps {\n /** Array of filter configurations */\n filters: ActiveFilterConfig[];\n /** Custom className for the container */\n className?: string;\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Component that displays active filter badges with individual clear buttons\n * and an optional \"clear all\" button.\n *\n * @example\n * ```tsx\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * {\n * key: 'sorting',\n * label: 'Sort',\n * value: 'Name (A-Z)',\n * queryKeys: ['sortBy', 'sortOrder'],\n * isActive: true,\n * },\n * ];\n *\n * <ActiveFilterBadges filters={activeFilters} />\n * ```\n */\nexport function ActiveFilterBadges({\n filters,\n className,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n onClearFilter,\n onClearAll,\n}: ActiveFilterBadgesProps) {\n // Get only active filters\n const activeFilters = useMemo(() => {\n return filters.filter((filter) => filter.isActive && filter.value);\n }, [filters]);\n\n // Clear all function\n const clearAll = () => {\n const allQueryKeys = activeFilters.map((filter) => filter.queryKeys);\n onClearAll(allQueryKeys);\n };\n\n // Don't render if no active filters\n if (activeFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {activeFilters.map((filter) => {\n return (\n <FilterBadge\n key={filter.key}\n filter={filter}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n />\n );\n })}\n\n {showClearAll && activeFilters.length > 1 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearAll} className=\"h-7 px-2 text-xs\">\n {clearAllLabel}\n </Button>\n )}\n </div>\n );\n}\n\ninterface FilterBadgeProps {\n filter: ActiveFilterConfig;\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n onClearFilter: (queryKeys: string | string[]) => void;\n}\n\nfunction FilterBadge({ filter, renderBadge, onClearFilter }: FilterBadgeProps) {\n const clearFilter = () => {\n onClearFilter(filter.queryKeys);\n };\n\n if (renderBadge) {\n return <>{renderBadge(filter, clearFilter)}</>;\n }\n\n return (\n <Badge className=\"flex items-center gap-1 pr-1 border-border border\">\n <span className=\"text-xs\">\n {filter.label}: {filter.value}\n </span>\n <button\n onClick={clearFilter}\n className=\"ml-1 rounded-full p-0.5 hover:bg-black/10 focus:bg-black/10 focus:outline-none\"\n aria-label={`Clear ${filter.label} filter`}\n >\n <X className=\"h-3 w-3\" />\n </button>\n </Badge>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@turtleclub/ui\";\nimport { FiltersGrid } from \"./FiltersGrid\";\nimport { FiltersPopover } from \"./FiltersPopover\";\nimport { ActiveFilterBadges, ActiveFilterConfig } from \"./ActiveFilterBadges\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersWrapperProps {\n /** Array of filter configurations */\n filters: FilterConfig[];\n /** Array of active filter configurations for badges */\n activeFilters: ActiveFilterConfig[];\n /** Layout type: 'grid' or 'popover' */\n layout: \"grid\" | \"popover\";\n /** Custom className for the wrapper */\n className?: string;\n /** Custom className for the active badges section */\n badgesClassName?: string;\n\n // Grid-specific props\n /** Number of columns for grid layout (default: 3) */\n columns?: number;\n\n // Popover-specific props\n /** Button label for popover trigger (default: \"Filters\") */\n triggerLabel?: string;\n /** Number of columns in popover (default: 2) */\n popoverColumns?: number;\n /** Custom className for popover trigger button */\n popoverClassName?: string;\n /** Custom className for popover content */\n popoverContentClassName?: string;\n\n // Active badges props\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Whether to show active filter badges (default: true) */\n showActiveBadges?: boolean;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Unified wrapper component that combines filter controls with active filter badges.\n *\n * Supports both grid and popover layouts, automatically displays active filter badges\n * below the filter controls with individual and bulk clear functionality.\n *\n * @example\n * ```tsx\n * const filters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * component: <ChainFilter />,\n * enabled: true,\n * },\n * ];\n *\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * ];\n *\n * <FiltersWrapper\n * layout=\"grid\"\n * filters={filters}\n * activeFilters={activeFilters}\n * />\n * ```\n */\nexport function FiltersWrapper({\n filters,\n activeFilters,\n layout,\n className,\n badgesClassName,\n columns = 3,\n triggerLabel = \"Filters\",\n popoverColumns = 2,\n popoverClassName,\n popoverContentClassName,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n showActiveBadges = true,\n onClearFilter,\n onClearAll,\n}: FiltersWrapperProps) {\n const hasActiveFilters = activeFilters.some((filter) => filter.isActive && filter.value);\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n {/* Filter Controls */}\n {layout === \"grid\" ? (\n <FiltersGrid filters={filters} columns={columns} className={popoverClassName} />\n ) : (\n <FiltersPopover\n filters={filters}\n triggerLabel={triggerLabel}\n columns={popoverColumns}\n className={popoverClassName}\n popoverClassName={popoverContentClassName}\n />\n )}\n\n {/* Active Filter Badges */}\n {showActiveBadges && hasActiveFilters && (\n <ActiveFilterBadges\n filters={activeFilters}\n className={badgesClassName}\n clearAllLabel={clearAllLabel}\n showClearAll={showClearAll}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n onClearAll={onClearAll}\n />\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useQueryState, parseAsInteger } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { PaginationState } from \"@tanstack/react-table\";\n\nexport interface UsePaginationOptions {\n /** Default page size (default: 10) */\n defaultPageSize?: number;\n /** Default page index (default: 0) */\n defaultPageIndex?: number;\n /** Query param key for page index (default: 'page') */\n pageIndexKey?: string;\n /** Query param key for page size (default: 'pageSize') */\n pageSizeKey?: string;\n}\n\nexport interface UsePaginationReturn {\n /** Current pagination state for TanStack Table */\n pagination: PaginationState;\n /** Function to update pagination state */\n setPagination: (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => void;\n /** Current page index (0-based) */\n pageIndex: number;\n /** Current page size */\n pageSize: number;\n /** Set page index directly */\n setPageIndex: (pageIndex: number) => void;\n /** Set page size directly */\n setPageSize: (pageSize: number) => void;\n /** Go to next page */\n nextPage: (totalPages?: number) => void;\n /** Go to previous page */\n previousPage: () => void;\n /** Go to first page */\n firstPage: () => void;\n /** Go to last page */\n lastPage: (totalPages: number) => void;\n /** Reset pagination to defaults */\n reset: () => void;\n /** Check if can go to next page */\n canNextPage: (totalPages?: number) => boolean;\n /** Check if can go to previous page */\n canPreviousPage: boolean;\n}\n\n/**\n * Hook for managing server-side pagination state using nuqs.\n *\n * This hook synchronizes pagination state with URL query parameters,\n * making it perfect for server-side pagination where the URL should\n * reflect the current page and page size.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * pagination,\n * setPagination,\n * pageIndex,\n * pageSize,\n * setPageIndex,\n * setPageSize\n * } = usePagination({\n * defaultPageSize: 20,\n * pageIndexKey: 'page',\n * pageSizeKey: 'limit'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualPagination: true,\n * pagination,\n * onPaginationChange: setPagination,\n * pageCount: Math.ceil(totalCount / pageSize),\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function usePagination(options: UsePaginationOptions = {}): UsePaginationReturn {\n const {\n defaultPageSize = 10,\n defaultPageIndex = 0,\n pageIndexKey = \"page\",\n pageSizeKey = \"pageSize\",\n } = options;\n\n // Use nuqs to manage query state\n const [rawPageIndex, setRawPageIndex] = useQueryState(\n pageIndexKey,\n parseAsInteger.withDefault(defaultPageIndex)\n );\n\n const [rawPageSize, setRawPageSize] = useQueryState(\n pageSizeKey,\n parseAsInteger.withDefault(defaultPageSize)\n );\n\n // Ensure page index is never negative\n const pageIndex = useMemo(() => Math.max(0, rawPageIndex), [rawPageIndex]);\n\n // Use page size directly from query state\n const pageSize = rawPageSize;\n\n // Create pagination state for TanStack Table\n const pagination = useMemo<PaginationState>(\n () => ({\n pageIndex,\n pageSize,\n }),\n [pageIndex, pageSize]\n );\n\n // Set pagination function that handles both object and function updates\n const setPagination = useCallback(\n (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => {\n const newPagination = typeof updater === \"function\" ? updater(pagination) : updater;\n\n if (newPagination.pageIndex !== pageIndex) {\n setRawPageIndex(Math.max(0, newPagination.pageIndex));\n }\n\n if (newPagination.pageSize !== pageSize) {\n setRawPageSize(newPagination.pageSize);\n }\n },\n [pagination, pageIndex, pageSize, setRawPageIndex, setRawPageSize]\n );\n\n // Individual setters\n const setPageIndex = useCallback(\n (newPageIndex: number) => {\n setRawPageIndex(Math.max(0, newPageIndex));\n },\n [setRawPageIndex]\n );\n\n const setPageSize = useCallback(\n (newPageSize: number) => {\n setRawPageSize(newPageSize);\n // Reset to first page when page size changes\n setRawPageIndex(0);\n },\n [setRawPageSize, setRawPageIndex]\n );\n\n // Navigation functions\n const nextPage = useCallback(\n (totalPages?: number) => {\n const nextPageIndex = pageIndex + 1;\n if (!totalPages || nextPageIndex < totalPages) {\n setPageIndex(nextPageIndex);\n }\n },\n [pageIndex, setPageIndex]\n );\n\n const previousPage = useCallback(() => {\n if (pageIndex > 0) {\n setPageIndex(pageIndex - 1);\n }\n }, [pageIndex, setPageIndex]);\n\n const firstPage = useCallback(() => {\n setPageIndex(0);\n }, [setPageIndex]);\n\n const lastPage = useCallback(\n (totalPages: number) => {\n setPageIndex(Math.max(0, totalPages - 1));\n },\n [setPageIndex]\n );\n\n // Reset function\n const reset = useCallback(() => {\n setRawPageIndex(defaultPageIndex);\n setRawPageSize(defaultPageSize);\n }, [setRawPageIndex, setRawPageSize, defaultPageIndex, defaultPageSize]);\n\n // Navigation state\n const canPreviousPage = pageIndex > 0;\n const canNextPage = useCallback(\n (totalPages?: number) => {\n if (!totalPages) return true; // Assume we can go next if total pages unknown\n return pageIndex < totalPages - 1;\n },\n [pageIndex]\n );\n\n return {\n pagination,\n setPagination,\n pageIndex,\n pageSize,\n setPageIndex,\n setPageSize,\n nextPage,\n previousPage,\n firstPage,\n lastPage,\n reset,\n canNextPage,\n canPreviousPage,\n };\n}\n","\"use client\";\n\nimport { useQueryState, parseAsString } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { SortingState } from \"@tanstack/react-table\";\n\nexport interface UseSortingOptions {\n /** Default sort column (default: undefined - no sorting) */\n defaultSortBy?: string;\n /** Default sort order (default: 'asc') */\n defaultSortOrder?: \"asc\" | \"desc\";\n /** Query param key for sort column (default: 'sortBy') */\n sortByKey?: string;\n /** Query param key for sort order (default: 'sortOrder') */\n sortOrderKey?: string;\n}\n\nexport interface UseSortingReturn {\n /** Current sorting state for TanStack Table */\n sorting: SortingState;\n /** Function to update sorting state */\n setSorting: (updater: SortingState | ((prev: SortingState) => SortingState)) => void;\n /** Current sort column (undefined if no sorting) */\n sortBy: string | undefined;\n /** Current sort order */\n sortOrder: \"asc\" | \"desc\";\n /** Set sort column and order directly */\n setSort: (column: string, order?: \"asc\" | \"desc\") => void;\n /** Clear all sorting */\n clearSort: () => void;\n /** Toggle sort order for a column */\n toggleSort: (column: string) => void;\n /** Check if a column is currently sorted */\n isSorted: (column: string) => boolean;\n /** Get sort order for a column */\n getSortOrder: (column: string) => \"asc\" | \"desc\" | undefined;\n}\n\n/**\n * Hook for managing server-side sorting state using nuqs.\n *\n * This hook synchronizes sorting state with URL query parameters,\n * making it perfect for server-side sorting where the URL should\n * reflect the current sort state.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * sorting,\n * setSorting,\n * sortBy,\n * sortOrder,\n * setSort,\n * toggleSort\n * } = useSorting({\n * defaultSortBy: 'name',\n * defaultSortOrder: 'asc'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualSorting: true,\n * sorting,\n * onSortingChange: setSorting,\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function useSorting(options: UseSortingOptions = {}): UseSortingReturn {\n const {\n defaultSortBy,\n defaultSortOrder = \"asc\",\n sortByKey = \"sortBy\",\n sortOrderKey = \"sortOrder\",\n } = options;\n\n // Use nuqs to manage query state\n const [sortBy, setSortBy] = useQueryState(\n sortByKey,\n parseAsString.withDefault(defaultSortBy || \"\")\n );\n\n const [sortOrder, setSortOrder] = useQueryState(\n sortOrderKey,\n parseAsString.withDefault(defaultSortOrder)\n );\n\n // Ensure sort order is valid\n const validSortOrder = useMemo(() => {\n return sortOrder === \"desc\" ? \"desc\" : \"asc\";\n }, [sortOrder]);\n\n // Create sorting state for TanStack Table\n const sorting = useMemo<SortingState>(() => {\n if (!sortBy || sortBy.trim() === \"\") {\n return [];\n }\n return [\n {\n id: sortBy,\n desc: validSortOrder === \"desc\",\n },\n ];\n }, [sortBy, validSortOrder]);\n\n // Set sorting function that handles both object and function updates\n const setSorting = useCallback(\n (updater: SortingState | ((prev: SortingState) => SortingState)) => {\n const newSorting = typeof updater === \"function\" ? updater(sorting) : updater;\n\n if (newSorting.length === 0) {\n // Clear sorting\n setSortBy(\"\");\n } else {\n // Set first sort (TanStack Table typically only has one sort at a time)\n const firstSort = newSorting[0];\n setSortBy(firstSort.id);\n setSortOrder(firstSort.desc ? \"desc\" : \"asc\");\n }\n },\n [sorting, setSortBy, setSortOrder]\n );\n\n // Set sort column and order directly\n const setSort = useCallback(\n (column: string, order: \"asc\" | \"desc\" = \"asc\") => {\n setSortBy(column);\n setSortOrder(order);\n },\n [setSortBy, setSortOrder]\n );\n\n // Clear all sorting\n const clearSort = useCallback(() => {\n setSortBy(null);\n }, [setSortBy]);\n\n // Toggle sort order for a column\n const toggleSort = useCallback(\n (column: string) => {\n if (sortBy === column) {\n // Same column, toggle order\n setSortOrder(validSortOrder === \"asc\" ? \"desc\" : \"asc\");\n } else {\n // Different column, set new column with asc\n setSortBy(column);\n setSortOrder(\"asc\");\n }\n },\n [sortBy, validSortOrder, setSortBy, setSortOrder]\n );\n\n // Check if a column is currently sorted\n const isSorted = useCallback(\n (column: string) => {\n return sortBy === column;\n },\n [sortBy]\n );\n\n // Get sort order for a column\n const getSortOrder = useCallback(\n (column: string) => {\n return sortBy === column ? validSortOrder : undefined;\n },\n [sortBy, validSortOrder]\n );\n\n return {\n sorting,\n setSorting,\n sortBy: sortBy || undefined,\n sortOrder: validSortOrder,\n setSort,\n clearSort,\n toggleSort,\n isSorted,\n getSortOrder,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainsSelector({\n value,\n onValueChange,\n placeholder = \"Select chains\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokensSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select tokens\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value.length > 0) {\n onValueChange([]);\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductsSelector({\n value,\n onValueChange,\n placeholder = \"Select products\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo, useEffect } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Selected product ID to filter opportunities */\n productId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitiesSelector({\n value,\n onValueChange,\n productId,\n placeholder = \"Select opportunities\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const isProductSelected = !!productId && productId.trim() !== \"\";\n\n const { data: opportunitiesData, isLoading } = useOpportunities({\n filters: {\n productId,\n },\n enabled: isProductSelected,\n });\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n // Clear selection when product changes\n useEffect(() => {\n if (!isProductSelected && value.length > 0) {\n onValueChange([]);\n }\n }, [isProductSelected, value, onValueChange]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isProductSelected}\n placeholder={\n !isProductSelected\n ? \"Select a product first\"\n : isLoading\n ? \"Loading opportunities...\"\n : placeholder\n }\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainSelector({\n value,\n onValueChange,\n placeholder = \"Select chain\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <Combobox\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokenSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select token\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value) {\n onValueChange(\"\");\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <Combobox\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductSelector({\n value,\n onValueChange,\n placeholder = \"Select product\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <Combobox\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo, useEffect } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Selected product ID to filter opportunities */\n productId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitySelector({\n value,\n onValueChange,\n productId,\n placeholder = \"Select opportunity\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const isProductSelected = !!productId && productId.trim() !== \"\";\n\n const { data: opportunitiesData, isLoading } = useOpportunities({\n filters: {\n productId,\n },\n enabled: isProductSelected,\n });\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n // Clear selection when product changes\n useEffect(() => {\n if (!isProductSelected && value) {\n onValueChange(\"\");\n }\n }, [isProductSelected, value, onValueChange]);\n\n return (\n <Combobox\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isProductSelected}\n placeholder={\n !isProductSelected\n ? \"Select a product first\"\n : isLoading\n ? \"Loading opportunities...\"\n : placeholder\n }\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n"],"mappings":"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","names":["Label","useQueryState","jsx","jsxs","useQueryState","jsx","useQueryState","parseAsString","Fragment","jsx","jsx","jsxs","cn","jsx","jsxs","Badge","Button","cn","Fragment","jsx","jsxs","cn","jsx","jsxs","cn","useQueryState","parseAsInteger","useMemo","useQueryState","parseAsString","useMemo","useCallback","useMemo","jsx","useEffect","useMemo","MultiSelect","jsx","useMemo","MultiSelect","jsx","useMemo","useEffect","MultiSelect","jsx","useMemo","useSupportedChains","jsx","useEffect","useMemo","Combobox","useSupportedTokens","jsx","useMemo","Combobox","useProducts","jsx","useMemo","useEffect","Combobox","useOpportunities","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/filters/RangeSliderFilter.tsx","../src/filters/BooleanFilter.tsx","../src/filters/Filter.tsx","../src/filters/MultiSelectFilter.tsx","../src/wrappers/FiltersGrid.tsx","../src/wrappers/FiltersPopover.tsx","../src/wrappers/ActiveFilterBadges.tsx","../src/wrappers/FiltersWrapper.tsx","../src/helpers/usePagination.ts","../src/helpers/useSorting.ts","../src/selectors/ChainsSelector.tsx","../src/selectors/TokensSelector.tsx","../src/selectors/ProductsSelector.tsx","../src/selectors/OpportunitiesSelector.tsx","../src/selectors/ChainSelector.tsx","../src/selectors/TokenSelector.tsx","../src/selectors/ProductSelector.tsx","../src/selectors/OpportunitySelector.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport { Slider, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsInteger } from \"nuqs\";\n\ninterface RangeSliderFilterProps {\n /** Query key for minimum value (default: 'min') */\n minQueryKey?: string;\n /** Query key for maximum value (default: 'max') */\n maxQueryKey?: string;\n /** Minimum value (default: 0) */\n min?: number;\n /** Maximum value (default: 100) */\n max?: number;\n /** Step value for slider (default: 1) */\n step?: number;\n /** Whether the filter is disabled */\n disabled?: boolean;\n /** Custom label for the filter */\n label: string;\n /** Whether to show values (default: true) */\n showValues?: boolean;\n /** Value formatter function */\n formatValue?: (value: number) => string;\n /** Custom className for the container */\n className?: string;\n}\n\nconst defaultFormatter = (value: number): string => {\n return value.toLocaleString();\n};\n\nexport function RangeSliderFilter({\n minQueryKey = \"min\",\n maxQueryKey = \"max\",\n min = 0,\n max = 100,\n step = 1,\n disabled = false,\n label = \"Range\",\n showValues = true,\n formatValue = defaultFormatter,\n className = \"\",\n}: RangeSliderFilterProps) {\n const [minValue, setMinValue] = useQueryState(minQueryKey, parseAsInteger.withDefault(min));\n\n const [maxValue, setMaxValue] = useQueryState(maxQueryKey, parseAsInteger.withDefault(max));\n\n // Local state for slider values (to avoid excessive URL updates)\n const [localRange, setLocalRange] = useState([minValue, maxValue]);\n\n // Update local state when query params change\n useEffect(() => {\n setLocalRange([minValue, maxValue]);\n }, [minValue, maxValue]);\n\n const handleRangeChange = (values: number[]) => {\n setLocalRange(values);\n };\n\n const handleRangeCommit = (values: number[]) => {\n const [newMin, newMax] = values;\n if (newMin !== minValue) {\n setMinValue(newMin === min ? null : newMin);\n }\n if (newMax !== maxValue) {\n setMaxValue(newMax === max ? null : newMax);\n }\n };\n\n const isDefaultRange = localRange[0] === min && localRange[1] === max;\n\n return (\n <div className={`space-y-3 ${className}`}>\n <div className=\"flex items-center justify-between\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {showValues && (\n <div className=\"flex items-center gap-1 text-xs text-muted-foreground\">\n <span>{formatValue(localRange[0])}</span>\n <span>-</span>\n <span>{formatValue(localRange[1])}</span>\n </div>\n )}\n </div>\n\n <div className=\"px-2\">\n <Slider\n value={localRange}\n onValueChange={handleRangeChange}\n onValueCommit={handleRangeCommit}\n min={min}\n max={max}\n step={step}\n disabled={disabled}\n className=\"w-full\"\n />\n </div>\n\n {showValues && (\n <div className=\"flex justify-between text-xs text-muted-foreground\">\n <span>{formatValue(min)}</span>\n <span>{formatValue(max)}</span>\n </div>\n )}\n\n {!isDefaultRange && (\n <div className=\"flex justify-end\">\n <button\n onClick={() => {\n setLocalRange([min, max]);\n handleRangeCommit([min, max]);\n }}\n className=\"text-xs text-muted-foreground hover:text-foreground transition-colors\"\n disabled={disabled}\n >\n Reset\n </button>\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Switch, Label } from \"@turtleclub/ui\";\nimport { useQueryState, parseAsBoolean } from \"nuqs\";\n\ninterface BooleanSwitchFilterProps {\n /** Query key for the boolean value (default: 'enabled') */\n queryKey?: string;\n /** Default value when not set (default: false) */\n defaultValue?: boolean;\n /** Whether the switch is disabled */\n disabled?: boolean;\n /** Label for the switch */\n label: string;\n /** Description text (optional) */\n description?: string;\n /** Custom className for the container */\n className?: string;\n}\n\nexport function BooleanFilter({\n queryKey = \"enabled\",\n defaultValue = false,\n disabled = false,\n label,\n description,\n className = \"\",\n}: BooleanSwitchFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsBoolean.withDefault(defaultValue));\n\n const handleToggle = (checked: boolean) => {\n // If the value is the same as default, remove from URL\n setValue(checked === defaultValue ? null : checked);\n };\n\n return (\n <div className={`flex items-center justify-between space-x-2 ${className}`}>\n <div className=\"space-y-0.5\">\n <Label className=\"text-sm font-medium\">{label}</Label>\n {description && <p className=\"text-xs text-muted-foreground\">{description}</p>}\n </div>\n <Switch checked={value} onCheckedChange={handleToggle} disabled={disabled} />\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsString } from \"nuqs\";\n\ninterface FilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: { value: string; onValueChange: (value: string) => void }) => React.ReactNode;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Generic Filter component that handles nuqs URL state management for single values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example Basic Single Selection\n * ```tsx\n * // Single chain selection - persists to URL as ?chainId=ethereum\n * <Filter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chain\"\n * />\n * )}\n * </Filter>\n * ```\n */\nexport function Filter({ queryKey, children, onValueChange }: FilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsString.withDefault(\"\"));\n\n const handleValueChange = (newValue: string) => {\n setValue(newValue || null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { useQueryState, parseAsArrayOf, parseAsString } from \"nuqs\";\n\ninterface MultiSelectFilterProps {\n /** Query parameter key */\n queryKey: string;\n /** Child component to render (selector) */\n children: (props: {\n value: string[];\n onValueChange: (values: string[]) => void;\n }) => React.ReactNode;\n /** Callback when values change */\n onValueChange?: (values: string[]) => void;\n}\n\n/**\n * Generic MultiSelectFilter component that handles nuqs URL state management for array values.\n *\n * Provides value and onValueChange props to child components,\n * decoupling selector logic from URL state management.\n *\n * @example\n * ```tsx\n * <MultiSelectFilter queryKey=\"chainId\">\n * {({ value, onValueChange }) => (\n * <ChainsSelector\n * value={value}\n * onValueChange={onValueChange}\n * placeholder=\"Select chains\"\n * />\n * )}\n * </MultiSelectFilter>\n * ```\n */\nexport function MultiSelectFilter({ queryKey, children, onValueChange }: MultiSelectFilterProps) {\n const [value, setValue] = useQueryState(queryKey, parseAsArrayOf(parseAsString).withDefault([]));\n\n const handleValueChange = (newValue: string[]) => {\n setValue(newValue.length > 0 ? newValue : null);\n onValueChange?.(newValue);\n };\n\n return <>{children({ value, onValueChange: handleValueChange })}</>;\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn, Label } from \"@turtleclub/ui\";\n\nexport interface FilterConfig {\n key: string;\n label: string;\n component: React.ReactNode;\n enabled: boolean;\n section?: string;\n}\n\nexport interface FiltersGridProps {\n filters: FilterConfig[];\n columns?: number;\n className?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersGrid({\n filters,\n columns = 3,\n className,\n sectionClassName,\n}: FiltersGridProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <div className={cn(\"space-y-4\", className)}>\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger, Button, cn, Label, Badge } from \"@turtleclub/ui\";\nimport { SlidersHorizontal } from \"lucide-react\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersPopoverProps {\n filters: FilterConfig[];\n triggerLabel?: string;\n columns?: number;\n className?: string;\n popoverClassName?: string;\n sectionClassName?: string;\n}\n\nexport function FiltersPopover({\n filters,\n triggerLabel = \"Filters\",\n columns = 2,\n className,\n popoverClassName,\n sectionClassName,\n}: FiltersPopoverProps) {\n const enabledFilters = filters.filter((filter) => filter.enabled);\n\n if (enabledFilters.length === 0) {\n return null;\n }\n\n // Group filters by section\n const sections = enabledFilters.reduce(\n (acc, filter) => {\n const sectionName = filter.section || \"default\";\n if (!acc[sectionName]) {\n acc[sectionName] = [];\n }\n acc[sectionName].push(filter);\n return acc;\n },\n {} as Record<string, typeof enabledFilters>\n );\n\n const sectionNames = Object.keys(sections);\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className={cn(className)}>\n <SlidersHorizontal className=\"mr-2 h-4 w-4\" />\n {triggerLabel}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n className={cn(\"w-auto min-w-[400px] max-w-[600px]\", popoverClassName)}\n align=\"start\"\n >\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"font-medium text-sm\">Filters</h4>\n </div>\n <div className=\"space-y-4\">\n {sectionNames.map((sectionName, sectionIndex) => (\n <div key={sectionName}>\n {sectionIndex > 0 && <div className=\"border-t border-border mb-4\" />}\n <div\n className={cn(\"grid gap-2\", sectionClassName)}\n style={{\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n }}\n >\n {sections[sectionName].map((filter) => (\n <div key={filter.key} className=\"flex flex-col gap-2\">\n {filter.component}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","\"use client\";\n\nimport React, { useMemo } from \"react\";\nimport { Badge, Button, cn } from \"@turtleclub/ui\";\nimport { X } from \"lucide-react\";\n\nexport interface ActiveFilterConfig {\n /** Unique key for the filter */\n key: string;\n /** Display label for the filter */\n label: string;\n /** Current filter value to display */\n value: string;\n /** Query parameter key(s) this filter uses */\n queryKeys: string | string[];\n /** Whether this filter is currently active */\n isActive: boolean;\n}\n\nexport interface ActiveFilterBadgesProps {\n /** Array of filter configurations */\n filters: ActiveFilterConfig[];\n /** Custom className for the container */\n className?: string;\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Component that displays active filter badges with individual clear buttons\n * and an optional \"clear all\" button.\n *\n * @example\n * ```tsx\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * {\n * key: 'sorting',\n * label: 'Sort',\n * value: 'Name (A-Z)',\n * queryKeys: ['sortBy', 'sortOrder'],\n * isActive: true,\n * },\n * ];\n *\n * <ActiveFilterBadges filters={activeFilters} />\n * ```\n */\nexport function ActiveFilterBadges({\n filters,\n className,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n onClearFilter,\n onClearAll,\n}: ActiveFilterBadgesProps) {\n // Get only active filters\n const activeFilters = useMemo(() => {\n return filters.filter((filter) => filter.isActive && filter.value);\n }, [filters]);\n\n // Clear all function\n const clearAll = () => {\n const allQueryKeys = activeFilters.map((filter) => filter.queryKeys);\n onClearAll(allQueryKeys);\n };\n\n // Don't render if no active filters\n if (activeFilters.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\"flex flex-wrap items-center gap-2\", className)}>\n {activeFilters.map((filter) => {\n return (\n <FilterBadge\n key={filter.key}\n filter={filter}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n />\n );\n })}\n\n {showClearAll && activeFilters.length > 1 && (\n <Button variant=\"ghost\" size=\"sm\" onClick={clearAll} className=\"h-7 px-2 text-xs\">\n {clearAllLabel}\n </Button>\n )}\n </div>\n );\n}\n\ninterface FilterBadgeProps {\n filter: ActiveFilterConfig;\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n onClearFilter: (queryKeys: string | string[]) => void;\n}\n\nfunction FilterBadge({ filter, renderBadge, onClearFilter }: FilterBadgeProps) {\n const clearFilter = () => {\n onClearFilter(filter.queryKeys);\n };\n\n if (renderBadge) {\n return <>{renderBadge(filter, clearFilter)}</>;\n }\n\n return (\n <Badge className=\"flex items-center gap-1 pr-1 border-border border\">\n <span className=\"text-xs\">\n {filter.label}: {filter.value}\n </span>\n <button\n onClick={clearFilter}\n className=\"ml-1 rounded-full p-0.5 hover:bg-black/10 focus:bg-black/10 focus:outline-none\"\n aria-label={`Clear ${filter.label} filter`}\n >\n <X className=\"h-3 w-3\" />\n </button>\n </Badge>\n );\n}\n","\"use client\";\n\nimport React from \"react\";\nimport { cn } from \"@turtleclub/ui\";\nimport { FiltersGrid } from \"./FiltersGrid\";\nimport { FiltersPopover } from \"./FiltersPopover\";\nimport { ActiveFilterBadges, ActiveFilterConfig } from \"./ActiveFilterBadges\";\nimport { FilterConfig } from \"./FiltersGrid\";\n\nexport interface FiltersWrapperProps {\n /** Array of filter configurations */\n filters: FilterConfig[];\n /** Array of active filter configurations for badges */\n activeFilters: ActiveFilterConfig[];\n /** Layout type: 'grid' or 'popover' */\n layout: \"grid\" | \"popover\";\n /** Custom className for the wrapper */\n className?: string;\n /** Custom className for the active badges section */\n badgesClassName?: string;\n\n // Grid-specific props\n /** Number of columns for grid layout (default: 3) */\n columns?: number;\n\n // Popover-specific props\n /** Button label for popover trigger (default: \"Filters\") */\n triggerLabel?: string;\n /** Number of columns in popover (default: 2) */\n popoverColumns?: number;\n /** Custom className for popover trigger button */\n popoverClassName?: string;\n /** Custom className for popover content */\n popoverContentClassName?: string;\n\n // Active badges props\n /** Label for clear all button (default: \"Clear All\") */\n clearAllLabel?: string;\n /** Whether to show clear all button (default: true) */\n showClearAll?: boolean;\n /** Custom render function for individual badges */\n renderBadge?: (filter: ActiveFilterConfig, clearFilter: () => void) => React.ReactNode;\n /** Whether to show active filter badges (default: true) */\n showActiveBadges?: boolean;\n /** Callback function to clear individual filter */\n onClearFilter: (queryKeys: string | string[]) => void;\n /** Callback function to clear all filters */\n onClearAll: (allQueryKeys: (string | string[])[]) => void;\n}\n\n/**\n * Unified wrapper component that combines filter controls with active filter badges.\n *\n * Supports both grid and popover layouts, automatically displays active filter badges\n * below the filter controls with individual and bulk clear functionality.\n *\n * @example\n * ```tsx\n * const filters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * component: <ChainFilter />,\n * enabled: true,\n * },\n * ];\n *\n * const activeFilters = [\n * {\n * key: 'chain',\n * label: 'Chain',\n * value: 'Ethereum',\n * queryKeys: 'chainId',\n * isActive: true,\n * },\n * ];\n *\n * <FiltersWrapper\n * layout=\"grid\"\n * filters={filters}\n * activeFilters={activeFilters}\n * />\n * ```\n */\nexport function FiltersWrapper({\n filters,\n activeFilters,\n layout,\n className,\n badgesClassName,\n columns = 3,\n triggerLabel = \"Filters\",\n popoverColumns = 2,\n popoverClassName,\n popoverContentClassName,\n clearAllLabel = \"Clear All\",\n showClearAll = true,\n renderBadge,\n showActiveBadges = true,\n onClearFilter,\n onClearAll,\n}: FiltersWrapperProps) {\n const hasActiveFilters = activeFilters.some((filter) => filter.isActive && filter.value);\n\n return (\n <div className={cn(\"space-y-3\", className)}>\n {/* Filter Controls */}\n {layout === \"grid\" ? (\n <FiltersGrid filters={filters} columns={columns} className={popoverClassName} />\n ) : (\n <FiltersPopover\n filters={filters}\n triggerLabel={triggerLabel}\n columns={popoverColumns}\n className={popoverClassName}\n popoverClassName={popoverContentClassName}\n />\n )}\n\n {/* Active Filter Badges */}\n {showActiveBadges && hasActiveFilters && (\n <ActiveFilterBadges\n filters={activeFilters}\n className={badgesClassName}\n clearAllLabel={clearAllLabel}\n showClearAll={showClearAll}\n renderBadge={renderBadge}\n onClearFilter={onClearFilter}\n onClearAll={onClearAll}\n />\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useQueryState, parseAsInteger } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { PaginationState } from \"@tanstack/react-table\";\n\nexport interface UsePaginationOptions {\n /** Default page size (default: 10) */\n defaultPageSize?: number;\n /** Default page index (default: 0) */\n defaultPageIndex?: number;\n /** Query param key for page index (default: 'page') */\n pageIndexKey?: string;\n /** Query param key for page size (default: 'pageSize') */\n pageSizeKey?: string;\n}\n\nexport interface UsePaginationReturn {\n /** Current pagination state for TanStack Table */\n pagination: PaginationState;\n /** Function to update pagination state */\n setPagination: (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => void;\n /** Current page index (0-based) */\n pageIndex: number;\n /** Current page size */\n pageSize: number;\n /** Set page index directly */\n setPageIndex: (pageIndex: number) => void;\n /** Set page size directly */\n setPageSize: (pageSize: number) => void;\n /** Go to next page */\n nextPage: (totalPages?: number) => void;\n /** Go to previous page */\n previousPage: () => void;\n /** Go to first page */\n firstPage: () => void;\n /** Go to last page */\n lastPage: (totalPages: number) => void;\n /** Reset pagination to defaults */\n reset: () => void;\n /** Check if can go to next page */\n canNextPage: (totalPages?: number) => boolean;\n /** Check if can go to previous page */\n canPreviousPage: boolean;\n}\n\n/**\n * Hook for managing server-side pagination state using nuqs.\n *\n * This hook synchronizes pagination state with URL query parameters,\n * making it perfect for server-side pagination where the URL should\n * reflect the current page and page size.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * pagination,\n * setPagination,\n * pageIndex,\n * pageSize,\n * setPageIndex,\n * setPageSize\n * } = usePagination({\n * defaultPageSize: 20,\n * pageIndexKey: 'page',\n * pageSizeKey: 'limit'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualPagination: true,\n * pagination,\n * onPaginationChange: setPagination,\n * pageCount: Math.ceil(totalCount / pageSize),\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function usePagination(options: UsePaginationOptions = {}): UsePaginationReturn {\n const {\n defaultPageSize = 10,\n defaultPageIndex = 0,\n pageIndexKey = \"page\",\n pageSizeKey = \"pageSize\",\n } = options;\n\n // Use nuqs to manage query state\n const [rawPageIndex, setRawPageIndex] = useQueryState(\n pageIndexKey,\n parseAsInteger.withDefault(defaultPageIndex)\n );\n\n const [rawPageSize, setRawPageSize] = useQueryState(\n pageSizeKey,\n parseAsInteger.withDefault(defaultPageSize)\n );\n\n // Ensure page index is never negative\n const pageIndex = useMemo(() => Math.max(0, rawPageIndex), [rawPageIndex]);\n\n // Use page size directly from query state\n const pageSize = rawPageSize;\n\n // Create pagination state for TanStack Table\n const pagination = useMemo<PaginationState>(\n () => ({\n pageIndex,\n pageSize,\n }),\n [pageIndex, pageSize]\n );\n\n // Set pagination function that handles both object and function updates\n const setPagination = useCallback(\n (updater: PaginationState | ((prev: PaginationState) => PaginationState)) => {\n const newPagination = typeof updater === \"function\" ? updater(pagination) : updater;\n\n if (newPagination.pageIndex !== pageIndex) {\n setRawPageIndex(Math.max(0, newPagination.pageIndex));\n }\n\n if (newPagination.pageSize !== pageSize) {\n setRawPageSize(newPagination.pageSize);\n }\n },\n [pagination, pageIndex, pageSize, setRawPageIndex, setRawPageSize]\n );\n\n // Individual setters\n const setPageIndex = useCallback(\n (newPageIndex: number) => {\n setRawPageIndex(Math.max(0, newPageIndex));\n },\n [setRawPageIndex]\n );\n\n const setPageSize = useCallback(\n (newPageSize: number) => {\n setRawPageSize(newPageSize);\n // Reset to first page when page size changes\n setRawPageIndex(0);\n },\n [setRawPageSize, setRawPageIndex]\n );\n\n // Navigation functions\n const nextPage = useCallback(\n (totalPages?: number) => {\n const nextPageIndex = pageIndex + 1;\n if (!totalPages || nextPageIndex < totalPages) {\n setPageIndex(nextPageIndex);\n }\n },\n [pageIndex, setPageIndex]\n );\n\n const previousPage = useCallback(() => {\n if (pageIndex > 0) {\n setPageIndex(pageIndex - 1);\n }\n }, [pageIndex, setPageIndex]);\n\n const firstPage = useCallback(() => {\n setPageIndex(0);\n }, [setPageIndex]);\n\n const lastPage = useCallback(\n (totalPages: number) => {\n setPageIndex(Math.max(0, totalPages - 1));\n },\n [setPageIndex]\n );\n\n // Reset function\n const reset = useCallback(() => {\n setRawPageIndex(defaultPageIndex);\n setRawPageSize(defaultPageSize);\n }, [setRawPageIndex, setRawPageSize, defaultPageIndex, defaultPageSize]);\n\n // Navigation state\n const canPreviousPage = pageIndex > 0;\n const canNextPage = useCallback(\n (totalPages?: number) => {\n if (!totalPages) return true; // Assume we can go next if total pages unknown\n return pageIndex < totalPages - 1;\n },\n [pageIndex]\n );\n\n return {\n pagination,\n setPagination,\n pageIndex,\n pageSize,\n setPageIndex,\n setPageSize,\n nextPage,\n previousPage,\n firstPage,\n lastPage,\n reset,\n canNextPage,\n canPreviousPage,\n };\n}\n","\"use client\";\n\nimport { useQueryState, parseAsString } from \"nuqs\";\nimport { useMemo, useCallback } from \"react\";\nimport type { SortingState } from \"@tanstack/react-table\";\n\nexport interface UseSortingOptions {\n /** Default sort column (default: undefined - no sorting) */\n defaultSortBy?: string;\n /** Default sort order (default: 'asc') */\n defaultSortOrder?: \"asc\" | \"desc\";\n /** Query param key for sort column (default: 'sortBy') */\n sortByKey?: string;\n /** Query param key for sort order (default: 'sortOrder') */\n sortOrderKey?: string;\n}\n\nexport interface UseSortingReturn {\n /** Current sorting state for TanStack Table */\n sorting: SortingState;\n /** Function to update sorting state */\n setSorting: (updater: SortingState | ((prev: SortingState) => SortingState)) => void;\n /** Current sort column (undefined if no sorting) */\n sortBy: string | undefined;\n /** Current sort order */\n sortOrder: \"asc\" | \"desc\";\n /** Set sort column and order directly */\n setSort: (column: string, order?: \"asc\" | \"desc\") => void;\n /** Clear all sorting */\n clearSort: () => void;\n /** Toggle sort order for a column */\n toggleSort: (column: string) => void;\n /** Check if a column is currently sorted */\n isSorted: (column: string) => boolean;\n /** Get sort order for a column */\n getSortOrder: (column: string) => \"asc\" | \"desc\" | undefined;\n}\n\n/**\n * Hook for managing server-side sorting state using nuqs.\n *\n * This hook synchronizes sorting state with URL query parameters,\n * making it perfect for server-side sorting where the URL should\n * reflect the current sort state.\n *\n * @example\n * ```tsx\n * function MyTable() {\n * const {\n * sorting,\n * setSorting,\n * sortBy,\n * sortOrder,\n * setSort,\n * toggleSort\n * } = useSorting({\n * defaultSortBy: 'name',\n * defaultSortOrder: 'asc'\n * });\n *\n * // Use with TanStack Table\n * const table = useReactTable({\n * data,\n * columns,\n * manualSorting: true,\n * sorting,\n * onSortingChange: setSorting,\n * });\n *\n * return <DataTable table={table} />;\n * }\n * ```\n */\nexport function useSorting(options: UseSortingOptions = {}): UseSortingReturn {\n const {\n defaultSortBy,\n defaultSortOrder = \"asc\",\n sortByKey = \"sortBy\",\n sortOrderKey = \"sortOrder\",\n } = options;\n\n // Use nuqs to manage query state\n const [sortBy, setSortBy] = useQueryState(\n sortByKey,\n parseAsString.withDefault(defaultSortBy || \"\")\n );\n\n const [sortOrder, setSortOrder] = useQueryState(\n sortOrderKey,\n parseAsString.withDefault(defaultSortOrder)\n );\n\n // Ensure sort order is valid\n const validSortOrder = useMemo(() => {\n return sortOrder === \"desc\" ? \"desc\" : \"asc\";\n }, [sortOrder]);\n\n // Create sorting state for TanStack Table\n const sorting = useMemo<SortingState>(() => {\n if (!sortBy || sortBy.trim() === \"\") {\n return [];\n }\n return [\n {\n id: sortBy,\n desc: validSortOrder === \"desc\",\n },\n ];\n }, [sortBy, validSortOrder]);\n\n // Set sorting function that handles both object and function updates\n const setSorting = useCallback(\n (updater: SortingState | ((prev: SortingState) => SortingState)) => {\n const newSorting = typeof updater === \"function\" ? updater(sorting) : updater;\n\n if (newSorting.length === 0) {\n // Clear sorting\n setSortBy(\"\");\n } else {\n // Set first sort (TanStack Table typically only has one sort at a time)\n const firstSort = newSorting[0];\n setSortBy(firstSort.id);\n setSortOrder(firstSort.desc ? \"desc\" : \"asc\");\n }\n },\n [sorting, setSortBy, setSortOrder]\n );\n\n // Set sort column and order directly\n const setSort = useCallback(\n (column: string, order: \"asc\" | \"desc\" = \"asc\") => {\n setSortBy(column);\n setSortOrder(order);\n },\n [setSortBy, setSortOrder]\n );\n\n // Clear all sorting\n const clearSort = useCallback(() => {\n setSortBy(null);\n }, [setSortBy]);\n\n // Toggle sort order for a column\n const toggleSort = useCallback(\n (column: string) => {\n if (sortBy === column) {\n // Same column, toggle order\n setSortOrder(validSortOrder === \"asc\" ? \"desc\" : \"asc\");\n } else {\n // Different column, set new column with asc\n setSortBy(column);\n setSortOrder(\"asc\");\n }\n },\n [sortBy, validSortOrder, setSortBy, setSortOrder]\n );\n\n // Check if a column is currently sorted\n const isSorted = useCallback(\n (column: string) => {\n return sortBy === column;\n },\n [sortBy]\n );\n\n // Get sort order for a column\n const getSortOrder = useCallback(\n (column: string) => {\n return sortBy === column ? validSortOrder : undefined;\n },\n [sortBy, validSortOrder]\n );\n\n return {\n sorting,\n setSorting,\n sortBy: sortBy || undefined,\n sortOrder: validSortOrder,\n setSort,\n clearSort,\n toggleSort,\n isSorted,\n getSortOrder,\n };\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainsSelector({\n value,\n onValueChange,\n placeholder = \"Select chains\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokensSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select tokens\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value.length > 0) {\n onValueChange([]);\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductsSelector({\n value,\n onValueChange,\n placeholder = \"Select products\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { MultiSelect } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity IDs */\n value: string[];\n /** Callback when selection changes */\n onValueChange: (values: string[]) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Maximum count to show in trigger */\n maxCount?: number;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitiesSelector({\n value,\n onValueChange,\n placeholder = \"Select opportunities\",\n disabled = false,\n className,\n maxCount = 1,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const { data: opportunitiesData, isLoading } = useOpportunities();\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n return (\n <MultiSelect\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading opportunities...\" : placeholder}\n closeOnSelect={closeOnSelect}\n maxCount={maxCount}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedChains } from \"@turtleclub/hooks\";\n\ninterface ChainSelectorProps {\n /** Selected chain ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ChainSelector({\n value,\n onValueChange,\n placeholder = \"Select chain\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ChainSelectorProps) {\n const { chains, isLoading } = useSupportedChains();\n\n const chainOptions = useMemo(() => {\n if (!chains || chains.length === 0) return [];\n\n const filteredChains = chains.filter((chain) => chain.status === \"active\");\n\n return filteredChains.map((chain) => ({\n label: chain.name,\n value: chain?.id ?? \"\",\n icon: chain.logoUrl\n ? () => (\n <img\n src={chain.logoUrl}\n alt={chain.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [chains]);\n\n return (\n <Combobox\n searchable={searchable}\n options={chainOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading chains...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useEffect, useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useSupportedTokens } from \"@turtleclub/hooks\";\n\ninterface TokenSelectorProps {\n /** Selected token ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Selected chain ID to filter tokens */\n chainId?: string;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function TokenSelector({\n value,\n onValueChange,\n chainId,\n placeholder = \"Select token\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: TokenSelectorProps) {\n const isChainSelected = !!chainId && chainId.trim() !== \"\";\n\n const { tokens, isLoading } = useSupportedTokens({\n // chainId: isChainSelected ? chainId : undefined,\n limit: 100,\n enabled: isChainSelected,\n });\n\n const tokenOptions = useMemo(() => {\n if (!tokens) return [];\n\n return tokens.map((token) => ({\n label: `${token.symbol} - ${token.name}`,\n value: token?.id || \"\",\n icon: token.logoUrl\n ? () => (\n <img\n src={token.logoUrl}\n alt={token.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [tokens]);\n\n // Clear selection when chain changes\n useEffect(() => {\n if (!isChainSelected && value) {\n onValueChange(\"\");\n }\n }, [isChainSelected, value, onValueChange]);\n\n return (\n <Combobox\n searchable={searchable}\n options={tokenOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading || !isChainSelected}\n placeholder={\n !isChainSelected ? \"Select a chain first\" : isLoading ? \"Loading tokens...\" : placeholder\n }\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useProducts } from \"@turtleclub/hooks\";\n\ninterface ProductSelectorProps {\n /** Selected product ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function ProductSelector({\n value,\n onValueChange,\n placeholder = \"Select product\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: ProductSelectorProps) {\n const { data: productsData, isLoading } = useProducts({});\n\n const products = useMemo(() => productsData?.products ?? [], [productsData?.products]);\n\n const productOptions = useMemo(() => {\n if (!products || products.length === 0) return [];\n\n return products.map((product) => ({\n label: product.name,\n value: product.id,\n icon: product.logoUrl\n ? () => (\n <img\n src={product.logoUrl}\n alt={product.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [products]);\n\n return (\n <Combobox\n searchable={searchable}\n options={productOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading products...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\nimport { Combobox } from \"@turtleclub/ui\";\nimport { useOpportunities } from \"@turtleclub/hooks\";\n\ninterface OpportunitySelectorProps {\n /** Selected opportunity ID */\n value: string;\n /** Callback when selection changes */\n onValueChange: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Whether the selector is disabled */\n disabled?: boolean;\n /** Custom className */\n className?: string;\n /** Whether to close on select */\n closeOnSelect?: boolean;\n /** Whether to show search */\n searchable?: boolean;\n}\n\nexport function OpportunitySelector({\n value,\n onValueChange,\n placeholder = \"Select opportunity\",\n disabled = false,\n className,\n closeOnSelect = true,\n searchable = true,\n}: OpportunitySelectorProps) {\n const { data: opportunitiesData, isLoading } = useOpportunities();\n\n const opportunities = useMemo(\n () => opportunitiesData?.opportunities ?? [],\n [opportunitiesData?.opportunities]\n );\n\n const opportunityOptions = useMemo(() => {\n if (!opportunities || opportunities.length === 0) return [];\n\n const filteredOpportunities = opportunities.filter((opp) => opp.status === \"active\");\n\n return filteredOpportunities.map((opportunity) => ({\n label: opportunity.name || opportunity.shortName,\n value: opportunity.id!,\n description: opportunity.shortName !== opportunity.name ? opportunity.shortName : undefined,\n icon: opportunity.depositTokens?.[0]?.logoUrl\n ? () => (\n <img\n src={opportunity.depositTokens[0].logoUrl}\n alt={opportunity.name}\n width={16}\n height={16}\n className=\"size-4 rounded-full\"\n />\n )\n : undefined,\n }));\n }, [opportunities]);\n\n return (\n <Combobox\n searchable={searchable}\n options={opportunityOptions}\n value={value}\n onValueChange={onValueChange}\n disabled={disabled || isLoading}\n placeholder={isLoading ? \"Loading opportunities...\" : placeholder}\n closeOnSelect={closeOnSelect}\n className={className}\n />\n );\n}\n"],"mappings":"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","names":["Label","useQueryState","jsx","jsxs","useQueryState","jsx","useQueryState","parseAsString","Fragment","jsx","jsx","jsxs","cn","jsx","jsxs","Badge","Button","cn","Fragment","jsx","jsxs","cn","jsx","jsxs","cn","useQueryState","parseAsInteger","useMemo","useQueryState","parseAsString","useMemo","useCallback","useMemo","jsx","useEffect","useMemo","MultiSelect","jsx","useMemo","MultiSelect","jsx","useMemo","MultiSelect","jsx","useMemo","useSupportedChains","jsx","useEffect","useMemo","Combobox","useSupportedTokens","jsx","useMemo","Combobox","useProducts","jsx","useMemo","Combobox","useOpportunities","jsx"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@turtleclub/core",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "163e7723f570e1e9efa1c48806e14e6d4a5a7d8d"
|
|
46
46
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useMemo
|
|
3
|
+
import { useMemo } from "react";
|
|
4
4
|
import { MultiSelect } from "@turtleclub/ui";
|
|
5
5
|
import { useOpportunities } from "@turtleclub/hooks";
|
|
6
6
|
|
|
@@ -9,8 +9,6 @@ interface OpportunitySelectorProps {
|
|
|
9
9
|
value: string[];
|
|
10
10
|
/** Callback when selection changes */
|
|
11
11
|
onValueChange: (values: string[]) => void;
|
|
12
|
-
/** Selected product ID to filter opportunities */
|
|
13
|
-
productId?: string;
|
|
14
12
|
/** Placeholder text */
|
|
15
13
|
placeholder?: string;
|
|
16
14
|
/** Whether the selector is disabled */
|
|
@@ -28,7 +26,6 @@ interface OpportunitySelectorProps {
|
|
|
28
26
|
export function OpportunitiesSelector({
|
|
29
27
|
value,
|
|
30
28
|
onValueChange,
|
|
31
|
-
productId,
|
|
32
29
|
placeholder = "Select opportunities",
|
|
33
30
|
disabled = false,
|
|
34
31
|
className,
|
|
@@ -36,14 +33,7 @@ export function OpportunitiesSelector({
|
|
|
36
33
|
closeOnSelect = true,
|
|
37
34
|
searchable = true,
|
|
38
35
|
}: OpportunitySelectorProps) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
const { data: opportunitiesData, isLoading } = useOpportunities({
|
|
42
|
-
filters: {
|
|
43
|
-
productId,
|
|
44
|
-
},
|
|
45
|
-
enabled: isProductSelected,
|
|
46
|
-
});
|
|
36
|
+
const { data: opportunitiesData, isLoading } = useOpportunities();
|
|
47
37
|
|
|
48
38
|
const opportunities = useMemo(
|
|
49
39
|
() => opportunitiesData?.opportunities ?? [],
|
|
@@ -73,27 +63,14 @@ export function OpportunitiesSelector({
|
|
|
73
63
|
}));
|
|
74
64
|
}, [opportunities]);
|
|
75
65
|
|
|
76
|
-
// Clear selection when product changes
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
if (!isProductSelected && value.length > 0) {
|
|
79
|
-
onValueChange([]);
|
|
80
|
-
}
|
|
81
|
-
}, [isProductSelected, value, onValueChange]);
|
|
82
|
-
|
|
83
66
|
return (
|
|
84
67
|
<MultiSelect
|
|
85
68
|
searchable={searchable}
|
|
86
69
|
options={opportunityOptions}
|
|
87
70
|
value={value}
|
|
88
71
|
onValueChange={onValueChange}
|
|
89
|
-
disabled={disabled || isLoading
|
|
90
|
-
placeholder={
|
|
91
|
-
!isProductSelected
|
|
92
|
-
? "Select a product first"
|
|
93
|
-
: isLoading
|
|
94
|
-
? "Loading opportunities..."
|
|
95
|
-
: placeholder
|
|
96
|
-
}
|
|
72
|
+
disabled={disabled || isLoading}
|
|
73
|
+
placeholder={isLoading ? "Loading opportunities..." : placeholder}
|
|
97
74
|
closeOnSelect={closeOnSelect}
|
|
98
75
|
maxCount={maxCount}
|
|
99
76
|
className={className}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { useMemo
|
|
3
|
+
import { useMemo } from "react";
|
|
4
4
|
import { Combobox } from "@turtleclub/ui";
|
|
5
5
|
import { useOpportunities } from "@turtleclub/hooks";
|
|
6
6
|
|
|
@@ -9,8 +9,6 @@ interface OpportunitySelectorProps {
|
|
|
9
9
|
value: string;
|
|
10
10
|
/** Callback when selection changes */
|
|
11
11
|
onValueChange: (value: string) => void;
|
|
12
|
-
/** Selected product ID to filter opportunities */
|
|
13
|
-
productId?: string;
|
|
14
12
|
/** Placeholder text */
|
|
15
13
|
placeholder?: string;
|
|
16
14
|
/** Whether the selector is disabled */
|
|
@@ -26,21 +24,13 @@ interface OpportunitySelectorProps {
|
|
|
26
24
|
export function OpportunitySelector({
|
|
27
25
|
value,
|
|
28
26
|
onValueChange,
|
|
29
|
-
productId,
|
|
30
27
|
placeholder = "Select opportunity",
|
|
31
28
|
disabled = false,
|
|
32
29
|
className,
|
|
33
30
|
closeOnSelect = true,
|
|
34
31
|
searchable = true,
|
|
35
32
|
}: OpportunitySelectorProps) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
const { data: opportunitiesData, isLoading } = useOpportunities({
|
|
39
|
-
filters: {
|
|
40
|
-
productId,
|
|
41
|
-
},
|
|
42
|
-
enabled: isProductSelected,
|
|
43
|
-
});
|
|
33
|
+
const { data: opportunitiesData, isLoading } = useOpportunities();
|
|
44
34
|
|
|
45
35
|
const opportunities = useMemo(
|
|
46
36
|
() => opportunitiesData?.opportunities ?? [],
|
|
@@ -70,27 +60,14 @@ export function OpportunitySelector({
|
|
|
70
60
|
}));
|
|
71
61
|
}, [opportunities]);
|
|
72
62
|
|
|
73
|
-
// Clear selection when product changes
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
if (!isProductSelected && value) {
|
|
76
|
-
onValueChange("");
|
|
77
|
-
}
|
|
78
|
-
}, [isProductSelected, value, onValueChange]);
|
|
79
|
-
|
|
80
63
|
return (
|
|
81
64
|
<Combobox
|
|
82
65
|
searchable={searchable}
|
|
83
66
|
options={opportunityOptions}
|
|
84
67
|
value={value}
|
|
85
68
|
onValueChange={onValueChange}
|
|
86
|
-
disabled={disabled || isLoading
|
|
87
|
-
placeholder={
|
|
88
|
-
!isProductSelected
|
|
89
|
-
? "Select a product first"
|
|
90
|
-
: isLoading
|
|
91
|
-
? "Loading opportunities..."
|
|
92
|
-
: placeholder
|
|
93
|
-
}
|
|
69
|
+
disabled={disabled || isLoading}
|
|
70
|
+
placeholder={isLoading ? "Loading opportunities..." : placeholder}
|
|
94
71
|
closeOnSelect={closeOnSelect}
|
|
95
72
|
className={className}
|
|
96
73
|
/>
|