"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "EmptyDataStateUI", {
    enumerable: true,
    get: function() {
        return EmptyDataStateUI;
    }
});
const _templateLiteralTag = require("../../helpers/templateLiteralTag");
const _element = require("../../helpers/dom/element");
const _a11y = require("../../helpers/a11y");
const _string = require("../../helpers/string");
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;
}
const EMPTY_DATA_STATE_CLASS_NAME = 'ht-empty-data-state';
const MIN_HEIGHT = 150;
const TEMPLATE = `<div data-ref="emptyDataStateElement" class="${EMPTY_DATA_STATE_CLASS_NAME} handsontable">
  <div class="${EMPTY_DATA_STATE_CLASS_NAME}__content-wrapper">
    <div data-ref="emptyDataStateInner" class="${EMPTY_DATA_STATE_CLASS_NAME}__content-wrapper-inner"></div>
  </div>
</div>`;
const templateContent = ({ title, description, buttons }, isLoading = false)=>{
    const spinnerBlock = isLoading ? `<div class="${EMPTY_DATA_STATE_CLASS_NAME}__spinner" aria-hidden="true"></div>` : '';
    return `
  ${spinnerBlock}
  <div class="${EMPTY_DATA_STATE_CLASS_NAME}__content">
    ${title ? `<h2 class="${EMPTY_DATA_STATE_CLASS_NAME}__title">${(0, _string.stripTags)(title)}</h2>` : ''}
    ${description ? `<p class="${EMPTY_DATA_STATE_CLASS_NAME}__description">${(0, _string.stripTags)(description)}</p>` : ''}
  </div>
  <div
    data-ref="emptyDataStateButtons"
    class="${EMPTY_DATA_STATE_CLASS_NAME}__buttons${buttons?.length > 0 ? ` ${EMPTY_DATA_STATE_CLASS_NAME}__buttons--has-buttons` : ''}"
  >${!isLoading && buttons?.length > 0 ? buttons.map((button)=>`<button class="ht-button ht-button--${button.type}">${(0, _string.stripTags)(button.text)}</button>`).join('') : ''}</div>`;
};
/**
 * Creates, updates, or removes the min-height placeholder when there are no renderable rows.
 *
 * @param {Document} rootDocument - Root document for creating elements.
 * @param {View} view - The view instance.
 * @param {number} rows - Renderable row count.
 * @param {string} classNamePrefix - Base class name for the empty data state.
 * @param {{ element: HTMLElement | null }} placeholderState - In/out placeholder element reference.
 * @returns {void}
 */ function syncEmptyDataStatePlaceholder(rootDocument, view, rows, classNamePrefix, placeholderState) {
    if (rows !== 0) {
        placeholderState.element?.remove();
        placeholderState.element = null;
        return;
    }
    if (!placeholderState.element) {
        placeholderState.element = rootDocument.createElement('div');
        placeholderState.element.classList.add(`${classNamePrefix}-placeholder`);
        view._wt.wtTable.holder.appendChild(placeholderState.element);
    }
    placeholderState.element.style.width = '100%';
    placeholderState.element.style.height = `${MIN_HEIGHT}px`;
}
/**
 * Resolves the empty-data-state overlay width for the current view and column layout.
 *
 * @param {View} view - The view instance.
 * @param {number} cols - Renderable column count.
 * @param {boolean} treatAsPopulatedRowsForSizing - When `true`, use viewport width if horizontally window-scrollable.
 * @returns {number} Width in pixels.
 */ function computeEmptyDataStateWidth(view, cols, treatAsPopulatedRowsForSizing) {
    let width = view.getWorkspaceWidth();
    if (view.isHorizontallyScrollableByWindow()) {
        if (cols > 0) {
            width = view.getTotalTableWidth();
        } else if (treatAsPopulatedRowsForSizing) {
            width = view.getViewportWidth();
        }
    } else if (view.getTableWidth() - view.getRowHeaderWidth() < view.getViewportWidth() && cols > 0) {
        width = view.getTableWidth();
    }
    return width;
}
/**
 * Resolves the empty-data-state overlay height for the current view and header layout.
 *
 * @param {View} view - The view instance.
 * @param {number} cols - Renderable column count.
 * @param {number} headerCols - Column header count.
 * @param {number} scrollbarSize - Horizontal scrollbar thickness when scrollbars are shown.
 * @returns {number} Height in pixels.
 */ function computeEmptyDataStateHeight(view, cols, headerCols, scrollbarSize) {
    let height = view.getTableHeight();
    if (view.isVerticallyScrollableByWindow() || view.hasVerticalScroll()) {
        if (cols > 0) {
            height = view.hot.getTableHeight() - view.getColumnHeaderHeight();
        } else {
            height = view.hot.getTableHeight();
        }
    } else if (headerCols > 0 && cols > 0) {
        height = view.getViewportHeight() - scrollbarSize;
    } else if (headerCols > 0 && cols === 0) {
        height = view.getWorkspaceHeight() - scrollbarSize;
    }
    return height;
}
var /**
   * The root element where the emptyDataState UI will be installed.
   *
   * @type {HTMLElement}
   */ _rootElement = /*#__PURE__*/ new WeakMap(), /**
   * The root document where the emptyDataState UI will be installed.
   *
   * @type {Document}
   */ _rootDocument = /*#__PURE__*/ new WeakMap(), /**
   * The references to the UI elements.
   *
   * @type {object}
   */ _refs = /*#__PURE__*/ new WeakMap(), /**
   * The placeholder element.
   *
   * @type {HTMLElement}
   */ _placeholderElement = /*#__PURE__*/ new WeakMap();
class EmptyDataStateUI {
    /**
   * Creates the emptyDataState UI elements and sets up the structure.
   */ install() {
        if (_class_private_field_get(this, _refs)?.emptyDataStateElement) {
            return;
        }
        const elements = (0, _templateLiteralTag.html)`${TEMPLATE}`;
        _class_private_field_set(this, _refs, elements.refs);
        const { emptyDataStateInner, emptyDataStateElement } = _class_private_field_get(this, _refs);
        (0, _element.setAttribute)(emptyDataStateInner, [
            (0, _a11y.A11Y_TABINDEX)(-1)
        ]);
        (0, _element.setAttribute)(emptyDataStateElement, [
            (0, _a11y.A11Y_TABINDEX)(-1)
        ]);
        _class_private_field_get(this, _rootElement).after(elements.fragment);
    }
    /**
   * Gets the emptyDataState element.
   *
   * @returns {HTMLElement} The empty data state element.
   */ getElement() {
        return _class_private_field_get(this, _refs)?.emptyDataStateElement;
    }
    /**
   * Gets the focusable elements of the emptyDataState element.
   *
   * @returns {HTMLElement[]} The focusable elements.
   */ getFocusableElements() {
        const { emptyDataStateButtons, emptyDataStateInner } = _class_private_field_get(this, _refs);
        const emptyDataStateButtonsElements = Array.from(emptyDataStateButtons?.children);
        if (emptyDataStateButtonsElements.length === 0) {
            return [
                emptyDataStateInner
            ];
        }
        return emptyDataStateButtonsElements;
    }
    /**
   * Shows the emptyDataState element.
   */ show() {
        if (!_class_private_field_get(this, _refs)?.emptyDataStateElement) {
            return;
        }
        _class_private_field_get(this, _refs).emptyDataStateElement.style.display = 'block';
    }
    /**
   * Hides the emptyDataState element.
   */ hide() {
        if (!_class_private_field_get(this, _refs)?.emptyDataStateElement) {
            return;
        }
        _class_private_field_get(this, _placeholderElement)?.remove();
        _class_private_field_set(this, _placeholderElement, null);
        _class_private_field_get(this, _refs).emptyDataStateElement.style.display = 'none';
    }
    /**
   * Updates the content of the emptyDataState element.
   *
   * @param {string | object} message - The message to update.
   * @param {boolean} isLoading - When `true`, shows a loading spinner.
   * @returns {void}
   */ updateContent(message, isLoading = false) {
        const { emptyDataStateElement, emptyDataStateInner } = _class_private_field_get(this, _refs);
        let content = '';
        if (typeof message === 'string') {
            content = {
                title: message
            };
        } else {
            content = {
                title: message?.title,
                description: message?.description,
                buttons: message?.buttons
            };
        }
        const template = (0, _templateLiteralTag.html)`${templateContent(content, isLoading)}`;
        if (isLoading) {
            (0, _element.addClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--loading`);
            (0, _element.setAttribute)(emptyDataStateInner, [
                (0, _a11y.A11Y_BUSY)()
            ]);
        } else {
            (0, _element.removeClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--loading`);
            (0, _element.removeAttribute)(emptyDataStateInner, (0, _a11y.A11Y_BUSY)()[0]);
        }
        _class_private_field_set(this, _refs, {
            ..._class_private_field_get(this, _refs),
            ...template.refs
        });
        emptyDataStateInner.innerHTML = '';
        emptyDataStateInner.appendChild(template.fragment);
        if (!isLoading && content.buttons?.length > 0) {
            Array.from(_class_private_field_get(this, _refs).emptyDataStateButtons.children).forEach((button, index)=>{
                button.addEventListener('click', content.buttons[index].callback);
            });
        }
    }
    /**
   * Updates the class names of the emptyDataState element.
   *
   * @param {View} view - The view instance.
   */ updateClassNames(view) {
        const { emptyDataStateElement } = _class_private_field_get(this, _refs);
        if (view.countRenderableColumns() > 0 && view.getColumnHeadersCount() > 0) {
            (0, _element.addClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--disable-top-border`);
        } else {
            (0, _element.removeClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--disable-top-border`);
        }
        if (view.countRenderableRows() > 0 && view.getRowHeadersCount() > 0) {
            (0, _element.addClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--disable-inline-border`);
        } else {
            (0, _element.removeClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--disable-inline-border`);
        }
        if (view.hasHorizontalScroll() && !view.isHorizontallyScrollableByWindow()) {
            (0, _element.addClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--disable-bottom-border`);
        } else {
            (0, _element.removeClass)(emptyDataStateElement, `${EMPTY_DATA_STATE_CLASS_NAME}--disable-bottom-border`);
        }
    }
    /**
   * Updates the size of the emptyDataState element.
   *
   * @param {View} view - The view instance.
   * @param {boolean} [isLoading] - When `true` and the grid has renderable columns, use the same
   *   workspace sizing as when renderable rows exist (e.g. DataProvider fetch while a page is still shown).
   */ updateSize(view, isLoading = false) {
        const { emptyDataStateElement } = _class_private_field_get(this, _refs);
        const scrollbarSize = view.hasHorizontalScroll() ? (0, _element.getScrollbarWidth)(view.hot.rootDocument) : 0;
        const rows = view.countRenderableRows();
        const cols = view.countRenderableColumns();
        const headerCols = view.getColumnHeadersCount();
        const extendLayoutForLoading = isLoading === true && cols > 0;
        const treatAsPopulatedRowsForSizing = rows > 0 || extendLayoutForLoading;
        emptyDataStateElement.style.top = cols > 0 ? `${view.getColumnHeaderHeight()}px` : '0px';
        emptyDataStateElement.style.insetInlineStart = '0px';
        const placeholderState = {
            element: _class_private_field_get(this, _placeholderElement)
        };
        syncEmptyDataStatePlaceholder(_class_private_field_get(this, _rootDocument), view, rows, EMPTY_DATA_STATE_CLASS_NAME, placeholderState);
        _class_private_field_set(this, _placeholderElement, placeholderState.element);
        const width = computeEmptyDataStateWidth(view, cols, treatAsPopulatedRowsForSizing);
        const height = computeEmptyDataStateHeight(view, cols, headerCols, scrollbarSize);
        emptyDataStateElement.style.width = `${width}px`;
        emptyDataStateElement.style.height = `${height}px`;
    }
    /**
   * Removes the emptyDataState UI elements from the DOM and clears the refs.
   */ destroy() {
        _class_private_field_get(this, _refs)?.emptyDataStateElement?.remove();
        _class_private_field_get(this, _placeholderElement)?.remove();
        _class_private_field_set(this, _placeholderElement, null);
        _class_private_field_set(this, _refs, null);
    }
    constructor({ rootElement, rootDocument }){
        _class_private_field_init(this, _rootElement, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _rootDocument, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _refs, {
            writable: true,
            value: void 0
        });
        _class_private_field_init(this, _placeholderElement, {
            writable: true,
            value: void 0
        });
        _class_private_field_set(this, _rootElement, rootElement);
        _class_private_field_set(this, _rootDocument, rootDocument);
        this.install();
    }
}
