@nexgrid/react 0.1.0 → 0.2.1
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 +81 -65
- package/dist/index.cjs +1045 -318
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -37
- package/dist/index.d.ts +112 -37
- package/dist/index.js +1070 -330
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/styles.css +1724 -445
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A server-driven data grid for React and Next.js.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
TableX renders one page of rows at a time and never holds the dataset. Every
|
|
6
6
|
piece of user intent — page, page size, sort, search, filters — is expressed as
|
|
7
7
|
a single `QueryState` object that **you** own; the grid hands you the next one
|
|
8
8
|
and re-renders when you hand back the matching page. That is the whole contract.
|
|
@@ -10,16 +10,23 @@ There is no local sort that quietly reorders 10 rows out of 40,000, and no
|
|
|
10
10
|
client-side filter that hides records the total still counts.
|
|
11
11
|
|
|
12
12
|
Around that core it provides the things every real admin table ends up needing:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
- 🗂️ **Column Header Grouping (Multi-Level / Stacked Headers)** — Group sub-columns beneath parent categories with automatic `colSpan` and `rowSpan` calculation.
|
|
14
|
+
- 🚀 **Client-Side Pagination & In-Memory Engine** — Zero-config in-memory paging, sorting, search, filtering, and export over local arrays.
|
|
15
|
+
- 💾 **Grid State Persistence (`storageKey`)** — Automatically saves column widths, column order, hidden columns, and row density to `localStorage`.
|
|
16
|
+
- ↔️ **Column Resizing & Auto-Fit** — Interactive drag resize handles and double-click auto-fit measuring.
|
|
17
|
+
- 🏷️ **Active Filter Pills Bar** — Interactive chip badges beneath the toolbar for active search & column filters with one-click `✕` removal and "Clear all".
|
|
18
|
+
- 🔍 **Debounced global search** (350 ms), 3-state sorting cycle (`asc → desc → cleared`), multi-column sorting.
|
|
19
|
+
- 📌 **Pinned columns** (left / right freeze), master-detail accordion row expansion, summary/aggregation footer row.
|
|
20
|
+
- 📊 **Formatted Excel (`.xls`) and CSV export**, including whole-dataset export across pages.
|
|
21
|
+
- 📱 **Responsive layout** — Full desktop table at ≥ 768 px, smart card list below.
|
|
22
|
+
- 💛 **Dual Language Support** — 100% compatible with both **TypeScript (TSX)** and **plain JavaScript (JSX)** with JSDoc typing.
|
|
18
23
|
|
|
19
24
|
- Zero runtime dependencies beyond `@nexgrid/core`. React is a peer dependency.
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
25
|
+
- Ships ESM and CJS, with a `"use client"` banner so it drops straight into the Next.js App Router.
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<img src="https://raw.githubusercontent.com/ChhaganSinha/NexGrid/master/docs/assets/tablex-preview.png" alt="TableX React Data Grid Preview" width="100%" />
|
|
29
|
+
</p>
|
|
23
30
|
|
|
24
31
|
## Installation
|
|
25
32
|
|
|
@@ -43,10 +50,10 @@ changes, and pass the result straight through.
|
|
|
43
50
|
|
|
44
51
|
import { useCallback, useEffect, useState } from "react";
|
|
45
52
|
import {
|
|
46
|
-
|
|
53
|
+
TableX,
|
|
47
54
|
defaultQuery,
|
|
48
55
|
serializeQuery,
|
|
49
|
-
type
|
|
56
|
+
type TableXReactColumn,
|
|
50
57
|
type PagedResponse,
|
|
51
58
|
type QueryState,
|
|
52
59
|
} from "@nexgrid/react";
|
|
@@ -60,7 +67,7 @@ interface Student {
|
|
|
60
67
|
joinedAt: string;
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
const columns:
|
|
70
|
+
const columns: TableXReactColumn<Student>[] = [
|
|
64
71
|
{ accessorKey: "name", header: "Name", meta: { minWidth: 180 } },
|
|
65
72
|
{ accessorKey: "email", header: "Email" },
|
|
66
73
|
{
|
|
@@ -105,7 +112,7 @@ export function StudentsGrid() {
|
|
|
105
112
|
}, [load, query]);
|
|
106
113
|
|
|
107
114
|
return (
|
|
108
|
-
<
|
|
115
|
+
<TableX
|
|
109
116
|
caption="Students"
|
|
110
117
|
columns={columns}
|
|
111
118
|
data={page?.items ?? []}
|
|
@@ -132,7 +139,7 @@ Your endpoint must answer with a `PagedResponse<T>`:
|
|
|
132
139
|
{ "items": [], "page": 1, "pageSize": 10, "total": 0, "totalPages": 1 }
|
|
133
140
|
```
|
|
134
141
|
|
|
135
|
-
If your API is ASP.NET Core, `
|
|
142
|
+
If your API is ASP.NET Core, `TableX.AspNetCore` binds exactly the query string
|
|
136
143
|
`serializeQuery` produces and returns exactly this shape.
|
|
137
144
|
|
|
138
145
|
### Putting the query in the URL
|
|
@@ -145,7 +152,7 @@ const searchParams = useSearchParams();
|
|
|
145
152
|
const router = useRouter();
|
|
146
153
|
const query = useMemo(() => parseQuery(searchParams.toString()), [searchParams]);
|
|
147
154
|
|
|
148
|
-
<
|
|
155
|
+
<TableX
|
|
149
156
|
query={query}
|
|
150
157
|
onQueryChange={(next) => router.replace(`?${serializeQuery(next)}`)}
|
|
151
158
|
{...rest}
|
|
@@ -158,7 +165,7 @@ never put the grid into an impossible state.
|
|
|
158
165
|
|
|
159
166
|
## Next.js App Router
|
|
160
167
|
|
|
161
|
-
The published bundle starts with `"use client"`, so `<
|
|
168
|
+
The published bundle starts with `"use client"`, so `<TableX />` can be imported
|
|
162
169
|
directly from a Server Component without a wrapper:
|
|
163
170
|
|
|
164
171
|
```tsx
|
|
@@ -182,33 +189,41 @@ Two notes:
|
|
|
182
189
|
|
|
183
190
|
| Prop | Type | Default | Description |
|
|
184
191
|
|------|------|---------|-------------|
|
|
185
|
-
| `columns` | `
|
|
186
|
-
| `data` | `TData[]` | required | The
|
|
187
|
-
| `total` | `number` |
|
|
188
|
-
| `query` | `QueryState` |
|
|
189
|
-
| `onQueryChange` | `(next: QueryState) => void` |
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `
|
|
194
|
-
| `
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
192
|
+
| `columns` | `TableXReactColumn<TData>[]` | required | Column definitions, in display order (supports multi-level `columns`). |
|
|
193
|
+
| `data` | `TData[]` | required | The current page of rows, or the entire array if `clientSidePagination` is true. |
|
|
194
|
+
| `total` | `number` | optional in client mode | Total filtered row count from the server. Drives the pager. |
|
|
195
|
+
| `query` | `QueryState` | optional in client mode | The query the `data` above answers. |
|
|
196
|
+
| `onQueryChange` | `(next: QueryState) => void` | optional in client mode | Called with the next query on page / size / sort / search changes. |
|
|
197
|
+
| `clientSidePagination` | `boolean` | `false` | Enables zero-config in-memory paging, sorting, search, and filtering over local data. |
|
|
198
|
+
| `storageKey` | `string` | — | Persists custom column widths, column order, hidden columns, and density to `localStorage`. |
|
|
199
|
+
| `caption` | `string` | required | Accessible name for the table; also default export filename and sheet title. |
|
|
200
|
+
| `density` | `"compact" \| "default" \| "comfortable"` | `"default"` | Initial density preset. |
|
|
201
|
+
| `enableColumnResize` | `boolean` | `true` | Enables interactive drag-to-resize and double-click auto-fit on column borders. |
|
|
202
|
+
| `enableColumnFilters` | `boolean` | `true` | Enables 3-dot column filter popovers (⋮) for text, select, and range filters. |
|
|
203
|
+
| `enableSorting` | `boolean` | `true` | Global switch for column sorting. |
|
|
204
|
+
| `enableSummaryRow` | `boolean` | `false` | Renders a summary / aggregation row in `<tfoot>`. |
|
|
205
|
+
| `enableRowExpansion` | `boolean` | `false` | Master-detail accordion expandable sub-rows. |
|
|
206
|
+
| `renderExpandedRow` | `(row: TData) => ReactNode` | — | Render function for expanded row content. |
|
|
207
|
+
| `enableBulkActions` | `boolean` | `false` | Floating bottom pill bar for batch operations on selected rows. |
|
|
208
|
+
| `isLoading` | `boolean` | `false` | Replaces rows with a spinner while keeping toolbar and footer interactive. |
|
|
209
|
+
| `error` | `boolean` | `false` | Replaces the whole grid with an accessible error card. |
|
|
210
|
+
| `onRetry` | `() => void` | — | When set, the error card displays a retry button. |
|
|
211
|
+
| `enableSelection` | `boolean` | `false` | Renders row selection checkboxes. |
|
|
212
|
+
| `selectionMode` | `"multi" \| "single"` | `"multi"` | Whether multiple rows or only one row can be selected. |
|
|
213
|
+
| `onSelectionChange` | `(ids: string[]) => void` | — | Fires after each selection change. |
|
|
197
214
|
| `enableSearch` | `boolean` | `true` | Shows the debounced global search box. |
|
|
198
215
|
| `searchPlaceholder` | `string` | `locale.searchPlaceholder` | Placeholder text for the search box. |
|
|
199
|
-
| `toolbarActions` | `ReactNode` | — |
|
|
200
|
-
| `onRowClick` | `(row: TData) => void` | — | Row / card click handler. Adds
|
|
216
|
+
| `toolbarActions` | `ReactNode` | — | Custom actions rendered at the end of the toolbar. |
|
|
217
|
+
| `onRowClick` | `(row: TData) => void` | — | Row / card click handler. Adds pointer cursor and keyboard activation. |
|
|
201
218
|
| `getRowId` | `(row: TData) => string` | `String(row.id ?? row)` | Stable row identity, used for selection and React keys. |
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `onNotify` | `(notice: NexGridNotice) => void` | no-op | Receives `{ type, message }` for export progress, failures, and successes. |
|
|
211
|
-
| `theme` | `"light" \| "dark" \| "auto"` | `"light"` | Adds `.nxg-dark` / `.nxg-auto` to the root. |
|
|
219
|
+
| `showSerialNumber` | `boolean` | `true` | Shows automatic `S.No.` column, numbered across pages. |
|
|
220
|
+
| `enableExport` | `boolean` | `true` | Shows the export menu (Excel, CSV, Clipboard). |
|
|
221
|
+
| `exportFileName` | `string` | caption, slug-safe | File name prefix without extension. |
|
|
222
|
+
| `fetchEndpoint` | `string` | — | Endpoint used to page in the full dataset during export. |
|
|
223
|
+
| `badgeRules` | `readonly ExcelBadgeRule[]` | core's `DEFAULT_BADGE_RULES` | Value-based cell styling for Excel export. |
|
|
224
|
+
| `locale` | `Partial<TableXLocale>` | English defaults | Overrides for any user-facing string. |
|
|
225
|
+
| `onNotify` | `(notice: TableXNotice) => void` | no-op | Receives `{ type, message }` for notifications. |
|
|
226
|
+
| `theme` | `"light" \| "dark" \| "auto"` | `"light"` | Sets `.tbx-dark` / `.tbx-auto` theme mode. |
|
|
212
227
|
|
|
213
228
|
## Column definitions
|
|
214
229
|
|
|
@@ -220,9 +235,10 @@ A column is a plain object, structurally compatible with TanStack Table's
|
|
|
220
235
|
| `id` | `string` | Column id. Falls back to `accessorKey`. |
|
|
221
236
|
| `accessorKey` | `string` | The row property this column reads. |
|
|
222
237
|
| `header` | `string \| (ctx) => ReactNode` | Header content. A string is also used for menus and export headers. |
|
|
238
|
+
| `columns` | `TableXReactColumn<TData>[]` | Nested sub-columns for multi-level stacked column header groups. |
|
|
223
239
|
| `cell` | `(ctx: { row: { original: TData }, getValue(): unknown }) => ReactNode` | Custom cell renderer. Without it the raw value is rendered as text. |
|
|
224
240
|
| `enableSorting` | `boolean` | Sorting is on by default; set `false` to opt out. |
|
|
225
|
-
| `meta` | `
|
|
241
|
+
| `meta` | `TableXColumnMeta` | Layout and behavior hints — see below. |
|
|
226
242
|
|
|
227
243
|
### `meta`
|
|
228
244
|
|
|
@@ -245,7 +261,7 @@ hideable, and never exported.
|
|
|
245
261
|
the mobile card list, so the two can never drift apart.
|
|
246
262
|
|
|
247
263
|
```tsx
|
|
248
|
-
const columns:
|
|
264
|
+
const columns: TableXReactColumn<Student>[] = [
|
|
249
265
|
// A status pill.
|
|
250
266
|
{
|
|
251
267
|
accessorKey: "status",
|
|
@@ -298,38 +314,38 @@ Every color and shape in the stylesheet reads a CSS custom property, so you
|
|
|
298
314
|
re-skin the grid by overriding tokens — no class overrides, no `!important`.
|
|
299
315
|
|
|
300
316
|
```css
|
|
301
|
-
.
|
|
302
|
-
--
|
|
303
|
-
--
|
|
304
|
-
--
|
|
305
|
-
--
|
|
317
|
+
.tbx-root {
|
|
318
|
+
--tbx-primary: #7c3aed;
|
|
319
|
+
--tbx-primary-fg: #ffffff;
|
|
320
|
+
--tbx-radius: 8px;
|
|
321
|
+
--tbx-font: "Inter", system-ui, sans-serif;
|
|
306
322
|
}
|
|
307
323
|
```
|
|
308
324
|
|
|
309
325
|
| Token | Purpose |
|
|
310
326
|
|-------|---------|
|
|
311
|
-
| `--
|
|
312
|
-
| `--
|
|
313
|
-
| `--
|
|
314
|
-
| `--
|
|
315
|
-
| `--
|
|
316
|
-
| `--
|
|
317
|
-
| `--
|
|
318
|
-
| `--
|
|
319
|
-
| `--
|
|
320
|
-
| `--
|
|
327
|
+
| `--tbx-font`, `--tbx-font-mono` | Body font, and the serial-number font. |
|
|
328
|
+
| `--tbx-bg` | Input and pager background. |
|
|
329
|
+
| `--tbx-card`, `--tbx-card-2` | Panel background, and the table header band. |
|
|
330
|
+
| `--tbx-border` | Every border and divider. |
|
|
331
|
+
| `--tbx-fg`, `--tbx-muted-fg` | Primary and secondary text. |
|
|
332
|
+
| `--tbx-muted` | Hover fills and subtle chips. |
|
|
333
|
+
| `--tbx-primary`, `--tbx-primary-fg` | Accent: sort icons, current page, selection. |
|
|
334
|
+
| `--tbx-danger` | Destructive accents. |
|
|
335
|
+
| `--tbx-radius`, `--tbx-radius-sm` | Panel and control corner radii. |
|
|
336
|
+
| `--tbx-shadow`, `--tbx-focus-ring` | Elevation, and the focus ring. |
|
|
321
337
|
|
|
322
338
|
Dark mode is a class, not a media query, so it can follow whatever your app
|
|
323
339
|
already uses:
|
|
324
340
|
|
|
325
341
|
```tsx
|
|
326
|
-
<
|
|
327
|
-
<
|
|
342
|
+
<TableX theme="dark" {...props} /> {/* always dark */}
|
|
343
|
+
<TableX theme="auto" {...props} /> {/* follows the OS */}
|
|
328
344
|
```
|
|
329
345
|
|
|
330
|
-
`theme="dark"` puts `.
|
|
331
|
-
dark class higher up the tree, add `
|
|
332
|
-
alone — the stylesheet matches `.
|
|
346
|
+
`theme="dark"` puts `.tbx-dark` on the grid root. If your app already toggles a
|
|
347
|
+
dark class higher up the tree, add `tbx-dark` alongside it and leave `theme`
|
|
348
|
+
alone — the stylesheet matches `.tbx-dark .tbx-root` as well.
|
|
333
349
|
|
|
334
350
|
Responsive behavior is driven entirely by the stylesheet: the grid renders both a
|
|
335
351
|
table and a card list, and CSS shows the table at ≥ 768px and the cards below it.
|
|
@@ -348,7 +364,7 @@ If those requests fail it notifies you and falls back to the current page rather
|
|
|
348
364
|
than producing nothing.
|
|
349
365
|
|
|
350
366
|
```tsx
|
|
351
|
-
<
|
|
367
|
+
<TableX
|
|
352
368
|
fetchEndpoint="/api/students"
|
|
353
369
|
exportFileName="student_roster"
|
|
354
370
|
badgeRules={[
|
|
@@ -375,7 +391,7 @@ is `"info" | "success" | "error"`, ready to forward to whatever you already use.
|
|
|
375
391
|
Every user-facing string comes from a locale object. Override any subset:
|
|
376
392
|
|
|
377
393
|
```tsx
|
|
378
|
-
<
|
|
394
|
+
<TableX
|
|
379
395
|
locale={{
|
|
380
396
|
searchPlaceholder: "Rechercher…",
|
|
381
397
|
emptyText: "Aucun enregistrement ne correspond à votre recherche.",
|
|
@@ -428,5 +444,5 @@ one and that the sort cycle stays `asc → desc → cleared` across every adapte
|
|
|
428
444
|
|
|
429
445
|
## License
|
|
430
446
|
|
|
431
|
-
[MIT](https://github.com/ChhaganSinha/
|
|
447
|
+
[MIT](https://github.com/ChhaganSinha/TableX/blob/main/LICENSE) © 2026 Chhagan Sinha
|
|
432
448
|
|