Skip to content

fix(picker): menuitem focus when opened via mouse #5358

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

Merged
merged 19 commits into from
Apr 23, 2025
Merged

Conversation

nikkimk
Copy link
Contributor

@nikkimk nikkimk commented Apr 9, 2025

Description

Only sets focus if keyboard opens menu

Related issue(s)

Motivation and context

Focus should not be set on menuitems when opened via mouse.

How has this been tested?

  1. Go to https://opensource.adobe.com/spectrum-web-components/storybook/index.html?path=/story/menu-submenu--submenu
  2. Click on hamburger to open the menu.
  3. Menu is opened and focus should not be on first menu item.
  4. Click to close the menu.
  5. If hamburger menu is not focused, click Tab to focus on it.
  6. Click to open the menu,
  7. Menu is opened and focus should be on first menu item.
  • Did it pass in Desktop?
  • Did it pass in Mobile?
  • Did it pass in iPad?

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Chore (minor updates related to the tooling or maintenance of the repository, does not impact compiled assets)

Checklist

  • I have signed the Adobe Open Source CLA.
  • My code follows the code style of this project.
  • If my change required a change to the documentation, I have updated the documentation in this pull request.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have reviewed at the Accessibility Practices for this feature, see: Aria Practices

Best practices

This repository uses conventional commit syntax for each commit message; note that the GitHub UI does not use this by default so be cautious when accepting suggested changes. Avoid the "Update branch" button on the pull request and opt instead for rebasing your branch against main.

Copy link

changeset-bot bot commented Apr 9, 2025

🦋 Changeset detected

Latest commit: 9f49efc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 84 packages
Name Type
@spectrum-web-components/picker Patch
@spectrum-web-components/action-menu Patch
@spectrum-web-components/custom-vars-viewer Patch
example-project-rollup Patch
example-project-webpack Patch
@spectrum-web-components/story-decorator Patch
@spectrum-web-components/bundle Patch
@spectrum-web-components/breadcrumbs Patch
documentation Patch
@spectrum-web-components/eslint-plugin Patch
@spectrum-web-components/accordion Patch
@spectrum-web-components/action-bar Patch
@spectrum-web-components/action-button Patch
@spectrum-web-components/action-group Patch
@spectrum-web-components/alert-banner Patch
@spectrum-web-components/alert-dialog Patch
@spectrum-web-components/asset Patch
@spectrum-web-components/avatar Patch
@spectrum-web-components/badge Patch
@spectrum-web-components/button-group Patch
@spectrum-web-components/button Patch
@spectrum-web-components/card Patch
@spectrum-web-components/checkbox Patch
@spectrum-web-components/clear-button Patch
@spectrum-web-components/close-button Patch
@spectrum-web-components/coachmark Patch
@spectrum-web-components/color-area Patch
@spectrum-web-components/color-field Patch
@spectrum-web-components/color-handle Patch
@spectrum-web-components/color-loupe Patch
@spectrum-web-components/color-slider Patch
@spectrum-web-components/color-wheel Patch
@spectrum-web-components/combobox Patch
@spectrum-web-components/contextual-help Patch
@spectrum-web-components/dialog Patch
@spectrum-web-components/divider Patch
@spectrum-web-components/dropzone Patch
@spectrum-web-components/field-group Patch
@spectrum-web-components/field-label Patch
@spectrum-web-components/help-text Patch
@spectrum-web-components/icon Patch
@spectrum-web-components/icons-ui Patch
@spectrum-web-components/icons-workflow Patch
@spectrum-web-components/icons Patch
@spectrum-web-components/iconset Patch
@spectrum-web-components/illustrated-message Patch
@spectrum-web-components/infield-button Patch
@spectrum-web-components/link Patch
@spectrum-web-components/menu Patch
@spectrum-web-components/meter Patch
@spectrum-web-components/modal Patch
@spectrum-web-components/number-field Patch
@spectrum-web-components/overlay Patch
@spectrum-web-components/picker-button Patch
@spectrum-web-components/popover Patch
@spectrum-web-components/progress-bar Patch
@spectrum-web-components/progress-circle Patch
@spectrum-web-components/radio Patch
@spectrum-web-components/search Patch
@spectrum-web-components/sidenav Patch
@spectrum-web-components/slider Patch
@spectrum-web-components/split-view Patch
@spectrum-web-components/status-light Patch
@spectrum-web-components/swatch Patch
@spectrum-web-components/switch Patch
@spectrum-web-components/table Patch
@spectrum-web-components/tabs Patch
@spectrum-web-components/tags Patch
@spectrum-web-components/textfield Patch
@spectrum-web-components/thumbnail Patch
@spectrum-web-components/toast Patch
@spectrum-web-components/tooltip Patch
@spectrum-web-components/top-nav Patch
@spectrum-web-components/tray Patch
@spectrum-web-components/underlay Patch
@spectrum-web-components/vrt-compare Patch
@spectrum-web-components/base Patch
@spectrum-web-components/grid Patch
@spectrum-web-components/opacity-checkerboard Patch
@spectrum-web-components/reactive-controllers Patch
@spectrum-web-components/shared Patch
@spectrum-web-components/styles Patch
@spectrum-web-components/theme Patch
@spectrum-web-components/truncated Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link

github-actions bot commented Apr 9, 2025

Branch preview

Review the following VRT differences

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

@nikkimk nikkimk changed the title Nikkimk/fix action menu fix(picker): menuitem focus when opened via mouse Apr 9, 2025
Copy link

github-actions bot commented Apr 9, 2025

Tachometer results

Chrome

picker permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 643 kB 460.94ms - 466.35ms - faster ✔
16% - 18%
88.85ms - 98.54ms
branch 578 kB 553.32ms - 561.35ms slower ❌
19% - 21%
88.85ms - 98.54ms
-
Firefox

picker permalink

basic-test

Version Bytes Avg Time vs remote vs branch
npm latest 643 kB 1081.24ms - 1105.60ms - faster ✔
4% - 6%
40.84ms - 66.88ms
branch 578 kB 1142.67ms - 1151.89ms slower ❌
4% - 6%
40.84ms - 66.88ms
-

@@ -269,7 +265,7 @@ describe('ActionGroup', () => {

await elementUpdated(el);

await aTimeout(500);
await aTimeout(100);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At some point we really need to come up with something less brittle than aTimeout and nextFrame. There has to be a waitUntil condition we can use instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does changing from 500ms to 100ms removes any redundancy in this unit test case?

@@ -338,9 +331,13 @@ describe('ActionGroup', () => {
'mouse2: should not be focused on the fourth button'
).to.equal(-1);

await aTimeout(100);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Firefox wasn't opening without this.


await elementUpdated(el);
await aTimeout(500);
await elementUpdated(firstButton);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waiting for the first button to update eliminated the need for aTimeout

@@ -338,9 +331,13 @@ describe('ActionGroup', () => {
'mouse2: should not be focused on the fourth button'
).to.equal(-1);

await elementUpdated(el);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waiting for the element to update eliminated the need for aTimeout on line 321

@@ -368,12 +368,12 @@ export class PickerBase extends SizedMixin(SpectrumElement, {
item.selected = value;
}

public toggle(target?: boolean): void {
public toggle(target?: boolean, focusOnOpen?: boolean): void {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keyboard actions need to focus on open.

// Make a selection again
closed = oneEvent(el, 'sp-closed');
firstItem.click();
await sendKeys({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

focus happens with keyboard

@nikkimk nikkimk marked this pull request as ready for review April 18, 2025 12:26
@nikkimk nikkimk requested a review from a team as a code owner April 18, 2025 12:26
await nextFrame();
await nextFrame();
await nextFrame();
await waitUntil(() => el.children.length === 4);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@nikkimk nikkimk requested a review from Rajdeepc April 21, 2025 13:40
@aramos-adobe
Copy link

@nikkimk I tested it on my iPad and desktop and it works perfectly! I would suggest in your description, adding a step to press tab first and changing click down arrow key to press down arrow key. Hitting the tab key works for the iPad especially with external keyboards. If you don't hit tab it just shows the active state then the focus indicator until you hit the directional key a second time.

@@ -311,7 +312,20 @@ export class PickerBase extends SizedMixin(SpectrumElement, {
};

protected async keyboardOpen(): Promise<void> {
this.toggle(true);
// if the menu is not open, we need to toggle it and wait for it to open to focus on the first selected item
if (!this.open || !this.strategy.open) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opening via keyboard set focus on first item. If menu isn't already open, menu will be opened first.

@@ -373,14 +387,6 @@ export class PickerBase extends SizedMixin(SpectrumElement, {
return;
}
const open = typeof target !== 'undefined' ? target : !this.open;
if (open && !this.open)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only focus on first item if opened via keyboard.

@nikkimk nikkimk requested a review from caseyisonit April 21, 2025 23:28
Copy link
Contributor

@Rajdeepc Rajdeepc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works perfectly! Thanks for bringing this in!

Copy link
Contributor

@caseyisonit caseyisonit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM -- works great!

@caseyisonit
Copy link
Contributor

@nikkimk i just realized this needs a change set added before we merge

@Rajdeepc
Copy link
Contributor

@nikkimk i just realized this needs a change set added before we merge

An automation here would make life more easier: https://danger.systems/ to help us here

@nikkimk nikkimk enabled auto-merge (squash) April 23, 2025 11:40
@nikkimk nikkimk disabled auto-merge April 23, 2025 12:45
@nikkimk nikkimk enabled auto-merge (squash) April 23, 2025 12:52

// use keyboard to navigate to the second menu item and select it
await sendKeys({ press: 'ArrowDown' });
expect(actionMenu.children[0]).to.equal(document.activeElement);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test was still timing out on CI event though it passed locally, so I wanted to make sure a menuitem was focused before selecting it can closing the menu,

@nikkimk nikkimk merged commit 3c3bc2b into main Apr 23, 2025
24 checks passed
@nikkimk nikkimk deleted the nikkimk/fix-action-menu branch April 23, 2025 13:47
@TarunAdobe TarunAdobe restored the nikkimk/fix-action-menu branch April 24, 2025 10:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants