Lynx

Bottom Sheet

화면 하단에서 올라오는 시트 컴포넌트로, 드래그·snap·dismiss 상호작용을 제공합니다.

Engine ≥ 3.6<overlay>
사용 가능 버전@seed-design/[email protected], @seed-design/[email protected]
Lynx 예제를 불러오는 중입니다.

Installation

npx @seed-design/cli add ui:bottom-sheet

Usage

import {
  BottomSheetBody,
  BottomSheetContent,
  BottomSheetFooter,
  BottomSheetRoot,
  BottomSheetTrigger,
} from "@/components/ui/bottom-sheet";

export function App() {
  return (
    <BottomSheetRoot snapPoints={["fit", "80%"]}>
      <BottomSheetTrigger>
        <text>시트 열기</text>
      </BottomSheetTrigger>
      <BottomSheetContent title="제목" description="부가 설명" showHandle>
        <BottomSheetBody>
          <text>본문 콘텐츠</text>
        </BottomSheetBody>
        <BottomSheetFooter>
          <text>하단 액션 영역</text>
        </BottomSheetFooter>
      </BottomSheetContent>
    </BottomSheetRoot>
  );
}

BottomSheetTrigger는 Content 밖에 두세요.

container를 지정하지 않으면 Bottom Sheet는 Lynx view 안에 렌더링됩니다. container="window"처럼 native container 이름을 지정하면 host 화면까지 덮는 native overlay에 렌더링됩니다. overlayLevel은 overlay의 표시 순서를 정합니다. 이 기능을 사용할 때는 앱의 Lynx Engine이 <overlay>를 지원해야 합니다.

Imperative 제어

BottomSheetRoot에 ref를 전달하면 open, close, snapTo, expand, collapse 메서드를 호출할 수 있습니다. 이 메서드로 바꾼 열림 상태는 onOpenChange로 알리지 않습니다. open을 제어하는 경우에는 메서드 대신 open 값을 바꾸세요.

import { useRef } from "@lynx-js/react";
import { BottomSheetRoot, type BottomSheetRootRef } from "@/components/ui/bottom-sheet";

export function App() {
  const ref = useRef<BottomSheetRootRef>(null);

  return (
    <BottomSheetRoot ref={ref} snapPoints={["fit", "80%"]}>
      {/* ... */}
    </BottomSheetRoot>
  );
}

Props

BottomSheetRoot

Prop

Type

BottomSheetTrigger

고유 prop이 없습니다. className, style, children, bindtap을 받습니다.

BottomSheetContent

Prop

Type

title?ReactNode
description?ReactNode
container?(string & {}) | "spark" | "bullet" | "bulletPopup" | undefined
overlayLevel?2 | 1 | 3 | 4 | undefined

BottomSheetBody

고유 prop이 없습니다. className, style, children을 받습니다.

BottomSheetFooter

고유 prop이 없습니다. className, style, children을 받습니다.

Examples

Trigger

<BottomSheetTrigger>를 탭하면 Bottom Sheet가 열립니다. Lynx는 asChild를 지원하지 않습니다. Trigger는 자식 요소를 감싸는 <view>를 렌더링합니다.

Lynx 예제를 불러오는 중입니다.

Controlled

Trigger 외의 방식으로 Bottom Sheet를 열고 닫으려면 open과 onOpenChange로 상태를 제어합니다. 다음 예제는 버튼을 탭한 뒤 1초 후 Bottom Sheet를 엽니다.

Lynx 예제를 불러오는 중입니다.

onOpenChange Details

onOpenChange의 두 번째 인자는 { reason }입니다. Trigger로 열면 "trigger", 닫기 버튼으로 닫으면 "closeButton", 배경을 탭해 닫으면 "interactOutside", 시트를 끌어 닫으면 "drag"입니다. 닫히는 중에 시트를 다시 끌어 올리면 open이 true인 "drag"가 전달됩니다. Root ref의 메서드나 open prop으로 바꾼 상태에는 호출되지 않습니다. React 버전의 escapeKeyDown처럼 Lynx에 해당 입력이 없는 reason은 제공하지 않습니다.

Header Align

<BottomSheetRoot>의 headerAlign으로 title과 description을 왼쪽 또는 가운데에 정렬할 수 있습니다.

Lynx 예제를 불러오는 중입니다.

Long Content

내용에 맞춰 높이가 정해지는 시트는 화면 높이의 90%를 넘지 않고, 위쪽 inset이 그보다 크면 inset 아래까지로 제한됩니다. 제한에 닿으면 BottomSheetBody가 스크롤됩니다. Body가 스크롤된 상태에서 시작한 제스처는 Body만 움직이고, Body가 맨 위에 있을 때 아래로 끌어야 시트가 움직입니다.

Lynx 예제를 불러오는 중입니다.

Max Height

BottomSheetBody는 내용이 넘치면 세로로 스크롤합니다. 스크롤 영역을 최대 300px로 제한하려면 Body에 maxHeight를 지정하세요.

Lynx 예제를 불러오는 중입니다.

Snap Points

snapPoints에는 픽셀 숫자, 화면 높이 기준 백분율, 콘텐츠 크기에 맞추는 "fit"을 사용할 수 있습니다. 배열 순서가 snap index가 되며, initialSnap으로 처음 열릴 높이를 정합니다.

onSnapChange에서는 현재 index와 픽셀로 계산된 높이를 받을 수 있습니다. ref의 snapTo 메서드를 사용하면 원하는 높이로 이동할 수 있습니다.

Lynx 예제를 불러오는 중입니다.

드래그와 snap 애니메이션의 최종 동작은 QR 코드 패널에서 Lynx Explorer로 확인하세요. 문서 미리보기에서는 기기와 제스처 처리 결과가 다를 수 있습니다.

Fade From Index

Lynx는 fadeFromIndex를 지원하지 않습니다. snap index에 따른 Backdrop 투명도 변경도 지원하지 않습니다.

Show Handle

<BottomSheetContent>에 showHandle을 전달하면 Handle을 표시합니다. 기본값은 false입니다.

Lynx 예제를 불러오는 중입니다.

Show Close Button

<BottomSheetContent>에 showCloseButton prop을 전달하여 닫기 버튼을 표시할 수 있습니다. 기본 값은 true입니다.

showCloseButton을 false로 설정하면 닫기 버튼이 표시되지 않습니다. 이 경우 유저가 BottomSheet를 닫을 수 있는 방법을 제공해야 합니다.

Lynx 예제를 불러오는 중입니다.

Dismissible

Lynx에는 배경 탭, 드래그, ESC 닫기를 한 번에 제어하는 dismissible prop이 없습니다. enableDragToClose={false}로 드래그 닫기만 막을 수 있으며, Registry에서는 배경 탭 닫기를 끌 수 없습니다. ESC 키 닫기도 지원하지 않습니다. 닫기 동작을 막았다면 Footer 등에 닫기 버튼을 제공하세요.

With Scroll Fog

스크롤 힌트가 필요하면 Body 안에 Scroll Fog와 세로 <scroll-view>를 배치하세요. Body의 스크롤 영역 안에서는 height: "100%"가 기준으로 삼을 높이가 없으므로, ScrollFog에 고정 높이를 지정해야 합니다. fog 방향과 크기는 ScrollFog의 placement·size로, 스크롤바와 스크롤 동작은 <scroll-view> prop으로 제어합니다. 다만 이 <scroll-view>의 스크롤은 시트 드래그와 조정되지 않아, 스크롤한 상태에서 아래로 끌면 시트도 함께 움직입니다.

ScrollFog는 스크롤 위치와 관계없이 항상 효과를 표시하므로, <scroll-view>에 권장 padding인 상단 20px, 하단 80px을 지정해야 합니다.

Lynx 예제를 불러오는 중입니다.

Handle Only

<BottomSheetRoot>에 handleOnly를 전달하면 Bottom Sheet를 움직이는 세로 제스처 영역이 Handle로 제한됩니다. 이 옵션은 <BottomSheetContent showHandle>과 함께 사용하세요. 본문이 길 때는 Body 안의 스크롤 영역과 시트 드래그가 겹치지 않도록 이 조합을 권장합니다.

Lynx 예제를 불러오는 중입니다.

Skip Animation

skipAnimation을 전달하면 Bottom Sheet의 enter, exit, snap 애니메이션을 건너뜁니다.

Lynx 예제를 불러오는 중입니다.

웹 버전과의 차이

  • onOpenChange의 reason은 trigger, closeButton, interactOutside, drag만 제공합니다.
  • Trigger는 자식을 native view로 감싸며 asChild를 제공하지 않습니다.
  • Root ref의 open, close, snapTo, expand, collapse로 시트를 제어할 수 있습니다. ref로 바꾼 상태는 onOpenChange로 알리지 않습니다.
  • container와 overlayLevel로 native overlay의 위치와 표시 순서를 지정합니다.
  • Registry에서는 lazyMount와 unmountOnExit을 지원하지 않습니다.

Last updated on

목차