function MultiSelect({ label, onInputChange, onSelect, placeholder = '', height = '350px', displayOptions = true }){
let selectedOptions = [];
const multiInputContainer = render(['div', { class: 'p-1 border rounded-md flex-1 flex border-gray-300 bg-white py-2 pl-3 pr-12 shadow-sm focus-within:border-indigo-500 focus-within:outline-none focus-within:ring-1 focus-within:ring-indigo-500 space-x-2'}]);
const inputContainer = render(['div', { class: "relative mt-1" }]);
const optionsContainer = render(['div']);
function renderOptionsPlaceholder() {
const placeholder = render(['div', { class: 'h-60 mt-2 border border-dashed rounded-md flex items-center justify-center text-gray-400 text-md' }, 'SEARCH RESULTS']);
optionsContainer.replaceChildren(placeholder);
}
function renderInput() {
function handleSearchInput(e) {
const text = e.target.value;
(async function renderOptions() {
const options = await onInputChange(text);
if (!displayOptions || !Array.isArray(options)) return;
const el = render(['ul', {
class: `z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg
ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm`,
role: "listbox"
},
options.map(createListOption)
]);
optionsContainer.replaceChildren(el);
})()
}
const inputEl = render(['input', {
type: 'text',
class: "flex-1 border-none focus:ring-0 sm:text-sm",
role: "combobox",
'aria-controls': "options",
'aria-expanded': "false",
oninput: handleSearchInput,
placeholder
}
]);
if (selectedOptions.length > 0) {
function removeSelectedItem(item) {
selectedOptions = selectedOptions.filter(option => option.label !== item.label);
onSelect(selectedOptions);
renderInput();
}
function renderSelectedOption(selected) {
return render([
'div',
{class: 'inline-flex items-center gap-x-0.5 rounded-md bg-blue-100 px-2 py-1 text-xs font-medium text-blue-700'},
['div', selected.label],
['button',
{
type: 'button',
class: 'group relative -mr-1 h-3.5 w-3.5 rounded-sm hover:bg-blue-600/20',
onclick: () => removeSelectedItem(selected)
},
['svg', {
xmlns: "http://www.w3.org/2000/svg",
viewBox: '0 0 14 14',
class: 'h-3.5 w-3.5 stroke-blue-800/50 group-hover:stroke-blue-800/75'},
['path', { d: 'M4 4l6 6m0-6l-6 6'}]
],
['span', { class: 'absolute -inset-1'}]
]
]);
}
multiInputContainer.replaceChildren(...selectedOptions.map(renderSelectedOption), inputEl);
} else {
multiInputContainer.replaceChildren(inputEl);
}
if (displayOptions) {
renderOptionsPlaceholder();
}
}
function createListOption(option) {
return ["li", {
role: "option",
class: "relative cursor-pointer select-none py-2 pl-3 pr-9 text-gray-900 hover:text-white hover:bg-indigo-600",
tabindex: "-1",
onclick: () => {
selectedOptions = [...selectedOptions, option];
onSelect(selectedOptions);
renderInput();
}
}, ['span', { class: "block truncate"}, option.label]]
}
// set initial container
renderInput();
const tree = [
'div',
label ? ['label', { for: "combobox", class: "block text-sm font-medium text-gray-700" }, label] : ['div'],
multiInputContainer,
displayOptions ? optionsContainer : ['div']
]
const layout = ['div', { style: { padding: '6px'}}, tree];
return renderIframe(render(layout), { height: '350px' });
}