Skip to content

Commit

Permalink
feat(dialog): leverage Overlay v2
Browse files Browse the repository at this point in the history
  • Loading branch information
Westbrook committed Aug 18, 2023
1 parent 67b5d1b commit 5c21ab5
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 115 deletions.
1 change: 0 additions & 1 deletion packages/dialog/src/Dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,6 @@ export class Dialog extends FocusVisiblePolyfillMixin(

public override connectedCallback(): void {
super.connectedCallback();
this.tabIndex = 0;
window.addEventListener(
'resize',
this.shouldManageTabOrderForScrolling
Expand Down
28 changes: 19 additions & 9 deletions packages/dialog/src/DialogBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import '@spectrum-web-components/underlay/sp-underlay.js';
import '@spectrum-web-components/button/sp-button.js';

// Leveraged in build systems that use aliasing to prevent multiple registrations: https://github.com/adobe/spectrum-web-components/pull/3225
import '@spectrum-web-components/dialog/sp-dialog.js'
import '@spectrum-web-components/dialog/sp-dialog.js';
import modalWrapperStyles from '@spectrum-web-components/modal/src/modal-wrapper.css.js';
import modalStyles from '@spectrum-web-components/modal/src/modal.css.js';
import { Dialog } from './Dialog.js';
Expand Down Expand Up @@ -89,7 +89,6 @@ export class DialogBase extends FocusVisiblePolyfillMixin(SpectrumElement) {
await firstFocusable.updateComplete;
}
firstFocusable.focus();
this.removeAttribute('tabindex');
} else {
this.dialog.focus();
}
Expand Down Expand Up @@ -131,19 +130,27 @@ export class DialogBase extends FocusVisiblePolyfillMixin(SpectrumElement) {
);
}

private handleTransitionEvent(event: TransitionEvent): void {
this.dispatchEvent(
new TransitionEvent(event.type, {
bubbles: true,
composed: true,
propertyName: event.propertyName,
})
);
}

protected handleUnderlayTransitionend(event: TransitionEvent): void {
if (!this.open && event.propertyName === 'visibility') {
this.resolveTransitionPromise();
this.dispatchClosed();
}
this.handleTransitionEvent(event);
}

protected handleModalTransitionend(): void {
protected handleModalTransitionend(event: TransitionEvent): void {
if (this.open || !this.underlay) {
this.resolveTransitionPromise();
if (!this.open) {
this.dispatchClosed();
}
this.handleTransitionEvent(event);
}
}

Expand All @@ -156,6 +163,9 @@ export class DialogBase extends FocusVisiblePolyfillMixin(SpectrumElement) {
res();
};
});
if (!this.open) {
this.dispatchClosed();
}
}
super.update(changes);
}
Expand All @@ -173,12 +183,14 @@ export class DialogBase extends FocusVisiblePolyfillMixin(SpectrumElement) {
<sp-underlay
?open=${this.open}
@click=${this.dismiss}
@transitionrun=${this.handleTransitionEvent}
@transitionend=${this.handleUnderlayTransitionend}
></sp-underlay>
`
: html``}
<div
class="modal ${this.mode}"
@transitionrun=${this.handleTransitionEvent}
@transitionend=${this.handleModalTransitionend}
@close=${this.handleClose}
>
Expand All @@ -198,8 +210,6 @@ export class DialogBase extends FocusVisiblePolyfillMixin(SpectrumElement) {
this.dialog.shouldManageTabOrderForScrolling();
});
}
} else {
this.tabIndex = 0;
}
}
}
Expand Down
67 changes: 38 additions & 29 deletions packages/dialog/stories/dialog-base.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
Expand All @@ -14,32 +13,31 @@ import { html, TemplateResult } from '@spectrum-web-components/base';
import '@spectrum-web-components/dialog/sp-dialog-base.js';
import '@spectrum-web-components/dialog/sp-dialog.js';
import '@spectrum-web-components/button/sp-button.js';
import '@spectrum-web-components/overlay/overlay-trigger.js';
import '@spectrum-web-components/overlay/sp-overlay.js';
import '@spectrum-web-components/checkbox/sp-checkbox.js';
import { alertDestructive } from './dialog.stories.js';
import { portrait } from './images.js';
import { overlayTriggerDecorator } from './index.js';

export default {
title: 'Dialog Base',
component: 'sp-dialog-base',
decorators: [
(story: () => TemplateResult): TemplateResult => html`
<overlay-trigger type="modal" open="click" placement="none">
<sp-button slot="trigger" variant="primary">
(story: () => TemplateResult): TemplateResult => {
return html`
<sp-button variant="primary" id="trigger">
Toggle Dialog
</sp-button>
${story()}
</overlay-trigger>
`,
overlayTriggerDecorator,
<sp-overlay type="modal" trigger="trigger@click" open>
${story()}
</sp-overlay>
`;
},
],
};

export const Slotted = (): TemplateResult => html`
<sp-dialog-base
underlay
slot="click-content"
@click=${(event: Event) => {
if ((event.target as HTMLElement).localName === 'sp-button') {
(event.target as HTMLElement).dispatchEvent(
Expand All @@ -56,29 +54,37 @@ export const disabledButton = (): TemplateResult => {
return html`
<sp-dialog-base
underlay
slot="click-content"
@click=${(event: Event) => {
if ((event.target as HTMLElement).localName === 'sp-button') {
(event.target as HTMLElement).dispatchEvent(
new Event('close', { bubbles: true, composed: true })
);
}
}}
.overlayOpenCallback=${() => {
setTimeout(() => {
(
document.querySelector(
'#changing-header'
) as HTMLElement
).textContent = 'The button in this dialog is now enabled';
@sp-opened=${() => {
let count = 5;
const timer = setInterval(() => {
count -= 1;
if (!count) {
(
document.querySelector(
'#changing-header'
) as HTMLElement
).textContent =
'The button in this dialog is now enabled';
(
document.querySelector(
'#changing-button'
) as HTMLButtonElement
).disabled = false;
clearInterval(timer);
}
(
document.querySelector(
'#changing-button'
) as HTMLButtonElement
).disabled = false;
}, 5000);
document.querySelector('.time') as HTMLElement
).textContent = count.toString();
}, 1000);
}}
.overlayCloseCallback=${() => {
@close=${() => {
(
document.querySelector('#changing-header') as HTMLElement
).textContent = 'The button in this dialog is disabled';
Expand All @@ -87,13 +93,19 @@ export const disabledButton = (): TemplateResult => {
'#changing-button'
) as HTMLButtonElement
).disabled = true;
(document.querySelector('.time') as HTMLElement).textContent =
'5';
}}
>
<sp-dialog size="s">
<h2 slot="heading" id="changing-header">
The button in this dialog is disabled
</h2>
<p>After about 5 seconds the button with be enabled.</p>
<p>
After about
<span class="time">5</span>
seconds the button with be enabled.
</p>
<sp-button disabled slot="button" id="changing-button">
Ok
</sp-button>
Expand All @@ -105,7 +117,6 @@ export const disabledButton = (): TemplateResult => {
export const notAgain = (): TemplateResult => html`
<sp-dialog-base
underlay
slot="click-content"
@click=${(event: Event) => {
if ((event.target as HTMLElement).localName === 'sp-button') {
(event.target as HTMLElement).dispatchEvent(
Expand All @@ -132,7 +143,6 @@ export const notAgain = (): TemplateResult => html`
export const moreCustom = (): TemplateResult => html`
<sp-dialog-base
underlay
slot="click-content"
@click=${(event: Event) => {
if ((event.target as HTMLElement).localName === 'sp-button') {
(event.target as HTMLElement).dispatchEvent(
Expand Down Expand Up @@ -179,7 +189,6 @@ export const moreCustom = (): TemplateResult => html`
export const fullyCustom = (): TemplateResult => html`
<sp-dialog-base
underlay
slot="click-content"
@click=${(event: Event) => {
if ((event.target as HTMLElement).localName === 'button') {
(event.target as HTMLElement).dispatchEvent(
Expand Down
4 changes: 2 additions & 2 deletions packages/dialog/stories/dialog-wrapper.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,12 @@ export const wrapperDismissable = (
return html`
<sp-dialog-wrapper
?open=${open}
hero=${landscape}
.hero=${landscape}
dismissable
headline="Wrapped Dialog w/ Hero Image"
@close=${handleClose(args)}
size="s"
tabindex="0"
>
Content of the dialog
</sp-dialog-wrapper>
Expand Down Expand Up @@ -260,7 +261,6 @@ export const longContent = (
return html`
<overlay-trigger
type="modal"
placement="none"
@close=${handleClose(args)}
open=${ifDefined(open)}
>
Expand Down
35 changes: 15 additions & 20 deletions packages/dialog/test/dialog-base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ governing permissions and limitations under the License.
*/

import {
aTimeout,
elementUpdated,
expect,
fixture,
html,
nextFrame,
oneEvent,
} from '@open-wc/testing';
import { TemplateResult } from '@spectrum-web-components/base';
Expand All @@ -42,14 +42,14 @@ async function styledFixture<T extends Element>(
}

const overlayTrigger = (story: () => TemplateResult): TemplateResult => html`
<overlay-trigger type="modal" placement="none">
<overlay-trigger type="modal">
<sp-button slot="trigger" variant="primary">Toggle Dialog</sp-button>
${story()}
</overlay-trigger>
`;

describe('dialog base', () => {
it('does not close by default with interacting with buttons', async () => {
it('does not close by default when interacting with buttons', async () => {
const el = await styledFixture<OverlayTrigger>(
overlayTrigger(
() => html`
Expand All @@ -72,36 +72,32 @@ describe('dialog base', () => {

expect(el.open).to.be.undefined;
expect(dialog.open).to.be.false;
expect(dialog.parentElement?.localName).to.equal('overlay-trigger');
await nextFrame();
const opened = oneEvent(el, 'sp-opened');
el.open = 'click';
await opened;
await nextFrame();

expect(dialog.open).to.be.true;
expect(el.open).to.be.equal('click');
expect(dialog.parentElement?.localName).to.equal('active-overlay');

secondaryButton.click();
// Give time to ensure reactions DO NOT close the dialog.
await aTimeout(100);

expect(el.open).to.be.equal('click');
expect(dialog.parentElement?.localName).to.equal('active-overlay');

negativeButton.click();
// Give time to ensure reactions DO NOT close the dialog.
await aTimeout(100);

expect(el.open).to.be.equal('click');
expect(dialog.parentElement?.localName).to.equal('active-overlay');

const closed = oneEvent(el, 'sp-closed');
el.open = undefined;
dialog.open = false;
await closed;
await elementUpdated(el);

expect(dialog.open).to.be.false;
expect(el.open).to.be.undefined;
expect(dialog.parentElement?.localName).to.equal('overlay-trigger');
});
it('does not close by default with interacting with buttons when recycled', async () => {
it('does not close by default when interacting with buttons when recycled', async () => {
const el = await styledFixture<OverlayTrigger>(
overlayTrigger(
() => html`
Expand All @@ -124,26 +120,25 @@ describe('dialog base', () => {

expect(el.open).to.be.undefined;
expect(dialog.open).to.be.false;
expect(dialog.parentElement?.localName).to.equal('overlay-trigger');
await nextFrame();
const opened = oneEvent(el, 'sp-opened');
el.open = 'click';
await opened;
await nextFrame();

expect(dialog.open).to.be.true;
expect(el.open).to.be.equal('click');
expect(dialog.parentElement?.localName).to.equal('active-overlay');

secondaryButton.click();
// Give time to ensure reactions DO NOT close the dialog.
await aTimeout(100);

expect(el.open).to.be.equal('click');
expect(dialog.parentElement?.localName).to.equal('active-overlay');

negativeButton.click();
// Give time to ensure reactions DO NOT close the dialog.
await aTimeout(100);

expect(el.open).to.be.equal('click');
expect(dialog.parentElement?.localName).to.equal('active-overlay');

const closed = oneEvent(el, 'sp-closed');
dialog.open = false;
await closed;
Expand Down
Loading

0 comments on commit 5c21ab5

Please sign in to comment.