bolt-table 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # bolt-table
2
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.
3
+ A high-performance, zero-dependency\* React table component. Only the rows visible in the viewport are ever in the DOM — making it fast for datasets of any size uisng [TanStack Virtual](https://tanstack.com/virtual).
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/bolt-table)](https://www.npmjs.com/package/bolt-table)
6
6
  [![license](https://img.shields.io/npm/l/bolt-table)](./LICENSE)
@@ -10,7 +10,7 @@ A high-performance, fully-featured React table component built on [TanStack Virt
10
10
  ## Features
11
11
 
12
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
13
+ - **Drag to reorder columns** — custom zero-dependency drag-and-drop (no @dnd-kit needed)
14
14
  - **Column pinning** — pin columns to the left or right edge via right-click
15
15
  - **Column resizing** — drag the right edge of any header to resize
16
16
  - **Column hiding** — hide/show columns via the right-click context menu
@@ -24,23 +24,18 @@ A high-performance, fully-featured React table component built on [TanStack Virt
24
24
  - **Empty state** — custom renderer or default "No data" message
25
25
  - **Auto height** — table shrinks/grows to fit rows, capped at 10 rows by default
26
26
  - **Right-click context menu** — sort, filter, pin, hide, plus custom items
27
- - **Dark mode** — works out of the box with CSS variables
27
+ - **Theme-agnostic** — works in light and dark mode out of the box, no CSS variables needed
28
+ - **Custom icons** — override any built-in icon via the `icons` prop
28
29
 
29
30
  ---
30
31
 
31
32
  ## Installation
32
33
 
33
34
  ```bash
34
- npm install bolt-table
35
+ npm install bolt-table @tanstack/react-virtual
35
36
  ```
36
37
 
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
- ```
38
+ That's it. No other peer dependencies.
44
39
 
45
40
  ---
46
41
 
@@ -83,7 +78,7 @@ export default function App() {
83
78
 
84
79
  ## Next.js (App Router)
85
80
 
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:
81
+ BoltTable uses browser APIs and must be wrapped in a client boundary:
87
82
 
88
83
  ```tsx
89
84
  'use client';
@@ -94,9 +89,27 @@ import { BoltTable } from 'bolt-table';
94
89
 
95
90
  ## Styling
96
91
 
97
- BoltTable uses [Tailwind CSS](https://tailwindcss.com) utility classes and [Shadcn/ui](https://ui.shadcn.com) CSS variables (`--muted`, `--background`, `--border`, etc.).
92
+ BoltTable uses **inline CSS styles** for all defaults — no Tailwind, no CSS variables, no external stylesheets required. It works out of the box in any React project, light or dark mode.
93
+
94
+ You can customize everything via the `styles` and `classNames` props. If your project uses Tailwind, you can pass Tailwind classes through `classNames` and they'll be applied on top of the inline defaults.
95
+
96
+ ### Custom icons
97
+
98
+ All built-in icons are inline SVGs. Override any icon via the `icons` prop:
99
+
100
+ ```tsx
101
+ import type { BoltTableIcons } from 'bolt-table';
102
+
103
+ <BoltTable
104
+ icons={{
105
+ gripVertical: <MyGripIcon size={12} />,
106
+ sortAsc: <MySortUpIcon size={12} />,
107
+ chevronsLeft: <MyFirstPageIcon size={12} />,
108
+ }}
109
+ />
110
+ ```
98
111
 
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.
112
+ Available icon keys: `gripVertical`, `sortAsc`, `sortDesc`, `filter`, `filterClear`, `pin`, `pinOff`, `eyeOff`, `chevronDown`, `chevronLeft`, `chevronRight`, `chevronsLeft`, `chevronsRight`.
100
113
 
101
114
  ---
102
115
 
@@ -116,7 +129,8 @@ Make sure your project has Tailwind configured and the Shadcn CSS variables defi
116
129
  | `className` | `string` | `''` | Class name for the outer wrapper |
117
130
  | `classNames` | `ClassNamesTypes` | `{}` | Granular class overrides per table region |
118
131
  | `styles` | `StylesTypes` | `{}` | Inline style overrides per table region |
119
- | `gripIcon` | `ReactNode` | — | Custom drag grip icon (defaults to `GripVertical`) |
132
+ | `icons` | `BoltTableIcons` | — | Custom icon overrides for built-in SVG icons |
133
+ | `gripIcon` | `ReactNode` | — | Custom drag grip icon (deprecated, use `icons.gripVertical`) |
120
134
  | `hideGripIcon` | `boolean` | `false` | Hide the drag grip icon from all headers |
121
135
  | `pagination` | `PaginationType \| false` | — | Pagination config, or `false` to disable |
122
136
  | `onPaginationChange` | `(page, pageSize) => void` | — | Called when page or page size changes |
@@ -172,7 +186,6 @@ const columns: ColumnType<User>[] = [
172
186
  dataIndex: 'name',
173
187
  title: 'Name',
174
188
  sortable: true,
175
- // Optional custom comparator:
176
189
  sorter: (a, b) => a.name.localeCompare(b.name),
177
190
  },
178
191
  {
@@ -180,7 +193,6 @@ const columns: ColumnType<User>[] = [
180
193
  dataIndex: 'age',
181
194
  title: 'Age',
182
195
  sortable: true,
183
- // Default numeric comparator used when sorter is omitted
184
196
  },
185
197
  ];
186
198
 
@@ -217,7 +229,6 @@ const columns: ColumnType<User>[] = [
217
229
  dataIndex: 'status',
218
230
  title: 'Status',
219
231
  filterable: true,
220
- // Exact match instead of default substring:
221
232
  filterFn: (value, record) => record.status === value,
222
233
  },
223
234
  ];
@@ -245,11 +256,9 @@ const columns: ColumnType<User>[] = [
245
256
  ```tsx
246
257
  <BoltTable
247
258
  columns={columns}
248
- data={allUsers} // all 500 rows
259
+ data={allUsers}
249
260
  pagination={{ pageSize: 20 }}
250
- onPaginationChange={(page, size) => {
251
- setPage(page);
252
- }}
261
+ onPaginationChange={(page, size) => setPage(page)}
253
262
  />
254
263
  ```
255
264
 
@@ -258,7 +267,7 @@ const columns: ColumnType<User>[] = [
258
267
  ```tsx
259
268
  <BoltTable
260
269
  columns={columns}
261
- data={currentPageData} // only 20 rows
270
+ data={currentPageData}
262
271
  pagination={{
263
272
  current: page,
264
273
  pageSize: 20,
@@ -287,10 +296,9 @@ const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
287
296
  data={data}
288
297
  rowKey="id"
289
298
  rowSelection={{
290
- type: 'checkbox', // or 'radio'
299
+ type: 'checkbox',
291
300
  selectedRowKeys,
292
301
  onChange: (keys, rows) => setSelectedRowKeys(keys),
293
- // Disable selection for specific rows:
294
302
  getCheckboxProps: (record) => ({
295
303
  disabled: record.status === 'locked',
296
304
  }),
@@ -315,12 +323,9 @@ const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
315
323
  <pre>{JSON.stringify(record.details, null, 2)}</pre>
316
324
  </div>
317
325
  ),
318
- // Optional: control expanded state yourself
319
- // expandedRowKeys={expandedKeys}
320
- // onExpandedRowsChange={(keys) => setExpandedKeys(keys)}
321
326
  }}
322
- expandedRowHeight={150} // initial estimate
323
- maxExpandedRowHeight={400} // makes panel scrollable if taller
327
+ expandedRowHeight={150}
328
+ maxExpandedRowHeight={400}
324
329
  />
325
330
  ```
326
331
 
@@ -353,8 +358,6 @@ const loadMore = async () => {
353
358
 
354
359
  ### Column pinning
355
360
 
356
- Pinning via column definition:
357
-
358
361
  ```tsx
359
362
  const columns: ColumnType<User>[] = [
360
363
  { key: 'name', dataIndex: 'name', title: 'Name', pinned: 'left', width: 200 },
@@ -367,58 +370,6 @@ Users can also pin/unpin columns at runtime via the right-click context menu.
367
370
 
368
371
  ---
369
372
 
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
373
  ### Styling overrides
423
374
 
424
375
  ```tsx
@@ -443,27 +394,6 @@ const columns: ColumnType<User>[] = [
443
394
 
444
395
  ---
445
396
 
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
397
  ### Fixed height (fill parent)
468
398
 
469
399
  By default, BoltTable auto-sizes to its content. To fill a fixed-height container instead:
@@ -491,6 +421,7 @@ import type {
491
421
  PaginationType,
492
422
  SortDirection,
493
423
  DataRecord,
424
+ BoltTableIcons,
494
425
  } from 'bolt-table';
495
426
  ```
496
427
 
@@ -498,4 +429,4 @@ import type {
498
429
 
499
430
  ## License
500
431
 
501
- MIT © [Venkatesh Sirigineedi](https://github.com
432
+ MIT © [Venkatesh Sirigineedi](https://github.com/venkateshsirigineedi)
package/dist/index.d.mts CHANGED
@@ -278,7 +278,7 @@ interface ColumnContextMenuItem {
278
278
  label: React.ReactNode;
279
279
  /**
280
280
  * Optional icon shown to the left of the label.
281
- * Recommended size: 12–14px (e.g. a lucide-react icon at h-3 w-3).
281
+ * Recommended size: 12–14px .
282
282
  *
283
283
  * @example
284
284
  * icon: <CopyIcon className="h-3 w-3" />
@@ -1238,11 +1238,13 @@ interface DraggableHeaderProps {
1238
1238
  /**
1239
1239
  * Called when the user presses down on the resize handle at the right edge
1240
1240
  * of this header cell. Starts the resize drag operation in BoltTable.
1241
- *
1242
- * @param columnKey - The key of the column being resized
1243
- * @param event - The React mouse event from the resize handle mousedown
1244
1241
  */
1245
1242
  onResizeStart?: (columnKey: string, event: React$1.MouseEvent) => void;
1243
+ /**
1244
+ * Called when the user starts dragging this column header to reorder.
1245
+ * BoltTable handles the full drag lifecycle from this point.
1246
+ */
1247
+ onColumnDragStart?: (columnKey: string, event: React$1.PointerEvent) => void;
1246
1248
  /**
1247
1249
  * Shared styling overrides for header cells.
1248
1250
  * `styles.header` applies to all headers; `styles.pinnedHeader` applies
@@ -1264,7 +1266,7 @@ interface DraggableHeaderProps {
1264
1266
  hideGripIcon?: boolean;
1265
1267
  /**
1266
1268
  * A custom React node to use as the drag grip icon.
1267
- * When omitted, the default `GripVertical` icon from lucide-react is used.
1269
+ * When omitted, the default `GripVertical` icon is used.
1268
1270
  *
1269
1271
  * @example
1270
1272
  * gripIcon={<MyCustomDragIcon />}
@@ -1375,7 +1377,7 @@ interface DraggableHeaderProps {
1375
1377
  *
1376
1378
  * @internal This is an internal BoltTable component. Use BoltTable directly.
1377
1379
  */
1378
- declare const DraggableHeader: React$1.MemoExoticComponent<({ column, visualIndex, accentColor, onResizeStart, styles, classNames, hideGripIcon, gripIcon, stickyOffset, onTogglePin, onToggleHide, isLastColumn, sortDirection, onSort, filterValue, onFilter, onClearFilter, customContextMenuItems, icons, }: DraggableHeaderProps) => react_jsx_runtime.JSX.Element>;
1380
+ declare const DraggableHeader: React$1.MemoExoticComponent<({ column, visualIndex, accentColor, onResizeStart, styles, classNames, hideGripIcon, gripIcon, stickyOffset, onTogglePin, onToggleHide, isLastColumn, sortDirection, onSort, filterValue, onFilter, onClearFilter, customContextMenuItems, icons, onColumnDragStart, }: DraggableHeaderProps) => react_jsx_runtime.JSX.Element>;
1379
1381
 
1380
1382
  /**
1381
1383
  * The imperative handle exposed by ResizeOverlay via `ref`.
package/dist/index.d.ts CHANGED
@@ -278,7 +278,7 @@ interface ColumnContextMenuItem {
278
278
  label: React.ReactNode;
279
279
  /**
280
280
  * Optional icon shown to the left of the label.
281
- * Recommended size: 12–14px (e.g. a lucide-react icon at h-3 w-3).
281
+ * Recommended size: 12–14px .
282
282
  *
283
283
  * @example
284
284
  * icon: <CopyIcon className="h-3 w-3" />
@@ -1238,11 +1238,13 @@ interface DraggableHeaderProps {
1238
1238
  /**
1239
1239
  * Called when the user presses down on the resize handle at the right edge
1240
1240
  * of this header cell. Starts the resize drag operation in BoltTable.
1241
- *
1242
- * @param columnKey - The key of the column being resized
1243
- * @param event - The React mouse event from the resize handle mousedown
1244
1241
  */
1245
1242
  onResizeStart?: (columnKey: string, event: React$1.MouseEvent) => void;
1243
+ /**
1244
+ * Called when the user starts dragging this column header to reorder.
1245
+ * BoltTable handles the full drag lifecycle from this point.
1246
+ */
1247
+ onColumnDragStart?: (columnKey: string, event: React$1.PointerEvent) => void;
1246
1248
  /**
1247
1249
  * Shared styling overrides for header cells.
1248
1250
  * `styles.header` applies to all headers; `styles.pinnedHeader` applies
@@ -1264,7 +1266,7 @@ interface DraggableHeaderProps {
1264
1266
  hideGripIcon?: boolean;
1265
1267
  /**
1266
1268
  * A custom React node to use as the drag grip icon.
1267
- * When omitted, the default `GripVertical` icon from lucide-react is used.
1269
+ * When omitted, the default `GripVertical` icon is used.
1268
1270
  *
1269
1271
  * @example
1270
1272
  * gripIcon={<MyCustomDragIcon />}
@@ -1375,7 +1377,7 @@ interface DraggableHeaderProps {
1375
1377
  *
1376
1378
  * @internal This is an internal BoltTable component. Use BoltTable directly.
1377
1379
  */
1378
- declare const DraggableHeader: React$1.MemoExoticComponent<({ column, visualIndex, accentColor, onResizeStart, styles, classNames, hideGripIcon, gripIcon, stickyOffset, onTogglePin, onToggleHide, isLastColumn, sortDirection, onSort, filterValue, onFilter, onClearFilter, customContextMenuItems, icons, }: DraggableHeaderProps) => react_jsx_runtime.JSX.Element>;
1380
+ declare const DraggableHeader: React$1.MemoExoticComponent<({ column, visualIndex, accentColor, onResizeStart, styles, classNames, hideGripIcon, gripIcon, stickyOffset, onTogglePin, onToggleHide, isLastColumn, sortDirection, onSort, filterValue, onFilter, onClearFilter, customContextMenuItems, icons, onColumnDragStart, }: DraggableHeaderProps) => react_jsx_runtime.JSX.Element>;
1379
1381
 
1380
1382
  /**
1381
1383
  * The imperative handle exposed by ResizeOverlay via `ref`.