boneless-table 0.1.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 boneless-table contributors
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,67 @@
1
+ # boneless-table
2
+
3
+ An accessible, virtualized, unstyled React data table renderer built on TanStack Table.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install boneless-table
9
+ ```
10
+
11
+ ## Styling and icons
12
+
13
+ The package ships no CSS, Tailwind utilities, or icon dependency. Apply classes through
14
+ `className` and `classNames`, target stable `data-slot` attributes in your stylesheet, and pass
15
+ optional icons through `icons`. The documentation app contains a complete Tailwind theme built on
16
+ those hooks.
17
+
18
+ ## Usage
19
+
20
+ ```tsx
21
+ import { BonelessTable, type BonelessTableColumn } from 'boneless-table'
22
+
23
+ type Account = { id: string; name: string; plan: string }
24
+
25
+ const columns: BonelessTableColumn<Account>[] = [
26
+ { key: 'name', header: 'Account' },
27
+ { key: 'plan', header: 'Plan' },
28
+ ]
29
+
30
+ export function AccountsTable({ data }: { data: Account[] }) {
31
+ return <BonelessTable data={data} columns={columns} />
32
+ }
33
+ ```
34
+
35
+ See the repository documentation site for the complete API and configuration guide.
36
+
37
+ ## Layout and virtualization
38
+
39
+ Content-sized tables (`scroller="auto"`, the default) render all rows. Virtualization is enabled
40
+ when `scroller="fill"`, which must be placed in a parent with a stable height. Virtual rows are
41
+ measured after rendering, so cells may wrap or render variable-height content. Use
42
+ `virtualization={false}` to opt out in a fill layout.
43
+
44
+ For non-text column headers, set `meta.columnLabel` to provide the label shown in the built-in
45
+ column chooser; otherwise the chooser falls back to the column id.
46
+
47
+ ## Filtering performance
48
+
49
+ Text filters debounce updates by 150ms by default, so large client-side row models are not
50
+ recomputed on every keystroke. Set `filterDebounceMs={0}` for immediate filtering, or increase
51
+ the value when working with larger local datasets. This delay also reduces request churn for
52
+ server-filtered tables.
53
+
54
+ ## Expandable rows
55
+
56
+ Pass TanStack's `getSubRows` together with `tree` to render nested records. The default toolbar
57
+ adds one Expand all / Collapse all control, and indentation is contained inside the selected cell
58
+ so tree depth never changes column widths.
59
+
60
+ ```tsx
61
+ <BonelessTable
62
+ data={family}
63
+ columns={columns}
64
+ getSubRows={(person) => person.children}
65
+ tree={{ columnId: 'name', indentPx: 18 }}
66
+ />
67
+ ```
@@ -0,0 +1,258 @@
1
+ import { RowData, ColumnDef, Table, TableOptions, TableState, Column } from '@tanstack/react-table';
2
+ export { ColumnDef, ColumnFiltersState, ColumnOrderState, ExpandedState, SortingState, Table, TableOptions, VisibilityState, createColumnHelper, flexRender, getCoreRowModel, getExpandedRowModel, getFilteredRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
3
+ import * as react from 'react';
4
+ import { ReactNode, RefObject, ComponentType, AnchorHTMLAttributes, MouseEvent, KeyboardEvent } from 'react';
5
+
6
+ type ColumnAlignment = 'left' | 'right';
7
+ type ColumnBorders = 'none' | 'left' | 'right' | 'both';
8
+ type FilterType = 'text' | 'select';
9
+ type RevealMode = 'always' | 'hover';
10
+ type BonelessTableColumnSizing = {
11
+ widthPx: number;
12
+ } | {
13
+ minPx: number;
14
+ flex?: number;
15
+ };
16
+ type BonelessTableColumnSettings = {
17
+ sizing?: BonelessTableColumnSizing;
18
+ align?: ColumnAlignment;
19
+ borders?: ColumnBorders;
20
+ sorting?: {
21
+ enabled?: boolean;
22
+ reveal?: RevealMode;
23
+ };
24
+ filtering?: {
25
+ type: FilterType;
26
+ options?: readonly string[];
27
+ reveal?: RevealMode;
28
+ };
29
+ valueDisplay?: {
30
+ truncateAt: number;
31
+ suffix?: string;
32
+ };
33
+ };
34
+ type BonelessTableSettings = {
35
+ columnDefaults: Required<Pick<BonelessTableColumnSettings, 'align' | 'borders'>> & {
36
+ sizing: Required<NonNullable<BonelessTableColumnSettings['sizing']>>;
37
+ sorting: Required<NonNullable<BonelessTableColumnSettings['sorting']>>;
38
+ };
39
+ interactions: {
40
+ filterReveal: RevealMode;
41
+ horizontalOverflow: 'auto' | 'scroll';
42
+ };
43
+ };
44
+ declare const defaultBonelessTableSettings: BonelessTableSettings;
45
+ declare function mergeBonelessTableSettings(override?: DeepPartial<BonelessTableSettings>, base?: BonelessTableSettings): BonelessTableSettings;
46
+ declare function resolveColumnSettings(settings: BonelessTableSettings, column: {
47
+ columnDef: {
48
+ meta?: {
49
+ bonelessTable?: BonelessTableColumnSettings;
50
+ };
51
+ };
52
+ }): {
53
+ sizing: {
54
+ minPx?: number | undefined;
55
+ flex?: number;
56
+ widthPx: number;
57
+ } | {
58
+ minPx: number;
59
+ flex: number;
60
+ };
61
+ align: ColumnAlignment;
62
+ borders: ColumnBorders;
63
+ sorting: {
64
+ enabled: boolean;
65
+ reveal: RevealMode;
66
+ };
67
+ filtering: {
68
+ type: FilterType;
69
+ options?: readonly string[];
70
+ reveal?: RevealMode;
71
+ } | undefined;
72
+ valueDisplay: {
73
+ truncateAt: number;
74
+ suffix?: string;
75
+ } | undefined;
76
+ };
77
+ declare function compactValue(value: unknown, settings?: BonelessTableColumnSettings): string;
78
+
79
+ declare module '@tanstack/react-table' {
80
+ interface ColumnMeta<TData extends RowData, TValue> {
81
+ bonelessTable?: BonelessTableColumnSettings;
82
+ /** Accessible label used for this column in the built-in column chooser. */
83
+ columnLabel?: string;
84
+ }
85
+ }
86
+ /**
87
+ * A friendlier column input: use `key` for a data property instead of TanStack's `accessorKey`.
88
+ * `accessorKey` remains accepted for interoperability with existing TanStack column definitions.
89
+ */
90
+ type BonelessTableColumn<TData extends RowData, TValue = unknown> = ColumnDef<TData, TValue> | (Omit<ColumnDef<TData, TValue>, 'accessorKey'> & {
91
+ key: keyof TData & string;
92
+ });
93
+ type ResolvedBonelessTableColumn<TData extends RowData, TValue = unknown> = ColumnDef<TData, TValue>;
94
+ type DeepPartial<T> = {
95
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
96
+ };
97
+
98
+ type ColumnMenuIcons = Partial<{
99
+ close: ReactNode;
100
+ moveEarlier: ReactNode;
101
+ moveLater: ReactNode;
102
+ }>;
103
+ declare function ColumnMenu<TData>({ table, onClose, onMoveColumn, className, icons, id, triggerRef, }: {
104
+ table: Table<TData>;
105
+ onClose: () => void;
106
+ onMoveColumn: (id: string, direction: -1 | 1) => void;
107
+ className?: string;
108
+ /** Optional consumer-owned icons. Text labels remain available without them. */
109
+ icons?: ColumnMenuIcons;
110
+ id?: string;
111
+ /** The menu trigger is not an outside click; this lets it reliably toggle the dialog closed. */
112
+ triggerRef?: RefObject<HTMLElement | null>;
113
+ }): react.JSX.Element;
114
+
115
+ type BonelessTableRowLinkComponentProps = {
116
+ children: ReactNode;
117
+ className: string;
118
+ href: string;
119
+ 'aria-label'?: string;
120
+ target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
121
+ rel?: string;
122
+ };
123
+ type BonelessTableRowLink<TData extends RowData> = {
124
+ /** A framework-specific component such as Next.js Link that wraps each resolved row. */
125
+ component: ComponentType<BonelessTableRowLinkComponentProps>;
126
+ href: string | ((row: TData) => string | undefined);
127
+ label?: string | ((row: TData) => string | undefined);
128
+ target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
129
+ rel?: string;
130
+ };
131
+ declare function resolveRowHref<TData extends RowData>(link: Pick<BonelessTableRowLink<TData>, 'href'>, row: TData): string | undefined;
132
+ declare function resolveRowLinkLabel<TData extends RowData>(link: Pick<BonelessTableRowLink<TData>, 'label'>, row: TData): string | undefined;
133
+
134
+ type BonelessTableToolbarLayout<TData extends RowData> = (context: {
135
+ table: Table<TData>;
136
+ summary: ReactNode;
137
+ actions: ReactNode;
138
+ }) => ReactNode;
139
+ type BonelessTableSlot<TData extends RowData> = boolean | ReactNode | ((table: Table<TData>) => ReactNode);
140
+ type BonelessTableRowClickEvent = MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>;
141
+ /**
142
+ * Named hooks for your stylesheet. The renderer applies no default class names or visual styles.
143
+ */
144
+ type BonelessTableClassNames = Partial<{
145
+ root: string;
146
+ toolbar: string;
147
+ toolbarSummary: string;
148
+ toolbarHint: string;
149
+ toolbarActions: string;
150
+ scroller: string;
151
+ table: string;
152
+ headerGroup: string;
153
+ headerRow: string;
154
+ header: string;
155
+ headerButton: string;
156
+ sortIndicator: string;
157
+ rowGroup: string;
158
+ row: string;
159
+ cell: string;
160
+ footer: string;
161
+ filter: string;
162
+ columnMenu: string;
163
+ rowLink: string;
164
+ emptyState: string;
165
+ skeleton: string;
166
+ }>;
167
+ /** Optional consumer-owned icons. Omit these for a text-only renderer. */
168
+ type BonelessTableIcons = ColumnMenuIcons & {
169
+ reset?: ReactNode;
170
+ columns?: ReactNode;
171
+ search?: ReactNode;
172
+ sort?: (direction: false | 'asc' | 'desc') => ReactNode;
173
+ expand?: ReactNode;
174
+ collapse?: ReactNode;
175
+ };
176
+ type BonelessTableTreeOptions = {
177
+ /** Column that receives the in-cell indentation and row control. Defaults to the first visible column. */
178
+ columnId?: string;
179
+ /** Pixel increment per tree level. Indentation stays inside the cell and never changes the grid. */
180
+ indentPx?: number;
181
+ expandAllLabel?: string;
182
+ collapseAllLabel?: string;
183
+ };
184
+ type BonelessTablePresentationOptions<TData extends RowData> = {
185
+ settings?: DeepPartial<BonelessTableSettings>;
186
+ className?: string;
187
+ classNames?: BonelessTableClassNames;
188
+ icons?: BonelessTableIcons;
189
+ /** Enables nested row controls when used with TanStack's getSubRows option. */
190
+ tree?: boolean | BonelessTableTreeOptions;
191
+ isLoading?: boolean;
192
+ isFetchingMore?: boolean;
193
+ skeletonRows?: number;
194
+ skeletonLabel?: string;
195
+ onNearEnd?: () => void;
196
+ /** Enables onNearEnd. Keep this false while there is no next page or a request is in flight. */
197
+ canLoadMore?: boolean;
198
+ nearEndOffset?: number;
199
+ /** Delay text-filter updates to avoid recomputing large client-side row models on every keystroke. */
200
+ filterDebounceMs?: number;
201
+ /** Content-sized by default. Use fill only inside a parent that provides a stable height. */
202
+ scroller?: 'fill' | 'auto';
203
+ toolbar?: BonelessTableSlot<TData>;
204
+ /** Reposition the default summary and action controls without rebuilding their behavior. */
205
+ toolbarLayout?: BonelessTableToolbarLayout<TData>;
206
+ footer?: BonelessTableSlot<TData>;
207
+ totalCount?: number;
208
+ resultLabel?: string;
209
+ resultHint?: string;
210
+ onReset?: () => void;
211
+ onRowClick?: (row: TData, event: BonelessTableRowClickEvent) => void;
212
+ scrollToTopOn?: unknown;
213
+ rowLink?: BonelessTableRowLink<TData>;
214
+ /** Content shown when loading is complete and no rows match the current table state. */
215
+ emptyState?: ReactNode | ((table: Table<TData>) => ReactNode);
216
+ /** Set to false to render every row, or configure virtual rows when scroller is "fill". */
217
+ virtualization?: false | {
218
+ estimateSize?: number;
219
+ overscan?: number;
220
+ };
221
+ };
222
+ /**
223
+ * TanStack options supported by this renderer. Grouping, pagination, selection,
224
+ * pinning, sizing, and faceting are intentionally outside this component's UI contract.
225
+ * Nested expansion is supported through getSubRows together with the tree presentation option.
226
+ */
227
+ type BonelessTableOptions<TData extends RowData> = Omit<Pick<TableOptions<TData>, 'getRowId' | 'getCoreRowModel' | 'getFilteredRowModel' | 'getSortedRowModel' | 'getSubRows' | 'onSortingChange' | 'onColumnFiltersChange' | 'onColumnVisibilityChange' | 'onColumnOrderChange' | 'onExpandedChange' | 'manualSorting' | 'manualFiltering' | 'enableSorting' | 'enableMultiSort' | 'enableSortingRemoval' | 'enableMultiRemove' | 'maxMultiSortColCount' | 'filterFromLeafRows' | 'maxLeafRowFilterDepth' | 'isMultiSortEvent' | 'sortDescFirst' | 'sortingFns' | 'enableFilters' | 'filterFns' | 'defaultColumn' | 'renderFallbackValue' | 'meta' | 'debugTable' | 'debugHeaders' | 'debugColumns'>, 'getCoreRowModel' | 'getFilteredRowModel' | 'getSortedRowModel'> & Partial<Pick<TableOptions<TData>, 'getCoreRowModel' | 'getFilteredRowModel' | 'getSortedRowModel'>> & {
228
+ state?: Partial<Pick<TableState, 'sorting' | 'columnFilters' | 'columnVisibility' | 'columnOrder' | 'expanded'>>;
229
+ initialState?: Partial<Pick<TableState, 'sorting' | 'columnFilters' | 'columnVisibility' | 'columnOrder' | 'expanded'>>;
230
+ };
231
+ type BonelessTableProps<TData extends RowData> = BonelessTableOptions<TData> & BonelessTablePresentationOptions<TData> & {
232
+ data: TData[];
233
+ columns: BonelessTableColumn<TData>[];
234
+ };
235
+ declare function BonelessTable<TData extends RowData>({ data, columns, settings: settingsOverride, className, classNames, icons, tree: treeOption, isLoading, isFetchingMore, skeletonRows, skeletonLabel, onNearEnd, canLoadMore, nearEndOffset, filterDebounceMs, scroller, toolbar, toolbarLayout, footer, totalCount, resultLabel, resultHint, onReset, onRowClick, scrollToTopOn, rowLink, emptyState, virtualization, ...tableOptions }: BonelessTableProps<TData>): react.JSX.Element;
236
+
237
+ declare function defineColumns<TData extends RowData>(columns: BonelessTableColumn<TData>[]): BonelessTableColumn<TData>[];
238
+ declare function resolveColumns<TData extends RowData>(columns: BonelessTableColumn<TData>[]): ResolvedBonelessTableColumn<TData>[];
239
+ declare function withDefaultCells<TData extends RowData>(columns: ResolvedBonelessTableColumn<TData>[]): ResolvedBonelessTableColumn<TData>[];
240
+ declare function getColumnIds<TData extends RowData>(columns: BonelessTableColumn<TData>[]): string[];
241
+
242
+ declare function ColumnFilter<TData extends RowData>({ column, settings, className, icon, debounceMs, }: {
243
+ column: Column<TData, unknown>;
244
+ settings: NonNullable<BonelessTableColumnSettings['filtering']>;
245
+ className?: string;
246
+ /** Optional consumer-owned icon rendered before a text input. */
247
+ icon?: ReactNode;
248
+ debounceMs?: number;
249
+ }): react.JSX.Element;
250
+
251
+ declare function TableSkeleton({ columnCount, rows, label, classNames, }: {
252
+ columnCount: number;
253
+ rows: number;
254
+ label?: string;
255
+ classNames?: Pick<BonelessTableClassNames, 'row' | 'cell' | 'skeleton'>;
256
+ }): react.JSX.Element;
257
+
258
+ export { BonelessTable, type BonelessTableClassNames, type BonelessTableColumn, type BonelessTableColumnSettings, type BonelessTableIcons, type BonelessTableOptions, type BonelessTablePresentationOptions, type BonelessTableProps, type BonelessTableRowClickEvent, type BonelessTableRowLink, type BonelessTableRowLinkComponentProps, type BonelessTableSettings, type BonelessTableSlot, type BonelessTableToolbarLayout, type BonelessTableTreeOptions, type ColumnAlignment, type ColumnBorders, ColumnFilter, ColumnMenu, type DeepPartial, type FilterType, type ResolvedBonelessTableColumn, type RevealMode, TableSkeleton, compactValue, defaultBonelessTableSettings, defineColumns, getColumnIds, mergeBonelessTableSettings, resolveColumnSettings, resolveColumns, resolveRowHref, resolveRowLinkLabel, withDefaultCells };
@@ -0,0 +1,258 @@
1
+ import { RowData, ColumnDef, Table, TableOptions, TableState, Column } from '@tanstack/react-table';
2
+ export { ColumnDef, ColumnFiltersState, ColumnOrderState, ExpandedState, SortingState, Table, TableOptions, VisibilityState, createColumnHelper, flexRender, getCoreRowModel, getExpandedRowModel, getFilteredRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
3
+ import * as react from 'react';
4
+ import { ReactNode, RefObject, ComponentType, AnchorHTMLAttributes, MouseEvent, KeyboardEvent } from 'react';
5
+
6
+ type ColumnAlignment = 'left' | 'right';
7
+ type ColumnBorders = 'none' | 'left' | 'right' | 'both';
8
+ type FilterType = 'text' | 'select';
9
+ type RevealMode = 'always' | 'hover';
10
+ type BonelessTableColumnSizing = {
11
+ widthPx: number;
12
+ } | {
13
+ minPx: number;
14
+ flex?: number;
15
+ };
16
+ type BonelessTableColumnSettings = {
17
+ sizing?: BonelessTableColumnSizing;
18
+ align?: ColumnAlignment;
19
+ borders?: ColumnBorders;
20
+ sorting?: {
21
+ enabled?: boolean;
22
+ reveal?: RevealMode;
23
+ };
24
+ filtering?: {
25
+ type: FilterType;
26
+ options?: readonly string[];
27
+ reveal?: RevealMode;
28
+ };
29
+ valueDisplay?: {
30
+ truncateAt: number;
31
+ suffix?: string;
32
+ };
33
+ };
34
+ type BonelessTableSettings = {
35
+ columnDefaults: Required<Pick<BonelessTableColumnSettings, 'align' | 'borders'>> & {
36
+ sizing: Required<NonNullable<BonelessTableColumnSettings['sizing']>>;
37
+ sorting: Required<NonNullable<BonelessTableColumnSettings['sorting']>>;
38
+ };
39
+ interactions: {
40
+ filterReveal: RevealMode;
41
+ horizontalOverflow: 'auto' | 'scroll';
42
+ };
43
+ };
44
+ declare const defaultBonelessTableSettings: BonelessTableSettings;
45
+ declare function mergeBonelessTableSettings(override?: DeepPartial<BonelessTableSettings>, base?: BonelessTableSettings): BonelessTableSettings;
46
+ declare function resolveColumnSettings(settings: BonelessTableSettings, column: {
47
+ columnDef: {
48
+ meta?: {
49
+ bonelessTable?: BonelessTableColumnSettings;
50
+ };
51
+ };
52
+ }): {
53
+ sizing: {
54
+ minPx?: number | undefined;
55
+ flex?: number;
56
+ widthPx: number;
57
+ } | {
58
+ minPx: number;
59
+ flex: number;
60
+ };
61
+ align: ColumnAlignment;
62
+ borders: ColumnBorders;
63
+ sorting: {
64
+ enabled: boolean;
65
+ reveal: RevealMode;
66
+ };
67
+ filtering: {
68
+ type: FilterType;
69
+ options?: readonly string[];
70
+ reveal?: RevealMode;
71
+ } | undefined;
72
+ valueDisplay: {
73
+ truncateAt: number;
74
+ suffix?: string;
75
+ } | undefined;
76
+ };
77
+ declare function compactValue(value: unknown, settings?: BonelessTableColumnSettings): string;
78
+
79
+ declare module '@tanstack/react-table' {
80
+ interface ColumnMeta<TData extends RowData, TValue> {
81
+ bonelessTable?: BonelessTableColumnSettings;
82
+ /** Accessible label used for this column in the built-in column chooser. */
83
+ columnLabel?: string;
84
+ }
85
+ }
86
+ /**
87
+ * A friendlier column input: use `key` for a data property instead of TanStack's `accessorKey`.
88
+ * `accessorKey` remains accepted for interoperability with existing TanStack column definitions.
89
+ */
90
+ type BonelessTableColumn<TData extends RowData, TValue = unknown> = ColumnDef<TData, TValue> | (Omit<ColumnDef<TData, TValue>, 'accessorKey'> & {
91
+ key: keyof TData & string;
92
+ });
93
+ type ResolvedBonelessTableColumn<TData extends RowData, TValue = unknown> = ColumnDef<TData, TValue>;
94
+ type DeepPartial<T> = {
95
+ [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
96
+ };
97
+
98
+ type ColumnMenuIcons = Partial<{
99
+ close: ReactNode;
100
+ moveEarlier: ReactNode;
101
+ moveLater: ReactNode;
102
+ }>;
103
+ declare function ColumnMenu<TData>({ table, onClose, onMoveColumn, className, icons, id, triggerRef, }: {
104
+ table: Table<TData>;
105
+ onClose: () => void;
106
+ onMoveColumn: (id: string, direction: -1 | 1) => void;
107
+ className?: string;
108
+ /** Optional consumer-owned icons. Text labels remain available without them. */
109
+ icons?: ColumnMenuIcons;
110
+ id?: string;
111
+ /** The menu trigger is not an outside click; this lets it reliably toggle the dialog closed. */
112
+ triggerRef?: RefObject<HTMLElement | null>;
113
+ }): react.JSX.Element;
114
+
115
+ type BonelessTableRowLinkComponentProps = {
116
+ children: ReactNode;
117
+ className: string;
118
+ href: string;
119
+ 'aria-label'?: string;
120
+ target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
121
+ rel?: string;
122
+ };
123
+ type BonelessTableRowLink<TData extends RowData> = {
124
+ /** A framework-specific component such as Next.js Link that wraps each resolved row. */
125
+ component: ComponentType<BonelessTableRowLinkComponentProps>;
126
+ href: string | ((row: TData) => string | undefined);
127
+ label?: string | ((row: TData) => string | undefined);
128
+ target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
129
+ rel?: string;
130
+ };
131
+ declare function resolveRowHref<TData extends RowData>(link: Pick<BonelessTableRowLink<TData>, 'href'>, row: TData): string | undefined;
132
+ declare function resolveRowLinkLabel<TData extends RowData>(link: Pick<BonelessTableRowLink<TData>, 'label'>, row: TData): string | undefined;
133
+
134
+ type BonelessTableToolbarLayout<TData extends RowData> = (context: {
135
+ table: Table<TData>;
136
+ summary: ReactNode;
137
+ actions: ReactNode;
138
+ }) => ReactNode;
139
+ type BonelessTableSlot<TData extends RowData> = boolean | ReactNode | ((table: Table<TData>) => ReactNode);
140
+ type BonelessTableRowClickEvent = MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>;
141
+ /**
142
+ * Named hooks for your stylesheet. The renderer applies no default class names or visual styles.
143
+ */
144
+ type BonelessTableClassNames = Partial<{
145
+ root: string;
146
+ toolbar: string;
147
+ toolbarSummary: string;
148
+ toolbarHint: string;
149
+ toolbarActions: string;
150
+ scroller: string;
151
+ table: string;
152
+ headerGroup: string;
153
+ headerRow: string;
154
+ header: string;
155
+ headerButton: string;
156
+ sortIndicator: string;
157
+ rowGroup: string;
158
+ row: string;
159
+ cell: string;
160
+ footer: string;
161
+ filter: string;
162
+ columnMenu: string;
163
+ rowLink: string;
164
+ emptyState: string;
165
+ skeleton: string;
166
+ }>;
167
+ /** Optional consumer-owned icons. Omit these for a text-only renderer. */
168
+ type BonelessTableIcons = ColumnMenuIcons & {
169
+ reset?: ReactNode;
170
+ columns?: ReactNode;
171
+ search?: ReactNode;
172
+ sort?: (direction: false | 'asc' | 'desc') => ReactNode;
173
+ expand?: ReactNode;
174
+ collapse?: ReactNode;
175
+ };
176
+ type BonelessTableTreeOptions = {
177
+ /** Column that receives the in-cell indentation and row control. Defaults to the first visible column. */
178
+ columnId?: string;
179
+ /** Pixel increment per tree level. Indentation stays inside the cell and never changes the grid. */
180
+ indentPx?: number;
181
+ expandAllLabel?: string;
182
+ collapseAllLabel?: string;
183
+ };
184
+ type BonelessTablePresentationOptions<TData extends RowData> = {
185
+ settings?: DeepPartial<BonelessTableSettings>;
186
+ className?: string;
187
+ classNames?: BonelessTableClassNames;
188
+ icons?: BonelessTableIcons;
189
+ /** Enables nested row controls when used with TanStack's getSubRows option. */
190
+ tree?: boolean | BonelessTableTreeOptions;
191
+ isLoading?: boolean;
192
+ isFetchingMore?: boolean;
193
+ skeletonRows?: number;
194
+ skeletonLabel?: string;
195
+ onNearEnd?: () => void;
196
+ /** Enables onNearEnd. Keep this false while there is no next page or a request is in flight. */
197
+ canLoadMore?: boolean;
198
+ nearEndOffset?: number;
199
+ /** Delay text-filter updates to avoid recomputing large client-side row models on every keystroke. */
200
+ filterDebounceMs?: number;
201
+ /** Content-sized by default. Use fill only inside a parent that provides a stable height. */
202
+ scroller?: 'fill' | 'auto';
203
+ toolbar?: BonelessTableSlot<TData>;
204
+ /** Reposition the default summary and action controls without rebuilding their behavior. */
205
+ toolbarLayout?: BonelessTableToolbarLayout<TData>;
206
+ footer?: BonelessTableSlot<TData>;
207
+ totalCount?: number;
208
+ resultLabel?: string;
209
+ resultHint?: string;
210
+ onReset?: () => void;
211
+ onRowClick?: (row: TData, event: BonelessTableRowClickEvent) => void;
212
+ scrollToTopOn?: unknown;
213
+ rowLink?: BonelessTableRowLink<TData>;
214
+ /** Content shown when loading is complete and no rows match the current table state. */
215
+ emptyState?: ReactNode | ((table: Table<TData>) => ReactNode);
216
+ /** Set to false to render every row, or configure virtual rows when scroller is "fill". */
217
+ virtualization?: false | {
218
+ estimateSize?: number;
219
+ overscan?: number;
220
+ };
221
+ };
222
+ /**
223
+ * TanStack options supported by this renderer. Grouping, pagination, selection,
224
+ * pinning, sizing, and faceting are intentionally outside this component's UI contract.
225
+ * Nested expansion is supported through getSubRows together with the tree presentation option.
226
+ */
227
+ type BonelessTableOptions<TData extends RowData> = Omit<Pick<TableOptions<TData>, 'getRowId' | 'getCoreRowModel' | 'getFilteredRowModel' | 'getSortedRowModel' | 'getSubRows' | 'onSortingChange' | 'onColumnFiltersChange' | 'onColumnVisibilityChange' | 'onColumnOrderChange' | 'onExpandedChange' | 'manualSorting' | 'manualFiltering' | 'enableSorting' | 'enableMultiSort' | 'enableSortingRemoval' | 'enableMultiRemove' | 'maxMultiSortColCount' | 'filterFromLeafRows' | 'maxLeafRowFilterDepth' | 'isMultiSortEvent' | 'sortDescFirst' | 'sortingFns' | 'enableFilters' | 'filterFns' | 'defaultColumn' | 'renderFallbackValue' | 'meta' | 'debugTable' | 'debugHeaders' | 'debugColumns'>, 'getCoreRowModel' | 'getFilteredRowModel' | 'getSortedRowModel'> & Partial<Pick<TableOptions<TData>, 'getCoreRowModel' | 'getFilteredRowModel' | 'getSortedRowModel'>> & {
228
+ state?: Partial<Pick<TableState, 'sorting' | 'columnFilters' | 'columnVisibility' | 'columnOrder' | 'expanded'>>;
229
+ initialState?: Partial<Pick<TableState, 'sorting' | 'columnFilters' | 'columnVisibility' | 'columnOrder' | 'expanded'>>;
230
+ };
231
+ type BonelessTableProps<TData extends RowData> = BonelessTableOptions<TData> & BonelessTablePresentationOptions<TData> & {
232
+ data: TData[];
233
+ columns: BonelessTableColumn<TData>[];
234
+ };
235
+ declare function BonelessTable<TData extends RowData>({ data, columns, settings: settingsOverride, className, classNames, icons, tree: treeOption, isLoading, isFetchingMore, skeletonRows, skeletonLabel, onNearEnd, canLoadMore, nearEndOffset, filterDebounceMs, scroller, toolbar, toolbarLayout, footer, totalCount, resultLabel, resultHint, onReset, onRowClick, scrollToTopOn, rowLink, emptyState, virtualization, ...tableOptions }: BonelessTableProps<TData>): react.JSX.Element;
236
+
237
+ declare function defineColumns<TData extends RowData>(columns: BonelessTableColumn<TData>[]): BonelessTableColumn<TData>[];
238
+ declare function resolveColumns<TData extends RowData>(columns: BonelessTableColumn<TData>[]): ResolvedBonelessTableColumn<TData>[];
239
+ declare function withDefaultCells<TData extends RowData>(columns: ResolvedBonelessTableColumn<TData>[]): ResolvedBonelessTableColumn<TData>[];
240
+ declare function getColumnIds<TData extends RowData>(columns: BonelessTableColumn<TData>[]): string[];
241
+
242
+ declare function ColumnFilter<TData extends RowData>({ column, settings, className, icon, debounceMs, }: {
243
+ column: Column<TData, unknown>;
244
+ settings: NonNullable<BonelessTableColumnSettings['filtering']>;
245
+ className?: string;
246
+ /** Optional consumer-owned icon rendered before a text input. */
247
+ icon?: ReactNode;
248
+ debounceMs?: number;
249
+ }): react.JSX.Element;
250
+
251
+ declare function TableSkeleton({ columnCount, rows, label, classNames, }: {
252
+ columnCount: number;
253
+ rows: number;
254
+ label?: string;
255
+ classNames?: Pick<BonelessTableClassNames, 'row' | 'cell' | 'skeleton'>;
256
+ }): react.JSX.Element;
257
+
258
+ export { BonelessTable, type BonelessTableClassNames, type BonelessTableColumn, type BonelessTableColumnSettings, type BonelessTableIcons, type BonelessTableOptions, type BonelessTablePresentationOptions, type BonelessTableProps, type BonelessTableRowClickEvent, type BonelessTableRowLink, type BonelessTableRowLinkComponentProps, type BonelessTableSettings, type BonelessTableSlot, type BonelessTableToolbarLayout, type BonelessTableTreeOptions, type ColumnAlignment, type ColumnBorders, ColumnFilter, ColumnMenu, type DeepPartial, type FilterType, type ResolvedBonelessTableColumn, type RevealMode, TableSkeleton, compactValue, defaultBonelessTableSettings, defineColumns, getColumnIds, mergeBonelessTableSettings, resolveColumnSettings, resolveColumns, resolveRowHref, resolveRowLinkLabel, withDefaultCells };