diff --git a/packages/ncids-js/src/components/usa-modal/__tests__/modal.events.test.ts b/packages/ncids-js/src/components/usa-modal/__tests__/modal.events.test.ts index c5341a18c..6fa2a1dcf 100644 --- a/packages/ncids-js/src/components/usa-modal/__tests__/modal.events.test.ts +++ b/packages/ncids-js/src/components/usa-modal/__tests__/modal.events.test.ts @@ -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); }); }); diff --git a/packages/ncids-js/src/components/usa-modal/event-details/modal.close.esc.event-details.ts b/packages/ncids-js/src/components/usa-modal/event-details/modal.close.esc.event-details.ts deleted file mode 100644 index dc32b4f18..000000000 --- a/packages/ncids-js/src/components/usa-modal/event-details/modal.close.esc.event-details.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ModalEventDetails } from './modal.event-details'; - -/** - * Custom event details for the `modal:close.esc` event. - */ -export type ModalCloseEscEventDetails = ModalEventDetails & { - target: HTMLElement; -}; diff --git a/packages/ncids-js/src/components/usa-modal/event-details/modal.close.event-details.ts b/packages/ncids-js/src/components/usa-modal/event-details/modal.close.event-details.ts index 2cfeea6d8..3f583552a 100644 --- a/packages/ncids-js/src/components/usa-modal/event-details/modal.close.event-details.ts +++ b/packages/ncids-js/src/components/usa-modal/event-details/modal.close.event-details.ts @@ -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; }; diff --git a/packages/ncids-js/src/components/usa-modal/event-details/modal.close.outside.event-details.ts b/packages/ncids-js/src/components/usa-modal/event-details/modal.close.outside.event-details.ts deleted file mode 100644 index 875fc7125..000000000 --- a/packages/ncids-js/src/components/usa-modal/event-details/modal.close.outside.event-details.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ModalEventDetails } from './modal.event-details'; - -/** - * Custom event details for the `modal:close.outside` event. - */ -export type ModalCloseOutsideEventDetails = ModalEventDetails & { - target: HTMLElement; -}; diff --git a/packages/ncids-js/src/components/usa-modal/event-details/modal.event-details.ts b/packages/ncids-js/src/components/usa-modal/event-details/modal.event-details.ts index f9cf83af5..f67e603a5 100644 --- a/packages/ncids-js/src/components/usa-modal/event-details/modal.event-details.ts +++ b/packages/ncids-js/src/components/usa-modal/event-details/modal.event-details.ts @@ -4,4 +4,5 @@ export type ModalEventDetails = { /** The `.usa-modal` element. */ modal: HTMLElement; + target: HTMLElement; }; diff --git a/packages/ncids-js/src/components/usa-modal/event-details/modal.open.event-details.ts b/packages/ncids-js/src/components/usa-modal/event-details/modal.open.event-details.ts deleted file mode 100644 index 5b71c3568..000000000 --- a/packages/ncids-js/src/components/usa-modal/event-details/modal.open.event-details.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ModalEventDetails } from './modal.event-details'; - -/** - * Custom event details for the `modal:open` event. - */ -export type ModalOpenEventDetails = ModalEventDetails & { - target: HTMLElement; -}; diff --git a/packages/ncids-js/src/components/usa-modal/index.ts b/packages/ncids-js/src/components/usa-modal/index.ts index 43fdf44b1..b15acf59a 100644 --- a/packages/ncids-js/src/components/usa-modal/index.ts +++ b/packages/ncids-js/src/components/usa-modal/index.ts @@ -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 }; diff --git a/packages/ncids-js/src/components/usa-modal/modal.component.ts b/packages/ncids-js/src/components/usa-modal/modal.component.ts index 5fdab6a4b..2961a2985 100644 --- a/packages/ncids-js/src/components/usa-modal/modal.component.ts +++ b/packages/ncids-js/src/components/usa-modal/modal.component.ts @@ -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: * @@ -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 @@ -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. */ @@ -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. */ @@ -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. @@ -419,7 +424,7 @@ export class USAModal { this.modal.dispatchEvent( new CustomEvent('usa-modal:open', { bubbles: true, - detail: { + detail: { modal: this.modal, target: mouseEvent.target, }, @@ -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: { - 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: { + modal: this.modal, + target: evt.target as HTMLElement, + closeAction: closeAction, + }, + }) + ); } /** @@ -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: { - modal: this.modal, - target: mouseEvent.target, - }, - }) - ); } } @@ -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: { - target: keyboardEvent.target, - }, - }) - ); } break; diff --git a/testing/ncids-css-testing/src/stories/components/usa-modal/usa-modal.default.stories.jsx b/testing/ncids-css-testing/src/stories/components/usa-modal/usa-modal.default.stories.jsx index bd58c65fa..4d524c7ca 100644 --- a/testing/ncids-css-testing/src/stories/components/usa-modal/usa-modal.default.stories.jsx +++ b/testing/ncids-css-testing/src/stories/components/usa-modal/usa-modal.default.stories.jsx @@ -8,7 +8,9 @@ export default { title: 'Components/Modal/Default', component: Component, parameters: { - ncidsInitJs: () => USAModal.createAll(), + ncidsInitJs: () => { + USAModal.createAll(); + }, css, }, };