Dropdown
Dropdown은 뷰포트에 따라 PC에서는 드롭다운, 모바일에서는 바텀 시트로 등장하는 컴포넌트입니다.
How to use
import { Dropdown } from '@vibrant-ui/components';
Properties
| Prop | Type | Default | Description | 
|---|---|---|---|
| open | boolean | 열림 상태를 제어합니다. | |
| defaultOpen | boolean | false | 초기 열림 상태를 설정합니다. | 
| renderOpener | (_: { open: () => void; isOpen: boolean, ref: RefObject }) => ReactElementChild | open 함수를 이용하여 오프너 요소를 설정합니다. | |
| position | bottom|left|right|top|bottom-end|bottom-start|left-end|left-start|right-end|right-start|top-end|top-start | bottom | 드랍다운이 열리는 위치를 설정합니다. | 
| spacing | number | 8 | 드랍다운과 오프너 요소 사이의 간격을 설정합니다. | 
| renderContents | (_: { close: () => void }) => ReactElementChild | 내부 컨텐츠를 설정합니다. | |
| onClose | () => void | 컨텐츠 바깥 영역이 클릭되거나 닫기 버튼이 클릭됐을 때 호출됩니다. | 
Usage
제어
open 속성을 통해 열림 상태를 제어합니다.
const Controlled = () => {
  const [open, setOpen] = useState(false);
  return (
    <>
      <Pressable onClick={() => setOpen(true)}>
        열기
      </Pressable>
      <Dropdown
        open={open}
        onClose={() => setOpen(false)}
        renderContents={() => (
          <VStack spacing={20}>
            <Body level={2} px={20}>
              메뉴 1
            </Body>
            <Body level={2} px={20}>
              메뉴 2
            </Body>
          </VStack>
        )}
      />
    </>
  );
};
비제어
defaultOpen 속성을 통해 초기 열림 상태만 지정하고 이후의 상태는 Dropdown 컴포넌트 내부에서 관리됩니다.
render prop인 renderOpener 속성으로 Dropdown을 열리게 하는 요소를 지정할 수 있으며 전달인자로 Dropdown을 열린 상태로 변경하는 함수 open와 현재 열림 상태를 나타내는 isOpen 프로퍼티를 가진 객체를 제공합니다.
const Uncontrolled = () => (
  <Dropdown
    defaultOpen={false}
    renderOpener={({ open }) => (
      <Pressable onClick={open}>열기</Pressable>
    )}
    renderContents={() => (
      <VStack spacing={20}>
        <Body level={2} px={20}>
          메뉴 1
        </Body>
        <Body level={2} px={20}>
          메뉴 2
        </Body>
      </VStack>
    )}
  />
);
오프너
renderOpener 렌더 속성을 통해 드랍다운을 열기 위한 오프너 요소를 설정할 수 있습니다. 인자로 전달 받은 open 함수를 사용해서 원하는 요소의 이벤트 핸들러로 등록하여 드랍다운을 열도록 설정할 수 있으며, 드랍다운은 오프너 요소를 감싸는 컨테이너를 기준으로 위치가 설정됩니다.
만약 오프너를 감싸는 컨테이너가 아닌 특정 요소를 기준으로 드랍다운이 위치하길 원하는 경우에는 인자로 전달받은 ref로 원하는 요소에 등록합니다.
<HStack mx="auto" spacing={24}>
  <Dropdown
    position="top-end"
    renderOpener={({ ref, open }) => (
      // 드랍다운은 Pressable을 감싸는 컨테이너 기준으로 위치하게 됩니다
      <Pressable onClick={open}>열기</Pressable>
    )}
    renderContents={() => (
      <Body level={2} px={20}>
        컨텐츠
      </Body>
    )}
  />
  <Dropdown
    position="top-end"
    renderOpener={({ ref, open }) => (
      <>
        <Pressable onClick={open}>열기</Pressable>
        <Box
          // ref를 사용한 경우 드랍다운은 이 Box를 기준으로 위치하게 됩니다
          ref={ref}
          position="fixed"
          bottom={0}
          width={50}
          height={50}
          borderRadius={25}
          backgroundColor="surface2"
          elevationLevel={1}
        />
      </>
    )}
    renderContents={() => (
      <Body level={2} px={20}>
        컨텐츠
      </Body>
    )}
  />
</HStack>
위치
드랍다운의 위치는 position 속성을 통해 bottom, left ,right, top, bottom-end, bottom-start, left-end, left-start, right-end, right-start, top-end, top-start로 설정할 수 있습니다.
컨텐츠
다양한 콘텐츠가 담길 수 있으며, 콘텐츠의 깊이(depth)가 변하는 경우에도 닫히지 않고 동일한 컨테이너를 유지한 채 높이가 변화합니다. 메뉴나 필터의 옵션으로 사용될 수 있으며 이 외에도 다양한 패턴으로 사용될 수 있습니다.