"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SHAPE_TO_ICON = exports.SEARCH_ITEM_HEIGHT = void 0;
exports.isSpecFuzzyMatch = isSpecFuzzyMatch;
const fuzzy = require("fuzzy");
const classnames_1 = require("../../../../../client/classnames");
const debounce_1 = require("../../../../../client/debounce");
const element_1 = require("../../../../../client/element");
const custom_1 = require("../../../../../client/event/custom");
const focusin_1 = require("../../../../../client/event/focus/focusin");
const focusout_1 = require("../../../../../client/event/focus/focusout");
const input_1 = require("../../../../../client/event/input");
const keyboard_1 = require("../../../../../client/event/keyboard");
const click_1 = require("../../../../../client/event/pointer/click");
const pointerenter_1 = require("../../../../../client/event/pointer/pointerenter");
const scroll_1 = require("../../../../../client/event/scroll");
const parentElement_1 = require("../../../../../client/platform/web/parentElement");
const search_1 = require("../../../../../client/search");
const spec_1 = require("../../../../../client/spec");
const theme_1 = require("../../../../../client/theme");
const throttle_1 = require("../../../../../client/throttle");
const userSelect_1 = require("../../../../../client/util/style/userSelect");
const STRING_1 = require("../../../../../constant/STRING");
const array_1 = require("../../../../../util/array");
const clone_1 = require("../../../../../util/clone");
const grammar_1 = require("../../../../../util/grammar");
const sort_1 = require("../../../../../util/sort");
const string_1 = require("../../../../../util/string");
const f_1 = require("../../../../core/relation/Clamp/f");
const f_2 = require("../../../../f/object/Keys/f");
const Component_1 = require("../../../component/app/MicrophoneButton/Component");
const Component_2 = require("../../../core/component/TextBox/Component");
const Component_3 = require("../../Div/Component");
const Component_4 = require("../../Icon/Component");
const Component_5 = require("../IconButton/Component");
const Component_6 = require("../SearchInput/Component");
const Component_7 = require("../Tooltip/Component");
exports.SEARCH_ITEM_HEIGHT = 40;
const DEFAULT_STYLE = {
    position: 'relative',
    width: 'calc(100% + 4px)',
    maxWidth: '309px',
    height: 'initial',
    // overflowY: 'hidden',
    // overflowX: 'hidden',
    borderWidth: '1px 1px 0px 1px',
    borderStyle: 'solid',
    color: 'currentColor',
    borderColor: 'currentColor',
    padding: '0',
    backgroundColor: theme_1.COLOR_NONE,
    borderTopLeftRadius: '3px',
    borderTopRightRadius: '3px',
};
exports.SHAPE_TO_ICON = {
    rect: 'square',
    circle: 'circle',
};
function isSpecFuzzyMatch(str, pattern) {
    const cleanPattern = (0, string_1.removeWhiteSpace)(pattern.replace('-', ' '));
    const isMatch = fuzzy.match(cleanPattern, str, {
        caseSensitive: false,
    });
    return isMatch;
}
class Search extends element_1.Element {
    constructor($props, $system) {
        super($props, $system);
        this._input_value = '';
        this._shape = 'circle';
        this._ordered_id_list = [];
        this._filtered_id_list = [];
        this._item = {};
        this._filtered_list_item = [];
        this._list_item_div = {};
        this._list_item_content = {};
        this._list_item_name = {};
        this._list_hidden = true;
        this._selected_id = null;
        this._selected_index = 0;
        this._scrollTop = 0;
        this._reset = () => {
            // console.log('Search', '_reset')
            this._list.removeChildren();
            this._item = {};
            this._list_item_div = {};
            this._list_item_content = {};
            this._list_item_name = {};
            this._refresh_ordered_list();
            const total = this._ordered_id_list.length;
            let i = 0;
            for (const id of this._ordered_id_list) {
                this._add_list_item(id, i, total);
                i++;
            }
        };
        this._refresh_ordered_list = () => {
            const { classes } = this.$system;
            const { specs } = this._registry;
            const id_list = (0, f_2.keys)(specs);
            const ordered_id_list = id_list.sort((a, b) => {
                return (0, search_1.compareByComplexity)(specs, classes, a, b);
            });
            this._ordered_id_list = ordered_id_list;
            this._filtered_id_list = (0, clone_1.clone)(ordered_id_list);
            const ordered_id_set = new Set(ordered_id_list);
            for (const spec_id in this._item) {
                if (!ordered_id_set.has(spec_id)) {
                    this.__remove_list_item(spec_id);
                }
            }
        };
        this._set_list_item_color = (id, color) => {
            // console.log('Search', '_set_list_item_color', id, color)
            const selected_list_item = this._list_item_content[id];
            if (!selected_list_item) {
                // console.warn('selected list item not found')
                return;
            }
            selected_list_item.$element.style.color = color;
        };
        this._refresh_list = (preserve_selected) => {
            this._refresh_ordered_list();
            this._filter_list(preserve_selected);
        };
        this._find_new_item_index = (spec, list) => {
            const { classes } = this.$system;
            const { specs } = this._registry;
            if (list.length === 0) {
                return 0;
            }
            const index = (0, sort_1.binaryFindIndex)(list, (current_spec_id) => {
                const current_score = (0, search_1.compareByComplexity)(specs, classes, spec.id, current_spec_id);
                return current_score;
            });
            return index;
        };
        this._insert_list_item = (spec) => {
            var _a;
            const new_ordered_index = this._find_new_item_index(spec, this._ordered_id_list);
            this._ordered_id_list.splice(new_ordered_index, 0, spec.id);
            const match = fuzzy.match(this._input_value, (_a = spec.name) !== null && _a !== void 0 ? _a : '');
            if (match) {
                const new_filtered_index = this._find_new_item_index(spec, this._filtered_id_list);
                this._filtered_id_list.splice(new_filtered_index, 0, spec.id);
            }
            this._add_list_item(spec.id, new_ordered_index, this._ordered_id_list.length);
        };
        this._listen_registry = () => {
            this._registry_unlisten = this._registry.specs_.subscribe([], '*', (type, path, key, data) => {
                const { specs } = this._registry;
                const spec = data;
                if (path.length === 0) {
                    if (type === 'set') {
                        if (this._item[spec.id]) {
                            this._refresh_list_item(spec.id);
                            this._refresh_last_list_item_border();
                        }
                        else {
                            this._insert_list_item(spec);
                            if (!this._list_hidden) {
                                this._filter_list(true);
                            }
                        }
                    }
                    else if (type === 'delete') {
                        const specId = key;
                        // console.log('delete', specId)
                        if ((0, spec_1.isSystemSpec)(spec)) {
                            return;
                        }
                        this._remove_list_item(specId);
                        const selected_item_id = this._selected_id;
                        if (this._list_hidden) {
                            this._debounced_refresh_list();
                        }
                        else {
                            this._refresh_list();
                            if (selected_item_id === specId) {
                                this._select_first_list_item();
                            }
                        }
                    }
                }
            });
        };
        this._unlisten_registry = () => {
            this._registry_unlisten();
            this._registry_unlisten = undefined;
        };
        this._add_list_item = (id, i, total) => {
            // console.log('Search', '_add_list_item', id, i, total)
            const { specs } = this._registry;
            const spec = (0, spec_1.getSpec)(specs, id);
            const { name = '', metadata = {} } = spec;
            const icon = metadata.icon || 'question';
            const tags = metadata.tags || ['user'];
            const tagsStr = tags.join(' ');
            // const fuzzyName = `${name} ${tagsStr}`
            const fuzzyName = name;
            const finalName = name || STRING_1.UNTITLED;
            this._item[id] = { id, name, icon, tags, fuzzyName };
            const list_item_icon = new Component_4.default({
                style: { width: '18px', height: '18px', margin: '9px' },
                icon,
            }, this.$system);
            const list_item_main_name = new Component_2.default({
                style: {
                    width: 'fit-content',
                    height: '18px',
                    marginBottom: '2px',
                    ...(0, userSelect_1.userSelect)('none'),
                },
                value: finalName,
            }, this.$system);
            this._list_item_name[id] = list_item_main_name;
            const list_item_main_tags = new Component_2.default({
                style: {
                    fontSize: '12px',
                    width: 'fit-content',
                    height: '12px',
                    marginBottom: '1px',
                    ...(0, userSelect_1.userSelect)('none'),
                },
                value: tagsStr,
            }, this.$system);
            const list_item_main = new Component_3.default({
                style: {
                    display: 'flex',
                    flexDirection: 'column',
                    justifyContent: 'center',
                    marginBottom: '2px',
                    width: '100%',
                    height: '100%',
                },
            }, this.$system);
            list_item_main.appendChild(list_item_main_name);
            list_item_main.appendChild(list_item_main_tags);
            const list_item_content = new Component_3.default({
                className: 'search-list-item-content',
                style: {
                    display: 'flex',
                    width: '100%',
                    alignItems: 'center',
                    height: `${exports.SEARCH_ITEM_HEIGHT - 1}px`,
                    backgroundColor: theme_1.COLOR_NONE,
                },
            }, this.$system);
            list_item_content.appendChild(list_item_icon);
            list_item_content.appendChild(list_item_main);
            this._list_item_content[id] = list_item_content;
            const list_item_div_border_bottom = i < total - 1 ? `1px solid currentColor` : '';
            const list_item_div = new Component_3.default({
                className: 'search-list-item',
                style: {
                    borderBottom: list_item_div_border_bottom,
                    boxSizing: 'border-box',
                    width: `${309}px`,
                    height: '100%',
                    scrollSnapAlign: 'start',
                },
                data: {
                    id,
                },
            }, this.$system);
            list_item_div.preventDefault('mousedown');
            list_item_div.preventDefault('touchdown');
            list_item_div.appendChild(list_item_content);
            list_item_div.addEventListener((0, pointerenter_1.makePointerEnterListener)((event) => {
                this._on_list_item_pointer_enter(event, id);
            }));
            list_item_div.addEventListener((0, click_1.makeClickListener)({
                onClick: (event) => {
                    this._on_list_item_click(event, id);
                },
            }));
            this._list_item_div[id] = list_item_div;
            this._list.appendChild(list_item_div);
        };
        this._remove_list_item = (id) => {
            // console.log('Search', '_remove_list_item', id)
            const list_item_div = this._list_item_div[id];
            if (list_item_div) {
                this.__remove_list_item(id);
                (0, array_1.pull)(this._filtered_id_list, id);
                (0, array_1.pull)(this._ordered_id_list, id);
            }
        };
        this.__remove_list_item = (id) => {
            const list_item_div = this._list_item_div[id];
            if (list_item_div) {
                this._list.removeChild(list_item_div);
                delete this._list_item_div[id];
                delete this._item[id];
                delete this._list_item_name[id];
                delete this._list_item_content[id];
            }
        };
        this._refresh_list_item = (id) => {
            // console.log('Search', '_refresh_list_item', id)
            const list_item_div = this._list_item_div[id];
            const list_item_name = this._list_item_name[id];
            const spec = this._registry.getSpec(id);
            const { name = '', metadata = {} } = spec;
            const finalName = name || STRING_1.UNTITLED;
            const icon = metadata.icon || 'question';
            const tags = metadata.tags || [];
            const tagsStr = tags.join(' ');
            // const fuzzyName = `${name} ${tagsStr}`
            const fuzzyName = name;
            list_item_div.$element.style.borderBottom = `1px solid currentColor`;
            this._item[id] = { id, name, icon, tags, fuzzyName };
            list_item_name.setProp('value', finalName);
        };
        this._on_microphone_transcript = (0, throttle_1.throttle)(this.$system, (transcript) => {
            const value = transcript.toLowerCase().substr(0, 30);
            this._input.setProp('value', value);
            this._input_value = value;
            this._filter_list();
            this._input.focus();
        }, 100);
        this.start_microphone = () => {
            this._start_microphone();
        };
        this.stop_microphone = () => {
            this._stop_microphone();
        };
        this._start_microphone = () => {
            this._microphone.$unit.$setPinData({
                pinId: 'start',
                type: 'input',
                data: 'true',
            });
        };
        this._stop_microphone = () => {
            this._microphone.$unit.$setPinData({
                pinId: 'stop',
                type: 'input',
                data: 'true',
            });
        };
        this._on_input_keydown = ({ keyCode, repeat, key }, _event) => {
            // console.log('Search', '_on_input_keydown', keyCode, repeat)
            // prevent arrow up/down default
            if (keyCode === 38 || keyCode === 40 || keyCode === 186) {
                _event.preventDefault();
            }
            if (key === '\\') {
                if (!this._microphone.$output.recording) {
                    this._start_microphone();
                    _event.preventDefault();
                }
            }
            if (repeat) {
                if (keyCode === 8) {
                    //
                }
                else {
                    _event.preventDefault();
                }
            }
        };
        this._on_input_keyup = ({ key }) => {
            // console.log('Search', '_on_input_keyup')
            if (key === '\\') {
                if (this._microphone.$output.recording) {
                    this._stop_microphone();
                }
            }
        };
        this._on_input_focus_in = () => {
            // console.log('Search', '_on_input_focus_in')
            // setTimeout(() => {
            this._select_all();
            // }, 0)
            this._show_list();
        };
        this._select_all = () => {
            // console.log('Search', '_select_all')
            this._input.setSelectionRange(0, this._input_value.length);
        };
        this._on_input_click = () => {
            // this._input.setSelectionRange(0, this._input_value.length)
        };
        this._on_input_focus_out = () => {
            // console.log('Search', '_on_input_focus_out')
            this._hide_list();
        };
        this._show_list = () => {
            // console.log('Search', '_show_list')
            const { style = {} } = this.$props;
            const { color = 'currentColor' } = style;
            this._list_hidden = false;
            const filtered_total = this._filtered_id_list.length;
            const empty = filtered_total === 0;
            this._list.$element.style.display = 'block';
            this._input._input.$element.style.borderRadius = empty
                ? '3px 3px 0 0'
                : '0 0 0 0';
            this._input._input.$element.style.borderTopWidth = empty ? '0px' : '1px';
            if (!empty) {
                this._refresh_last_list_item_border();
                if (this._selected_id) {
                    this._scroll_into_item_if_needed(this._selected_id, false);
                }
            }
            this._dispatch_list_shown();
            if (this._selected_id) {
                this._dispatch_item_selected(this._selected_id);
            }
        };
        this._refresh_last_list_item_border = () => {
            const filtered_total = this._filtered_id_list.length;
            if (!filtered_total) {
                return;
            }
            const last_list_item_id = this._filtered_id_list[filtered_total - 1];
            const last_list_item_div = this._list_item_div[last_list_item_id];
            last_list_item_div.$element.style.borderBottom = ``;
        };
        this._dispatch_item_selected = (id) => {
            this.dispatchEvent('selected', { id });
        };
        this._dispatch_shape = () => {
            this.dispatchEvent('shape', { shape: this._shape });
        };
        this._dispatch_item_pick = (id) => {
            this.dispatchEvent('pick', { id });
        };
        this._dispatch_list_shown = () => {
            this.dispatchEvent('shown', {});
        };
        this._dispatch_list_hidden = () => {
            this.dispatchEvent('hidden', {});
        };
        this._dispatch_list_empty = () => {
            this.dispatchEvent('empty', {});
        };
        this._select_first_list_item = () => {
            const first_list_item_id = this._filtered_id_list[0];
            this._top_element_index = 0;
            this.set_selected_item_id(first_list_item_id, true);
        };
        this._hide_list = () => {
            this._list_hidden = true;
            this._input._input.$element.style.borderTopWidth = '0';
            this._list.$element.style.display = 'none';
            this._dispatch_list_hidden();
        };
        this._on_list_item_pointer_enter = ({}, id) => {
            // console.log('Search', '_on_list_item_pointer_enter')
            this.set_selected_item_id(id);
        };
        this._on_list_item_click = ({}, id) => {
            // console.log('Search', '_on_list_item_click')
            this._dispatch_item_pick(id);
        };
        this.set_selected_item_id = (id, force_scroll = false) => {
            const prev_selected_id = this._selected_id;
            this._set_selected_item_id(id, force_scroll);
            if (this._selected_id !== prev_selected_id) {
                this._dispatch_item_selected(id);
            }
        };
        this._set_selected_item_id = (id, force_scroll = false) => {
            // console.log('Search', '_set_selected_item_id', id, force_scroll)
            const { style = {}, selectedColor = 'currentColor' } = this.$props;
            const { color = 'currentColor' } = style;
            if (this._selected_id) {
                this._set_list_item_color(this._selected_id, color);
            }
            this._selected_id = id;
            this._set_list_item_color(id, selectedColor);
            if (!this._list_hidden) {
                this._scroll_into_item_if_needed(id, force_scroll);
            }
        };
        this.select_next = (offset) => {
            // console.log('Search', 'select_next', offset)
            let index = 0;
            if (this._selected_id) {
                index = this._ordered_id_list.indexOf(this._selected_id);
            }
            const next_index = (0, f_1.clamp)(index + offset, 0, this._ordered_id_list.length - 1);
            const next_selected_spec_id = this._ordered_id_list[next_index];
            this.set_selected_item_id(next_selected_spec_id);
        };
        this._top_element_index = 0;
        this._scroll_into_item_if_needed = (id, force = false) => {
            // console.log('Search', '_scroll_into_item_if_needed', id, force)
            const { scrollTop } = this._list.$element;
            const scroll_index = scrollTop / exports.SEARCH_ITEM_HEIGHT;
            const selected_id_index = this._filtered_id_list.indexOf(id);
            // const scroll_index = this._top_element_index ?? selected_id_index
            if (force ||
                selected_id_index - scroll_index >= 4 ||
                selected_id_index - scroll_index < 0) {
                const list_item = this._list_item_div[id];
                list_item.$element.scrollIntoView({ behavior: 'auto', block: 'nearest' });
                this._top_element_index = selected_id_index;
                // this._list.$element.scrollTop = selected_id_index * SEARCH_ITEM_HEIGHT
                // this._list.$element.scrollTo({
                //   top: selected_id_index * SEARCH_ITEM_HEIGHT,
                //   behavior: 'auto',
                // })
            }
        };
        this._debounced_refresh_list = (0, debounce_1.debounce)(this.$system, (preserve_selected = false) => {
            this._refresh_list(preserve_selected);
        }, 0);
        this._filter_list = (preserve_selected = false) => {
            // console.log('Search', '_filter_list')
            const { specs } = this._registry;
            const { style = {}, filter = () => true } = this.$props;
            const { color = 'currentColor' } = style;
            let filtered_id_list = [];
            const filtered_score = {};
            const fuzzy_pattern = this._input_value;
            const reverse_spaced_fuzzy_pattern = fuzzy_pattern
                .split(' ')
                .reverse()
                .join(' ');
            for (const id of this._ordered_id_list) {
                if (this._list_item_div[id]) {
                    this._refresh_list_item(id);
                }
                else {
                    const spec = specs[id];
                    this._insert_list_item(spec);
                }
                const { fuzzyName } = this._item[id];
                const list_item_div = this._list_item_div[id];
                const fuzzy_match = isSpecFuzzyMatch(fuzzyName, fuzzy_pattern) ||
                    isSpecFuzzyMatch(fuzzyName, reverse_spaced_fuzzy_pattern);
                if ((fuzzy_pattern === '' || fuzzy_match) &&
                    filter(id) &&
                    (this._shape === 'circle' || (0, spec_1.isComponentId)(specs, id))) {
                    filtered_score[id] = 0;
                    if (fuzzy_match) {
                        const { score } = fuzzy_match;
                        filtered_score[id] = score;
                    }
                    list_item_div.$element.style.display = 'flex';
                    filtered_id_list.push(id);
                }
                else {
                    list_item_div.$element.style.display = 'none';
                }
            }
            filtered_id_list = filtered_id_list.sort((a, b) => {
                const a_score = filtered_score[a];
                const b_score = filtered_score[b];
                return b_score - a_score;
            });
            this._filtered_id_list = filtered_id_list;
            let filtered_total = filtered_id_list.length;
            if (filtered_total > 0) {
                for (let i = 0; i < filtered_total; i++) {
                    const id = this._filtered_id_list[i];
                    const list_item_div = this._list_item_div[id];
                    this._list.removeChild(list_item_div);
                    this._list.appendChild(list_item_div);
                }
                if (!this._list_hidden) {
                    this._refresh_last_list_item_border();
                    this._input._input.$element.style.borderRadius = '0';
                    this._input._input.$element.style.borderTopWidth = '1px';
                }
                if (preserve_selected) {
                    if (this._selected_id) {
                        if (this._filtered_id_list.includes(this._selected_id)) {
                            this._top_element_index = 0;
                            this._scroll_into_item_if_needed(this._selected_id, false);
                        }
                        else {
                            this._select_first_list_item();
                        }
                    }
                    else {
                        this._select_first_list_item();
                    }
                }
                else {
                    this._select_first_list_item();
                }
            }
            else {
                this._input._input.$element.style.borderRadius = '3px 3px 0px 0px';
                this._input._input.$element.style.borderTopWidth = '0';
                if (this._selected_id) {
                    this._set_list_item_color(this._selected_id, color);
                }
                this._selected_id = null;
                this._dispatch_list_empty();
            }
            if (this._filtered_id_list.length > 0) {
                this._refresh_last_list_item_border();
            }
        };
        this._on_input_input = (value) => {
            if (value === ';') {
                this._setValue(this._input_value);
                return;
            }
            this._input_value = value;
            this._filter_list();
        };
        this._on_arrow_down_keydown = () => {
            if (!this._list_hidden && this._selected_id) {
                const selected_id_index = this._filtered_id_list.indexOf(this._selected_id);
                if (selected_id_index < this._filtered_id_list.length - 1) {
                    const next_selected_id_index = selected_id_index + 1;
                    const next_selected_id = this._filtered_id_list[next_selected_id_index];
                    this.set_selected_item_id(next_selected_id);
                }
            }
        };
        this._on_arrow_up_keydown = () => {
            if (!this._list_hidden && this._selected_id) {
                const selected_id_index = this._filtered_id_list.indexOf(this._selected_id);
                if (selected_id_index > 0) {
                    const next_selected_id_index = selected_id_index - 1;
                    const next_selected_id = this._filtered_id_list[next_selected_id_index];
                    this.set_selected_item_id(next_selected_id);
                }
            }
        };
        this._on_ctrl_p_keydown = () => {
            const { api: { window: { setTimeout }, }, } = this.$system;
            // console.log('Search', 'on_ctrl_p_keydown')
            setTimeout(() => {
                this._hide_list();
            }, 0);
        };
        this._on_escape_keydown = () => {
            const { api: { window: { setTimeout }, }, } = this.$system;
            // console.log('Search', '_on_escape_keydown')
            setTimeout(() => {
                this._hide_list();
            }, 0);
        };
        this._on_enter_keydown = () => {
            const { api: { window: { setTimeout }, }, } = this.$system;
            if (!this._list_hidden && this._selected_id) {
                setTimeout(() => {
                    if (this._selected_id) {
                        // Safari
                        // apparently selecting the input might inadvertently refocus it,
                        // which is certainly unexpected, so this call must absolutely
                        // come before dispatching a (possibly side-effecting) event
                        this._select_all();
                        this._dispatch_item_pick(this._selected_id);
                    }
                }, 0);
            }
        };
        this.getValue = () => {
            return this._input_value;
        };
        this.getShape = () => {
            return this._shape;
        };
        this.setValue = (value) => {
            // console.log('Search', 'setValue', value)
            this._setValue(value);
            this._filter_list(true);
        };
        this._setValue = (value) => {
            this._input_value = value;
            this._input.setProp('value', value);
        };
        this.toggleShape = () => {
            const shape = this._shape === 'circle' ? 'rect' : 'circle';
            this.setShape(shape);
        };
        this.setShape = (shape) => {
            this._setShape(shape);
            this._dispatch_shape();
        };
        this._setShape = (shape, emit) => {
            if (this._shape !== shape) {
                this._shape = shape;
                this._shape_button.setProp('icon', exports.SHAPE_TO_ICON[shape]);
                this._filter_list();
            }
        };
        const { className, style = {}, selected, registry } = this.$props;
        this._registry = registry !== null && registry !== void 0 ? registry : this.$system;
        const list = new Component_3.default({
            className: 'search-list',
            style: {
                position: 'relative',
                maxHeight: `${4 * exports.SEARCH_ITEM_HEIGHT - 1}px`,
                overflowY: 'auto',
                overflowX: 'hidden',
                display: this._list_hidden ? 'none' : 'block',
                width: 'calc(100% + 13px)',
                height: '100%',
                boxSizing: 'content-box',
                scrollSnapType: 'y mandatory',
            },
        }, this.$system);
        list.addEventListener((0, scroll_1.makeScrollListener)((event) => {
            this._scrollTop = this._list.$element.scrollTop;
        }));
        this._list = list;
        this._reset();
        const input = new Component_6.default({}, this.$system);
        input.addEventListener((0, keyboard_1.makeKeydownListener)(this._on_input_keydown));
        input.addEventListener((0, keyboard_1.makeKeyupListener)(this._on_input_keyup));
        input.addEventListener((0, focusin_1.makeFocusInListener)(this._on_input_focus_in));
        input.addEventListener((0, focusout_1.makeFocusOutListener)(this._on_input_focus_out));
        input.addEventListener((0, input_1.makeInputListener)(this._on_input_input));
        input.addEventListener((0, keyboard_1.makeShortcutListener)([
            {
                combo: 'ArrowDown',
                keydown: this._on_arrow_down_keydown,
                multiple: true,
            },
            {
                combo: 'ArrowUp',
                keydown: this._on_arrow_up_keydown,
                multiple: true,
            },
            { combo: 'Escape', keydown: this._on_escape_keydown },
            {
                // combo: 'Ctrl + p',
                combo: ['Ctrl + ;', ';'],
                // combo: 'Ctrl + /',
                keydown: this._on_ctrl_p_keydown,
                strict: false,
            },
            {
                // combo: 'p',
                combo: ';',
                // combo: '/',
                keydown: (key, { ctrlKey }) => {
                    if (ctrlKey) {
                        this._on_ctrl_p_keydown();
                    }
                },
            },
            {
                combo: ['Enter', 'Shift + Enter'],
                keydown: this._on_enter_keydown,
            },
        ]));
        this._input = input;
        const { api: { speech: { SpeechGrammarList }, }, } = this.$system;
        const microphone = new Component_1.default({
            style: {
                position: 'absolute',
                right: '0',
                bottom: '0',
                width: '18px',
                height: '18px',
                padding: '11px 9px 10px 11px',
            },
            opt: {
                grammars: SpeechGrammarList
                    ? (0, grammar_1.specNameGrammar)(this.$system)
                    : undefined,
                lang: 'en-us',
                maxAlternatives: 1,
                continuous: false,
                interimResults: true,
            },
        }, this.$system);
        microphone.addEventListener((0, custom_1.makeCustomListener)('text', this._on_microphone_transcript));
        microphone.preventDefault('mousedown');
        microphone.preventDefault('touchdown');
        this._microphone = microphone;
        const shape_button = new Component_5.default({
            icon: 'circle',
            style: {
                position: 'absolute',
                left: '0',
                bottom: '0px',
                width: '18px',
                height: '18px',
                padding: '11px 11px 10px 9px',
                ...(0, userSelect_1.userSelect)('none'),
            },
            title: 'layout',
        }, this.$system);
        shape_button.addEventListener((0, click_1.makeClickListener)({
            onClick: () => {
                this.toggleShape();
            },
        }));
        shape_button.preventDefault('mousedown');
        shape_button.preventDefault('touchdown');
        this._shape_button = shape_button;
        const search = new Component_3.default({
            className: (0, classnames_1.classnames)('search', className),
            style: {
                ...DEFAULT_STYLE,
                ...style,
            },
            title: 'search',
        }, this.$system);
        search.registerParentRoot(list);
        search.registerParentRoot(input);
        search.registerParentRoot(shape_button);
        search.registerParentRoot(microphone);
        const tooltip = new Component_7.default({
            shortcut: ';',
        }, this.$system);
        this._tooltip = tooltip;
        const shape_tooltip = new Component_7.default({
            shortcut: 'l',
        }, this.$system);
        this._shape_tooltip = shape_tooltip;
        const microphone_tooltip = new Component_7.default({
            shortcut: '|',
        }, this.$system);
        this._microphone_tooltip = microphone_tooltip;
        this._search = search;
        const $element = (0, parentElement_1.parentElement)($system);
        this.$element = $element;
        this.$slot = {
            default: search,
        };
        this.$unbundled = false;
        this.$primitive = true;
        if (selected) {
            if (this._filtered_id_list.includes(selected)) {
                this._set_selected_item_id(selected);
            }
        }
        else {
            if (this._ordered_id_list.length > 0) {
                this._select_first_list_item();
            }
        }
        this.registerRoot(search);
        this.registerRoot(tooltip);
        this.registerRoot(shape_tooltip);
        this.registerRoot(microphone_tooltip);
        this._listen_registry();
    }
    onPropChanged(prop, current) {
        if (prop === 'style') {
            const style = {
                ...DEFAULT_STYLE,
                ...current,
            };
            this._search.setProp('style', style);
        }
        else if (prop === 'selectedColor') {
            if (this._selected_id) {
                const { selectedColor = 'currentColor' } = this.$props;
                this._set_list_item_color(this._selected_id, selectedColor);
            }
        }
        else if (prop === 'selected') {
            const { selected } = this.$props;
            if (selected) {
                this._set_selected_item_id(selected);
            }
        }
        else if (prop === 'filter') {
            this._filter_list(true);
        }
        else if (prop === 'registry') {
            if (this._registry === current) {
                return;
            }
            this._registry = current !== null && current !== void 0 ? current : this.$system;
            this._unlisten_registry();
            this._listen_registry();
            this._refresh_list();
        }
        else if (prop === 'shape') {
            this._setShape(current !== null && current !== void 0 ? current : 'circle');
        }
    }
    focus(options = { preventScroll: true }) {
        this._input._input.focus(options);
    }
    blur() {
        this._input._input.blur();
    }
    getList() {
        return this._filtered_id_list;
    }
    onMount() {
        // console.log('Search', 'onMount')
    }
    onUnmount() {
        // console.log('Search', 'onUnmount')
    }
    onConnected() {
        // console.log('Search', 'onConnected')
    }
    onDestroy() {
        // console.log('Search', 'onDestroy')
        this._unlisten_registry();
    }
    showTooltip() {
        const bbox = this._search.getBoundingClientRect();
        this._tooltip.show(bbox.x + bbox.width / 2 - Component_7.TOOLTIP_WIDTH / 2, bbox.y - exports.SEARCH_ITEM_HEIGHT + 6);
        this._shape_tooltip.show(bbox.x + 6, bbox.y - exports.SEARCH_ITEM_HEIGHT + 6);
        this._microphone_tooltip.show(bbox.x + bbox.width - Component_7.TOOLTIP_WIDTH - 4.5, bbox.y - exports.SEARCH_ITEM_HEIGHT + 6);
    }
    hideTooltip() {
        this._tooltip.hide();
        this._shape_tooltip.hide();
        this._microphone_tooltip.hide();
    }
}
exports.default = Search;
//# sourceMappingURL=Component.js.map