@manusiakemos/laravel-tanstack-react 0.1.0 → 0.1.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 +284 -33
- package/dist/index.cjs +638 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +364 -4
- package/dist/index.d.ts +364 -4
- package/dist/index.js +623 -3
- package/dist/index.js.map +1 -1
- package/package.json +7 -1
- package/src/components/DataTable.tsx +166 -0
- package/src/components/DataTableFilter.tsx +217 -0
- package/src/components/DataTablePagination.tsx +271 -0
- package/src/components/DataTableSearch.tsx +173 -0
- package/src/components/layouts/DataTableSplitLayout.tsx +153 -0
- package/src/components/ui/button.tsx +49 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/select.tsx +27 -0
- package/src/components/ui/table.tsx +120 -0
- package/src/hooks/useDataTable.ts +1 -1
- package/src/index.ts +60 -2
- package/src/lib/cn.ts +10 -0
package/README.md
CHANGED
|
@@ -23,59 +23,244 @@ composer require manusiakemos/laravel-tanstack
|
|
|
23
23
|
## Quick start
|
|
24
24
|
|
|
25
25
|
```tsx
|
|
26
|
-
import {
|
|
27
|
-
|
|
26
|
+
import {
|
|
27
|
+
DataTable,
|
|
28
|
+
DataTableFilter,
|
|
29
|
+
DataTablePagination,
|
|
30
|
+
DataTableSearch,
|
|
31
|
+
useDataTable,
|
|
32
|
+
} from '@manusiakemos/laravel-tanstack-react'
|
|
28
33
|
|
|
29
34
|
interface User {
|
|
30
35
|
id: number
|
|
31
36
|
name: string
|
|
32
37
|
email: string
|
|
38
|
+
status: 'active' | 'inactive'
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
export default function UsersIndex() {
|
|
36
42
|
const { table, loading, meta } = useDataTable<User>({
|
|
37
43
|
endpoint: '/datatable/users',
|
|
38
44
|
columns: [
|
|
39
|
-
{ accessorKey: 'name', header: '
|
|
40
|
-
{ accessorKey: 'email', header: 'Email' },
|
|
45
|
+
{ accessorKey: 'name', header: 'Name', enableSorting: true },
|
|
46
|
+
{ accessorKey: 'email', header: 'Email', enableSorting: true },
|
|
47
|
+
{
|
|
48
|
+
accessorKey: 'status',
|
|
49
|
+
header: 'Status',
|
|
50
|
+
enableColumnFilter: true,
|
|
51
|
+
},
|
|
41
52
|
],
|
|
42
53
|
})
|
|
43
54
|
|
|
44
55
|
return (
|
|
45
|
-
<
|
|
46
|
-
<
|
|
47
|
-
{table
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
</tr>
|
|
69
|
-
))}
|
|
70
|
-
</tbody>
|
|
71
|
-
</table>
|
|
56
|
+
<div className="space-y-4">
|
|
57
|
+
<div className="flex flex-wrap gap-3">
|
|
58
|
+
<DataTableSearch table={table} placeholder="Search users..." />
|
|
59
|
+
<DataTableFilter
|
|
60
|
+
table={table}
|
|
61
|
+
columnId="status"
|
|
62
|
+
options={[
|
|
63
|
+
{ label: 'Active', value: 'active' },
|
|
64
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
65
|
+
]}
|
|
66
|
+
placeholder="All statuses"
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<DataTable table={table} loading={loading} />
|
|
71
|
+
|
|
72
|
+
<DataTablePagination
|
|
73
|
+
table={table}
|
|
74
|
+
meta={meta}
|
|
75
|
+
showPageSize
|
|
76
|
+
showFirstLast
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
72
79
|
)
|
|
73
80
|
}
|
|
74
81
|
```
|
|
75
82
|
|
|
76
83
|
That's it. Pagination, sorting, filtering, and global search are all wired up. Your backend controller stays under 10 lines (see the Composer package README).
|
|
77
84
|
|
|
78
|
-
|
|
85
|
+
> **Styling.** Components ship pre-styled with [shadcn/ui](https://ui.shadcn.com)-style Tailwind classes (Button, Input, Select, Table primitives are bundled). Make sure Tailwind is configured in your app with the standard shadcn theme tokens (`--background`, `--foreground`, `--primary`, `--border`, `--ring`, `--muted-foreground`, etc.). Every component accepts `className`, fine-grained `classNames`, and a full `render` prop so you can swap in your own UI.
|
|
86
|
+
|
|
87
|
+
See the [full Inertia example](./examples/inertia-users-index.tsx) for pagination, filters, and search wiring.
|
|
88
|
+
|
|
89
|
+
## Components
|
|
90
|
+
|
|
91
|
+
All four components below are **fully customizable via props** — you can override class names, labels, sub-element styles, or replace the entire UI via the `render` prop while keeping the table wiring intact.
|
|
92
|
+
|
|
93
|
+
### `<DataTable />`
|
|
94
|
+
|
|
95
|
+
Shadcn-styled table with built-in sort indicators, empty state, and loading state.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
<DataTable
|
|
99
|
+
table={table}
|
|
100
|
+
loading={loading}
|
|
101
|
+
emptyMessage="No users yet."
|
|
102
|
+
loadingMessage="Fetching..."
|
|
103
|
+
onRowClick={(user) => navigate(`/users/${user.id}`)}
|
|
104
|
+
className="rounded-lg"
|
|
105
|
+
classNames={{ row: 'hover:bg-muted/30', cell: 'py-3' }}
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `<DataTableSearch />`
|
|
110
|
+
|
|
111
|
+
Global search. Debounced by default; pass `debounce={false}` to switch to **manual mode with a Search button** (input + button, submits on click or Enter).
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
{/* Debounced (default, 300ms) */}
|
|
115
|
+
<DataTableSearch table={table} placeholder="Search..." />
|
|
116
|
+
|
|
117
|
+
{/* Custom debounce delay */}
|
|
118
|
+
<DataTableSearch table={table} debounce={500} />
|
|
119
|
+
|
|
120
|
+
{/* Manual submit — Search button */}
|
|
121
|
+
<DataTableSearch table={table} debounce={false} placeholder="Search..." />
|
|
122
|
+
|
|
123
|
+
{/* Fully custom UI */}
|
|
124
|
+
<DataTableSearch
|
|
125
|
+
table={table}
|
|
126
|
+
render={({ value, setValue, submit }) => (
|
|
127
|
+
<MyCombobox value={value} onChange={setValue} onSubmit={submit} />
|
|
128
|
+
)}
|
|
129
|
+
/>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
| Prop | Type | Default | Description |
|
|
133
|
+
|---|---|---|---|
|
|
134
|
+
| `debounce` | `boolean \| number` | `true` | `true` → 300ms; number → custom ms; `false` → manual + Search button. |
|
|
135
|
+
| `placeholder` | `string` | `'Search...'` | Placeholder text. |
|
|
136
|
+
| `submitLabel` | `ReactNode` | Search icon + "Search" | Button label when `debounce={false}`. |
|
|
137
|
+
| `className` | `string` | — | Root wrapper class. |
|
|
138
|
+
| `inputClassName` | `string` | — | Class merged into the Input. |
|
|
139
|
+
| `buttonClassName` | `string` | — | Class merged into the submit Button. |
|
|
140
|
+
| `onSearch` | `(value: string) => void` | — | Fired when the search is committed. |
|
|
141
|
+
| `render` | `(props) => ReactNode` | — | Full UI override. |
|
|
142
|
+
|
|
143
|
+
### `<DataTablePagination />`
|
|
144
|
+
|
|
145
|
+
Prev/next (and optional first/last) buttons, page-size selector, row-count summary.
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
<DataTablePagination
|
|
149
|
+
table={table}
|
|
150
|
+
meta={meta}
|
|
151
|
+
showPageSize
|
|
152
|
+
showFirstLast
|
|
153
|
+
pageSizeOptions={[10, 25, 50, 100]}
|
|
154
|
+
labels={{ previous: 'Prev', next: 'Next', page: 'Hal' }}
|
|
155
|
+
classNames={{ info: 'text-xs', button: 'rounded-full' }}
|
|
156
|
+
/>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Use the `render` prop to take over rendering entirely while keeping the navigation handlers wired up.
|
|
160
|
+
|
|
161
|
+
### `<DataTableFilter />`
|
|
162
|
+
|
|
163
|
+
Per-column filter. Four built-in modes:
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
{/* Single select */}
|
|
167
|
+
<DataTableFilter
|
|
168
|
+
table={table}
|
|
169
|
+
columnId="status"
|
|
170
|
+
options={[
|
|
171
|
+
{ label: 'Active', value: 'active' },
|
|
172
|
+
{ label: 'Inactive', value: 'inactive' },
|
|
173
|
+
]}
|
|
174
|
+
placeholder="All statuses"
|
|
175
|
+
/>
|
|
176
|
+
|
|
177
|
+
{/* Multi-select (sends ?filter[status][]=… arrays) */}
|
|
178
|
+
<DataTableFilter
|
|
179
|
+
table={table}
|
|
180
|
+
columnId="role"
|
|
181
|
+
type="multiselect"
|
|
182
|
+
options={[
|
|
183
|
+
{ label: 'Admin', value: 'admin' },
|
|
184
|
+
{ label: 'Editor', value: 'editor' },
|
|
185
|
+
]}
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
{/* Text input */}
|
|
189
|
+
<DataTableFilter
|
|
190
|
+
table={table}
|
|
191
|
+
columnId="name"
|
|
192
|
+
type="input"
|
|
193
|
+
placeholder="Filter name"
|
|
194
|
+
/>
|
|
195
|
+
|
|
196
|
+
{/* Fully custom — popover, combobox, date picker, anything */}
|
|
197
|
+
<DataTableFilter
|
|
198
|
+
table={table}
|
|
199
|
+
columnId="status"
|
|
200
|
+
render={({ value, setValue }) => (
|
|
201
|
+
<MyFancyFilter value={value} onChange={setValue} />
|
|
202
|
+
)}
|
|
203
|
+
/>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `<DataTableSplitLayout />`
|
|
207
|
+
|
|
208
|
+
Predefined "split toolbar" layout that composes `DataTableSearch`, `DataTableFilter`s, `DataTable`, and `DataTablePagination` for you — search left, filters/actions right, table in the middle, pagination info left + controls right.
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
import {
|
|
212
|
+
Button,
|
|
213
|
+
DataTableFilter,
|
|
214
|
+
DataTableSplitLayout,
|
|
215
|
+
useDataTable,
|
|
216
|
+
} from '@manusiakemos/laravel-tanstack-react'
|
|
217
|
+
|
|
218
|
+
const { table, loading, meta } = useDataTable<User>({ /* ... */ })
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<DataTableSplitLayout
|
|
222
|
+
table={table}
|
|
223
|
+
meta={meta}
|
|
224
|
+
loading={loading}
|
|
225
|
+
searchProps={{ placeholder: 'Search users...' }}
|
|
226
|
+
filters={
|
|
227
|
+
<>
|
|
228
|
+
<DataTableFilter table={table} columnId="status" options={statusOpts} />
|
|
229
|
+
<DataTableFilter table={table} columnId="role" type="multiselect" options={roleOpts} />
|
|
230
|
+
</>
|
|
231
|
+
}
|
|
232
|
+
actions={<Button>+ Add user</Button>}
|
|
233
|
+
paginationProps={{ showPageSize: true, showFirstLast: true }}
|
|
234
|
+
tableProps={{ emptyMessage: 'No users found.' }}
|
|
235
|
+
/>
|
|
236
|
+
)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
| Prop | Type | Description |
|
|
240
|
+
|---|---|---|
|
|
241
|
+
| `table` | `Table<TData>` | Required. From `useDataTable`. |
|
|
242
|
+
| `meta` | `DataTableMeta \| null` | For the row-count summary. |
|
|
243
|
+
| `loading` | `boolean` | Forwarded to `<DataTable />`. |
|
|
244
|
+
| `search` | `ReactNode` | Override the entire search slot. |
|
|
245
|
+
| `searchProps` | `Partial<DataTableSearchProps>` | Forwarded to the auto-rendered search. |
|
|
246
|
+
| `filters` | `ReactNode` | Right-toolbar slot (typically one or more `<DataTableFilter />`s). |
|
|
247
|
+
| `actions` | `ReactNode` | Far-right slot for page-level actions (Add button, export, …). |
|
|
248
|
+
| `tableProps` | `Partial<DataTableProps>` | Forwarded to `<DataTable />`. |
|
|
249
|
+
| `paginationProps` | `Partial<DataTablePaginationProps>` | Forwarded to `<DataTablePagination />`. |
|
|
250
|
+
| `className` | `string` | Root wrapper class. |
|
|
251
|
+
| `classNames` | `{ root, toolbar, toolbarLeft, toolbarRight, body, footer }` | Fine-grained class names. |
|
|
252
|
+
|
|
253
|
+
### Shadcn primitives
|
|
254
|
+
|
|
255
|
+
The bundled primitives are re-exported so you can compose your own UI without pulling in a separate copy:
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import {
|
|
259
|
+
Button, Input, Select,
|
|
260
|
+
Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
|
|
261
|
+
cn,
|
|
262
|
+
} from '@manusiakemos/laravel-tanstack-react'
|
|
263
|
+
```
|
|
79
264
|
|
|
80
265
|
## API
|
|
81
266
|
|
|
@@ -178,7 +363,7 @@ export default function Index() {
|
|
|
178
363
|
const { table } = useDataTable<User>({
|
|
179
364
|
endpoint: '/datatable/users',
|
|
180
365
|
columns: [
|
|
181
|
-
{ accessorKey: 'name', header: '
|
|
366
|
+
{ accessorKey: 'name', header: 'Name' },
|
|
182
367
|
{
|
|
183
368
|
accessorKey: 'status',
|
|
184
369
|
header: 'Status',
|
|
@@ -242,6 +427,72 @@ See the [backend package docs](https://github.com/manusiakemos/laravel-tanstack)
|
|
|
242
427
|
- [ ] Optimistic row updates
|
|
243
428
|
- [ ] Built-in CSV export trigger
|
|
244
429
|
|
|
430
|
+
## Contributing
|
|
431
|
+
|
|
432
|
+
Contributions are welcome — bug fixes, new features, docs, and tests.
|
|
433
|
+
|
|
434
|
+
### Language policy
|
|
435
|
+
|
|
436
|
+
**All contributions must be in English.** This applies to:
|
|
437
|
+
|
|
438
|
+
- Source code: identifiers (variables, functions, types, files), string literals, JSX text, UI copy, placeholders, error messages, and log output.
|
|
439
|
+
- Comments and JSDoc.
|
|
440
|
+
- Documentation: README, examples, code samples, and any other Markdown.
|
|
441
|
+
- Commit messages, PR titles, and PR descriptions.
|
|
442
|
+
- Issue reports and discussion replies.
|
|
443
|
+
|
|
444
|
+
This keeps the package usable by the broadest possible audience and consistent for future maintainers. If you need locale-specific copy in your own app, override it on the consumer side (e.g. translate column headers in your call to `useDataTable`); do not localize the package itself.
|
|
445
|
+
|
|
446
|
+
### Getting set up
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
git clone https://github.com/manusiakemos/laravel-tanstack-react.git
|
|
450
|
+
cd laravel-tanstack-react
|
|
451
|
+
npm install
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Node 18+ is required.
|
|
455
|
+
|
|
456
|
+
### Workflow
|
|
457
|
+
|
|
458
|
+
1. Fork the repo and create a topic branch off `main`:
|
|
459
|
+
```bash
|
|
460
|
+
git checkout -b fix/short-description
|
|
461
|
+
```
|
|
462
|
+
2. Make your change. Keep the public API surface small and the diff focused.
|
|
463
|
+
3. Add or update tests for any behavior change. The suite lives under `tests/` and runs against `happy-dom`.
|
|
464
|
+
4. Run the full check locally before opening a PR:
|
|
465
|
+
```bash
|
|
466
|
+
npm run lint
|
|
467
|
+
npm run format
|
|
468
|
+
npm run typecheck
|
|
469
|
+
npm run test
|
|
470
|
+
npm run build
|
|
471
|
+
```
|
|
472
|
+
5. Update `CHANGELOG.md` under `## [Unreleased]` describing the change (Added / Changed / Fixed / Removed).
|
|
473
|
+
6. Open a pull request against `main`. Include:
|
|
474
|
+
- what changed and why
|
|
475
|
+
- any breaking-change notes (call them out explicitly)
|
|
476
|
+
- a code sample if you added a new option or hook
|
|
477
|
+
|
|
478
|
+
### Commit style
|
|
479
|
+
|
|
480
|
+
Short, imperative, present tense. Prefix with a conventional scope when useful:
|
|
481
|
+
|
|
482
|
+
```
|
|
483
|
+
feat: add `extraHeaders` option to default fetcher
|
|
484
|
+
fix: cancel in-flight request when endpoint changes
|
|
485
|
+
docs: clarify Sanctum CSRF requirement
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### Reporting bugs
|
|
489
|
+
|
|
490
|
+
Open an issue at [github.com/manusiakemos/laravel-tanstack-react/issues](https://github.com/manusiakemos/laravel-tanstack-react/issues) with:
|
|
491
|
+
|
|
492
|
+
- a minimal reproduction (CodeSandbox or repo)
|
|
493
|
+
- the version of this package, `@tanstack/react-table`, and React you're on
|
|
494
|
+
- the actual vs. expected behavior
|
|
495
|
+
|
|
245
496
|
## License
|
|
246
497
|
|
|
247
498
|
MIT.
|