List
가로 행으로 구성된 콘텐츠를 표현하는 컴포넌트입니다.
import "./styles";
import IconILowercaseSerifCircleLine from "@karrotmarket/lynx-monochrome-icon/IconILowercaseSerifCircleLine";
import IconPersonCircleLine from "@karrotmarket/lynx-monochrome-icon/IconPersonCircleLine";
import { PrefixIcon, SuffixIcon } from "@seed-design/lynx-react";
import { ListHeader } from "@/components/ui/list-header";
import { List, ListDivider, ListItem } from "@/components/ui/list";
export default function Example() {
return (
<view className="list-preview">
<ListHeader>리스트 헤더</ListHeader>
<List>
<ListItem title="기본 리스트 아이템" />
<ListDivider />
<ListItem
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="아이콘이 있는 리스트 아이템"
detail="부가 정보가 포함된 설명"
suffix={<SuffixIcon icon={<IconILowercaseSerifCircleLine />} />}
/>
</List>
</view>
);
}Installation
npx @seed-design/cli@latest add ui:listpnpm dlx @seed-design/cli@latest add ui:listyarn dlx @seed-design/cli@latest add ui:listbun x @seed-design/cli@latest add ui:list의존성 설치
npm install @karrotmarket/lynx-monochrome-icon @seed-design/lynx-reactyarn add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-reactpnpm add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-reactbun add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-react아래 코드를 복사 후 붙여넣고 사용하세요
/**
* @file ui:list
* @requires @seed-design/lynx-react@^1.0.0
* @requires @seed-design/lynx-css@^1.0.0
* @requires @karrotmarket/lynx-monochrome-icon@>=1.20.0 <2.0.0
**/
import * as React from "@lynx-js/react";
import IconCheckmarkFatFill from "@karrotmarket/lynx-monochrome-icon/IconCheckmarkFatFill";
import IconMinusFatFill from "@karrotmarket/lynx-monochrome-icon/IconMinusFatFill";
import {
Checkbox as SeedCheckbox,
Divider as SeedDivider,
type DividerProps as SeedDividerProps,
List as SeedList,
RadioGroup as SeedRadioGroup,
Switch as SeedSwitch,
} from "@seed-design/lynx-react";
export interface ListProps extends SeedList.RootProps {}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const List = SeedList.Root;
interface ListItemContentProps {
title: React.ReactNode;
detail?: React.ReactNode;
prefix?: React.ReactNode;
suffix?: React.ReactNode;
}
function renderListItemContent({ title, detail, prefix, suffix }: ListItemContentProps) {
return (
<>
{prefix != null ? <SeedList.Prefix>{prefix}</SeedList.Prefix> : null}
<SeedList.Content>
<SeedList.Title>{title}</SeedList.Title>
{detail != null ? <SeedList.Detail>{detail}</SeedList.Detail> : null}
</SeedList.Content>
{suffix != null ? <SeedList.Suffix>{suffix}</SeedList.Suffix> : null}
</>
);
}
export interface ListItemProps extends Omit<SeedList.ItemProps, "children">, ListItemContentProps {}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const ListItem = React.forwardRef<unknown, ListItemProps>(
({ title, detail, prefix, suffix, ...props }, ref) => {
return (
<SeedList.Item ref={ref} {...props}>
{renderListItemContent({ title, detail, prefix, suffix })}
</SeedList.Item>
);
},
);
ListItem.displayName = "ListItem";
export interface ListButtonItemProps
extends Omit<SeedList.ButtonItemProps, "children">,
ListItemContentProps {}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const ListButtonItem = React.forwardRef<unknown, ListButtonItemProps>(
({ title, detail, prefix, suffix, ...props }, ref) => {
return (
<SeedList.ButtonItem ref={ref} {...props}>
{renderListItemContent({ title, detail, prefix, suffix })}
</SeedList.ButtonItem>
);
},
);
ListButtonItem.displayName = "ListButtonItem";
export interface ListCheckItemProps
extends Omit<SeedList.CheckboxItemProps, "children">,
ListItemContentProps {}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const ListCheckItem = React.forwardRef<unknown, ListCheckItemProps>(
({ title, detail, prefix, suffix, ...props }, ref) => {
const defaultSuffix = (
<SeedCheckbox.Control>
<SeedCheckbox.Indicator
checked={<IconCheckmarkFatFill />}
indeterminate={<IconMinusFatFill />}
/>
</SeedCheckbox.Control>
);
return (
<SeedList.CheckboxItem ref={ref} {...props}>
{renderListItemContent({
title,
detail,
prefix,
suffix: suffix === undefined ? defaultSuffix : suffix,
})}
</SeedList.CheckboxItem>
);
},
);
ListCheckItem.displayName = "ListCheckItem";
export interface ListRadioItemProps
extends Omit<SeedList.RadioItemProps, "children">,
ListItemContentProps {}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const ListRadioItem = React.forwardRef<unknown, ListRadioItemProps>(
({ title, detail, prefix, suffix, ...props }, ref) => {
const defaultSuffix = (
<SeedRadioGroup.ItemControl>
<SeedRadioGroup.ItemIndicator />
</SeedRadioGroup.ItemControl>
);
return (
<SeedList.RadioItem ref={ref} {...props}>
{renderListItemContent({
title,
detail,
prefix,
suffix: suffix === undefined ? defaultSuffix : suffix,
})}
</SeedList.RadioItem>
);
},
);
ListRadioItem.displayName = "ListRadioItem";
export interface ListSwitchItemProps
extends Omit<SeedList.SwitchItemProps, "children">,
ListItemContentProps {}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const ListSwitchItem = React.forwardRef<unknown, ListSwitchItemProps>(
({ title, detail, prefix, suffix, ...props }, ref) => {
const defaultSuffix = (
<SeedSwitch.Control>
<SeedSwitch.Thumb />
</SeedSwitch.Control>
);
return (
<SeedList.SwitchItem ref={ref} {...props}>
{renderListItemContent({
title,
detail,
prefix,
suffix: suffix === undefined ? defaultSuffix : suffix,
})}
</SeedList.SwitchItem>
);
},
);
ListSwitchItem.displayName = "ListSwitchItem";
export interface ListDividerProps extends SeedDividerProps {
/**
* @default false
*/
"accessibility-element"?: SeedDividerProps["accessibility-element"];
}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const ListDivider = React.forwardRef<unknown, ListDividerProps>(
({ "accessibility-element": accessibilityElement = false, ...props }, ref) => {
return <SeedDivider ref={ref} accessibility-element={accessibilityElement} {...props} />;
},
);
ListDivider.displayName = "ListDivider";
/**
* This file is a snippet from SEED Design, helping you get started quickly with @seed-design/* packages.
* You can extend this snippet however you want.
*/
/**
* @file ui:list
* @requires @seed-design/lynx-react@^1.0.0
* @requires @seed-design/lynx-css@^1.0.0
**/
import {
ListHeader as SeedListHeader,
type ListHeaderProps as SeedListHeaderProps,
} from "@seed-design/lynx-react";
export interface ListHeaderProps extends SeedListHeaderProps {}
/**
* @see https://seed-design.io/lynx/components/list
*/
export const ListHeader = SeedListHeader;
/**
* This file is a snippet from SEED Design, helping you get started quickly with @seed-design/* packages.
* You can extend this snippet however you want.
*/
Usage
import { ListHeader } from "@/components/ui/list-header";
import { List, ListDivider, ListItem } from "@/components/ui/list";
<view>
<ListHeader>리스트 헤더</ListHeader>
<List>
<ListItem title="리스트 아이템 1" />
<ListDivider />
<ListItem title="리스트 아이템 2" />
</List>
</view>Props
ListHeader
Prop
Type
List
고유 prop이 없습니다. className, style, children을 받습니다.
List Items
Prop
Type
disabled?boolean | undefinedtitleReact.ReactNodedetail?React.ReactNodeprefix?React.ReactNodesuffix?React.ReactNodeProp
Type
disabled?boolean | undefinedtitleReact.ReactNodedetail?React.ReactNodeprefix?React.ReactNodesuffix?React.ReactNodeLynx에는 HTML anchor에 해당하는 기본 요소가 없습니다. 링크 이동은 ListButtonItem의 bindtap에서 앱 라우터를 호출해 처리합니다.
Prop
Type
onCheckedChange?((checked: boolean) => void) | undefinedtitleReact.ReactNodedetail?React.ReactNodeprefix?React.ReactNodesuffix?React.ReactNodeProp
Type
onCheckedChange?((checked: boolean) => void) | undefinedtitleReact.ReactNodedetail?React.ReactNodeprefix?React.ReactNodesuffix?React.ReactNodeProp
Type
valuestringtitleReact.ReactNodedetail?React.ReactNodeprefix?React.ReactNodesuffix?React.ReactNodeProp
Type
Examples
Using ListHeader
ListHeader는 List 밖에 둡니다. 헤더에 액션이 필요하면 형제 요소로 배치하세요.
import "./styles";
import IconChevronRightLine from "@karrotmarket/lynx-monochrome-icon/IconChevronRightLine";
import IconLockLine from "@karrotmarket/lynx-monochrome-icon/IconLockLine";
import IconPersonCircleLine from "@karrotmarket/lynx-monochrome-icon/IconPersonCircleLine";
import IconQuestionmarkCircleFill from "@karrotmarket/lynx-monochrome-icon/IconQuestionmarkCircleFill";
import { ActionButton, PrefixIcon, SuffixIcon } from "@seed-design/lynx-react";
import { List, ListButtonItem, ListDivider } from "@/components/ui/list";
import { ListHeader } from "@/components/ui/list-header";
function AccountList() {
return (
<List>
<ListButtonItem
title="내 계정"
detail="이메일과 연락처, 본인 인증 관리"
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
suffix={<SuffixIcon icon={<IconChevronRightLine />} />}
/>
<ListButtonItem
title="보안 · 인증 관리"
detail="비밀번호, 생체 인증 사용을 관리해요"
prefix={<PrefixIcon icon={<IconLockLine />} />}
suffix={<SuffixIcon icon={<IconChevronRightLine />} />}
/>
</List>
);
}
export default function Example() {
return (
<view className="list-preview__sections">
<view className="list-preview__section">
<ListHeader variant="mediumWeak">variant="mediumWeak"</ListHeader>
<AccountList />
</view>
<ListDivider />
<view className="list-preview__section">
<ListHeader variant="boldSolid">variant="boldSolid"</ListHeader>
<AccountList />
</view>
<ListDivider />
<view className="list-preview__section">
<view className="list-preview__row list-preview__header-row">
<ListHeader>List Header with Action Button</ListHeader>
<ActionButton variant="ghost" size="small">
<PrefixIcon icon={<IconQuestionmarkCircleFill />} />
도움말
</ActionButton>
</view>
<AccountList />
</view>
</view>
);
}Affixes (Prefix/Suffix)
import "./styles";
import IconArrowUpBracketDownFill from "@karrotmarket/lynx-monochrome-icon/IconArrowUpBracketDownFill";
import IconILowercaseSerifCircleLine from "@karrotmarket/lynx-monochrome-icon/IconILowercaseSerifCircleLine";
import { useState } from "@lynx-js/react";
import { ActionButton, Icon, PrefixIcon } from "@seed-design/lynx-react";
import { List, ListDivider, ListItem } from "@/components/ui/list";
export default function Example() {
const [pressed, setPressed] = useState(false);
return (
<List className="list-preview">
<ListItem
prefix={
<view className="list-preview__avatar">
<text className="list-preview__avatar-label">A</text>
</view>
}
title="Prefix에 Avatar 넣기"
detail="Amet elit ullamco magna."
/>
<ListDivider />
<ListItem
title="Prefix에 아이콘 넣기"
detail="Deserunt nulla elit est."
prefix={<PrefixIcon icon={<IconILowercaseSerifCircleLine />} />}
/>
<ListDivider />
<ListItem
title="Suffix에 Action Button 넣기"
detail="Veniam non est non ut consequat."
suffix={
<ActionButton size="xsmall" variant="neutralWeak">
액션 버튼
</ActionButton>
}
/>
<ListDivider />
<ListItem
title="Suffix에 Action Button (Ghost) 넣기"
detail="Deserunt nulla elit est."
suffix={
<ActionButton size="small" variant="ghost" layout="iconOnly" accessibility-label="공유">
<Icon icon={<IconArrowUpBracketDownFill />} />
</ActionButton>
}
/>
<ListDivider />
<ListItem
title="Suffix에 토글 액션 넣기"
detail="Sit eu incididunt aute ea elit ex."
suffix={
<ActionButton
size="xsmall"
variant={pressed ? "neutralSolid" : "neutralWeak"}
bindtap={() => {
"background only";
setPressed((value) => !value);
}}
>
{pressed ? "선택됨" : "토글 버튼"}
</ActionButton>
}
/>
</List>
);
}Clickable List Items
ListButtonItem을 사용하면 리스트 항목 전체를 탭할 수 있습니다. Lynx에는 ListLinkItem이 없으므로 화면 이동은 bindtap에서 앱 라우터를 호출합니다.
import "./styles";
import IconArrowUpRightLine from "@karrotmarket/lynx-monochrome-icon/IconArrowUpRightLine";
import IconCheckmarkFill from "@karrotmarket/lynx-monochrome-icon/IconCheckmarkFill";
import IconChevronRightLine from "@karrotmarket/lynx-monochrome-icon/IconChevronRightLine";
import IconPenHorizlineFill from "@karrotmarket/lynx-monochrome-icon/IconPenHorizlineFill";
import IconPlusFill from "@karrotmarket/lynx-monochrome-icon/IconPlusFill";
import IconSquare2StackedFill from "@karrotmarket/lynx-monochrome-icon/IconSquare2StackedFill";
import { useState } from "@lynx-js/react";
import { ActionButton, PrefixIcon, SuffixIcon } from "@seed-design/lynx-react";
import { List, ListButtonItem, ListDivider, ListItem } from "@/components/ui/list";
export default function Example() {
const [status, setStatus] = useState("아직 탭하지 않았어요");
const [subscribed, setSubscribed] = useState(false);
const [copied, setCopied] = useState(false);
return (
<view className="list-preview">
<List>
<ListItem
title="ListItem은 클릭할 수 없어요. 눌러보세요."
detail="우측의 Action Button만 클릭할 수 있어요"
suffix={
<ActionButton
variant="ghost"
size="xsmall"
bindtap={() => {
"background only";
setStatus("편집 클릭됨");
}}
>
<PrefixIcon icon={<IconPenHorizlineFill />} />
편집
</ActionButton>
}
/>
<ListDivider />
<ListButtonItem
title="ListButtonItem은 클릭할 수 있어요. 눌러보세요."
detail="리스트 항목 전체와 우측의 토글 액션을 각각 탭할 수 있어요"
bindtap={() => {
"background only";
setStatus("리스트 아이템 클릭됨");
}}
suffix={
<view className="list-preview__suffix">
<view catchtap={() => {}}>
<ActionButton
variant={subscribed ? "neutralSolid" : "neutralWeak"}
size="xsmall"
bindtap={() => {
"background only";
setSubscribed((value) => !value);
setStatus("모아보기 상태 변경됨");
}}
>
<PrefixIcon icon={subscribed ? <IconCheckmarkFill /> : <IconPlusFill />} />
{subscribed ? "모아보는 중" : "모아보기"}
</ActionButton>
</view>
<SuffixIcon icon={<IconChevronRightLine />} />
</view>
}
/>
<ListDivider />
<ListButtonItem
title="ListButtonItem은 클릭할 수 있어요. 눌러보세요."
detail="리스트 항목 전체와 우측의 커스텀 버튼을 각각 탭할 수 있어요"
bindtap={() => {
"background only";
setStatus("리스트 아이템 클릭됨");
}}
suffix={
<view className="list-preview__suffix">
<view
className="list-preview__custom-button"
accessibility-element={true}
accessibility-traits="button"
catchtap={() => {
"background only";
setStatus("커스텀 버튼 클릭됨");
}}
>
<text className="list-preview__custom-button-label">커스텀 버튼</text>
</view>
<SuffixIcon icon={<IconChevronRightLine />} />
</view>
}
/>
<ListDivider />
<ListButtonItem
title="링크 이동도 ListButtonItem으로 처리해요."
detail="탭 이벤트에서 앱 라우터를 호출합니다"
bindtap={() => {
"background only";
setStatus("링크 이동 요청됨");
}}
suffix={
<view className="list-preview__suffix">
<view catchtap={() => {}}>
<ActionButton
variant="neutralWeak"
size="xsmall"
bindtap={() => {
"background only";
setCopied(true);
setStatus("URL 복사됨");
}}
>
<PrefixIcon icon={copied ? <IconCheckmarkFill /> : <IconSquare2StackedFill />} />
{copied ? "복사됨" : "URL 복사"}
</ActionButton>
</view>
<SuffixIcon icon={<IconArrowUpRightLine />} />
</view>
}
/>
</List>
<text className="list-preview__status">{status}</text>
</view>
);
}inputs in List Items
ListSwitchItem, ListCheckItem, ListRadioItem을 사용하면 항목 전체를 탭해 값을 바꿀 수 있습니다. snippet은 각 컨트롤을 기본 suffix로 렌더링합니다. suffix={null}을 전달하면 기본 컨트롤을 숨길 수 있습니다.
import "./styles";
import IconTrashcanLine from "@karrotmarket/lynx-monochrome-icon/IconTrashcanLine";
import { PrefixIcon } from "@seed-design/lynx-react";
import { List, ListDivider, ListSwitchItem } from "@/components/ui/list";
export default function Example() {
return (
<List className="list-preview">
<ListSwitchItem
title="삭제하기 전에 확인"
prefix={<PrefixIcon icon={<IconTrashcanLine />} />}
/>
<ListDivider />
<ListSwitchItem
title="메시지 요약"
detail="핵심 내용만 빠르게 확인해보세요."
defaultChecked
/>
</List>
);
}import "./styles";
import { HStack } from "@seed-design/lynx-react";
import { Badge } from "@/components/ui/badge";
import { Checkmark } from "@/components/ui/checkbox";
import { List, ListCheckItem, ListDivider } from "@/components/ui/list";
export default function Example() {
return (
<List className="list-preview">
<ListCheckItem
accessibility-label="알림 수신 동의"
title={
<HStack gap="x1_5" align="center">
<text>알림 수신 동의</text>
<Badge variant="weak">권장</Badge>
</HStack>
}
detail="푸시 알림을 받으시겠습니까?"
defaultChecked
/>
<ListDivider />
<ListCheckItem
title="마케팅 정보 수신 동의"
detail="마케팅 정보를 받으시겠습니까?"
prefix={<Checkmark tone="neutral" size="large" />}
suffix={null}
defaultChecked
/>
<ListDivider />
<ListCheckItem
prefix={<Checkmark tone="neutral" size="large" variant="ghost" />}
suffix={null}
title="Ghost Variant"
/>
</List>
);
}import "./styles";
import { List, ListDivider, ListRadioItem } from "@/components/ui/list";
import { RadioGroup, Radiomark } from "@/components/ui/radio-group";
export default function Example() {
return (
<RadioGroup className="list-preview" defaultValue="option1" accessibility-label="옵션 선택">
<List>
<ListRadioItem
value="option1"
title="옵션 1"
detail="첫 번째 선택지"
suffix={<Radiomark tone="neutral" size="large" />}
/>
<ListDivider />
<ListRadioItem
value="option2"
title="옵션 2"
detail="두 번째 선택지"
prefix={<Radiomark tone="neutral" size="large" />}
suffix={null}
/>
<ListDivider />
<ListRadioItem
value="option3"
title="옵션 3"
detail="세 번째 선택지"
prefix={<Radiomark tone="neutral" size="large" />}
suffix={null}
/>
</List>
</RadioGroup>
);
}Accessibility
ListButtonItem은 title에서 접근성 이름을 만듭니다. 제목에 <text>나 <view>를 직접 넣거나 부가 텍스트가 섞이면 accessibility-label을 지정하세요.
선택 항목은 행 전체를 하나의 접근성 요소로 노출하고 선택 상태를 전달합니다. ListRadioItem은 Registry snippet의 RadioGroup 안에 두고 그룹의 접근성 이름을 지정하세요.
import { List, ListRadioItem } from "@/components/ui/list";
import { RadioGroup } from "@/components/ui/radio-group";
<RadioGroup defaultValue="짜장" accessibility-label="점심 메뉴">
<List>
<ListRadioItem value="짜장" title="짜장" />
<ListRadioItem value="짬뽕" title="짬뽕" />
</List>
</RadioGroup>Disabled
import "./styles";
import IconChevronRightLine from "@karrotmarket/lynx-monochrome-icon/IconChevronRightLine";
import IconPersonCircleLine from "@karrotmarket/lynx-monochrome-icon/IconPersonCircleLine";
import IconSlashCircleLine from "@karrotmarket/lynx-monochrome-icon/IconSlashCircleLine";
import { PrefixIcon, SuffixIcon } from "@seed-design/lynx-react";
import { List, ListButtonItem, ListCheckItem, ListRadioItem } from "@/components/ui/list";
import { RadioGroup } from "@/components/ui/radio-group";
export default function Example() {
return (
<view className="list-preview__sections">
<List>
<ListButtonItem
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="활성화된 ListButtonItem"
detail="Cupidatat et pariatur amet."
suffix={<SuffixIcon icon={<IconChevronRightLine />} />}
/>
<ListCheckItem
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="활성화된 ListCheckItem"
/>
</List>
<RadioGroup defaultValue="enabled" accessibility-label="활성화 옵션">
<List>
<ListRadioItem
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="활성화된 ListRadioItem"
value="enabled"
/>
</List>
</RadioGroup>
<List>
<ListButtonItem
disabled
prefix={<PrefixIcon icon={<IconSlashCircleLine />} />}
title="비활성화된 ListButtonItem"
detail="Cupidatat et pariatur amet."
suffix={<SuffixIcon icon={<IconChevronRightLine />} />}
/>
<ListCheckItem
disabled
prefix={<PrefixIcon icon={<IconSlashCircleLine />} />}
title="비활성화된 ListCheckItem"
/>
</List>
<RadioGroup defaultValue="disabled" accessibility-label="비활성화 옵션">
<List>
<ListRadioItem
disabled
prefix={<PrefixIcon icon={<IconSlashCircleLine />} />}
title="비활성화된 ListRadioItem"
value="disabled"
/>
</List>
</RadioGroup>
</view>
);
}Variants
Highlighted
import "./styles";
import IconPersonCircleLine from "@karrotmarket/lynx-monochrome-icon/IconPersonCircleLine";
import { useState } from "@lynx-js/react";
import { PrefixIcon } from "@seed-design/lynx-react";
import { List, ListButtonItem, ListDivider, ListItem } from "@/components/ui/list";
import { Switch } from "@/components/ui/switch";
export default function Example() {
const [highlighted, setHighlighted] = useState(true);
return (
<view className="list-preview__sections">
<List>
<ListButtonItem
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="버튼"
detail="Enim aute duis magna mollit aute sit aliquip duis ut tempor sunt."
/>
<ListDivider />
<ListButtonItem
highlighted
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="하이라이트된 버튼"
detail="Enim aute duis magna mollit aute sit aliquip duis ut tempor sunt."
/>
<ListDivider />
<ListButtonItem
highlighted
disabled
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="하이라이트 및 비활성화된 버튼"
detail="Enim aute duis magna mollit aute sit aliquip duis ut tempor sunt."
/>
</List>
<List>
<ListItem
prefix={<PrefixIcon icon={<IconPersonCircleLine />} />}
title="하이라이트"
highlighted={highlighted}
/>
</List>
<view className="list-preview__row">
<text>highlight</text>
<Switch checked={highlighted} onCheckedChange={setHighlighted} />
</view>
</view>
);
}With Bottom Sheet
import "./styles";
import IconArrowClockwiseCircularFill from "@karrotmarket/lynx-monochrome-icon/IconArrowClockwiseCircularFill";
import { useRef, useState } from "@lynx-js/react";
import { ActionButton, PrefixIcon } from "@seed-design/lynx-react";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
type BottomSheetRootRef,
BottomSheetTrigger,
} from "@/components/ui/bottom-sheet";
import { List, ListCheckItem } from "@/components/ui/list";
const TYPES = ["버스", "지하철", "택시", "자전거", "도보"] as const;
export default function Example() {
const sheetRef = useRef<BottomSheetRootRef>(null);
const [selectedTypes, setSelectedTypes] = useState<(typeof TYPES)[number][]>([]);
return (
<BottomSheetRoot ref={sheetRef}>
<BottomSheetTrigger>
<ActionButton variant="neutralSolid">BottomSheet 열기</ActionButton>
</BottomSheetTrigger>
<BottomSheetContent title="교통수단" description="이동할 교통수단을 선택해주세요.">
<BottomSheetBody style={{ height: "280px" }}>
<List>
{TYPES.map((type) => (
<ListCheckItem
key={type}
title={type}
checked={selectedTypes.includes(type)}
onCheckedChange={() => {
setSelectedTypes((previous) =>
previous.includes(type)
? previous.filter((item) => item !== type)
: [...previous, type],
);
}}
/>
))}
</List>
</BottomSheetBody>
<BottomSheetFooter>
<view className="list-preview__bottom-sheet-actions">
<ActionButton
size="large"
variant="neutralSolid"
disabled={selectedTypes.length === 0}
bindtap={() => {
"background only";
sheetRef.current?.close();
}}
>
경로 찾기
</ActionButton>
<ActionButton
size="small"
variant="ghost"
disabled={selectedTypes.length === 0}
bindtap={() => {
"background only";
setSelectedTypes([]);
}}
>
<PrefixIcon icon={<IconArrowClockwiseCircularFill />} />
초기화
</ActionButton>
</view>
</BottomSheetFooter>
</BottomSheetContent>
</BottomSheetRoot>
);
}Alignment
React의 alignItems prop은 Lynx List에서 지원하지 않습니다. 상단 정렬이 필요하면 슬롯을 직접 배치한 별도 레이아웃을 사용하세요.
Border Radius
React의 itemBorderRadius prop은 Lynx List에서 지원하지 않습니다. Lynx 항목의 눌림 반경은 Recipe가 정한 값을 사용합니다. 둥근 카드 안에서는 바깥 컨테이너에 border-radius와 overflow: hidden을 적용하세요.
웹 버전과의 차이
- 항목을 탭할 때는
onClick대신bindtap을 사용합니다. - 링크 항목은
ListButtonItem의bindtap에서 앱 라우터를 호출합니다. - 선택 항목은 행 전체가 컨트롤의 상태와 접근성 값을 가집니다.
Lynx 미지원 기능
as와asChild를 지원하지 않습니다.itemBorderRadius대신 바깥 컨테이너에 반경과 clipping을 적용하세요.alignItems대신 별도 레이아웃을 구성하세요.- Header의 제목과 액션은 형제 요소로 배치하세요.
Last updated on