Lynx

Box

Box 컴포넌트는 Lynx에서 가장 기초적인 레이아웃 표면을 구성하는 컴포넌트입니다.

사용을 권장하지 않아요

레이아웃은 사용 중인 zero-runtime 스타일링 라이브러리로 구성하는 것을 권장해요. 이유와 대체 예제는 Styling 가이드에서 확인하세요.

Installation

npm install @seed-design/lynx-react @seed-design/lynx-css

Usage

import { Box, Text } from "@seed-design/lynx-react";

export function App() {
  return (
    <Box bg="bg.brandWeak" borderColor="stroke.brandWeak" borderWidth={1} borderRadius="r3" p="x4">
      <Text textStyle="t5Bold" color="fg.brand">
        Box
      </Text>
    </Box>
  );
}

Box는 Lynx 네이티브 <view>를 렌더링합니다. bg, p, borderRadius 같은 스타일 prop은 SEED 토큰을 직접 object style 값으로 변환해 적용합니다.

Props

Prop

Type

bg?(string & {}) | ScopedColorBg | ScopedColorPalette | ScopedColorBanner | undefined
background?(string & {}) | ScopedColorBg | ScopedColorPalette | ScopedColorBanner | undefined
color?(string & {}) | ScopedColorPalette | ScopedColorFg | undefined
borderColor?(string & {}) | ScopedColorPalette | ScopedColorStroke | undefined
borderWidth?0 | (string & {}) | 1 | undefined
borderTopWidth?0 | (string & {}) | 1 | undefined
borderRightWidth?0 | (string & {}) | 1 | undefined
borderBottomWidth?0 | (string & {}) | 1 | undefined
borderLeftWidth?0 | (string & {}) | 1 | undefined
borderRadius?0 | (string & {}) | "r0_5" | "r1" | "r1_5" | "r2" | "r2_5" | "r3" | "r3_5" | "r4" | "r5" | "r6" | "full" | undefined
borderTopLeftRadius?0 | (string & {}) | "r0_5" | "r1" | "r1_5" | "r2" | "r2_5" | "r3" | "r3_5" | "r4" | "r5" | "r6" | "full" | undefined
borderTopRightRadius?0 | (string & {}) | "r0_5" | "r1" | "r1_5" | "r2" | "r2_5" | "r3" | "r3_5" | "r4" | "r5" | "r6" | "full" | undefined
borderBottomRightRadius?0 | (string & {}) | "r0_5" | "r1" | "r1_5" | "r2" | "r2_5" | "r3" | "r3_5" | "r4" | "r5" | "r6" | "full" | undefined
borderBottomLeftRadius?0 | (string & {}) | "r0_5" | "r1" | "r1_5" | "r2" | "r2_5" | "r3" | "r3_5" | "r4" | "r5" | "r6" | "full" | undefined
width?Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | "full" | undefined
minWidth?Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | "full" | undefined
maxWidth?Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | "full" | undefined
height?Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | "full" | undefined
minHeight?Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | "full" | undefined
maxHeight?Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | "full" | undefined
top?0 | (string & {}) | undefined
left?0 | (string & {}) | undefined
right?0 | (string & {}) | undefined
bottom?0 | (string & {}) | undefined
padding?0 | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
p?0 | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
paddingX?0 | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
px?0 | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
paddingY?0 | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
py?0 | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
paddingTop?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
pt?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
paddingRight?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
pr?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
paddingBottom?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
pb?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
paddingLeft?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
pl?0 | "safeArea" | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
display?(string & {}) | "flex" | "none" | undefined
position?(string & {}) | "relative" | "absolute" | "fixed" | undefined
overflowX?"hidden" | (string & {}) | "visible" | undefined
overflowY?"hidden" | (string & {}) | "visible" | undefined
zIndex?Property.ZIndex | undefined
flexGrow?boolean | Property.FlexGrow | undefined
flexShrink?boolean | Property.FlexShrink | undefined
flexDirection?(string & {}) | "row" | "column" | "rowReverse" | "columnReverse" | undefined
flexWrap?boolean | "nowrap" | "wrap" | undefined
justifyContent?(string & {}) | "flexStart" | "flexEnd" | "center" | "spaceBetween" | "spaceAround" | undefined
justifySelf?Property.JustifySelf | undefined
alignItems?(string & {}) | "flexStart" | "flexEnd" | "center" | "stretch" | undefined
alignContent?(string & {}) | "flexStart" | "flexEnd" | "center" | "stretch" | undefined
alignSelf?(string & {}) | "flexStart" | "flexEnd" | "center" | "stretch" | undefined
gap?0 | Dimension | "spacingX.betweenChips" | "spacingX.globalGutter" | "spacingY.componentDefault" | "spacingY.navToTitle" | "spacingY.screenBottom" | "spacingY.betweenText" | (string & {}) | undefined
bleed?BleedValue | undefined
bleedX?BleedValue | undefined
bleedY?BleedValue | undefined
bleedTop?BleedValue | undefined
bleedRight?BleedValue | undefined
bleedBottom?BleedValue | undefined
bleedLeft?BleedValue | undefined
margin?MarginValue | undefined
m?MarginValue | undefined
marginX?MarginValue | undefined
mx?MarginValue | undefined
marginY?MarginValue | undefined
my?MarginValue | undefined
marginTop?MarginValue | undefined
mt?MarginValue | undefined
marginRight?MarginValue | undefined
mr?MarginValue | undefined
marginBottom?MarginValue | undefined
mb?MarginValue | undefined
marginLeft?MarginValue | undefined
ml?MarginValue | undefined

Style Props

현재 Box에서 여는 스타일 prop은 Lynx에서 안정적으로 검증한 범위로 제한합니다.

분류Props
색상bg, background, color, borderColor
테두리borderWidth, borderTopWidth, borderRightWidth, borderBottomWidth, borderLeftWidth, borderRadius와 corner radius props
크기width, minWidth, maxWidth, height, minHeight, maxHeight
패딩p, px, py, pt, pr, pb, pl과 longhand padding props
마진m, mx, my, mt, mr, mb, ml과 longhand margin props
Bleedbleed, bleedX, bleedY, bleedTop, bleedRight, bleedBottom, bleedLeft
Flexdisplay, flexDirection, flexWrap, flexGrow, flexShrink, alignItems, alignContent, alignSelf, justifyContent, justifySelf, gap
배치position, top, right, bottom, left, zIndex, overflowX, overflowY

명시적인 style prop은 마지막에 merge되므로, 필요한 경우 계산된 스타일을 덮어쓸 수 있습니다.

<Box p="x3" style={{ paddingLeft: "24px" }}>
  <Text>paddingLeft만 직접 override</Text>
</Box>

style prop은 inline style로 적용되므로 같은 속성을 지정한 className utility보다 우선합니다. className으로 지정할 속성은 style prop으로 함께 지정하지 마세요. 예를 들어 px="x3" className="pl-x7"의 왼쪽 패딩은 x3입니다.

pt, pr, pb, pl에 "safeArea"를 지정하면 host가 넘긴 safeAreaInsetTop, safeAreaInsetRight, safeAreaInsetBottom, safeAreaInsetLeft global props를 padding으로 적용합니다. 값이 없거나 음수이면 env(safe-area-inset-*)을 사용합니다. top과 bottom은 값이 0이어도 env()를 사용합니다.

Margin과 Bleed

margin prop은 SEED 토큰, 길이, "auto"를 받습니다. 방향별 prop이 축 prop(mx, my)보다, 축 prop이 m보다 우선합니다.

bleed prop은 음수 margin을 적용해, 요소를 부모의 padding 영역까지 넓힙니다. 값은 "16px" 같은 px 길이, 0, "safeArea"를 받습니다. "safeArea"를 지정하면 같은 방향의 safe area inset만큼 넓힙니다.

<Box pl="safeArea" pr="safeArea">
  <Box bleedX="safeArea" bg="bg.brandWeak">
    배경은 화면 끝까지 채우고, 내용은 부모의 safe area 안쪽 기준으로 둡니다.
  </Box>
</Box>

margin 계열과 bleed 계열은 모두 margin-*으로 변환되므로 함께 지정할 수 없습니다. 이 제약 때문에 BoxProps, VStackProps, HStackProps는 union 타입입니다. 이 타입을 확장할 때는 interface ... extends 대신 type을 사용하세요.

type MyBoxProps = BoxProps & { label: string };

Native Props

Box는 style prop 외에 루트 <view>의 native 속성(className, id, accessibility-*, bind*·main-thread:* 이벤트, data-* 등)과 ref를 받아 그대로 전달합니다. style prop과 같은 이름의 native 속성은 style prop으로 해석합니다.

웹 버전과의 차이

Lynx Box는 React Box와 다음과 같은 차이가 있습니다.

  • as, asChild를 지원하지 않습니다. Lynx 컴파일러 제약 때문에 네이티브 <view>를 컴포넌트 파일 안에서 직접 렌더링합니다.
  • bgGradient, boxShadow, unstable_transform처럼 아직 Lynx에서 검증하지 않은 StyleProps는 열지 않습니다.
  • bleed prop은 SEED 토큰("x4", "spacingX.globalGutter" 등)과 "asPadding"을 받지 않습니다. 토큰은 CSS 변수로 변환되는데, Lynx는 inline style의 calc() 안에 있는 CSS 변수를 적용하지 않기 때문입니다. 토큰과 같은 값의 px 길이를 지정하세요.
  • 반응형 값({ base, md }), hideFrom, _active, gridColumn, gridRow를 지원하지 않습니다. 스타일은 CSS 변수가 아니라 object style로 바로 적용됩니다.
  • 이벤트는 웹의 onClick 대신 Lynx의 bindtap 계열 prop을 사용합니다. 접근성은 aria-* 대신 accessibility-* prop을 사용합니다.

Last updated on

목차