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.
- package/LICENSE +21 -0
- package/README.md +501 -0
- package/dist/index.d.mts +1542 -0
- package/dist/index.d.ts +1542 -0
- package/dist/index.js +2051 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2043 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Keerthi Venkatesh
|
|
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,501 @@
|
|
|
1
|
+
# @venkateshsirigineedi/bolt-table
|
|
2
|
+
|
|
3
|
+
A high-performance, fully-featured React table component built on [TanStack Virtual](https://tanstack.com/virtual) and [@dnd-kit](https://dndkit.com). Only the rows visible in the viewport are ever in the DOM — making it fast for datasets of any size.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@venkateshsirigineedi/bolt-table)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Row virtualization** — only visible rows are rendered, powered by TanStack Virtual
|
|
13
|
+
- **Drag to reorder columns** — grab any header and drag it to a new position
|
|
14
|
+
- **Column pinning** — pin columns to the left or right edge via right-click
|
|
15
|
+
- **Column resizing** — drag the right edge of any header to resize
|
|
16
|
+
- **Column hiding** — hide/show columns via the right-click context menu
|
|
17
|
+
- **Sorting** — client-side or server-side, with custom comparators per column
|
|
18
|
+
- **Filtering** — client-side or server-side, with custom filter functions per column
|
|
19
|
+
- **Pagination** — client-side slice or server-side with full control
|
|
20
|
+
- **Row selection** — checkbox or radio, with select-all, indeterminate state, and disabled rows
|
|
21
|
+
- **Expandable rows** — auto-measured content panels below each row, controlled or uncontrolled
|
|
22
|
+
- **Shimmer loading** — animated skeleton rows on initial load and infinite scroll append
|
|
23
|
+
- **Infinite scroll** — `onEndReached` callback with configurable threshold
|
|
24
|
+
- **Empty state** — custom renderer or default "No data" message
|
|
25
|
+
- **Auto height** — table shrinks/grows to fit rows, capped at 10 rows by default
|
|
26
|
+
- **Right-click context menu** — sort, filter, pin, hide, plus custom items
|
|
27
|
+
- **Dark mode** — works out of the box with CSS variables
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @venkateshsirigineedi/bolt-table
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Peer dependencies
|
|
38
|
+
|
|
39
|
+
These must be installed separately in your project:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @tanstack/react-virtual @dnd-kit/core @dnd-kit/sortable lucide-react
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Quick start
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { BoltTable, ColumnType } from '@venkateshsirigineedi/bolt-table';
|
|
51
|
+
|
|
52
|
+
interface User {
|
|
53
|
+
id: string;
|
|
54
|
+
name: string;
|
|
55
|
+
email: string;
|
|
56
|
+
age: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const columns: ColumnType<User>[] = [
|
|
60
|
+
{ key: 'name', dataIndex: 'name', title: 'Name', width: 200 },
|
|
61
|
+
{ key: 'email', dataIndex: 'email', title: 'Email', width: 280 },
|
|
62
|
+
{ key: 'age', dataIndex: 'age', title: 'Age', width: 80 },
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const data: User[] = [
|
|
66
|
+
{ id: '1', name: 'Alice', email: 'alice@example.com', age: 28 },
|
|
67
|
+
{ id: '2', name: 'Bob', email: 'bob@example.com', age: 34 },
|
|
68
|
+
{ id: '3', name: 'Charlie', email: 'charlie@example.com', age: 22 },
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
export default function App() {
|
|
72
|
+
return (
|
|
73
|
+
<BoltTable<User>
|
|
74
|
+
columns={columns}
|
|
75
|
+
data={data}
|
|
76
|
+
rowKey="id"
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Next.js (App Router)
|
|
85
|
+
|
|
86
|
+
BoltTable uses browser APIs and must be wrapped in a client boundary. Remove the `'use client'` directive from the component files and wrap usage instead:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
'use client';
|
|
90
|
+
import { BoltTable } from '@venkateshsirigineedi/bolt-table';
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Styling
|
|
96
|
+
|
|
97
|
+
BoltTable uses [Tailwind CSS](https://tailwindcss.com) utility classes and [Shadcn/ui](https://ui.shadcn.com) CSS variables (`--muted`, `--background`, `--border`, etc.).
|
|
98
|
+
|
|
99
|
+
Make sure your project has Tailwind configured and the Shadcn CSS variables defined in your global stylesheet. If you use a different design system, you can override styles via the `styles` and `classNames` props.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Props
|
|
104
|
+
|
|
105
|
+
### `BoltTable`
|
|
106
|
+
|
|
107
|
+
| Prop | Type | Default | Description |
|
|
108
|
+
|------|------|---------|-------------|
|
|
109
|
+
| `columns` | `ColumnType<T>[]` | — | Column definitions (required) |
|
|
110
|
+
| `data` | `T[]` | — | Row data array (required) |
|
|
111
|
+
| `rowKey` | `string \| (record: T) => string` | `'id'` | Unique row identifier |
|
|
112
|
+
| `rowHeight` | `number` | `40` | Height of each row in pixels |
|
|
113
|
+
| `expandedRowHeight` | `number` | `200` | Estimated height for expanded rows |
|
|
114
|
+
| `maxExpandedRowHeight` | `number` | — | Max height for expanded row panels (makes them scrollable) |
|
|
115
|
+
| `accentColor` | `string` | `'#1890ff'` | Color used for sort icons, selected rows, resize line, etc. |
|
|
116
|
+
| `className` | `string` | `''` | Class name for the outer wrapper |
|
|
117
|
+
| `classNames` | `ClassNamesTypes` | `{}` | Granular class overrides per table region |
|
|
118
|
+
| `styles` | `StylesTypes` | `{}` | Inline style overrides per table region |
|
|
119
|
+
| `gripIcon` | `ReactNode` | — | Custom drag grip icon (defaults to `GripVertical`) |
|
|
120
|
+
| `hideGripIcon` | `boolean` | `false` | Hide the drag grip icon from all headers |
|
|
121
|
+
| `pagination` | `PaginationType \| false` | — | Pagination config, or `false` to disable |
|
|
122
|
+
| `onPaginationChange` | `(page, pageSize) => void` | — | Called when page or page size changes |
|
|
123
|
+
| `onColumnResize` | `(columnKey, newWidth) => void` | — | Called when a column is resized |
|
|
124
|
+
| `onColumnOrderChange` | `(newOrder) => void` | — | Called when columns are reordered |
|
|
125
|
+
| `onColumnPin` | `(columnKey, pinned) => void` | — | Called when a column is pinned/unpinned |
|
|
126
|
+
| `onColumnHide` | `(columnKey, hidden) => void` | — | Called when a column is hidden/shown |
|
|
127
|
+
| `rowSelection` | `RowSelectionConfig<T>` | — | Row selection config |
|
|
128
|
+
| `expandable` | `ExpandableConfig<T>` | — | Expandable row config |
|
|
129
|
+
| `onEndReached` | `() => void` | — | Called when scrolled near the bottom (infinite scroll) |
|
|
130
|
+
| `onEndReachedThreshold` | `number` | `5` | Rows from end to trigger `onEndReached` |
|
|
131
|
+
| `isLoading` | `boolean` | `false` | Shows shimmer skeleton rows when `true` |
|
|
132
|
+
| `onSortChange` | `(columnKey, direction) => void` | — | Server-side sort handler (disables local sort) |
|
|
133
|
+
| `onFilterChange` | `(filters) => void` | — | Server-side filter handler (disables local filter) |
|
|
134
|
+
| `columnContextMenuItems` | `ColumnContextMenuItem[]` | — | Custom items appended to the header context menu |
|
|
135
|
+
| `autoHeight` | `boolean` | `true` | Auto-size table height to content (capped at 10 rows) |
|
|
136
|
+
| `layoutLoading` | `boolean` | `false` | Show full skeleton layout (headers + rows) |
|
|
137
|
+
| `emptyRenderer` | `ReactNode` | — | Custom empty state content |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### `ColumnType<T>`
|
|
142
|
+
|
|
143
|
+
| Field | Type | Default | Description |
|
|
144
|
+
|-------|------|---------|-------------|
|
|
145
|
+
| `key` | `string` | — | Unique column identifier (required) |
|
|
146
|
+
| `dataIndex` | `string` | — | Row object property to display (required) |
|
|
147
|
+
| `title` | `string \| ReactNode` | — | Header label (required) |
|
|
148
|
+
| `width` | `number` | `150` | Column width in pixels |
|
|
149
|
+
| `render` | `(value, record, index) => ReactNode` | — | Custom cell renderer |
|
|
150
|
+
| `shimmerRender` | `() => ReactNode` | — | Custom shimmer skeleton for this column |
|
|
151
|
+
| `sortable` | `boolean` | `true` | Show sort controls for this column |
|
|
152
|
+
| `sorter` | `boolean \| (a: T, b: T) => number` | — | Custom sort comparator for client-side sort |
|
|
153
|
+
| `filterable` | `boolean` | `true` | Show filter option in context menu |
|
|
154
|
+
| `filterFn` | `(value, record, dataIndex) => boolean` | — | Custom filter predicate for client-side filter |
|
|
155
|
+
| `hidden` | `boolean` | `false` | Hide this column |
|
|
156
|
+
| `pinned` | `'left' \| 'right' \| false` | `false` | Pin this column to an edge |
|
|
157
|
+
| `className` | `string` | — | Class applied to all cells in this column |
|
|
158
|
+
| `style` | `CSSProperties` | — | Styles applied to all cells in this column |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Examples
|
|
163
|
+
|
|
164
|
+
### Sorting
|
|
165
|
+
|
|
166
|
+
**Client-side** (no `onSortChange` — BoltTable sorts locally):
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
const columns: ColumnType<User>[] = [
|
|
170
|
+
{
|
|
171
|
+
key: 'name',
|
|
172
|
+
dataIndex: 'name',
|
|
173
|
+
title: 'Name',
|
|
174
|
+
sortable: true,
|
|
175
|
+
// Optional custom comparator:
|
|
176
|
+
sorter: (a, b) => a.name.localeCompare(b.name),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
key: 'age',
|
|
180
|
+
dataIndex: 'age',
|
|
181
|
+
title: 'Age',
|
|
182
|
+
sortable: true,
|
|
183
|
+
// Default numeric comparator used when sorter is omitted
|
|
184
|
+
},
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
<BoltTable columns={columns} data={data} />
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Server-side** (provide `onSortChange` — BoltTable delegates to you):
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
const [sortKey, setSortKey] = useState('');
|
|
194
|
+
const [sortDir, setSortDir] = useState<SortDirection>(null);
|
|
195
|
+
|
|
196
|
+
<BoltTable
|
|
197
|
+
columns={columns}
|
|
198
|
+
data={serverData}
|
|
199
|
+
onSortChange={(key, dir) => {
|
|
200
|
+
setSortKey(key);
|
|
201
|
+
setSortDir(dir);
|
|
202
|
+
refetch({ sortKey: key, sortDir: dir });
|
|
203
|
+
}}
|
|
204
|
+
/>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Filtering
|
|
210
|
+
|
|
211
|
+
**Client-side** (no `onFilterChange`):
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
const columns: ColumnType<User>[] = [
|
|
215
|
+
{
|
|
216
|
+
key: 'status',
|
|
217
|
+
dataIndex: 'status',
|
|
218
|
+
title: 'Status',
|
|
219
|
+
filterable: true,
|
|
220
|
+
// Exact match instead of default substring:
|
|
221
|
+
filterFn: (value, record) => record.status === value,
|
|
222
|
+
},
|
|
223
|
+
];
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Server-side**:
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
<BoltTable
|
|
230
|
+
columns={columns}
|
|
231
|
+
data={serverData}
|
|
232
|
+
onFilterChange={(filters) => {
|
|
233
|
+
setActiveFilters(filters);
|
|
234
|
+
refetch({ filters });
|
|
235
|
+
}}
|
|
236
|
+
/>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### Pagination
|
|
242
|
+
|
|
243
|
+
**Client-side** (pass all data, BoltTable slices it):
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
<BoltTable
|
|
247
|
+
columns={columns}
|
|
248
|
+
data={allUsers} // all 500 rows
|
|
249
|
+
pagination={{ pageSize: 20 }}
|
|
250
|
+
onPaginationChange={(page, size) => {
|
|
251
|
+
setPage(page);
|
|
252
|
+
}}
|
|
253
|
+
/>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Server-side** (pass only the current page):
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
<BoltTable
|
|
260
|
+
columns={columns}
|
|
261
|
+
data={currentPageData} // only 20 rows
|
|
262
|
+
pagination={{
|
|
263
|
+
current: page,
|
|
264
|
+
pageSize: 20,
|
|
265
|
+
total: 500,
|
|
266
|
+
showTotal: (total, [from, to]) => `${from}-${to} of ${total} users`,
|
|
267
|
+
}}
|
|
268
|
+
onPaginationChange={(page, size) => fetchPage(page, size)}
|
|
269
|
+
/>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Disable pagination:**
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
<BoltTable columns={columns} data={data} pagination={false} />
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### Row selection
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
|
284
|
+
|
|
285
|
+
<BoltTable
|
|
286
|
+
columns={columns}
|
|
287
|
+
data={data}
|
|
288
|
+
rowKey="id"
|
|
289
|
+
rowSelection={{
|
|
290
|
+
type: 'checkbox', // or 'radio'
|
|
291
|
+
selectedRowKeys,
|
|
292
|
+
onChange: (keys, rows) => setSelectedRowKeys(keys),
|
|
293
|
+
// Disable selection for specific rows:
|
|
294
|
+
getCheckboxProps: (record) => ({
|
|
295
|
+
disabled: record.status === 'locked',
|
|
296
|
+
}),
|
|
297
|
+
}}
|
|
298
|
+
/>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
### Expandable rows
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
<BoltTable
|
|
307
|
+
columns={columns}
|
|
308
|
+
data={data}
|
|
309
|
+
rowKey="id"
|
|
310
|
+
expandable={{
|
|
311
|
+
rowExpandable: (record) => record.details !== null,
|
|
312
|
+
expandedRowRender: (record) => (
|
|
313
|
+
<div style={{ padding: 16 }}>
|
|
314
|
+
<h4>{record.name} — Details</h4>
|
|
315
|
+
<pre>{JSON.stringify(record.details, null, 2)}</pre>
|
|
316
|
+
</div>
|
|
317
|
+
),
|
|
318
|
+
// Optional: control expanded state yourself
|
|
319
|
+
// expandedRowKeys={expandedKeys}
|
|
320
|
+
// onExpandedRowsChange={(keys) => setExpandedKeys(keys)}
|
|
321
|
+
}}
|
|
322
|
+
expandedRowHeight={150} // initial estimate
|
|
323
|
+
maxExpandedRowHeight={400} // makes panel scrollable if taller
|
|
324
|
+
/>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
### Infinite scroll
|
|
330
|
+
|
|
331
|
+
```tsx
|
|
332
|
+
const [data, setData] = useState<User[]>([]);
|
|
333
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
334
|
+
|
|
335
|
+
const loadMore = async () => {
|
|
336
|
+
setIsLoading(true);
|
|
337
|
+
const newRows = await fetchNextPage();
|
|
338
|
+
setData(prev => [...prev, ...newRows]);
|
|
339
|
+
setIsLoading(false);
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
<BoltTable
|
|
343
|
+
columns={columns}
|
|
344
|
+
data={data}
|
|
345
|
+
isLoading={isLoading}
|
|
346
|
+
onEndReached={loadMore}
|
|
347
|
+
onEndReachedThreshold={8}
|
|
348
|
+
pagination={false}
|
|
349
|
+
/>
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### Column pinning
|
|
355
|
+
|
|
356
|
+
Pinning via column definition:
|
|
357
|
+
|
|
358
|
+
```tsx
|
|
359
|
+
const columns: ColumnType<User>[] = [
|
|
360
|
+
{ key: 'name', dataIndex: 'name', title: 'Name', pinned: 'left', width: 200 },
|
|
361
|
+
{ key: 'email', dataIndex: 'email', title: 'Email', width: 250 },
|
|
362
|
+
{ key: 'actions', dataIndex: 'actions', title: 'Actions', pinned: 'right', width: 100 },
|
|
363
|
+
];
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Users can also pin/unpin columns at runtime via the right-click context menu.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
### Custom cell rendering
|
|
371
|
+
|
|
372
|
+
```tsx
|
|
373
|
+
const columns: ColumnType<User>[] = [
|
|
374
|
+
{
|
|
375
|
+
key: 'status',
|
|
376
|
+
dataIndex: 'status',
|
|
377
|
+
title: 'Status',
|
|
378
|
+
width: 120,
|
|
379
|
+
render: (value, record) => (
|
|
380
|
+
<span
|
|
381
|
+
style={{
|
|
382
|
+
padding: '2px 8px',
|
|
383
|
+
borderRadius: 4,
|
|
384
|
+
fontSize: 12,
|
|
385
|
+
backgroundColor: record.status === 'active' ? '#d1fae5' : '#fee2e2',
|
|
386
|
+
color: record.status === 'active' ? '#065f46' : '#991b1b',
|
|
387
|
+
}}
|
|
388
|
+
>
|
|
389
|
+
{String(value)}
|
|
390
|
+
</span>
|
|
391
|
+
),
|
|
392
|
+
},
|
|
393
|
+
];
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
### Custom context menu items
|
|
399
|
+
|
|
400
|
+
```tsx
|
|
401
|
+
<BoltTable
|
|
402
|
+
columns={columns}
|
|
403
|
+
data={data}
|
|
404
|
+
columnContextMenuItems={[
|
|
405
|
+
{
|
|
406
|
+
key: 'copy',
|
|
407
|
+
label: 'Copy column data',
|
|
408
|
+
icon: <CopyIcon className="h-3 w-3" />,
|
|
409
|
+
onClick: (columnKey) => copyColumnToClipboard(columnKey),
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
key: 'reset-width',
|
|
413
|
+
label: 'Reset width',
|
|
414
|
+
onClick: (columnKey) => resetColumnWidth(columnKey),
|
|
415
|
+
},
|
|
416
|
+
]}
|
|
417
|
+
/>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
### Styling overrides
|
|
423
|
+
|
|
424
|
+
```tsx
|
|
425
|
+
<BoltTable
|
|
426
|
+
columns={columns}
|
|
427
|
+
data={data}
|
|
428
|
+
accentColor="#6366f1"
|
|
429
|
+
classNames={{
|
|
430
|
+
header: 'text-xs uppercase tracking-wider text-gray-500',
|
|
431
|
+
cell: 'text-sm',
|
|
432
|
+
pinnedHeader: 'border-r border-indigo-200',
|
|
433
|
+
pinnedCell: 'border-r border-indigo-100',
|
|
434
|
+
}}
|
|
435
|
+
styles={{
|
|
436
|
+
header: { fontWeight: 600 },
|
|
437
|
+
rowHover: { backgroundColor: '#f0f9ff' },
|
|
438
|
+
rowSelected: { backgroundColor: '#e0e7ff' },
|
|
439
|
+
pinnedBg: 'rgba(238, 242, 255, 0.95)',
|
|
440
|
+
}}
|
|
441
|
+
/>
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
### Loading skeleton
|
|
447
|
+
|
|
448
|
+
```tsx
|
|
449
|
+
// Full skeleton on initial load (no data yet)
|
|
450
|
+
<BoltTable
|
|
451
|
+
columns={columns}
|
|
452
|
+
data={[]}
|
|
453
|
+
isLoading={true}
|
|
454
|
+
pagination={{ pageSize: 20 }}
|
|
455
|
+
/>
|
|
456
|
+
|
|
457
|
+
// Layout skeleton before column widths are known
|
|
458
|
+
<BoltTable
|
|
459
|
+
columns={columns}
|
|
460
|
+
data={[]}
|
|
461
|
+
layoutLoading={true}
|
|
462
|
+
/>
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
### Fixed height (fill parent)
|
|
468
|
+
|
|
469
|
+
By default, BoltTable auto-sizes to its content. To fill a fixed-height container instead:
|
|
470
|
+
|
|
471
|
+
```tsx
|
|
472
|
+
<div style={{ height: 600 }}>
|
|
473
|
+
<BoltTable
|
|
474
|
+
columns={columns}
|
|
475
|
+
data={data}
|
|
476
|
+
autoHeight={false}
|
|
477
|
+
/>
|
|
478
|
+
</div>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Type exports
|
|
484
|
+
|
|
485
|
+
```ts
|
|
486
|
+
import type {
|
|
487
|
+
ColumnType,
|
|
488
|
+
ColumnContextMenuItem,
|
|
489
|
+
RowSelectionConfig,
|
|
490
|
+
ExpandableConfig,
|
|
491
|
+
PaginationType,
|
|
492
|
+
SortDirection,
|
|
493
|
+
DataRecord,
|
|
494
|
+
} from '@venkateshsirigineedi/bolt-table';
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
## License
|
|
500
|
+
|
|
501
|
+
MIT © [Venkatesh Sirigineedi](https://github.com/venkateshsirigineedi)
|