사용자에게 중요한 정보나 팁을 시각적으로 강조하여 전달하는 메시지 컴포넌트입니다.
@seed-design/lynx-react@0.5.0, @seed-design/lynx-css@0.9.0
import "./styles" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout description = "Aute nulla proident tempor minim eiusmod. In nostrud officia irure laborum." />
< ActionableCallout description = "Aute nulla proident tempor minim eiusmod. In nostrud officia irure laborum." />
< DismissibleCallout description = "Aute nulla proident tempor minim eiusmod. In nostrud officia irure laborum." />
</ view >
</ view >
);
}
npx @seed-design/cli@latest add ui:callout pnpm dlx @seed-design/cli@latest add ui:callout yarn dlx @seed-design/cli@latest add ui:callout bun x @seed-design/cli@latest add ui:callout
의존성 설치
npm install @karrotmarket/lynx-monochrome-icon @seed-design/lynx-react yarn add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-react pnpm add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-react bun add @karrotmarket/lynx-monochrome-icon @seed-design/lynx-react 아래 코드를 복사 후 붙여넣고 사용하세요 /**
* @file ui:callout
* @requires @seed-design/lynx-react@>=0.5.0 <1.0.0
* @requires @seed-design/lynx-css@>=0.9.0 <1.0.0
**/
import IconChevronRightLine from "@karrotmarket/lynx-monochrome-icon/IconChevronRightLine" ;
import IconXmarkLine from "@karrotmarket/lynx-monochrome-icon/IconXmarkLine" ;
import * as React from "@lynx-js/react" ;
import {
Callout as SeedCallout,
PrefixIcon,
SuffixIcon,
type PrefixIconProps,
} from "@seed-design/lynx-react" ;
export interface CalloutProps
extends Omit < SeedCallout . RootProps , "children" | "open" | "defaultOpen" | "onDismiss" > {
prefixIcon ?: PrefixIconProps [ "icon" ];
title ?: React . ReactNode ;
description : React . ReactNode ;
linkProps ?: SeedCallout . LinkProps ;
}
/**
* @see https://seed-design.io/lynx/components/callout
*/
export const Callout = React. forwardRef < unknown , CalloutProps >(
({ prefixIcon , title , description , linkProps , ... otherProps }, ref ) => {
return (
< SeedCallout.Root ref = {ref} { ... otherProps}>
{prefixIcon ? < PrefixIcon icon = {prefixIcon} /> : null }
< SeedCallout.Content >
{title ? < SeedCallout.Title >{title}</ SeedCallout.Title > : null }
< SeedCallout.Description >{description}</ SeedCallout.Description >
{linkProps ? < SeedCallout.Link { ... linkProps} /> : null }
</ SeedCallout.Content >
</ SeedCallout.Root >
);
},
);
Callout.displayName = "Callout" ;
export interface ActionableCalloutProps
extends Omit < SeedCallout . RootProps , "children" | "open" | "defaultOpen" | "onDismiss" > {
prefixIcon ?: PrefixIconProps [ "icon" ];
title ?: React . ReactNode ;
description : React . ReactNode ;
}
/**
* @see https://seed-design.io/lynx/components/callout
*/
export const ActionableCallout = React. forwardRef < unknown , ActionableCalloutProps >(
({ prefixIcon , title , description , ... otherProps }, ref ) => {
return (
< SeedCallout.Root ref = {ref} { ... otherProps}>
{prefixIcon ? < PrefixIcon icon = {prefixIcon} /> : null }
< SeedCallout.Content >
{title ? < SeedCallout.Title >{title}</ SeedCallout.Title > : null }
< SeedCallout.Description >{description}</ SeedCallout.Description >
</ SeedCallout.Content >
< SuffixIcon icon = {< IconChevronRightLine />} />
</ SeedCallout.Root >
);
},
);
ActionableCallout.displayName = "ActionableCallout" ;
export interface DismissibleCalloutProps extends Omit < SeedCallout . RootProps , "children" > {
prefixIcon ?: PrefixIconProps [ "icon" ];
title ?: React . ReactNode ;
description : React . ReactNode ;
linkProps ?: SeedCallout . LinkProps ;
dismissLabel ?: string ;
}
/**
* @see https://seed-design.io/lynx/components/callout
*/
export const DismissibleCallout = React. forwardRef < unknown , DismissibleCalloutProps >(
({ prefixIcon , title , description , linkProps , dismissLabel = "닫기" , ... otherProps }, ref ) => {
return (
< SeedCallout.Root ref = {ref} { ... otherProps}>
{prefixIcon ? < PrefixIcon icon = {prefixIcon} /> : null }
< SeedCallout.Content >
{title ? < SeedCallout.Title >{title}</ SeedCallout.Title > : null }
< SeedCallout.Description >{description}</ SeedCallout.Description >
{linkProps ? < SeedCallout.Link { ... linkProps} /> : null }
</ SeedCallout.Content >
< SeedCallout.CloseButton accessibility-label = {dismissLabel}>
< SuffixIcon icon = {< IconXmarkLine />} />
</ SeedCallout.CloseButton >
</ SeedCallout.Root >
);
},
);
DismissibleCallout.displayName = "DismissibleCallout" ;
/**
* 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.
*/
prefixIcon?React.ReactElement < LynxIconElementProps, string | React.JSXElementConstructor < any >> | undefined
title?React.ReactNode
descriptionReact.ReactNode
linkProps?SeedCallout.LinkProps | undefined
bindtap?EventHandler < BaseTouchEvent < Target >> | undefined
main-thread:bindtap?EventHandler < BaseTouchEvent < Element >> | undefined
style?CSSProperties | undefined
className?string | undefined
prefixIcon?React.ReactElement < LynxIconElementProps, string | React.JSXElementConstructor < any >> | undefined
title?React.ReactNode
descriptionReact.ReactNode
bindtap?EventHandler < BaseTouchEvent < Target >> | undefined
main-thread:bindtap?EventHandler < BaseTouchEvent < Element >> | undefined
style?CSSProperties | undefined
className?string | undefined
prefixIcon?React.ReactElement < LynxIconElementProps, string | React.JSXElementConstructor < any >> | undefined
title?React.ReactNode
descriptionReact.ReactNode
linkProps?SeedCallout.LinkProps | undefined
dismissLabel?string | undefined
open?boolean | undefined
defaultOpen?boolean | undefined
onDismiss?(() => void ) | undefined
bindtap?EventHandler < BaseTouchEvent < Target >> | undefined
main-thread:bindtap?EventHandler < BaseTouchEvent < Element >> | undefined
style?CSSProperties | undefined
className?string | undefined
설치한 스니펫은 기본 Callout, 전체 영역을 탭할 수 있는 ActionableCallout, 닫을 수 있는 DismissibleCallout을 내보냅니다.
import { Callout } from "@/components/ui/callout" ;
export function App () {
return < Callout title = "알림" description = "새로운 소식을 확인해 보세요." />;
}
저수준 조합이 필요하면 @seed-design/lynx-react의 컴파운드 API를 직접 사용할 수 있습니다.
import { Callout } from "@seed-design/lynx-react" ;
export function App () {
return (
< Callout.Root tone = "informative" >
< Callout.Content >
< Callout.Title >알림</ Callout.Title >
< Callout.Description >새로운 소식을 확인해 보세요.</ Callout.Description >
</ Callout.Content >
</ Callout.Root >
);
}
import "./styles" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout description = {description} />
< ActionableCallout description = {description} />
< DismissibleCallout description = {description} />
</ view >
</ view >
);
}
import "./styles" ;
import IconCalendarFill from "@karrotmarket/lynx-monochrome-icon/IconCalendarFill" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout prefixIcon = {< IconCalendarFill />} description = {description} />
< ActionableCallout prefixIcon = {< IconCalendarFill />} description = {description} />
< DismissibleCallout prefixIcon = {< IconCalendarFill />} description = {description} />
</ view >
</ view >
);
}
import "./styles" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout title = "타이틀" description = {description} />
< ActionableCallout title = "타이틀" description = {description} />
< DismissibleCallout title = "타이틀" description = {description} />
</ view >
</ view >
);
}
ActionableCallout에서는 linkProps를 제공하지 않아요.
import "./styles" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout description = {description} linkProps = {{ children: "시도해 보기" }} />
< DismissibleCallout description = {description} linkProps = {{ children: "시도해 보기" }} />
</ view >
</ view >
);
}
import "./styles" ;
import IconCalendarFill from "@karrotmarket/lynx-monochrome-icon/IconCalendarFill" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout
title = "타이틀"
prefixIcon = {< IconCalendarFill />}
description = {description}
linkProps = {{ children: "시도해 보기" }}
/>
< DismissibleCallout
title = "타이틀"
prefixIcon = {< IconCalendarFill />}
description = {description}
linkProps = {{ children: "시도해 보기" }}
/>
</ view >
</ view >
);
}
tone은 neutral, informative, positive, warning, critical, magic을 지원합니다. 기본값은 neutral입니다.
import "./styles" ;
import IconCalendarFill from "@karrotmarket/lynx-monochrome-icon/IconCalendarFill" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout tone = "neutral" prefixIcon = {< IconCalendarFill />} description = {description} />
< ActionableCallout
tone = "neutral"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
< DismissibleCallout
tone = "neutral"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
</ view >
</ view >
);
}
import "./styles" ;
import IconCalendarFill from "@karrotmarket/lynx-monochrome-icon/IconCalendarFill" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout tone = "informative" prefixIcon = {< IconCalendarFill />} description = {description} />
< ActionableCallout
tone = "informative"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
< DismissibleCallout
tone = "informative"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
</ view >
</ view >
);
}
import "./styles" ;
import IconCalendarFill from "@karrotmarket/lynx-monochrome-icon/IconCalendarFill" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout tone = "positive" prefixIcon = {< IconCalendarFill />} description = {description} />
< ActionableCallout
tone = "positive"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
< DismissibleCallout
tone = "positive"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
</ view >
</ view >
);
}
import "./styles" ;
import IconCalendarFill from "@karrotmarket/lynx-monochrome-icon/IconCalendarFill" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout tone = "warning" prefixIcon = {< IconCalendarFill />} description = {description} />
< ActionableCallout
tone = "warning"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
< DismissibleCallout
tone = "warning"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
</ view >
</ view >
);
}
import "./styles" ;
import IconCalendarFill from "@karrotmarket/lynx-monochrome-icon/IconCalendarFill" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout tone = "critical" prefixIcon = {< IconCalendarFill />} description = {description} />
< ActionableCallout
tone = "critical"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
< DismissibleCallout
tone = "critical"
prefixIcon = {< IconCalendarFill />}
description = {description}
/>
</ view >
</ view >
);
}
import "./styles" ;
import IconSparkle2 from "@karrotmarket/lynx-multicolor-icon/IconSparkle2" ;
import { useSeedClassName } from "@seed-design/lynx-react" ;
import { ActionableCallout, Callout, DismissibleCallout } from "@/components/ui/callout" ;
const description =
"기능에 대한 안내 또는 유익한 내용을 전달해요. 콜아웃은 꼭 필요한 경우에만 절제하여 사용해요." ;
export default function Example () {
const seedClassName = useSeedClassName ({ colorMode: "system" });
return (
< view className = { `${ seedClassName } docs-lynx-callout-root` }>
< view className = "callout-preview" >
< Callout tone = "magic" prefixIcon = {< IconSparkle2 />} description = {description} />
< ActionableCallout tone = "magic" prefixIcon = {< IconSparkle2 />} description = {description} />
< DismissibleCallout tone = "magic" prefixIcon = {< IconSparkle2 />} description = {description} />
</ view >
</ view >
);
}
영역 React Lynx 엘리먼트 div, span, buttonview, text이벤트 onClickbindtap, main-thread:bindtap접근성 HTML 의미 요소, ARIA accessibility-*다형성 asChild 지원미지원 링크 밑줄 text-decorationLynx 프리셋 제약으로 테두리 기반 표현
Lynx에서는 탭할 수 있는 Root를 누르는 동안 pressed Recipe variant를 적용합니다. Callout.Link는 기본적으로 accessibility-traits="link"를 사용합니다. 탭할 수 있는 Root와 CloseButton에는 button 역할을 적용합니다.
asChild: Lynx에는 DOM Slot 기반 다형 렌더링이 없습니다.
링크 레이블을 자식 요소로 렌더링: asChild 대신 링크 문구를 linkProps.children에 전달하고 탭 동작은 linkProps.bindtap으로 처리하세요.