@tanstack/vue-table 9.0.0-beta.3 → 9.0.0-beta.30

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 (40) hide show
  1. package/README.md +1 -0
  2. package/dist/FlexRender.cjs.map +1 -1
  3. package/dist/FlexRender.d.cts +30 -12
  4. package/dist/FlexRender.d.ts +30 -12
  5. package/dist/FlexRender.js.map +1 -1
  6. package/dist/createTableHook.cjs +23 -64
  7. package/dist/createTableHook.cjs.map +1 -1
  8. package/dist/createTableHook.d.cts +52 -28
  9. package/dist/createTableHook.d.ts +52 -28
  10. package/dist/createTableHook.js +23 -64
  11. package/dist/createTableHook.js.map +1 -1
  12. package/dist/flex-render.d.cts +2 -2
  13. package/dist/flex-render.d.ts +2 -2
  14. package/dist/index.d.cts +4 -4
  15. package/dist/index.d.ts +4 -4
  16. package/dist/reactivity.cjs +10 -19
  17. package/dist/reactivity.cjs.map +1 -1
  18. package/dist/reactivity.js +10 -19
  19. package/dist/reactivity.js.map +1 -1
  20. package/dist/useTable.cjs +12 -20
  21. package/dist/useTable.cjs.map +1 -1
  22. package/dist/useTable.d.cts +11 -51
  23. package/dist/useTable.d.ts +11 -51
  24. package/dist/useTable.js +13 -21
  25. package/dist/useTable.js.map +1 -1
  26. package/package.json +4 -4
  27. package/skills/vue/client-to-server/SKILL.md +21 -26
  28. package/skills/vue/compose-with-tanstack-form/SKILL.md +4 -4
  29. package/skills/vue/compose-with-tanstack-pacer/SKILL.md +6 -3
  30. package/skills/vue/compose-with-tanstack-query/SKILL.md +18 -20
  31. package/skills/vue/compose-with-tanstack-store/SKILL.md +7 -6
  32. package/skills/vue/compose-with-tanstack-virtual/SKILL.md +8 -4
  33. package/skills/vue/getting-started/SKILL.md +55 -49
  34. package/skills/vue/migrate-v8-to-v9/SKILL.md +50 -32
  35. package/skills/vue/production-readiness/SKILL.md +28 -21
  36. package/skills/vue/table-state/SKILL.md +22 -26
  37. package/src/FlexRender.ts +28 -13
  38. package/src/createTableHook.ts +126 -90
  39. package/src/reactivity.ts +17 -43
  40. package/src/useTable.ts +23 -101
package/src/reactivity.ts CHANGED
@@ -1,20 +1,17 @@
1
- import {
2
- computed,
3
- getCurrentScope,
4
- onScopeDispose,
5
- shallowRef,
6
- watch,
7
- } from 'vue'
8
- import { batch, createAtom } from '@tanstack/vue-store'
1
+ import { computed, shallowRef, watch } from 'vue'
2
+ import { batch } from '@tanstack/store'
9
3
  import type {
10
4
  TableAtomOptions,
11
5
  TableReactivityBindings,
12
6
  } from '@tanstack/table-core/reactivity'
13
- import type { Atom, Observer, ReadonlyAtom } from '@tanstack/vue-store'
7
+ import type {
8
+ Atom,
9
+ Observer,
10
+ ReadonlyAtom,
11
+ Subscription,
12
+ } from '@tanstack/store'
14
13
  import type { ComputedRef, ShallowRef } from 'vue'
15
14
 
16
- const optionsStoreDebugName = 'table/optionsStore'
17
-
18
15
  function observerToCallback<T>(
19
16
  observerOrNext: Observer<T> | ((value: T) => void),
20
17
  ): (value: T) => void {
@@ -64,50 +61,27 @@ function refToWritableAtom<T>(source: ShallowRef<T>): Atom<T> {
64
61
  * refs.
65
62
  */
66
63
  export function vueReactivity(): TableReactivityBindings {
64
+ const subscriptions = new Set<Subscription>()
65
+
67
66
  return {
68
67
  createOptionsStore: true,
69
- wrapExternalAtoms: false,
70
- addSubscription: () => {
71
- throw new Error(
72
- 'Feature not supported in current reactivity implementation',
73
- )
68
+ wrapExternalAtoms: true,
69
+ addSubscription: (subscription) => {
70
+ subscriptions.add(subscription)
74
71
  },
75
72
  unmount: () => {
76
- throw new Error(
77
- 'Feature not supported in current reactivity implementation',
78
- )
73
+ subscriptions.forEach((s) => s.unsubscribe())
74
+ subscriptions.clear()
79
75
  },
80
76
  schedule: (fn) => queueMicrotask(() => fn()),
81
77
  createReadonlyAtom: <T>(fn: () => T, _options?: TableAtomOptions<T>) => {
82
- const storeAtom = createAtom(() => fn(), {
83
- compare: _options?.compare,
84
- })
85
- const version = shallowRef(0)
86
- const subscription = storeAtom.subscribe(() => {
87
- version.value += 1
88
- })
89
- if (getCurrentScope()) {
90
- onScopeDispose(() => subscription.unsubscribe())
91
- }
92
-
93
- return refToReadonlyAtom(
94
- computed(() => {
95
- version.value
96
- return storeAtom.get()
97
- }),
98
- )
78
+ return refToReadonlyAtom(computed(() => fn()))
99
79
  },
100
80
  createWritableAtom: <T>(
101
81
  value: T,
102
82
  _options?: TableAtomOptions<T>,
103
83
  ): Atom<T> => {
104
- if (_options?.debugName === optionsStoreDebugName) {
105
- return refToWritableAtom(shallowRef(value) as ShallowRef<T>)
106
- }
107
-
108
- return createAtom(value, {
109
- compare: _options?.compare,
110
- })
84
+ return refToWritableAtom(shallowRef(value) as ShallowRef<T>)
111
85
  },
112
86
  untrack: (fn) => fn(),
113
87
  batch,
package/src/useTable.ts CHANGED
@@ -1,30 +1,15 @@
1
- import { unref, watch } from 'vue'
1
+ import { getCurrentScope, onScopeDispose, unref, watch } from 'vue'
2
2
  import { constructTable } from '@tanstack/table-core'
3
- import { shallow, useSelector } from '@tanstack/vue-store'
4
3
  import { flatMerge, mergeProxy } from './merge-proxy'
5
4
  import { vueReactivity } from './reactivity'
6
5
  import type {
7
- Atom,
8
- ReadonlyAtom,
9
- ReadonlyStore,
10
- Store,
11
- } from '@tanstack/vue-store'
12
- import type {
13
- NoInfer,
14
6
  RowData,
15
7
  Table,
16
8
  TableFeatures,
17
9
  TableOptions,
18
- TableState,
19
10
  } from '@tanstack/table-core'
20
11
  import type { MaybeRef, VNode } from 'vue'
21
12
 
22
- export type SubscribeSource<TValue> =
23
- | Atom<TValue>
24
- | ReadonlyAtom<TValue>
25
- | Store<TValue>
26
- | ReadonlyStore<TValue>
27
-
28
13
  export type TableOptionsWithReactiveData<
29
14
  TFeatures extends TableFeatures,
30
15
  TData extends RowData,
@@ -61,57 +46,13 @@ function getReactiveOptionDeps<
61
46
  export type VueTable<
62
47
  TFeatures extends TableFeatures,
63
48
  TData extends RowData,
64
- TSelected = TableState<TFeatures>,
65
- > = Omit<Table<TFeatures, TData>, 'store'> & {
66
- /**
67
- * @deprecated Prefer `table.state` for render reads,
68
- * `table.atoms.<slice>.get()` for slice snapshots, or
69
- * `table.Subscribe` / `useSelector(table.store, selector)` for explicit
70
- * subscriptions. `table.store.state` is a current-value snapshot and is easy
71
- * to misuse in render code.
72
- */
73
- readonly store: Table<TFeatures, TData>['store']
74
- /**
75
- * Store mode: `selector` required. Source mode: pass `source` (atom or store); omit
76
- * `selector` for the whole value (identity), or pass `selector` to project. Split
77
- * overloads so source-only infers `TSourceValue` for `children` (see React `Subscribe`).
49
+ > = Table<TFeatures, TData> & {
50
+ /** Creates a reactive render boundary. The child function reads the table
51
+ * atoms it needs, so Vue only tracks those atom reads.
78
52
  */
79
- Subscribe: {
80
- <TSourceValue>(props: {
81
- source: SubscribeSource<TSourceValue>
82
- selector?: undefined
83
- children:
84
- | ((state: Readonly<TSourceValue>) => VNode | Array<VNode>)
85
- | VNode
86
- | Array<VNode>
87
- }): VNode | Array<VNode>
88
- <TSourceValue, TSubSelected>(props: {
89
- source: SubscribeSource<TSourceValue>
90
- selector: (state: TSourceValue) => TSubSelected
91
- children:
92
- | ((state: Readonly<TSubSelected>) => VNode | Array<VNode>)
93
- | VNode
94
- | Array<VNode>
95
- }): VNode | Array<VNode>
96
- <TSubSelected>(props: {
97
- selector: (state: NoInfer<TableState<TFeatures>>) => TSubSelected
98
- children:
99
- | ((state: Readonly<TSubSelected>) => VNode | Array<VNode>)
100
- | VNode
101
- | Array<VNode>
102
- }): VNode | Array<VNode>
103
- }
104
- /**
105
- * The selected state of the table. This state may not match the structure of
106
- * the full table state because it is selected by the selector function that
107
- * you pass as the 2nd argument to `useTable`.
108
- *
109
- * @example
110
- * const table = useTable(options, (state) => ({ globalFilter: state.globalFilter })) // only globalFilter is part of the selected state
111
- *
112
- * console.log(table.state.globalFilter)
113
- */
114
- readonly state: Readonly<TSelected>
53
+ Subscribe: (props: {
54
+ children: (atoms: Table<TFeatures, TData>['atoms']) => VNode | Array<VNode>
55
+ }) => VNode | Array<VNode>
115
56
  }
116
57
 
117
58
  /**
@@ -119,34 +60,28 @@ export type VueTable<
119
60
  *
120
61
  * Table options may contain Vue refs or computed values. The adapter unwraps
121
62
  * those reactive inputs, watches them with synchronous flushing, and keeps the
122
- * table options in sync. The optional selector projects from `table.store` and
123
- * exposes the selected value on `table.state`.
63
+ * table options in sync. Use `table.Subscribe` or native Vue computed values
64
+ * around `table.atoms.<slice>.get()` for selected reactive reads.
124
65
  *
125
66
  * @example
126
67
  * ```ts
127
68
  * const table = useTable(
128
69
  * {
129
70
  * features,
130
- * rowModels: {},
131
71
  * columns,
132
72
  * data,
133
73
  * },
134
- * (state) => ({ pagination: state.pagination }),
135
74
  * )
136
- *
137
- * table.state.pagination
138
75
  * ```
139
76
  */
140
77
  export function useTable<
141
78
  TFeatures extends TableFeatures,
142
79
  TData extends RowData,
143
- TSelected = TableState<TFeatures>,
144
80
  >(
145
81
  tableOptions:
146
82
  | TableOptions<TFeatures, TData>
147
83
  | TableOptionsWithReactiveData<TFeatures, TData>,
148
- selector?: (state: TableState<TFeatures>) => TSelected,
149
- ): VueTable<TFeatures, TData, TSelected> {
84
+ ): VueTable<TFeatures, TData> {
150
85
  const syncTableOptions = (
151
86
  table: Table<TFeatures, TData>,
152
87
  options: TableOptionsWithReactiveData<TFeatures, TData>,
@@ -156,9 +91,11 @@ export function useTable<
156
91
  )
157
92
  }
158
93
 
94
+ const reactivity = vueReactivity()
95
+
159
96
  const mergedOptions = mergeProxy(tableOptions, {
160
97
  features: {
161
- coreReativityFeature: vueReactivity(),
98
+ coreReactivityFeature: reactivity,
162
99
  ...(unref(tableOptions.features) ?? {}),
163
100
  },
164
101
  }) as TableOptionsWithReactiveData<TFeatures, TData>
@@ -177,7 +114,11 @@ export function useTable<
177
114
  ) as TableOptions<TFeatures, TData>
178
115
 
179
116
  const coreTable = constructTable(resolvedOptions)
180
- const table = coreTable as unknown as VueTable<TFeatures, TData, TSelected>
117
+ const table = coreTable as unknown as VueTable<TFeatures, TData>
118
+
119
+ if (getCurrentScope()) {
120
+ onScopeDispose(() => reactivity.unmount?.())
121
+ }
181
122
 
182
123
  watch(
183
124
  () => getReactiveOptionDeps(mergedOptions),
@@ -222,30 +163,11 @@ export function useTable<
222
163
  { immediate: true },
223
164
  )
224
165
 
225
- table.Subscribe = ((props: {
226
- source?: SubscribeSource<unknown>
227
- selector?: ((state: unknown) => unknown) | undefined
228
- children:
229
- | ((state: Readonly<unknown>) => VNode | Array<VNode>)
230
- | VNode
231
- | Array<VNode>
166
+ table.Subscribe = (props: {
167
+ children: (atoms: Table<TFeatures, TData>['atoms']) => VNode | Array<VNode>
232
168
  }) => {
233
- const source = props.source ?? table.store
234
- const selected = useSelector(source as never, props.selector as never, {
235
- compare: shallow,
236
- })
237
- if (typeof props.children === 'function') {
238
- return props.children(selected.value as Readonly<unknown>)
239
- }
240
- return props.children
241
- }) as VueTable<TFeatures, TData, TSelected>['Subscribe']
242
-
243
- const stateStore = useSelector(table.store, selector)
244
-
245
- return {
246
- ...table,
247
- get state() {
248
- return stateStore.value
249
- },
169
+ return props.children(table.atoms as Table<TFeatures, TData>['atoms'])
250
170
  }
171
+
172
+ return table
251
173
  }