import { h, Host, } from "@stencil/core";
import LeftArrow from "./assets/left-arrow.svg";
import RightArrow from "./assets/right-arrow.svg";
import { getSlotElements } from "../../utils/helpers";
import { checkResizeObserver, elementOverflowsX } from "../../utils/helpers";
import { IcBrandForegroundEnum, } from "../../utils/types";
const SCROLL_DELAY_MS = 200;
export class HorizontalScroll {
    constructor() {
        this.buttonStateSet = false;
        this.firstItemVisible = true;
        this.itemOverflow = false;
        this.lastItemVisible = false;
        /**
         * The appearance of the horizontal scroll, e.g. dark, light or the default.
         */
        this.appearance = "default";
        /** @internal Determines whether black variant of the tabs should be displayed. */
        this.monochrome = false;
        /**
         * @internal  Sets the theme color to the dark or light theme color. "inherit" will set the color based on the system settings or ic-theme component.
         */
        this.theme = "inherit";
        /**
         * @internal The name of the event that triggers focus handler logic.
         */
        this.focusTrigger = "focus";
        this.focusHandler = (event) => {
            this.itemFocusHandler(Array.from(this.items).indexOf(event.target));
        };
        this.resizeObserverCallback = () => {
            if (this.el.clientWidth >= this.itemsContainerEl.scrollWidth) {
                this.itemOverflow = false;
            }
            else {
                this.itemOverflow = elementOverflowsX(this.itemsContainerEl);
            }
            if (this.itemOverflow) {
                this.lastItemVisible =
                    this.itemsContainerEl.offsetWidth + this.itemsContainerEl.scrollLeft >=
                        this.itemsContainerEl.scrollWidth;
            }
        };
        this.runResizeObserver = () => {
            this.resizeObserver = new ResizeObserver(() => {
                this.resizeObserverCallback();
            });
            this.resizeObserver.observe(this.itemsContainerEl);
        };
        this.scrollLeft = () => {
            this.scrollItemIntoView(this.getCurrentLeftItem() - 1);
        };
        this.scrollRight = () => {
            this.scrollItemIntoView(this.getCurrentLeftItem() + 1);
        };
        this.longScrollRight = () => {
            this.scrollRight();
            this.scrollDelay = window.setTimeout(this.longScrollRight, SCROLL_DELAY_MS);
        };
        this.longScrollLeft = () => {
            this.scrollLeft();
            this.scrollDelay = window.setTimeout(this.longScrollLeft, SCROLL_DELAY_MS);
        };
        this.leftArrowMouseDownHandler = (e) => {
            e.preventDefault();
            this.scrollDelay = window.setTimeout(this.longScrollLeft, SCROLL_DELAY_MS);
        };
        this.rightArrowMouseDownHandler = (e) => {
            e.preventDefault();
            this.scrollDelay = window.setTimeout(this.longScrollRight, SCROLL_DELAY_MS);
        };
        this.arrowMouseUpHandler = () => {
            window.clearTimeout(this.scrollDelay);
        };
        this.getCurrentLeftItem = () => {
            const index = this.itemOffsets.findIndex((el) => el > Math.round(this.itemsContainerEl.scrollLeft));
            return index < 0 ? 0 : index;
        };
        this.scrollHandler = () => {
            window.clearTimeout(this.isScrolling);
            // Set a timeout to run after scrolling ends
            this.isScrolling = window.setTimeout(this.scrollStopped, 50);
        };
        this.scrollStopped = () => {
            // If scrollItemIntoView has been called, the button states will already be set
            // Can't just handle it here as it causes strange jumping behaviour in positioning
            const scrollLeft = Math.round(this.itemsContainerEl.scrollLeft);
            if (this.buttonStateSet === false) {
                this.firstItemVisible = scrollLeft === 0;
                this.lastItemVisible =
                    this.itemsContainerEl.offsetWidth + scrollLeft >=
                        this.itemsContainerEl.scrollWidth;
            }
            this.buttonStateSet = false;
        };
    }
    componentWillLoad() {
        this.itemsContainerEl = this.el.children[0];
        this.itemsContainerEl.addEventListener("scroll", this.scrollHandler);
        this.items = getSlotElements(this.itemsContainerEl);
        this.items.forEach((item) => {
            if (item.addEventListener) {
                item.addEventListener(this.focusTrigger, this.focusHandler);
            }
        });
    }
    componentDidLoad() {
        var _a;
        let runningTotal = 0;
        this.itemOffsets = this.items.map((item) => {
            runningTotal += item.offsetWidth;
            return runningTotal;
        });
        checkResizeObserver(this.runResizeObserver);
        // Add event listener to scroll containers as mouse events are not fired on disabled elements (ic-button's <button>)
        // 'mouseleave' needed in case the user moves their mouse while holding the arrow buttons
        // - 'mouseup' otherwise not detected and scrolling not stopped
        const scrollArrows = Array.from(((_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll("div")) || []);
        ["mouseup", "mouseleave"].forEach((event) => {
            scrollArrows.forEach((arrow) => arrow.addEventListener(event, this.arrowMouseUpHandler));
        });
    }
    disconnectedCallback() {
        var _a, _b, _c;
        if (this.resizeObserver !== undefined) {
            this.resizeObserver.disconnect();
        }
        const scrollArrows = Array.from(((_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll("div")) || []);
        ["mouseup", "mouseleave"].forEach((event) => {
            scrollArrows.forEach((arrow) => arrow.removeEventListener(event, this.arrowMouseUpHandler));
        });
        (_b = this.items) === null || _b === void 0 ? void 0 : _b.forEach((item) => {
            if (item.removeEventListener) {
                item.removeEventListener(this.focusTrigger, this.focusHandler);
            }
        });
        (_c = this.itemsContainerEl) === null || _c === void 0 ? void 0 : _c.removeEventListener("scroll", this.scrollHandler);
    }
    /**
     * @internal if side scrolling enabled, scrolls the specified item into view.
     */
    async scrollItemIntoView(itemPosition) {
        this.firstItemVisible = itemPosition <= 0;
        const newScrollPos = itemPosition <= 0 ? 0 : this.itemOffsets[itemPosition - 1];
        this.lastItemVisible =
            this.itemsContainerEl.offsetWidth + newScrollPos >=
                this.itemsContainerEl.scrollWidth;
        this.buttonStateSet = true;
        this.itemsContainerEl.scrollLeft = newScrollPos;
    }
    itemFocusHandler(itemPosition) {
        if (this.itemOverflow) {
            this.scrollItemIntoView(itemPosition);
        }
    }
    render() {
        const { firstItemVisible, lastItemVisible, itemOverflow } = this;
        return (h(Host, { key: '329d00bc4e7ebfab434cb41dd32e919820c5adb5', class: {
                ["ic-horizontal-scroll-visible"]: itemOverflow,
                ["ic-horizontal-scroll-dark"]: this.appearance === IcBrandForegroundEnum.Dark,
                ["ic-horizontal-scroll-light"]: this.appearance === IcBrandForegroundEnum.Light,
                [`ic-theme-${this.theme}`]: this.theme !== "inherit",
            } }, h("div", { key: 'ed231bf1fcd68399e29e790026b377bf8f96a14e', "aria-hidden": "true", class: {
                ["scroll-container-left"]: true,
                ["hidden"]: !itemOverflow,
                ["disabled"]: firstItemVisible,
            }, role: "tab" }, h("ic-button", { key: 'c34f45cb44e242939985f792a21e482a11078fba', class: "scroll-arrow", variant: "icon-tertiary", "aria-label": "Scroll left", theme: this.theme === "light" || this.theme === "inherit"
                ? "dark"
                : "light", monochrome: this.monochrome, innerHTML: LeftArrow, disabled: firstItemVisible, tabindex: "-1", onClick: this.scrollLeft, onMouseDown: this.leftArrowMouseDownHandler }), h("span", { key: 'c5b52e4cfa655f8dc499e69da531870f4e4fe216', class: "scroll-splitter-left" })), h("slot", { key: '8478dc63668ed2e842182c47e9a3b27b77ac642f' }), h("div", { key: 'b9b0e21e69a40f7afda403db3db8b983257240c0', "aria-hidden": "true", class: {
                ["scroll-container-right"]: true,
                ["hidden"]: !itemOverflow,
                ["disabled"]: lastItemVisible,
            }, role: "tab" }, h("span", { key: '909936dddf54502bb1bdc3fdfdf36d59b5582238', class: "scroll-splitter-right" }), h("ic-button", { key: '4e9093a9da1b3e387933dfc2495f1279bb7ad180', class: "scroll-arrow", variant: "icon-tertiary", "aria-label": "Scroll right", theme: this.theme === "light" || this.theme === "inherit"
                ? "dark"
                : "light", monochrome: this.monochrome, innerHTML: RightArrow, disabled: lastItemVisible, tabindex: "-1", onClick: this.scrollRight, onMouseDown: this.rightArrowMouseDownHandler }))));
    }
    static get is() { return "ic-horizontal-scroll"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["./ic-horizontal-scroll.css"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["ic-horizontal-scroll.css"]
        };
    }
    static get properties() {
        return {
            "appearance": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "IcBrandForeground",
                    "resolved": "\"dark\" | \"default\" | \"light\" | undefined",
                    "references": {
                        "IcBrandForeground": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcBrandForeground"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The appearance of the horizontal scroll, e.g. dark, light or the default."
                },
                "getter": false,
                "setter": false,
                "attribute": "appearance",
                "reflect": false,
                "defaultValue": "\"default\""
            },
            "monochrome": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Determines whether black variant of the tabs should be displayed."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "monochrome",
                "reflect": false,
                "defaultValue": "false"
            },
            "theme": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "IcThemeMode",
                    "resolved": "\"dark\" | \"inherit\" | \"light\" | undefined",
                    "references": {
                        "IcThemeMode": {
                            "location": "import",
                            "path": "../../utils/types",
                            "id": "src/utils/types.ts::IcThemeMode"
                        }
                    }
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "Sets the theme color to the dark or light theme color. \"inherit\" will set the color based on the system settings or ic-theme component."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "theme",
                "reflect": false,
                "defaultValue": "\"inherit\""
            },
            "focusTrigger": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "internal",
                            "text": "The name of the event that triggers focus handler logic."
                        }],
                    "text": ""
                },
                "getter": false,
                "setter": false,
                "attribute": "focus-trigger",
                "reflect": false,
                "defaultValue": "\"focus\""
            }
        };
    }
    static get states() {
        return {
            "firstItemVisible": {},
            "itemOverflow": {},
            "lastItemVisible": {}
        };
    }
    static get methods() {
        return {
            "scrollItemIntoView": {
                "complexType": {
                    "signature": "(itemPosition: number) => Promise<void>",
                    "parameters": [{
                            "name": "itemPosition",
                            "type": "number",
                            "docs": ""
                        }],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "",
                    "tags": [{
                            "name": "internal",
                            "text": "if side scrolling enabled, scrolls the specified item into view."
                        }]
                }
            }
        };
    }
    static get elementRef() { return "el"; }
}
//# sourceMappingURL=ic-horizontal-scroll.js.map
