"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "default", {
    enumerable: true,
    get: function() {
        return _default;
    }
});
const _element = require("../../../helpers/dom/element");
const _feature = require("../../../helpers/feature");
const _function = require("../../../helpers/function");
const _array = require("../../../helpers/array");
const _unicode = require("../../../helpers/unicode");
const _console = require("../../../helpers/console");
const _overlay = require("./overlay");
const _stickyScrollStrategy = require("./stickyScrollStrategy");
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);
}
var /**
   * An array of the all overlays.
   *
   * @type {Overlay[]}
   */ _overlays = /*#__PURE__*/ new WeakMap(), /**
   * Indicates whether the rendering state has changed for one of the overlays.
   *
   * @type {boolean}
   */ _hasRenderingStateChanged = /*#__PURE__*/ new WeakMap(), /**
   * Cached vertical scroll position used to deduplicate `onScrollVertically` callbacks.
   * Tracks the value returned by `topOverlay.getScrollPosition()` at the time the callback
   * was last fired so that a second call with an unchanged position is suppressed.
   *
   * @type {number | null}
   */ _lastVerticalScrollPositionForCallback = /*#__PURE__*/ new WeakMap(), /**
   * Cached horizontal scroll position used to deduplicate `onScrollHorizontally` callbacks.
   * Tracks the value returned by `inlineStartOverlay.getScrollPosition()` at the time the
   * callback was last fired so that a second call with an unchanged position is suppressed.
   *
   * @type {number | null}
   */ _lastHorizontalScrollPositionForCallback = /*#__PURE__*/ new WeakMap(), /**
   * The amount of times the ResizeObserver callback was fired in direct succession.
   *
   * @type {number}
   */ _containerDomResizeCount = /*#__PURE__*/ new WeakMap(), /**
   * The timeout ID for the ResizeObserver endless-loop-blocking logic.
   *
   * @type {number}
   */ _containerDomResizeCountTimeout = /*#__PURE__*/ new WeakMap(), /**
   * Debounced `updateLastSpreaderSize` / `adjustElementsSize` used during scroll so rapid
   * `refresh` calls do not repeat layout work every frame.
   *
   * @type {Function}
   */ _postponedAdjustElementsSize = /*#__PURE__*/ new WeakMap(), /**
   * Strategy that manages the sticky-scroll optimization during native
   * scrollbar drag. Extracted as a separate class to isolate the sticky
   * positioning lifecycle from the overlay coordinator.
   *
   * @type {StickyScrollStrategy}
   */ _stickyScroll = /*#__PURE__*/ new WeakMap(), /**
   * Caches the initial vertical and horizontal scroll positions for callback deduplication.
   */ _cacheScrollCallbackPositions = /*#__PURE__*/ new WeakSet(), /**
   * Checks whether the vertical scroll position has changed since the last `onScrollVertically`
   * callback and updates the cache. Returns `true` when the callback should fire.
   *
   * @returns {boolean}
   */ _didVerticalScrollPositionChange = /*#__PURE__*/ new WeakSet(), /**
   * Checks whether the horizontal scroll position has changed since the last `onScrollHorizontally`
   * callback and updates the cache. Returns `true` when the callback should fire.
   *
   * @returns {boolean}
   */ _didHorizontalScrollPositionChange = /*#__PURE__*/ new WeakSet(), /**
   * Adjust the elements size if needed.
   */ _adjustElementsSizeIfNeeded = /*#__PURE__*/ new WeakSet();
/**
 * @class Overlays
 */ class Overlays {
    /**
   * Get the list of references to all overlays.
   *
   * @param {boolean} [includeMaster = false] If set to `true`, the list will contain the master table as the last
   * element.
   * @returns {(TopOverlay|TopInlineStartCornerOverlay|InlineStartOverlay|BottomOverlay|BottomInlineStartCornerOverlay)[]}
   */ getOverlays(includeMaster = false) {
        const overlays = [
            ..._class_private_field_get(this, _overlays)
        ];
        if (includeMaster) {
            overlays.push(this.wtTable);
        }
        return overlays;
    }
    /**
   * Retrieve browser line height and apply its value to `browserLineHeight`.
   *
   * @private
   */ initBrowserLineHeight() {
        const { rootWindow, rootDocument } = this.domBindings;
        const computedStyle = rootWindow.getComputedStyle(rootDocument.body);
        /**
     * Sometimes `line-height` might be set to 'normal'. In that case, a default `font-size` should be multiplied by roughly 1.2.
     * Https://developer.mozilla.org/pl/docs/Web/CSS/line-height#Values.
     */ const lineHeight = parseInt(computedStyle.lineHeight, 10);
        const lineHeightFalback = parseInt(computedStyle.fontSize, 10) * 1.2;
        this.browserLineHeight = lineHeight || lineHeightFalback;
    }
    /**
   * Prepare overlays based on user settings.
   *
   * @private
   */ initOverlays() {
        const args = [
            this.wot,
            this.facadeGetter,
            this.wtSettings,
            this.domBindings
        ];
        // todo refactoring: IOC, collection or factories.
        // TODO refactoring, conceive about using generic collection of overlays.
        this.topOverlay = new _overlay.TopOverlay(...args);
        this.bottomOverlay = new _overlay.BottomOverlay(...args);
        this.inlineStartOverlay = new _overlay.InlineStartOverlay(...args);
        // TODO discuss, the controversial here would be removing the lazy creation mechanism for corners.
        // TODO cond. Has no any visual impact. They're initially hidden in same way like left, top, and bottom overlays.
        this.topInlineStartCornerOverlay = new _overlay.TopInlineStartCornerOverlay(...args, this.topOverlay, this.inlineStartOverlay);
        this.bottomInlineStartCornerOverlay = new _overlay.BottomInlineStartCornerOverlay(...args, this.bottomOverlay, this.inlineStartOverlay);
        _class_private_field_set(this, _overlays, [
            this.topOverlay,
            this.bottomOverlay,
            this.inlineStartOverlay,
            this.topInlineStartCornerOverlay,
            this.bottomInlineStartCornerOverlay
        ]);
    }
    /**
   * Runs logic for the overlays before the table is drawn.
   */ beforeDraw() {
        _class_private_field_set(this, _hasRenderingStateChanged, _class_private_field_get(this, _overlays).reduce((acc, overlay)=>{
            return overlay.hasRenderingStateChanged() || acc;
        }, false));
        _class_private_field_get(this, _overlays).forEach((overlay)=>overlay.updateStateOfRendering('before'));
    }
    /**
   * Runs logic for the overlays after the table is drawn.
   */ afterDraw() {
        this.syncScrollWithMaster();
        _class_private_field_get(this, _overlays).forEach((overlay)=>{
            const hasRenderingStateChanged = overlay.hasRenderingStateChanged();
            overlay.updateStateOfRendering('after');
            if (hasRenderingStateChanged && !overlay.needFullRender) {
                overlay.reset();
            }
        });
    }
    /**
   * Refresh and redraw table.
   */ refreshAll() {
        if (!this.wot.drawn) {
            return;
        }
        if (!this.wtTable.holder.parentNode) {
            // Walkontable was detached from DOM, but this handler was not removed
            this.destroy();
            return;
        }
        this.wot.draw(true);
        if (this.verticalScrolling && _class_private_method_get(this, _didVerticalScrollPositionChange, didVerticalScrollPositionChange).call(this)) {
            this.inlineStartOverlay.onScroll(); // todo the inlineStartOverlay.onScroll() fires hook. Why is it needed there, not in any another place?
        }
        if (this.horizontalScrolling && _class_private_method_get(this, _didHorizontalScrollPositionChange, didHorizontalScrollPositionChange).call(this)) {
            this.topOverlay.onScroll();
        }
        this.verticalScrolling = false;
        this.horizontalScrolling = false;
    }
    /**
   * Register all necessary event listeners.
   */ registerListeners() {
        const { rootDocument, rootWindow } = this.domBindings;
        const { mainTableScrollableElement: topOverlayScrollableElement } = this.topOverlay;
        const { mainTableScrollableElement: inlineStartOverlayScrollableElement } = this.inlineStartOverlay;
        this.eventManager.addEventListener(rootDocument.documentElement, 'keydown', (event)=>this.onKeyDown(event));
        this.eventManager.addEventListener(rootDocument.documentElement, 'keyup', ()=>this.onKeyUp());
        this.eventManager.addEventListener(rootDocument, 'visibilitychange', ()=>this.onKeyUp());
        _class_private_field_get(this, _stickyScroll).registerListeners();
        this.eventManager.addEventListener(topOverlayScrollableElement, 'scroll', (event)=>this.onTableScroll(event), {
            passive: true
        });
        if (topOverlayScrollableElement !== inlineStartOverlayScrollableElement) {
            this.eventManager.addEventListener(inlineStartOverlayScrollableElement, 'scroll', (event)=>this.onTableScroll(event), {
                passive: true
            });
        }
        const isScrollOnWindow = this.scrollableElement === rootWindow;
        const preventWheel = this.wtSettings.getSetting('preventWheel');
        const wheelEventOptions = {
            passive: isScrollOnWindow
        };
        this.eventManager.addEventListener(this.wtTable.wtRootElement, 'wheel', (event)=>this.onCloneWheel(event, preventWheel), wheelEventOptions);
        const overlays = [
            this.topOverlay,
            this.bottomOverlay,
            this.inlineStartOverlay,
            this.topInlineStartCornerOverlay,
            this.bottomInlineStartCornerOverlay
        ];
        overlays.forEach((overlay)=>{
            this.eventManager.addEventListener(overlay.clone.wtTable.holder, 'wheel', (event)=>this.onCloneWheel(event, preventWheel), wheelEventOptions);
        });
        let resizeTimeout;
        this.eventManager.addEventListener(rootWindow, 'resize', ()=>{
            (0, _feature.requestAnimationFrame)(()=>{
                clearTimeout(resizeTimeout);
                this.wtSettings.getSetting('onWindowResize');
                resizeTimeout = setTimeout(()=>{
                    // Remove resizing the window from the ResizeObserver's endless-loop-blocking logic.
                    _class_private_field_set(this, _containerDomResizeCount, 0);
                }, 200);
            });
        });
        if (!isScrollOnWindow) {
            this.resizeObserver.observe(this.wtTable.wtRootElement.parentElement);
        }
    }
    /**
   * Scroll listener.
   *
   * @param {Event} event The mouse event object.
   */ onTableScroll(event) {
        // There was if statement which controlled flow of this function. It avoided the execution of the next lines
        // on mobile devices. It was changed. Broader description of this case is included within issue #4856.
        const rootWindow = this.domBindings.rootWindow;
        const masterHorizontal = this.inlineStartOverlay.mainTableScrollableElement;
        const masterVertical = this.topOverlay.mainTableScrollableElement;
        const target = event.target;
        // For key press, sync only master -> overlay position because while pressing Walkontable.render is triggered
        // by hot.refreshBorder
        if (this.keyPressed) {
            if (masterVertical !== rootWindow && target !== rootWindow && !event.target.contains(masterVertical) || masterHorizontal !== rootWindow && target !== rootWindow && !event.target.contains(masterHorizontal)) {
                return;
            }
        }
        this.syncScrollPositions(event);
    }
    /**
   * Wheel listener for cloned overlays.
   *
   * @param {Event} event The mouse event object.
   * @param {boolean} preventDefault If `true`, the `preventDefault` will be called on event object.
   */ onCloneWheel(event, preventDefault) {
        // Fix for Windows OS, where the ctrl key is used to zoom the page (issue #dev-2405).
        if (event.ctrlKey) {
            return;
        }
        const { rootWindow } = this.domBindings;
        // There was if statement which controlled flow of this function. It avoided the execution of the next lines
        // on mobile devices. It was changed. Broader description of this case is included within issue #4856.
        const masterHorizontal = this.inlineStartOverlay.mainTableScrollableElement;
        const masterVertical = this.topOverlay.mainTableScrollableElement;
        const target = event.target;
        // For key press, sync only master -> overlay position because while pressing Walkontable.render is triggered
        // by hot.refreshBorder
        const shouldNotWheelVertically = masterVertical !== rootWindow && target !== rootWindow && !target.contains(masterVertical);
        const shouldNotWheelHorizontally = masterHorizontal !== rootWindow && target !== rootWindow && !target.contains(masterHorizontal);
        if (this.keyPressed && (shouldNotWheelVertically || shouldNotWheelHorizontally) || this.scrollableElement === rootWindow) {
            return;
        }
        const isScrollPossible = this.translateMouseWheelToScroll(event);
        if (preventDefault || this.scrollableElement !== rootWindow && isScrollPossible) {
            event.preventDefault();
        }
    }
    /**
   * Key down listener.
   *
   * @param {Event} event The keyboard event object.
   */ onKeyDown(event) {
        this.keyPressed = (0, _unicode.isKey)(event.keyCode, 'ARROW_UP|ARROW_RIGHT|ARROW_DOWN|ARROW_LEFT');
    }
    /**
   * Key up listener.
   */ onKeyUp() {
        this.keyPressed = false;
    }
    /**
   * Translate wheel event into scroll event and sync scroll overlays position.
   *
   * @private
   * @param {Event} event The mouse event object.
   * @returns {boolean}
   */ translateMouseWheelToScroll(event) {
        let deltaY = isNaN(event.deltaY) ? -1 * event.wheelDeltaY : event.deltaY;
        let deltaX = isNaN(event.deltaX) ? -1 * event.wheelDeltaX : event.deltaX;
        if (event.deltaMode === 1) {
            deltaX += deltaX * this.browserLineHeight;
            deltaY += deltaY * this.browserLineHeight;
        }
        const isScrollVerticallyPossible = this.scrollVertically(deltaY);
        const isScrollHorizontallyPossible = this.scrollHorizontally(deltaX);
        return isScrollVerticallyPossible || isScrollHorizontallyPossible;
    }
    /**
   * Scrolls main scrollable element horizontally.
   *
   * @param {number} delta Relative value to scroll.
   * @returns {boolean}
   */ scrollVertically(delta) {
        const previousScroll = this.scrollableElement.scrollTop;
        this.scrollableElement.scrollTop += delta;
        return previousScroll !== this.scrollableElement.scrollTop;
    }
    /**
   * Scrolls main scrollable element horizontally.
   *
   * @param {number} delta Relative value to scroll.
   * @returns {boolean}
   */ scrollHorizontally(delta) {
        const previousScroll = this.scrollableElement.scrollLeft;
        this.scrollableElement.scrollLeft += delta;
        return previousScroll !== this.scrollableElement.scrollLeft;
    }
    /**
   * Synchronize scroll position between master table and overlay table.
   *
   * @private
   */ syncScrollPositions() {
        if (this.destroyed) {
            return;
        }
        const topHolder = this.topOverlay.clone.wtTable.holder; // todo rethink
        const leftHolder = this.inlineStartOverlay.clone.wtTable.holder; // todo rethink
        const preventOverflow = this.wtSettings.getSetting('preventOverflow');
        let scrollX = this.scrollableElement.scrollLeft;
        let scrollY = this.scrollableElement.scrollTop;
        if (this.wot.wtViewport.isHorizontallyScrollableByWindow() && (typeof preventOverflow === 'boolean' && preventOverflow || preventOverflow !== 'horizontal')) {
            scrollX = this.scrollableElement.scrollX;
        }
        if (this.wot.wtViewport.isVerticallyScrollableByWindow() && (typeof preventOverflow === 'boolean' && preventOverflow || preventOverflow !== 'vertical')) {
            scrollY = this.scrollableElement.scrollY;
        }
        this.horizontalScrolling = this.lastScrollX !== scrollX;
        this.verticalScrolling = this.lastScrollY !== scrollY;
        this.lastScrollX = scrollX;
        this.lastScrollY = scrollY;
        _class_private_field_get(this, _stickyScroll).tryActivate(this.verticalScrolling, this.horizontalScrolling);
        if (this.horizontalScrolling) {
            topHolder.scrollLeft = scrollX;
            const bottomHolder = this.bottomOverlay.needFullRender ? this.bottomOverlay.clone.wtTable.holder : null; // todo rethink
            if (bottomHolder) {
                bottomHolder.scrollLeft = scrollX;
            }
        }
        if (this.verticalScrolling) {
            leftHolder.scrollTop = scrollY;
        }
        this.refreshAll();
        _class_private_field_get(this, _stickyScroll).syncOffsets();
    }
    /**
   * Synchronize overlay scrollbars with the master scrollbar.
   */ syncScrollWithMaster() {
        if (!_class_private_field_get(this, _hasRenderingStateChanged)) {
            return;
        }
        const master = this.topOverlay.mainTableScrollableElement;
        const { scrollLeft, scrollTop } = master;
        if (this.topOverlay.needFullRender) {
            this.topOverlay.clone.wtTable.holder.scrollLeft = scrollLeft; // todo rethink, *overlay.setScroll*()
        }
        if (this.bottomOverlay.needFullRender) {
            this.bottomOverlay.clone.wtTable.holder.scrollLeft = scrollLeft; // todo rethink, *overlay.setScroll*()
        }
        if (this.inlineStartOverlay.needFullRender) {
            this.inlineStartOverlay.clone.wtTable.holder.scrollTop = scrollTop; // todo rethink, *overlay.setScroll*()
        }
        _class_private_field_set(this, _hasRenderingStateChanged, false);
    }
    /**
   * Update the main scrollable elements for all the overlays.
   */ updateMainScrollableElements() {
        this.eventManager.clearEvents(true);
        this.inlineStartOverlay.updateMainScrollableElement();
        this.topOverlay.updateMainScrollableElement();
        if (this.bottomOverlay.needFullRender) {
            this.bottomOverlay.updateMainScrollableElement();
        }
        const { wtTable } = this;
        const { rootWindow } = this.domBindings;
        const computedOverflow = rootWindow.getComputedStyle(wtTable.wtRootElement.parentNode).getPropertyValue('overflow');
        if (computedOverflow === 'hidden' || computedOverflow === 'clip') {
            this.scrollableElement = wtTable.holder;
        } else {
            this.scrollableElement = (0, _element.getScrollableElement)(wtTable.TABLE);
        }
        this.registerListeners();
    }
    /**
   *
   */ destroy() {
        _class_private_field_get(this, _postponedAdjustElementsSize).cancel();
        if (_class_private_field_get(this, _containerDomResizeCountTimeout) !== null) {
            clearTimeout(_class_private_field_get(this, _containerDomResizeCountTimeout));
            _class_private_field_set(this, _containerDomResizeCountTimeout, null);
        }
        this.resizeObserver.disconnect();
        _class_private_field_get(this, _stickyScroll).destroy();
        this.eventManager.destroy();
        // todo, probably all below `destroy` calls has no sense. To analyze
        this.topOverlay.destroy();
        if (this.bottomOverlay.clone) {
            this.bottomOverlay.destroy();
        }
        this.inlineStartOverlay.destroy();
        if (this.topInlineStartCornerOverlay) {
            this.topInlineStartCornerOverlay.destroy();
        }
        if (this.bottomInlineStartCornerOverlay && this.bottomInlineStartCornerOverlay.clone) {
            this.bottomInlineStartCornerOverlay.destroy();
        }
        this.destroyed = true;
    }
    /**
   * @param {boolean} [fastDraw=false] When `true`, try to refresh only the positions of borders without rerendering
   *                                   the data. It will only work if Table.draw() does not force
   *                                   rendering anyway.
   */ refresh(fastDraw = false) {
        const isScrollTriggered = this.verticalScrolling || this.horizontalScrolling;
        if (isScrollTriggered) {
            _class_private_field_get(this, _postponedAdjustElementsSize).call(this);
        } else {
            _class_private_method_get(this, _adjustElementsSizeIfNeeded, adjustElementsSizeIfNeeded).call(this);
        }
        if (this.bottomOverlay.clone) {
            this.bottomOverlay.refresh(fastDraw);
        }
        this.inlineStartOverlay.refresh(fastDraw);
        this.topOverlay.refresh(fastDraw);
        if (this.topInlineStartCornerOverlay) {
            this.topInlineStartCornerOverlay.refresh(fastDraw);
        }
        if (this.bottomInlineStartCornerOverlay && this.bottomInlineStartCornerOverlay.clone) {
            this.bottomInlineStartCornerOverlay.refresh(fastDraw);
        }
    }
    /**
   * Update the last cached spreader size with the current size.
   *
   * @returns {boolean} `true` if the lastSpreaderSize cache was updated, `false` otherwise.
   */ updateLastSpreaderSize() {
        const spreader = this.wtTable.spreader;
        const width = spreader.clientWidth;
        const height = spreader.clientHeight;
        const needsUpdating = width !== this.spreaderLastSize.width || height !== this.spreaderLastSize.height;
        if (needsUpdating) {
            this.spreaderLastSize.width = width;
            this.spreaderLastSize.height = height;
        }
        return needsUpdating;
    }
    /**
   * Adjust overlays elements size and master table size.
   */ adjustElementsSize() {
        const { wtViewport } = this.wot;
        const { wtTable } = this;
        const { rootWindow } = this.domBindings;
        const isWindowScrolled = this.scrollableElement === rootWindow;
        const totalColumns = this.wtSettings.getSetting('totalColumns');
        const totalRows = this.wtSettings.getSetting('totalRows');
        const headerRowSize = wtViewport.getRowHeaderWidth();
        const headerColumnSize = wtViewport.getColumnHeaderHeight();
        // The internal row height calculator contains a known issue that results in a 1px miscalculation.
        // Ideally, this should be addressed at the core level. However, resolving it is non-trivial,
        // as the flaw is embedded across multiple core modules and corresponding test cases.
        // This limitation does not affect when the external calculator is used (AutoRowSize), which
        // computes heights accurately, so no adjustment is required when using it.
        const hiderHeightComp = this.wtSettings.getSetting('externalRowCalculator') ? 0 : 1;
        const proposedHiderHeight = headerColumnSize + this.topOverlay.sumCellSizes(0, totalRows) + hiderHeightComp;
        const proposedHiderWidth = headerRowSize + this.inlineStartOverlay.sumCellSizes(0, totalColumns);
        const hiderElement = wtTable.hider;
        const hiderStyle = hiderElement.style;
        const isScrolledBeyondHiderHeight = ()=>{
            return isWindowScrolled ? false : this.scrollableElement.scrollTop > Math.max(0, proposedHiderHeight - wtTable.holder.clientHeight);
        };
        const isScrolledBeyondHiderWidth = ()=>{
            return isWindowScrolled ? false : this.scrollableElement.scrollLeft > Math.max(0, proposedHiderWidth - wtTable.holder.clientWidth);
        };
        const columnHeaderBorderCompensation = isScrolledBeyondHiderHeight() ? 1 : 0;
        const rowHeaderBorderCompensation = isScrolledBeyondHiderWidth() ? 1 : 0;
        // If the elements are being adjusted after scrolling the table from the very beginning to the very end,
        // we need to adjust the hider dimensions by the header border size. (https://github.com/handsontable/dev-handsontable/issues/1772)
        hiderStyle.width = `${proposedHiderWidth + rowHeaderBorderCompensation}px`;
        hiderStyle.height = `${proposedHiderHeight + columnHeaderBorderCompensation}px`;
        this.topOverlay.adjustElementsSize();
        this.inlineStartOverlay.adjustElementsSize();
        this.bottomOverlay.adjustElementsSize();
    }
    /**
   * Expand the hider vertically element by the provided delta value.
   *
   * @param {number} heightDelta The delta value to expand the hider element by.
   */ expandHiderVerticallyBy(heightDelta) {
        const { wtTable } = this;
        wtTable.hider.style.height = `${parseInt(wtTable.hider.style.height, 10) + heightDelta}px`;
    }
    /**
   * Expand the hider horizontally element by the provided delta value.
   *
   * @param {number} widthDelta The delta value to expand the hider element by.
   */ expandHiderHorizontallyBy(widthDelta) {
        const { wtTable } = this;
        wtTable.hider.style.width = `${parseInt(wtTable.hider.style.width, 10) + widthDelta}px`;
    }
    /**
   *
   */ applyToDOM() {
        if (!this.wtTable.isVisible()) {
            return;
        }
        this.topOverlay.applyToDOM();
        if (this.bottomOverlay.clone) {
            this.bottomOverlay.applyToDOM();
        }
        this.inlineStartOverlay.applyToDOM();
        _class_private_field_get(this, _stickyScroll).syncOffsets();
    }
    /**
   * Get the parent overlay of the provided element.
   *
   * @param {HTMLElement} element An element to process.
   * @returns {object|null}
   */ getParentOverlay(element) {
        if (!element) {
            return null;
        }
        const overlays = [
            this.topOverlay,
            this.inlineStartOverlay,
            this.bottomOverlay,
            this.topInlineStartCornerOverlay,
            this.bottomInlineStartCornerOverlay
        ];
        let result = null;
        (0, _array.arrayEach)(overlays, (overlay)=>{
            if (!overlay) {
                return;
            }
            if (overlay.clone && overlay.clone.wtTable.TABLE.contains(element)) {
                result = overlay.clone;
            }
        });
        return result;
    }
    /**
   * Synchronize the class names between the main overlay table and the tables on the other overlays.
   *
   */ syncOverlayTableClassNames() {
        const masterTable = this.wtTable.TABLE;
        const overlays = [
            this.topOverlay,
            this.inlineStartOverlay,
            this.bottomOverlay,
            this.topInlineStartCornerOverlay,
            this.bottomInlineStartCornerOverlay
        ];
        (0, _array.arrayEach)(overlays, (elem)=>{
            if (!elem) {
                return;
            }
            elem.clone.wtTable.TABLE.className = masterTable.className; // todo demeter
        });
    }
    /**
   * @param {Walkontable} wotInstance The Walkontable instance. @todo refactoring remove.
   * @param {FacadeGetter} facadeGetter Function which return proper facade.
   * @param {DomBindings} domBindings Bindings into DOM.
   * @param {Settings} wtSettings The Walkontable settings.
   * @param {EventManager} eventManager The walkontable event manager.
   * @param {MasterTable} wtTable The master table.
   */ constructor(wotInstance, facadeGetter, domBindings, wtSettings, eventManager, wtTable){
        _class_private_method_init(this, _cacheScrollCallbackPositions);
        _class_private_method_init(this, _didVerticalScrollPositionChange);
        _class_private_method_init(this, _didHorizontalScrollPositionChange);
        _class_private_method_init(this, _adjustElementsSizeIfNeeded);
        _class_private_field_init(this, _overlays, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _hasRenderingStateChanged, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _lastVerticalScrollPositionForCallback, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _lastHorizontalScrollPositionForCallback, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _containerDomResizeCount, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _containerDomResizeCountTimeout, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _postponedAdjustElementsSize, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _stickyScroll, {
            writable: true,
            value: void 0
        });
        /**
   * Walkontable instance's reference.
   *
   * @protected
   * @type {Walkontable}
   */ this.wot = null;
        _class_private_field_set(this, _overlays, []);
        /**
   * Refer to the TopOverlay instance.
   *
   * @protected
   * @type {TopOverlay}
   */ this.topOverlay = null;
        /**
   * Refer to the BottomOverlay instance.
   *
   * @protected
   * @type {BottomOverlay}
   */ this.bottomOverlay = null;
        /**
   * Refer to the InlineStartOverlay or instance.
   *
   * @protected
   * @type {InlineStartOverlay}
   */ this.inlineStartOverlay = null;
        /**
   * Refer to the TopInlineStartCornerOverlay instance.
   *
   * @protected
   * @type {TopInlineStartCornerOverlay}
   */ this.topInlineStartCornerOverlay = null;
        /**
   * Refer to the BottomInlineStartCornerOverlay instance.
   *
   * @protected
   * @type {BottomInlineStartCornerOverlay}
   */ this.bottomInlineStartCornerOverlay = null;
        /**
   * Browser line height for purposes of translating mouse wheel.
   *
   * @private
   * @type {number}
   */ this.browserLineHeight = undefined;
        /**
   * The walkontable settings.
   *
   * @protected
   * @type {Settings}
   */ this.wtSettings = null;
        _class_private_field_set(this, _hasRenderingStateChanged, false);
        _class_private_field_set(this, _lastVerticalScrollPositionForCallback, null);
        _class_private_field_set(this, _lastHorizontalScrollPositionForCallback, null);
        _class_private_field_set(this, _containerDomResizeCount, 0);
        _class_private_field_set(this, _containerDomResizeCountTimeout, null);
        _class_private_field_set(this, _postponedAdjustElementsSize, (0, _function.debounce)(_class_private_method_get(this, _adjustElementsSizeIfNeeded, adjustElementsSizeIfNeeded).bind(this), 200));
        _class_private_field_set(this, _stickyScroll, new _stickyScrollStrategy.StickyScrollStrategy(this));
        /**
   * The instance of the ResizeObserver that observes the size of the Walkontable wrapper element.
   * In case of the size change detection the `onContainerElementResize` is fired.
   *
   * @private
   * @type {ResizeObserver}
   */ this.resizeObserver = new ResizeObserver((entries)=>{
            (0, _feature.requestAnimationFrame)(()=>{
                if (!Array.isArray(entries) || !entries.length) {
                    return;
                }
                _class_private_field_set(this, _containerDomResizeCount, _class_private_field_get(this, _containerDomResizeCount) + 1);
                if (_class_private_field_get(this, _containerDomResizeCount) === 300) {
                    (0, _console.warn)('The ResizeObserver callback was fired too many times in direct succession.' + '\nThis may be due to an infinite loop caused by setting a dynamic height/width (for example, ' + 'with the `dvh` units) to a Handsontable container\'s parent. ' + '\nThe observer will be disconnected.');
                    this.resizeObserver.disconnect();
                }
                // This logic is required to prevent an endless loop of the ResizeObserver callback.
                // https://github.com/handsontable/dev-handsontable/issues/1898#issuecomment-2154794817
                if (_class_private_field_get(this, _containerDomResizeCountTimeout) !== null) {
                    clearTimeout(_class_private_field_get(this, _containerDomResizeCountTimeout));
                }
                _class_private_field_set(this, _containerDomResizeCountTimeout, setTimeout(()=>{
                    _class_private_field_set(this, _containerDomResizeCount, 0);
                }, 100));
                this.wtSettings.getSetting('onContainerElementResize');
            });
        });
        this.wot = wotInstance;
        this.wtSettings = wtSettings;
        this.domBindings = domBindings;
        this.facadeGetter = facadeGetter;
        this.wtTable = wtTable;
        const { rootDocument, rootWindow } = this.domBindings;
        // legacy support
        this.instance = this.wot; // todo refactoring: move to facade
        this.eventManager = eventManager;
        // TODO refactoring: probably invalid place to this logic
        this.scrollbarSize = (0, _element.getScrollbarWidth)(rootDocument);
        const computedOverflow = rootWindow.getComputedStyle(wtTable.wtRootElement.parentNode).getPropertyValue('overflow');
        const isOverflowClip = computedOverflow === 'hidden' || computedOverflow === 'clip';
        this.scrollableElement = isOverflowClip ? wtTable.holder : (0, _element.getScrollableElement)(wtTable.TABLE);
        this.initOverlays();
        _class_private_method_get(this, _cacheScrollCallbackPositions, cacheScrollCallbackPositions).call(this);
        this.destroyed = false;
        this.keyPressed = false;
        this.spreaderLastSize = {
            width: null,
            height: null
        };
        this.verticalScrolling = false;
        this.horizontalScrolling = false;
        this.initBrowserLineHeight();
        this.registerListeners();
        this.lastScrollX = rootWindow.scrollX;
        this.lastScrollY = rootWindow.scrollY;
    }
}
function cacheScrollCallbackPositions() {
    _class_private_field_set(this, _lastVerticalScrollPositionForCallback, this.topOverlay.getScrollPosition());
    _class_private_field_set(this, _lastHorizontalScrollPositionForCallback, this.inlineStartOverlay.getScrollPosition());
}
function didVerticalScrollPositionChange() {
    const current = this.topOverlay.getScrollPosition();
    if (_class_private_field_get(this, _lastVerticalScrollPositionForCallback) === current) {
        return false;
    }
    _class_private_field_set(this, _lastVerticalScrollPositionForCallback, current);
    return true;
}
function didHorizontalScrollPositionChange() {
    const current = this.inlineStartOverlay.getScrollPosition();
    if (_class_private_field_get(this, _lastHorizontalScrollPositionForCallback) === current) {
        return false;
    }
    _class_private_field_set(this, _lastHorizontalScrollPositionForCallback, current);
    return true;
}
function adjustElementsSizeIfNeeded() {
    if (this.destroyed) {
        return;
    }
    const wasSpreaderSizeUpdated = this.updateLastSpreaderSize();
    if (wasSpreaderSizeUpdated) {
        this.adjustElementsSize();
    }
}
const _default = Overlays;
