periplo-ui 3.24.1 → 3.25.1
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/components/Combobox/Combobox.js +19 -2
- package/dist/components/Combobox/Combobox.js.map +1 -1
- package/dist/components/DataTable/DataTable.js +31 -4
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/DataTable/components/DataTableRowSelector.d.ts +3 -1
- package/dist/components/DataTable/components/DataTableRowSelector.js +17 -4
- package/dist/components/DataTable/components/DataTableRowSelector.js.map +1 -1
- package/dist/components/DataTable/components/DataTableSelectHeader.d.ts +3 -1
- package/dist/components/DataTable/components/DataTableSelectHeader.js +17 -11
- package/dist/components/DataTable/components/DataTableSelectHeader.js.map +1 -1
- package/dist/components/DataTable/components/DataTableToolbar.d.ts +2 -0
- package/dist/components/DataTable/components/DataTableToolbar.js +15 -1
- package/dist/components/DataTable/components/DataTableToolbar.js.map +1 -1
- package/dist/components/DataTable/hooks/useSelection.d.ts +1 -0
- package/dist/components/DataTable/hooks/useSelection.js +4 -1
- package/dist/components/DataTable/hooks/useSelection.js.map +1 -1
- package/dist/components/DataTable/types.d.ts +8 -0
- package/dist/components/DatePicker/DatePicker.js +1 -3
- package/dist/components/DatePicker/DatePicker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { CaretUpDown, Check } from '@phosphor-icons/react';
|
|
3
|
-
import { useState, useMemo } from 'react';
|
|
3
|
+
import { useState, useMemo, useRef, useEffect } from 'react';
|
|
4
4
|
import { cn } from '../../lib/utils.js';
|
|
5
5
|
import { Button, buttonVariants } from '../Button/Button.js';
|
|
6
6
|
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from '../Command/Command.js';
|
|
7
7
|
import { PopoverRoot, PopoverTrigger, PopoverContent } from '../Popover/Popover.js';
|
|
8
|
+
import { TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent } from '../Tooltip/Tooltip.js';
|
|
8
9
|
|
|
10
|
+
const ComboboxOptionWithTooltip = ({ label }) => {
|
|
11
|
+
const textRef = useRef(null);
|
|
12
|
+
const [isTruncated, setIsTruncated] = useState(false);
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
const frame = requestAnimationFrame(() => {
|
|
15
|
+
if (textRef.current) {
|
|
16
|
+
setIsTruncated(textRef.current.scrollWidth > textRef.current.clientWidth);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return () => cancelAnimationFrame(frame);
|
|
20
|
+
}, [label]);
|
|
21
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration: 300, children: [
|
|
22
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("span", { ref: textRef, className: "block truncate", children: label }) }),
|
|
23
|
+
isTruncated && /* @__PURE__ */ jsx(TooltipContent, { children: label })
|
|
24
|
+
] }) });
|
|
25
|
+
};
|
|
9
26
|
const Combobox = ({
|
|
10
27
|
id,
|
|
11
28
|
options,
|
|
@@ -89,7 +106,7 @@ const Combobox = ({
|
|
|
89
106
|
className: `mr-2 h-4 w-4 ${value === optionValue ? "opacity-100" : "opacity-0"}`
|
|
90
107
|
}
|
|
91
108
|
),
|
|
92
|
-
/* @__PURE__ */ jsx(
|
|
109
|
+
/* @__PURE__ */ jsx(ComboboxOptionWithTooltip, { label: getOptionLabel(option) })
|
|
93
110
|
] }) }, optionValue);
|
|
94
111
|
}) })
|
|
95
112
|
] }) })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Combobox.js","sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import { CaretUpDown, Check } from '@phosphor-icons/react'\nimport { useMemo, useState } from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { Button, buttonVariants } from '../Button'\nimport { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '../Command'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\n\nexport type ComboboxProps<T> = {\n /** Unique identifier for the combobox */\n id?: string\n /** Array of options to display in the combobox */\n options: Array<T>\n /** Currently selected value */\n value?: string\n /** Callback fired when selection changes */\n onChange: (value: string) => void\n /** Function to get the unique identifier from an option. */\n getOptionValue: (option: T) => string\n /** Function to get the display text from an option. */\n getOptionLabel: (option: T) => string\n /** Custom render function for options. If not provided, defaults to showing a checkmark and label */\n renderOption?: (option: T, isSelected: boolean) => React.ReactNode\n /** Placeholder text shown when no option is selected */\n placeholder?: string\n /** Placeholder text for the search input field */\n searchPlaceholder?: string\n /** Message shown when no options match the search query */\n emptyMessage?: string\n /** Additional CSS classes to apply to the combobox trigger */\n className?: string\n /** Whether the combobox is disabled */\n disabled?: boolean\n /** Maximum height of the options list. Can be any valid CSS height value */\n maxHeight?: string | number\n /** Whether the selection can be cleared by selecting the same option again */\n clearable?: boolean\n /** Whether to close the dropdown when an option is selected */\n closeOnSelect?: boolean\n /** Whether the combobox is in a loading state */\n loading?: boolean\n /** Message to show when in loading state */\n loadingPlaceholder?: string\n /** Whether the combobox has an error */\n error?: boolean | string\n /** Custom function to filter options based on search term */\n filterOptions?: (options: Array<T>, searchTerm: string) => Array<T>\n}\n\n/**\n * A searchable combobox component with support for custom rendering, keyboard navigation, and search filtering.\n *\n * @example\n * ```tsx\n * interface User {\n * id: string\n * name: string\n * email: string\n * }\n *\n * <Combobox<User>\n * options={users}\n * value={selectedUserId}\n * onChange={setSelectedUserId}\n * getOptionValue={(user) => user.id}\n * getOptionLabel={(user) => user.name}\n * />\n * ```\n *\n * @example Custom filtering\n * ```tsx\n * <Combobox<User>\n * options={users}\n * value={selectedUserId}\n * onChange={setSelectedUserId}\n * getOptionValue={(user) => user.id}\n * getOptionLabel={(user) => user.name}\n * filterOptions={(options, searchTerm) =>\n * options.filter(user =>\n * user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n * user.email.toLowerCase().includes(searchTerm.toLowerCase())\n * )\n * }\n * />\n * ```\n */\nexport const Combobox = <T extends object>({\n id,\n options,\n value,\n onChange,\n getOptionValue,\n getOptionLabel,\n placeholder = 'Select...',\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found.',\n className = 'w-60',\n disabled = false,\n maxHeight = '300px',\n renderOption,\n clearable = false,\n closeOnSelect = true,\n loading = false,\n loadingPlaceholder = 'Cargando...',\n error = false,\n filterOptions,\n}: ComboboxProps<T>) => {\n const [open, setOpen] = useState(false)\n const [searchTerm, setSearchTerm] = useState('')\n\n const selectedOption = options.find((option) => getOptionValue(option) === value)\n\n const filteredOptions = useMemo(() => {\n if (!filterOptions) {\n return options.filter((option) => getOptionLabel(option).toLowerCase().includes(searchTerm.toLowerCase()))\n }\n\n return searchTerm ? filterOptions(options, searchTerm) : options\n }, [filterOptions, options, searchTerm, getOptionLabel])\n\n const handleSelect = (currentValue: string) => {\n const newValue = clearable && currentValue === value ? '' : currentValue\n onChange(newValue)\n if (closeOnSelect) {\n setOpen(false)\n }\n }\n\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <PopoverRoot open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n id={id}\n type=\"button\"\n disabled={disabled}\n variant=\"text\"\n className={cn(\n buttonVariants({ variant: 'input' }),\n 'flex h-10 w-full justify-between rounded-lg',\n open && 'border-neutral-950',\n disabled && 'cursor-not-allowed',\n error && 'border-error-400 focus-visible:border-error-700',\n className,\n )}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n >\n <span className={cn('block truncate', !selectedOption && 'text-neutral-300')}>\n {selectedOption ? getOptionLabel(selectedOption) : placeholder}\n </span>\n <CaretUpDown className=\"h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0\">\n <Command shouldFilter={false}>\n <CommandInput\n placeholder={searchPlaceholder}\n disabled={loading}\n value={searchTerm}\n onValueChange={setSearchTerm}\n />\n <CommandList style={{ maxHeight }}>\n {loading ? (\n <div className=\"text-muted-foreground flex items-center justify-center py-6 text-sm\">\n {loadingPlaceholder}\n </div>\n ) : (\n <>\n {filteredOptions.length === 0 && <CommandEmpty>{emptyMessage}</CommandEmpty>}\n <CommandGroup>\n {filteredOptions.map((option) => {\n const optionValue = getOptionValue(option)\n return (\n <CommandItem key={optionValue} value={optionValue} onSelect={handleSelect}>\n {renderOption ? (\n renderOption(option, value === optionValue)\n ) : (\n <>\n <Check\n className={`mr-2 h-4 w-4 ${value === optionValue ? 'opacity-100' : 'opacity-0'}`}\n />\n <span className=\"block truncate\">{getOptionLabel(option)}</span>\n </>\n )}\n </CommandItem>\n )\n })}\n </CommandGroup>\n </>\n )}\n </CommandList>\n </Command>\n </PopoverContent>\n </PopoverRoot>\n {typeof error === 'string' && <span className=\"text-sm text-error-500\">{error}</span>}\n </div>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Combobox.js","sources":["../../../src/components/Combobox/Combobox.tsx"],"sourcesContent":["import { CaretUpDown, Check } from '@phosphor-icons/react'\nimport { useEffect, useMemo, useRef, useState } from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { Button, buttonVariants } from '../Button'\nimport { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from '../Command'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\nimport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from '../Tooltip'\n\nconst ComboboxOptionWithTooltip = ({ label }: { label: string }) => {\n const textRef = useRef<HTMLSpanElement>(null)\n const [isTruncated, setIsTruncated] = useState(false)\n\n useEffect(() => {\n const frame = requestAnimationFrame(() => {\n if (textRef.current) {\n setIsTruncated(textRef.current.scrollWidth > textRef.current.clientWidth)\n }\n })\n\n return () => cancelAnimationFrame(frame)\n }, [label])\n\n return (\n <TooltipProvider>\n <TooltipRoot delayDuration={300}>\n <TooltipTrigger asChild>\n <span ref={textRef} className=\"block truncate\">\n {label}\n </span>\n </TooltipTrigger>\n {isTruncated && <TooltipContent>{label}</TooltipContent>}\n </TooltipRoot>\n </TooltipProvider>\n )\n}\n\nexport type ComboboxProps<T> = {\n /** Unique identifier for the combobox */\n id?: string\n /** Array of options to display in the combobox */\n options: Array<T>\n /** Currently selected value */\n value?: string\n /** Callback fired when selection changes */\n onChange: (value: string) => void\n /** Function to get the unique identifier from an option. */\n getOptionValue: (option: T) => string\n /** Function to get the display text from an option. */\n getOptionLabel: (option: T) => string\n /** Custom render function for options. If not provided, defaults to showing a checkmark and label */\n renderOption?: (option: T, isSelected: boolean) => React.ReactNode\n /** Placeholder text shown when no option is selected */\n placeholder?: string\n /** Placeholder text for the search input field */\n searchPlaceholder?: string\n /** Message shown when no options match the search query */\n emptyMessage?: string\n /** Additional CSS classes to apply to the combobox trigger */\n className?: string\n /** Whether the combobox is disabled */\n disabled?: boolean\n /** Maximum height of the options list. Can be any valid CSS height value */\n maxHeight?: string | number\n /** Whether the selection can be cleared by selecting the same option again */\n clearable?: boolean\n /** Whether to close the dropdown when an option is selected */\n closeOnSelect?: boolean\n /** Whether the combobox is in a loading state */\n loading?: boolean\n /** Message to show when in loading state */\n loadingPlaceholder?: string\n /** Whether the combobox has an error */\n error?: boolean | string\n /** Custom function to filter options based on search term */\n filterOptions?: (options: Array<T>, searchTerm: string) => Array<T>\n}\n\n/**\n * A searchable combobox component with support for custom rendering, keyboard navigation, and search filtering.\n *\n * @example\n * ```tsx\n * interface User {\n * id: string\n * name: string\n * email: string\n * }\n *\n * <Combobox<User>\n * options={users}\n * value={selectedUserId}\n * onChange={setSelectedUserId}\n * getOptionValue={(user) => user.id}\n * getOptionLabel={(user) => user.name}\n * />\n * ```\n *\n * @example Custom filtering\n * ```tsx\n * <Combobox<User>\n * options={users}\n * value={selectedUserId}\n * onChange={setSelectedUserId}\n * getOptionValue={(user) => user.id}\n * getOptionLabel={(user) => user.name}\n * filterOptions={(options, searchTerm) =>\n * options.filter(user =>\n * user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||\n * user.email.toLowerCase().includes(searchTerm.toLowerCase())\n * )\n * }\n * />\n * ```\n */\nexport const Combobox = <T extends object>({\n id,\n options,\n value,\n onChange,\n getOptionValue,\n getOptionLabel,\n placeholder = 'Select...',\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found.',\n className = 'w-60',\n disabled = false,\n maxHeight = '300px',\n renderOption,\n clearable = false,\n closeOnSelect = true,\n loading = false,\n loadingPlaceholder = 'Cargando...',\n error = false,\n filterOptions,\n}: ComboboxProps<T>) => {\n const [open, setOpen] = useState(false)\n const [searchTerm, setSearchTerm] = useState('')\n\n const selectedOption = options.find((option) => getOptionValue(option) === value)\n\n const filteredOptions = useMemo(() => {\n if (!filterOptions) {\n return options.filter((option) => getOptionLabel(option).toLowerCase().includes(searchTerm.toLowerCase()))\n }\n\n return searchTerm ? filterOptions(options, searchTerm) : options\n }, [filterOptions, options, searchTerm, getOptionLabel])\n\n const handleSelect = (currentValue: string) => {\n const newValue = clearable && currentValue === value ? '' : currentValue\n onChange(newValue)\n if (closeOnSelect) {\n setOpen(false)\n }\n }\n\n return (\n <div className=\"flex w-full flex-col gap-1\">\n <PopoverRoot open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n id={id}\n type=\"button\"\n disabled={disabled}\n variant=\"text\"\n className={cn(\n buttonVariants({ variant: 'input' }),\n 'flex h-10 w-full justify-between rounded-lg',\n open && 'border-neutral-950',\n disabled && 'cursor-not-allowed',\n error && 'border-error-400 focus-visible:border-error-700',\n className,\n )}\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n >\n <span className={cn('block truncate', !selectedOption && 'text-neutral-300')}>\n {selectedOption ? getOptionLabel(selectedOption) : placeholder}\n </span>\n <CaretUpDown className=\"h-4 w-4 shrink-0 opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"p-0\">\n <Command shouldFilter={false}>\n <CommandInput\n placeholder={searchPlaceholder}\n disabled={loading}\n value={searchTerm}\n onValueChange={setSearchTerm}\n />\n <CommandList style={{ maxHeight }}>\n {loading ? (\n <div className=\"text-muted-foreground flex items-center justify-center py-6 text-sm\">\n {loadingPlaceholder}\n </div>\n ) : (\n <>\n {filteredOptions.length === 0 && <CommandEmpty>{emptyMessage}</CommandEmpty>}\n <CommandGroup>\n {filteredOptions.map((option) => {\n const optionValue = getOptionValue(option)\n return (\n <CommandItem key={optionValue} value={optionValue} onSelect={handleSelect}>\n {renderOption ? (\n renderOption(option, value === optionValue)\n ) : (\n <>\n <Check\n className={`mr-2 h-4 w-4 ${value === optionValue ? 'opacity-100' : 'opacity-0'}`}\n />\n <ComboboxOptionWithTooltip label={getOptionLabel(option)} />\n </>\n )}\n </CommandItem>\n )\n })}\n </CommandGroup>\n </>\n )}\n </CommandList>\n </Command>\n </PopoverContent>\n </PopoverRoot>\n {typeof error === 'string' && <span className=\"text-sm text-error-500\">{error}</span>}\n </div>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -59,14 +59,40 @@ function DataTable({
|
|
|
59
59
|
selectedIds,
|
|
60
60
|
data,
|
|
61
61
|
handleSelectAll,
|
|
62
|
-
isLoading
|
|
62
|
+
isLoading,
|
|
63
|
+
isSelectionDisabled: selection?.isSelectionDisabled ?? false,
|
|
64
|
+
selectionDisabledTooltip: selection?.labels?.selectionDisabledTooltip
|
|
63
65
|
}
|
|
64
66
|
),
|
|
65
|
-
[
|
|
67
|
+
[
|
|
68
|
+
isBackendPagination,
|
|
69
|
+
selectedIds,
|
|
70
|
+
data,
|
|
71
|
+
handleSelectAll,
|
|
72
|
+
isLoading,
|
|
73
|
+
selection?.isSelectionDisabled,
|
|
74
|
+
selection?.labels?.selectionDisabledTooltip
|
|
75
|
+
]
|
|
66
76
|
);
|
|
67
77
|
const SelectColumnCell = React.useCallback(
|
|
68
|
-
({ row }) => /* @__PURE__ */ jsx(
|
|
69
|
-
|
|
78
|
+
({ row }) => /* @__PURE__ */ jsx(
|
|
79
|
+
DataTableRowSelector,
|
|
80
|
+
{
|
|
81
|
+
row,
|
|
82
|
+
selectedIds,
|
|
83
|
+
getRowId,
|
|
84
|
+
handleRowSelect,
|
|
85
|
+
isRowSelectionDisabled: selection?.isRowSelectionDisabled,
|
|
86
|
+
rowSelectionDisabledTooltip: selection?.labels?.rowSelectionDisabledTooltip
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
[
|
|
90
|
+
selectedIds,
|
|
91
|
+
getRowId,
|
|
92
|
+
handleRowSelect,
|
|
93
|
+
selection?.isRowSelectionDisabled,
|
|
94
|
+
selection?.labels?.rowSelectionDisabledTooltip
|
|
95
|
+
]
|
|
70
96
|
);
|
|
71
97
|
const tableColumns = React.useMemo(() => {
|
|
72
98
|
const baseColumns = [...userColumns];
|
|
@@ -88,6 +114,7 @@ function DataTable({
|
|
|
88
114
|
onSelectionStart: selection.onSelectionStart,
|
|
89
115
|
onSelectionCancel: selection.onSelectionCancel,
|
|
90
116
|
selectionSummary: selection.labels?.selectionSummary,
|
|
117
|
+
isSelectionDisabled: selection.isSelectionDisabled,
|
|
91
118
|
labels: selection.labels
|
|
92
119
|
};
|
|
93
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTable.js","sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\n'use client'\n\nimport {\n flexRender,\n getCoreRowModel,\n getPaginationRowModel,\n useReactTable,\n VisibilityState,\n Row,\n PaginationState,\n Updater,\n} from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport { Table as TableComponent, TableHeader, TableHead, TableRow } from '../Table'\nimport { Typography } from '../Typography'\n\nimport { DataTableBody } from './components/DataTableBody'\nimport { DataTablePagination } from './components/DataTablePagination'\nimport { DataTableRowSelector } from './components/DataTableRowSelector'\nimport { DataTableSelectHeader } from './components/DataTableSelectHeader'\nimport { DataTableToolbar } from './components/DataTableToolbar'\nimport { useSelection } from './hooks/useSelection'\nimport { DataTableProps } from './types'\n\nimport { cn } from '@/lib/utils'\n\n/**\n * A feature-rich data table component built on top of TanStack Table.\n * Provides sorting, filtering, pagination, and column visibility controls.\n */\nexport function DataTable<TData extends object>({\n columns: userColumns,\n data,\n getRowId = (row: TData) => (row as { id: string }).id,\n showColumnVisibilityControls = true,\n isLoading = false,\n pagination,\n primaryFilters,\n secondaryFilters,\n activePrimaryFiltersCount = 0,\n activeSecondaryFiltersCount = 0,\n selection,\n labels = {\n columnVisibilityButton: 'Hide columns',\n filters: 'Filters',\n moreFilters: 'More filters',\n },\n emptyState = {\n title: 'No data available',\n description: 'Try adjusting your filters or search criteria',\n },\n className,\n tableClassName,\n}: DataTableProps<TData>) {\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = React.useState(0)\n\n const isBackendPagination = pagination !== undefined && 'onPageChange' in pagination\n\n const total = isBackendPagination ? pagination.total : data.length\n const pageSize = pagination?.pageSize ?? (isLoading ? 10 : data.length)\n const totalPages = Math.ceil(total / pageSize)\n\n const { selectedIds, handleRowSelect, handleSelectAll } = useSelection({\n data,\n getRowId,\n selection,\n })\n\n const rowSelection = React.useMemo(\n () => Object.fromEntries(Array.from(selectedIds).map((id) => [id, true])),\n [selectedIds],\n )\n\n const SelectColumnHeader = React.useCallback(\n () => (\n <DataTableSelectHeader\n isBackendPagination={isBackendPagination}\n selectedIds={selectedIds}\n data={data}\n handleSelectAll={handleSelectAll}\n isLoading={isLoading}\n />\n ),\n [isBackendPagination, selectedIds, data, handleSelectAll, isLoading],\n )\n\n const SelectColumnCell = React.useCallback(\n ({ row }: { row: Row<TData> }) => (\n <DataTableRowSelector row={row} selectedIds={selectedIds} getRowId={getRowId} handleRowSelect={handleRowSelect} />\n ),\n [selectedIds, getRowId, handleRowSelect],\n )\n\n const tableColumns = React.useMemo(() => {\n const baseColumns = [...userColumns]\n if (selection !== undefined) {\n const selectColumn = {\n id: 'select',\n size: 50,\n cell: SelectColumnCell,\n header: SelectColumnHeader,\n }\n baseColumns.unshift(selectColumn)\n }\n return baseColumns\n }, [userColumns, selection, SelectColumnCell, SelectColumnHeader])\n\n const toolbarSelectionProps = React.useMemo(() => {\n if (isBackendPagination && selection) {\n return {\n isSelectionStarted: selection.isSelectionStarted,\n onSelectionStart: selection.onSelectionStart,\n onSelectionCancel: selection.onSelectionCancel,\n selectionSummary: selection.labels?.selectionSummary,\n labels: selection.labels,\n }\n }\n return undefined\n }, [isBackendPagination, selection])\n\n const currentPage = isBackendPagination ? pagination.currentPage : pageIndex + 1\n const handlePageChange = isBackendPagination ? pagination.onPageChange : (page: number) => setPageIndex(page - 1)\n\n const tablePaginationState = React.useMemo(() => {\n if (!pagination) {\n return undefined\n }\n return {\n pageIndex: isBackendPagination ? pagination.currentPage - 1 : pageIndex,\n pageSize,\n }\n }, [pagination, isBackendPagination, pageIndex, pageSize])\n\n const tableGetPaginationRowModel = React.useMemo(() => {\n return pagination && !isBackendPagination ? getPaginationRowModel() : undefined\n }, [pagination, isBackendPagination])\n\n const tableOnPaginationChange = React.useCallback(\n (updater: Updater<PaginationState>) => {\n if (typeof updater === 'function') {\n const newState = updater({ pageIndex, pageSize })\n setPageIndex(newState.pageIndex)\n }\n },\n [pageIndex, pageSize, setPageIndex],\n )\n\n const table = useReactTable({\n data,\n columns: tableColumns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: tableGetPaginationRowModel,\n onColumnVisibilityChange: setColumnVisibility,\n enableRowSelection: !!selection,\n getRowId: getRowId,\n state: {\n columnVisibility,\n rowSelection,\n pagination: tablePaginationState,\n },\n manualPagination: isBackendPagination,\n onPaginationChange: isBackendPagination ? undefined : tableOnPaginationChange,\n })\n\n return (\n <div className={cn('flex h-full min-h-0 w-full flex-1 flex-col gap-2 overflow-hidden', className)}>\n <DataTableToolbar\n table={table}\n showColumnVisibilityControls={showColumnVisibilityControls}\n primaryFilters={primaryFilters}\n secondaryFilters={secondaryFilters}\n activePrimaryFiltersCount={activePrimaryFiltersCount}\n activeSecondaryFiltersCount={activeSecondaryFiltersCount}\n labels={labels}\n selection={toolbarSelectionProps}\n />\n\n <div className=\"flex min-h-0 flex-1 flex-col rounded-md border bg-white\">\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <div className=\"h-full overflow-auto\">\n <TableComponent className=\"w-full overscroll-contain\" tableClassName={cn('table-fixed ', tableClassName)}>\n <TableHeader className=\"sticky top-0 z-10 bg-neutral-50\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead\n key={header.id}\n className=\"whitespace-normal\"\n style={{ width: header.column.columnDef.size }}\n >\n <Typography weight=\"medium\">\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </Typography>\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <DataTableBody\n table={table}\n isLoading={isLoading}\n pageSize={pageSize}\n getRowId={getRowId}\n rowSelection={rowSelection}\n isSelectionStarted={selection?.isSelectionStarted ?? false}\n emptyState={emptyState}\n />\n </TableComponent>\n </div>\n </div>\n {!!pagination && (\n <div className=\"border-t px-4 py-2\">\n <DataTablePagination\n table={table}\n total={total}\n pageSize={pageSize}\n currentPage={currentPage}\n totalPages={totalPages}\n onPageChange={handlePageChange}\n isLoading={pagination.isLoading}\n labels={pagination.labels}\n />\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAiCO;AAAyC;AACrC;AACT;AACmD;AACpB;AACnB;AACZ;AACA;AACA;AAC4B;AACE;AAC9B;AACS;AACiB;AACf;AACI;AACf;AACa;AACJ;AACM;AACf;AACA;AAEF;AACE;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAuE;AACrE;AACA;AACA;AAGF;AAA2B;AAC+C;AAC5D;AAGd;AAAiC;AAE7B;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AAAA;AACF;AAEiE;AAGrE;AAA+B;AAEqF;AAE3E;AAGzC;AACE;AACA;AACE;AAAqB;AACf;AACE;AACA;AACE;AAEV;AAAgC;AAElC;AAAO;AAGT;AACE;AACE;AAAO;AACyB;AACF;AACC;AACO;AAClB;AACpB;AAEF;AAAO;AAGT;AACA;AAEA;AACE;AACE;AAAO;AAET;AAAO;AACyD;AAC9D;AACF;AAGF;AACE;AAAsE;AAGxE;AAAsC;AAElC;AACE;AACA;AAA+B;AACjC;AACF;AACkC;AAGpC;AAA4B;AAC1B;AACS;AACwB;AACV;AACG;AACJ;AACtB;AACO;AACL;AACA;AACY;AACd;AACkB;AACoC;AAGxD;AAEI;AAAA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AAAA;AACb;AAGE;AAGM;AAIQ;AAAC;AAAA;AAEW;AACmC;AAM7C;AAAA;AARY;AAatB;AACA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACqD;AACrD;AAAA;AACF;AAGN;AAGI;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACc;AACQ;AACH;AAAA;AAEvB;AAEJ;AAGN;;"}
|
|
1
|
+
{"version":3,"file":"DataTable.js","sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */\n/* eslint-disable @typescript-eslint/no-dynamic-delete */\n'use client'\n\nimport {\n flexRender,\n getCoreRowModel,\n getPaginationRowModel,\n useReactTable,\n VisibilityState,\n Row,\n PaginationState,\n Updater,\n} from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport { Table as TableComponent, TableHeader, TableHead, TableRow } from '../Table'\nimport { Typography } from '../Typography'\n\nimport { DataTableBody } from './components/DataTableBody'\nimport { DataTablePagination } from './components/DataTablePagination'\nimport { DataTableRowSelector } from './components/DataTableRowSelector'\nimport { DataTableSelectHeader } from './components/DataTableSelectHeader'\nimport { DataTableToolbar } from './components/DataTableToolbar'\nimport { useSelection } from './hooks/useSelection'\nimport { DataTableProps } from './types'\n\nimport { cn } from '@/lib/utils'\n\n/**\n * A feature-rich data table component built on top of TanStack Table.\n * Provides sorting, filtering, pagination, and column visibility controls.\n */\nexport function DataTable<TData extends object>({\n columns: userColumns,\n data,\n getRowId = (row: TData) => (row as { id: string }).id,\n showColumnVisibilityControls = true,\n isLoading = false,\n pagination,\n primaryFilters,\n secondaryFilters,\n activePrimaryFiltersCount = 0,\n activeSecondaryFiltersCount = 0,\n selection,\n labels = {\n columnVisibilityButton: 'Hide columns',\n filters: 'Filters',\n moreFilters: 'More filters',\n },\n emptyState = {\n title: 'No data available',\n description: 'Try adjusting your filters or search criteria',\n },\n className,\n tableClassName,\n}: DataTableProps<TData>) {\n const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = React.useState(0)\n\n const isBackendPagination = pagination !== undefined && 'onPageChange' in pagination\n\n const total = isBackendPagination ? pagination.total : data.length\n const pageSize = pagination?.pageSize ?? (isLoading ? 10 : data.length)\n const totalPages = Math.ceil(total / pageSize)\n\n const { selectedIds, handleRowSelect, handleSelectAll } = useSelection({\n data,\n getRowId,\n selection,\n })\n\n const rowSelection = React.useMemo(\n () => Object.fromEntries(Array.from(selectedIds).map((id) => [id, true])),\n [selectedIds],\n )\n\n const SelectColumnHeader = React.useCallback(\n () => (\n <DataTableSelectHeader\n isBackendPagination={isBackendPagination}\n selectedIds={selectedIds}\n data={data}\n handleSelectAll={handleSelectAll}\n isLoading={isLoading}\n isSelectionDisabled={selection?.isSelectionDisabled ?? false}\n selectionDisabledTooltip={selection?.labels?.selectionDisabledTooltip}\n />\n ),\n [\n isBackendPagination,\n selectedIds,\n data,\n handleSelectAll,\n isLoading,\n selection?.isSelectionDisabled,\n selection?.labels?.selectionDisabledTooltip,\n ],\n )\n\n const SelectColumnCell = React.useCallback(\n ({ row }: { row: Row<TData> }) => (\n <DataTableRowSelector\n row={row}\n selectedIds={selectedIds}\n getRowId={getRowId}\n handleRowSelect={handleRowSelect}\n isRowSelectionDisabled={selection?.isRowSelectionDisabled}\n rowSelectionDisabledTooltip={selection?.labels?.rowSelectionDisabledTooltip}\n />\n ),\n [\n selectedIds,\n getRowId,\n handleRowSelect,\n selection?.isRowSelectionDisabled,\n selection?.labels?.rowSelectionDisabledTooltip,\n ],\n )\n\n const tableColumns = React.useMemo(() => {\n const baseColumns = [...userColumns]\n if (selection !== undefined) {\n const selectColumn = {\n id: 'select',\n size: 50,\n cell: SelectColumnCell,\n header: SelectColumnHeader,\n }\n baseColumns.unshift(selectColumn)\n }\n return baseColumns\n }, [userColumns, selection, SelectColumnCell, SelectColumnHeader])\n\n const toolbarSelectionProps = React.useMemo(() => {\n if (isBackendPagination && selection) {\n return {\n isSelectionStarted: selection.isSelectionStarted,\n onSelectionStart: selection.onSelectionStart,\n onSelectionCancel: selection.onSelectionCancel,\n selectionSummary: selection.labels?.selectionSummary,\n isSelectionDisabled: selection.isSelectionDisabled,\n labels: selection.labels,\n }\n }\n return undefined\n }, [isBackendPagination, selection])\n\n const currentPage = isBackendPagination ? pagination.currentPage : pageIndex + 1\n const handlePageChange = isBackendPagination ? pagination.onPageChange : (page: number) => setPageIndex(page - 1)\n\n const tablePaginationState = React.useMemo(() => {\n if (!pagination) {\n return undefined\n }\n return {\n pageIndex: isBackendPagination ? pagination.currentPage - 1 : pageIndex,\n pageSize,\n }\n }, [pagination, isBackendPagination, pageIndex, pageSize])\n\n const tableGetPaginationRowModel = React.useMemo(() => {\n return pagination && !isBackendPagination ? getPaginationRowModel() : undefined\n }, [pagination, isBackendPagination])\n\n const tableOnPaginationChange = React.useCallback(\n (updater: Updater<PaginationState>) => {\n if (typeof updater === 'function') {\n const newState = updater({ pageIndex, pageSize })\n setPageIndex(newState.pageIndex)\n }\n },\n [pageIndex, pageSize, setPageIndex],\n )\n\n const table = useReactTable({\n data,\n columns: tableColumns,\n getCoreRowModel: getCoreRowModel(),\n getPaginationRowModel: tableGetPaginationRowModel,\n onColumnVisibilityChange: setColumnVisibility,\n enableRowSelection: !!selection,\n getRowId: getRowId,\n state: {\n columnVisibility,\n rowSelection,\n pagination: tablePaginationState,\n },\n manualPagination: isBackendPagination,\n onPaginationChange: isBackendPagination ? undefined : tableOnPaginationChange,\n })\n\n return (\n <div className={cn('flex h-full min-h-0 w-full flex-1 flex-col gap-2 overflow-hidden', className)}>\n <DataTableToolbar\n table={table}\n showColumnVisibilityControls={showColumnVisibilityControls}\n primaryFilters={primaryFilters}\n secondaryFilters={secondaryFilters}\n activePrimaryFiltersCount={activePrimaryFiltersCount}\n activeSecondaryFiltersCount={activeSecondaryFiltersCount}\n labels={labels}\n selection={toolbarSelectionProps}\n />\n\n <div className=\"flex min-h-0 flex-1 flex-col rounded-md border bg-white\">\n <div className=\"min-h-0 flex-1 overflow-auto\">\n <div className=\"h-full overflow-auto\">\n <TableComponent className=\"w-full overscroll-contain\" tableClassName={cn('table-fixed ', tableClassName)}>\n <TableHeader className=\"sticky top-0 z-10 bg-neutral-50\">\n {table.getHeaderGroups().map((headerGroup) => (\n <TableRow key={headerGroup.id}>\n {headerGroup.headers.map((header) => (\n <TableHead\n key={header.id}\n className=\"whitespace-normal\"\n style={{ width: header.column.columnDef.size }}\n >\n <Typography weight=\"medium\">\n {header.isPlaceholder\n ? null\n : flexRender(header.column.columnDef.header, header.getContext())}\n </Typography>\n </TableHead>\n ))}\n </TableRow>\n ))}\n </TableHeader>\n <DataTableBody\n table={table}\n isLoading={isLoading}\n pageSize={pageSize}\n getRowId={getRowId}\n rowSelection={rowSelection}\n isSelectionStarted={selection?.isSelectionStarted ?? false}\n emptyState={emptyState}\n />\n </TableComponent>\n </div>\n </div>\n {!!pagination && (\n <div className=\"border-t px-4 py-2\">\n <DataTablePagination\n table={table}\n total={total}\n pageSize={pageSize}\n currentPage={currentPage}\n totalPages={totalPages}\n onPageChange={handlePageChange}\n isLoading={pagination.isLoading}\n labels={pagination.labels}\n />\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;AAiCO;AAAyC;AACrC;AACT;AACmD;AACpB;AACnB;AACZ;AACA;AACA;AAC4B;AACE;AAC9B;AACS;AACiB;AACf;AACI;AACf;AACa;AACJ;AACM;AACf;AACA;AAEF;AACE;AACA;AAEA;AAEA;AACA;AACA;AAEA;AAAuE;AACrE;AACA;AACA;AAGF;AAA2B;AAC+C;AAC5D;AAGd;AAAiC;AAE7B;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACuD;AACV;AAAA;AAC/C;AAEF;AACE;AACA;AACA;AACA;AACA;AACW;AACQ;AACrB;AAGF;AAA+B;AAE3B;AAAC;AAAA;AACC;AACA;AACA;AACA;AACmC;AACa;AAAA;AAClD;AAEF;AACE;AACA;AACA;AACW;AACQ;AACrB;AAGF;AACE;AACA;AACE;AAAqB;AACf;AACE;AACA;AACE;AAEV;AAAgC;AAElC;AAAO;AAGT;AACE;AACE;AAAO;AACyB;AACF;AACC;AACO;AACL;AACb;AACpB;AAEF;AAAO;AAGT;AACA;AAEA;AACE;AACE;AAAO;AAET;AAAO;AACyD;AAC9D;AACF;AAGF;AACE;AAAsE;AAGxE;AAAsC;AAElC;AACE;AACA;AAA+B;AACjC;AACF;AACkC;AAGpC;AAA4B;AAC1B;AACS;AACwB;AACV;AACG;AACJ;AACtB;AACO;AACL;AACA;AACY;AACd;AACkB;AACoC;AAGxD;AAEI;AAAA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AAAA;AACb;AAGE;AAGM;AAIQ;AAAC;AAAA;AAEW;AACmC;AAM7C;AAAA;AARY;AAatB;AACA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACqD;AACrD;AAAA;AACF;AAGN;AAGI;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACc;AACQ;AACH;AAAA;AAEvB;AAEJ;AAGN;;"}
|
|
@@ -4,6 +4,8 @@ type DataTableRowSelectorProps<TData extends object> = {
|
|
|
4
4
|
readonly selectedIds: Set<string>;
|
|
5
5
|
readonly getRowId: (original: TData) => string;
|
|
6
6
|
readonly handleRowSelect: (rowId: string, checked: boolean) => void;
|
|
7
|
+
readonly isRowSelectionDisabled?: boolean | ((row: TData) => boolean);
|
|
8
|
+
readonly rowSelectionDisabledTooltip?: string | ((row: TData) => string | undefined);
|
|
7
9
|
};
|
|
8
|
-
export declare function DataTableRowSelector<TData extends object>({ row, selectedIds, getRowId, handleRowSelect, }: DataTableRowSelectorProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function DataTableRowSelector<TData extends object>({ row, selectedIds, getRowId, handleRowSelect, isRowSelectionDisabled, rowSelectionDisabledTooltip, }: DataTableRowSelectorProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
9
11
|
export {};
|
|
@@ -1,20 +1,33 @@
|
|
|
1
|
-
import { jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { Checkbox } from '../../Checkbox/Checkbox.js';
|
|
3
|
+
import { TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent } from '../../Tooltip/Tooltip.js';
|
|
3
4
|
|
|
4
5
|
function DataTableRowSelector({
|
|
5
6
|
row,
|
|
6
7
|
selectedIds,
|
|
7
8
|
getRowId,
|
|
8
|
-
handleRowSelect
|
|
9
|
+
handleRowSelect,
|
|
10
|
+
isRowSelectionDisabled,
|
|
11
|
+
rowSelectionDisabledTooltip
|
|
9
12
|
}) {
|
|
10
|
-
|
|
13
|
+
const isDisabled = typeof isRowSelectionDisabled === "function" ? isRowSelectionDisabled(row.original) : isRowSelectionDisabled ?? false;
|
|
14
|
+
const tooltipText = typeof rowSelectionDisabledTooltip === "function" ? rowSelectionDisabledTooltip(row.original) : rowSelectionDisabledTooltip;
|
|
15
|
+
const checkbox = /* @__PURE__ */ jsx(
|
|
11
16
|
Checkbox,
|
|
12
17
|
{
|
|
13
18
|
checked: selectedIds.has(getRowId(row.original)),
|
|
14
19
|
onCheckedChange: (checked) => handleRowSelect(getRowId(row.original), !!checked),
|
|
15
|
-
"aria-label": "Select row"
|
|
20
|
+
"aria-label": "Select row",
|
|
21
|
+
disabled: isDisabled
|
|
16
22
|
}
|
|
17
23
|
);
|
|
24
|
+
if (isDisabled && tooltipText) {
|
|
25
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration: 200, children: [
|
|
26
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { children: checkbox }) }),
|
|
27
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: tooltipText })
|
|
28
|
+
] }) });
|
|
29
|
+
}
|
|
30
|
+
return checkbox;
|
|
18
31
|
}
|
|
19
32
|
|
|
20
33
|
export { DataTableRowSelector };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTableRowSelector.js","sources":["../../../../src/components/DataTable/components/DataTableRowSelector.tsx"],"sourcesContent":["import { Row } from '@tanstack/react-table'\n\nimport { Checkbox } from '@/components/Checkbox'\n\ntype DataTableRowSelectorProps<TData extends object> = {\n readonly row: Row<TData>\n readonly selectedIds: Set<string>\n readonly getRowId: (original: TData) => string\n readonly handleRowSelect: (rowId: string, checked: boolean) => void\n}\n\nexport function DataTableRowSelector<TData extends object>({\n row,\n selectedIds,\n getRowId,\n handleRowSelect,\n}: DataTableRowSelectorProps<TData>) {\n
|
|
1
|
+
{"version":3,"file":"DataTableRowSelector.js","sources":["../../../../src/components/DataTable/components/DataTableRowSelector.tsx"],"sourcesContent":["import { Row } from '@tanstack/react-table'\n\nimport { Checkbox } from '@/components/Checkbox'\nimport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from '@/components/Tooltip'\n\ntype DataTableRowSelectorProps<TData extends object> = {\n readonly row: Row<TData>\n readonly selectedIds: Set<string>\n readonly getRowId: (original: TData) => string\n readonly handleRowSelect: (rowId: string, checked: boolean) => void\n readonly isRowSelectionDisabled?: boolean | ((row: TData) => boolean)\n readonly rowSelectionDisabledTooltip?: string | ((row: TData) => string | undefined)\n}\n\nexport function DataTableRowSelector<TData extends object>({\n row,\n selectedIds,\n getRowId,\n handleRowSelect,\n isRowSelectionDisabled,\n rowSelectionDisabledTooltip,\n}: DataTableRowSelectorProps<TData>) {\n const isDisabled =\n typeof isRowSelectionDisabled === 'function'\n ? isRowSelectionDisabled(row.original)\n : (isRowSelectionDisabled ?? false)\n\n const tooltipText =\n typeof rowSelectionDisabledTooltip === 'function'\n ? rowSelectionDisabledTooltip(row.original)\n : rowSelectionDisabledTooltip\n\n const checkbox = (\n <Checkbox\n checked={selectedIds.has(getRowId(row.original))}\n onCheckedChange={(checked) => handleRowSelect(getRowId(row.original), !!checked)}\n aria-label=\"Select row\"\n disabled={isDisabled}\n />\n )\n\n if (isDisabled && tooltipText) {\n return (\n <TooltipProvider>\n <TooltipRoot delayDuration={200}>\n <TooltipTrigger asChild>\n <div>{checkbox}</div>\n </TooltipTrigger>\n <TooltipContent>{tooltipText}</TooltipContent>\n </TooltipRoot>\n </TooltipProvider>\n )\n }\n\n return checkbox\n}\n"],"names":[],"mappings":";;;;AAcO,SAAS,oBAA2C,CAAA;AAAA,EACzD,GAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,sBAAA;AAAA,EACA;AACF,CAAqC,EAAA;AACnC,EAAM,MAAA,UAAA,GACJ,OAAO,sBAA2B,KAAA,UAAA,GAC9B,uBAAuB,GAAI,CAAA,QAAQ,IAClC,sBAA0B,IAAA,KAAA;AAEjC,EAAA,MAAM,cACJ,OAAO,2BAAA,KAAgC,aACnC,2BAA4B,CAAA,GAAA,CAAI,QAAQ,CACxC,GAAA,2BAAA;AAEN,EAAA,MAAM,QACJ,mBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAS,WAAY,CAAA,GAAA,CAAI,QAAS,CAAA,GAAA,CAAI,QAAQ,CAAC,CAAA;AAAA,MAC/C,eAAA,EAAiB,CAAC,OAAA,KAAY,eAAgB,CAAA,QAAA,CAAS,IAAI,QAAQ,CAAA,EAAG,CAAC,CAAC,OAAO,CAAA;AAAA,MAC/E,YAAW,EAAA,YAAA;AAAA,MACX,QAAU,EAAA;AAAA;AAAA,GACZ;AAGF,EAAA,IAAI,cAAc,WAAa,EAAA;AAC7B,IAAA,uBACG,GAAA,CAAA,eAAA,EAAA,EACC,QAAC,kBAAA,IAAA,CAAA,WAAA,EAAA,EAAY,eAAe,GAC1B,EAAA,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,kBAAe,OAAO,EAAA,IAAA,EACrB,QAAC,kBAAA,GAAA,CAAA,KAAA,EAAA,EAAK,oBAAS,CACjB,EAAA,CAAA;AAAA,sBACA,GAAA,CAAC,kBAAgB,QAAY,EAAA,WAAA,EAAA;AAAA,KAAA,EAC/B,CACF,EAAA,CAAA;AAAA;AAIJ,EAAO,OAAA,QAAA;AACT;;;;"}
|
|
@@ -4,6 +4,8 @@ type SelectAllHeaderProps<TData extends object> = {
|
|
|
4
4
|
readonly data: Array<TData>;
|
|
5
5
|
readonly handleSelectAll: (checked: boolean) => void;
|
|
6
6
|
readonly isLoading: boolean;
|
|
7
|
+
readonly isSelectionDisabled: boolean;
|
|
8
|
+
readonly selectionDisabledTooltip: string | undefined;
|
|
7
9
|
};
|
|
8
|
-
export declare function DataTableSelectHeader<TData extends object>({ isBackendPagination, selectedIds, data, handleSelectAll, isLoading, }: SelectAllHeaderProps<TData>): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export declare function DataTableSelectHeader<TData extends object>({ isBackendPagination, selectedIds, data, handleSelectAll, isLoading, isSelectionDisabled, selectionDisabledTooltip, }: SelectAllHeaderProps<TData>): import("react/jsx-runtime").JSX.Element | null;
|
|
9
11
|
export {};
|
|
@@ -1,25 +1,31 @@
|
|
|
1
|
-
import { jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { Checkbox } from '../../Checkbox/Checkbox.js';
|
|
3
|
+
import { TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent } from '../../Tooltip/Tooltip.js';
|
|
3
4
|
|
|
4
5
|
function DataTableSelectHeader({
|
|
5
6
|
isBackendPagination,
|
|
6
7
|
selectedIds,
|
|
7
8
|
data,
|
|
8
9
|
handleSelectAll,
|
|
9
|
-
isLoading
|
|
10
|
+
isLoading,
|
|
11
|
+
isSelectionDisabled,
|
|
12
|
+
selectionDisabledTooltip
|
|
10
13
|
}) {
|
|
11
14
|
if (isBackendPagination) {
|
|
12
15
|
return null;
|
|
13
16
|
}
|
|
14
|
-
return /* @__PURE__ */ jsx(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration: 200, children: [
|
|
18
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
19
|
+
Checkbox,
|
|
20
|
+
{
|
|
21
|
+
checked: selectedIds.size === data.length,
|
|
22
|
+
onCheckedChange: handleSelectAll,
|
|
23
|
+
disabled: isLoading || !data.length || isSelectionDisabled,
|
|
24
|
+
"aria-label": "Select all rows"
|
|
25
|
+
}
|
|
26
|
+
) }),
|
|
27
|
+
selectionDisabledTooltip && /* @__PURE__ */ jsx(TooltipContent, { children: selectionDisabledTooltip })
|
|
28
|
+
] }) });
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
export { DataTableSelectHeader };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTableSelectHeader.js","sources":["../../../../src/components/DataTable/components/DataTableSelectHeader.tsx"],"sourcesContent":["import { Checkbox } from '@/components/Checkbox'\n\ntype SelectAllHeaderProps<TData extends object> = {\n readonly isBackendPagination: boolean\n readonly selectedIds: Set<string>\n readonly data: Array<TData>\n readonly handleSelectAll: (checked: boolean) => void\n readonly isLoading: boolean\n}\n\nexport function DataTableSelectHeader<TData extends object>({\n isBackendPagination,\n selectedIds,\n data,\n handleSelectAll,\n isLoading,\n}: SelectAllHeaderProps<TData>) {\n if (isBackendPagination) {\n return null\n }\n\n return (\n <Checkbox\n
|
|
1
|
+
{"version":3,"file":"DataTableSelectHeader.js","sources":["../../../../src/components/DataTable/components/DataTableSelectHeader.tsx"],"sourcesContent":["import { Checkbox } from '@/components/Checkbox'\nimport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from '@/components/Tooltip'\n\ntype SelectAllHeaderProps<TData extends object> = {\n readonly isBackendPagination: boolean\n readonly selectedIds: Set<string>\n readonly data: Array<TData>\n readonly handleSelectAll: (checked: boolean) => void\n readonly isLoading: boolean\n readonly isSelectionDisabled: boolean\n readonly selectionDisabledTooltip: string | undefined\n}\n\nexport function DataTableSelectHeader<TData extends object>({\n isBackendPagination,\n selectedIds,\n data,\n handleSelectAll,\n isLoading,\n isSelectionDisabled,\n selectionDisabledTooltip,\n}: SelectAllHeaderProps<TData>) {\n if (isBackendPagination) {\n return null\n }\n\n return (\n <TooltipProvider>\n <TooltipRoot delayDuration={200}>\n <TooltipTrigger asChild>\n <Checkbox\n checked={selectedIds.size === data.length}\n onCheckedChange={handleSelectAll}\n disabled={isLoading || !data.length || isSelectionDisabled}\n aria-label=\"Select all rows\"\n />\n </TooltipTrigger>\n {selectionDisabledTooltip && <TooltipContent>{selectionDisabledTooltip}</TooltipContent>}\n </TooltipRoot>\n </TooltipProvider>\n )\n}\n"],"names":[],"mappings":";;;;AAaO,SAAS,qBAA4C,CAAA;AAAA,EAC1D,mBAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAgC,EAAA;AAC9B,EAAA,IAAI,mBAAqB,EAAA;AACvB,IAAO,OAAA,IAAA;AAAA;AAGT,EAAA,uBACG,GAAA,CAAA,eAAA,EAAA,EACC,QAAC,kBAAA,IAAA,CAAA,WAAA,EAAA,EAAY,eAAe,GAC1B,EAAA,QAAA,EAAA;AAAA,oBAAC,GAAA,CAAA,cAAA,EAAA,EAAe,SAAO,IACrB,EAAA,QAAA,kBAAA,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,OAAA,EAAS,WAAY,CAAA,IAAA,KAAS,IAAK,CAAA,MAAA;AAAA,QACnC,eAAiB,EAAA,eAAA;AAAA,QACjB,QAAU,EAAA,SAAA,IAAa,CAAC,IAAA,CAAK,MAAU,IAAA,mBAAA;AAAA,QACvC,YAAW,EAAA;AAAA;AAAA,KAEf,EAAA,CAAA;AAAA,IACC,wBAAA,oBAA6B,GAAA,CAAA,cAAA,EAAA,EAAgB,QAAyB,EAAA,wBAAA,EAAA;AAAA,GAAA,EACzE,CACF,EAAA,CAAA;AAEJ;;;;"}
|
|
@@ -18,10 +18,12 @@ type DataTableToolbarProps<TData> = {
|
|
|
18
18
|
onSelectionStart?: () => void;
|
|
19
19
|
onSelectionCancel?: () => void;
|
|
20
20
|
selectionSummary?: string | null;
|
|
21
|
+
isSelectionDisabled?: boolean;
|
|
21
22
|
labels?: {
|
|
22
23
|
startSelection?: string;
|
|
23
24
|
cancelSelection?: string;
|
|
24
25
|
selectionSummary?: string;
|
|
26
|
+
selectionDisabledTooltip?: string;
|
|
25
27
|
};
|
|
26
28
|
};
|
|
27
29
|
};
|
|
@@ -5,6 +5,7 @@ import { Button } from '../../Button/Button.js';
|
|
|
5
5
|
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuCheckboxItem, DropdownMenuSeparator } from '../../DropdownMenu/DropdownMenu.js';
|
|
6
6
|
import { PopoverRoot, PopoverTrigger, PopoverContent } from '../../Popover/Popover.js';
|
|
7
7
|
import { Typography } from '../../Typography/Typography.js';
|
|
8
|
+
import { TooltipProvider, TooltipRoot, TooltipTrigger, TooltipContent } from '../../Tooltip/Tooltip.js';
|
|
8
9
|
import { useIsMobile } from '../../../lib/useMobile.js';
|
|
9
10
|
import { cn } from '../../../lib/utils.js';
|
|
10
11
|
|
|
@@ -48,7 +49,20 @@ function DataTableToolbar({
|
|
|
48
49
|
selection && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: selection.isSelectionStarted ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
49
50
|
/* @__PURE__ */ jsx(Button, { variant: "text", size: "sm", StartIcon: X, onClick: selection.onSelectionCancel, children: selectionLabels.cancelSelection }),
|
|
50
51
|
selection.selectionSummary && !isMobile && /* @__PURE__ */ jsx(Typography, { variant: "body-sm", className: "text-neutral-600", children: selection.selectionSummary })
|
|
51
|
-
] }) : /* @__PURE__ */ jsx(
|
|
52
|
+
] }) : /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration: 200, children: [
|
|
53
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
54
|
+
Button,
|
|
55
|
+
{
|
|
56
|
+
variant: "text",
|
|
57
|
+
size: "sm",
|
|
58
|
+
StartIcon: SelectionAll,
|
|
59
|
+
onClick: selection.onSelectionStart,
|
|
60
|
+
disabled: selection.isSelectionDisabled,
|
|
61
|
+
children: selectionLabels.startSelection
|
|
62
|
+
}
|
|
63
|
+
) }) }),
|
|
64
|
+
selection.labels?.selectionDisabledTooltip && /* @__PURE__ */ jsx(TooltipContent, { children: selection.labels.selectionDisabledTooltip })
|
|
65
|
+
] }) }) })
|
|
52
66
|
] }),
|
|
53
67
|
/* @__PURE__ */ jsxs("div", { className: cn("flex items-center gap-2", isMobile ? "w-full justify-end" : ""), children: [
|
|
54
68
|
(isMobile ? primaryFilters || secondaryFilters : secondaryFilters) && /* @__PURE__ */ jsxs(PopoverRoot, { children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTableToolbar.js","sources":["../../../../src/components/DataTable/components/DataTableToolbar.tsx"],"sourcesContent":["import { TextColumns, FunnelSimple, X, SelectionAll } from '@phosphor-icons/react'\nimport { Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport { Badge } from '../../Badge'\nimport { Button } from '../../Button'\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../../DropdownMenu'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../../Popover'\nimport { Typography } from '../../Typography'\n\nimport { useIsMobile } from '@/lib/useMobile'\nimport { cn } from '@/lib/utils'\n\ntype DataTableToolbarProps<TData> = {\n readonly table: Table<TData>\n readonly showColumnVisibilityControls?: boolean\n readonly primaryFilters?: React.ReactNode\n readonly secondaryFilters?: React.ReactNode\n readonly activePrimaryFiltersCount?: number\n readonly activeSecondaryFiltersCount?: number\n readonly labels?: {\n columnVisibilityButton?: string\n columnVisibilitySelectAll?: string\n filters?: string\n moreFilters?: string\n }\n readonly selection?: {\n isSelectionStarted?: boolean\n onSelectionStart?: () => void\n onSelectionCancel?: () => void\n selectionSummary?: string | null\n labels?: {\n startSelection?: string\n cancelSelection?: string\n selectionSummary?: string\n }\n }\n}\n\nconst defaultLabels = {\n columnVisibilityButton: 'Hide columns',\n columnVisibilitySelectAll: 'Select all',\n filters: 'Filters',\n moreFilters: 'More filters',\n startSelection: 'Start selection',\n cancelSelection: 'Cancel selection',\n}\n\nconst defaultSelectionLabels = {\n startSelection: 'Start selection',\n cancelSelection: 'Cancel selection',\n}\n\nexport function DataTableToolbar<TData>({\n table,\n showColumnVisibilityControls = true,\n primaryFilters,\n secondaryFilters,\n activePrimaryFiltersCount = 0,\n activeSecondaryFiltersCount = 0,\n selection,\n labels: labelsProp,\n}: DataTableToolbarProps<TData>) {\n const isMobile = useIsMobile()\n\n const labels = {\n ...defaultLabels,\n ...labelsProp,\n }\n\n const selectionLabels = {\n ...defaultSelectionLabels,\n ...selection?.labels,\n }\n\n if (!showColumnVisibilityControls && !primaryFilters && !secondaryFilters && !selection) {\n return null\n }\n\n return (\n <div className=\"flex flex-shrink-0 items-end justify-between p-1\">\n <div className=\"flex flex-col items-start gap-2\">\n {!isMobile && primaryFilters && <div className=\"flex items-center gap-2\">{primaryFilters}</div>}\n {selection && (\n <div className=\"flex items-center gap-2\">\n {selection.isSelectionStarted ? (\n <>\n <Button variant=\"text\" size=\"sm\" StartIcon={X} onClick={selection.onSelectionCancel}>\n {selectionLabels.cancelSelection}\n </Button>\n {selection.selectionSummary && !isMobile && (\n <Typography variant=\"body-sm\" className=\"text-neutral-600\">\n {selection.selectionSummary}\n </Typography>\n )}\n </>\n ) : (\n <Button variant=\"text\" size=\"sm\" StartIcon={SelectionAll} onClick={selection.onSelectionStart}>\n {selectionLabels.startSelection}\n </Button>\n )}\n </div>\n )}\n </div>\n <div className={cn('flex items-center gap-2', isMobile ? 'w-full justify-end' : '')}>\n {/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */}\n {(isMobile ? primaryFilters || secondaryFilters : secondaryFilters) && (\n <PopoverRoot>\n <PopoverTrigger asChild>\n <Button variant=\"text\" size=\"sm\" StartIcon={FunnelSimple} className=\"relative whitespace-nowrap\">\n {((isMobile && activePrimaryFiltersCount + activeSecondaryFiltersCount > 0) ||\n (!isMobile && activeSecondaryFiltersCount > 0)) && (\n <Badge\n count={\n isMobile ? activePrimaryFiltersCount + activeSecondaryFiltersCount : activeSecondaryFiltersCount\n }\n color=\"primary\"\n ping={false}\n className=\"absolute -right-1 -top-1\"\n />\n )}\n {!primaryFilters || isMobile ? labels.filters : labels.moreFilters}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"center\"\n className={cn('w-fit p-4', isMobile && 'max-h-[80vh] w-[95vw] overflow-y-auto')}\n >\n <div className=\"flex flex-col gap-4\">\n {isMobile && primaryFilters && primaryFilters}\n {secondaryFilters}\n </div>\n </PopoverContent>\n </PopoverRoot>\n )}\n {showColumnVisibilityControls && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"text\" size=\"sm\" className={cn('whitespace-nowrap')} StartIcon={TextColumns}>\n {labels.columnVisibilityButton}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent>\n <DropdownMenuCheckboxItem\n key={'all-columns'}\n className=\"capitalize\"\n checked={table.getAllColumns().every((column) => column.getIsVisible())}\n onSelect={(event) => event.preventDefault()}\n onCheckedChange={(value) => table.getAllColumns().forEach((column) => column.toggleVisibility(!!value))}\n >\n {labels.columnVisibilitySelectAll}\n </DropdownMenuCheckboxItem>\n <DropdownMenuSeparator className=\"bg-neutral-100\" />\n {table\n .getAllColumns()\n .filter((column) => column.getCanHide() && column.id !== 'select')\n .map((column) => {\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n className=\"capitalize\"\n checked={column.getIsVisible()}\n onSelect={(event) => event.preventDefault()}\n onCheckedChange={(value) => column.toggleVisibility(!!value)}\n >\n {column.columnDef.header?.toString()}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </div>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataTableToolbar.js","sources":["../../../../src/components/DataTable/components/DataTableToolbar.tsx"],"sourcesContent":["import { TextColumns, FunnelSimple, X, SelectionAll } from '@phosphor-icons/react'\nimport { Table } from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport { Badge } from '../../Badge'\nimport { Button } from '../../Button'\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../../DropdownMenu'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../../Popover'\nimport { Typography } from '../../Typography'\n\nimport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from '@/components/Tooltip'\nimport { useIsMobile } from '@/lib/useMobile'\nimport { cn } from '@/lib/utils'\n\ntype DataTableToolbarProps<TData> = {\n readonly table: Table<TData>\n readonly showColumnVisibilityControls?: boolean\n readonly primaryFilters?: React.ReactNode\n readonly secondaryFilters?: React.ReactNode\n readonly activePrimaryFiltersCount?: number\n readonly activeSecondaryFiltersCount?: number\n readonly labels?: {\n columnVisibilityButton?: string\n columnVisibilitySelectAll?: string\n filters?: string\n moreFilters?: string\n }\n readonly selection?: {\n isSelectionStarted?: boolean\n onSelectionStart?: () => void\n onSelectionCancel?: () => void\n selectionSummary?: string | null\n isSelectionDisabled?: boolean\n labels?: {\n startSelection?: string\n cancelSelection?: string\n selectionSummary?: string\n selectionDisabledTooltip?: string\n }\n }\n}\n\nconst defaultLabels = {\n columnVisibilityButton: 'Hide columns',\n columnVisibilitySelectAll: 'Select all',\n filters: 'Filters',\n moreFilters: 'More filters',\n startSelection: 'Start selection',\n cancelSelection: 'Cancel selection',\n}\n\nconst defaultSelectionLabels = {\n startSelection: 'Start selection',\n cancelSelection: 'Cancel selection',\n}\n\nexport function DataTableToolbar<TData>({\n table,\n showColumnVisibilityControls = true,\n primaryFilters,\n secondaryFilters,\n activePrimaryFiltersCount = 0,\n activeSecondaryFiltersCount = 0,\n selection,\n labels: labelsProp,\n}: DataTableToolbarProps<TData>) {\n const isMobile = useIsMobile()\n\n const labels = {\n ...defaultLabels,\n ...labelsProp,\n }\n\n const selectionLabels = {\n ...defaultSelectionLabels,\n ...selection?.labels,\n }\n\n if (!showColumnVisibilityControls && !primaryFilters && !secondaryFilters && !selection) {\n return null\n }\n\n return (\n <div className=\"flex flex-shrink-0 items-end justify-between p-1\">\n <div className=\"flex flex-col items-start gap-2\">\n {!isMobile && primaryFilters && <div className=\"flex items-center gap-2\">{primaryFilters}</div>}\n {selection && (\n <div className=\"flex items-center gap-2\">\n {selection.isSelectionStarted ? (\n <>\n <Button variant=\"text\" size=\"sm\" StartIcon={X} onClick={selection.onSelectionCancel}>\n {selectionLabels.cancelSelection}\n </Button>\n {selection.selectionSummary && !isMobile && (\n <Typography variant=\"body-sm\" className=\"text-neutral-600\">\n {selection.selectionSummary}\n </Typography>\n )}\n </>\n ) : (\n <TooltipProvider>\n <TooltipRoot delayDuration={200}>\n <TooltipTrigger asChild>\n <div>\n <Button\n variant=\"text\"\n size=\"sm\"\n StartIcon={SelectionAll}\n onClick={selection.onSelectionStart}\n disabled={selection.isSelectionDisabled}\n >\n {selectionLabels.startSelection}\n </Button>\n </div>\n </TooltipTrigger>\n {selection.labels?.selectionDisabledTooltip && (\n <TooltipContent>{selection.labels.selectionDisabledTooltip}</TooltipContent>\n )}\n </TooltipRoot>\n </TooltipProvider>\n )}\n </div>\n )}\n </div>\n <div className={cn('flex items-center gap-2', isMobile ? 'w-full justify-end' : '')}>\n {/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */}\n {(isMobile ? primaryFilters || secondaryFilters : secondaryFilters) && (\n <PopoverRoot>\n <PopoverTrigger asChild>\n <Button variant=\"text\" size=\"sm\" StartIcon={FunnelSimple} className=\"relative whitespace-nowrap\">\n {((isMobile && activePrimaryFiltersCount + activeSecondaryFiltersCount > 0) ||\n (!isMobile && activeSecondaryFiltersCount > 0)) && (\n <Badge\n count={\n isMobile ? activePrimaryFiltersCount + activeSecondaryFiltersCount : activeSecondaryFiltersCount\n }\n color=\"primary\"\n ping={false}\n className=\"absolute -right-1 -top-1\"\n />\n )}\n {!primaryFilters || isMobile ? labels.filters : labels.moreFilters}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"center\"\n className={cn('w-fit p-4', isMobile && 'max-h-[80vh] w-[95vw] overflow-y-auto')}\n >\n <div className=\"flex flex-col gap-4\">\n {isMobile && primaryFilters && primaryFilters}\n {secondaryFilters}\n </div>\n </PopoverContent>\n </PopoverRoot>\n )}\n {showColumnVisibilityControls && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"text\" size=\"sm\" className={cn('whitespace-nowrap')} StartIcon={TextColumns}>\n {labels.columnVisibilityButton}\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent>\n <DropdownMenuCheckboxItem\n key={'all-columns'}\n className=\"capitalize\"\n checked={table.getAllColumns().every((column) => column.getIsVisible())}\n onSelect={(event) => event.preventDefault()}\n onCheckedChange={(value) => table.getAllColumns().forEach((column) => column.toggleVisibility(!!value))}\n >\n {labels.columnVisibilitySelectAll}\n </DropdownMenuCheckboxItem>\n <DropdownMenuSeparator className=\"bg-neutral-100\" />\n {table\n .getAllColumns()\n .filter((column) => column.getCanHide() && column.id !== 'select')\n .map((column) => {\n return (\n <DropdownMenuCheckboxItem\n key={column.id}\n className=\"capitalize\"\n checked={column.getIsVisible()}\n onSelect={(event) => event.preventDefault()}\n onCheckedChange={(value) => column.toggleVisibility(!!value)}\n >\n {column.columnDef.header?.toString()}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n </div>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { SelectionConfig } from '../types';
|
|
|
2
2
|
type UseSelectionProps<TData> = {
|
|
3
3
|
data: Array<TData>;
|
|
4
4
|
getRowId: (row: TData) => string;
|
|
5
|
+
isRowSelectionDisabled?: boolean | ((row: TData) => boolean);
|
|
5
6
|
selection?: SelectionConfig<TData>;
|
|
6
7
|
};
|
|
7
8
|
type UseSelectionReturn = {
|
|
@@ -10,7 +10,10 @@ function useSelection({ data, getRowId, selection }) {
|
|
|
10
10
|
if (!selection) return;
|
|
11
11
|
const row = data.find((row2) => getRowId(row2) === id);
|
|
12
12
|
if (row) {
|
|
13
|
-
selection.
|
|
13
|
+
const isDisabled = typeof selection.isRowSelectionDisabled === "function" ? selection.isRowSelectionDisabled(row) : selection.isRowSelectionDisabled;
|
|
14
|
+
if (!isDisabled) {
|
|
15
|
+
selection.onSelect?.(row, selected);
|
|
16
|
+
}
|
|
14
17
|
}
|
|
15
18
|
},
|
|
16
19
|
[data, getRowId, selection]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSelection.js","sources":["../../../../src/components/DataTable/hooks/useSelection.ts"],"sourcesContent":["import { useMemo, useCallback } from 'react'\n\nimport { SelectionConfig } from '../types'\n\ntype UseSelectionProps<TData> = {\n data: Array<TData>\n getRowId: (row: TData) => string\n selection?: SelectionConfig<TData>\n}\n\ntype UseSelectionReturn = {\n selectedIds: Set<string>\n isRowSelected: (id: string) => boolean\n handleRowSelect: (id: string, selected: boolean) => void\n handleSelectAll: (selected: boolean) => void\n showHeaderCheckbox: boolean\n}\n\nexport function useSelection<TData>({ data, getRowId, selection }: UseSelectionProps<TData>): UseSelectionReturn {\n const selectedIds = useMemo(() => {\n if (!selection) return new Set<string>()\n return new Set(data.filter(selection.isSelected).map(getRowId))\n }, [data, getRowId, selection])\n\n const handleRowSelect = useCallback(\n (id: string, selected: boolean) => {\n if (!selection) return\n const row = data.find((row) => getRowId(row) === id)\n if (row) {\n selection.onSelect?.(row, selected)\n }\n },\n [data, getRowId, selection],\n )\n\n const handleSelectAll = useCallback(\n (selected: boolean) => {\n if (!selection?.onSelectAll) return\n selection.onSelectAll(selected)\n },\n [selection],\n )\n\n const isRowSelected = useCallback((id: string) => selectedIds.has(id), [selectedIds])\n\n const showHeaderCheckbox = !!selection\n\n return {\n selectedIds,\n isRowSelected,\n handleRowSelect,\n handleSelectAll,\n showHeaderCheckbox,\n }\n}\n"],"names":["row"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"useSelection.js","sources":["../../../../src/components/DataTable/hooks/useSelection.ts"],"sourcesContent":["import { useMemo, useCallback } from 'react'\n\nimport { SelectionConfig } from '../types'\n\ntype UseSelectionProps<TData> = {\n data: Array<TData>\n getRowId: (row: TData) => string\n isRowSelectionDisabled?: boolean | ((row: TData) => boolean)\n selection?: SelectionConfig<TData>\n}\n\ntype UseSelectionReturn = {\n selectedIds: Set<string>\n isRowSelected: (id: string) => boolean\n handleRowSelect: (id: string, selected: boolean) => void\n handleSelectAll: (selected: boolean) => void\n showHeaderCheckbox: boolean\n}\n\nexport function useSelection<TData>({ data, getRowId, selection }: UseSelectionProps<TData>): UseSelectionReturn {\n const selectedIds = useMemo(() => {\n if (!selection) return new Set<string>()\n return new Set(data.filter(selection.isSelected).map(getRowId))\n }, [data, getRowId, selection])\n\n const handleRowSelect = useCallback(\n (id: string, selected: boolean) => {\n if (!selection) return\n const row = data.find((row) => getRowId(row) === id)\n\n if (row) {\n const isDisabled =\n typeof selection.isRowSelectionDisabled === 'function'\n ? selection.isRowSelectionDisabled(row)\n : selection.isRowSelectionDisabled\n if (!isDisabled) {\n selection.onSelect?.(row, selected)\n }\n }\n },\n [data, getRowId, selection],\n )\n\n const handleSelectAll = useCallback(\n (selected: boolean) => {\n if (!selection?.onSelectAll) return\n selection.onSelectAll(selected)\n },\n [selection],\n )\n\n const isRowSelected = useCallback((id: string) => selectedIds.has(id), [selectedIds])\n\n const showHeaderCheckbox = !!selection\n\n return {\n selectedIds,\n isRowSelected,\n handleRowSelect,\n handleSelectAll,\n showHeaderCheckbox,\n }\n}\n"],"names":["row"],"mappings":";;AAmBO,SAAS,YAAoB,CAAA,EAAE,IAAM,EAAA,QAAA,EAAU,WAA2D,EAAA;AAC/G,EAAM,MAAA,WAAA,GAAc,QAAQ,MAAM;AAChC,IAAA,IAAI,CAAC,SAAA,EAAkB,uBAAA,IAAI,GAAY,EAAA;AACvC,IAAO,OAAA,IAAI,IAAI,IAAK,CAAA,MAAA,CAAO,UAAU,UAAU,CAAA,CAAE,GAAI,CAAA,QAAQ,CAAC,CAAA;AAAA,GAC7D,EAAA,CAAC,IAAM,EAAA,QAAA,EAAU,SAAS,CAAC,CAAA;AAE9B,EAAA,MAAM,eAAkB,GAAA,WAAA;AAAA,IACtB,CAAC,IAAY,QAAsB,KAAA;AACjC,MAAA,IAAI,CAAC,SAAW,EAAA;AAChB,MAAM,MAAA,GAAA,GAAM,KAAK,IAAK,CAAA,CAACA,SAAQ,QAASA,CAAAA,IAAG,MAAM,EAAE,CAAA;AAEnD,MAAA,IAAI,GAAK,EAAA;AACP,QAAM,MAAA,UAAA,GACJ,OAAO,SAAU,CAAA,sBAAA,KAA2B,aACxC,SAAU,CAAA,sBAAA,CAAuB,GAAG,CAAA,GACpC,SAAU,CAAA,sBAAA;AAChB,QAAA,IAAI,CAAC,UAAY,EAAA;AACf,UAAU,SAAA,CAAA,QAAA,GAAW,KAAK,QAAQ,CAAA;AAAA;AACpC;AACF,KACF;AAAA,IACA,CAAC,IAAM,EAAA,QAAA,EAAU,SAAS;AAAA,GAC5B;AAEA,EAAA,MAAM,eAAkB,GAAA,WAAA;AAAA,IACtB,CAAC,QAAsB,KAAA;AACrB,MAAI,IAAA,CAAC,WAAW,WAAa,EAAA;AAC7B,MAAA,SAAA,CAAU,YAAY,QAAQ,CAAA;AAAA,KAChC;AAAA,IACA,CAAC,SAAS;AAAA,GACZ;AAEA,EAAM,MAAA,aAAA,GAAgB,WAAY,CAAA,CAAC,EAAe,KAAA,WAAA,CAAY,IAAI,EAAE,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEpF,EAAM,MAAA,kBAAA,GAAqB,CAAC,CAAC,SAAA;AAE7B,EAAO,OAAA;AAAA,IACL,WAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
|
|
@@ -48,8 +48,16 @@ export type SelectionConfig<TData> = {
|
|
|
48
48
|
onSelectionCancel?: () => void
|
|
49
49
|
/** Whether selection mode is active (for backend pagination) */
|
|
50
50
|
isSelectionStarted?: boolean
|
|
51
|
+
/** Whether the selection is disabled */
|
|
52
|
+
isSelectionDisabled?: boolean
|
|
53
|
+
/** Whether the row selection is disabled */
|
|
54
|
+
isRowSelectionDisabled?: boolean | ((row: TData) => boolean)
|
|
51
55
|
/** Selection-related labels for UI customization */
|
|
52
56
|
labels?: {
|
|
57
|
+
/** Text for the selection disabled tooltip */
|
|
58
|
+
selectionDisabledTooltip?: string | undefined
|
|
59
|
+
/** Tooltip text shown when the checkbox is disabled */
|
|
60
|
+
rowSelectionDisabledTooltip?: string | ((row: TData) => string | undefined)
|
|
53
61
|
/** Text for the start selection button (default: "Select") */
|
|
54
62
|
startSelection?: string
|
|
55
63
|
/** Text for the cancel selection button (default: "Cancel") */
|
|
@@ -114,8 +114,7 @@ function DatePicker({
|
|
|
114
114
|
...baseProps,
|
|
115
115
|
mode: "single",
|
|
116
116
|
selected: singleDate,
|
|
117
|
-
onSelect: (date) => handleSelect(date)
|
|
118
|
-
defaultMonth: singleDate ?? /* @__PURE__ */ new Date()
|
|
117
|
+
onSelect: (date) => handleSelect(date)
|
|
119
118
|
};
|
|
120
119
|
}
|
|
121
120
|
return {
|
|
@@ -123,7 +122,6 @@ function DatePicker({
|
|
|
123
122
|
mode: "range",
|
|
124
123
|
selected: dateRange,
|
|
125
124
|
onSelect: (range) => handleSelect(range),
|
|
126
|
-
defaultMonth: dateRange?.from ?? /* @__PURE__ */ new Date(),
|
|
127
125
|
numberOfMonths: rest.numberOfMonths ?? 2
|
|
128
126
|
};
|
|
129
127
|
}, [variant, rest, singleDate, dateRange, handleSelect, resolvedLocale]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.js","sources":["../../../src/components/DatePicker/DatePicker.tsx"],"sourcesContent":["'use client'\n\nimport { CalendarBlank } from '@phosphor-icons/react'\nimport { format as formatFn, Locale } from 'date-fns'\nimport { enUS, es, pt, enGB, de, it, fr } from 'date-fns/locale'\nimport * as React from 'react'\nimport { PropsBase, PropsRangeRequired, PropsSingleRequired } from 'react-day-picker'\n\nimport { Button, buttonVariants } from '../Button'\nimport { Calendar } from '../Calendar'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\n\nimport {\n formatOutputDate,\n formatOutputRange,\n parseInputDate,\n parseInputRange,\n InputDate,\n InputRange,\n ValueFormat,\n} from '@/lib/dateUtils'\nimport { cn } from '@/lib/utils'\n\ntype SupportedLocaleString = 'enUS' | 'es' | 'pt' | 'enGB' | 'de' | 'it' | 'fr'\n\nconst localeMap: Record<SupportedLocaleString, Locale> = {\n enUS,\n es,\n pt,\n enGB,\n de,\n it,\n fr,\n}\n\nexport type DateRange = {\n from?: Date\n to?: Date\n}\n\nexport type IsoDateRange = {\n from?: string\n to?: string\n}\n\ntype DatePickerOutput<Variant extends 'single' | 'range', Format extends ValueFormat> = Variant extends 'single'\n ? Format extends 'date'\n ? Date | undefined\n : string | undefined\n : Format extends 'date'\n ? DateRange | undefined\n : IsoDateRange | undefined\n\ntype DatePickerInput<V extends 'single' | 'range'> = V extends 'single'\n ? Date | string | undefined\n : { from?: Date | string; to?: Date | string } | undefined\n\nexport type DatePickerProps<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'> = {\n /**\n * Placeholder text displayed when no date is selected\n * @default 'Pick a date' for single mode, 'Pick a date range' for range mode\n */\n readonly placeholder?: string\n\n /**\n * Format string to use when displaying the selected date in the button\n * @default 'MMM d, yyyy'\n */\n readonly displayFormat?: string\n\n /**\n * ClassName for the button\n */\n readonly buttonClassName?: string\n\n /**\n * Whether to allow the user to show the year switcher menu\n * @default true for single mode, false for range mode\n */\n readonly showYearSwitcher?: boolean\n\n /**\n * Initial value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly initialValue?: DatePickerInput<V>\n\n /**\n * Current value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly value?: DatePickerInput<V>\n\n /**\n * Determines if the picker should close after a selection\n * @default true for single mode, false for range mode\n */\n readonly closeOnSelect?: boolean\n\n /**\n * Determines the format of the value provided to the onChange callback\n * - 'iso' (default): onChange receives ISO string(s) ('yyyy-MM-dd')\n * - 'date': onChange receives JavaScript Date object(s)\n *\n * Note: The component accepts both Date objects and ISO strings for value/initialValue\n * regardless of this setting.\n * @default 'iso'\n */\n readonly valueFormat?: F\n\n /**\n * Callback when date or date range changes\n */\n readonly onChange?: (value: DatePickerOutput<V, F>) => void\n\n /**\n * DatePicker mode - single date or date range\n * @default 'single'\n */\n readonly variant?: V\n\n /**\n * The locale to use for formatting dates and determining the start of the week.\n * Can be a string identifier for supported locales ('enUS', 'es', 'pt', 'enGB', 'de', 'it', 'fr')\n * or a Locale object from date-fns/locale for other languages.\n * @default 'enUS'\n */\n readonly locale?: SupportedLocaleString | Locale\n} & Omit<PropsBase, 'mode' | 'selected' | 'onSelect' | 'locale'>\n\nfunction DatePicker<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'>({\n variant = 'single' as V,\n placeholder = variant === 'single' ? 'Pick a date' : 'Pick a date range',\n valueFormat = 'iso' as F,\n initialValue: initialValueProp,\n value: valueProp,\n onChange,\n buttonClassName,\n displayFormat = 'MMM d, yyyy',\n closeOnSelect = variant === 'single',\n showYearSwitcher = variant === 'single',\n locale: localeProp = 'enUS',\n ...rest\n}: DatePickerProps<V, F>) {\n const [isOpen, setIsOpen] = React.useState(false)\n\n const resolvedLocale = React.useMemo(() => {\n if (typeof localeProp === 'string') {\n return localeMap[localeProp]\n }\n return localeProp\n }, [localeProp])\n\n const [internalSingleDate, setInternalSingleDate] = React.useState<Date | undefined>(() => {\n if (variant === 'single') {\n return parseInputDate(initialValueProp as InputDate)\n }\n return undefined\n })\n\n const [internalDateRange, setInternalDateRange] = React.useState<DateRange | undefined>(() => {\n if (variant === 'range') {\n return parseInputRange(initialValueProp as InputRange)\n }\n return undefined\n })\n\n React.useEffect(() => {\n if (variant === 'single') {\n const parsedValue = parseInputDate(valueProp as InputDate)\n if (parsedValue?.getTime() !== internalSingleDate?.getTime()) {\n setInternalSingleDate(parsedValue)\n }\n } else {\n const parsedValue = parseInputRange(valueProp as InputRange)\n if (\n parsedValue?.from?.getTime() !== internalDateRange?.from?.getTime() ||\n parsedValue?.to?.getTime() !== internalDateRange?.to?.getTime()\n ) {\n setInternalDateRange(parsedValue)\n }\n }\n }, [valueProp, variant])\n\n const singleDate = internalSingleDate\n const dateRange = internalDateRange\n\n const handleSelect = React.useCallback(\n (selectedDate: Date | DateRange | undefined) => {\n if (variant === 'single') {\n const date = selectedDate as Date | undefined\n setInternalSingleDate(date)\n if (onChange) {\n const output = valueFormat === 'date' ? date : formatOutputDate(date, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n }\n if (closeOnSelect) {\n setIsOpen(false)\n }\n } else {\n const range = selectedDate as DateRange | undefined\n setInternalDateRange(range)\n if (onChange) {\n const output = valueFormat === 'date' ? range : formatOutputRange(range, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n }\n }\n },\n [variant, valueFormat, onChange, closeOnSelect],\n )\n\n const formatForDisplay = () => {\n const formatOptions = { locale: resolvedLocale }\n if (variant === 'single') {\n return singleDate ? formatFn(singleDate, displayFormat, formatOptions) : placeholder\n }\n\n if (!dateRange) return placeholder\n const fromStr = dateRange.from ? formatFn(dateRange.from, displayFormat, formatOptions) : '...'\n const toStr = dateRange.to ? formatFn(dateRange.to, displayFormat, formatOptions) : '...'\n if (!dateRange.from && !dateRange.to) return placeholder\n if (!dateRange.from) return `... - ${toStr}`\n if (!dateRange.to) return `${fromStr} - ...`\n return `${fromStr} - ${toStr}`\n }\n\n const calendarProps = React.useMemo(() => {\n const baseProps = {\n ...rest,\n locale: resolvedLocale,\n initialFocus: true,\n }\n\n if (variant === 'single') {\n return {\n ...baseProps,\n mode: 'single' as const,\n selected: singleDate,\n onSelect: (date: Date | undefined) => handleSelect(date),\n defaultMonth: singleDate ?? new Date(),\n } as PropsSingleRequired\n }\n\n return {\n ...baseProps,\n mode: 'range' as const,\n selected: dateRange,\n onSelect: (range: DateRange | undefined) => handleSelect(range),\n defaultMonth: dateRange?.from ?? new Date(),\n numberOfMonths: rest.numberOfMonths ?? 2,\n } as PropsRangeRequired\n }, [variant, rest, singleDate, dateRange, handleSelect, resolvedLocale])\n\n return (\n <PopoverRoot open={isOpen} onOpenChange={setIsOpen}>\n <PopoverTrigger asChild>\n <Button\n id={rest.id}\n variant=\"ghost\"\n className={cn(\n 'relative flex w-fit items-center justify-start text-left font-normal',\n !(variant === 'single' ? singleDate : dateRange) && 'text-muted-foreground',\n buttonVariants({ variant: 'input' }),\n buttonClassName,\n )}\n disabled={typeof rest.disabled === 'boolean' ? rest.disabled : false}\n >\n <CalendarBlank className=\"absolute left-4 h-4 w-4 shrink-0\" />\n <span className=\"w-full pl-7 text-center\">{formatForDisplay()}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"center\">\n <Calendar\n {...calendarProps}\n className=\"border-0\"\n showYearSwitcher={variant === 'single' ? showYearSwitcher : false}\n />\n </PopoverContent>\n </PopoverRoot>\n )\n}\n\nDatePicker.displayName = 'DatePicker'\n\nexport { DatePicker }\n"],"names":[],"mappings":";;;;;;;;;;;;AAyBA;AAAyD;AACvD;AACA;AACA;AACA;AACA;AACA;AAEF;AAiGA;AAA4F;AAChF;AAC2C;AACvC;AACA;AACP;AACP;AACA;AACgB;AACY;AACG;AACV;AAEvB;AACE;AAEA;AACE;AACE;AAA2B;AAE7B;AAAO;AAGT;AACE;AACE;AAAmD;AAErD;AAAO;AAGT;AACE;AACE;AAAqD;AAEvD;AAAO;AAGT;AACE;AACE;AACA;AACE;AAAiC;AACnC;AAEA;AACA;AAIE;AAAgC;AAClC;AACF;AAGF;AACA;AAEA;AAA2B;AAEvB;AACE;AACA;AACA;AACE;AACA;AAAyC;AAE3C;AACE;AAAe;AACjB;AAEA;AACA;AACA;AACE;AACA;AAAyC;AAC3C;AACF;AACF;AAC8C;AAGhD;AACE;AACA;AACE;AAAyE;AAG3E;AACA;AACA;AACA;AACA;AACA;AACA;AAA4B;AAG9B;AACE;AAAkB;AACb;AACK;AACM;AAGhB;AACE;AAAO;AACF;AACG;AACI;AAC6C;AAClB;AACvC;AAGF;AAAO;AACF;AACG;AACI;AACoD;AACpB;AACH;AACzC;AAGF;AAEI;AACE;AAAC;AAAA;AACU;AACD;AACG;AACT;AACoD;AACjB;AACnC;AACF;AAC+D;AAE/D;AAA4D;AACE;AAAA;AAAA;AAElE;AAEE;AAAC;AAAA;AACK;AACM;AACkD;AAAA;AAEhE;AAGN;AAEA;;"}
|
|
1
|
+
{"version":3,"file":"DatePicker.js","sources":["../../../src/components/DatePicker/DatePicker.tsx"],"sourcesContent":["'use client'\n\nimport { CalendarBlank } from '@phosphor-icons/react'\nimport { format as formatFn, Locale } from 'date-fns'\nimport { enUS, es, pt, enGB, de, it, fr } from 'date-fns/locale'\nimport * as React from 'react'\nimport { PropsBase, PropsRangeRequired, PropsSingleRequired } from 'react-day-picker'\n\nimport { Button, buttonVariants } from '../Button'\nimport { Calendar } from '../Calendar'\nimport { PopoverContent, PopoverRoot, PopoverTrigger } from '../Popover'\n\nimport {\n formatOutputDate,\n formatOutputRange,\n parseInputDate,\n parseInputRange,\n InputDate,\n InputRange,\n ValueFormat,\n} from '@/lib/dateUtils'\nimport { cn } from '@/lib/utils'\n\ntype SupportedLocaleString = 'enUS' | 'es' | 'pt' | 'enGB' | 'de' | 'it' | 'fr'\n\nconst localeMap: Record<SupportedLocaleString, Locale> = {\n enUS,\n es,\n pt,\n enGB,\n de,\n it,\n fr,\n}\n\nexport type DateRange = {\n from?: Date\n to?: Date\n}\n\nexport type IsoDateRange = {\n from?: string\n to?: string\n}\n\ntype DatePickerOutput<Variant extends 'single' | 'range', Format extends ValueFormat> = Variant extends 'single'\n ? Format extends 'date'\n ? Date | undefined\n : string | undefined\n : Format extends 'date'\n ? DateRange | undefined\n : IsoDateRange | undefined\n\ntype DatePickerInput<V extends 'single' | 'range'> = V extends 'single'\n ? Date | string | undefined\n : { from?: Date | string; to?: Date | string } | undefined\n\nexport type DatePickerProps<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'> = {\n /**\n * Placeholder text displayed when no date is selected\n * @default 'Pick a date' for single mode, 'Pick a date range' for range mode\n */\n readonly placeholder?: string\n\n /**\n * Format string to use when displaying the selected date in the button\n * @default 'MMM d, yyyy'\n */\n readonly displayFormat?: string\n\n /**\n * ClassName for the button\n */\n readonly buttonClassName?: string\n\n /**\n * Whether to allow the user to show the year switcher menu\n * @default true for single mode, false for range mode\n */\n readonly showYearSwitcher?: boolean\n\n /**\n * Initial value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly initialValue?: DatePickerInput<V>\n\n /**\n * Current value for the date picker\n * Accepts both Date objects and ISO strings regardless of valueFormat setting\n */\n readonly value?: DatePickerInput<V>\n\n /**\n * Determines if the picker should close after a selection\n * @default true for single mode, false for range mode\n */\n readonly closeOnSelect?: boolean\n\n /**\n * Determines the format of the value provided to the onChange callback\n * - 'iso' (default): onChange receives ISO string(s) ('yyyy-MM-dd')\n * - 'date': onChange receives JavaScript Date object(s)\n *\n * Note: The component accepts both Date objects and ISO strings for value/initialValue\n * regardless of this setting.\n * @default 'iso'\n */\n readonly valueFormat?: F\n\n /**\n * Callback when date or date range changes\n */\n readonly onChange?: (value: DatePickerOutput<V, F>) => void\n\n /**\n * DatePicker mode - single date or date range\n * @default 'single'\n */\n readonly variant?: V\n\n /**\n * The locale to use for formatting dates and determining the start of the week.\n * Can be a string identifier for supported locales ('enUS', 'es', 'pt', 'enGB', 'de', 'it', 'fr')\n * or a Locale object from date-fns/locale for other languages.\n * @default 'enUS'\n */\n readonly locale?: SupportedLocaleString | Locale\n} & Omit<PropsBase, 'mode' | 'selected' | 'onSelect' | 'locale'>\n\nfunction DatePicker<V extends 'single' | 'range' = 'single', F extends ValueFormat = 'iso'>({\n variant = 'single' as V,\n placeholder = variant === 'single' ? 'Pick a date' : 'Pick a date range',\n valueFormat = 'iso' as F,\n initialValue: initialValueProp,\n value: valueProp,\n onChange,\n buttonClassName,\n displayFormat = 'MMM d, yyyy',\n closeOnSelect = variant === 'single',\n showYearSwitcher = variant === 'single',\n locale: localeProp = 'enUS',\n ...rest\n}: DatePickerProps<V, F>) {\n const [isOpen, setIsOpen] = React.useState(false)\n\n const resolvedLocale = React.useMemo(() => {\n if (typeof localeProp === 'string') {\n return localeMap[localeProp]\n }\n return localeProp\n }, [localeProp])\n\n const [internalSingleDate, setInternalSingleDate] = React.useState<Date | undefined>(() => {\n if (variant === 'single') {\n return parseInputDate(initialValueProp as InputDate)\n }\n return undefined\n })\n\n const [internalDateRange, setInternalDateRange] = React.useState<DateRange | undefined>(() => {\n if (variant === 'range') {\n return parseInputRange(initialValueProp as InputRange)\n }\n return undefined\n })\n\n React.useEffect(() => {\n if (variant === 'single') {\n const parsedValue = parseInputDate(valueProp as InputDate)\n if (parsedValue?.getTime() !== internalSingleDate?.getTime()) {\n setInternalSingleDate(parsedValue)\n }\n } else {\n const parsedValue = parseInputRange(valueProp as InputRange)\n if (\n parsedValue?.from?.getTime() !== internalDateRange?.from?.getTime() ||\n parsedValue?.to?.getTime() !== internalDateRange?.to?.getTime()\n ) {\n setInternalDateRange(parsedValue)\n }\n }\n }, [valueProp, variant])\n\n const singleDate = internalSingleDate\n const dateRange = internalDateRange\n\n const handleSelect = React.useCallback(\n (selectedDate: Date | DateRange | undefined) => {\n if (variant === 'single') {\n const date = selectedDate as Date | undefined\n setInternalSingleDate(date)\n if (onChange) {\n const output = valueFormat === 'date' ? date : formatOutputDate(date, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n }\n if (closeOnSelect) {\n setIsOpen(false)\n }\n } else {\n const range = selectedDate as DateRange | undefined\n setInternalDateRange(range)\n if (onChange) {\n const output = valueFormat === 'date' ? range : formatOutputRange(range, 'iso')\n onChange(output as DatePickerOutput<V, F>)\n }\n }\n },\n [variant, valueFormat, onChange, closeOnSelect],\n )\n\n const formatForDisplay = () => {\n const formatOptions = { locale: resolvedLocale }\n if (variant === 'single') {\n return singleDate ? formatFn(singleDate, displayFormat, formatOptions) : placeholder\n }\n\n if (!dateRange) return placeholder\n const fromStr = dateRange.from ? formatFn(dateRange.from, displayFormat, formatOptions) : '...'\n const toStr = dateRange.to ? formatFn(dateRange.to, displayFormat, formatOptions) : '...'\n if (!dateRange.from && !dateRange.to) return placeholder\n if (!dateRange.from) return `... - ${toStr}`\n if (!dateRange.to) return `${fromStr} - ...`\n return `${fromStr} - ${toStr}`\n }\n\n const calendarProps = React.useMemo(() => {\n const baseProps = {\n ...rest,\n locale: resolvedLocale,\n initialFocus: true,\n }\n\n if (variant === 'single') {\n return {\n ...baseProps,\n mode: 'single' as const,\n selected: singleDate,\n onSelect: (date: Date | undefined) => handleSelect(date),\n } as PropsSingleRequired\n }\n\n return {\n ...baseProps,\n mode: 'range' as const,\n selected: dateRange,\n onSelect: (range: DateRange | undefined) => handleSelect(range),\n numberOfMonths: rest.numberOfMonths ?? 2,\n } as PropsRangeRequired\n }, [variant, rest, singleDate, dateRange, handleSelect, resolvedLocale])\n\n return (\n <PopoverRoot open={isOpen} onOpenChange={setIsOpen}>\n <PopoverTrigger asChild>\n <Button\n id={rest.id}\n variant=\"ghost\"\n className={cn(\n 'relative flex w-fit items-center justify-start text-left font-normal',\n !(variant === 'single' ? singleDate : dateRange) && 'text-muted-foreground',\n buttonVariants({ variant: 'input' }),\n buttonClassName,\n )}\n disabled={typeof rest.disabled === 'boolean' ? rest.disabled : false}\n >\n <CalendarBlank className=\"absolute left-4 h-4 w-4 shrink-0\" />\n <span className=\"w-full pl-7 text-center\">{formatForDisplay()}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\" align=\"center\">\n <Calendar\n {...calendarProps}\n className=\"border-0\"\n showYearSwitcher={variant === 'single' ? showYearSwitcher : false}\n />\n </PopoverContent>\n </PopoverRoot>\n )\n}\n\nDatePicker.displayName = 'DatePicker'\n\nexport { DatePicker }\n"],"names":[],"mappings":";;;;;;;;;;;;AAyBA;AAAyD;AACvD;AACA;AACA;AACA;AACA;AACA;AAEF;AAiGA;AAA4F;AAChF;AAC2C;AACvC;AACA;AACP;AACP;AACA;AACgB;AACY;AACG;AACV;AAEvB;AACE;AAEA;AACE;AACE;AAA2B;AAE7B;AAAO;AAGT;AACE;AACE;AAAmD;AAErD;AAAO;AAGT;AACE;AACE;AAAqD;AAEvD;AAAO;AAGT;AACE;AACE;AACA;AACE;AAAiC;AACnC;AAEA;AACA;AAIE;AAAgC;AAClC;AACF;AAGF;AACA;AAEA;AAA2B;AAEvB;AACE;AACA;AACA;AACE;AACA;AAAyC;AAE3C;AACE;AAAe;AACjB;AAEA;AACA;AACA;AACE;AACA;AAAyC;AAC3C;AACF;AACF;AAC8C;AAGhD;AACE;AACA;AACE;AAAyE;AAG3E;AACA;AACA;AACA;AACA;AACA;AACA;AAA4B;AAG9B;AACE;AAAkB;AACb;AACK;AACM;AAGhB;AACE;AAAO;AACF;AACG;AACI;AAC6C;AACzD;AAGF;AAAO;AACF;AACG;AACI;AACoD;AACvB;AACzC;AAGF;AAEI;AACE;AAAC;AAAA;AACU;AACD;AACG;AACT;AACoD;AACjB;AACnC;AACF;AAC+D;AAE/D;AAA4D;AACE;AAAA;AAAA;AAElE;AAEE;AAAC;AAAA;AACK;AACM;AACkD;AAAA;AAEhE;AAGN;AAEA;;"}
|