Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Snackbar 컴포넌트 구현 #162

Merged
merged 22 commits into from
Nov 8, 2024
Merged

feat: Snackbar 컴포넌트 구현 #162

merged 22 commits into from
Nov 8, 2024

Conversation

seocylucky
Copy link
Member

@seocylucky seocylucky commented Oct 30, 2024

1️⃣ 어떤 작업을 했나요? (Summary)

Snackbar 구현 작업을 했습니다.

type === 'info' type === 'error'
image image

2️⃣ 알아두시면 좋아요!

상태를 전역에서 관리하기 위해 Context API를 사용했습니다.

  return (
    <SnackbarContext.Provider value={{ showSnackbar }}>
      {children}
      {snackbar &&
        ReactDOM.createPortal(
          <StyledSnackbarContainer position={snackbar.position || 'center'}>
            <Snackbar {...snackbar} onClose={removeSnackbar} isClosing={isClosing} />
          </StyledSnackbarContainer>,
          document.body
        )}
    </SnackbarContext.Provider>
  );

선언적으로 스낵바를 호출하기 위해 useSnackbar 훅으로 빼서 사용할 수 있도록 하였습니다.

export const useSnackbar = () => {
  const { showSnackbar } = useSnackbarContext();

  const snackbar = (props: SnackbarWithoutClosingProps) => {
    showSnackbar(props);
  };

  return { snackbar };
};

isClosing과 onClose의 차이

isClosing

isClosing은 스낵바가 닫히는 상태를 나타내는 boolean 값.
이 값으로 애니메이션 제어를 하고 스낵바가 DOM에서 제거되기 전에 닫히는 애니메이션을 끝까지 보여주기 위한 용도! 없으면 애니메이션 없이 그냥 닫혀버려요.

onClose

스낵바가 닫힐 때 호출되는 함수.
스낵바가 닫히는 애니메이션이 끝난 후, 스낵바를 실제로 DOM에서 제거하는 역할을 합니다.

useTouchMouseDrag가 무엇이냐

마우스 드래그 또는 터치 스와이프 동작을 감지하여 스낵바 닫기를 수행할 수 있도록 구현된 함수입니다.
info 스낵바만 드래그해서 닫습니다! error 스낵바는 X버튼으로만 닫을 수 있음 참고!

3️⃣ 추후 작업

리뷰 반영!
배경색 토큰 반영 시 코드 수정 필요

4️⃣ 체크리스트 (Checklist)

  • main 브랜치의 최신 코드를 pull 받았나요?

Copy link
Collaborator

@nijuy nijuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다! 코드에서 공들인 티가 팍팍 나네요
궁금한 부분은 코멘트로 남겨뒀어요

SpongebobThumbsupGIF

오전까지 리뷰한다 해놓고. 전 거짓말쟁이입니다.
볼 내용이 생각보다 많더라고요~~!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChipGroupTabs의 경우 컴포넌트와 관련된 훅은 (컴포넌트 폴더)/hooks로 분리했는데요,
일관성을 위해 스낵바에서 생긴 두 개의 훅도 위처럼 분리해두면 좋겠습니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

반영했습니다~ -> 43d50c4

Comment on lines 11 to 12
isClosing?: boolean;
position: SnackbarPosition;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

styled component prop 타입의 필드명엔 $를 붙이기로 했는데,
두 필드에선 붙이지 않은 이유가 따로 있을까요?

참고로 $를 붙이는 이유는 스타일을 위해 생성한 prop이 DOM까지 전달되는 것을 막기 위해서입니다! 지금 콘솔 경고가 뜨는 것도 이 이유에서에요

image

자세한 내용은 스타일드 컴포넌트 문서의 transient props 섹션에서 확인하실 수 있습니다!!


이 맥락에서 SnackbarProps 타입의 필드명에는 $를 떼는 게 덜 헷갈릴 거 같어용

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저것은..... 이유가 있습니다...
바로 저의 불찰 때문이죠.... 호호 반영 바로 해버렸습니다

이 맥락에서 SnackbarProps 타입의 필드명에는 $를 떼는 게 덜 헷갈릴 거 같어용

오 예리하네요 보리 반영했습니다ㅎㅎㅎㅎ -> bb5de21

Comment on lines 32 to 53
useEffect(() => {
const element = elementRef.current;
if (element) {
element.addEventListener('mousedown', handleStart);
window.addEventListener('mousemove', handleMove);
window.addEventListener('mouseup', handleEnd);

element.addEventListener('touchstart', handleStart);
element.addEventListener('touchmove', handleMove);
element.addEventListener('touchend', handleEnd);

return () => {
element.removeEventListener('mousedown', handleStart);
window.removeEventListener('mousemove', handleMove);
window.removeEventListener('mouseup', handleEnd);

element.removeEventListener('touchstart', handleStart);
element.removeEventListener('touchmove', handleMove);
element.removeEventListener('touchend', handleEnd);
};
}
}, [isDragging, startY]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피그마 보니까 type="error"의 경우 드래그로 닫는 게 불가능해야 하는데,
지금은 드래그로도 닫을 수 있게 되어있습니다!

image

drag error

useMouseTouchDrag에 type을 넘겨서 이벤트 리스너를 조건부로 달거나,
StyledSnackbar에서 type="info"일 때만 ref를 달거나.....🤔

러프하게 생각나는 방법들을 대충 적어놓긴 했는데,
어쨌든 위 방법이 아니더라도 조치가 필요해보여요!!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

헉 원래 ref로 처리했었는데 코드가 반영이 안됐었네여 일단 ref로 다시 처리 했습니다!!
style transient props 처리에 같이 제가 커밋을 해버렸네요😅
같이 확인해주심 될 것 같아요🫶🏻🫶🏻 -> bb5de21

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

당신정말최고야

Comment on lines 41 to 46
`type` - Snackbar의 종류 (info 또는 error). 기본 값은 `info`입니다. <br />
`width` - Snackbar의 가로 길이 (px, %, 등). 기본적으로 글자 길이에 맞게 가로 길이가 정해집니다. <br />
`margin` - 왼쪽 오른쪽의 margin 값. 기본 값은 `16px`입니다. <br />
`message` - Snackbar의 내용 (메시지). 필수 프로퍼티입니다. <br />
`duration` - Snackbar가 자동으로 닫히기 전까지의 시간(ms). 기본 값은 `5000`입니다. <br />
`position` - Snackbar의 위치 (left, center, right, full-width). 기본 값은 `center`입니다.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 prop에 대한 설명이 사용법 섹션에 리스트로 들어가 있는데,
아래처럼 문서 내용을 좀 더 추가하는 건 어떨까요?

사용법 섹션

필수 프로퍼티인 message에 대한 내용만 남긴다
(두 줄 초과 시 말줄임표로 처리한다는 부분)

예시 섹션 (별도로 생성)

각 prop에 대한 구체적인 설명을 해당 위치로 분리

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 참고해서 수정 사항 반영 다 끝나면 수정해보겠습니다~

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정 완료했습니다~ prop 예시를 밑에 몇개 둘까했는데 스낵바 컴포넌트 특성상 일일이 예시 테스트 주기가 번거로울 것 같아서
위에 Control 있으니 설명만 넣었습니당 -> 3ea81f0

@@ -0,0 +1,17 @@
export type SnackbarType = 'info' | 'error';
export type SnackbarHeightType = 1 | 2;
export type SnackbarPosition = 'left' | 'center' | 'right' | 'full-width';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

피그마에 따라 SnackbarPosition의 종류로 'full-width'를 넣은 걸로 이해했는데

image

코드를 보니까 'full-width'는 position보다 width prop의 한 종류여야 하지 않나? 하는 생각이 들어서요

width: ${({ position }) => (position === 'full-width' ? '100%' : 'fit-content')};

width prop은 단위까지 입력받는다는 점에서.. 템플릿 리터럴 타입을 활용해보는 건 어떻게 생각하세요??

(CSS 함수나 여러 단위를 생각하면 별도 타입으로 분리하는 게 더 깔끔하겠네요 😅)

width?: 'full-width' | `${number}px` | `${number}rem` | ...;

참고로 위 방식으로 고치게 되면 width에 'full-width' 타입 값이 들어왔을 땐 사용자가 position을 설정해도 무시하는 방식의 처리를 추가해야 할 거 같습니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 생각해보니 그렇네요 position에 들어가면 따로 위치 처리가 필요없어서 둔거긴한데.. 의미상 안 맞아서 분리하는게 나아 보이긴 하네요

흠 단위는 px, rem, em, %, vh, vw, 정도로 할까요?!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

뷰포트 높이에 따라 토스트 너비를 조절하는 경우가 있을지 잘 상상이 안 가서, vh는 없어도 무방할 거 같단 생각입니다!
만약 단위만 넣어두면 calc()은 못 쓸텐데, 이건 포함시키지 않아도 될까요?

Copy link
Member Author

@seocylucky seocylucky Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calc()도 추가하겠습니당~ -> 08c7f4c

Comment on lines 3 to 4
import { BoxButton } from '../BoxButton';
import { Snackbar } from './Snackbar';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import/order 관련해서 에러/경고 줄이 몇 개 뜨던데, 혹시 저만 그런가요?? 제 린트 설정이 꼬인 건지 적용이 덜 된건지 잘 몰으겠네요.....................

image

Copy link
Member Author

@seocylucky seocylucky Oct 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

보니 저 코드가 상대경로로 되어 있어서 나는 린트 에러 같네여 절대경로로 다음처럼 바꿔놓을테니 확인 부탁드려요!!!
-> 01a5ad2

import { BoxButton } from '@/components/BoxButton';

Copy link
Collaborator

@nijuy nijuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼼꼼쓰한 반영 멋지네요 꼼체
돌려보면서 스타일 관련해서 발견한 게 조금 더 있어서 코멘트 달아놨어요 흑흑
왜 이런 건 바로바로 안 보이는 거야!~~!!!

shouldForwardProp: (prop) => prop !== 'isClosing',
})<StyledSnackbarProps>`
position: relative;
padding: 24px;
Copy link
Collaborator

@nijuy nijuy Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기 padding 16이에요 24에요?..............
image

제가 왼쪽 보고 스타일 점검해가지고... 잠시 헷갈려서 댓글을 여러 번 고쳤는데 ^^... 미안합니다미안합니다
24가 맞다면 조용히 resolve 해주십시오

height: ${({ $heightType }) => ($heightType === 2 ? '72px' : '52px')};
border-radius: ${({ theme }) => theme.semantic.radius.m}px;

${({ theme }) => theme.typo.B3_Rg_14}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

info일 때 typo ➡️ PC/Body/B3_Rg_14
error일 때 typo ➡️ PC/Body/B3_Sb_14

피그마에 비해 글자가 날씬하길래 보니까 타이포 스타일이 다르더라고요!

image

Suggested change
${({ theme }) => theme.typo.B3_Rg_14}
${({ $type, theme }) => ($type === 'info' ? theme.typo.B3_Rg_14 : theme.typo.B3_Sb_14)}

Copy link
Member Author

@seocylucky seocylucky Nov 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋㅋㅋ아 대박 진정한 꼼꼼이는 보리 당신 꼼보...👍🏻

커밋 suggestion 할게영 -> 27ba6ad

Copy link
Collaborator

@nijuy nijuy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mdx에서 사용하고 있는 Story는 3갠데 (Test, info, Overflow) stories.tsx에는 5개가 있어서요! (+ Info, Error) 혹시 mdx에서 사용되지 않는 스토리들이 남아있는 이유가 있을까요?
또 스토리명은 대문자로 시작하면 좋을 거 같습니다! (test -> Test)

수정사항이 자잘하게 많았는데 고생하셨습니다 😋👍👍👍

@seocylucky
Copy link
Member Author

@nijuy 아핫 현재 스토리북에 사용된거는 Test, Type, OverflowTest 이렇게 3가지입니다!! 나머지 안쓰이는 두 개는 삭제할게요~
=> 6a732d2

@seocylucky seocylucky merged commit 767e68a into develop Nov 8, 2024
@seocylucky seocylucky deleted the feat/#153-snackbar branch November 8, 2024 07:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: Snackbar 컴포넌트 구현
2 participants