DeveloperP5 본문

개발자 리소스

토큰과 컴포넌트를 소비하는 방법 — Web/React와 Flutter(wiz_ui) 모두 설치·테마·계약·테스트 게이트까지 사용 가능.

마지막 업데이트 2026-06-13

설치 · 소비 (Web)#

@wds/ui-web는 사내 GitLab npm 레지스트리로 배포됩니다 — 다른 제품에서 설치해 쓰는 방법은 패키지 설치 가이드 를 보세요. 모노레포 안에서는 같은 워크스페이스에서 배럴로 가져옵니다.

import { Button, Input, Modal } from '@wds/ui-web';

컴포넌트는 --wds-* CSS 변수를 소비합니다 — 앱이 토큰 시트를 한 번 로드하고 [data-theme]로 테마를 전환합니다(다크는 다크 모드 참조).

// 앱 진입(layout 등)에서 생성된 토큰 시트를 1회 로드 (codegen 산출물 tokens/dist/wds.css)
import '../../tokens/dist/wds.css';
// <html data-theme="light | dark"> 에서 테마 결정 — FOUC 방지 스크립트는 동기 주입

브레이크포인트 상수가 필요하면 별도 서브패스로 가져옵니다(CSS 미디어쿼리는 var() 불가라 JS 상수로 소비 — ADR-012).

import { BP } from '@wds/ui-web/breakpoints'; // BP.compact 600 · BP.expanded 840

ref 전달 (React 19 ref-as-prop)#

전 컴포넌트(58종)가 ref를 전달합니다 — 선택적 가산 prop이라 기존 호출은 무영향. React 19에서 ref는 일반 prop이므로 forwardRef 없이 직접 받습니다. ref 타깃은 컴포넌트 종류로 정해집니다(정본: COMPONENT_API §2).

종류ref 타깃
폼 컨트롤네이티브 컨트롤 요소(input/textarea/토글 button)Input·Checkbox·Switch·Slider
버튼·링크루트 인터랙티브 요소Button·IconButton·Chip·TextLink
트리거 보유 오버레이트리거 buttonSelect·Popover·DropdownMenu·DatePicker
명령형 다이얼로그패널 [role=dialog]닫힘(미마운트) 동안 nullModal·Drawer·BottomSheet·SideSheet
레이아웃·합성·Tooltip최외곽 루트Card·Stack·Tabs·DataGrid·Tooltip

폼 컨트롤 ref가 래퍼가 아니라 컨트롤 요소를 가리키므로 React Hook Form 등록이 바로 동작합니다.

const { register } = useForm();
<Input aria-label="이메일" {...register('email')} />; // ref가 내부 <input>에 병합된다

명령형 다이얼로그는 닫혀 있으면 포털이 미마운트되어 ref.currentnull입니다 — 열림 이후에 패널을 참조하세요.

테스트 게이트#

루트에서 단일 명령으로 전 게이트를 돌립니다.

make check       # 빠른(~13초): 타입체크 · eslint · stylelint(DD-4) · 유닛
make check-full  # 전체(~5분): check + 실브라우저 axe + 시각 회귀(빌드 포함)
make hooks       # push 전 make check 자동 실행(opt-in, core.hooksPath)
게이트명령잡는 것
토큰 대비/패리티pnpm --filter @wds/build-tokens testWCAG AA·토널 대비 법칙·Web↔Dart 일치
컴포넌트 유닛pnpm --filter @wds/ui-web test동작·ARIA 구조(jsdom axe)
실브라우저 a11ypnpm --filter @wds/ui-web test:browsercolor-contrast 실측(Chromium)
시각 회귀pnpm --filter @wds/portal test:visual브레이크포인트×테마 픽셀 디프

스타일은 --wds-* 토큰만 허용됩니다(DD-4 — stylelint가 색·그림자·라디우스·보더· 폰트의 raw 값을 차단). 베이스라인 갱신은 pnpm --filter @wds/portal test:visual:update.

설치 · 소비 (Flutter — wiz_ui)#

같은 토큰 SSOT가 wiz_tokens.dart로 생성되어 flutter/wiz_ui에 흐릅니다. 모노레포 안에서는 path 의존, 외부 제품 리포는 git tag 의존(AD-9 — ref: 고정, main 직소비 금지)으로 가져옵니다. Pretendard(OFL)가 패키지에 동봉되어 별도 폰트 설정이 필요 없습니다.

dependencies:
  wiz_ui:
    git:
      url: ...               # wiz-design-system 저장소
      path: flutter/wiz_ui
      ref: wiz_ui-v0.5.0     # 릴리스 태그 고정

테마는 WizTheme 팩토리 한 쌍으로 적용하고, 색은 WizTheme.of(context)로 읽습니다.

import 'package:wiz_ui/wiz_ui.dart';

MaterialApp(theme: WizTheme.light(), darkTheme: WizTheme.dark(), themeMode: mode);

final c = WizTheme.of(context).colors; // WizColorScheme — c.primary, c.textMuted …

컴포넌트 15종(WizButton~WizKnowledgeCard)은 웹과 같은 계약을 따릅니다 — variant는 enum, 크기는 WizSize.sm/md/lg, 비활성화는 onPressed: null 관용, 슬롯은 Widget?. 전체 매핑 규칙은 COMPONENT_API §3이 정본입니다.

웹(React)Flutter비고
variant="secondary"variant: WizButtonVariant.secondary유니온 = enum
disabledonPressed: null (+enabled)Flutter 관용 우선
leadingIcon={node}leadingIcon: Widget?슬롯 = Widget
Modal open/onCloseawait WizModal.show(context, …)명령형 — pop 값이 Future로
useToast()WizToaster.show(context, …)우하단 스택·자동 닫힘
useResponsive()WizResponsive.of(context)compact/medium/expanded 동일 경계

반응형은 WizResponsive + 레이아웃 프리미티브(WizStack·WizContainer·WizGrid· WizSplit — 웹 4종과 동일 토큰)로 구성하고, WizGrid는 size class에 따라 4/8/12컬럼을 자동 적용합니다.

Flutter 게이트#

cd flutter/wiz_ui
flutter analyze              # 0 이슈 (strict)
flutter test                 # 단위·위젯·골든
cd example && flutter test   # 데모 + 웹/Flutter 로그인 패리티 diff ≤ 5%

패리티는 같은 카드 폭의 웹 캡처와 Flutter 골든을 픽셀 비교하는 게이트로 상시 검증됩니다(현재 실측 라이트 2.70% · 다크 2.55%). 설치·계약·하니스의 전체 정본은 저장소 docs/FLUTTER_GUIDE.md입니다.