diff --git a/packages/core/src/components/DialogBox/Actions/Actions.tsx b/packages/core/src/components/DialogBox/Actions/Actions.tsx deleted file mode 100644 index 7b779df06..000000000 --- a/packages/core/src/components/DialogBox/Actions/Actions.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { WithStyle } from '@medly-components/utils'; -import type { FC } from 'react'; -import { memo, useContext } from 'react'; -import { DialogBoxContext } from '../DialogBox.context'; -import * as Styled from './Actions.styled'; -import { DialogBoxActionUserProps } from './types'; - -const Component: FC = memo(({ children, alignItems }) => { - const { id } = useContext(DialogBoxContext); - - return {children}; -}); -Component.displayName = 'Actions'; -export const Actions: FC & WithStyle = Object.assign(Component, { Style: Styled.Actions }); diff --git a/packages/core/src/components/DialogBox/Actions/index.ts b/packages/core/src/components/DialogBox/Actions/index.ts deleted file mode 100644 index c7fa68f81..000000000 --- a/packages/core/src/components/DialogBox/Actions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Actions as default } from './Actions'; diff --git a/packages/core/src/components/DialogBox/DialogBox.stories.mdx b/packages/core/src/components/DialogBox/DialogBox.stories.mdx index 91067beff..5c6b7101d 100644 --- a/packages/core/src/components/DialogBox/DialogBox.stories.mdx +++ b/packages/core/src/components/DialogBox/DialogBox.stories.mdx @@ -6,7 +6,7 @@ import * as stories from './DialogBox.stories'; # DialogBox -`DialogBox` are windows that appear in front of app content to give critical information, request a decision, or involve multiple tasks. It consists of a Header, Content, and Action. +`DialogBox` are windows that appear in front of app content to give critical information, request a decision, or involve multiple tasks. It consists of a Header, Content, and Action. You can play with the component in the canvas tab. @@ -16,13 +16,13 @@ You can play with the component in the canvas tab. - + - + ``` -Shadow appears on the Header and Actions section if you scroll through the content. +Shadow appears on the Header and Footer section if you scroll through the content. To close the dialog box, you can either: diff --git a/packages/core/src/components/DialogBox/DialogBox.stories.tsx b/packages/core/src/components/DialogBox/DialogBox.stories.tsx index ec75ea002..e51665cb7 100644 --- a/packages/core/src/components/DialogBox/DialogBox.stories.tsx +++ b/packages/core/src/components/DialogBox/DialogBox.stories.tsx @@ -1,16 +1,16 @@ import { defaultTheme, DialogBoxTheme } from '@medly-components/theme'; +import type { FC } from 'react'; import { useCallback, useState } from 'react'; import Button from '../Button'; -import { DialogBoxActionUserProps } from './Actions/types'; import { DialogBox } from './DialogBox'; -import type { FC } from 'react'; +import { DialogBoxFooterProps } from './Footer/types'; export const ThemeInterface: FC = () => null; ThemeInterface.defaultProps = { ...defaultTheme.modal }; -export const DialogBoxActionProps: FC = () => null; +export const DialogBoxActionProps: FC = () => null; DialogBoxActionProps.defaultProps = { alignItems: 'right' }; @@ -23,18 +23,18 @@ export const Basic = () => { return ( <> - + Are you sure? Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - + - + ); diff --git a/packages/core/src/components/DialogBox/DialogBox.test.tsx b/packages/core/src/components/DialogBox/DialogBox.test.tsx index 431572f08..7d20f9a3a 100644 --- a/packages/core/src/components/DialogBox/DialogBox.test.tsx +++ b/packages/core/src/components/DialogBox/DialogBox.test.tsx @@ -4,14 +4,14 @@ import { DialogBoxProps } from './types'; const dialogBoxRenderer = ({ open = false, - onCloseModal = jest.fn(), + onClose = jest.fn(), minWidth, minHeight, shouldCloseOnOutsideClick = false, showCloseIcon = false }: DialogBoxProps) => render( - +

Demo Header

@@ -22,7 +22,7 @@ const dialogBoxRenderer = ({ popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum - Demo Actions + Demo Footer
); @@ -42,38 +42,38 @@ describe('DialogBox component', () => { expect(container).toBeEmptyDOMElement(); }); - it('should call onCloseModal on pressing escape key', () => { - const mockOnCloseModal = jest.fn(); - const { container } = dialogBoxRenderer({ open: true, onCloseModal: mockOnCloseModal }); + it('should call onClose on pressing escape key', () => { + const mockOnClose = jest.fn(); + const { container } = dialogBoxRenderer({ open: true, onClose: mockOnClose }); fireEvent.keyDown(container, { key: 'Escape', code: 27 }); - expect(mockOnCloseModal).toBeCalled(); + expect(mockOnClose).toBeCalled(); }); - it('should call onCloseModal on click on overlay background', () => { - const mockOnCloseModal = jest.fn(); - const { container } = dialogBoxRenderer({ open: true, onCloseModal: mockOnCloseModal, shouldCloseOnOutsideClick: true }); + it('should call onClose on click on overlay background', () => { + const mockOnClose = jest.fn(); + const { container } = dialogBoxRenderer({ open: true, onClose: mockOnClose, shouldCloseOnOutsideClick: true }); fireEvent.click(container.querySelector('#medly-dialog-box') as HTMLDivElement); - expect(mockOnCloseModal).toBeCalled(); + expect(mockOnClose).toBeCalled(); }); it('should be able to render any JSX element in header', () => { - const mockOnCloseModal = jest.fn(); + const mockOnClose = jest.fn(); const { container } = render( - + Demo Header Demo Content - +

Demo Header

-
+
); expect(container.querySelector('p')).toBeInTheDocument(); }); - it('should call onCloseModal on click on close icon', () => { - const mockOnCloseModal = jest.fn(); - dialogBoxRenderer({ open: true, onCloseModal: mockOnCloseModal, shouldCloseOnOutsideClick: true, showCloseIcon: true }); + it('should call onClose on click on close icon', () => { + const mockOnClose = jest.fn(); + dialogBoxRenderer({ open: true, onClose: mockOnClose, shouldCloseOnOutsideClick: true, showCloseIcon: true }); fireEvent.click(screen.getByTestId('medly-dialog-box-close-button') as HTMLElement); - expect(mockOnCloseModal).toBeCalled(); + expect(mockOnClose).toBeCalled(); }); }); diff --git a/packages/core/src/components/DialogBox/DialogBox.tsx b/packages/core/src/components/DialogBox/DialogBox.tsx index aad19ef20..6580643ea 100644 --- a/packages/core/src/components/DialogBox/DialogBox.tsx +++ b/packages/core/src/components/DialogBox/DialogBox.tsx @@ -1,35 +1,25 @@ import { useCombinedRefs, useKeyPress, WithStyle } from '@medly-components/utils'; -import { memo, forwardRef, useRef, useCallback, useEffect, useState } from 'react'; -import Actions from './Actions'; +import type { FC } from 'react'; +import { forwardRef, memo, useCallback, useEffect, useRef, useState } from 'react'; +import CloseIcon from '../Modal/CloseIcon'; import Content from './Content'; import { DialogBoxContext } from './DialogBox.context'; import { DialogBoxBackgroundStyled } from './DialogBox.styled'; +import Footer from './Footer'; import Header from './Header'; import Popup from './Popup'; import { DialogBoxProps, DialogBoxStaticProps } from './types'; -import type { FC } from 'react'; -import CloseIcon from '../Modal/CloseIcon'; const Component: FC = memo( forwardRef((props, ref) => { - const { - id, - open, - onCloseModal, - children, - minWidth, - shouldCloseOnOutsideClick, - minHeight, - showCloseIcon = false, - ...restProps - } = props, + const { id, open, onClose, children, minWidth, shouldCloseOnOutsideClick, minHeight, showCloseIcon = false, ...restProps } = props, isEscPressed = useKeyPress('Escape'), dialogBoxRef = useCombinedRefs(ref, useRef(null)), [shouldRender, setShouldRender] = useState(open); const handleBackgroundClick = useCallback(() => { - shouldCloseOnOutsideClick && onCloseModal && onCloseModal(); - }, [shouldCloseOnOutsideClick, onCloseModal]); + shouldCloseOnOutsideClick && onClose && onClose(); + }, [shouldCloseOnOutsideClick, onClose]); useEffect(() => { if (open) { @@ -49,12 +39,12 @@ const Component: FC = memo( }, [open]); useEffect(() => { - open && isEscPressed && onCloseModal && onCloseModal(); + open && isEscPressed && onClose && onClose(); }, [open, isEscPressed]); const handleCloseModal = useCallback(() => { - onCloseModal && onCloseModal(); - }, [onCloseModal]); + onClose && onClose(); + }, [onClose]); return shouldRender ? ( @@ -88,5 +78,5 @@ export const DialogBox: FC & WithStyle & DialogBoxStaticProps = Header, Popup, Content, - Actions + Footer }); diff --git a/packages/core/src/components/DialogBox/Actions/Actions.styled.tsx b/packages/core/src/components/DialogBox/Footer/Footer.styled.tsx similarity index 80% rename from packages/core/src/components/DialogBox/Actions/Actions.styled.tsx rename to packages/core/src/components/DialogBox/Footer/Footer.styled.tsx index 5d044b350..c881d9972 100644 --- a/packages/core/src/components/DialogBox/Actions/Actions.styled.tsx +++ b/packages/core/src/components/DialogBox/Footer/Footer.styled.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; -import { DialogBoxActionUserProps } from './types'; +import { DialogBoxFooterProps } from './types'; -export const Actions = styled('div')` +export const Footer = styled('div')` display: flex; z-index: 10; margin-top: 3rem; @@ -28,6 +28,6 @@ export const Actions = styled('div')` } } `; -Actions.defaultProps = { +Footer.defaultProps = { alignItems: 'right' }; diff --git a/packages/core/src/components/DialogBox/Actions/Actions.test.tsx b/packages/core/src/components/DialogBox/Footer/Footer.test.tsx similarity index 61% rename from packages/core/src/components/DialogBox/Actions/Actions.test.tsx rename to packages/core/src/components/DialogBox/Footer/Footer.test.tsx index b51055166..9800c6a3b 100644 --- a/packages/core/src/components/DialogBox/Actions/Actions.test.tsx +++ b/packages/core/src/components/DialogBox/Footer/Footer.test.tsx @@ -1,16 +1,16 @@ import { render } from '@test-utils'; -import { Actions } from './Actions'; -import { DialogBoxActionUserProps } from './types'; +import { Footer } from './Footer'; +import { DialogBoxFooterProps } from './types'; describe('DialogBox action component', () => { - const testData: [DialogBoxActionUserProps['alignItems'], string][] = [ + const testData: [DialogBoxFooterProps['alignItems'], string][] = [ ['left', 'flex-start'], ['center', 'center'], ['right', 'flex-end'] ]; test.each(testData)('should align actions properly when align-items props is %s', (alignItems, flexValue) => { - const { container } = render(Demo Actions); + const { container } = render(
Demo Footer
); expect(container.querySelector('#default-id-actions')).toHaveStyle(`justify-content: ${flexValue}`); }); }); diff --git a/packages/core/src/components/DialogBox/Footer/Footer.tsx b/packages/core/src/components/DialogBox/Footer/Footer.tsx new file mode 100644 index 000000000..5192377db --- /dev/null +++ b/packages/core/src/components/DialogBox/Footer/Footer.tsx @@ -0,0 +1,14 @@ +import { WithStyle } from '@medly-components/utils'; +import type { FC } from 'react'; +import { memo, useContext } from 'react'; +import { DialogBoxContext } from '../DialogBox.context'; +import * as Styled from './Footer.styled'; +import { DialogBoxFooterProps } from './types'; + +const Component: FC = memo(({ children, alignItems }) => { + const { id } = useContext(DialogBoxContext); + + return {children}; +}); +Component.displayName = 'Footer'; +export const Footer: FC & WithStyle = Object.assign(Component, { Style: Styled.Footer }); diff --git a/packages/core/src/components/DialogBox/Footer/index.ts b/packages/core/src/components/DialogBox/Footer/index.ts new file mode 100644 index 000000000..467bde316 --- /dev/null +++ b/packages/core/src/components/DialogBox/Footer/index.ts @@ -0,0 +1 @@ +export { Footer as default } from './Footer'; diff --git a/packages/core/src/components/DialogBox/Actions/types.ts b/packages/core/src/components/DialogBox/Footer/types.ts similarity index 70% rename from packages/core/src/components/DialogBox/Actions/types.ts rename to packages/core/src/components/DialogBox/Footer/types.ts index 718458874..6a8c7e923 100644 --- a/packages/core/src/components/DialogBox/Actions/types.ts +++ b/packages/core/src/components/DialogBox/Footer/types.ts @@ -1,4 +1,4 @@ -export type DialogBoxActionUserProps = { +export type DialogBoxFooterProps = { /** Use this to align actions horizontally */ alignItems?: 'left' | 'center' | 'right'; }; diff --git a/packages/core/src/components/DialogBox/__snapshots__/DialogBox.test.tsx.snap b/packages/core/src/components/DialogBox/__snapshots__/DialogBox.test.tsx.snap index 908c59770..d2d006054 100644 --- a/packages/core/src/components/DialogBox/__snapshots__/DialogBox.test.tsx.snap +++ b/packages/core/src/components/DialogBox/__snapshots__/DialogBox.test.tsx.snap @@ -1,33 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`DialogBox component should render properly when it is open 1`] = ` -.c4 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - z-index: 10; - margin-top: 3rem; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - -ms-flex-pack: end; - justify-content: flex-end; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; -} - -.c4 > * { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - -ms-flex-positive: 1; - flex-grow: 1; -} - -.c4 > * + * { - margin: 1.6rem 0 0; -} - .c3 { -webkit-flex: 1; -ms-flex: 1; @@ -60,6 +33,33 @@ exports[`DialogBox component should render properly when it is open 1`] = ` overflow: hidden; } +.c4 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + z-index: 10; + margin-top: 3rem; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} + +.c4 > * { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c4 > * + * { + margin: 1.6rem 0 0; +} + .c2 { background-color: #ffffff; color: #13181D; @@ -153,7 +153,7 @@ exports[`DialogBox component should render properly when it is open 1`] = ` class="c4" id="medly-dialog-box-actions" > - Demo Actions + Demo Footer @@ -161,31 +161,63 @@ exports[`DialogBox component should render properly when it is open 1`] = ` `; exports[`DialogBox component should render properly with close icon when it is open 1`] = ` -.c6 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - z-index: 10; - margin-top: 3rem; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - -ms-flex-pack: end; - justify-content: flex-end; - -webkit-flex-direction: column; - -ms-flex-direction: column; - flex-direction: column; +.c2 { + overflow: visible; + font-size: 2.4rem; + -webkit-transition: all 100ms linear; + transition: all 100ms linear; + cursor: pointer; + padding: 0.8rem; + border-radius: 50%; + background-color: #EBF1FA; } -.c6 > * { - -webkit-box-flex: 1; - -webkit-flex-grow: 1; - -ms-flex-positive: 1; - flex-grow: 1; +.c2 * { + fill-opacity: 1; + -webkit-transition: all 100ms linear; + transition: all 100ms linear; + fill: #607890; } -.c6 > * + * { - margin: 1.6rem 0 0; +.c3 { + -webkit-transform: translate3d(0,0,0); + -ms-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + -webkit-perspective: 1000; + -moz-perspective: 1000; + -ms-perspective: 1000; + perspective: 1000; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + top: 1.4rem; + right: 1.4rem; + z-index: 20; + position: absolute; + border-radius: 50%; + border: none; + background-color: #ffffff; +} + +.c3 * { + fill: #607890; +} + +.c3:hover { + background-color: #eff2f4; + box-shadow: 0 2px 8px rgba(239,242,244,0.5); +} + +.c3:hover * { + fill: #607890; +} + +.c3:active { + background-color: #dfe4e9; + box-shadow: none; +} + +.c3:active * { + fill: #435465; } .c5 { @@ -220,6 +252,33 @@ exports[`DialogBox component should render properly with close icon when it is o overflow: hidden; } +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + z-index: 10; + margin-top: 3rem; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} + +.c6 > * { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c6 > * + * { + margin: 1.6rem 0 0; +} + .c4 { background-color: #ffffff; color: #13181D; @@ -248,65 +307,6 @@ exports[`DialogBox component should render properly with close icon when it is o animation: slideIn 0.4s cubic-bezier(0,0,0.33,1); } -.c2 { - overflow: visible; - font-size: 2.4rem; - -webkit-transition: all 100ms linear; - transition: all 100ms linear; - cursor: pointer; - padding: 0.8rem; - border-radius: 50%; - background-color: #EBF1FA; -} - -.c2 * { - fill-opacity: 1; - -webkit-transition: all 100ms linear; - transition: all 100ms linear; - fill: #607890; -} - -.c3 { - -webkit-transform: translate3d(0,0,0); - -ms-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); - -webkit-perspective: 1000; - -moz-perspective: 1000; - -ms-perspective: 1000; - perspective: 1000; - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - top: 1.4rem; - right: 1.4rem; - z-index: 20; - position: absolute; - border-radius: 50%; - border: none; - background-color: #ffffff; -} - -.c3 * { - fill: #607890; -} - -.c3:hover { - background-color: #eff2f4; - box-shadow: 0 2px 8px rgba(239,242,244,0.5); -} - -.c3:hover * { - fill: #607890; -} - -.c3:active { - background-color: #dfe4e9; - box-shadow: none; -} - -.c3:active * { - fill: #435465; -} - @media (min-width:600px) { .c6 { -webkit-flex-direction: row; @@ -389,7 +389,7 @@ exports[`DialogBox component should render properly with close icon when it is o class="c6" id="medly-dialog-box-actions" > - Demo Actions + Demo Footer diff --git a/packages/core/src/components/DialogBox/types.ts b/packages/core/src/components/DialogBox/types.ts index 667109231..bd29b2147 100644 --- a/packages/core/src/components/DialogBox/types.ts +++ b/packages/core/src/components/DialogBox/types.ts @@ -1,13 +1,13 @@ import { HTMLProps, WithStyle } from '@medly-components/utils'; -import { DialogBoxActionUserProps } from './Actions/types'; -import { DialogBoxPopupProps } from './Popup/types'; import type { FC } from 'react'; +import { DialogBoxFooterProps } from './Footer/types'; +import { DialogBoxPopupProps } from './Popup/types'; export interface DialogBoxProps extends HTMLProps { /** Shows modal only when this prop is true */ open?: boolean; /** Function to be called on closing modal */ - onCloseModal?: () => void; + onClose?: () => void; /** Min width in px/rem/% (1rem = 10px) */ minWidth?: string; /** Min height in px/rem/% (1rem = 10px) */ @@ -26,7 +26,7 @@ export interface DialogBoxStaticProps { Popup: FC & WithStyle; Header: FC & WithStyle; Content: FC & WithStyle; - Actions: FC & WithStyle; + Footer: FC & WithStyle; } export interface DialogBoxContextType { id: string; diff --git a/packages/core/src/components/Drawer/types.ts b/packages/core/src/components/Drawer/types.ts index 30219a3ee..22b8689ab 100644 --- a/packages/core/src/components/Drawer/types.ts +++ b/packages/core/src/components/Drawer/types.ts @@ -1,13 +1,18 @@ import { HTMLProps, WithStyle } from '@medly-components/utils'; +import type { Dispatch, FC } from 'react'; import { ScrollActionTypes } from '../Modal/scrollStateReducer/types'; import { DrawerFooterProps } from './Footer/types'; -import type { FC, Dispatch } from 'react'; export interface DrawerProps extends HTMLProps { + /** Shows drawer only when this prop is true */ open?: boolean; + /** Position of the drawer*/ position?: 'left' | 'right'; + /** Function to be called on closing drawer */ onClose: () => void; + /** Width of the drawer */ width?: string; + /** set it true to show it with the overlay */ withOverlay?: boolean; } diff --git a/packages/core/src/components/Modal/Actions/Actions.tsx b/packages/core/src/components/Modal/Actions/Actions.tsx deleted file mode 100644 index d4161d79a..000000000 --- a/packages/core/src/components/Modal/Actions/Actions.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { WithStyle } from '@medly-components/utils'; -import { useContext, memo } from 'react'; -import { ModalContext } from '../Modal.context'; -import * as Styled from './Actions.styled'; -import { ModalActionUserProps } from './types'; -import type { FC } from 'react'; - -const Component: FC = memo(({ children, alignItems }) => { - const { id, scrollState, isSmallScreen } = useContext(ModalContext); - - return {children}; -}); -Component.displayName = 'Actions'; -export const Actions: FC & WithStyle = Object.assign(Component, { Style: Styled.Actions }); diff --git a/packages/core/src/components/Modal/Actions/index.ts b/packages/core/src/components/Modal/Actions/index.ts deleted file mode 100644 index c7fa68f81..000000000 --- a/packages/core/src/components/Modal/Actions/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { Actions as default } from './Actions'; diff --git a/packages/core/src/components/Modal/Actions/Actions.styled.tsx b/packages/core/src/components/Modal/Footer/Footer.styled.tsx similarity index 93% rename from packages/core/src/components/Modal/Actions/Actions.styled.tsx rename to packages/core/src/components/Modal/Footer/Footer.styled.tsx index 1d70c3151..cbd3de534 100644 --- a/packages/core/src/components/Modal/Actions/Actions.styled.tsx +++ b/packages/core/src/components/Modal/Footer/Footer.styled.tsx @@ -3,7 +3,7 @@ import { rgba } from 'polished'; import styled from 'styled-components'; import { StyledProps } from './types'; -export const Actions = styled('div')` +export const Footer = styled('div')` display: flex; z-index: 10; padding: ${({ theme }) => `${theme.spacing.S4} ${theme.spacing.M2} ${theme.spacing.M2}`}; @@ -26,6 +26,6 @@ export const Actions = styled('div')` } `} `; -Actions.defaultProps = { +Footer.defaultProps = { alignItems: 'right' }; diff --git a/packages/core/src/components/Modal/Actions/Actions.test.tsx b/packages/core/src/components/Modal/Footer/Footer.test.tsx similarity index 61% rename from packages/core/src/components/Modal/Actions/Actions.test.tsx rename to packages/core/src/components/Modal/Footer/Footer.test.tsx index 311f041c4..a9129dd91 100644 --- a/packages/core/src/components/Modal/Actions/Actions.test.tsx +++ b/packages/core/src/components/Modal/Footer/Footer.test.tsx @@ -1,8 +1,8 @@ import { render } from '@test-utils'; -import { Actions } from './Actions'; -import { ModalActionUserProps } from './types'; +import { Footer } from './Footer'; +import { ModalFooterProps } from './types'; -const testData: [ModalActionUserProps['alignItems'], string][] = [ +const testData: [ModalFooterProps['alignItems'], string][] = [ ['left', 'flex-start'], ['center', 'center'], ['right', 'flex-end'] @@ -10,7 +10,7 @@ const testData: [ModalActionUserProps['alignItems'], string][] = [ describe('Modal action component', () => { test.each(testData)('should align actions properly when align-items props is %s', (alignItems, flexValue) => { - const { container } = render(Demo Actions); + const { container } = render(
Demo Footer
); expect(container.querySelector('#default-id-actions')).toHaveStyle(`justify-content: ${flexValue}`); }); }); diff --git a/packages/core/src/components/Modal/Footer/Footer.tsx b/packages/core/src/components/Modal/Footer/Footer.tsx new file mode 100644 index 000000000..d13d4c0e0 --- /dev/null +++ b/packages/core/src/components/Modal/Footer/Footer.tsx @@ -0,0 +1,14 @@ +import { WithStyle } from '@medly-components/utils'; +import type { FC } from 'react'; +import { memo, useContext } from 'react'; +import { ModalContext } from '../Modal.context'; +import * as Styled from './Footer.styled'; +import { ModalFooterProps } from './types'; + +const Component: FC = memo(({ children, alignItems }) => { + const { id, scrollState, isSmallScreen } = useContext(ModalContext); + + return {children}; +}); +Component.displayName = 'Footer'; +export const Footer: FC & WithStyle = Object.assign(Component, { Style: Styled.Footer }); diff --git a/packages/core/src/components/Modal/Footer/index.ts b/packages/core/src/components/Modal/Footer/index.ts new file mode 100644 index 000000000..467bde316 --- /dev/null +++ b/packages/core/src/components/Modal/Footer/index.ts @@ -0,0 +1 @@ +export { Footer as default } from './Footer'; diff --git a/packages/core/src/components/Modal/Actions/types.ts b/packages/core/src/components/Modal/Footer/types.ts similarity index 67% rename from packages/core/src/components/Modal/Actions/types.ts rename to packages/core/src/components/Modal/Footer/types.ts index 13b7a086a..d13a197ad 100644 --- a/packages/core/src/components/Modal/Actions/types.ts +++ b/packages/core/src/components/Modal/Footer/types.ts @@ -1,11 +1,11 @@ import { ScrollState } from '../types'; -export type ModalActionUserProps = { +export type ModalFooterProps = { /** Use this to align actions horizontally */ alignItems?: 'left' | 'center' | 'right'; }; -export interface StyledProps extends ModalActionUserProps { +export interface StyledProps extends ModalFooterProps { isSmallScreen: boolean; scrollState: ScrollState; } diff --git a/packages/core/src/components/Modal/Modal.stories.mdx b/packages/core/src/components/Modal/Modal.stories.mdx index c64d9c6a5..8afc6f1bf 100644 --- a/packages/core/src/components/Modal/Modal.stories.mdx +++ b/packages/core/src/components/Modal/Modal.stories.mdx @@ -7,7 +7,7 @@ import * as stories from './Modal.stories'; # Modal The `Modal` components is a separate windows within an application that is overlaid on the primary window. The contents behind a modal dialog are inert, meaning you cannot interact with the content behind the dialog. It is a common user interface pattern that provides information or requires confirmation. -It consists of a Header, Content, and Actions. You can play with the component in the canvas tab. +It consists of a Header, Content, and Footer. You can play with the component in the canvas tab. ```tsx import { Modal } from '@medly-components/core'; @@ -22,14 +22,14 @@ export const DummyComponent: React.FC = React.memo(() => { return ( <> - + Add User - + - + ); @@ -40,7 +40,7 @@ DummyComponent.displayName = 'DummyComponent'; ## Shadow Effect -The shadow effect apears on the Header & Actions section if you scroll through the content. +The shadow effect apears on the Header & Footer section if you scroll through the content. ### Keyboard Support diff --git a/packages/core/src/components/Modal/Modal.stories.tsx b/packages/core/src/components/Modal/Modal.stories.tsx index 002999ba5..cdbf88a9d 100644 --- a/packages/core/src/components/Modal/Modal.stories.tsx +++ b/packages/core/src/components/Modal/Modal.stories.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components'; import Button from '../Button'; import Input from '../Input'; import SingleSelect from '../SingleSelect'; -import { ModalActionUserProps } from './Actions/types'; +import { ModalFooterProps } from './Footer/types'; import { Modal } from './Modal'; const options = [ @@ -19,7 +19,7 @@ ThemeInterface.defaultProps = { ...defaultTheme.modal }; -export const ModalActionProps: FC = () => null; +export const ModalActionProps: FC = () => null; ModalActionProps.defaultProps = { alignItems: 'right' }; @@ -43,7 +43,7 @@ export const Basic = () => { return ( - + Add User
@@ -84,9 +84,9 @@ export const Basic = () => { />
- + - +
); diff --git a/packages/core/src/components/Modal/Modal.test.tsx b/packages/core/src/components/Modal/Modal.test.tsx index 0e345125d..e6952290c 100644 --- a/packages/core/src/components/Modal/Modal.test.tsx +++ b/packages/core/src/components/Modal/Modal.test.tsx @@ -5,14 +5,14 @@ import { ModalBackgroundProps, ModalProps } from './types'; const modalRenderer = ({ open = false, - onCloseModal = jest.fn(), + onClose = jest.fn(), minWidth, minHeight, shouldCloseOnOutsideClick = false, disableEscapeKeyDown = false }: ModalProps) => render( - +

Demo Header

@@ -23,7 +23,7 @@ const modalRenderer = ({ popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum - Demo Actions + Demo Footer
); @@ -58,53 +58,53 @@ describe('Modal component', () => { expect(document.body).toHaveStyle({ overflow: 'unset' }); }); - it('should call onCloseModal on click on close icon', () => { - const mockOnCloseModal = jest.fn(); - modalRenderer({ open: true, onCloseModal: mockOnCloseModal }); + it('should call onClose on click on close icon', () => { + const mockOnClose = jest.fn(); + modalRenderer({ open: true, onClose: mockOnClose }); fireEvent.click(screen.getByTitle('medly-modal-close-icon')); - expect(mockOnCloseModal).toBeCalled(); + expect(mockOnClose).toBeCalled(); }); - it('should not call onCloseModal on pressing escape key when disableEscapeKeyDown prop is passed', () => { - const mockOnCloseModal = jest.fn(), - { container } = modalRenderer({ open: true, onCloseModal: mockOnCloseModal, disableEscapeKeyDown: true }), + it('should not call onClose on pressing escape key when disableEscapeKeyDown prop is passed', () => { + const mockOnClose = jest.fn(), + { container } = modalRenderer({ open: true, onClose: mockOnClose, disableEscapeKeyDown: true }), popup = container.querySelector('#medly-modal-popup') as HTMLDivElement; fireEvent.keyDown(popup, { key: 'Escape', code: 27 }); - expect(mockOnCloseModal).not.toBeCalled(); + expect(mockOnClose).not.toBeCalled(); }); - it('should call onCloseModal on pressing escape key', () => { - const mockOnCloseModal = jest.fn(), - { container } = modalRenderer({ open: true, onCloseModal: mockOnCloseModal }), + it('should call onClose on pressing escape key', () => { + const mockOnClose = jest.fn(), + { container } = modalRenderer({ open: true, onClose: mockOnClose }), popup = container.querySelector('#medly-modal-popup') as HTMLDivElement; fireEvent.keyDown(popup, { key: 'Escape', code: 27 }); - expect(mockOnCloseModal).toBeCalled(); + expect(mockOnClose).toBeCalled(); }); - it('should call onCloseModal on click on overlay background', () => { - const mockOnCloseModal = jest.fn(); - const { container } = modalRenderer({ open: true, onCloseModal: mockOnCloseModal, shouldCloseOnOutsideClick: true }); + it('should call onClose on click on overlay background', () => { + const mockOnClose = jest.fn(); + const { container } = modalRenderer({ open: true, onClose: mockOnClose, shouldCloseOnOutsideClick: true }); fireEvent.click(container.querySelector('#medly-modal') as HTMLDivElement); - expect(mockOnCloseModal).toBeCalled(); + expect(mockOnClose).toBeCalled(); }); - it('should not call onCloseModal on click on modal', () => { - const mockOnCloseModal = jest.fn(); - const { container } = modalRenderer({ open: true, onCloseModal: mockOnCloseModal, shouldCloseOnOutsideClick: true }); + it('should not call onClose on click on modal', () => { + const mockOnClose = jest.fn(); + const { container } = modalRenderer({ open: true, onClose: mockOnClose, shouldCloseOnOutsideClick: true }); fireEvent.click(container.querySelector('#medly-modal-popup') as HTMLDivElement); - expect(mockOnCloseModal).not.toBeCalled(); + expect(mockOnClose).not.toBeCalled(); expect(container.querySelector('#medly-modal-popup')).toBeInTheDocument(); }); it('should be able to render any JSX element in header', () => { - const mockOnCloseModal = jest.fn(); + const mockOnClose = jest.fn(); const { container } = render( - + Demo Header Demo Content - +

Demo Header

-
+
); expect(container.querySelector('p')).toBeInTheDocument(); diff --git a/packages/core/src/components/Modal/Modal.tsx b/packages/core/src/components/Modal/Modal.tsx index 0edb06f96..e0b7f2c90 100644 --- a/packages/core/src/components/Modal/Modal.tsx +++ b/packages/core/src/components/Modal/Modal.tsx @@ -1,8 +1,8 @@ import { useCombinedRefs, useKeyPress, useWindowSize, WithStyle } from '@medly-components/utils'; import { FC, forwardRef, memo, MouseEvent, useCallback, useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react'; -import Actions from './Actions'; import CloseIcon from './CloseIcon'; import Content from './Content'; +import Footer from './Footer'; import Header from './Header'; import { ModalContext } from './Modal.context'; import { InnerContainerStyled, ModalBackgroundStyled } from './Modal.styled'; @@ -18,7 +18,7 @@ const Component: FC = memo( forwardRef((props, ref) => { const { open, - onCloseModal, + onClose, overflowVisible, children, minWidth, @@ -40,8 +40,8 @@ const Component: FC = memo( const handleCloseModal = useCallback(() => { if (modalRef.current) manager.remove(modalRef.current); - onCloseModal && onCloseModal(); - }, [onCloseModal, manager]), + onClose && onClose(); + }, [onClose, manager]), handleBackgroundClick = useCallback( (event: MouseEvent) => event.currentTarget === event.target && shouldCloseOnOutsideClick && handleCloseModal(), @@ -118,5 +118,5 @@ export const Modal: FC & WithStyle & ModalStaticProps = Object.assig Header, Popup, Content, - Actions + Footer }); diff --git a/packages/core/src/components/Modal/__snapshots__/Modal.test.tsx.snap b/packages/core/src/components/Modal/__snapshots__/Modal.test.tsx.snap index edd9a9ce3..0c506b37c 100644 --- a/packages/core/src/components/Modal/__snapshots__/Modal.test.tsx.snap +++ b/packages/core/src/components/Modal/__snapshots__/Modal.test.tsx.snap @@ -88,27 +88,6 @@ exports[`Modal component background at small screen size should render properly `; exports[`Modal component should render properly when it is open 1`] = ` -.c7 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - z-index: 10; - padding: 1.6rem 3.2rem 3.2rem; - box-shadow: 0 -1.8rem 1.6rem -1.6rem rgba(176,188,200,0.6); - -webkit-flex-direction: row; - -ms-flex-direction: row; - flex-direction: row; - -webkit-box-pack: end; - -webkit-justify-content: flex-end; - -ms-flex-pack: end; - justify-content: flex-end; -} - -.c7 > * + * { - margin-left: 1.6rem; -} - .c2 { overflow: visible; font-size: 2.4rem; @@ -176,6 +155,27 @@ exports[`Modal component should render properly when it is open 1`] = ` padding: 0.8rem 3.2rem 2.4rem; } +.c7 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + z-index: 10; + padding: 1.6rem 3.2rem 3.2rem; + box-shadow: 0 -1.8rem 1.6rem -1.6rem rgba(176,188,200,0.6); + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.c7 > * + * { + margin-left: 1.6rem; +} + .c5 { box-sizing: border-box; background-color: #ffffff; @@ -259,18 +259,6 @@ exports[`Modal component should render properly when it is open 1`] = ` overflow: hidden; } -@media (max-width:767px) { - .c7 { - padding: 1.6rem; - } -} - -@media (min-width:768px) and (max-height:700px) { - .c7 { - padding: 1.6rem 3.2rem; - } -} - @media (max-width:767px) { .c6 { padding: 0.8rem 1.6rem 2.4rem; @@ -302,6 +290,18 @@ exports[`Modal component should render properly when it is open 1`] = ` } } +@media (max-width:767px) { + .c7 { + padding: 1.6rem; + } +} + +@media (min-width:768px) and (max-height:700px) { + .c7 { + padding: 1.6rem 3.2rem; + } +} + @media (min-width:768px) { .c5 { position: relative; @@ -425,7 +425,7 @@ exports[`Modal component should render properly when it is open 1`] = ` class="c7" id="medly-modal-actions" > - Demo Actions + Demo Footer diff --git a/packages/core/src/components/Modal/types.ts b/packages/core/src/components/Modal/types.ts index 18ce8ed6f..c9137b957 100644 --- a/packages/core/src/components/Modal/types.ts +++ b/packages/core/src/components/Modal/types.ts @@ -1,6 +1,6 @@ import { HTMLProps, WithStyle } from '@medly-components/utils'; import type { Dispatch, FC, RefObject } from 'react'; -import { ModalActionUserProps } from './Actions/types'; +import { ModalFooterProps } from './Footer/types'; import { ModalPopupProps } from './Popup/types'; import { ScrollActionTypes } from './scrollStateReducer/types'; @@ -8,7 +8,7 @@ export interface ModalProps extends HTMLProps { /** Shows modal only when this prop is true */ open?: boolean; /** Function to be called on closing modal */ - onCloseModal?: () => void; + onClose?: () => void; /** Set it true to allow modal overflow to be visible */ overflowVisible?: boolean; /** Min width in px/rem/% (1rem = 10px) */ @@ -34,7 +34,7 @@ export interface ModalStaticProps { Popup: FC & WithStyle; Header: FC & WithStyle; Content: FC & WithStyle; - Actions: FC & WithStyle; + Footer: FC & WithStyle; } export interface InnerContainerProps { diff --git a/packages/core/src/components/SearchBox/SearchBox.stories.mdx b/packages/core/src/components/SearchBox/SearchBox.stories.mdx index aee074bc3..fb7914fe9 100644 --- a/packages/core/src/components/SearchBox/SearchBox.stories.mdx +++ b/packages/core/src/components/SearchBox/SearchBox.stories.mdx @@ -17,11 +17,11 @@ A `SearchBox` or search bar component is a text field which takes your input and {() => { const [options, setOptions] = useState([]), - onInputChangeHandler = value => value.length > 2 && setOptions([...optionsArray, { label: 'Test', value: 'Test' }]); + onChangeHandler = value => value.length > 2 && setOptions([...optionsArray, { label: 'Test', value: 'Test' }]); return ( {() => { const [options, setOptions] = useState([]), - onInputChangeHandler = value => value.length > 2 && setOptions([...optionsArray, { label: 'Test', value: 'Test' }]); + onChangeHandler = value => value.length > 2 && setOptions([...optionsArray, { label: 'Test', value: 'Test' }]); return ( { it('should call onSearch on clicking on search icon with input value', () => { const onSearch = jest.fn(); - const { inputEl } = renderComponent({ onSearch, onInputChange: jest.fn(), placeholder: 'search' }); + const { inputEl } = renderComponent({ onSearch, onChange: jest.fn(), placeholder: 'search' }); fireEvent.change(inputEl, { target: { value: 'R' } }); fireEvent.click(screen.getByTitle('search icon')); expect(onSearch).toHaveBeenCalledWith('R'); @@ -41,7 +41,7 @@ describe('SearchBox', () => { it('should call onSearch on pressing enter key with the input value', () => { const onSearch = jest.fn(), - withOptionCB = { placeholder: 'search', onInputChange: jest.fn(), onSearch }; + withOptionCB = { placeholder: 'search', onChange: jest.fn(), onSearch }; const { container, inputEl } = renderComponent(withOptionCB); fireEvent.focus(inputEl); @@ -52,7 +52,7 @@ describe('SearchBox', () => { it('should call onClear on clicking on clear icon', () => { const onClear = jest.fn(), - { container, inputEl } = renderComponent({ placeholder: 'search', onInputChange: jest.fn(), onClear }); + { container, inputEl } = renderComponent({ placeholder: 'search', onChange: jest.fn(), onClear }); fireEvent.change(inputEl, { target: { value: 'Dummy' } }); fireEvent.keyDown(container, { key: 'Enter', code: 13 }); fireEvent.click(screen.getByTitle('close icon')); @@ -63,7 +63,7 @@ describe('SearchBox', () => { describe('close icon', () => { const props = { placeholder: 'search', - onInputChange: jest.fn() + onChange: jest.fn() }; it('should render close icon when user provides initial value', () => { @@ -159,7 +159,7 @@ describe('SearchBox', () => { const defaultReturnObj = { target: { value: 'Dummy' } }; const props = { placeholder: 'search', - onInputChange: jest.fn(), + onChange: jest.fn(), options: [ { label: 'Dummy 1', value: 'Dummy 1' }, { label: 'Dummy 2', value: 'Dummy 2' } diff --git a/packages/core/src/components/SearchBox/SearchBox.tsx b/packages/core/src/components/SearchBox/SearchBox.tsx index 48b4d2af7..f7cd2beb4 100644 --- a/packages/core/src/components/SearchBox/SearchBox.tsx +++ b/packages/core/src/components/SearchBox/SearchBox.tsx @@ -18,7 +18,7 @@ const Component: FC = memo( options: defaultOptions, size, placeholder, - onInputChange, + onChange, onOptionSelected, onClear, onSearch, @@ -74,7 +74,7 @@ const Component: FC = memo( const { value } = event.target; updateIsTyping(value.length !== 0); setShowCloseIcon(value.length !== 0); - onInputChange && onInputChange(value); + onChange && onChange(value); }, []), handleOptionClick = useCallback( (option: Option) => { diff --git a/packages/core/src/components/SearchBox/types.ts b/packages/core/src/components/SearchBox/types.ts index 814a46359..d973598cc 100644 --- a/packages/core/src/components/SearchBox/types.ts +++ b/packages/core/src/components/SearchBox/types.ts @@ -14,7 +14,7 @@ export type WrapperProps = { areOptionsVisible?: boolean; }; -export interface SearchBoxProps extends Omit, 'size'> { +export interface SearchBoxProps extends Omit, 'size' | 'onChange'> { /** Size for search box can be 'S' | 'M' */ size?: Size; /** Option for search results in form of label and value */ @@ -38,7 +38,7 @@ export interface SearchBoxProps extends Omit, 'size' /** Function to be called on selecting the option */ onOptionSelected?: (value: Option) => void; /** Function to be called on input value changes */ - onInputChange?: (value: string) => void; + onChange?: (value: string) => void; } export type StyledSearchBoxProps = SearchBoxProps & {