import { r as registerInstance, c as createEvent, h, d as getElement } from './core-4636ab56.js';
import './_commonjsHelpers-4ab098b6.js';
import { _ } from './lodash-62c1633d.js';

function resolveJson(input) {
    return typeof input === "string" ? JSON.parse(input) : input;
}

function throwTypeLiteralNotSupported(name, value, allValues) {
    throw new Error(`${name} value of "${value}" is invalid. 
    valid values are: ${allValues.join(", ")}`);
}

const AllDistinctModeLiterals = [
    "value",
    "label",
    "all",
    "any",
    "none"
];

function distinctFilter(input, mode) {
    let output;
    switch (mode) {
        case "none":
            output = input;
            break;
        case "all":
            output = _.chain(input)
                .uniqBy(a => a.value)
                .uniqBy(a => a.label)
                .value();
            break;
        case "any":
            output = _.uniqWith(input, (a, b) => a.label === b.label && a.value === b.value);
            break;
        case "label":
            output = _.uniqBy(input, a => a.label);
            break;
        case "value":
            output = _.uniqBy(input, a => a.value);
            break;
        default:
            throwTypeLiteralNotSupported("distinctMode", mode, AllDistinctModeLiterals);
    }
    return output;
}

const AllTypeLiterals = ["single", "multi"];

const PwcChoices = class {
    constructor(hostRef) {
        registerInstance(this, hostRef);
        /**
         * The selection behaviour.
         * "multi" allows selection of multiple options.
         * "single" allows selection of only a single option (just like the native HTML select element).
         */
        this.type = "multi";
        /**
         * If true, the placeholder will be hidden if there are selected options.
         */
        this.autoHidePlaceholder = true;
        /**
         * This determines wheter the dropdown is open or not.
         */
        this.dropdownIsOpen = false;
        /**
         * If true, selected option bubbles will have close buttons.
         */
        this.showCloseButtons = true;
        /**
         * If true, the option will be removed from available options after selection.
         */
        this.uniqueSelections = true;
        /**
         * This will be displayed in the dropdown when there are no options left to choose.
         */
        this.noOptionsString = "No options to choose from.";
        /**
         * This is the mode of filtering we use to make given option objects distinct.
         * "none" disables the distinct filtering behaviour.
         */
        this.distinctMode = "none";
        this.doNotEmitChangeEvent = false;
        this.selectedOptions = [];
        this.selectedOptionsChanged = createEvent(this, "selectedOptionsChanged", 7);
    }
    typeWatchHandler(newValue) {
        if (!AllTypeLiterals.includes(newValue)) {
            throwTypeLiteralNotSupported("type", newValue, AllTypeLiterals);
        }
    }
    optionsWatchHandler(newValue) {
        this.resolvedOptions = distinctFilter(resolveJson(newValue), this.distinctMode);
    }
    distinctModeWatchHandler(newValue) {
        if (!AllDistinctModeLiterals.includes(newValue)) {
            throwTypeLiteralNotSupported("distinctMode", newValue, AllDistinctModeLiterals);
        }
    }
    selectedOptionsWatchHandler(newValue) {
        if (!this.doNotEmitChangeEvent) {
            this.selectedOptionsChanged.emit(newValue);
        }
        this.doNotEmitChangeEvent = false;
    }
    /**
     * Returns the values of currently selected options.
     */
    async getSelectedOptionsAsValues() {
        return this.selectedOptions.map(o => o.value);
    }
    /**
     * Returns the labels of currently selected options.
     */
    async getSelectedOptionsAsLabels() {
        return this.selectedOptions.map(o => o.label);
    }
    /**
     * Returns the selected options as objects (as passed in to this component).
     */
    async getSelectedOptionsAsObjects() {
        return this.selectedOptions;
    }
    optionDiscardedHandler(event) {
        const payload = event.detail;
        const newSelectedItems = [...this.selectedOptions];
        newSelectedItems.splice(payload.index, 1);
        this.selectedOptions = newSelectedItems;
    }
    inputBarClickedHandler() {
        this.dropdownIsOpen = !this.dropdownIsOpen;
    }
    dropdownItemClickedHandler(event) {
        switch (this.type) {
            case "multi":
                this.selectedOptions = [
                    ...this.selectedOptions,
                    event.detail.option.original
                ];
                break;
            case "single":
                this.selectedOptions = [event.detail.option.original];
                this.dropdownIsOpen = false;
                break;
        }
    }
    windowClickHandler() {
        this.dropdownIsOpen = false;
    }
    selfClickHandler(event) {
        // stop propagation so windowClickHandler doesn't capture it.
        event.stopPropagation();
    }
    componentWillLoad() {
        this.optionsWatchHandler(this.options);
        this.typeWatchHandler(this.type);
        this.distinctModeWatchHandler(this.distinctMode);
        this.doNotEmitChangeEvent = true;
        this.selectInitialSelectedOptions();
    }
    selectInitialSelectedOptions() {
        const initialSelections = _.filter(this.resolvedOptions, o => o.initialSelected && o.initialSelected === true);
        if (this.type === "single" && initialSelections.length > 1) {
            throw new Error("You have multiple initial selected options, but the type is `single`!");
        }
        this.selectedOptions = [...initialSelections];
    }
    componentDidLoad() {
        this.form = this.root.closest("form");
        if (this.form) {
            this.form.addEventListener("reset", this.handleFormReset.bind(this));
        }
    }
    componentDidUnload() {
        if (this.form) {
            this.form.removeEventListener("reset", this.handleFormReset.bind(this));
        }
    }
    handleFormReset() {
        this.doNotEmitChangeEvent = true;
        this.selectInitialSelectedOptions();
    }
    constructInputBar() {
        return (h("pwc-choices-input-bar", { options: this.selectedOptions, showCloseButtons: this.showCloseButtons, placeholder: this.placeholder, autoHidePlaceholder: this.autoHidePlaceholder, type: this.type }));
    }
    constructDropdown() {
        const dropdownOptions = this.uniqueSelections
            ? _.difference(this.resolvedOptions, this.selectedOptions)
            : this.resolvedOptions;
        return (h("pwc-choices-dropdown", { noOptionsString: this.noOptionsString, options: dropdownOptions, searchBarPlaceholder: this.searchBarPlaceholder }));
    }
    render() {
        return [
            this.constructInputBar(),
            this.dropdownIsOpen && this.constructDropdown()
        ];
    }
    get root() { return getElement(this); }
    static get watchers() { return {
        "type": ["typeWatchHandler"],
        "options": ["optionsWatchHandler"],
        "distinctMode": ["distinctModeWatchHandler"],
        "selectedOptions": ["selectedOptionsWatchHandler"]
    }; }
    static get style() { return "pwc-choices {\n  display: block;\n  margin: 0;\n  padding: 0;\n  font-size: medium;\n  font-family: Calibri, sans-serif;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  position: relative;\n  width: 100%;\n}"; }
};

export { PwcChoices as pwc_choices };
