Skip to content

Commit

Permalink
fix(expressive-modal): ensure waiting for transitionend event (carbon…
Browse files Browse the repository at this point in the history
…-design-system#5189)

### Related Ticket(s)

Refs carbon-design-system#5173.

### Description

Changes the "focus on the primary focusable element" logic in `<dds-expressive-modal>` to wait for `transitionend` event. Without it, the attempt to focus fails.

Also changes `<dds-locale-modal>` to make `<dds-region-item>` as the primary focusable element.

### Changelog

**Changed**

- The "focus on the primary focusable element" logic in `<dds-expressive-modal>` to wait for `transitionend` event.
- `<dds-locale-modal>` to make `<dds-region-item>` as the primary focusable element.
  • Loading branch information
asudoh authored and IgnacioBecerra committed Feb 22, 2021
1 parent a16cf27 commit 8e6eb37
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @license
*
* Copyright IBM Corp. 2020
* Copyright IBM Corp. 2020, 2021
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
Expand Down Expand Up @@ -104,7 +104,6 @@ describe('dds-expressive-modal', function() {

describe('Showing/hiding', function() {
it('Should support using Carbon core primary button in footer as the primary focus element', async function() {
spyOn(DDSExpressiveModal as any, '_delay').and.callFake(() => {});
render(
html`
<dds-expressive-modal>
Expand All @@ -118,6 +117,7 @@ describe('dds-expressive-modal', function() {
const modal = document.querySelector('dds-expressive-modal') as DDSExpressiveModal;
const input = modal.querySelector('input') as HTMLInputElement;
const button = modal.querySelector('bx-btn') as HTMLButtonElement;
spyOn(modal as any, '_waitForTransitionEnd').and.callFake(() => {});
spyOn(input, 'focus');
spyOn(button, 'focus');
modal.open = true;
Expand All @@ -128,7 +128,6 @@ describe('dds-expressive-modal', function() {
});

it('Should support using primary button in footer as the primary focus element', async function() {
spyOn(DDSExpressiveModal as any, '_delay').and.callFake(() => {});
render(
html`
<dds-expressive-modal>
Expand All @@ -142,6 +141,7 @@ describe('dds-expressive-modal', function() {
const modal = document.querySelector('dds-expressive-modal') as DDSExpressiveModal;
const input = modal.querySelector('input') as HTMLInputElement;
const button = modal.querySelector('dds-btn') as HTMLButtonElement;
spyOn(modal as any, '_waitForTransitionEnd').and.callFake(() => {});
spyOn(input, 'focus');
spyOn(button, 'focus');
modal.open = true;
Expand All @@ -152,7 +152,6 @@ describe('dds-expressive-modal', function() {
});

it('Should support specifying the primary focus element', async function() {
spyOn(DDSExpressiveModal as any, '_delay').and.callFake(() => {});
render(
html`
<dds-expressive-modal>
Expand All @@ -166,6 +165,7 @@ describe('dds-expressive-modal', function() {
const modal = document.querySelector('dds-expressive-modal') as DDSExpressiveModal;
const input = modal.querySelector('input') as HTMLInputElement;
const button = modal.querySelector('button') as HTMLButtonElement;
spyOn(modal as any, '_waitForTransitionEnd').and.callFake(() => {});
spyOn(input, 'focus');
spyOn(button, 'focus');
modal.open = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @license
*
* Copyright IBM Corp. 2020
* Copyright IBM Corp. 2020, 2021
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
Expand All @@ -20,6 +20,7 @@ import {
} from 'lit-element';
import ddsSettings from '@carbon/ibmdotcom-utilities/es/utilities/settings/settings.js';
import settings from 'carbon-components/es/globals/js/settings.js';
import on from 'carbon-components/es/globals/js/misc/on';
import { selectorTabbable } from 'carbon-web-components/es/globals/settings.js';
import HostListener from 'carbon-web-components/es/globals/decorators/host-listener.js';
import HostListenerMixin from 'carbon-web-components/es/globals/mixins/host-listener.js';
Expand Down Expand Up @@ -224,6 +225,29 @@ class DDSExpressiveModal extends StableSelectorMixin(HostListenerMixin(LitElemen
}
}

/**
* @param timeout The number of milliseconds as the longest time waiting for `transitionend` event.
* @returns A promise that is resolves when `transitionend` on the host element fires.
*/
private _waitForTransitionEnd(timeout: number = 1000) {
return new Promise(resolve => {
let done = false;
let hTransitionEnd;
const handleResolve = () => {
if (hTransitionEnd) {
hTransitionEnd.release();
hTransitionEnd = null;
}
if (!done) {
resolve(undefined);
done = true;
}
};
on(this, 'transitionend', handleResolve);
setTimeout(handleResolve, timeout);
});
}

/**
* @returns The header content.
*/
Expand Down Expand Up @@ -320,7 +344,7 @@ class DDSExpressiveModal extends StableSelectorMixin(HostListenerMixin(LitElemen
if (this.open) {
this._launcher = this.ownerDocument!.activeElement;
const primaryFocusNode = this.querySelector((this.constructor as typeof DDSExpressiveModal).selectorPrimaryFocus);
await (this.constructor as typeof DDSExpressiveModal)._delay();
await this._waitForTransitionEnd();
if (primaryFocusNode) {
// For cases where a `carbon-web-components` component (e.g. `<bx-btn>`) being `primaryFocusNode`,
// where its first update/render cycle that makes it focusable happens after `<bx-modal>`'s first update/render cycle
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @license
*
* Copyright IBM Corp. 2020
* Copyright IBM Corp. 2020, 2021
*
* This source code is licensed under the Apache-2.0 license found in the
* LICENSE file in the root directory of this source tree.
Expand Down Expand Up @@ -187,6 +187,16 @@ class DDSLocaleModal extends DDSExpressiveModal {
return `${ddsPrefix}-locale-search`;
}

/**
* A selector selecting the nodes that should be focused when modal gets open.
*/
static get selectorPrimaryFocus() {
return `
[data-modal-primary-focus],
${ddsPrefix}-region-item
`;
}

static get stableSelector() {
return `${ddsPrefix}--locale-modal`;
}
Expand Down

0 comments on commit 8e6eb37

Please sign in to comment.