@tanstack/angular-table 9.0.0-alpha.49 → 9.0.0-alpha.51
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/fesm2022/tanstack-angular-table.mjs +114 -25
- package/dist/fesm2022/tanstack-angular-table.mjs.map +1 -1
- package/dist/types/tanstack-angular-table.d.ts +15 -2
- package/package.json +2 -2
- package/skills/angular/compose-with-tanstack-store/SKILL.md +9 -8
- package/skills/angular/migrate-v8-to-v9/SKILL.md +20 -16
- package/skills/angular/production-readiness/SKILL.md +8 -7
- package/skills/angular/table-state/SKILL.md +8 -4
- package/src/injectTable.ts +74 -1
- package/src/reactivity.ts +104 -33
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
name: angular/compose-with-tanstack-store
|
|
3
3
|
description: >
|
|
4
4
|
Compose TanStack Table v9 with `@tanstack/angular-store`. TanStack Table v9 is itself built on
|
|
5
|
-
TanStack Store — each state slice is an atom.
|
|
6
|
-
readonly, signal-backed), `table.store` (flat readonly
|
|
5
|
+
TanStack Store — each state slice is an atom. Read surfaces include `table.atoms.<slice>`
|
|
6
|
+
(per-slice readonly, signal-backed), `table.state` / `table.store` (flat readonly views), and `table.baseAtoms.<slice>`
|
|
7
7
|
(writable). The `atoms` table option lets you replace an internal slice with an external
|
|
8
8
|
TanStack Store atom for cross-app sharing (URL sync, persistence, multi-table coordination).
|
|
9
9
|
In Angular, native signals + `state` + `on[State]Change` is the default; reach for external
|
|
@@ -42,11 +42,12 @@ sources:
|
|
|
42
42
|
|
|
43
43
|
Every TanStack Table instance exposes its state at three layers:
|
|
44
44
|
|
|
45
|
-
| Surface | Shape | Angular reactivity | Use when
|
|
46
|
-
| ------------------------- | --------------------------------- | ------------------------------- |
|
|
47
|
-
| `table.baseAtoms.<slice>` | Writable `Atom<T>` | Backed by an Angular `signal` | Direct internal writes; rare
|
|
48
|
-
| `table.atoms.<slice>` | Readonly `Atom<T>` (derived) | Backed by an Angular `computed` | Reading or driving Angular reactivity per-slice
|
|
49
|
-
| `table.
|
|
45
|
+
| Surface | Shape | Angular reactivity | Use when |
|
|
46
|
+
| ------------------------- | --------------------------------- | ------------------------------- | ----------------------------------------------- |
|
|
47
|
+
| `table.baseAtoms.<slice>` | Writable `Atom<T>` | Backed by an Angular `signal` | Direct internal writes; rare |
|
|
48
|
+
| `table.atoms.<slice>` | Readonly `Atom<T>` (derived) | Backed by an Angular `computed` | Reading or driving Angular reactivity per-slice |
|
|
49
|
+
| `table.state` | Readonly flat proxy | Reads from slice atoms | Full-state JSON/debug output |
|
|
50
|
+
| `table.store` | Readonly flat `Store<TableState>` | Backed by an Angular `computed` | Low-level flat store access; rare |
|
|
50
51
|
|
|
51
52
|
All three are populated only for **registered features** (`_features`). All
|
|
52
53
|
three are signal-backed via `angularReactivity(injector)`:
|
|
@@ -60,7 +61,7 @@ tracks the dependency.
|
|
|
60
61
|
```ts
|
|
61
62
|
this.table.atoms.pagination.get() // current value (reactive)
|
|
62
63
|
this.table.atoms.pagination.subscribe(obs) // RxJS observer form
|
|
63
|
-
this.table.
|
|
64
|
+
this.table.state.pagination // flat proxy read; prefer atoms for narrow reads
|
|
64
65
|
this.table.baseAtoms.pagination.set(...) // direct internal write (avoid)
|
|
65
66
|
```
|
|
66
67
|
|
|
@@ -3,8 +3,8 @@ name: angular/migrate-v8-to-v9
|
|
|
3
3
|
description: >
|
|
4
4
|
Mechanical v8 → v9 migration for `@tanstack/angular-table`: `createAngularTable` →
|
|
5
5
|
`injectTable`, `get*RowModel()` options → `_rowModels` factories with explicit `*Fns`,
|
|
6
|
-
required `_features` via `tableFeatures()`,
|
|
7
|
-
of `table.getState()`, `createColumnHelper<TFeatures, TData>()` generic-order flip, every
|
|
6
|
+
required `_features` via `tableFeatures()`, state access via `table.atoms.<slice>.get()`
|
|
7
|
+
or `table.state` instead of `table.getState()`, `createColumnHelper<TFeatures, TData>()` generic-order flip, every
|
|
8
8
|
type now requires `TFeatures`, `enablePinning` split into `enableColumnPinning` /
|
|
9
9
|
`enableRowPinning`, `sortingFn` → `sortFn` rename pile, `ColumnSizingInfo` → `ColumnResizing`
|
|
10
10
|
split, removal of `_`-prefixed internals, signal-backed atoms replacing v8 memoized accessors,
|
|
@@ -124,24 +124,26 @@ Row-model and feature lookup tables → [`references/v8-to-v9-mapping.md`](refer
|
|
|
124
124
|
|
|
125
125
|
---
|
|
126
126
|
|
|
127
|
-
## 3. State access: `getState()` → `table.
|
|
127
|
+
## 3. State access: `getState()` → atoms or `table.state`
|
|
128
128
|
|
|
129
129
|
```ts
|
|
130
130
|
// v8
|
|
131
131
|
const { sorting, pagination } = table.getState()
|
|
132
132
|
|
|
133
|
-
// v9 — flat
|
|
134
|
-
const { sorting, pagination } = table.
|
|
133
|
+
// v9 — full-state flat proxy
|
|
134
|
+
const { sorting, pagination } = table.state
|
|
135
135
|
|
|
136
|
-
// v9 — per slice (
|
|
136
|
+
// v9 — per slice (preferred for Angular render code)
|
|
137
137
|
const sorting = table.atoms.sorting.get()
|
|
138
138
|
const pagination = table.atoms.pagination.get()
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
-
In Angular, all three (`table.atoms.<slice>`, `table.
|
|
141
|
+
In Angular, all three (`table.atoms.<slice>`, `table.state`,
|
|
142
142
|
`table.baseAtoms.<slice>`) are signal-backed — reading them inside a template,
|
|
143
143
|
`computed(...)`, or `effect(...)` registers an Angular dependency
|
|
144
|
-
automatically. No `toSignal(...)` wrappers needed.
|
|
144
|
+
automatically. No `toSignal(...)` wrappers needed. Prefer direct atom reads for
|
|
145
|
+
specific slices; keep `table.state` for full-state JSON/debug output or code
|
|
146
|
+
that genuinely wants the flat state shape.
|
|
145
147
|
|
|
146
148
|
See `tanstack-table/angular/table-state` for the full state surface mental
|
|
147
149
|
model.
|
|
@@ -275,7 +277,8 @@ v8 backed reactivity with manual memoized getters. v9's adapter
|
|
|
275
277
|
`computed` and every writable atom with an Angular `signal`. Consequences:
|
|
276
278
|
|
|
277
279
|
- **No `toSignal(...)` adapters around table state.** Read `table.atoms.x.get()`
|
|
278
|
-
|
|
280
|
+
directly inside templates, `computed`, `effect` for specific slices. Use
|
|
281
|
+
`table.state` when you need the full-state flat shape.
|
|
279
282
|
- **`computed(...)` is for derivation / equality, not for "make it reactive".**
|
|
280
283
|
Use `{ equal: shallow }` from `@tanstack/angular-table` on object/array
|
|
281
284
|
slices to skip downstream work on no-op updates.
|
|
@@ -306,8 +309,8 @@ v8 backed reactivity with manual memoized getters. v9's adapter
|
|
|
306
309
|
- [ ] Update `createColumnHelper<Person>()` → `createColumnHelper<typeof _features, Person>()`.
|
|
307
310
|
- [ ] Update every `ColumnDef<Person>` / `Cell<Person, X>` etc. to include
|
|
308
311
|
`TFeatures`.
|
|
309
|
-
- [ ] Replace `table.getState()` reads with `table.
|
|
310
|
-
`table.
|
|
312
|
+
- [ ] Replace `table.getState().slice` reads with `table.atoms.<slice>.get()`
|
|
313
|
+
where possible; use `table.state` for full-state/debug reads.
|
|
311
314
|
- [ ] Remove any usage of the v8 single `onStateChange` — split into per-slice
|
|
312
315
|
`on[State]Change`.
|
|
313
316
|
- [ ] In `on[State]Change` callbacks, handle both value and updater-fn shapes.
|
|
@@ -366,12 +369,13 @@ _rowModels: {
|
|
|
366
369
|
Same for sorting, pagination, expanding, grouping, faceting. Selection,
|
|
367
370
|
visibility, ordering, pinning, sizing, resizing do **not** need a row model.
|
|
368
371
|
|
|
369
|
-
### 4. (HIGH) `getState()` → `table.
|
|
372
|
+
### 4. (HIGH) `getState()` → `table.state` text replacement can be too broad
|
|
370
373
|
|
|
371
|
-
Bulk-replacing `table.getState().x` with `table.
|
|
372
|
-
value_ reads, but
|
|
373
|
-
|
|
374
|
-
needs no wrapper.
|
|
374
|
+
Bulk-replacing `table.getState().x` with `table.state.x` works for _current
|
|
375
|
+
value_ reads, but it hides which slice the component depends on. For Angular
|
|
376
|
+
render code and reactive derivations, switch to `table.atoms.x.get()` — it's
|
|
377
|
+
already signal-backed and needs no wrapper. Keep `table.state` for full-state
|
|
378
|
+
debug output.
|
|
375
379
|
|
|
376
380
|
### 5. (HIGH) Stale `sortingFn` / `sortingFns` references in column defs
|
|
377
381
|
|
|
@@ -6,7 +6,7 @@ description: >
|
|
|
6
6
|
stable references OUTSIDE the `injectTable` initializer; pass only the `*Fns` your data needs
|
|
7
7
|
to `createSortedRowModel` / `createFilteredRowModel` / `createGroupedRowModel`; use
|
|
8
8
|
`ChangeDetectionStrategy.OnPush`; lean on signal-backed atoms (`table.atoms.<slice>.get()`)
|
|
9
|
-
instead of broad `table.
|
|
9
|
+
instead of broad `table.state` reads where granularity matters; use `{ equal: shallow }`
|
|
10
10
|
on object/array `computed` selectors; set `getRowId` for stable identity; track by `id` in
|
|
11
11
|
every `@for`; defer cell components with `flexRenderComponent` only when you need its options;
|
|
12
12
|
scope DI tokens via `[tanStackTable*]` directives to kill prop drilling.
|
|
@@ -148,20 +148,21 @@ All `examples/angular/*` use `OnPush`. Match that.
|
|
|
148
148
|
|
|
149
149
|
---
|
|
150
150
|
|
|
151
|
-
## 4. Read narrowly — `table.atoms.<slice>.get()` over `table.
|
|
151
|
+
## 4. Read narrowly — `table.atoms.<slice>.get()` over `table.state`
|
|
152
152
|
|
|
153
153
|
Both surfaces are signal-backed. The difference is _which signal_ gets read.
|
|
154
154
|
|
|
155
155
|
```ts
|
|
156
|
-
// Wider —
|
|
157
|
-
const pageIndex = computed(() => this.table.
|
|
156
|
+
// Wider — reads through the flat state proxy
|
|
157
|
+
const pageIndex = computed(() => this.table.state.pagination.pageIndex)
|
|
158
158
|
|
|
159
159
|
// Narrower — depends only on the pagination atom
|
|
160
160
|
const pageIndex = computed(() => this.table.atoms.pagination.get().pageIndex)
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
For most apps the difference is negligible. For high-frequency
|
|
164
|
-
deeply-derived components, prefer per-atom reads.
|
|
163
|
+
For most apps the difference is negligible. For render code, high-frequency
|
|
164
|
+
atoms, or deeply-derived components, prefer per-atom reads. Keep `table.state`
|
|
165
|
+
for places that genuinely want the full-state shape, such as debug JSON.
|
|
165
166
|
|
|
166
167
|
---
|
|
167
168
|
|
|
@@ -347,7 +348,7 @@ the wiring cost. Pick exactly one source of truth per slice (see
|
|
|
347
348
|
- [ ] Cell render fns return primitives or component classes when possible;
|
|
348
349
|
`flexRenderComponent(...)` reserved for explicit-option cases.
|
|
349
350
|
- [ ] Reading state inside `effect`s / heavy `computed`s uses
|
|
350
|
-
`table.atoms.<slice>.get()` (not the flat
|
|
351
|
+
`table.atoms.<slice>.get()` (not the flat state proxy).
|
|
351
352
|
- [ ] Object/array `computed` selectors that feed expensive downstream use
|
|
352
353
|
`{ equal: shallow }`.
|
|
353
354
|
- [ ] No `cell` / `header` / `table` inputs drilled through multiple
|
|
@@ -30,6 +30,7 @@ sources:
|
|
|
30
30
|
> on top of TanStack Store (`alien-signals`). In Angular, the adapter bridges those
|
|
31
31
|
> atoms to native Angular signals, so reading `table.atoms.<slice>.get()` from a
|
|
32
32
|
> template, `computed(...)`, or `effect(...)` participates in Angular reactivity.
|
|
33
|
+
> Prefer that direct atom read when you need a specific state slice.
|
|
33
34
|
>
|
|
34
35
|
> This is the prerequisite for every other Angular Table skill. Don't skip it.
|
|
35
36
|
|
|
@@ -145,17 +146,20 @@ A table instance has three ways to look at its state:
|
|
|
145
146
|
| ------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------- |
|
|
146
147
|
| `table.baseAtoms.<slice>` | writable TanStack Store atom (always exists for registered slices) | low-level direct write; rare |
|
|
147
148
|
| `table.atoms.<slice>` | **readonly** derived atom per registered feature; backed by Angular `computed` | reading current value or driving reactivity |
|
|
148
|
-
| `table.
|
|
149
|
+
| `table.state` | flat proxy object over every registered slice | full-state JSON/debug output |
|
|
149
150
|
|
|
150
151
|
All three are signal-backed in Angular. Reading any of them inside a template,
|
|
151
|
-
`computed(...)`, or `effect(...)` registers an Angular dependency.
|
|
152
|
+
`computed(...)`, or `effect(...)` registers an Angular dependency. For normal
|
|
153
|
+
render code, prefer `table.atoms.<slice>.get()` so the read is explicit and
|
|
154
|
+
limited to the slice the component needs. Use `table.state` when you actually
|
|
155
|
+
need the flat full-state shape, such as `JSON.stringify(table.state, null, 2)`.
|
|
152
156
|
|
|
153
157
|
```ts
|
|
154
158
|
// Read current value (anywhere)
|
|
155
159
|
const pagination = this.table.atoms.pagination.get()
|
|
156
160
|
|
|
157
|
-
// Same value
|
|
158
|
-
const pagination2 = this.table.
|
|
161
|
+
// Same value through the flat proxy; use mainly for full-state debug output
|
|
162
|
+
const pagination2 = this.table.state.pagination
|
|
159
163
|
|
|
160
164
|
// Reactive derivation with custom equality
|
|
161
165
|
import { computed } from '@angular/core'
|
package/src/injectTable.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
Table,
|
|
21
21
|
TableFeatures,
|
|
22
22
|
TableOptions,
|
|
23
|
+
TableState,
|
|
23
24
|
} from '@tanstack/table-core'
|
|
24
25
|
|
|
25
26
|
export type SubscribeSource<TValue> =
|
|
@@ -31,7 +32,70 @@ export type SubscribeSource<TValue> =
|
|
|
31
32
|
export type AngularTable<
|
|
32
33
|
TFeatures extends TableFeatures,
|
|
33
34
|
TData extends RowData,
|
|
34
|
-
> = Table<TFeatures, TData>
|
|
35
|
+
> = Table<TFeatures, TData> & {
|
|
36
|
+
/**
|
|
37
|
+
* @deprecated Prefer `table.atoms.<slice>.get()` for template/render reads
|
|
38
|
+
* of a specific state slice, `table.state` for full-state debug snapshots, or
|
|
39
|
+
* Angular computed values around explicit selectors. `table.store.state` is a
|
|
40
|
+
* current-value snapshot and is easy to misuse in render code.
|
|
41
|
+
*/
|
|
42
|
+
readonly store: Table<TFeatures, TData>['store']
|
|
43
|
+
/**
|
|
44
|
+
* The current table state exposed as a flat proxy. Prefer
|
|
45
|
+
* `table.atoms.<slice>.get()` when reading a specific slice.
|
|
46
|
+
*/
|
|
47
|
+
readonly state: Readonly<TableState<TFeatures>>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function createStateProxy<
|
|
51
|
+
TFeatures extends TableFeatures,
|
|
52
|
+
TData extends RowData,
|
|
53
|
+
>(table: Table<TFeatures, TData>): Readonly<TableState<TFeatures>> {
|
|
54
|
+
const getSnapshot = () => {
|
|
55
|
+
const snapshot = {} as TableState<TFeatures>
|
|
56
|
+
const stateKeys = Object.keys(table.initialState) as Array<
|
|
57
|
+
keyof TableState<TFeatures>
|
|
58
|
+
>
|
|
59
|
+
|
|
60
|
+
for (const key of stateKeys) {
|
|
61
|
+
snapshot[key] = table.atoms[key].get()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return snapshot
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const target = {} as TableState<TFeatures>
|
|
68
|
+
|
|
69
|
+
return new Proxy(target, {
|
|
70
|
+
get(target, prop, receiver) {
|
|
71
|
+
if (prop === 'toJSON') {
|
|
72
|
+
return getSnapshot
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (typeof prop === 'string' && prop in table.initialState) {
|
|
76
|
+
return table.atoms[prop as keyof TableState<TFeatures>]?.get()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return Reflect.get(target, prop, receiver)
|
|
80
|
+
},
|
|
81
|
+
has(_, prop) {
|
|
82
|
+
return typeof prop === 'string' && prop in table.initialState
|
|
83
|
+
},
|
|
84
|
+
ownKeys() {
|
|
85
|
+
return Reflect.ownKeys(table.initialState)
|
|
86
|
+
},
|
|
87
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
88
|
+
if (typeof prop !== 'string' || !(prop in table.initialState)) {
|
|
89
|
+
return undefined
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
enumerable: true,
|
|
94
|
+
configurable: true,
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
})
|
|
98
|
+
}
|
|
35
99
|
|
|
36
100
|
/**
|
|
37
101
|
* Creates and returns an Angular-reactive table instance.
|
|
@@ -107,6 +171,15 @@ export function injectTable<
|
|
|
107
171
|
coreReativityFeature: angularReactivity(injector),
|
|
108
172
|
...options()._features,
|
|
109
173
|
},
|
|
174
|
+
}) as AngularTable<TFeatures, TData>
|
|
175
|
+
const stateProxy = createStateProxy(table)
|
|
176
|
+
|
|
177
|
+
Object.defineProperty(table, 'state', {
|
|
178
|
+
get() {
|
|
179
|
+
return stateProxy
|
|
180
|
+
},
|
|
181
|
+
configurable: true,
|
|
182
|
+
enumerable: true,
|
|
110
183
|
})
|
|
111
184
|
|
|
112
185
|
let isMount = true
|
package/src/reactivity.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
DestroyRef,
|
|
3
|
+
NgZone,
|
|
4
|
+
computed,
|
|
5
|
+
effect,
|
|
6
|
+
signal,
|
|
7
|
+
untracked,
|
|
8
|
+
} from '@angular/core'
|
|
9
|
+
import { batch, createAtom } from '@tanstack/angular-store'
|
|
3
10
|
import type { Atom, Observer, ReadonlyAtom } from '@tanstack/angular-store'
|
|
4
11
|
import type {
|
|
5
12
|
TableAtomOptions,
|
|
@@ -7,70 +14,134 @@ import type {
|
|
|
7
14
|
} from '@tanstack/table-core/reactivity'
|
|
8
15
|
import type { Injector, Signal, WritableSignal } from '@angular/core'
|
|
9
16
|
|
|
17
|
+
const optionsStoreDebugName = 'table/optionsStore'
|
|
18
|
+
|
|
19
|
+
function observerToCallback<T>(
|
|
20
|
+
observerOrNext: Observer<T> | ((value: T) => void),
|
|
21
|
+
): (value: T) => void {
|
|
22
|
+
return typeof observerOrNext === 'function'
|
|
23
|
+
? observerOrNext
|
|
24
|
+
: (value) => observerOrNext.next?.(value)
|
|
25
|
+
}
|
|
26
|
+
|
|
10
27
|
function signalToReadonlyAtom<T>(
|
|
11
|
-
|
|
12
|
-
|
|
28
|
+
source: Signal<T>,
|
|
29
|
+
getSource: () => T,
|
|
30
|
+
subscribeSource: (observerOrNext: Observer<T> | ((value: T) => void)) => {
|
|
31
|
+
unsubscribe: () => void
|
|
32
|
+
},
|
|
13
33
|
): ReadonlyAtom<T> {
|
|
14
|
-
return Object.assign(
|
|
15
|
-
get: () =>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
34
|
+
return Object.assign(source, {
|
|
35
|
+
get: () => {
|
|
36
|
+
const value = getSource()
|
|
37
|
+
source()
|
|
38
|
+
return value
|
|
20
39
|
},
|
|
40
|
+
subscribe: subscribeSource as ReadonlyAtom<T>['subscribe'],
|
|
21
41
|
})
|
|
22
42
|
}
|
|
23
43
|
|
|
24
44
|
function signalToWritableAtom<T>(
|
|
25
|
-
|
|
45
|
+
source: WritableSignal<T>,
|
|
26
46
|
injector: Injector,
|
|
27
47
|
): Atom<T> {
|
|
28
|
-
|
|
48
|
+
const observers = new Set<(value: T) => void>()
|
|
49
|
+
let observed = false
|
|
50
|
+
effect(
|
|
51
|
+
() => {
|
|
52
|
+
const value = source()
|
|
53
|
+
if (!observed) {
|
|
54
|
+
observed = true
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
observers.forEach((observer) => observer(value))
|
|
58
|
+
},
|
|
59
|
+
{ injector },
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return Object.assign(source.asReadonly(), {
|
|
29
63
|
set: (updater: T | ((prevVal: T) => T)) => {
|
|
30
64
|
typeof updater === 'function'
|
|
31
|
-
?
|
|
32
|
-
:
|
|
33
|
-
},
|
|
34
|
-
get: () => signal(),
|
|
35
|
-
subscribe: (observer: Observer<T>) => {
|
|
36
|
-
return toObservable(computed(signal), { injector: injector }).subscribe(
|
|
37
|
-
observer,
|
|
38
|
-
)
|
|
65
|
+
? source.update(updater as (val: T) => T)
|
|
66
|
+
: source.set(updater)
|
|
39
67
|
},
|
|
68
|
+
get: () => source(),
|
|
69
|
+
subscribe: ((observerOrNext: Observer<T> | ((value: T) => void)) => {
|
|
70
|
+
const observer = observerToCallback(observerOrNext)
|
|
71
|
+
observers.add(observer)
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
unsubscribe: () => observers.delete(observer),
|
|
75
|
+
}
|
|
76
|
+
}) as Atom<T>['subscribe'],
|
|
40
77
|
})
|
|
41
78
|
}
|
|
42
79
|
|
|
43
80
|
/**
|
|
44
81
|
* Creates the table-core reactivity bindings used by the Angular adapter.
|
|
45
82
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
83
|
+
* Table state atoms are backed by TanStack Store atoms. The options store stays
|
|
84
|
+
* framework-native because row-model APIs read `table.options` directly during
|
|
85
|
+
* render. Readonly table atoms bridge Store dependency tracking into Angular
|
|
86
|
+
* computed signals.
|
|
50
87
|
*/
|
|
51
88
|
export function angularReactivity(injector: Injector): TableReactivityBindings {
|
|
52
89
|
const ngZone = injector.get(NgZone)
|
|
90
|
+
const destroyRef = injector.get(DestroyRef)
|
|
91
|
+
|
|
53
92
|
return {
|
|
54
93
|
createOptionsStore: true,
|
|
55
94
|
schedule: (fn) => ngZone.runOutsideAngular(() => queueMicrotask(fn)),
|
|
56
95
|
createReadonlyAtom: <T>(fn: () => T, options?: TableAtomOptions<T>) => {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
96
|
+
const storeAtom = createAtom(() => fn(), {
|
|
97
|
+
compare: options?.compare,
|
|
98
|
+
})
|
|
99
|
+
const version = signal(0, {
|
|
100
|
+
equal: () => false,
|
|
101
|
+
})
|
|
102
|
+
const subscription = storeAtom.subscribe(() => {
|
|
103
|
+
version.update((value) => value + 1)
|
|
60
104
|
})
|
|
61
|
-
|
|
105
|
+
destroyRef.onDestroy(() => subscription.unsubscribe())
|
|
106
|
+
|
|
107
|
+
const value = computed(
|
|
108
|
+
() => {
|
|
109
|
+
version()
|
|
110
|
+
return storeAtom.get()
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
equal: options?.compare,
|
|
114
|
+
debugName: options?.debugName,
|
|
115
|
+
},
|
|
116
|
+
)
|
|
117
|
+
return signalToReadonlyAtom(
|
|
118
|
+
value,
|
|
119
|
+
() => storeAtom.get(),
|
|
120
|
+
(observerOrNext) => {
|
|
121
|
+
const observer = observerToCallback(observerOrNext)
|
|
122
|
+
return storeAtom.subscribe(() => {
|
|
123
|
+
observer(storeAtom.get())
|
|
124
|
+
})
|
|
125
|
+
},
|
|
126
|
+
)
|
|
62
127
|
},
|
|
63
128
|
createWritableAtom: <T>(
|
|
64
129
|
value: T,
|
|
65
130
|
options?: TableAtomOptions<T>,
|
|
66
131
|
): Atom<T> => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
132
|
+
if (options?.debugName === optionsStoreDebugName) {
|
|
133
|
+
const writableSignal = signal(value, {
|
|
134
|
+
equal: options.compare,
|
|
135
|
+
debugName: options.debugName,
|
|
136
|
+
})
|
|
137
|
+
return signalToWritableAtom(writableSignal, injector)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return createAtom(value, {
|
|
141
|
+
compare: options?.compare,
|
|
70
142
|
})
|
|
71
|
-
return signalToWritableAtom(writableSignal, injector)
|
|
72
143
|
},
|
|
73
144
|
untrack: untracked,
|
|
74
|
-
batch
|
|
145
|
+
batch,
|
|
75
146
|
}
|
|
76
147
|
}
|