Skip to content

Commit

Permalink
fix(overlay): allow "receives-focus" to target the root of an overlay (
Browse files Browse the repository at this point in the history
…#3658)

* fix(overlay): allow "receives-focus" to target the root of an overlay

* ci: update golden images cache

* docs(overlay): massage types
  • Loading branch information
Westbrook Johnson authored Sep 18, 2023
1 parent b06abb9 commit 0db1025
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ executors:
parameters:
current_golden_images_hash:
type: string
default: 9494051c6e69193df911d0f2571c794fe6f20f00
default: a1b36206c9a867825429a05c55190164ddfeb3be
wireit_cache_name:
type: string
default: wireit
Expand Down
4 changes: 4 additions & 0 deletions packages/overlay/src/OverlayDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
guaranteedAllTransitionend,
} from './AbstractOverlay.js';
import type { AbstractOverlay } from './AbstractOverlay.js';
import { userFocusableSelector } from '@spectrum-web-components/shared';

export function OverlayDialog<T extends Constructor<AbstractOverlay>>(
constructor: T
Expand Down Expand Up @@ -76,6 +77,9 @@ export function OverlayDialog<T extends Constructor<AbstractOverlay>>(
// Show/focus workflow when opening _only_.
return;
}
if (el.matches(userFocusableSelector)) {
focusEl = el;
}
focusEl = focusEl || firstFocusableIn(el);
if (!focusEl) {
const childSlots = el.querySelectorAll('slot');
Expand Down
4 changes: 4 additions & 0 deletions packages/overlay/src/OverlayNoPopover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
overlayTimer,
} from './AbstractOverlay.js';
import type { AbstractOverlay } from './AbstractOverlay.js';
import { userFocusableSelector } from '@spectrum-web-components/shared';

export function OverlayNoPopover<T extends Constructor<AbstractOverlay>>(
constructor: T
Expand Down Expand Up @@ -81,6 +82,9 @@ export function OverlayNoPopover<T extends Constructor<AbstractOverlay>>(
if (targetOpenState !== true) {
return;
}
if (el.matches(userFocusableSelector)) {
focusEl = el;
}
focusEl = focusEl || firstFocusableIn(el);
if (focusEl) {
return;
Expand Down
4 changes: 4 additions & 0 deletions packages/overlay/src/OverlayPopover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
overlayTimer,
} from './AbstractOverlay.js';
import type { AbstractOverlay } from './AbstractOverlay.js';
import { userFocusableSelector } from '@spectrum-web-components/shared';

function isOpen(el: HTMLElement): boolean {
let popoverOpen = false;
Expand Down Expand Up @@ -149,6 +150,9 @@ export function OverlayPopover<T extends Constructor<AbstractOverlay>>(
if (!targetOpenState) {
return;
}
if (el.matches(userFocusableSelector)) {
focusEl = el;
}
focusEl = focusEl || firstFocusableIn(el);
if (focusEl) {
return;
Expand Down
32 changes: 32 additions & 0 deletions packages/overlay/stories/overlay-element.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type Properties = {
interaction: 'click' | 'hover' | 'longpress';
open?: boolean;
placement?: Placement;
receivesFocus: 'true' | 'false' | 'auto';
type?: OverlayTypes;
};

Expand Down Expand Up @@ -152,6 +153,37 @@ longpress.args = {
type: 'auto',
};

/**
* Proxy for fully encapsulated overlay containers that need to
* pass `focus` into a shadow child element.
*/
export const receivesFocus = ({
interaction,
open,
placement,
receivesFocus,
type,
}: Properties): TemplateResult => html`
<sp-action-button id="trigger">
Open the overlay (with focus)
</sp-action-button>
<sp-overlay
?open=${open}
trigger="trigger@${interaction}"
type=${ifDefined(type)}
placement=${ifDefined(placement)}
.receivesFocus=${receivesFocus}
>
<a href="https://example.com">Click Content</a>
</sp-overlay>
`;
receivesFocus.args = {
interaction: 'click',
placement: 'bottom-start',
type: 'auto',
receivesFocus: 'true',
} as Properties;

export const transformed = (args: Properties): TemplateResult => html`
<style>
.transformed {
Expand Down
16 changes: 16 additions & 0 deletions packages/overlay/test/overlay-element.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import '@spectrum-web-components/button/sp-button.js';
import { sendMouse } from '../../../test/plugins/browser.js';
import { Button } from '@spectrum-web-components/button';
import { sendKeys } from '@web/test-runner-commands';
import { receivesFocus } from '../stories/overlay-element.stories.js';

const OVERLAY_TYPES = ['modal', 'page', 'hint', 'auto', 'manual'] as const;
type OverlayTypes = typeof OVERLAY_TYPES[number];
Expand Down Expand Up @@ -652,6 +653,21 @@ describe('sp-overlay', () => {
});
describe('[type="auto"]', () => {
opensDeclaratively('auto');
it('receives focus', async () => {
const test = await fixture(html`
<div>${receivesFocus(receivesFocus.args)}</div>
`);
const trigger = test.querySelector('#trigger') as Button;
const overlay = test.querySelector('a');

expect(document.activeElement === overlay).to.be.false;

const opened = oneEvent(trigger, 'sp-opened');
trigger.click();
await opened;

expect(document.activeElement === overlay).to.be.true;
});
});
describe('[type="manual"]', () => {
opensDeclaratively('manual');
Expand Down

0 comments on commit 0db1025

Please sign in to comment.