Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(select): fix auto scroll to selected item in ion-select #30202

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 44 additions & 48 deletions core/src/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -319,58 +319,54 @@ export class Select implements ComponentInterface {

await overlay.present();

// focus selected option for popovers and modals
if (this.interface === 'popover' || this.interface === 'modal') {
const indexOfSelected = this.childOpts.findIndex((o) => o.value === this.value);

if (indexOfSelected > -1) {
const selectedItem = overlay.querySelector<HTMLElement>(
`.select-interface-option:nth-child(${indexOfSelected + 1})`
);

if (selectedItem) {
/**
* Browsers such as Firefox do not
* correctly delegate focus when manually
* focusing an element with delegatesFocus.
* We work around this by manually focusing
* the interactive element.
* ion-radio and ion-checkbox are the only
* elements that ion-select-popover uses, so
* we only need to worry about those two components
* when focusing.
*/
const interactiveEl = selectedItem.querySelector<HTMLElement>('ion-radio, ion-checkbox') as
| HTMLIonRadioElement
| HTMLIonCheckboxElement
| null;
if (interactiveEl) {
// Needs to be called before `focusVisibleElement` to prevent issue with focus event bubbling
// and removing `ion-focused` style
interactiveEl.setFocus();
}
const indexOfSelected = this.childOpts.findIndex((o) => o.value === this.value);
if (indexOfSelected > -1) {
const selectedItem = overlay.querySelector<HTMLElement>(
`.select-interface-option:nth-child(${indexOfSelected + 1})`
);

focusVisibleElement(selectedItem);
}
} else {
if (selectedItem) {
/**
* If no value is set then focus the first enabled option.
* Browsers such as Firefox do not
* correctly delegate focus when manually
* focusing an element with delegatesFocus.
* We work around this by manually focusing
* the interactive element.
* ion-radio and ion-checkbox are the only
* elements that ion-select-popover uses, so
* we only need to worry about those two components
* when focusing.
*/
const firstEnabledOption = overlay.querySelector<HTMLElement>(
'ion-radio:not(.radio-disabled), ion-checkbox:not(.checkbox-disabled)'
) as HTMLIonRadioElement | HTMLIonCheckboxElement | null;

if (firstEnabledOption) {
/**
* Focus the option for the same reason as we do above.
*
* Needs to be called before `focusVisibleElement` to prevent issue with focus event bubbling
* and removing `ion-focused` style
*/
firstEnabledOption.setFocus();

focusVisibleElement(firstEnabledOption.closest('ion-item')!);
const interactiveEl = selectedItem.querySelector<HTMLElement>('ion-radio, ion-checkbox') as
| HTMLIonRadioElement
| HTMLIonCheckboxElement
| null;
if (interactiveEl) {
// Needs to be called before `focusVisibleElement` to prevent issue with focus event bubbling
// and removing `ion-focused` style
interactiveEl.setFocus();
}

focusVisibleElement(selectedItem);
}
} else {
/**
* If no value is set then focus the first enabled option.
*/
const firstEnabledOption = overlay.querySelector<HTMLElement>(
'ion-radio:not(.radio-disabled), ion-checkbox:not(.checkbox-disabled)'
) as HTMLIonRadioElement | HTMLIonCheckboxElement | null;

if (firstEnabledOption) {
/**
* Focus the option for the same reason as we do above.
*
* Needs to be called before `focusVisibleElement` to prevent issue with focus event bubbling
* and removing `ion-focused` style
*/
firstEnabledOption.setFocus();

focusVisibleElement(firstEnabledOption.closest('ion-item')!);
}
}

Expand Down
150 changes: 150 additions & 0 deletions core/src/components/select/test/basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,156 @@
</ion-item>
</ion-list>

<ion-list>
<ion-list-header>
<ion-label>Single Value - Overflowing Options</ion-label>
</ion-list-header>

<ion-item>
<ion-select id="alert-select2" label="Alert" placeholder="Select one" interface="alert" value="dragonfruit">
<ion-select-option value="apples">Apples</ion-select-option>
<ion-select-option value="oranges">Oranges</ion-select-option>
<ion-select-option value="pears">Pears</ion-select-option>
<ion-select-option value="pineaple">Pineaple</ion-select-option>
<ion-select-option value="peach">Peach</ion-select-option>
<ion-select-option value="melon">Melon</ion-select-option>
<ion-select-option value="watermelon">Watermelon</ion-select-option>
<ion-select-option value="strawberry">Strawberry</ion-select-option>
<ion-select-option value="grapes">Grapes</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="mango">Mango</ion-select-option>
<ion-select-option value="dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="kiwi">Kiwi</ion-select-option>
<ion-select-option value="blackberry">Blackberry</ion-select-option>
<ion-select-option value="blueberry">Blueberry</ion-select-option>
</ion-select>
</ion-item>

<ion-item>
<ion-select label="Popover" placeholder="Select one" interface="popover" value="2watermelon">
<ion-select-option value="apples">Apples</ion-select-option>
<ion-select-option value="oranges">Oranges</ion-select-option>
<ion-select-option value="pears">Pears</ion-select-option>
<ion-select-option value="pineaple">Pineaple</ion-select-option>
<ion-select-option value="peach">Peach</ion-select-option>
<ion-select-option value="melon">Melon</ion-select-option>
<ion-select-option value="watermelon">Watermelon</ion-select-option>
<ion-select-option value="strawberry">Strawberry</ion-select-option>
<ion-select-option value="grapes">Grapes</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="mango">Mango</ion-select-option>
<ion-select-option value="dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="kiwi">Kiwi</ion-select-option>
<ion-select-option value="blackberry">Blackberry</ion-select-option>
<ion-select-option value="blueberry">Blueberry</ion-select-option>

<ion-select-option value="1apples">Apples</ion-select-option>
<ion-select-option value="1oranges">Oranges</ion-select-option>
<ion-select-option value="1pears">Pears</ion-select-option>
<ion-select-option value="1pineaple">Pineaple</ion-select-option>
<ion-select-option value="1peach">Peach</ion-select-option>
<ion-select-option value="1melon">Melon</ion-select-option>
<ion-select-option value="1watermelon">Watermelon</ion-select-option>
<ion-select-option value="1strawberry">Strawberry</ion-select-option>
<ion-select-option value="1grapes">Grapes</ion-select-option>
<ion-select-option value="1banana">Banana</ion-select-option>
<ion-select-option value="1mango">Mango</ion-select-option>
<ion-select-option value="1dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="1kiwi">Kiwi</ion-select-option>
<ion-select-option value="1blackberry">Blackberry</ion-select-option>
<ion-select-option value="1blueberry">Blueberry</ion-select-option>

<ion-select-option value="2apples">Apples</ion-select-option>
<ion-select-option value="2oranges">Oranges</ion-select-option>
<ion-select-option value="2pears">Pears</ion-select-option>
<ion-select-option value="2pineaple">Pineaple</ion-select-option>
<ion-select-option value="2peach">Peach</ion-select-option>
<ion-select-option value="2melon">Melon</ion-select-option>
<ion-select-option value="2watermelon">Watermelon</ion-select-option>
<ion-select-option value="2strawberry">Strawberry</ion-select-option>
<ion-select-option value="2grapes">Grapes</ion-select-option>
<ion-select-option value="2banana">Banana</ion-select-option>
<ion-select-option value="2mango">Mango</ion-select-option>
<ion-select-option value="2dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="2kiwi">Kiwi</ion-select-option>
<ion-select-option value="2blackberry">Blackberry</ion-select-option>
<ion-select-option value="2blueberry">Blueberry</ion-select-option>
</ion-select>
</ion-item>

<ion-item>
<ion-select label="Action Sheet" placeholder="Select one" interface="action-sheet" value="2watermelon">
<ion-select-option value="apples">Apples</ion-select-option>
<ion-select-option value="oranges">Oranges</ion-select-option>
<ion-select-option value="pears">Pears</ion-select-option>
<ion-select-option value="pineaple">Pineaple</ion-select-option>
<ion-select-option value="peach">Peach</ion-select-option>
<ion-select-option value="melon">Melon</ion-select-option>
<ion-select-option value="watermelon">Watermelon</ion-select-option>
<ion-select-option value="strawberry">Strawberry</ion-select-option>
<ion-select-option value="grapes">Grapes</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="mango">Mango</ion-select-option>
<ion-select-option value="dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="kiwi">Kiwi</ion-select-option>
<ion-select-option value="blackberry">Blackberry</ion-select-option>
<ion-select-option value="blueberry">Blueberry</ion-select-option>

<ion-select-option value="1apples">Apples</ion-select-option>
<ion-select-option value="1oranges">Oranges</ion-select-option>
<ion-select-option value="1pears">Pears</ion-select-option>
<ion-select-option value="1pineaple">Pineaple</ion-select-option>
<ion-select-option value="1peach">Peach</ion-select-option>
<ion-select-option value="1melon">Melon</ion-select-option>
<ion-select-option value="1watermelon">Watermelon</ion-select-option>
<ion-select-option value="1strawberry">Strawberry</ion-select-option>
<ion-select-option value="1grapes">Grapes</ion-select-option>
<ion-select-option value="1banana">Banana</ion-select-option>
<ion-select-option value="1mango">Mango</ion-select-option>
<ion-select-option value="1dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="1kiwi">Kiwi</ion-select-option>
<ion-select-option value="1blackberry">Blackberry</ion-select-option>
<ion-select-option value="1blueberry">Blueberry</ion-select-option>

<ion-select-option value="2apples">Apples</ion-select-option>
<ion-select-option value="2oranges">Oranges</ion-select-option>
<ion-select-option value="2pears">Pears</ion-select-option>
<ion-select-option value="2pineaple">Pineaple</ion-select-option>
<ion-select-option value="2peach">Peach</ion-select-option>
<ion-select-option value="2melon">Melon</ion-select-option>
<ion-select-option value="2watermelon">Watermelon</ion-select-option>
<ion-select-option value="2strawberry">Strawberry</ion-select-option>
<ion-select-option value="2grapes">Grapes</ion-select-option>
<ion-select-option value="2banana">Banana</ion-select-option>
<ion-select-option value="2mango">Mango</ion-select-option>
<ion-select-option value="2dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="2kiwi">Kiwi</ion-select-option>
<ion-select-option value="2blackberry">Blackberry</ion-select-option>
<ion-select-option value="2blueberry">Blueberry</ion-select-option>
</ion-select>
</ion-item>

<ion-item>
<ion-select label="Modal" placeholder="Select one" interface="modal" value="kiwi">
<ion-select-option value="apples">Apples</ion-select-option>
<ion-select-option value="oranges">Oranges</ion-select-option>
<ion-select-option value="pears">Pears</ion-select-option>
<ion-select-option value="pineaple">Pineaple</ion-select-option>
<ion-select-option value="peach">Peach</ion-select-option>
<ion-select-option value="melon">Melon</ion-select-option>
<ion-select-option value="watermelon">Watermelon</ion-select-option>
<ion-select-option value="strawberry">Strawberry</ion-select-option>
<ion-select-option value="grapes">Grapes</ion-select-option>
<ion-select-option value="banana">Banana</ion-select-option>
<ion-select-option value="mango">Mango</ion-select-option>
<ion-select-option value="dragonfruit">Dragonfruit</ion-select-option>
<ion-select-option value="kiwi">Kiwi</ion-select-option>
<ion-select-option value="blackberry">Blackberry</ion-select-option>
<ion-select-option value="blueberry">Blueberry</ion-select-option>
</ion-select>
</ion-item>
</ion-list>

<ion-list>
<ion-list-header>
<ion-label>Multiple Value Select</ion-label>
Expand Down
Loading