@tanstack/angular-table 9.0.0-alpha.1 → 9.0.0-alpha.11

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 (37) hide show
  1. package/dist/fesm2022/tanstack-angular-table.mjs +1370 -239
  2. package/dist/fesm2022/tanstack-angular-table.mjs.map +1 -1
  3. package/dist/types/tanstack-angular-table.d.ts +767 -0
  4. package/package.json +27 -17
  5. package/src/angularReactivityFeature.ts +210 -0
  6. package/src/flex-render/context.ts +14 -0
  7. package/src/flex-render/flags.ts +34 -0
  8. package/src/flex-render/flexRenderComponent.ts +288 -0
  9. package/src/flex-render/flexRenderComponentFactory.ts +241 -0
  10. package/src/flex-render/renderer.ts +376 -0
  11. package/src/flex-render/view.ts +165 -0
  12. package/src/flexRender.ts +124 -0
  13. package/src/helpers/cell.ts +104 -0
  14. package/src/helpers/createTableHook.ts +480 -0
  15. package/src/helpers/flexRenderCell.ts +136 -0
  16. package/src/helpers/header.ts +99 -0
  17. package/src/helpers/table.ts +87 -0
  18. package/src/index.ts +17 -70
  19. package/src/injectTable.ts +123 -0
  20. package/src/{lazy-signal-initializer.ts → lazySignalInitializer.ts} +2 -2
  21. package/src/reactivityUtils.ts +232 -0
  22. package/dist/esm2022/flex-render.mjs +0 -133
  23. package/dist/esm2022/index.mjs +0 -48
  24. package/dist/esm2022/lazy-signal-initializer.mjs +0 -43
  25. package/dist/esm2022/proxy.mjs +0 -83
  26. package/dist/esm2022/tanstack-angular-table.mjs +0 -5
  27. package/dist/flex-render.d.ts +0 -30
  28. package/dist/index.d.ts +0 -5
  29. package/dist/lazy-signal-initializer.d.ts +0 -5
  30. package/dist/proxy.d.ts +0 -3
  31. package/src/__tests__/createAngularTable.test.ts +0 -95
  32. package/src/__tests__/flex-render.test.ts +0 -156
  33. package/src/__tests__/lazy-init.test.ts +0 -124
  34. package/src/__tests__/test-setup.ts +0 -12
  35. package/src/__tests__/test-utils.ts +0 -62
  36. package/src/flex-render.ts +0 -164
  37. package/src/proxy.ts +0 -97
@@ -0,0 +1,241 @@
1
+ import {
2
+ ChangeDetectorRef,
3
+ ComponentRef,
4
+ Injectable,
5
+ Injector,
6
+ KeyValueDiffer,
7
+ KeyValueDiffers,
8
+ OutputEmitterRef,
9
+ OutputRefSubscription,
10
+ ViewContainerRef,
11
+ } from '@angular/core'
12
+ import { FlexRenderComponent } from './flexRenderComponent'
13
+
14
+ @Injectable()
15
+ export class FlexRenderComponentFactory {
16
+ readonly #viewContainerRef: ViewContainerRef
17
+
18
+ constructor(viewContainerRef: ViewContainerRef) {
19
+ this.#viewContainerRef = viewContainerRef
20
+ }
21
+
22
+ createComponent<T>(
23
+ flexRenderComponent: FlexRenderComponent<T>,
24
+ componentInjector: Injector,
25
+ ): FlexRenderComponentRef<T> {
26
+ const componentRef = this.#viewContainerRef.createComponent(
27
+ flexRenderComponent.component,
28
+ {
29
+ injector: componentInjector,
30
+ directives: flexRenderComponent.directives,
31
+ bindings: flexRenderComponent.bindings ?? [],
32
+ },
33
+ )
34
+ const view = new FlexRenderComponentRef(
35
+ componentRef,
36
+ flexRenderComponent,
37
+ componentInjector,
38
+ )
39
+
40
+ const { inputs, outputs } = flexRenderComponent
41
+
42
+ if (inputs) view.setInputs(inputs)
43
+ if (outputs) view.setOutputs(outputs)
44
+
45
+ return view
46
+ }
47
+ }
48
+
49
+ export class FlexRenderComponentRef<T> {
50
+ readonly #keyValueDiffersFactory: KeyValueDiffers
51
+ #componentData: FlexRenderComponent<T>
52
+ #inputValueDiffer: KeyValueDiffer<string, unknown>
53
+
54
+ readonly #outputRegistry: FlexRenderComponentOutputManager
55
+
56
+ constructor(
57
+ readonly componentRef: ComponentRef<T>,
58
+ componentData: FlexRenderComponent<T>,
59
+ readonly componentInjector: Injector,
60
+ ) {
61
+ this.#componentData = componentData
62
+ this.#keyValueDiffersFactory = componentInjector.get(KeyValueDiffers)
63
+
64
+ this.#outputRegistry = new FlexRenderComponentOutputManager(
65
+ this.#keyValueDiffersFactory,
66
+ this.outputs,
67
+ )
68
+
69
+ this.#inputValueDiffer = this.#keyValueDiffersFactory
70
+ .find(this.inputs)
71
+ .create()
72
+ this.#inputValueDiffer.diff(this.inputs)
73
+
74
+ this.componentRef.onDestroy(() => this.#outputRegistry.unsubscribeAll())
75
+ }
76
+
77
+ get component() {
78
+ return this.#componentData.component
79
+ }
80
+
81
+ get inputs() {
82
+ return this.#componentData.inputs ?? {}
83
+ }
84
+
85
+ get outputs() {
86
+ return this.#componentData.outputs ?? {}
87
+ }
88
+
89
+ /**
90
+ * Get component input and output diff by the given item
91
+ */
92
+ diff(item: FlexRenderComponent<T>) {
93
+ return {
94
+ inputDiff: this.#inputValueDiffer.diff(item.inputs ?? {}),
95
+ outputDiff: this.#outputRegistry.diff(item.outputs ?? {}),
96
+ }
97
+ }
98
+ /**
99
+ *
100
+ * @param compare Whether the current ref component instance is the same as the given one
101
+ */
102
+ eqType(compare: FlexRenderComponent<T>): boolean {
103
+ return compare.component === this.component
104
+ }
105
+
106
+ /**
107
+ * Tries to update current component refs input by the new given content component.
108
+ */
109
+ update(content: FlexRenderComponent<T>) {
110
+ const eq = this.eqType(content)
111
+ if (!eq) return
112
+ const { inputDiff, outputDiff } = this.diff(content)
113
+ if (inputDiff) {
114
+ inputDiff.forEachAddedItem((item) =>
115
+ this.setInput(item.key, item.currentValue),
116
+ )
117
+ inputDiff.forEachChangedItem((item) =>
118
+ this.setInput(item.key, item.currentValue),
119
+ )
120
+ inputDiff.forEachRemovedItem((item) => this.setInput(item.key, undefined))
121
+ }
122
+ if (outputDiff) {
123
+ outputDiff.forEachAddedItem((item) => {
124
+ this.setOutput(item.key, item.currentValue)
125
+ })
126
+ outputDiff.forEachChangedItem((item) => {
127
+ if (item.currentValue) {
128
+ this.#outputRegistry.setListener(item.key, item.currentValue)
129
+ } else {
130
+ this.#outputRegistry.unsubscribe(item.key)
131
+ }
132
+ })
133
+ outputDiff.forEachRemovedItem((item) => {
134
+ this.#outputRegistry.unsubscribe(item.key)
135
+ })
136
+ }
137
+
138
+ this.#componentData = content
139
+ }
140
+
141
+ markAsDirty(): void {
142
+ this.componentRef.injector.get(ChangeDetectorRef).markForCheck()
143
+ }
144
+
145
+ setInputs(inputs: Record<string, unknown>) {
146
+ for (const prop in inputs) {
147
+ this.setInput(prop, inputs[prop])
148
+ }
149
+ }
150
+
151
+ setInput(key: string, value: unknown) {
152
+ if (this.#componentData.allowedInputNames.includes(key)) {
153
+ this.componentRef.setInput(key, value)
154
+ }
155
+ }
156
+
157
+ setOutputs(
158
+ outputs: Record<
159
+ string,
160
+ OutputEmitterRef<unknown>['emit'] | null | undefined
161
+ >,
162
+ ) {
163
+ this.#outputRegistry.unsubscribeAll()
164
+ for (const prop in outputs) {
165
+ this.setOutput(prop, outputs[prop])
166
+ }
167
+ }
168
+
169
+ setOutput(
170
+ outputName: string,
171
+ emit: OutputEmitterRef<unknown>['emit'] | undefined | null,
172
+ ): void {
173
+ if (!this.#componentData.allowedOutputNames.includes(outputName)) return
174
+ if (!emit) {
175
+ this.#outputRegistry.unsubscribe(outputName)
176
+ return
177
+ }
178
+
179
+ const hasListener = this.#outputRegistry.hasListener(outputName)
180
+ this.#outputRegistry.setListener(outputName, emit)
181
+
182
+ if (hasListener) {
183
+ return
184
+ }
185
+
186
+ const instance = this.componentRef.instance
187
+ const output = instance[outputName as keyof typeof instance]
188
+ if (output && output instanceof OutputEmitterRef) {
189
+ output.subscribe((value) => {
190
+ this.#outputRegistry.getListener(outputName)?.(value)
191
+ })
192
+ }
193
+ }
194
+ }
195
+
196
+ class FlexRenderComponentOutputManager {
197
+ readonly #outputSubscribers: Record<string, OutputRefSubscription> = {}
198
+ readonly #outputListeners: Record<string, (...args: Array<any>) => void> = {}
199
+
200
+ readonly #valueDiffer: KeyValueDiffer<
201
+ string,
202
+ undefined | null | OutputEmitterRef<unknown>['emit']
203
+ >
204
+
205
+ constructor(keyValueDiffers: KeyValueDiffers, initialOutputs: any) {
206
+ this.#valueDiffer = keyValueDiffers.find(initialOutputs).create()
207
+ if (initialOutputs) {
208
+ this.#valueDiffer.diff(initialOutputs)
209
+ }
210
+ }
211
+
212
+ hasListener(outputName: string) {
213
+ return outputName in this.#outputListeners
214
+ }
215
+
216
+ setListener(outputName: string, callback: (...args: Array<any>) => void) {
217
+ this.#outputListeners[outputName] = callback
218
+ }
219
+
220
+ getListener(outputName: string) {
221
+ return this.#outputListeners[outputName]
222
+ }
223
+
224
+ unsubscribeAll(): void {
225
+ for (const prop in this.#outputSubscribers) {
226
+ this.unsubscribe(prop)
227
+ }
228
+ }
229
+
230
+ unsubscribe(outputName: string) {
231
+ if (outputName in this.#outputSubscribers) {
232
+ this.#outputSubscribers[outputName]?.unsubscribe()
233
+ delete this.#outputSubscribers[outputName]
234
+ delete this.#outputListeners[outputName]
235
+ }
236
+ }
237
+
238
+ diff(outputs: Record<string, OutputEmitterRef<unknown>['emit'] | undefined>) {
239
+ return this.#valueDiffer.diff(outputs ?? {})
240
+ }
241
+ }
@@ -0,0 +1,376 @@
1
+ import {
2
+ Injector,
3
+ computed,
4
+ effect,
5
+ runInInjectionContext,
6
+ untracked,
7
+ } from '@angular/core'
8
+ import { TanStackTableToken } from '../helpers/table'
9
+ import { TanStackTableCellToken } from '../helpers/cell'
10
+ import { TanStackTableHeaderToken } from '../helpers/header'
11
+ import { FlexRenderComponentProps } from './context'
12
+ import { FlexRenderFlags } from './flags'
13
+ import {
14
+ FlexRenderComponentView,
15
+ FlexRenderTemplateView,
16
+ mapToFlexRenderTypedContent,
17
+ } from './view'
18
+ import { flexRenderComponent } from './flexRenderComponent'
19
+ import { FlexRenderComponentFactory } from './flexRenderComponentFactory'
20
+ import type { FlexRenderComponent } from './flexRenderComponent'
21
+ import type {
22
+ EffectRef,
23
+ TemplateRef,
24
+ Type,
25
+ ViewContainerRef,
26
+ } from '@angular/core'
27
+ import type { FlexRenderTypedContent, FlexRenderView } from './view'
28
+ import type {
29
+ CellContext,
30
+ CellData,
31
+ HeaderContext,
32
+ RowData,
33
+ TableFeatures,
34
+ } from '@tanstack/table-core'
35
+
36
+ export type FlexRenderContent<TProps extends NonNullable<unknown>> =
37
+ | string
38
+ | number
39
+ | Type<TProps>
40
+ | FlexRenderComponent<TProps>
41
+ | TemplateRef<{ $implicit: TProps }>
42
+ | null
43
+ | Record<any, any>
44
+ | undefined
45
+
46
+ export type FlexRenderInputContent<TProps extends NonNullable<unknown>> =
47
+ | number
48
+ | string
49
+ | ((props: TProps) => FlexRenderContent<TProps>)
50
+ | null
51
+ | undefined
52
+
53
+ /**
54
+ * Options used to create a {@link FlexViewRenderer}.
55
+ *
56
+ * This renderer is designed to be embedded inside a directive/component that owns the
57
+ * `ViewContainerRef` and possibly a fallback `TemplateRef`.
58
+ */
59
+ interface RendererViewOptions<TProps extends NonNullable<unknown>> {
60
+ /**
61
+ * Signal-like getter that returns the latest renderable content.
62
+ */
63
+ content: () => FlexRenderInputContent<TProps>
64
+ /**
65
+ * Signal-like getter returning the current props/context object.
66
+ */
67
+ props: () => NoInfer<TProps>
68
+ /**
69
+ * Getter returning the base injector to evaluate render functions in.
70
+ *
71
+ * If `content` is a function, it will be executed inside this injection context
72
+ * via `runInInjectionContext` so Angular DI works as expected.
73
+ */
74
+ injector: () => Injector
75
+ /**
76
+ * Container that will host the dynamically created view/component.
77
+ */
78
+ viewContainerRef: ViewContainerRef
79
+ /**
80
+ * Fallback template used for primitive rendering.
81
+ *
82
+ * The template is instantiated with `$implicit` set to the primitive string/number.
83
+ */
84
+ templateRef: TemplateRef<unknown>
85
+ }
86
+
87
+ /**
88
+ * Internal view renderer used by Angular TanStack Table to implement `flexRender` directives.
89
+ *
90
+ * @internal Use FlexRender directives instead.
91
+ */
92
+ export class FlexViewRenderer<
93
+ TFeatures extends TableFeatures,
94
+ TRowData extends RowData,
95
+ TValue extends CellData,
96
+ TProps extends
97
+ | NonNullable<unknown>
98
+ | CellContext<TFeatures, TRowData, TValue>
99
+ | HeaderContext<TFeatures, TRowData, TValue>,
100
+ > {
101
+ #renderFlags = FlexRenderFlags.ViewFirstRender
102
+ #renderView: FlexRenderView<any> | null = null
103
+ #currentRenderEffectRef: EffectRef | null = null
104
+ #content: () => FlexRenderInputContent<TProps>
105
+ #props: () => TProps
106
+ #injector: () => Injector
107
+ #viewContainerRef: ViewContainerRef
108
+ #templateRef: TemplateRef<unknown>
109
+ #flexRenderComponentFactory: FlexRenderComponentFactory
110
+
111
+ readonly #getLatestContentValue = () => {
112
+ const content = this.#content()
113
+ const props = this.#props()
114
+ return typeof content !== 'function'
115
+ ? content
116
+ : runInInjectionContext(this.#injector(), () => content(props))
117
+ }
118
+
119
+ readonly #latestContent = computed(() => this.#getLatestContentValue())
120
+
121
+ #getContentValue = computed(() => {
122
+ const latestContent = this.#latestContent()
123
+ return mapToFlexRenderTypedContent(latestContent)
124
+ })
125
+
126
+ constructor(options: RendererViewOptions<TProps>) {
127
+ this.#content = options.content
128
+ this.#props = options.props
129
+ this.#injector = options.injector
130
+ this.#templateRef = options.templateRef
131
+ this.#viewContainerRef = options.viewContainerRef
132
+ this.#flexRenderComponentFactory = new FlexRenderComponentFactory(
133
+ this.#viewContainerRef,
134
+ )
135
+ }
136
+
137
+ mount(): EffectRef {
138
+ let previousContent: FlexRenderInputContent<TProps>
139
+ let previousProps: TProps
140
+
141
+ return effect(() => {
142
+ const props = this.#props()
143
+ const content = this.#content()
144
+
145
+ if (!(this.#renderFlags & FlexRenderFlags.ViewFirstRender)) {
146
+ if (previousContent !== content) {
147
+ this.#renderFlags |= FlexRenderFlags.ContentChanged
148
+ }
149
+ if (previousProps !== props) {
150
+ this.#renderFlags |= FlexRenderFlags.PropsReferenceChanged
151
+ }
152
+ }
153
+
154
+ untracked(() => this.#update())
155
+
156
+ if (FlexRenderFlags.ViewFirstRender & this.#renderFlags) {
157
+ this.#renderFlags &= ~FlexRenderFlags.ViewFirstRender
158
+ }
159
+
160
+ previousContent = content
161
+ previousProps = props
162
+ })
163
+ }
164
+
165
+ destroy(): void {
166
+ if (this.#currentRenderEffectRef) {
167
+ this.#currentRenderEffectRef.destroy()
168
+ this.#currentRenderEffectRef = null
169
+ }
170
+ if (this.#renderView) {
171
+ this.#renderView.unmount()
172
+ this.#renderView = null
173
+ }
174
+ }
175
+
176
+ #update() {
177
+ if (
178
+ this.#renderFlags &
179
+ (FlexRenderFlags.ContentChanged | FlexRenderFlags.ViewFirstRender)
180
+ ) {
181
+ this.#render()
182
+ return
183
+ }
184
+
185
+ if (this.#renderFlags & FlexRenderFlags.PropsReferenceChanged) {
186
+ if (this.#renderView) this.#renderView.updateProps(this.#props())
187
+ this.#renderFlags &= ~FlexRenderFlags.PropsReferenceChanged
188
+ }
189
+
190
+ if (this.#renderFlags & FlexRenderFlags.Dirty) {
191
+ if (this.#renderView) this.#renderView.dirtyCheck()
192
+ this.#renderFlags &= ~FlexRenderFlags.Dirty
193
+ }
194
+ }
195
+
196
+ #render() {
197
+ // When the view is recreated from scratch (content change or first render),
198
+ // we have to destroy the current effect listener since it will be recreated
199
+ // skipping the first call (FlexRenderFlags.RenderEffectChecked)
200
+ if (this.#shouldRecreateEntireView() && this.#currentRenderEffectRef) {
201
+ this.#currentRenderEffectRef.destroy()
202
+ this.#currentRenderEffectRef = null
203
+ this.#renderFlags &= ~FlexRenderFlags.RenderEffectChecked
204
+ }
205
+
206
+ this.#viewContainerRef.clear()
207
+ if (this.#renderView) {
208
+ this.#renderView.unmount()
209
+ this.#renderView = null
210
+ }
211
+
212
+ this.#renderFlags =
213
+ (this.#renderFlags & FlexRenderFlags.ViewFirstRender) |
214
+ (this.#renderFlags & FlexRenderFlags.RenderEffectChecked)
215
+
216
+ const resolvedContent = this.#getContentValue()
217
+ this.#renderView = this.#renderViewByContent(resolvedContent)
218
+ // If the content is a function `content(props)`, we initialize an effect
219
+ // to react to changes. If the current fn uses signals, we will set the DirtySignal flag
220
+ // to re-schedule the component updates
221
+ if (
222
+ !this.#currentRenderEffectRef &&
223
+ typeof untracked(this.#content) === 'function'
224
+ ) {
225
+ this.#currentRenderEffectRef = effect(
226
+ () => {
227
+ this.#latestContent()
228
+ if (!(this.#renderFlags & FlexRenderFlags.RenderEffectChecked)) {
229
+ this.#renderFlags |= FlexRenderFlags.RenderEffectChecked
230
+ return
231
+ }
232
+ this.#renderFlags |= FlexRenderFlags.Dirty
233
+ this.#doCheck()
234
+ },
235
+ { injector: this.#viewContainerRef.injector },
236
+ )
237
+ }
238
+ }
239
+
240
+ #shouldRecreateEntireView() {
241
+ return (
242
+ this.#renderFlags &
243
+ FlexRenderFlags.ContentChanged &
244
+ FlexRenderFlags.ViewFirstRender
245
+ )
246
+ }
247
+
248
+ #doCheck() {
249
+ const latestContent = this.#getContentValue()
250
+ if (latestContent.kind === 'null' || !this.#renderView) {
251
+ this.#renderFlags |= FlexRenderFlags.ContentChanged
252
+ } else {
253
+ this.#renderView.content = latestContent
254
+ const { kind: previousKind } = this.#renderView.previousContent
255
+ if (latestContent.kind !== previousKind) {
256
+ this.#renderFlags |= FlexRenderFlags.ContentChanged
257
+ }
258
+ }
259
+ this.#update()
260
+ }
261
+
262
+ #renderViewByContent(
263
+ content: FlexRenderTypedContent,
264
+ ): FlexRenderView<any> | null {
265
+ if (content.kind === 'primitive') {
266
+ return this.#renderStringContent(content)
267
+ } else if (content.kind === 'templateRef') {
268
+ return this.#renderTemplateRefContent(content)
269
+ } else if (content.kind === 'flexRenderComponent') {
270
+ return this.#renderComponent(content)
271
+ } else if (content.kind === 'component') {
272
+ return this.#renderCustomComponent(content)
273
+ } else {
274
+ return null
275
+ }
276
+ }
277
+
278
+ #renderStringContent(
279
+ template: Extract<FlexRenderTypedContent, { kind: 'primitive' }>,
280
+ ): FlexRenderTemplateView {
281
+ const context = () => {
282
+ const content = this.#content()
283
+ return typeof content === 'string' || typeof content === 'number'
284
+ ? content
285
+ : runInInjectionContext(this.#injector(), () =>
286
+ content?.(this.#props()),
287
+ )
288
+ }
289
+ const ref = this.#viewContainerRef.createEmbeddedView(this.#templateRef, {
290
+ get $implicit() {
291
+ return context()
292
+ },
293
+ })
294
+ return new FlexRenderTemplateView(template, ref)
295
+ }
296
+
297
+ #renderTemplateRefContent(
298
+ template: Extract<FlexRenderTypedContent, { kind: 'templateRef' }>,
299
+ ): FlexRenderTemplateView {
300
+ const latestContext = () => this.#props()
301
+ const view = this.#viewContainerRef.createEmbeddedView(
302
+ template.content,
303
+ {
304
+ get $implicit() {
305
+ return latestContext()
306
+ },
307
+ },
308
+ { injector: this.#getInjector() },
309
+ )
310
+ return new FlexRenderTemplateView(template, view)
311
+ }
312
+
313
+ #renderComponent(
314
+ flexRenderComponent: Extract<
315
+ FlexRenderTypedContent,
316
+ { kind: 'flexRenderComponent' }
317
+ >,
318
+ ): FlexRenderComponentView {
319
+ const { injector } = flexRenderComponent.content
320
+ const componentInjector = this.#getInjector(injector)
321
+ const view = this.#flexRenderComponentFactory.createComponent(
322
+ flexRenderComponent.content,
323
+ componentInjector,
324
+ )
325
+ return new FlexRenderComponentView(flexRenderComponent, view)
326
+ }
327
+
328
+ #renderCustomComponent(
329
+ component: Extract<FlexRenderTypedContent, { kind: 'component' }>,
330
+ ): FlexRenderComponentView {
331
+ const instance = flexRenderComponent(component.content, {
332
+ inputs: this.#props(),
333
+ })
334
+ const injector = this.#getInjector(instance.injector)
335
+ const view = this.#flexRenderComponentFactory.createComponent(
336
+ instance,
337
+ injector,
338
+ )
339
+ return new FlexRenderComponentView(component, view)
340
+ }
341
+
342
+ #getInjector(parentInjector?: Injector) {
343
+ const getContext = () => this.#props()
344
+ const proxy = new Proxy(this.#props(), {
345
+ get: (_, key) => getContext()[key as keyof typeof _],
346
+ })
347
+
348
+ const staticProviders = []
349
+ if ('table' in proxy) {
350
+ staticProviders.push({
351
+ provide: TanStackTableToken,
352
+ useValue: () => proxy.table,
353
+ })
354
+ }
355
+ if ('cell' in proxy) {
356
+ staticProviders.push({
357
+ provide: TanStackTableCellToken,
358
+ useValue: () => proxy.cell,
359
+ })
360
+ }
361
+ if ('header' in proxy) {
362
+ staticProviders.push({
363
+ provide: TanStackTableHeaderToken,
364
+ useValue: () => proxy.header,
365
+ })
366
+ }
367
+
368
+ return Injector.create({
369
+ parent: parentInjector ?? this.#injector(),
370
+ providers: [
371
+ ...staticProviders,
372
+ { provide: FlexRenderComponentProps, useValue: proxy },
373
+ ],
374
+ })
375
+ }
376
+ }