/*!
 * KoliBri - The accessible HTML-Standard
 */
import { h } from "@stencil/core";
import { a11yHintLabelingLandmarks, devHint, validateCollapsible, validateHasCompactButton, validateHasIconsWhenExpanded, validateHideLabel, validateLabel, } from "../../schema";
import { KolButtonWcTag, KolLinkWcTag } from "../../core/component-names";
import { translate } from "../../i18n";
import clsx from "../../utils/clsx";
import { createRelatedUniqueId, createUniqueId } from "../../utils/dev.utils";
import { addNavLabel, removeNavLabel } from "../../utils/unique-nav-labels";
import { watchNavLinks } from "./validation";
const linkValidator = (link) => {
    if (typeof link === 'object' && typeof link._label === 'string') {
        if (Array.isArray(link._children)) {
            return linksValidator(link._children);
        }
        return false;
    }
    return true;
};
const linksValidator = (links) => {
    if (Array.isArray(links)) {
        return links.find(linkValidator) !== undefined;
    }
    return true;
};
const entryIsLink = (entryProps) => {
    return typeof entryProps._href === 'string';
};
const entryIsButton = (entryProps) => {
    var _a;
    return entryProps._href === undefined && typeof ((_a = entryProps._on) === null || _a === void 0 ? void 0 : _a.onClick) === 'function';
};
export class KolNav {
    constructor() {
        this.navId = createUniqueId('kol-nav');
        this.listId = createRelatedUniqueId(this.navId, 'list');
        this.handleToggleExpansionClick = (children) => {
            if (children) {
                if (this.state._expandedChildren.includes(children)) {
                    this.collapseChildren(children);
                }
                else {
                    this.expandChildren(children);
                }
            }
        };
        this.linkList = (props) => {
            return (h("ul", { class: clsx('kol-nav__list', {
                    'kol-nav__list--nested': props.deep > 0,
                    'kol-nav__list--vertical': props.deep !== 0,
                }), id: props.deep > 0 ? props.id : undefined }, props.links.map((link, index) => {
                return this.li(props.collapsible, props.deep, index, link, props.id);
            })));
        };
        this._collapsible = true;
        this._hasCompactButton = false;
        this._hasIconsWhenExpanded = false;
        this._hideLabel = false;
        this.state = {
            _collapsible: true,
            _hasCompactButton: false,
            _hasIconsWhenExpanded: false,
            _hideLabel: false,
            _label: '',
            _links: [],
            _expandedChildren: [],
        };
    }
    expandChildren(children) {
        this.state = Object.assign(Object.assign({}, this.state), { _expandedChildren: [...this.state._expandedChildren, children] });
    }
    collapseChildren(children) {
        this.state = Object.assign(Object.assign({}, this.state), { _expandedChildren: this.state._expandedChildren.filter((searchChildren) => searchChildren !== children) });
    }
    buildIconObject(collapsible, expanded, leftIcon) {
        const icon = {
            left: '',
            right: '',
        };
        if (this.state._hasIconsWhenExpanded && leftIcon) {
            icon.left = leftIcon;
        }
        if (this.state._hideLabel) {
            if (leftIcon) {
                icon.left = leftIcon;
            }
            else {
                icon.left = 'kolicon-link';
            }
        }
        if (collapsible) {
            if (expanded) {
                icon.right = 'kolicon-minus';
            }
            else {
                icon.right = 'kolicon-plus';
            }
        }
        return icon;
    }
    entry(collapsible, hasChildren, entry, expanded, ariaID) {
        var _a;
        const leftIcon = typeof entry._icons === 'string' ? entry._icons : typeof ((_a = entry._icons) === null || _a === void 0 ? void 0 : _a.left) === 'string' ? entry._icons.left : undefined;
        const icons = this.buildIconObject(collapsible && hasChildren, expanded, leftIcon);
        return (h("div", { class: "kol-nav__entry-wrapper" }, entryIsLink(entry) ? (h(KolLinkWcTag, Object.assign({ class: clsx('kol-nav__entry kol-nav__entry--link', {
                'kol-nav__entry--collapsible': collapsible,
            }) }, entry, { _hideLabel: this.state._hideLabel, _icons: icons, _ariaControls: collapsible && hasChildren && expanded ? ariaID : undefined, _ariaExpanded: collapsible && hasChildren ? expanded : undefined }))) : (h(KolButtonWcTag, { class: clsx('kol-nav__entry kol-nav__entry--button', {
                'kol-nav__entry--collapsible': collapsible,
            }), _label: entry._label, _hideLabel: this.state._hideLabel, _icons: icons, _ariaControls: collapsible && hasChildren && expanded ? ariaID : undefined, _ariaExpanded: collapsible && hasChildren ? expanded : undefined, _on: {
                onClick: (event, value) => {
                    if (entryIsButton(entry) && typeof entry._on.onClick === 'function') {
                        entry._on.onClick(event, value);
                    }
                    this.handleToggleExpansionClick(entry._children);
                },
            } }))));
    }
    li(collapsible, deep, index, link, ariaIDparent) {
        const active = !!link._active;
        const hasChildren = Array.isArray(link._children) && link._children.length > 0;
        const expanded = Boolean(link._children && this.state._expandedChildren.includes(link._children));
        const ariaID = createRelatedUniqueId(ariaIDparent, `${deep}-${index}`);
        return (h("li", { class: clsx('kol-nav__list-item', {
                'kol-nav__list-item--active': active,
                'kol-nav__list-item--expanded': expanded,
                'kol-nav__list-item--has-children': hasChildren,
            }), key: index }, this.entry(collapsible, hasChildren, link, expanded, ariaID), expanded && h(this.linkList, { collapsible: collapsible, deep: deep + 1, links: link._children || [], id: ariaID })));
    }
    initializeExpandedChildren() {
        this.state = Object.assign(Object.assign({}, this.state), { _expandedChildren: [] });
        const handleBranch = (branch) => {
            if (branch._active) {
                if (branch._children) {
                    this.expandChildren(branch._children);
                }
                return true;
            }
            else if (branch._children) {
                for (const childBranch of branch._children) {
                    if (handleBranch(childBranch)) {
                        this.expandChildren(branch._children);
                        return true;
                    }
                }
            }
            return false;
        };
        this.state._links.forEach(handleBranch);
    }
    render() {
        const collapsible = this.state._collapsible === true;
        return (h("div", { key: '168e77bd4e310d31ec72afcc5dc4633df3a5852c', class: clsx('kol-nav', {
                'kol-nav--is-compact': this.state._hideLabel,
            }) }, h("nav", { key: 'd27ea32253853f5ab13df4cceec8245a69564179', "aria-label": this.state._label, class: "kol-nav__navigation", id: this.navId }, h(this.linkList, { key: '43080dfc66978e4161adb904094f8b7a4585798c', collapsible: collapsible, deep: 0, links: this.state._links, id: this.listId })), this.state._hasCompactButton && (h("div", { key: '917c25c8c29c3f980dd95c19cac2b3857c9f06fd', class: "kol-nav__compact" }, h(KolButtonWcTag, { key: 'c08ed259ed0721edaa769a44e7b9b96c50091f30', class: "kol-nav__toggle-button", _ariaControls: this.navId, _ariaExpanded: !this.state._hideLabel, _icons: this.state._hideLabel ? 'kolicon-chevron-right' : 'kolicon-chevron-left', _hideLabel: true, _label: translate(this.state._hideLabel ? 'kol-nav-maximize' : 'kol-nav-minimize'), _on: {
                onClick: () => {
                    this.state = Object.assign(Object.assign({}, this.state), { _hideLabel: !this.state._hideLabel });
                },
            }, _tooltipAlign: "right" })))));
    }
    validateCollapsible(value) {
        validateCollapsible(this, value);
    }
    validateHasCompactButton(value) {
        validateHasCompactButton(this, value);
    }
    validateHasIconsWhenExpanded(value) {
        validateHasIconsWhenExpanded(this, value);
    }
    validateHideLabel(value) {
        validateHideLabel(this, value);
    }
    validateLabel(value, _oldValue, initial = false) {
        if (!initial) {
            removeNavLabel(this.state._label);
        }
        validateLabel(this, value, {
            required: true,
        });
        a11yHintLabelingLandmarks(value);
        addNavLabel(this.state._label);
    }
    validateLinks(value) {
        watchNavLinks('KolNav', this, value);
        devHint(`[KolNav] The navigation structure is not yet validated recursively.`);
        this.initializeExpandedChildren();
    }
    componentWillLoad() {
        this.validateCollapsible(this._collapsible);
        this.validateHideLabel(this._hideLabel);
        this.validateHasCompactButton(this._hasCompactButton);
        this.validateHasIconsWhenExpanded(this._hasIconsWhenExpanded);
        this.validateLabel(this._label, undefined, true);
        this.validateLinks(this._links);
        this.initializeExpandedChildren();
    }
    disconnectedCallback() {
        removeNavLabel(this.state._label);
    }
    static get is() { return "kol-nav"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "default": ["./style.scss"]
        };
    }
    static get styleUrls() {
        return {
            "default": ["style.css"]
        };
    }
    static get properties() {
        return {
            "_collapsible": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "TODO",
                            "text": ": Change type back to `CollapsiblePropType` after Stencil#4663 has been resolved."
                        }],
                    "text": "Defines if navigation nodes can be collapsed or not. Enabled by default."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "_collapsible",
                "defaultValue": "true"
            },
            "_hasCompactButton": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Creates a button below the navigation, that toggles _collapsible."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "_has-compact-button",
                "defaultValue": "false"
            },
            "_hasIconsWhenExpanded": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Shows icons next to the navigation item labels, even when the navigation is not collapsed."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "_has-icons-when-expanded",
                "defaultValue": "false"
            },
            "_hideLabel": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean | undefined",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [{
                            "name": "TODO",
                            "text": ": Change type back to `HideLabelPropType` after Stencil#4663 has been resolved."
                        }],
                    "text": "Hides the caption by default and displays the caption text with a tooltip when the\ninteractive element is focused or the mouse is over it."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "_hide-label",
                "defaultValue": "false"
            },
            "_label": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "LabelPropType",
                    "resolved": "string",
                    "references": {
                        "LabelPropType": {
                            "location": "import",
                            "path": "../../schema",
                            "id": "src/schema/index.ts::LabelPropType"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Defines the visible or semantic label of the component (e.g. aria-label, label, headline, caption, summary, etc.)."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "_label"
            },
            "_links": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "Stringified<ButtonOrLinkOrTextWithChildrenProps[]>",
                    "resolved": "ButtonOrLinkOrTextWithChildrenProps[] | string",
                    "references": {
                        "Stringified": {
                            "location": "import",
                            "path": "../../schema",
                            "id": "src/schema/index.ts::Stringified"
                        },
                        "ButtonOrLinkOrTextWithChildrenProps": {
                            "location": "import",
                            "path": "../../schema",
                            "id": "src/schema/index.ts::ButtonOrLinkOrTextWithChildrenProps"
                        }
                    }
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Defines the list of links, buttons or texts to render."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "_links"
            }
        };
    }
    static get states() {
        return {
            "state": {}
        };
    }
    static get watchers() {
        return [{
                "propName": "_collapsible",
                "methodName": "validateCollapsible"
            }, {
                "propName": "_hasCompactButton",
                "methodName": "validateHasCompactButton"
            }, {
                "propName": "_hasIconsWhenExpanded",
                "methodName": "validateHasIconsWhenExpanded"
            }, {
                "propName": "_hideLabel",
                "methodName": "validateHideLabel"
            }, {
                "propName": "_label",
                "methodName": "validateLabel"
            }, {
                "propName": "_links",
                "methodName": "validateLinks"
            }];
    }
}
//# sourceMappingURL=shadow.js.map
