@tanstack/svelte-table 9.0.0-beta.2 → 9.0.0-beta.21
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/dist/createTable.svelte.d.ts +0 -1
- package/dist/createTable.svelte.js +1 -2
- package/dist/createTableHook.svelte.d.ts +6 -6
- package/dist/createTableHook.svelte.js +5 -5
- package/package.json +4 -4
- package/skills/svelte/client-to-server/SKILL.md +8 -10
- package/skills/svelte/compose-with-tanstack-form/SKILL.md +3 -4
- package/skills/svelte/compose-with-tanstack-pacer/SKILL.md +1 -1
- package/skills/svelte/compose-with-tanstack-query/SKILL.md +0 -3
- package/skills/svelte/compose-with-tanstack-store/SKILL.md +1 -8
- package/skills/svelte/compose-with-tanstack-virtual/SKILL.md +6 -3
- package/skills/svelte/getting-started/SKILL.md +22 -24
- package/skills/svelte/migrate-v8-to-v9/SKILL.md +33 -25
- package/skills/svelte/production-readiness/SKILL.md +7 -5
- package/skills/svelte/table-state/SKILL.md +11 -15
- package/src/createTable.svelte.ts +1 -2
- package/src/createTableHook.svelte.ts +6 -9
|
@@ -17,7 +17,6 @@ import { svelteReactivity } from './reactivity.svelte';
|
|
|
17
17
|
* const table = createTable(
|
|
18
18
|
* {
|
|
19
19
|
* features,
|
|
20
|
-
* rowModels: {},
|
|
21
20
|
* columns,
|
|
22
21
|
* data,
|
|
23
22
|
* },
|
|
@@ -32,7 +31,7 @@ export function createTable(tableOptions, selector) {
|
|
|
32
31
|
// 1. Merge reactivity into options using mergeObjects (preserves getters)
|
|
33
32
|
const mergedOptions = mergeObjects(tableOptions, {
|
|
34
33
|
features: {
|
|
35
|
-
|
|
34
|
+
coreReactivityFeature: svelteReactivity(),
|
|
36
35
|
...tableOptions.features,
|
|
37
36
|
},
|
|
38
37
|
});
|
|
@@ -213,12 +213,12 @@ export type AppSvelteTable<TFeatures extends TableFeatures, TData extends RowDat
|
|
|
213
213
|
* rowPaginationFeature,
|
|
214
214
|
* rowSortingFeature,
|
|
215
215
|
* columnFilteringFeature,
|
|
216
|
-
* }),
|
|
217
|
-
* rowModels: {
|
|
218
216
|
* paginatedRowModel: createPaginatedRowModel(),
|
|
219
|
-
* sortedRowModel: createSortedRowModel(
|
|
220
|
-
* filteredRowModel: createFilteredRowModel(
|
|
221
|
-
*
|
|
217
|
+
* sortedRowModel: createSortedRowModel(),
|
|
218
|
+
* filteredRowModel: createFilteredRowModel(),
|
|
219
|
+
* sortFns,
|
|
220
|
+
* filterFns,
|
|
221
|
+
* }),
|
|
222
222
|
* tableComponents: { PaginationControls, RowCount },
|
|
223
223
|
* cellComponents: { TextCell, NumberCell },
|
|
224
224
|
* headerComponents: { SortIndicator, ColumnFilter },
|
|
@@ -228,7 +228,7 @@ export type AppSvelteTable<TFeatures extends TableFeatures, TData extends RowDat
|
|
|
228
228
|
export declare function createTableHook<TFeatures extends TableFeatures, const TTableComponents extends Record<string, ComponentType<any>>, const TCellComponents extends Record<string, ComponentType<any>>, const THeaderComponents extends Record<string, ComponentType<any>>>({ tableComponents, cellComponents, headerComponents, ...defaultTableOptions }: CreateTableHookOptions<TFeatures, TTableComponents, TCellComponents, THeaderComponents>): {
|
|
229
229
|
appFeatures: TFeatures;
|
|
230
230
|
createAppColumnHelper: <TData extends RowData>() => AppColumnHelper<TFeatures, TData, TCellComponents, THeaderComponents>;
|
|
231
|
-
createAppTable: <TData extends RowData, TSelected = TableState<TFeatures>>(tableOptions: Omit<TableOptions<TFeatures, TData>, "features"
|
|
231
|
+
createAppTable: <TData extends RowData, TSelected = TableState<TFeatures>>(tableOptions: Omit<TableOptions<TFeatures, TData>, "features">, selector?: (state: TableState<TFeatures>) => TSelected) => AppSvelteTable<TFeatures, TData, TSelected, TTableComponents, TCellComponents, THeaderComponents>;
|
|
232
232
|
useTableContext: <TData extends RowData = RowData>() => SvelteTable<TFeatures, TData>;
|
|
233
233
|
useCellContext: <TValue extends CellData = unknown>() => Cell<TFeatures, any, TValue>;
|
|
234
234
|
useHeaderContext: <TValue extends CellData = unknown>() => Header<TFeatures, any, TValue>;
|
|
@@ -34,12 +34,12 @@ import FlexRenderSvelte from './FlexRender.svelte';
|
|
|
34
34
|
* rowPaginationFeature,
|
|
35
35
|
* rowSortingFeature,
|
|
36
36
|
* columnFilteringFeature,
|
|
37
|
-
* }),
|
|
38
|
-
* rowModels: {
|
|
39
37
|
* paginatedRowModel: createPaginatedRowModel(),
|
|
40
|
-
* sortedRowModel: createSortedRowModel(
|
|
41
|
-
* filteredRowModel: createFilteredRowModel(
|
|
42
|
-
*
|
|
38
|
+
* sortedRowModel: createSortedRowModel(),
|
|
39
|
+
* filteredRowModel: createFilteredRowModel(),
|
|
40
|
+
* sortFns,
|
|
41
|
+
* filterFns,
|
|
42
|
+
* }),
|
|
43
43
|
* tableComponents: { PaginationControls, RowCount },
|
|
44
44
|
* cellComponents: { TextCell, NumberCell },
|
|
45
45
|
* headerComponents: { SortIndicator, ColumnFilter },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/svelte-table",
|
|
3
|
-
"version": "9.0.0-beta.
|
|
3
|
+
"version": "9.0.0-beta.21",
|
|
4
4
|
"description": "Headless UI for building powerful tables & datagrids for Svelte.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@tanstack/svelte-store": "^0.12.0",
|
|
56
|
-
"@tanstack/table-core": "9.0.0-beta.
|
|
56
|
+
"@tanstack/table-core": "9.0.0-beta.21"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@sveltejs/package": "^2.5.8",
|
|
60
60
|
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
|
61
61
|
"eslint-plugin-svelte": "^3.19.0",
|
|
62
|
-
"svelte": "^5.56.
|
|
63
|
-
"svelte-check": "^4.
|
|
62
|
+
"svelte": "^5.56.2",
|
|
63
|
+
"svelte-check": "^4.6.0"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"svelte": "^5.0.0"
|
|
@@ -3,9 +3,9 @@ name: svelte/client-to-server
|
|
|
3
3
|
description: >
|
|
4
4
|
Convert a client-side Svelte table to server-side (manual) modes. Toggle `manualPagination`,
|
|
5
5
|
`manualSorting`, `manualFiltering`, `manualGrouping`, `manualExpanding` for whatever the server
|
|
6
|
-
owns, drop the matching `
|
|
7
|
-
`rowCount` for the pager, then drive the request from `table.atoms.pagination`
|
|
8
|
-
`table.atoms.sorting` / etc. (or external atoms you own)
|
|
6
|
+
owns, drop the matching row-model factory slots from `tableFeatures` and any `features` you no
|
|
7
|
+
longer need, supply `rowCount` for the pager, then drive the request from `table.atoms.pagination`
|
|
8
|
+
/ `table.atoms.sorting` / etc. (or external atoms you own) using rune-aware getters
|
|
9
9
|
(`get data()`, `get rowCount()`) so the table re-syncs in `$effect.pre`. Svelte 5+ only.
|
|
10
10
|
type: lifecycle
|
|
11
11
|
library: tanstack-table
|
|
@@ -44,8 +44,7 @@ already-paged window is perfectly valid for medium datasets.
|
|
|
44
44
|
| `manualGrouping` | Server returns already-grouped rows | Pre-shaped data |
|
|
45
45
|
| `manualExpanding` | Server resolves sub-rows | Server-provided sub-row tree |
|
|
46
46
|
|
|
47
|
-
When a stage is manual, you can drop its row-model factory
|
|
48
|
-
need `paginatedRowModel: createPaginatedRowModel()`.
|
|
47
|
+
When a stage is manual, you can drop its row-model factory slot from `tableFeatures`. `manualPagination: true` does not need `paginatedRowModel: createPaginatedRowModel()` in the features object.
|
|
49
48
|
|
|
50
49
|
## Step 1 — Identify what's moving server-side
|
|
51
50
|
|
|
@@ -111,7 +110,6 @@ const filters = useSelector(filtersAtom)
|
|
|
111
110
|
// No row-model factories for these — server owns them.
|
|
112
111
|
const table = createTable({
|
|
113
112
|
features,
|
|
114
|
-
rowModels: {},
|
|
115
113
|
columns,
|
|
116
114
|
get data() {
|
|
117
115
|
return query.data?.rows ?? []
|
|
@@ -196,11 +194,11 @@ const table = createTable({
|
|
|
196
194
|
columnFilteringFeature,
|
|
197
195
|
rowPaginationFeature,
|
|
198
196
|
rowSortingFeature,
|
|
197
|
+
filteredRowModel: createFilteredRowModel(), // client filters the page
|
|
198
|
+
sortedRowModel: createSortedRowModel(), // client sorts the page
|
|
199
|
+
filterFns,
|
|
200
|
+
sortFns,
|
|
199
201
|
}),
|
|
200
|
-
rowModels: {
|
|
201
|
-
filteredRowModel: createFilteredRowModel(filterFns), // client filters the page
|
|
202
|
-
sortedRowModel: createSortedRowModel(sortFns), // client sorts the page
|
|
203
|
-
},
|
|
204
202
|
columns,
|
|
205
203
|
get data() {
|
|
206
204
|
return query.data?.rows ?? []
|
|
@@ -116,6 +116,9 @@ Each cell type is a small Svelte component that knows which row + field it edits
|
|
|
116
116
|
const features = tableFeatures({
|
|
117
117
|
rowPaginationFeature,
|
|
118
118
|
columnFilteringFeature,
|
|
119
|
+
filteredRowModel: createFilteredRowModel(),
|
|
120
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
121
|
+
filterFns,
|
|
119
122
|
})
|
|
120
123
|
|
|
121
124
|
const columnHelper = createColumnHelper<typeof features, Person>()
|
|
@@ -170,10 +173,6 @@ Each cell type is a small Svelte component that knows which row + field it edits
|
|
|
170
173
|
|
|
171
174
|
const table = createTable({
|
|
172
175
|
features,
|
|
173
|
-
rowModels: {
|
|
174
|
-
filteredRowModel: createFilteredRowModel(filterFns),
|
|
175
|
-
paginatedRowModel: createPaginatedRowModel(),
|
|
176
|
-
},
|
|
177
176
|
columns,
|
|
178
177
|
get data() {
|
|
179
178
|
// The form is the source of truth.
|
|
@@ -95,7 +95,7 @@ Same shape, calling `table.setGlobalFilter`:
|
|
|
95
95
|
|
|
96
96
|
## Throttle column resizing
|
|
97
97
|
|
|
98
|
-
`columnResizingFeature` writes to `columnSizing` continuously. v9 supports `columnResizeMode:
|
|
98
|
+
`columnResizingFeature` (which requires `columnSizingFeature` to also be registered in `tableFeatures`) writes to `columnSizing` continuously. v9 supports `columnResizeMode:
|
|
99
99
|
'onChange' | 'onEnd'` — the default is `'onChange'` (commit per-frame). For very heavy tables,
|
|
100
100
|
either:
|
|
101
101
|
|
|
@@ -58,7 +58,6 @@ the affected pipeline stages, pipe the result back through reactive getters.
|
|
|
58
58
|
|
|
59
59
|
const table = createTable({
|
|
60
60
|
features,
|
|
61
|
-
rowModels: {},
|
|
62
61
|
columns,
|
|
63
62
|
get data() {
|
|
64
63
|
return dataQuery.data?.rows ?? []
|
|
@@ -115,7 +114,6 @@ const dataQuery = createQuery(() => ({
|
|
|
115
114
|
|
|
116
115
|
const table = createTable({
|
|
117
116
|
features,
|
|
118
|
-
rowModels: {},
|
|
119
117
|
columns,
|
|
120
118
|
get data() {
|
|
121
119
|
return dataQuery.data?.rows ?? []
|
|
@@ -152,7 +150,6 @@ const table = createTable({
|
|
|
152
150
|
rowSortingFeature,
|
|
153
151
|
columnFilteringFeature,
|
|
154
152
|
}),
|
|
155
|
-
rowModels: {},
|
|
156
153
|
columns,
|
|
157
154
|
get data() {
|
|
158
155
|
return dataQuery.data?.rows ?? []
|
|
@@ -46,7 +46,7 @@ If a slice is supplied externally via `atoms`, `table.atoms.<slice>` reads from
|
|
|
46
46
|
|
|
47
47
|
## The Svelte bindings (what `svelteReactivity()` actually does)
|
|
48
48
|
|
|
49
|
-
The Svelte adapter ships `svelteReactivity()` and installs it as `
|
|
49
|
+
The Svelte adapter ships `svelteReactivity()` and installs it as `coreReactivityFeature`. It
|
|
50
50
|
maps Store primitives to runes:
|
|
51
51
|
|
|
52
52
|
- Readonly atoms → `$derived.by(fn)`
|
|
@@ -83,7 +83,6 @@ The second argument to `createTable` is a TanStack Store selector. The result is
|
|
|
83
83
|
const table = createTable(
|
|
84
84
|
{
|
|
85
85
|
features,
|
|
86
|
-
rowModels: { paginatedRowModel: createPaginatedRowModel() },
|
|
87
86
|
columns,
|
|
88
87
|
get data() {
|
|
89
88
|
return data
|
|
@@ -161,9 +160,6 @@ const pagination = useSelector(paginationAtom)
|
|
|
161
160
|
|
|
162
161
|
const table = createTable({
|
|
163
162
|
features,
|
|
164
|
-
rowModels: {
|
|
165
|
-
/* ... */
|
|
166
|
-
},
|
|
167
163
|
columns,
|
|
168
164
|
get data() {
|
|
169
165
|
return data
|
|
@@ -215,9 +211,6 @@ export const rowSelectionAtom = createAtom<RowSelectionState>({})
|
|
|
215
211
|
|
|
216
212
|
const table = createTable({
|
|
217
213
|
features,
|
|
218
|
-
rowModels: {
|
|
219
|
-
/* ... */
|
|
220
|
-
},
|
|
221
214
|
columns,
|
|
222
215
|
get data() {
|
|
223
216
|
return data
|
|
@@ -59,13 +59,17 @@ pnpm add @tanstack/svelte-virtual
|
|
|
59
59
|
import { createVirtualizer } from '@tanstack/svelte-virtual'
|
|
60
60
|
import { get } from 'svelte/store'
|
|
61
61
|
|
|
62
|
-
const features = tableFeatures({
|
|
62
|
+
const features = tableFeatures({
|
|
63
|
+
columnSizingFeature,
|
|
64
|
+
rowSortingFeature,
|
|
65
|
+
sortedRowModel: createSortedRowModel(),
|
|
66
|
+
sortFns,
|
|
67
|
+
})
|
|
63
68
|
|
|
64
69
|
let data = $state<Person[]>(makeData(200_000))
|
|
65
70
|
|
|
66
71
|
const table = createTable({
|
|
67
72
|
features,
|
|
68
|
-
rowModels: { sortedRowModel: createSortedRowModel(sortFns) },
|
|
69
73
|
columns,
|
|
70
74
|
get data() {
|
|
71
75
|
return data
|
|
@@ -218,7 +222,6 @@ const flatData = $derived(
|
|
|
218
222
|
|
|
219
223
|
const table = createTable({
|
|
220
224
|
features: tableFeatures({}),
|
|
221
|
-
rowModels: {},
|
|
222
225
|
columns,
|
|
223
226
|
get data() {
|
|
224
227
|
return flatData
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: svelte/getting-started
|
|
3
3
|
description: >
|
|
4
4
|
End-to-end first-table journey for `@tanstack/svelte-table@9` on Svelte 5. Install the adapter,
|
|
5
|
-
declare `features` with `tableFeatures()
|
|
6
|
-
|
|
5
|
+
declare `features` with `tableFeatures()` (including row-model factories and `*Fns` registries as
|
|
6
|
+
feature slots), build a typed column helper with both `TFeatures` and `TData` generics, instantiate
|
|
7
7
|
the table with `createTable(options)` using `$state` data and `get data()` reactive option getters,
|
|
8
8
|
and render with `FlexRender`. Svelte 5+ only — Svelte 3/4 must use v8.
|
|
9
9
|
type: lifecycle
|
|
@@ -51,18 +51,17 @@ pnpm add @tanstack/svelte-store
|
|
|
51
51
|
You do **not** install `@tanstack/table-core` separately — the Svelte adapter re-exports
|
|
52
52
|
everything you need (column helpers, feature objects, row-model factories, types).
|
|
53
53
|
|
|
54
|
-
## 2. Define `features`
|
|
54
|
+
## 2. Define `features`
|
|
55
55
|
|
|
56
56
|
v9 is explicit. You opt in to every feature and every row model. The core row model is
|
|
57
57
|
included by default, so the minimum viable table is:
|
|
58
58
|
|
|
59
59
|
```ts
|
|
60
60
|
const features = tableFeatures({})
|
|
61
|
-
const rowModels = {}
|
|
62
61
|
```
|
|
63
62
|
|
|
64
|
-
For anything beyond a flat table, register the features you'll use
|
|
65
|
-
row-model factories
|
|
63
|
+
For anything beyond a flat table, register the features you'll use along with the matching
|
|
64
|
+
row-model factories and `*Fns` registries — all as slots inside `tableFeatures`:
|
|
66
65
|
|
|
67
66
|
```ts
|
|
68
67
|
import {
|
|
@@ -81,13 +80,12 @@ const features = tableFeatures({
|
|
|
81
80
|
rowPaginationFeature,
|
|
82
81
|
rowSortingFeature,
|
|
83
82
|
columnFilteringFeature,
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
const rowModels = {
|
|
87
83
|
paginatedRowModel: createPaginatedRowModel(),
|
|
88
|
-
sortedRowModel: createSortedRowModel(
|
|
89
|
-
filteredRowModel: createFilteredRowModel(
|
|
90
|
-
|
|
84
|
+
sortedRowModel: createSortedRowModel(),
|
|
85
|
+
filteredRowModel: createFilteredRowModel(),
|
|
86
|
+
sortFns,
|
|
87
|
+
filterFns,
|
|
88
|
+
})
|
|
91
89
|
```
|
|
92
90
|
|
|
93
91
|
**Skipping a feature** in `features` means its state slice does not exist on `table.atoms`,
|
|
@@ -166,7 +164,6 @@ option (`columns`, `rowCount`, `state.*`).
|
|
|
166
164
|
|
|
167
165
|
const table = createTable({
|
|
168
166
|
features,
|
|
169
|
-
rowModels: {},
|
|
170
167
|
columns,
|
|
171
168
|
get data() {
|
|
172
169
|
return data
|
|
@@ -230,13 +227,13 @@ focus, scroll, and any per-row component state.
|
|
|
230
227
|
tableFeatures,
|
|
231
228
|
} from '@tanstack/svelte-table'
|
|
232
229
|
|
|
233
|
-
const features = tableFeatures({
|
|
230
|
+
const features = tableFeatures({
|
|
231
|
+
rowPaginationFeature,
|
|
232
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
233
|
+
})
|
|
234
234
|
|
|
235
235
|
const table = createTable({
|
|
236
236
|
features,
|
|
237
|
-
rowModels: {
|
|
238
|
-
paginatedRowModel: createPaginatedRowModel(),
|
|
239
|
-
},
|
|
240
237
|
columns,
|
|
241
238
|
get data() {
|
|
242
239
|
return data
|
|
@@ -273,8 +270,7 @@ const pagination = subscribeTable(table.atoms.pagination)
|
|
|
273
270
|
|
|
274
271
|
## 7. `createTableHook` (when you have more than one table)
|
|
275
272
|
|
|
276
|
-
For apps with multiple tables, define
|
|
277
|
-
once:
|
|
273
|
+
For apps with multiple tables, define `features` (including row-model factories) and shared components once:
|
|
278
274
|
|
|
279
275
|
```ts
|
|
280
276
|
// hooks/table.ts
|
|
@@ -289,11 +285,13 @@ import {
|
|
|
289
285
|
} from '@tanstack/svelte-table'
|
|
290
286
|
|
|
291
287
|
export const { createAppTable, createAppColumnHelper } = createTableHook({
|
|
292
|
-
features: tableFeatures({
|
|
293
|
-
|
|
288
|
+
features: tableFeatures({
|
|
289
|
+
rowPaginationFeature,
|
|
290
|
+
rowSortingFeature,
|
|
294
291
|
paginatedRowModel: createPaginatedRowModel(),
|
|
295
|
-
sortedRowModel: createSortedRowModel(
|
|
296
|
-
|
|
292
|
+
sortedRowModel: createSortedRowModel(),
|
|
293
|
+
sortFns,
|
|
294
|
+
}),
|
|
297
295
|
})
|
|
298
296
|
```
|
|
299
297
|
|
|
@@ -319,7 +317,7 @@ export const { createAppTable, createAppColumnHelper } = createTableHook({
|
|
|
319
317
|
|
|
320
318
|
- **Svelte 3/4.** Adapter will not work. See top of file.
|
|
321
319
|
- **`createSvelteTable` / `useSvelteTable` / `getCoreRowModel`** — all v8 names. v9 uses
|
|
322
|
-
`createTable`
|
|
320
|
+
`createTable` with row-model factories registered as slots in `tableFeatures({ paginatedRowModel: createPaginatedRowModel(), ... })`.
|
|
323
321
|
- **Plain `data` instead of `get data()` getter.** Table will not see data updates. Always
|
|
324
322
|
pass a reactive getter for state that lives in `$state`.
|
|
325
323
|
- **Missing feature in `features`.** `table.setSorting` / `column.getCanSort` won't exist.
|
|
@@ -3,10 +3,11 @@ name: svelte/migrate-v8-to-v9
|
|
|
3
3
|
description: >
|
|
4
4
|
Mechanical migration from `@tanstack/svelte-table@8` to `@tanstack/svelte-table@9`. v9 in Svelte
|
|
5
5
|
is a full rewrite — Svelte 5 runes only (no Svelte 3/4), no `/legacy` adapter (unlike React),
|
|
6
|
-
`createSvelteTable` → `createTable`, `getCoreRowModel` / `getSortedRowModel` factories →
|
|
7
|
-
|
|
8
|
-
writable-store `state` → rune-based getters / external atoms,
|
|
9
|
-
`on[State]Change` or `atoms`. Plan a feature-by-feature audit, not a
|
|
6
|
+
`createSvelteTable` → `createTable`, `getCoreRowModel` / `getSortedRowModel` factories →
|
|
7
|
+
row-model factories registered as slots inside `tableFeatures({...})`, `flexRender` helper →
|
|
8
|
+
`<FlexRender>` component, writable-store `state` → rune-based getters / external atoms,
|
|
9
|
+
`onStateChange` → per-slice `on[State]Change` or `atoms`. Plan a feature-by-feature audit, not a
|
|
10
|
+
search-and-replace.
|
|
10
11
|
type: lifecycle
|
|
11
12
|
library: tanstack-table
|
|
12
13
|
framework: svelte
|
|
@@ -46,11 +47,11 @@ There is no third option. Trying to install v9 on a Svelte 4 codebase will error
|
|
|
46
47
|
| -------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
47
48
|
| `createSvelteTable(options)` | `createTable(options, selector?)` |
|
|
48
49
|
| `getCoreRowModel()` | included by default; no factory |
|
|
49
|
-
| `getPaginationRowModel()` | `
|
|
50
|
-
| `getSortedRowModel()` | `
|
|
51
|
-
| `getFilteredRowModel()` | `
|
|
52
|
-
| `getExpandedRowModel()` | `
|
|
53
|
-
| `getGroupedRowModel()` | `
|
|
50
|
+
| `getPaginationRowModel()` | `tableFeatures({ paginatedRowModel: createPaginatedRowModel() })` |
|
|
51
|
+
| `getSortedRowModel()` | `tableFeatures({ sortedRowModel: createSortedRowModel(), sortFns })` |
|
|
52
|
+
| `getFilteredRowModel()` | `tableFeatures({ filteredRowModel: createFilteredRowModel(), filterFns })` |
|
|
53
|
+
| `getExpandedRowModel()` | `tableFeatures({ expandedRowModel: createExpandedRowModel() })` |
|
|
54
|
+
| `getGroupedRowModel()` | `tableFeatures({ groupedRowModel: createGroupedRowModel(), aggregationFns })` |
|
|
54
55
|
| `getFacetedRowModel()` / `MinMax` / `UniqueValues` | facet APIs auto-derived when `*Facet*Feature` registered |
|
|
55
56
|
| `flexRender(template, ctx)` helper | `<FlexRender header={h} />` / `<FlexRender cell={c} />` / `<FlexRender footer={h} />` |
|
|
56
57
|
| `ColumnDef<TData>` | `ColumnDef<TFeatures, TData>` (extra generic) |
|
|
@@ -79,8 +80,7 @@ For each Svelte component that uses the table:
|
|
|
79
80
|
`import { createTable, FlexRender, tableFeatures, ... }`.
|
|
80
81
|
4. **Add `features`.** Create `const features = tableFeatures({ ... only the features this
|
|
81
82
|
table uses ... })`.
|
|
82
|
-
5. **Move row-model factories
|
|
83
|
-
entry with the matching `create*RowModel(*Fns)` factory.
|
|
83
|
+
5. **Move row-model factories into `tableFeatures`.** Every `get*RowModel: get*RowModel()` becomes a slot inside `tableFeatures({ ..., create*RowModel() })`. Any `*Fns` registry that was passed as a factory argument is now also a named slot in the same `tableFeatures` call.
|
|
84
84
|
6. **Generic columns.** Add `<typeof features, TData>` to `ColumnDef<>` and
|
|
85
85
|
`createColumnHelper<>()`. TypeScript will tell you when you missed one.
|
|
86
86
|
7. **`data` as a getter.** `data: data` → `get data() { return data }`. Same for any other
|
|
@@ -99,7 +99,7 @@ table uses ... })`.
|
|
|
99
99
|
<script lang="ts">
|
|
100
100
|
// v8
|
|
101
101
|
import { writable } from 'svelte/store'
|
|
102
|
-
const options = writable({
|
|
102
|
+
const options = writable({ data, columns })
|
|
103
103
|
$: $options.state = $state
|
|
104
104
|
</script>
|
|
105
105
|
```
|
|
@@ -111,7 +111,6 @@ table uses ... })`.
|
|
|
111
111
|
```ts
|
|
112
112
|
const table = createTable({
|
|
113
113
|
features,
|
|
114
|
-
rowModels: { paginatedRowModel: createPaginatedRowModel() },
|
|
115
114
|
columns,
|
|
116
115
|
get data() {
|
|
117
116
|
return data
|
|
@@ -131,12 +130,17 @@ const table = createTable({
|
|
|
131
130
|
|
|
132
131
|
const table = createTable({
|
|
133
132
|
features,
|
|
134
|
-
rowModels: { ... },
|
|
135
133
|
columns,
|
|
136
|
-
get data() {
|
|
134
|
+
get data() {
|
|
135
|
+
return data
|
|
136
|
+
},
|
|
137
137
|
state: {
|
|
138
|
-
get sorting() {
|
|
139
|
-
|
|
138
|
+
get sorting() {
|
|
139
|
+
return sorting
|
|
140
|
+
},
|
|
141
|
+
get pagination() {
|
|
142
|
+
return pagination
|
|
143
|
+
},
|
|
140
144
|
},
|
|
141
145
|
onSortingChange: (updater) => {
|
|
142
146
|
sorting = updater instanceof Function ? updater(sorting) : updater
|
|
@@ -154,16 +158,20 @@ const table = createTable({
|
|
|
154
158
|
import { createAtom, useSelector } from '@tanstack/svelte-store'
|
|
155
159
|
|
|
156
160
|
const sortingAtom = createAtom<SortingState>([])
|
|
157
|
-
const paginationAtom = createAtom<PaginationState>({
|
|
161
|
+
const paginationAtom = createAtom<PaginationState>({
|
|
162
|
+
pageIndex: 0,
|
|
163
|
+
pageSize: 10,
|
|
164
|
+
})
|
|
158
165
|
|
|
159
166
|
const sorting = useSelector(sortingAtom)
|
|
160
167
|
const pagination = useSelector(paginationAtom)
|
|
161
168
|
|
|
162
169
|
const table = createTable({
|
|
163
170
|
features,
|
|
164
|
-
rowModels: { ... },
|
|
165
171
|
columns,
|
|
166
|
-
get data() {
|
|
172
|
+
get data() {
|
|
173
|
+
return data
|
|
174
|
+
},
|
|
167
175
|
atoms: {
|
|
168
176
|
sorting: sortingAtom,
|
|
169
177
|
pagination: paginationAtom,
|
|
@@ -221,8 +229,8 @@ import { renderSnippet } from '@tanstack/svelte-table'
|
|
|
221
229
|
## After the rewrite — verify
|
|
222
230
|
|
|
223
231
|
- `pnpm test:types` (or `svelte-check`) catches missing `<typeof features, TData>` generics,
|
|
224
|
-
missing `features`
|
|
225
|
-
them.
|
|
232
|
+
missing `features` or row-model factory slots, and feature APIs called on tables that didn't
|
|
233
|
+
register them.
|
|
226
234
|
- `pnpm build` should pass with the new `features` set. Bundle should shrink — only the
|
|
227
235
|
features you register are included.
|
|
228
236
|
- Click through every table screen. Reset buttons, multi-sort, pagination reset on filter,
|
|
@@ -241,9 +249,9 @@ import { renderSnippet } from '@tanstack/svelte-table'
|
|
|
241
249
|
changed" bugs during migration.
|
|
242
250
|
- **Plain `features: { rowPaginationFeature }` instead of `tableFeatures({...})`.** Loses
|
|
243
251
|
inference; you'll get `any` everywhere.
|
|
244
|
-
- **Forgetting feature registration after
|
|
245
|
-
`paginatedRowModel: createPaginatedRowModel()`
|
|
246
|
-
`
|
|
252
|
+
- **Forgetting feature registration after adding the row-model factory slot.** Adding
|
|
253
|
+
`paginatedRowModel: createPaginatedRowModel()` to `tableFeatures` without also including
|
|
254
|
+
`rowPaginationFeature` does nothing.
|
|
247
255
|
- **Reimplementing v8 helpers** (`flexRender`-style functions, manual store subscriptions,
|
|
248
256
|
hand-rolled selectors) instead of using `FlexRender` / `subscribeTable` / atom selectors.
|
|
249
257
|
That's the #1 AI tell on this migration.
|
|
@@ -69,8 +69,9 @@ If you find yourself running a table without a feature's UI ever showing, drop t
|
|
|
69
69
|
`createTable` syncs options in `$effect.pre`. If any of these identities flip every component
|
|
70
70
|
run, the table re-syncs more than it needs to.
|
|
71
71
|
|
|
72
|
-
- **`features
|
|
73
|
-
|
|
72
|
+
- **`features`**: declare at module scope, not inside the component function, and never
|
|
73
|
+
inside `$derived` / `$effect`. The `features` object now also carries row-model factories
|
|
74
|
+
and `*Fns` registries, so keeping it stable prevents unnecessary re-sync.
|
|
74
75
|
- **`columns`**: same — module scope or `$state.frozen` / a non-reactive `const` in the
|
|
75
76
|
component. Reactive recompute of columns is rare and almost always a bug.
|
|
76
77
|
- **`data`**: pass with a getter (`get data()`) so the reference is stable when the data
|
|
@@ -80,8 +81,10 @@ run, the table re-syncs more than it needs to.
|
|
|
80
81
|
```svelte
|
|
81
82
|
<script lang="ts">
|
|
82
83
|
// module scope is fine in .svelte too, when truly static
|
|
83
|
-
const features = tableFeatures({
|
|
84
|
-
|
|
84
|
+
const features = tableFeatures({
|
|
85
|
+
rowPaginationFeature,
|
|
86
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
87
|
+
})
|
|
85
88
|
const columns = columnHelper.columns([
|
|
86
89
|
/* ... */
|
|
87
90
|
])
|
|
@@ -91,7 +94,6 @@ run, the table re-syncs more than it needs to.
|
|
|
91
94
|
|
|
92
95
|
const table = createTable({
|
|
93
96
|
features,
|
|
94
|
-
rowModels,
|
|
95
97
|
columns,
|
|
96
98
|
get data() {
|
|
97
99
|
return data
|
|
@@ -48,7 +48,7 @@ A table instance has three (and a half) state surfaces:
|
|
|
48
48
|
- `table.state` — the value returned by the optional selector passed as the second argument to
|
|
49
49
|
`createTable`. **Svelte-only surface.**
|
|
50
50
|
|
|
51
|
-
The Svelte adapter installs `svelteReactivity()` as the `
|
|
51
|
+
The Svelte adapter installs `svelteReactivity()` as the `coreReactivityFeature`:
|
|
52
52
|
|
|
53
53
|
| Core concept | Svelte binding |
|
|
54
54
|
| ------------- | --------------- |
|
|
@@ -81,14 +81,13 @@ import {
|
|
|
81
81
|
const features = tableFeatures({
|
|
82
82
|
rowPaginationFeature,
|
|
83
83
|
rowSortingFeature,
|
|
84
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
85
|
+
sortedRowModel: createSortedRowModel(),
|
|
86
|
+
sortFns,
|
|
84
87
|
})
|
|
85
88
|
|
|
86
89
|
const table = createTable({
|
|
87
90
|
features,
|
|
88
|
-
rowModels: {
|
|
89
|
-
paginatedRowModel: createPaginatedRowModel(),
|
|
90
|
-
sortedRowModel: createSortedRowModel(sortFns),
|
|
91
|
-
},
|
|
92
91
|
columns,
|
|
93
92
|
get data() {
|
|
94
93
|
return data
|
|
@@ -122,7 +121,6 @@ exposed as `table.state`. The default selector returns the full registered state
|
|
|
122
121
|
const table = createTable(
|
|
123
122
|
{
|
|
124
123
|
features,
|
|
125
|
-
rowModels: { paginatedRowModel: createPaginatedRowModel() },
|
|
126
124
|
columns,
|
|
127
125
|
get data() {
|
|
128
126
|
return data
|
|
@@ -186,7 +184,6 @@ The default: set starting values, let the table own the rest. `initialState` als
|
|
|
186
184
|
```ts
|
|
187
185
|
const table = createTable({
|
|
188
186
|
features,
|
|
189
|
-
rowModels: {},
|
|
190
187
|
columns,
|
|
191
188
|
get data() {
|
|
192
189
|
return data
|
|
@@ -231,7 +228,6 @@ const pagination = useSelector(paginationAtom)
|
|
|
231
228
|
|
|
232
229
|
const table = createTable({
|
|
233
230
|
features,
|
|
234
|
-
rowModels: {},
|
|
235
231
|
columns,
|
|
236
232
|
get data() {
|
|
237
233
|
return data
|
|
@@ -266,7 +262,6 @@ updates.
|
|
|
266
262
|
|
|
267
263
|
const table = createTable({
|
|
268
264
|
features,
|
|
269
|
-
rowModels: {},
|
|
270
265
|
columns,
|
|
271
266
|
get data() {
|
|
272
267
|
return data
|
|
@@ -340,8 +335,7 @@ Always key `{#each}` blocks on stable ids (`headerGroup.id`, `header.id`, `row.i
|
|
|
340
335
|
|
|
341
336
|
## `createTableHook` — app-wide composition
|
|
342
337
|
|
|
343
|
-
Create one configured hook per app: shared `features
|
|
344
|
-
component registries.
|
|
338
|
+
Create one configured hook per app: shared `features` (including row-model factories), defaults, and pre-bound component registries.
|
|
345
339
|
|
|
346
340
|
```ts
|
|
347
341
|
import {
|
|
@@ -363,11 +357,13 @@ export const {
|
|
|
363
357
|
useCellContext,
|
|
364
358
|
useHeaderContext,
|
|
365
359
|
} = createTableHook({
|
|
366
|
-
features: tableFeatures({
|
|
367
|
-
|
|
360
|
+
features: tableFeatures({
|
|
361
|
+
rowPaginationFeature,
|
|
362
|
+
rowSortingFeature,
|
|
368
363
|
paginatedRowModel: createPaginatedRowModel(),
|
|
369
|
-
sortedRowModel: createSortedRowModel(
|
|
370
|
-
|
|
364
|
+
sortedRowModel: createSortedRowModel(),
|
|
365
|
+
sortFns,
|
|
366
|
+
}),
|
|
371
367
|
cellComponents: { TextCell },
|
|
372
368
|
headerComponents: { SortIndicator },
|
|
373
369
|
})
|
|
@@ -51,7 +51,6 @@ export type SvelteTable<
|
|
|
51
51
|
* const table = createTable(
|
|
52
52
|
* {
|
|
53
53
|
* features,
|
|
54
|
-
* rowModels: {},
|
|
55
54
|
* columns,
|
|
56
55
|
* data,
|
|
57
56
|
* },
|
|
@@ -73,7 +72,7 @@ export function createTable<
|
|
|
73
72
|
// 1. Merge reactivity into options using mergeObjects (preserves getters)
|
|
74
73
|
const mergedOptions = mergeObjects(tableOptions, {
|
|
75
74
|
features: {
|
|
76
|
-
|
|
75
|
+
coreReactivityFeature: svelteReactivity(),
|
|
77
76
|
...tableOptions.features,
|
|
78
77
|
},
|
|
79
78
|
}) as TableOptions<TFeatures, TData>
|
|
@@ -404,12 +404,12 @@ export type AppSvelteTable<
|
|
|
404
404
|
* rowPaginationFeature,
|
|
405
405
|
* rowSortingFeature,
|
|
406
406
|
* columnFilteringFeature,
|
|
407
|
-
* }),
|
|
408
|
-
* rowModels: {
|
|
409
407
|
* paginatedRowModel: createPaginatedRowModel(),
|
|
410
|
-
* sortedRowModel: createSortedRowModel(
|
|
411
|
-
* filteredRowModel: createFilteredRowModel(
|
|
412
|
-
*
|
|
408
|
+
* sortedRowModel: createSortedRowModel(),
|
|
409
|
+
* filteredRowModel: createFilteredRowModel(),
|
|
410
|
+
* sortFns,
|
|
411
|
+
* filterFns,
|
|
412
|
+
* }),
|
|
413
413
|
* tableComponents: { PaginationControls, RowCount },
|
|
414
414
|
* cellComponents: { TextCell, NumberCell },
|
|
415
415
|
* headerComponents: { SortIndicator, ColumnFilter },
|
|
@@ -527,10 +527,7 @@ export function createTableHook<
|
|
|
527
527
|
TData extends RowData,
|
|
528
528
|
TSelected = TableState<TFeatures>,
|
|
529
529
|
>(
|
|
530
|
-
tableOptions: Omit<
|
|
531
|
-
TableOptions<TFeatures, TData>,
|
|
532
|
-
'features' | 'rowModels'
|
|
533
|
-
>,
|
|
530
|
+
tableOptions: Omit<TableOptions<TFeatures, TData>, 'features'>,
|
|
534
531
|
selector?: (state: TableState<TFeatures>) => TSelected,
|
|
535
532
|
): AppSvelteTable<
|
|
536
533
|
TFeatures,
|