Skip to content

Commit 06ccb84

Browse files
fix(SelectField): keep menu open on reactive updates; close only on selection or outside click (#638)
* Refactor SelectField component to improve option filtering logic and prevent menu closure on reactive updates * Improve SelectField behavior to keep menu open on reactive value updates and clearing * Ran prettier & added changeset
1 parent 17cb522 commit 06ccb84

File tree

3 files changed

+23
-19
lines changed

3 files changed

+23
-19
lines changed

.changeset/fine-vans-move.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte-ux': patch
3+
---
4+
5+
fix(SelectField): keep menu open on reactive updates; close only on selection or outside click

packages/svelte-ux/src/lib/components/SelectField.svelte

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@
118118
119119
// Capture for next change
120120
prevValue = selected?.value;
121-
prevSelected = selectOption(selected);
121+
// Do not close menu when selection is updated reactively
122+
prevSelected = selectOption(selected, false);
122123
} else if (/*value !== undefined &&*/ value !== prevValue) {
123124
// Removed `value !== undefined` to clear searchText when value is set to undefined. Might be a breaking change
124125
logger.info('value changed', {
@@ -131,7 +132,7 @@
131132
132133
// Capture for next change
133134
prevValue = value;
134-
prevSelected = selectValue(value);
135+
prevSelected = selectValue(value, false);
135136
} else {
136137
logger.info('neither selected or value changed (options only)');
137138
// Reselect value if menu is not open and options possibly changed (which could result in new display text for the select value)
@@ -358,17 +359,17 @@
358359
/**
359360
* Select option by value
360361
*/
361-
function selectValue(value: TValue | null | undefined) {
362+
function selectValue(value: TValue | null | undefined, closeMenu: boolean = true) {
362363
logger.debug('selectValue', { value, options, filteredOptions });
363364
364365
const option = options?.find((option) => option.value === value) ?? null;
365-
return selectOption(option);
366+
return selectOption(option, closeMenu);
366367
}
367368
368369
/**
369370
* Select option by object
370371
*/
371-
function selectOption(option: MenuOption<TValue> | null) {
372+
function selectOption(option: MenuOption<TValue> | null, closeMenu: boolean = true) {
372373
logger.info('selectOption', { option });
373374
374375
const previousValue = value;
@@ -389,7 +390,9 @@
389390
dispatch('change', { option, value });
390391
}
391392
392-
hide('selectOption');
393+
if (closeMenu) {
394+
hide('selectOption');
395+
}
393396
394397
return option;
395398
}
@@ -418,7 +421,8 @@
418421
419422
function clear() {
420423
logger.info('clear');
421-
selectOption(null);
424+
// Clearing should not close the menu🤞; keep it open if it already is
425+
selectOption(null, false);
422426
filteredOptions = options;
423427
}
424428
</script>

packages/svelte-ux/src/routes/docs/components/SelectField/+page.svelte

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,13 @@
7575
let selectedStr: 'any' | 'even' | 'odds' = 'any';
7676
7777
// Filter options based on toggle selection
78-
$: optionsFiltered = options.map((o) => {
79-
const matches =
80-
selectedStr === 'even'
81-
? typeof o.value === 'number' && o.value % 2 === 0
82-
: selectedStr === 'odds'
83-
? typeof o.value === 'number' && o.value % 2 !== 0
84-
: true;
85-
86-
return {
87-
...o,
88-
disabled: (o.disabled ?? false) || !matches,
89-
};
78+
$: optionsFiltered = options.filter((o) => {
79+
if (selectedStr === 'even') {
80+
return typeof o.value === 'number' && o.value % 2 === 0;
81+
} else if (selectedStr === 'odds') {
82+
return typeof o.value === 'number' && o.value % 2 !== 0;
83+
}
84+
return true;
9085
});
9186
</script>
9287

0 commit comments

Comments
 (0)