[mui]SwipeableDrawer 컴포넌트 생성하기

hansoom·2023년 8월 6일
0

design system

목록 보기
3/4
post-thumbnail

SwipeableDrawer 컴포넌트


이와 같이 bottom에서 모달이 떠 bottom sheet 컴포넌트로 content list를 확인할 수 있도록 하는 컴포넌트를 구현할 것이다.

여기 bottom sheet이 떠 위로 올린 후 스크롤을 내리면서 content list 확인이 가능하게 구현할 것이다.

1. 모바일일 경우에 해당 컴포넌트가 뜰 수 있게 설정

  • MainLayout.tsx
import { Box, Toolbar, useMediaQuery } from '@mui/material';

// 모바일 영역
const query = '(min-width:0px) and (max-width:600px)';
 /**
   * Media Query Hook (SSR에서 동작)
   * 너비가 [0-360] 픽셀이면 true를 반환
   */
const isMobile = useMediaQuery(query, { noSsr: false });

<Box component="main" sx={{ flexGrow: 1, backgroundColor: 'gray' }}>
        {/* Mobile 용 AppBar 영역만큼 차지해줌 */}
        {isMobile && <Toolbar />}

        {/* 현재 라우팅된 페이지 */}
        {children}

        {/* Mobile 전용 BottomSheet 영역  */}
        {isMobile && <BottomSheet />}
</Box>

2. BottomSheet 컴포넌트 생성

2-1. 하단 드로워 위에 빈 높이 계산

// Bottom Sheet FUll 높이 값 : 
// DRAWER Puller 높이 + Toolbar 높이 + 빈 Toolbar 높이 + 여유 높이
const BOTTOM_SHEET_FULL_HEIGHT =
  DRAWER_BLEEDING + TOOL_BAR_HEIGHT + EMPTY_TOOL_BAR_HEIGHT + 20;

하단 드로어의 전체 높이를 계산하는데 사용되는 변수 BOTTOM_SHEET_FULL_HEIGHT를 정의한다.

2-2. 하단 드로어 열고 닫는 상태 정의

const [open, setOpen] = useState(false);
// Bottom Modal Open 함수
const handleOpen = useCallback(() => {
    setOpen(true);
}, []);

  // Bottom Modal Close 함수
const handleClose = useCallback(() => {
    setOpen(false);
}, []);

2-3. 글로벌 css 스타일 정의

import { Global } from '@emotion/react';
<Global
        styles={{
          '.MuiDrawer-root > .MuiPaper-root': {
            height: `calc(100% - ${BOTTOM_SHEET_FULL_HEIGHT}px)`,
            overflow: 'visible',
          },
        }}
/>

Global 컴포넌트를 사용하여 글로벌 CSS 스타일을 적용한다. 여기서는 드로어의 스타일을 정의해준다.

높이는 앞에서 정의한 높이 값을 뺀 값으로 높이 값을 가질 수 있도록 한다.

'visible' 값은 내용이 넘칠 경우 스크롤바가 표시되지 않고 내용이 넘칠 수 있도록 한다.

2-4. SwipeableDrawer 컴포넌트 props 설정

 const container =
    window !== undefined ? () => window.document.body : undefined;

<SwipeableDrawer
  container={container}
  anchor="bottom"
  open={open}
  onOpen={handleOpen}
  onClose={handleClose}
  swipeAreaWidth={DRAWER_BLEEDING}
  disableSwipeToOpen={false}
  ModalProps={{ keepMounted: true }}
>

container: 하단 드로어를 포함하는 부모 요소를 가리키는 함수
anchor: 드로어 위치 설정(아래)
open: 드로어 열고 닫기 상태값 넣어주기
onOpen, onClose: 상태 값 true, false로 set하는 함수 넣어주기
swipeAreaWidth: 스와이프 동작을 감지할 영역의 너비를 설정
disableSwipeToOpen={false}: 스와이프 동작으로 드로어를 열 수 있도록 설정
ModalProps: keepMounted: true는 모달이 열려 있을 때도 DOM에 유지

2-5. 드로어 안에 컨텐츠 css 코드 정의

<StyledBox>
   <Puller />
   <ContentBox>
      <ContentList />
   </ContentBox>
</StyledBox>
  • styled-component 코드
import { Box, styled } from '@mui/material';

export const DRAWER_BLEEDING = 106;

export const StyledBox = styled(Box)(({ theme }) => ({
  backgroundColor:
    theme.palette.mode === 'light' ? '#fff' : theme.palette.grey[800],
  position: 'absolute',
  top: -DRAWER_BLEEDING,
  borderTopLeftRadius: 8,
  borderTopRightRadius: 8,
  right: 0,
  left: 0,
  boxShadow: '0px 2px 9px 5px gray',
  visibility: 'visible',
  height: `calc(100% + ${DRAWER_BLEEDING}px)`,
}));

export const Puller = styled(Box)(() => ({
  width: 40,
  height: 3,
  backgroundColor: '#E4E4E4',
  borderRadius: 3,
  position: 'absolute',
  top: 20,
  left: 'calc(50% - 15px)',
}));

export const ContentBox = styled(Box)`
  margin-top: 50px;
  height: 90%;
  overflow: auto;
  scrollbar-width: none;
  &::-webkit-scrollbar {
    display: none;
  }
`;

0개의 댓글