Skip to content

Commit

Permalink
Merge pull request #60 from FRONTENDSCHOOL5/feature/#55
Browse files Browse the repository at this point in the history
♻️ refactor: BottomSheet 컴포넌트 코드 최소화 리팩토링
  • Loading branch information
mihyunLee authored Jun 18, 2023
2 parents 156e5c5 + d1dd50f commit 587e7e7
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 96 deletions.
11 changes: 9 additions & 2 deletions src/components/common/BottomSheet/BasicModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ import React from 'react';
import styled from 'styled-components';

const BasicModalWrapper = styled.div`
height: 192px;
margin: 0 16px;
padding: 16px;
max-height: 548px;
overflow-y: scroll;
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
`;

export default function BasicModal({ children }) {
Expand Down
61 changes: 24 additions & 37 deletions src/components/common/BottomSheet/BottomSheet.jsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,38 @@
import React, { useState, useEffect, useRef } from 'react';
import { BottomSheetDim, ModalBox, HeaderModal } from './BottomSheetStyle';
import ListModal from './ListModal';
import BasicModal from './BasicModal';
import React, { useState, useEffect } from 'react';
import { BottomSheetDim, BottomSheetWrapper, ModalBox, ModalHandle } from './BottomSheetStyle';

// type: basic, list
function BottomSheet({ type = 'basic', isShow, setIsShow, children }) {
const [animate, setAnimate] = useState(false);
const [localVisible, setLocalVisible] = useState(isShow);
const wrapperRef = useRef(null);
const modalBoxRef = useRef(null);
export default function BottomSheet({ isShow, onClick, children }) {
const [isVisible, setIsVisible] = useState(false);

useEffect(() => {
setLocalVisible(isShow);
}, [isShow]);
let modalTimer;

useEffect(() => {
if (localVisible && !isShow) {
setAnimate(true);
setTimeout(() => setAnimate(false), 250);
if (isShow) {
setIsVisible(true);
} else {
modalTimer = setTimeout(() => setIsVisible(false), 250);
} // 0.25초뒤에 없어짐
setLocalVisible(isShow);
}, [localVisible, isShow]);

// Dim 클릭했을 때, ModalBox부분을 제외한 영역이어야 동작하도록
const handleDimClick = (e) => {
if (wrapperRef.current && modalBoxRef.current && !modalBoxRef.current.contains(e.target)) {
setIsShow(false);
}
};

// ModalBox의 HeaderModal을 클릭했을 때 동작
const handleHeaderModalClick = () => {
setIsShow(false);
};
return () => {
if (modalTimer !== undefined) {
clearTimeout(modalTimer);
}
};
}, [isShow]);

if (!localVisible && !animate) return null;
if (!isVisible) {
return null;
}

return (
<>
<BottomSheetDim onClick={handleDimClick} disappear={!isShow} ref={wrapperRef}>
<ModalBox disappear={!isShow} ref={modalBoxRef}>
<HeaderModal onClick={handleHeaderModalClick} />
{type === 'list' ? <ListModal /> : <BasicModal>{children}</BasicModal>}
<BottomSheetWrapper>
<ModalBox isShow={isShow}>
{children}
<ModalHandle onClick={onClick} aria-label='모달 닫기' />
</ModalBox>
</BottomSheetDim>
<BottomSheetDim isShow={isShow} onClick={onClick} />
</BottomSheetWrapper>
</>
);
}

export default BottomSheet;
60 changes: 21 additions & 39 deletions src/components/common/BottomSheet/BottomSheetStyle.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import styled, { css, keyframes } from 'styled-components';
import styled, { keyframes } from 'styled-components';

const fadeIn = keyframes`
from {
Expand All @@ -23,13 +23,13 @@ const slideUp = keyframes`
}
to {
transform: translateY(calc(100% - ${({ LEN }) => (LEN < 425 ? LEN : 425)}px));
transform: translateY(0);
}
`;

const slideDown = keyframes`
from {
transform: translateY(calc(100% - ${({ LEN }) => (LEN < 425 ? LEN : 425)}px));
transform: translateY(0);
}
to {
Expand All @@ -38,66 +38,48 @@ const slideDown = keyframes`
`;

export const BottomSheetDim = styled.div`
position: absolute;
position: fixed;
top: 0;
width: 100%;
width: clamp(390px, 100%, 720px);
height: 100vh;
margin: 0 auto;
background-color: rgba(0, 0, 0, 0.3);
transition: background-color 0.25s ease-out;
display: flex;
flex-direction: column;
justify-content: space-between;
animation: ${fadeIn} 0.25s ease-out forwards;
${(props) =>
props.disappear &&
css`
animation-name: ${fadeOut};
`}
animation: ${(p) => (p.isShow ? fadeIn : fadeOut)} 0.3s ease-out;
transition: background-color 0.3s ease-out;
`;

export const ModalBox = styled.div`
width: inherit;
height: ${({ LEN }) => (LEN < 425 ? LEN : 425)}px;
border-radius: 1rem 1rem 0 0;
export const BottomSheetWrapper = styled.article`
width: 100%;
position: absolute;
bottom: 0;
`;

export const ModalBox = styled.div`
position: relative;
bottom: 0;
z-index: 50;
border-radius: 20px 20px 0 0;
padding-top: 48px;
display: flex;
flex-direction: column;
background-color: ${({ theme }) => theme.colors.white};
animation: ${slideUp} 0.25s ease-out forwards;
${(props) =>
props.disappear &&
css`
animation-name: ${slideDown};
animation-timing-function: ease-in;
`}
animation: ${(p) => (p.isShow ? slideUp : slideDown)} 0.3s ease-out;
`;

export const HeaderModal = styled.button`
export const ModalHandle = styled.button`
width: 100%;
height: 48px;
position: relative;
position: absolute;
top: 0;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50px;
height: 4px;
background-color: ${({ theme }) => theme.colors.gray100};
}
`;
37 changes: 19 additions & 18 deletions src/components/common/BottomSheet/ListModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,35 @@ import React from 'react';
import styled from 'styled-components';

const BottomSheetListWrapper = styled.ul`
max-height: 425px;
overflow-y: scroll;
::-webkit-scrollbar {
width: 0;
background: transparent;
}
margin-bottom: 10px;
`;

const ListItem = styled.li`
height: 48px;
display: flex;
align-items: center;
padding: 0 24px;
height: 46px;
padding: 14px 26px;
font-size: ${({ theme }) => theme.fontSize.sm};
cursor: pointer;
`;

const LEN = 0;

export default function ListModal({ items }) {
const LEN = items.length * 48;
const TYPES = {
profile: ['설정 및 개인정보', '로그아웃'],
myPost: ['삭제', '수정'],
userPost: ['신고하기'],
chat: ['채팅방 나가기'],
myComment: ['삭제'],
userComment: ['신고하기'],
};

export default function ListModal({ type, onClick }) {
return (
<BottomSheetListWrapper>
{items.map((item, index) => (
<ListItem key={index}>{item}</ListItem>
{TYPES[type].map((item, index) => (
<ListItem key={index} onClick={onClick}>
<button type='button' onClick={onClick}>
{item}
</button>
</ListItem>
))}
</BottomSheetListWrapper>
);
}

export { LEN };
1 change: 1 addition & 0 deletions src/layout/BasicLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const LayoutWrapper = styled.div`
margin: 0 auto;
position: relative;
background-color: #fff;
overflow-y: hidden;
`;

const LayoutMain = styled.div`
Expand Down

0 comments on commit 587e7e7

Please sign in to comment.