combobox: add stateless mode
This commit is contained in:
@@ -50,6 +50,8 @@
|
|||||||
lazy?: boolean;
|
lazy?: boolean;
|
||||||
/** uses a compact layout for the search input with less padding and smaller text */
|
/** uses a compact layout for the search input with less padding and smaller text */
|
||||||
compact?: boolean;
|
compact?: boolean;
|
||||||
|
/** allows the user to select an option without selecting a value (events are still triggered) */
|
||||||
|
stateless?: boolean;
|
||||||
notFoundMessage?: string;
|
notFoundMessage?: string;
|
||||||
class?: ClassValue | null | undefined;
|
class?: ClassValue | null | undefined;
|
||||||
use?: () => void;
|
use?: () => void;
|
||||||
@@ -77,6 +79,7 @@
|
|||||||
loading = false,
|
loading = false,
|
||||||
lazy = false,
|
lazy = false,
|
||||||
compact = false,
|
compact = false,
|
||||||
|
stateless = false,
|
||||||
notFoundMessage = 'No results found',
|
notFoundMessage = 'No results found',
|
||||||
class: classValue,
|
class: classValue,
|
||||||
use,
|
use,
|
||||||
@@ -191,6 +194,13 @@
|
|||||||
onclose?.(); // trigger onclose event if defined
|
onclose?.(); // trigger onclose event if defined
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** updates the value of the combobox and triggers any callbacks, including closing the picker */
|
||||||
|
const updateValue = (newValue: ComboboxOption) => {
|
||||||
|
if (!stateless) value = newValue;
|
||||||
|
closePicker();
|
||||||
|
onchange?.(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
/** action to set the minimum width of the combobox based on the number of options */
|
/** action to set the minimum width of the combobox based on the number of options */
|
||||||
const minWidth: Action<HTMLDivElement, { options: ComboboxOption[] }> = (
|
const minWidth: Action<HTMLDivElement, { options: ComboboxOption[] }> = (
|
||||||
container,
|
container,
|
||||||
@@ -290,10 +300,7 @@
|
|||||||
export const setValueByString = (searchVal: string) => {
|
export const setValueByString = (searchVal: string) => {
|
||||||
const item = options.find((opt) => opt.value === searchVal);
|
const item = options.find((opt) => opt.value === searchVal);
|
||||||
if (item) {
|
if (item) {
|
||||||
value = item;
|
updateValue(item);
|
||||||
searchValue = '';
|
|
||||||
closePicker();
|
|
||||||
onchange?.(item);
|
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Combobox: No option found with value "${searchVal}"`);
|
console.warn(`Combobox: No option found with value "${searchVal}"`);
|
||||||
}
|
}
|
||||||
@@ -393,7 +400,7 @@
|
|||||||
aria-label={getLabel(item)}
|
aria-label={getLabel(item)}
|
||||||
aria-disabled={item.disabled}
|
aria-disabled={item.disabled}
|
||||||
class={[
|
class={[
|
||||||
'picker-item options-center mb-0.5 flex min-h-10 flex-wrap py-2.5 pr-1.5 pl-5',
|
'mb-0.5 flex min-h-10 flex-wrap items-center py-2.5 pr-1.5 pl-5',
|
||||||
'rounded-sm text-sm capitalize outline-hidden select-none',
|
'rounded-sm text-sm capitalize outline-hidden select-none',
|
||||||
'hover:bg-sui-accent-500/30 dark:hover:bg-sui-accent-700/30',
|
'hover:bg-sui-accent-500/30 dark:hover:bg-sui-accent-700/30',
|
||||||
item.value === highlighted?.value && 'bg-sui-accent-500/80 dark:bg-sui-accent-700/80',
|
item.value === highlighted?.value && 'bg-sui-accent-500/80 dark:bg-sui-accent-700/80',
|
||||||
@@ -402,10 +409,8 @@
|
|||||||
role="option"
|
role="option"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
if (item.disabled) return;
|
if (item.disabled) return;
|
||||||
value = item;
|
updateValue(item);
|
||||||
closePicker();
|
|
||||||
searchInput?.focus();
|
searchInput?.focus();
|
||||||
onchange?.(item);
|
|
||||||
}}
|
}}
|
||||||
onkeydown={() => {}}
|
onkeydown={() => {}}
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
@@ -523,14 +528,12 @@
|
|||||||
|
|
||||||
if (e.key === 'Tab' || e.key === 'Enter') {
|
if (e.key === 'Tab' || e.key === 'Enter') {
|
||||||
if (open && highlighted && !highlighted.disabled && highlighted.value !== value?.value) {
|
if (open && highlighted && !highlighted.disabled && highlighted.value !== value?.value) {
|
||||||
value = highlighted;
|
updateValue(highlighted);
|
||||||
onchange?.(highlighted);
|
|
||||||
}
|
}
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
|
closePicker();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
closePicker();
|
|
||||||
return;
|
return;
|
||||||
} else if (e.key === 'Escape') {
|
} else if (e.key === 'Escape') {
|
||||||
closePicker();
|
closePicker();
|
||||||
|
|||||||
@@ -136,7 +136,8 @@
|
|||||||
|
|
||||||
<Combobox
|
<Combobox
|
||||||
loading
|
loading
|
||||||
label="Loading state combobox"
|
label="Loading stateless combobox"
|
||||||
|
stateless
|
||||||
placeholder="Choose..."
|
placeholder="Choose..."
|
||||||
options={[
|
options={[
|
||||||
{ value: 'option1', label: 'Option 1' },
|
{ value: 'option1', label: 'Option 1' },
|
||||||
|
|||||||
Reference in New Issue
Block a user