11import { constructTable } from '@tanstack/table-core'
2- import { TanStackStoreSelector } from '@tanstack/lit-store'
32import { litReactivity } from './reactivity'
43import { FlexRender } from './flexRender'
4+
5+ import { subscribe } from './subscribe-directive'
56import type {
6- Atom ,
7- ReadonlyAtom ,
8- ReadonlyStore ,
9- Store ,
10- } from '@tanstack/lit-store'
11- import type {
12- NoInfer ,
137 RowData ,
148 Table ,
159 TableFeatures ,
1610 TableOptions ,
1711 TableState ,
1812} from '@tanstack/table-core'
19- import type {
20- ReactiveController ,
21- ReactiveControllerHost ,
22- TemplateResult ,
23- } from 'lit'
24-
25- export type SubscribeSource < TValue > =
26- | Atom < TValue >
27- | ReadonlyAtom < TValue >
28- | Store < TValue >
29- | ReadonlyStore < TValue >
13+ import type { ReactiveController , ReactiveControllerHost } from 'lit'
3014
3115/**
3216 * The extended table type returned by the Lit adapter.
@@ -46,45 +30,34 @@ export type LitTable<
4630 */
4731 readonly store : Table < TFeatures , TData > [ 'store' ]
4832 /**
49- * Subscribe to a selected slice of table state, or to a single source (atom or store).
50- *
51- * **Lit note:** `TableController` still wires host updates via the full `table.store`
52- * subscription — source mode matches the React API and reads `source.get()` at render
53- * time. True source-only invalidation can be added later via `source.subscribe`.
33+ * Subscribes to the table's underlying state store within a Lit template.
34+ * Re-renders only the targeted template slice when the observed state changes.
5435 *
5536 * @example
5637 * ```ts
57- * table.Subscribe({
58- * selector: (state) => ({ rowSelection: state.rowSelection }),
59- * children: (state) => html`<div>${JSON.stringify(state)}</div>`,
60- * })
38+ * // 1. Subscribe to a specific state slice (re-renders ONLY when rowSelection changes)
39+ * html`
40+ * <div>
41+ * ${table.subscribe(
42+ * table.store,
43+ * (state) => state.rowSelection,
44+ * (rowSelection) => html`<span>Selected: ${JSON.stringify(rowSelection)}</span>`
45+ * )}
46+ * </div>
47+ * `
48+ *
49+ * // 2. Subscribe to the full state (re-renders on any state mutation)
50+ * html`
51+ * <div>
52+ * ${table.subscribe(
53+ * table.store,
54+ * (state) => html`<span>Total rows: ${state.rowModel.rows.length}</span>`
55+ * )}
56+ * </div>
57+ * `
6158 * ```
6259 */
63- Subscribe : {
64- < TSourceValue > ( props : {
65- source : SubscribeSource < TSourceValue >
66- selector ?: undefined
67- children :
68- | ( ( state : Readonly < TSourceValue > ) => TemplateResult | string )
69- | TemplateResult
70- | string
71- } ) : TemplateResult | string
72- < TSourceValue , TSubscribeSelected > ( props : {
73- source : SubscribeSource < TSourceValue >
74- selector : ( state : TSourceValue ) => TSubscribeSelected
75- children :
76- | ( ( state : Readonly < TSubscribeSelected > ) => TemplateResult | string )
77- | TemplateResult
78- | string
79- } ) : TemplateResult | string
80- < TSubscribeSelected > ( props : {
81- selector : ( state : NoInfer < TableState < TFeatures > > ) => TSubscribeSelected
82- children :
83- | ( ( state : Readonly < TSubscribeSelected > ) => TemplateResult | string )
84- | TemplateResult
85- | string
86- } ) : TemplateResult | string
87- }
60+ subscribe : typeof subscribe
8861 /**
8962 * The selected state of the table. This state may not match the structure of
9063 * the full table state because it is selected by the selector function that
@@ -152,13 +125,6 @@ export class TableController<
152125 private _storeSubscription ?: { unsubscribe : ( ) => void }
153126 private _optionsSubscription ?: { unsubscribe : ( ) => void }
154127 private _notifier = 0
155- private _selectorCache = new WeakMap <
156- SubscribeSource < unknown > ,
157- Map <
158- ( ( state : unknown ) => unknown ) | undefined ,
159- TanStackStoreSelector < unknown >
160- >
161- > ( )
162128
163129 constructor ( host : ReactiveControllerHost ) {
164130 ; ( this . host = host ) . addController ( this )
@@ -217,33 +183,9 @@ export class TableController<
217183 // Capture for closure
218184 const tableInstance = this . _table
219185
220- // Attach Subscribe function
221- const Subscribe = ( ( props : {
222- source ?: SubscribeSource < unknown >
223- selector ?: ( state : unknown ) => unknown
224- children :
225- | ( ( state : Readonly < unknown > ) => TemplateResult | string )
226- | TemplateResult
227- | string
228- } ) : TemplateResult | string => {
229- const source = props . source ?? tableInstance . store
230-
231- const storeSelector : TanStackStoreSelector < unknown > =
232- this . _getOrCreateSelector ( source , props . selector )
233-
234- // TODO: update to newest version of Tanstack Store: https://github.com/TanStack/store/pull/329
235- const selectedState = storeSelector . value
236-
237- if ( typeof props . children === 'function' ) {
238- return props . children ( selectedState as Readonly < unknown > )
239- }
240-
241- return props . children
242- } ) as LitTable < TFeatures , TData , TSelected > [ 'Subscribe' ]
243-
244186 return {
245187 ...this . _table ,
246- Subscribe ,
188+ subscribe ,
247189 FlexRender,
248190 get state ( ) {
249191 return ( selector ?.( tableInstance . store . state ) ??
@@ -275,56 +217,5 @@ export class TableController<
275217 this . _storeSubscription = undefined
276218 this . _optionsSubscription ?. unsubscribe ( )
277219 this . _optionsSubscription = undefined
278- this . _selectorCache = new WeakMap ( )
279- }
280-
281- /**
282- * Get or create a TanStackStoreSelector for the given source and selector.
283- *
284- * Caches selectors by source (WeakMap) and selector function to avoid
285- * creating new controllers on every render cycle.
286- *
287- * @param source The atom or store to subscribe to
288- * @param selector Optional selector function to select a slice of the source state
289- * @returns A cached TanStackStoreSelector instance that subscribes to the source and applies the selector
290- */
291- private _getOrCreateSelector = (
292- source ?: SubscribeSource < unknown > ,
293- selector ?: ( state : unknown ) => unknown ,
294- ) : TanStackStoreSelector < unknown > => {
295- if ( ! source ) {
296- return new TanStackStoreSelector ( this . host , ( ) => source , selector )
297- }
298-
299- if ( ! this . _selectorCache . has ( source ) ) {
300- this . _selectorCache . set ( source , new Map ( ) )
301- }
302- const selectorMap = this . _selectorCache . get ( source )
303-
304- // Get or create the selector for this source + selector combination
305- if ( selectorMap ?. has ( selector ) ) {
306- return (
307- selectorMap . get ( selector ) ??
308- this . createSelectorForSource ( source , selector )
309- )
310- }
311-
312- const storeSelector = this . createSelectorForSource ( source , selector )
313- selectorMap ?. set ( selector , storeSelector )
314-
315- return storeSelector
316- }
317-
318- /**
319- * Create a new TanStackStoreSelector for the given source and selector without caching.
320- * @param source The atom or store to subscribe to
321- * @param selector Optional selector function to select a slice of the source state
322- * @returns A new TanStackStoreSelector instance that subscribes to the source and applies the selector
323- */
324- private createSelectorForSource = (
325- source : SubscribeSource < unknown > ,
326- selector ?: ( state : unknown ) => unknown ,
327- ) : TanStackStoreSelector < unknown > => {
328- return new TanStackStoreSelector ( this . host , ( ) => source , selector )
329220 }
330221}
0 commit comments