"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
function _export(target, all) {
    for(var name in all)Object.defineProperty(target, name, {
        enumerable: true,
        get: Object.getOwnPropertyDescriptor(all, name).get
    });
}
_export(exports, {
    get Filters () {
        return Filters;
    },
    get PLUGIN_KEY () {
        return PLUGIN_KEY;
    },
    get PLUGIN_PRIORITY () {
        return PLUGIN_PRIORITY;
    }
});
const _base = require("../base");
const _array = require("../../helpers/array");
const _templateLiteralTag = require("../../helpers/templateLiteralTag");
const _console = require("../../helpers/console");
const _number = require("../../helpers/number");
const _element = require("../../helpers/dom/element");
const _unicode = require("../../helpers/unicode");
const _valueAccessors = require("../../utils/valueAccessors");
const _object = require("../../helpers/object");
const _predefinedItems = require("../contextMenu/predefinedItems");
const _constants = /*#__PURE__*/ _interop_require_wildcard(require("../../i18n/constants"));
const _condition = require("./component/condition");
const _operators = require("./component/operators");
const _value = require("./component/value");
const _actionBar = require("./component/actionBar");
const _conditionCollection = /*#__PURE__*/ _interop_require_default(require("./conditionCollection"));
const _dataFilter = /*#__PURE__*/ _interop_require_default(require("./dataFilter"));
const _conditionUpdateObserver = /*#__PURE__*/ _interop_require_default(require("./conditionUpdateObserver"));
const _utils = require("./utils");
const _focusController = require("./menu/focusController");
const _constants1 = require("./constants");
const _translations = require("../../translations");
function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_apply_descriptor_get(receiver, descriptor) {
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}
function _class_apply_descriptor_set(receiver, descriptor, value) {
    if (descriptor.set) {
        descriptor.set.call(receiver, value);
    } else {
        if (!descriptor.writable) {
            throw new TypeError("attempted to set read only private field");
        }
        descriptor.value = value;
    }
}
function _class_extract_field_descriptor(receiver, privateMap, action) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to " + action + " private field on non-instance");
    }
    return privateMap.get(receiver);
}
function _class_private_field_get(receiver, privateMap) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
    return _class_apply_descriptor_get(receiver, descriptor);
}
function _class_private_field_init(obj, privateMap, value) {
    _check_private_redeclaration(obj, privateMap);
    privateMap.set(obj, value);
}
function _class_private_field_set(receiver, privateMap, value) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
    _class_apply_descriptor_set(receiver, descriptor, value);
    return value;
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _getRequireWildcardCache(nodeInterop) {
    if (typeof WeakMap !== "function") return null;
    var cacheBabelInterop = new WeakMap();
    var cacheNodeInterop = new WeakMap();
    return (_getRequireWildcardCache = function(nodeInterop) {
        return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
    })(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
    if (!nodeInterop && obj && obj.__esModule) {
        return obj;
    }
    if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
        return {
            default: obj
        };
    }
    var cache = _getRequireWildcardCache(nodeInterop);
    if (cache && cache.has(obj)) {
        return cache.get(obj);
    }
    var newObj = {
        __proto__: null
    };
    var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
    for(var key in obj){
        if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
            var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
            if (desc && (desc.get || desc.set)) {
                Object.defineProperty(newObj, key, desc);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    newObj.default = obj;
    if (cache) {
        cache.set(obj, newObj);
    }
    return newObj;
}
const PLUGIN_KEY = 'filters';
const PLUGIN_PRIORITY = 250;
const SHORTCUTS_GROUP = PLUGIN_KEY;
var /**
   * Menu focus navigator allows switching the focus position through Tab and Shift Tab keys.
   *
   * @type {MenuFocusNavigator|undefined}
   */ _menuFocusNavigator = /*#__PURE__*/ new WeakMap(), /**
   * Traces the new menu instances to apply the focus navigation to the latest one.
   *
   * @type {WeakSet<Menu>}
   */ _dropdownMenuTraces = /*#__PURE__*/ new WeakMap(), /**
   * Stores the previous state of the condition stack before the latest filter operation.
   * This is used in the `beforeFilter` plugin to allow performing the undo operation.
   *
   * @type {Array}
   */ _previousConditionStack = /*#__PURE__*/ new WeakMap(), /**
   * Snapshot of [[#previousConditionStack]] at the start of [[filter]] when the DataProvider plugin is active.
   * Used to restore filter UI after `fetchRows` fails (the fetch request used the in-collection state; this holds the last committed stack).
   *
   * @type {Array}
   */ _dataProviderFilterRollbackStack = /*#__PURE__*/ new WeakMap(), /**
   * Indicates if the DataProvider plugin is active.
   *
   * @type {boolean}
   */ _isDataProviderActive = /*#__PURE__*/ new WeakMap(), /**
   * `afterChange` listener.
   *
   * @param {Array} changes Array of changes.
   */ _onAfterChange = /*#__PURE__*/ new WeakSet(), /**
   * After dataProvider fetch listener.
   *
   * @param {object} [result] Fetch result (filters match the request that just completed). May include `filtersConditionsStack` (Array).
   */ _onAfterDataProviderFetch = /*#__PURE__*/ new WeakSet(), /**
   * After dataProvider fetch error listener.
   */ _onAfterDataProviderFetchError = /*#__PURE__*/ new WeakSet(), /**
   * After dropdown menu show listener.
   */ _onAfterDropdownMenuShow = /*#__PURE__*/ new WeakSet(), /**
   * After dropdown menu hide listener.
   */ _onAfterDropdownMenuHide = /*#__PURE__*/ new WeakSet(), /**
   * Hooks applies the new dropdown menu instance to the focus navigator.
   */ _onBeforeDropdownMenuShow = /*#__PURE__*/ new WeakSet(), /**
   * After dropdown menu default options listener.
   *
   * @param {object} defaultOptions ContextMenu default item options.
   */ _onAfterDropdownMenuDefaultOptions = /*#__PURE__*/ new WeakSet(), /**
   * On action bar submit listener.
   *
   * @private
   * @param {string} submitType The submit type.
   */ _onActionBarSubmit = /*#__PURE__*/ new WeakSet(), /**
   * On component change listener.
   *
   * @param {BaseComponent} component Component inheriting BaseComponent.
   * @param {object} command Menu item object (command).
   */ _onComponentChange = /*#__PURE__*/ new WeakSet(), /**
   * On component SelectUI closed listener.
   */ _onSelectUIClosed = /*#__PURE__*/ new WeakSet(), /**
   * On after get column header listener.
   *
   * @param {number} col Visual column index.
   * @param {HTMLTableCellElement} TH Header's TH element.
   *
   */ _onAfterGetColHeader = /*#__PURE__*/ new WeakSet(), /**
   * It updates the components state. The state is triggered by ConditionUpdateObserver, which
   * reacts to any condition added to the condition collection. It may be added through the UI
   * components or by API call.
   *
   * @param {object} conditionsState An object with the state generated by UI components.
   */ _updateComponents = /*#__PURE__*/ new WeakSet();
class Filters extends _base.BasePlugin {
    static get PLUGIN_KEY() {
        return PLUGIN_KEY;
    }
    static get PLUGIN_PRIORITY() {
        return PLUGIN_PRIORITY;
    }
    static get DEFAULT_SETTINGS() {
        return {
            searchMode: 'show'
        };
    }
    static get SETTINGS_VALIDATORS() {
        return {
            searchMode: (value)=>typeof value === 'string' && [
                    'show',
                    'apply'
                ].includes(value)
        };
    }
    static get PLUGIN_DEPS() {
        return [
            'plugin:DropdownMenu',
            'plugin:HiddenRows',
            'cell-type:checkbox'
        ];
    }
    /**
   * Checks if the plugin is enabled in the handsontable settings. This method is executed in {@link Hooks#beforeInit}
   * hook and if it returns `true` then the {@link Filters#enablePlugin} method is called.
   *
   * @returns {boolean}
   */ isEnabled() {
        /* eslint-disable no-unneeded-ternary */ return this.hot.getSettings()[PLUGIN_KEY] ? true : false;
    }
    /**
   * Enables the plugin functionality for this Handsontable instance.
   */ enablePlugin() {
        if (this.enabled) {
            return;
        }
        _class_private_field_set(this, _isDataProviderActive, this.hot.runHooks('hasExternalDataSource') === true);
        this.filtersRowsMap = this.hot.rowIndexMapper.registerMap(this.pluginName, new _translations.TrimmingMap());
        this.dropdownMenuPlugin = this.hot.getPlugin('dropdownMenu');
        const dropdownSettings = this.hot.getSettings().dropdownMenu;
        const menuContainer = dropdownSettings && dropdownSettings.uiContainer || this.hot.rootPortalElement;
        const addConfirmationHooks = (component)=>{
            component.addLocalHook('accept', ()=>_class_private_method_get(this, _onActionBarSubmit, onActionBarSubmit).call(this, 'accept'));
            component.addLocalHook('cancel', ()=>_class_private_method_get(this, _onActionBarSubmit, onActionBarSubmit).call(this, 'cancel'));
            component.addLocalHook('change', (command)=>_class_private_method_get(this, _onComponentChange, onComponentChange).call(this, component, command));
            return component;
        };
        const filterByConditionLabel = ()=>`${this.hot.getTranslatedPhrase(_constants.FILTERS_DIVS_FILTER_BY_CONDITION)}:`;
        const filterValueLabel = ()=>`${this.hot.getTranslatedPhrase(_constants.FILTERS_DIVS_FILTER_BY_VALUE)}:`;
        if (!this.components.get('filter_by_condition')) {
            const conditionComponent = new _condition.ConditionComponent(this.hot, {
                id: 'filter_by_condition',
                name: filterByConditionLabel,
                addSeparator: false,
                menuContainer
            });
            conditionComponent.addLocalHook('afterClose', ()=>_class_private_method_get(this, _onSelectUIClosed, onSelectUIClosed).call(this));
            this.components.set('filter_by_condition', addConfirmationHooks(conditionComponent));
        }
        if (!this.components.get('filter_operators')) {
            this.components.set('filter_operators', new _operators.OperatorsComponent(this.hot, {
                id: 'filter_operators',
                name: 'Operators'
            }));
        }
        if (!this.components.get('filter_by_condition2')) {
            const conditionComponent = new _condition.ConditionComponent(this.hot, {
                id: 'filter_by_condition2',
                name: '',
                addSeparator: true,
                menuContainer
            });
            conditionComponent.addLocalHook('afterClose', ()=>_class_private_method_get(this, _onSelectUIClosed, onSelectUIClosed).call(this));
            this.components.set('filter_by_condition2', addConfirmationHooks(conditionComponent));
        }
        if (!this.components.get('filter_by_value')) {
            const searchMode = this.getSetting('searchMode');
            this.components.set('filter_by_value', addConfirmationHooks(new _value.ValueComponent(this.hot, {
                id: 'filter_by_value',
                name: filterValueLabel,
                searchMode,
                hiddenWhen: ()=>_class_private_field_get(this, _isDataProviderActive)
            })));
        }
        if (!this.components.get('filter_action_bar')) {
            this.components.set('filter_action_bar', addConfirmationHooks(new _actionBar.ActionBarComponent(this.hot, {
                id: 'filter_action_bar',
                name: 'Action bar'
            })));
        }
        if (!this.conditionCollection) {
            this.conditionCollection = new _conditionCollection.default(this.hot);
        }
        if (!this.conditionUpdateObserver) {
            this.conditionUpdateObserver = new _conditionUpdateObserver.default(this.hot, this.conditionCollection, (physicalColumn)=>this.getDataMapAtColumn(physicalColumn));
            this.conditionUpdateObserver.addLocalHook('update', (conditionState)=>_class_private_method_get(this, _updateComponents, updateComponents).call(this, conditionState));
        }
        this.components.forEach((component)=>component.show());
        this.addHook('afterDropdownMenuDefaultOptions', (...args)=>_class_private_method_get(this, _onAfterDropdownMenuDefaultOptions, onAfterDropdownMenuDefaultOptions).call(this, ...args));
        this.addHook('beforeDropdownMenuShow', ()=>_class_private_method_get(this, _onBeforeDropdownMenuShow, onBeforeDropdownMenuShow).call(this));
        this.addHook('afterDropdownMenuShow', ()=>_class_private_method_get(this, _onAfterDropdownMenuShow, onAfterDropdownMenuShow).call(this));
        this.addHook('afterDropdownMenuHide', ()=>_class_private_method_get(this, _onAfterDropdownMenuHide, onAfterDropdownMenuHide).call(this));
        this.addHook('afterChange', (changes)=>_class_private_method_get(this, _onAfterChange, onAfterChange).call(this, changes));
        this.addHook('afterDataProviderFetch', (result)=>_class_private_method_get(this, _onAfterDataProviderFetch, onAfterDataProviderFetch).call(this, result));
        this.addHook('afterDataProviderFetchError', ()=>_class_private_method_get(this, _onAfterDataProviderFetchError, onAfterDataProviderFetchError).call(this));
        // Temp. solution (extending menu items bug in contextMenu/dropdownMenu)
        if (this.hot.getSettings().dropdownMenu && this.dropdownMenuPlugin) {
            this.dropdownMenuPlugin.disablePlugin();
            this.dropdownMenuPlugin.enablePlugin();
        }
        if (!_class_private_field_get(this, _menuFocusNavigator) && this.dropdownMenuPlugin.enabled) {
            const focusableItems = [
                // A fake menu item that once focused allows escaping from the focus navigation (using Tab keys)
                // to the menu navigation using arrow keys.
                {
                    focus: ()=>{
                        const menu = _class_private_field_get(this, _menuFocusNavigator).getMenu();
                        const menuNavigator = menu.getNavigator();
                        const lastSelectedMenuItem = _class_private_field_get(this, _menuFocusNavigator).getLastMenuPage();
                        menu.focus();
                        if (lastSelectedMenuItem > 0) {
                            menuNavigator.setCurrentPage(lastSelectedMenuItem);
                        } else {
                            menuNavigator.toFirstItem();
                        }
                    }
                },
                ...Array.from(this.components).map(([, component])=>component.getElements()).flat()
            ];
            _class_private_field_set(this, _menuFocusNavigator, (0, _focusController.createMenuFocusController)(this.dropdownMenuPlugin.menu, focusableItems));
            const forwardToFocusNavigation = (event)=>{
                _class_private_field_get(this, _menuFocusNavigator).listen();
                event.preventDefault();
                if ((0, _unicode.isKey)(event.keyCode, 'TAB')) {
                    if (event.shiftKey) {
                        _class_private_field_get(this, _menuFocusNavigator).toPreviousItem();
                    } else {
                        _class_private_field_get(this, _menuFocusNavigator).toNextItem();
                    }
                }
            };
            this.components.get('filter_by_value').addLocalHook('listTabKeydown', forwardToFocusNavigation);
            this.components.get('filter_by_condition').addLocalHook('selectTabKeydown', forwardToFocusNavigation);
        }
        this.registerShortcuts();
        super.enablePlugin();
    }
    /**
   * Update plugin state after Handsontable settings update.
   */ updatePlugin() {
        this.disablePlugin();
        this.enablePlugin();
        super.updatePlugin();
    }
    /**
   * Disables the plugin functionality for this Handsontable instance.
   */ disablePlugin() {
        if (this.enabled) {
            if (this.dropdownMenuPlugin?.enabled) {
                this.dropdownMenuPlugin.menu.clearLocalHooks();
            }
            this.components.forEach((component, key)=>{
                component.destroy();
                this.components.set(key, null);
            });
            this.conditionCollection.destroy();
            this.conditionCollection = null;
            this.hot.rowIndexMapper.unregisterMap(this.pluginName);
        }
        this.unregisterShortcuts();
        super.disablePlugin();
    }
    /**
   * Register shortcuts responsible for clearing the filters.
   *
   * @private
   */ registerShortcuts() {
        this.hot.getShortcutManager().getContext('grid').addShortcut({
            keys: [
                [
                    'Alt',
                    'A'
                ]
            ],
            stopPropagation: true,
            callback: ()=>{
                const selection = this.hot.getSelected();
                this.clearConditions();
                this.filter();
                if (selection) {
                    this.hot.selectCells(selection);
                }
            },
            group: SHORTCUTS_GROUP
        });
    }
    /**
   * Unregister shortcuts responsible for clearing the filters.
   *
   * @private
   */ unregisterShortcuts() {
        this.hot.getShortcutManager().getContext('grid').removeShortcutsByGroup(SHORTCUTS_GROUP);
    }
    /* eslint-disable jsdoc/require-description-complete-sentence */ /**
   * @memberof Filters#
   * @function addCondition
   * @description
   * Adds condition to the conditions collection at specified column index.
   *
   * Possible predefined conditions:
   *
   * | Condition | Description | Expected `args` |
   * |---|---|---|
   * | `begins_with` | Begins with | `[value: string]`, e.g. `['de']` |
   * | `between` | Between | `[from: number\|string, to: number\|string]`, e.g. `[10, 50]` |
   * | `by_value` | By value | `[[...values: Array]]`, e.g. `[['ing', 'ed', 'as']]`. The outer array wraps a single inner array that contains all values to **keep** (show) after filtering. |
   * | `contains` | Contains | `[value: string]`, e.g. `['ing']` |
   * | `date_after` | After a date | `[dateString: string]`, e.g. `['1/1/2023']`. The format must match the column's `dateFormat` option. |
   * | `date_before` | Before a date | `[dateString: string]`, e.g. `['1/1/2023']`. The format must match the column's `dateFormat` option. |
   * | `date_today` | Today | `[]` |
   * | `date_tomorrow` | Tomorrow | `[]` |
   * | `date_yesterday` | Yesterday | `[]` |
   * | `empty` | Empty | `[]` |
   * | `ends_with` | Ends with | `[value: string]`, e.g. `['ing']` |
   * | `eq` | Equal | `[value: string\|number]`, e.g. `['John']` |
   * | `gt` | Greater than | `[value: number]`, e.g. `[95]` |
   * | `gte` | Greater than or equal | `[value: number]`, e.g. `[95]` |
   * | `intl_date_after` | After a date (locale-aware) | `[dateString: string]`, e.g. `['2023-01-01']` |
   * | `intl_date_before` | Before a date (locale-aware) | `[dateString: string]`, e.g. `['2023-01-01']` |
   * | `intl_date_between` | Between dates (locale-aware) | `[fromDateString: string, toDateString: string]`, e.g. `['2023-01-01', '2023-12-31']` |
   * | `intl_date_today` | Today (locale-aware) | `[]` |
   * | `intl_date_tomorrow` | Tomorrow (locale-aware) | `[]` |
   * | `intl_date_yesterday` | Yesterday (locale-aware) | `[]` |
   * | `intl_time_after` | After a time (locale-aware) | `[timeString: string]`, e.g. `['12:00']` |
   * | `intl_time_before` | Before a time (locale-aware) | `[timeString: string]`, e.g. `['08:00']` |
   * | `intl_time_between` | Between times (locale-aware) | `[fromTimeString: string, toTimeString: string]`, e.g. `['08:00', '12:00']` |
   * | `lt` | Less than | `[value: number]`, e.g. `[10]` |
   * | `lte` | Less than or equal | `[value: number]`, e.g. `[10]` |
   * | `none` | None (no filter) | `[]` |
   * | `not_between` | Not between | `[from: number\|string, to: number\|string]`, e.g. `[10, 50]` |
   * | `not_contains` | Not contains | `[value: string]`, e.g. `['ing']` |
   * | `not_empty` | Not empty | `[]` |
   * | `neq` | Not equal | `[value: string\|number]`, e.g. `['John']` |
   *
   * Possible operations on collection of conditions:
   *  * `conjunction` - [**Conjunction**](https://en.wikipedia.org/wiki/Logical_conjunction) on conditions collection (by default), i.e. for such operation: <br/> c1 AND c2 AND c3 AND c4 ... AND cn === TRUE, where c1 ... cn are conditions.
   *  * `disjunction` - [**Disjunction**](https://en.wikipedia.org/wiki/Logical_disjunction) on conditions collection, i.e. for such operation: <br/> c1 OR c2 OR c3 OR c4 ... OR cn === TRUE, where c1, c2, c3, c4 ... cn are conditions.
   *  * `disjunctionWithExtraCondition` - **Disjunction** on first `n - 1`\* conditions from collection with an extra requirement computed from the last condition, i.e. for such operation: <br/> c1 OR c2 OR c3 OR c4 ... OR cn-1 AND cn === TRUE, where c1, c2, c3, c4 ... cn are conditions.
   *
   * \* when `n` is collection size; it's used i.e. for one operation introduced from UI (when choosing from filter's drop-down menu two conditions with OR operator between them, mixed with choosing values from the multiple choice select)
   *
   * **Note**: Mind that you cannot mix different types of operations (for instance, if you use `conjunction`, use it consequently for a particular column).
   *
   * **Note**: If the number of conditions added programmatically via `addCondition()` exceeds the capacity of the
   * filter's dropdown UI (at most 2 regular conditions and 1 `by_value` condition per column), the extra conditions
   * will be applied to the data but will not be visible or editable in the dropdown menu.
   *
   * @example
   * ::: only-for javascript
   * ```js
   * const container = document.getElementById('example');
   * const hot = new Handsontable(container, {
   *   data: getData(),
   *   filters: true
   * });
   *
   * // access to filters plugin instance
   * const filtersPlugin = hot.getPlugin('filters');
   *
   * // add filter "Begins with" with value "de" to column at index 1
   * filtersPlugin.addCondition(1, 'begins_with', ['de']);
   * filtersPlugin.filter();
   *
   * // add filter "Between" 10 and 50 to column at index 1
   * filtersPlugin.addCondition(1, 'between', [10, 50]);
   * filtersPlugin.filter();
   *
   * // add filter "By value" to column at index 1
   * // in this case all values that don't match will be filtered
   * filtersPlugin.addCondition(1, 'by_value', [['ing', 'ed', 'as', 'on']]);
   * filtersPlugin.filter();
   *
   * // add filter "Contains" with value "ing" to column at index 1
   * filtersPlugin.addCondition(1, 'contains', ['ing']);
   * filtersPlugin.filter();
   *
   * // add filter "After a date" with value "1/1/2023" to column at index 1
   * filtersPlugin.addCondition(1, 'date_after', ['1/1/2023']);
   * filtersPlugin.filter();
   *
   * // add filter "Before a date" with value "1/1/2023" to column at index 1
   * filtersPlugin.addCondition(1, 'date_before', ['1/1/2023']);
   * filtersPlugin.filter();
   *
   * // add filter "Today" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'date_today', []);
   * filtersPlugin.filter();
   *
   * // add filter "Tomorrow" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'date_tomorrow', []);
   * filtersPlugin.filter();
   *
   * // add filter "Yesterday" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'date_yesterday', []);
   * filtersPlugin.filter();
   *
   * // add filter "Empty" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'empty', []);
   * filtersPlugin.filter();
   *
   * // add filter "Ends with" with value "ing" to column at index 1
   * filtersPlugin.addCondition(1, 'ends_with', ['ing']);
   * filtersPlugin.filter();
   *
   * // add filter "Equal" with value "John" to column at index 1
   * filtersPlugin.addCondition(1, 'eq', ['John']);
   * filtersPlugin.filter();
   *
   * // add filter "Greater than" 95 to column at index 1
   * filtersPlugin.addCondition(1, 'gt', [95]);
   * filtersPlugin.filter();
   *
   * // add filter "Greater than or equal" 95 to column at index 1
   * filtersPlugin.addCondition(1, 'gte', [95]);
   * filtersPlugin.filter();
   *
   * // add filter "Less than" 10 to column at index 1
   * filtersPlugin.addCondition(1, 'lt', [10]);
   * filtersPlugin.filter();
   *
   * // add filter "Less than or equal" 10 to column at index 1
   * filtersPlugin.addCondition(1, 'lte', [10]);
   * filtersPlugin.filter();
   *
   * // add filter "None" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'none', []);
   * filtersPlugin.filter();
   *
   * // add filter "Not between" 10 and 50 to column at index 1
   * filtersPlugin.addCondition(1, 'not_between', [10, 50]);
   * filtersPlugin.filter();
   *
   * // add filter "Not contains" with value "ing" to column at index 1
   * filtersPlugin.addCondition(1, 'not_contains', ['ing']);
   * filtersPlugin.filter();
   *
   * // add filter "Not empty" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'not_empty', []);
   * filtersPlugin.filter();
   *
   * // add filter "Not equal" with value "John" to column at index 1
   * filtersPlugin.addCondition(1, 'neq', ['John']);
   * filtersPlugin.filter();
   * ```
   * :::
   *
   * ::: only-for react
   * ```jsx
   * const hotRef = useRef(null);
   *
   * ...
   *
   * <HotTable
   *   ref={hotRef}
   *   data={getData()}
   *   filters={true}
   * />
   *
   * // access to filters plugin instance
   * const hot = hotRef.current.hotInstance;
   * const filtersPlugin = hot.getPlugin('filters');
   *
   * // add filter "Begins with" with value "de" to column at index 1
   * filtersPlugin.addCondition(1, 'begins_with', ['de']);
   * filtersPlugin.filter();
   *
   * // add filter "Between" 10 and 50 to column at index 1
   * filtersPlugin.addCondition(1, 'between', [10, 50]);
   * filtersPlugin.filter();
   *
   * // add filter "By value" to column at index 1
   * // in this case all values that don't match will be filtered
   * filtersPlugin.addCondition(1, 'by_value', [['ing', 'ed', 'as', 'on']]);
   * filtersPlugin.filter();
   *
   * // add filter "Contains" with value "ing" to column at index 1
   * filtersPlugin.addCondition(1, 'contains', ['ing']);
   * filtersPlugin.filter();
   *
   * // add filter "After a date" with value "1/1/2023" to column at index 1
   * filtersPlugin.addCondition(1, 'date_after', ['1/1/2023']);
   * filtersPlugin.filter();
   *
   * // add filter "Before a date" with value "1/1/2023" to column at index 1
   * filtersPlugin.addCondition(1, 'date_before', ['1/1/2023']);
   * filtersPlugin.filter();
   *
   * // add filter "Today" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'date_today', []);
   * filtersPlugin.filter();
   *
   * // add filter "Tomorrow" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'date_tomorrow', []);
   * filtersPlugin.filter();
   *
   * // add filter "Yesterday" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'date_yesterday', []);
   * filtersPlugin.filter();
   *
   * // add filter "Empty" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'empty', []);
   * filtersPlugin.filter();
   *
   * // add filter "Ends with" with value "ing" to column at index 1
   * filtersPlugin.addCondition(1, 'ends_with', ['ing']);
   * filtersPlugin.filter();
   *
   * // add filter "Equal" with value "John" to column at index 1
   * filtersPlugin.addCondition(1, 'eq', ['John']);
   * filtersPlugin.filter();
   *
   * // add filter "Greater than" 95 to column at index 1
   * filtersPlugin.addCondition(1, 'gt', [95]);
   * filtersPlugin.filter();
   *
   * // add filter "Greater than or equal" 95 to column at index 1
   * filtersPlugin.addCondition(1, 'gte', [95]);
   * filtersPlugin.filter();
   *
   * // add filter "Less than" 10 to column at index 1
   * filtersPlugin.addCondition(1, 'lt', [10]);
   * filtersPlugin.filter();
   *
   * // add filter "Less than or equal" 10 to column at index 1
   * filtersPlugin.addCondition(1, 'lte', [10]);
   * filtersPlugin.filter();
   *
   * // add filter "None" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'none', []);
   * filtersPlugin.filter();
   *
   * // add filter "Not between" 10 and 50 to column at index 1
   * filtersPlugin.addCondition(1, 'not_between', [10, 50]);
   * filtersPlugin.filter();
   *
   * // add filter "Not contains" with value "ing" to column at index 1
   * filtersPlugin.addCondition(1, 'not_contains', ['ing']);
   * filtersPlugin.filter();
   *
   * // add filter "Not empty" with no arguments to column at index 1
   * filtersPlugin.addCondition(1, 'not_empty', []);
   * filtersPlugin.filter();
   *
   * // add filter "Not equal" with value "John" to column at index 1
   * filtersPlugin.addCondition(1, 'neq', ['John']);
   * filtersPlugin.filter();
   * ```
   * :::
   *
   * ::: only-for angular
   * ```ts
   * import { AfterViewInit, Component, ViewChild } from "@angular/core";
   * import {
   *   GridSettings,
   *   HotTableModule,
   *   HotTableComponent,
   * } from "@handsontable/angular-wrapper";
   *
   * `@Component`({
   *   selector: "app-example",
   *   standalone: true,
   *   imports: [HotTableModule],
   *   template: ` <div>
   *     <hot-table [settings]="gridSettings" />
   *   </div>`,
   * })
   * export class ExampleComponent implements AfterViewInit {
   *   `@ViewChild`(HotTableComponent, { static: false })
   *   readonly hotTable!: HotTableComponent;
   *
   *   readonly gridSettings = <GridSettings>{
   *     data: this.getData(),
   *     filters: true,
   *   };
   *
   *   ngAfterViewInit(): void {
   *     // Access to filters plugin instance
   *     const hot = this.hotTable.hotInstance;
   *     const filtersPlugin = hot.getPlugin("filters");
   *
   *     // Add filter "Begins with" with value "de" to column at index 1
   *     filtersPlugin.addCondition(1, "begins_with", ["de"]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Between" 10 and 50 to column at index 1
   *     filtersPlugin.addCondition(1, "between", [10, 50]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "By value" to column at index 1
   *     // In this case, all values that don't match will be filtered.
   *     filtersPlugin.addCondition(1, "by_value", [["ing", "ed", "as", "on"]]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Contains" with value "ing" to column at index 1
   *     filtersPlugin.addCondition(1, "contains", ["ing"]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "After a date" with value "1/1/2023" to column at index 1
   *     filtersPlugin.addCondition(1, "date_after", ["1/1/2023"]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Before a date" with value "1/1/2023" to column at index 1
   *     filtersPlugin.addCondition(1, "date_before", ["1/1/2023"]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Today" with no arguments to column at index 1
   *     filtersPlugin.addCondition(1, "date_today", []);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Tomorrow" with no arguments to column at index 1
   *     filtersPlugin.addCondition(1, "date_tomorrow", []);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Yesterday" with no arguments to column at index 1
   *     filtersPlugin.addCondition(1, "date_yesterday", []);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Empty" with no arguments to column at index 1
   *     filtersPlugin.addCondition(1, "empty", []);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Ends with" with value "ing" to column at index 1
   *     filtersPlugin.addCondition(1, "ends_with", ["ing"]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Equal" with value "John" to column at index 1
   *     filtersPlugin.addCondition(1, "eq", ["John"]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Greater than" 95 to column at index 1
   *     filtersPlugin.addCondition(1, "gt", [95]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Greater than or equal" 95 to column at index 1
   *     filtersPlugin.addCondition(1, "gte", [95]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Less than" 10 to column at index 1
   *     filtersPlugin.addCondition(1, "lt", [10]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Less than or equal" 10 to column at index 1
   *     filtersPlugin.addCondition(1, "lte", [10]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "None" with no arguments to column at index 1
   *     filtersPlugin.addCondition(1, "none", []);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Not between" 10 and 50 to column at index 1
   *     filtersPlugin.addCondition(1, "not_between", [10, 50]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Not contains" with value "ing" to column at index 1
   *     filtersPlugin.addCondition(1, "not_contains", ["ing"]);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Not empty" with no arguments to column at index 1
   *     filtersPlugin.addCondition(1, "not_empty", []);
   *     filtersPlugin.filter();
   *
   *     // Add filter "Not equal" with value "John" to column at index 1
   *     filtersPlugin.addCondition(1, "neq", ["John"]);
   *     filtersPlugin.filter();
   *   }
   *
   *   private getData(): any[] {
   *     // Get some data
   *   }
   * }
   * ```
   * :::
   *
   * @param {number} column Visual column index.
   * @param {string} name Condition short name.
   * @param {Array} args Condition arguments. The expected format depends on the condition - see the table above for details.
   * @param {string} [operationId=conjunction] `id` of operation which is performed on the column.
   */ /* eslint-enable jsdoc/require-description-complete-sentence */ addCondition(column, name, args, operationId = _constants1.OPERATION_AND) {
        if (name === _constants1.CONDITION_BY_VALUE && _class_private_field_get(this, _isDataProviderActive)) {
            return;
        }
        const physicalColumn = this.hot.toPhysicalColumn(column);
        this.conditionCollection.addCondition(physicalColumn, {
            command: {
                key: name
            },
            args
        }, operationId);
    }
    /**
   * Removes conditions at specified column index.
   *
   * @param {number} column Visual column index.
   */ removeConditions(column) {
        const physicalColumn = this.hot.toPhysicalColumn(column);
        this.conditionCollection.removeConditions(physicalColumn);
    }
    /**
   * Clears all conditions previously added to the collection for the specified column index or, if the column index
   * was not passed, clear the conditions for all columns.
   *
   * @param {number} [column] Visual column index.
   */ clearConditions(column) {
        if (column === undefined) {
            this.conditionCollection.clean();
        } else {
            const physicalColumn = this.hot.toPhysicalColumn(column);
            this.conditionCollection.removeConditions(physicalColumn);
        }
    }
    /**
   * Imports filter conditions to all columns to the plugin. The method accepts
   * the array of conditions with the same structure as the {@link Filters#exportConditions} method returns.
   * Importing conditions will replace the current conditions. Once replaced, the state of the condition
   * will be reflected in the UI. To apply the changes and filter the table, call
   * the {@link Filters#filter} method eventually.
   *
   * @param {Array} conditions Array of conditions.
   */ importConditions(conditions) {
        this.conditionCollection.importAllConditions(conditions);
    }
    /* eslint-disable jsdoc/require-description-complete-sentence */ /**
   * Exports filter conditions for all columns from the plugin.
   * The array represents the filter state for each column. For example:
   *
   * ```js
   * [
   *   {
   *     column: 1,
   *     operation: 'conjunction',
   *     conditions: [
   *       { name: 'gt', args: [95] },
   *     ]
   *   },
   *   {
   *     column: 7,
   *     operation: 'conjunction',
   *     conditions: [
   *       { name: 'contains', args: ['mike'] },
   *       { name: 'begins_with', args: ['m'] },
   *     ]
   *   },
   * ]
   * ```
   *
   * @returns {Array}
   */ exportConditions() {
        return this.conditionCollection.exportAllConditions();
    }
    /* eslint-enable jsdoc/require-description-complete-sentence */ /**
   * Filters data based on added filter conditions.
   *
   * @fires Hooks#beforeFilter
   * @fires Hooks#afterFilter
   */ filter() {
        const { navigableHeaders } = this.hot.getSettings();
        const needToFilter = !this.conditionCollection.isEmpty();
        const conditions = this.exportConditions();
        if (_class_private_field_get(this, _isDataProviderActive)) {
            _class_private_field_set(this, _dataProviderFilterRollbackStack, (0, _object.deepClone)(_class_private_field_get(this, _previousConditionStack)));
        }
        const allowFiltering = this.hot.runHooks('beforeFilter', conditions, _class_private_field_get(this, _previousConditionStack));
        if (allowFiltering !== false && needToFilter) {
            const dataFilter = this._createDataFilter();
            const trimmedRows = [];
            let rowIndexesToShow = [];
            this.hot.batchExecution(()=>{
                this.filtersRowsMap.clear();
                rowIndexesToShow = (0, _array.arrayMap)(dataFilter.filter(), (rowData)=>rowData.meta.row);
                const rowIndexesToShowAssertion = (0, _utils.createArrayAssertion)(rowIndexesToShow);
                (0, _number.rangeEach)(this.hot.countSourceRows() - 1, (row)=>{
                    if (!rowIndexesToShowAssertion(row)) {
                        trimmedRows.push(row);
                    }
                });
                (0, _array.arrayEach)(trimmedRows, (physicalRow)=>{
                    this.filtersRowsMap.setValueAtIndex(physicalRow, true);
                });
            }, true);
            if (!navigableHeaders && !rowIndexesToShow.length) {
                this.hot.deselectCell();
            }
            _class_private_field_set(this, _previousConditionStack, this.exportConditions());
        } else if (allowFiltering !== false && !needToFilter) {
            _class_private_field_set(this, _previousConditionStack, this.exportConditions());
            this.filtersRowsMap.clear();
        } else if (_class_private_field_get(this, _isDataProviderActive)) {
            _class_private_field_set(this, _previousConditionStack, this.exportConditions());
        } else {
            this.importConditions(_class_private_field_get(this, _previousConditionStack));
        }
        if (this.hot.selection.isSelected()) {
            this.hot.selectCell(navigableHeaders ? -1 : 0, this.hot.getSelectedRangeActive().highlight.col);
        }
        if (allowFiltering !== false) {
            this.hot.runHooks('afterFilter', conditions);
            this.hot.view.adjustElementsSize();
            this.hot.render();
        }
    }
    /**
   * Gets last selected column index.
   *
   * @returns {{visualIndex: number, physicalIndex: number} | null} Returns `null` when a column is
   * not selected. Otherwise, returns an object with `visualIndex` and `physicalIndex` properties containing
   * the index of the column.
   */ getSelectedColumn() {
        const highlight = this.hot.getSelectedRangeActive()?.highlight;
        if (!highlight) {
            return null;
        }
        return {
            visualIndex: highlight.col,
            physicalIndex: this.hot.toPhysicalColumn(highlight.col)
        };
    }
    /**
   * Returns the full dataset for a column with cell meta for each row. The dataset is independent of
   * any index mapper - no matter if the data is filtered, sorted, or otherwise transformed all rows
   * are included.
   *
   * @param {number} physicalColumn The physical column index.
   * @returns {Array<{meta: CellProperties, value: any}>} Array of objects with `meta` and `value`, one per source row.
   */ getDataMapAtColumn(physicalColumn) {
        const countSourceRows = this.hot.countSourceRows();
        const visualColumn = this.hot.toVisualColumn(physicalColumn);
        const data = [];
        for(let physicalRow = 0; physicalRow < countSourceRows; physicalRow++){
            const cellMeta = this.hot._getMetaManager().getCellMeta(physicalRow, physicalColumn, {
                visualRow: physicalRow,
                visualColumn: physicalColumn,
                skipMetaExtension: true
            });
            let value = (0, _valueAccessors.getValueGetterValue)(this.hot.getSourceDataAtCell(physicalRow, visualColumn), cellMeta);
            if (this.hot.hasHook('modifyData')) {
                const valueHolder = (0, _object.createObjectPropListener)(value);
                // Physical indexes are passed here on purpose. In this context they match the visual ones.
                this.hot.runHooks('modifyData', physicalRow, physicalColumn, valueHolder, 'get');
                if (valueHolder.isTouched()) {
                    value = valueHolder.value;
                }
            }
            data.push({
                meta: cellMeta,
                value: (0, _utils.toEmptyString)(value)
            });
        }
        return data;
    }
    /**
   * Update the condition of ValueComponent, based on the handled changes.
   *
   * @private
   * @param {number} columnIndex Physical column index of handled ValueComponent condition.
   */ updateValueComponentCondition(columnIndex) {
        const visualColumnIndex = this.hot.toVisualColumn(columnIndex);
        const dataAtCol = this.hot.getDataAtCol(visualColumnIndex);
        const selectedValues = (0, _utils.unifyColumnValues)(dataAtCol);
        this.conditionUpdateObserver.updateStatesAtColumn(columnIndex, selectedValues);
    }
    /**
   * Restores components to its saved state.
   *
   * @private
   * @param {Array} components List of components.
   */ restoreComponents(components) {
        const physicalIndex = this.getSelectedColumn()?.physicalIndex;
        components.forEach((component)=>{
            if (component.isHidden()) {
                return;
            }
            component.restoreState(physicalIndex);
        });
        this.updateDependentComponentsVisibility();
    }
    /**
   * Get an operation, based on the number and types of arguments (where arguments are states of components).
   *
   * @param {string} suggestedOperation Operation which was chosen by user from UI.
   * @param {object} byConditionState1 State of first condition component.
   * @param {object} byConditionState2 State of second condition component.
   * @param {object} byValueState State of value component.
   * @private
   * @returns {string}
   */ getOperationBasedOnArguments(suggestedOperation, byConditionState1, byConditionState2, byValueState) {
        let operation = suggestedOperation;
        if (operation === _constants1.OPERATION_OR && byConditionState1.command.key !== _constants1.CONDITION_NONE && byConditionState2.command.key !== _constants1.CONDITION_NONE && byValueState.command.key !== _constants1.CONDITION_NONE) {
            operation = _constants1.OPERATION_OR_THEN_VARIABLE;
        } else if (byValueState.command.key !== _constants1.CONDITION_NONE) {
            if (byConditionState1.command.key === _constants1.CONDITION_NONE || byConditionState2.command.key === _constants1.CONDITION_NONE) {
                operation = _constants1.OPERATION_AND;
            }
        }
        return operation;
    }
    /**
   * Listen to the keyboard input on document body and forward events to instance of Handsontable
   * created by DropdownMenu plugin.
   *
   * @private
   */ setListeningDropdownMenu() {
        if (this.dropdownMenuPlugin) {
            this.dropdownMenuPlugin.setListening();
        }
    }
    /**
   * Updates visibility of some of the components, based on the state of the parent component.
   *
   * @private
   */ updateDependentComponentsVisibility() {
        const component = this.components.get('filter_by_condition');
        const { command } = component.getState();
        const componentsToShow = [
            this.components.get('filter_by_condition2'),
            this.components.get('filter_operators')
        ];
        if (command.showOperators) {
            this.showComponents(...componentsToShow);
        } else {
            this.hideComponents(...componentsToShow);
        }
    }
    /**
   * Creates DataFilter instance based on condition collection.
   *
   * @private
   * @param {ConditionCollection} conditionCollection Condition collection object.
   * @returns {DataFilter}
   */ _createDataFilter(conditionCollection = this.conditionCollection) {
        return new _dataFilter.default(conditionCollection, (physicalColumn)=>this.getDataMapAtColumn(physicalColumn));
    }
    /**
   * Returns indexes of passed components inside list of `dropdownMenu` items.
   *
   * @private
   * @param {...BaseComponent} components List of components.
   * @returns {Array}
   */ getIndexesOfComponents(...components) {
        const indexes = [];
        if (!this.dropdownMenuPlugin) {
            return indexes;
        }
        const menu = this.dropdownMenuPlugin.menu;
        (0, _array.arrayEach)(components, (component)=>{
            (0, _array.arrayEach)(menu.menuItems, (item, index)=>{
                if (item.key === component.getMenuItemDescriptor().key) {
                    indexes.push(index);
                }
            });
        });
        return indexes;
    }
    /**
   * Changes visibility of component.
   *
   * @private
   * @param {boolean} visible Determine if components should be visible.
   * @param {...BaseComponent} components List of components.
   */ changeComponentsVisibility(visible = true, ...components) {
        if (!this.dropdownMenuPlugin) {
            return;
        }
        const menu = this.dropdownMenuPlugin.menu;
        const hotMenu = menu.hotMenu;
        const hiddenRows = hotMenu.getPlugin('hiddenRows');
        const indexes = this.getIndexesOfComponents(...components);
        if (visible) {
            hiddenRows.showRows(indexes);
        } else {
            hiddenRows.hideRows(indexes);
        }
        hotMenu.render();
    }
    /**
   * Hides components of filters `dropdownMenu`.
   *
   * @private
   * @param {...BaseComponent} components List of components.
   */ hideComponents(...components) {
        this.changeComponentsVisibility(false, ...components);
    }
    /**
   * Shows components of filters `dropdownMenu`.
   *
   * @private
   * @param {...BaseComponent} components List of components.
   */ showComponents(...components) {
        this.changeComponentsVisibility(true, ...components);
    }
    /**
   * Destroys the plugin instance.
   */ destroy() {
        if (this.enabled) {
            this.components.forEach((component, key)=>{
                if (component !== null) {
                    component.destroy();
                    this.components.set(key, null);
                }
            });
            this.conditionCollection.destroy();
            this.conditionUpdateObserver.destroy();
            this.hot.rowIndexMapper.unregisterMap(this.pluginName);
        }
        super.destroy();
    }
    constructor(hotInstance){
        super(hotInstance), _class_private_method_init(this, _onAfterChange), _class_private_method_init(this, _onAfterDataProviderFetch), _class_private_method_init(this, _onAfterDataProviderFetchError), _class_private_method_init(this, _onAfterDropdownMenuShow), _class_private_method_init(this, _onAfterDropdownMenuHide), _class_private_method_init(this, _onBeforeDropdownMenuShow), _class_private_method_init(this, _onAfterDropdownMenuDefaultOptions), _class_private_method_init(this, _onActionBarSubmit), _class_private_method_init(this, _onComponentChange), _class_private_method_init(this, _onSelectUIClosed), _class_private_method_init(this, _onAfterGetColHeader), _class_private_method_init(this, _updateComponents), _class_private_field_init(this, _menuFocusNavigator, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _dropdownMenuTraces, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _previousConditionStack, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _dataProviderFilterRollbackStack, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _isDataProviderActive, {
            writable: true,
            value: void 0
        }), /**
   * Instance of {@link DropdownMenu}.
   *
   * @private
   * @type {DropdownMenu}
   */ this.dropdownMenuPlugin = null, /**
   * Instance of {@link ConditionCollection}.
   *
   * @private
   * @type {ConditionCollection}
   */ this.conditionCollection = null, /**
   * Instance of {@link ConditionUpdateObserver}.
   *
   * @private
   * @type {ConditionUpdateObserver}
   */ this.conditionUpdateObserver = null, /**
   * Map, where key is component identifier and value represent `BaseComponent` element or it derivatives.
   *
   * @private
   * @type {Map}
   */ this.components = new Map([
            [
                'filter_by_condition',
                null
            ],
            [
                'filter_operators',
                null
            ],
            [
                'filter_by_condition2',
                null
            ],
            [
                'filter_by_value',
                null
            ],
            [
                'filter_action_bar',
                null
            ]
        ]), /**
   * Map of skipped rows by plugin.
   *
   * @private
   * @type {null|TrimmingMap}
   */ this.filtersRowsMap = null, _class_private_field_set(this, _dropdownMenuTraces, new WeakSet()), _class_private_field_set(this, _previousConditionStack, []), _class_private_field_set(this, _dataProviderFilterRollbackStack, []), _class_private_field_set(this, _isDataProviderActive, false);
        // One listener for the enable/disable functionality
        this.hot.addHook('afterGetColHeader', (...args)=>_class_private_method_get(this, _onAfterGetColHeader, onAfterGetColHeader).call(this, ...args));
    }
}
function onAfterChange(changes) {
    if (changes) {
        (0, _array.arrayEach)(changes, (change)=>{
            const [, prop] = change;
            const visualColumnIndex = this.hot.propToCol(prop);
            const physicalColumnIndex = this.hot.toPhysicalColumn(visualColumnIndex);
            if (this.conditionCollection.hasConditions(physicalColumnIndex)) {
                this.updateValueComponentCondition(physicalColumnIndex);
            }
        });
    }
}
function onAfterDataProviderFetch(result) {
    this.importConditions(result?.filtersConditionsStack ?? []);
}
function onAfterDataProviderFetchError() {
    this.importConditions(_class_private_field_get(this, _dataProviderFilterRollbackStack));
}
function onAfterDropdownMenuShow() {
    const menu = this.dropdownMenuPlugin.menu;
    this.restoreComponents(Array.from(this.components.values()));
    menu.updateMenuDimensions();
}
function onAfterDropdownMenuHide() {
    this.components.get('filter_by_condition').getSelectElement().closeOptions();
    this.components.get('filter_by_condition2').getSelectElement().closeOptions();
}
function onBeforeDropdownMenuShow() {
    const mainMenu = this.dropdownMenuPlugin.menu;
    if (!_class_private_field_get(this, _dropdownMenuTraces).has(mainMenu)) {
        _class_private_field_get(this, _menuFocusNavigator).setMenu(mainMenu);
    }
    _class_private_field_get(this, _dropdownMenuTraces).add(mainMenu);
}
function onAfterDropdownMenuDefaultOptions(defaultOptions) {
    defaultOptions.items.push({
        name: _predefinedItems.SEPARATOR
    });
    this.components.forEach((component)=>{
        defaultOptions.items.push(component.getMenuItemDescriptor());
    });
}
function onActionBarSubmit(submitType) {
    if (submitType === 'accept') {
        const selectedColumn = this.getSelectedColumn();
        if (selectedColumn === null) {
            this.dropdownMenuPlugin?.close();
            return;
        }
        const { physicalIndex } = selectedColumn;
        const byConditionState1 = this.components.get('filter_by_condition').getState();
        const byConditionState2 = this.components.get('filter_by_condition2').getState();
        const byValueState = this.components.get('filter_by_value').getState();
        const operation = this.getOperationBasedOnArguments(this.components.get('filter_operators').getActiveOperationId(), byConditionState1, byConditionState2, byValueState);
        this.conditionUpdateObserver.groupChanges();
        let columnStackPosition = this.conditionCollection.getColumnStackPosition(physicalIndex);
        if (columnStackPosition === -1) {
            columnStackPosition = undefined;
        }
        this.conditionCollection.removeConditions(physicalIndex);
        if (byConditionState1.command.key !== _constants1.CONDITION_NONE) {
            this.conditionCollection.addCondition(physicalIndex, byConditionState1, operation, columnStackPosition);
            if (byConditionState2.command.key !== _constants1.CONDITION_NONE) {
                this.conditionCollection.addCondition(physicalIndex, byConditionState2, operation, columnStackPosition);
            }
        }
        if (byValueState.command.key !== _constants1.CONDITION_NONE && !_class_private_field_get(this, _isDataProviderActive)) {
            this.conditionCollection.addCondition(physicalIndex, byValueState, operation, columnStackPosition);
        }
        this.conditionUpdateObserver.flush();
        this.components.forEach((component)=>component.saveState(physicalIndex));
        this.filter();
    }
    this.dropdownMenuPlugin?.close();
}
function onComponentChange(component, command) {
    const menu = this.dropdownMenuPlugin.menu;
    this.updateDependentComponentsVisibility();
    if (component.constructor === _condition.ConditionComponent && !command.inputsCount) {
        this.setListeningDropdownMenu();
    }
    menu.updateMenuDimensions();
}
function onSelectUIClosed() {
    this.setListeningDropdownMenu();
}
function onAfterGetColHeader(col, TH) {
    const physicalColumn = this.hot.toPhysicalColumn(col);
    if (this.enabled && this.conditionCollection.hasConditions(physicalColumn) && (0, _element.isBottomMostColumnHeader)(TH)) {
        (0, _element.addClass)(TH, 'htFiltersActive');
    } else {
        (0, _element.removeClass)(TH, 'htFiltersActive');
    }
}
function updateComponents(conditionsState) {
    if (!this.dropdownMenuPlugin?.enabled) {
        return;
    }
    const { editedConditionStack: { conditions, column }, conditionArgsChange } = conditionsState;
    if (Array.isArray(conditionArgsChange)) {
        // update the previous condition stack (only for 'by_value' condition) on each dataset
        // change to make the undo/redo work properly
        _class_private_field_set(this, _previousConditionStack, _class_private_field_get(this, _previousConditionStack).map((stack)=>{
            if (stack.column === column && conditions.length > 0) {
                stack.conditions.forEach((condition)=>{
                    if (condition.name === 'by_value') {
                        condition.args = [
                            [
                                ...conditionArgsChange
                            ]
                        ];
                    }
                });
            }
            return stack;
        }));
    }
    const conditionsByValue = conditions.filter((condition)=>condition.name === _constants1.CONDITION_BY_VALUE);
    const conditionsWithoutByValue = conditions.filter((condition)=>condition.name !== _constants1.CONDITION_BY_VALUE);
    if (conditionsByValue.length >= 2 || conditionsWithoutByValue.length >= 3) {
        (0, _console.warn)((0, _templateLiteralTag.toSingleLine)`The filter conditions have been applied properly, but couldn’t be displayed visually.\x20
        The dropdown menu supports at most 2 regular conditions and 1 'filter by value' condition per column,\x20
        but more were provided. For more details see the documentation.`);
    } else {
        const operationType = this.conditionCollection.getOperation(column);
        this.components.get('filter_by_condition').updateState(conditionsWithoutByValue[0], column);
        this.components.get('filter_by_condition2').updateState(conditionsWithoutByValue[1], column);
        this.components.get('filter_operators').updateState(operationType, column);
        this.components.get('filter_by_value').updateState(conditionsState);
    }
}
