= Number(required) ? JSON.stringify(selected) : null}
tabindex="-1"
aria-hidden="true"
aria-label="ignore this, used only to prevent form submission if select is required but empty"
class="form-control"
bind:this={form_input}
on:invalid={() => {
invalid = true
let msg
if (maxSelect && maxSelect > 1 && Number(required) > 1) {
msg = `Please select between ${required} and ${maxSelect} options`
} else if (Number(required) > 1) {
msg = `Please select at least ${required} options`
} else {
msg = `Please select an option`
}
form_input?.setCustomValidity(msg)
}}
/>
{#if loading}
spinner
{/if}
{#if disabled}
disable
{:else if selected.length > 0}
{#if maxSelect !== 1 && selected.length > 1 && !disableRemoveAll}
{/if}
{/if}
{#if allowUserOptions || (searchText && noMatchingOptionsMsg) || options?.length > 0}
{@const option = matchingOptions[index]}
{@const {
label,
disabled = null,
title = null,
selectedTitle = null,
disabledTitle = defaultDisabledTitle
} = option instanceof Object ? option : { label: option }}
{
if (!disabled) add(option, event)
}}
title={disabled ? disabledTitle : (is_selected(label) && selectedTitle) || title}
class={twMerge('hover:bg-blue-100 hover:dark:bg-gray-900 cursor-pointer !px-2 py-1')}
on:mouseover={() => {
if (!disabled) activeIndex = index
}}
on:focus={() => {
if (!disabled) activeIndex = index
}}
on:mouseout={() => (activeIndex = null)}
on:blur={() => (activeIndex = null)}
role="option"
aria-selected="false"
style={get_style(option, `option`)}
>
{#if parseLabelsAsHtml}
{@html get_label(option)}
{:else}
{get_label(option)}
{/if}
{#if searchText}
{@const text_input_is_duplicate = selected.map(get_label).includes(searchText)}
{@const is_dupe = !duplicates && text_input_is_duplicate && `dupe`}
{@const can_create = Boolean(allowUserOptions && createOptionMsg) && `create`}
{@const no_match =
Boolean(matchingOptions?.length == 0 && noMatchingOptionsMsg) && `no-match`}
{@const msgType = is_dupe || can_create || no_match}
{#if msgType}
{@const msg = {
dupe: duplicateOptionMsg,
create: createOptionMsg,
'no-match': noMatchingOptionsMsg
}[msgType]}
{
if (allowUserOptions) add(searchText, event)
}}
title={createOptionMsg}
class:active={option_msg_is_active}
on:mouseover={() => (option_msg_is_active = true)}
on:focus={() => (option_msg_is_active = true)}
on:mouseout={() => (option_msg_is_active = false)}
on:blur={() => (option_msg_is_active = false)}
role="option"
aria-selected="false"
class="user-msg p-1"
style:cursor={{
dupe: `not-allowed`,
create: `pointer`,
'no-match': `default`
}[msgType]}
>
{msg}
{/if}
{/if}
{/if}