import { proxyCustomElement, HTMLElement, createEvent, writeTask, h, Host } from '@stencil/core/internal/client';
import { _ as __decorate, a as __metadata } from './tslib.es6.js';
import { B as BEM } from './bem.js';
import { F as FOCUS_KEYS } from './focus-visible.js';
import { d as defaultBalAriaForm } from './form.js';
import { s as stopEventBubbling } from './form-input.js';
import { r as raf } from './helpers.js';
import { L as Logger } from './log.js';
import { a as isSpaceKey, i as isEnterKey, c as isArrowUpKey, g as isArrowLeftKey, b as isArrowDownKey, h as isArrowRightKey, j as isHomeKey, k as isEndKey } from './keyboard.helpers.js';
import { L as ListenToFocus } from './focus.decorator.js';
import { L as ListenToAnimation } from './animation.decorator.js';
import { L as ListenToVisibility } from './visibility.decorator.js';
import { L as ListenToBreakpoints } from './breakpoints.decorator.js';
import { L as ListenToWindowResize } from './window-resize.decorator.js';

const balSegmentCss = ":root{--bal-segment-background:var(--bal-color-grey-2);--bal-segment-background-invalid:var(--bal-color-danger-1);--bal-segment-item-focus-border:var(--bal-color-border-primary);--bal-segment-item-text-color:var(--bal-body-color);--bal-segment-item-text-color-checked:var(--bal-body-color);--bal-segment-item-text-color-checked-hovered:var(--bal-color-text-primary-hovered);--bal-segment-item-text-color-checked-pressed:var(--bal-color-text-primary-pressed);--bal-segment-item-text-color-invalid:var(--bal-color-text-danger);--bal-segment-item-text-color-invalid-hovered:var(--bal-color-text-danger-hovered);--bal-segment-item-text-color-invalid-pressed:var(--bal-color-text-danger-pressed);--bal-segment-item-text-color-disabled:var(--bal-color-text-grey);--bal-segment-item-text-color-disabled-checked:var(--bal-color-text-grey-dark);--bal-segment-item-divider-background:var(--bal-color-grey);--bal-segment-item-divider-background-invalid:var(--bal-color-danger-2);--bal-segment-item-indicator-background:var(--bal-color-purple-2);--bal-segment-item-indicator-background-invalid:var(--bal-color-danger-4);--bal-segment-item-indicator-background-disabled:var(--bal-color-grey-3)}.bal-segment{display:-ms-flexbox;display:flex;background:var(--bal-segment-background);border-radius:var(--bal-radius-normal);gap:.125rem;gap:.125rem;padding:.25rem;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.bal-segment--invalid{background:var(--bal-segment-background-invalid)}.bal-segment--vertical{-ms-flex-direction:column;flex-direction:column;width:100%}.bal-segment--vertical .bal-segment-item__button{width:100%;-ms-flex:1;flex:1}.bal-segment--vertical.bal-segment--scrollable{overflow:auto;max-height:240px}.bal-segment--expanded{width:100%;min-width:100%;-ms-flex-pack:start;justify-content:flex-start;-ms-flex-align:center;align-items:center}.bal-segment--expanded .bal-segment-item,.bal-segment--expanded .bal-segment-item>button{-ms-flex:1;flex:1;width:100%}.bal-segment--expanded .bal-segment-item .bal-content,.bal-segment--expanded .bal-segment-item>button .bal-content{-ms-flex-pack:center;justify-content:center;-ms-flex-align:center;align-items:center}";

const Segment = /*@__PURE__*/ proxyCustomElement(class Segment extends HTMLElement {
    constructor(registerHost) {
        super();
        if (registerHost !== false) {
            this.__registerHost();
        }
        this.balFocus = createEvent(this, "balFocus", 7);
        this.balBlur = createEvent(this, "balBlur", 7);
        this.balChange = createEvent(this, "balChange", 7);
        this.balSelect = createEvent(this, "balSelect", 7);
        this.balVertical = createEvent(this, "balVertical", 7);
        this.keyboardMode = true;
        this.isVertical = false;
        this.isMobile = false;
        this.maxWidth = 0;
        this.ariaForm = defaultBalAriaForm;
        /**
         * PUBLIC PROPERTY API
         * ------------------------------------------------------
         */
        /**
         * If `true`, the segment is shown red.
         */
        this.invalid = false;
        /**
         * If `true`, in Angular reactive forms the control will not be set invalid
         */
        this.autoInvalidOff = false;
        /**
         * If `true`, the user cannot interact with the segment.
         */
        this.disabled = false;
        /**
         * If `true`, the segment items are presented vertical as a list.
         */
        this.vertical = false;
        /**
         * If `true`, and is vertical then the list height is limited and scrollable.
         */
        this.scrollable = false;
        /**
         * If `true`, the element uses the whole width
         */
        this.expanded = false;
        /**
         * LISTENERS
         * ------------------------------------------------------
         */
        this.hasFocus = false;
        this.getSegmentItem = (selector) => {
            var _a, _b;
            const items = this.allItems.filter(item => !item.disabled);
            const currIndex = items.findIndex(item => item === document.activeElement.closest('bal-segment-item'));
            switch (selector) {
                case 'current':
                    return items[currIndex];
                case 'first':
                    return items[0];
                case 'last':
                    return items[items.length - 1];
                case 'next':
                    return (_a = items[currIndex + 1]) !== null && _a !== void 0 ? _a : items[0];
                case 'previous':
                    return (_b = items[currIndex - 1]) !== null && _b !== void 0 ? _b : items[items.length - 1];
                default:
                    return null;
            }
        };
        /**
         * PRIVATE EVENT HANDLERS
         * ------------------------------------------------------
         */
        this.onPointerDown = () => {
            this.keyboardMode = false;
        };
        this.onSlottedItemsChange = () => {
            /**
             * When the slotted segment buttons change we need to
             * ensure that the new segment buttons are checked if
             * the value matches the segment button value.
             */
            this.valueChanged(this.value);
            this.defineWidth();
        };
        this.onClick = (ev) => {
            if (this.disabled) {
                return;
            }
            const current = ev.target;
            const previous = this.checked;
            // If the current element is a segment then that means
            // the user tried to swipe to a segment button and
            // click a segment button at the same time so we should
            // not update the checked segment button
            if (current.tagName === 'BAL-SEGMENT') {
                return;
            }
            if (current && current.setFocus) {
                current.setFocus();
            }
            if (previous) {
                this.checkButton(previous, current);
            }
            else {
                this.setCheckedClasses();
                this.checkButton(current, current);
            }
            if (current !== previous) {
                this.emitValueChange();
            }
        };
    }
    createLogger(log) {
        this.log = log;
    }
    invalidChanged() {
        this.allItems.map(item => (item.invalid = this.invalid));
    }
    disabledChanged() {
        this.allItems.map(item => (item.disabled = this.disabled));
    }
    valueChanged(value) {
        /**
         * `balSelect` is emitted every time the value changes (internal or external changes).
         * Used by `bal-segment-item` to determine if the button should be checked.
         */
        this.balSelect.emit(value);
        this.setCheckedClasses();
    }
    /**
     * LIFECYCLE
     * ------------------------------------------------------
     */
    connectedCallback() {
        this.el.addEventListener('touchstart', this.onPointerDown);
        this.el.addEventListener('mousedown', this.onPointerDown);
        this.disabledChanged();
        this.isVertical = this.vertical;
    }
    disconnectedCallback() {
        this.el.removeEventListener('touchstart', this.onPointerDown);
        this.el.removeEventListener('mousedown', this.onPointerDown);
    }
    async componentDidLoad() {
        this.setCheckedClasses();
        this.defineWidth();
    }
    focusInListener(ev) {
        this.balFocus.emit(ev);
    }
    focusOutListener(ev) {
        this.balBlur.emit(ev);
    }
    animationListener() {
        const childRect = this.el.getBoundingClientRect();
        this.maxWidth = childRect.width;
        this.windowResizeListener();
    }
    visibilityListener() {
        const childRect = this.el.getBoundingClientRect();
        this.maxWidth = childRect.width;
        this.windowResizeListener();
    }
    breakpointListener(breakpoints) {
        this.isMobile = breakpoints.mobile;
    }
    windowResizeListener() {
        if (this.vertical === false && this.maxWidth > 0) {
            const parent = this.el.parentElement.getBoundingClientRect();
            if (parent.width < this.maxWidth) {
                //
                // element in horizontal is to big
                this.emitVerticalChange(true);
            }
            else {
                //
                // element has enough space in parent element
                this.emitVerticalChange(false);
            }
        }
        else {
            this.emitVerticalChange(true);
        }
    }
    listenOnKeyDownOutside() {
        this.keyboardMode = true;
    }
    listenOnKeyDown(ev) {
        this.keyboardMode = FOCUS_KEYS.includes(ev.key);
        let forceChange = false;
        let current;
        if (isSpaceKey(ev) || isEnterKey(ev)) {
            stopEventBubbling(ev);
            current = this.getSegmentItem('current');
            forceChange = this.value !== current.value;
            this.value = current.value;
        }
        else if (isArrowUpKey(ev) || isArrowLeftKey(ev)) {
            stopEventBubbling(ev);
            current = this.getSegmentItem('previous');
        }
        else if (isArrowDownKey(ev) || isArrowRightKey(ev)) {
            stopEventBubbling(ev);
            current = this.getSegmentItem('next');
        }
        else if (isHomeKey(ev)) {
            stopEventBubbling(ev);
            current = this.getSegmentItem('first');
        }
        else if (isEndKey(ev)) {
            stopEventBubbling(ev);
            current = this.getSegmentItem('last');
        }
        if (!current) {
            return;
        }
        const previous = this.checked;
        if (current !== previous || forceChange) {
            this.checkButton(previous, current);
            this.emitValueChange();
        }
        if (current) {
            current.setFocus();
        }
    }
    /**
     * PUBLIC METHODS
     * ------------------------------------------------------
     */
    /**
     * @internal
     */
    async setAriaForm(ariaForm) {
        this.ariaForm = Object.assign({}, ariaForm);
    }
    /**
     * GETTERS
     * ------------------------------------------------------
     */
    get allItems() {
        return Array.from(this.el.querySelectorAll('bal-segment-item'));
    }
    get checked() {
        return this.allItems.find(item => item.value === this.value);
    }
    /**
     * PRIVATE METHODS
     * ------------------------------------------------------
     */
    emitValueChange() {
        this.balChange.emit(this.value);
    }
    emitVerticalChange(isVertical) {
        if (this.isVertical !== isVertical) {
            this.isVertical = isVertical;
            this.balVertical.emit(this.isVertical);
        }
    }
    defineWidth() {
        raf(() => {
            if (this.isVertical === false) {
                const childRect = this.el.getBoundingClientRect();
                this.maxWidth = childRect.width;
            }
            this.windowResizeListener();
        });
    }
    getIndicator(item) {
        if (item) {
            const root = item.shadowRoot || item;
            return root.querySelector('.bal-segment-item__indicator');
        }
        return null;
    }
    checkButton(previous, current) {
        const previousIndicator = this.getIndicator(previous);
        const currentIndicator = this.getIndicator(current);
        if (previousIndicator === null || currentIndicator === null) {
            return;
        }
        const previousClientRect = previousIndicator.getBoundingClientRect();
        const currentClientRect = currentIndicator.getBoundingClientRect();
        const widthDelta = previousClientRect.width / currentClientRect.width;
        const xPosition = previousClientRect.left - currentClientRect.left;
        // Scale the indicator width to match the previous indicator width
        // and translate it on top of the previous indicator
        let transform = `translate3d(${xPosition}px, 0, 0) scaleX(${widthDelta})`;
        if (this.isVertical) {
            const heightDelta = previousClientRect.height / currentClientRect.height;
            const yPosition = previousClientRect.top - currentClientRect.top;
            // Scale the indicator width to match the previous indicator width
            // and translate it on top of the previous indicator
            transform = `translate3d(0, ${yPosition}px, 0) scaleY(${heightDelta})`;
        }
        writeTask(() => {
            // Remove the transition before positioning on top of the previous indicator
            currentIndicator.classList.remove('bal-segment-item__indicator--animated');
            currentIndicator.style.setProperty('transform', transform);
            // Force a repaint to ensure the transform happens
            currentIndicator.getBoundingClientRect();
            // Add the transition to move the indicator into place
            currentIndicator.classList.add('bal-segment-item__indicator--animated');
            // Remove the transform to slide the indicator back to the button clicked
            currentIndicator.style.setProperty('transform', '');
        });
        this.value = current.value;
        this.setCheckedClasses();
    }
    setCheckedClasses() {
        const items = this.allItems;
        const index = items.findIndex(item => item.value === this.value);
        const next = index + 1;
        const previous = index - 1;
        for (const item of items) {
            item.classList.remove('bal-segment-item--after-checked');
            item.classList.remove('bal-segment-item--before-checked');
        }
        if (next < items.length) {
            items[next].classList.add('bal-segment-item--after-checked');
        }
        if (previous < items.length && previous >= 0) {
            items[previous].classList.add('bal-segment-item--before-checked');
        }
    }
    /**
     * RENDER
     * ------------------------------------------------------
     */
    render() {
        const { invalid, isVertical, scrollable, keyboardMode, expanded, isMobile, disabled } = this;
        const block = BEM.block('segment');
        return (h(Host, { key: '08fb99b658d704d85ab181d55d7bdbce7ee40fd8', role: "radiogroup", id: this.ariaForm.controlId, "aria-labelledby": this.ariaForm.labelId, "aria-describedby": this.ariaForm.messageId, class: Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, block.class()), block.modifier('invalid').class(invalid)), block.modifier('vertical').class(isVertical)), block.modifier('scrollable').class(scrollable)), block.modifier('keyboard').class(keyboardMode)), block.modifier('disabled').class(disabled)), block.modifier('expanded').class((expanded || isMobile) && !isVertical)), onClick: this.onClick }, h("slot", { key: '432741fe51dc5c83ea241506687de13469afc149', onSlotchange: this.onSlottedItemsChange })));
    }
    get el() { return this; }
    static get watchers() { return {
        "invalid": ["invalidChanged"],
        "disabled": ["disabledChanged"],
        "value": ["valueChanged"]
    }; }
    static get style() { return balSegmentCss; }
}, [260, "bal-segment", {
        "invalid": [4],
        "autoInvalidOff": [516, "auto-invalid-off"],
        "disabled": [4],
        "vertical": [4],
        "scrollable": [4],
        "expanded": [4],
        "value": [1032],
        "focusedValue": [32],
        "keyboardMode": [32],
        "isVertical": [32],
        "isMobile": [32],
        "maxWidth": [32],
        "ariaForm": [32],
        "setAriaForm": [64]
    }, [[4, "keydown", "listenOnKeyDownOutside"], [0, "keydown", "listenOnKeyDown"]], {
        "invalid": ["invalidChanged"],
        "disabled": ["disabledChanged"],
        "value": ["valueChanged"]
    }]);
__decorate([
    Logger('bal-segment'),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Function]),
    __metadata("design:returntype", void 0)
], Segment.prototype, "createLogger", null);
__decorate([
    ListenToFocus(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], Segment.prototype, "focusInListener", null);
__decorate([
    ListenToFocus(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], Segment.prototype, "focusOutListener", null);
__decorate([
    ListenToAnimation(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], Segment.prototype, "animationListener", null);
__decorate([
    ListenToVisibility(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], Segment.prototype, "visibilityListener", null);
__decorate([
    ListenToBreakpoints(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], Segment.prototype, "breakpointListener", null);
__decorate([
    ListenToWindowResize(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], Segment.prototype, "windowResizeListener", null);
function defineCustomElement$1() {
    if (typeof customElements === "undefined") {
        return;
    }
    const components = ["bal-segment"];
    components.forEach(tagName => { switch (tagName) {
        case "bal-segment":
            if (!customElements.get(tagName)) {
                customElements.define(tagName, Segment);
            }
            break;
    } });
}

const BalSegment = Segment;
const defineCustomElement = defineCustomElement$1;

export { BalSegment, defineCustomElement };
