Skip to content

Commit

Permalink
fix(overlay): prevent focus based hover interaction without :focus-vi…
Browse files Browse the repository at this point in the history
…sible
  • Loading branch information
Westbrook committed Mar 19, 2024
1 parent f79c419 commit 79337ff
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 10 deletions.
9 changes: 8 additions & 1 deletion packages/overlay/src/HoverController.ts
Expand Up @@ -13,7 +13,10 @@ governing permissions and limitations under the License.
import { conditionAttributeWithId } from '@spectrum-web-components/base/src/condition-attribute-with-id.js';
import { randomID } from '@spectrum-web-components/shared/src/random-id.js';

import { InteractionController, InteractionTypes } from './InteractionController.js';
import {
InteractionController,
InteractionTypes,
} from './InteractionController.js';
import { noop } from './AbstractOverlay.js';

const HOVER_DELAY = 300;
Expand All @@ -30,6 +33,10 @@ export class HoverController extends InteractionController {
pointerentered = false;

handleTargetFocusin(): void {
// eslint-disable-next-line @spectrum-web-components/document-active-element
if (!document.activeElement?.matches(':focus-visible')) {
return;
}
this.host.open = true;
this.focusedin = true;
}
Expand Down
17 changes: 13 additions & 4 deletions packages/overlay/test/overlay-lifecycle.test.ts
Expand Up @@ -22,7 +22,11 @@ import '@spectrum-web-components/tooltip/sp-tooltip.js';
import '@spectrum-web-components/action-button/sp-action-button.js';
import { OverlayTrigger } from '@spectrum-web-components/overlay';
import '@spectrum-web-components/overlay/overlay-trigger.js';
import { a11ySnapshot, findAccessibilityNode } from '@web/test-runner-commands';
import {
a11ySnapshot,
findAccessibilityNode,
sendKeys,
} from '@web/test-runner-commands';
import { Tooltip } from '@spectrum-web-components/tooltip';

describe('Overlay Trigger - accessible hover content management', () => {
Expand Down Expand Up @@ -158,10 +162,15 @@ describe('Overlay Trigger - accessible hover content management', () => {
expect(trigger.getAttribute('aria-describedby')).to.equal(tooltip.id);
expect(el.open).to.be.undefined;

// For `:focus-visible` heuristic.
const input = document.createElement('input');
el.insertAdjacentElement('afterbegin', input);
input.focus();

const opened = oneEvent(el, 'sp-opened');
trigger.dispatchEvent(
new FocusEvent('focusin', { bubbles: true, composed: true })
);
await sendKeys({
press: 'Tab',
});
await opened;

expect(trigger.getAttribute('aria-describedby')).to.equal(tooltip.id);
Expand Down
23 changes: 19 additions & 4 deletions packages/overlay/test/overlay-trigger-hover-click.test.ts
Expand Up @@ -31,6 +31,8 @@ import { sendMouse } from '../../../test/plugins/browser.js';
import { clickAndHoverTargets, deep } from '../stories/overlay.stories.js';
import { ignoreResizeObserverLoopError } from '../../../test/testing-helpers.js';
import { Tooltip } from '@spectrum-web-components/tooltip/src/Tooltip.js';
import { sendKeys } from '@web/test-runner-commands';
import { Button } from '@spectrum-web-components/button';

ignoreResizeObserverLoopError(before, after);

Expand Down Expand Up @@ -209,6 +211,7 @@ describe('Overlay Trigger - Hover and Click', () => {
<div>${deep()}</div>
`);
const el = test.querySelector('overlay-trigger') as OverlayTrigger;
const trigger = test.querySelector('sp-button') as Button;
const button = el.querySelector('sp-action-button') as ActionButton;
const button2 = el.querySelector(
'sp-action-button:nth-of-type(2)'
Expand All @@ -219,10 +222,18 @@ describe('Overlay Trigger - Hover and Click', () => {
expect(tooltip.open).to.be.false;

const opened = oneEvent(el, 'sp-opened');
const tooltipOpen = oneEvent(button, 'sp-opened');
el.open = 'click';
trigger.focus();
// For `:focus-visible` heuristic.
await sendKeys({
press: 'Tab',
});
await sendKeys({
press: 'Shift+Tab',
});
await sendKeys({
press: 'Space',
});
await opened;
await tooltipOpen;

expect(el.open).to.equal('click');
expect(tooltip.open).to.be.true;
Expand All @@ -235,7 +246,11 @@ describe('Overlay Trigger - Hover and Click', () => {
expect(tooltip.open).to.be.true;

let closed = oneEvent(button, 'sp-closed');
button2.focus();
expect(document.activeElement === button, `button focused`).to.be.true;
await sendKeys({
press: 'Tab',
});
expect(document.activeElement === button2, `button focused`).to.be.true;
await closed;

expect(el.open).to.equal('click');
Expand Down
9 changes: 8 additions & 1 deletion packages/overlay/test/overlay-trigger-longpress.test.ts
Expand Up @@ -56,8 +56,15 @@ describe('Overlay Trigger - Longpress', () => {
expect(this.content).to.not.be.null;
expect(this.content.open).to.be.false;

// For `:focus-visible` heuristic.
const input = document.createElement('input');
this.el.insertAdjacentElement('beforebegin', input);
input.focus();

const open = oneEvent(this.el, 'sp-opened');
this.trigger.focus();
await sendKeys({
press: 'Tab',
});
await open;
});
it('opens/closes for `Space`', async function () {
Expand Down

0 comments on commit 79337ff

Please sign in to comment.