diff --git a/frontend/.prettierignore b/frontend/.prettierignore index 9e1caa2..ca799dd 100644 --- a/frontend/.prettierignore +++ b/frontend/.prettierignore @@ -1,2 +1,4 @@ package.json -.eslintrc \ No newline at end of file +.gitignore +.eslintrc +.next diff --git a/frontend/jest.config.js b/frontend/jest.config.js index c067c56..e4099cf 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -12,7 +12,7 @@ const customJestConfig = { // setupFilesAfterEnv: ['/jest.setup.js'], // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work moduleDirectories: ['node_modules', '/'], - testEnvironment: 'jest-environment-jsdom' + testEnvironment: 'jest-environment-jsdom', }; // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async diff --git a/frontend/package.json b/frontend/package.json index f0b9095..615548a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,7 @@ "lint": "yarn lint:eslint && yarn lint:prettier", "lint:eslint": "eslint './src/**/*.{js,ts,tsx}' --cache", "lint:prettier": "prettier --ignore-path .gitignore --check './**/*.{js,ts,tsx}'", - "lint:prettier-write": "prettier --ignore-path .gitignore --ignore-path .next './**/*.{js,ts,tsx}' -w", + "lint:prettier-write": "prettier './**/*.{js,ts,tsx}' -w", "test": "NODE_ENV=test jest --watch", "test:ci": "NODE_ENV=test jest --ci --reporters jest-silent-reporter" }, diff --git a/frontend/src/components/Dialog/Close.module.css b/frontend/src/components/Dialog/Close.module.css index d3645cf..2b7a9fe 100644 --- a/frontend/src/components/Dialog/Close.module.css +++ b/frontend/src/components/Dialog/Close.module.css @@ -10,6 +10,7 @@ align-items: center; justify-content: center; transition: all .2s; + text-indent: -9999px; } .close:hover:before { box-shadow: white 0 0 5px; @@ -26,6 +27,7 @@ background-color: rgba(0, 0, 0, 1); box-shadow: white 0 0 4px; border-radius: 100%; - padding: 2px; + padding: 1px 2px 3px; line-height: 100%; + text-indent: 0; } diff --git a/frontend/src/components/Dialog/Dialog.module.css b/frontend/src/components/Dialog/Dialog.module.css index 31880a6..afc7446 100644 --- a/frontend/src/components/Dialog/Dialog.module.css +++ b/frontend/src/components/Dialog/Dialog.module.css @@ -1,6 +1,6 @@ .dialogRoot { - width: 100%; - height: 100%; + width: 100vw; + height: 100vh; display: flex; position: fixed; top: 0; @@ -9,18 +9,39 @@ justify-content: center; align-items: center; transition: all 0.25s ease-in; - visibility: visible; - opacity: 1; backdrop-filter: blur(1px); + opacity: 0; } -.dialogRootFadeOut { - visibility: visible; - opacity: 0; +.dialogRootShow { + opacity: 1; +} + +.dialog[open]::backdrop { + animation-name: backdrop-fade; + animation-duration: 0.25s; + animation-timing-function: ease-in; + animation-direction: alternate; + animation-fill-mode: forwards; +} + +.dialog.close::backdrop { + animation-name: backdrop-fade; + animation-duration: 0.5s; + animation-timing-function: ease-out; + animation-direction: alternate-reverse; + animation-fill-mode: backwards; + animation-delay: 0.5s; + background: transparent; } -.dialogRoot.hide { - display: none; +@keyframes backdrop-fade { + from { + background: transparent; + } + to { + background: rgba(0, 0, 0, 0.5); + } } .dialog { @@ -28,7 +49,13 @@ border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); padding: 16px; - max-width: 400px; + max-width: 80vh; + overflow: visible; +} + +.dialog::backdrop { + transition: all 0.25s ease-in-out; + /*background: transparent;*/ } .blockScrolling { diff --git a/frontend/src/components/Dialog/Dialog.test.tsx b/frontend/src/components/Dialog/Dialog.test.tsx index 4959a7e..2ea2143 100644 --- a/frontend/src/components/Dialog/Dialog.test.tsx +++ b/frontend/src/components/Dialog/Dialog.test.tsx @@ -1,13 +1,17 @@ import { render, screen, fireEvent } from '@testing-library/react'; import React from 'react'; import { Dialog } from '.'; -import '@testing-library/jest-dom' +import '@testing-library/jest-dom'; test('renders and opens the dialog when isOpen is true', () => { const onClose = jest.fn(); const children =
Test Content
; - render({children}); + render( + + {children} + + ); // Dialog should be in the document const dialogElement = screen.getByRole('dialog'); @@ -25,7 +29,11 @@ test('does not render and closes the dialog when isOpen is false', () => { const onClose = jest.fn(); const children =
Test Content
; - render({children}); + render( + + {children} + + ); // Dialog should not be in the document const dialogElement = screen.queryByRole('dialog'); @@ -36,7 +44,11 @@ test('calls onClose when clicking outside the dialog', () => { const onClose = jest.fn(); const children =
Test Content
; - render({children}); + render( + + {children} + + ); // Click outside the dialog fireEvent.click(screen.getByTestId('dialog-root')); diff --git a/frontend/src/components/Dialog/Dialog.tsx b/frontend/src/components/Dialog/Dialog.tsx index e69de29..9c4c728 100644 --- a/frontend/src/components/Dialog/Dialog.tsx +++ b/frontend/src/components/Dialog/Dialog.tsx @@ -0,0 +1,109 @@ +import React, { useEffect, useRef, useCallback, type ReactNode } from 'react'; +import closeStyle from './Close.module.css'; +import styles from './Dialog.module.css'; +import { modalStack } from './DialogManager'; + +type ModalProps = { + children: ReactNode; + isOpen: boolean; + onClose: () => void; +}; + +export const Dialog: React.FC = (props: ModalProps) => { + const dialogRef = useRef(null); + const dialogRootRef = useRef(null); + const { isOpen, onClose, children } = props; + + // Handle tab key press + const handleTabKey = useCallback((event: KeyboardEvent) => { + if (event.key === 'Tab') { + const focusableElements = + dialogRef.current?.querySelectorAll( + 'a[href], button, textarea, input[type="text"], input[type="radio"], input[type="checkbox"], select' + ); + + if (!focusableElements || focusableElements.length === 0) return; + + const firstFocusableElement = focusableElements[0]; + const lastFocusableElement = + focusableElements[focusableElements.length - 1]; + + if (event.shiftKey && document.activeElement === firstFocusableElement) { + event.preventDefault(); + lastFocusableElement?.focus(); + } else if ( + !event.shiftKey && + document.activeElement === lastFocusableElement + ) { + event.preventDefault(); + firstFocusableElement?.focus(); + } + } + }, []); + + useEffect(() => { + if (isOpen) { + modalStack.add(dialogRef.current as HTMLDialogElement); + document.addEventListener('keydown', handleTabKey); + document.body.classList.add(styles['blockScrolling'] as string); + } else { + modalStack.delete(dialogRef.current as HTMLDialogElement); + document.removeEventListener('keydown', handleTabKey); + document.body.classList.remove(styles['blockScrolling'] as string); + } + + return () => { + document.removeEventListener('keydown', handleTabKey); + document.body.classList.remove(styles['blockScrolling'] as string); + }; + }, [isOpen, handleTabKey]); + + // Close modal, either by clicking on the backdrop or the "close" icon. + const handleClose = useCallback(() => { + // @ts-expect-error will be refactored + dialogRootRef.current?.classList.add(styles.dialogRootFadeOut); + setTimeout(() => { + // @ts-expect-error will be refactored + dialogRootRef.current?.classList.toggle(styles.dialogRootFadeOut); + // @ts-expect-error will be refactored + dialogRootRef.current?.classList.add(styles.hide); + }, 250); + + // Calls the user of this component passed event handler. + setTimeout(onClose, 500); + modalStack.delete(dialogRef.current as HTMLDialogElement); + }, [onClose]); + + // Close modal when clicking outside of it + const handleOutsideClick = useCallback( + (event: React.MouseEvent) => { + event.stopPropagation(); + + // eslint-disable-next-line eqeqeq + const modalStackArray = [...modalStack]; + if ( + event.target === dialogRootRef.current && + modalStackArray.at(-1) === dialogRef.current + ) { + handleClose(); + } + }, + [handleClose] + ); + + if (!isOpen) return null; + + return ( +
+ + + {children} + +
+ ); +}; diff --git a/frontend/src/components/Dialog/DialogModal.test.tsx b/frontend/src/components/Dialog/DialogModal.test.tsx new file mode 100644 index 0000000..be09521 --- /dev/null +++ b/frontend/src/components/Dialog/DialogModal.test.tsx @@ -0,0 +1,73 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { DialogModal as Dialog } from './DialogModal'; +import '@testing-library/jest-dom'; +import {describe} from "@jest/globals"; + +describe('DialogModal', () => { + test('renders and opens the dialog when isOpen is true', () => { + const onClose = jest.fn(); + const children =
Test Content
; + + render( + + {children} + + ); + + // Dialog should be in the document + const dialogElement = screen.getByTestId('dialog'); + expect(dialogElement).toBeInTheDocument(); + + // Dialog should have the "open" attribute set to true + setTimeout(() => { + expect(dialogElement).toHaveAttribute('open', ''); + }, 500); + + // Children should be rendered inside the dialog + const childElement = screen.getByText('Test Content'); + expect(childElement).toBeInTheDocument(); + }); + + test('does not render and closes the dialog when isOpen is false', () => { + const onClose = jest.fn(); + const children =
Test Content
; + + render( + + {children} + + ); + + // Dialog should not be in the document + const dialogElement = screen.queryByRole('dialog'); + expect(dialogElement).not.toBeInTheDocument(); + }); + + test('calls onClose when clicking outside the dialog', () => { + const onClose = jest.fn(); + const children =
Test Content
; + + render( + + {children} + + ); + + // Click outside the dialog + fireEvent( + document, + new MouseEvent('click', { + bubbles: true, + cancelable: true, + clientX: 25, + clientY: 25, + }) + ); + + // onClose should be called + setTimeout(() => { + expect(onClose).toHaveBeenCalledTimes(1); + }, 500); + }); +}) diff --git a/frontend/src/components/Dialog/DialogModal.tsx b/frontend/src/components/Dialog/DialogModal.tsx new file mode 100644 index 0000000..78386ae --- /dev/null +++ b/frontend/src/components/Dialog/DialogModal.tsx @@ -0,0 +1,99 @@ +import React, { + useEffect, + useRef, + useCallback, + type ReactNode, +} from 'react'; +import closeStyle from './Close.module.css'; +import styles from './Dialog.module.css'; +import { modalStack } from "./DialogManager"; + +type ModalProps = { + children: ReactNode; + closeOnBackdropClick?: boolean; + isOpen: boolean; + onClose: () => void; +}; + +export const DialogModal: React.FC = (props: ModalProps) => { + const dialogRef = useRef(null); + const { closeOnBackdropClick = true, isOpen, onClose, children } = props; + + // Close modal, either by clicking on the backdrop or the "close" icon. + const handleClose = useCallback(() => { + dialogRef.current?.classList.add(styles['close'] as string); + setTimeout(() => { + if (dialogRef.current?.open) { + dialogRef.current.close(); + dialogRef.current.classList.remove(styles['close'] as string); + } + + onClose(); + }, 250); + + modalStack.delete(dialogRef.current as HTMLDialogElement); + }, [onClose]); + + useEffect(() => { + if (isOpen) { + modalStack.add(dialogRef.current as HTMLDialogElement); + setTimeout(() => { + if (!dialogRef.current?.open) { + dialogRef.current?.showModal(); + } + + document.body.classList.add(styles['blockScrolling'] as string); + }, 250); + } else { + // handleClose(); + document.body.classList.remove(styles['blockScrolling'] as string); + } + + return () => { + document.body.classList.remove(styles['blockScrolling'] as string); + }; + }, [isOpen]); + + // Close modal when clicking outside of it + const handleOutsideClick = useCallback( + (event: React.MouseEvent) => { + event.stopPropagation(); + const rect = dialogRef.current?.getBoundingClientRect() as DOMRect; + const isInDialog = + rect.top <= event.clientY && + event.clientY <= rect.top + rect.height && + rect.left <= event.clientX && + event.clientX <= rect.left + rect.width; + + const modalStackArray = [...modalStack]; + if ( + !isInDialog && + closeOnBackdropClick && + modalStackArray.at(-1) === dialogRef.current + ) { + handleClose(); + } + }, + [closeOnBackdropClick, handleClose] + ); + + if (!isOpen) return null; + + return ( + + + × + + {children} + + ); +}; diff --git a/frontend/src/components/Dialog/DialogNonModal.test.tsx b/frontend/src/components/Dialog/DialogNonModal.test.tsx new file mode 100644 index 0000000..e192dda --- /dev/null +++ b/frontend/src/components/Dialog/DialogNonModal.test.tsx @@ -0,0 +1,62 @@ +import { render, screen, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { DialogNonModal as Dialog } from './DialogNonModal'; +import '@testing-library/jest-dom'; + +describe('DialogNonModal', () => { + test('renders and opens the dialog when isOpen is true', () => { + const onClose = jest.fn(); + const children =
Test Content
; + + render( + + {children} + + ); + + // Dialog should be in the document + const dialogElement = screen.getByRole('dialog'); + expect(dialogElement).toBeInTheDocument(); + + // Dialog should have the "open" attribute set to true + expect(dialogElement).toHaveAttribute('open', ''); + + // Children should be rendered inside the dialog + const childElement = screen.getByText('Test Content'); + expect(childElement).toBeInTheDocument(); + }); + + test('does not render and closes the dialog when isOpen is false', () => { + const onClose = jest.fn(); + const children =
Test Content
; + + render( + + {children} + + ); + + // Dialog should not be in the document + const dialogElement = screen.queryByRole('dialog'); + expect(dialogElement).not.toBeInTheDocument(); + }); + + test('calls onClose when clicking outside the dialog', () => { + const onClose = jest.fn(); + const children =
Test Content
; + + render( + + {children} + + ); + + // Click outside the dialog + fireEvent.click(screen.getByTestId('dialog-root')); + + // onClose should be called + setTimeout(() => { + expect(onClose).toHaveBeenCalledTimes(1); + }, 1_500); + }); +}); diff --git a/frontend/src/components/Dialog/DialogNonModal.tsx b/frontend/src/components/Dialog/DialogNonModal.tsx new file mode 100644 index 0000000..53529c2 --- /dev/null +++ b/frontend/src/components/Dialog/DialogNonModal.tsx @@ -0,0 +1,137 @@ +import React, { + useEffect, + useRef, + useCallback, + useState, + type ReactNode, + type SyntheticEvent, +} from 'react'; +import closeStyle from './Close.module.css'; +import styles from './Dialog.module.css'; +import { modalStack } from "./DialogManager"; + +type ModalProps = { + children: ReactNode; + closeOnBackdropClick?: boolean; + isOpen: boolean; + onClose: (event: KeyboardEvent | SyntheticEvent) => void; +}; +export const DialogNonModal: React.FC = (props: ModalProps) => { + const dialogRef = useRef(null); + const dialogRootRef = useRef(null); + const [zIndex, setZIndex] = useState(0); + const { closeOnBackdropClick = true, isOpen, onClose, children } = props; + + // Handle tab key press + const handleTabKey = useCallback((event: KeyboardEvent) => { + if (event.key === 'Tab') { + if (!dialogRef.current?.contains(event.target as Node)) { + event.preventDefault(); + event.stopPropagation(); + return; + } + + const focusableElements = dialogRef.current.querySelectorAll( + 'a[href], button, textarea, input, select' + ); + // Removes elements which have the tabIndex set to "-1" i.e. are not focusable and + // sorts again by the tabIndex itself, because querySelectorAll returns the DOM order. + const filteredElements = [ + ...(focusableElements as NodeListOf), + ] + .filter((domElement) => domElement.tabIndex !== -1) + .sort((a, b) => a.tabIndex - b.tabIndex); + + if (filteredElements.length === 0) return; + + const firstFocusableElement = filteredElements.at(0); + const lastFocusableElement = filteredElements.at(-1); + + if (event.shiftKey && document.activeElement === firstFocusableElement) { + event.preventDefault(); + lastFocusableElement?.focus(); + } else if ( + !event.shiftKey && + document.activeElement === lastFocusableElement + ) { + event.preventDefault(); + firstFocusableElement?.focus(); + } + } + }, []); + + // Close modal, either by clicking on the backdrop or the "close" icon. + const handleClose = useCallback(() => { + dialogRootRef.current?.classList.remove(styles['dialogRootShow'] as string); + + // Calls the user of this component passed event handler. + setTimeout(onClose, 250); + modalStack.delete(dialogRef.current as HTMLDialogElement); + }, [onClose]); + + useEffect(() => { + if (isOpen) { + modalStack.add(dialogRef.current as HTMLDialogElement); + setZIndex( + 10_000 + [...modalStack].indexOf(dialogRef.current as HTMLDialogElement) + ); + setTimeout(() => { + dialogRootRef.current?.classList.add( + styles['dialogRootShow'] as string + ); + }, 0); + document.addEventListener('keydown', handleTabKey); + document.body.classList.add(styles['blockScrolling'] as string); + } else { + handleClose(); + document.removeEventListener('keydown', handleTabKey); + document.body.classList.remove(styles['blockScrolling'] as string); + } + + return () => { + document.removeEventListener('keydown', handleTabKey); + document.body.classList.remove(styles['blockScrolling'] as string); + }; + }, [isOpen, handleClose, handleTabKey]); + + // Close modal when clicking outside of it + const handleOutsideClick = useCallback( + (event: React.MouseEvent) => { + event.stopPropagation(); + + // eslint-disable-next-line eqeqeq + const modalStackArray = [...modalStack]; + if ( + event.target === dialogRootRef.current && + modalStackArray.at(-1) === dialogRef.current + ) { + handleClose(); + } + }, + [handleClose] + ); + + if (!isOpen) return null; + + return ( +
{}} + ref={dialogRootRef} + style={{ zIndex }} + > + + + × + + {children} + +
+ ); +}; diff --git a/frontend/src/components/Dialog/README.md b/frontend/src/components/Dialog/README.md index cce374d..2217793 100644 --- a/frontend/src/components/Dialog/README.md +++ b/frontend/src/components/Dialog/README.md @@ -1,7 +1,12 @@ ## Dialog Component @ Contra ### Thought process -This is an interview, of course, but anyways in my mind I designed this component to be used in a design system, that can be reused across applications. So I made very few assumptions of what and how this component shall be used. +This is an interview, of course, but in my mind I designed this component to be used in a design system, that can be reused across applications. So I made very few assumptions of what and how this component shall be used. + +### Learnings +The difficult part was how dialog is treated from the browser itself. Only when called via `showModal` the element is displayed in its top layer and has the features like trapping focus and the backdrop. +If we use `open` to be more React-like, the element itself behaves in a non-modal way. +Because of this behaviour there's no simple "one-size-fits-all" solution, and we must leave some of the details to the consumer of the component, but with proper documentation, easing their own experience. ### Implementation To use this component, your `onClose` prop MUST call a function that sets the state variable of `isOpen` back to `false`, such as: @@ -16,8 +21,9 @@ This component can be extended to support additional styles, either for the dial ### Props -| Name | Type | Default | Description | -|----------|---------------------|---------|----------------------------------------------------------------------------------------------------------------------------------| -| children | ReactNode | null | Child elements for the dialog. | -| isOpen | boolean | - | Whether the dialog should be open (required) | -| onClose | function | null | Function that updates isOpen to switch to true or false (required) | +| Name | Type | Default | Description | +|----------------------|---------------------|---------|----------------------------------------------------------------------| +| children | ReactNode | null | Child elements for the dialog. | +| isOpen | boolean | - | Whether the dialog should be open (required) | +| closeOnBackdropClick | boolean | true | Whether the dialog closes when clicking the backdrop | +| onClose | function | null | Function that updates isOpen to switch from true to false (required) | diff --git a/frontend/src/components/Dialog/index.tsx b/frontend/src/components/Dialog/index.tsx index 9f3f1ea..96ae125 100644 --- a/frontend/src/components/Dialog/index.tsx +++ b/frontend/src/components/Dialog/index.tsx @@ -1,109 +1,3 @@ -import React, { useEffect, useRef, useCallback, type ReactNode } from 'react'; -import closeStyle from './Close.module.css'; -import styles from './Dialog.module.css'; -import { modalStack } from './DialogManager'; - -type ModalProps = { - children: ReactNode; - isOpen: boolean; - onClose: () => void; -}; - -export const Dialog: React.FC = (props: ModalProps) => { - const dialogRef = useRef(null); - const dialogRootRef = useRef(null); - const { isOpen, onClose, children } = props; - - // Handle tab key press - const handleTabKey = useCallback((event: KeyboardEvent) => { - if (event.key === 'Tab') { - const focusableElements = - dialogRef.current?.querySelectorAll( - 'a[href], button, textarea, input[type="text"], input[type="radio"], input[type="checkbox"], select' - ); - - if (!focusableElements || focusableElements.length === 0) return; - - const firstFocusableElement = focusableElements[0]; - const lastFocusableElement = - focusableElements[focusableElements.length - 1]; - - if (event.shiftKey && document.activeElement === firstFocusableElement) { - event.preventDefault(); - lastFocusableElement?.focus(); - } else if ( - !event.shiftKey && - document.activeElement === lastFocusableElement - ) { - event.preventDefault(); - firstFocusableElement?.focus(); - } - } - }, []); - - useEffect(() => { - if (isOpen) { - modalStack.add(dialogRef.current as HTMLDialogElement); - document.addEventListener('keydown', handleTabKey); - document.body.classList.add(styles.blockScrolling); - } else { - modalStack.delete(dialogRef.current as HTMLDialogElement); - document.removeEventListener('keydown', handleTabKey); - document.body.classList.remove(styles.blockScrolling); - } - - return () => { - document.removeEventListener('keydown', handleTabKey); - document.body.classList.remove(styles.blockScrolling); - }; - }, [isOpen, handleTabKey]); - - // Close modal, either by clicking on the backdrop or the "close" icon. - const handleClose = useCallback(() => { - // @ts-expect-error will be refactored - dialogRootRef.current?.classList.add(styles.dialogRootFadeOut); - setTimeout(() => { - // @ts-expect-error will be refactored - dialogRootRef.current?.classList.toggle(styles.dialogRootFadeOut); - // @ts-expect-error will be refactored - dialogRootRef.current?.classList.add(styles.hide); - }, 250); - - // Calls the user of this component passed event handler. - setTimeout(onClose, 500); - modalStack.delete(dialogRef.current as HTMLDialogElement); - }, [onClose]); - - // Close modal when clicking outside of it - const handleOutsideClick = useCallback( - (event: MouseEvent) => { - event.stopPropagation(); - - // eslint-disable-next-line eqeqeq - const modalStackArray = [...modalStack]; - if ( - event.target === dialogRootRef.current && - modalStackArray.at(-1) === dialogRef.current - ) { - handleClose(); - } - }, - [handleClose] - ); - - if (!isOpen) return null; - - return ( -
- - - {children} - -
- ); -}; +export * from './Dialog'; +export * from './DialogModal'; +export * from './DialogNonModal'; diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index c55a1c9..79ac5f1 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -1,13 +1,18 @@ /* eslint-disable canonical/filename-match-exported */ import { type NextPage } from 'next'; import { Dialog } from 'components/Dialog'; +import { DialogModal } from 'components/Dialog/DialogModal'; +import { DialogNonModal } from 'components/Dialog/DialogNonModal'; import { useState } from 'react'; const toggleState = (previousState: boolean) => !previousState; const Index: NextPage = () => { - const [dialogOneOpen, setDialogOneOpen] = useState(true); - const [dialogTwoOpen, setDialogTwoOpen] = useState(true); + const [dialogOneOpen, setDialogOneOpen] = useState(false); + const [dialogTwoOpen, setDialogTwoOpen] = useState(false); + const [dialogModal, setDialogModal] = useState(false); + const [dialogNonModal, setDialogNonModal] = useState(false); + if (typeof window !== 'undefined') document.body.style.height = '3000px'; return ( <> @@ -18,7 +23,21 @@ const Index: NextPage = () => { - {/* eslint-disable-next-line no-console */} + + + setDialogOneOpen(toggleState)} @@ -29,9 +48,26 @@ const Index: NextPage = () => { isOpen={dialogTwoOpen} onClose={() => setDialogTwoOpen(toggleState)} > - + + + + + setDialogModal(false)}> +

This is testing the Dialog Modal.

+ + + + + +
+ setDialogNonModal(false)} + > +

This is testing the Dialog Non Modal.

+
); };