From fe71df1387d62a5884cc82a9624a15fa82f0c71c Mon Sep 17 00:00:00 2001 From: Vivek jain Date: Wed, 21 Feb 2024 10:09:26 +0530 Subject: [PATCH 1/4] feat(dialogv2): made intial changes to add dialogv2 --- apps/storybook/.storybook/manager.js | 2 +- .../components/Dialogv2/dialogv2.styles.ts | 37 ++++++ .../src/components/Dialogv2/dialogv2.tsx | 108 ++++++++++++++++++ .../Dialogv2/story/Dialogv2.stories.tsx | 60 ++++++++++ .../Dialogv2/tests/dialogV2.test.tsx | 70 ++++++++++++ 5 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 packages/react/src/components/Dialogv2/dialogv2.styles.ts create mode 100644 packages/react/src/components/Dialogv2/dialogv2.tsx create mode 100644 packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx create mode 100644 packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx diff --git a/apps/storybook/.storybook/manager.js b/apps/storybook/.storybook/manager.js index a3dfaf47..9240bc59 100644 --- a/apps/storybook/.storybook/manager.js +++ b/apps/storybook/.storybook/manager.js @@ -1,4 +1,4 @@ -import { addons } from '@storybook/addons'; +import { addons } from '@storybook/manager-api'; import theme from './theme'; addons.setConfig({ theme }); diff --git a/packages/react/src/components/Dialogv2/dialogv2.styles.ts b/packages/react/src/components/Dialogv2/dialogv2.styles.ts new file mode 100644 index 00000000..56435101 --- /dev/null +++ b/packages/react/src/components/Dialogv2/dialogv2.styles.ts @@ -0,0 +1,37 @@ +import { pxToRem, styled } from '@project44-manifest/react-styles'; + +export const DialogV2Wrapper = styled('div', { + display: 'flex', + backgroundColor: '$background-primary', + borderRadius: '$small', + boxShadow: '$small', + boxSizing: 'border-box', + flexDirection: 'column', + outline: 0, + padding: '$large', + position: 'relative', + maxHeight: 'calc(100vh - 75px) !important', + overflowY: 'auto', + variants: { + size: { + small: { + width: pxToRem(480), + }, + medium: { + width: pxToRem(640), + }, + large: { + width: pxToRem(960), + }, + }, + edgeToEdge: { + noPadding: { + padding: '0px', + }, + }, + }, + defaultVariants: { + size: 'large', + edgeToEdge: '', + }, +}); diff --git a/packages/react/src/components/Dialogv2/dialogv2.tsx b/packages/react/src/components/Dialogv2/dialogv2.tsx new file mode 100644 index 00000000..c8f0fbe9 --- /dev/null +++ b/packages/react/src/components/Dialogv2/dialogv2.tsx @@ -0,0 +1,108 @@ +import React from 'react'; +import { ForwardRefComponent } from '@project44-manifest/react-types'; +import { DialogElement } from '../Dialog/Dialog.types'; +import { DialogV2Wrapper } from './dialogv2.styles'; +import { DialogHeader } from '../DialogHeader'; +import { DialogContent } from '../DialogContent'; +import { DialogFooter } from '../DialogFooter'; +import { cx } from '@project44-manifest/react-styles'; +import { useMergedRef } from '../../hooks'; +import { useDialog } from '@react-aria/dialog'; +import { DialogProvider } from '../Dialog/Dialog.context'; +import { mergeProps } from '@react-aria/utils'; +import { Modal } from '../Modal'; + +export enum DialogV2Size { + small = 'small', + medium = 'medium', + large = 'large', +} + +export interface DialogV2Props { + isOpen?: boolean; + headerProps: { + title: string; + onClose: () => void; + }; + body: string | React.ReactNode; + footer?: string | React.ReactNode; + isDismissable?: boolean; + isKeyboardDismissDisabled?: boolean; + size?: DialogV2Size; + edgeToEdge?: boolean; +} + +export const DialogV2Impl = React.forwardRef((props, forwardedRef) => { + const { + as, + children, + className: classNameProp, + isDismissable, + headerProps, + body, + footer, + edgeToEdge, + size = DialogV2Size.medium, + ...other + } = props; + + const { title, onClose } = headerProps; + + const dialogRef = React.useRef(null); + const mergedRef = useMergedRef(dialogRef, forwardedRef); + + const { dialogProps, titleProps } = useDialog({ role: 'dialog' }, dialogRef); + + const context = React.useMemo( + () => ({ + isDismissable, + titleProps, + onClose, + }), + [isDismissable, onClose, titleProps], + ); + + const className = cx('manifest-dialog', classNameProp, { + [`manifest-dialog-${size}`]: size, + [`manifest-dialog-edgeToEdge`]: edgeToEdge, + }); + + return ( + + + {title} + {body} + {footer && {footer}} + + + ); +}) as ForwardRefComponent; + +DialogV2Impl.displayName = 'DialogImpl'; + +export const DialogV2 = React.forwardRef((props, forwardedRef) => { + const { isDismissable = true, isKeyboardDismissDisabled = false, isOpen, ...other } = props; + + const { onClose } = other.headerProps; + return ( + + + + ); +}) as ForwardRefComponent; + +DialogV2.displayName = 'DialogV2'; diff --git a/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx b/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx new file mode 100644 index 00000000..d2723d80 --- /dev/null +++ b/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx @@ -0,0 +1,60 @@ +import * as React from 'react'; +import { Meta, StoryFn } from '@storybook/react'; +import { Button } from '../../..'; +import { DialogV2, DialogV2Props, DialogV2Size } from '../dialogv2'; + +const meta: Meta = { + component: DialogV2, + title: 'Components/Dialogv2', + argTypes: { + size: { + options: [DialogV2Size.small, DialogV2Size.medium, DialogV2Size.large], + control: { type: 'radio' }, + }, + }, +}; + +export default meta; + +export const Default: StoryFn = (args: DialogV2Props) => { + const [isOpen, setIsOpen] = React.useState(false); + + const handleClose = React.useCallback(() => void setIsOpen(false), []); + const handleOpen = React.useCallback(() => void setIsOpen(true), []); + + const props: DialogV2Props = { + isOpen: isOpen, + headerProps: { + title: 'Dialog Title', + onClose: handleClose, + }, + body: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt + ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation + ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in + reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur + sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id + est laborum.`, + footer: ( + <> + + + + ), + }; + + return ( + <> + + + + ); +}; + +Default.args = { + isDismissable: true, + isKeyboardDismissDisabled: true, + edgeToEdge: false, + size: DialogV2Size.small, +}; diff --git a/packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx b/packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx new file mode 100644 index 00000000..0e91604f --- /dev/null +++ b/packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx @@ -0,0 +1,70 @@ +import { act, render, screen } from '@testing-library/react'; +import { DialogV2, DialogV2Size } from '../dialogv2'; + +beforeAll(() => { + jest.useFakeTimers(); +}); + +afterEach(() => { + jest.clearAllMocks(); + + act(() => { + jest.runAllTimers(); + }); +}); + +afterAll(() => { + jest.restoreAllMocks(); +}); + +it('should render dialogV2', () => { + let onClose = jest.fn(); + render( + , + ); + + expect(screen.getByTestId('dialogV2Wrapper')).toBeInTheDocument(); +}); + +it('should render footer', () => { + let onClose = jest.fn(); + render( + , + ); + + expect(screen.getByTestId('dialogV2Footer')).toBeInTheDocument(); +}); + +it('should react to size', () => { + let onClose = jest.fn(); + render( + , + ); + expect(screen.getByTestId('dialogV2Wrapper').className.includes('manifest-dialog-small')).toBe( + true, + ); +}); From fdb9cc2d0b87772cd99d58f4bf1318c9510ac069 Mon Sep 17 00:00:00 2001 From: Vivek jain Date: Wed, 21 Feb 2024 10:31:08 +0530 Subject: [PATCH 2/4] feat(dialogv2): made changes to add position property for modal --- .../react/src/components/Dialogv2/dialogv2.tsx | 11 ++++++++++- .../Dialogv2/story/Dialogv2.stories.tsx | 6 ++++++ .../react/src/components/Modal/Modal.styles.ts | 17 +++++++++++++++++ packages/react/src/components/Modal/Modal.tsx | 5 +++-- .../react/src/components/Modal/Modal.types.ts | 10 ++++++++++ 5 files changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/react/src/components/Dialogv2/dialogv2.tsx b/packages/react/src/components/Dialogv2/dialogv2.tsx index c8f0fbe9..28b6f65c 100644 --- a/packages/react/src/components/Dialogv2/dialogv2.tsx +++ b/packages/react/src/components/Dialogv2/dialogv2.tsx @@ -11,6 +11,7 @@ import { useDialog } from '@react-aria/dialog'; import { DialogProvider } from '../Dialog/Dialog.context'; import { mergeProps } from '@react-aria/utils'; import { Modal } from '../Modal'; +import { ModalPosition } from '../Modal/Modal.types'; export enum DialogV2Size { small = 'small', @@ -30,6 +31,7 @@ export interface DialogV2Props { isKeyboardDismissDisabled?: boolean; size?: DialogV2Size; edgeToEdge?: boolean; + position?: ModalPosition; } export const DialogV2Impl = React.forwardRef((props, forwardedRef) => { @@ -89,7 +91,13 @@ export const DialogV2Impl = React.forwardRef((props, forwardedRef) => { DialogV2Impl.displayName = 'DialogImpl'; export const DialogV2 = React.forwardRef((props, forwardedRef) => { - const { isDismissable = true, isKeyboardDismissDisabled = false, isOpen, ...other } = props; + const { + isDismissable = true, + isKeyboardDismissDisabled = false, + isOpen, + position, + ...other + } = props; const { onClose } = other.headerProps; return ( @@ -99,6 +107,7 @@ export const DialogV2 = React.forwardRef((props, forwardedRef) => { isOpen={isOpen} onClose={onClose} data-testid="dialogV2Modal" + position={position} > diff --git a/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx b/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx index d2723d80..f03694fb 100644 --- a/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx +++ b/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Meta, StoryFn } from '@storybook/react'; import { Button } from '../../..'; import { DialogV2, DialogV2Props, DialogV2Size } from '../dialogv2'; +import { ModalPosition } from '../../Modal/Modal.types'; const meta: Meta = { component: DialogV2, @@ -11,6 +12,10 @@ const meta: Meta = { options: [DialogV2Size.small, DialogV2Size.medium, DialogV2Size.large], control: { type: 'radio' }, }, + position: { + options: [ModalPosition.top, ModalPosition.center], + control: { type: 'radio' }, + }, }, }; @@ -57,4 +62,5 @@ Default.args = { isKeyboardDismissDisabled: true, edgeToEdge: false, size: DialogV2Size.small, + position: ModalPosition.top, }; diff --git a/packages/react/src/components/Modal/Modal.styles.ts b/packages/react/src/components/Modal/Modal.styles.ts index 4743dec7..c23102b7 100644 --- a/packages/react/src/components/Modal/Modal.styles.ts +++ b/packages/react/src/components/Modal/Modal.styles.ts @@ -46,6 +46,23 @@ export const StyledModalWrapper = styled('div', { visibility: 'visible', }, }, + position: { + top: { + top: '64px', + inlineSize: 'auto', + left: '0px', + right: '0px', + alignItems: 'flex-start', + }, + center: { + alignItems: 'center', + justifyContent: 'center', + }, + }, + }, + + defaultVariants: { + position: 'top', }, }); diff --git a/packages/react/src/components/Modal/Modal.tsx b/packages/react/src/components/Modal/Modal.tsx index dc6bb4a4..08fc6470 100644 --- a/packages/react/src/components/Modal/Modal.tsx +++ b/packages/react/src/components/Modal/Modal.tsx @@ -6,7 +6,7 @@ import { useMergedRef } from '../../hooks'; import { mergeProps } from '../../utils'; import { Overlay } from '../Overlay'; import { StyledModal, StyledModalWrapper, StyledUnderlay } from './Modal.styles'; -import type { ModalElement, ModalProps } from './Modal.types'; +import { ModalElement, ModalProps, ModalPosition } from './Modal.types'; /** * Modal implementation; Need to initialize the overlay component before calling @@ -24,6 +24,7 @@ const ModalImpl = React.forwardRef((props, forwardedRef) => { isKeyboardDismissDisabled, isOpen, onClose, + position = ModalPosition.top, ...other } = props; @@ -51,7 +52,7 @@ const ModalImpl = React.forwardRef((props, forwardedRef) => { return ( <> - + void; + + /** + * Handles position of modal wrapper + */ + position?: ModalPosition; } From 58e5c9f53ea4a8c50c2fdf5766d7f467e2d9d4bb Mon Sep 17 00:00:00 2001 From: Vivek jain Date: Wed, 21 Feb 2024 11:08:20 +0530 Subject: [PATCH 3/4] feat(dialogv2): added changeset --- .changeset/pretty-bears-nail.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/pretty-bears-nail.md diff --git a/.changeset/pretty-bears-nail.md b/.changeset/pretty-bears-nail.md new file mode 100644 index 00000000..832400aa --- /dev/null +++ b/.changeset/pretty-bears-nail.md @@ -0,0 +1,6 @@ +--- +'storybook-manifest': minor +'@project44-manifest/react': minor +--- + +Added dialog version 2 From 501d0bf1e9278997f0685106943074b7105700a1 Mon Sep 17 00:00:00 2001 From: Vivek jain Date: Wed, 21 Feb 2024 11:19:07 +0530 Subject: [PATCH 4/4] feat(dialogv2): fixed linting errors --- .../src/components/Dialogv2/dialogv2.tsx | 36 +++++++++---------- .../Dialogv2/story/Dialogv2.stories.tsx | 6 ++-- .../Dialogv2/tests/dialogV2.test.tsx | 28 +++++++-------- packages/react/src/components/Modal/Modal.tsx | 2 +- 4 files changed, 35 insertions(+), 37 deletions(-) diff --git a/packages/react/src/components/Dialogv2/dialogv2.tsx b/packages/react/src/components/Dialogv2/dialogv2.tsx index 28b6f65c..f6e30c0a 100644 --- a/packages/react/src/components/Dialogv2/dialogv2.tsx +++ b/packages/react/src/components/Dialogv2/dialogv2.tsx @@ -1,17 +1,17 @@ import React from 'react'; -import { ForwardRefComponent } from '@project44-manifest/react-types'; -import { DialogElement } from '../Dialog/Dialog.types'; -import { DialogV2Wrapper } from './dialogv2.styles'; -import { DialogHeader } from '../DialogHeader'; -import { DialogContent } from '../DialogContent'; -import { DialogFooter } from '../DialogFooter'; +import { useDialog } from '@react-aria/dialog'; +import { mergeProps } from '@react-aria/utils'; import { cx } from '@project44-manifest/react-styles'; +import type { ForwardRefComponent } from '@project44-manifest/react-types'; import { useMergedRef } from '../../hooks'; -import { useDialog } from '@react-aria/dialog'; import { DialogProvider } from '../Dialog/Dialog.context'; -import { mergeProps } from '@react-aria/utils'; +import { DialogElement } from '../Dialog/Dialog.types'; +import { DialogContent } from '../DialogContent'; +import { DialogFooter } from '../DialogFooter'; +import { DialogHeader } from '../DialogHeader'; import { Modal } from '../Modal'; import { ModalPosition } from '../Modal/Modal.types'; +import { DialogV2Wrapper } from './dialogv2.styles'; export enum DialogV2Size { small = 'small', @@ -25,8 +25,8 @@ export interface DialogV2Props { title: string; onClose: () => void; }; - body: string | React.ReactNode; - footer?: string | React.ReactNode; + body: React.ReactNode | string; + footer?: React.ReactNode | string; isDismissable?: boolean; isKeyboardDismissDisabled?: boolean; size?: DialogV2Size; @@ -66,7 +66,7 @@ export const DialogV2Impl = React.forwardRef((props, forwardedRef) => { const className = cx('manifest-dialog', classNameProp, { [`manifest-dialog-${size}`]: size, - [`manifest-dialog-edgeToEdge`]: edgeToEdge, + 'manifest-dialog-edgeToEdge': edgeToEdge, }); return ( @@ -76,13 +76,13 @@ export const DialogV2Impl = React.forwardRef((props, forwardedRef) => { ref={mergedRef} as={as} className={className} - size={size} + data-testid="dialogV2Wrapper" edgeToEdge={edgeToEdge ? 'noPadding' : undefined} - data-testid={'dialogV2Wrapper'} + size={size} > - {title} - {body} - {footer && {footer}} + {title} + {body} + {footer && {footer}} ); @@ -102,12 +102,12 @@ export const DialogV2 = React.forwardRef((props, forwardedRef) => { const { onClose } = other.headerProps; return ( diff --git a/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx b/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx index f03694fb..af105833 100644 --- a/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx +++ b/packages/react/src/components/Dialogv2/story/Dialogv2.stories.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; import { Meta, StoryFn } from '@storybook/react'; import { Button } from '../../..'; -import { DialogV2, DialogV2Props, DialogV2Size } from '../dialogv2'; import { ModalPosition } from '../../Modal/Modal.types'; +import { DialogV2, DialogV2Props, DialogV2Size } from '../dialogv2'; const meta: Meta = { component: DialogV2, @@ -28,7 +28,7 @@ export const Default: StoryFn = (args: DialogV2Props) => { const handleOpen = React.useCallback(() => void setIsOpen(true), []); const props: DialogV2Props = { - isOpen: isOpen, + isOpen, headerProps: { title: 'Dialog Title', onClose: handleClose, @@ -52,7 +52,7 @@ export const Default: StoryFn = (args: DialogV2Props) => { return ( <> - + ); }; diff --git a/packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx b/packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx index 0e91604f..8cb547a7 100644 --- a/packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx +++ b/packages/react/src/components/Dialogv2/tests/dialogV2.test.tsx @@ -18,13 +18,13 @@ afterAll(() => { }); it('should render dialogV2', () => { - let onClose = jest.fn(); + const onClose = jest.fn(); render( , @@ -34,16 +34,16 @@ it('should render dialogV2', () => { }); it('should render footer', () => { - let onClose = jest.fn(); + const onClose = jest.fn(); render( , ); @@ -51,20 +51,18 @@ it('should render footer', () => { }); it('should react to size', () => { - let onClose = jest.fn(); + const onClose = jest.fn(); render( , ); - expect(screen.getByTestId('dialogV2Wrapper').className.includes('manifest-dialog-small')).toBe( - true, - ); + expect(screen.getByTestId('dialogV2Wrapper').className).toContain('manifest-dialog-small'); }); diff --git a/packages/react/src/components/Modal/Modal.tsx b/packages/react/src/components/Modal/Modal.tsx index 08fc6470..f40ce3e2 100644 --- a/packages/react/src/components/Modal/Modal.tsx +++ b/packages/react/src/components/Modal/Modal.tsx @@ -6,7 +6,7 @@ import { useMergedRef } from '../../hooks'; import { mergeProps } from '../../utils'; import { Overlay } from '../Overlay'; import { StyledModal, StyledModalWrapper, StyledUnderlay } from './Modal.styles'; -import { ModalElement, ModalProps, ModalPosition } from './Modal.types'; +import { ModalElement, ModalPosition, ModalProps } from './Modal.types'; /** * Modal implementation; Need to initialize the overlay component before calling