From 7805321e4b630c14855375eb242f5a4f90f7fdd1 Mon Sep 17 00:00:00 2001 From: Boima Konuwa Date: Sun, 28 Mar 2021 16:29:58 -0400 Subject: [PATCH 1/8] feat: Add Modal component --- example/src/App.js | 5 + src/components/Modal/Modal.module.css | 129 +++++++++++++++ src/components/Modal/Modal.test.tsx | 57 +++++++ src/components/Modal/Modal.tsx | 160 ++++++++++++++++++ src/components/Modal/README.md | 17 ++ src/components/Modal/index.ts | 1 + src/components/Modal/story.tsx | 230 ++++++++++++++++++++++++++ src/index.ts | 1 + src/shared/variables.css | 1 + src/stories/index.js | 1 + 10 files changed, 602 insertions(+) create mode 100644 src/components/Modal/Modal.module.css create mode 100644 src/components/Modal/Modal.test.tsx create mode 100644 src/components/Modal/Modal.tsx create mode 100644 src/components/Modal/README.md create mode 100644 src/components/Modal/index.ts create mode 100644 src/components/Modal/story.tsx diff --git a/example/src/App.js b/example/src/App.js index cef385f4..21f57df4 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -26,6 +26,7 @@ import { Input, InputTime, Typography, + Modal, // IMPORT_INJECTOR } from '@cision/rover-ui'; @@ -405,6 +406,10 @@ const App = () => { +
+ +
+ {/** USAGE_INJECTOR */} ); diff --git a/src/components/Modal/Modal.module.css b/src/components/Modal/Modal.module.css new file mode 100644 index 00000000..c5b5fe38 --- /dev/null +++ b/src/components/Modal/Modal.module.css @@ -0,0 +1,129 @@ +.modal { + z-index: var(--rvr-zindex-modal-backdrop); + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; + background-color:rgba(0, 0, 0, 0.3); + display: flex; + flex-flow: column nowrap; + align-items: center; + justify-content: center; + opacity: 0; + transition: all 0.3s ease-in-out; + overflow: auto; + pointer-events: none; +} + +.enterDone { + opacity: 1; + pointer-events: visible; +} + +.exit { + opacity: 0; +} + +.modalContent { + display: flex; + flex-flow: column nowrap; + z-index: var(--rvr-zindex-modal); + background-color: var(--rvr-white); + box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.5); + border-radius: 4px; + transition: all 0.3s ease-in-out; + overflow: auto; + transform: translateY(-200px); + margin: var(--rvr-space-bordered-lg); + max-height: 100%; + max-width: 100%; +} + +.enterDone .modalContent { + transform: translateY(0); +} + +.exit .modalContent { + transform: translateY(-200px); +} + +.modalHeader { + flex: 0 0 auto; + border-radius: 4px 4px 0px 0px; +} + +.modalHeader.level--primary { + background: var(--rvr-gray-10); + border-bottom: 1px solid var(--rvr-gray-20) +} + +.modalHeader.level--warning { + background: var(--rvr-yellow-lite-2); + border-bottom: 1px solid var(--rvr-yellow); +} + +.modalHeader.level--info { + background: var(--rvr-blue-lite-2); + border-bottom: 1px solid var(--rvr-blue); +} + +.modalHeader.level--danger { + background: var(--rvr-red-lite-2); + border-bottom: 1px solid var(--rvr-red); +} + + +.modalFooter { + flex: 0 0 auto; + border-top: 1px solid var(--rvr-gray-20); + background: var(--rvr-white); +} + +.modalHeader, .modalFooter { + padding: 12px; +} + +.modalTitle { + margin: 0; +} + +.modalBody { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + padding: 10px; +} + +.bodyHasOpenModal { + overflow: hidden; +} + +.size--sm { + width: 340px; +} + +.size--md { + width: 578px; +} + +.size--lg { + width: 815px; +} + +/*max-height: calc(var(--rvr-baseSize) * 40*/ +@media (max-height: 320px) { + .modalBody { + flex: 0 0 auto; + } + + .modalContent { + flex: 0 0 auto; + max-height: none; + } + + .modal { + justify-content: flex-start; + } +} + diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx new file mode 100644 index 00000000..9aab1bf7 --- /dev/null +++ b/src/components/Modal/Modal.test.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; + +import Modal from './Modal'; + +describe('Modal', () => { + it('renders', () => { + render(); + expect(screen.getByTestId('Modal-Test')).toBeInTheDocument(); + }); + + it("does not render when 'isOpen' prop is false", () => { + render(); + expect(screen.queryByTestId('Modal-Test')).not.toBeInTheDocument(); + }); + + describe('Modal CSS Classes', () => { + test.each` + size | level | sizeClass | levelClass + ${'sm'} | ${'primary'} | ${'size--sm'} | ${'level--primary'} + ${'md'} | ${'warning'} | ${'size--md'} | ${'level--warning'} + ${'lg'} | ${undefined} | ${'size--lg'} | ${'level--primary'} + ${undefined} | ${undefined} | ${'size--md'} | ${'level--primary'} + ${'lg'} | ${'info'} | ${'size--lg'} | ${'level--info'} + ${undefined} | ${'danger'} | ${'size--md'} | ${'level--danger'} + `( + 'when size prop = $size and level prop = $level, the modal should have css classes $sizeClass and $levelClass', + ({ size, level, sizeClass, levelClass }) => { + render( + + +

Test Header

+
+
+ ); + const modalContentDiv = screen.getAllByRole('presentation')[1]; + expect(modalContentDiv).toHaveClass(sizeClass); + expect(screen.getByTestId('Modal-Header')).toHaveClass(levelClass); + } + ); + }); + + describe('onClose callback', () => { + it('calls onClose callback when the escape key is pressed', async () => { + const onClose = jest.fn(); + render(); + const modal = screen.getByTestId('Modal-Test'); + expect(modal).toBeInTheDocument(); + fireEvent.keyUp(modal, { + key: 'Escape', + code: 'Escape', + }); + expect(onClose).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx new file mode 100644 index 00000000..e2f8772a --- /dev/null +++ b/src/components/Modal/Modal.tsx @@ -0,0 +1,160 @@ +import React, { CSSProperties, useCallback, useEffect, useMemo } from 'react'; +import { CSSTransition } from 'react-transition-group'; +import classNames from 'classnames'; +import { ClassValue } from 'classnames/types'; + +import ReactDOM from 'react-dom'; +import styles from './Modal.module.css'; + +type Size = 'sm' | 'md' | 'lg'; +type Level = 'primary' | 'warning' | 'info' | 'danger'; + +interface ModalProps { + children?: React.ReactNode; + className?: ClassValue; + isOpen?: boolean; + onClose?: () => void; + size?: Size; + style?: CSSProperties; +} + +type ModalChildProps = Pick; +type ModalHeaderProps = Pick & { + level?: Level; +}; + +type ModalType = React.FC & { + Header: React.FC; + Footer: React.FC; + Body: React.FC; +}; + +const Modal: ModalType = ({ + children, + className: passedClassName = '', + isOpen = false, + onClose = () => {}, + size = 'md', + style: passedStyle = {}, + ...passedProps +}) => { + const handleEscape = useCallback( + (e: KeyboardEvent) => { + if (isOpen && e.code === 'Escape' && onClose) { + onClose(); + } + }, + [isOpen, onClose] + ); + + useEffect(() => { + if (isOpen) { + window.addEventListener('keyup', handleEscape); + } + + if (!isOpen) { + window.removeEventListener('keyup', handleEscape); + } + + return () => { + if (isOpen) window.removeEventListener('keyup', handleEscape); + }; + }, [handleEscape, isOpen]); + + useEffect(() => { + if (isOpen) { + document.body.className = classNames( + document.body.className, + styles.bodyHasOpenModal + ); + } else { + document.body.className = document.body.className + .replace(styles.bodyHasOpenModal, '') + .trim(); + } + }, [isOpen]); + + const modalContentStyle = useMemo( + () => + classNames( + styles.modalContent, + { + [styles[`size--${size}`]]: size, + }, + passedClassName + ), + [passedClassName, size] + ); + return ReactDOM.createPortal( + +
+
e.stopPropagation()} + > + {children} +
+
+
, + document.body + ); +}; + +const Header: React.FC = ({ + children, + className = '', + level = 'primary', + ...props +}) => ( +
+ {children} +
+); + +const Body: React.FC = ({ + children, + className = '', + ...props +}) => ( +
+ {children} +
+); + +const Footer: React.FC = ({ + children, + className = '', + ...props +}) => ( +
+ {children} +
+); + +Modal.Header = Header; +Modal.Body = Body; +Modal.Footer = Footer; + +export default Modal; diff --git a/src/components/Modal/README.md b/src/components/Modal/README.md new file mode 100644 index 00000000..4d0c75ba --- /dev/null +++ b/src/components/Modal/README.md @@ -0,0 +1,17 @@ +# \ + +**A configurable Modal component that automatically triggers onClose when escape key is pressed or clicked outside** + +This component can be used as a dialog box that slides in from the top. + +Below is an example structure of the `` + +``` + + (optional) + --- main content of the modal goes here --- + (optional) + +``` + +This will render a modal with a header at the top, a footer at the bottom, and a body block that scrolls if the interior content extends outside the height of the parent. diff --git a/src/components/Modal/index.ts b/src/components/Modal/index.ts new file mode 100644 index 00000000..0690fecf --- /dev/null +++ b/src/components/Modal/index.ts @@ -0,0 +1 @@ +export { default } from './Modal'; diff --git a/src/components/Modal/story.tsx b/src/components/Modal/story.tsx new file mode 100644 index 00000000..02660cc3 --- /dev/null +++ b/src/components/Modal/story.tsx @@ -0,0 +1,230 @@ +import React, { useState } from 'react'; +import { storiesOf } from '@storybook/react'; +import { Wrap } from '../../stories/storybook-helpers'; + +import Modal from '.'; +import Readme from './README.md'; + +import Button from '../Button'; +import Typography from '../Typography'; +import Input from '../Input'; + +function SmallModalExample() { + const [isOpen, setIsOpen] = useState(false); + + const openModal = () => { + setIsOpen(true); + }; + + const closeModal = () => { + setIsOpen(false); + }; + + return ( + <> +
+
Small modal
+ +
+ + +

Modal Title

+
+ +

This is the modal body

+

This is the modal body

+

This is the modal body

+

This is the modal body

+

This is the modal body

+
+ + + +
+ + ); +} + +const MediumModalExample = () => { + const [isOpen, setIsOpen] = useState(false); + + const openModal = () => { + setIsOpen(true); + }; + + const closeModal = () => { + setIsOpen(false); + }; + + return ( + <> +
+
Medium modal
+ +
+ + +

Modal Title

+
+ +

This is the modal body

+
+ + + +
+ + ); +}; + +const LargeModalExample = () => { + const [isOpen, setIsOpen] = useState(false); + + const openModal = () => { + setIsOpen(true); + }; + + const closeModal = () => { + setIsOpen(false); + }; + + return ( + <> +
+
large modal example
+ +
+ + + + Sign up Form + + + +
+
+ First Name + {}} + value="" + /> +
+
+ Last Name + {}} + value="" + /> +
+
+ Email + {}} + value="" + /> +
+
+ Password + {}} + value="" + /> +
+
+
+ +
+ + +
+
+
+ + ); +}; + +storiesOf('Galaxies/Modal', module) + .addParameters({ + readme: { + sidebar: Readme, + }, + }) + .add( + 'Overview', + () => ( + {}}> + +

Modal Title

+
+ +

This is the modal body

+
+ + + +
+ ), + { + info: { + inline: true, + source: true, + }, + } + ) + .add( + 'Examples', + () => ( + <> + + + + + + + + + + + ), + { + info: { + inline: false, + source: false, + }, + } + ); diff --git a/src/index.ts b/src/index.ts index 693fd09f..e89e3ba1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,3 +34,4 @@ export { default as Tooltip, EasyRichTooltip } from './components/Tooltip'; export { default as Input } from './components/Input'; export { default as InputTime } from './components/InputTime'; export { default as Typography } from './components/Typography'; +export { default as Modal } from './components/Modal'; diff --git a/src/shared/variables.css b/src/shared/variables.css index f0cd3a91..ff4cb33c 100644 --- a/src/shared/variables.css +++ b/src/shared/variables.css @@ -25,4 +25,5 @@ /* Borders */ --rvr-border-radius: 4px; + --rvr-tile-border-radius: 6px; } diff --git a/src/stories/index.js b/src/stories/index.js index fc21574e..eb351939 100644 --- a/src/stories/index.js +++ b/src/stories/index.js @@ -73,4 +73,5 @@ import '../components/Tooltip/story'; import '../components/Input/story'; import '../components/InputTime/story'; import '../components/Typography/story'; +import '../components/Modal/story'; /** INJECTOR */ From 8050d172dac5fc44a86c1c51d465d52fd4e29ae2 Mon Sep 17 00:00:00 2001 From: Boima Konuwa Date: Sun, 18 Apr 2021 11:32:12 -0400 Subject: [PATCH 2/8] cleaned up css class names --- src/components/Modal/Modal.module.css | 39 +++++++++++++-------------- src/components/Modal/Modal.test.tsx | 14 +++++----- src/components/Modal/Modal.tsx | 27 +++++++++---------- 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/components/Modal/Modal.module.css b/src/components/Modal/Modal.module.css index c5b5fe38..59e8d6be 100644 --- a/src/components/Modal/Modal.module.css +++ b/src/components/Modal/Modal.module.css @@ -1,4 +1,4 @@ -.modal { +.Modal { z-index: var(--rvr-zindex-modal-backdrop); position: fixed; left: 0; @@ -25,7 +25,7 @@ opacity: 0; } -.modalContent { +.content { display: flex; flex-flow: column nowrap; z-index: var(--rvr-zindex-modal); @@ -40,55 +40,52 @@ max-width: 100%; } -.enterDone .modalContent { +.enterDone .content { transform: translateY(0); } -.exit .modalContent { +.exit .content { transform: translateY(-200px); } -.modalHeader { +.Header { flex: 0 0 auto; border-radius: 4px 4px 0px 0px; } -.modalHeader.level--primary { +.Header.level--primary { background: var(--rvr-gray-10); border-bottom: 1px solid var(--rvr-gray-20) } -.modalHeader.level--warning { +.Header.level--warning { background: var(--rvr-yellow-lite-2); border-bottom: 1px solid var(--rvr-yellow); } -.modalHeader.level--info { +.Header.level--info { background: var(--rvr-blue-lite-2); border-bottom: 1px solid var(--rvr-blue); } -.modalHeader.level--danger { +.Header.level--danger { background: var(--rvr-red-lite-2); border-bottom: 1px solid var(--rvr-red); } -.modalFooter { +.Footer { flex: 0 0 auto; border-top: 1px solid var(--rvr-gray-20); background: var(--rvr-white); } -.modalHeader, .modalFooter { +.Header, .Footer { padding: 12px; } -.modalTitle { - margin: 0; -} -.modalBody { +.Body { flex: 1 1 auto; min-height: 0; overflow-y: auto; @@ -99,30 +96,30 @@ overflow: hidden; } -.size--sm { +.sm { width: 340px; } -.size--md { +.md { width: 578px; } -.size--lg { +.lg { width: 815px; } /*max-height: calc(var(--rvr-baseSize) * 40*/ @media (max-height: 320px) { - .modalBody { + .Body { flex: 0 0 auto; } - .modalContent { + .content { flex: 0 0 auto; max-height: none; } - .modal { + .Modal { justify-content: flex-start; } } diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx index 9aab1bf7..0d271b17 100644 --- a/src/components/Modal/Modal.test.tsx +++ b/src/components/Modal/Modal.test.tsx @@ -17,13 +17,13 @@ describe('Modal', () => { describe('Modal CSS Classes', () => { test.each` - size | level | sizeClass | levelClass - ${'sm'} | ${'primary'} | ${'size--sm'} | ${'level--primary'} - ${'md'} | ${'warning'} | ${'size--md'} | ${'level--warning'} - ${'lg'} | ${undefined} | ${'size--lg'} | ${'level--primary'} - ${undefined} | ${undefined} | ${'size--md'} | ${'level--primary'} - ${'lg'} | ${'info'} | ${'size--lg'} | ${'level--info'} - ${undefined} | ${'danger'} | ${'size--md'} | ${'level--danger'} + size | level | sizeClass | levelClass + ${'sm'} | ${'primary'} | ${'sm'} | ${'level--primary'} + ${'md'} | ${'warning'} | ${'md'} | ${'level--warning'} + ${'lg'} | ${undefined} | ${'lg'} | ${'level--primary'} + ${undefined} | ${undefined} | ${'md'} | ${'level--primary'} + ${'lg'} | ${'info'} | ${'lg'} | ${'level--info'} + ${undefined} | ${'danger'} | ${'md'} | ${'level--danger'} `( 'when size prop = $size and level prop = $level, the modal should have css classes $sizeClass and $levelClass', ({ size, level, sizeClass, levelClass }) => { diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx index e2f8772a..b8bf8eec 100644 --- a/src/components/Modal/Modal.tsx +++ b/src/components/Modal/Modal.tsx @@ -1,4 +1,4 @@ -import React, { CSSProperties, useCallback, useEffect, useMemo } from 'react'; +import React, { CSSProperties, useCallback, useEffect } from 'react'; import { CSSTransition } from 'react-transition-group'; import classNames from 'classnames'; import { ClassValue } from 'classnames/types'; @@ -74,17 +74,14 @@ const Modal: ModalType = ({ } }, [isOpen]); - const modalContentStyle = useMemo( - () => - classNames( - styles.modalContent, - { - [styles[`size--${size}`]]: size, - }, - passedClassName - ), - [passedClassName, size] + const modalContentStyle = classNames( + styles.content, + { + [styles[size]]: size, + }, + passedClassName ); + return ReactDOM.createPortal(
= ({
= ({ className = '', ...props }) => ( -
+
{children}
); @@ -148,7 +145,7 @@ const Footer: React.FC = ({ className = '', ...props }) => ( -
+
{children}
); From 67e39c7c114dbab89e4be1e1eeb315ebc6e1990d Mon Sep 17 00:00:00 2001 From: Boima Konuwa Date: Mon, 19 Apr 2021 22:02:10 -0400 Subject: [PATCH 3/8] add logic to auto focus and focus trapping in the modal --- src/components/Modal/Modal.test.tsx | 2 +- src/components/Modal/Modal.tsx | 130 ++++++++++++++++++++++------ src/components/Modal/story.tsx | 39 ++++++--- 3 files changed, 135 insertions(+), 36 deletions(-) diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx index 0d271b17..b024de18 100644 --- a/src/components/Modal/Modal.test.tsx +++ b/src/components/Modal/Modal.test.tsx @@ -34,7 +34,7 @@ describe('Modal', () => { ); - const modalContentDiv = screen.getAllByRole('presentation')[1]; + const modalContentDiv = screen.getByRole('dialog'); expect(modalContentDiv).toHaveClass(sizeClass); expect(screen.getByTestId('Modal-Header')).toHaveClass(levelClass); } diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx index b8bf8eec..f41d237a 100644 --- a/src/components/Modal/Modal.tsx +++ b/src/components/Modal/Modal.tsx @@ -1,4 +1,10 @@ -import React, { CSSProperties, useCallback, useEffect } from 'react'; +import React, { + createContext, + createRef, + CSSProperties, + useCallback, + useEffect, +} from 'react'; import { CSSTransition } from 'react-transition-group'; import classNames from 'classnames'; import { ClassValue } from 'classnames/types'; @@ -29,6 +35,25 @@ type ModalType = React.FC & { Body: React.FC; }; +const modalRef = createRef(); +const modalContext = createContext({ onClose: () => {} }); + +const getFocusableElements = (element: HTMLElement) => { + return element?.querySelectorAll( + 'a, button, textarea, input, input[type="radio"], input[type="checkbox"], select' + ); +}; + +const getFirstFocusableElement = (element: HTMLElement) => { + const focusableElements = getFocusableElements(element); + return focusableElements && focusableElements[0]; +}; + +const getLastFocusableElement = (element: HTMLElement) => { + const focusableElements = getFocusableElements(element); + return focusableElements && focusableElements[focusableElements.length - 1]; +}; + const Modal: ModalType = ({ children, className: passedClassName = '', @@ -41,25 +66,67 @@ const Modal: ModalType = ({ const handleEscape = useCallback( (e: KeyboardEvent) => { if (isOpen && e.code === 'Escape' && onClose) { - onClose(); + if (!modalRef?.current?.contains(document.activeElement)) { + onClose(); + } + (document.activeElement as HTMLElement).blur(); } }, [isOpen, onClose] ); + //Trap focus in the modal when tabbing thru elements + const handleTabKey = useCallback((e: KeyboardEvent) => { + const focusableElements = getFocusableElements( + modalRef?.current as HTMLElement + ); + + if (focusableElements) { + const firstFocusableElement = getFirstFocusableElement( + modalRef?.current as HTMLElement + ); + + const lastFocusableElement = getLastFocusableElement( + modalRef?.current as HTMLElement + ); + + if (!e.shiftKey && document.activeElement === lastFocusableElement) { + (firstFocusableElement as HTMLElement)?.focus(); + return e.preventDefault(); + } + + if (e.shiftKey && document.activeElement === firstFocusableElement) { + (lastFocusableElement as HTMLElement)?.focus(); + return e.preventDefault(); + } + } + + return null; + }, []); + useEffect(() => { + const keyListenerMap = new Map([ + ['Escape', handleEscape], + ['Tab', handleTabKey], + ]); + + const keyListener = (e: KeyboardEvent) => { + const listener = keyListenerMap.get(e.code); + return listener && listener(e); + }; + if (isOpen) { - window.addEventListener('keyup', handleEscape); + window.addEventListener('keyup', keyListener); } if (!isOpen) { - window.removeEventListener('keyup', handleEscape); + window.removeEventListener('keyup', keyListener); } return () => { - if (isOpen) window.removeEventListener('keyup', handleEscape); + if (isOpen) window.removeEventListener('keyup', keyListener); }; - }, [handleEscape, isOpen]); + }, [handleEscape, handleTabKey, isOpen]); useEffect(() => { if (isOpen) { @@ -67,6 +134,12 @@ const Modal: ModalType = ({ document.body.className, styles.bodyHasOpenModal ); + + const firstElement = getFirstFocusableElement( + modalRef?.current as HTMLElement + ); + + (firstElement as HTMLElement)?.focus(); } else { document.body.className = document.body.className .replace(styles.bodyHasOpenModal, '') @@ -82,6 +155,13 @@ const Modal: ModalType = ({ passedClassName ); + const handleClickBackdrop = (e: React.MouseEvent) => { + if (e.target && modalRef?.current?.contains(e.target as HTMLElement)) { + return; + } + onClose(); + }; + return ReactDOM.createPortal( -
e.stopPropagation()} - > - {children} +
+ + {children} +
, @@ -117,18 +195,20 @@ const Header: React.FC = ({ className = '', level = 'primary', ...props -}) => ( -
- {children} -
-); +}) => { + return ( +
+ {children} +
+ ); +}; const Body: React.FC = ({ children, diff --git a/src/components/Modal/story.tsx b/src/components/Modal/story.tsx index 02660cc3..3cdff9c2 100644 --- a/src/components/Modal/story.tsx +++ b/src/components/Modal/story.tsx @@ -87,6 +87,13 @@ const MediumModalExample = () => { const LargeModalExample = () => { const [isOpen, setIsOpen] = useState(false); + const initialInputValues = { + firstName: '', + lastName: '', + email: '', + password: '', + }; + const [formInputValues, setFormInputValues] = useState(initialInputValues); const openModal = () => { setIsOpen(true); @@ -94,6 +101,18 @@ const LargeModalExample = () => { const closeModal = () => { setIsOpen(false); + setFormInputValues({ + ...initialInputValues, + }); + }; + + const handleInputChange = (event) => { + event.persist(); + + setFormInputValues({ + ...formInputValues, + [event.target.name]: event.target.value, + }); }; return ( @@ -118,10 +137,10 @@ const LargeModalExample = () => { autoComplete="off" className="border py-2 px-3 text-grey-darkest" type="text" - name="first-name" + name="firstName" placeholder="First Name" - onChange={() => {}} - value="" + onChange={handleInputChange} + value={formInputValues.firstName} />
@@ -130,10 +149,10 @@ const LargeModalExample = () => { autoComplete="off" className="border py-2 px-3 text-grey-darkest" type="text" - name="last-name" + name="lastName" placeholder="Last Name" - onChange={() => {}} - value="" + onChange={handleInputChange} + value={formInputValues.lastName} />
@@ -144,8 +163,8 @@ const LargeModalExample = () => { type="text" name="email" placeholder="Email" - onChange={() => {}} - value="" + onChange={handleInputChange} + value={formInputValues.email} />
@@ -155,8 +174,8 @@ const LargeModalExample = () => { className="border py-2 px-3 text-grey-darkest" type="password" name="password" - onChange={() => {}} - value="" + onChange={handleInputChange} + value={formInputValues.password} />
From 46f24766728eb42191d59fcf3339007e178dfc80 Mon Sep 17 00:00:00 2001 From: Boima Konuwa Date: Sun, 25 Apr 2021 11:39:22 -0400 Subject: [PATCH 4/8] Add example of Modal usage --- example/src/App.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/example/src/App.js b/example/src/App.js index 21f57df4..69372594 100644 --- a/example/src/App.js +++ b/example/src/App.js @@ -40,6 +40,7 @@ const App = () => { const [tooltipOpen, setTooltipOpen] = useState(false); const [inputValue, setInputValue] = useState(''); const [inputTimeValue, setInputTimeValue] = useState(''); + const [isModalOpen, setIsModalOpen] = useState(false); const toggleTooltip = function () { setTooltipOpen((prev) => !prev); @@ -407,7 +408,32 @@ const App = () => {
- +
+ +
+ setIsModalOpen(false)} + size="md" + > + +

Modal Header

+
+ +

Modal Body

+

You can put all of your interesting content in the modal body

+

+ Click outside the modal or use the escape key to close the modal +

+
+ + + +
{/** USAGE_INJECTOR */} From a69b14b05c5be66052266793e19d3eecef04862e Mon Sep 17 00:00:00 2001 From: Boima Konuwa Date: Sun, 25 Apr 2021 12:14:33 -0400 Subject: [PATCH 5/8] update unit test by adding snapshot to verify the component renders what is expected in the UI --- example/yarn.lock | 289 ++---------------- src/components/Modal/Modal.test.tsx | 24 ++ .../Modal/__snapshots__/Modal.test.tsx.snap | 40 +++ 3 files changed, 91 insertions(+), 262 deletions(-) create mode 100644 src/components/Modal/__snapshots__/Modal.test.tsx.snap diff --git a/example/yarn.lock b/example/yarn.lock index 8627436b..cb993746 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -2,119 +2,6 @@ # yarn lockfile v1 -"@babel/code-frame@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" - integrity sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw== - dependencies: - "@babel/highlight" "^7.10.1" - -"@babel/generator@^7.10.1": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" - integrity sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA== - dependencies: - "@babel/types" "^7.10.2" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.0.0": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.1.tgz#f6d08acc6f70bbd59b436262553fb2e259a1a268" - integrity sha512-ewp3rvJEwLaHgyWGe4wQssC2vjks3E80WiUe2BpMb0KhreTjMROCbxXcEovTrbeGVdQct5VjQfrv9EgC+xMzCw== - dependencies: - "@babel/types" "^7.10.1" - -"@babel/helper-function-name@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz#92bd63829bfc9215aca9d9defa85f56b539454f4" - integrity sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ== - dependencies: - "@babel/helper-get-function-arity" "^7.10.1" - "@babel/template" "^7.10.1" - "@babel/types" "^7.10.1" - -"@babel/helper-get-function-arity@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d" - integrity sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw== - dependencies: - "@babel/types" "^7.10.1" - -"@babel/helper-module-imports@^7.0.0": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz#dd331bd45bccc566ce77004e9d05fe17add13876" - integrity sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg== - dependencies: - "@babel/types" "^7.10.1" - -"@babel/helper-split-export-declaration@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" - integrity sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g== - dependencies: - "@babel/types" "^7.10.1" - -"@babel/helper-validator-identifier@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5" - integrity sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw== - -"@babel/highlight@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" - integrity sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg== - dependencies: - "@babel/helper-validator-identifier" "^7.10.1" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.10.1": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" - integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ== - -"@babel/runtime@^7.4.2": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839" - integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.10.1": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" - integrity sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig== - dependencies: - "@babel/code-frame" "^7.10.1" - "@babel/parser" "^7.10.1" - "@babel/types" "^7.10.1" - -"@babel/traverse@^7.0.0": - version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" - integrity sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ== - dependencies: - "@babel/code-frame" "^7.10.1" - "@babel/generator" "^7.10.1" - "@babel/helper-function-name" "^7.10.1" - "@babel/helper-split-export-declaration" "^7.10.1" - "@babel/parser" "^7.10.1" - "@babel/types" "^7.10.1" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.10.1", "@babel/types@^7.10.2": - version "7.10.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" - integrity sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng== - dependencies: - "@babel/helper-validator-identifier" "^7.10.1" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - "@cision/react-container-query@1.0.0-alpha.3": version "1.0.0-alpha.3" resolved "https://registry.yarnpkg.com/@cision/react-container-query/-/react-container-query-1.0.0-alpha.3.tgz#65651049cd3178cd3f3d3c53b3202e66b50ef4c3" @@ -124,30 +11,8 @@ resize-observer-lite "0.2.3" "@cision/rover-ui@link:..": - version "2.4.8" - dependencies: - "@cision/react-container-query" "1.0.0-alpha.3" - classnames "^2.2.6" - lodash "^4.17.19" - styled-components "^4.2.0" - styled-system "^4.1.0" - -"@emotion/is-prop-valid@^0.8.1": - version "0.8.8" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" - integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== - dependencies: - "@emotion/memoize" "0.7.4" - -"@emotion/memoize@0.7.4": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" - integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== - -"@emotion/unitless@^0.7.0": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + version "0.0.0" + uid "" abab@^1.0.3: version "1.0.4" @@ -803,16 +668,6 @@ babel-plugin-jest-hoist@^20.0.3: resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-20.0.3.tgz#afedc853bd3f8dc3548ea671fbe69d03cc2c1767" integrity sha1-r+3IU70/jcNUjqZx++adA8wsF2c= -"babel-plugin-styled-components@>= 1": - version "1.10.7" - resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz#3494e77914e9989b33cc2d7b3b29527a949d635c" - integrity sha512-MBMHGcIA22996n9hZRf/UJLVVgkEOITuR2SvjHLb5dSTUyR4ZRGn+ngITapes36FI3WLxZHfRhkA1ffHxihOrg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-module-imports" "^7.0.0" - babel-plugin-syntax-jsx "^6.18.0" - lodash "^4.17.11" - babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -838,7 +693,7 @@ babel-plugin-syntax-flow@^6.18.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0= -babel-plugin-syntax-jsx@^6.18.0, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: +babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= @@ -1679,11 +1534,6 @@ camelcase@^4.0.0, camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= -camelize@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= - caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" @@ -2180,11 +2030,6 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= -css-color-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" - integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= - css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -2229,15 +2074,6 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.2" regexpu-core "^4.6.0" -css-to-react-native@^2.2.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.3.2.tgz#e75e2f8f7aa385b4c3611c52b074b70a002f2e7d" - integrity sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw== - dependencies: - camelize "^1.0.0" - css-color-keywords "^1.0.0" - postcss-value-parser "^3.3.0" - css-what@2.1: version "2.1.3" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" @@ -2347,13 +2183,6 @@ debug@^3.0.1, debug@^3.1.0, debug@^3.1.1: dependencies: ms "^2.1.1" -debug@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3614,11 +3443,6 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - globals@^9.17.0, globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4432,11 +4256,6 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -is-what@^3.3.1: - version "3.8.0" - resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.8.0.tgz#610bc46a524355f2424eb85eedc6ebbbf7e1ff8c" - integrity sha512-UKeBoQfV8bjlM4pmx1FLDHdxslW/1mTksEs8ReVsilPmUv5cORd4+2/wFcviI3cUjrLybxCjzc8DnodAzJ/Wrg== - is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" @@ -4786,7 +4605,7 @@ js-base64@^2.1.9: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.0.tgz#cc0091315f85616ad766789e46ced20b5c989ed3" integrity sha512-jmCv6u76N7XtpXoF+aS5tNUQLRAJe1DgN9JXO5csoCkEIAPPLwWy93OQo/RoydkD6vyTf1oKKgto8SH7LM+Ong== -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +"js-tokens@^3.0.0 || ^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== @@ -4847,11 +4666,6 @@ jsesc@^1.3.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -5122,7 +4936,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.15.0, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0: +"lodash@>=3.5 <5", lodash@^4.15.0, lodash@^4.17.14, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -5142,7 +4956,7 @@ longest@^1.0.1: resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= -loose-envify@^1.0.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -5237,11 +5051,6 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" -memoize-one@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" - integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== - memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -5266,13 +5075,6 @@ meow@^3.3.0, meow@^3.7.0: redent "^1.0.0" trim-newlines "^1.0.0" -merge-anything@^2.2.4: - version "2.4.4" - resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-2.4.4.tgz#6226b2ac3d3d3fc5fb9e8d23aa400df25f98fdf0" - integrity sha512-l5XlriUDJKQT12bH+rVhAHjwIuXWdAIecGwsYjv2LJo+dA1AeRTmeQS+3QBpO6lEthBMDi2IUMpLC1yyRvGlwQ== - dependencies: - is-what "^3.3.1" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -6398,17 +6200,17 @@ promise@8.0.1: dependencies: asap "~2.0.3" -prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" +prop-types@^15.5.10: + version "0.0.0" + uid "" + +prop-types@^15.6.2: + version "0.0.0" + uid "" "prop-types@link:../node_modules/prop-types": version "0.0.0" + uid "" proxy-addr@~2.0.5: version "2.0.6" @@ -6580,13 +6382,14 @@ react-dev-utils@^5.0.2: "react-dom@link:../node_modules/react-dom": version "0.0.0" + uid "" react-error-overlay@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.1.tgz#417addb0814a90f3a7082eacba7cee588d00da89" integrity sha512-xXUbDAZkU08aAkjtUvldqbvI04ogv+a1XdHxvYuHPYKIVk/42BIOD0zSKTHAWV4+gDy3yGm283z2072rA2gdtw== -react-is@^16.6.0, react-is@^16.8.1: +react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -6639,6 +6442,7 @@ react-scripts@^1.1.4: "react@link:../node_modules/react": version "0.0.0" + uid "" read-pkg-up@^1.0.1: version "1.0.1" @@ -6760,11 +6564,6 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.4: - version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" - integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== - regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -7104,6 +6903,14 @@ sax@^1.2.1, sax@~1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + schema-utils@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf" @@ -7349,7 +7156,7 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: +source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -7579,43 +7386,6 @@ style-loader@0.19.0: loader-utils "^1.0.2" schema-utils "^0.3.0" -styled-components@^4.2.0: - version "4.4.1" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.4.1.tgz#e0631e889f01db67df4de576fedaca463f05c2f2" - integrity sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@emotion/is-prop-valid" "^0.8.1" - "@emotion/unitless" "^0.7.0" - babel-plugin-styled-components ">= 1" - css-to-react-native "^2.2.2" - memoize-one "^5.0.0" - merge-anything "^2.2.4" - prop-types "^15.5.4" - react-is "^16.6.0" - stylis "^3.5.0" - stylis-rule-sheet "^0.0.10" - supports-color "^5.5.0" - -styled-system@^4.1.0: - version "4.2.4" - resolved "https://registry.yarnpkg.com/styled-system/-/styled-system-4.2.4.tgz#8909f91396c30b92295b4eddec5f7b89f8c8d767" - integrity sha512-44X7n09gDvwx7yjquEXsjiNALK0dxGgAJdpO5cb/PdL+D4mhSLKWig4/EhH4vHJLbwu/kumURHyvKxygaBfg0A== - dependencies: - "@babel/runtime" "^7.4.2" - prop-types "^15.7.2" - -stylis-rule-sheet@^0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430" - integrity sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw== - -stylis@^3.5.0: - version "3.5.4" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe" - integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q== - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -7635,7 +7405,7 @@ supports-color@^4.2.1: dependencies: has-flag "^2.0.0" -supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: +supports-color@^5.1.0, supports-color@^5.3.0, supports-color@^5.4.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -7787,11 +7557,6 @@ to-fast-properties@^1.0.3: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx index b024de18..f64a7275 100644 --- a/src/components/Modal/Modal.test.tsx +++ b/src/components/Modal/Modal.test.tsx @@ -4,7 +4,31 @@ import '@testing-library/jest-dom'; import Modal from './Modal'; +const defaultProps = { + isOpen: true, + onClose: jest.fn(), +}; + +const renderModal = (props = defaultProps) => + render( + + +

Modal Header

+
+ +

Modal Body

+
+ +

Modal Footer

+
+
+ ); describe('Modal', () => { + it('renders correctly', () => { + const { baseElement } = renderModal(); + expect(baseElement).toMatchSnapshot(); + }); + it('renders', () => { render(); expect(screen.getByTestId('Modal-Test')).toBeInTheDocument(); diff --git a/src/components/Modal/__snapshots__/Modal.test.tsx.snap b/src/components/Modal/__snapshots__/Modal.test.tsx.snap new file mode 100644 index 00000000..deb67d32 --- /dev/null +++ b/src/components/Modal/__snapshots__/Modal.test.tsx.snap @@ -0,0 +1,40 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Modal renders correctly 1`] = ` + +
+ + +`; From 5a2c2513e1dfade95a4c8b8c93826a8d9dbf9d07 Mon Sep 17 00:00:00 2001 From: Chris Garcia Date: Tue, 27 Apr 2021 14:29:21 -0500 Subject: [PATCH 6/8] fix: Modal focus trap works better with keydown listener, add focus trap tests, upgrade testing-library packages --- src/components/Modal/Modal.test.tsx | 4 +- src/components/Modal/Modal.tsx | 6 +- yarn.lock | 126 ++-------------------------- 3 files changed, 14 insertions(+), 122 deletions(-) diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx index f64a7275..1e0ee7d0 100644 --- a/src/components/Modal/Modal.test.tsx +++ b/src/components/Modal/Modal.test.tsx @@ -71,10 +71,12 @@ describe('Modal', () => { render(); const modal = screen.getByTestId('Modal-Test'); expect(modal).toBeInTheDocument(); - fireEvent.keyUp(modal, { + + fireEvent.keyDown(modal, { key: 'Escape', code: 'Escape', }); + expect(onClose).toHaveBeenCalledTimes(1); }); }); diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx index f41d237a..e8bad0d1 100644 --- a/src/components/Modal/Modal.tsx +++ b/src/components/Modal/Modal.tsx @@ -116,15 +116,15 @@ const Modal: ModalType = ({ }; if (isOpen) { - window.addEventListener('keyup', keyListener); + window.addEventListener('keydown', keyListener); } if (!isOpen) { - window.removeEventListener('keyup', keyListener); + window.removeEventListener('keydown', keyListener); } return () => { - if (isOpen) window.removeEventListener('keyup', keyListener); + if (isOpen) window.removeEventListener('keydown', keyListener); }; }, [handleEscape, handleTabKey, isOpen]); diff --git a/yarn.lock b/yarn.lock index 16f86575..2b8e12bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -89,7 +89,7 @@ lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.8.3": +"@babel/helper-annotate-as-pure@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== @@ -1087,7 +1087,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.9.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== @@ -1115,7 +1115,7 @@ "@babel/parser" "^7.8.6" "@babel/types" "^7.8.6" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.9.0", "@babel/traverse@^7.9.6": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.9.0", "@babel/traverse@^7.9.6": version "7.9.6" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.6.tgz#5540d7577697bf619cc57b92aa0f1c231a94f442" integrity sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg== @@ -1230,7 +1230,7 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== -"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.1": +"@emotion/is-prop-valid@0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== @@ -1281,7 +1281,7 @@ resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== -"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.0": +"@emotion/unitless@0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== @@ -2338,14 +2338,6 @@ resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.5.tgz#527d20ef68571a4af02ed74350164e7a67544860" integrity sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw== -"@types/hoist-non-react-statics@*": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - "@types/html-minifier-terser@^5.0.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" @@ -2459,13 +2451,6 @@ dependencies: "@types/react" "*" -"@types/react-native@*": - version "0.62.12" - resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.62.12.tgz#24407983b527749f37b512cd5d2bdc6133810b17" - integrity sha512-EuM2QOx0LGwY3mKQ313+QcTYOwJhw5eggmE42GO4ElIKIfNK+zxxM6Pe9dT1Eq8eCJXY0oG327L7gUBWniwNNA== - dependencies: - "@types/react" "*" - "@types/react-syntax-highlighter@11.0.4": version "11.0.4" resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz#d86d17697db62f98046874f62fdb3e53a0bbc4cd" @@ -2519,23 +2504,6 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== -"@types/styled-components@^4.4.1": - version "4.4.3" - resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-4.4.3.tgz#74dd00ad760845a98890a8539361d8afc32059de" - integrity sha512-U0udeNOZBfUkJycmGJwmzun0FBt11rZy08weVQmE2xfUNAbX8AGOEWxWna2d+qAUKxKgMlcG+TZT0+K2FfDcnQ== - dependencies: - "@types/hoist-non-react-statics" "*" - "@types/react" "*" - "@types/react-native" "*" - csstype "^2.2.0" - -"@types/styled-system@^5.1.9": - version "5.1.9" - resolved "https://registry.yarnpkg.com/@types/styled-system/-/styled-system-5.1.9.tgz#8baac8f6eca9e0bd5768c175ca5ce1f2d6f61ade" - integrity sha512-QlWv6tmQV8dqk8s+LSLb9QAtmuQEnfv4f8lKKZkMgDqRFVmxJDBwEw0u4zhpxp56u0hdR+TCIk9dGfOw3TkCoQ== - dependencies: - csstype "^2.6.9" - "@types/tapable@*", "@types/tapable@^1.0.5": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" @@ -3859,16 +3827,6 @@ babel-plugin-react-docgen@^4.0.0, babel-plugin-react-docgen@^4.1.0: react-docgen "^5.0.0" recast "^0.14.7" -"babel-plugin-styled-components@>= 1": - version "1.10.7" - resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.10.7.tgz#3494e77914e9989b33cc2d7b3b29527a949d635c" - integrity sha512-MBMHGcIA22996n9hZRf/UJLVVgkEOITuR2SvjHLb5dSTUyR4ZRGn+ngITapes36FI3WLxZHfRhkA1ffHxihOrg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.0.0" - "@babel/helper-module-imports" "^7.0.0" - babel-plugin-syntax-jsx "^6.18.0" - lodash "^4.17.11" - babel-plugin-syntax-jsx@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" @@ -4543,11 +4501,6 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= -camelize@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= - can-use-dom@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/can-use-dom/-/can-use-dom-0.1.0.tgz#22cc4a34a0abc43950f42c6411024a3f6366b45a" @@ -5315,11 +5268,6 @@ css-blank-pseudo@^0.1.4: dependencies: postcss "^7.0.5" -css-color-keywords@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" - integrity sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU= - css-color-names@0.0.4, css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -5431,15 +5379,6 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.2" regexpu-core "^4.6.0" -css-to-react-native@^2.2.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.3.2.tgz#e75e2f8f7aa385b4c3611c52b074b70a002f2e7d" - integrity sha512-VOFaeZA053BqvvvqIA8c9n0+9vFppVBAHCp6JgFTtTMU3Mzi+XnelJ9XC9ul3BqFzZyQ5N+H0SnwsWT2Ebchxw== - dependencies: - camelize "^1.0.0" - css-color-keywords "^1.0.0" - postcss-value-parser "^3.3.0" - css-tree@1.0.0-alpha.37: version "1.0.0-alpha.37" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" @@ -5583,7 +5522,7 @@ cssstyle@^1.0.0, cssstyle@^1.1.1: dependencies: cssom "0.3.x" -csstype@^2.2.0, csstype@^2.5.7, csstype@^2.6.7, csstype@^2.6.9: +csstype@^2.2.0, csstype@^2.5.7, csstype@^2.6.7: version "2.6.10" resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.10.tgz#e63af50e66d7c266edb6b32909cfd0aabe03928b" integrity sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w== @@ -8978,11 +8917,6 @@ is-upper-case@^1.1.0: dependencies: upper-case "^1.1.0" -is-what@^3.3.1: - version "3.8.0" - resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.8.0.tgz#610bc46a524355f2424eb85eedc6ebbbf7e1ff8c" - integrity sha512-UKeBoQfV8bjlM4pmx1FLDHdxslW/1mTksEs8ReVsilPmUv5cORd4+2/wFcviI3cUjrLybxCjzc8DnodAzJ/Wrg== - is-whitespace-character@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" @@ -10434,13 +10368,6 @@ meow@^5.0.0: trim-newlines "^2.0.0" yargs-parser "^10.0.0" -merge-anything@^2.2.4: - version "2.4.4" - resolved "https://registry.yarnpkg.com/merge-anything/-/merge-anything-2.4.4.tgz#6226b2ac3d3d3fc5fb9e8d23aa400df25f98fdf0" - integrity sha512-l5XlriUDJKQT12bH+rVhAHjwIuXWdAIecGwsYjv2LJo+dA1AeRTmeQS+3QBpO6lEthBMDi2IUMpLC1yyRvGlwQ== - dependencies: - is-what "^3.3.1" - merge-deep@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2" @@ -13172,7 +13099,7 @@ react-inspector@^4.0.0: is-dom "^1.0.9" prop-types "^15.6.1" -react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.3, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: +react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.3, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -15043,33 +14970,6 @@ style-search@^0.1.0: resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= -styled-components@^4.2.0: - version "4.4.1" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.4.1.tgz#e0631e889f01db67df4de576fedaca463f05c2f2" - integrity sha512-RNqj14kYzw++6Sr38n7197xG33ipEOktGElty4I70IKzQF1jzaD1U4xQ+Ny/i03UUhHlC5NWEO+d8olRCDji6g== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@emotion/is-prop-valid" "^0.8.1" - "@emotion/unitless" "^0.7.0" - babel-plugin-styled-components ">= 1" - css-to-react-native "^2.2.2" - memoize-one "^5.0.0" - merge-anything "^2.2.4" - prop-types "^15.5.4" - react-is "^16.6.0" - stylis "^3.5.0" - stylis-rule-sheet "^0.0.10" - supports-color "^5.5.0" - -styled-system@^4.1.0: - version "4.2.4" - resolved "https://registry.yarnpkg.com/styled-system/-/styled-system-4.2.4.tgz#8909f91396c30b92295b4eddec5f7b89f8c8d767" - integrity sha512-44X7n09gDvwx7yjquEXsjiNALK0dxGgAJdpO5cb/PdL+D4mhSLKWig4/EhH4vHJLbwu/kumURHyvKxygaBfg0A== - dependencies: - "@babel/runtime" "^7.4.2" - prop-types "^15.7.2" - stylehacks@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" @@ -15144,16 +15044,6 @@ stylelint@^9.10.1: svg-tags "^1.0.0" table "^5.0.0" -stylis-rule-sheet@^0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz#44e64a2b076643f4b52e5ff71efc04d8c3c4a430" - integrity sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw== - -stylis@^3.5.0: - version "3.5.4" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe" - integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q== - sugarss@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" @@ -15173,7 +15063,7 @@ supports-color@^3.2.3: dependencies: has-flag "^1.0.0" -supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: +supports-color@^5.3.0, supports-color@^5.4.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== From 92037a342a8b98eaaa4f3387c7b98442d9294456 Mon Sep 17 00:00:00 2001 From: Boima Konuwa Date: Mon, 3 May 2021 07:54:28 -0400 Subject: [PATCH 7/8] fix: use userEvent.type to simulate escape key press --- src/components/Modal/Modal.test.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx index 1e0ee7d0..2a969d8d 100644 --- a/src/components/Modal/Modal.test.tsx +++ b/src/components/Modal/Modal.test.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; +import userEvent from '@testing-library/user-event'; import Modal from './Modal'; const defaultProps = { @@ -72,10 +73,7 @@ describe('Modal', () => { const modal = screen.getByTestId('Modal-Test'); expect(modal).toBeInTheDocument(); - fireEvent.keyDown(modal, { - key: 'Escape', - code: 'Escape', - }); + userEvent.type(modal, '{esc}'); expect(onClose).toHaveBeenCalledTimes(1); }); From e03f45f65a7035004ec3898b98855aabbeb2e896 Mon Sep 17 00:00:00 2001 From: Boima Konuwa Date: Mon, 3 May 2021 08:43:18 -0400 Subject: [PATCH 8/8] fixed failing test --- src/components/Modal/Modal.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Modal/Modal.test.tsx b/src/components/Modal/Modal.test.tsx index 2a969d8d..28931cd7 100644 --- a/src/components/Modal/Modal.test.tsx +++ b/src/components/Modal/Modal.test.tsx @@ -75,7 +75,7 @@ describe('Modal', () => { userEvent.type(modal, '{esc}'); - expect(onClose).toHaveBeenCalledTimes(1); + expect(onClose).toHaveBeenCalled(); }); }); });