/*!
 * Custom elements for Nanopore-Digital Web applications
 */
import { Build, Host, } from "@stencil/core";
import { h } from "../../utils/renderer";
import { getSvgContent, iconContent } from "./request";
import { getName, getUrl } from "./utils";
/**
 * An SVG loader / helper. Comes bundled with font-awesome pro icons & ONT pictogram and device icons.
 * Lazily loads SVG as icons become visible.
 *
 * @status stable
 * @version 1.0.0
 */
export class Icon {
    io;
    el;
    svgContent;
    isVisible = false;
    isLoading = true;
    /**
     * Specifies the color of the icon. If not specified, the icon will inherit the color of the parent element.
     */
    color;
    /**
     * Specifies the role to use for accessibility. Defaults to 'presentation' (invisible to screen-readers)
     */
    role;
    setAriaLabel() {
        if (!this.ariaLabel && !this.el.ariaLabel) {
            if (!this.role || this.role !== 'presentation') {
                // if the role is not 'presentation' and the user did not explicitly set a role,
                // let's try and derive one from the icon name
                const label = getName(this.name, this.icon);
                // user did not provide a label
                // come up with the label based on the icon name
                if (label) {
                    this.ariaLabel = label.split('/').slice(-1)[0].replace(/-/g, ' ');
                }
            }
        }
        else if (this.role === 'presentation') {
            this.ariaLabel = undefined;
        }
    }
    /**
     * Specifies the label to use for accessibility. Defaults to the icon name.
     */
    ariaLabel;
    updateRole() {
        // force the role to be 'img' if the aria-label is explicitly set
        if (this.ariaLabel)
            this.role = 'img';
        else if (!this.ariaLabel)
            this.role = 'presentation';
    }
    /**
     * Specifies whether the icon should horizontally flip when `dir` is `"rtl"`.
     * By default, when an 'arrow' or 'chevron' icon is used, it will flip automatically when detecting `dir="rtl"` on the document or closest ancestor.
     */
    flipRtl;
    /**
     * Specifies which icon to use from the built-in set of icons.
     */
    name;
    /**
     * Specifies the exact `src` of an SVG file to use.
     */
    src;
    /**
     * A combination of both `name` and `src`. If a `src` url is detected
     * it will set the `src` property. Otherwise it assumes it's a built-in named
     * SVG and set the `name` property.
     */
    icon;
    /**
     * The size of the icon. `auto` automatically sizes according to the font-size of the parent element.
     * *Note*: size will be different on 'pictogram' and 'device' vs 'font awesome' icons.
     */
    size = 'auto';
    /**
     * If enabled, nano-icon will be loaded lazily when it's visible in the viewport.
     * Default, `true`.
     */
    lazy = true;
    loadIcon() {
        if (Build.isBrowser && this.isVisible) {
            const url = getUrl(this);
            if (url) {
                if (iconContent.has(url)) {
                    // sync if it's already loaded
                    this.svgContent = iconContent.get(url);
                    requestAnimationFrame(() => {
                        this.isLoading = false;
                        this.nanoLoad.emit();
                    });
                }
                else {
                    // async if it hasn't been loaded
                    getSvgContent(url).then(() => {
                        this.svgContent = iconContent.get(url);
                        requestAnimationFrame(() => {
                            this.isLoading = false;
                            this.nanoLoad.emit();
                        });
                        this.setAriaLabel();
                    }, () => {
                        // error loading icon
                        this.nanoError.emit();
                    });
                }
            }
        }
    }
    /** Emitted when the icon has finished loading. */
    nanoLoad;
    /** Emitted when the icon fails to load. */
    nanoError;
    waitUntilVisible(el, rootMargin, cb) {
        if (Build.isBrowser &&
            this.lazy &&
            typeof window !== 'undefined' &&
            window.IntersectionObserver) {
            const io = (this.io = new window.IntersectionObserver((data) => {
                if (data[0].isIntersecting || (data[1] && data[1].isIntersecting)) {
                    io.disconnect();
                    this.io = undefined;
                    cb();
                }
            }, { rootMargin }));
            io.observe(el);
        }
        else {
            // not a browser env (e.g. node)
            // or we're not loading lazily
            // or env doesn't support IntersectionObserver (testing?)
            // - immediately fetch icon
            cb();
        }
    }
    isRtl() {
        // doc is in rtl
        if (this.el.ownerDocument?.dir === 'rtl')
            return true;
        // html element is in rtl element
        if (this.el.closest('[dir="rtl"]'))
            return true;
        // nested in a shadow dom - see if that host element is contained in an rtl element
        const rootNode = this.el.getRootNode();
        const ownerHost = rootNode.host;
        if (ownerHost && ownerHost.closest('[dir="rtl"]'))
            return true;
        return false;
    }
    connectedCallback() {
        // purposely do not return the promise here because loading
        // the svg file should not hold up loading the app
        // only load the svg if it's visible
        this.waitUntilVisible(this.el, '50px', () => {
            this.isVisible = true;
            this.loadIcon();
        });
    }
    disconnectedCallback() {
        if (this.io) {
            this.io.disconnect();
            this.io = undefined;
        }
    }
    componentWillLoad() {
        this.updateRole();
        this.setAriaLabel();
    }
    render() {
        const flipRtl = this.flipRtl ||
            (this.name &&
                this.name.match(/right|left/) &&
                (this.name.indexOf('arrow') > -1 ||
                    this.name.indexOf('chevron') > -1) &&
                this.isRtl());
        return (h(Host, { key: '5c392d7707158df8b3c3d75f00824e597c3a87a9', class: {
                loading: this.isLoading,
                'flip-rtl': !!flipRtl,
                'nano-icon': true,
            } }, Build.isBrowser && this.svgContent ? (h("div", { class: "icon-inner", innerHTML: this.svgContent })) : (h("div", { class: "icon-inner" }))));
    }
    static get is() { return "nano-icon"; }
    static get encapsulation() { return "shadow"; }
    static get originalStyleUrls() {
        return {
            "$": ["icon.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["icon.css"]
        };
    }
    static get assetsDirs() { return ["device", "pictogram", "flag"]; }
    static get properties() {
        return {
            "color": {
                "type": "string",
                "attribute": "color",
                "mutable": false,
                "complexType": {
                    "original": "'primary' | 'neutral'",
                    "resolved": "\"neutral\" | \"primary\"",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Specifies the color of the icon. If not specified, the icon will inherit the color of the parent element."
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "role": {
                "type": "string",
                "attribute": "role",
                "mutable": true,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Specifies the role to use for accessibility. Defaults to 'presentation' (invisible to screen-readers)"
                },
                "getter": false,
                "setter": false,
                "reflect": true
            },
            "ariaLabel": {
                "type": "string",
                "attribute": "aria-label",
                "mutable": true,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Specifies the label to use for accessibility. Defaults to the icon name."
                },
                "getter": false,
                "setter": false,
                "reflect": true
            },
            "flipRtl": {
                "type": "boolean",
                "attribute": "flip-rtl",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Specifies whether the icon should horizontally flip when `dir` is `\"rtl\"`.\nBy default, when an 'arrow' or 'chevron' icon is used, it will flip automatically when detecting `dir=\"rtl\"` on the document or closest ancestor."
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "name": {
                "type": "string",
                "attribute": "name",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Specifies which icon to use from the built-in set of icons."
                },
                "getter": false,
                "setter": false,
                "reflect": true
            },
            "src": {
                "type": "string",
                "attribute": "src",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Specifies the exact `src` of an SVG file to use."
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "icon": {
                "type": "any",
                "attribute": "icon",
                "mutable": false,
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "A combination of both `name` and `src`. If a `src` url is detected\nit will set the `src` property. Otherwise it assumes it's a built-in named\nSVG and set the `name` property."
                },
                "getter": false,
                "setter": false,
                "reflect": false
            },
            "size": {
                "type": "string",
                "attribute": "size",
                "mutable": false,
                "complexType": {
                    "original": "| 'small'\n    | 'regular'\n    | 'large'\n    | 'xl'\n    | 'auto'",
                    "resolved": "\"auto\" | \"large\" | \"regular\" | \"small\" | \"xl\"",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The size of the icon. `auto` automatically sizes according to the font-size of the parent element.\n*Note*: size will be different on 'pictogram' and 'device' vs 'font awesome' icons."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "defaultValue": "'auto'"
            },
            "lazy": {
                "type": "boolean",
                "attribute": "lazy",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "If enabled, nano-icon will be loaded lazily when it's visible in the viewport.\nDefault, `true`."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "defaultValue": "true"
            }
        };
    }
    static get states() {
        return {
            "svgContent": {},
            "isVisible": {},
            "isLoading": {}
        };
    }
    static get events() {
        return [{
                "method": "nanoLoad",
                "name": "nanoLoad",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the icon has finished loading."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }, {
                "method": "nanoError",
                "name": "nanoError",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the icon fails to load."
                },
                "complexType": {
                    "original": "any",
                    "resolved": "any",
                    "references": {}
                }
            }];
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "role",
                "methodName": "setAriaLabel"
            }, {
                "propName": "ariaLabel",
                "methodName": "updateRole"
            }, {
                "propName": "name",
                "methodName": "loadIcon"
            }, {
                "propName": "src",
                "methodName": "loadIcon"
            }, {
                "propName": "icon",
                "methodName": "loadIcon"
            }];
    }
}
