From db6c8ccab4b3f22b012a24527a218edf705f88ef Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 27 Jul 2024 18:58:52 +0900 Subject: [PATCH 1/9] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9D=B4=EB=93=9C?= =?UTF-8?q?=EB=B0=94=EB=A5=BC=20=EB=8B=AB=EB=8A=94=20=EC=95=A0=EB=8B=88?= =?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/useSidebar.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/hooks/useSidebar.ts b/frontend/src/hooks/useSidebar.ts index 3e18260e7..50feb9344 100644 --- a/frontend/src/hooks/useSidebar.ts +++ b/frontend/src/hooks/useSidebar.ts @@ -1,21 +1,19 @@ import { useState } from 'react'; const useSidebar = () => { - const CLOSE_TIME = 1000; const OPEN_TIME = 0.5; const [isSidebarModalOpen, setIsSidebarModalOpen] = useState(false); const [isSidebarHidden, setIsSidebarHidden] = useState(true); const closeSidebar = () => { + setIsSidebarModalOpen(false); setIsSidebarHidden(true); - setTimeout(() => { - setIsSidebarModalOpen(false); - }, CLOSE_TIME); }; const openSidebar = () => { setIsSidebarModalOpen(true); + setTimeout(() => { setIsSidebarHidden(false); }, OPEN_TIME); From 819384191aa1c6b67b0296eabc03e07e81d7bafb Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 27 Jul 2024 18:59:25 +0900 Subject: [PATCH 2/9] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9D=B4=EB=93=9C?= =?UTF-8?q?=EB=B0=94=EA=B0=80=20=EB=8D=94=20=EB=B9=A8=EB=A6=AC=20=EC=97=B4?= =?UTF-8?q?=EB=A6=AC=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/modals/SideModal/styles.ts | 2 +- frontend/src/hooks/useSidebar.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/common/modals/SideModal/styles.ts b/frontend/src/components/common/modals/SideModal/styles.ts index acfa0d454..c64b13db8 100644 --- a/frontend/src/components/common/modals/SideModal/styles.ts +++ b/frontend/src/components/common/modals/SideModal/styles.ts @@ -8,5 +8,5 @@ export const SidebarWrapper = styled.div` position: absolute; top: 0; left: ${(props) => (props.$isSidebarHidden ? '-100%' : 0)}; - transition: left 1s ease-in-out; + transition: left 0.2s ease-in-out; `; diff --git a/frontend/src/hooks/useSidebar.ts b/frontend/src/hooks/useSidebar.ts index 50feb9344..c117e6ecc 100644 --- a/frontend/src/hooks/useSidebar.ts +++ b/frontend/src/hooks/useSidebar.ts @@ -1,7 +1,7 @@ import { useState } from 'react'; const useSidebar = () => { - const OPEN_TIME = 0.5; + const OPEN_TIME = 0.2; const [isSidebarModalOpen, setIsSidebarModalOpen] = useState(false); const [isSidebarHidden, setIsSidebarHidden] = useState(true); From 3a3a277ca11ff65c12be694601163801c4c979f1 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 27 Jul 2024 21:43:55 +0900 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=EB=AA=A8=EB=8B=AC=EC=9D=98=20?= =?UTF-8?q?=EB=B0=B0=EA=B2=BD=20=ED=81=B4=EB=A6=AD=20=EB=B0=8F=20esc=20?= =?UTF-8?q?=ED=82=A4=EB=A5=BC=20=EB=88=8C=EB=A0=80=EC=9D=84=20=EB=95=8C=20?= =?UTF-8?q?=EB=AA=A8=EB=8B=AC=EC=9D=B4=20=EB=8B=AB=ED=9E=88=EB=8A=94=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.tsx | 2 +- .../common/modals/SideModal/index.tsx | 13 +++++-- frontend/src/hooks/useModalClose.ts | 35 +++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 frontend/src/hooks/useModalClose.ts diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c9c093b6e..603c083ed 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -9,7 +9,7 @@ const App = () => { return ( {isSidebarModalOpen && ( - + )} diff --git a/frontend/src/components/common/modals/SideModal/index.tsx b/frontend/src/components/common/modals/SideModal/index.tsx index 9513eb71b..d75d51ba6 100644 --- a/frontend/src/components/common/modals/SideModal/index.tsx +++ b/frontend/src/components/common/modals/SideModal/index.tsx @@ -1,6 +1,7 @@ -import React, { PropsWithChildren } from 'react'; +import React, { PropsWithChildren, useRef } from 'react'; import ModalPortal from '@/components/common/modals/ModalPortal'; +import useModalClose from '@/hooks/useModalClose'; import ModalBackground from '../ModalBackground'; @@ -8,13 +9,19 @@ import * as S from './styles'; interface SideModalProps { isSidebarHidden: boolean; + closeModal: () => void; } -const SideModal: React.FC> = ({ children: Sidebar, isSidebarHidden }) => { +const SideModal: React.FC> = ({ children: Sidebar, isSidebarHidden, closeModal }) => { + const modalRef = useRef(null); + useModalClose(closeModal, modalRef); + return ( - {Sidebar} + + {Sidebar} + ); diff --git a/frontend/src/hooks/useModalClose.ts b/frontend/src/hooks/useModalClose.ts new file mode 100644 index 000000000..95e85bcf7 --- /dev/null +++ b/frontend/src/hooks/useModalClose.ts @@ -0,0 +1,35 @@ +import { useEffect, RefObject } from 'react'; + +const useModalClose = (closeModal: () => void, modalRef: RefObject) => { + const isNodeElement = (element: EventTarget | null): element is Node => { + return element instanceof Node; + }; + + const isModalChildren = (targetElement: Node | null) => { + return modalRef.current ? modalRef.current.contains(targetElement) : false; + }; + + useEffect(() => { + const handleBackgroundClick = (event: MouseEvent) => { + if (isNodeElement(event.target) && !isModalChildren(event.target)) { + closeModal(); + } + }; + + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') closeModal(); + }; + + // NOTE: 모달을 여는 클릭 이벤트가 모달을 닫는 핸들러의 이벤트로 들어가는 것을 막기 위해 + // 모달을 닫는 클릭 이벤트에 대한 핸들러를 capture 단계에서 추가 + document.addEventListener('click', handleBackgroundClick, true); + document.addEventListener('keydown', handleKeyDown); + + return () => { + document.removeEventListener('click', handleBackgroundClick, true); + document.removeEventListener('keydown', handleKeyDown); + }; + }, [closeModal, modalRef]); +}; + +export default useModalClose; From c0923c1d19b03df7827a6346326611165d3435fe Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 27 Jul 2024 21:49:40 +0900 Subject: [PATCH 4/9] =?UTF-8?q?chore:=20hooks=20index=EC=97=90=20useModalC?= =?UTF-8?q?lose=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/modals/SideModal/index.tsx | 2 +- frontend/src/hooks/index.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/common/modals/SideModal/index.tsx b/frontend/src/components/common/modals/SideModal/index.tsx index d75d51ba6..6a53fdc0c 100644 --- a/frontend/src/components/common/modals/SideModal/index.tsx +++ b/frontend/src/components/common/modals/SideModal/index.tsx @@ -1,7 +1,7 @@ import React, { PropsWithChildren, useRef } from 'react'; import ModalPortal from '@/components/common/modals/ModalPortal'; -import useModalClose from '@/hooks/useModalClose'; +import { useModalClose } from '@/hooks'; import ModalBackground from '../ModalBackground'; diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts index 3e0c491d6..470a24f9d 100644 --- a/frontend/src/hooks/index.ts +++ b/frontend/src/hooks/index.ts @@ -1 +1,2 @@ export { default as useSidebar } from './useSidebar'; +export { default as useModalClose } from './useModalClose'; From e9719ea097d1dad6e7855d008f005e3e32b23781 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sat, 27 Jul 2024 21:55:30 +0900 Subject: [PATCH 5/9] =?UTF-8?q?feat:=20=EC=82=AC=EC=9D=B4=EB=93=9C?= =?UTF-8?q?=EB=B0=94=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=ED=85=9C=EC=9D=84=20=ED=81=B4=EB=A6=AD=ED=96=88=EC=9D=84=20?= =?UTF-8?q?=EB=95=8C=20=EC=82=AC=EC=9D=B4=EB=93=9C=EB=B0=94=EA=B0=80=20?= =?UTF-8?q?=EB=8B=AB=ED=9E=88=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/layouts/Sidebar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/layouts/Sidebar/index.tsx b/frontend/src/components/layouts/Sidebar/index.tsx index b89589fe6..6f15f78a1 100644 --- a/frontend/src/components/layouts/Sidebar/index.tsx +++ b/frontend/src/components/layouts/Sidebar/index.tsx @@ -43,7 +43,7 @@ const Sidebar = ({ closeSidebar }: SidebarProps) => { {menuItems.map((item) => ( - {item.label} + {item.label} ))} From d708d72932e9a4c444d5c198338d958aaee9ac31 Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Sun, 28 Jul 2024 21:52:38 +0900 Subject: [PATCH 6/9] =?UTF-8?q?refactor:=20useModalClose=20=ED=9B=85?= =?UTF-8?q?=EC=9D=84=20=EB=AA=A8=EB=93=A0=20=EB=AA=A8=EB=8B=AC=EC=9D=98=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=EC=B5=9C=EC=83=81=EC=9C=84=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=9D=B8=20ModalBackground=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modals/ModalBackground/index.tsx | 19 ++++++++++++++++--- .../common/modals/SideModal/index.tsx | 12 +++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/frontend/src/components/common/modals/ModalBackground/index.tsx b/frontend/src/components/common/modals/ModalBackground/index.tsx index 4696030b4..9dcb65833 100644 --- a/frontend/src/components/common/modals/ModalBackground/index.tsx +++ b/frontend/src/components/common/modals/ModalBackground/index.tsx @@ -1,9 +1,22 @@ -import React from 'react'; +import React, { PropsWithChildren, useRef } from 'react'; + +import { useModalClose } from '@/hooks'; import * as S from './styles'; -const ModalBackground = ({ children }: React.PropsWithChildren) => { - return {children}; +interface ModalBackgroundProps { + closeModal: () => void; +} + +const ModalBackground: React.FC> = ({ children, closeModal }) => { + const modalRef = useRef(null); + useModalClose(closeModal, modalRef); + + return ( + +
{children}
+
+ ); }; export default ModalBackground; diff --git a/frontend/src/components/common/modals/SideModal/index.tsx b/frontend/src/components/common/modals/SideModal/index.tsx index 6a53fdc0c..0041b6777 100644 --- a/frontend/src/components/common/modals/SideModal/index.tsx +++ b/frontend/src/components/common/modals/SideModal/index.tsx @@ -1,7 +1,6 @@ -import React, { PropsWithChildren, useRef } from 'react'; +import React, { PropsWithChildren } from 'react'; import ModalPortal from '@/components/common/modals/ModalPortal'; -import { useModalClose } from '@/hooks'; import ModalBackground from '../ModalBackground'; @@ -13,15 +12,10 @@ interface SideModalProps { } const SideModal: React.FC> = ({ children: Sidebar, isSidebarHidden, closeModal }) => { - const modalRef = useRef(null); - useModalClose(closeModal, modalRef); - return ( - - - {Sidebar} - + + {Sidebar} ); From c88b09e83960c0dfeb70fb06867e10120757da7a Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Mon, 29 Jul 2024 19:05:15 +0900 Subject: [PATCH 7/9] =?UTF-8?q?refactor:=20ModalBackground=EB=A5=BC=20?= =?UTF-8?q?=ED=81=B4=EB=A6=AD=ED=96=88=EC=9D=84=20=EB=95=8C=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=EC=9D=B4=20=EB=8B=AB=ED=9E=88=EA=B2=8C=20=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=EB=84=88=EB=A5=BC=20document=20=EB=8C=80=EC=8B=A0=20Background?= =?UTF-8?q?=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/modals/ModalBackground/index.tsx | 10 +++------- frontend/src/hooks/useModalClose.ts | 18 +++++++++--------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/common/modals/ModalBackground/index.tsx b/frontend/src/components/common/modals/ModalBackground/index.tsx index 9dcb65833..399859995 100644 --- a/frontend/src/components/common/modals/ModalBackground/index.tsx +++ b/frontend/src/components/common/modals/ModalBackground/index.tsx @@ -9,14 +9,10 @@ interface ModalBackgroundProps { } const ModalBackground: React.FC> = ({ children, closeModal }) => { - const modalRef = useRef(null); - useModalClose(closeModal, modalRef); + const modalBackgroundRef = useRef(null); + useModalClose(closeModal, modalBackgroundRef); - return ( - -
{children}
-
- ); + return {children}; }; export default ModalBackground; diff --git a/frontend/src/hooks/useModalClose.ts b/frontend/src/hooks/useModalClose.ts index 95e85bcf7..42744adfc 100644 --- a/frontend/src/hooks/useModalClose.ts +++ b/frontend/src/hooks/useModalClose.ts @@ -1,17 +1,17 @@ import { useEffect, RefObject } from 'react'; -const useModalClose = (closeModal: () => void, modalRef: RefObject) => { +const useModalClose = (closeModal: () => void, modalBackgroundRef: RefObject) => { const isNodeElement = (element: EventTarget | null): element is Node => { return element instanceof Node; }; - const isModalChildren = (targetElement: Node | null) => { - return modalRef.current ? modalRef.current.contains(targetElement) : false; + const isModalBackground = (targetElement: Node | null) => { + return modalBackgroundRef.current ? modalBackgroundRef.current === targetElement : false; }; useEffect(() => { const handleBackgroundClick = (event: MouseEvent) => { - if (isNodeElement(event.target) && !isModalChildren(event.target)) { + if (isNodeElement(event.target) && isModalBackground(event.target)) { closeModal(); } }; @@ -20,16 +20,16 @@ const useModalClose = (closeModal: () => void, modalRef: RefObject) if (event.key === 'Escape') closeModal(); }; - // NOTE: 모달을 여는 클릭 이벤트가 모달을 닫는 핸들러의 이벤트로 들어가는 것을 막기 위해 - // 모달을 닫는 클릭 이벤트에 대한 핸들러를 capture 단계에서 추가 - document.addEventListener('click', handleBackgroundClick, true); + const modalBackGroundElement = modalBackgroundRef.current; + + modalBackGroundElement?.addEventListener('click', handleBackgroundClick); document.addEventListener('keydown', handleKeyDown); return () => { - document.removeEventListener('click', handleBackgroundClick, true); + modalBackGroundElement?.removeEventListener('click', handleBackgroundClick); document.removeEventListener('keydown', handleKeyDown); }; - }, [closeModal, modalRef]); + }, [closeModal, modalBackgroundRef]); }; export default useModalClose; From 0ece398ea44e9ad122d34d8654685fee1a15f9cc Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Tue, 30 Jul 2024 11:28:54 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20esc=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=B4=20=EB=AA=A8=EB=8B=AC=EC=9D=84=20=EB=8B=AB=EC=95=98?= =?UTF-8?q?=EC=9D=84=20=EB=95=8C=20=ED=96=84=EB=B2=84=EA=B1=B0=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=EC=97=90=20=ED=8F=AC=EC=BB=A4=EC=8A=A4=EA=B0=80=20?= =?UTF-8?q?=EC=83=9D=EA=B8=B0=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20=EB=B0=8F=20=EB=B3=80=EC=88=98=EB=AA=85=20=EB=8C=80?= =?UTF-8?q?=EC=86=8C=EB=AC=B8=EC=9E=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/useModalClose.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/frontend/src/hooks/useModalClose.ts b/frontend/src/hooks/useModalClose.ts index 42744adfc..1c1f9fb72 100644 --- a/frontend/src/hooks/useModalClose.ts +++ b/frontend/src/hooks/useModalClose.ts @@ -9,6 +9,17 @@ const useModalClose = (closeModal: () => void, modalBackgroundRef: RefObject { + return element instanceof HTMLElement; + }; + + const blurFocusing = () => { + const activeElement = document.activeElement; + + if (!isHTMLElement(activeElement)) return; + if (typeof activeElement.blur === 'function') activeElement.blur(); + }; + useEffect(() => { const handleBackgroundClick = (event: MouseEvent) => { if (isNodeElement(event.target) && isModalBackground(event.target)) { @@ -17,16 +28,20 @@ const useModalClose = (closeModal: () => void, modalBackgroundRef: RefObject { - if (event.key === 'Escape') closeModal(); + if (event.key === 'Escape') { + event.preventDefault(); + blurFocusing(); + closeModal(); + } }; - const modalBackGroundElement = modalBackgroundRef.current; + const modalBackgroundElement = modalBackgroundRef.current; - modalBackGroundElement?.addEventListener('click', handleBackgroundClick); + modalBackgroundElement?.addEventListener('click', handleBackgroundClick); document.addEventListener('keydown', handleKeyDown); return () => { - modalBackGroundElement?.removeEventListener('click', handleBackgroundClick); + modalBackgroundElement?.removeEventListener('click', handleBackgroundClick); document.removeEventListener('keydown', handleKeyDown); }; }, [closeModal, modalBackgroundRef]); From 0400c776f3fa2cba54b4e9f4cc93e81cf8c821fd Mon Sep 17 00:00:00 2001 From: ImxYJL Date: Wed, 31 Jul 2024 11:31:00 +0900 Subject: [PATCH 9/9] =?UTF-8?q?refactor:=20useEffect=20=EB=82=B4=EB=B6=80?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=EB=93=A4=EC=9D=84=20=ED=9B=85=20=EC=99=B8?= =?UTF-8?q?=EB=B6=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20=EB=B0=8F=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/hooks/useModalClose.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/frontend/src/hooks/useModalClose.ts b/frontend/src/hooks/useModalClose.ts index 1c1f9fb72..96b465531 100644 --- a/frontend/src/hooks/useModalClose.ts +++ b/frontend/src/hooks/useModalClose.ts @@ -13,6 +13,7 @@ const useModalClose = (closeModal: () => void, modalBackgroundRef: RefObject { const activeElement = document.activeElement; @@ -20,21 +21,22 @@ const useModalClose = (closeModal: () => void, modalBackgroundRef: RefObject { - const handleBackgroundClick = (event: MouseEvent) => { - if (isNodeElement(event.target) && isModalBackground(event.target)) { - closeModal(); - } - }; + const handleBackgroundClick = (event: MouseEvent) => { + if (isNodeElement(event.target) && isModalBackground(event.target)) { + closeModal(); + } + }; - const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === 'Escape') { - event.preventDefault(); - blurFocusing(); - closeModal(); - } - }; + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + event.preventDefault(); + blurFocusing(); + closeModal(); + } + }; + + useEffect(() => { const modalBackgroundElement = modalBackgroundRef.current; modalBackgroundElement?.addEventListener('click', handleBackgroundClick);