@tanstack/angular-table 9.0.0-alpha.10 → 9.0.0-alpha.12

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,323 +1,1502 @@
1
1
  import * as i0 from '@angular/core';
2
- import { untracked, computed, inject, Injector, ComponentRef, ChangeDetectorRef, TemplateRef, Type, isSignal, ViewContainerRef, Directive, Inject, Input, InjectionToken, signal } from '@angular/core';
3
- import { _createTable } from '@tanstack/table-core';
2
+ import { InjectionToken, input, inject, Directive, reflectComponentType, TemplateRef, Type, Injectable, KeyValueDiffers, ChangeDetectorRef, OutputEmitterRef, runInInjectionContext, computed, effect, untracked, Injector, ViewContainerRef, DestroyRef, isSignal, signal, assertInInjectionContext } from '@angular/core';
3
+ import { getMemoFnMeta, $internalMemoFnMeta, constructTable, createColumnHelper } from '@tanstack/table-core';
4
4
  export * from '@tanstack/table-core';
5
+ import { injectStore } from '@tanstack/angular-store';
5
6
 
6
7
  /**
7
- * Implementation from @tanstack/angular-query
8
- * {@link https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/util/lazy-init/lazy-init.ts}
8
+ * Injection token that provides access to the current {@link AngularTable} instance.
9
+ *
10
+ * This token is provided by the {@link TanStackTable} directive.
9
11
  */
10
- function lazyInit(initializer) {
11
- let object = null;
12
- const initializeObject = () => {
13
- if (!object) {
14
- object = untracked(() => initializer());
12
+ const TanStackTableToken = new InjectionToken('[TanStack Table] Table Context');
13
+ /**
14
+ * Provides a TanStack Table instance (`AngularTable`) in Angular DI.
15
+ *
16
+ * The table can be injected by:
17
+ * - any descendant of an element using `[tanStackTable]="..."`
18
+ * - any component instantiated by `*flexRender` when the render props contains `table`
19
+ *
20
+ * @example
21
+ * ```html
22
+ * <div [tanStackTable]="table">
23
+ * <app-pagination />
24
+ * </div>
25
+ * ```
26
+ *
27
+ * ```ts
28
+ * @Component({
29
+ * selector: 'app-pagination',
30
+ * template: `
31
+ * <button (click)="prev()" [disabled]="!table().getCanPreviousPage()">Prev</button>
32
+ * <button (click)="next()" [disabled]="!table().getCanNextPage()">Next</button>
33
+ * `,
34
+ * })
35
+ * export class PaginationComponent {
36
+ * readonly table = injectTableContext()
37
+ *
38
+ * prev() {
39
+ * this.table().previousPage()
40
+ * }
41
+ * next() {
42
+ * this.table().nextPage()
43
+ * }
44
+ * }
45
+ * ```
46
+ */
47
+ class TanStackTable {
48
+ /**
49
+ * The current TanStack Table instance.
50
+ *
51
+ * Provided as a required signal input so DI consumers always read the latest value.
52
+ */
53
+ table = input.required({ ...(ngDevMode ? { debugName: "table" } : {}), alias: 'tanStackTable' });
54
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TanStackTable, deps: [], target: i0.ɵɵFactoryTarget.Directive });
55
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: TanStackTable, isStandalone: true, selector: "[tanStackTable]", inputs: { table: { classPropertyName: "table", publicName: "tanStackTable", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
56
+ {
57
+ provide: TanStackTableToken,
58
+ useFactory: () => inject(TanStackTable).table,
59
+ },
60
+ ], exportAs: ["table"], ngImport: i0 });
61
+ }
62
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TanStackTable, decorators: [{
63
+ type: Directive,
64
+ args: [{
65
+ selector: '[tanStackTable]',
66
+ exportAs: 'table',
67
+ providers: [
68
+ {
69
+ provide: TanStackTableToken,
70
+ useFactory: () => inject(TanStackTable).table,
71
+ },
72
+ ],
73
+ }]
74
+ }], propDecorators: { table: [{ type: i0.Input, args: [{ isSignal: true, alias: "tanStackTable", required: true }] }] } });
75
+ /**
76
+ * Injects the current TanStack Table instance signal.
77
+ *
78
+ * Available when:
79
+ * - there is a nearest `[tanStackTable]` directive in the DI tree, or
80
+ * - the caller is rendered via `*flexRender` with render props containing `table`
81
+ */
82
+ function injectTableContext() {
83
+ return inject(TanStackTableToken);
84
+ }
85
+
86
+ /**
87
+ * Injection token that provides access to the current cell.
88
+ *
89
+ * This token is provided by the {@link TanStackTableCell} directive.
90
+ */
91
+ const TanStackTableCellToken = new InjectionToken('[TanStack Table] CellContext');
92
+ /**
93
+ * Provides a TanStack Table `Cell` instance in Angular DI.
94
+ *
95
+ * The cell can be injected by:
96
+ * - any descendant of an element using `[tanStackTableCell]="..."`
97
+ * - any component instantiated by `*flexRender` when the render props contains `cell`
98
+ *
99
+ * @example
100
+ * Inject from the nearest `[tanStackTableCell]`:
101
+ * ```html
102
+ * <td [tanStackTableCell]="cell">
103
+ * <app-cell-actions />
104
+ * </td>
105
+ * ```
106
+ *
107
+ * ```ts
108
+ * @Component({
109
+ * selector: 'app-cell-actions',
110
+ * template: `{{ cell().id }}`,
111
+ * })
112
+ * export class CellActionsComponent {
113
+ * readonly cell = injectTableCellContext()
114
+ * }
115
+ * ```
116
+ *
117
+ * @example
118
+ * Inject inside a component rendered via `flexRender`:
119
+ * ```ts
120
+ * @Component({
121
+ * selector: 'app-price-cell',
122
+ * template: `{{ cell().getValue() }}`,
123
+ * })
124
+ * export class PriceCellComponent {
125
+ * readonly cell = injectTableCellContext()
126
+ * }
127
+ * ```
128
+ */
129
+ class TanStackTableCell {
130
+ /**
131
+ * The current TanStack Table cell.
132
+ *
133
+ * Provided as a required signal input so DI consumers always read the latest value.
134
+ */
135
+ cell = input.required({ ...(ngDevMode ? { debugName: "cell" } : {}), alias: 'tanStackTableCell' });
136
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TanStackTableCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
137
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: TanStackTableCell, isStandalone: true, selector: "[tanStackTableCell]", inputs: { cell: { classPropertyName: "cell", publicName: "tanStackTableCell", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
138
+ {
139
+ provide: TanStackTableCellToken,
140
+ useFactory: () => inject(TanStackTableCell).cell,
141
+ },
142
+ ], exportAs: ["cell"], ngImport: i0 });
143
+ }
144
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TanStackTableCell, decorators: [{
145
+ type: Directive,
146
+ args: [{
147
+ selector: '[tanStackTableCell]',
148
+ exportAs: 'cell',
149
+ providers: [
150
+ {
151
+ provide: TanStackTableCellToken,
152
+ useFactory: () => inject(TanStackTableCell).cell,
153
+ },
154
+ ],
155
+ }]
156
+ }], propDecorators: { cell: [{ type: i0.Input, args: [{ isSignal: true, alias: "tanStackTableCell", required: true }] }] } });
157
+ /**
158
+ * Injects the current TanStack Table cell signal.
159
+ *
160
+ * Available when:
161
+ * - there is a nearest `[tanStackTableCell]` directive in the DI tree, or
162
+ * - the caller is rendered via `*flexRender` with render props containing `cell`
163
+ */
164
+ function injectTableCellContext() {
165
+ return inject(TanStackTableCellToken);
166
+ }
167
+
168
+ /**
169
+ * Injection token that provides access to the current header.
170
+ *
171
+ * This token is provided by the {@link TanStackTableHeader} directive.
172
+ */
173
+ const TanStackTableHeaderToken = new InjectionToken('[TanStack Table] HeaderContext');
174
+ /**
175
+ * Provides a TanStack Table `Header` instance in Angular DI.
176
+ *
177
+ * The header can be injected by:
178
+ * - any descendant of an element using `[tanStackTableHeader]="..."`
179
+ * - any component instantiated by `*flexRender` when the render props contains `header`
180
+ *
181
+ * @example
182
+ * ```html
183
+ * <th [tanStackTableHeader]="header">
184
+ * <app-sort-indicator />
185
+ * </th>
186
+ * ```
187
+ *
188
+ * ```ts
189
+ * @Component({
190
+ * selector: 'app-sort-indicator',
191
+ * template: `
192
+ * <button (click)="toggle()">
193
+ * {{ header().column.id }}
194
+ * </button>
195
+ * `,
196
+ * })
197
+ * export class SortIndicatorComponent {
198
+ * readonly header = injectTableHeaderContext()
199
+ *
200
+ * toggle() {
201
+ * this.header().column.toggleSorting()
202
+ * }
203
+ * }
204
+ * ```
205
+ */
206
+ class TanStackTableHeader {
207
+ /**
208
+ * The current TanStack Table header.
209
+ *
210
+ * Provided as a required signal input so DI consumers always read the latest value.
211
+ */
212
+ header = input.required({ ...(ngDevMode ? { debugName: "header" } : {}), alias: 'tanStackTableHeader' });
213
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TanStackTableHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive });
214
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: TanStackTableHeader, isStandalone: true, selector: "[tanStackTableHeader]", inputs: { header: { classPropertyName: "header", publicName: "tanStackTableHeader", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
215
+ {
216
+ provide: TanStackTableHeaderToken,
217
+ useFactory: () => inject(TanStackTableHeader).header,
218
+ },
219
+ ], exportAs: ["header"], ngImport: i0 });
220
+ }
221
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TanStackTableHeader, decorators: [{
222
+ type: Directive,
223
+ args: [{
224
+ selector: '[tanStackTableHeader]',
225
+ exportAs: 'header',
226
+ providers: [
227
+ {
228
+ provide: TanStackTableHeaderToken,
229
+ useFactory: () => inject(TanStackTableHeader).header,
230
+ },
231
+ ],
232
+ }]
233
+ }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "tanStackTableHeader", required: true }] }] } });
234
+ /**
235
+ * Injects the current TanStack Table header signal.
236
+ *
237
+ * Available when:
238
+ * - there is a nearest `[tanStackTableHeader]` directive in the DI tree, or
239
+ * - the caller is rendered via `*flexRender` with render props containing `header`
240
+ */
241
+ function injectTableHeaderContext() {
242
+ return inject(TanStackTableHeaderToken);
243
+ }
244
+
245
+ const FlexRenderComponentProps = new InjectionToken('[@tanstack/angular-table] Flex render component context props');
246
+ /**
247
+ * Inject the flex render context props.
248
+ *
249
+ * Can be used in components rendered via FlexRender directives.
250
+ */
251
+ function injectFlexRenderContext() {
252
+ return inject(FlexRenderComponentProps);
253
+ }
254
+
255
+ /**
256
+ * Flags used to manage and optimize the rendering lifecycle of the content of the cell
257
+ * while using {@link FlexViewRenderer}.
258
+ */
259
+ const FlexRenderFlags = {
260
+ /**
261
+ * Indicates that the view is being created for the first time or will be cleared during the next update phase.
262
+ * This is the initial state and will transition after the first ngDoCheck.
263
+ */
264
+ ViewFirstRender: 1 << 0,
265
+ /**
266
+ * Indicates the `content` property has been modified or the view requires a complete re-render.
267
+ * When this flag is enabled, the view will be cleared and recreated from scratch.
268
+ */
269
+ ContentChanged: 1 << 1,
270
+ /**
271
+ * Indicates that the `props` property reference has changed.
272
+ * When this flag is enabled, the view context is updated based on the type of the content.
273
+ *
274
+ * For Component view, inputs will be updated and view will be marked as dirty.
275
+ * For TemplateRef and primitive values, view will be marked as dirty
276
+ */
277
+ PropsReferenceChanged: 1 << 2,
278
+ /**
279
+ * Indicates that the current rendered view needs to be checked for changes.
280
+ * This will be set to true when `content(props)` result has changed or during
281
+ * forced update
282
+ */
283
+ Dirty: 1 << 3,
284
+ /**
285
+ * Indicates that the first render effect has been checked at least one time.
286
+ */
287
+ RenderEffectChecked: 1 << 4,
288
+ };
289
+
290
+ /**
291
+ * Helper function to create a {@link FlexRenderComponent} instance, with better type-safety.
292
+ *
293
+ * @example
294
+ * ```ts
295
+ * import {flexRenderComponent} from '@tanstack/angular-table'
296
+ * import {inputBinding, outputBinding} from '@angular/core';
297
+ *
298
+ * const columns = [
299
+ * {
300
+ * cell: ({ row }) => {
301
+ * return flexRenderComponent(MyComponent, {
302
+ * inputs: { value: mySignalValue() },
303
+ * outputs: { valueChange: (val) => {} }
304
+ * // or using angular native createComponent#binding api
305
+ * bindings: [
306
+ * inputBinding('value', mySignalValue),
307
+ * outputBinding('valueChange', value => {
308
+ * console.log("my value changed to", value)
309
+ * })
310
+ * ]
311
+ * })
312
+ * },
313
+ * },
314
+ * ]
315
+ * ```
316
+ */
317
+ function flexRenderComponent(component, options) {
318
+ const { inputs, injector, outputs, directives, bindings } = options ?? {};
319
+ return new FlexRenderComponentInstance(component, inputs, injector, outputs, directives, bindings);
320
+ }
321
+ /**
322
+ * Wrapper class for a component that will be used as content for {@link FlexRenderDirective}
323
+ *
324
+ * Prefer {@link flexRenderComponent} helper for better type-safety
325
+ */
326
+ class FlexRenderComponentInstance {
327
+ component;
328
+ inputs;
329
+ injector;
330
+ outputs;
331
+ directives;
332
+ bindings;
333
+ mirror;
334
+ allowedInputNames = [];
335
+ allowedOutputNames = [];
336
+ constructor(component, inputs, injector, outputs, directives, bindings) {
337
+ this.component = component;
338
+ this.inputs = inputs;
339
+ this.injector = injector;
340
+ this.outputs = outputs;
341
+ this.directives = directives;
342
+ this.bindings = bindings;
343
+ const mirror = reflectComponentType(component);
344
+ if (!mirror) {
345
+ throw new Error(`[@tanstack-table/angular] The provided symbol is not a component`);
15
346
  }
16
- };
17
- queueMicrotask(() => initializeObject());
18
- const table = () => { };
19
- return new Proxy(table, {
20
- apply(target, thisArg, argArray) {
21
- initializeObject();
22
- if (typeof object === 'function') {
23
- return Reflect.apply(object, thisArg, argArray);
24
- }
25
- return Reflect.apply(target, thisArg, argArray);
26
- },
27
- get(_, prop, receiver) {
28
- initializeObject();
29
- return Reflect.get(object, prop, receiver);
30
- },
31
- has(_, prop) {
32
- initializeObject();
33
- return Reflect.has(object, prop);
34
- },
35
- ownKeys() {
36
- initializeObject();
37
- return Reflect.ownKeys(object);
38
- },
39
- getOwnPropertyDescriptor() {
40
- return {
41
- enumerable: true,
42
- configurable: true,
43
- };
44
- },
45
- });
347
+ this.mirror = mirror;
348
+ for (const input of this.mirror.inputs) {
349
+ this.allowedInputNames.push(input.propName);
350
+ }
351
+ for (const output of this.mirror.outputs) {
352
+ this.allowedOutputNames.push(output.propName);
353
+ }
354
+ }
46
355
  }
47
356
 
48
- function proxifyTable(tableSignal) {
49
- const internalState = tableSignal;
50
- return new Proxy(internalState, {
51
- apply() {
52
- return tableSignal();
53
- },
54
- get(target, property) {
55
- if (target[property]) {
56
- return target[property];
357
+ function mapToFlexRenderTypedContent(content) {
358
+ if (content === null || content === undefined) {
359
+ return { kind: 'null' };
360
+ }
361
+ if (typeof content === 'string' || typeof content === 'number') {
362
+ return { kind: 'primitive', content };
363
+ }
364
+ if (content instanceof FlexRenderComponentInstance) {
365
+ return { kind: 'flexRenderComponent', content };
366
+ }
367
+ else if (content instanceof TemplateRef) {
368
+ return { kind: 'templateRef', content };
369
+ }
370
+ else if (content instanceof Type) {
371
+ return { kind: 'component', content };
372
+ }
373
+ else {
374
+ return { kind: 'primitive', content };
375
+ }
376
+ }
377
+ class FlexRenderView {
378
+ view;
379
+ #previousContent;
380
+ #content;
381
+ constructor(initialContent, view) {
382
+ this.#content = initialContent;
383
+ this.view = view;
384
+ }
385
+ get previousContent() {
386
+ return this.#previousContent ?? { kind: 'null' };
387
+ }
388
+ get content() {
389
+ return this.#content;
390
+ }
391
+ set content(content) {
392
+ this.#previousContent = this.#content;
393
+ this.#content = content;
394
+ }
395
+ }
396
+ class FlexRenderTemplateView extends FlexRenderView {
397
+ constructor(initialContent, view) {
398
+ super(initialContent, view);
399
+ }
400
+ updateProps(props) {
401
+ this.view.markForCheck();
402
+ }
403
+ dirtyCheck() {
404
+ // Basically a no-op. When the view is created via EmbeddedViewRef, we don't need to do any manual update
405
+ // since this type of content has a proxy as a context, then every time the root component is checked for changes,
406
+ // the property getter will be re-evaluated.
407
+ //
408
+ // If in a future we need to manually mark the view as dirty, just uncomment next line
409
+ // this.view.markForCheck()
410
+ }
411
+ unmount() {
412
+ this.view.destroy();
413
+ }
414
+ onDestroy(callback) {
415
+ this.view.onDestroy(callback);
416
+ }
417
+ }
418
+ class FlexRenderComponentView extends FlexRenderView {
419
+ constructor(initialContent, view) {
420
+ super(initialContent, view);
421
+ }
422
+ updateProps(props) {
423
+ switch (this.content.kind) {
424
+ case 'component': {
425
+ this.view.setInputs(props);
426
+ break;
427
+ }
428
+ case 'flexRenderComponent': {
429
+ // No-op. When FlexRenderFlags.PropsReferenceChanged is set,
430
+ // FlexRenderComponent will be updated into `dirtyCheck`.
431
+ break;
432
+ }
433
+ }
434
+ }
435
+ dirtyCheck() {
436
+ switch (this.content.kind) {
437
+ case 'component': {
438
+ // Component context is currently valuated with the cell context. Since it's reference
439
+ // shouldn't change, we force mark the component as dirty in order to re-evaluate function invocation in view.
440
+ // NOTE: this should behave like having a component with ChangeDetectionStrategy.Default
441
+ this.view.markAsDirty();
442
+ break;
57
443
  }
58
- const table = untracked(tableSignal);
59
- /**
60
- * Attempt to convert all accessors into computed ones,
61
- * excluding handlers as they do not retain any reactive value
62
- */
63
- if (property.startsWith('get') &&
64
- !property.endsWith('Handler') &&
65
- !property.endsWith('Model')) {
66
- const maybeFn = table[property];
67
- if (typeof maybeFn === 'function') {
68
- Object.defineProperty(target, property, {
69
- value: toComputed(tableSignal, maybeFn),
70
- configurable: true,
71
- enumerable: true,
72
- });
73
- return target[property];
444
+ case 'flexRenderComponent': {
445
+ // Given context instance will always have a different reference than the previous one,
446
+ // so instead of recreating the entire view, we will only update the current view
447
+ if (this.view.eqType(this.content.content)) {
448
+ this.view.update(this.content.content);
74
449
  }
450
+ this.view.markAsDirty();
451
+ break;
75
452
  }
76
- // @ts-expect-error
77
- return (target[property] = table[property]);
78
- },
79
- has(_, prop) {
80
- return !!untracked(tableSignal)[prop];
81
- },
82
- ownKeys() {
83
- return Reflect.ownKeys(untracked(tableSignal));
84
- },
85
- getOwnPropertyDescriptor() {
86
- return {
87
- enumerable: true,
88
- configurable: true,
89
- };
90
- },
91
- });
453
+ }
454
+ }
455
+ unmount() {
456
+ this.view.componentRef.destroy();
457
+ }
458
+ onDestroy(callback) {
459
+ this.view.componentRef.onDestroy(callback);
460
+ }
92
461
  }
93
- /**
94
- * Here we'll handle all type of accessors:
95
- * - 0 argument -> e.g. table.getCanNextPage())
96
- * - 0~1 arguments -> e.g. table.getIsSomeRowsPinned(position?)
97
- * - 1 required argument -> e.g. table.getColumn(columnId)
98
- * - 1+ argument -> e.g. table.getRow(id, searchAll?)
99
- *
100
- * Since we are not able to detect automatically the accessors parameters,
101
- * we'll wrap all accessors into a cached function wrapping a computed
102
- * that return it's value based on the given parameters
103
- */
104
- function toComputed(signal, fn) {
105
- const hasArgs = fn.length > 0;
106
- if (!hasArgs) {
107
- return computed(() => {
108
- void signal();
109
- return fn();
462
+
463
+ class FlexRenderComponentFactory {
464
+ #viewContainerRef;
465
+ constructor(viewContainerRef) {
466
+ this.#viewContainerRef = viewContainerRef;
467
+ }
468
+ createComponent(flexRenderComponent, componentInjector) {
469
+ const componentRef = this.#viewContainerRef.createComponent(flexRenderComponent.component, {
470
+ injector: componentInjector,
471
+ directives: flexRenderComponent.directives,
472
+ bindings: flexRenderComponent.bindings ?? [],
110
473
  });
474
+ const view = new FlexRenderComponentRef(componentRef, flexRenderComponent, componentInjector);
475
+ const { inputs, outputs } = flexRenderComponent;
476
+ if (inputs)
477
+ view.setInputs(inputs);
478
+ if (outputs)
479
+ view.setOutputs(outputs);
480
+ return view;
111
481
  }
112
- const computedCache = {};
113
- return (...argsArray) => {
114
- const serializedArgs = serializeArgs(...argsArray);
115
- if (computedCache.hasOwnProperty(serializedArgs)) {
116
- return computedCache[serializedArgs]?.();
482
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FlexRenderComponentFactory, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Injectable });
483
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FlexRenderComponentFactory });
484
+ }
485
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FlexRenderComponentFactory, decorators: [{
486
+ type: Injectable
487
+ }], ctorParameters: () => [{ type: i0.ViewContainerRef }] });
488
+ class FlexRenderComponentRef {
489
+ componentRef;
490
+ componentInjector;
491
+ #keyValueDiffersFactory;
492
+ #componentData;
493
+ #inputValueDiffer;
494
+ #outputRegistry;
495
+ constructor(componentRef, componentData, componentInjector) {
496
+ this.componentRef = componentRef;
497
+ this.componentInjector = componentInjector;
498
+ this.#componentData = componentData;
499
+ this.#keyValueDiffersFactory = componentInjector.get(KeyValueDiffers);
500
+ this.#outputRegistry = new FlexRenderComponentOutputManager(this.#keyValueDiffersFactory, this.outputs);
501
+ this.#inputValueDiffer = this.#keyValueDiffersFactory
502
+ .find(this.inputs)
503
+ .create();
504
+ this.#inputValueDiffer.diff(this.inputs);
505
+ this.componentRef.onDestroy(() => this.#outputRegistry.unsubscribeAll());
506
+ }
507
+ get component() {
508
+ return this.#componentData.component;
509
+ }
510
+ get inputs() {
511
+ return this.#componentData.inputs ?? {};
512
+ }
513
+ get outputs() {
514
+ return this.#componentData.outputs ?? {};
515
+ }
516
+ /**
517
+ * Get component input and output diff by the given item
518
+ */
519
+ diff(item) {
520
+ return {
521
+ inputDiff: this.#inputValueDiffer.diff(item.inputs ?? {}),
522
+ outputDiff: this.#outputRegistry.diff(item.outputs ?? {}),
523
+ };
524
+ }
525
+ /**
526
+ *
527
+ * @param compare Whether the current ref component instance is the same as the given one
528
+ */
529
+ eqType(compare) {
530
+ return compare.component === this.component;
531
+ }
532
+ /**
533
+ * Tries to update current component refs input by the new given content component.
534
+ */
535
+ update(content) {
536
+ const eq = this.eqType(content);
537
+ if (!eq)
538
+ return;
539
+ const { inputDiff, outputDiff } = this.diff(content);
540
+ if (inputDiff) {
541
+ inputDiff.forEachAddedItem((item) => this.setInput(item.key, item.currentValue));
542
+ inputDiff.forEachChangedItem((item) => this.setInput(item.key, item.currentValue));
543
+ inputDiff.forEachRemovedItem((item) => this.setInput(item.key, undefined));
117
544
  }
118
- const computedSignal = computed(() => {
119
- void signal();
120
- return fn(...argsArray);
121
- });
122
- computedCache[serializedArgs] = computedSignal;
123
- return computedSignal();
124
- };
545
+ if (outputDiff) {
546
+ outputDiff.forEachAddedItem((item) => {
547
+ this.setOutput(item.key, item.currentValue);
548
+ });
549
+ outputDiff.forEachChangedItem((item) => {
550
+ if (item.currentValue) {
551
+ this.#outputRegistry.setListener(item.key, item.currentValue);
552
+ }
553
+ else {
554
+ this.#outputRegistry.unsubscribe(item.key);
555
+ }
556
+ });
557
+ outputDiff.forEachRemovedItem((item) => {
558
+ this.#outputRegistry.unsubscribe(item.key);
559
+ });
560
+ }
561
+ this.#componentData = content;
562
+ }
563
+ markAsDirty() {
564
+ this.componentRef.injector.get(ChangeDetectorRef).markForCheck();
565
+ }
566
+ setInputs(inputs) {
567
+ for (const prop in inputs) {
568
+ this.setInput(prop, inputs[prop]);
569
+ }
570
+ }
571
+ setInput(key, value) {
572
+ if (this.#componentData.allowedInputNames.includes(key)) {
573
+ this.componentRef.setInput(key, value);
574
+ }
575
+ }
576
+ setOutputs(outputs) {
577
+ this.#outputRegistry.unsubscribeAll();
578
+ for (const prop in outputs) {
579
+ this.setOutput(prop, outputs[prop]);
580
+ }
581
+ }
582
+ setOutput(outputName, emit) {
583
+ if (!this.#componentData.allowedOutputNames.includes(outputName))
584
+ return;
585
+ if (!emit) {
586
+ this.#outputRegistry.unsubscribe(outputName);
587
+ return;
588
+ }
589
+ const hasListener = this.#outputRegistry.hasListener(outputName);
590
+ this.#outputRegistry.setListener(outputName, emit);
591
+ if (hasListener) {
592
+ return;
593
+ }
594
+ const instance = this.componentRef.instance;
595
+ const output = instance[outputName];
596
+ if (output && output instanceof OutputEmitterRef) {
597
+ output.subscribe((value) => {
598
+ this.#outputRegistry.getListener(outputName)?.(value);
599
+ });
600
+ }
601
+ }
125
602
  }
126
- function serializeArgs(...args) {
127
- return JSON.stringify(args);
603
+ class FlexRenderComponentOutputManager {
604
+ #outputSubscribers = {};
605
+ #outputListeners = {};
606
+ #valueDiffer;
607
+ constructor(keyValueDiffers, initialOutputs) {
608
+ this.#valueDiffer = keyValueDiffers.find(initialOutputs).create();
609
+ if (initialOutputs) {
610
+ this.#valueDiffer.diff(initialOutputs);
611
+ }
612
+ }
613
+ hasListener(outputName) {
614
+ return outputName in this.#outputListeners;
615
+ }
616
+ setListener(outputName, callback) {
617
+ this.#outputListeners[outputName] = callback;
618
+ }
619
+ getListener(outputName) {
620
+ return this.#outputListeners[outputName];
621
+ }
622
+ unsubscribeAll() {
623
+ for (const prop in this.#outputSubscribers) {
624
+ this.unsubscribe(prop);
625
+ }
626
+ }
627
+ unsubscribe(outputName) {
628
+ if (outputName in this.#outputSubscribers) {
629
+ this.#outputSubscribers[outputName]?.unsubscribe();
630
+ delete this.#outputSubscribers[outputName];
631
+ delete this.#outputListeners[outputName];
632
+ }
633
+ }
634
+ diff(outputs) {
635
+ return this.#valueDiffer.diff(outputs ?? {});
636
+ }
128
637
  }
129
638
 
130
- class FlexRenderDirective {
131
- viewContainerRef;
132
- templateRef;
133
- content = undefined;
134
- props = {};
135
- injector = inject(Injector);
136
- constructor(viewContainerRef, templateRef) {
137
- this.viewContainerRef = viewContainerRef;
138
- this.templateRef = templateRef;
139
- }
140
- ref = null;
141
- ngOnChanges(changes) {
142
- if (this.ref instanceof ComponentRef) {
143
- this.ref.injector.get(ChangeDetectorRef).markForCheck();
144
- }
145
- if (!changes['content']) {
146
- return;
639
+ /**
640
+ * Internal view renderer used by Angular TanStack Table to implement `flexRender` directives.
641
+ *
642
+ * @internal Use FlexRender directives instead.
643
+ */
644
+ class FlexViewRenderer {
645
+ #renderFlags = FlexRenderFlags.ViewFirstRender;
646
+ #renderView = null;
647
+ #currentRenderEffectRef = null;
648
+ #content;
649
+ #props;
650
+ #injector;
651
+ #viewContainerRef;
652
+ #templateRef;
653
+ #flexRenderComponentFactory;
654
+ #getLatestContentValue = () => {
655
+ const content = this.#content();
656
+ const props = this.#props();
657
+ return typeof content !== 'function'
658
+ ? content
659
+ : runInInjectionContext(this.#injector(), () => content(props));
660
+ };
661
+ #latestContent = computed(() => this.#getLatestContentValue(), ...(ngDevMode ? [{ debugName: "#latestContent" }] : []));
662
+ #getContentValue = computed(() => {
663
+ const latestContent = this.#latestContent();
664
+ return mapToFlexRenderTypedContent(latestContent);
665
+ }, ...(ngDevMode ? [{ debugName: "#getContentValue" }] : []));
666
+ constructor(options) {
667
+ this.#content = options.content;
668
+ this.#props = options.props;
669
+ this.#injector = options.injector;
670
+ this.#templateRef = options.templateRef;
671
+ this.#viewContainerRef = options.viewContainerRef;
672
+ this.#flexRenderComponentFactory = new FlexRenderComponentFactory(this.#viewContainerRef);
673
+ }
674
+ mount() {
675
+ let previousContent;
676
+ let previousProps;
677
+ return effect(() => {
678
+ const props = this.#props();
679
+ const content = this.#content();
680
+ if (!(this.#renderFlags & FlexRenderFlags.ViewFirstRender)) {
681
+ if (previousContent !== content) {
682
+ this.#renderFlags |= FlexRenderFlags.ContentChanged;
683
+ }
684
+ if (previousProps !== props) {
685
+ this.#renderFlags |= FlexRenderFlags.PropsReferenceChanged;
686
+ }
687
+ }
688
+ untracked(() => this.#update());
689
+ if (FlexRenderFlags.ViewFirstRender & this.#renderFlags) {
690
+ this.#renderFlags &= ~FlexRenderFlags.ViewFirstRender;
691
+ }
692
+ previousContent = content;
693
+ previousProps = props;
694
+ });
695
+ }
696
+ destroy() {
697
+ if (this.#currentRenderEffectRef) {
698
+ this.#currentRenderEffectRef.destroy();
699
+ this.#currentRenderEffectRef = null;
700
+ }
701
+ if (this.#renderView) {
702
+ this.#renderView.unmount();
703
+ this.#renderView = null;
147
704
  }
148
- this.render();
149
705
  }
150
- render() {
151
- this.viewContainerRef.clear();
152
- const { content, props } = this;
153
- if (content === null || content === undefined) {
154
- this.ref = null;
706
+ #update() {
707
+ if (this.#renderFlags &
708
+ (FlexRenderFlags.ContentChanged | FlexRenderFlags.ViewFirstRender)) {
709
+ this.#render();
155
710
  return;
156
711
  }
157
- if (typeof content === 'function') {
158
- return this.renderContent(content(props));
712
+ if (this.#renderFlags & FlexRenderFlags.PropsReferenceChanged) {
713
+ if (this.#renderView)
714
+ this.#renderView.updateProps(this.#props());
715
+ this.#renderFlags &= ~FlexRenderFlags.PropsReferenceChanged;
716
+ }
717
+ if (this.#renderFlags & FlexRenderFlags.Dirty) {
718
+ if (this.#renderView)
719
+ this.#renderView.dirtyCheck();
720
+ this.#renderFlags &= ~FlexRenderFlags.Dirty;
721
+ }
722
+ }
723
+ #render() {
724
+ // When the view is recreated from scratch (content change or first render),
725
+ // we have to destroy the current effect listener since it will be recreated
726
+ // skipping the first call (FlexRenderFlags.RenderEffectChecked)
727
+ if (this.#shouldRecreateEntireView() && this.#currentRenderEffectRef) {
728
+ this.#currentRenderEffectRef.destroy();
729
+ this.#currentRenderEffectRef = null;
730
+ this.#renderFlags &= ~FlexRenderFlags.RenderEffectChecked;
731
+ }
732
+ this.#viewContainerRef.clear();
733
+ if (this.#renderView) {
734
+ this.#renderView.unmount();
735
+ this.#renderView = null;
736
+ }
737
+ this.#renderFlags =
738
+ (this.#renderFlags & FlexRenderFlags.ViewFirstRender) |
739
+ (this.#renderFlags & FlexRenderFlags.RenderEffectChecked);
740
+ const resolvedContent = this.#getContentValue();
741
+ this.#renderView = this.#renderViewByContent(resolvedContent);
742
+ // If the content is a function `content(props)`, we initialize an effect
743
+ // to react to changes. If the current fn uses signals, we will set the DirtySignal flag
744
+ // to re-schedule the component updates
745
+ if (!this.#currentRenderEffectRef &&
746
+ typeof untracked(this.#content) === 'function') {
747
+ this.#currentRenderEffectRef = effect(() => {
748
+ this.#latestContent();
749
+ if (!(this.#renderFlags & FlexRenderFlags.RenderEffectChecked)) {
750
+ this.#renderFlags |= FlexRenderFlags.RenderEffectChecked;
751
+ return;
752
+ }
753
+ this.#renderFlags |= FlexRenderFlags.Dirty;
754
+ this.#doCheck();
755
+ }, { ...(ngDevMode ? { debugName: "#currentRenderEffectRef" } : {}), injector: this.#viewContainerRef.injector });
756
+ }
757
+ }
758
+ #shouldRecreateEntireView() {
759
+ return (this.#renderFlags &
760
+ FlexRenderFlags.ContentChanged &
761
+ FlexRenderFlags.ViewFirstRender);
762
+ }
763
+ #doCheck() {
764
+ const latestContent = this.#getContentValue();
765
+ if (latestContent.kind === 'null' || !this.#renderView) {
766
+ this.#renderFlags |= FlexRenderFlags.ContentChanged;
159
767
  }
160
768
  else {
161
- return this.renderContent(content);
769
+ this.#renderView.content = latestContent;
770
+ const { kind: previousKind } = this.#renderView.previousContent;
771
+ if (latestContent.kind !== previousKind) {
772
+ this.#renderFlags |= FlexRenderFlags.ContentChanged;
773
+ }
162
774
  }
775
+ this.#update();
163
776
  }
164
- renderContent(content) {
165
- if (typeof content === 'string' || typeof content === 'number') {
166
- return this.renderStringContent();
777
+ #renderViewByContent(content) {
778
+ if (content.kind === 'primitive') {
779
+ return this.#renderStringContent(content);
167
780
  }
168
- if (content instanceof TemplateRef) {
169
- return this.viewContainerRef.createEmbeddedView(content, this.getTemplateRefContext());
781
+ else if (content.kind === 'templateRef') {
782
+ return this.#renderTemplateRefContent(content);
170
783
  }
171
- else if (content instanceof FlexRenderComponent) {
172
- return this.renderComponent(content);
784
+ else if (content.kind === 'flexRenderComponent') {
785
+ return this.#renderComponent(content);
173
786
  }
174
- else if (content instanceof Type) {
175
- return this.renderCustomComponent(content);
787
+ else if (content.kind === 'component') {
788
+ return this.#renderCustomComponent(content);
176
789
  }
177
790
  else {
178
791
  return null;
179
792
  }
180
793
  }
181
- renderStringContent() {
794
+ #renderStringContent(template) {
182
795
  const context = () => {
183
- return typeof this.content === 'string' ||
184
- typeof this.content === 'number'
185
- ? this.content
186
- : this.content?.(this.props);
796
+ const content = this.#content();
797
+ return typeof content === 'string' || typeof content === 'number'
798
+ ? content
799
+ : runInInjectionContext(this.#injector(), () => content?.(this.#props()));
187
800
  };
188
- return this.viewContainerRef.createEmbeddedView(this.templateRef, {
801
+ const ref = this.#viewContainerRef.createEmbeddedView(this.#templateRef, {
189
802
  get $implicit() {
190
803
  return context();
191
804
  },
192
805
  });
806
+ return new FlexRenderTemplateView(template, ref);
193
807
  }
194
- renderComponent(flexRenderComponent) {
195
- const { component, inputs, injector } = flexRenderComponent;
196
- const getContext = () => this.props;
197
- const proxy = new Proxy(this.props, {
198
- get: (_, key) => getContext()?.[key],
808
+ #renderTemplateRefContent(template) {
809
+ const latestContext = () => this.#props();
810
+ const view = this.#viewContainerRef.createEmbeddedView(template.content, {
811
+ get $implicit() {
812
+ return latestContext();
813
+ },
814
+ }, { injector: this.#getInjector() });
815
+ return new FlexRenderTemplateView(template, view);
816
+ }
817
+ #renderComponent(flexRenderComponent) {
818
+ const { injector } = flexRenderComponent.content;
819
+ const componentInjector = this.#getInjector(injector);
820
+ const view = this.#flexRenderComponentFactory.createComponent(flexRenderComponent.content, componentInjector);
821
+ return new FlexRenderComponentView(flexRenderComponent, view);
822
+ }
823
+ #renderCustomComponent(component) {
824
+ const instance = flexRenderComponent(component.content, {
825
+ inputs: this.#props(),
199
826
  });
200
- const componentInjector = Injector.create({
201
- parent: injector ?? this.injector,
202
- providers: [{ provide: FlexRenderComponentProps, useValue: proxy }],
827
+ const injector = this.#getInjector(instance.injector);
828
+ const view = this.#flexRenderComponentFactory.createComponent(instance, injector);
829
+ return new FlexRenderComponentView(component, view);
830
+ }
831
+ #getInjector(parentInjector) {
832
+ const getContext = () => this.#props();
833
+ const proxy = new Proxy(this.#props(), {
834
+ get: (_, key) => getContext()[key],
203
835
  });
204
- const componentRef = this.viewContainerRef.createComponent(component, {
205
- injector: componentInjector,
836
+ const staticProviders = [];
837
+ if ('table' in proxy) {
838
+ staticProviders.push({
839
+ provide: TanStackTableToken,
840
+ useValue: () => proxy.table,
841
+ });
842
+ }
843
+ if ('cell' in proxy) {
844
+ staticProviders.push({
845
+ provide: TanStackTableCellToken,
846
+ useValue: () => proxy.cell,
847
+ });
848
+ }
849
+ if ('header' in proxy) {
850
+ staticProviders.push({
851
+ provide: TanStackTableHeaderToken,
852
+ useValue: () => proxy.header,
853
+ });
854
+ }
855
+ return Injector.create({
856
+ parent: parentInjector ?? this.#injector(),
857
+ providers: [
858
+ ...staticProviders,
859
+ { provide: FlexRenderComponentProps, useValue: proxy },
860
+ ],
206
861
  });
207
- for (const prop in inputs) {
208
- if (componentRef.instance?.hasOwnProperty(prop)) {
209
- componentRef.setInput(prop, inputs[prop]);
210
- }
862
+ }
863
+ }
864
+
865
+ /**
866
+ * Simplified directive wrapper of `*flexRender`.
867
+ *
868
+ * Use this utility component to render headers, cells, or footers with custom markup.
869
+ *
870
+ * Only one prop (`cell`, `header`, or `footer`) may be passed based on the used selector.
871
+ *
872
+ * @example
873
+ * ```html
874
+ * <td *flexRenderCell="cell; let cell">{{cell}}</td>
875
+ * <th *flexRenderHeader="header; let header">{{header}}</th>
876
+ * <th *flexRenderFooter="footer; let footer">{{footer}}</th>
877
+ * ```
878
+ *
879
+ * This replaces calling `*flexRender` directly like this:
880
+ * ```html
881
+ * <td *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let cell">{{cell}}</td>
882
+ * <td *flexRender="header.column.columnDef.header; props: header.getContext(); let header">{{header}}</td>
883
+ * <td *flexRender="footer.column.columnDef.footer; props: footer.getContext(); let footer">{{footer}}</td>
884
+ * ```
885
+ *
886
+ * Can be imported through {@link FlexRenderCell} or {@link FlexRender} import,
887
+ * which the latter is preferred.
888
+ *
889
+ * @example
890
+ * ```ts
891
+ * import {FlexRender} from '@tanstack/angular-table
892
+ *
893
+ * @Component({
894
+ * // ...
895
+ * imports: [
896
+ * FlexRender
897
+ * ]
898
+ * })
899
+ * ```
900
+ */
901
+ class FlexRenderCell {
902
+ cell = input(undefined, { ...(ngDevMode ? { debugName: "cell" } : {}), alias: 'flexRenderCell' });
903
+ header = input(undefined, { ...(ngDevMode ? { debugName: "header" } : {}), alias: 'flexRenderHeader' });
904
+ footer = input(undefined, { ...(ngDevMode ? { debugName: "footer" } : {}), alias: 'flexRenderFooter' });
905
+ #renderData = computed(() => {
906
+ const cell = this.cell();
907
+ const header = this.header();
908
+ const footer = this.footer();
909
+ if (cell) {
910
+ return [cell.column.columnDef.cell, cell.getContext()];
211
911
  }
212
- return componentRef;
912
+ if (header) {
913
+ return [header.column.columnDef.header, header.getContext()];
914
+ }
915
+ if (footer) {
916
+ return [footer.column.columnDef.footer, footer.getContext()];
917
+ }
918
+ return [null, null];
919
+ }, { ...(ngDevMode ? { debugName: "#renderData" } : {}), equal: (a, b) => {
920
+ return a[0] === b[0] && a[1] === b[1];
921
+ } });
922
+ #injector = inject(Injector);
923
+ #templateRef = inject(TemplateRef);
924
+ #viewContainerRef = inject(ViewContainerRef);
925
+ constructor() {
926
+ const content = computed(() => this.#renderData()[0], ...(ngDevMode ? [{ debugName: "content" }] : []));
927
+ const props = computed(() => this.#renderData()[1], ...(ngDevMode ? [{ debugName: "props" }] : []));
928
+ const renderer = new FlexViewRenderer({
929
+ content: content,
930
+ props: props,
931
+ injector: () => this.#injector,
932
+ templateRef: this.#templateRef,
933
+ viewContainerRef: this.#viewContainerRef,
934
+ });
935
+ renderer.mount();
936
+ inject(DestroyRef).onDestroy(() => {
937
+ renderer.destroy();
938
+ });
213
939
  }
214
- renderCustomComponent(component) {
215
- const componentRef = this.viewContainerRef.createComponent(component, {
940
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FlexRenderCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
941
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: FlexRenderCell, isStandalone: true, selector: "ng-template[flexRenderCell], ng-template[flexRenderFooter], ng-template[flexRenderHeader]", inputs: { cell: { classPropertyName: "cell", publicName: "flexRenderCell", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "flexRenderHeader", isSignal: true, isRequired: false, transformFunction: null }, footer: { classPropertyName: "footer", publicName: "flexRenderFooter", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
942
+ }
943
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FlexRenderCell, decorators: [{
944
+ type: Directive,
945
+ args: [{
946
+ selector: 'ng-template[flexRenderCell], ng-template[flexRenderFooter], ng-template[flexRenderHeader]',
947
+ }]
948
+ }], ctorParameters: () => [], propDecorators: { cell: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexRenderCell", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexRenderHeader", required: false }] }], footer: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexRenderFooter", required: false }] }] } });
949
+
950
+ /**
951
+ * Use this utility directive to render headers, cells, or footers with custom markup.
952
+ *
953
+ * Note: If you are rendering cell, header, or footer without custom context or other props,
954
+ * you can use the {@link FlexRenderCell} directive as shorthand instead .
955
+ *
956
+ * @example
957
+ * ```ts
958
+ * import {FlexRender} from '@tanstack/angular-table';
959
+ *
960
+ * @Component({
961
+ * imports: [FlexRender],
962
+ * template: `
963
+ * <td
964
+ * *flexRender="
965
+ * cell.column.columnDef.cell;
966
+ * props: cell.getContext();
967
+ * let cell"
968
+ * >
969
+ * {{cell}}
970
+ * </td>
971
+ *
972
+ * <th
973
+ * *flexRender="
974
+ * header.column.columnDef.header;
975
+ * props: header.getContext();
976
+ * let header"
977
+ * >
978
+ * {{header}}
979
+ * </td>
980
+ *
981
+ * <td
982
+ * *flexRender="
983
+ * footer.column.columnDef.footer;
984
+ * props: footer.getContext();
985
+ * let footer"
986
+ * >
987
+ * {{footer}}
988
+ * </td>
989
+ * `,
990
+ * })
991
+ * class App {
992
+ * }
993
+ * ```
994
+ *
995
+ * Can be imported through {@link FlexRenderDirective} or {@link FlexRender} import,
996
+ * which the latter is preferred.
997
+ */
998
+ class FlexRenderDirective {
999
+ content = input(undefined, { ...(ngDevMode ? { debugName: "content" } : {}), alias: 'flexRender' });
1000
+ props = input({}, { ...(ngDevMode ? { debugName: "props" } : {}), alias: 'flexRenderProps' });
1001
+ injector = input(inject(Injector), { ...(ngDevMode ? { debugName: "injector" } : {}), alias: 'flexRenderInjector' });
1002
+ #viewContainerRef = inject(ViewContainerRef);
1003
+ #templateRef = inject(TemplateRef);
1004
+ constructor() {
1005
+ const renderer = new FlexViewRenderer({
1006
+ content: this.content,
1007
+ props: this.props,
216
1008
  injector: this.injector,
1009
+ templateRef: this.#templateRef,
1010
+ viewContainerRef: this.#viewContainerRef,
1011
+ });
1012
+ renderer.mount();
1013
+ inject(DestroyRef).onDestroy(() => {
1014
+ renderer.destroy();
217
1015
  });
218
- for (const prop in this.props) {
219
- // Only signal based input can be added here
220
- if (componentRef.instance?.hasOwnProperty(prop) &&
221
- // @ts-ignore
222
- isSignal(componentRef.instance[prop])) {
223
- componentRef.setInput(prop, this.props[prop]);
224
- }
225
- }
226
- return componentRef;
227
- }
228
- getTemplateRefContext() {
229
- const getContext = () => this.props;
230
- return {
231
- get $implicit() {
232
- return getContext();
233
- },
234
- };
235
1016
  }
236
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: FlexRenderDirective, deps: [{ token: ViewContainerRef }, { token: TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
237
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.5", type: FlexRenderDirective, isStandalone: true, selector: "[flexRender]", inputs: { content: ["flexRender", "content"], props: ["flexRenderProps", "props"], injector: ["flexRenderInjector", "injector"] }, usesOnChanges: true, ngImport: i0 });
1017
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FlexRenderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1018
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.1", type: FlexRenderDirective, isStandalone: true, selector: "ng-template[flexRender]", inputs: { content: { classPropertyName: "content", publicName: "flexRender", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "flexRenderProps", isSignal: true, isRequired: false, transformFunction: null }, injector: { classPropertyName: "injector", publicName: "flexRenderInjector", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
238
1019
  }
239
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.5", ngImport: i0, type: FlexRenderDirective, decorators: [{
1020
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: FlexRenderDirective, decorators: [{
240
1021
  type: Directive,
241
1022
  args: [{
242
- selector: '[flexRender]',
243
- standalone: true,
1023
+ selector: 'ng-template[flexRender]',
244
1024
  }]
245
- }], ctorParameters: () => [{ type: i0.ViewContainerRef, decorators: [{
246
- type: Inject,
247
- args: [ViewContainerRef]
248
- }] }, { type: i0.TemplateRef, decorators: [{
249
- type: Inject,
250
- args: [TemplateRef]
251
- }] }], propDecorators: { content: [{
252
- type: Input,
253
- args: [{ required: true, alias: 'flexRender' }]
254
- }], props: [{
255
- type: Input,
256
- args: [{ required: true, alias: 'flexRenderProps' }]
257
- }], injector: [{
258
- type: Input,
259
- args: [{ required: false, alias: 'flexRenderInjector' }]
260
- }] } });
261
- class FlexRenderComponent {
262
- component;
263
- inputs;
264
- injector;
265
- constructor(component, inputs = {}, injector) {
266
- this.component = component;
267
- this.inputs = inputs;
268
- this.injector = injector;
1025
+ }], ctorParameters: () => [], propDecorators: { content: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexRender", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexRenderProps", required: false }] }], injector: [{ type: i0.Input, args: [{ isSignal: true, alias: "flexRenderInjector", required: false }] }] } });
1026
+
1027
+ const $TABLE_REACTIVE = Symbol('reactive');
1028
+ function markReactive(obj) {
1029
+ Object.defineProperty(obj, $TABLE_REACTIVE, { value: true });
1030
+ }
1031
+ function isReactive(obj) {
1032
+ return Reflect.get(obj, $TABLE_REACTIVE) === true;
1033
+ }
1034
+ /**
1035
+ * Defines a lazy computed property on an object. The property is initialized
1036
+ * with a getter that computes its value only when accessed for the first time.
1037
+ * After the first access, the computed value is cached, and the getter is
1038
+ * replaced with a direct property assignment for efficiency.
1039
+ *
1040
+ * @internal should be used only internally
1041
+ */
1042
+ function defineLazyComputedProperty(notifier, setObjectOptions) {
1043
+ const { originalObject, property, overridePrototype, valueFn } = setObjectOptions;
1044
+ if (overridePrototype) {
1045
+ assignReactivePrototypeAPI(notifier, originalObject, property);
1046
+ }
1047
+ else {
1048
+ Object.defineProperty(originalObject, property, {
1049
+ enumerable: true,
1050
+ configurable: true,
1051
+ get() {
1052
+ const computedValue = toComputed(notifier, valueFn, property);
1053
+ markReactive(computedValue);
1054
+ // Once the property is set the first time, we don't need a getter anymore
1055
+ // since we have a computed / cached fn value
1056
+ Object.defineProperty(originalObject, property, {
1057
+ value: computedValue,
1058
+ configurable: true,
1059
+ enumerable: true,
1060
+ });
1061
+ return computedValue;
1062
+ },
1063
+ });
269
1064
  }
270
1065
  }
271
- const FlexRenderComponentProps = new InjectionToken('[@tanstack/angular-table] Flex render component context props');
272
- function injectFlexRenderContext() {
273
- return inject(FlexRenderComponentProps);
1066
+ /**
1067
+ * @description Transform a function into a computed that react to given notifier re-computations
1068
+ *
1069
+ * Here we'll handle all type of accessors:
1070
+ * - 0 argument -> e.g. table.getCanNextPage())
1071
+ * - 0~1 arguments -> e.g. table.getIsSomeRowsPinned(position?)
1072
+ * - 1 required argument -> e.g. table.getColumn(columnId)
1073
+ * - 1+ argument -> e.g. table.getRow(id, searchAll?)
1074
+ *
1075
+ * Since we are not able to detect automatically the accessors parameters,
1076
+ * we'll wrap all accessors into a cached function wrapping a computed
1077
+ * that return it's value based on the given parameters
1078
+ *
1079
+ * @internal should be used only internally
1080
+ */
1081
+ function toComputed(notifier, fn, debugName) {
1082
+ const hasArgs = getFnArgsLength(fn) > 0;
1083
+ if (!hasArgs) {
1084
+ const computedFn = computed(() => {
1085
+ void notifier();
1086
+ return fn();
1087
+ }, { ...(ngDevMode ? { debugName: "computedFn" } : {}), debugName });
1088
+ Object.defineProperty(computedFn, 'name', { value: debugName });
1089
+ markReactive(computedFn);
1090
+ return computedFn;
1091
+ }
1092
+ const computedFn = function (...argsArray) {
1093
+ const cacheable = argsArray.length === 0 ||
1094
+ argsArray.every((arg) => {
1095
+ return (arg === null ||
1096
+ arg === undefined ||
1097
+ typeof arg === 'string' ||
1098
+ typeof arg === 'number' ||
1099
+ typeof arg === 'boolean' ||
1100
+ typeof arg === 'symbol');
1101
+ });
1102
+ if (!cacheable) {
1103
+ return fn.apply(this, argsArray);
1104
+ }
1105
+ const serializedArgs = serializeArgs(...argsArray);
1106
+ if ((computedFn._reactiveCache ??= {})[serializedArgs]) {
1107
+ return computedFn._reactiveCache[serializedArgs]();
1108
+ }
1109
+ const computedSignal = computed(() => {
1110
+ void notifier();
1111
+ return fn.apply(this, argsArray);
1112
+ }, { ...(ngDevMode ? { debugName: "computedSignal" } : {}), debugName });
1113
+ computedFn._reactiveCache[serializedArgs] = computedSignal;
1114
+ return computedSignal();
1115
+ };
1116
+ Object.defineProperty(computedFn, 'name', { value: debugName });
1117
+ markReactive(computedFn);
1118
+ return computedFn;
1119
+ }
1120
+ function serializeArgs(...args) {
1121
+ return JSON.stringify(args);
1122
+ }
1123
+ function getFnArgsLength(fn) {
1124
+ return Math.max(0, getMemoFnMeta(fn)?.originalArgsLength ?? fn.length);
1125
+ }
1126
+ function assignReactivePrototypeAPI(notifier, prototype, fnName) {
1127
+ if (isReactive(prototype[fnName]))
1128
+ return;
1129
+ const fn = prototype[fnName];
1130
+ const originalArgsLength = getFnArgsLength(fn);
1131
+ if (originalArgsLength <= 1) {
1132
+ Object.defineProperty(prototype, fnName, {
1133
+ enumerable: true,
1134
+ configurable: true,
1135
+ get() {
1136
+ const self = this;
1137
+ // Create a cache in the current prototype to allow the signals
1138
+ // to be garbage collected. Shorthand for a WeakMap implementation
1139
+ self._reactiveCache ??= {};
1140
+ const cached = (self._reactiveCache[`${self.id}${fnName}`] ??= computed(() => {
1141
+ notifier();
1142
+ return fn.apply(self);
1143
+ }, {}));
1144
+ markReactive(cached);
1145
+ cached[$internalMemoFnMeta] = {
1146
+ originalArgsLength,
1147
+ };
1148
+ return cached;
1149
+ },
1150
+ });
1151
+ }
1152
+ else {
1153
+ prototype[fnName] = function (...args) {
1154
+ notifier();
1155
+ return fn.apply(this, args);
1156
+ };
1157
+ markReactive(prototype[fnName]);
1158
+ prototype[fnName][$internalMemoFnMeta] = {
1159
+ originalArgsLength,
1160
+ };
1161
+ }
1162
+ }
1163
+ function setReactivePropertiesOnObject(notifier, obj, options) {
1164
+ const { skipProperty } = options;
1165
+ if (isReactive(obj)) {
1166
+ return;
1167
+ }
1168
+ markReactive(obj);
1169
+ for (const property in obj) {
1170
+ const value = obj[property];
1171
+ if (isSignal(value) ||
1172
+ typeof value !== 'function' ||
1173
+ skipProperty(property)) {
1174
+ continue;
1175
+ }
1176
+ defineLazyComputedProperty(notifier, {
1177
+ valueFn: value,
1178
+ property,
1179
+ originalObject: obj,
1180
+ overridePrototype: options.overridePrototype,
1181
+ });
1182
+ }
1183
+ }
1184
+
1185
+ /**
1186
+ * Resolves the user-provided `reactivity.*` config to a skip predicate.
1187
+ *
1188
+ * - `false` is handled by callers (feature method returns early)
1189
+ * - `true` selects the default predicate
1190
+ * - a function overrides the default predicate
1191
+ */
1192
+ const getUserSkipPropertyFn = (value, defaultPropertyFn) => {
1193
+ if (typeof value === 'boolean') {
1194
+ return defaultPropertyFn;
1195
+ }
1196
+ return value ?? defaultPropertyFn;
1197
+ };
1198
+ function constructAngularReactivityFeature() {
1199
+ return {
1200
+ getDefaultTableOptions(table) {
1201
+ return {
1202
+ reactivity: {
1203
+ header: true,
1204
+ column: true,
1205
+ row: true,
1206
+ cell: true,
1207
+ },
1208
+ };
1209
+ },
1210
+ constructTableAPIs: (table) => {
1211
+ const rootNotifier = signal(null, ...(ngDevMode ? [{ debugName: "rootNotifier" }] : []));
1212
+ table.setTableNotifier = (notifier) => rootNotifier.set(notifier);
1213
+ table.get = computed(() => rootNotifier()(), { ...(ngDevMode ? { debugName: "get" } : {}), equal: () => false });
1214
+ setReactivePropertiesOnObject(table.get, table, {
1215
+ overridePrototype: false,
1216
+ skipProperty: skipBaseProperties,
1217
+ });
1218
+ },
1219
+ assignCellPrototype: (prototype, table) => {
1220
+ if (table.options.reactivity?.cell === false) {
1221
+ return;
1222
+ }
1223
+ setReactivePropertiesOnObject(table.get, prototype, {
1224
+ skipProperty: getUserSkipPropertyFn(table.options.reactivity?.cell, skipBaseProperties),
1225
+ overridePrototype: true,
1226
+ });
1227
+ },
1228
+ assignColumnPrototype: (prototype, table) => {
1229
+ if (table.options.reactivity?.column === false) {
1230
+ return;
1231
+ }
1232
+ setReactivePropertiesOnObject(table.get, prototype, {
1233
+ skipProperty: getUserSkipPropertyFn(table.options.reactivity?.cell, skipBaseProperties),
1234
+ overridePrototype: true,
1235
+ });
1236
+ },
1237
+ assignHeaderPrototype: (prototype, table) => {
1238
+ if (table.options.reactivity?.header === false) {
1239
+ return;
1240
+ }
1241
+ setReactivePropertiesOnObject(table.get, prototype, {
1242
+ skipProperty: getUserSkipPropertyFn(table.options.reactivity?.cell, skipBaseProperties),
1243
+ overridePrototype: true,
1244
+ });
1245
+ },
1246
+ assignRowPrototype: (prototype, table) => {
1247
+ if (table.options.reactivity?.row === false) {
1248
+ return;
1249
+ }
1250
+ setReactivePropertiesOnObject(table.get, prototype, {
1251
+ skipProperty: getUserSkipPropertyFn(table.options.reactivity?.cell, skipBaseProperties),
1252
+ overridePrototype: true,
1253
+ });
1254
+ },
1255
+ };
1256
+ }
1257
+ /**
1258
+ * Angular reactivity feature that add reactive signal supports in table core instance.
1259
+ * This is used internally by the Angular table adapter `injectTable`.
1260
+ *
1261
+ * @private
1262
+ */
1263
+ const angularReactivityFeature = constructAngularReactivityFeature();
1264
+ /**
1265
+ * Default predicate used to skip base/non-reactive properties.
1266
+ */
1267
+ function skipBaseProperties(property) {
1268
+ return (
1269
+ // equals `getContext`
1270
+ property === 'getContext' ||
1271
+ // start with `_`
1272
+ property[0] === '_' ||
1273
+ // doesn't start with `get`, but faster
1274
+ !(property[0] === 'g' && property[1] === 'e' && property[2] === 't') ||
1275
+ // ends with `Handler`
1276
+ property.endsWith('Handler'));
1277
+ }
1278
+
1279
+ /**
1280
+ * Implementation from @tanstack/angular-query
1281
+ * {https://github.com/TanStack/query/blob/main/packages/angular-query-experimental/src/util/lazy-init/lazy-init.ts}
1282
+ */
1283
+ function lazyInit(initializer) {
1284
+ let object = null;
1285
+ const initializeObject = () => {
1286
+ if (!object) {
1287
+ object = untracked(() => initializer());
1288
+ }
1289
+ };
1290
+ queueMicrotask(() => initializeObject());
1291
+ const table = () => { };
1292
+ return new Proxy(table, {
1293
+ apply(target, thisArg, argArray) {
1294
+ initializeObject();
1295
+ if (typeof object === 'function') {
1296
+ return Reflect.apply(object, thisArg, argArray);
1297
+ }
1298
+ return Reflect.apply(target, thisArg, argArray);
1299
+ },
1300
+ get(_, prop, receiver) {
1301
+ initializeObject();
1302
+ return Reflect.get(object, prop, receiver);
1303
+ },
1304
+ has(_, prop) {
1305
+ initializeObject();
1306
+ return Reflect.has(object, prop);
1307
+ },
1308
+ ownKeys() {
1309
+ initializeObject();
1310
+ return Reflect.ownKeys(object);
1311
+ },
1312
+ getOwnPropertyDescriptor() {
1313
+ return {
1314
+ enumerable: true,
1315
+ configurable: true,
1316
+ };
1317
+ },
1318
+ });
274
1319
  }
275
1320
 
276
- function injectTable(options) {
1321
+ /**
1322
+ * Creates and returns an Angular-reactive table instance.
1323
+ *
1324
+ * The initializer is intentionally re-evaluated whenever any signal read inside it changes.
1325
+ * This is how the adapter keeps the table in sync with Angular's reactivity model.
1326
+ *
1327
+ * Because of that behavior, keep expensive/static values (for example `columns`, feature setup, row models)
1328
+ * as stable references outside the initializer, and only read reactive state (`data()`, pagination/filter/sorting signals, etc.)
1329
+ * inside it.
1330
+ *
1331
+ * The returned table is also signal-reactive: table state and table APIs are wired for Angular signals, so you can safely consume table methods inside `computed(...)` and `effect(...)`.
1332
+ *
1333
+ * @example
1334
+ * 1. Register the table features you need
1335
+ * ```ts
1336
+ * // Register only the features you need
1337
+ * import {tableFeatures, rowPaginationFeature} from '@tanstack/angular-table';
1338
+ * const _features = tableFeatures({
1339
+ * rowPaginationFeature,
1340
+ * // ...all other features you need
1341
+ * })
1342
+ *
1343
+ * // Use all table core features
1344
+ * import {stockFeatures} from '@tanstack/angular-table';
1345
+ * const _features = tableFeatures(stockFeatures);
1346
+ * ```
1347
+ * 2. Prepare the table columns
1348
+ * ```ts
1349
+ * import {ColumnDef} from '@tanstack/angular-table';
1350
+ *
1351
+ * type MyData = {}
1352
+ *
1353
+ * const columns: ColumnDef<typeof _features, MyData>[] = [
1354
+ * // ...column definitions
1355
+ * ]
1356
+ *
1357
+ * // or using createColumnHelper
1358
+ * import {createColumnHelper} from '@tanstack/angular-table';
1359
+ * const columnHelper = createColumnHelper<typeof _features, MyData>();
1360
+ * const columns = columnHelper.columns([
1361
+ * columnHelper.accessor(...),
1362
+ * // ...other columns
1363
+ * ])
1364
+ * ```
1365
+ * 3. Create the table instance with `injectTable`
1366
+ * ```ts
1367
+ * const table = injectTable(() => {
1368
+ * // ...table options,
1369
+ * _features,
1370
+ * columns: columns,
1371
+ * data: myDataSignal(),
1372
+ * })
1373
+ * ```
1374
+ *
1375
+ * @returns An Angular-reactive TanStack Table instance.
1376
+ */
1377
+ function injectTable(options, selector = (state) => state) {
1378
+ assertInInjectionContext(injectTable);
1379
+ const injector = inject(Injector);
277
1380
  return lazyInit(() => {
278
1381
  const resolvedOptions = {
279
- state: {},
280
- onStateChange: () => { },
281
- renderFallbackValue: null,
282
1382
  ...options(),
1383
+ _features: {
1384
+ ...options()._features,
1385
+ angularReactivityFeature,
1386
+ },
283
1387
  };
284
- const table = _createTable(resolvedOptions);
285
- // By default, manage table state here using the table's initial state
286
- const state = signal(table.initialState);
287
- // Compose table options using computed.
288
- // This is to allow `tableSignal` to listen and set table option
1388
+ const table = constructTable(resolvedOptions);
289
1389
  const updatedOptions = computed(() => {
290
- // listen to table state changed
291
- const tableState = state();
292
- // listen to input options changed
293
- const tableOptions = options();
294
- return {
1390
+ const tableOptionsValue = options();
1391
+ const result = {
295
1392
  ...table.options,
296
- ...resolvedOptions,
297
- ...tableOptions,
298
- state: { ...tableState, ...tableOptions.state },
299
- onStateChange: updater => {
300
- const value = updater instanceof Function ? updater(tableState) : updater;
301
- state.set(value);
302
- resolvedOptions.onStateChange?.(updater);
1393
+ ...tableOptionsValue,
1394
+ _features: {
1395
+ ...tableOptionsValue._features,
1396
+ angularReactivityFeature,
303
1397
  },
304
1398
  };
305
- });
306
- // convert table instance to signal for proxify to listen to any table state and options changes
307
- const tableSignal = computed(() => {
1399
+ if (tableOptionsValue.state) {
1400
+ result.state = tableOptionsValue.state;
1401
+ }
1402
+ return result;
1403
+ }, ...(ngDevMode ? [{ debugName: "updatedOptions" }] : []));
1404
+ const tableState = injectStore(table.store, (state) => state, { injector });
1405
+ const tableSignalNotifier = computed(() => {
1406
+ tableState();
308
1407
  table.setOptions(updatedOptions());
1408
+ untracked(() => table.baseStore.setState((prev) => ({ ...prev })));
309
1409
  return table;
310
- }, {
311
- equal: () => false,
1410
+ }, { ...(ngDevMode ? { debugName: "tableSignalNotifier" } : {}), equal: () => false });
1411
+ table.setTableNotifier(tableSignalNotifier);
1412
+ table.Subscribe = function Subscribe(props) {
1413
+ return injectStore(table.store, props.selector, {
1414
+ injector,
1415
+ equal: props.equal,
1416
+ });
1417
+ };
1418
+ Object.defineProperty(table, 'state', {
1419
+ value: injectStore(table.store, selector, { injector }),
312
1420
  });
313
- // proxify Table instance to provide ability for consumer to listen to any table state changes
314
- return proxifyTable(tableSignal);
1421
+ return table;
315
1422
  });
316
1423
  }
317
1424
 
1425
+ function createTableHook({ tableComponents, cellComponents, headerComponents, ...defaultTableOptions }) {
1426
+ function injectTableContext$1() {
1427
+ return injectTableContext();
1428
+ }
1429
+ function injectTableHeaderContext$1() {
1430
+ return injectTableHeaderContext();
1431
+ }
1432
+ function injectTableCellContext$1() {
1433
+ return injectTableCellContext();
1434
+ }
1435
+ function injectFlexRenderHeaderContext() {
1436
+ return injectFlexRenderContext();
1437
+ }
1438
+ function injectFlexRenderCellContext() {
1439
+ return injectFlexRenderContext();
1440
+ }
1441
+ function injectAppTable(tableOptions, selector) {
1442
+ function appCell(cell) {
1443
+ return cell;
1444
+ }
1445
+ function appHeader(header) {
1446
+ return header;
1447
+ }
1448
+ function appFooter(footer) {
1449
+ return footer;
1450
+ }
1451
+ const appTableFeatures = {
1452
+ constructTableAPIs: (table) => {
1453
+ Object.assign(table, tableComponents, { appCell, appHeader, appFooter });
1454
+ },
1455
+ assignCellPrototype(prototype) {
1456
+ Object.assign(prototype, cellComponents);
1457
+ },
1458
+ assignHeaderPrototype(prototype) {
1459
+ Object.assign(prototype, headerComponents);
1460
+ },
1461
+ };
1462
+ return injectTable(() => {
1463
+ const options = {
1464
+ ...defaultTableOptions,
1465
+ ...tableOptions(),
1466
+ };
1467
+ options._features = { ...options._features, appTableFeatures };
1468
+ return options;
1469
+ }, selector);
1470
+ }
1471
+ function createAppColumnHelper() {
1472
+ // The runtime implementation is the same - components are attached at render time
1473
+ // This cast provides the enhanced types for column definitions
1474
+ return createColumnHelper();
1475
+ }
1476
+ return {
1477
+ createAppColumnHelper,
1478
+ injectTableContext: injectTableContext$1,
1479
+ injectTableHeaderContext: injectTableHeaderContext$1,
1480
+ injectTableCellContext: injectTableCellContext$1,
1481
+ injectFlexRenderHeaderContext,
1482
+ injectFlexRenderCellContext,
1483
+ injectAppTable,
1484
+ };
1485
+ }
1486
+
1487
+ /**
1488
+ * Constant helper to import FlexRender directives.
1489
+ *
1490
+ * You should prefer to use this constant over importing the directives separately,
1491
+ * as it ensures you always have the correct set of directives over library updates.
1492
+ *
1493
+ * @see {@link FlexRenderDirective} and {@link FlexRenderCell} for more details on the directives included in this export.
1494
+ */
1495
+ const FlexRender = [FlexRenderDirective, FlexRenderCell];
1496
+
318
1497
  /**
319
1498
  * Generated bundle index. Do not edit.
320
1499
  */
321
1500
 
322
- export { FlexRenderComponent, FlexRenderDirective, injectFlexRenderContext, injectTable };
1501
+ export { FlexRender, FlexRenderCell, FlexRenderComponentInstance, FlexRenderDirective, TanStackTable, TanStackTableCell, TanStackTableCellToken, TanStackTableHeader, TanStackTableHeaderToken, TanStackTableToken, angularReactivityFeature, createTableHook, flexRenderComponent, injectFlexRenderContext, injectTable, injectTableCellContext, injectTableContext, injectTableHeaderContext };
323
1502
  //# sourceMappingURL=tanstack-angular-table.mjs.map