@snowpact/react-tanstack-query-table 1.3.0 → 1.4.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/README.md CHANGED
@@ -8,49 +8,84 @@ Ultra-light, registry-based data table for React + TanStack Table + TanStack Que
8
8
  - **Registry-based**: Inject your own i18n, Link component, confirmation dialogs
9
9
  - **TypeScript**: Full type support with generics
10
10
  - **Two modes**: Client-side and Server-side pagination/filtering/sorting
11
- - **Customizable**: Override styles via registry
11
+ - **Customizable**: Override styles via CSS variables or registry
12
12
 
13
- ## Installation
13
+ ## Quick Setup
14
+
15
+ ### 1. Install
14
16
 
15
17
  ```bash
18
+ npm install @tanstack/react-query @tanstack/react-table
16
19
  npm install @snowpact/react-tanstack-query-table
17
- # or
18
- pnpm add @snowpact/react-tanstack-query-table
19
20
  ```
20
21
 
21
- ### Peer Dependencies
22
+ ### 2. Import styles
22
23
 
23
- ```bash
24
- npm install @tanstack/react-query @tanstack/react-table react react-dom
24
+ ```tsx
25
+ // In your app entry point (main.tsx or App.tsx)
26
+ import '@snowpact/react-tanstack-query-table/styles.css';
25
27
  ```
26
28
 
27
- ### Import Styles
29
+ ### 3. Setup once
30
+
31
+ ```tsx
32
+ import { setupSnowTable } from '@snowpact/react-tanstack-query-table';
33
+ import { Link } from 'react-router-dom';
34
+
35
+ // Your translation function (or just return the key)
36
+ const t = (key: string) => translations[key] || key;
37
+
38
+ setupSnowTable({
39
+ t,
40
+ LinkComponent: Link,
41
+ confirm: ({ title }) => window.confirm(title),
42
+ });
43
+ ```
28
44
 
29
- Import the library CSS in your app entry point:
45
+ ### 4. Use the table
30
46
 
31
47
  ```tsx
32
- import '@snowpact/react-tanstack-query-table/styles.css';
48
+ import { SnowClientDataTable, SnowColumnConfig } from '@snowpact/react-tanstack-query-table';
49
+
50
+ type User = { id: string; name: string; email: string; status: string };
51
+
52
+ const columns: SnowColumnConfig<User>[] = [
53
+ { key: 'name', label: 'Name' },
54
+ { key: 'email', label: 'Email' },
55
+ { key: 'status', label: 'Status' },
56
+ ];
57
+
58
+ <SnowClientDataTable
59
+ queryKey={['users']}
60
+ fetchAllItemsEndpoint={() => fetchUsers()}
61
+ columnConfig={columns}
62
+ enableGlobalSearch
63
+ enablePagination
64
+ />
33
65
  ```
34
66
 
35
- ### Customization (Optional)
67
+ That's it! You have a working data table.
68
+
69
+ ---
70
+
71
+ ## Advanced Configuration
72
+
73
+ ### Theme Customization
36
74
 
37
- You can customize the library appearance by overriding CSS variables:
75
+ Override CSS variables to match your design:
38
76
 
39
77
  ```css
40
78
  :root {
41
- --snow-background: #ffffff; /* Main background (table, rows, inputs) */
42
- --snow-foreground: #0a0a0a; /* Main text color */
43
- --snow-secondary: #f5f5f5; /* Secondary background (headers, hover) */
44
- --snow-secondary-foreground: #737373; /* Secondary text color */
45
- --snow-border: #d4d4d4; /* Border color */
46
- --snow-ring: #a3a3a3; /* Focus ring color */
47
- --snow-radius: 0.375rem; /* Border radius */
79
+ --snow-background: #ffffff;
80
+ --snow-foreground: #0a0a0a;
81
+ --snow-secondary: #f5f5f5;
82
+ --snow-secondary-foreground: #737373;
83
+ --snow-border: #d4d4d4;
84
+ --snow-ring: #a3a3a3;
85
+ --snow-radius: 0.375rem;
48
86
  }
49
- ```
50
87
 
51
- **Dark mode example:**
52
-
53
- ```css
88
+ /* Dark mode */
54
89
  .dark {
55
90
  --snow-background: #1a1a2e;
56
91
  --snow-foreground: #eaeaea;
@@ -61,73 +96,100 @@ You can customize the library appearance by overriding CSS variables:
61
96
  }
62
97
  ```
63
98
 
64
- ## Quick Start
65
-
66
- ### 1. Setup (once in your app)
99
+ ### Setup with i18n (react-i18next)
67
100
 
68
101
  ```tsx
69
- // Import styles first
70
- import '@snowpact/react-tanstack-query-table/styles.css';
71
-
72
- import { setupSnowTable } from '@snowpact/react-tanstack-query-table';
73
102
  import { useTranslation } from 'react-i18next';
74
- import { Link } from 'react-router-dom';
75
- import { useConfirm } from './your-confirm-dialog';
103
+
104
+ // Get t function at module level or use a hook wrapper
105
+ const { t } = i18n;
76
106
 
77
107
  setupSnowTable({
78
- useTranslation: () => useTranslation(),
108
+ t: (key) => t(key),
79
109
  LinkComponent: Link,
80
- useConfirm: () => useConfirm(),
110
+ confirm: ({ title, content }) => {
111
+ const message = typeof content === 'string' ? `${title}\n\n${content}` : title;
112
+ return window.confirm(message);
113
+ },
81
114
  });
82
115
  ```
83
116
 
84
- > **Full setup example**: See [examples/full-setup.md](./examples/full-setup.md) for a complete Shadcn/UI integration with custom `useConfirm` hook and translations.
117
+ Required translation keys:
118
+ - `dataTable.search` - Search placeholder
119
+ - `dataTable.elements` - "elements" label
120
+ - `dataTable.searchEmpty` - Empty state text
121
+ - `dataTable.resetFilters` - Reset button tooltip
122
+ - `dataTable.columns` - Columns button label
85
123
 
86
- ### 2. Use a Client Table
124
+ ### Setup with custom confirm dialog
87
125
 
88
126
  ```tsx
89
- import { SnowClientDataTable, SnowColumnConfig } from '@snowpact/react-tanstack-query-table';
90
- import { Edit, Trash } from 'lucide-react';
127
+ import { useConfirmDialog } from './your-confirm-hook';
91
128
 
92
- type User = { id: string; name: string; email: string };
129
+ // If you have a hook-based confirm dialog
130
+ const confirmDialog = useConfirmDialog();
93
131
 
94
- const columns: SnowColumnConfig<User>[] = [{ key: 'name' }, { key: 'email' }];
132
+ setupSnowTable({
133
+ t,
134
+ LinkComponent: Link,
135
+ confirm: async ({ title, content, confirmText, cancelText }) => {
136
+ return confirmDialog.open({
137
+ title,
138
+ description: content,
139
+ confirmLabel: confirmText,
140
+ cancelLabel: cancelText,
141
+ });
142
+ },
143
+ });
144
+ ```
95
145
 
96
- <SnowClientDataTable
97
- queryKey={['users']}
98
- fetchAllItemsEndpoint={() => fetchUsers()}
99
- columnConfig={columns}
100
- actions={[
101
- { type: 'click', icon: Edit, label: 'Edit', onClick: user => editUser(user) },
102
- { type: 'endpoint', icon: Trash, label: 'Delete', endpoint: user => deleteUser(user.id) },
103
- ]}
104
- enableGlobalSearch
105
- enablePagination
106
- />;
146
+ ### Override component styles (rare)
147
+
148
+ For deep customization, override internal Tailwind classes:
149
+
150
+ ```tsx
151
+ setupSnowTable({
152
+ t,
153
+ LinkComponent: Link,
154
+ confirm: ({ title }) => window.confirm(title),
155
+ styles: {
156
+ button: {
157
+ visual: 'rounded-full bg-primary text-primary-foreground',
158
+ hover: 'hover:bg-primary/90',
159
+ },
160
+ table: {
161
+ header: 'bg-slate-100 dark:bg-slate-800',
162
+ rowHover: 'hover:bg-slate-50',
163
+ },
164
+ input: 'rounded-full border-2 border-primary',
165
+ },
166
+ });
107
167
  ```
108
168
 
169
+ ---
170
+
109
171
  ## Client vs Server Mode
110
172
 
111
- | Mode | Component | Use case | Data handling |
112
- | ---------- | ----------------- | ------------- | ----------------------------------------------- |
113
- | **Client** | `SnowClientDataTable` | < 5,000 items | All data loaded, filtered/sorted locally |
114
- | **Server** | `SnowServerDataTable` | > 5,000 items | Paginated API, server handles filtering/sorting |
173
+ | Mode | Component | Use case | Data handling |
174
+ | ---------- | --------------------- | ------------- | ---------------------------------------- |
175
+ | **Client** | `SnowClientDataTable` | < 5,000 items | All data loaded, filtered/sorted locally |
176
+ | **Server** | `SnowServerDataTable` | > 5,000 items | Server handles pagination/filtering |
115
177
 
116
178
  ### SnowClientDataTable
117
179
 
118
- Best for small to medium datasets. Fetches all data once via React Query, then handles pagination, search, and sorting entirely in the browser.
180
+ Fetches all data once, handles everything in the browser:
119
181
 
120
182
  ```tsx
121
183
  <SnowClientDataTable
122
184
  queryKey={['users']}
123
- fetchAllItemsEndpoint={() => api.getUsers()} // Returns User[]
185
+ fetchAllItemsEndpoint={() => api.getUsers()}
124
186
  columnConfig={columns}
125
187
  />
126
188
  ```
127
189
 
128
190
  ### SnowServerDataTable
129
191
 
130
- Best for large datasets. The server handles pagination, search, filtering, and sorting. Returns paginated results with a total count.
192
+ Server handles pagination, search, filtering, and sorting:
131
193
 
132
194
  ```tsx
133
195
  import { SnowServerDataTable, ServerFetchParams } from '@snowpact/react-tanstack-query-table';
@@ -141,21 +203,25 @@ const fetchUsers = async (params: ServerFetchParams) => {
141
203
  };
142
204
  };
143
205
 
144
- <SnowServerDataTable queryKey={['users']} fetchServerEndpoint={fetchUsers} columnConfig={columns} />;
206
+ <SnowServerDataTable
207
+ queryKey={['users']}
208
+ fetchServerEndpoint={fetchUsers}
209
+ columnConfig={columns}
210
+ />
145
211
  ```
146
212
 
213
+ ---
214
+
147
215
  ## Actions
148
216
 
149
- Actions appear as buttons in each row. Three types are available:
217
+ Actions appear as buttons in each row:
150
218
 
151
219
  ### Click Action
152
220
 
153
- Simple callback when clicked.
154
-
155
221
  ```tsx
156
222
  {
157
223
  type: 'click',
158
- icon: Edit,
224
+ icon: EditIcon,
159
225
  label: 'Edit',
160
226
  onClick: (item) => openEditModal(item),
161
227
  }
@@ -163,12 +229,10 @@ Simple callback when clicked.
163
229
 
164
230
  ### Link Action
165
231
 
166
- Navigates to a URL. Uses your registered `LinkComponent`.
167
-
168
232
  ```tsx
169
233
  {
170
234
  type: 'link',
171
- icon: Eye,
235
+ icon: EyeIcon,
172
236
  label: 'View',
173
237
  href: (item) => `/users/${item.id}`,
174
238
  external: false, // true for target="_blank"
@@ -177,123 +241,57 @@ Navigates to a URL. Uses your registered `LinkComponent`.
177
241
 
178
242
  ### Endpoint Action
179
243
 
180
- Calls an async endpoint (API mutation). Integrates with React Query invalidation.
181
-
182
- ```tsx
183
- {
184
- type: 'endpoint',
185
- icon: Trash,
186
- label: 'Delete',
187
- endpoint: (item) => api.deleteUser(item.id),
188
- onSuccess: () => queryClient.invalidateQueries(['users']),
189
- onError: (error) => toast.error(error.message),
190
- }
191
- ```
192
-
193
- ### Confirmation Dialog
194
-
195
- Any action can require confirmation before executing:
196
-
197
244
  ```tsx
198
245
  {
199
246
  type: 'endpoint',
200
- icon: Trash,
247
+ icon: TrashIcon,
201
248
  label: 'Delete',
202
249
  variant: 'danger',
203
250
  endpoint: (item) => api.deleteUser(item.id),
251
+ onSuccess: () => queryClient.invalidateQueries(['users']),
204
252
  confirm: {
205
253
  title: 'Delete user?',
206
254
  content: 'This action cannot be undone.',
207
- confirmText: 'Delete',
208
- cancelText: 'Cancel',
209
- },
210
- }
211
- ```
212
-
213
- For forms inside confirm dialogs, use a function to access the `close` helper:
214
-
215
- ```tsx
216
- {
217
- type: 'click',
218
- icon: Edit,
219
- label: 'Change Status',
220
- onClick: () => {},
221
- confirm: {
222
- title: 'Change Status',
223
- hideButtons: true, // Form handles its own buttons
224
- content: ({ close }) => (
225
- <StatusForm
226
- onSuccess={() => {
227
- queryClient.invalidateQueries(['users']);
228
- close();
229
- }}
230
- />
231
- ),
232
255
  },
233
256
  }
234
257
  ```
235
258
 
236
- ### Action Options
237
-
238
- | Option | Type | Description |
239
- | ----------- | ----------------------------------------------------------- | ---------------------------------------- |
240
- | `icon` | `ComponentType<SVGProps>` | Icon component (lucide-react or any SVG) |
241
- | `label` | `string` | Button label (used for tooltip) |
242
- | `variant` | `'default' \| 'danger' \| 'warning' \| 'info' \| 'success'` | Button color variant |
243
- | `display` | `'button' \| 'dropdown'` | Show as button or in dropdown menu |
244
- | `hidden` | `boolean` | Conditionally hide the action |
245
- | `disabled` | `boolean` | Disable the action |
246
- | `showLabel` | `boolean` | Show label text next to icon |
247
-
248
259
  ### Dynamic Actions
249
260
 
250
- Actions can be functions that return the action config, allowing per-row customization:
251
-
252
261
  ```tsx
253
262
  actions={[
254
263
  (item) => ({
255
264
  type: 'click',
256
- icon: item.isActive ? Pause : Play,
265
+ icon: item.isActive ? PauseIcon : PlayIcon,
257
266
  label: item.isActive ? 'Deactivate' : 'Activate',
258
267
  onClick: () => toggleStatus(item),
259
- hidden: item.role === 'admin', // Hide for admins
268
+ hidden: item.role === 'admin',
260
269
  }),
261
270
  ]}
262
271
  ```
263
272
 
264
- ## Search & Filtering
273
+ ---
265
274
 
266
- ### Global Search
267
-
268
- Enable fuzzy search across all columns:
269
-
270
- ```tsx
271
- <SnowClientDataTable enableGlobalSearch texts={{ searchPlaceholder: 'Search users...' }} />
272
- ```
275
+ ## Filters
273
276
 
274
- For custom search values (computed columns):
277
+ ### Global Search
275
278
 
276
279
  ```tsx
277
- const columns: SnowColumnConfig<User>[] = [
278
- {
279
- key: '_extra_fullName',
280
- label: 'Full Name',
281
- render: item => `${item.firstName} ${item.lastName}`,
282
- searchableValue: item => `${item.firstName} ${item.lastName}`,
283
- },
284
- ];
280
+ <SnowClientDataTable
281
+ enableGlobalSearch
282
+ texts={{ searchPlaceholder: 'Search users...' }}
283
+ />
285
284
  ```
286
285
 
287
286
  ### Column Filters
288
287
 
289
- Multi-select dropdown filters:
290
-
291
288
  ```tsx
292
289
  <SnowClientDataTable
293
290
  filters={[
294
291
  {
295
292
  key: 'status',
296
293
  label: 'Status',
294
+ multipleSelection: true, // Allow multiple values
297
295
  options: [
298
296
  { value: 'active', label: 'Active' },
299
297
  { value: 'inactive', label: 'Inactive' },
@@ -313,14 +311,11 @@ Multi-select dropdown filters:
313
311
 
314
312
  ### Prefilters (Tabs)
315
313
 
316
- Quick segmentation via tabs:
317
-
318
314
  ```tsx
319
315
  <SnowClientDataTable
320
316
  prefilters={[
321
317
  { id: 'all', label: 'All' },
322
318
  { id: 'active', label: 'Active' },
323
- { id: 'archived', label: 'Archived' },
324
319
  ]}
325
320
  prefilterFn={(item, prefilterId) => {
326
321
  if (prefilterId === 'all') return true;
@@ -329,72 +324,37 @@ Quick segmentation via tabs:
329
324
  />
330
325
  ```
331
326
 
332
- For server mode, the `prefilter` value is sent to your endpoint.
327
+ ---
333
328
 
334
- ## Advanced Configuration
329
+ ## Other Features
335
330
 
336
- ### Column Configuration
337
-
338
- Users can show/hide columns via a settings button. Configuration is saved in cookies.
331
+ ### URL State Persistence
339
332
 
340
333
  ```tsx
341
- <SnowClientDataTable
342
- enableColumnConfiguration
343
- columnConfig={[
344
- { key: 'name' }, // Always visible
345
- { key: 'email' },
346
- { key: 'details', meta: { defaultHidden: true } }, // Hidden by default
347
- ]}
348
- />
334
+ <SnowClientDataTable persistState />
349
335
  ```
350
336
 
351
- ### URL State Persistence
337
+ Saves pagination, search, filters, and sorting in URL params.
352
338
 
353
- Persist table state (pagination, search, filters, sorting) in URL query params:
339
+ ### Column Configuration
354
340
 
355
341
  ```tsx
356
342
  <SnowClientDataTable
357
- persistState // State saved in URL
343
+ enableColumnConfiguration
344
+ columnConfig={[
345
+ { key: 'name' },
346
+ { key: 'details', meta: { defaultHidden: true } },
347
+ ]}
358
348
  />
359
349
  ```
360
350
 
361
- URL params used:
362
-
363
- - `dt_page`, `dt_pageSize` - Pagination
364
- - `dt_search` - Search query
365
- - `dt_prefilter` - Active prefilter
366
- - `dt_filters` - Column filters
367
- - `dt_sortBy`, `dt_sortDesc` - Sorting
368
-
369
- ### Column Meta Properties
370
-
371
- ```tsx
372
- {
373
- key: 'actions',
374
- meta: {
375
- width: '100px', // Fixed width
376
- minWidth: '80px', // Minimum width
377
- center: true, // Center content
378
- defaultHidden: true, // Hidden by default
379
- disableColumnClick: true, // Disable row click for this column
380
- },
381
- }
382
- ```
383
-
384
351
  ### Sorting
385
352
 
386
- ```tsx
387
- <SnowClientDataTable enableSorting defaultSortBy="createdAt" defaultSortOrder="desc" />
388
- ```
389
-
390
- ### Pagination
391
-
392
353
  ```tsx
393
354
  <SnowClientDataTable
394
- enablePagination
395
- defaultPageSize={25}
396
- displayTotalNumber // Show "X elements"
397
- enableElementLabel // Show element label
355
+ enableSorting
356
+ defaultSortBy="createdAt"
357
+ defaultSortOrder="desc"
398
358
  />
399
359
  ```
400
360
 
@@ -402,35 +362,35 @@ URL params used:
402
362
 
403
363
  ```tsx
404
364
  <SnowClientDataTable
405
- onRowClick={item => navigate(`/users/${item.id}`)}
406
- activeRowId={selectedUserId} // Highlight active row
365
+ onRowClick={(item) => navigate(`/users/${item.id}`)}
366
+ activeRowId={selectedUserId}
407
367
  />
408
368
  ```
409
369
 
410
- ### Custom Styles
411
-
412
- Override default Tailwind classes via the registry:
370
+ ### Custom Column Rendering
413
371
 
414
372
  ```tsx
415
- setupSnowTable({
416
- // ... other options
417
- styles: {
418
- table: {
419
- wrapper: 'border border-gray-200 rounded-lg',
420
- header: 'bg-gray-50',
421
- row: 'hover:bg-gray-100',
422
- },
423
- button: {
424
- visual: 'bg-blue-500 text-white',
425
- hover: 'hover:bg-blue-600',
426
- },
373
+ const columns: SnowColumnConfig<User>[] = [
374
+ { key: 'name', label: 'Name' },
375
+ {
376
+ key: 'status',
377
+ label: 'Status',
378
+ render: (item) => (
379
+ <span className={item.status === 'active' ? 'text-green-500' : 'text-red-500'}>
380
+ {item.status}
381
+ </span>
382
+ ),
427
383
  },
428
- });
384
+ {
385
+ key: '_extra_fullName', // Use _extra_ prefix for computed columns
386
+ label: 'Full Name',
387
+ render: (item) => `${item.firstName} ${item.lastName}`,
388
+ searchableValue: (item) => `${item.firstName} ${item.lastName}`,
389
+ },
390
+ ];
429
391
  ```
430
392
 
431
- ### Action Tooltips
432
-
433
- Action buttons automatically display tooltips on hover. The tooltip uses your theme's CSS variables (`--snow-foreground`, `--snow-background`, `--snow-radius`) for consistent styling.
393
+ ---
434
394
 
435
395
  ## API Reference
436
396
 
@@ -441,23 +401,22 @@ Action buttons automatically display tooltips on hover. The tooltip uses your th
441
401
  | `queryKey` | `string[]` | Required | React Query cache key |
442
402
  | `fetchAllItemsEndpoint` | `() => Promise<T[]>` | Required | Data fetching function |
443
403
  | `columnConfig` | `SnowColumnConfig<T>[]` | Required | Column definitions |
444
- | `actions` | `TableAction<T>[]` | `[]` | Row actions |
445
- | `filters` | `FilterConfig<T>[]` | `[]` | Column filters |
446
- | `prefilters` | `PreFilter[]` | `[]` | Tab filters |
404
+ | `actions` | `TableAction<T>[]` | - | Row actions |
405
+ | `filters` | `FilterConfig<T>[]` | - | Column filters |
406
+ | `prefilters` | `PreFilter[]` | - | Tab filters |
447
407
  | `prefilterFn` | `(item, id) => boolean` | - | Client-side prefilter logic |
448
408
  | `persistState` | `boolean` | `false` | Persist state in URL |
449
409
  | `enableGlobalSearch` | `boolean` | `false` | Enable search bar |
450
- | `enablePagination` | `boolean` | `false` | Enable pagination |
451
- | `enableSorting` | `boolean` | `false` | Enable column sorting |
410
+ | `enablePagination` | `boolean` | `true` | Enable pagination |
411
+ | `enableSorting` | `boolean` | `true` | Enable column sorting |
452
412
  | `enableColumnConfiguration` | `boolean` | `false` | Enable column visibility toggle |
453
- | `enableResetFilters` | `boolean` | `false` | Show reset filters button |
454
413
  | `defaultPageSize` | `number` | `10` | Initial page size |
455
414
  | `defaultSortBy` | `string` | - | Initial sort column |
456
415
  | `defaultSortOrder` | `'asc' \| 'desc'` | `'asc'` | Initial sort direction |
457
416
 
458
417
  ### SnowServerDataTable Props
459
418
 
460
- Same as `SnowClientDataTable`, except:
419
+ Same as `SnowClientDataTable`, plus:
461
420
 
462
421
  | Prop | Type | Description |
463
422
  | --------------------- | -------------------------------------------------------------------- | ------------------------ |