diff --git a/.changeset/itchy-experts-relax.md b/.changeset/itchy-experts-relax.md new file mode 100644 index 0000000000..d3c15fd34a --- /dev/null +++ b/.changeset/itchy-experts-relax.md @@ -0,0 +1,5 @@ +--- +'@leafygreen-ui/confirmation-modal': minor +--- + +Updated Button types to use ButtonProps instead of BaseButtonProps to extend props that can be passed in, such as 'id' diff --git a/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.spec.tsx b/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.spec.tsx index 4eb5609bdb..1cda01f2a7 100644 --- a/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.spec.tsx +++ b/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.spec.tsx @@ -6,7 +6,7 @@ import { axe } from 'jest-axe'; import { getLgIds as getLgModalIds } from '@leafygreen-ui/modal'; import { getLgIds } from '..'; -import ConfirmationModal from '..'; +import { ConfirmationModal } from '..'; const lgIds = getLgIds(); @@ -110,7 +110,7 @@ describe('packages/confirmation-modal', () => { }); // TODO: remove - buttonText is deprecated - test('overrides "confirmButtonProps"', () => { + test('overrides deprecated "buttonText" with "confirmButtonProps"', () => { const { getByText } = renderModal({ open: true, buttonText: 'custom button text', @@ -201,6 +201,72 @@ describe('packages/confirmation-modal', () => { expect(confirmSpy).not.toHaveBeenCalled(); expect(cancelSpy).toHaveBeenCalledTimes(1); }); + + test('closes modal when `handleClose` sets state to false', async () => { + const confirmSpy = jest.fn(); + const handleCloseSpy = jest.fn((_e?: MouseEvent | KeyboardEvent) => {}); + + const TestWrapper = () => { + const [open, setOpen] = useState(true); + + const handleClose = (e?: MouseEvent | KeyboardEvent) => { + handleCloseSpy(e); + setOpen(false); + }; + + return ( + + Content text + + ); + }; + + const { getByText, getByRole } = render(); + + const button = getByText('Cancel'); + const modal = getByRole('dialog'); + expect(button).toBeVisible(); + expect(modal).toBeVisible(); + + // Click the button - the event is not passed to the `onCancel` callback + // but we verify the function is called + userEvent.click(button); + expect(confirmSpy).not.toHaveBeenCalled(); + expect(handleCloseSpy).toHaveBeenCalledTimes(1); + expect(handleCloseSpy).toHaveBeenCalledWith(undefined); + + // Verify that the function signature accepts MouseEvent by calling it directly + const mockMouseEvent = new MouseEvent('click', { bubbles: true }); + handleCloseSpy.mockClear(); + handleCloseSpy(mockMouseEvent); + expect(handleCloseSpy).toHaveBeenCalledWith(mockMouseEvent); + + await waitFor(() => expect(modal).not.toBeVisible()); + }); + }); + + describe('button id props', () => { + test('propagates to the buttons', () => { + const { getByText } = renderModal({ + open: true, + confirmButtonProps: { id: 'my-confirm-btn', children: 'Confirm' }, + cancelButtonProps: { id: 'my-cancel-btn' }, + }); + + const confirmButton = getByText('Confirm').closest('button'); + expect(confirmButton).toHaveAttribute('id', 'my-confirm-btn'); + + const cancelButton = getByText('Cancel').closest('button'); + expect(cancelButton).toHaveAttribute('id', 'my-cancel-btn'); + }); }); describe('closes when', () => { @@ -585,6 +651,29 @@ describe('packages/confirmation-modal', () => { > Hey + + + Hey + + + + Hey + ; }); }); diff --git a/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.types.ts b/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.types.ts index 45722a1df1..c8f21804c1 100644 --- a/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.types.ts +++ b/packages/confirmation-modal/src/ConfirmationModal/ConfirmationModal.types.ts @@ -1,4 +1,4 @@ -import { BaseButtonProps } from '@leafygreen-ui/button'; +import { ButtonProps } from '@leafygreen-ui/button'; import { ModalProps } from '@leafygreen-ui/modal'; export const Variant = { @@ -11,9 +11,16 @@ export type Variant = (typeof Variant)[keyof typeof Variant]; interface CustomButtonOnClick { onClick?: () => void; } -type CustomConfirmButtonProps = Omit & + +// Exclude anchor types (where href is required) to ensure buttons render as buttons +type ButtonOnlyProps = Omit< + Exclude, { href: string }>, + 'onClick' | 'as' +>; + +type CustomConfirmButtonProps = Omit & CustomButtonOnClick; -type CustomCancelButtonProps = Omit & +type CustomCancelButtonProps = Omit & CustomButtonOnClick; export interface ConfirmationModalProps extends Omit {