Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,12 @@ describe('USA Modal - Events', () => {

const overlay = document.querySelectorAll('.usa-modal-overlay');
await user.click(overlay[0]);
await expect(ModalCloseOverlayEvent).toHaveBeenCalledTimes(1);
await expect(modalClosedEvent).toHaveBeenCalledTimes(2);

await user.click(openers[0]);
await expect(modalOpenedEvent).toHaveBeenCalledTimes(3);

await user.keyboard('[Escape]');
await expect(ModalCloseEscapeEvent).toHaveBeenCalledTimes(1);
await expect(modalClosedEvent).toHaveBeenCalledTimes(3);
});
});

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { ModalEventDetails } from './modal.event-details';

export enum ModalCloseAction {
KEY_ESCAPE = 'escape',
CLICK_OUTSIDE = 'outside',
CLOSE_BUTTON = 'close',
FOOTER_BUTTON = 'footer',
OTHER_BUTTON = 'other',
}

/**
* Custom event details for the `modal:close` event.
*/
export type ModalCloseEventDetails = ModalEventDetails & {
target: HTMLElement;
closeAction?: ModalCloseAction;
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
export type ModalEventDetails = {
/** The `.usa-modal` element. */
modal: HTMLElement;
target: HTMLElement;
};

This file was deleted.

11 changes: 1 addition & 10 deletions packages/ncids-js/src/components/usa-modal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,5 @@ export { USAModal } from './modal.component';

import type { ModalEventDetails } from './event-details/modal.event-details';
import type { ModalCloseEventDetails } from './event-details/modal.close.event-details';
import type { ModalCloseOutsideEventDetails } from './event-details/modal.close.outside.event-details';
import type { ModalCloseEscEventDetails } from './event-details/modal.close.esc.event-details';
import type { ModalOpenEventDetails } from './event-details/modal.open.event-details';

export type {
ModalEventDetails,
ModalCloseEventDetails,
ModalCloseOutsideEventDetails,
ModalCloseEscEventDetails,
ModalOpenEventDetails,
};
export type { ModalEventDetails, ModalCloseEventDetails };
89 changes: 47 additions & 42 deletions packages/ncids-js/src/components/usa-modal/modal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* import '@nciocpl/ncids-js/usa-modal/auto-init';
* ```
*
* ## Advanced Options
* ## Advanced Options
* If you need access to the modal instance to further customize your site,
* you can manually initialize the modal:
*
Expand Down Expand Up @@ -81,9 +81,8 @@
*
* // add handleModalOpen to button or link
* modalElements.addEventListener('click', (e) => modal.handleModalOpen(e), false);
*
*
* ```
*
* ## HTML Events
*
* The modal component will dispatch the following
Expand All @@ -93,8 +92,6 @@
*
* - `usa-modal:open`: Dispatched when the modal is opened. Includes details about the modal and the triggering element.
* - `usa-modal:close`: Dispatched when the modal is closed from an element with the `data-close-modal` attribute.
* - `usa-modal:close:outside`: Dispatched when the modal is closed by clicking outside the modal (on the overlay).
* - `usa-modal:close:escape`: Dispatched when the modal is closed by pressing the Escape key.
*
* These events provide hooks for integrating with analytics or other JavaScript logic to enhance user interaction tracking.
*/
Expand All @@ -104,10 +101,9 @@ import { ModalContent } from './modal-content';
import { ModalButtons } from './modal-buttons';
import { FocusTrap } from '../../utils/focus-trap';
import { scrollbarWidth } from './utils/scrollbar-width';
import { ModalOpenEventDetails } from './event-details/modal.open.event-details';
import { ModalEventDetails } from './event-details/modal.event-details';
import { ModalCloseEventDetails } from './event-details/modal.close.event-details';
import { ModalCloseOutsideEventDetails } from './event-details/modal.close.outside.event-details';
import { ModalCloseEscEventDetails } from './event-details/modal.close.esc.event-details';
import { ModalCloseAction } from './event-details/modal.close.event-details';

export class USAModal {
/** The .usa-modal element. */
Expand Down Expand Up @@ -243,6 +239,15 @@ export class USAModal {
USAModal._components.set(this.modal, this);
}

/**
* Gets the modal HTMLElement.
*
* @returns The modal HTMLElement.
*/
public getModalElement(): HTMLElement {
return this.modal;
}

/**
* Configures the modal wrapper element with necessary attributes for accessibility.
* This includes setting ARIA attributes and ensuring the wrapper is visible.
Expand Down Expand Up @@ -419,7 +424,7 @@ export class USAModal {
this.modal.dispatchEvent(
new CustomEvent('usa-modal:open', {
bubbles: true,
detail: <ModalOpenEventDetails>{
detail: <ModalEventDetails>{
modal: this.modal,
target: mouseEvent.target,
},
Expand All @@ -434,20 +439,37 @@ export class USAModal {
*/
public handleModalClose(event: Event): void {
const mouseEvent = event as MouseEvent;
// Make sure we're only clicking on the close element
if (mouseEvent.target == mouseEvent.currentTarget) {
this.deActivateModal();

this.modal.dispatchEvent(
new CustomEvent('usa-modal:close', {
bubbles: true,
detail: <ModalCloseEventDetails>{
modal: this.modal,
target: mouseEvent.target,
},
})
);
// Check which button was clicked, close or footer buttons
const closeButton = mouseEvent.currentTarget as HTMLElement;
// Determine what button was clicked to close the modal
if (closeButton.classList.contains('usa-modal__close')) {
// If the close button was clicked
this.dispatchCloseEvent(ModalCloseAction.CLOSE_BUTTON, event);
} else if (closeButton.closest('.usa-modal__footer')) {
// If the button that was clicked was in the modal footer
this.dispatchCloseEvent(ModalCloseAction.FOOTER_BUTTON, event);
} else {
// Other button inside the modal (like a custom button in the content)
this.dispatchCloseEvent(ModalCloseAction.OTHER_BUTTON, event);
}
this.deActivateModal();
}

private dispatchCloseEvent(
closeAction: ModalCloseAction,
event: Event
): void {
const evt = event as Event;
this.modal.dispatchEvent(
new CustomEvent('usa-modal:close', {
bubbles: true,
detail: <ModalCloseEventDetails>{
modal: this.modal,
target: evt.target as HTMLElement,
closeAction: closeAction,
},
})
);
}

/**
Expand All @@ -457,19 +479,10 @@ export class USAModal {
*/
private handleModalCloseOutside(event: Event): void {
const mouseEvent = event as MouseEvent;
// Make sure we're only clicking on the close element
// Make sure we're only clicking on the overlay element
if (mouseEvent.target == mouseEvent.currentTarget) {
this.dispatchCloseEvent(ModalCloseAction.CLICK_OUTSIDE, event);
this.deActivateModal();

this.modal.dispatchEvent(
new CustomEvent('usa-modal:close:outside', {
bubbles: true,
detail: <ModalCloseOutsideEventDetails>{
modal: this.modal,
target: mouseEvent.target,
},
})
);
}
}

Expand All @@ -487,16 +500,8 @@ export class USAModal {
Dismisses the modal if it is visible.
*/
if (this.modal) {
this.dispatchCloseEvent(ModalCloseAction.KEY_ESCAPE, event);
this.deActivateModal();

this.modal.dispatchEvent(
new CustomEvent('usa-modal:close:escape', {
bubbles: true,
detail: <ModalCloseEscEventDetails>{
target: keyboardEvent.target,
},
})
);
}

break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export default {
title: 'Components/Modal/Default',
component: Component,
parameters: {
ncidsInitJs: () => USAModal.createAll(),
ncidsInitJs: () => {
USAModal.createAll();
},
css,
},
};
Expand Down