@smicolon/ai-kit 0.0.1 → 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.
Files changed (163) hide show
  1. package/.claude-plugin/CLAUDE.md +7 -0
  2. package/.claude-plugin/marketplace.json +373 -0
  3. package/README.md +132 -0
  4. package/package.json +13 -3
  5. package/packs/architect/CHANGELOG.md +17 -0
  6. package/packs/architect/README.md +58 -0
  7. package/packs/architect/agents/system-architect.md +768 -0
  8. package/packs/architect/commands/diagram-create.md +300 -0
  9. package/packs/better-auth/.claude-plugin/plugin.json +14 -0
  10. package/packs/better-auth/.mcp.json +14 -0
  11. package/packs/better-auth/CHANGELOG.md +26 -0
  12. package/packs/better-auth/README.md +125 -0
  13. package/packs/better-auth/agents/auth-architect.md +278 -0
  14. package/packs/better-auth/commands/auth-provider-add.md +265 -0
  15. package/packs/better-auth/commands/auth-setup.md +298 -0
  16. package/packs/better-auth/skills/auth-security/SKILL.md +425 -0
  17. package/packs/better-auth/skills/better-auth-patterns/SKILL.md +455 -0
  18. package/packs/dev-loop/.claude-plugin/plugin.json +10 -0
  19. package/packs/dev-loop/CHANGELOG.md +69 -0
  20. package/packs/dev-loop/README.md +155 -0
  21. package/packs/dev-loop/commands/cancel-dev.md +21 -0
  22. package/packs/dev-loop/commands/dev-loop.md +72 -0
  23. package/packs/dev-loop/commands/dev-plan.md +351 -0
  24. package/packs/dev-loop/hooks/hooks.json +15 -0
  25. package/packs/dev-loop/hooks/stop-hook.sh +178 -0
  26. package/packs/dev-loop/scripts/setup-dev-loop.sh +194 -0
  27. package/packs/dev-loop/skills/tdd-planner/SKILL.md +249 -0
  28. package/packs/dev-loop/skills/tdd-planner/references/framework-patterns.md +874 -0
  29. package/packs/dev-loop/skills/tdd-planner/references/good-example.md +260 -0
  30. package/packs/dev-loop/skills/tdd-planner/references/plan-template.md +275 -0
  31. package/packs/django/CHANGELOG.md +39 -0
  32. package/packs/django/README.md +92 -0
  33. package/packs/django/agents/django-architect.md +182 -0
  34. package/packs/django/agents/django-builder.md +250 -0
  35. package/packs/django/agents/django-feature-based.md +420 -0
  36. package/packs/django/agents/django-reviewer.md +253 -0
  37. package/packs/django/agents/django-tester.md +230 -0
  38. package/packs/django/commands/api-endpoint.md +285 -0
  39. package/packs/django/commands/model-create.md +178 -0
  40. package/packs/django/commands/test-generate.md +325 -0
  41. package/packs/django/rules/migrations.md +138 -0
  42. package/packs/django/rules/models.md +167 -0
  43. package/packs/django/rules/serializers.md +126 -0
  44. package/packs/django/rules/services.md +131 -0
  45. package/packs/django/rules/tests.md +140 -0
  46. package/packs/django/rules/views.md +102 -0
  47. package/packs/django/skills/import-convention-enforcer/SKILL.md +226 -0
  48. package/packs/django/skills/import-convention-enforcer/patterns/django-imports.md +343 -0
  49. package/packs/django/skills/migration-safety-checker/SKILL.md +375 -0
  50. package/packs/django/skills/model-entity-validator/SKILL.md +298 -0
  51. package/packs/django/skills/performance-optimizer/SKILL.md +447 -0
  52. package/packs/django/skills/red-phase-verifier/SKILL.md +180 -0
  53. package/packs/django/skills/security-first-validator/SKILL.md +435 -0
  54. package/packs/django/skills/test-coverage-advisor/SKILL.md +394 -0
  55. package/packs/django/skills/test-validity-checker/SKILL.md +194 -0
  56. package/packs/failure-log/.claude-plugin/plugin.json +14 -0
  57. package/packs/failure-log/CHANGELOG.md +20 -0
  58. package/packs/failure-log/README.md +168 -0
  59. package/packs/failure-log/commands/failure-add.md +106 -0
  60. package/packs/failure-log/commands/failure-list.md +89 -0
  61. package/packs/failure-log/hooks/hooks.json +16 -0
  62. package/packs/failure-log/hooks/scripts/inject-failures.sh +64 -0
  63. package/packs/failure-log/skills/failure-log-manager/SKILL.md +164 -0
  64. package/packs/flutter/.claude-plugin/plugin.json +10 -0
  65. package/packs/flutter/CHANGELOG.md +19 -0
  66. package/packs/flutter/README.md +170 -0
  67. package/packs/flutter/agents/flutter-architect.md +166 -0
  68. package/packs/flutter/agents/flutter-builder.md +303 -0
  69. package/packs/flutter/agents/release-manager.md +355 -0
  70. package/packs/flutter/commands/fastlane-setup.md +188 -0
  71. package/packs/flutter/commands/flutter-build.md +90 -0
  72. package/packs/flutter/commands/flutter-deploy.md +133 -0
  73. package/packs/flutter/commands/flutter-test.md +117 -0
  74. package/packs/flutter/commands/signing-setup.md +209 -0
  75. package/packs/flutter/hooks/hooks.json +17 -0
  76. package/packs/flutter/skills/fastlane-knowledge/SKILL.md +193 -0
  77. package/packs/flutter/skills/flutter-architecture/SKILL.md +127 -0
  78. package/packs/flutter/skills/store-publishing/SKILL.md +163 -0
  79. package/packs/hono/.claude-plugin/plugin.json +19 -0
  80. package/packs/hono/CHANGELOG.md +19 -0
  81. package/packs/hono/README.md +143 -0
  82. package/packs/hono/agents/hono-architect.md +240 -0
  83. package/packs/hono/agents/hono-builder.md +285 -0
  84. package/packs/hono/agents/hono-reviewer.md +279 -0
  85. package/packs/hono/agents/hono-tester.md +346 -0
  86. package/packs/hono/commands/middleware-create.md +223 -0
  87. package/packs/hono/commands/project-init.md +306 -0
  88. package/packs/hono/commands/route-create.md +153 -0
  89. package/packs/hono/commands/rpc-client.md +263 -0
  90. package/packs/hono/hooks/hooks.json +4 -0
  91. package/packs/hono/skills/cloudflare-bindings/SKILL.md +408 -0
  92. package/packs/hono/skills/hono-patterns/SKILL.md +309 -0
  93. package/packs/hono/skills/rpc-typesafe/SKILL.md +388 -0
  94. package/packs/hono/skills/zod-validation/SKILL.md +332 -0
  95. package/packs/nestjs/CHANGELOG.md +29 -0
  96. package/packs/nestjs/README.md +75 -0
  97. package/packs/nestjs/agents/nestjs-architect.md +402 -0
  98. package/packs/nestjs/agents/nestjs-builder.md +301 -0
  99. package/packs/nestjs/agents/nestjs-tester.md +437 -0
  100. package/packs/nestjs/commands/module-create.md +369 -0
  101. package/packs/nestjs/rules/controllers.md +92 -0
  102. package/packs/nestjs/rules/dto.md +124 -0
  103. package/packs/nestjs/rules/entities.md +102 -0
  104. package/packs/nestjs/rules/services.md +106 -0
  105. package/packs/nestjs/skills/barrel-export-manager/SKILL.md +389 -0
  106. package/packs/nestjs/skills/import-convention-enforcer/SKILL.md +365 -0
  107. package/packs/nextjs/CHANGELOG.md +36 -0
  108. package/packs/nextjs/README.md +76 -0
  109. package/packs/nextjs/agents/frontend-tester.md +680 -0
  110. package/packs/nextjs/agents/frontend-visual.md +820 -0
  111. package/packs/nextjs/agents/nextjs-architect.md +331 -0
  112. package/packs/nextjs/agents/nextjs-modular.md +433 -0
  113. package/packs/nextjs/commands/component-create.md +398 -0
  114. package/packs/nextjs/rules/api-routes.md +129 -0
  115. package/packs/nextjs/rules/components.md +106 -0
  116. package/packs/nextjs/rules/hooks.md +132 -0
  117. package/packs/nextjs/skills/accessibility-validator/SKILL.md +445 -0
  118. package/packs/nextjs/skills/import-convention-enforcer/SKILL.md +399 -0
  119. package/packs/nextjs/skills/react-form-validator/SKILL.md +569 -0
  120. package/packs/nuxtjs/CHANGELOG.md +30 -0
  121. package/packs/nuxtjs/README.md +56 -0
  122. package/packs/nuxtjs/agents/frontend-tester.md +680 -0
  123. package/packs/nuxtjs/agents/frontend-visual.md +820 -0
  124. package/packs/nuxtjs/agents/nuxtjs-architect.md +537 -0
  125. package/packs/nuxtjs/commands/component-create.md +223 -0
  126. package/packs/nuxtjs/rules/components.md +101 -0
  127. package/packs/nuxtjs/rules/composables.md +118 -0
  128. package/packs/nuxtjs/rules/server-routes.md +127 -0
  129. package/packs/nuxtjs/skills/accessibility-validator/SKILL.md +183 -0
  130. package/packs/nuxtjs/skills/import-convention-enforcer/SKILL.md +196 -0
  131. package/packs/nuxtjs/skills/veevalidate-form-validator/SKILL.md +190 -0
  132. package/packs/onboard/CHANGELOG.md +22 -0
  133. package/packs/onboard/README.md +103 -0
  134. package/packs/onboard/agents/onboard-guide.md +118 -0
  135. package/packs/onboard/commands/onboard.md +313 -0
  136. package/packs/onboard/skills/onboard-context-provider/SKILL.md +98 -0
  137. package/packs/tanstack-router/.claude-plugin/plugin.json +14 -0
  138. package/packs/tanstack-router/CHANGELOG.md +30 -0
  139. package/packs/tanstack-router/README.md +113 -0
  140. package/packs/tanstack-router/agents/tanstack-architect.md +173 -0
  141. package/packs/tanstack-router/agents/tanstack-builder.md +360 -0
  142. package/packs/tanstack-router/agents/tanstack-tester.md +454 -0
  143. package/packs/tanstack-router/commands/form-create.md +313 -0
  144. package/packs/tanstack-router/commands/query-create.md +263 -0
  145. package/packs/tanstack-router/commands/route-create.md +190 -0
  146. package/packs/tanstack-router/commands/table-create.md +413 -0
  147. package/packs/tanstack-router/skills/ai-patterns/SKILL.md +370 -0
  148. package/packs/tanstack-router/skills/db-patterns/SKILL.md +346 -0
  149. package/packs/tanstack-router/skills/devtools-patterns/SKILL.md +415 -0
  150. package/packs/tanstack-router/skills/form-patterns/SKILL.md +425 -0
  151. package/packs/tanstack-router/skills/pacer-patterns/SKILL.md +341 -0
  152. package/packs/tanstack-router/skills/query-patterns/SKILL.md +359 -0
  153. package/packs/tanstack-router/skills/router-patterns/SKILL.md +285 -0
  154. package/packs/tanstack-router/skills/store-patterns/SKILL.md +351 -0
  155. package/packs/tanstack-router/skills/table-patterns/SKILL.md +531 -0
  156. package/packs/tanstack-router/skills/tanstack-conventions/SKILL.md +428 -0
  157. package/packs/tanstack-router/skills/virtual-patterns/SKILL.md +490 -0
  158. package/packs/worktree/.claude-plugin/plugin.json +19 -0
  159. package/packs/worktree/CHANGELOG.md +24 -0
  160. package/packs/worktree/README.md +110 -0
  161. package/packs/worktree/commands/wt.md +73 -0
  162. package/packs/worktree/scripts/wt.sh +396 -0
  163. package/packs/worktree/skills/worktree-manager/SKILL.md +68 -0
@@ -0,0 +1,531 @@
1
+ ---
2
+ name: TanStack Table Patterns
3
+ description: >-
4
+ Auto-enforce TanStack Table best practices for headless data tables. Activates
5
+ when creating tables, implementing sorting, filtering, pagination, or building
6
+ data grids in React applications.
7
+ version: 1.0.0
8
+ ---
9
+
10
+ # TanStack Table Patterns
11
+
12
+ This skill enforces TanStack Table best practices for headless, type-safe data tables.
13
+
14
+ ## Basic Table Setup
15
+
16
+ ```typescript
17
+ import {
18
+ createColumnHelper,
19
+ useReactTable,
20
+ getCoreRowModel,
21
+ flexRender,
22
+ } from '@tanstack/react-table'
23
+ import type { Post } from '@/features/posts/types'
24
+
25
+ const columnHelper = createColumnHelper<Post>()
26
+
27
+ const columns = [
28
+ columnHelper.accessor('title', {
29
+ header: 'Title',
30
+ cell: (info) => info.getValue(),
31
+ }),
32
+ columnHelper.accessor('author.name', {
33
+ header: 'Author',
34
+ cell: (info) => info.getValue(),
35
+ }),
36
+ columnHelper.accessor('createdAt', {
37
+ header: 'Created',
38
+ cell: (info) => new Date(info.getValue()).toLocaleDateString(),
39
+ }),
40
+ columnHelper.display({
41
+ id: 'actions',
42
+ header: 'Actions',
43
+ cell: ({ row }) => <PostActions post={row.original} />,
44
+ }),
45
+ ]
46
+
47
+ export function PostsTable({ data }: { data: Post[] }) {
48
+ const table = useReactTable({
49
+ data,
50
+ columns,
51
+ getCoreRowModel: getCoreRowModel(),
52
+ })
53
+
54
+ return (
55
+ <table>
56
+ <thead>
57
+ {table.getHeaderGroups().map((headerGroup) => (
58
+ <tr key={headerGroup.id}>
59
+ {headerGroup.headers.map((header) => (
60
+ <th key={header.id}>
61
+ {header.isPlaceholder
62
+ ? null
63
+ : flexRender(header.column.columnDef.header, header.getContext())}
64
+ </th>
65
+ ))}
66
+ </tr>
67
+ ))}
68
+ </thead>
69
+ <tbody>
70
+ {table.getRowModel().rows.map((row) => (
71
+ <tr key={row.id}>
72
+ {row.getVisibleCells().map((cell) => (
73
+ <td key={cell.id}>
74
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
75
+ </td>
76
+ ))}
77
+ </tr>
78
+ ))}
79
+ </tbody>
80
+ </table>
81
+ )
82
+ }
83
+ ```
84
+
85
+ ## Sorting
86
+
87
+ ```typescript
88
+ import {
89
+ useReactTable,
90
+ getCoreRowModel,
91
+ getSortedRowModel,
92
+ type SortingState,
93
+ } from '@tanstack/react-table'
94
+ import { useState } from 'react'
95
+
96
+ export function SortableTable({ data }: { data: Post[] }) {
97
+ const [sorting, setSorting] = useState<SortingState>([])
98
+
99
+ const columns = [
100
+ columnHelper.accessor('title', {
101
+ header: ({ column }) => (
102
+ <button
103
+ onClick={() => column.toggleSorting()}
104
+ className="flex items-center gap-1"
105
+ >
106
+ Title
107
+ {column.getIsSorted() === 'asc' ? ' ↑' : column.getIsSorted() === 'desc' ? ' ↓' : ''}
108
+ </button>
109
+ ),
110
+ cell: (info) => info.getValue(),
111
+ }),
112
+ // More columns...
113
+ ]
114
+
115
+ const table = useReactTable({
116
+ data,
117
+ columns,
118
+ state: { sorting },
119
+ onSortingChange: setSorting,
120
+ getCoreRowModel: getCoreRowModel(),
121
+ getSortedRowModel: getSortedRowModel(),
122
+ })
123
+
124
+ return (/* table JSX */)
125
+ }
126
+ ```
127
+
128
+ ## Filtering
129
+
130
+ ### Global Filter
131
+ ```typescript
132
+ import {
133
+ useReactTable,
134
+ getCoreRowModel,
135
+ getFilteredRowModel,
136
+ type ColumnFiltersState,
137
+ } from '@tanstack/react-table'
138
+
139
+ export function FilterableTable({ data }: { data: Post[] }) {
140
+ const [globalFilter, setGlobalFilter] = useState('')
141
+
142
+ const table = useReactTable({
143
+ data,
144
+ columns,
145
+ state: { globalFilter },
146
+ onGlobalFilterChange: setGlobalFilter,
147
+ getCoreRowModel: getCoreRowModel(),
148
+ getFilteredRowModel: getFilteredRowModel(),
149
+ })
150
+
151
+ return (
152
+ <div>
153
+ <input
154
+ type="search"
155
+ placeholder="Search all columns..."
156
+ value={globalFilter}
157
+ onChange={(e) => setGlobalFilter(e.target.value)}
158
+ />
159
+ {/* table JSX */}
160
+ </div>
161
+ )
162
+ }
163
+ ```
164
+
165
+ ### Column Filters
166
+ ```typescript
167
+ import { useState } from 'react'
168
+ import type { ColumnFiltersState } from '@tanstack/react-table'
169
+
170
+ export function ColumnFilterTable({ data }: { data: Post[] }) {
171
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
172
+
173
+ const columns = [
174
+ columnHelper.accessor('status', {
175
+ header: 'Status',
176
+ cell: (info) => info.getValue(),
177
+ filterFn: 'equals',
178
+ }),
179
+ // More columns...
180
+ ]
181
+
182
+ const table = useReactTable({
183
+ data,
184
+ columns,
185
+ state: { columnFilters },
186
+ onColumnFiltersChange: setColumnFilters,
187
+ getCoreRowModel: getCoreRowModel(),
188
+ getFilteredRowModel: getFilteredRowModel(),
189
+ })
190
+
191
+ return (
192
+ <div>
193
+ <select
194
+ onChange={(e) =>
195
+ table.getColumn('status')?.setFilterValue(e.target.value || undefined)
196
+ }
197
+ >
198
+ <option value="">All statuses</option>
199
+ <option value="draft">Draft</option>
200
+ <option value="published">Published</option>
201
+ </select>
202
+ {/* table JSX */}
203
+ </div>
204
+ )
205
+ }
206
+ ```
207
+
208
+ ## Pagination
209
+
210
+ ### Client-Side Pagination
211
+ ```typescript
212
+ import {
213
+ useReactTable,
214
+ getCoreRowModel,
215
+ getPaginationRowModel,
216
+ } from '@tanstack/react-table'
217
+
218
+ export function PaginatedTable({ data }: { data: Post[] }) {
219
+ const table = useReactTable({
220
+ data,
221
+ columns,
222
+ getCoreRowModel: getCoreRowModel(),
223
+ getPaginationRowModel: getPaginationRowModel(),
224
+ initialState: {
225
+ pagination: { pageSize: 10 },
226
+ },
227
+ })
228
+
229
+ return (
230
+ <div>
231
+ {/* table JSX */}
232
+ <div className="pagination">
233
+ <button
234
+ onClick={() => table.previousPage()}
235
+ disabled={!table.getCanPreviousPage()}
236
+ >
237
+ Previous
238
+ </button>
239
+ <span>
240
+ Page {table.getState().pagination.pageIndex + 1} of{' '}
241
+ {table.getPageCount()}
242
+ </span>
243
+ <button
244
+ onClick={() => table.nextPage()}
245
+ disabled={!table.getCanNextPage()}
246
+ >
247
+ Next
248
+ </button>
249
+ <select
250
+ value={table.getState().pagination.pageSize}
251
+ onChange={(e) => table.setPageSize(Number(e.target.value))}
252
+ >
253
+ {[10, 20, 50].map((size) => (
254
+ <option key={size} value={size}>
255
+ Show {size}
256
+ </option>
257
+ ))}
258
+ </select>
259
+ </div>
260
+ </div>
261
+ )
262
+ }
263
+ ```
264
+
265
+ ### Server-Side Pagination
266
+ ```typescript
267
+ import { useQuery } from '@tanstack/react-query'
268
+ import { Route } from '@tanstack/react-router'
269
+
270
+ export function ServerPaginatedTable() {
271
+ const { page, pageSize } = Route.useSearch()
272
+ const navigate = Route.useNavigate()
273
+
274
+ const { data, isLoading } = useQuery({
275
+ queryKey: queryKeys.posts.list({ page, pageSize }),
276
+ queryFn: () => postApi.getPosts({ page, pageSize }),
277
+ })
278
+
279
+ const table = useReactTable({
280
+ data: data?.items ?? [],
281
+ columns,
282
+ pageCount: data?.pageCount ?? -1,
283
+ state: {
284
+ pagination: { pageIndex: page - 1, pageSize },
285
+ },
286
+ onPaginationChange: (updater) => {
287
+ const newState =
288
+ typeof updater === 'function'
289
+ ? updater({ pageIndex: page - 1, pageSize })
290
+ : updater
291
+ navigate({
292
+ search: (prev) => ({
293
+ ...prev,
294
+ page: newState.pageIndex + 1,
295
+ pageSize: newState.pageSize,
296
+ }),
297
+ })
298
+ },
299
+ getCoreRowModel: getCoreRowModel(),
300
+ manualPagination: true,
301
+ })
302
+
303
+ if (isLoading) return <Skeleton />
304
+
305
+ return (/* table with pagination controls */)
306
+ }
307
+ ```
308
+
309
+ ## Row Selection
310
+
311
+ ```typescript
312
+ import {
313
+ useReactTable,
314
+ getCoreRowModel,
315
+ type RowSelectionState,
316
+ } from '@tanstack/react-table'
317
+
318
+ export function SelectableTable({ data, onSelectionChange }: Props) {
319
+ const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
320
+
321
+ const columns = [
322
+ columnHelper.display({
323
+ id: 'select',
324
+ header: ({ table }) => (
325
+ <input
326
+ type="checkbox"
327
+ checked={table.getIsAllRowsSelected()}
328
+ onChange={table.getToggleAllRowsSelectedHandler()}
329
+ />
330
+ ),
331
+ cell: ({ row }) => (
332
+ <input
333
+ type="checkbox"
334
+ checked={row.getIsSelected()}
335
+ onChange={row.getToggleSelectedHandler()}
336
+ />
337
+ ),
338
+ }),
339
+ // Other columns...
340
+ ]
341
+
342
+ const table = useReactTable({
343
+ data,
344
+ columns,
345
+ state: { rowSelection },
346
+ onRowSelectionChange: setRowSelection,
347
+ getCoreRowModel: getCoreRowModel(),
348
+ enableRowSelection: true,
349
+ })
350
+
351
+ // Get selected rows
352
+ const selectedRows = table.getSelectedRowModel().rows.map((row) => row.original)
353
+
354
+ return (
355
+ <div>
356
+ <span>{selectedRows.length} selected</span>
357
+ {/* table JSX */}
358
+ </div>
359
+ )
360
+ }
361
+ ```
362
+
363
+ ## Column Visibility
364
+
365
+ ```typescript
366
+ import { useState } from 'react'
367
+ import type { VisibilityState } from '@tanstack/react-table'
368
+
369
+ export function ColumnVisibilityTable({ data }: { data: Post[] }) {
370
+ const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
371
+
372
+ const table = useReactTable({
373
+ data,
374
+ columns,
375
+ state: { columnVisibility },
376
+ onColumnVisibilityChange: setColumnVisibility,
377
+ getCoreRowModel: getCoreRowModel(),
378
+ })
379
+
380
+ return (
381
+ <div>
382
+ <div className="column-toggles">
383
+ {table.getAllLeafColumns().map((column) => (
384
+ <label key={column.id}>
385
+ <input
386
+ type="checkbox"
387
+ checked={column.getIsVisible()}
388
+ onChange={column.getToggleVisibilityHandler()}
389
+ />
390
+ {column.id}
391
+ </label>
392
+ ))}
393
+ </div>
394
+ {/* table JSX */}
395
+ </div>
396
+ )
397
+ }
398
+ ```
399
+
400
+ ## Complete Feature Table
401
+
402
+ ```typescript
403
+ import {
404
+ createColumnHelper,
405
+ useReactTable,
406
+ getCoreRowModel,
407
+ getSortedRowModel,
408
+ getFilteredRowModel,
409
+ getPaginationRowModel,
410
+ flexRender,
411
+ type SortingState,
412
+ type ColumnFiltersState,
413
+ } from '@tanstack/react-table'
414
+ import { useState } from 'react'
415
+
416
+ export function FullFeaturedTable<T>({
417
+ data,
418
+ columns,
419
+ }: {
420
+ data: T[]
421
+ columns: ColumnDef<T>[]
422
+ }) {
423
+ const [sorting, setSorting] = useState<SortingState>([])
424
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
425
+ const [globalFilter, setGlobalFilter] = useState('')
426
+
427
+ const table = useReactTable({
428
+ data,
429
+ columns,
430
+ state: {
431
+ sorting,
432
+ columnFilters,
433
+ globalFilter,
434
+ },
435
+ onSortingChange: setSorting,
436
+ onColumnFiltersChange: setColumnFilters,
437
+ onGlobalFilterChange: setGlobalFilter,
438
+ getCoreRowModel: getCoreRowModel(),
439
+ getSortedRowModel: getSortedRowModel(),
440
+ getFilteredRowModel: getFilteredRowModel(),
441
+ getPaginationRowModel: getPaginationRowModel(),
442
+ })
443
+
444
+ return (
445
+ <div className="table-container">
446
+ {/* Search */}
447
+ <input
448
+ type="search"
449
+ placeholder="Search..."
450
+ value={globalFilter}
451
+ onChange={(e) => setGlobalFilter(e.target.value)}
452
+ />
453
+
454
+ {/* Table */}
455
+ <table>
456
+ <thead>
457
+ {table.getHeaderGroups().map((headerGroup) => (
458
+ <tr key={headerGroup.id}>
459
+ {headerGroup.headers.map((header) => (
460
+ <th key={header.id}>
461
+ {flexRender(header.column.columnDef.header, header.getContext())}
462
+ </th>
463
+ ))}
464
+ </tr>
465
+ ))}
466
+ </thead>
467
+ <tbody>
468
+ {table.getRowModel().rows.map((row) => (
469
+ <tr key={row.id}>
470
+ {row.getVisibleCells().map((cell) => (
471
+ <td key={cell.id}>
472
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
473
+ </td>
474
+ ))}
475
+ </tr>
476
+ ))}
477
+ </tbody>
478
+ </table>
479
+
480
+ {/* Pagination */}
481
+ <div className="pagination">
482
+ <button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
483
+ Previous
484
+ </button>
485
+ <span>
486
+ Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
487
+ </span>
488
+ <button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
489
+ Next
490
+ </button>
491
+ </div>
492
+ </div>
493
+ )
494
+ }
495
+ ```
496
+
497
+ ## Conventions to Enforce
498
+
499
+ 1. **Column helper** - Use `createColumnHelper<T>()` for type safety
500
+ 2. **FlexRender** - Always use `flexRender()` for headers and cells
501
+ 3. **Stable columns** - Define columns outside component or memoize
502
+ 4. **Server pagination** - Use `manualPagination: true` with API
503
+ 5. **URL state** - Sync table state with router search params
504
+ 6. **Accessibility** - Include proper table semantics and roles
505
+
506
+ ## Anti-Patterns to Block
507
+
508
+ ```typescript
509
+ // ❌ WRONG: Columns inside component without memo
510
+ function Table() {
511
+ const columns = [/* columns recreated every render */]
512
+ }
513
+
514
+ // ✅ CORRECT: Columns outside or memoized
515
+ const columns = [/* stable reference */]
516
+ function Table() {
517
+ const table = useReactTable({ columns, ... })
518
+ }
519
+
520
+ // ❌ WRONG: Not using flexRender
521
+ <td>{cell.getValue()}</td>
522
+
523
+ // ✅ CORRECT: Use flexRender
524
+ <td>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
525
+
526
+ // ❌ WRONG: Hardcoded pagination
527
+ const [page, setPage] = useState(1)
528
+
529
+ // ✅ CORRECT: URL-synced pagination
530
+ const { page } = Route.useSearch()
531
+ ```