Skip to content

Commit ae24248

Browse files
committed
feat: simplified Subscribe by remove table prop in favor of just source
1 parent 893f519 commit ae24248

10 files changed

Lines changed: 183 additions & 232 deletions

File tree

packages/angular-table/src/injectTable.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ import {
77
untracked,
88
} from '@angular/core'
99
import { constructTable } from '@tanstack/table-core'
10+
import { injectSelector, shallow } from '@tanstack/angular-store'
1011
import { lazyInit } from './lazySignalInitializer'
1112
import { angularReactivity } from './reactivity'
12-
import type { Atom, ReadonlyAtom } from '@tanstack/angular-store'
13+
import type {
14+
Atom,
15+
ReadonlyAtom,
16+
ReadonlyStore,
17+
Store,
18+
} from '@tanstack/angular-store'
1319
import type {
1420
RowData,
1521
Table,
@@ -19,6 +25,12 @@ import type {
1925
} from '@tanstack/table-core'
2026
import type { Signal, ValueEqualityFn } from '@angular/core'
2127

28+
export type SubscribeSource<TValue> =
29+
| Atom<TValue>
30+
| ReadonlyAtom<TValue>
31+
| Store<TValue>
32+
| ReadonlyStore<TValue>
33+
2234
/**
2335
* Store mode: pass `selector` (required) to project from full table state.
2436
* Source mode: pass `source` (atom or store); omit `selector` for the whole value
@@ -27,12 +39,12 @@ import type { Signal, ValueEqualityFn } from '@angular/core'
2739
*/
2840
export interface AngularTableComputed<TFeatures extends TableFeatures> {
2941
<TSourceValue>(props: {
30-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
42+
source: SubscribeSource<TSourceValue>
3143
selector?: undefined
3244
equal?: ValueEqualityFn<TSourceValue>
3345
}): Signal<Readonly<TSourceValue>>
3446
<TSourceValue, TSubSelected>(props: {
35-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
47+
source: SubscribeSource<TSourceValue>
3648
selector: (state: TSourceValue) => TSubSelected
3749
equal?: ValueEqualityFn<TSubSelected>
3850
}): Signal<Readonly<TSubSelected>>
@@ -59,10 +71,7 @@ export type AngularTable<
5971
* Creates a computed that subscribe to changes in the table store with a custom selector.
6072
* Default equality function is "shallow".
6173
*/
62-
computed: <TSubSelected = {}>(props: {
63-
selector: (state: TableState<TFeatures>) => TSubSelected
64-
equal?: ValueEqualityFn<TSubSelected>
65-
}) => Signal<Readonly<TSubSelected>>
74+
computed: AngularTableComputed<TFeatures>
6675
}
6776

6877
/**
@@ -160,14 +169,21 @@ export function injectTable<
160169
{ injector, debugName: 'tableOptionsUpdate' },
161170
)
162171

163-
table.computed = function Subscribe<TSubSelected = {}>(props: {
164-
selector: (state: TableState<TFeatures>) => TSubSelected
165-
equal?: ValueEqualityFn<TSubSelected>
172+
table.computed = function Subscribe(props: {
173+
source?: SubscribeSource<unknown>
174+
selector?: (state: unknown) => unknown
175+
equal?: ValueEqualityFn<unknown>
166176
}) {
167-
return computed(() => props.selector(table.store.get()), {
168-
equal: props.equal,
169-
})
170-
}
177+
const source = props.source ?? table.store
178+
return injectSelector(
179+
source,
180+
props.selector ?? ((state: unknown) => state),
181+
{
182+
compare: props.equal ?? shallow,
183+
injector,
184+
},
185+
)
186+
} as AngularTableComputed<TFeatures>
171187

172188
Object.defineProperty(table, 'state', {
173189
value: computed(() => selector(table.store.get())),

packages/lit-table/src/TableController.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { constructTable } from '@tanstack/table-core'
22
import { litReactivity } from './reactivity'
33
import { FlexRender } from './flexRender'
4-
import type { Atom, ReadonlyAtom } from '@tanstack/store'
4+
import type { Atom, ReadonlyAtom, ReadonlyStore, Store } from '@tanstack/store'
55
import type {
66
NoInfer,
77
RowData,
@@ -16,6 +16,12 @@ import type {
1616
TemplateResult,
1717
} from 'lit'
1818

19+
export type SubscribeSource<TValue> =
20+
| Atom<TValue>
21+
| ReadonlyAtom<TValue>
22+
| Store<TValue>
23+
| ReadonlyStore<TValue>
24+
1925
/**
2026
* The extended table type returned by the Lit adapter.
2127
* Includes a `Subscribe` method for fine-grained state subscriptions
@@ -43,15 +49,15 @@ export type LitTable<
4349
*/
4450
Subscribe: {
4551
<TSourceValue>(props: {
46-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
52+
source: SubscribeSource<TSourceValue>
4753
selector?: undefined
4854
children:
4955
| ((state: Readonly<TSourceValue>) => TemplateResult | string)
5056
| TemplateResult
5157
| string
5258
}): TemplateResult | string
5359
<TSourceValue, TSubscribeSelected>(props: {
54-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
60+
source: SubscribeSource<TSourceValue>
5561
selector: (state: TSourceValue) => TSubscribeSelected
5662
children:
5763
| ((state: Readonly<TSubscribeSelected>) => TemplateResult | string)
@@ -178,20 +184,17 @@ export class TableController<
178184

179185
// Attach Subscribe function
180186
const Subscribe = function Subscribe(props: {
181-
source?: Atom<unknown> | ReadonlyAtom<unknown>
187+
source?: SubscribeSource<unknown>
182188
selector?: (state: unknown) => unknown
183189
children:
184190
| ((state: Readonly<unknown>) => TemplateResult | string)
185191
| TemplateResult
186192
| string
187193
}): TemplateResult | string {
188-
let selectedState: unknown
189-
if (props.source !== undefined) {
190-
const v = props.source.get()
191-
selectedState = props.selector !== undefined ? props.selector(v) : v
192-
} else {
193-
selectedState = props.selector!(tableInstance.store.state)
194-
}
194+
const source = props.source ?? tableInstance.store
195+
const value = source.get()
196+
const selectedState =
197+
props.selector !== undefined ? props.selector(value) : value
195198
if (typeof props.children === 'function') {
196199
return props.children(selectedState as Readonly<unknown>)
197200
}
@@ -215,7 +218,6 @@ export class TableController<
215218
this.host.requestUpdate()
216219
})
217220

218-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
219221
this._optionsSubscription = this._table.optionsStore!.subscribe(() => {
220222
this._notifier++
221223
this.host.requestUpdate()

packages/preact-table/src/Subscribe.ts

Lines changed: 32 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
import { shallow, useSelector } from '@tanstack/preact-store'
2-
import type { Atom, ReadonlyAtom } from '@tanstack/preact-store'
32
import type {
4-
RowData,
5-
Table,
6-
TableFeatures,
7-
TableState,
8-
} from '@tanstack/table-core'
3+
Atom,
4+
ReadonlyAtom,
5+
ReadonlyStore,
6+
Store,
7+
} from '@tanstack/preact-store'
8+
import type { TableFeatures, TableState } from '@tanstack/table-core'
99
import type { ComponentChildren } from 'preact'
1010

11+
export type SubscribeSource<TValue> =
12+
| Atom<TValue>
13+
| ReadonlyAtom<TValue>
14+
| Store<TValue>
15+
| ReadonlyStore<TValue>
16+
1117
/**
1218
* Subscribe to `table.store` (full table state). The selector receives the full
1319
* {@link TableState}.
1420
*/
1521
export type SubscribePropsWithStore<
1622
TFeatures extends TableFeatures,
17-
TData extends RowData,
1823
TSelected,
1924
> = {
20-
table: Table<TFeatures, TData>
25+
source: SubscribeSource<TableState<TFeatures>>
2126
/**
2227
* Select from full table state. Re-renders when the selected value changes
2328
* (shallow compare).
@@ -34,111 +39,63 @@ export type SubscribePropsWithStore<
3439
* `table.optionsStore`). Omitting `selector` is equivalent to the identity
3540
* selector — children receive `TSourceValue`.
3641
*/
37-
export type SubscribePropsWithSourceIdentity<
38-
TFeatures extends TableFeatures,
39-
TData extends RowData,
40-
TSourceValue,
41-
> = {
42-
table: Table<TFeatures, TData>
43-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
42+
export type SubscribePropsWithSourceIdentity<TSourceValue> = {
43+
source: SubscribeSource<TSourceValue>
4444
selector?: undefined
4545
children: ((state: TSourceValue) => ComponentChildren) | ComponentChildren
4646
}
4747

4848
/**
4949
* Subscribe to a projected value from a source (atom or store).
5050
*/
51-
export type SubscribePropsWithSourceWithSelector<
52-
TFeatures extends TableFeatures,
53-
TData extends RowData,
54-
TSourceValue,
55-
TSelected,
56-
> = {
57-
table: Table<TFeatures, TData>
58-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
51+
export type SubscribePropsWithSourceWithSelector<TSourceValue, TSelected> = {
52+
source: SubscribeSource<TSourceValue>
5953
selector: (state: TSourceValue) => TSelected
6054
children: ((state: TSelected) => ComponentChildren) | ComponentChildren
6155
}
6256

6357
/**
6458
* Subscribe to a single source — atom or store (identity or projected).
6559
*/
66-
export type SubscribePropsWithSource<
67-
TFeatures extends TableFeatures,
68-
TData extends RowData,
69-
TSourceValue,
70-
TSelected = TSourceValue,
71-
> =
72-
| SubscribePropsWithSourceIdentity<TFeatures, TData, TSourceValue>
73-
| SubscribePropsWithSourceWithSelector<
74-
TFeatures,
75-
TData,
76-
TSourceValue,
77-
TSelected
78-
>
60+
export type SubscribePropsWithSource<TSourceValue, TSelected = TSourceValue> =
61+
| SubscribePropsWithSourceIdentity<TSourceValue>
62+
| SubscribePropsWithSourceWithSelector<TSourceValue, TSelected>
7963

8064
export type SubscribeProps<
8165
TFeatures extends TableFeatures,
82-
TData extends RowData,
8366
TSelected = unknown,
8467
TSourceValue = unknown,
8568
> =
86-
| SubscribePropsWithStore<TFeatures, TData, TSelected>
87-
| SubscribePropsWithSourceIdentity<TFeatures, TData, TSourceValue>
88-
| SubscribePropsWithSourceWithSelector<
89-
TFeatures,
90-
TData,
91-
TSourceValue,
92-
TSelected
93-
>
69+
| SubscribePropsWithStore<TFeatures, TSelected>
70+
| SubscribePropsWithSourceIdentity<TSourceValue>
71+
| SubscribePropsWithSourceWithSelector<TSourceValue, TSelected>
9472

9573
/**
9674
* A Preact component that allows you to subscribe to the table state.
9775
*
9876
* For `table.Subscribe` from `useTable`, prefer that API — it uses overloads so
9977
* JSX contextual typing works. This standalone component uses a union `props` type.
10078
*/
101-
export function Subscribe<
102-
TFeatures extends TableFeatures,
103-
TData extends RowData,
104-
TSourceValue,
105-
>(
106-
props: SubscribePropsWithSourceIdentity<TFeatures, TData, TSourceValue>,
79+
export function Subscribe<TSourceValue>(
80+
props: SubscribePropsWithSourceIdentity<TSourceValue>,
10781
): ComponentChildren
108-
export function Subscribe<
109-
TFeatures extends TableFeatures,
110-
TData extends RowData,
111-
TSourceValue,
112-
TSelected,
113-
>(
114-
props: SubscribePropsWithSourceWithSelector<
115-
TFeatures,
116-
TData,
117-
TSourceValue,
118-
TSelected
119-
>,
82+
export function Subscribe<TSourceValue, TSelected>(
83+
props: SubscribePropsWithSourceWithSelector<TSourceValue, TSelected>,
12084
): ComponentChildren
121-
export function Subscribe<
122-
TFeatures extends TableFeatures,
123-
TData extends RowData,
124-
TSelected,
125-
>(
126-
props: SubscribePropsWithStore<TFeatures, TData, TSelected>,
85+
export function Subscribe<TFeatures extends TableFeatures, TSelected>(
86+
props: SubscribePropsWithStore<TFeatures, TSelected>,
12787
): ComponentChildren
12888
export function Subscribe<
12989
TFeatures extends TableFeatures,
130-
TData extends RowData,
13190
TSelected,
13291
TSourceValue,
13392
>(
134-
props: SubscribeProps<TFeatures, TData, TSelected, TSourceValue>,
93+
props: SubscribeProps<TFeatures, TSelected, TSourceValue>,
13594
): ComponentChildren {
136-
const source = 'source' in props ? props.source : props.table.store
137-
const selectFn =
138-
'source' in props ? (props.selector ?? ((x: unknown) => x)) : props.selector
95+
const selectFn = props.selector ?? ((x: unknown) => x)
13996

14097
const selected = useSelector(
141-
source as never,
98+
props.source as never,
14299
selectFn as Parameters<typeof useSelector>[1],
143100
{
144101
compare: shallow,

packages/preact-table/src/useTable.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ import type {
1212
TableOptions,
1313
TableState,
1414
} from '@tanstack/table-core'
15-
import type { Atom, ReadonlyAtom } from '@tanstack/preact-store'
1615
import type { ComponentChildren } from 'preact'
1716
import type { FlexRenderProps } from './FlexRender'
18-
import type { SubscribePropsWithStore } from './Subscribe'
17+
import type { SubscribePropsWithStore, SubscribeSource } from './Subscribe'
1918

2019
export type PreactTable<
2120
TFeatures extends TableFeatures,
@@ -51,20 +50,17 @@ export type PreactTable<
5150
*/
5251
Subscribe: {
5352
<TSourceValue>(props: {
54-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
53+
source: SubscribeSource<TSourceValue>
5554
selector?: undefined
5655
children: ((state: TSourceValue) => ComponentChildren) | ComponentChildren
5756
}): ComponentChildren
5857
<TSourceValue, TSubSelected>(props: {
59-
source: Atom<TSourceValue> | ReadonlyAtom<TSourceValue>
58+
source: SubscribeSource<TSourceValue>
6059
selector: (state: TSourceValue) => TSubSelected
6160
children: ((state: TSubSelected) => ComponentChildren) | ComponentChildren
6261
}): ComponentChildren
6362
<TSubSelected>(
64-
props: Omit<
65-
SubscribePropsWithStore<TFeatures, TData, TSubSelected>,
66-
'table'
67-
>,
63+
props: Omit<SubscribePropsWithStore<TFeatures, TSubSelected>, 'source'>,
6864
): ComponentChildren
6965
}
7066
/**
@@ -99,9 +95,11 @@ export function useTable<
9995
}) as PreactTable<TFeatures, TData, TSelected>
10096

10197
tableInstance.Subscribe = ((props: any) => {
98+
const source = props.source ?? tableInstance.store
99+
102100
return Subscribe({
103101
...props,
104-
table: tableInstance,
102+
source,
105103
})
106104
}) as PreactTable<TFeatures, TData, TSelected>['Subscribe']
107105

0 commit comments

Comments
 (0)