Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
5 changes: 5 additions & 0 deletions .changeset/itchy-experts-relax.md
Original file line number Diff line number Diff line change
@@ -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'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, one more thing. I think we should also add some tests in the types behave as expected block that verifies you can pass an ID and that the href is not accepted.

Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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 (
<ConfirmationModal
title="Title text"
buttonText="Confirm"
open={open}
onConfirm={confirmSpy}
cancelButtonProps={{
onClick: handleClose,
}}
>
Content text
</ConfirmationModal>
);
};

const { getByText, getByRole } = render(<TestWrapper />);

const button = getByText('Cancel');
const modal = getByRole('dialog');
expect(button).toBeVisible();
expect(modal).toBeVisible();

// Click the button - the component's handleCancel doesn't pass the event,
// 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', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -9,11 +9,18 @@ export const Variant = {
export type Variant = (typeof Variant)[keyof typeof Variant];

interface CustomButtonOnClick {
onClick?: () => void;
onClick?: (args?: MouseEvent | KeyboardEvent) => void;
}
type CustomConfirmButtonProps = Omit<BaseButtonProps, 'variant' | 'onClick'> &

// Exclude anchor types (where href is required) to ensure buttons render as buttons
type ButtonOnlyProps = Omit<
Exclude<ButtonProps<'button'>, { href: string }>,
'onClick' | 'as'
>;

type CustomConfirmButtonProps = Omit<ButtonOnlyProps, 'variant'> &
CustomButtonOnClick;
type CustomCancelButtonProps = Omit<BaseButtonProps, 'onClick' | 'children'> &
type CustomCancelButtonProps = Omit<ButtonOnlyProps, 'children'> &
CustomButtonOnClick;

export interface ConfirmationModalProps extends Omit<ModalProps, 'size'> {
Expand Down
Loading