From 5359a54ea89b26af9c15dc6e46ea6e87afba8dd3 Mon Sep 17 00:00:00 2001 From: Yossi Saadi Date: Tue, 24 Sep 2024 14:52:05 +0300 Subject: [PATCH] feat(Modal): modal component with basic functionality (#2417) --- .../ModalNew/Modal/Modal.module.scss | 12 ++++ .../src/components/ModalNew/Modal/Modal.tsx | 54 ++++++++++++++++++ .../components/ModalNew/Modal/Modal.types.tsx | 15 +++++ .../ModalNew/Modal/__tests__/Modal.test.tsx | 56 +++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 packages/core/src/components/ModalNew/Modal/Modal.module.scss create mode 100644 packages/core/src/components/ModalNew/Modal/Modal.tsx create mode 100644 packages/core/src/components/ModalNew/Modal/Modal.types.tsx create mode 100644 packages/core/src/components/ModalNew/Modal/__tests__/Modal.test.tsx diff --git a/packages/core/src/components/ModalNew/Modal/Modal.module.scss b/packages/core/src/components/ModalNew/Modal/Modal.module.scss new file mode 100644 index 0000000000..dc85357ca8 --- /dev/null +++ b/packages/core/src/components/ModalNew/Modal/Modal.module.scss @@ -0,0 +1,12 @@ +.overlay { + position: fixed; + inset: 0; + background-color: rgba(41, 47, 76, 0.7); +} + +.modal { + position: relative; + display: flex; + flex-direction: column; + background-color: var(--primary-background-color); +} diff --git a/packages/core/src/components/ModalNew/Modal/Modal.tsx b/packages/core/src/components/ModalNew/Modal/Modal.tsx new file mode 100644 index 0000000000..edd1eb486e --- /dev/null +++ b/packages/core/src/components/ModalNew/Modal/Modal.tsx @@ -0,0 +1,54 @@ +import React, { forwardRef } from "react"; +import cx from "classnames"; +import { getTestId } from "../../../tests/test-ids-utils"; +import { ComponentDefaultTestId } from "../../../tests/constants"; +import styles from "./Modal.module.scss"; +import { ModalProps } from "./Modal.types"; +import ModalTopActions from "../ModalTopActions/ModalTopActions"; + +const Modal = forwardRef( + ( + { + // Would be implemented in a later PR + // eslint-disable-next-line @typescript-eslint/no-unused-vars + show, + // Would be implemented in a later PR + // eslint-disable-next-line @typescript-eslint/no-unused-vars + size = "medium", + renderHeaderAction, + closeButtonTheme, + closeButtonAriaLabel, + onClose, + children, + className, + id, + "data-testid": dataTestId + }: ModalProps, + ref: React.ForwardedRef + ) => { + return ( +
+ +
+ ); + } +); + +export default Modal; diff --git a/packages/core/src/components/ModalNew/Modal/Modal.types.tsx b/packages/core/src/components/ModalNew/Modal/Modal.types.tsx new file mode 100644 index 0000000000..633549eeb4 --- /dev/null +++ b/packages/core/src/components/ModalNew/Modal/Modal.types.tsx @@ -0,0 +1,15 @@ +import { VibeComponentProps } from "../../../types"; +import React from "react"; +import { ModalTopActionsProps } from "../ModalTopActions/ModalTopActions.types"; + +export type ModalSize = "small" | "medium" | "large"; + +export interface ModalProps extends VibeComponentProps { + show: boolean; + size?: ModalSize; + closeButtonTheme?: ModalTopActionsProps["color"]; + closeButtonAriaLabel?: ModalTopActionsProps["closeButtonAriaLabel"]; + onClose?: ModalTopActionsProps["onClose"]; + renderHeaderAction?: ModalTopActionsProps["renderAction"]; + children: React.ReactNode; +} diff --git a/packages/core/src/components/ModalNew/Modal/__tests__/Modal.test.tsx b/packages/core/src/components/ModalNew/Modal/__tests__/Modal.test.tsx new file mode 100644 index 0000000000..559b192f17 --- /dev/null +++ b/packages/core/src/components/ModalNew/Modal/__tests__/Modal.test.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import { render, fireEvent } from "@testing-library/react"; +import Modal from "../Modal"; + +describe("Modal", () => { + const closeButtonAriaLabel = "Close modal"; + const childrenContent = My content; + + it("renders the modal with the correct role", () => { + const { getByTestId } = render( + + {childrenContent} + + ); + + expect(getByTestId("modal")).toHaveAttribute("role", "dialog"); + }); + + it("renders the modal with the correct aria-modal", () => { + const { getByTestId } = render( + + {childrenContent} + + ); + + expect(getByTestId("modal")).toHaveAttribute("aria-modal", "true"); + }); + + it("renders the children content correctly", () => { + const { getByText } = render( + + {childrenContent} + + ); + + expect(getByText("My content")).toBeInTheDocument(); + }); + + it("calls onClose when the close button is clicked", () => { + const mockOnClose = jest.fn(); + const { getByLabelText } = render( + + {childrenContent} + + ); + + fireEvent.click(getByLabelText(closeButtonAriaLabel)); + expect(mockOnClose).toHaveBeenCalled(); + }); + + it.todo("does not render when 'show' is false"); + + it.todo("renders the correct aria-labelledby"); + + it.todo("renders the correct aria-describedby"); +});