bolt-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.
@@ -0,0 +1,1542 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React$1, { ReactNode, CSSProperties } from 'react';
3
+ import { Virtualizer } from '@tanstack/react-virtual';
4
+
5
+ /**
6
+ * The direction of a column sort.
7
+ *
8
+ * - `'asc'` — ascending order (A → Z, 0 → 9)
9
+ * - `'desc'` — descending order (Z → A, 9 → 0)
10
+ * - `null` — no sort applied
11
+ *
12
+ * @example
13
+ * const [sortDir, setSortDir] = useState<SortDirection>(null);
14
+ */
15
+ type SortDirection = 'asc' | 'desc' | null;
16
+ /**
17
+ * Defines the shape of a single column in BoltTable.
18
+ *
19
+ * @typeParam T - The type of a single row record. Defaults to `unknown`.
20
+ *
21
+ * @example
22
+ * const columns: ColumnType<User>[] = [
23
+ * {
24
+ * key: 'name',
25
+ * dataIndex: 'name',
26
+ * title: 'Full Name',
27
+ * width: 200,
28
+ * sortable: true,
29
+ * render: (value, record) => <strong>{record.name}</strong>,
30
+ * },
31
+ * ];
32
+ */
33
+ interface ColumnType<T = unknown> {
34
+ /**
35
+ * The text or React node shown in the column header.
36
+ *
37
+ * @example
38
+ * title: 'Full Name'
39
+ * title: <span style={{ color: 'red' }}>Name</span>
40
+ */
41
+ title: string | ReactNode;
42
+ /**
43
+ * The key in the row data object whose value this column displays.
44
+ * Must match a property name on your row record type `T`.
45
+ *
46
+ * @example
47
+ * // For a row { id: 1, firstName: 'John' }
48
+ * dataIndex: 'firstName'
49
+ */
50
+ dataIndex: string;
51
+ /**
52
+ * The fixed pixel width of this column.
53
+ * If omitted, defaults to `150px`.
54
+ * The last column always stretches to fill remaining space (minmax).
55
+ *
56
+ * @example
57
+ * width: 200
58
+ */
59
+ width?: number;
60
+ /**
61
+ * A unique identifier for this column.
62
+ * Used internally for drag-and-drop ordering, pinning, hiding, and sorting.
63
+ * Should match `dataIndex` in most cases unless you have computed columns.
64
+ *
65
+ * @example
66
+ * key: 'firstName'
67
+ */
68
+ key: string;
69
+ /**
70
+ * Custom render function for the cell content.
71
+ * If omitted, the raw value from `dataIndex` is rendered as-is.
72
+ *
73
+ * @param text - The raw cell value (`record[dataIndex]`)
74
+ * @param record - The full row data object
75
+ * @param index - The row index (0-based) in the current page/view
76
+ * @returns A React node to render inside the cell
77
+ *
78
+ * @example
79
+ * render: (value, record) => (
80
+ * <span style={{ color: record.isActive ? 'green' : 'gray' }}>
81
+ * {String(value)}
82
+ * </span>
83
+ * )
84
+ */
85
+ render?: (text: unknown, record: T, index: number) => ReactNode;
86
+ /**
87
+ * Custom render function for the shimmer (loading skeleton) state.
88
+ * When the table is loading and has no data, this replaces the default
89
+ * animated pulse bar for this column.
90
+ *
91
+ * @returns A React node to render as the loading placeholder
92
+ *
93
+ * @example
94
+ * shimmerRender: () => (
95
+ * <div style={{ width: 40, height: 40, borderRadius: '50%', background: '#eee' }} />
96
+ * )
97
+ */
98
+ shimmerRender?: () => ReactNode;
99
+ /**
100
+ * Whether this column shows sort controls (ascending/descending).
101
+ * Defaults to `true`. Set to `false` to hide sorting for this column entirely.
102
+ *
103
+ * @default true
104
+ *
105
+ * @example
106
+ * sortable: false // disables sort UI for this column
107
+ */
108
+ sortable?: boolean;
109
+ /**
110
+ * Custom sort comparator used for **client-side** (local) sorting.
111
+ * Only applies when no `onSortChange` callback is provided to BoltTable
112
+ * (i.e. you are not doing server-side sorting).
113
+ *
114
+ * - Pass `true` to use the default comparator (string localeCompare / number subtraction).
115
+ * - Pass a function `(a, b) => number` for custom sort logic.
116
+ * Return negative if `a` should come first, positive if `b` should come first, 0 if equal.
117
+ *
118
+ * @example
119
+ * // Default comparator
120
+ * sorter: true
121
+ *
122
+ * // Custom comparator — sort by string length
123
+ * sorter: (a, b) => String(a.name).length - String(b.name).length
124
+ *
125
+ * // Custom comparator — sort by date
126
+ * sorter: (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
127
+ */
128
+ sorter?: boolean | ((a: T, b: T) => number);
129
+ /**
130
+ * Whether this column shows a filter control in the context menu.
131
+ * Defaults to `true`. Set to `false` to hide filtering for this column.
132
+ *
133
+ * @default true
134
+ *
135
+ * @example
136
+ * filterable: false // disables filter UI for this column
137
+ */
138
+ filterable?: boolean;
139
+ /**
140
+ * Custom filter predicate used for **client-side** (local) filtering.
141
+ * Only applies when no `onFilterChange` callback is provided to BoltTable.
142
+ *
143
+ * @param filterValue - The string the user typed into the filter input
144
+ * @param record - The full row data object being tested
145
+ * @param dataIndex - The column's `dataIndex` value
146
+ * @returns `true` to keep the row, `false` to exclude it
147
+ *
148
+ * Falls back to a case-insensitive substring match when not provided.
149
+ *
150
+ * @example
151
+ * // Only show rows where the status exactly matches the filter
152
+ * filterFn: (filterValue, record) =>
153
+ * record.status === filterValue
154
+ *
155
+ * // Numeric range filter — keep rows where age >= filterValue
156
+ * filterFn: (filterValue, record) =>
157
+ * Number(record.age) >= Number(filterValue)
158
+ */
159
+ filterFn?: (filterValue: string, record: T, dataIndex: string) => boolean;
160
+ /**
161
+ * Whether this column is hidden by default on first render.
162
+ * The user can still show it via column visibility controls if you expose them.
163
+ *
164
+ * @default false
165
+ */
166
+ defaultHidden?: boolean;
167
+ /**
168
+ * Which side this column is pinned to by default on first render.
169
+ * - `'left'` — column sticks to the left edge while scrolling horizontally
170
+ * - `'right'` — column sticks to the right edge
171
+ * - `false` — column is not pinned (scrolls normally)
172
+ *
173
+ * @default false
174
+ */
175
+ defaultPinned?: 'left' | 'right' | false;
176
+ /**
177
+ * Controls the current hidden state of the column.
178
+ * Use this for controlled visibility (managed by parent state).
179
+ * For uncontrolled, use `defaultHidden` instead.
180
+ *
181
+ * @example
182
+ * hidden: hiddenColumns.includes('email')
183
+ */
184
+ hidden?: boolean;
185
+ /**
186
+ * Controls the current pinned state of the column.
187
+ * Use this for controlled pinning (managed by parent state).
188
+ * For uncontrolled, use `defaultPinned` instead.
189
+ *
190
+ * - `'left'` — pinned to the left
191
+ * - `'right'` — pinned to the right
192
+ * - `false` — not pinned
193
+ *
194
+ * @example
195
+ * pinned: 'left'
196
+ */
197
+ pinned?: 'left' | 'right' | false;
198
+ /**
199
+ * Additional CSS class name(s) applied to every cell in this column,
200
+ * including both the header and body cells.
201
+ *
202
+ * @example
203
+ * className: 'text-right font-mono'
204
+ */
205
+ className?: string;
206
+ /**
207
+ * Inline CSS styles applied to every cell in this column,
208
+ * including both the header and body cells.
209
+ *
210
+ * @example
211
+ * style: { textAlign: 'right', fontFamily: 'monospace' }
212
+ */
213
+ style?: React.CSSProperties;
214
+ }
215
+ /**
216
+ * A single item in the column header context menu (right-click menu).
217
+ * Use `columnContextMenuItems` on BoltTable to inject custom actions
218
+ * alongside the built-in sort/filter/pin/hide options.
219
+ *
220
+ * @example
221
+ * const menuItems: ColumnContextMenuItem[] = [
222
+ * {
223
+ * key: 'copy',
224
+ * label: 'Copy column data',
225
+ * icon: <CopyIcon />,
226
+ * onClick: (columnKey) => copyColumnToClipboard(columnKey),
227
+ * },
228
+ * {
229
+ * key: 'delete',
230
+ * label: 'Remove column',
231
+ * danger: true,
232
+ * onClick: (columnKey) => removeColumn(columnKey),
233
+ * },
234
+ * ];
235
+ */
236
+ interface ColumnContextMenuItem {
237
+ /**
238
+ * Unique identifier for this menu item.
239
+ * Used as the React `key` prop — must be unique among all custom items.
240
+ */
241
+ key: string;
242
+ /**
243
+ * The label shown in the menu. Can be a string or any React node.
244
+ *
245
+ * @example
246
+ * label: 'Copy column'
247
+ * label: <span style={{ fontWeight: 'bold' }}>Copy column</span>
248
+ */
249
+ label: React.ReactNode;
250
+ /**
251
+ * Optional icon shown to the left of the label.
252
+ * Recommended size: 12–14px (e.g. a lucide-react icon at h-3 w-3).
253
+ *
254
+ * @example
255
+ * icon: <CopyIcon className="h-3 w-3" />
256
+ */
257
+ icon?: React.ReactNode;
258
+ /**
259
+ * When `true`, the label renders in red to indicate a destructive action.
260
+ *
261
+ * @default false
262
+ */
263
+ danger?: boolean;
264
+ /**
265
+ * When `true`, the item is grayed out and the click handler is not called.
266
+ *
267
+ * @default false
268
+ */
269
+ disabled?: boolean;
270
+ /**
271
+ * Called when the user clicks this menu item.
272
+ *
273
+ * @param columnKey - The `key` of the column whose header was right-clicked
274
+ *
275
+ * @example
276
+ * onClick: (columnKey) => console.log('Clicked on column:', columnKey)
277
+ */
278
+ onClick: (columnKey: string) => void;
279
+ }
280
+ /**
281
+ * How the row selection was triggered.
282
+ *
283
+ * - `'all'` — select/deselect all rows via the header checkbox
284
+ * - `'single'` — a single row was selected (radio or single click)
285
+ * - `'multiple'` — individual checkboxes toggled
286
+ */
287
+ type RowSelectMethod = 'all' | 'single' | 'multiple';
288
+ /**
289
+ * Configuration for expandable rows.
290
+ * When provided, each row gets an expand toggle button that reveals
291
+ * a custom rendered panel below the row.
292
+ *
293
+ * @typeParam T - The type of a single row record
294
+ *
295
+ * @example
296
+ * const expandable: ExpandableConfig<Order> = {
297
+ * rowExpandable: (record) => record.items.length > 0,
298
+ * expandedRowRender: (record) => (
299
+ * <div>
300
+ * {record.items.map(item => <div key={item.id}>{item.name}</div>)}
301
+ * </div>
302
+ * ),
303
+ * };
304
+ */
305
+ interface ExpandableConfig<T = unknown> {
306
+ /**
307
+ * When `true`, all rows are expanded on initial render.
308
+ * Takes priority over `defaultExpandedRowKeys`.
309
+ *
310
+ * @default false
311
+ */
312
+ defaultExpandAllRows?: boolean;
313
+ /**
314
+ * Controlled list of currently expanded row keys.
315
+ * When provided, BoltTable operates in **controlled mode** — you must
316
+ * update this list yourself in `onExpandedRowsChange`.
317
+ * When omitted, BoltTable manages expansion state internally.
318
+ *
319
+ * @example
320
+ * expandedRowKeys={expandedKeys}
321
+ */
322
+ expandedRowKeys?: React.Key[];
323
+ /**
324
+ * Renders the expanded content panel for a row.
325
+ * This panel appears directly below the row when it is expanded.
326
+ * The panel auto-sizes to its content height.
327
+ *
328
+ * @param record - The row data object
329
+ * @param index - The row index (0-based)
330
+ * @param indent - The indent level (always 0 for flat tables)
331
+ * @param expanded - Whether the row is currently expanded (`true`)
332
+ * @returns The React content to render in the expanded panel
333
+ *
334
+ * @example
335
+ * expandedRowRender: (record) => (
336
+ * <pre>{JSON.stringify(record, null, 2)}</pre>
337
+ * )
338
+ */
339
+ expandedRowRender: (record: T, index: number, indent: number, expanded: boolean) => ReactNode;
340
+ /**
341
+ * Row keys that are expanded by default on first render (uncontrolled mode).
342
+ * Ignored when `expandedRowKeys` is provided.
343
+ *
344
+ * @example
345
+ * defaultExpandedRowKeys={['row-1', 'row-3']}
346
+ */
347
+ defaultExpandedRowKeys?: React.Key[];
348
+ /**
349
+ * Called whenever the set of expanded rows changes.
350
+ * In controlled mode, use this to update your `expandedRowKeys` state.
351
+ *
352
+ * @param expandedKeys - The full list of currently expanded row keys
353
+ *
354
+ * @example
355
+ * onExpandedRowsChange={(keys) => setExpandedKeys(keys)}
356
+ */
357
+ onExpandedRowsChange?: (expandedKeys: React.Key[]) => void;
358
+ /**
359
+ * Controls whether to show the expand icon for a specific row.
360
+ * Return `false` to hide the toggle for rows that cannot be expanded visually.
361
+ *
362
+ * @example
363
+ * showExpandIcon: (record) => record.hasChildren
364
+ */
365
+ showExpandIcon?: (record: T) => boolean;
366
+ /**
367
+ * Determines whether a specific row is expandable.
368
+ * When this returns `false` for a row, no expand button is rendered for it.
369
+ *
370
+ * @example
371
+ * rowExpandable: (record) => record.subRows.length > 0
372
+ */
373
+ rowExpandable?: (record: T) => boolean;
374
+ }
375
+ /**
376
+ * Configuration for row selection (checkboxes or radio buttons).
377
+ * When provided, a selection column is prepended to the left of the table.
378
+ *
379
+ * @typeParam T - The type of a single row record
380
+ *
381
+ * @example
382
+ * // Checkbox selection
383
+ * const rowSelection: RowSelectionConfig<User> = {
384
+ * type: 'checkbox',
385
+ * selectedRowKeys,
386
+ * onChange: (keys, rows) => setSelectedRowKeys(keys),
387
+ * };
388
+ *
389
+ * // Radio selection (single row only)
390
+ * const rowSelection: RowSelectionConfig<User> = {
391
+ * type: 'radio',
392
+ * selectedRowKeys,
393
+ * onChange: (keys, rows) => setSelectedRowKeys(keys),
394
+ * };
395
+ */
396
+ interface RowSelectionConfig<T = unknown> {
397
+ /**
398
+ * The type of selection control.
399
+ * - `'checkbox'` — multiple rows can be selected (default)
400
+ * - `'radio'` — only one row can be selected at a time
401
+ *
402
+ * @default 'checkbox'
403
+ */
404
+ type?: 'checkbox' | 'radio';
405
+ /**
406
+ * When `true`, hides the "select all" checkbox in the header.
407
+ * Useful when using radio mode or when you want to prevent bulk selection.
408
+ *
409
+ * @default false
410
+ */
411
+ hideSelectAll?: boolean;
412
+ /**
413
+ * The currently selected row keys (controlled).
414
+ * This must always be provided — BoltTable does not manage selection state internally.
415
+ * Keys are matched against the value returned by the `rowKey` prop on BoltTable.
416
+ *
417
+ * @example
418
+ * selectedRowKeys={['row-1', 'row-5']}
419
+ */
420
+ selectedRowKeys: React.Key[];
421
+ /**
422
+ * Called when the header "select all" checkbox is toggled.
423
+ *
424
+ * @param selected - `true` if selecting all, `false` if deselecting all
425
+ * @param selectedRows - The rows that are now selected
426
+ * @param changeRows - The rows that changed in this action
427
+ *
428
+ * @example
429
+ * onSelectAll: (selected, rows) => {
430
+ * setSelectedKeys(selected ? rows.map(r => r.id) : []);
431
+ * }
432
+ */
433
+ onSelectAll?: (selected: boolean, selectedRows: T[], changeRows: T[]) => void;
434
+ /**
435
+ * Called when a single row's checkbox or radio is toggled.
436
+ *
437
+ * @param record - The row record that was toggled
438
+ * @param selected - `true` if the row is now selected
439
+ * @param selectedRows - All currently selected rows after this change
440
+ * @param nativeEvent - The original DOM event
441
+ *
442
+ * @example
443
+ * onSelect: (record, selected) => {
444
+ * console.log(`Row ${record.id} is now ${selected ? 'selected' : 'deselected'}`);
445
+ * }
446
+ */
447
+ onSelect?: (record: T, selected: boolean, selectedRows: T[], nativeEvent: Event) => void;
448
+ /**
449
+ * Called whenever the selection changes for any reason (single toggle or select all).
450
+ * This is the primary callback for keeping your state in sync.
451
+ *
452
+ * @param selectedRowKeys - The full list of currently selected row keys
453
+ * @param selectedRows - The full list of currently selected row records
454
+ * @param info - Metadata about how the change was triggered
455
+ *
456
+ * @example
457
+ * onChange: (keys, rows) => {
458
+ * setSelectedRowKeys(keys);
459
+ * setSelectedRows(rows);
460
+ * }
461
+ */
462
+ onChange?: (selectedRowKeys: React.Key[], selectedRows: T[], info: {
463
+ type: RowSelectMethod;
464
+ }) => void;
465
+ /**
466
+ * Returns additional props for the checkbox/radio of a specific row.
467
+ * Currently supports `disabled` to prevent a row from being selected.
468
+ *
469
+ * @param record - The row record
470
+ * @returns An object with optional `disabled` boolean
471
+ *
472
+ * @example
473
+ * getCheckboxProps: (record) => ({
474
+ * disabled: record.status === 'locked',
475
+ * })
476
+ */
477
+ getCheckboxProps?: (record: T) => {
478
+ disabled?: boolean;
479
+ };
480
+ }
481
+ /**
482
+ * Configuration for the pagination footer.
483
+ * Pass `false` to the `pagination` prop on BoltTable to disable pagination entirely.
484
+ *
485
+ * BoltTable supports both **client-side** and **server-side** pagination:
486
+ * - **Client-side**: pass all your data at once; BoltTable slices it per page automatically.
487
+ * - **Server-side**: pass only the current page's data; set `total` to the full dataset size
488
+ * and handle `onPaginationChange` to fetch the next page from your API.
489
+ *
490
+ * @example
491
+ * // Client-side (pass all data)
492
+ * pagination={{ pageSize: 20 }}
493
+ *
494
+ * // Server-side
495
+ * pagination={{
496
+ * current: page,
497
+ * pageSize: 20,
498
+ * total: 500,
499
+ * showTotal: (total, range) => `${range[0]}-${range[1]} of ${total}`,
500
+ * }}
501
+ */
502
+ interface PaginationType {
503
+ /**
504
+ * The current active page number (1-based).
505
+ * Required for controlled / server-side pagination.
506
+ * Defaults to `1` if omitted.
507
+ *
508
+ * @example
509
+ * current: 3 // currently on page 3
510
+ */
511
+ current?: number;
512
+ /**
513
+ * Number of rows displayed per page.
514
+ * The user can also change this via the page-size selector in the footer.
515
+ *
516
+ * @default 10
517
+ *
518
+ * @example
519
+ * pageSize: 25
520
+ */
521
+ pageSize?: number;
522
+ /**
523
+ * The total number of rows across **all pages**.
524
+ * Required for server-side pagination so BoltTable knows how many pages exist.
525
+ * For client-side pagination, omit this — BoltTable calculates it from `data.length`.
526
+ *
527
+ * @example
528
+ * total: 1234 // 1234 rows total on the server
529
+ */
530
+ total?: number;
531
+ /**
532
+ * Custom renderer for the "showing X-Y of Z" text in the pagination footer.
533
+ *
534
+ * @param total - The total number of rows
535
+ * @param range - A tuple `[start, end]` of the currently visible row range
536
+ * @returns A React node to render as the total label
537
+ *
538
+ * @example
539
+ * showTotal: (total, [start, end]) => `Showing ${start} to ${end} of ${total} results`
540
+ */
541
+ showTotal?: (total: number, range: [number, number]) => ReactNode;
542
+ }
543
+ /**
544
+ * The base type for a row record in BoltTable.
545
+ * All row data objects must be indexable by string keys.
546
+ *
547
+ * BoltTable is generic over `T extends DataRecord`, so you can pass your
548
+ * own strongly-typed row type for full type safety in `render`, `sorter`,
549
+ * `filterFn`, and selection callbacks.
550
+ *
551
+ * @example
552
+ * interface User extends DataRecord {
553
+ * id: string;
554
+ * name: string;
555
+ * email: string;
556
+ * age: number;
557
+ * }
558
+ *
559
+ * <BoltTable<User> columns={columns} data={users} />
560
+ */
561
+ type DataRecord = Record<string, unknown>;
562
+
563
+ /**
564
+ * Props for the BoltTable component.
565
+ *
566
+ * @typeParam T - The type of a single row record. Must extend `DataRecord`
567
+ * (i.e. `Record<string, unknown>`). Pass your own interface for
568
+ * full type safety in column `render`, `sorter`, and `filterFn`.
569
+ *
570
+ * @example
571
+ * interface User {
572
+ * id: string;
573
+ * name: string;
574
+ * email: string;
575
+ * age: number;
576
+ * }
577
+ *
578
+ * <BoltTable<User>
579
+ * columns={columns}
580
+ * data={users}
581
+ * rowKey="id"
582
+ * pagination={{ pageSize: 20 }}
583
+ * />
584
+ */
585
+ interface BoltTableProps<T extends DataRecord = DataRecord> {
586
+ /**
587
+ * Column definitions array. Controls what columns are shown, their order,
588
+ * width, pinning, sort/filter behavior, and cell rendering.
589
+ *
590
+ * BoltTable watches this array for changes using a content fingerprint
591
+ * (key + hidden + pinned + width). The internal column state syncs whenever
592
+ * the fingerprint changes, but sub-pixel width jitter (e.g. percentage widths)
593
+ * is normalized to avoid unnecessary re-syncs.
594
+ *
595
+ * @example
596
+ * const columns: ColumnType<User>[] = [
597
+ * { key: 'name', dataIndex: 'name', title: 'Name', width: 200, sortable: true },
598
+ * { key: 'email', dataIndex: 'email', title: 'Email', width: 250 },
599
+ * { key: 'age', dataIndex: 'age', title: 'Age', width: 80, sortable: true },
600
+ * ];
601
+ */
602
+ readonly columns: ColumnType<T>[];
603
+ /**
604
+ * The row data to display. Each element corresponds to one table row.
605
+ *
606
+ * For **client-side** pagination/sort/filter, pass the full dataset.
607
+ * BoltTable will slice, sort, and filter it internally.
608
+ *
609
+ * For **server-side** operations, pass only the current page's data and
610
+ * provide `onSortChange`, `onFilterChange`, and `onPaginationChange` callbacks
611
+ * to handle these operations on your server.
612
+ *
613
+ * @example
614
+ * data={users} // User[]
615
+ */
616
+ readonly data: T[];
617
+ /**
618
+ * Height of each regular (non-expanded) row in pixels.
619
+ * All rows must have the same base height for virtualization to work correctly.
620
+ *
621
+ * @default 40
622
+ *
623
+ * @example
624
+ * rowHeight={48}
625
+ */
626
+ readonly rowHeight?: number;
627
+ /**
628
+ * The **estimated** height (in pixels) for expanded row content panels.
629
+ * Used as the initial size estimate when a row is first expanded, before
630
+ * the actual content height has been measured by ResizeObserver.
631
+ * Once measured, the virtualizer updates to the real height.
632
+ *
633
+ * Set this close to your typical expanded row height for the smoothest experience.
634
+ *
635
+ * @default 200
636
+ *
637
+ * @example
638
+ * expandedRowHeight={300}
639
+ */
640
+ readonly expandedRowHeight?: number;
641
+ /**
642
+ * Optional maximum height in pixels for expanded row panels.
643
+ * When the expanded content exceeds this height, the panel becomes scrollable.
644
+ * When omitted, panels grow to their full content height.
645
+ *
646
+ * @example
647
+ * maxExpandedRowHeight={400}
648
+ */
649
+ readonly maxExpandedRowHeight?: number;
650
+ /**
651
+ * The primary color used for interactive elements throughout the table:
652
+ * - Sort direction indicators in column headers
653
+ * - Active filter icon in column headers
654
+ * - Column resize overlay line and label
655
+ * - Selected row background tint (as a transparent overlay)
656
+ * - Expand/collapse chevron buttons
657
+ * - Checkbox and radio button accent color
658
+ * - Highlighted sort/filter options in the context menu
659
+ * - Page number highlight in the pagination footer
660
+ *
661
+ * Accepts any valid CSS color string.
662
+ *
663
+ * @default '#1890ff'
664
+ *
665
+ * @example
666
+ * accentColor="#6366f1" // indigo
667
+ * accentColor="#10b981" // emerald
668
+ * accentColor="hsl(262, 80%, 50%)"
669
+ */
670
+ readonly accentColor?: string;
671
+ /**
672
+ * Additional CSS class name applied to the outermost wrapper div of BoltTable.
673
+ * Use this to apply custom sizing, border, or shadow to the table container.
674
+ *
675
+ * @example
676
+ * className="rounded-lg border shadow-sm"
677
+ */
678
+ readonly className?: string;
679
+ /**
680
+ * Granular CSS class name overrides for specific parts of the table.
681
+ * Each key targets a different region of the table.
682
+ *
683
+ * @example
684
+ * classNames={{
685
+ * header: 'text-xs uppercase tracking-wider',
686
+ * cell: 'text-sm',
687
+ * row: 'border-b',
688
+ * pinnedHeader: 'bg-blue-50',
689
+ * pinnedCell: 'bg-blue-50/50',
690
+ * }}
691
+ */
692
+ readonly classNames?: ClassNamesTypes;
693
+ /**
694
+ * Inline style overrides for specific parts of the table.
695
+ * Applied after all default and className-based styles, so these take
696
+ * the highest specificity.
697
+ *
698
+ * Note: `pinnedBg` is a special string property (not CSSProperties) that
699
+ * sets the background color of pinned column cells and headers directly.
700
+ *
701
+ * @example
702
+ * styles={{
703
+ * header: { fontSize: 12, fontWeight: 600 },
704
+ * pinnedBg: 'rgba(239, 246, 255, 0.9)',
705
+ * rowHover: { backgroundColor: '#f0f9ff' },
706
+ * rowSelected: { backgroundColor: '#dbeafe' },
707
+ * }}
708
+ */
709
+ readonly styles?: StylesTypes;
710
+ /**
711
+ * A custom React node to use as the drag grip icon in column headers.
712
+ * When omitted, the default `GripVertical` icon from lucide-react is used.
713
+ * Ignored when `hideGripIcon` is `true`.
714
+ *
715
+ * @example
716
+ * gripIcon={<DragHandleIcon className="h-3 w-3" />}
717
+ */
718
+ readonly gripIcon?: React$1.ReactNode;
719
+ /**
720
+ * When `true`, the drag grip icon is hidden from all column headers.
721
+ * Columns can still be dragged even without the grip icon.
722
+ *
723
+ * @default false
724
+ *
725
+ * @example
726
+ * hideGripIcon={true}
727
+ */
728
+ readonly hideGripIcon?: boolean;
729
+ /**
730
+ * Pagination configuration for the footer, or `false` to disable pagination entirely.
731
+ *
732
+ * **Client-side pagination** (pass all data, BoltTable slices it):
733
+ * ```tsx
734
+ * pagination={{ pageSize: 20 }}
735
+ * ```
736
+ *
737
+ * **Server-side pagination** (pass only current page's data):
738
+ * ```tsx
739
+ * pagination={{ current: page, pageSize: 20, total: 500 }}
740
+ * onPaginationChange={(page, size) => fetchPage(page, size)}
741
+ * ```
742
+ *
743
+ * **Disable pagination:**
744
+ * ```tsx
745
+ * pagination={false}
746
+ * ```
747
+ *
748
+ * @default undefined (pagination footer shown with default settings)
749
+ */
750
+ readonly pagination?: PaginationType | false;
751
+ /**
752
+ * Called when the user changes the current page or page size via the pagination footer.
753
+ * Required for server-side pagination. For client-side pagination, this is optional
754
+ * (BoltTable handles page changes internally).
755
+ *
756
+ * @param page - The new page number (1-based)
757
+ * @param pageSize - The new page size
758
+ *
759
+ * @example
760
+ * onPaginationChange={(page, size) => {
761
+ * setCurrentPage(page);
762
+ * setPageSize(size);
763
+ * fetchData({ page, size });
764
+ * }}
765
+ */
766
+ readonly onPaginationChange?: (page: number, pageSize: number) => void;
767
+ /**
768
+ * Called when the user finishes resizing a column (on mouse up).
769
+ * Use this to persist the new width to your state or storage.
770
+ *
771
+ * @param columnKey - The `key` of the resized column
772
+ * @param newWidth - The new column width in pixels
773
+ *
774
+ * @example
775
+ * onColumnResize={(key, width) => {
776
+ * setColumnWidths(prev => ({ ...prev, [key]: width }));
777
+ * }}
778
+ */
779
+ readonly onColumnResize?: (columnKey: string, newWidth: number) => void;
780
+ /**
781
+ * Called after the user drops a column header into a new position.
782
+ * Receives the full new column key order.
783
+ * Use this to persist the order to your state or storage.
784
+ *
785
+ * @param newOrder - Array of all column keys in their new order
786
+ *
787
+ * @example
788
+ * onColumnOrderChange={(order) => {
789
+ * setColumnOrder(order);
790
+ * }}
791
+ */
792
+ readonly onColumnOrderChange?: (newOrder: string[]) => void;
793
+ /**
794
+ * Called when the user pins or unpins a column via the context menu.
795
+ *
796
+ * @param columnKey - The `key` of the column whose pin state changed
797
+ * @param pinned - The new pin state: `'left'`, `'right'`, or `false`
798
+ *
799
+ * @example
800
+ * onColumnPin={(key, pinned) => {
801
+ * setColumns(prev => prev.map(col =>
802
+ * col.key === key ? { ...col, pinned } : col
803
+ * ));
804
+ * }}
805
+ */
806
+ readonly onColumnPin?: (columnKey: string, pinned: 'left' | 'right' | false) => void;
807
+ /**
808
+ * Called when the user hides or shows a column via the context menu.
809
+ * Note: pinned columns cannot be hidden.
810
+ *
811
+ * @param columnKey - The `key` of the column whose visibility changed
812
+ * @param hidden - `true` if the column is now hidden, `false` if now visible
813
+ *
814
+ * @example
815
+ * onColumnHide={(key, hidden) => {
816
+ * setColumns(prev => prev.map(col =>
817
+ * col.key === key ? { ...col, hidden } : col
818
+ * ));
819
+ * }}
820
+ */
821
+ readonly onColumnHide?: (columnKey: string, hidden: boolean) => void;
822
+ /**
823
+ * Determines the unique key for each row. Used for selection, expansion,
824
+ * and stable virtualizer item keys.
825
+ *
826
+ * Can be:
827
+ * - A **string**: the name of a property on the row object (e.g. `'id'`)
828
+ * - A **function**: `(record) => string` for computed keys
829
+ * - A **number** or **symbol**: property access by index/symbol
830
+ *
831
+ * Always returns a string internally (numbers/symbols are coerced to string).
832
+ *
833
+ * @default 'id'
834
+ *
835
+ * @example
836
+ * rowKey="id"
837
+ * rowKey={(record) => `${record.type}-${record.id}`}
838
+ */
839
+ readonly rowKey?: string | ((record: T) => string) | number | symbol;
840
+ /**
841
+ * Row selection configuration. When provided, prepends a checkbox (or radio)
842
+ * column to the left of the table.
843
+ *
844
+ * BoltTable does not manage selection state internally — you must track
845
+ * `selectedRowKeys` in your own state and update it in `onChange`.
846
+ *
847
+ * @example
848
+ * rowSelection={{
849
+ * type: 'checkbox',
850
+ * selectedRowKeys,
851
+ * onChange: (keys) => setSelectedRowKeys(keys),
852
+ * }}
853
+ */
854
+ expandable?: ExpandableConfig<T>;
855
+ /**
856
+ * Expandable row configuration. When provided, prepends an expand toggle
857
+ * column to the left of the table (to the right of the selection column
858
+ * if both are used).
859
+ *
860
+ * Supports both controlled (`expandedRowKeys`) and uncontrolled modes.
861
+ *
862
+ * @example
863
+ * expandable={{
864
+ * rowExpandable: (record) => record.hasDetails,
865
+ * expandedRowRender: (record) => <DetailPanel record={record} />,
866
+ * }}
867
+ */
868
+ readonly rowSelection?: RowSelectionConfig<T>;
869
+ /**
870
+ * Called when the user scrolls near the bottom of the table.
871
+ * Use this for infinite scroll / load-more behavior.
872
+ * Fires when the last visible row is within `onEndReachedThreshold` rows of the end.
873
+ *
874
+ * A debounce guard prevents this from firing repeatedly — it resets automatically
875
+ * when `data.length` changes or when `isLoading` flips back to `false`.
876
+ *
877
+ * @example
878
+ * onEndReached={() => {
879
+ * if (!isLoading) fetchNextPage();
880
+ * }}
881
+ */
882
+ readonly onEndReached?: () => void;
883
+ /**
884
+ * How many rows from the end of the list should trigger `onEndReached`.
885
+ * A higher value triggers loading earlier (more buffer); lower means later.
886
+ *
887
+ * @default 5
888
+ *
889
+ * @example
890
+ * onEndReachedThreshold={10}
891
+ */
892
+ readonly onEndReachedThreshold?: number;
893
+ /**
894
+ * When `true` and `data` is empty, the table renders animated shimmer
895
+ * skeleton rows instead of the empty state or real data.
896
+ *
897
+ * When `true` and `data` is non-empty (e.g. loading the next page in
898
+ * infinite scroll), a small number of shimmer rows are appended at the
899
+ * bottom below the real data.
900
+ *
901
+ * @default false
902
+ *
903
+ * @example
904
+ * isLoading={isFetching}
905
+ */
906
+ readonly isLoading?: boolean;
907
+ /**
908
+ * Scroll indicator configuration (reserved for future use).
909
+ * Currently unused but accepted to avoid prop-drilling issues in parent components.
910
+ */
911
+ readonly scrollIndicators?: {
912
+ vertical?: boolean;
913
+ horizontal?: boolean;
914
+ };
915
+ /**
916
+ * Called when the user changes the sort direction via the column header context menu.
917
+ *
918
+ * **Server-side sorting**: provide this callback. BoltTable will NOT sort the
919
+ * data locally — it will pass the event to you and display the data as-is.
920
+ *
921
+ * **Client-side sorting** (default): omit this callback. BoltTable will sort
922
+ * the data locally using `column.sorter` or a default comparator.
923
+ *
924
+ * @param columnKey - The `key` of the column being sorted
925
+ * @param direction - The new sort direction, or `null` to clear the sort
926
+ *
927
+ * @example
928
+ * // Server-side
929
+ * onSortChange={(key, dir) => {
930
+ * setSortKey(key);
931
+ * setSortDir(dir);
932
+ * refetch({ sortKey: key, sortDir: dir });
933
+ * }}
934
+ */
935
+ readonly onSortChange?: (columnKey: string, direction: SortDirection) => void;
936
+ /**
937
+ * Called when the user applies or clears a column filter via the context menu.
938
+ *
939
+ * **Server-side filtering**: provide this callback. BoltTable will NOT filter
940
+ * the data locally — it passes the full filters map to you.
941
+ *
942
+ * **Client-side filtering** (default): omit this callback. BoltTable will filter
943
+ * locally using `column.filterFn` or a default case-insensitive substring match.
944
+ *
945
+ * @param filters - A map of `{ [columnKey]: filterValue }` for all active filters.
946
+ * A column is removed from the map when its filter is cleared.
947
+ *
948
+ * @example
949
+ * // Server-side
950
+ * onFilterChange={(filters) => {
951
+ * setActiveFilters(filters);
952
+ * refetch({ filters });
953
+ * }}
954
+ */
955
+ readonly onFilterChange?: (filters: Record<string, string>) => void;
956
+ /**
957
+ * Custom items to append to the bottom of the right-click context menu
958
+ * that appears on column headers. These appear after the built-in
959
+ * sort / filter / pin / hide options.
960
+ *
961
+ * @example
962
+ * columnContextMenuItems={[
963
+ * {
964
+ * key: 'copy-col',
965
+ * label: 'Copy column data',
966
+ * icon: <CopyIcon className="h-3 w-3" />,
967
+ * onClick: (columnKey) => copyColumnToClipboard(columnKey),
968
+ * },
969
+ * ]}
970
+ */
971
+ readonly columnContextMenuItems?: ColumnContextMenuItem[];
972
+ /**
973
+ * Controls how the table's height is determined.
974
+ *
975
+ * - `true` (default): the table **auto-sizes** to its content, up to a maximum
976
+ * of 10 rows. Shorter tables occupy less vertical space. The container uses
977
+ * `maxHeight` so a smaller flex parent can still clip it.
978
+ *
979
+ * - `false`: the table fills its parent container (`height: 100%`). The parent
980
+ * is fully responsible for providing a height. Use this when BoltTable is
981
+ * placed inside a fixed-height container (e.g. a modal, a resizable panel).
982
+ *
983
+ * @default true
984
+ *
985
+ * @example
986
+ * // Table inside a fixed-height panel
987
+ * autoHeight={false}
988
+ */
989
+ readonly autoHeight?: boolean;
990
+ /**
991
+ * When `true`, renders a full shimmer skeleton layout (including column headers)
992
+ * before the table's column widths have been calculated from real data.
993
+ *
994
+ * Use this for the initial page load when you don't yet know the column widths
995
+ * but want to show a realistic skeleton immediately.
996
+ *
997
+ * Differs from `isLoading`:
998
+ * - `layoutLoading=true` → entire grid (headers + rows) is a skeleton
999
+ * - `isLoading=true` → headers are real, only body rows are skeletons
1000
+ *
1001
+ * @default false
1002
+ *
1003
+ * @example
1004
+ * layoutLoading={!columnsResolved}
1005
+ */
1006
+ readonly layoutLoading?: boolean;
1007
+ /**
1008
+ * Custom React node to render when the table has no data and is not loading.
1009
+ * Replaces the default "No data" message.
1010
+ * The empty state is centered in the visible viewport (sticky left + fixed width)
1011
+ * so it always appears centered even when the table is scrolled horizontally.
1012
+ *
1013
+ * @example
1014
+ * emptyRenderer={
1015
+ * <div className="flex flex-col items-center gap-2 py-12 text-muted-foreground">
1016
+ * <SearchX className="h-8 w-8" />
1017
+ * <p>No results found</p>
1018
+ * </div>
1019
+ * }
1020
+ */
1021
+ readonly emptyRenderer?: React$1.ReactNode;
1022
+ }
1023
+ /**
1024
+ * CSS class name overrides for specific regions of BoltTable.
1025
+ * All fields are optional — omit any you don't need to customize.
1026
+ *
1027
+ * @example
1028
+ * const classNames: ClassNamesTypes = {
1029
+ * header: 'text-xs font-semibold uppercase text-gray-500',
1030
+ * cell: 'text-sm text-gray-900',
1031
+ * pinnedHeader: 'bg-blue-50 border-r border-blue-200',
1032
+ * pinnedCell: 'bg-blue-50/50',
1033
+ * };
1034
+ */
1035
+ interface ClassNamesTypes {
1036
+ /**
1037
+ * Applied to all non-pinned column header cells.
1038
+ * Pinned headers also receive `pinnedHeader` on top of this.
1039
+ */
1040
+ header?: string;
1041
+ /** Applied to all body cells (both pinned and non-pinned) */
1042
+ cell?: string;
1043
+ /** Applied to each row's wrapper element (reserved for future use) */
1044
+ row?: string;
1045
+ /**
1046
+ * Applied to the floating drag overlay header shown while dragging a column.
1047
+ * Use this to style the "ghost" column that follows the cursor.
1048
+ */
1049
+ dragHeader?: string;
1050
+ /**
1051
+ * Applied additionally to pinned column header cells (on top of `header`).
1052
+ * Use this to add a border, background, or shadow to distinguish pinned headers.
1053
+ */
1054
+ pinnedHeader?: string;
1055
+ /**
1056
+ * Applied additionally to pinned column body cells.
1057
+ * Use this to add a border or separator between pinned and scrolling columns.
1058
+ */
1059
+ pinnedCell?: string;
1060
+ /**
1061
+ * Applied to the expanded row content panel (the div below an expanded row).
1062
+ * Does not affect the row itself, only the expanded panel.
1063
+ */
1064
+ expandedRow?: string;
1065
+ }
1066
+ /**
1067
+ * Inline style overrides for specific regions of BoltTable.
1068
+ * Applied after all default styles, so these take the highest specificity.
1069
+ *
1070
+ * All fields accept standard React `CSSProperties` except `pinnedBg`,
1071
+ * which accepts a CSS color string directly.
1072
+ *
1073
+ * @example
1074
+ * const styles: StylesTypes = {
1075
+ * header: { fontSize: 12, letterSpacing: '0.05em' },
1076
+ * rowHover: { backgroundColor: '#f8fafc' },
1077
+ * rowSelected: { backgroundColor: '#eff6ff' },
1078
+ * pinnedBg: 'rgba(239, 246, 255, 0.95)',
1079
+ * };
1080
+ */
1081
+ interface StylesTypes {
1082
+ /** Inline styles for all non-pinned column header cells */
1083
+ header?: CSSProperties;
1084
+ /** Inline styles for all body cells */
1085
+ cell?: CSSProperties;
1086
+ /** Inline styles for each row wrapper (reserved for future use) */
1087
+ row?: CSSProperties;
1088
+ /**
1089
+ * Inline styles for the drag overlay header shown while dragging a column.
1090
+ * Applied on top of `header` styles.
1091
+ */
1092
+ dragHeader?: CSSProperties;
1093
+ /**
1094
+ * Inline styles for pinned column header cells.
1095
+ * Applied on top of `header` styles.
1096
+ */
1097
+ pinnedHeader?: CSSProperties;
1098
+ /**
1099
+ * Inline styles for pinned column body cells.
1100
+ * Applied on top of `cell` styles.
1101
+ */
1102
+ pinnedCell?: CSSProperties;
1103
+ /** Inline styles for the expanded row content panel */
1104
+ expandedRow?: CSSProperties;
1105
+ /**
1106
+ * CSS color string applied as the background of hovered rows.
1107
+ * Defaults to `hsl(var(--muted) / 0.5)` if omitted.
1108
+ *
1109
+ * @example
1110
+ * rowHover: { backgroundColor: '#f8fafc' }
1111
+ */
1112
+ rowHover?: CSSProperties;
1113
+ /**
1114
+ * CSS color string applied as the background tint of selected rows.
1115
+ * Defaults to `${accentColor}15` (accentColor at 8% opacity).
1116
+ *
1117
+ * @example
1118
+ * rowSelected: { backgroundColor: '#dbeafe' }
1119
+ */
1120
+ rowSelected?: CSSProperties;
1121
+ /**
1122
+ * CSS color string for the background of pinned column cells and headers.
1123
+ * Accepts any valid CSS color. Defaults to a semi-transparent white/dark
1124
+ * based on the current theme.
1125
+ *
1126
+ * @example
1127
+ * pinnedBg: 'rgba(239, 246, 255, 0.9)'
1128
+ */
1129
+ pinnedBg?: string;
1130
+ }
1131
+ /**
1132
+ * BoltTable — high-performance virtualized React table.
1133
+ *
1134
+ * Renders only the rows currently visible in the viewport using TanStack Virtual,
1135
+ * making it suitable for datasets of any size without performance degradation.
1136
+ *
1137
+ * @typeParam T - Your row data type. Must extend `DataRecord` (i.e. `Record<string, unknown>`).
1138
+ *
1139
+ * @example
1140
+ * // Minimal usage
1141
+ * <BoltTable
1142
+ * columns={[
1143
+ * { key: 'name', dataIndex: 'name', title: 'Name' },
1144
+ * { key: 'email', dataIndex: 'email', title: 'Email' },
1145
+ * ]}
1146
+ * data={users}
1147
+ * />
1148
+ *
1149
+ * @example
1150
+ * // Full-featured server-side example
1151
+ * <BoltTable<User>
1152
+ * columns={columns}
1153
+ * data={pageData}
1154
+ * rowKey="id"
1155
+ * isLoading={isFetching}
1156
+ * pagination={{ current: page, pageSize: 20, total: totalCount }}
1157
+ * onPaginationChange={(p, size) => fetchPage(p, size)}
1158
+ * onSortChange={(key, dir) => refetch({ sortKey: key, sortDir: dir })}
1159
+ * onFilterChange={(filters) => refetch({ filters })}
1160
+ * rowSelection={{ selectedRowKeys, onChange: (keys) => setSelectedRowKeys(keys) }}
1161
+ * expandable={{
1162
+ * rowExpandable: (r) => r.hasDetails,
1163
+ * expandedRowRender: (r) => <DetailPanel record={r} />,
1164
+ * }}
1165
+ * accentColor="#6366f1"
1166
+ * autoHeight={false}
1167
+ * />
1168
+ */
1169
+ declare function BoltTable<T extends DataRecord = DataRecord>({ columns: initialColumns, data, rowHeight, expandedRowHeight, maxExpandedRowHeight, accentColor, className, classNames, styles, gripIcon, hideGripIcon, pagination, onPaginationChange, onColumnResize, onColumnOrderChange, onColumnPin, onColumnHide, rowSelection, expandable, rowKey, onEndReached, onEndReachedThreshold, isLoading, onSortChange, onFilterChange, columnContextMenuItems, autoHeight, layoutLoading, emptyRenderer, }: BoltTableProps<T>): react_jsx_runtime.JSX.Element;
1170
+
1171
+ /**
1172
+ * Props for the DraggableHeader component.
1173
+ * This is an internal component used by BoltTable — all props are passed
1174
+ * automatically and you do not need to use DraggableHeader directly.
1175
+ */
1176
+ interface DraggableHeaderProps {
1177
+ /**
1178
+ * The column definition for this header cell.
1179
+ * Controls width, pinning, sort/filter capabilities, title, and styling.
1180
+ */
1181
+ column: ColumnType<DataRecord>;
1182
+ /**
1183
+ * The visual position index of this column in the ordered column array.
1184
+ * Used to set the CSS `grid-column` placement so headers align with body cells.
1185
+ */
1186
+ visualIndex: number;
1187
+ /**
1188
+ * The accent color used for sort indicators, filter icons, the active sort
1189
+ * highlight in the context menu, and the resize handle hover line.
1190
+ *
1191
+ * @default '#1890ff'
1192
+ */
1193
+ accentColor?: string;
1194
+ /**
1195
+ * Called when the user presses down on the resize handle at the right edge
1196
+ * of this header cell. Starts the resize drag operation in BoltTable.
1197
+ *
1198
+ * @param columnKey - The key of the column being resized
1199
+ * @param event - The React mouse event from the resize handle mousedown
1200
+ */
1201
+ onResizeStart?: (columnKey: string, event: React$1.MouseEvent) => void;
1202
+ /**
1203
+ * Shared styling overrides for header cells.
1204
+ * `styles.header` applies to all headers; `styles.pinnedHeader` applies
1205
+ * additionally to pinned column headers.
1206
+ */
1207
+ styles?: StylesTypes;
1208
+ /**
1209
+ * Shared CSS class name overrides for header cells.
1210
+ * `classNames.header` applies to all headers; `classNames.pinnedHeader`
1211
+ * applies additionally to pinned column headers.
1212
+ */
1213
+ classNames?: ClassNamesTypes;
1214
+ /**
1215
+ * When `true`, the drag grip icon on the left of the header label is hidden.
1216
+ * The column can still be dragged; only the visual indicator is removed.
1217
+ *
1218
+ * @default false
1219
+ */
1220
+ hideGripIcon?: boolean;
1221
+ /**
1222
+ * A custom React node to use as the drag grip icon.
1223
+ * When omitted, the default `GripVertical` icon from lucide-react is used.
1224
+ *
1225
+ * @example
1226
+ * gripIcon={<MyCustomDragIcon />}
1227
+ */
1228
+ gripIcon?: React$1.ReactNode;
1229
+ /**
1230
+ * The pixel offset from the pinned edge (left or right) for this column.
1231
+ * Used to set `left` or `right` CSS on sticky-positioned pinned headers.
1232
+ * Calculated by BoltTable based on the total width of all preceding pinned columns.
1233
+ */
1234
+ stickyOffset?: number;
1235
+ /**
1236
+ * Called when the user pins or unpins this column via the context menu
1237
+ * or the unpin button shown on pinned headers.
1238
+ *
1239
+ * @param columnKey - The key of the column being toggled
1240
+ * @param pinned - The new pinned state: `'left'`, `'right'`, or `false` (unpinned)
1241
+ */
1242
+ onTogglePin?: (columnKey: string, pinned: 'left' | 'right' | false) => void;
1243
+ /**
1244
+ * Called when the user clicks "Hide Column" in the context menu.
1245
+ * The column's `hidden` property will be toggled in BoltTable's state.
1246
+ * Pinned columns cannot be hidden and this will never be called for them.
1247
+ *
1248
+ * @param columnKey - The key of the column being hidden
1249
+ */
1250
+ onToggleHide?: (columnKey: string) => void;
1251
+ /**
1252
+ * Whether this is the rightmost visible column.
1253
+ * When `true`, the header cell uses `width: 100%` instead of a fixed pixel
1254
+ * width so it stretches to fill any remaining horizontal space.
1255
+ *
1256
+ * @default false
1257
+ */
1258
+ isLastColumn?: boolean;
1259
+ /**
1260
+ * The current sort direction applied to this column.
1261
+ * - `'asc'` — column is sorted ascending (ArrowUpAZ icon shown)
1262
+ * - `'desc'` — column is sorted descending (ArrowDownAZ icon shown)
1263
+ * - `null` — column is not currently sorted (no icon shown)
1264
+ *
1265
+ * Passed from BoltTable's sort state; only set for the currently sorted column.
1266
+ */
1267
+ sortDirection?: SortDirection;
1268
+ /**
1269
+ * Called when the user clicks a sort option in the context menu.
1270
+ *
1271
+ * @param columnKey - The key of the column to sort
1272
+ * @param direction - The requested sort direction (`'asc'`, `'desc'`, or `undefined` to toggle)
1273
+ */
1274
+ onSort?: (columnKey: string, direction?: SortDirection) => void;
1275
+ /**
1276
+ * The current filter value active on this column.
1277
+ * When non-empty, a small Filter icon is shown in the header label.
1278
+ *
1279
+ * @default ''
1280
+ */
1281
+ filterValue?: string;
1282
+ /**
1283
+ * Called when the user submits a new filter value via the context menu input.
1284
+ *
1285
+ * @param columnKey - The key of the column being filtered
1286
+ * @param value - The filter string entered by the user
1287
+ */
1288
+ onFilter?: (columnKey: string, value: string) => void;
1289
+ /**
1290
+ * Called when the user clicks "Clear Filter" in the context menu.
1291
+ *
1292
+ * @param columnKey - The key of the column whose filter should be cleared
1293
+ */
1294
+ onClearFilter?: (columnKey: string) => void;
1295
+ /**
1296
+ * Additional custom items to append at the bottom of the right-click context menu.
1297
+ * These appear after the built-in sort/filter/pin/hide options.
1298
+ *
1299
+ * @example
1300
+ * customContextMenuItems={[
1301
+ * {
1302
+ * key: 'copy',
1303
+ * label: 'Copy column data',
1304
+ * icon: <CopyIcon />,
1305
+ * onClick: (columnKey) => copyColumn(columnKey),
1306
+ * }
1307
+ * ]}
1308
+ */
1309
+ customContextMenuItems?: ColumnContextMenuItem[];
1310
+ }
1311
+ /**
1312
+ * DraggableHeader — a single column header cell for BoltTable.
1313
+ *
1314
+ * Features:
1315
+ * - **Drag to reorder**: grip icon on the left; dragging is disabled for pinned columns.
1316
+ * - **Resize handle**: a 12px wide invisible hit area on the right edge.
1317
+ * - **Sort indicators**: ArrowUpAZ / ArrowDownAZ shown when sorted.
1318
+ * - **Filter indicator**: small Filter icon when a filter is active.
1319
+ * - **Right-click context menu**: sort asc/desc, filter input, pin left/right, hide column,
1320
+ * plus any custom items passed via `customContextMenuItems`.
1321
+ * - **Unpin button**: replaces the resize handle on pinned columns.
1322
+ *
1323
+ * Wrapped in `React.memo` with a custom equality check — only re-renders when
1324
+ * its own column's data changes, preventing cascade re-renders across all headers
1325
+ * when a single column's sort/filter/width changes.
1326
+ *
1327
+ * @internal This is an internal BoltTable component. Use BoltTable directly.
1328
+ */
1329
+ declare const DraggableHeader: React$1.MemoExoticComponent<({ column, visualIndex, accentColor, onResizeStart, styles, classNames, hideGripIcon, gripIcon, stickyOffset, onTogglePin, onToggleHide, isLastColumn, sortDirection, onSort, filterValue, onFilter, onClearFilter, customContextMenuItems, }: DraggableHeaderProps) => react_jsx_runtime.JSX.Element>;
1330
+
1331
+ /**
1332
+ * The imperative handle exposed by ResizeOverlay via `ref`.
1333
+ * All three methods must be called in sequence during a resize operation:
1334
+ * `show()` → `move()` (many times) → `hide()`.
1335
+ */
1336
+ interface ResizeOverlayHandle {
1337
+ /**
1338
+ * Makes the overlay visible and positions it at the start of a resize.
1339
+ * Call this on `mousedown` of the resize handle.
1340
+ *
1341
+ * @param viewportX - The initial mouse X position in viewport coordinates (e.clientX)
1342
+ * @param columnName - The name/title of the column being resized (shown in the label)
1343
+ * @param areaRect - The bounding rect of the scroll container (from getBoundingClientRect)
1344
+ * @param headerLeftLocal - The left edge of the column header in scroll-content coordinates
1345
+ * @param minSize - The minimum allowed column width in pixels (used to clamp the line)
1346
+ * @param scrollTop - Current vertical scroll offset of the container (scrollTop)
1347
+ * @param scrollLeft - Current horizontal scroll offset of the container (scrollLeft)
1348
+ * @param initialLineX - The initial X position of the vertical line in content coordinates
1349
+ */
1350
+ show: (viewportX: number, columnName: string, areaRect: DOMRect, headerLeftLocal: number, minSize: number, scrollTop: number, scrollLeft: number, initialLineX: number) => void;
1351
+ /**
1352
+ * Moves the vertical line to follow the mouse cursor during a resize drag.
1353
+ * Call this on every `mousemove` event while dragging.
1354
+ * The line is clamped to never go below the column's minimum width.
1355
+ *
1356
+ * @param viewportX - The current mouse X position in viewport coordinates (e.clientX)
1357
+ */
1358
+ move: (viewportX: number) => void;
1359
+ /**
1360
+ * Hides the overlay completely.
1361
+ * Call this on `mouseup` when the resize operation ends.
1362
+ */
1363
+ hide: () => void;
1364
+ }
1365
+ /**
1366
+ * Props for the ResizeOverlay component.
1367
+ */
1368
+ interface ResizeOverlayProps {
1369
+ /**
1370
+ * The accent color used for the resize line and label background.
1371
+ * Should match the `accentColor` prop passed to BoltTable for visual consistency.
1372
+ *
1373
+ * @default '#1778ff'
1374
+ *
1375
+ * @example
1376
+ * accentColor="#6366f1"
1377
+ */
1378
+ accentColor?: string;
1379
+ }
1380
+ /**
1381
+ * ResizeOverlay — visual feedback component for column resize operations.
1382
+ *
1383
+ * Renders a colored vertical line and a floating column-name label that track
1384
+ * the user's cursor during a column resize drag. All DOM updates are direct
1385
+ * (bypassing React state) for zero-lag, 60fps movement.
1386
+ *
1387
+ * This component is an implementation detail of BoltTable and is not intended
1388
+ * to be used standalone. It is mounted once inside the scroll container and
1389
+ * controlled imperatively via the `ResizeOverlayHandle` ref.
1390
+ *
1391
+ * @example
1392
+ * // Inside BoltTable:
1393
+ * const resizeOverlayRef = useRef<ResizeOverlayHandle>(null);
1394
+ *
1395
+ * // On resize start:
1396
+ * resizeOverlayRef.current?.show(e.clientX, 'Name', areaRect, headerLeft, 40, scrollTop, scrollLeft, initX);
1397
+ *
1398
+ * // On mouse move:
1399
+ * resizeOverlayRef.current?.move(e.clientX);
1400
+ *
1401
+ * // On mouse up:
1402
+ * resizeOverlayRef.current?.hide();
1403
+ *
1404
+ * // In JSX:
1405
+ * <ResizeOverlay ref={resizeOverlayRef} accentColor={accentColor} />
1406
+ */
1407
+ declare const ResizeOverlay: React$1.ForwardRefExoticComponent<ResizeOverlayProps & React$1.RefAttributes<ResizeOverlayHandle>>;
1408
+
1409
+ /**
1410
+ * Props for the TableBody component.
1411
+ * All props are passed automatically by BoltTable — this is an internal component.
1412
+ */
1413
+ interface TableBodyProps {
1414
+ /** The current page's row data (already sliced/filtered/sorted by BoltTable) */
1415
+ data: DataRecord[];
1416
+ /** The ordered visible columns (left pinned → unpinned → right pinned) */
1417
+ orderedColumns: ColumnType<DataRecord>[];
1418
+ /**
1419
+ * The TanStack Virtual row virtualizer instance.
1420
+ * Provides `getVirtualItems()` and `getTotalSize()` for rendering.
1421
+ */
1422
+ rowVirtualizer: Virtualizer<HTMLDivElement, Element>;
1423
+ /**
1424
+ * Map of column key → sticky offset in pixels.
1425
+ * For left-pinned columns: distance from the left edge.
1426
+ * For right-pinned columns: distance from the right edge.
1427
+ */
1428
+ columnOffsets: Map<string, number>;
1429
+ /** Shared style overrides passed down from BoltTable */
1430
+ styles?: StylesTypes;
1431
+ /** Shared class name overrides passed down from BoltTable */
1432
+ classNames?: ClassNamesTypes;
1433
+ /**
1434
+ * Row selection configuration.
1435
+ * When provided, the `__select__` column renders checkboxes or radio buttons.
1436
+ * `undefined` during shimmer loading to prevent selection UI on skeleton rows.
1437
+ */
1438
+ rowSelection?: RowSelectionConfig<DataRecord>;
1439
+ /**
1440
+ * Pre-normalized selected row keys (all converted to strings).
1441
+ * Normalized in BoltTable so Cell never has to deal with number/string mismatches.
1442
+ *
1443
+ * @default []
1444
+ */
1445
+ normalizedSelectedKeys?: string[];
1446
+ /**
1447
+ * Returns the string key for a given row record and index.
1448
+ * Derived from BoltTable's `rowKey` prop. Always returns a string.
1449
+ *
1450
+ * @param record - The row data object
1451
+ * @param index - The row's position in the data array
1452
+ */
1453
+ getRowKey?: (record: DataRecord, index: number) => string;
1454
+ /**
1455
+ * Expandable row configuration.
1456
+ * When provided, rows in `resolvedExpandedKeys` render an expanded content panel.
1457
+ * `undefined` during shimmer loading to prevent expand UI on skeleton rows.
1458
+ */
1459
+ expandable?: ExpandableConfig<DataRecord>;
1460
+ /**
1461
+ * The set of currently expanded row keys.
1462
+ * Used to determine whether to render the expanded content panel for each row.
1463
+ */
1464
+ resolvedExpandedKeys?: Set<React$1.Key>;
1465
+ /**
1466
+ * Height of each regular (non-expanded) row in pixels.
1467
+ * Must match the `rowHeight` prop passed to BoltTable.
1468
+ *
1469
+ * @default 40
1470
+ */
1471
+ rowHeight?: number;
1472
+ /**
1473
+ * Total pixel width of all columns combined.
1474
+ * Used to set `minWidth` on the column spacer so the grid never collapses
1475
+ * below the sum of all column widths.
1476
+ */
1477
+ totalTableWidth?: number;
1478
+ /**
1479
+ * The visible width of the scroll container in pixels.
1480
+ * Used to set the width of expanded row panels and the empty state div
1481
+ * so they fill exactly the visible viewport rather than the full content width.
1482
+ */
1483
+ scrollAreaWidth?: number;
1484
+ /**
1485
+ * The accent color used for the expand toggle button chevron icon.
1486
+ * Should match the `accentColor` prop on BoltTable.
1487
+ *
1488
+ * @default '#1890ff'
1489
+ */
1490
+ accentColor?: string;
1491
+ /**
1492
+ * Ref to the scroll container element.
1493
+ * Reserved for potential future use (e.g. programmatic scrolling from within TableBody).
1494
+ */
1495
+ scrollContainerRef?: React$1.RefObject<HTMLDivElement | null>;
1496
+ /**
1497
+ * When `true`, all cells render as animated shimmer skeletons instead of
1498
+ * real data. Used during initial loading when `data` is empty.
1499
+ *
1500
+ * @default false
1501
+ */
1502
+ isLoading?: boolean;
1503
+ /**
1504
+ * Called by `MeasuredExpandedRow` when an expanded row's content height changes.
1505
+ * BoltTable uses this to update the virtualizer's size estimate for that row,
1506
+ * triggering a re-layout so the expanded content is never clipped.
1507
+ *
1508
+ * @param rowKey - The string key of the row whose expanded height changed
1509
+ * @param contentHeight - The new content height in pixels (border-box)
1510
+ */
1511
+ onExpandedRowResize?: (rowKey: string, contentHeight: number) => void;
1512
+ /**
1513
+ * Optional maximum height in pixels for expanded row panels.
1514
+ * When set, the panel becomes scrollable if its content exceeds this height.
1515
+ * When omitted, the panel grows to its full content height.
1516
+ *
1517
+ * @example
1518
+ * maxExpandedRowHeight={300}
1519
+ */
1520
+ maxExpandedRowHeight?: number;
1521
+ }
1522
+ /**
1523
+ * TableBody — the virtualized body renderer for BoltTable.
1524
+ *
1525
+ * Renders the visible rows using TanStack Virtual's window virtualization.
1526
+ * Only the rows currently in (or near) the viewport are in the DOM.
1527
+ *
1528
+ * Layout strategy:
1529
+ * - One `<div>` per column, spanning the full virtual height (`totalSize`px).
1530
+ * - Inside each column div, only the visible rows are rendered as
1531
+ * `position: absolute` cells stacked at their `virtualRow.start` offset.
1532
+ * - Pinned columns use `position: sticky` on the column div itself, backed
1533
+ * by a semi-transparent background to visually separate from scrolling content.
1534
+ * - Expanded rows are rendered in a separate full-width overlay div that sits
1535
+ * on top of all column divs (z-index: 15) and uses `position: sticky; left: 0`
1536
+ * to stay viewport-locked during horizontal scroll.
1537
+ *
1538
+ * @internal This is an internal BoltTable component. Use BoltTable directly.
1539
+ */
1540
+ declare const TableBody: React$1.FC<TableBodyProps>;
1541
+
1542
+ export { BoltTable, type ColumnContextMenuItem, type ColumnType, type DataRecord, DraggableHeader, type ExpandableConfig, type PaginationType, ResizeOverlay, type RowSelectionConfig, type SortDirection, TableBody };