@tanstack/vue-table 9.0.0-beta.2 → 9.0.0-beta.4

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.
@@ -1,5 +1,4 @@
1
1
  import { createColumnHelper as coreCreateColumnHelper } from '@tanstack/table-core'
2
- import { useSelector } from '@tanstack/vue-store'
3
2
  import { defineComponent, h, inject, provide } from 'vue'
4
3
  import { FlexRender } from './FlexRender'
5
4
  import { mergeProxy } from './merge-proxy'
@@ -192,31 +191,22 @@ export type CreateTableHookOptions<
192
191
  headerComponents?: THeaderComponents
193
192
  }
194
193
 
195
- export interface AppTableProps<
196
- TFeatures extends TableFeatures,
197
- TSelected = unknown,
198
- > {
199
- selector?: (state: TableState<TFeatures>) => TSelected
200
- }
194
+ export interface AppTableProps {}
201
195
 
202
196
  export interface AppCellProps<
203
197
  TFeatures extends TableFeatures,
204
198
  TData extends RowData,
205
199
  TValue extends CellData = CellData,
206
- TSelected = unknown,
207
200
  > {
208
201
  cell: Cell<TFeatures, TData, TValue>
209
- selector?: (state: TableState<TFeatures>) => TSelected
210
202
  }
211
203
 
212
204
  export interface AppHeaderProps<
213
205
  TFeatures extends TableFeatures,
214
206
  TData extends RowData,
215
207
  TValue extends CellData = CellData,
216
- TSelected = unknown,
217
208
  > {
218
209
  header: Header<TFeatures, TData, TValue>
219
- selector?: (state: TableState<TFeatures>) => TSelected
220
210
  }
221
211
 
222
212
  export type AppVueTable<
@@ -226,9 +216,9 @@ export type AppVueTable<
226
216
  TTableComponents extends Record<string, ComponentType<any>>,
227
217
  TCellComponents extends Record<string, ComponentType<any>>,
228
218
  THeaderComponents extends Record<string, ComponentType<any>>,
229
- > = VueTable<TFeatures, TData, TSelected> &
219
+ > = VueTable<TFeatures, TData> &
230
220
  NoInfer<TTableComponents> & {
231
- AppTable: Component<AppTableProps<TFeatures>>
221
+ AppTable: Component<AppTableProps>
232
222
  AppCell: Component<AppCellProps<TFeatures, TData>>
233
223
  AppHeader: Component<AppHeaderProps<TFeatures, TData>>
234
224
  AppFooter: Component<AppHeaderProps<TFeatures, TData>>
@@ -314,7 +304,7 @@ export function createTableHook<
314
304
  THeaderComponents
315
305
  >) {
316
306
  const TableContext = Symbol('TableContext') as InjectionKey<
317
- VueTable<TFeatures, any, any>
307
+ VueTable<TFeatures, any>
318
308
  >
319
309
  const CellContext = Symbol('CellContext') as InjectionKey<
320
310
  Cell<TFeatures, any, any>
@@ -410,19 +400,15 @@ export function createTableHook<
410
400
  },
411
401
  })
412
402
 
413
- function useAppTable<
414
- TData extends RowData,
415
- TSelected = TableState<TFeatures>,
416
- >(
403
+ function useAppTable<TData extends RowData>(
417
404
  tableOptions: Omit<
418
405
  TableOptionsWithReactiveData<TFeatures, TData>,
419
406
  'features' | 'rowModels'
420
407
  >,
421
- selector?: (state: TableState<TFeatures>) => TSelected,
422
408
  ): AppVueTable<
423
409
  TFeatures,
424
410
  TData,
425
- TSelected,
411
+ TableState<TFeatures>,
426
412
  TTableComponents,
427
413
  TCellComponents,
428
414
  THeaderComponents
@@ -432,28 +418,14 @@ export function createTableHook<
432
418
  tableOptions,
433
419
  ) as TableOptionsWithReactiveData<TFeatures, TData>
434
420
 
435
- const table = useTable<TFeatures, TData, TSelected>(mergedOptions, selector)
421
+ const table = useTable<TFeatures, TData>(mergedOptions)
436
422
 
437
423
  const AppTable = defineComponent({
438
424
  name: 'AppTable',
439
- props: {
440
- selector: {
441
- type: Function as PropType<(state: TableState<TFeatures>) => unknown>,
442
- default: undefined,
443
- },
444
- },
445
- setup(props, { slots }) {
425
+ setup(_, { slots }) {
446
426
  provide(TableContext, table)
447
- const selected = props.selector
448
- ? useSelector(table.store, props.selector)
449
- : undefined
450
-
451
427
  return () => {
452
- if (!props.selector) {
453
- return slots.default?.()
454
- }
455
-
456
- return slots.default?.({ state: selected?.value })
428
+ return slots.default?.()
457
429
  }
458
430
  },
459
431
  })
@@ -465,20 +437,12 @@ export function createTableHook<
465
437
  type: Object as PropType<object>,
466
438
  required: true,
467
439
  },
468
- selector: {
469
- type: Function as PropType<(state: TableState<TFeatures>) => unknown>,
470
- default: undefined,
471
- },
472
440
  },
473
441
  setup(props, { slots }) {
474
442
  const cell = props.cell as Cell<TFeatures, TData, any>
475
443
 
476
444
  provide(CellContext, cell)
477
445
 
478
- const selected = props.selector
479
- ? useSelector(table.store, props.selector)
480
- : undefined
481
-
482
446
  const extendedCell = Object.assign(cell, {
483
447
  FlexRender: CellFlexRender,
484
448
  ...(cellComponents ?? {}),
@@ -486,11 +450,7 @@ export function createTableHook<
486
450
  TCellComponents & { FlexRender: Component }
487
451
 
488
452
  return () => {
489
- return slots.default?.(
490
- props.selector
491
- ? { cell: extendedCell, state: selected?.value }
492
- : { cell: extendedCell },
493
- )
453
+ return slots.default?.({ cell: extendedCell })
494
454
  }
495
455
  },
496
456
  })
@@ -502,20 +462,12 @@ export function createTableHook<
502
462
  type: Object as PropType<object>,
503
463
  required: true,
504
464
  },
505
- selector: {
506
- type: Function as PropType<(state: TableState<TFeatures>) => unknown>,
507
- default: undefined,
508
- },
509
465
  },
510
466
  setup(props, { slots }) {
511
467
  const header = props.header as Header<TFeatures, TData, any>
512
468
 
513
469
  provide(HeaderContext, header)
514
470
 
515
- const selected = props.selector
516
- ? useSelector(table.store, props.selector)
517
- : undefined
518
-
519
471
  const extendedHeader = Object.assign(header, {
520
472
  FlexRender: HeaderFlexRender,
521
473
  ...(headerComponents ?? {}),
@@ -523,11 +475,7 @@ export function createTableHook<
523
475
  THeaderComponents & { FlexRender: Component }
524
476
 
525
477
  return () => {
526
- return slots.default?.(
527
- props.selector
528
- ? { header: extendedHeader, state: selected?.value }
529
- : { header: extendedHeader },
530
- )
478
+ return slots.default?.({ header: extendedHeader })
531
479
  }
532
480
  },
533
481
  })
@@ -539,20 +487,12 @@ export function createTableHook<
539
487
  type: Object as PropType<object>,
540
488
  required: true,
541
489
  },
542
- selector: {
543
- type: Function as PropType<(state: TableState<TFeatures>) => unknown>,
544
- default: undefined,
545
- },
546
490
  },
547
491
  setup(props, { slots }) {
548
492
  const header = props.header as Header<TFeatures, TData, any>
549
493
 
550
494
  provide(HeaderContext, header)
551
495
 
552
- const selected = props.selector
553
- ? useSelector(table.store, props.selector)
554
- : undefined
555
-
556
496
  const extendedHeader = Object.assign(header, {
557
497
  FlexRender: FooterFlexRender,
558
498
  ...(headerComponents ?? {}),
@@ -560,11 +500,7 @@ export function createTableHook<
560
500
  THeaderComponents & { FlexRender: Component }
561
501
 
562
502
  return () => {
563
- return slots.default?.(
564
- props.selector
565
- ? { header: extendedHeader, state: selected?.value }
566
- : { header: extendedHeader },
567
- )
503
+ return slots.default?.({ header: extendedHeader })
568
504
  }
569
505
  },
570
506
  })
@@ -579,7 +515,7 @@ export function createTableHook<
579
515
  }) as AppVueTable<
580
516
  TFeatures,
581
517
  TData,
582
- TSelected,
518
+ TableState<TFeatures>,
583
519
  TTableComponents,
584
520
  TCellComponents,
585
521
  THeaderComponents
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,16 +1,8 @@
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,
@@ -19,12 +11,6 @@ import type {
19
11
  } from '@tanstack/table-core'
20
12
  import type { MaybeRef, VNode } from 'vue'
21
13
 
22
- export type SubscribeSource<TValue> =
23
- | Atom<TValue>
24
- | ReadonlyAtom<TValue>
25
- | Store<TValue>
26
- | ReadonlyStore<TValue>
27
-
28
14
  export type TableOptionsWithReactiveData<
29
15
  TFeatures extends TableFeatures,
30
16
  TData extends RowData,
@@ -61,57 +47,19 @@ function getReactiveOptionDeps<
61
47
  export type VueTable<
62
48
  TFeatures extends TableFeatures,
63
49
  TData extends RowData,
64
- TSelected = TableState<TFeatures>,
65
50
  > = Omit<Table<TFeatures, TData>, 'store'> & {
66
51
  /**
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.
52
+ * @deprecated Prefer `table.atoms.<slice>.get()` for slice snapshots, or
53
+ * `table.Subscribe` for explicit subscriptions. `table.store.state` is a
54
+ * current-value snapshot and is easy to misuse in render code.
72
55
  */
73
56
  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`).
78
- */
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)
57
+ /** Creates a reactive render boundary. The child function reads the table
58
+ * atoms it needs, so Vue only tracks those atom reads.
113
59
  */
114
- readonly state: Readonly<TSelected>
60
+ Subscribe: (props: {
61
+ children: (atoms: Table<TFeatures, TData>['atoms']) => VNode | Array<VNode>
62
+ }) => VNode | Array<VNode>
115
63
  }
116
64
 
117
65
  /**
@@ -119,8 +67,8 @@ export type VueTable<
119
67
  *
120
68
  * Table options may contain Vue refs or computed values. The adapter unwraps
121
69
  * 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`.
70
+ * table options in sync. Use `table.Subscribe` or native Vue computed values
71
+ * around `table.atoms.<slice>.get()` for selected reactive reads.
124
72
  *
125
73
  * @example
126
74
  * ```ts
@@ -131,22 +79,17 @@ export type VueTable<
131
79
  * columns,
132
80
  * data,
133
81
  * },
134
- * (state) => ({ pagination: state.pagination }),
135
82
  * )
136
- *
137
- * table.state.pagination
138
83
  * ```
139
84
  */
140
85
  export function useTable<
141
86
  TFeatures extends TableFeatures,
142
87
  TData extends RowData,
143
- TSelected = TableState<TFeatures>,
144
88
  >(
145
89
  tableOptions:
146
90
  | TableOptions<TFeatures, TData>
147
91
  | TableOptionsWithReactiveData<TFeatures, TData>,
148
- selector?: (state: TableState<TFeatures>) => TSelected,
149
- ): VueTable<TFeatures, TData, TSelected> {
92
+ ): VueTable<TFeatures, TData> {
150
93
  const syncTableOptions = (
151
94
  table: Table<TFeatures, TData>,
152
95
  options: TableOptionsWithReactiveData<TFeatures, TData>,
@@ -156,9 +99,11 @@ export function useTable<
156
99
  )
157
100
  }
158
101
 
102
+ const reactivity = vueReactivity()
103
+
159
104
  const mergedOptions = mergeProxy(tableOptions, {
160
105
  features: {
161
- coreReativityFeature: vueReactivity(),
106
+ coreReativityFeature: reactivity,
162
107
  ...(unref(tableOptions.features) ?? {}),
163
108
  },
164
109
  }) as TableOptionsWithReactiveData<TFeatures, TData>
@@ -177,7 +122,11 @@ export function useTable<
177
122
  ) as TableOptions<TFeatures, TData>
178
123
 
179
124
  const coreTable = constructTable(resolvedOptions)
180
- const table = coreTable as unknown as VueTable<TFeatures, TData, TSelected>
125
+ const table = coreTable as unknown as VueTable<TFeatures, TData>
126
+
127
+ if (getCurrentScope()) {
128
+ onScopeDispose(() => reactivity.unmount?.())
129
+ }
181
130
 
182
131
  watch(
183
132
  () => getReactiveOptionDeps(mergedOptions),
@@ -222,30 +171,11 @@ export function useTable<
222
171
  { immediate: true },
223
172
  )
224
173
 
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>
174
+ table.Subscribe = (props: {
175
+ children: (atoms: Table<TFeatures, TData>['atoms']) => VNode | Array<VNode>
232
176
  }) => {
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
- },
177
+ return props.children(table.atoms)
250
178
  }
179
+
180
+ return table
251
181
  }