Add confirm() method to DialogController

Like hide(), but dispatches an event to indicate that the dialog was 'confirmed'
pull/12185/head
Sage Abdullah 2024-07-01 14:13:56 +01:00 zatwierdzone przez Thibaud Colas
rodzic 1c2616623d
commit 3e6e4f2ee3
2 zmienionych plików z 79 dodań i 4 usunięć

Wyświetl plik

@ -103,6 +103,70 @@ describe('DialogController', () => {
expect(document.documentElement.style.overflowY).toBe('');
});
it('should support the ability to confirm the dialog with an event to indicate the confirmation', async () => {
const hiddenListener = jest.fn();
document.addEventListener('w-dialog:hidden', hiddenListener);
const confirmedListener = jest.fn();
document.addEventListener('w-dialog:confirmed', confirmedListener);
// Add a confirm button to the dialog
const dialogBody = document.getElementById('dialog-body');
const confirmButton = document.createElement('button');
confirmButton.type = 'button';
confirmButton.setAttribute('data-action', 'w-dialog#confirm');
dialogBody.appendChild(confirmButton);
application.start();
await Promise.resolve();
expect(hiddenListener).not.toHaveBeenCalled();
expect(confirmedListener).not.toHaveBeenCalled();
const dialog = document.getElementById('dialog-container');
// closed by default
expect(dialog.getAttribute('aria-hidden')).toEqual('true');
expect(document.documentElement.style.overflowY).toBe('');
// show the dialog manually
dialog.dispatchEvent(new CustomEvent('w-dialog:show'));
expect(dialog.getAttribute('aria-hidden')).toEqual(null);
expect(hiddenListener).not.toHaveBeenCalled();
expect(confirmedListener).not.toHaveBeenCalled();
// add style to root element on shown by default
expect(document.documentElement.style.overflowY).toBe('hidden');
// hide the dialog using the confirm button
confirmButton.click();
expect(dialog.getAttribute('aria-hidden')).toEqual('true');
// w-dialog:hide event should still be dispatched
expect(hiddenListener).toHaveBeenCalledWith(
expect.objectContaining({
detail: expect.objectContaining({
body: dialogBody,
dialog: expect.any(Object),
}),
}),
);
// reset style on root element when hidden by default
expect(document.documentElement.style.overflowY).toBe('');
// w-dialog:confirmed event should be dispatched
expect(confirmedListener).toHaveBeenCalledWith(
expect.objectContaining({
detail: expect.objectContaining({
body: dialogBody,
dialog: expect.any(Object),
}),
}),
);
});
it('should support the ability use a theme to avoid document style change', async () => {
const dialog = document.getElementById('dialog-container');

Wyświetl plik

@ -29,14 +29,17 @@ export class DialogController extends Controller<HTMLElement> {
/** Optional targets that will be dispatched events for key dialog events. */
declare readonly notifyTargets: HTMLElement[];
get eventDetail() {
return { body: this.bodyTarget, dialog: this.dialog };
}
connect() {
this.dialog = new A11yDialog(this.element);
const detail = { body: this.bodyTarget, dialog: this.dialog };
const isFloating = this.themeValue === FLOATING;
this.dialog
.on('show', () => {
if (!isFloating) document.documentElement.style.overflowY = 'hidden';
this.dispatch('shown', { detail, cancelable: false });
this.dispatch('shown', { detail: this.eventDetail, cancelable: false });
this.notifyTargets.forEach((target) => {
this.dispatch('shown', {
target,
@ -47,7 +50,10 @@ export class DialogController extends Controller<HTMLElement> {
})
.on('hide', () => {
if (!isFloating) document.documentElement.style.overflowY = '';
this.dispatch('hidden', { detail, cancelable: false });
this.dispatch('hidden', {
detail: this.eventDetail,
cancelable: false,
});
this.notifyTargets.forEach((target) => {
this.dispatch('hidden', {
target,
@ -56,7 +62,7 @@ export class DialogController extends Controller<HTMLElement> {
});
});
});
this.dispatch('ready', { detail });
this.dispatch('ready', { detail: this.eventDetail });
if (this.notifyTargets && Array.isArray(this.notifyTargets)) {
this.notifyTargets.forEach((target) => {
this.dispatch('ready', { target, bubbles: false, cancelable: false });
@ -72,4 +78,9 @@ export class DialogController extends Controller<HTMLElement> {
show() {
this.dialog.show();
}
confirm() {
this.hide();
this.dispatch('confirmed', { detail: this.eventDetail, cancelable: false });
}
}