@tanstack/angular-table 8.20.5 → 8.21.2

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,6 +1,6 @@
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 { untracked, computed, InjectionToken, inject, reflectComponentType, ViewContainerRef, Injectable, KeyValueDiffers, ChangeDetectorRef, OutputEmitterRef, TemplateRef, Type, Injector, runInInjectionContext, effect, Directive, Inject, Input, signal } from '@angular/core';
3
+ import { memo, createTable } from '@tanstack/table-core';
4
4
  export * from '@tanstack/table-core';
5
5
 
6
6
  /**
@@ -61,8 +61,12 @@ function proxifyTable(tableSignal) {
61
61
  * excluding handlers as they do not retain any reactive value
62
62
  */
63
63
  if (property.startsWith('get') &&
64
- !property.endsWith('Handler') &&
65
- !property.endsWith('Model')) {
64
+ !property.endsWith('Handler')
65
+ // e.g. getCoreRowModel, getSelectedRowModel etc.
66
+ // We need that after a signal change even `rowModel` may mark the view as dirty.
67
+ // This allows to always get the latest `getContext` value while using flexRender
68
+ // && !property.endsWith('Model')
69
+ ) {
66
70
  const maybeFn = table[property];
67
71
  if (typeof maybeFn === 'function') {
68
72
  Object.defineProperty(target, property, {
@@ -127,120 +131,548 @@ function serializeArgs(...args) {
127
131
  return JSON.stringify(args);
128
132
  }
129
133
 
134
+ const FlexRenderComponentProps = new InjectionToken('[@tanstack/angular-table] Flex render component context props');
135
+ function injectFlexRenderContext() {
136
+ return inject(FlexRenderComponentProps);
137
+ }
138
+
139
+ /**
140
+ * Flags used to manage and optimize the rendering lifecycle of content of the cell,
141
+ * while using FlexRenderDirective.
142
+ */
143
+ var FlexRenderFlags;
144
+ (function (FlexRenderFlags) {
145
+ /**
146
+ * Indicates that the view is being created for the first time or will be cleared during the next update phase.
147
+ * This is the initial state and will transition after the first ngDoCheck.
148
+ */
149
+ FlexRenderFlags[FlexRenderFlags["ViewFirstRender"] = 1] = "ViewFirstRender";
150
+ /**
151
+ * Represents a state where the view is not dirty, meaning no changes require rendering updates.
152
+ */
153
+ FlexRenderFlags[FlexRenderFlags["Pristine"] = 2] = "Pristine";
154
+ /**
155
+ * Indicates the `content` property has been modified or the view requires a complete re-render.
156
+ * When this flag is enabled, the view will be cleared and recreated from scratch.
157
+ */
158
+ FlexRenderFlags[FlexRenderFlags["ContentChanged"] = 4] = "ContentChanged";
159
+ /**
160
+ * Indicates that the `props` property reference has changed.
161
+ * When this flag is enabled, the view context is updated based on the type of the content.
162
+ *
163
+ * For Component view, inputs will be updated and view will be marked as dirty.
164
+ * For TemplateRef and primitive values, view will be marked as dirty
165
+ */
166
+ FlexRenderFlags[FlexRenderFlags["PropsReferenceChanged"] = 8] = "PropsReferenceChanged";
167
+ /**
168
+ * Indicates that the current rendered view needs to be checked for changes.
169
+ */
170
+ FlexRenderFlags[FlexRenderFlags["DirtyCheck"] = 16] = "DirtyCheck";
171
+ /**
172
+ * Indicates that a signal within the `content(props)` result has changed
173
+ */
174
+ FlexRenderFlags[FlexRenderFlags["DirtySignal"] = 32] = "DirtySignal";
175
+ /**
176
+ * Indicates that the first render effect has been checked at least one time.
177
+ */
178
+ FlexRenderFlags[FlexRenderFlags["RenderEffectChecked"] = 64] = "RenderEffectChecked";
179
+ })(FlexRenderFlags || (FlexRenderFlags = {}));
180
+
181
+ /**
182
+ * Helper function to create a [@link FlexRenderComponent] instance, with better type-safety.
183
+ *
184
+ * - options object must be passed when the given component instance contains at least one required signal input.
185
+ * - options/inputs is typed with the given component inputs
186
+ * - options/outputs is typed with the given component outputs
187
+ */
188
+ function flexRenderComponent(component, ...options) {
189
+ const { inputs, injector, outputs } = options?.[0] ?? {};
190
+ return new FlexRenderComponent(component, inputs, injector, outputs);
191
+ }
192
+ /**
193
+ * Wrapper class for a component that will be used as content for {@link FlexRenderDirective}
194
+ *
195
+ * Prefer {@link flexRenderComponent} helper for better type-safety
196
+ */
197
+ class FlexRenderComponent {
198
+ component;
199
+ inputs;
200
+ injector;
201
+ outputs;
202
+ mirror;
203
+ allowedInputNames = [];
204
+ allowedOutputNames = [];
205
+ constructor(component, inputs, injector, outputs) {
206
+ this.component = component;
207
+ this.inputs = inputs;
208
+ this.injector = injector;
209
+ this.outputs = outputs;
210
+ const mirror = reflectComponentType(component);
211
+ if (!mirror) {
212
+ throw new Error(`[@tanstack-table/angular] The provided symbol is not a component`);
213
+ }
214
+ this.mirror = mirror;
215
+ for (const input of this.mirror.inputs) {
216
+ this.allowedInputNames.push(input.propName);
217
+ }
218
+ for (const output of this.mirror.outputs) {
219
+ this.allowedOutputNames.push(output.propName);
220
+ }
221
+ }
222
+ }
223
+
224
+ class FlexRenderComponentFactory {
225
+ #viewContainerRef = inject(ViewContainerRef);
226
+ createComponent(flexRenderComponent, componentInjector) {
227
+ const componentRef = this.#viewContainerRef.createComponent(flexRenderComponent.component, {
228
+ injector: componentInjector,
229
+ });
230
+ const view = new FlexRenderComponentRef(componentRef, flexRenderComponent, componentInjector);
231
+ const { inputs, outputs } = flexRenderComponent;
232
+ if (inputs)
233
+ view.setInputs(inputs);
234
+ if (outputs)
235
+ view.setOutputs(outputs);
236
+ return view;
237
+ }
238
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FlexRenderComponentFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
239
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FlexRenderComponentFactory });
240
+ }
241
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FlexRenderComponentFactory, decorators: [{
242
+ type: Injectable
243
+ }] });
244
+ class FlexRenderComponentRef {
245
+ componentRef;
246
+ componentInjector;
247
+ #keyValueDiffersFactory;
248
+ #componentData;
249
+ #inputValueDiffer;
250
+ #outputRegistry;
251
+ constructor(componentRef, componentData, componentInjector) {
252
+ this.componentRef = componentRef;
253
+ this.componentInjector = componentInjector;
254
+ this.#componentData = componentData;
255
+ this.#keyValueDiffersFactory = componentInjector.get(KeyValueDiffers);
256
+ this.#outputRegistry = new FlexRenderComponentOutputManager(this.#keyValueDiffersFactory, this.outputs);
257
+ this.#inputValueDiffer = this.#keyValueDiffersFactory
258
+ .find(this.inputs)
259
+ .create();
260
+ this.#inputValueDiffer.diff(this.inputs);
261
+ this.componentRef.onDestroy(() => this.#outputRegistry.unsubscribeAll());
262
+ }
263
+ get component() {
264
+ return this.#componentData.component;
265
+ }
266
+ get inputs() {
267
+ return this.#componentData.inputs ?? {};
268
+ }
269
+ get outputs() {
270
+ return this.#componentData.outputs ?? {};
271
+ }
272
+ /**
273
+ * Get component input and output diff by the given item
274
+ */
275
+ diff(item) {
276
+ return {
277
+ inputDiff: this.#inputValueDiffer.diff(item.inputs ?? {}),
278
+ outputDiff: this.#outputRegistry.diff(item.outputs ?? {}),
279
+ };
280
+ }
281
+ /**
282
+ *
283
+ * @param compare Whether the current ref component instance is the same as the given one
284
+ */
285
+ eqType(compare) {
286
+ return compare.component === this.component;
287
+ }
288
+ /**
289
+ * Tries to update current component refs input by the new given content component.
290
+ */
291
+ update(content) {
292
+ const eq = this.eqType(content);
293
+ if (!eq)
294
+ return;
295
+ const { inputDiff, outputDiff } = this.diff(content);
296
+ if (inputDiff) {
297
+ inputDiff.forEachAddedItem(item => this.setInput(item.key, item.currentValue));
298
+ inputDiff.forEachChangedItem(item => this.setInput(item.key, item.currentValue));
299
+ inputDiff.forEachRemovedItem(item => this.setInput(item.key, undefined));
300
+ }
301
+ if (outputDiff) {
302
+ outputDiff.forEachAddedItem(item => {
303
+ this.setOutput(item.key, item.currentValue);
304
+ });
305
+ outputDiff.forEachChangedItem(item => {
306
+ if (item.currentValue) {
307
+ this.#outputRegistry.setListener(item.key, item.currentValue);
308
+ }
309
+ else {
310
+ this.#outputRegistry.unsubscribe(item.key);
311
+ }
312
+ });
313
+ outputDiff.forEachRemovedItem(item => {
314
+ this.#outputRegistry.unsubscribe(item.key);
315
+ });
316
+ }
317
+ this.#componentData = content;
318
+ }
319
+ markAsDirty() {
320
+ this.componentRef.injector.get(ChangeDetectorRef).markForCheck();
321
+ }
322
+ setInputs(inputs) {
323
+ for (const prop in inputs) {
324
+ this.setInput(prop, inputs[prop]);
325
+ }
326
+ }
327
+ setInput(key, value) {
328
+ if (this.#componentData.allowedInputNames.includes(key)) {
329
+ this.componentRef.setInput(key, value);
330
+ }
331
+ }
332
+ setOutputs(outputs) {
333
+ this.#outputRegistry.unsubscribeAll();
334
+ for (const prop in outputs) {
335
+ this.setOutput(prop, outputs[prop]);
336
+ }
337
+ }
338
+ setOutput(outputName, emit) {
339
+ if (!this.#componentData.allowedOutputNames.includes(outputName))
340
+ return;
341
+ if (!emit) {
342
+ this.#outputRegistry.unsubscribe(outputName);
343
+ return;
344
+ }
345
+ const hasListener = this.#outputRegistry.hasListener(outputName);
346
+ this.#outputRegistry.setListener(outputName, emit);
347
+ if (hasListener) {
348
+ return;
349
+ }
350
+ const instance = this.componentRef.instance;
351
+ const output = instance[outputName];
352
+ if (output && output instanceof OutputEmitterRef) {
353
+ output.subscribe(value => {
354
+ this.#outputRegistry.getListener(outputName)?.(value);
355
+ });
356
+ }
357
+ }
358
+ }
359
+ class FlexRenderComponentOutputManager {
360
+ #outputSubscribers = {};
361
+ #outputListeners = {};
362
+ #valueDiffer;
363
+ constructor(keyValueDiffers, initialOutputs) {
364
+ this.#valueDiffer = keyValueDiffers.find(initialOutputs).create();
365
+ if (initialOutputs) {
366
+ this.#valueDiffer.diff(initialOutputs);
367
+ }
368
+ }
369
+ hasListener(outputName) {
370
+ return outputName in this.#outputListeners;
371
+ }
372
+ setListener(outputName, callback) {
373
+ this.#outputListeners[outputName] = callback;
374
+ }
375
+ getListener(outputName) {
376
+ return this.#outputListeners[outputName];
377
+ }
378
+ unsubscribeAll() {
379
+ for (const prop in this.#outputSubscribers) {
380
+ this.unsubscribe(prop);
381
+ }
382
+ }
383
+ unsubscribe(outputName) {
384
+ if (outputName in this.#outputSubscribers) {
385
+ this.#outputSubscribers[outputName]?.unsubscribe();
386
+ delete this.#outputSubscribers[outputName];
387
+ delete this.#outputListeners[outputName];
388
+ }
389
+ }
390
+ diff(outputs) {
391
+ return this.#valueDiffer.diff(outputs ?? {});
392
+ }
393
+ }
394
+
395
+ function mapToFlexRenderTypedContent(content) {
396
+ if (content === null || content === undefined) {
397
+ return { kind: 'null' };
398
+ }
399
+ if (typeof content === 'string' || typeof content === 'number') {
400
+ return { kind: 'primitive', content };
401
+ }
402
+ if (content instanceof FlexRenderComponent) {
403
+ return { kind: 'flexRenderComponent', content };
404
+ }
405
+ else if (content instanceof TemplateRef) {
406
+ return { kind: 'templateRef', content };
407
+ }
408
+ else if (content instanceof Type) {
409
+ return { kind: 'component', content };
410
+ }
411
+ else {
412
+ return { kind: 'primitive', content };
413
+ }
414
+ }
415
+ class FlexRenderView {
416
+ view;
417
+ #previousContent;
418
+ #content;
419
+ constructor(initialContent, view) {
420
+ this.#content = initialContent;
421
+ this.view = view;
422
+ }
423
+ get previousContent() {
424
+ return this.#previousContent ?? { kind: 'null' };
425
+ }
426
+ get content() {
427
+ return this.#content;
428
+ }
429
+ set content(content) {
430
+ this.#previousContent = this.#content;
431
+ this.#content = content;
432
+ }
433
+ }
434
+ class FlexRenderTemplateView extends FlexRenderView {
435
+ constructor(initialContent, view) {
436
+ super(initialContent, view);
437
+ }
438
+ updateProps(props) {
439
+ this.view.markForCheck();
440
+ }
441
+ dirtyCheck() {
442
+ // Basically a no-op. When the view is created via EmbeddedViewRef, we don't need to do any manual update
443
+ // since this type of content has a proxy as a context, then every time the root component is checked for changes,
444
+ // the property getter will be re-evaluated.
445
+ //
446
+ // If in a future we need to manually mark the view as dirty, just uncomment next line
447
+ // this.view.markForCheck()
448
+ }
449
+ onDestroy(callback) {
450
+ this.view.onDestroy(callback);
451
+ }
452
+ }
453
+ class FlexRenderComponentView extends FlexRenderView {
454
+ constructor(initialContent, view) {
455
+ super(initialContent, view);
456
+ }
457
+ updateProps(props) {
458
+ switch (this.content.kind) {
459
+ case 'component': {
460
+ this.view.setInputs(props);
461
+ break;
462
+ }
463
+ case 'flexRenderComponent': {
464
+ // No-op. When FlexRenderFlags.PropsReferenceChanged is set,
465
+ // FlexRenderComponent will be updated into `dirtyCheck`.
466
+ break;
467
+ }
468
+ }
469
+ }
470
+ dirtyCheck() {
471
+ switch (this.content.kind) {
472
+ case 'component': {
473
+ // Component context is currently valuated with the cell context. Since it's reference
474
+ // shouldn't change, we force mark the component as dirty in order to re-evaluate function invocation in view.
475
+ // NOTE: this should behave like having a component with ChangeDetectionStrategy.Default
476
+ this.view.markAsDirty();
477
+ break;
478
+ }
479
+ case 'flexRenderComponent': {
480
+ // Given context instance will always have a different reference than the previous one,
481
+ // so instead of recreating the entire view, we will only update the current view
482
+ if (this.view.eqType(this.content.content)) {
483
+ this.view.update(this.content.content);
484
+ }
485
+ this.view.markAsDirty();
486
+ break;
487
+ }
488
+ }
489
+ }
490
+ onDestroy(callback) {
491
+ this.view.componentRef.onDestroy(callback);
492
+ }
493
+ }
494
+
130
495
  class FlexRenderDirective {
131
496
  viewContainerRef;
132
497
  templateRef;
498
+ #flexRenderComponentFactory = inject(FlexRenderComponentFactory);
499
+ #changeDetectorRef = inject(ChangeDetectorRef);
133
500
  content = undefined;
134
501
  props = {};
135
502
  injector = inject(Injector);
503
+ renderFlags = FlexRenderFlags.ViewFirstRender;
504
+ renderView = null;
505
+ #latestContent = () => {
506
+ const { content, props } = this;
507
+ return typeof content !== 'function'
508
+ ? content
509
+ : runInInjectionContext(this.injector, () => content(props));
510
+ };
511
+ #getContentValue = memo(() => [this.#latestContent(), this.props, this.content], latestContent => {
512
+ return mapToFlexRenderTypedContent(latestContent);
513
+ }, { key: 'flexRenderContentValue', debug: () => false });
136
514
  constructor(viewContainerRef, templateRef) {
137
515
  this.viewContainerRef = viewContainerRef;
138
516
  this.templateRef = templateRef;
139
517
  }
140
- ref = null;
141
518
  ngOnChanges(changes) {
142
- if (this.ref instanceof ComponentRef) {
143
- this.ref.injector.get(ChangeDetectorRef).markForCheck();
519
+ if (changes['props']) {
520
+ this.renderFlags |= FlexRenderFlags.PropsReferenceChanged;
144
521
  }
145
- if (!changes['content']) {
522
+ if (changes['content']) {
523
+ this.renderFlags |=
524
+ FlexRenderFlags.ContentChanged | FlexRenderFlags.ViewFirstRender;
525
+ this.update();
526
+ }
527
+ }
528
+ ngDoCheck() {
529
+ if (this.renderFlags & FlexRenderFlags.ViewFirstRender) {
530
+ // On the initial render, the view is created during the `ngOnChanges` hook.
531
+ // Since `ngDoCheck` is called immediately afterward, there's no need to check for changes in this phase.
532
+ this.renderFlags &= ~FlexRenderFlags.ViewFirstRender;
146
533
  return;
147
534
  }
148
- this.render();
535
+ this.renderFlags |= FlexRenderFlags.DirtyCheck;
536
+ const latestContent = this.#getContentValue();
537
+ if (latestContent.kind === 'null' || !this.renderView) {
538
+ this.renderFlags |= FlexRenderFlags.ContentChanged;
539
+ }
540
+ else {
541
+ this.renderView.content = latestContent;
542
+ const { kind: previousKind } = this.renderView.previousContent;
543
+ if (latestContent.kind !== previousKind) {
544
+ this.renderFlags |= FlexRenderFlags.ContentChanged;
545
+ }
546
+ }
547
+ this.update();
149
548
  }
150
- render() {
151
- this.viewContainerRef.clear();
152
- const { content, props } = this;
153
- if (content === null || content === undefined) {
154
- this.ref = null;
549
+ update() {
550
+ if (this.renderFlags &
551
+ (FlexRenderFlags.ContentChanged | FlexRenderFlags.ViewFirstRender)) {
552
+ this.render();
155
553
  return;
156
554
  }
157
- if (typeof content === 'function') {
158
- return this.renderContent(content(props));
555
+ if (this.renderFlags & FlexRenderFlags.PropsReferenceChanged) {
556
+ if (this.renderView)
557
+ this.renderView.updateProps(this.props);
558
+ this.renderFlags &= ~FlexRenderFlags.PropsReferenceChanged;
559
+ }
560
+ if (this.renderFlags &
561
+ (FlexRenderFlags.DirtyCheck | FlexRenderFlags.DirtySignal)) {
562
+ if (this.renderView)
563
+ this.renderView.dirtyCheck();
564
+ this.renderFlags &= ~(FlexRenderFlags.DirtyCheck | FlexRenderFlags.DirtySignal);
565
+ }
566
+ }
567
+ #currentEffectRef = null;
568
+ render() {
569
+ if (this.#shouldRecreateEntireView() && this.#currentEffectRef) {
570
+ this.#currentEffectRef.destroy();
571
+ this.#currentEffectRef = null;
572
+ this.renderFlags &= ~FlexRenderFlags.RenderEffectChecked;
573
+ }
574
+ this.viewContainerRef.clear();
575
+ this.renderFlags =
576
+ FlexRenderFlags.Pristine |
577
+ (this.renderFlags & FlexRenderFlags.ViewFirstRender) |
578
+ (this.renderFlags & FlexRenderFlags.RenderEffectChecked);
579
+ const resolvedContent = this.#getContentValue();
580
+ if (resolvedContent.kind === 'null') {
581
+ this.renderView = null;
159
582
  }
160
583
  else {
161
- return this.renderContent(content);
584
+ this.renderView = this.#renderViewByContent(resolvedContent);
585
+ }
586
+ // If the content is a function `content(props)`, we initialize an effect
587
+ // in order to react to changes if the given definition use signals.
588
+ if (!this.#currentEffectRef && typeof this.content === 'function') {
589
+ this.#currentEffectRef = effect(() => {
590
+ this.#latestContent();
591
+ if (!(this.renderFlags & FlexRenderFlags.RenderEffectChecked)) {
592
+ this.renderFlags |= FlexRenderFlags.RenderEffectChecked;
593
+ return;
594
+ }
595
+ this.renderFlags |= FlexRenderFlags.DirtySignal;
596
+ // This will mark the view as changed,
597
+ // so we'll try to check for updates into ngDoCheck
598
+ this.#changeDetectorRef.markForCheck();
599
+ }, { injector: this.viewContainerRef.injector });
162
600
  }
163
601
  }
164
- renderContent(content) {
165
- if (typeof content === 'string' || typeof content === 'number') {
166
- return this.renderStringContent();
602
+ #shouldRecreateEntireView() {
603
+ return (this.renderFlags &
604
+ FlexRenderFlags.ContentChanged &
605
+ FlexRenderFlags.ViewFirstRender);
606
+ }
607
+ #renderViewByContent(content) {
608
+ if (content.kind === 'primitive') {
609
+ return this.#renderStringContent(content);
167
610
  }
168
- if (content instanceof TemplateRef) {
169
- return this.viewContainerRef.createEmbeddedView(content, this.getTemplateRefContext());
611
+ else if (content.kind === 'templateRef') {
612
+ return this.#renderTemplateRefContent(content);
170
613
  }
171
- else if (content instanceof FlexRenderComponent) {
172
- return this.renderComponent(content);
614
+ else if (content.kind === 'flexRenderComponent') {
615
+ return this.#renderComponent(content);
173
616
  }
174
- else if (content instanceof Type) {
175
- return this.renderCustomComponent(content);
617
+ else if (content.kind === 'component') {
618
+ return this.#renderCustomComponent(content);
176
619
  }
177
620
  else {
178
621
  return null;
179
622
  }
180
623
  }
181
- renderStringContent() {
624
+ #renderStringContent(template) {
182
625
  const context = () => {
183
626
  return typeof this.content === 'string' ||
184
627
  typeof this.content === 'number'
185
628
  ? this.content
186
629
  : this.content?.(this.props);
187
630
  };
188
- return this.viewContainerRef.createEmbeddedView(this.templateRef, {
631
+ const ref = this.viewContainerRef.createEmbeddedView(this.templateRef, {
189
632
  get $implicit() {
190
633
  return context();
191
634
  },
192
635
  });
636
+ return new FlexRenderTemplateView(template, ref);
193
637
  }
194
- renderComponent(flexRenderComponent) {
195
- const { component, inputs, injector } = flexRenderComponent;
638
+ #renderTemplateRefContent(template) {
639
+ const latestContext = () => this.props;
640
+ const view = this.viewContainerRef.createEmbeddedView(template.content, {
641
+ get $implicit() {
642
+ return latestContext();
643
+ },
644
+ });
645
+ return new FlexRenderTemplateView(template, view);
646
+ }
647
+ #renderComponent(flexRenderComponent) {
648
+ const { inputs, outputs, injector } = flexRenderComponent.content;
196
649
  const getContext = () => this.props;
197
650
  const proxy = new Proxy(this.props, {
198
- get: (_, key) => getContext()?.[key],
651
+ get: (_, key) => getContext()[key],
199
652
  });
200
653
  const componentInjector = Injector.create({
201
654
  parent: injector ?? this.injector,
202
655
  providers: [{ provide: FlexRenderComponentProps, useValue: proxy }],
203
656
  });
204
- const componentRef = this.viewContainerRef.createComponent(component, {
205
- injector: componentInjector,
206
- });
207
- for (const prop in inputs) {
208
- if (componentRef.instance?.hasOwnProperty(prop)) {
209
- componentRef.setInput(prop, inputs[prop]);
210
- }
211
- }
212
- return componentRef;
657
+ const view = this.#flexRenderComponentFactory.createComponent(flexRenderComponent.content, componentInjector);
658
+ return new FlexRenderComponentView(flexRenderComponent, view);
213
659
  }
214
- renderCustomComponent(component) {
215
- const componentRef = this.viewContainerRef.createComponent(component, {
660
+ #renderCustomComponent(component) {
661
+ const view = this.#flexRenderComponentFactory.createComponent(flexRenderComponent(component.content, {
662
+ inputs: this.props,
216
663
  injector: this.injector,
217
- });
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
- };
664
+ }), this.injector);
665
+ return new FlexRenderComponentView(component, view);
235
666
  }
236
667
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FlexRenderDirective, deps: [{ token: ViewContainerRef }, { token: TemplateRef }], target: i0.ɵɵFactoryTarget.Directive });
237
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.11", type: FlexRenderDirective, isStandalone: true, selector: "[flexRender]", inputs: { content: ["flexRender", "content"], props: ["flexRenderProps", "props"], injector: ["flexRenderInjector", "injector"] }, usesOnChanges: true, ngImport: i0 });
668
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.11", type: FlexRenderDirective, isStandalone: true, selector: "[flexRender]", inputs: { content: ["flexRender", "content"], props: ["flexRenderProps", "props"], injector: ["flexRenderInjector", "injector"] }, providers: [FlexRenderComponentFactory], usesOnChanges: true, ngImport: i0 });
238
669
  }
239
670
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImport: i0, type: FlexRenderDirective, decorators: [{
240
671
  type: Directive,
241
672
  args: [{
242
673
  selector: '[flexRender]',
243
674
  standalone: true,
675
+ providers: [FlexRenderComponentFactory],
244
676
  }]
245
677
  }], ctorParameters: () => [{ type: i0.ViewContainerRef, decorators: [{
246
678
  type: Inject,
@@ -258,20 +690,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.11", ngImpo
258
690
  type: Input,
259
691
  args: [{ required: false, alias: 'flexRenderInjector' }]
260
692
  }] } });
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;
269
- }
270
- }
271
- const FlexRenderComponentProps = new InjectionToken('[@tanstack/angular-table] Flex render component context props');
272
- function injectFlexRenderContext() {
273
- return inject(FlexRenderComponentProps);
274
- }
275
693
 
276
694
  function createAngularTable(options) {
277
695
  return lazyInit(() => {
@@ -319,5 +737,5 @@ function createAngularTable(options) {
319
737
  * Generated bundle index. Do not edit.
320
738
  */
321
739
 
322
- export { FlexRenderComponent, FlexRenderDirective, createAngularTable, injectFlexRenderContext };
740
+ export { FlexRenderDirective as FlexRender, FlexRenderComponent, FlexRenderDirective, createAngularTable, flexRenderComponent, injectFlexRenderContext };
323
741
  //# sourceMappingURL=tanstack-angular-table.mjs.map