Skip to content

Commit 2f16a86

Browse files
committed
chore: sync
1 parent b8723d4 commit 2f16a86

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

public/r/data-table.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
},
5656
{
5757
"path": "src/components/data-table-slider-filter.tsx",
58-
"content": "\"use client\";\r\n\r\nimport type { Column } from \"@tanstack/react-table\";\r\nimport * as React from \"react\";\r\n\r\nimport { Button } from \"@/components/ui/button\";\r\nimport { Input } from \"@/components/ui/input\";\r\nimport { Label } from \"@/components/ui/label\";\r\nimport {\r\n Popover,\r\n PopoverContent,\r\n PopoverTrigger,\r\n} from \"@/components/ui/popover\";\r\nimport { Separator } from \"@/components/ui/separator\";\r\nimport { Slider } from \"@/components/ui/slider\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { PlusCircle, XCircle } from \"lucide-react\";\r\n\r\ntype RangeValue = [number, number];\r\n\r\nfunction getIsValidRange(value: unknown): value is RangeValue {\r\n return (\r\n Array.isArray(value) &&\r\n value.length === 2 &&\r\n typeof value[0] === \"number\" &&\r\n typeof value[1] === \"number\"\r\n );\r\n}\r\n\r\ninterface DataTableSliderFilterProps<TData> {\r\n column: Column<TData, unknown>;\r\n title?: string;\r\n}\r\n\r\nexport function DataTableSliderFilter<TData>({\r\n column,\r\n title,\r\n}: DataTableSliderFilterProps<TData>) {\r\n const id = React.useId();\r\n\r\n const columnFilterValue = getIsValidRange(column.getFilterValue())\r\n ? (column.getFilterValue() as RangeValue)\r\n : undefined;\r\n\r\n const defaultRange = column.columnDef.meta?.range;\r\n const unit = column.columnDef.meta?.unit;\r\n\r\n const [min, max] = React.useMemo((): RangeValue => {\r\n if (defaultRange && getIsValidRange(defaultRange)) return defaultRange;\r\n\r\n const values = column.getFacetedMinMaxValues();\r\n if (values && Array.isArray(values) && values.length === 2) {\r\n const [minVal, maxVal] = values;\r\n if (typeof minVal === \"number\" && typeof maxVal === \"number\") {\r\n return [minVal, maxVal];\r\n }\r\n }\r\n\r\n return [0, 100];\r\n }, [column, defaultRange]);\r\n\r\n const step = React.useMemo(() => {\r\n const rangeSize = max - min;\r\n if (rangeSize <= 20) return 1;\r\n if (rangeSize <= 100) return Math.ceil(rangeSize / 20);\r\n return Math.ceil(rangeSize / 50);\r\n }, [min, max]);\r\n\r\n const range = React.useMemo(() => {\r\n return columnFilterValue ?? [min, max];\r\n }, [columnFilterValue, min, max]);\r\n\r\n const onReset = React.useCallback(\r\n (event?: React.MouseEvent) => {\r\n event?.stopPropagation();\r\n column.setFilterValue(undefined);\r\n },\r\n [column],\r\n );\r\n\r\n const formatValue = React.useCallback((value: number) => {\r\n return value.toLocaleString(undefined, {\r\n maximumFractionDigits: 0,\r\n });\r\n }, []);\r\n\r\n const onFromInputChange = React.useCallback(\r\n (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const numValue = Number(event.target.value);\r\n if (!Number.isNaN(numValue) && numValue >= min && numValue <= max) {\r\n const newRange: RangeValue = [numValue, max];\r\n column.setFilterValue(newRange);\r\n }\r\n },\r\n [column, min, max],\r\n );\r\n\r\n const onToInputChange = React.useCallback(\r\n (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const numValue = Number(event.target.value);\r\n if (!Number.isNaN(numValue) && numValue <= max && numValue >= min) {\r\n const newRange: RangeValue = [min, numValue];\r\n column.setFilterValue(newRange);\r\n }\r\n },\r\n [column, max, min],\r\n );\r\n\r\n const onSliderValueChange = React.useCallback(\r\n (value: RangeValue) => {\r\n if (Array.isArray(value) && value.length === 2) {\r\n column.setFilterValue(value);\r\n }\r\n },\r\n [column],\r\n );\r\n\r\n return (\r\n <Popover>\r\n <PopoverTrigger asChild>\r\n <Button variant=\"outline\" size=\"sm\" className=\"border-dashed\">\r\n {columnFilterValue ? (\r\n <div\r\n role=\"button\"\r\n aria-label={`Clear ${title} filter`}\r\n tabIndex={0}\r\n className=\"rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\r\n onClick={onReset}\r\n >\r\n <XCircle />\r\n </div>\r\n ) : (\r\n <PlusCircle />\r\n )}\r\n <span>{title}</span>\r\n {columnFilterValue ? (\r\n <>\r\n <Separator\r\n orientation=\"vertical\"\r\n className=\"mx-0.5 data-[orientation=vertical]:h-4\"\r\n />\r\n {formatValue(columnFilterValue[0])} -{\" \"}\r\n {formatValue(columnFilterValue[1])}\r\n {unit ? ` ${unit}` : \"\"}\r\n </>\r\n ) : null}\r\n </Button>\r\n </PopoverTrigger>\r\n <PopoverContent align=\"start\" className=\"flex w-auto flex-col gap-4\">\r\n <div className=\"flex flex-col gap-3\">\r\n <p className=\"font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\">\r\n {title}\r\n </p>\r\n <div className=\"flex items-center gap-4\">\r\n <Label htmlFor={`${id}-from`} className=\"sr-only\">\r\n From\r\n </Label>\r\n <div className=\"relative\">\r\n <Input\r\n id={`${id}-from`}\r\n type=\"number\"\r\n aria-valuemin={min}\r\n aria-valuemax={max}\r\n inputMode=\"numeric\"\r\n pattern=\"[0-9]*\"\r\n placeholder={min.toString()}\r\n min={min}\r\n max={max}\r\n value={range[0]?.toString()}\r\n onChange={onFromInputChange}\r\n className={cn(\"h-8 w-24\", unit && \"pr-8\")}\r\n />\r\n {unit && (\r\n <span className=\"absolute top-0 right-0 bottom-0 flex items-center rounded-r-md bg-accent px-2 text-muted-foreground text-sm\">\r\n {unit}\r\n </span>\r\n )}\r\n </div>\r\n <Label htmlFor={`${id}-to`} className=\"sr-only\">\r\n to\r\n </Label>\r\n <div className=\"relative\">\r\n <Input\r\n id={`${id}-to`}\r\n type=\"number\"\r\n aria-valuemin={min}\r\n aria-valuemax={max}\r\n inputMode=\"numeric\"\r\n pattern=\"[0-9]*\"\r\n placeholder={max.toString()}\r\n min={min}\r\n max={max}\r\n value={range[1]?.toString()}\r\n onChange={onToInputChange}\r\n className={cn(\"h-8 w-24\", unit && \"pr-8\")}\r\n />\r\n {unit && (\r\n <span className=\"absolute top-0 right-0 bottom-0 flex items-center rounded-r-md bg-accent px-2 text-muted-foreground text-sm\">\r\n {unit}\r\n </span>\r\n )}\r\n </div>\r\n </div>\r\n <Label htmlFor={`${id}-slider`} className=\"sr-only\">\r\n {title} slider\r\n </Label>\r\n <Slider\r\n id={`${id}-slider`}\r\n min={min}\r\n max={max}\r\n step={step}\r\n value={range}\r\n onValueChange={onSliderValueChange}\r\n />\r\n </div>\r\n <Button\r\n aria-label={`Clear ${title} filter`}\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={onReset}\r\n >\r\n Clear\r\n </Button>\r\n </PopoverContent>\r\n </Popover>\r\n );\r\n}\r\n",
58+
"content": "\"use client\";\n\nimport type { Column } from \"@tanstack/react-table\";\nimport * as React from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { Slider } from \"@/components/ui/slider\";\nimport { cn } from \"@/lib/utils\";\nimport { PlusCircle, XCircle } from \"lucide-react\";\n\ntype RangeValue = [number, number];\n\nfunction getIsValidRange(value: unknown): value is RangeValue {\n return (\n Array.isArray(value) &&\n value.length === 2 &&\n typeof value[0] === \"number\" &&\n typeof value[1] === \"number\"\n );\n}\n\ninterface DataTableSliderFilterProps<TData> {\n column: Column<TData, unknown>;\n title?: string;\n}\n\nexport function DataTableSliderFilter<TData>({\n column,\n title,\n}: DataTableSliderFilterProps<TData>) {\n const id = React.useId();\n\n const columnFilterValue = getIsValidRange(column.getFilterValue())\n ? (column.getFilterValue() as RangeValue)\n : undefined;\n\n const defaultRange = column.columnDef.meta?.range;\n const unit = column.columnDef.meta?.unit;\n\n const [min, max] = React.useMemo((): RangeValue => {\n if (defaultRange && getIsValidRange(defaultRange)) return defaultRange;\n\n const values = column.getFacetedMinMaxValues();\n if (values && Array.isArray(values) && values.length === 2) {\n const [minVal, maxVal] = values;\n if (typeof minVal === \"number\" && typeof maxVal === \"number\") {\n return [minVal, maxVal];\n }\n }\n\n return [0, 100];\n }, [column, defaultRange]);\n\n const step = React.useMemo(() => {\n const rangeSize = max - min;\n if (rangeSize <= 20) return 1;\n if (rangeSize <= 100) return Math.ceil(rangeSize / 20);\n return Math.ceil(rangeSize / 50);\n }, [min, max]);\n\n const range = React.useMemo(() => {\n return columnFilterValue ?? [min, max];\n }, [columnFilterValue, min, max]);\n\n const onReset = React.useCallback(\n (event?: React.MouseEvent) => {\n event?.stopPropagation();\n column.setFilterValue(undefined);\n },\n [column],\n );\n\n const formatValue = React.useCallback((value: number) => {\n return value.toLocaleString(undefined, {\n maximumFractionDigits: 0,\n });\n }, []);\n\n const onFromInputChange = React.useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const numValue = Number(event.target.value);\n if (!Number.isNaN(numValue) && numValue >= min && numValue <= max) {\n const newRange: RangeValue = [numValue, max];\n column.setFilterValue(newRange);\n }\n },\n [column, min, max],\n );\n\n const onToInputChange = React.useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const numValue = Number(event.target.value);\n if (!Number.isNaN(numValue) && numValue <= max && numValue >= min) {\n const newRange: RangeValue = [min, numValue];\n column.setFilterValue(newRange);\n }\n },\n [column, max, min],\n );\n\n const onSliderValueChange = React.useCallback(\n (value: RangeValue) => {\n if (Array.isArray(value) && value.length === 2) {\n column.setFilterValue(value);\n }\n },\n [column],\n );\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" size=\"sm\" className=\"border-dashed\">\n {columnFilterValue ? (\n <div\n role=\"button\"\n aria-label={`Clear ${title} filter`}\n tabIndex={0}\n className=\"rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n onClick={onReset}\n >\n <XCircle />\n </div>\n ) : (\n <PlusCircle />\n )}\n <span>{title}</span>\n {columnFilterValue ? (\n <>\n <Separator\n orientation=\"vertical\"\n className=\"mx-0.5 data-[orientation=vertical]:h-4\"\n />\n {formatValue(columnFilterValue[0])} -{\" \"}\n {formatValue(columnFilterValue[1])}\n {unit ? ` ${unit}` : \"\"}\n </>\n ) : null}\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"flex w-auto flex-col gap-4\">\n <div className=\"flex flex-col gap-3\">\n <p className=\"font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\">\n {title}\n </p>\n <div className=\"flex items-center gap-4\">\n <Label htmlFor={`${id}-from`} className=\"sr-only\">\n From\n </Label>\n <div className=\"relative\">\n <Input\n id={`${id}-from`}\n type=\"number\"\n aria-valuemin={min}\n aria-valuemax={max}\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n placeholder={min.toString()}\n min={min}\n max={max}\n value={range[0]?.toString()}\n onChange={onFromInputChange}\n className={cn(\"h-8 w-24\", unit && \"pr-8\")}\n />\n {unit && (\n <span className=\"absolute top-0 right-0 bottom-0 flex items-center rounded-r-md bg-accent px-2 text-muted-foreground text-sm\">\n {unit}\n </span>\n )}\n </div>\n <Label htmlFor={`${id}-to`} className=\"sr-only\">\n to\n </Label>\n <div className=\"relative\">\n <Input\n id={`${id}-to`}\n type=\"number\"\n aria-valuemin={min}\n aria-valuemax={max}\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n placeholder={max.toString()}\n min={min}\n max={max}\n value={range[1]?.toString()}\n onChange={onToInputChange}\n className={cn(\"h-8 w-24\", unit && \"pr-8\")}\n />\n {unit && (\n <span className=\"absolute top-0 right-0 bottom-0 flex items-center rounded-r-md bg-accent px-2 text-muted-foreground text-sm\">\n {unit}\n </span>\n )}\n </div>\n </div>\n <Label htmlFor={`${id}-slider`} className=\"sr-only\">\n {title} slider\n </Label>\n <Slider\n id={`${id}-slider`}\n min={min}\n max={max}\n step={step}\n value={range}\n onValueChange={onSliderValueChange}\n />\n </div>\n <Button\n aria-label={`Clear ${title} filter`}\n variant=\"outline\"\n size=\"sm\"\n onClick={onReset}\n >\n Clear\n </Button>\n </PopoverContent>\n </Popover>\n );\n}\n",
5959
"type": "registry:component"
6060
},
6161
{

0 commit comments

Comments
 (0)