From 6c5fb78e84eaa080e84409e2e874f88acdb1d1cb Mon Sep 17 00:00:00 2001 From: novice0840 Date: Wed, 16 Oct 2024 17:40:43 +0900 Subject: [PATCH 01/11] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20hook=20=EC=A0=9C=EA=B1=B0=20#3?= =?UTF-8?q?35?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/Modal/Modal.tsx | 1 - .../Modal/hooks/useDisableBackgroundScroll.ts | 15 --------------- 2 files changed, 16 deletions(-) delete mode 100644 frontend/src/components/common/Modal/hooks/useDisableBackgroundScroll.ts diff --git a/frontend/src/components/common/Modal/Modal.tsx b/frontend/src/components/common/Modal/Modal.tsx index 99ef66816..4fdc2a654 100644 --- a/frontend/src/components/common/Modal/Modal.tsx +++ b/frontend/src/components/common/Modal/Modal.tsx @@ -1,7 +1,6 @@ import React, { ButtonHTMLAttributes, HTMLAttributes, useRef } from 'react'; import ReactDOM from 'react-dom'; -import useDisableBackgroundScroll from './hooks/useDisableBackgroundScroll'; import useModalEscClose from './hooks/useModalEscClose'; import { modalBackdropLayout, diff --git a/frontend/src/components/common/Modal/hooks/useDisableBackgroundScroll.ts b/frontend/src/components/common/Modal/hooks/useDisableBackgroundScroll.ts deleted file mode 100644 index ccd6004c6..000000000 --- a/frontend/src/components/common/Modal/hooks/useDisableBackgroundScroll.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useEffect } from 'react'; - -const useDisableBackgroundScroll = (isOpen: boolean) => { - useEffect(() => { - if (isOpen) { - document.body.style.overflow = 'hidden'; - - return () => { - document.body.style.overflow = 'auto'; - }; - } - }, [isOpen]); -}; - -export default useDisableBackgroundScroll; From 136e9c3f109e9fb2b6214837f52561c0298ec4c0 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Wed, 16 Oct 2024 19:11:55 +0900 Subject: [PATCH 02/11] =?UTF-8?q?refactor:=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=20=EC=B2=AB=20=EB=A1=9C=EB=94=A9=20=EC=8B=9C=20header=EB=A1=9C?= =?UTF-8?q?=20focus=20=EC=9D=B4=EB=8F=99=20#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/layout/Header/Header.tsx | 15 ++++++++------- frontend/src/hooks/useFocus.ts | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 frontend/src/hooks/useFocus.ts diff --git a/frontend/src/components/layout/Header/Header.tsx b/frontend/src/components/layout/Header/Header.tsx index 61d4219c1..b520063d5 100644 --- a/frontend/src/components/layout/Header/Header.tsx +++ b/frontend/src/components/layout/Header/Header.tsx @@ -1,3 +1,4 @@ +/* eslint-disable jsx-a11y/no-noninteractive-tabindex */ import { useNavigate, useParams } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; @@ -21,6 +22,7 @@ import SettingIcon from '@/assets/images/settingsIcon.webp'; import RoomSettingModal from '@/components/common/RoomSettingModal/RoomSettingModal'; import { ROUTES } from '@/constants/routes'; import useBalanceContentQuery from '@/hooks/useBalanceContentQuery'; +import useFocus from '@/hooks/useFocus'; import useModal from '@/hooks/useModal'; import { memberInfoState } from '@/recoil/atom'; @@ -61,13 +63,13 @@ export const RoomSettingHeader = ({ title }: HeaderProps) => { const { show } = useModal(); const { handleExit } = useExit(); const { isMaster } = useRecoilValue(memberInfoState); - const handleClickRoomSetting = () => { show(RoomSettingModal); }; + const focusRef = useFocus(); return ( -
+
@@ -87,13 +89,12 @@ export const RoomSettingHeader = ({ title }: HeaderProps) => { export const RoundHeader = () => { const { roomId } = useParams(); const isRoundResultPage = location.pathname === ROUTES.roundResult(Number(roomId)); - const { balanceContent } = useBalanceContentQuery(Number(roomId)); - const title = isRoundResultPage ? '투표 결과' : '밸런스 게임'; + const focusRef = useFocus(); return ( -
+
{balanceContent.currentRound}/{balanceContent.totalRound} @@ -106,13 +107,13 @@ export const RoundHeader = () => { // 5. 좌측 상단 뒤로가기, 가운데 제목 차지하는 헤더 (API 호출 X) : 라운드 투표 현황 export const BackHeader = ({ title }: HeaderProps) => { const navigate = useNavigate(); - + const focusRef = useFocus(); const goToBack = () => { navigate(-1); }; return ( -
+
diff --git a/frontend/src/hooks/useFocus.ts b/frontend/src/hooks/useFocus.ts new file mode 100644 index 000000000..5265480e0 --- /dev/null +++ b/frontend/src/hooks/useFocus.ts @@ -0,0 +1,15 @@ +import { useEffect, useRef } from 'react'; + +const useFocus = () => { + const focusRef = useRef(null); + + useEffect(() => { + if (focusRef.current) { + focusRef.current.focus(); + } + }, []); + + return focusRef; +}; + +export default useFocus; From 495abec2dd202a0298052bdad70a4816e7439e11 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Wed, 16 Oct 2024 20:15:20 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20modal=20=EC=B0=BD=20=EB=9C=A8?= =?UTF-8?q?=EB=A9=B4=20modal=EB=A1=9C=20focus=20=EC=9D=B4=EB=8F=99=20#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/Modal/Modal.tsx | 12 ++++++++++-- frontend/src/index.tsx | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/common/Modal/Modal.tsx b/frontend/src/components/common/Modal/Modal.tsx index 4fdc2a654..5e5bab2c0 100644 --- a/frontend/src/components/common/Modal/Modal.tsx +++ b/frontend/src/components/common/Modal/Modal.tsx @@ -1,3 +1,4 @@ +/* eslint-disable jsx-a11y/no-noninteractive-tabindex */ import React, { ButtonHTMLAttributes, HTMLAttributes, useRef } from 'react'; import ReactDOM from 'react-dom'; @@ -16,6 +17,7 @@ import { } from './Modal.styled'; import CloseIcon from '@/assets/images/closeIcon.png'; +import useFocus from '@/hooks/useFocus'; export interface ModalProps extends React.PropsWithChildren<{ @@ -27,7 +29,7 @@ export interface ModalProps const Modal = ({ children, isOpen, onClose, position = 'center', ...restProps }: ModalProps) => { const modalRef = useRef(null); - + const focusRef = useFocus(); useModalEscClose(isOpen, onClose); const handleOutsideClick = (event: React.MouseEvent | React.KeyboardEvent) => { @@ -41,7 +43,13 @@ const Modal = ({ children, isOpen, onClose, position = 'center', ...restProps }: const modalContent = ( /* eslint jsx-a11y/no-static-element-interactions: "off" */ // 모달을 제외한 영역을 클릭시 모달이 꺼지도록 설정하기 위해 설정함 -
+
{children}
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 7ba7c7146..614eddc4d 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -26,7 +26,7 @@ const enableMocking = async () => { const { worker } = await import('./mocks/browser'); - return await worker.start(); + // return await worker.start(); }; enableMocking().then(() => { @@ -38,7 +38,7 @@ enableMocking().then(() => { - + {/* */} , From 1221f26c1380c1204661b036304c750f70beeba0 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Wed, 16 Oct 2024 20:16:12 +0900 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20index.tsx=20=EC=9E=98=EB=AA=BB?= =?UTF-8?q?=EB=90=9C=20=EC=A3=BC=EC=84=9D=20=EB=90=98=EB=8F=8C=EB=A6=BC=20?= =?UTF-8?q?#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 614eddc4d..7ba7c7146 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -26,7 +26,7 @@ const enableMocking = async () => { const { worker } = await import('./mocks/browser'); - // return await worker.start(); + return await worker.start(); }; enableMocking().then(() => { @@ -38,7 +38,7 @@ enableMocking().then(() => { - {/* */} + , From 1e93f1c385d7e620e3987278db989d9d47c895a1 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Fri, 18 Oct 2024 14:37:38 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20modal=20close=20=EC=8B=9C=20focus?= =?UTF-8?q?=20=EC=9B=90=EB=9E=98=EB=8C=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/RoomSetting/RoomSetting.tsx | 5 ++++- .../common/AlertModal/AlertModal.tsx | 7 ++++--- .../src/components/common/Modal/Modal.tsx | 20 +++++++++++++++++-- .../RoomSettingModal/RoomSettingModal.tsx | 7 +++++-- .../src/components/layout/Header/Header.tsx | 1 - .../providers/ModalProvider/ModalProvider.tsx | 4 +++- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/RoomSetting/RoomSetting.tsx b/frontend/src/components/RoomSetting/RoomSetting.tsx index e3fa55368..e0d99e4a6 100644 --- a/frontend/src/components/RoomSetting/RoomSetting.tsx +++ b/frontend/src/components/RoomSetting/RoomSetting.tsx @@ -1,3 +1,4 @@ +import { useRef } from 'react'; import { useRecoilValue } from 'recoil'; import { @@ -15,6 +16,7 @@ import useModal from '@/hooks/useModal'; import { memberInfoState } from '@/recoil/atom'; const RoomSetting = () => { + const closeRef = useRef(null); const { roomSetting } = useGetRoomInfo(); const { isMaster } = useRecoilValue(memberInfoState); const { show } = useModal(); @@ -25,7 +27,7 @@ const RoomSetting = () => { 타이머 ${roomSetting.timeLimit / 1000}초.`; const handleClickCategory = () => { - show(RoomSettingModal); + show(RoomSettingModal, { closeRef }); }; return ( @@ -35,6 +37,7 @@ const RoomSetting = () => { aria-label="방 설정" css={roomSettingLayout} onClick={isMaster ? handleClickCategory : () => {}} + ref={closeRef} >
라운드 diff --git a/frontend/src/components/common/AlertModal/AlertModal.tsx b/frontend/src/components/common/AlertModal/AlertModal.tsx index 1c81e6388..0bf1b211a 100644 --- a/frontend/src/components/common/AlertModal/AlertModal.tsx +++ b/frontend/src/components/common/AlertModal/AlertModal.tsx @@ -1,4 +1,4 @@ -import { Fragment } from 'react'; +import { Fragment, RefObject } from 'react'; import { alertModalTitle, alertText, messageContainer } from './AlertModal.styled'; import Modal from '../Modal/Modal'; @@ -9,16 +9,17 @@ interface AlertModalProps { onConfirm?: () => void; message?: string; title?: string; + closeRef?: RefObject; } -const AlertModal = ({ isOpen, onClose, onConfirm, message, title }: AlertModalProps) => { +const AlertModal = ({ isOpen, onClose, onConfirm, message, title, closeRef }: AlertModalProps) => { const handleClick = () => { onConfirm && onConfirm(); onClose(); }; return ( - + {title || '알림'} diff --git a/frontend/src/components/common/Modal/Modal.tsx b/frontend/src/components/common/Modal/Modal.tsx index 5e5bab2c0..9230c5c76 100644 --- a/frontend/src/components/common/Modal/Modal.tsx +++ b/frontend/src/components/common/Modal/Modal.tsx @@ -1,5 +1,5 @@ /* eslint-disable jsx-a11y/no-noninteractive-tabindex */ -import React, { ButtonHTMLAttributes, HTMLAttributes, useRef } from 'react'; +import React, { ButtonHTMLAttributes, HTMLAttributes, RefObject, useEffect, useRef } from 'react'; import ReactDOM from 'react-dom'; import useModalEscClose from './hooks/useModalEscClose'; @@ -25,9 +25,17 @@ export interface ModalProps onClose: () => void; position?: 'top' | 'bottom' | 'center'; style?: React.CSSProperties; + closeRef?: RefObject; }> {} -const Modal = ({ children, isOpen, onClose, position = 'center', ...restProps }: ModalProps) => { +const Modal = ({ + children, + isOpen, + onClose, + closeRef, + position = 'center', + ...restProps +}: ModalProps) => { const modalRef = useRef(null); const focusRef = useFocus(); useModalEscClose(isOpen, onClose); @@ -38,6 +46,14 @@ const Modal = ({ children, isOpen, onClose, position = 'center', ...restProps }: } }; + useEffect(() => { + return () => { + if (closeRef?.current) { + closeRef.current.focus(); + } + }; + }, [closeRef?.current]); + if (!isOpen) return null; const modalContent = ( diff --git a/frontend/src/components/common/RoomSettingModal/RoomSettingModal.tsx b/frontend/src/components/common/RoomSettingModal/RoomSettingModal.tsx index 300fa7208..8c3de9c7d 100644 --- a/frontend/src/components/common/RoomSettingModal/RoomSettingModal.tsx +++ b/frontend/src/components/common/RoomSettingModal/RoomSettingModal.tsx @@ -1,3 +1,5 @@ +import { RefObject } from 'react'; + import CategoryDropdown from './CategoryDropdown/CategoryDropdown'; import useRoomSetting from './hooks/useRoomSetting'; import RoomSettingContainer from './RoomSettingContainer/RoomSettingContainer'; @@ -17,9 +19,10 @@ const TIMER_PER_ROUND_LIST = [5000, 10000, 15000]; interface RoomSettingModalProps { isOpen: boolean; onClose: () => void; + closeRef?: RefObject; } -const RoomSettingModal = ({ isOpen, onClose }: RoomSettingModalProps) => { +const RoomSettingModal = ({ isOpen, onClose, closeRef }: RoomSettingModalProps) => { const { roomSetting, handleClickOption, @@ -31,7 +34,7 @@ const RoomSettingModal = ({ isOpen, onClose }: RoomSettingModalProps) => { const { category, totalRound, timeLimitPerRound } = roomSetting; return ( - + 방 설정 diff --git a/frontend/src/components/layout/Header/Header.tsx b/frontend/src/components/layout/Header/Header.tsx index 422c93830..d0b73e0c0 100644 --- a/frontend/src/components/layout/Header/Header.tsx +++ b/frontend/src/components/layout/Header/Header.tsx @@ -69,7 +69,6 @@ export const RoomSettingHeader = ({ title }: HeaderProps) => { const handleClickRoomSetting = () => { show(RoomSettingModal); }; - const focusRef = useFocus(); const handleClickExit = () => { show(AlertModal, { message: '정말로 나가시겠습니까?', onConfirm: handleExit }); diff --git a/frontend/src/providers/ModalProvider/ModalProvider.tsx b/frontend/src/providers/ModalProvider/ModalProvider.tsx index 38dcbf19e..afca7878d 100644 --- a/frontend/src/providers/ModalProvider/ModalProvider.tsx +++ b/frontend/src/providers/ModalProvider/ModalProvider.tsx @@ -1,9 +1,10 @@ -import { createContext, PropsWithChildren, useMemo, useState } from 'react'; +import { createContext, PropsWithChildren, RefObject, useMemo, useState } from 'react'; interface ModalProps { title?: string; message?: string; onConfirm?: () => void; + closeRef?: RefObject; } interface ModalState extends ModalProps { @@ -39,6 +40,7 @@ const ModalProvider = ({ children }: PropsWithChildren) => { message: props?.message, onConfirm: props?.onConfirm, isOpen: true, + closeRef: props?.closeRef, }); }; From 79f367f07046034b5e706b17048ca02f0decb488 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Fri, 18 Oct 2024 14:54:39 +0900 Subject: [PATCH 06/11] =?UTF-8?q?feat:=20=EC=B4=88=EB=8C=80=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=ED=81=B4=EB=A6=AD=20=EC=8B=9C?= =?UTF-8?q?=20=20focus=20=EC=9B=90=EB=9E=98=EB=8C=80=EB=A1=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyMembersContainer/ReadyMembersContainer.tsx | 7 ++++--- frontend/src/components/common/InviteModal/InviteModal.tsx | 6 ++++-- frontend/src/components/layout/Header/Header.tsx | 6 ++++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx b/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx index 1d2ec20e9..f6495be9a 100644 --- a/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx +++ b/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import { useRecoilState } from 'recoil'; import { @@ -25,9 +25,10 @@ const ReadyMembersContainer = () => { const { members, master } = useGetRoomInfo(); const { show } = useModal(); const [memberInfo, setMemberInfo] = useRecoilState(memberInfoState); + const closeRef = useRef(null); const handleClickInvite = () => { - show(InviteModal); + show(InviteModal, { closeRef }); }; // 원래 방장이 아니다 + 방장의 memberId와 내 memberId가 같다 -> 방장으로 변경 @@ -42,7 +43,7 @@ const ReadyMembersContainer = () => { 총 인원 {members.length}명
총 인원 {members.length}명
-
diff --git a/frontend/src/components/common/InviteModal/InviteModal.tsx b/frontend/src/components/common/InviteModal/InviteModal.tsx index 34bed3c62..33d490791 100644 --- a/frontend/src/components/common/InviteModal/InviteModal.tsx +++ b/frontend/src/components/common/InviteModal/InviteModal.tsx @@ -1,3 +1,4 @@ +import { RefObject } from 'react'; import QRCode from 'react-qr-code'; import { useRecoilValue } from 'recoil'; @@ -23,9 +24,10 @@ import { roomUuidState } from '@/recoil/atom'; interface InviteModalProps { isOpen: boolean; onClose: () => void; + closeRef?: RefObject; } -const InviteModal = ({ isOpen, onClose }: InviteModalProps) => { +const InviteModal = ({ isOpen, onClose, closeRef }: InviteModalProps) => { const roomUuid = useRecoilValue(roomUuidState); const inviteUrl = INVITE_URL(roomUuid); @@ -38,7 +40,7 @@ const InviteModal = ({ isOpen, onClose }: InviteModalProps) => { }; return ( - + 초대하기 diff --git a/frontend/src/components/layout/Header/Header.tsx b/frontend/src/components/layout/Header/Header.tsx index d0b73e0c0..adc048c7e 100644 --- a/frontend/src/components/layout/Header/Header.tsx +++ b/frontend/src/components/layout/Header/Header.tsx @@ -1,4 +1,5 @@ /* eslint-disable jsx-a11y/no-noninteractive-tabindex */ +import { useRef } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; @@ -65,9 +66,10 @@ export const RoomSettingHeader = ({ title }: HeaderProps) => { const { show } = useModal(); const { isMaster } = useRecoilValue(memberInfoState); const { handleExit } = useExit(); + const closeRef = useRef(null); const handleClickRoomSetting = () => { - show(RoomSettingModal); + show(RoomSettingModal, { closeRef }); }; const handleClickExit = () => { @@ -81,7 +83,7 @@ export const RoomSettingHeader = ({ title }: HeaderProps) => {

{title}

{isMaster ? ( - ) : ( From 3a7240b4d18c590e7808ebc72f1c0f581eb03fe6 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Fri, 18 Oct 2024 15:28:22 +0900 Subject: [PATCH 07/11] =?UTF-8?q?feat:=20modal=20=EB=8B=AB=ED=9E=90=20?= =?UTF-8?q?=EB=95=8C=20=20focus=20=EC=9B=90=EB=9E=98=EB=8C=80=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/common/Button/Button.tsx | 40 +++++++++---------- .../NextRoundButton/NextRoundButton.tsx | 5 ++- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/common/Button/Button.tsx b/frontend/src/components/common/Button/Button.tsx index a8309f6bc..fee1e1e3c 100644 --- a/frontend/src/components/common/Button/Button.tsx +++ b/frontend/src/components/common/Button/Button.tsx @@ -1,4 +1,4 @@ -import React, { ButtonHTMLAttributes } from 'react'; +import React, { ButtonHTMLAttributes, forwardRef } from 'react'; import { buttonLayout } from './Button.styled'; @@ -13,26 +13,22 @@ interface ButtonProps extends ButtonHTMLAttributes { bottom?: boolean; } -const Button: React.FC = ({ - text, - onClick, - disabled, - size, - radius, - fontSize, - bottom, - ...props -}) => { - return ( - - ); -}; +const Button = forwardRef( + ({ text, onClick, disabled, size, radius, fontSize, bottom, ...props }, ref) => { + return ( + + ); + }, +); + +Button.displayName = 'Button'; export default Button; diff --git a/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx b/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx index 495017bf9..501b53523 100644 --- a/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx +++ b/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx @@ -1,3 +1,4 @@ +import { useRef } from 'react'; import { useParams } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; @@ -17,18 +18,20 @@ const NextRoundButton = () => { const { mutate: moveNextRound } = useMoveNextRoundMutation(Number(roomId)); const memberInfo = useRecoilValue(memberInfoState); const { show } = useModal(); + const closeRef = useRef(null); const randomRoundNextMessage = createRandomNextRoundMessage(); const isLastRound = balanceContent?.currentRound === balanceContent?.totalRound; const showModal = () => { - show(AlertModal, { message: randomRoundNextMessage, onConfirm: moveNextRound }); + show(AlertModal, { message: randomRoundNextMessage, onConfirm: moveNextRound, closeRef }); }; return (
{memberInfo.isMaster ? ( @@ -98,9 +102,10 @@ export const RoundResultHeader = () => { const { roomId } = useParams(); const { balanceContent } = useBalanceContentQuery(Number(roomId)); const screenReaderRoundResult = `${balanceContent.totalRound}라운드 중. ${balanceContent.currentRound}라운드. 투표 결과 페이지`; + const focusRef = useFocus(); return ( -
+
{screenReaderRoundResult} {balanceContent.currentRound}/{balanceContent.totalRound} @@ -120,9 +125,10 @@ export const GameHeader = () => { const { totalRound, currentRound, timeLimit } = balanceContent; const screenReaderHeader = `${totalRound}라운드.중.${currentRound}라운드. 밸런스 게임 페이지. 제한 시간 ${convertMsecToSecond(timeLimit)}초.`; + const focusRef = useFocus(); return ( -
+
{screenReaderHeader} {currentRound}/{totalRound} From 9c278e339a442b0a10ac526bbf7a5b2bb3f033c8 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Mon, 21 Oct 2024 20:03:29 +0900 Subject: [PATCH 09/11] =?UTF-8?q?refactor:=20modal=EC=97=90=20aria-modal?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/Modal/Modal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/components/common/Modal/Modal.tsx b/frontend/src/components/common/Modal/Modal.tsx index 9230c5c76..ddabc7a48 100644 --- a/frontend/src/components/common/Modal/Modal.tsx +++ b/frontend/src/components/common/Modal/Modal.tsx @@ -62,6 +62,7 @@ const Modal = ({
Date: Mon, 21 Oct 2024 21:45:05 +0900 Subject: [PATCH 10/11] =?UTF-8?q?refactor:=20closeRef=20->=20returnFocusRe?= =?UTF-8?q?f=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReadyMembersContainer/ReadyMembersContainer.tsx | 6 +++--- frontend/src/components/RoomSetting/RoomSetting.tsx | 6 +++--- .../src/components/common/AlertModal/AlertModal.tsx | 13 ++++++++++--- .../components/common/InviteModal/InviteModal.tsx | 11 ++++++++--- frontend/src/components/common/Modal/Modal.tsx | 10 +++++----- .../common/NextRoundButton/NextRoundButton.tsx | 6 +++--- .../common/RoomSettingModal/RoomSettingModal.tsx | 11 ++++++++--- frontend/src/components/layout/Header/Header.tsx | 6 +++--- .../src/providers/ModalProvider/ModalProvider.tsx | 4 ++-- 9 files changed, 45 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx b/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx index f6495be9a..a3f9e2dd7 100644 --- a/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx +++ b/frontend/src/components/ReadyMembersContainer/ReadyMembersContainer.tsx @@ -25,10 +25,10 @@ const ReadyMembersContainer = () => { const { members, master } = useGetRoomInfo(); const { show } = useModal(); const [memberInfo, setMemberInfo] = useRecoilState(memberInfoState); - const closeRef = useRef(null); + const returnFocusRef = useRef(null); const handleClickInvite = () => { - show(InviteModal, { closeRef }); + show(InviteModal, { returnFocusRef }); }; // 원래 방장이 아니다 + 방장의 memberId와 내 memberId가 같다 -> 방장으로 변경 @@ -43,7 +43,7 @@ const ReadyMembersContainer = () => { 총 인원 {members.length}명
총 인원 {members.length}명
-
diff --git a/frontend/src/components/RoomSetting/RoomSetting.tsx b/frontend/src/components/RoomSetting/RoomSetting.tsx index e0d99e4a6..66f751b75 100644 --- a/frontend/src/components/RoomSetting/RoomSetting.tsx +++ b/frontend/src/components/RoomSetting/RoomSetting.tsx @@ -16,7 +16,7 @@ import useModal from '@/hooks/useModal'; import { memberInfoState } from '@/recoil/atom'; const RoomSetting = () => { - const closeRef = useRef(null); + const returnFocusRef = useRef(null); const { roomSetting } = useGetRoomInfo(); const { isMaster } = useRecoilValue(memberInfoState); const { show } = useModal(); @@ -27,7 +27,7 @@ const RoomSetting = () => { 타이머 ${roomSetting.timeLimit / 1000}초.`; const handleClickCategory = () => { - show(RoomSettingModal, { closeRef }); + show(RoomSettingModal, { returnFocusRef }); }; return ( @@ -37,7 +37,7 @@ const RoomSetting = () => { aria-label="방 설정" css={roomSettingLayout} onClick={isMaster ? handleClickCategory : () => {}} - ref={closeRef} + ref={returnFocusRef} >
라운드 diff --git a/frontend/src/components/common/AlertModal/AlertModal.tsx b/frontend/src/components/common/AlertModal/AlertModal.tsx index 0bf1b211a..ddfbb66b7 100644 --- a/frontend/src/components/common/AlertModal/AlertModal.tsx +++ b/frontend/src/components/common/AlertModal/AlertModal.tsx @@ -9,17 +9,24 @@ interface AlertModalProps { onConfirm?: () => void; message?: string; title?: string; - closeRef?: RefObject; + returnFocusRef?: RefObject; } -const AlertModal = ({ isOpen, onClose, onConfirm, message, title, closeRef }: AlertModalProps) => { +const AlertModal = ({ + isOpen, + onClose, + onConfirm, + message, + title, + returnFocusRef, +}: AlertModalProps) => { const handleClick = () => { onConfirm && onConfirm(); onClose(); }; return ( - + {title || '알림'} diff --git a/frontend/src/components/common/InviteModal/InviteModal.tsx b/frontend/src/components/common/InviteModal/InviteModal.tsx index 33d490791..83ecb0ec0 100644 --- a/frontend/src/components/common/InviteModal/InviteModal.tsx +++ b/frontend/src/components/common/InviteModal/InviteModal.tsx @@ -24,10 +24,10 @@ import { roomUuidState } from '@/recoil/atom'; interface InviteModalProps { isOpen: boolean; onClose: () => void; - closeRef?: RefObject; + returnFocusRef?: RefObject; } -const InviteModal = ({ isOpen, onClose, closeRef }: InviteModalProps) => { +const InviteModal = ({ isOpen, onClose, returnFocusRef }: InviteModalProps) => { const roomUuid = useRecoilValue(roomUuidState); const inviteUrl = INVITE_URL(roomUuid); @@ -40,7 +40,12 @@ const InviteModal = ({ isOpen, onClose, closeRef }: InviteModalProps) => { }; return ( - + 초대하기 diff --git a/frontend/src/components/common/Modal/Modal.tsx b/frontend/src/components/common/Modal/Modal.tsx index ddabc7a48..f54a20c2e 100644 --- a/frontend/src/components/common/Modal/Modal.tsx +++ b/frontend/src/components/common/Modal/Modal.tsx @@ -25,14 +25,14 @@ export interface ModalProps onClose: () => void; position?: 'top' | 'bottom' | 'center'; style?: React.CSSProperties; - closeRef?: RefObject; + returnFocusRef?: RefObject; }> {} const Modal = ({ children, isOpen, onClose, - closeRef, + returnFocusRef, position = 'center', ...restProps }: ModalProps) => { @@ -48,11 +48,11 @@ const Modal = ({ useEffect(() => { return () => { - if (closeRef?.current) { - closeRef.current.focus(); + if (returnFocusRef?.current) { + returnFocusRef.current.focus(); } }; - }, [closeRef?.current]); + }, [returnFocusRef?.current]); if (!isOpen) return null; diff --git a/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx b/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx index 501b53523..e22138ebe 100644 --- a/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx +++ b/frontend/src/components/common/NextRoundButton/NextRoundButton.tsx @@ -18,20 +18,20 @@ const NextRoundButton = () => { const { mutate: moveNextRound } = useMoveNextRoundMutation(Number(roomId)); const memberInfo = useRecoilValue(memberInfoState); const { show } = useModal(); - const closeRef = useRef(null); + const returnFocusRef = useRef(null); const randomRoundNextMessage = createRandomNextRoundMessage(); const isLastRound = balanceContent?.currentRound === balanceContent?.totalRound; const showModal = () => { - show(AlertModal, { message: randomRoundNextMessage, onConfirm: moveNextRound, closeRef }); + show(AlertModal, { message: randomRoundNextMessage, onConfirm: moveNextRound, returnFocusRef }); }; return (
{memberInfo.isMaster ? (

{title}

{isMaster ? ( - ) : ( diff --git a/frontend/src/providers/ModalProvider/ModalProvider.tsx b/frontend/src/providers/ModalProvider/ModalProvider.tsx index afca7878d..b7d4b1825 100644 --- a/frontend/src/providers/ModalProvider/ModalProvider.tsx +++ b/frontend/src/providers/ModalProvider/ModalProvider.tsx @@ -4,7 +4,7 @@ interface ModalProps { title?: string; message?: string; onConfirm?: () => void; - closeRef?: RefObject; + returnFocusRef?: RefObject; } interface ModalState extends ModalProps { @@ -40,7 +40,7 @@ const ModalProvider = ({ children }: PropsWithChildren) => { message: props?.message, onConfirm: props?.onConfirm, isOpen: true, - closeRef: props?.closeRef, + returnFocusRef: props?.returnFocusRef, }); }; From a1e27828546a8086e9579d1e64a0379835ebdff7 Mon Sep 17 00:00:00 2001 From: novice0840 Date: Mon, 21 Oct 2024 21:47:27 +0900 Subject: [PATCH 11/11] =?UTF-8?q?refactor:=20modal=EC=97=90=20aria-modal?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20#335?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/common/Modal/Modal.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/components/common/Modal/Modal.tsx b/frontend/src/components/common/Modal/Modal.tsx index f54a20c2e..f9b263fa8 100644 --- a/frontend/src/components/common/Modal/Modal.tsx +++ b/frontend/src/components/common/Modal/Modal.tsx @@ -1,4 +1,5 @@ /* eslint-disable jsx-a11y/no-noninteractive-tabindex */ +/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ import React, { ButtonHTMLAttributes, HTMLAttributes, RefObject, useEffect, useRef } from 'react'; import ReactDOM from 'react-dom'; @@ -62,6 +63,7 @@ const Modal = ({