@elabs-ai/components-data 4.0.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/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/index.d.ts +293 -0
- package/dist/index.js +933 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
- package/src/column-picker/column-picker.stories.tsx +65 -0
- package/src/column-picker/column-picker.test.tsx +134 -0
- package/src/column-picker/column-picker.tsx +75 -0
- package/src/column-picker/index.ts +1 -0
- package/src/data-table/data-table.stories.tsx +804 -0
- package/src/data-table/data-table.test.tsx +1513 -0
- package/src/data-table/data-table.tsx +1375 -0
- package/src/data-table/index.ts +7 -0
- package/src/facet-filter/facet-filter.stories.tsx +121 -0
- package/src/facet-filter/facet-filter.test.tsx +175 -0
- package/src/facet-filter/facet-filter.tsx +104 -0
- package/src/facet-filter/index.ts +1 -0
- package/src/filter-bar/filter-bar.stories.tsx +58 -0
- package/src/filter-bar/filter-bar.test.tsx +60 -0
- package/src/filter-bar/filter-bar.tsx +20 -0
- package/src/filter-bar/index.ts +1 -0
- package/src/index.ts +18 -0
- package/src/search-input/index.ts +1 -0
- package/src/search-input/search-input.stories.tsx +45 -0
- package/src/search-input/search-input.test.tsx +99 -0
- package/src/search-input/search-input.tsx +81 -0
- package/src/templates-data-app.stories.tsx +160 -0
- package/src/to-csv.test.ts +147 -0
- package/src/to-csv.ts +102 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Manuel Reimitz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<!-- brand-ui:gen:readme:start -->
|
|
2
|
+
<!-- Generated by scripts/gen-package-readmes.mjs — do not edit inside these markers. -->
|
|
3
|
+
|
|
4
|
+
# `@elabs-ai/components-data`
|
|
5
|
+
|
|
6
|
+
> TanStack DataTable, FilterBar, SearchInput, FacetFilter, ColumnPicker.
|
|
7
|
+
|
|
8
|
+
Part of **brand-ui**, a source-owned, token-driven React component system.
|
|
9
|
+
These packages are **private** and are not published to any registry — they are
|
|
10
|
+
consumed from this workspace. See `docs/CONSUMING.md`.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
Inside this monorepo the packages resolve as workspace dependencies:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
"@elabs-ai/components-data": "workspace:*"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Set up styling (do not skip)
|
|
21
|
+
|
|
22
|
+
Components are Tailwind v4 classes backed by semantic tokens. Two lines in
|
|
23
|
+
your CSS entry, or **everything renders unstyled** — the single most common
|
|
24
|
+
mistake:
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
@import "@elabs-ai/components-tokens/styles.css";
|
|
28
|
+
@source "../node_modules/@elabs-ai/components-data/dist";
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The `@source` line is required because Tailwind ignores `node_modules`. Add
|
|
32
|
+
one per brand-ui package you render. Then wrap your app once:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { ThemeProvider } from "@elabs-ai/components-tokens";
|
|
36
|
+
|
|
37
|
+
<ThemeProvider defaultTheme="light">{children}</ThemeProvider>;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## What's in it
|
|
41
|
+
|
|
42
|
+
5 exported components — including `ColumnPicker`, `DataTable`, `FacetFilter`, `FilterBar`, `SearchInput`.
|
|
43
|
+
|
|
44
|
+
Don't guess the API — ask the CLI:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pnpm add -D @elabs-ai/components-cli
|
|
48
|
+
pnpm exec brand-ui search <query> # find a component
|
|
49
|
+
pnpm exec brand-ui docs <Name> # its real props, from source
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Using an AI coding agent?
|
|
53
|
+
|
|
54
|
+
For Claude Code, install the plugin from this repo's checkout:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
/plugin marketplace add .
|
|
58
|
+
/plugin install brand-ui
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`brand-ui docs <Name>` returns intent, composition, state→token mappings and
|
|
62
|
+
anti-patterns — tell your agent to run it instead of guessing a prop. The CLI
|
|
63
|
+
also runs as an MCP server (`brand-ui mcp`).
|
|
64
|
+
|
|
65
|
+
## Full guide
|
|
66
|
+
|
|
67
|
+
Tailwind and Next.js wiring, per-package extras, agent enablement and a
|
|
68
|
+
prompt for migrating an existing project: `docs/CONSUMING.md`.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
UNLICENSED — private.
|
|
73
|
+
|
|
74
|
+
<!-- brand-ui:gen:readme:end -->
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, InputHTMLAttributes, ButtonHTMLAttributes, Ref, ReactElement } from 'react';
|
|
3
|
+
import { ColumnDef, Table, SortingState, OnChangeFn, VisibilityState, ColumnFiltersState, PaginationState, ColumnPinningState, Row } from '@tanstack/react-table';
|
|
4
|
+
export { CellContext, ColumnDef, ColumnPinningState, Row, Table } from '@tanstack/react-table';
|
|
5
|
+
|
|
6
|
+
/** Snapshot of table slice state — used for saved-view serialise/rehydrate. */
|
|
7
|
+
interface DataTableViewState {
|
|
8
|
+
sorting: SortingState;
|
|
9
|
+
columnVisibility: VisibilityState;
|
|
10
|
+
columnFilters: ColumnFiltersState;
|
|
11
|
+
globalFilter?: string;
|
|
12
|
+
pagination?: PaginationState;
|
|
13
|
+
/**
|
|
14
|
+
* Which columns are frozen to the left/right edge (#333). OPTIONAL on purpose:
|
|
15
|
+
* the other members predate it, and a required key would break every consumer
|
|
16
|
+
* that already constructs a `DataTableViewState` literal.
|
|
17
|
+
*/
|
|
18
|
+
columnPinning?: ColumnPinningState;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Argument object fired by `onServerChange` whenever a manual slice changes.
|
|
22
|
+
* The consuming app should re-fetch with these params and update `data`.
|
|
23
|
+
*/
|
|
24
|
+
interface DataTableServerArgs {
|
|
25
|
+
pagination: PaginationState;
|
|
26
|
+
sorting: SortingState;
|
|
27
|
+
columnFilters: ColumnFiltersState;
|
|
28
|
+
globalFilter: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fires when a row is activated (#337).
|
|
32
|
+
*
|
|
33
|
+
* Both activation paths deliver a `click`: a pointer click on the row body, and
|
|
34
|
+
* a keyboard Enter/Space on the row's hidden activation `<button>` (which the
|
|
35
|
+
* browser dispatches as a click). So the handler takes ONE event type — there is
|
|
36
|
+
* nothing for the caller to branch on.
|
|
37
|
+
*/
|
|
38
|
+
type DataTableRowClickHandler<TData> = (row: Row<TData>, event: React.MouseEvent<HTMLElement>) => void;
|
|
39
|
+
interface DataTableProps<TData, TValue> extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
40
|
+
columns: ColumnDef<TData, TValue>[];
|
|
41
|
+
data: TData[];
|
|
42
|
+
/** Render a toolbar above the table; receives the table instance. */
|
|
43
|
+
toolbar?: (table: Table<TData>) => ReactNode;
|
|
44
|
+
/** Enable client-side pagination. */
|
|
45
|
+
enablePagination?: boolean;
|
|
46
|
+
pageSize?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Hide the pager once there's genuinely only one page
|
|
49
|
+
* (`table.getPageCount() <= 1`). Default `true`. When `manualPagination` is
|
|
50
|
+
* set without `rowCount`/`pageCount`, the page count isn't knowable (TanStack
|
|
51
|
+
* falls back to the current page's row count) — in that ambiguous case the
|
|
52
|
+
* pager still renders regardless of this flag, so the existing dev warning
|
|
53
|
+
* (#227) stays the diagnostic instead of a silently-hidden pager. Set to
|
|
54
|
+
* `false` to always show the pager (e.g. while a server total is still
|
|
55
|
+
* loading and you'd rather show a disabled pager than none).
|
|
56
|
+
*/
|
|
57
|
+
hidePaginationWhenSingle?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Controlled global filter value. When provided, the table reflects this
|
|
60
|
+
* value and the component manages no internal filter state. Keep the source
|
|
61
|
+
* of truth in the app and pass it down — never mutate the filter during
|
|
62
|
+
* render (e.g. `table.setGlobalFilter()` in `toolbar`), which loops.
|
|
63
|
+
*/
|
|
64
|
+
globalFilter?: string;
|
|
65
|
+
/** Fires when the table requests a global-filter change (e.g. from typeahead). */
|
|
66
|
+
onGlobalFilterChange?: (value: string) => void;
|
|
67
|
+
/** Controlled sorting state. When provided the component is sorted-controlled. */
|
|
68
|
+
sorting?: SortingState;
|
|
69
|
+
onSortingChange?: OnChangeFn<SortingState>;
|
|
70
|
+
/** Controlled column-visibility state. */
|
|
71
|
+
columnVisibility?: VisibilityState;
|
|
72
|
+
onColumnVisibilityChange?: OnChangeFn<VisibilityState>;
|
|
73
|
+
/** Controlled column-filters state. */
|
|
74
|
+
columnFilters?: ColumnFiltersState;
|
|
75
|
+
onColumnFiltersChange?: OnChangeFn<ColumnFiltersState>;
|
|
76
|
+
/** Controlled pagination state. */
|
|
77
|
+
pagination?: PaginationState;
|
|
78
|
+
onPaginationChange?: OnChangeFn<PaginationState>;
|
|
79
|
+
/**
|
|
80
|
+
* Controlled column-pinning state (#333) — the columns frozen against the
|
|
81
|
+
* left and/or right edge while the rest of the table scrolls horizontally.
|
|
82
|
+
* When provided the component is pinning-controlled; otherwise it manages the
|
|
83
|
+
* slice internally and can be seeded once via `initialView.columnPinning`.
|
|
84
|
+
*
|
|
85
|
+
* A pinned column MUST declare an explicit `size` in its `ColumnDef`: the
|
|
86
|
+
* sticky offset is computed from TanStack's `column.getStart("left")` /
|
|
87
|
+
* `getAfter("right")`, which sum the DECLARED sizes, so an auto-width column
|
|
88
|
+
* would render at a width that doesn't match its own offset. A dev-only
|
|
89
|
+
* warning fires for a pinned column with no `size`.
|
|
90
|
+
*
|
|
91
|
+
* Pinning is a LAYOUT concern, not a query concern — it is client-only and
|
|
92
|
+
* never joins `DataTableServerArgs` / `onServerChange`.
|
|
93
|
+
*/
|
|
94
|
+
columnPinning?: ColumnPinningState;
|
|
95
|
+
onColumnPinningChange?: OnChangeFn<ColumnPinningState>;
|
|
96
|
+
/**
|
|
97
|
+
* One-shot rehydrate for uncontrolled slices only (ignored for any slice
|
|
98
|
+
* whose corresponding controlled prop is set). Maps to `useReactTable`'s
|
|
99
|
+
* `initialState`.
|
|
100
|
+
*/
|
|
101
|
+
initialView?: Partial<DataTableViewState>;
|
|
102
|
+
/**
|
|
103
|
+
* When true, sorting is handled by the server. Pass `sorting` (controlled)
|
|
104
|
+
* and handle `onServerChange` to re-fetch with the new sort params.
|
|
105
|
+
* NOTE: controlled ≠ manual — a controlled `sorting` with `manualSorting:false`
|
|
106
|
+
* still sorts locally.
|
|
107
|
+
*/
|
|
108
|
+
manualSorting?: boolean;
|
|
109
|
+
/**
|
|
110
|
+
* When true, filtering is handled by the server.
|
|
111
|
+
* NOTE: a controlled `columnFilters` with `manualFiltering:false` still
|
|
112
|
+
* filters locally.
|
|
113
|
+
*/
|
|
114
|
+
manualFiltering?: boolean;
|
|
115
|
+
/** When true, pagination is handled by the server. */
|
|
116
|
+
manualPagination?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Total row count — used by the server model so TanStack can derive
|
|
119
|
+
* page count. Required when `manualPagination` is true and `pageCount` is
|
|
120
|
+
* not provided.
|
|
121
|
+
*/
|
|
122
|
+
rowCount?: number;
|
|
123
|
+
/**
|
|
124
|
+
* Total page count — alternative to `rowCount` for server pagination. When
|
|
125
|
+
* both are provided, `pageCount` wins.
|
|
126
|
+
*/
|
|
127
|
+
pageCount?: number;
|
|
128
|
+
/**
|
|
129
|
+
* Fired after any manual-slice change with the current {pagination, sorting,
|
|
130
|
+
* columnFilters, globalFilter}. The component never fetches; the app must
|
|
131
|
+
* re-fetch and update `data`.
|
|
132
|
+
*/
|
|
133
|
+
onServerChange?: (args: DataTableServerArgs) => void;
|
|
134
|
+
/** When true: overlay spinner; on empty+loading show skeleton rows instead of empty message. */
|
|
135
|
+
loading?: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Opt-in to row virtualization (for very large lists). Mutually exclusive
|
|
138
|
+
* with enablePagination in practice — if both are set, virtualization wins
|
|
139
|
+
* and pagination is silently ignored.
|
|
140
|
+
*/
|
|
141
|
+
enableRowVirtualization?: boolean;
|
|
142
|
+
/** Estimated row height in px (used by the virtualizer). Default: 40. */
|
|
143
|
+
estimateRowHeight?: number;
|
|
144
|
+
/** Virtualizer overscan (rows rendered above/below the visible window). Default: 8. */
|
|
145
|
+
overscan?: number;
|
|
146
|
+
/** CSS max-height of the scroll container in virtualized mode. Default: "32rem". */
|
|
147
|
+
maxBodyHeight?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Number of skeleton placeholder rows to render while loading.
|
|
150
|
+
* Defaults to `pageSize` (non-virtualized) or `min(10, pageSize)` (virtualized).
|
|
151
|
+
*/
|
|
152
|
+
loadingRows?: number;
|
|
153
|
+
/**
|
|
154
|
+
* Gentle alternating row stripes ("zebra") as the row-separation cue, instead
|
|
155
|
+
* of a hairline divider between every row. Default `true` — the stripe is the
|
|
156
|
+
* single separation gesture, so rows carry no divider (a divider on a striped
|
|
157
|
+
* row would be a redundant boundary). Set `false` for the classic line model
|
|
158
|
+
* (a `border-border-strong` divider between rows, no stripes).
|
|
159
|
+
*/
|
|
160
|
+
zebra?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* Fires when a row is activated (#337). Setting it adds ONE activation
|
|
163
|
+
* target per row: a visually-hidden `<button>` rendered inside the row's
|
|
164
|
+
* first cell. That button is the row's keyboard tab stop and its accessible
|
|
165
|
+
* name; a pointer click anywhere else in the row resolves to the same
|
|
166
|
+
* handler, so mouse and keyboard converge on one control instead of two
|
|
167
|
+
* competing ones (a focusable `<tr>` cannot carry an activation role without
|
|
168
|
+
* destroying `row` table semantics).
|
|
169
|
+
*
|
|
170
|
+
* Guarded: a click that originates on a nested interactive control
|
|
171
|
+
* (button/link/input/checkbox/…) or is the tail end of a text-selection drag
|
|
172
|
+
* does NOT fire it. Optional; omitting it renders rows exactly as before.
|
|
173
|
+
*/
|
|
174
|
+
onRowClick?: DataTableRowClickHandler<TData>;
|
|
175
|
+
/**
|
|
176
|
+
* Accessible name for the row's hidden activation button (#337). Only read
|
|
177
|
+
* when `onRowClick` is set. Defaults to the row's first visible cell value
|
|
178
|
+
* when that is a string/number (the row's primary identifier — the same
|
|
179
|
+
* naming a link in that cell would get), else the localized
|
|
180
|
+
* `data.table.rowAction` fallback. Supply it whenever the first cell isn't a
|
|
181
|
+
* good name for the row.
|
|
182
|
+
*/
|
|
183
|
+
rowActionLabel?: (row: Row<TData>) => string;
|
|
184
|
+
/**
|
|
185
|
+
* Per-row className, merged alongside the existing zebra/line/hover/selected
|
|
186
|
+
* classes via `cn()` (so it can't accidentally clobber them) (#337).
|
|
187
|
+
*/
|
|
188
|
+
rowClassName?: (row: Row<TData>) => string;
|
|
189
|
+
/**
|
|
190
|
+
* Accessible name for the table, rendered as a visually-hidden (`sr-only`)
|
|
191
|
+
* `<caption>` — the first child of `<table>`. Screen readers announce it as
|
|
192
|
+
* the table's name and it makes column-header navigation meaningful.
|
|
193
|
+
* Optional; omit it only when the surrounding page already labels the table
|
|
194
|
+
* unambiguously (e.g. an adjacent heading) (#338).
|
|
195
|
+
*/
|
|
196
|
+
caption?: ReactNode;
|
|
197
|
+
/** Message shown when there are no rows and not loading. */
|
|
198
|
+
emptyMessage?: ReactNode;
|
|
199
|
+
className?: string;
|
|
200
|
+
}
|
|
201
|
+
declare const DataTableWithRef: <TData, TValue>(props: DataTableProps<TData, TValue> & {
|
|
202
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
203
|
+
}) => React.ReactElement | null;
|
|
204
|
+
|
|
205
|
+
interface SearchInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value"> {
|
|
206
|
+
value: string;
|
|
207
|
+
onValueChange: (value: string) => void;
|
|
208
|
+
/** Visually-hidden accessible label. Defaults to "Search". */
|
|
209
|
+
label?: string;
|
|
210
|
+
containerClassName?: string;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Search field with a leading icon and a clear button. Controlled.
|
|
214
|
+
*
|
|
215
|
+
* `disabled` (available via the extended `InputHTMLAttributes`) is how a
|
|
216
|
+
* consumer signals a pending fetch (D5 — the app owns fetch state, this
|
|
217
|
+
* control just reflects it; see loading-states.md). It is forwarded to the
|
|
218
|
+
* `<Input>` explicitly AND gates the clear button — while disabled the clear
|
|
219
|
+
* affordance is hidden so it can't mutate the filter mid-request (#269/#8).
|
|
220
|
+
*/
|
|
221
|
+
declare function SearchInput({ value, onValueChange, label, placeholder, className, containerClassName, disabled, ...props }: SearchInputProps): react.JSX.Element;
|
|
222
|
+
|
|
223
|
+
interface FilterBarProps {
|
|
224
|
+
/** Left cluster: search + facet filters. */
|
|
225
|
+
children: ReactNode;
|
|
226
|
+
/** Right cluster: column picker, export, primary actions. */
|
|
227
|
+
actions?: ReactNode;
|
|
228
|
+
className?: string;
|
|
229
|
+
}
|
|
230
|
+
/** Horizontal toolbar that groups table filters and actions. */
|
|
231
|
+
declare function FilterBar({ children, actions, className }: FilterBarProps): react.JSX.Element;
|
|
232
|
+
|
|
233
|
+
interface FacetOption {
|
|
234
|
+
label: string;
|
|
235
|
+
value: string;
|
|
236
|
+
}
|
|
237
|
+
interface FacetFilterProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "title"> {
|
|
238
|
+
title: string;
|
|
239
|
+
options: FacetOption[];
|
|
240
|
+
/** Currently selected values (controlled). */
|
|
241
|
+
selected: string[];
|
|
242
|
+
onSelectedChange: (values: string[]) => void;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Multi-select faceted filter rendered as a dropdown of toggles.
|
|
246
|
+
*
|
|
247
|
+
* `disabled` (forwarded to the trigger `Button`) is how a consumer signals a
|
|
248
|
+
* pending fetch (D5 — the app owns fetch state, this control just reflects
|
|
249
|
+
* it; see loading-states.md).
|
|
250
|
+
*
|
|
251
|
+
* The trigger takes `Button`'s DEFAULT size (`h-9`), not `sm` (#346): a facet
|
|
252
|
+
* filter lives in a toolbar beside `Select` / `Input` / `DatePicker`, all of
|
|
253
|
+
* which land on `h-9` (Select's own default rung, Input hardcoded, DatePicker
|
|
254
|
+
* via this same Button default). An `sm` trigger was the lone `h-8` outlier in
|
|
255
|
+
* that row, so the top and bottom edges of a filter bar didn't line up.
|
|
256
|
+
*/
|
|
257
|
+
declare const FacetFilter: react.ForwardRefExoticComponent<FacetFilterProps & react.RefAttributes<HTMLButtonElement>>;
|
|
258
|
+
|
|
259
|
+
interface ColumnPickerProps<TData> extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
260
|
+
table: Table<TData>;
|
|
261
|
+
/** Trigger label. Defaults to "Columns". */
|
|
262
|
+
label?: string;
|
|
263
|
+
}
|
|
264
|
+
declare const ColumnPicker: <TData>(props: ColumnPickerProps<TData> & {
|
|
265
|
+
ref?: Ref<HTMLButtonElement>;
|
|
266
|
+
}) => ReactElement | null;
|
|
267
|
+
|
|
268
|
+
type CsvColumn<TData> = {
|
|
269
|
+
key: keyof TData & string;
|
|
270
|
+
header?: string;
|
|
271
|
+
};
|
|
272
|
+
interface ToCsvOptions<TData> {
|
|
273
|
+
/** Subset/reorder of columns. Omitted → all keys from rows[0]. */
|
|
274
|
+
columns?: CsvColumn<TData>[];
|
|
275
|
+
/** Emit header row. Default true. */
|
|
276
|
+
header?: boolean;
|
|
277
|
+
/** Field delimiter. Default ",". */
|
|
278
|
+
delimiter?: string;
|
|
279
|
+
}
|
|
280
|
+
interface DownloadCsvOptions<TData> extends ToCsvOptions<TData> {
|
|
281
|
+
/** File name without extension. Default "download". */
|
|
282
|
+
filename?: string;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Serialize rows to a CSV string (no DOM access — safe for SSR / jsdom).
|
|
286
|
+
*/
|
|
287
|
+
declare function toCsv<TData extends Record<string, unknown>>(rows: TData[], opts?: ToCsvOptions<TData>): string;
|
|
288
|
+
/**
|
|
289
|
+
* Trigger a CSV file download in the browser. No-op in SSR environments.
|
|
290
|
+
*/
|
|
291
|
+
declare function downloadCsv<TData extends Record<string, unknown>>(rows: TData[], opts?: DownloadCsvOptions<TData>): void;
|
|
292
|
+
|
|
293
|
+
export { ColumnPicker, type ColumnPickerProps, type CsvColumn, DataTableWithRef as DataTable, type DataTableProps, type DataTableRowClickHandler, type DataTableServerArgs, type DataTableViewState, type DownloadCsvOptions, FacetFilter, type FacetFilterProps, type FacetOption, FilterBar, type FilterBarProps, SearchInput, type SearchInputProps, type ToCsvOptions, downloadCsv, toCsv };
|