/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { Host, readTask, } from "@stencil/core";
import { h, transformTag } from "../../utils/renderer";
import { cyrb53 } from "../../utils/math";
import { debounce } from "../../utils/throttle";
import { findScrollParent, isInViewport } from "../../utils/scroll";
import { perMark } from "../../utils/performance";
import { TableColHead } from "./table.header";
import { TableRow, TableHeadFootRow } from "./table.row";
import { TableCell } from "./table.cell";
import { CSSNAMESPACE } from "./table.constants";
import { generateStore, storeSearch, storeSetConfig, storeSetData, storeSort, storeFilter, } from "./table.store";
import { TablePinService } from "./table.pin-service";
const measurePerf = false;
let id = 0;
/**
 * Enables the search, filter and sort of tabular data.
 *
 * @version 3.0.0
 * @status stable
 *
 * @slot caption - The table's caption. You must either use this or the `caption` attribute.
 * @slot no-results - text to display when search or filtering yields no results
 */
export class NanoDataTable {
    constructor() {
        this.debounceSetLoading = debounce(this.debounceSetLoading.bind(this), 50);
    }
    // Public API
    // Props
    /** Function called whenever `col.cellTemplate` renders an unknown object.
     * The function should render a valid HTMLElement to the cell arg.
     * Example usage - render JSX from a 3rd party lib and append the result to the cell element. */
    customRenderer;
    /** If true, will render any nested table in a scrollable container (using `overflow: auto`) */
    scrollable = false;
    /** A descriptive title of the table.
     * You must use this or the `slot="caption"` for accessibility */
    caption;
    /** Show the caption on-screen */
    showCaption = false;
    /** Will show a loading state when set to true.
     * By default, will be shown automatically if `rows` is a promise waiting to resolve / or falsy
     * *or* when performing custom filtering or sorting.
     * *Note* when set manually, will overwrite any internal loading state.
     * Set to 'undefined' to revert to default behaviour. */
    loading = undefined;
    get _loading() {
        return this.loading !== undefined ? this.loading : this.internalLoading;
    }
    set _loading(l) {
        if (this.loading !== undefined)
            return;
        this.debounceSetLoading(l);
    }
    debounceSetLoading(l) {
        this.internalLoading = l;
    }
    internalLoading = true;
    /** When loading rows asynchronously render this number of placeholder rows */
    placeholderSize = 10;
    /** The data to place in the table */
    rows;
    handleRowsChange() {
        if (!this.rows) {
            this._loading = true;
            return;
        }
        this._loading = true;
        Promise.resolve(this.rows).then(async (rows) => {
            await storeSetData(this.host, rows);
            // reset everything
            if (!this.customFilterApplied) {
                // if we have a custom filter applied (which causes new rows),
                // we don't want to reset filters as this will cause a loop
                this.currentFilters = '';
            }
            else {
                this.customFilterApplied = false;
            }
            this.currentSort = '';
            await this.columnInit();
            if (!this.isReady)
                requestAnimationFrame(() => this.setInitialBlockDimension());
            this._loading = false;
            if (this.tablePinnedService)
                this.tablePinnedService.assessRows();
        });
    }
    /** The column config used to present the rows of data */
    columns = [];
    async handleColsChange() {
        await storeSetConfig(this.host, this.columns);
        if (this.isReady)
            this.columnInit();
    }
    /** Used for custom thead row rendering */
    headRender = { pinned: 'top' };
    /** Used for custom row rendering */
    rowRender;
    /** Used for custom tfoot row rendering */
    footRender = { pinned: 'bottom' };
    /** Whether to show a `<tfoot>` component */
    showFooter = false;
    /** To improve performance, data is split into blocks
     * which are shown / hidden and rendered as they become visible.
     * Use this to control the number of hits within a block -
     * A block should fill a scrolling viewport.
     * The less perBlock the better for performance */
    perBlock = 50;
    /** The number of total blocks currently rendered in the table. @readonly */
    get blocksLength() {
        return this.blocks.length;
    }
    /** Term to search for in the data */
    searchTerm;
    /** A custom filtering function. Should return a promise.
     * If the promise resolves as `true` the column UI will be updated.
     * If the promise resolves as falsy, the sort will be performed by the component.
     * A good use-case would be performing the filter on a server / via fetch.
     * Then on success, updating the table's data via the `rows` property */
    customFilterFn;
    /** A custom sorting function. Should return a promise.
     * If the promise resolves as `true` the column UI will be updated.
     * If the promise resolves as falsey, the sort will be performed by the component.
     * A good use-case would be performing the sort on a server / via fetch.
     * Then on success, updating the table's data via the `rows` property */
    customSortFn;
    /**
     * The default sortable option for all columns.
     * `true` will enable column sorting unless you set `sortable: false` on a column
     * `false` will disable column sorting unless you set `sortable: true` on a column
     */
    defaultSort = true;
    handleSearchTermChange() {
        this.searchStart();
    }
    /** If true, will show a spinner at the bottom of the table when loading */
    showPaginateSpinner = false;
    /** Use this to render the table with roughly the correct dimensions.
     * a use-case might be; fetch a small initial dataset to minimise load-time,
     * render the table with the correct dimensions, the table becomes interactive,
     * load the rest of the data
     */
    virtualTotalItems = 0;
    virtualTotalItemsChangeHandler() {
        this.setBlocks();
    }
    /** @readonly - shows the currently applied filters */
    get appliedFilters() {
        return this.filters;
    }
    /** Fired when the table has done it's first complete render */
    nanoTblReady;
    /** Fired whenever a block is activated by scrolling into view / becoming visible
     * This could be leveraged for infinite scrolling / to fetch more data.
     */
    nanoTblBlockRendered;
    /** Fired before a column is sorted.
     * `event.preventDefault()` to stop sorting.  */
    nanoTblBeforeSort;
    /** Fired after a column is sorted */
    nanoTblAfterSort;
    /** Fired before a column is filtered.
     * `event.preventDefault()` to stop filtering. */
    nanoTblBeforeFilter;
    /** Fired after a column is sorted */
    nanoTblAfterFilter;
    /** Fired before a general search.
     * `event.preventDefault()` to stop searching.  */
    nanoTblBeforeSearch;
    /** Fired after a general / cross column search */
    nanoTblAfterSearch;
    /** Fired before a general search.
     * `event.preventDefault()` to stop searching.  */
    nanoTblBeforeEdit;
    /** Remove any column sorts currently applied
     * @returns a promise which resolves when complete */
    async resetSorting() {
        const col = this.columns.find((c) => !!c.order);
        if (!col)
            return;
        return this.sortStart(null, col.prop);
    }
    /** Apply a sort on a column
     * @returns a promise which resolves when complete */
    async addSort(column, order) {
        const col = this.columns.find((c) => c.prop === column);
        if (!col)
            throw new Error('Cannot find column with ' + column);
        return this.sortStart(order, col.prop);
    }
    /** Remove any column filters currently applied
     * @returns a promise which resolves when complete */
    async resetFilters() {
        this.filters = [];
        return this.filterStart();
    }
    /** Apply a filter on a column
     * @param filters - the filters to apply
     * @param additive - if true, will add the filters to any currently applied
     * @returns a promise which resolves when complete
     */
    async addFilters(filters, additive = true) {
        if (!additive)
            this.filters = [];
        return this.filterStart(filters, additive);
    }
    /** Remove filters from a column
     * @param columnNames - the filters to apply
     * @returns a promise which resolves when complete
     */
    async removeFilters(columnNames) {
        this.filters = this.filters.filter((f) => !columnNames.includes(f.prop));
        return this.filterStart();
    }
    /** Updates a row model at a given index
     * @param row - the row to update.
     * @param rowIndex - the row index to insert this row
     */
    async updateRow(row, rowIndex) {
        this.rows.splice(rowIndex, 1, row);
        this.handleRowsChange();
    }
    // TODO.
    // change this.rows to be a Map instead?
    // this will allow 'padding' < inserting row data at a non-adjacent index
    // /**
    //  * During pagination or infinite scroll
    //  * you may not always want to load data in serial order.
    //  * This method allows you to insert a block of results at a particular index.
    //  * Use in-conjunction with `virtualTotalItems`
    //  * @param blockIndex - where to insert
    //  * @param rows - what to insert
    //  */
    //  @Method()
    //  async insertBlock(blockIndex: number, rows: TableTypes.NanoTable['rows']) {
    //    this.pauseAutoBlockAssign = true;
    //    const cRows = (this.rows as TableTypes.NanoTable['rows']);
    //    if (cRows.length < (blockIndex * this.perBlock)) {
    //      (this.rows as TableTypes.NanoTable['rows'])
    //    }
    //    (this.rows as TableTypes.NanoTable['rows']).splice((blockIndex * this.perBlock)-1, 0, ...rows);
    //    console.log(this.rows)
    //    debugger;
    //    await this.handleRowsChange(this.rows);
    //    this.blocks[blockIndex] = {rows, __uuid: cyrb53(rows.map((b) => b.__uuid).join())};
    //    this.blocks = this.blocks;
    //    this.pauseAutoBlockAssign = true;
    //    console.log(this.rows, this.blocks)
    //  }
    // Private State
    host;
    renderId = 'tbl-' + id++;
    store;
    filters = [];
    currentFilters = '[]';
    currentSort = '';
    tableEle;
    topAnchorEle;
    activeWatcherIo;
    tablePinnedService;
    customFilterApplied = false;
    // Block view management
    /** `tr` elements split into units - defined by `perBlock`
      These are show / hidden for perf */
    blocks = [];
    activeBlocks = [0, 1];
    measureHeight = 0;
    blockElements;
    blockHeights = [];
    // uses the first 'tr' of an active block as our yard stick
    set measureEle(el) {
        if (!el)
            return;
        const potentialHeight = el.getBoundingClientRect().height;
        this.measureHeight =
            Math.abs(this.measureHeight - potentialHeight) < 5
                ? this.measureHeight
                : potentialHeight;
        this.unitHeight =
            el.querySelector('tr')?.getBoundingClientRect().height || this.unitHeight;
    }
    unitHeight = 0;
    get scrollParent() {
        return this._scrollParent;
    }
    set scrollParent(ele) {
        if (ele === this._scrollParent)
            return;
        if (this._scrollParent) {
            (this._scrollParent === document.documentElement
                ? document
                : this._scrollParent).removeEventListener('scroll', this.scrollHandler);
        }
        (ele === document.documentElement ? document : ele).addEventListener('scroll', this.scrollHandler);
        this._scrollParent = ele;
    }
    _scrollParent;
    // used to fire `nanoTblBlockRendered` on block render change
    get primaryBlockIndex() {
        return this._primaryBlockIndex;
    }
    set primaryBlockIndex(blockIndex) {
        if (this._primaryBlockIndex === blockIndex)
            return;
        this._primaryBlockIndex = blockIndex;
        // fire block change event
        this.nanoTblBlockRendered.emit({
            block: blockIndex,
            totalBlocks: this.blockElements.length,
        });
    }
    _primaryBlockIndex;
    // Misc.
    get isReady() {
        return this._isReady;
    }
    set isReady(ready) {
        if (ready === this._isReady)
            return;
        this._isReady = ready;
        if (this.isReady)
            requestAnimationFrame(() => this.handleReady());
    }
    _isReady = false;
    // Private Logic
    // Listeners
    handleReady() {
        const hash = window.location.hash;
        if (hash.length > 1) {
            try {
                const idRow = document.querySelector(hash);
                if (idRow)
                    idRow.scrollIntoView();
                // eslint-disable-next-line no-empty
            }
            catch (_e) { }
        }
        this.nanoTblReady.emit();
    }
    /**
     * Start a sort - can be cancelled by `preventDefault`
     * @param order - column order
     * @param column - column config object
     * @returns A promise
     */
    sortStart = async (order, column, element) => {
        // did order change?
        if (this.currentSort === order + ':' + column)
            return;
        this._loading = true;
        const sortEvent = this.nanoTblBeforeSort.emit({ column: column, order });
        if (sortEvent.defaultPrevented)
            return;
        perMark('sort');
        this.currentSort = order + ':' + column;
        // doesn't make sense to leave user in place for a sort
        this.scrollToTop(element);
        if (this.customSortFn) {
            try {
                const res = await this.customSortFn(column, order);
                // if the response is 'true', the custom sort did it's thing
                // handover to finish and stop loading state.
                // if response is falsey, carry on to do a FE sort
                if (res === true) {
                    this.sortComplete(order, column);
                    this._loading = false;
                    return;
                }
            }
            catch (e) {
                // if response errored, stop loading state
                // clear current sort cache
                console.warn('custom sort failed', e);
                this.currentSort = '';
                this._loading = false;
                return;
            }
        }
        try {
            await storeSort(this.host, column, order);
            this.sortComplete(order, column);
        }
        catch (e) {
            console.warn('sort failed', e);
            this.currentSort = '';
        }
        finally {
            if (this.blocks.length)
                this._loading = false;
        }
    };
    /**
     * Complete a sort. Reflects the order to ui.
     * @param order - column order
     * @param column - column config object
     */
    sortComplete(order, column) {
        this.columns = this.columns.map((c) => {
            if (c.prop === column)
                return { ...c, order };
            return { ...c, order: null };
        });
        this.nanoTblAfterSort.emit({ column: column, order });
        perMark('sort', true);
    }
    async searchStart() {
        this._loading = true;
        const sortEvent = this.nanoTblBeforeSearch.emit({ term: this.searchTerm });
        if (sortEvent.defaultPrevented)
            return;
        perMark('search');
        // doesn't make sense to leave user in place for a search
        this.scrollToTop();
        try {
            await storeSearch(this.host, this.searchTerm);
            this.nanoTblAfterSearch.emit({ term: this.searchTerm });
            perMark('search', true);
        }
        catch (e) {
            console.warn('search failed', e);
        }
        finally {
            this._loading = false;
        }
    }
    async filterStart(filters, additive = true) {
        if (filters) {
            if (additive) {
                this.filters = [
                    ...this.filters.filter((f) => !filters.find((ff) => ff.prop === f.prop)),
                    ...filters,
                ];
            }
            else {
                this.filters = filters;
            }
        }
        if (this.currentFilters === JSON.stringify(this.filters))
            return;
        this._loading = true;
        const sortEvent = this.nanoTblBeforeFilter.emit({ filters: this.filters });
        if (sortEvent.defaultPrevented)
            return;
        perMark('filter');
        this.currentFilters = JSON.stringify(this.filters);
        // doesn't make sense to leave user in place for a search
        this.scrollToTop();
        if (this.customFilterFn) {
            try {
                const res = await this.customFilterFn(this.filters);
                // if the response is 'true', the custom filter did it's thing
                // handover to finish and stop loading state.
                // if response is falsy, carry on to do a FE filter
                if (res === true) {
                    this.customFilterApplied = true;
                    await this.filterComplete();
                    this._loading = false;
                    return;
                }
            }
            catch (e) {
                // if response errored, stop loading state
                // clear current sort cache
                console.warn('custom filter failed', e);
                this.currentFilters = '';
                this._loading = false;
                return;
            }
        }
        try {
            await this.filterComplete();
        }
        catch (e) {
            console.warn('filter failed', e);
        }
        finally {
            this._loading = false;
        }
    }
    async filterComplete() {
        this.columns = this.columns.map((c) => {
            const cFilter = this.filters.find((f) => f.prop === c.prop);
            // if we found a filter AND
            // it isn't true / false and has a length OR
            // it is true or false
            if (cFilter &&
                ((typeof cFilter.filter !== 'boolean' && cFilter.filter.length) ||
                    typeof cFilter.filter === 'boolean'))
                c.filter = cFilter.filter;
            // if a filter value is not set OR
            // it isn't true / false and has no length
            else if ((c.filter !== null && c.filter !== undefined) ||
                (!!c.filter && typeof c.filter !== 'boolean' && !c.filter.length))
                c.filter = undefined;
            return c;
        });
        await storeFilter(this.host, this.filters);
        this.nanoTblAfterFilter.emit({ filters: this.filters });
        perMark('filter', true);
    }
    /** Scrolls to the top immediately - used whilst sorting / filtering */
    scrollToTop(element) {
        if (!this.scrollParent)
            return;
        const scrollBehaviour = this.scrollParent.style?.scrollBehavior;
        const scrollX = this.scrollParent.scrollLeft;
        this.scrollParent.style.scrollBehavior = 'auto';
        if (this.topAnchorEle && !isInViewport(this.topAnchorEle, 0.1)) {
            this.host.scrollIntoView();
        }
        if (element && !isInViewport(element, 1))
            setTimeout(() => element.scrollIntoView({ block: 'start' }), 500);
        if (scrollX)
            this.scrollParent.scrollLeft = scrollX;
        if (scrollBehaviour)
            this.scrollParent.style.scrollBehavior = scrollBehaviour;
        this.scrollHandler();
    }
    setMeasureElement() {
        return new Promise((resolve) => {
            readTask(() => {
                this.measureEle = this.blockElements.find((b) => !b?.classList?.contains(`${CSSNAMESPACE}__inactive`));
                resolve();
            });
        });
    }
    /**
     * Makes sure we have dimensions on at least one, active tbody element.
     * We'll use this is a yard stick for inactive tbody elements in future.
     * These elements have no natural height (on account of all their rows being hidden)
     */
    setInitialBlockDimension() {
        if (!this.blockElements?.length)
            return;
        perMark('blockDims');
        const testForDimensions = async () => {
            await this.setMeasureElement();
            if (this.unitHeight)
                return true;
            return false;
        };
        const dimensionsReady = new Promise((resolve) => {
            testForDimensions().then(async (ready) => {
                if (ready)
                    resolve();
                else {
                    // it's likely this table is hidden in the dom.
                    // we need to wait until it's visible
                    const observer = new IntersectionObserver(async () => {
                        if (await testForDimensions()) {
                            resolve();
                            observer.disconnect();
                        }
                    }, { root: this.scrollParent });
                    observer.observe(this.tableEle);
                }
            });
        });
        // we're all finished.
        dimensionsReady.then(() => {
            perMark('blockDims', true);
            perMark('init', true);
            requestAnimationFrame(() => (this.isReady = true));
        });
    }
    /** Apply initial columns settings */
    async columnInit() {
        this.filters = this.columns
            .filter((c) => c.filter !== undefined && c.filter !== null)
            .map((c) => {
            const { filter, prop } = c;
            return { prop, filter };
        });
        if (this.searchTerm) {
            await this.searchStart();
        }
        if (this.filters.length) {
            await this.filterStart();
        }
        // apply sort
        const col = this.columns.find((c) => !!c.order);
        if (col) {
            await this.sortStart(col.order, col.prop);
        }
        if (this.tablePinnedService)
            this.tablePinnedService.assessCols();
    }
    /** Split up all incoming rows into 'blocks' split amongst tbody elements.
     * These can then be hidden / shown to improve performance.
     */
    setBlocks() {
        const dRows = this.store.data.state.rows;
        if (!dRows.length) {
            this.blocks = [];
            return;
        }
        perMark('setBlocks');
        // this.ignoreIO = true;
        let i = 1;
        const l = this.virtualTotalItems > dRows.length
            ? this.virtualTotalItems
            : dRows.length;
        let rows = [];
        const blocks = [];
        // old skool loop for perf
        for (i; i <= l; i++) {
            rows.push(this.store.data.state.rows[i - 1] || { __uuid: '' });
            if (i % this.perBlock === 0) {
                // assign a UUID for the whole block
                // for block diffing
                blocks.push({ rows, __uuid: cyrb53(rows.map((b) => b.__uuid).join()) });
                rows = [];
            }
        }
        // any leftover rows
        if (rows.length) {
            blocks.push({ rows, __uuid: cyrb53(rows.map((b) => b.__uuid).join()) });
        }
        this.blocks = blocks;
        perMark('setBlocks', true);
    }
    /**
     * Returns a block render height.
     * If it's currently active - let auto do it's thing
     * If we've rendered it before - return that
     * If all else fails, let's guess it
     * @param blockIndex
     * @returns a height string (incl px)
     */
    getBlockHeight(blockIndex) {
        if (this.blockHeights.length) {
            const cachedBlockHeight = this.blockHeights.find((bh) => bh.blockIndex === blockIndex);
            if (cachedBlockHeight && cachedBlockHeight.height)
                return cachedBlockHeight.height;
        }
        const blockLength = this.blocks[blockIndex].rows.length;
        if (blockLength === this.perBlock && this.measureHeight) {
            return this.measureHeight;
        }
        return this.unitHeight ? this.unitHeight * blockLength : 100;
    }
    /** cache the height for all active blocks for later renders */
    setBlockHeight() {
        this.activeBlocks.forEach((blockIndex) => {
            const el = this.blockElements[blockIndex];
            if (!el)
                return;
            readTask(() => {
                if (el.classList.contains(`${CSSNAMESPACE}__inactive`))
                    return;
                const height = el.getBoundingClientRect().height;
                // cache height to our block heights array
                // for subsequent renders
                const fBhIdx = this.blockHeights.findIndex((bh) => bh.blockIndex === blockIndex);
                if (fBhIdx > -1) {
                    this.blockHeights[fBhIdx] = { height, blockIndex };
                }
                else
                    this.blockHeights.push({ height, blockIndex });
            });
        });
    }
    /**
     * On scroll, loop through all blocks' heights and cumulatively, add them together.
     * When we find that the scroll position is less than this cumulative block height -
     * stop loop - it's on the current active block.
     */
    scrollHandler = () => {
        let scrollPos = 0;
        perMark('scrollHandler');
        // don't listen if this table isn't in the viewport
        if (!this.store?.general.state.isActive || !this.rows)
            return;
        if (this.primaryBlockIndex === undefined)
            this.primaryBlockIndex = 0;
        readTask(() => {
            scrollPos =
                typeof this.scrollParent.scrollTop !== 'undefined'
                    ? this.scrollParent.scrollTop
                    : window.scrollY;
            scrollPos += this.host.offsetTop;
            if (this.tablePinnedService) {
                this.tablePinnedService.onScroll({
                    x: typeof this.scrollParent.scrollLeft !== 'undefined'
                        ? this.scrollParent.scrollLeft
                        : window.scrollX,
                    y: scrollPos,
                });
            }
            let cumulativeHeight = this.host.offsetTop;
            let blockIndex = 0;
            const blockLen = this.blocks.length;
            while (blockIndex < blockLen && scrollPos >= cumulativeHeight) {
                cumulativeHeight += this.getBlockHeight(blockIndex);
                if (scrollPos < cumulativeHeight) {
                    const potentialBlocks = [
                        blockIndex,
                        blockIndex + 1,
                        // Math.max(0, blockIndex - 1),
                    ];
                    if (potentialBlocks.toString() !== this.activeBlocks.toString()) {
                        this.activeBlocks = potentialBlocks;
                    }
                    this.primaryBlockIndex = blockIndex;
                }
                blockIndex++;
            }
            perMark('scrollHandler', true);
        });
    };
    /** Process slotted content */
    processSlots() {
        // see if we have slot content
        if (!this.caption && !this.host.querySelector('[slot="caption"]')) {
            console.error('For accessibility you must set a `caption` prop or use the `caption` slot');
        }
    }
    /** Adds an IO. Makes sure our scroll listener is only active when
     * the table is in viewport */
    setupActiveWatcher() {
        if (!this.host || !this.scrollParent || !this.store)
            return;
        if (this.activeWatcherIo) {
            this.activeWatcherIo.disconnect();
            this.activeWatcherIo = undefined;
        }
        const io = (this.activeWatcherIo = new IntersectionObserver(([e]) => {
            if (e.isIntersecting)
                this.store.general.state.isActive = true;
            else
                this.store.general.state.isActive = false;
        }, { root: this.scrollParent, threshold: 0 }));
        io.observe(this.scrollable ? this.tableEle : this.host);
    }
    // Component lifecycle
    async componentWillLoad() {
        perMark('init');
        // setup stores
        this.store = await generateStore(this.host, this.columns, this.scrollParent, this.isReady);
        this.handleRowsChange();
        this.store.general.onChange('isActive', () => {
            this.scrollHandler();
        });
        this.store.data.onChange('rows', () => this.setBlocks());
        // setup dom and attach listeners
        this.processSlots();
        this.setBlocks();
        if (!this.scrollable) {
            this.scrollParent = findScrollParent(this.host);
            this.setupActiveWatcher();
        }
    }
    connectedCallback() {
        if (!this.scrollable) {
            this.scrollParent = findScrollParent(this.host);
            this.setupActiveWatcher();
        }
    }
    componentDidLoad() {
        this.setInitialBlockDimension();
        if (this.scrollable) {
            this.scrollParent = this.host
                .querySelector(transformTag('nano-masked-overflow'))
                .shadowRoot.querySelector('.onav__scroller');
            this.setupActiveWatcher();
        }
        if (!this.tablePinnedService) {
            this.tablePinnedService = new TablePinService(this.tableEle, this.scrollParent);
        }
    }
    componentShouldUpdate(_newVal, _oldVal, stateName) {
        // stop double rendering - we use the store for rendering internally
        // the public facing props are kept in-sync with the store
        // but we don't want it to cause renders
        if (['rows', 'columns'].includes(stateName))
            return false;
        if (measurePerf)
            console.info(stateName, _newVal, _oldVal);
    }
    componentWillRender() {
        perMark('render');
    }
    componentDidRender() {
        this.setMeasureElement().then(() => this.setBlockHeight());
        perMark('render', true);
    }
    disconnectedCallback() {
        if (!this.activeWatcherIo)
            return;
        this.activeWatcherIo.disconnect();
        this.activeWatcherIo = undefined;
        (this.scrollParent === document.documentElement
            ? document
            : this.scrollParent).removeEventListener('scroll', this.scrollHandler);
    }
    render() {
        this.blockElements = [];
        const Wrap = (content) => {
            return this.scrollable ? (h("nano-masked-overflow", { hideScrollbars: false, scrollControls: false, label: this.caption }, content)) : (h("div", null, content));
        };
        return (h(Host, { class: "nano-data-table" }, h("div", { class: `${CSSNAMESPACE}__top-anchor`, ref: (a) => (this.topAnchorEle = a) }, "\u00A0"), h("nano-resize-observe", { onNanoResize: () => {
                if (this.tablePinnedService)
                    this.tablePinnedService.onResize();
            } }), Wrap(h("div", { class: `${CSSNAMESPACE}__wrap` }, h("nano-progress-bar", {
            // indeterminate
            class: {
                [`${CSSNAMESPACE}__progress-bar`]: true,
                [`${CSSNAMESPACE}__progress-bar--show`]: this._loading,
            }
        }, h("progress", null)), h("table", { "aria-rowcount": this.store.data.state.rows.length, "aria-colcount": this.store.config.state.columns.length, class: `${CSSNAMESPACE}`, ref: (tbl) => (this.tableEle = tbl), id: 'nano-data-table-' + this.renderId, "aria-busy": this._loading || undefined }, h("caption", { class: {
                [`${CSSNAMESPACE}__caption`]: true,
                [`${CSSNAMESPACE}__caption--hide`]: !this.showCaption,
            } }, h("slot", { name: "caption" }, this.caption)), h("thead", null, h(TableHeadFootRow, { rowRenderer: this.headRender }, this.store.config.state.columns.map((colModel) => [
            h(TableColHead, { column: colModel, headRenderer: this.headRender, onColumnSortClick: this.sortStart, defaults: {
                    sortable: this.defaultSort,
                } }),
        ]))), this._loading && !this.blocks.length && (h("tbody", { class: `${CSSNAMESPACE}__active ${CSSNAMESPACE}__loading` }, [...Array(this.placeholderSize).keys()].map((rowIndex) => (h("tr", null, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell, { rowIndex: rowIndex, colIndex: colIndex, nestedContent: () => (h("span", { class: "n-loader-skeleton" }, h("span", null, "Content loading"))) })))))))), h("tr", { hidden: !!this._loading || !!this.blocks.length }, h("th", { class: `${CSSNAMESPACE}__th`, colSpan: this.store.config.state.columns.length }, h("div", { class: "nano-tbl__cell-content nano-tbl__cell-content--no-result" }, h("slot", { name: "no-results" }, "No results found")))), this.blocks.map((block, blockIndex) => (h("tbody", { key: block.__uuid, id: `tbody-${this.renderId}-${blockIndex}`, ref: (tb) => {
                this.blockElements.push(tb);
            }, class: {
                [`${CSSNAMESPACE}__inactive`]: !this.activeBlocks.includes(blockIndex),
                [`${CSSNAMESPACE}__active`]: this.activeBlocks.includes(blockIndex),
            } }, this.activeBlocks.includes(blockIndex) ? (block.rows.map((row, i) => {
            const rowIndex = blockIndex > 0 ? blockIndex * this.perBlock + i : i;
            return (h(TableRow, { rowRenderer: this.rowRender, rowModel: row, rowIndex: rowIndex }, this.store.config.state.columns.map((_colModel, colIndex) => (h(TableCell, { rowIndex: rowIndex, colIndex: colIndex })))));
        })) : (h("tr", { class: `${CSSNAMESPACE}__tr--placeholder` }, h("td", { colSpan: this.store.config.state.columns.length, style: {
                height: this.getBlockHeight(blockIndex) + 'px',
            } })))))), this.showFooter && (h("tfoot", null, h(TableHeadFootRow, { rowRenderer: this.footRender }, this.store.config.state.columns.map((colModel) => [
            h(TableColHead, { column: colModel, headRenderer: this.footRender, onColumnSortClick: this.sortStart, defaults: {
                    sortable: this.defaultSort,
                } }),
        ]))))), !!this.blocks.length && this.showPaginateSpinner && (h("nano-spinner", { class: {
                [`${CSSNAMESPACE}__spinner`]: true,
                [`${CSSNAMESPACE}__spinner--show`]: this._loading,
            } }))))));
    }
    static get is() { return "nano-data-table"; }
    static get originalStyleUrls() {
        return {
            "$": ["table.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["table.css"]
        };
    }
    static get properties() {
        return {
            "customRenderer": {
                "type": "unknown",
                "attribute": "custom-renderer",
                "mutable": false,
                "complexType": {
                    "original": "(\n    node: any,\n    cell: HTMLElement | DocumentFragment\n  ) => void | Promise<string>",
                    "resolved": "(node: any, cell: HTMLElement | DocumentFragment) => void | Promise<string>",
                    "references": {
                        "HTMLElement": {
                            "location": "global",
                            "id": "global::HTMLElement"
                        },
                        "DocumentFragment": {
                            "location": "global",
                            "id": "global::DocumentFragment"
                        },
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Function called whenever `col.cellTemplate` renders an unknown object.\nThe function should render a valid HTMLElement to the cell arg.\nExample usage - render JSX from a 3rd party lib and append the result to the cell element."
                },
                "getter": false,
                "setter": false
            },
            "scrollable": {
                "type": "boolean",
                "attribute": "scrollable",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If true, will render any nested table in a scrollable container (using `overflow: auto`)"
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "false"
            },
            "caption": {
                "type": "string",
                "attribute": "caption",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "A descriptive title of the table.\nYou must use this or the `slot=\"caption\"` for accessibility"
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "showCaption": {
                "type": "boolean",
                "attribute": "show-caption",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Show the caption on-screen"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "loading": {
                "type": "boolean",
                "attribute": "loading",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Will show a loading state when set to true.\nBy default, will be shown automatically if `rows` is a promise waiting to resolve / or falsy\n*or* when performing custom filtering or sorting.\n*Note* when set manually, will overwrite any internal loading state.\nSet to 'undefined' to revert to default behaviour."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "undefined"
            },
            "placeholderSize": {
                "type": "number",
                "attribute": "placeholder-size",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "When loading rows asynchronously render this number of placeholder rows"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "10"
            },
            "rows": {
                "type": "unknown",
                "attribute": "rows",
                "mutable": false,
                "complexType": {
                    "original": "| TableTypes.NanoTable['rows']\n    | Promise<TableTypes.NanoTable['rows']>",
                    "resolved": "Promise<RowGeneric[]> | RowGeneric[]",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        },
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The data to place in the table"
                },
                "getter": false,
                "setter": false
            },
            "columns": {
                "type": "unknown",
                "attribute": "columns",
                "mutable": true,
                "complexType": {
                    "original": "TableTypes.NanoTable<any>['columns']",
                    "resolved": "ColumnConfig<any>[]",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The column config used to present the rows of data"
                },
                "getter": false,
                "setter": false,
                "defaultValue": "[]"
            },
            "headRender": {
                "type": "unknown",
                "attribute": "head-render",
                "mutable": false,
                "complexType": {
                    "original": "TableTypes.HeadFootRenderer",
                    "resolved": "HeadFootRenderer<RowData<RowGeneric>>",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Used for custom thead row rendering"
                },
                "getter": false,
                "setter": false,
                "defaultValue": "{ pinned: 'top' }"
            },
            "rowRender": {
                "type": "unknown",
                "attribute": "row-render",
                "mutable": false,
                "complexType": {
                    "original": "TableTypes.RowRenderer",
                    "resolved": "RowRenderer<RowData<RowGeneric>>",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Used for custom row rendering"
                },
                "getter": false,
                "setter": false
            },
            "footRender": {
                "type": "unknown",
                "attribute": "foot-render",
                "mutable": false,
                "complexType": {
                    "original": "TableTypes.HeadFootRenderer",
                    "resolved": "HeadFootRenderer<RowData<RowGeneric>>",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Used for custom tfoot row rendering"
                },
                "getter": false,
                "setter": false,
                "defaultValue": "{ pinned: 'bottom' }"
            },
            "showFooter": {
                "type": "boolean",
                "attribute": "show-footer",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Whether to show a `<tfoot>` component"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "perBlock": {
                "type": "number",
                "attribute": "per-block",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "To improve performance, data is split into blocks\nwhich are shown / hidden and rendered as they become visible.\nUse this to control the number of hits within a block -\nA block should fill a scrolling viewport.\nThe less perBlock the better for performance"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "50"
            },
            "blocksLength": {
                "type": "number",
                "attribute": "blocks-length",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "readonly",
                            "text": undefined
                        }],
                    "text": "The number of total blocks currently rendered in the table."
                },
                "getter": true,
                "setter": false,
                "reflect": false
            },
            "searchTerm": {
                "type": "string",
                "attribute": "search-term",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Term to search for in the data"
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "customFilterFn": {
                "type": "unknown",
                "attribute": "custom-filter-fn",
                "mutable": false,
                "complexType": {
                    "original": "(\n    filters: TableTypes.Filter[]\n  ) => Promise<true | TableTypes.Falsy>",
                    "resolved": "(filters: Filter[]) => Promise<true | Falsy>",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        },
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "A custom filtering function. Should return a promise.\nIf the promise resolves as `true` the column UI will be updated.\nIf the promise resolves as falsy, the sort will be performed by the component.\nA good use-case would be performing the filter on a server / via fetch.\nThen on success, updating the table's data via the `rows` property"
                },
                "getter": false,
                "setter": false
            },
            "customSortFn": {
                "type": "unknown",
                "attribute": "custom-sort-fn",
                "mutable": false,
                "complexType": {
                    "original": "(\n    property: TableTypes.Prop,\n    order: TableTypes.Order\n  ) => Promise<true | TableTypes.Falsy>",
                    "resolved": "(property: keyof RowGeneric, order: Order) => Promise<true | Falsy>",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        },
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "A custom sorting function. Should return a promise.\nIf the promise resolves as `true` the column UI will be updated.\nIf the promise resolves as falsey, the sort will be performed by the component.\nA good use-case would be performing the sort on a server / via fetch.\nThen on success, updating the table's data via the `rows` property"
                },
                "getter": false,
                "setter": false
            },
            "defaultSort": {
                "type": "boolean",
                "attribute": "default-sort",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "The default sortable option for all columns.\n`true` will enable column sorting unless you set `sortable: false` on a column\n`false` will disable column sorting unless you set `sortable: true` on a column"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "true"
            },
            "showPaginateSpinner": {
                "type": "boolean",
                "attribute": "show-paginate-spinner",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If true, will show a spinner at the bottom of the table when loading"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "false"
            },
            "virtualTotalItems": {
                "type": "number",
                "attribute": "virtual-total-items",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Use this to render the table with roughly the correct dimensions.\na use-case might be; fetch a small initial dataset to minimise load-time,\nrender the table with the correct dimensions, the table becomes interactive,\nload the rest of the data"
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "0"
            },
            "appliedFilters": {
                "type": "unknown",
                "attribute": "applied-filters",
                "mutable": false,
                "complexType": {
                    "original": "TableTypes.Filter[]",
                    "resolved": "Filter[]",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "readonly",
                            "text": "- shows the currently applied filters"
                        }],
                    "text": ""
                },
                "getter": true,
                "setter": false,
                "defaultValue": "[]"
            }
        };
    }
    static get states() {
        return {
            "internalLoading": {},
            "blocks": {},
            "activeBlocks": {}
        };
    }
    static get events() {
        return [{
                "method": "nanoTblReady",
                "name": "nanoTblReady",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired when the table has done it's first complete render"
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoTblBlockRendered",
                "name": "nanoTblBlockRendered",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired whenever a block is activated by scrolling into view / becoming visible\nThis could be leveraged for infinite scrolling / to fetch more data."
                },
                "complexType": {
                    "original": "{\n    block: number;\n    totalBlocks: number;\n  }",
                    "resolved": "{ block: number; totalBlocks: number; }",
                    "references": {}
                }
            }, {
                "method": "nanoTblBeforeSort",
                "name": "nanoTblBeforeSort",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired before a column is sorted.\n`event.preventDefault()` to stop sorting."
                },
                "complexType": {
                    "original": "{\n    column: TableTypes.Prop;\n    order: TableTypes.Order;\n  }",
                    "resolved": "{ column: keyof RowGeneric; order: Order; }",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                }
            }, {
                "method": "nanoTblAfterSort",
                "name": "nanoTblAfterSort",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired after a column is sorted"
                },
                "complexType": {
                    "original": "{\n    column: TableTypes.Prop;\n    order: TableTypes.Order;\n  }",
                    "resolved": "{ column: keyof RowGeneric; order: Order; }",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                }
            }, {
                "method": "nanoTblBeforeFilter",
                "name": "nanoTblBeforeFilter",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired before a column is filtered.\n`event.preventDefault()` to stop filtering."
                },
                "complexType": {
                    "original": "{ filters: TableTypes.Filter[] }",
                    "resolved": "{ filters: Filter[]; }",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                }
            }, {
                "method": "nanoTblAfterFilter",
                "name": "nanoTblAfterFilter",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired after a column is sorted"
                },
                "complexType": {
                    "original": "{ filters: TableTypes.Filter[] }",
                    "resolved": "{ filters: Filter[]; }",
                    "references": {
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    }
                }
            }, {
                "method": "nanoTblBeforeSearch",
                "name": "nanoTblBeforeSearch",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired before a general search.\n`event.preventDefault()` to stop searching."
                },
                "complexType": {
                    "original": "{ term: string }",
                    "resolved": "{ term: string; }",
                    "references": {}
                }
            }, {
                "method": "nanoTblAfterSearch",
                "name": "nanoTblAfterSearch",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired after a general / cross column search"
                },
                "complexType": {
                    "original": "{ term: string }",
                    "resolved": "{ term: string; }",
                    "references": {}
                }
            }, {
                "method": "nanoTblBeforeEdit",
                "name": "nanoTblBeforeEdit",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Fired before a general search.\n`event.preventDefault()` to stop searching."
                },
                "complexType": {
                    "original": "{ term: string }",
                    "resolved": "{ term: string; }",
                    "references": {}
                }
            }];
    }
    static get methods() {
        return {
            "resetSorting": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Remove any column sorts currently applied",
                    "tags": [{
                            "name": "returns",
                            "text": "a promise which resolves when complete"
                        }]
                }
            },
            "addSort": {
                "complexType": {
                    "signature": "(column: TableTypes.Prop, order: TableTypes.Order) => Promise<void>",
                    "parameters": [{
                            "name": "column",
                            "type": "keyof RowGeneric",
                            "docs": ""
                        }, {
                            "name": "order",
                            "type": "\"desc\" | \"asc\"",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Apply a sort on a column",
                    "tags": [{
                            "name": "returns",
                            "text": "a promise which resolves when complete"
                        }]
                }
            },
            "resetFilters": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Remove any column filters currently applied",
                    "tags": [{
                            "name": "returns",
                            "text": "a promise which resolves when complete"
                        }]
                }
            },
            "addFilters": {
                "complexType": {
                    "signature": "(filters: TableTypes.Filter[], additive?: boolean) => Promise<void>",
                    "parameters": [{
                            "name": "filters",
                            "type": "Filter[]",
                            "docs": "- the filters to apply"
                        }, {
                            "name": "additive",
                            "type": "boolean",
                            "docs": "- if true, will add the filters to any currently applied"
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Apply a filter on a column",
                    "tags": [{
                            "name": "param",
                            "text": "filters - the filters to apply"
                        }, {
                            "name": "param",
                            "text": "additive - if true, will add the filters to any currently applied"
                        }, {
                            "name": "returns",
                            "text": "a promise which resolves when complete"
                        }]
                }
            },
            "removeFilters": {
                "complexType": {
                    "signature": "(columnNames: TableTypes.Prop[]) => Promise<void>",
                    "parameters": [{
                            "name": "columnNames",
                            "type": "(keyof RowGeneric)[]",
                            "docs": "- the filters to apply"
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Remove filters from a column",
                    "tags": [{
                            "name": "param",
                            "text": "columnNames - the filters to apply"
                        }, {
                            "name": "returns",
                            "text": "a promise which resolves when complete"
                        }]
                }
            },
            "updateRow": {
                "complexType": {
                    "signature": "(row: TableTypes.RowData, rowIndex: number) => Promise<void>",
                    "parameters": [{
                            "name": "row",
                            "type": "RowGeneric & { __uuid?: string | number; __index?: number; }",
                            "docs": "- the row to update."
                        }, {
                            "name": "rowIndex",
                            "type": "number",
                            "docs": "- the row index to insert this row"
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        },
                        "TableTypes": {
                            "location": "import",
                            "path": "./table-interface",
                            "id": "src/components/data-table/table-interface.d.ts::TableTypes"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Updates a row model at a given index",
                    "tags": [{
                            "name": "param",
                            "text": "row - the row to update."
                        }, {
                            "name": "param",
                            "text": "rowIndex - the row index to insert this row"
                        }]
                }
            }
        };
    }
    static get elementRef() { return "host"; }
    static get watchers() {
        return [{
                "propName": "rows",
                "methodName": "handleRowsChange"
            }, {
                "propName": "columns",
                "methodName": "handleColsChange"
            }, {
                "propName": "searchTerm",
                "methodName": "handleSearchTermChange"
            }, {
                "propName": "virtualTotalItems",
                "methodName": "virtualTotalItemsChangeHandler"
            }];
    }
}
