UNPKG

@tanstack/angular-table

Version:

Headless UI for building powerful tables & datagrids for Angular.

1,401 lines 54.1 kB
import * as i0 from '@angular/core';
import { InjectionToken, input, inject, Directive, reflectComponentType, Injectable, ChangeDetectorRef, OutputEmitterRef, TemplateRef, Type, runInInjectionContext, computed, effect, untracked, Injector, ViewContainerRef, DestroyRef, assertInInjectionContext, NgZone, signal } from '@angular/core';
import { constructTable, createColumnHelper } from '@tanstack/table-core';
export * from '@tanstack/table-core';
import { toObservable } from '@angular/core/rxjs-interop';
export { shallow } from '@tanstack/angular-store';

/**
 * Injection token that provides access to the current cell.
 *
 * This token is provided by the {@link TanStackTableCell} directive.
 */
const TanStackTableCellToken = new InjectionToken('[TanStack Table] CellContext');
/**
 * Provides a TanStack Table `Cell` instance in Angular DI.
 *
 * The cell can be injected by:
 * - any descendant of an element using `[tanStackTableCell]="..."`
 * - any component instantiated by `*flexRender` when the render props contains `cell`
 *
 * @example
 * Inject from the nearest `[tanStackTableCell]`:
 * ```html
 * <td [tanStackTableCell]="cell">
 *   <app-cell-actions />
 * </td>
 * ```
 *
 * ```ts
 * @Component({
 *   selector: 'app-cell-actions',
 *   template: `{{ cell().id }}`,
 * })
 * export class CellActionsComponent {
 *   readonly cell = injectTableCellContext()
 * }
 * ```
 *
 * @example
 * Inject inside a component rendered via `flexRender`:
 * ```ts
 * @Component({
 *   selector: 'app-price-cell',
 *   template: `{{ cell().getValue() }}`,
 * })
 * export class PriceCellComponent {
 *   readonly cell = injectTableCellContext()
 * }
 * ```
 */
class TanStackTableCell {
    /**
     * The current TanStack Table cell.
     *
     * Provided as a required signal input so DI consumers always read the latest value.
     */
    cell = input.required({ ...(ngDevMode ? { debugName: "cell" } : /* istanbul ignore next */ {}), alias: 'tanStackTableCell' });
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: TanStackTableCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.1", type: TanStackTableCell, isStandalone: true, selector: "[tanStackTableCell]", inputs: { cell: { classPropertyName: "cell", publicName: "tanStackTableCell", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
            {
                provide: TanStackTableCellToken,
                useFactory: () => inject(TanStackTableCell).cell,
            },
        ], exportAs: ["cell"], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: TanStackTableCell, decorators: [{
            type: Directive,
            args: [{
                    selector: '[tanStackTableCell]',
                    exportAs: 'cell',
                    providers: [
                        {
                            provide: TanStackTableCellToken,
                            useFactory: () => inject(TanStackTableCell).cell,
                        },
                    ],
                }]
        }], propDecorators: { cell: [{ type: i0.Input, args: [{ isSignal: true, alias: "tanStackTableCell", required: true }] }] } });
/**
 * Injects the current TanStack Table cell signal.
 *
 * Available when:
 * - there is a nearest `[tanStackTableCell]` directive in the DI tree, or
 * - the caller is rendered via `*flexRender` with render props containing `cell`
 */
function injectTableCellContext() {
    return inject(TanStackTableCellToken);
}

/**
 * Injection token that provides access to the current header.
 *
 * This token is provided by the {@link TanStackTableHeader} directive.
 */
const TanStackTableHeaderToken = new InjectionToken('[TanStack Table] HeaderContext');
/**
 * Provides a TanStack Table `Header` instance in Angular DI.
 *
 * The header can be injected by:
 * - any descendant of an element using `[tanStackTableHeader]="..."`
 * - any component instantiated by `*flexRender` when the render props contains `header`
 *
 * @example
 * ```html
 * <th [tanStackTableHeader]="header">
 *   <app-sort-indicator />
 * </th>
 * ```
 *
 * ```ts
 * @Component({
 *   selector: 'app-sort-indicator',
 *   template: `
 *     <button (click)="toggle()">
 *       {{ header().column.id }}
 *     </button>
 *   `,
 * })
 * export class SortIndicatorComponent {
 *   readonly header = injectTableHeaderContext()
 *
 *   toggle() {
 *     this.header().column.toggleSorting()
 *   }
 * }
 * ```
 */
class TanStackTableHeader {
    /**
     * The current TanStack Table header.
     *
     * Provided as a required signal input so DI consumers always read the latest value.
     */
    header = input.required({ ...(ngDevMode ? { debugName: "header" } : /* istanbul ignore next */ {}), alias: 'tanStackTableHeader' });
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: TanStackTableHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.1", type: TanStackTableHeader, isStandalone: true, selector: "[tanStackTableHeader]", inputs: { header: { classPropertyName: "header", publicName: "tanStackTableHeader", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
            {
                provide: TanStackTableHeaderToken,
                useFactory: () => inject(TanStackTableHeader).header,
            },
        ], exportAs: ["header"], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: TanStackTableHeader, decorators: [{
            type: Directive,
            args: [{
                    selector: '[tanStackTableHeader]',
                    exportAs: 'header',
                    providers: [
                        {
                            provide: TanStackTableHeaderToken,
                            useFactory: () => inject(TanStackTableHeader).header,
                        },
                    ],
                }]
        }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "tanStackTableHeader", required: true }] }] } });
/**
 * Injects the current TanStack Table header signal.
 *
 * Available when:
 * - there is a nearest `[tanStackTableHeader]` directive in the DI tree, or
 * - the caller is rendered via `*flexRender` with render props containing `header`
 */
function injectTableHeaderContext() {
    return inject(TanStackTableHeaderToken);
}

/**
 * Injection token that provides access to the current {@link AngularTable} instance.
 *
 * This token is provided by the {@link TanStackTable} directive.
 */
const TanStackTableToken = new InjectionToken('[TanStack Table] Table Context');
/**
 * Provides a TanStack Table instance (`AngularTable`) in Angular DI.
 *
 * The table can be injected by:
 * - any descendant of an element using `[tanStackTable]="..."`
 * - any component instantiated by `*flexRender` when the render props contains `table`
 *
 * @example
 * ```html
 * <div [tanStackTable]="table">
 *   <app-pagination />
 * </div>
 * ```
 *
 * ```ts
 * @Component({
 *   selector: 'app-pagination',
 *   template: `
 *     <button (click)="prev()" [disabled]="!table().getCanPreviousPage()">Prev</button>
 *     <button (click)="next()" [disabled]="!table().getCanNextPage()">Next</button>
 *   `,
 * })
 * export class PaginationComponent {
 *   readonly table = injectTableContext()
 *
 *   prev() {
 *     this.table().previousPage()
 *   }
 *   next() {
 *     this.table().nextPage()
 *   }
 * }
 * ```
 */
class TanStackTable {
    /**
     * The current TanStack Table instance.
     *
     * Provided as a required signal input so DI consumers always read the latest value.
     */
    table = input.required({ ...(ngDevMode ? { debugName: "table" } : /* istanbul ignore next */ {}), alias: 'tanStackTable' });
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: TanStackTable, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.1", type: TanStackTable, isStandalone: true, selector: "[tanStackTable]", inputs: { table: { classPropertyName: "table", publicName: "tanStackTable", isSignal: true, isRequired: true, transformFunction: null } }, providers: [
            {
                provide: TanStackTableToken,
                useFactory: () => inject(TanStackTable).table,
            },
        ], exportAs: ["table"], ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: TanStackTable, decorators: [{
            type: Directive,
            args: [{
                    selector: '[tanStackTable]',
                    exportAs: 'table',
                    providers: [
                        {
                            provide: TanStackTableToken,
                            useFactory: () => inject(TanStackTable).table,
                        },
                    ],
                }]
        }], propDecorators: { table: [{ type: i0.Input, args: [{ isSignal: true, alias: "tanStackTable", required: true }] }] } });
/**
 * Injects the current TanStack Table instance signal.
 *
 * Available when:
 * - there is a nearest `[tanStackTable]` directive in the DI tree, or
 * - the caller is rendered via `*flexRender` with render props containing `table`
 */
function injectTableContext() {
    return inject(TanStackTableToken);
}

const FlexRenderComponentProps = new InjectionToken('[@tanstack/angular-table] Flex render component context props');
/**
 * Inject the flex render context props.
 *
 * Can be used in components rendered via FlexRender directives.
 */
function injectFlexRenderContext() {
    return inject(FlexRenderComponentProps);
}

/**
 * Flags used to manage and optimize the rendering lifecycle of content inside
 * {@link FlexViewRenderer}.
 */
const FlexRenderFlags = {
    /**
     * The renderer has not completed its initial update. The first update creates
     * the view from scratch, then clears this flag.
     */
    ViewFirstRender: 1 << 0,
    /**
     * The `content` input changed by reference, or its resolved value is not
     * compatible with the mounted view. The next update recreates the view.
     */
    ContentChanged: 1 << 1,
    /**
     * The `props` input changed by reference. Components receive the latest
     * inputs and embedded templates are marked so their getter-backed context is
     * evaluated again.
     */
    PropsReferenceChanged: 1 << 2,
    /**
     * A render function produced compatible content that must be synchronized
     * with the mounted view without recreating it.
     */
    Dirty: 1 << 3,
    /**
     * The render-function effect completed its initial dependency read. That
     * first execution records dependencies; subsequent executions update the
     * view.
     */
    RenderEffectChecked: 1 << 4,
};

/**
 * Helper function to create a {@link FlexRenderComponent} instance, with better type-safety.
 *
 * @example
 * ```ts
 * import {flexRenderComponent} from '@tanstack/angular-table'
 * import {inputBinding, outputBinding} from '@angular/core';
 *
 * const columns = [
 *   {
 *     cell: ({ row }) => {
 *        return flexRenderComponent(MyComponent, {
 *          inputs: { value: mySignalValue() },
 *          outputs: { valueChange: (val) => {} }
 *          // or using angular native createComponent#binding api
 *          bindings: [
 *            inputBinding('value', mySignalValue),
 *            outputBinding('valueChange', value => {
 *              console.log("my value changed to", value)
 *            })
 *          ]
 *        })
 *     },
 *   },
 * ]
 * ```
 */
function flexRenderComponent(component, options) {
    const { key, inputs, injector, outputs, directives, bindings } = options ?? {};
    return new FlexRenderComponentInstance(component, inputs, injector, outputs, directives, bindings, key);
}
/**
 * Wrapper class for a component that will be used as content for {@link FlexRenderDirective}
 *
 * Prefer {@link flexRenderComponent} for better type-safety.
 */
class FlexRenderComponentInstance {
    component;
    inputs;
    injector;
    outputs;
    directives;
    bindings;
    key;
    mirror;
    metadata;
    constructor(component, inputs, injector, outputs, directives, bindings, key) {
        this.component = component;
        this.inputs = inputs;
        this.injector = injector;
        this.outputs = outputs;
        this.directives = directives;
        this.bindings = bindings;
        this.key = key;
        this.metadata = resolveComponentTypeMetadata(component);
        this.mirror = this.metadata.mirror;
    }
}
const typeCache = new WeakMap();
function resolveComponentTypeMetadata(type) {
    let metadata = typeCache.get(type);
    if (metadata)
        return metadata;
    const mirror = reflectComponentType(type);
    if (!mirror) {
        throw new Error(`[@tanstack-table/angular] The provided symbol is not a component`);
    }
    const inputNames = new Map();
    const outputNames = new Set();
    for (const input of mirror.inputs) {
        inputNames.set(input.propName, input.templateName);
        if (input.templateName !== input.propName) {
            inputNames.set(input.templateName, input.templateName);
        }
    }
    for (const output of mirror.outputs) {
        // Outputs are read from the component instance, so only their class
        // property names are valid here. Template aliases are not instance keys.
        outputNames.add(output.propName);
    }
    metadata = { mirror, inputNames, outputNames };
    typeCache.set(type, metadata);
    return metadata;
}

/**
 * Creates and manages Angular component instances used by flex-rendered table
 * content.
 */
class FlexRenderComponentFactory {
    #viewContainerRef;
    constructor(viewContainerRef) {
        this.#viewContainerRef = viewContainerRef;
    }
    createComponent(flexRenderComponent, componentInjector) {
        const componentRef = this.#viewContainerRef.createComponent(flexRenderComponent.component, {
            injector: componentInjector,
            directives: flexRenderComponent.directives,
            bindings: flexRenderComponent.bindings,
        });
        const view = new FlexRenderComponentRef(componentRef, flexRenderComponent, componentInjector);
        const { inputs, outputs } = flexRenderComponent;
        if (inputs)
            view.setInputs(inputs);
        if (outputs)
            view.setOutputs(outputs);
        return view;
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FlexRenderComponentFactory, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FlexRenderComponentFactory });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FlexRenderComponentFactory, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i0.ViewContainerRef }] });
/**
 * Runtime wrapper around an Angular component rendered by `FlexRenderDirective`.
 *
 * It diffs inputs and outputs across table updates so component renderers can
 * be reused instead of recreated on every cell/header render.
 */
class FlexRenderComponentRef {
    componentRef;
    componentInjector;
    #componentData;
    #creationKey;
    #outputRegistry;
    constructor(componentRef, componentData, componentInjector) {
        this.componentRef = componentRef;
        this.componentInjector = componentInjector;
        this.#componentData = componentData;
        this.#creationKey = componentData.key;
        this.#outputRegistry = new FlexRenderComponentOutputManager();
        this.componentRef.onDestroy(() => this.#outputRegistry.unsubscribeAll());
    }
    get component() {
        return this.#componentData.component;
    }
    get inputs() {
        return this.#componentData.inputs ?? {};
    }
    get outputs() {
        return this.#componentData.outputs ?? {};
    }
    /**
     *
     * @param compare Whether the current ref component instance is the same as the given one
     */
    eqType(compare) {
        return compare.component === this.component;
    }
    canReuse(compare) {
        return this.eqType(compare) && Object.is(compare.key, this.#creationKey);
    }
    /**
     * Tries to update current component refs input by the new given content component.
     */
    update(content) {
        if (!this.canReuse(content))
            return;
        this.#syncInputs(content.inputs ?? {});
        this.#syncOutputs(content.outputs ?? {});
        this.#componentData = content;
    }
    markAsDirty() {
        this.componentRef.injector.get(ChangeDetectorRef).markForCheck();
    }
    setInputs(inputs) {
        for (const prop of Object.keys(inputs)) {
            this.setInput(prop, inputs[prop]);
        }
    }
    setInput(key, value) {
        const inputName = this.#componentData.metadata.inputNames.get(key);
        if (inputName === undefined)
            return;
        this.componentRef.setInput(inputName, value);
    }
    setOutputs(outputs) {
        this.#outputRegistry.unsubscribeAll();
        for (const prop of Object.keys(outputs)) {
            this.setOutput(prop, outputs[prop]);
        }
    }
    setOutput(key, emit) {
        if (!this.#componentData.metadata.outputNames.has(key))
            return;
        const outputName = key;
        if (!emit) {
            this.#outputRegistry.unsubscribe(outputName);
            return;
        }
        // If the output was already subscribed, just swap the listener callback.
        const hasSubscription = this.#outputRegistry.hasSubscription(outputName);
        this.#outputRegistry.setListener(outputName, emit);
        if (hasSubscription) {
            return;
        }
        const instance = this.componentRef.instance;
        const output = instance[outputName];
        if (output && output instanceof OutputEmitterRef) {
            this.#outputRegistry.setSubscription(outputName, output.subscribe((value) => {
                this.#outputRegistry.getListener(outputName)?.(value);
            }));
        }
    }
    #syncInputs(newInputs) {
        // Inputs use patch semantics: omitted keys keep their current value, while
        // an explicitly provided `undefined` is forwarded to Angular.
        for (const prop of Object.keys(newInputs)) {
            this.setInput(prop, newInputs[prop]);
        }
    }
    #syncOutputs(outputs) {
        const outputKeys = Object.keys(outputs);
        const currentSubscribedKeys = this.#outputRegistry.getSubscribedKeys();
        // When outputs updates, unsubscribe missing keys
        for (const key of currentSubscribedKeys) {
            if (!outputKeys.includes(key)) {
                this.#outputRegistry.unsubscribe(key);
            }
        }
        for (const prop of outputKeys) {
            this.setOutput(prop, outputs[prop]);
        }
    }
}
class FlexRenderComponentOutputManager {
    #outputSubscribers = new Map();
    #outputListeners = new Map();
    getSubscribedKeys() {
        return Array.from(this.#outputListeners.keys());
    }
    hasSubscription(outputName) {
        return this.#outputSubscribers.has(outputName);
    }
    setListener(outputName, callback) {
        this.#outputListeners.set(outputName, callback);
    }
    getListener(outputName) {
        return this.#outputListeners.get(outputName);
    }
    setSubscription(outputName, subscription) {
        this.#outputSubscribers.set(outputName, subscription);
    }
    unsubscribeAll() {
        for (const outputName of this.#outputListeners.keys()) {
            this.unsubscribe(outputName);
        }
    }
    unsubscribe(outputName) {
        this.#outputSubscribers.get(outputName)?.unsubscribe();
        this.#outputSubscribers.delete(outputName);
        this.#outputListeners.delete(outputName);
    }
}

/**
 * Normalizes arbitrary Angular flex-render content into the renderer's internal
 * tagged representation.
 *
 * This lets the directive decide whether to reuse, update, or recreate an
 * embedded view or component view.
 */
function mapToFlexRenderTypedContent(content) {
    if (content === null || content === undefined) {
        return { kind: 'null' };
    }
    if (typeof content === 'string' || typeof content === 'number') {
        return { kind: 'primitive', content };
    }
    if (content instanceof FlexRenderComponentInstance) {
        return { kind: 'flexRenderComponent', content };
    }
    else if (content instanceof TemplateRef) {
        return { kind: 'templateRef', content };
    }
    else if (content instanceof Type) {
        return { kind: 'component', content };
    }
    else {
        return { kind: 'primitive', content };
    }
}
class FlexRenderView {
    view;
    #content;
    constructor(initialContent, view) {
        this.#content = initialContent;
        this.view = view;
    }
    get content() {
        return this.#content;
    }
    set content(content) {
        this.#content = content;
    }
}
/**
 * Tracks an Angular embedded template view rendered by `FlexRenderDirective`.
 *
 * Template views receive updated props through their proxied context and can be
 * reused while the rendered content kind stays compatible.
 */
class FlexRenderTemplateView extends FlexRenderView {
    constructor(initialContent, view) {
        super(initialContent, view);
    }
    updateProps(_props) {
        if (this.content.kind === 'templateRef') {
            // Template contexts are getter-backed. Mark the embedded view so Angular
            // reads the latest props; the context object itself does not need to be
            // replaced.
            this.view.markForCheck();
        }
    }
    dirtyCheck() {
        if (this.content.kind === 'primitive') {
            // Primitive contexts are getter-backed too. The renderer has already
            // memoized the new value, so checking the view is enough to refresh
            // `$implicit` without mutating the context.
            this.view.markForCheck();
        }
    }
    unmount() {
        this.view.destroy();
    }
    canReuse(compare) {
        return ((this.content.kind === 'primitive' && compare.kind === 'primitive') ||
            (this.content.kind === 'templateRef' &&
                compare.kind === 'templateRef' &&
                this.content.content === compare.content));
    }
}
/**
 * Tracks an Angular component view rendered by `FlexRenderDirective`.
 *
 * Component views own input/output updates for `flexRenderComponent(...)`
 * results and component classes rendered directly from column definitions.
 */
class FlexRenderComponentView extends FlexRenderView {
    constructor(initialContent, view) {
        super(initialContent, view);
    }
    updateProps(props) {
        switch (this.content.kind) {
            case 'component': {
                this.view.setInputs(props);
                break;
            }
            case 'flexRenderComponent': {
                // No-op. A props change can produce a new wrapper descriptor; its
                // inputs and outputs are synchronized by `dirtyCheck`.
                break;
            }
        }
    }
    dirtyCheck() {
        switch (this.content.kind) {
            case 'component': {
                // Component context is currently valuated with the cell context. Since it's reference
                // shouldn't change, we force mark the component as dirty in order to re-evaluate function invocation in view.
                // NOTE: this should behave like having a component with ChangeDetectionStrategy.Default
                this.view.markAsDirty();
                break;
            }
            case 'flexRenderComponent': {
                // Render functions commonly create a new descriptor on every run. If
                // its type and key still identify the mounted instance, update that
                // instance instead of recreating the component view.
                if (this.view.eqType(this.content.content)) {
                    this.view.update(this.content.content);
                }
                this.view.markAsDirty();
                break;
            }
        }
    }
    unmount() {
        this.view.componentRef.destroy();
    }
    canReuse(compare) {
        return ((this.content.kind === 'component' &&
            compare.kind === 'component' &&
            this.content.content === compare.content) ||
            (this.content.kind === 'flexRenderComponent' &&
                compare.kind === 'flexRenderComponent' &&
                this.view.canReuse(compare.content)));
    }
}

/**
 * Internal view renderer used by Angular TanStack Table to implement `flexRender` directives.
 *
 * @internal Use FlexRender directives instead.
 */
class FlexViewRenderer {
    #renderFlags = FlexRenderFlags.ViewFirstRender;
    #renderView = null;
    #outerRenderEffectRef = null;
    #currentRenderEffectRef = null;
    #content;
    #props;
    #injector;
    #viewContainerRef;
    #templateRef;
    #flexRenderComponentFactory;
    #getLatestContentValue = () => {
        const content = this.#content();
        const props = this.#props();
        return typeof content !== 'function'
            ? content
            : runInInjectionContext(this.#injector(), () => content(props));
    };
    #latestContent = computed(() => this.#getLatestContentValue(), /* @ts-ignore */
    ...(ngDevMode ? [{ debugName: "#latestContent" }] : /* istanbul ignore next */ []));
    #getContentValue = computed(() => {
        return mapToFlexRenderTypedContent(this.#latestContent());
    }, /* @ts-ignore */
    ...(ngDevMode ? [{ debugName: "#getContentValue" }] : /* istanbul ignore next */ []));
    constructor(options) {
        this.#content = options.content;
        this.#props = options.props;
        this.#injector = options.injector;
        this.#templateRef = options.templateRef;
        this.#viewContainerRef = options.viewContainerRef;
        this.#flexRenderComponentFactory = new FlexRenderComponentFactory(this.#viewContainerRef);
    }
    mount() {
        if (this.#outerRenderEffectRef) {
            return this.#outerRenderEffectRef;
        }
        let previousContent;
        let previousProps;
        this.#outerRenderEffectRef = effect(() => {
            const props = this.#props();
            const content = this.#content();
            if (!(this.#renderFlags & FlexRenderFlags.ViewFirstRender)) {
                if (previousContent !== content) {
                    // A new content input may install a different render function (or
                    // stop rendering a function), so its dependency effect must be
                    // replaced. Incompatible values returned by the same function only
                    // recreate the view and keep the existing effect.
                    this.#destroyContentEffect();
                    this.#renderFlags |= FlexRenderFlags.ContentChanged;
                }
                if (previousProps !== props) {
                    this.#renderFlags |= FlexRenderFlags.PropsReferenceChanged;
                }
            }
            untracked(() => this.#update());
            if (this.#renderFlags & FlexRenderFlags.ViewFirstRender) {
                this.#renderFlags &= ~FlexRenderFlags.ViewFirstRender;
            }
            previousContent = content;
            previousProps = props;
        }, { ...(ngDevMode ? { debugName: "#outerRenderEffectRef" } : /* istanbul ignore next */ {}), injector: this.#viewContainerRef.injector });
        return this.#outerRenderEffectRef;
    }
    destroy() {
        if (this.#outerRenderEffectRef) {
            this.#outerRenderEffectRef.destroy();
            this.#outerRenderEffectRef = null;
        }
        this.#destroyContentEffect();
        this.#destroyView();
        this.#renderFlags = FlexRenderFlags.ViewFirstRender;
    }
    #destroyContentEffect() {
        if (this.#currentRenderEffectRef) {
            this.#currentRenderEffectRef.destroy();
            this.#currentRenderEffectRef = null;
        }
        this.#renderFlags &= ~FlexRenderFlags.RenderEffectChecked;
    }
    #update() {
        if (this.#renderFlags &
            (FlexRenderFlags.ContentChanged | FlexRenderFlags.ViewFirstRender)) {
            this.#render();
            return;
        }
        if (this.#renderFlags & FlexRenderFlags.PropsReferenceChanged) {
            this.#renderView?.updateProps(this.#props());
            this.#renderFlags &= ~FlexRenderFlags.PropsReferenceChanged;
        }
        if (this.#renderFlags & FlexRenderFlags.Dirty) {
            this.#renderView?.dirtyCheck();
            this.#renderFlags &= ~FlexRenderFlags.Dirty;
        }
    }
    #render() {
        // Resolved content can require a new view without changing the render
        // function. Preserve its effect and checked state across that replacement.
        this.#destroyView();
        this.#renderFlags &=
            FlexRenderFlags.ViewFirstRender | FlexRenderFlags.RenderEffectChecked;
        const content = this.#getContentValue();
        this.#renderView = this.#renderViewByContent(content);
        // Render functions can read signals. Keep their dependency tracking in a
        // dedicated effect so the outer effect remains responsible only for
        // content and props input-reference changes.
        if (!this.#currentRenderEffectRef &&
            typeof untracked(this.#content) === 'function') {
            this.#currentRenderEffectRef = effect(() => {
                const latestContent = this.#getContentValue();
                if (!(this.#renderFlags & FlexRenderFlags.RenderEffectChecked)) {
                    this.#renderFlags |= FlexRenderFlags.RenderEffectChecked;
                    return;
                }
                untracked(() => {
                    this.#renderFlags |= FlexRenderFlags.Dirty;
                    this.#doCheck(latestContent);
                });
            }, { ...(ngDevMode ? { debugName: "#currentRenderEffectRef" } : /* istanbul ignore next */ {}), injector: this.#viewContainerRef.injector });
        }
    }
    #doCheck(latestContent) {
        if (latestContent.kind === 'null' ||
            !this.#renderView ||
            !this.#renderView.canReuse(latestContent)) {
            this.#renderFlags |= FlexRenderFlags.ContentChanged;
        }
        else {
            this.#renderView.content = latestContent;
        }
        this.#update();
    }
    #destroyView() {
        if (this.#renderView) {
            this.#renderView.unmount();
            this.#renderView = null;
        }
    }
    #renderViewByContent(content) {
        if (content.kind === 'primitive') {
            return this.#renderStringContent(content);
        }
        else if (content.kind === 'templateRef') {
            return this.#renderTemplateRefContent(content);
        }
        else if (content.kind === 'flexRenderComponent') {
            return this.#renderComponent(content);
        }
        else if (content.kind === 'component') {
            return this.#renderCustomComponent(content);
        }
        return null;
    }
    #renderStringContent(template) {
        const latestContent = () => untracked(this.#getContentValue);
        const ref = this.#viewContainerRef.createEmbeddedView(this.#templateRef, {
            get $implicit() {
                // The view can be checked while an incompatible replacement is being
                // scheduled. Only expose content that still belongs to this context.
                const content = latestContent();
                return content.kind === 'primitive' ? content.content : undefined;
            },
        });
        return new FlexRenderTemplateView(template, ref);
    }
    #renderTemplateRefContent(template) {
        const latestProps = () => untracked(this.#props);
        const view = this.#viewContainerRef.createEmbeddedView(template.content, {
            get $implicit() {
                return latestProps();
            },
        }, { injector: this.#getInjector() });
        return new FlexRenderTemplateView(template, view);
    }
    #renderComponent(flexRenderComponent) {
        const componentInjector = this.#getInjector(flexRenderComponent.content.injector);
        const view = this.#flexRenderComponentFactory.createComponent(flexRenderComponent.content, componentInjector);
        return new FlexRenderComponentView(flexRenderComponent, view);
    }
    #renderCustomComponent(component) {
        const instance = flexRenderComponent(component.content, {
            inputs: this.#props(),
        });
        const injector = this.#getInjector(instance.injector);
        const view = this.#flexRenderComponentFactory.createComponent(instance, injector);
        return new FlexRenderComponentView(component, view);
    }
    #getInjector(parentInjector) {
        const getContext = () => this.#props();
        const proxy = new Proxy(this.#props(), {
            get: (_, key) => getContext()[key],
        });
        const staticProviders = [];
        if ('table' in proxy) {
            staticProviders.push({
                provide: TanStackTableToken,
                useValue: () => proxy.table,
            });
        }
        if ('cell' in proxy) {
            staticProviders.push({
                provide: TanStackTableCellToken,
                useValue: () => proxy.cell,
            });
        }
        if ('header' in proxy) {
            staticProviders.push({
                provide: TanStackTableHeaderToken,
                useValue: () => proxy.header,
            });
        }
        return Injector.create({
            parent: parentInjector ?? this.#injector(),
            providers: [
                ...staticProviders,
                { provide: FlexRenderComponentProps, useValue: proxy },
            ],
        });
    }
}

/**
 * Simplified directive wrapper of `*flexRender`.
 *
 * Use this utility component to render headers, cells, or footers with custom markup.
 *
 * Only one prop (`cell`, `header`, or `footer`) may be passed based on the used selector.
 *
 * @example
 * ```html
 * <td *flexRenderCell="cell; let cell">{{cell}}</td>
 * <th *flexRenderHeader="header; let header">{{header}}</th>
 * <th *flexRenderFooter="footer; let footer">{{footer}}</th>
 * ```
 *
 * This replaces calling `*flexRender` directly like this:
 * ```html
 * <td *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let cell">{{cell}}</td>
 * <td *flexRender="header.column.columnDef.header; props: header.getContext(); let header">{{header}}</td>
 * <td *flexRender="footer.column.columnDef.footer; props: footer.getContext(); let footer">{{footer}}</td>
 * ```
 *
 * Can be imported through {@link FlexRenderCell} or {@link FlexRender}, with
 * the latter preferred.
 *
 * @example
 * ```ts
 * import {FlexRender} from '@tanstack/angular-table'
 *
 * @Component({
 *  // ...
 *  imports: [
 *    FlexRender
 *  ]
 * })
 * ```
 */
class FlexRenderCell {
    cell = input(undefined, { ...(ngDevMode ? { debugName: "cell" } : /* istanbul ignore next */ {}), alias: 'flexRenderCell' });
    header = input(undefined, { ...(ngDevMode ? { debugName: "header" } : /* istanbul ignore next */ {}), alias: 'flexRenderHeader' });
    footer = input(undefined, { ...(ngDevMode ? { debugName: "footer" } : /* istanbul ignore next */ {}), alias: 'flexRenderFooter' });
    #renderData = computed(() => {
        const cell = this.cell();
        const header = this.header();
        const footer = this.footer();
        if (cell) {
            const def = cell.column.columnDef;
            const groupingCell = cell;
            const groupingDef = def;
            if (groupingCell.getIsAggregated?.()) {
                return [groupingDef.aggregatedCell ?? def.cell, cell.getContext()];
            }
            if (groupingCell.getIsPlaceholder?.()) {
                return [null, null];
            }
            return [cell.column.columnDef.cell, cell.getContext()];
        }
        if (header) {
            return [header.column.columnDef.header, header.getContext()];
        }
        if (footer) {
            return [footer.column.columnDef.footer, footer.getContext()];
        }
        return [null, null];
    }, { ...(ngDevMode ? { debugName: "#renderData" } : /* istanbul ignore next */ {}), equal: (a, b) => {
            return a[0] === b[0] && a[1] === b[1];
        } });
    #injector = inject(Injector);
    #templateRef = inject(TemplateRef);
    #viewContainerRef = inject(ViewContainerRef);
    constructor() {
        const content = computed(() => this.#renderData()[0], /* @ts-ignore */
        ...(ngDevMode ? [{ debugName: "content" }] : /* istanbul ignore next */ []));
        const props = computed(() => this.#renderData()[1], /* @ts-ignore */
        ...(ngDevMode ? [{ debugName: "props" }] : /* istanbul ignore next */ []));
        const renderer = new FlexViewRenderer({
            content: content,
            props: props,
            injector: () => this.#injector,
            templateRef: this.#templateRef,
            viewContainerRef: this.#viewContainerRef,
        });
        renderer.mount();
        inject(DestroyRef).onDestroy(() => {
            renderer.destroy();
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FlexRenderCell, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.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 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FlexRenderCell, decorators: [{
            type: Directive,
            args: [{
                    selector: 'ng-template[flexRenderCell], ng-template[flexRenderFooter], ng-template[flexRenderHeader]',
                }]
        }], 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 }] }] } });

/**
 * Use this utility directive to render headers, cells, or footers with custom markup.
 *
 * Note: If you are rendering cell, header, or footer without custom context or other props,
 * you can use the {@link FlexRenderCell} directive as shorthand instead .
 *
 * @example
 * ```ts
 * import {FlexRender} from '@tanstack/angular-table';
 *
 * @Component({
 *   imports: [FlexRender],
 *   template: `
 *      <td
 *        *flexRender="
 *          cell.column.columnDef.cell;
 *          props: cell.getContext();
 *          let cell"
 *      >
 *        {{cell}}
 *      </td>
 *
 *      <th
 *        *flexRender="
 *          header.column.columnDef.header;
 *          props: header.getContext();
 *          let header"
 *        >
 *        {{header}}
 *      </td>
 *
 *      <td
 *        *flexRender="
 *          footer.column.columnDef.footer;
 *          props: footer.getContext();
 *          let footer"
 *      >
 *        {{footer}}
 *      </td>
 *   `,
 * })
 * class App {
 * }
 * ```
 *
 * Can be imported through {@link FlexRenderDirective} or {@link FlexRender},
 * with the latter preferred.
 */
class FlexRenderDirective {
    content = input(undefined, { ...(ngDevMode ? { debugName: "content" } : /* istanbul ignore next */ {}), alias: 'flexRender' });
    props = input({}, { ...(ngDevMode ? { debugName: "props" } : /* istanbul ignore next */ {}), alias: 'flexRenderProps' });
    injector = input(inject(Injector), { ...(ngDevMode ? { debugName: "injector" } : /* istanbul ignore next */ {}), alias: 'flexRenderInjector' });
    #viewContainerRef = inject(ViewContainerRef);
    #templateRef = inject(TemplateRef);
    constructor() {
        const renderer = new FlexViewRenderer({
            content: this.content,
            props: this.props,
            injector: this.injector,
            templateRef: this.#templateRef,
            viewContainerRef: this.#viewContainerRef,
        });
        renderer.mount();
        inject(DestroyRef).onDestroy(() => {
            renderer.destroy();
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FlexRenderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.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 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FlexRenderDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: 'ng-template[flexRender]',
                }]
        }], 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 }] }] } });

function lazyInit(initializer) {
    assertInInjectionContext(lazyInit);
    let object = null;
    const initializeObject = () => {
        if (!object) {
            object = untracked(() => initializer());
        }
    };
    effect(() => initializeObject(), {
        debugName: 'tableLazyInitEffect',
    });
    const table = () => { };
    const proxy = new Proxy(table, {
        apply(target, thisArg, argArray) {
            initializeObject();
            if (typeof object === 'function') {
                return Reflect.apply(object, thisArg, argArray);
            }
            return Reflect.apply(target, thisArg, argArray);
        },
        get(_, prop, receiver) {
            initializeObject();
            return Reflect.get(object, prop, receiver);
        },
        has(_, prop) {
            initializeObject();
            return Reflect.has(object, prop);
        },
        ownKeys() {
            initializeObject();
            return Reflect.ownKeys(object);
        },
        getOwnPropertyDescriptor() {
            return {
                enumerable: true,
                configurable: true,
            };
        },
    });
    return {
        value: proxy,
        get rawValue() {
            return object;
        },
        get initialized() {
            return !!object;
        },
    };
}

function signalToReadonlyAtom(signal, injector, debugName) {
    const _signal = Object.assign(signal, {
        get: () => signal(),
        subscribe: (observer) => {
            return untracked(() => toObservable(signal, { injector: injector }).subscribe(observer));
        },
    });
    if (debugName) {
        _signal.toString = () => debugName;
    }
    return _signal;
}
function signalToWritableAtom(signal, injector, debugName) {
    const _signal = Object.assign(signal.asReadonly(), {
        set: (updater) => {
            typeof updater === 'function'
                ? signal.update(updater)
                : signal.set(updater);
        },
        get: () => signal(),
        subscribe: (observer) => {
            return untracked(() => toObservable(signal, { injector: injector }).subscribe(observer));
        },
    });
    if (debugName) {
        _signal.toString = () => debugName;
    }
    return _signal;
}
/**
 * Creates the table-core reactivity bindings used by the Angular adapter.
 *
 * Table state atoms are backed by TanStack Store atoms. The options store stays
 * framework-native because row-model APIs read `table.options` directly during
 * render. Readonly table atoms bridge Store dependency tracking into Angular
 * computed signals.
 */
function angularReactivity(injector) {
    const ngZone = injector.get(NgZone);
    const subscriptions = new Set();
    return {
        createOptionsStore: true,
        wrapExternalAtoms: true,
        addSubscription: (subscription) => {
            subscriptions.add(subscription);
        },
        unmount: () => {
            subscriptions.forEach((s) => s.unsubscribe());
            subscriptions.clear();
        },
        schedule: (fn) => ngZone.runOutsideAngular(() => queueMicrotask(fn)),
        createReadonlyAtom: (fn, options) => {
            const signal = computed(() => fn(), {
                equal: options?.compare,
                debugName: options?.debugName,
            });
            return signalToReadonlyAtom(signal, injector, options?.debugName);
        },
        createWritableAtom: (value, options) => {
            const writableSignal = signal(value, {
                equal: options?.compare,
                debugName: options?.debugName,
            });
            return signalToWritableAtom(writableSignal, injector, options?.debugName);
        },
        untrack: untracked,
        batch: (fn) => fn(),
    };
}

/**
 * Creates and returns an Angular-reactive table instance.
 *
 * The initializer is intentionally re-evaluated whenever any signal read inside it changes.
 * This is how the adapter keeps the table in sync with Angular's reactivity model.
 *
 * Because of that behavior, keep expensive/static values (for example `columns`, feature setup, row models)
 * as stable references outside the initializer, and only read reactive state (`data()`, pagination/filter/sorting signals, etc.)
 * inside it.
 *
 * 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(...)`.
 *
 * @example
 * 1. Register the table features you need
 * ```ts
 * // Register only the features you need
 * import {tableFeatures, rowPaginationFeature} from '@tanstack/angular-table';
 * const features = tableFeatures({
 *  rowPaginationFeature,
 *  // ...all other features you need
 * })
 *
 * // Use all table core features
 * import {stockFeatures} from '@tanstack/angular-table';
 * const features = tableFeatures(stockFeatures);
 * ```
 * 2. Prepare the table columns
 * ```ts
 * import {ColumnDef} from '@tanstack/angular-table';
 *
 * type MyData = {}
 *
 * const columns: ColumnDef<typeof features, MyData>[] = [
 *   // ...column definitions
 * ]
 *
 * // or using createColumnHelper
 * import {createColumnHelper} from '@tanstack/angular-table';
 * const columnHelper = createColumnHelper<typeof features, MyData>();
 * const columns = columnHelper.columns([
 *  columnHelper.accessor(...),
 *  // ...other columns
 * ])
 * ```
 * 3. Create the table instance with `injectTable`
 * ```ts
 * const table = injectTable(() => {
 *   // ...table options,
 *   features,
 *   columns: columns,
 *   data: myDataSignal(),
 * })
 * ```
 *
 * @returns An Angular-reactive TanStack Table instance.
 */
function injectTable(optionsFactory) {
    assertInInjectionContext(injectTable);
    const injector = inject(Injector);
    const ngZone = inject(NgZone);
    const destroyRef = inject(DestroyRef);
    const options = computed(() => optionsFactory(), /* @ts-ignore */
    ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
    const coreReactivityFeature = angularReactivity(injector);
    const lazyTable = ngZone.runOutsideAngular(() => lazyInit(() => {
        const currentOptions = options();
        const features = {
            coreReactivityFeature,
            ...currentOptions.features,
        };
        return constructTable({
            ...currentOptions,
            features,
        });
    }));
    destroyRef.onDestroy(() => {
        if (lazyTable.initialized) {
            lazyTable.value._reactivity.unmount?.();
        }
    });
    let previousOptions = undefined;
    effect(() => {
        const currentOptions = options();
        // rawValue will be always valued here due to internal lazyInit effect
        const tableInstance = lazyTable.rawValue;
        if (previousOptions === currentOptions)
            return;
        untracked(() => tableInstance.setOptions((previous) => ({
            ...previous,
            ...currentOptions,
        })));
        previousOptions = currentOptions;
    }, { injector, debugName: 'tableOptionsUpdate' });
    return lazyTable.value;
}

/**
 * Creates app-scoped Angular table helpers with features, row models, and
 * renderable component maps pre-bound.
 *
 * Use this when an app or design system wants typed `injectAppTable`,
 * pre-bound column helpers, and typed table/cell/header context injection
 * helpers without repeating the same feature and component generics.
 *
 * @example
 * ```ts
 * const { injectAppTable, createAppColumnHelper } = createTableHook({
 *   features,
 *   tableComponents: {},
 *   cellComponents: {},
 *   headerComponents: {},
 * })
 * ```
 */
function createTableHook({ tableComponents, cellComponents, headerComponents, ...defaultTableOptions }) {
    function injectTableContext$1() {
        // `injectAppTable` Object.assign-es `tableComponents` onto the same table
        // instance it returns (via `constructTableAPIs`), and that instance is what
        // gets provided to DI, so this asserts the runtime shape.
        return injectTableContext();
    }
    function injectTableHeaderContext$1() {
        // `injectAppTable` Object.assign-es `headerComponents` onto the header
        // prototype (via `assignHeaderPrototype`), so every header instance carries
        // them. This asserts the runtime shape.
        return injectTableHeaderContext();
    }
    function injectTableCellContext$1() {
        // `injectAppTable` Object.assign-es `cellComponents` onto the cell prototype
        // (via `assignCellPrototype`), so every cell instance carries them. This
        // asserts the runtime shape.
        return injectTableCellContext();
    }
    function injectFlexRenderHeaderContext() {
        return injectFlexRenderContext();
    }
    function injectFlexRenderCellContext() {
        return injectFlexRenderContext();
    }
    function injectAppTable(tableOptions) {
        function appCell(cell) {
            return cell;
        }
        function appHeader(header) {
            return header;
        }
        function appFooter(footer) {
            return footer;
        }
        const appTableFeatures = {
            constructTableAPIs: (table) => {
                Object.assign(table, tableComponents, { appCell, appHeader, appFooter });
            },
            assignCellPrototype(prototype) {
                Object.assign(prototype, cellComponents);
            },
            assignHeaderPrototype(prototype) {
                Object.assign(prototype, headerComponents);
            },
        };
        return injectTable(() => {
            return {
                ...defaultTableOptions,
                ...tableOptions(),
                features: {
                    ...defaultTableOptions.features,
                    appTableFeatures,
                },
            };
        });
    }
    function createAppColumnHelper() {
        // The runtime implementation is the same - components are attached at render time
        // This cast provides the enhanced types for column definitions
        return createColumnHelper();
    }
    return {
        createAppColumnHelper,
        injectTableContext: injectTableContext$1,
        injectTableHeaderContext: injectTableHeaderContext$1,
        injectTableCellContext: injectTableCellContext$1,
        injectFlexRenderHeaderContext,
        injectFlexRenderCellContext,
        injectAppTable,
    };
}

/**
 * Constant helper to import FlexRender directives.
 *
 * You should prefer to use this constant over importing the directives separately,
 * as it ensures you always have the correct set of directives over library updates.
 *
 * @see {@link FlexRenderDirective} and {@link FlexRenderCell} for more details on the directives included in this export.
 */
const FlexRender = [FlexRenderDirective, FlexRenderCell];

/**
 * Generated bundle index. Do not edit.
 */

export { FlexRender, FlexRenderCell, FlexRenderComponentInstance, FlexRenderDirective, TanStackTable, TanStackTableCell, TanStackTableCellToken, TanStackTableHeader, TanStackTableHeaderToken, TanStackTableToken, createTableHook, flexRenderComponent, injectFlexRenderContext, injectTable, injectTableCellContext, injectTableContext, injectTableHeaderContext };
//# sourceMappingURL=tanstack-angular-table.mjs.map