import Choices from "choices.js";
import { select } from "../../core/dom";
import { isString } from "../../core/util/types";
import { is_equal } from "../../core/util/eq";
import * as inputs from "../../styles/widgets/inputs.css";
import choices_css from "../../styles/widgets/choices.css";
import { InputWidget, InputWidgetView } from "./input_widget";
function retarget(event) {
    Object.defineProperty(event, "target", {
        get: () => event.composedPath()[0] ?? null,
        configurable: true,
    });
    return event;
}
class OurChoices extends Choices {
    static __name__ = "OurChoices";
    _onFocus(event) {
        super._onFocus(retarget(event));
    }
    _onBlur(event) {
        super._onBlur(retarget(event));
    }
    _onKeyUp(event) {
        super._onKeyUp(retarget(event));
    }
    _onKeyDown(event) {
        super._onKeyDown(retarget(event));
    }
    _onClick(event) {
        super._onClick(retarget(event));
    }
    _onTouchEnd(event) {
        super._onTouchEnd(retarget(event));
    }
    _onMouseDown(event) {
        super._onMouseDown(retarget(event));
    }
    _onMouseOver(event) {
        super._onMouseOver(retarget(event));
    }
}
export class MultiChoiceView extends InputWidgetView {
    static __name__ = "MultiChoiceView";
    choice_el;
    connect_signals() {
        super.connect_signals();
        this.connect(this.model.properties.disabled.change, () => this.set_disabled());
        const { value, max_items, option_limit, search_option_limit, delete_button, placeholder, options, name, title } = this.model.properties;
        this.on_change([max_items, option_limit, search_option_limit, delete_button, placeholder, options, name, title], () => this.render());
        this.on_change(value, () => {
            // Detects if value change originated in UI or elsewhere. Choices.js automatically
            // updates itself, so we don't have to do anything, and in fact we shouldn't do
            // anything, because the component is finicky and hard to update without breaking
            // something, loosing focus, etc.
            if (!is_equal(this.model.value, this._current_values)) {
                this.render();
            }
        });
    }
    stylesheets() {
        return [...super.stylesheets(), choices_css];
    }
    _render_input() {
        return this.input_el = select({
            multiple: true,
            class: inputs.input,
            name: this.model.name,
            disabled: this.model.disabled,
        });
    }
    render() {
        super.render();
        const selected = new Set(this.model.value);
        const choices = this.model.options.map((opt) => {
            let value, label;
            if (isString(opt)) {
                value = label = opt;
            }
            else {
                [value, label] = opt;
            }
            return { value, label, selected: selected.has(value) };
        });
        const fill = this.model.solid ? "solid" : "light";
        const item = `choices__item ${fill}`;
        const button = `choices__button ${fill}`;
        const options = {
            choices,
            itemSelectText: "",
            duplicateItemsAllowed: false,
            shouldSort: false,
            removeItemButton: this.model.delete_button,
            classNames: { item, button }, // XXX: missing typings
            placeholderValue: this.model.placeholder,
            maxItemCount: this.model.max_items ?? -1,
            renderChoiceLimit: this.model.option_limit ?? -1,
            searchResultLimit: this.model.search_option_limit ?? 4,
        };
        this.choice_el = new OurChoices(this.input_el, options);
        this.input_el.addEventListener("change", () => this.change_input());
    }
    set_disabled() {
        if (this.model.disabled) {
            this.choice_el.disable();
        }
        else {
            this.choice_el.enable();
        }
    }
    get _current_values() {
        const values = this.choice_el.getValue();
        return values.map((item) => item.value);
    }
    change_input() {
        this.model.value = this._current_values;
        super.change_input();
    }
}
export class MultiChoice extends InputWidget {
    static __name__ = "MultiChoice";
    constructor(attrs) {
        super(attrs);
    }
    static {
        this.prototype.default_view = MultiChoiceView;
        this.define(({ Bool, Int, Str, List, Tuple, Or, Nullable }) => ({
            value: [List(Str), []],
            options: [List(Or(Str, Tuple(Str, Str))), []],
            max_items: [Nullable(Int), null],
            delete_button: [Bool, true],
            placeholder: [Nullable(Str), null],
            option_limit: [Nullable(Int), null],
            search_option_limit: [Nullable(Int), null],
            solid: [Bool, true],
        }));
    }
}
//# sourceMappingURL=multi_choice.js.map