periplo-ui 4.5.0 → 4.6.0
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/Checkbox/Checkbox.d.ts +4 -4
- package/dist/components/Checkbox/Checkbox.js +3 -1
- package/dist/components/Checkbox/Checkbox.js.map +1 -1
- package/dist/components/DataTable/DataTable.d.ts +1 -1
- package/dist/components/DataTable/DataTable.js +49 -18
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/DataTable/components/DataTableBody.d.ts +12 -3
- package/dist/components/DataTable/components/DataTableBody.js +43 -8
- package/dist/components/DataTable/components/DataTableBody.js.map +1 -1
- package/dist/components/DataTable/components/DataTableGroupRow.d.ts +10 -0
- package/dist/components/DataTable/components/DataTableGroupRow.js +25 -0
- package/dist/components/DataTable/components/DataTableGroupRow.js.map +1 -0
- package/dist/components/DataTable/components/DataTableGroupRowSelector.d.ts +9 -0
- package/dist/components/DataTable/components/DataTableGroupRowSelector.js +32 -0
- package/dist/components/DataTable/components/DataTableGroupRowSelector.js.map +1 -0
- package/dist/components/DataTable/components/DataTableSelectHeader.js +16 -10
- package/dist/components/DataTable/components/DataTableSelectHeader.js.map +1 -1
- package/dist/components/DataTable/hooks/useGroupExpansion.d.ts +19 -0
- package/dist/components/DataTable/hooks/useGroupExpansion.js +34 -0
- package/dist/components/DataTable/hooks/useGroupExpansion.js.map +1 -0
- package/dist/components/DataTable/types.d.ts +27 -6
- package/dist/components/DataTable/utils.d.ts +6 -0
- package/dist/components/DataTable/utils.js +15 -0
- package/dist/components/DataTable/utils.js.map +1 -0
- package/package.json +1 -1
|
@@ -3,8 +3,8 @@ import * as React from 'react';
|
|
|
3
3
|
type CheckboxProps = {
|
|
4
4
|
/** Additional CSS classes to be applied to the checkbox */
|
|
5
5
|
className?: string;
|
|
6
|
-
/** The controlled checked state of the checkbox */
|
|
7
|
-
checked?:
|
|
6
|
+
/** The controlled checked state of the checkbox. `'indeterminate'` renders a partial (dash) state. */
|
|
7
|
+
checked?: CheckboxPrimitive.CheckedState;
|
|
8
8
|
/** The default checked state when initially rendered */
|
|
9
9
|
defaultChecked?: boolean;
|
|
10
10
|
/** Whether the checkbox is disabled */
|
|
@@ -42,8 +42,8 @@ type CheckboxProps = {
|
|
|
42
42
|
declare const Checkbox: React.ForwardRefExoticComponent<{
|
|
43
43
|
/** Additional CSS classes to be applied to the checkbox */
|
|
44
44
|
className?: string;
|
|
45
|
-
/** The controlled checked state of the checkbox */
|
|
46
|
-
checked?:
|
|
45
|
+
/** The controlled checked state of the checkbox. `'indeterminate'` renders a partial (dash) state. */
|
|
46
|
+
checked?: CheckboxPrimitive.CheckedState;
|
|
47
47
|
/** The default checked state when initially rendered */
|
|
48
48
|
defaultChecked?: boolean;
|
|
49
49
|
/** Whether the checkbox is disabled */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { Check } from '@phosphor-icons/react/dist/ssr/Check';
|
|
3
|
+
import { Minus } from '@phosphor-icons/react/dist/ssr/Minus';
|
|
3
4
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
4
5
|
import * as React from 'react';
|
|
5
6
|
import { cn } from '../../lib/utils.js';
|
|
@@ -14,11 +15,12 @@ const Checkbox = React.forwardRef(
|
|
|
14
15
|
"focus-visible:ring-2 focus-visible:ring-neutral-500 focus-visible:ring-offset-2 focus-visible:outline-none",
|
|
15
16
|
"disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-50",
|
|
16
17
|
"data-[state=checked]:border-neutral-500 data-[state=checked]:bg-neutral-500",
|
|
18
|
+
"data-[state=indeterminate]:border-neutral-500 data-[state=indeterminate]:bg-neutral-500",
|
|
17
19
|
"hover:border-neutral-500 disabled:hover:border-neutral-300 data-[state=checked]:hover:border-neutral-500",
|
|
18
20
|
className
|
|
19
21
|
),
|
|
20
22
|
...props,
|
|
21
|
-
children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: cn("absolute inset-0 flex items-center justify-center"), children: /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5 text-white" }) })
|
|
23
|
+
children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: cn("absolute inset-0 flex items-center justify-center"), children: props.checked === "indeterminate" ? /* @__PURE__ */ jsx(Minus, { className: "h-3.5 w-3.5 text-white", weight: "bold" }) : /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5 text-white" }) })
|
|
22
24
|
}
|
|
23
25
|
)
|
|
24
26
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Checkbox.js","sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import { Check } from '@phosphor-icons/react/dist/ssr/Check'\nimport * as CheckboxPrimitive from '@radix-ui/react-checkbox'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\n\ntype CheckboxProps = {\n /** Additional CSS classes to be applied to the checkbox */\n className?: string\n /** The controlled checked state of the checkbox */\n checked?:
|
|
1
|
+
{"version":3,"file":"Checkbox.js","sources":["../../../src/components/Checkbox/Checkbox.tsx"],"sourcesContent":["import { Check } from '@phosphor-icons/react/dist/ssr/Check'\nimport { Minus } from '@phosphor-icons/react/dist/ssr/Minus'\nimport * as CheckboxPrimitive from '@radix-ui/react-checkbox'\nimport * as React from 'react'\n\nimport { cn } from '@/lib/utils'\n\ntype CheckboxProps = {\n /** Additional CSS classes to be applied to the checkbox */\n className?: string\n /** The controlled checked state of the checkbox. `'indeterminate'` renders a partial (dash) state. */\n checked?: CheckboxPrimitive.CheckedState\n /** The default checked state when initially rendered */\n defaultChecked?: boolean\n /** Whether the checkbox is disabled */\n disabled?: boolean\n /** Whether the checkbox is required in a form */\n required?: boolean\n /** The name of the checkbox when used in a form */\n name?: string\n /** The value of the checkbox when used in a form */\n value?: string\n /** Handler called when the checked state changes */\n onCheckedChange?: (checked: boolean) => void\n} & React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>\n\n/**\n * A controlled checkbox component built on top of Radix UI Checkbox.\n *\n * @example\n * ```tsx\n * // Basic usage\n * <Checkbox />\n *\n * // With controlled state\n * <Checkbox checked={checked} onCheckedChange={setChecked} />\n *\n * // With form integration\n * <Checkbox name=\"terms\" required />\n *\n * // With label\n * <div className=\"flex items-center gap-2\">\n * <Checkbox id=\"terms\" />\n * <label htmlFor=\"terms\">Accept terms</label>\n * </div>\n * ```\n */\nconst Checkbox = React.forwardRef<React.ComponentRef<typeof CheckboxPrimitive.Root>, CheckboxProps>(\n ({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n 'peer relative h-5 w-5 shrink-0 rounded-[5px] border border-neutral-300 transition-colors',\n 'focus-visible:ring-2 focus-visible:ring-neutral-500 focus-visible:ring-offset-2 focus-visible:outline-none',\n 'disabled:cursor-not-allowed disabled:bg-neutral-100 disabled:opacity-50',\n 'data-[state=checked]:border-neutral-500 data-[state=checked]:bg-neutral-500',\n 'data-[state=indeterminate]:border-neutral-500 data-[state=indeterminate]:bg-neutral-500',\n 'hover:border-neutral-500 disabled:hover:border-neutral-300 data-[state=checked]:hover:border-neutral-500',\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator className={cn('absolute inset-0 flex items-center justify-center')}>\n {props.checked === 'indeterminate' ? (\n <Minus className=\"h-3.5 w-3.5 text-white\" weight=\"bold\" />\n ) : (\n <Check className=\"h-3.5 w-3.5 text-white\" />\n )}\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n ),\n)\n\nCheckbox.displayName = 'Checkbox'\n\nexport type { CheckboxProps }\nexport { Checkbox }\n"],"names":[],"mappings":";;;;;;;AA+CA,MAAM,WAAW,KAAA,CAAM,UAAA;AAAA,EACrB,CAAC,EAAE,SAAA,EAAW,GAAG,KAAA,IAAS,GAAA,qBACxB,GAAA;AAAA,IAAC,iBAAA,CAAkB,IAAA;AAAA,IAAlB;AAAA,MACC,GAAA;AAAA,MACA,SAAA,EAAW,EAAA;AAAA,QACT,0FAAA;AAAA,QACA,4GAAA;AAAA,QACA,yEAAA;AAAA,QACA,6EAAA;AAAA,QACA,yFAAA;AAAA,QACA,0GAAA;AAAA,QACA;AAAA,OACF;AAAA,MACC,GAAG,KAAA;AAAA,MAEJ,QAAA,kBAAA,GAAA,CAAC,kBAAkB,SAAA,EAAlB,EAA4B,WAAW,EAAA,CAAG,mDAAmD,CAAA,EAC3F,QAAA,EAAA,KAAA,CAAM,OAAA,KAAY,eAAA,uBAChB,KAAA,EAAA,EAAM,SAAA,EAAU,0BAAyB,MAAA,EAAO,MAAA,EAAO,oBAExD,GAAA,CAAC,KAAA,EAAA,EAAM,SAAA,EAAU,wBAAA,EAAyB,CAAA,EAE9C;AAAA;AAAA;AAGN;AAEA,QAAA,CAAS,WAAA,GAAc,UAAA;;;;"}
|
|
@@ -3,4 +3,4 @@ import { DataTableProps } from './types';
|
|
|
3
3
|
* A feature-rich data table component built on top of TanStack Table.
|
|
4
4
|
* Provides sorting, filtering, pagination, and column visibility controls.
|
|
5
5
|
*/
|
|
6
|
-
export declare function DataTable<TData extends object>({ columns: userColumns, data, getRowId, columnVisibility: columnVisibilityConfig, isLoading, pagination, primaryFilters, secondaryFilters, activePrimaryFiltersCount, activeSecondaryFiltersCount, selection, labels, emptyState, className, tableClassName, }: DataTableProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function DataTable<TData extends object>({ columns: userColumns, data, getRowId, columnVisibility: columnVisibilityConfig, isLoading, pagination, grouping, primaryFilters, secondaryFilters, activePrimaryFiltersCount, activeSecondaryFiltersCount, selection, labels, emptyState, className, tableClassName, }: DataTableProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
-
import { getPaginationRowModel, useReactTable, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
3
|
+
import { getPaginationRowModel, useReactTable, getExpandedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { Table, TableHeader, TableRow, TableHead } from '../Table/Table.js';
|
|
6
6
|
import { Typography } from '../Typography/Typography.js';
|
|
7
7
|
import { DataTableBody } from './components/DataTableBody.js';
|
|
8
|
+
import { DataTableGroupRowSelector } from './components/DataTableGroupRowSelector.js';
|
|
8
9
|
import { DataTablePagination } from './components/DataTablePagination.js';
|
|
9
10
|
import { DataTableRowSelector } from './components/DataTableRowSelector.js';
|
|
10
11
|
import { DataTableSelectHeader } from './components/DataTableSelectHeader.js';
|
|
11
12
|
import { DataTableToolbar } from './components/DataTableToolbar.js';
|
|
13
|
+
import { useGroupExpansion } from './hooks/useGroupExpansion.js';
|
|
12
14
|
import { useSelection } from './hooks/useSelection.js';
|
|
15
|
+
import { flattenLeaves } from './utils.js';
|
|
13
16
|
import { cn } from '../../lib/utils.js';
|
|
14
17
|
|
|
15
18
|
function DataTable({
|
|
@@ -19,6 +22,7 @@ function DataTable({
|
|
|
19
22
|
columnVisibility: columnVisibilityConfig,
|
|
20
23
|
isLoading = false,
|
|
21
24
|
pagination,
|
|
25
|
+
grouping,
|
|
22
26
|
primaryFilters,
|
|
23
27
|
secondaryFilters,
|
|
24
28
|
activePrimaryFiltersCount = 0,
|
|
@@ -39,12 +43,17 @@ function DataTable({
|
|
|
39
43
|
const [pageIndex, setPageIndex] = React.useState(0);
|
|
40
44
|
const columnVisibilityState = columnVisibilityConfig?.state ?? internalColumnVisibility;
|
|
41
45
|
const setColumnVisibilityState = columnVisibilityConfig?.onChange ?? setInternalColumnVisibility;
|
|
46
|
+
const { isGroupOpen, toggleGroup } = useGroupExpansion({ grouping, data, getRowId });
|
|
47
|
+
const selectionData = React.useMemo(
|
|
48
|
+
() => grouping ? flattenLeaves(data, grouping.getSubRows) : data,
|
|
49
|
+
[grouping, data]
|
|
50
|
+
);
|
|
42
51
|
const isBackendPagination = pagination !== void 0 && "onPageChange" in pagination;
|
|
43
52
|
const total = isBackendPagination ? pagination.total : data.length;
|
|
44
53
|
const pageSize = pagination?.pageSize ?? (isLoading ? 10 : data.length);
|
|
45
54
|
const totalPages = Math.ceil(total / pageSize);
|
|
46
55
|
const { selectedIds, handleRowSelect, handleSelectAll } = useSelection({
|
|
47
|
-
data,
|
|
56
|
+
data: selectionData,
|
|
48
57
|
getRowId,
|
|
49
58
|
selection
|
|
50
59
|
});
|
|
@@ -58,7 +67,7 @@ function DataTable({
|
|
|
58
67
|
{
|
|
59
68
|
isBackendPagination,
|
|
60
69
|
selectedIds,
|
|
61
|
-
data,
|
|
70
|
+
data: selectionData,
|
|
62
71
|
handleSelectAll,
|
|
63
72
|
isLoading,
|
|
64
73
|
isSelectionDisabled: selection?.isSelectionDisabled ?? false,
|
|
@@ -68,7 +77,7 @@ function DataTable({
|
|
|
68
77
|
[
|
|
69
78
|
isBackendPagination,
|
|
70
79
|
selectedIds,
|
|
71
|
-
|
|
80
|
+
selectionData,
|
|
72
81
|
handleSelectAll,
|
|
73
82
|
isLoading,
|
|
74
83
|
selection?.isSelectionDisabled,
|
|
@@ -76,18 +85,32 @@ function DataTable({
|
|
|
76
85
|
]
|
|
77
86
|
);
|
|
78
87
|
const SelectColumnCell = React.useCallback(
|
|
79
|
-
({ row }) =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
({ row }) => {
|
|
89
|
+
if (grouping && row.getCanExpand()) {
|
|
90
|
+
return /* @__PURE__ */ jsx(
|
|
91
|
+
DataTableGroupRowSelector,
|
|
92
|
+
{
|
|
93
|
+
row,
|
|
94
|
+
selectedIds,
|
|
95
|
+
getRowId,
|
|
96
|
+
handleRowSelect
|
|
97
|
+
}
|
|
98
|
+
);
|
|
88
99
|
}
|
|
89
|
-
|
|
100
|
+
return /* @__PURE__ */ jsx(
|
|
101
|
+
DataTableRowSelector,
|
|
102
|
+
{
|
|
103
|
+
row,
|
|
104
|
+
selectedIds,
|
|
105
|
+
getRowId,
|
|
106
|
+
handleRowSelect,
|
|
107
|
+
isRowSelectionDisabled: selection?.isRowSelectionDisabled,
|
|
108
|
+
rowSelectionDisabledTooltip: selection?.labels?.rowSelectionDisabledTooltip
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
},
|
|
90
112
|
[
|
|
113
|
+
grouping,
|
|
91
114
|
selectedIds,
|
|
92
115
|
getRowId,
|
|
93
116
|
handleRowSelect,
|
|
@@ -149,13 +172,16 @@ function DataTable({
|
|
|
149
172
|
columns: tableColumns,
|
|
150
173
|
getCoreRowModel: getCoreRowModel(),
|
|
151
174
|
getPaginationRowModel: tableGetPaginationRowModel,
|
|
175
|
+
getSubRows: grouping?.getSubRows,
|
|
176
|
+
getExpandedRowModel: grouping ? getExpandedRowModel() : void 0,
|
|
152
177
|
onColumnVisibilityChange: setColumnVisibilityState,
|
|
153
178
|
enableRowSelection: !!selection,
|
|
154
179
|
getRowId,
|
|
155
180
|
state: {
|
|
156
181
|
columnVisibility: columnVisibilityState,
|
|
157
182
|
rowSelection,
|
|
158
|
-
pagination: tablePaginationState
|
|
183
|
+
pagination: tablePaginationState,
|
|
184
|
+
expanded: grouping ? true : void 0
|
|
159
185
|
},
|
|
160
186
|
manualPagination: isBackendPagination,
|
|
161
187
|
onPaginationChange: isBackendPagination ? void 0 : tableOnPaginationChange
|
|
@@ -175,7 +201,7 @@ function DataTable({
|
|
|
175
201
|
}
|
|
176
202
|
),
|
|
177
203
|
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col rounded-md border bg-white", children: [
|
|
178
|
-
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx("div", { className: "h-full overflow-auto", children: /* @__PURE__ */ jsxs(Table, { className: "w-full
|
|
204
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: /* @__PURE__ */ jsx("div", { className: "h-full scrollbar-gutter-stable overflow-auto overscroll-x-none overscroll-y-auto", children: /* @__PURE__ */ jsxs(Table, { className: "w-full", tableClassName: cn("min-w-max", tableClassName), children: [
|
|
179
205
|
/* @__PURE__ */ jsx(TableHeader, { className: "sticky top-0 z-10 bg-neutral-50", children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(TableHead, { style: { width: header.column.columnDef.size }, children: /* @__PURE__ */ jsx(Typography, { weight: "medium", className: "whitespace-nowrap", children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) }) }, header.id)) }, headerGroup.id)) }),
|
|
180
206
|
/* @__PURE__ */ jsx(
|
|
181
207
|
DataTableBody,
|
|
@@ -185,8 +211,13 @@ function DataTable({
|
|
|
185
211
|
pageSize,
|
|
186
212
|
getRowId,
|
|
187
213
|
rowSelection,
|
|
188
|
-
|
|
189
|
-
|
|
214
|
+
emptyState,
|
|
215
|
+
group: grouping ? {
|
|
216
|
+
renderGroupRow: grouping.renderGroupRow,
|
|
217
|
+
renderGroupSelector: selection ? SelectColumnCell : void 0,
|
|
218
|
+
isOpen: (row) => isGroupOpen(getRowId(row.original)),
|
|
219
|
+
onToggle: (row) => toggleGroup(getRowId(row.original))
|
|
220
|
+
} : void 0
|
|
190
221
|
}
|
|
191
222
|
)
|
|
192
223
|
] }) }) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTable.js","sources":["../../../src/components/DataTable/DataTable.tsx"],"sourcesContent":["'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 columnVisibility: columnVisibilityConfig,\n isLoading = false,\n pagination,\n primaryFilters,\n secondaryFilters,\n activePrimaryFiltersCount = 0,\n activeSecondaryFiltersCount = 0,\n selection,\n labels = {\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 [internalColumnVisibility, setInternalColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = React.useState(0)\n\n const columnVisibilityState = columnVisibilityConfig?.state ?? internalColumnVisibility\n const setColumnVisibilityState = columnVisibilityConfig?.onChange ?? setInternalColumnVisibility\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: setColumnVisibilityState,\n enableRowSelection: !!selection,\n getRowId: getRowId,\n state: {\n columnVisibility: columnVisibilityState,\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 columnVisibility={columnVisibilityConfig}\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 key={header.id} style={{ width: header.column.columnDef.size }}>\n <Typography weight=\"medium\" className=\"whitespace-nowrap\">\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":";;;;;;;;;;;;;;AA+BO;AAAyC;AACrC;AACT;AACmD;AACjC;AACN;AACZ;AACA;AACA;AAC4B;AACE;AAC9B;AACS;AACE;AACI;AACf;AACa;AACJ;AACM;AACf;AACA;AAEF;AACE;AACA;AAEA;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;AACa;AAClB;AACY;AACd;AACkB;AACoC;AAGxD;AAEI;AAAA;AAAC;AAAA;AACC;AACkB;AAClB;AACA;AACA;AACA;AACA;AACW;AAAA;AACb;AAGE;AAGM;AAcA;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":["'use client'\n\nimport {\n flexRender,\n getCoreRowModel,\n getExpandedRowModel,\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 { DataTableGroupRowSelector } from './components/DataTableGroupRowSelector'\nimport { DataTablePagination } from './components/DataTablePagination'\nimport { DataTableRowSelector } from './components/DataTableRowSelector'\nimport { DataTableSelectHeader } from './components/DataTableSelectHeader'\nimport { DataTableToolbar } from './components/DataTableToolbar'\nimport { useGroupExpansion } from './hooks/useGroupExpansion'\nimport { useSelection } from './hooks/useSelection'\nimport { DataTableProps } from './types'\nimport { flattenLeaves } from './utils'\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 columnVisibility: columnVisibilityConfig,\n isLoading = false,\n pagination,\n grouping,\n primaryFilters,\n secondaryFilters,\n activePrimaryFiltersCount = 0,\n activeSecondaryFiltersCount = 0,\n selection,\n labels = {\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 [internalColumnVisibility, setInternalColumnVisibility] = React.useState<VisibilityState>({})\n const [pageIndex, setPageIndex] = React.useState(0)\n\n const columnVisibilityState = columnVisibilityConfig?.state ?? internalColumnVisibility\n const setColumnVisibilityState = columnVisibilityConfig?.onChange ?? setInternalColumnVisibility\n\n const { isGroupOpen, toggleGroup } = useGroupExpansion({ grouping, data, getRowId })\n\n const selectionData = React.useMemo(\n () => (grouping ? flattenLeaves(data, grouping.getSubRows) : data),\n [grouping, data],\n )\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: selectionData,\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={selectionData}\n handleSelectAll={handleSelectAll}\n isLoading={isLoading}\n isSelectionDisabled={selection?.isSelectionDisabled ?? false}\n selectionDisabledTooltip={selection?.labels?.selectionDisabledTooltip}\n />\n ),\n [\n isBackendPagination,\n selectedIds,\n selectionData,\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 if (grouping && row.getCanExpand()) {\n return (\n <DataTableGroupRowSelector\n row={row}\n selectedIds={selectedIds}\n getRowId={getRowId}\n handleRowSelect={handleRowSelect}\n />\n )\n }\n return (\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 [\n grouping,\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 getSubRows: grouping?.getSubRows,\n getExpandedRowModel: grouping ? getExpandedRowModel() : undefined,\n onColumnVisibilityChange: setColumnVisibilityState,\n enableRowSelection: !!selection,\n getRowId: getRowId,\n state: {\n columnVisibility: columnVisibilityState,\n rowSelection,\n pagination: tablePaginationState,\n expanded: grouping ? true : undefined,\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 columnVisibility={columnVisibilityConfig}\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 scrollbar-gutter-stable overflow-auto overscroll-x-none overscroll-y-auto\">\n <TableComponent className=\"w-full\" tableClassName={cn('min-w-max', 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 key={header.id} style={{ width: header.column.columnDef.size }}>\n <Typography weight=\"medium\" className=\"whitespace-nowrap\">\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 emptyState={emptyState}\n group={\n grouping\n ? {\n renderGroupRow: grouping.renderGroupRow,\n renderGroupSelector: selection ? SelectColumnCell : undefined,\n isOpen: (row: Row<TData>) => isGroupOpen(getRowId(row.original)),\n onToggle: (row: Row<TData>) => toggleGroup(getRowId(row.original)),\n }\n : undefined\n }\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":";;;;;;;;;;;;;;;;;AAmCO;AAAyC;AACrC;AACT;AACmD;AACjC;AACN;AACZ;AACA;AACA;AACA;AAC4B;AACE;AAC9B;AACS;AACE;AACI;AACf;AACa;AACJ;AACM;AACf;AACA;AAEF;AACE;AACA;AAEA;AACA;AAEA;AAEA;AAA4B;AACmC;AAC9C;AAGjB;AAEA;AACA;AACA;AAEA;AAAuE;AAC/D;AACN;AACA;AAGF;AAA2B;AAC+C;AAC5D;AAGd;AAAiC;AAE7B;AAAC;AAAA;AACC;AACA;AACM;AACN;AACA;AACuD;AACV;AAAA;AAC/C;AAEF;AACE;AACA;AACA;AACA;AACA;AACW;AACQ;AACrB;AAGF;AAA+B;AAE3B;AACE;AACE;AAAC;AAAA;AACC;AACA;AACA;AACA;AAAA;AACF;AAGJ;AACE;AAAC;AAAA;AACC;AACA;AACA;AACA;AACmC;AACa;AAAA;AAClD;AAEJ;AACA;AACE;AACA;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;AACD;AACkC;AAC9B;AACJ;AACtB;AACO;AACa;AAClB;AACY;AACgB;AAC9B;AACkB;AACoC;AAGxD;AAEI;AAAA;AAAC;AAAA;AACC;AACkB;AAClB;AACA;AACA;AACA;AACA;AACW;AAAA;AACb;AAGE;AAGM;AAcA;AACA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AAGM;AAC2B;AAC2B;AACW;AACE;AAEnE;AAAA;AAER;AAGN;AAGI;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACc;AACQ;AACH;AAAA;AAEvB;AAEJ;AAGN;;"}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import { Table } from '@tanstack/react-table';
|
|
1
|
+
import { Table, Row } from '@tanstack/react-table';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
import { RowIdentifierFn } from '../types';
|
|
4
|
+
type GroupRenderConfig<TData> = {
|
|
5
|
+
readonly renderGroupRow?: (row: Row<TData>) => ReactNode;
|
|
6
|
+
readonly renderGroupSelector?: React.ComponentType<{
|
|
7
|
+
row: Row<TData>;
|
|
8
|
+
}>;
|
|
9
|
+
readonly isOpen: (row: Row<TData>) => boolean;
|
|
10
|
+
readonly onToggle: (row: Row<TData>) => void;
|
|
11
|
+
};
|
|
3
12
|
type DataTableBodyProps<TData> = {
|
|
4
13
|
readonly table: Table<TData>;
|
|
5
14
|
readonly isLoading?: boolean;
|
|
6
15
|
readonly pageSize: number;
|
|
7
16
|
readonly getRowId: RowIdentifierFn<TData>;
|
|
8
17
|
readonly rowSelection: Record<string, boolean>;
|
|
9
|
-
readonly isSelectionStarted: boolean;
|
|
10
18
|
readonly emptyState: {
|
|
11
19
|
title: string;
|
|
12
20
|
description: string;
|
|
@@ -14,6 +22,7 @@ type DataTableBodyProps<TData> = {
|
|
|
14
22
|
imageAlt?: string;
|
|
15
23
|
imageClassName?: string;
|
|
16
24
|
};
|
|
25
|
+
readonly group?: GroupRenderConfig<TData>;
|
|
17
26
|
};
|
|
18
|
-
export declare function DataTableBody<TData>({ table, isLoading, pageSize, getRowId, rowSelection,
|
|
27
|
+
export declare function DataTableBody<TData>({ table, isLoading, pageSize, getRowId, rowSelection, emptyState, group, }: DataTableBodyProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
19
28
|
export {};
|
|
@@ -3,13 +3,23 @@ import { flexRender } from '@tanstack/react-table';
|
|
|
3
3
|
import { Skeleton } from '../../Skeleton/Skeleton.js';
|
|
4
4
|
import { TableBody, TableRow, TableCell } from '../../Table/Table.js';
|
|
5
5
|
import { Typography } from '../../Typography/Typography.js';
|
|
6
|
+
import { DataTableGroupRow } from './DataTableGroupRow.js';
|
|
6
7
|
import { cn } from '../../../lib/utils.js';
|
|
7
8
|
|
|
8
|
-
function TableRowComponent({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
return /* @__PURE__ */ jsx(TableRow, { "data-selected": isSelected, children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { style: { width: cell.column.columnDef.size }, children: /* @__PURE__ */ jsx(
|
|
9
|
+
function TableRowComponent({ row, isSelected, isCollapsible = false, isOpen = true }) {
|
|
10
|
+
if (!isCollapsible) {
|
|
11
|
+
return /* @__PURE__ */ jsx(TableRow, { "data-selected": isSelected, children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { style: { width: cell.column.columnDef.size }, children: /* @__PURE__ */ jsx(Typography, { className: "whitespace-nowrap", children: cell.column.columnDef.cell && flexRender(cell.column.columnDef.cell, cell.getContext()) }) }, cell.id)) });
|
|
12
|
+
}
|
|
13
|
+
return /* @__PURE__ */ jsx(TableRow, { "data-selected": isSelected, className: cn("transition-colors", !isOpen && "border-b-0"), children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { style: { width: cell.column.columnDef.size }, className: "p-0", children: /* @__PURE__ */ jsx(
|
|
14
|
+
"div",
|
|
15
|
+
{
|
|
16
|
+
className: cn(
|
|
17
|
+
"grid transition-[grid-template-rows] duration-200 ease-in-out",
|
|
18
|
+
isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
|
|
19
|
+
),
|
|
20
|
+
children: /* @__PURE__ */ jsx("div", { className: "min-w-max overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "px-4 py-4", children: /* @__PURE__ */ jsx(Typography, { className: "whitespace-nowrap", children: cell.column.columnDef.cell && flexRender(cell.column.columnDef.cell, cell.getContext()) }) }) })
|
|
21
|
+
}
|
|
22
|
+
) }, cell.id)) });
|
|
13
23
|
}
|
|
14
24
|
function DataTableBody({
|
|
15
25
|
table,
|
|
@@ -17,8 +27,8 @@ function DataTableBody({
|
|
|
17
27
|
pageSize,
|
|
18
28
|
getRowId,
|
|
19
29
|
rowSelection,
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
emptyState,
|
|
31
|
+
group
|
|
22
32
|
}) {
|
|
23
33
|
if (isLoading) {
|
|
24
34
|
return /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: pageSize }).map((_unused, index) => /* @__PURE__ */ jsx(TableRow, { children: table.getAllColumns().filter((column) => column.getIsVisible()).map((column) => {
|
|
@@ -54,10 +64,35 @@ function DataTableBody({
|
|
|
54
64
|
/* @__PURE__ */ jsx(Typography, { variant: "title-sm", className: "text-center opacity-80", children: emptyState.description })
|
|
55
65
|
] }) }) }) });
|
|
56
66
|
}
|
|
67
|
+
const visibleColumnCount = table.getVisibleLeafColumns().length;
|
|
57
68
|
return /* @__PURE__ */ jsx(TableBody, { children: rows.map((row) => {
|
|
58
69
|
const rowId = getRowId(row.original);
|
|
70
|
+
if (group && row.getCanExpand()) {
|
|
71
|
+
const content = group.renderGroupRow?.(row) ?? `${String(row.getLeafRows().length)} items`;
|
|
72
|
+
return /* @__PURE__ */ jsx(
|
|
73
|
+
DataTableGroupRow,
|
|
74
|
+
{
|
|
75
|
+
colSpan: visibleColumnCount,
|
|
76
|
+
selector: group.renderGroupSelector ? /* @__PURE__ */ jsx(group.renderGroupSelector, { row }) : void 0,
|
|
77
|
+
content,
|
|
78
|
+
isOpen: group.isOpen(row),
|
|
79
|
+
onToggle: () => group.onToggle(row)
|
|
80
|
+
},
|
|
81
|
+
rowId
|
|
82
|
+
);
|
|
83
|
+
}
|
|
59
84
|
const isSelected = rowSelection[rowId] ?? false;
|
|
60
|
-
|
|
85
|
+
const parentRow = group ? row.getParentRow() : void 0;
|
|
86
|
+
return /* @__PURE__ */ jsx(
|
|
87
|
+
TableRowComponent,
|
|
88
|
+
{
|
|
89
|
+
row,
|
|
90
|
+
isSelected,
|
|
91
|
+
isCollapsible: !!group,
|
|
92
|
+
isOpen: parentRow ? group?.isOpen(parentRow) ?? true : true
|
|
93
|
+
},
|
|
94
|
+
rowId
|
|
95
|
+
);
|
|
61
96
|
}) });
|
|
62
97
|
}
|
|
63
98
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DataTableBody.js","sources":["../../../../src/components/DataTable/components/DataTableBody.tsx"],"sourcesContent":["import { Table, flexRender, Row } from '@tanstack/react-table'\n\nimport { Skeleton } from '../../Skeleton'\nimport { TableBody, TableCell, TableRow } from '../../Table'\nimport { Typography } from '../../Typography'\nimport { RowIdentifierFn } from '../types'\n\nimport { cn } from '@/lib/utils'\n\ntype DataTableBodyProps<TData> = {\n readonly table: Table<TData>\n readonly isLoading?: boolean\n readonly pageSize: number\n readonly getRowId: RowIdentifierFn<TData>\n readonly rowSelection: Record<string, boolean>\n readonly isSelectionStarted: boolean\n readonly emptyState: {\n title: string\n description: string\n imageRoute?: string\n imageAlt?: string\n imageClassName?: string\n }\n}\n\ntype TableRowProps<TData> = {\n readonly row: Row<TData>\n readonly isSelectable: boolean\n readonly isSelected: boolean\n readonly isSelectionStarted: boolean\n readonly getRowId: (row: TData) => string\n readonly handleRowSelect: (checked: boolean, row: TData) => void\n}\n\nfunction TableRowComponent<TData>({\n row,\n isSelected,\n}: Readonly<Omit<TableRowProps<TData>, 'isSelectable' | 'getRowId' | 'handleRowSelect'>>) {\n return (\n <TableRow data-selected={isSelected}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id} style={{ width: cell.column.columnDef.size }}>\n <Typography>\n {cell.column.columnDef.cell && flexRender(cell.column.columnDef.cell, cell.getContext())}\n </Typography>\n </TableCell>\n ))}\n </TableRow>\n )\n}\n\nexport function DataTableBody<TData>({\n table,\n isLoading,\n pageSize,\n getRowId,\n rowSelection,\n isSelectionStarted,\n emptyState,\n}: DataTableBodyProps<TData>) {\n if (isLoading) {\n return (\n <TableBody>\n {Array.from({ length: pageSize }).map((_unused, index) => (\n <TableRow key={`skeleton-row-${String(index)}`}>\n {table\n .getAllColumns()\n .filter((column) => column.getIsVisible())\n .map((column) => {\n let skeletonClass = 'h-[20px] w-full'\n if (column.id === 'actions') skeletonClass = 'h-8 w-8 shrink-0'\n else if (column.id === 'select') skeletonClass = 'h-5 w-5 shrink-0'\n\n let justifyClass = 'justify-center'\n if (column.id === 'actions') justifyClass = 'justify-end'\n else if (column.id === 'select') justifyClass = 'justify-start'\n\n return (\n <TableCell\n key={`skeleton-cell-${String(index)}-${column.id}`}\n style={{ width: column.columnDef.size }}\n >\n <div className={cn('flex items-center', justifyClass)}>\n <Skeleton className={cn(skeletonClass)} />\n </div>\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n )\n }\n\n const rows = table.getRowModel().rows\n\n if (!rows.length) {\n const visibleColumns = table.getAllColumns().filter((col) => col.getIsVisible())\n\n return (\n <TableBody>\n <TableRow className=\"h-full\">\n <TableCell colSpan={visibleColumns.length} className=\"h-full p-0\">\n <div className=\"mt-20 flex h-full w-full flex-col items-center justify-center\">\n {emptyState.imageRoute && (\n <img\n className={cn('mb-6 w-[200px] md:w-[300px]', emptyState.imageClassName)}\n src={emptyState.imageRoute}\n alt={emptyState.imageAlt ?? 'No data available'}\n />\n )}\n <Typography variant=\"title-md\" weight=\"semibold\" className=\"text-center\">\n {emptyState.title}\n </Typography>\n <Typography variant=\"title-sm\" className=\"text-center opacity-80\">\n {emptyState.description}\n </Typography>\n </div>\n </TableCell>\n </TableRow>\n </TableBody>\n )\n }\n\n return (\n <TableBody>\n {rows.map((row) => {\n const rowId = getRowId(row.original)\n const isSelected = rowSelection[rowId] ?? false\n return (\n <TableRowComponent key={rowId} row={row} isSelected={isSelected} isSelectionStarted={isSelectionStarted} />\n )\n })}\n </TableBody>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DataTableBody.js","sources":["../../../../src/components/DataTable/components/DataTableBody.tsx"],"sourcesContent":["import { Table, flexRender, Row } from '@tanstack/react-table'\nimport { ReactNode } from 'react'\n\nimport { Skeleton } from '../../Skeleton'\nimport { TableBody, TableCell, TableRow } from '../../Table'\nimport { Typography } from '../../Typography'\nimport { RowIdentifierFn } from '../types'\n\nimport { DataTableGroupRow } from './DataTableGroupRow'\n\nimport { cn } from '@/lib/utils'\n\ntype GroupRenderConfig<TData> = {\n readonly renderGroupRow?: (row: Row<TData>) => ReactNode\n readonly renderGroupSelector?: React.ComponentType<{ row: Row<TData> }>\n readonly isOpen: (row: Row<TData>) => boolean\n readonly onToggle: (row: Row<TData>) => void\n}\n\ntype DataTableBodyProps<TData> = {\n readonly table: Table<TData>\n readonly isLoading?: boolean\n readonly pageSize: number\n readonly getRowId: RowIdentifierFn<TData>\n readonly rowSelection: Record<string, boolean>\n readonly emptyState: {\n title: string\n description: string\n imageRoute?: string\n imageAlt?: string\n imageClassName?: string\n }\n readonly group?: GroupRenderConfig<TData>\n}\n\ntype TableRowProps<TData> = {\n readonly row: Row<TData>\n readonly isSelected: boolean\n readonly isCollapsible?: boolean\n readonly isOpen?: boolean\n}\n\nfunction TableRowComponent<TData>({ row, isSelected, isCollapsible = false, isOpen = true }: TableRowProps<TData>) {\n if (!isCollapsible) {\n return (\n <TableRow data-selected={isSelected}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id} style={{ width: cell.column.columnDef.size }}>\n <Typography className=\"whitespace-nowrap\">\n {cell.column.columnDef.cell && flexRender(cell.column.columnDef.cell, cell.getContext())}\n </Typography>\n </TableCell>\n ))}\n </TableRow>\n )\n }\n\n return (\n <TableRow data-selected={isSelected} className={cn('transition-colors', !isOpen && 'border-b-0')}>\n {row.getVisibleCells().map((cell) => (\n <TableCell key={cell.id} style={{ width: cell.column.columnDef.size }} className=\"p-0\">\n <div\n className={cn(\n 'grid transition-[grid-template-rows] duration-200 ease-in-out',\n isOpen ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',\n )}\n >\n <div className=\"min-w-max overflow-hidden\">\n <div className=\"px-4 py-4\">\n <Typography className=\"whitespace-nowrap\">\n {cell.column.columnDef.cell && flexRender(cell.column.columnDef.cell, cell.getContext())}\n </Typography>\n </div>\n </div>\n </div>\n </TableCell>\n ))}\n </TableRow>\n )\n}\n\nexport function DataTableBody<TData>({\n table,\n isLoading,\n pageSize,\n getRowId,\n rowSelection,\n emptyState,\n group,\n}: DataTableBodyProps<TData>) {\n if (isLoading) {\n return (\n <TableBody>\n {Array.from({ length: pageSize }).map((_unused, index) => (\n <TableRow key={`skeleton-row-${String(index)}`}>\n {table\n .getAllColumns()\n .filter((column) => column.getIsVisible())\n .map((column) => {\n let skeletonClass = 'h-[20px] w-full'\n if (column.id === 'actions') skeletonClass = 'h-8 w-8 shrink-0'\n else if (column.id === 'select') skeletonClass = 'h-5 w-5 shrink-0'\n\n let justifyClass = 'justify-center'\n if (column.id === 'actions') justifyClass = 'justify-end'\n else if (column.id === 'select') justifyClass = 'justify-start'\n\n return (\n <TableCell\n key={`skeleton-cell-${String(index)}-${column.id}`}\n style={{ width: column.columnDef.size }}\n >\n <div className={cn('flex items-center', justifyClass)}>\n <Skeleton className={cn(skeletonClass)} />\n </div>\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n )\n }\n\n const rows = table.getRowModel().rows\n\n if (!rows.length) {\n const visibleColumns = table.getAllColumns().filter((col) => col.getIsVisible())\n\n return (\n <TableBody>\n <TableRow className=\"h-full\">\n <TableCell colSpan={visibleColumns.length} className=\"h-full p-0\">\n <div className=\"mt-20 flex h-full w-full flex-col items-center justify-center\">\n {emptyState.imageRoute && (\n <img\n className={cn('mb-6 w-[200px] md:w-[300px]', emptyState.imageClassName)}\n src={emptyState.imageRoute}\n alt={emptyState.imageAlt ?? 'No data available'}\n />\n )}\n <Typography variant=\"title-md\" weight=\"semibold\" className=\"text-center\">\n {emptyState.title}\n </Typography>\n <Typography variant=\"title-sm\" className=\"text-center opacity-80\">\n {emptyState.description}\n </Typography>\n </div>\n </TableCell>\n </TableRow>\n </TableBody>\n )\n }\n\n const visibleColumnCount = table.getVisibleLeafColumns().length\n\n return (\n <TableBody>\n {rows.map((row) => {\n const rowId = getRowId(row.original)\n\n if (group && row.getCanExpand()) {\n const content = group.renderGroupRow?.(row) ?? `${String(row.getLeafRows().length)} items`\n return (\n <DataTableGroupRow\n key={rowId}\n colSpan={visibleColumnCount}\n selector={group.renderGroupSelector ? <group.renderGroupSelector row={row} /> : undefined}\n content={content}\n isOpen={group.isOpen(row)}\n onToggle={() => group.onToggle(row)}\n />\n )\n }\n\n const isSelected = rowSelection[rowId] ?? false\n const parentRow = group ? row.getParentRow() : undefined\n return (\n <TableRowComponent\n key={rowId}\n row={row}\n isSelected={isSelected}\n isCollapsible={!!group}\n isOpen={parentRow ? (group?.isOpen(parentRow) ?? true) : true}\n />\n )\n })}\n </TableBody>\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
type DataTableGroupRowProps = {
|
|
3
|
+
readonly colSpan: number;
|
|
4
|
+
readonly selector?: ReactNode;
|
|
5
|
+
readonly content: ReactNode;
|
|
6
|
+
readonly isOpen: boolean;
|
|
7
|
+
readonly onToggle: () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function DataTableGroupRow({ colSpan, selector, content, isOpen, onToggle }: DataTableGroupRowProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { CaretRight } from '@phosphor-icons/react/dist/ssr/CaretRight';
|
|
3
|
+
import { TableRow, TableCell } from '../../Table/Table.js';
|
|
4
|
+
import { Typography } from '../../Typography/Typography.js';
|
|
5
|
+
import { cn } from '../../../lib/utils.js';
|
|
6
|
+
|
|
7
|
+
function DataTableGroupRow({ colSpan, selector, content, isOpen, onToggle }) {
|
|
8
|
+
return /* @__PURE__ */ jsx(TableRow, { onClick: onToggle, "aria-expanded": isOpen, className: "cursor-pointer bg-white hover:bg-neutral-50", children: /* @__PURE__ */ jsx(TableCell, { colSpan, className: "p-0", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
9
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [
|
|
10
|
+
selector,
|
|
11
|
+
/* @__PURE__ */ jsx(Typography, { weight: "medium", children: content })
|
|
12
|
+
] }),
|
|
13
|
+
/* @__PURE__ */ jsx("div", { className: "sticky right-0 flex items-center bg-inherit px-4 py-4", children: /* @__PURE__ */ jsx(
|
|
14
|
+
CaretRight,
|
|
15
|
+
{
|
|
16
|
+
size: 16,
|
|
17
|
+
weight: "bold",
|
|
18
|
+
className: cn("shrink-0 transition-transform", isOpen && "rotate-90")
|
|
19
|
+
}
|
|
20
|
+
) })
|
|
21
|
+
] }) }) });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { DataTableGroupRow };
|
|
25
|
+
//# sourceMappingURL=DataTableGroupRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTableGroupRow.js","sources":["../../../../src/components/DataTable/components/DataTableGroupRow.tsx"],"sourcesContent":["import { CaretRight } from '@phosphor-icons/react/dist/ssr/CaretRight'\nimport { ReactNode } from 'react'\n\nimport { TableCell, TableRow } from '../../Table'\nimport { Typography } from '../../Typography'\n\nimport { cn } from '@/lib/utils'\n\ntype DataTableGroupRowProps = {\n readonly colSpan: number\n readonly selector?: ReactNode\n readonly content: ReactNode\n readonly isOpen: boolean\n readonly onToggle: () => void\n}\n\nexport function DataTableGroupRow({ colSpan, selector, content, isOpen, onToggle }: DataTableGroupRowProps) {\n return (\n <TableRow onClick={onToggle} aria-expanded={isOpen} className=\"cursor-pointer bg-white hover:bg-neutral-50\">\n <TableCell colSpan={colSpan} className=\"p-0\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3 px-4 py-4\">\n {selector}\n <Typography weight=\"medium\">{content}</Typography>\n </div>\n <div className=\"sticky right-0 flex items-center bg-inherit px-4 py-4\">\n <CaretRight\n size={16}\n weight=\"bold\"\n className={cn('shrink-0 transition-transform', isOpen && 'rotate-90')}\n />\n </div>\n </div>\n </TableCell>\n </TableRow>\n )\n}\n"],"names":[],"mappings":";;;;;;AAgBO,SAAS,kBAAkB,EAAE,OAAA,EAAS,UAAU,OAAA,EAAS,MAAA,EAAQ,UAAS,EAA2B;AAC1G,EAAA,2BACG,QAAA,EAAA,EAAS,OAAA,EAAS,QAAA,EAAU,eAAA,EAAe,QAAQ,SAAA,EAAU,6CAAA,EAC5D,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,SAAkB,SAAA,EAAU,KAAA,EACrC,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,mCAAA,EACb,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,mCAAA,EACZ,QAAA,EAAA;AAAA,MAAA,QAAA;AAAA,sBACD,GAAA,CAAC,UAAA,EAAA,EAAW,MAAA,EAAO,QAAA,EAAU,QAAA,EAAA,OAAA,EAAQ;AAAA,KAAA,EACvC,CAAA;AAAA,oBACA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uDAAA,EACb,QAAA,kBAAA,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,EAAA;AAAA,QACN,MAAA,EAAO,MAAA;AAAA,QACP,SAAA,EAAW,EAAA,CAAG,+BAAA,EAAiC,MAAA,IAAU,WAAW;AAAA;AAAA,KACtE,EACF;AAAA,GAAA,EACF,GACF,CAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Row } from '@tanstack/react-table';
|
|
2
|
+
type DataTableGroupRowSelectorProps<TData extends object> = {
|
|
3
|
+
readonly row: Row<TData>;
|
|
4
|
+
readonly selectedIds: Set<string>;
|
|
5
|
+
readonly getRowId: (original: TData) => string;
|
|
6
|
+
readonly handleRowSelect: (rowId: string, checked: boolean) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare function DataTableGroupRowSelector<TData extends object>({ row, selectedIds, getRowId, handleRowSelect, }: DataTableGroupRowSelectorProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Checkbox } from '../../Checkbox/Checkbox.js';
|
|
3
|
+
|
|
4
|
+
function DataTableGroupRowSelector({
|
|
5
|
+
row,
|
|
6
|
+
selectedIds,
|
|
7
|
+
getRowId,
|
|
8
|
+
handleRowSelect
|
|
9
|
+
}) {
|
|
10
|
+
const leafRows = row.getLeafRows();
|
|
11
|
+
const leafIds = leafRows.map((leaf) => getRowId(leaf.original));
|
|
12
|
+
const selectedCount = leafIds.filter((id) => selectedIds.has(id)).length;
|
|
13
|
+
const allSelected = leafIds.length > 0 && selectedCount === leafIds.length;
|
|
14
|
+
const someSelected = selectedCount > 0 && !allSelected;
|
|
15
|
+
const handleToggle = (checked) => {
|
|
16
|
+
leafIds.forEach((id) => handleRowSelect(id, checked));
|
|
17
|
+
};
|
|
18
|
+
return /* @__PURE__ */ jsx(
|
|
19
|
+
Checkbox,
|
|
20
|
+
{
|
|
21
|
+
checked: someSelected ? "indeterminate" : allSelected,
|
|
22
|
+
onCheckedChange: (checked) => handleToggle(!!checked),
|
|
23
|
+
onClick: (event) => event.stopPropagation(),
|
|
24
|
+
className: "cursor-default",
|
|
25
|
+
disabled: leafIds.length === 0,
|
|
26
|
+
"aria-label": "Select group"
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { DataTableGroupRowSelector };
|
|
32
|
+
//# sourceMappingURL=DataTableGroupRowSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DataTableGroupRowSelector.js","sources":["../../../../src/components/DataTable/components/DataTableGroupRowSelector.tsx"],"sourcesContent":["import { Row } from '@tanstack/react-table'\n\nimport { Checkbox } from '@/components/Checkbox'\n\ntype DataTableGroupRowSelectorProps<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 DataTableGroupRowSelector<TData extends object>({\n row,\n selectedIds,\n getRowId,\n handleRowSelect,\n}: DataTableGroupRowSelectorProps<TData>) {\n const leafRows = row.getLeafRows()\n const leafIds = leafRows.map((leaf) => getRowId(leaf.original))\n const selectedCount = leafIds.filter((id) => selectedIds.has(id)).length\n\n const allSelected = leafIds.length > 0 && selectedCount === leafIds.length\n const someSelected = selectedCount > 0 && !allSelected\n\n const handleToggle = (checked: boolean) => {\n leafIds.forEach((id) => handleRowSelect(id, checked))\n }\n\n return (\n <Checkbox\n checked={someSelected ? 'indeterminate' : allSelected}\n onCheckedChange={(checked) => handleToggle(!!checked)}\n onClick={(event) => event.stopPropagation()}\n className=\"cursor-default\"\n disabled={leafIds.length === 0}\n aria-label=\"Select group\"\n />\n )\n}\n"],"names":[],"mappings":";;;AAWO,SAAS,yBAAA,CAAgD;AAAA,EAC9D,GAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAA0C;AACxC,EAAA,MAAM,QAAA,GAAW,IAAI,WAAA,EAAY;AACjC,EAAA,MAAM,OAAA,GAAU,SAAS,GAAA,CAAI,CAAC,SAAS,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAC,CAAA;AAC9D,EAAA,MAAM,aAAA,GAAgB,QAAQ,MAAA,CAAO,CAAC,OAAO,WAAA,CAAY,GAAA,CAAI,EAAE,CAAC,CAAA,CAAE,MAAA;AAElE,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,MAAA,GAAS,CAAA,IAAK,kBAAkB,OAAA,CAAQ,MAAA;AACpE,EAAA,MAAM,YAAA,GAAe,aAAA,GAAgB,CAAA,IAAK,CAAC,WAAA;AAE3C,EAAA,MAAM,YAAA,GAAe,CAAC,OAAA,KAAqB;AACzC,IAAA,OAAA,CAAQ,QAAQ,CAAC,EAAA,KAAO,eAAA,CAAgB,EAAA,EAAI,OAAO,CAAC,CAAA;AAAA,EACtD,CAAA;AAEA,EAAA,uBACE,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAS,eAAe,eAAA,GAAkB,WAAA;AAAA,MAC1C,iBAAiB,CAAC,OAAA,KAAY,YAAA,CAAa,CAAC,CAAC,OAAO,CAAA;AAAA,MACpD,OAAA,EAAS,CAAC,KAAA,KAAU,KAAA,CAAM,eAAA,EAAgB;AAAA,MAC1C,SAAA,EAAU,gBAAA;AAAA,MACV,QAAA,EAAU,QAAQ,MAAA,KAAW,CAAA;AAAA,MAC7B,YAAA,EAAW;AAAA;AAAA,GACb;AAEJ;;;;"}
|
|
@@ -14,17 +14,23 @@ function DataTableSelectHeader({
|
|
|
14
14
|
if (isBackendPagination) {
|
|
15
15
|
return null;
|
|
16
16
|
}
|
|
17
|
+
const allSelected = data.length > 0 && selectedIds.size === data.length;
|
|
18
|
+
const someSelected = selectedIds.size > 0 && !allSelected;
|
|
19
|
+
const checkbox = /* @__PURE__ */ jsx(
|
|
20
|
+
Checkbox,
|
|
21
|
+
{
|
|
22
|
+
checked: someSelected ? "indeterminate" : allSelected,
|
|
23
|
+
onCheckedChange: handleSelectAll,
|
|
24
|
+
disabled: isLoading || !data.length || isSelectionDisabled,
|
|
25
|
+
"aria-label": "Select all rows"
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
if (!selectionDisabledTooltip) {
|
|
29
|
+
return checkbox;
|
|
30
|
+
}
|
|
17
31
|
return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration: 200, children: [
|
|
18
|
-
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
19
|
-
|
|
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 })
|
|
32
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "inline-flex", children: checkbox }) }),
|
|
33
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: selectionDisabledTooltip })
|
|
28
34
|
] }) });
|
|
29
35
|
}
|
|
30
36
|
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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 const allSelected = data.length > 0 && selectedIds.size === data.length\n const someSelected = selectedIds.size > 0 && !allSelected\n\n const checkbox = (\n <Checkbox\n checked={someSelected ? 'indeterminate' : allSelected}\n onCheckedChange={handleSelectAll}\n disabled={isLoading || !data.length || isSelectionDisabled}\n aria-label=\"Select all rows\"\n />\n )\n\n if (!selectionDisabledTooltip) {\n return checkbox\n }\n\n return (\n <TooltipProvider>\n <TooltipRoot delayDuration={200}>\n <TooltipTrigger asChild>\n <div className=\"inline-flex\">{checkbox}</div>\n </TooltipTrigger>\n <TooltipContent>{selectionDisabledTooltip}</TooltipContent>\n </TooltipRoot>\n </TooltipProvider>\n )\n}\n"],"names":[],"mappings":";;;;AAaO,SAAS,qBAAA,CAA4C;AAAA,EAC1D,mBAAA;AAAA,EACA,WAAA;AAAA,EACA,IAAA;AAAA,EACA,eAAA;AAAA,EACA,SAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAA,EAAgC;AAC9B,EAAA,IAAI,mBAAA,EAAqB;AACvB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,cAAc,IAAA,CAAK,MAAA,GAAS,CAAA,IAAK,WAAA,CAAY,SAAS,IAAA,CAAK,MAAA;AACjE,EAAA,MAAM,YAAA,GAAe,WAAA,CAAY,IAAA,GAAO,CAAA,IAAK,CAAC,WAAA;AAE9C,EAAA,MAAM,QAAA,mBACJ,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,OAAA,EAAS,eAAe,eAAA,GAAkB,WAAA;AAAA,MAC1C,eAAA,EAAiB,eAAA;AAAA,MACjB,QAAA,EAAU,SAAA,IAAa,CAAC,IAAA,CAAK,MAAA,IAAU,mBAAA;AAAA,MACvC,YAAA,EAAW;AAAA;AAAA,GACb;AAGF,EAAA,IAAI,CAAC,wBAAA,EAA0B;AAC7B,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,uBACE,GAAA,CAAC,eAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,WAAA,EAAA,EAAY,eAAe,GAAA,EAC1B,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,SAAO,IAAA,EACrB,QAAA,kBAAA,GAAA,CAAC,SAAI,SAAA,EAAU,aAAA,EAAe,oBAAS,CAAA,EACzC,CAAA;AAAA,oBACA,GAAA,CAAC,kBAAgB,QAAA,EAAA,wBAAA,EAAyB;AAAA,GAAA,EAC5C,CAAA,EACF,CAAA;AAEJ;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { GroupingConfig, RowIdentifierFn } from '../types';
|
|
2
|
+
type UseGroupExpansionParams<TData> = {
|
|
3
|
+
grouping?: GroupingConfig<TData>;
|
|
4
|
+
data: Array<TData>;
|
|
5
|
+
getRowId: RowIdentifierFn<TData>;
|
|
6
|
+
};
|
|
7
|
+
type UseGroupExpansionResult = {
|
|
8
|
+
/** Whether the group identified by `groupId` is currently expanded. */
|
|
9
|
+
isGroupOpen: (groupId: string) => boolean;
|
|
10
|
+
/** Toggles the expanded state of the group identified by `groupId`. */
|
|
11
|
+
toggleGroup: (groupId: string) => void;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Encapsulates the expanded-state bookkeeping for grouped tables: tracks which
|
|
15
|
+
* groups are open (supporting both controlled and uncontrolled modes) and
|
|
16
|
+
* exposes helpers to query and toggle individual groups.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useGroupExpansion<TData>({ grouping, data, getRowId, }: UseGroupExpansionParams<TData>): UseGroupExpansionResult;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
function useGroupExpansion({
|
|
4
|
+
grouping,
|
|
5
|
+
data,
|
|
6
|
+
getRowId
|
|
7
|
+
}) {
|
|
8
|
+
const [internalExpanded, setInternalExpanded] = React.useState(grouping?.defaultOpen ? true : {});
|
|
9
|
+
const expandedState = grouping?.open ?? internalExpanded;
|
|
10
|
+
const setExpandedState = grouping?.onOpenChange ?? setInternalExpanded;
|
|
11
|
+
const isGroupOpen = React.useCallback(
|
|
12
|
+
(groupId) => expandedState === true || typeof expandedState === "object" && expandedState[groupId] === true,
|
|
13
|
+
[expandedState]
|
|
14
|
+
);
|
|
15
|
+
const groupIds = React.useMemo(
|
|
16
|
+
() => grouping ? data.filter((item) => (grouping.getSubRows(item)?.length ?? 0) > 0).map(getRowId) : [],
|
|
17
|
+
[grouping, data, getRowId]
|
|
18
|
+
);
|
|
19
|
+
const toggleGroup = React.useCallback(
|
|
20
|
+
(groupId) => {
|
|
21
|
+
const updater = (prev) => {
|
|
22
|
+
const current = prev === true ? Object.fromEntries(groupIds.map((id) => [id, true])) : { ...prev };
|
|
23
|
+
current[groupId] = !current[groupId];
|
|
24
|
+
return current;
|
|
25
|
+
};
|
|
26
|
+
setExpandedState(updater);
|
|
27
|
+
},
|
|
28
|
+
[setExpandedState, groupIds]
|
|
29
|
+
);
|
|
30
|
+
return { isGroupOpen, toggleGroup };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { useGroupExpansion };
|
|
34
|
+
//# sourceMappingURL=useGroupExpansion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useGroupExpansion.js","sources":["../../../../src/components/DataTable/hooks/useGroupExpansion.ts"],"sourcesContent":["import { ExpandedState, Updater } from '@tanstack/react-table'\nimport * as React from 'react'\n\nimport { GroupingConfig, RowIdentifierFn } from '../types'\n\ntype UseGroupExpansionParams<TData> = {\n grouping?: GroupingConfig<TData>\n data: Array<TData>\n getRowId: RowIdentifierFn<TData>\n}\n\ntype UseGroupExpansionResult = {\n /** Whether the group identified by `groupId` is currently expanded. */\n isGroupOpen: (groupId: string) => boolean\n /** Toggles the expanded state of the group identified by `groupId`. */\n toggleGroup: (groupId: string) => void\n}\n\n/**\n * Encapsulates the expanded-state bookkeeping for grouped tables: tracks which\n * groups are open (supporting both controlled and uncontrolled modes) and\n * exposes helpers to query and toggle individual groups.\n */\nexport function useGroupExpansion<TData>({\n grouping,\n data,\n getRowId,\n}: UseGroupExpansionParams<TData>): UseGroupExpansionResult {\n const [internalExpanded, setInternalExpanded] = React.useState<ExpandedState>(grouping?.defaultOpen ? true : {})\n\n const expandedState = grouping?.open ?? internalExpanded\n const setExpandedState = grouping?.onOpenChange ?? setInternalExpanded\n\n const isGroupOpen = React.useCallback(\n (groupId: string) =>\n expandedState === true || (typeof expandedState === 'object' && expandedState[groupId] === true),\n [expandedState],\n )\n\n const groupIds = React.useMemo(\n () => (grouping ? data.filter((item) => (grouping.getSubRows(item)?.length ?? 0) > 0).map(getRowId) : []),\n [grouping, data, getRowId],\n )\n\n const toggleGroup = React.useCallback(\n (groupId: string) => {\n const updater = (prev: ExpandedState): ExpandedState => {\n const current = prev === true ? Object.fromEntries(groupIds.map((id) => [id, true])) : { ...prev }\n current[groupId] = !current[groupId]\n return current\n }\n ;(setExpandedState as (u: Updater<ExpandedState>) => void)(updater)\n },\n [setExpandedState, groupIds],\n )\n\n return { isGroupOpen, toggleGroup }\n}\n"],"names":[],"mappings":";;AAuBO,SAAS,iBAAA,CAAyB;AAAA,EACvC,QAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAA4D;AAC1D,EAAA,MAAM,CAAC,gBAAA,EAAkB,mBAAmB,CAAA,GAAI,KAAA,CAAM,SAAwB,QAAA,EAAU,WAAA,GAAc,IAAA,GAAO,EAAE,CAAA;AAE/G,EAAA,MAAM,aAAA,GAAgB,UAAU,IAAA,IAAQ,gBAAA;AACxC,EAAA,MAAM,gBAAA,GAAmB,UAAU,YAAA,IAAgB,mBAAA;AAEnD,EAAA,MAAM,cAAc,KAAA,CAAM,WAAA;AAAA,IACxB,CAAC,YACC,aAAA,KAAkB,IAAA,IAAS,OAAO,aAAA,KAAkB,QAAA,IAAY,aAAA,CAAc,OAAO,CAAA,KAAM,IAAA;AAAA,IAC7F,CAAC,aAAa;AAAA,GAChB;AAEA,EAAA,MAAM,WAAW,KAAA,CAAM,OAAA;AAAA,IACrB,MAAO,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,CAAC,UAAU,QAAA,CAAS,UAAA,CAAW,IAAI,CAAA,EAAG,UAAU,CAAA,IAAK,CAAC,EAAE,GAAA,CAAI,QAAQ,IAAI,EAAC;AAAA,IACvG,CAAC,QAAA,EAAU,IAAA,EAAM,QAAQ;AAAA,GAC3B;AAEA,EAAA,MAAM,cAAc,KAAA,CAAM,WAAA;AAAA,IACxB,CAAC,OAAA,KAAoB;AACnB,MAAA,MAAM,OAAA,GAAU,CAAC,IAAA,KAAuC;AACtD,QAAA,MAAM,UAAU,IAAA,KAAS,IAAA,GAAO,MAAA,CAAO,WAAA,CAAY,SAAS,GAAA,CAAI,CAAC,EAAA,KAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAA,GAAI,EAAE,GAAG,IAAA,EAAK;AACjG,QAAA,OAAA,CAAQ,OAAO,CAAA,GAAI,CAAC,OAAA,CAAQ,OAAO,CAAA;AACnC,QAAA,OAAO,OAAA;AAAA,MACT,CAAA;AACC,MAAC,iBAAyD,OAAO,CAAA;AAAA,IACpE,CAAA;AAAA,IACA,CAAC,kBAAkB,QAAQ;AAAA,GAC7B;AAEA,EAAA,OAAO,EAAE,aAAa,WAAA,EAAY;AACpC;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ColumnDef, OnChangeFn, VisibilityState } from '@tanstack/react-table';
|
|
1
|
+
import { ColumnDef, ExpandedState, OnChangeFn, Row, VisibilityState } from '@tanstack/react-table';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
export type User = {
|
|
4
4
|
id: string;
|
|
@@ -107,7 +107,19 @@ export type BackendPaginationProps = {
|
|
|
107
107
|
/** Callback when page changes */
|
|
108
108
|
readonly onPageChange: (page: number) => void;
|
|
109
109
|
} & BasePaginationProps;
|
|
110
|
-
export type
|
|
110
|
+
export type GroupingConfig<TData> = {
|
|
111
|
+
/** Returns the children for a row. Return `undefined`/empty for leaf rows (no group). */
|
|
112
|
+
readonly getSubRows: (row: TData) => Array<TData> | undefined;
|
|
113
|
+
/** Whether all groups are expanded on first render (default: `false`, all collapsed). */
|
|
114
|
+
readonly defaultOpen?: boolean;
|
|
115
|
+
/** Controlled expanded state. When provided, you must manage it via `onOpenChange`. */
|
|
116
|
+
readonly open?: ExpandedState;
|
|
117
|
+
/** Callback when the expanded state changes (controlled mode). */
|
|
118
|
+
readonly onOpenChange?: OnChangeFn<ExpandedState>;
|
|
119
|
+
/** Renders the content of a group row (label, count, etc.). Defaults to an item count. */
|
|
120
|
+
readonly renderGroupRow?: (row: Row<TData>) => ReactNode;
|
|
121
|
+
};
|
|
122
|
+
type DataTableBaseProps<TData> = {
|
|
111
123
|
/** Array of column definitions that describe the table structure */
|
|
112
124
|
readonly columns: Array<ColumnDef<TData>>;
|
|
113
125
|
/** Array of data items to be displayed in the table */
|
|
@@ -116,8 +128,6 @@ export type DataTableProps<TData> = {
|
|
|
116
128
|
readonly columnVisibility?: ColumnVisibilityConfig;
|
|
117
129
|
/** Whether the table is in a loading state */
|
|
118
130
|
readonly isLoading?: boolean;
|
|
119
|
-
/** Pagination configuration. If not provided, pagination is disabled */
|
|
120
|
-
readonly pagination?: BasePaginationProps | BackendPaginationProps;
|
|
121
131
|
/** Primary filters that appear directly above the table */
|
|
122
132
|
readonly primaryFilters?: ReactNode;
|
|
123
133
|
/** Secondary filters that appear in the filters dropdown */
|
|
@@ -154,13 +164,23 @@ export type DataTableProps<TData> = {
|
|
|
154
164
|
readonly className?: string;
|
|
155
165
|
/** Optional className for the table */
|
|
156
166
|
readonly tableClassName?: string;
|
|
157
|
-
}
|
|
167
|
+
};
|
|
168
|
+
type IdProps<TData> = HasId<TData> extends true ? {
|
|
158
169
|
/** Function to get unique identifier from a row. Not needed when data has 'id' property */
|
|
159
170
|
readonly getRowId?: RowIdentifierFn<TData>;
|
|
160
171
|
} : {
|
|
161
172
|
/** Function to get unique identifier from a row. Required when data doesn't have 'id' property */
|
|
162
173
|
readonly getRowId: RowIdentifierFn<TData>;
|
|
163
|
-
}
|
|
174
|
+
};
|
|
175
|
+
type PaginatedVariant = {
|
|
176
|
+
readonly pagination?: BasePaginationProps | BackendPaginationProps;
|
|
177
|
+
readonly grouping?: never;
|
|
178
|
+
};
|
|
179
|
+
type GroupedVariant<TData> = {
|
|
180
|
+
readonly grouping: GroupingConfig<TData>;
|
|
181
|
+
readonly pagination?: never;
|
|
182
|
+
};
|
|
183
|
+
export type DataTableProps<TData> = DataTableBaseProps<TData> & IdProps<TData> & (PaginatedVariant | GroupedVariant<TData>);
|
|
164
184
|
/**
|
|
165
185
|
* Type helper to check if a type has an 'id' property
|
|
166
186
|
*/
|
|
@@ -171,3 +191,4 @@ export type HasId<T> = T extends {
|
|
|
171
191
|
* Function to get a unique identifier from a row
|
|
172
192
|
*/
|
|
173
193
|
export type RowIdentifierFn<T> = (row: T) => string;
|
|
194
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively flattens a sub-row tree into its leaf items, discarding group
|
|
3
|
+
* nodes. Used so selection (counts, select-all, ids) operates over the actual
|
|
4
|
+
* selectable leaf rows rather than the group containers.
|
|
5
|
+
*/
|
|
6
|
+
export declare function flattenLeaves<TData>(data: Array<TData>, getSubRows: (row: TData) => Array<TData> | undefined): Array<TData>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
function flattenLeaves(data, getSubRows) {
|
|
2
|
+
const leaves = [];
|
|
3
|
+
for (const item of data) {
|
|
4
|
+
const children = getSubRows(item);
|
|
5
|
+
if (children && children.length > 0) {
|
|
6
|
+
leaves.push(...flattenLeaves(children, getSubRows));
|
|
7
|
+
} else {
|
|
8
|
+
leaves.push(item);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return leaves;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { flattenLeaves };
|
|
15
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/components/DataTable/utils.ts"],"sourcesContent":["/**\n * Recursively flattens a sub-row tree into its leaf items, discarding group\n * nodes. Used so selection (counts, select-all, ids) operates over the actual\n * selectable leaf rows rather than the group containers.\n */\nexport function flattenLeaves<TData>(\n data: Array<TData>,\n getSubRows: (row: TData) => Array<TData> | undefined,\n): Array<TData> {\n const leaves: Array<TData> = []\n for (const item of data) {\n const children = getSubRows(item)\n if (children && children.length > 0) {\n leaves.push(...flattenLeaves(children, getSubRows))\n } else {\n leaves.push(item)\n }\n }\n return leaves\n}\n"],"names":[],"mappings":"AAKO,SAAS,aAAA,CACd,MACA,UAAA,EACc;AACd,EAAA,MAAM,SAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,QAAQ,IAAA,EAAM;AACvB,IAAA,MAAM,QAAA,GAAW,WAAW,IAAI,CAAA;AAChC,IAAA,IAAI,QAAA,IAAY,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AACnC,MAAA,MAAA,CAAO,IAAA,CAAK,GAAG,aAAA,CAAc,QAAA,EAAU,UAAU,CAAC,CAAA;AAAA,IACpD,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IAClB;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;;;;"}
|