-
{item.name}
+
{item.name}
YD Design System Typography 영덕 디자인 시스템
-
+
.{item.class} • {item.size} / {item.line} • {item.weight}
diff --git a/src/styles/globals.css b/src/styles/globals.css
index d740ed5..482efca 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -17,6 +17,7 @@
@import "./token.components/token.components.tabs.css";
@import "./token.components/token.components.calendar.css";
@import "./token.components/token.components.number-input.css";
+@import "./token.components/token.components.layout.css";
/* 모든 스크롤바에 적용 */
diff --git a/src/styles/token.components/token.components.card.css b/src/styles/token.components/token.components.card.css
index abec511..70c770f 100644
--- a/src/styles/token.components/token.components.card.css
+++ b/src/styles/token.components/token.components.card.css
@@ -1,14 +1,24 @@
/**
* Card 컴포넌트 스타일.
- * card-navy-50 스타일을 token.semantic.css에서 가져와 사용합니다.
+ * 콘텐츠를 담는 면(surface)으로, outlined(테두리) / filled(배경) 두 가지 variant 를 지원합니다.
*/
@layer components {
.yds-card {
display: block;
box-sizing: border-box;
- border-style: solid;
+ padding: var(--card-padding);
+ border-radius: var(--card-border-radius);
}
-
+
+ .yds-card-outlined {
+ border: var(--yds-border-width) solid var(--color-card-outlined-border);
+ }
+
+ .yds-card-filled {
+ background-color: var(--color-card-filled-bg);
+ }
+
+ /* 하위 호환: 기존 card-navy-* 유틸을 className 으로 넘기던 사용처 유지 */
.yds-card.card-navy-50 {
border-color: var(--color-secondary-50);
border-width: var(--yds-border-width);
diff --git a/src/styles/token.components/token.components.layout.css b/src/styles/token.components/token.components.layout.css
new file mode 100644
index 0000000..dc88fec
--- /dev/null
+++ b/src/styles/token.components/token.components.layout.css
@@ -0,0 +1,128 @@
+/**
+ * Layout(Stack / Inline / Field) 컴포넌트 스타일.
+ * 컴포넌트 사이의 간격을 spacing 토큰으로 강제하는 조합용 프리미티브입니다.
+ * Stack 은 수직 나열, Inline 은 수평 나열(줄바꿈), Field 는 라벨+입력+메시지 묶음을 담당합니다.
+ */
+@layer components {
+ .yds-stack {
+ display: flex;
+ flex-direction: column;
+ box-sizing: border-box;
+ }
+
+ /* Stack Gaps */
+ .yds-stack-gap-sm {
+ gap: var(--stack-gap-sm);
+ }
+
+ .yds-stack-gap-md {
+ gap: var(--stack-gap-md);
+ }
+
+ .yds-stack-gap-lg {
+ gap: var(--stack-gap-lg);
+ }
+
+ /* Stack Aligns */
+ .yds-stack-align-start {
+ align-items: flex-start;
+ }
+
+ .yds-stack-align-center {
+ align-items: center;
+ }
+
+ .yds-stack-align-end {
+ align-items: flex-end;
+ }
+
+ .yds-stack-align-stretch {
+ align-items: stretch;
+ }
+
+ .yds-inline {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ box-sizing: border-box;
+ }
+
+ /* Inline Gaps */
+ .yds-inline-gap-sm {
+ gap: var(--inline-gap-sm);
+ }
+
+ .yds-inline-gap-md {
+ gap: var(--inline-gap-md);
+ }
+
+ .yds-inline-gap-lg {
+ gap: var(--inline-gap-lg);
+ }
+
+ /* Inline Aligns (교차축) */
+ .yds-inline-align-start {
+ align-items: flex-start;
+ }
+
+ .yds-inline-align-center {
+ align-items: center;
+ }
+
+ .yds-inline-align-end {
+ align-items: flex-end;
+ }
+
+ /* Inline Justifies (주축) */
+ .yds-inline-justify-start {
+ justify-content: flex-start;
+ }
+
+ .yds-inline-justify-center {
+ justify-content: center;
+ }
+
+ .yds-inline-justify-end {
+ justify-content: flex-end;
+ }
+
+ .yds-inline-justify-between {
+ justify-content: space-between;
+ }
+
+ .yds-field {
+ display: flex;
+ flex-direction: column;
+ gap: var(--field-gap);
+ box-sizing: border-box;
+ }
+
+ .yds-field-label {
+ color: var(--color-field-label-text);
+ font-size: var(--field-label-typography-font-size);
+ line-height: var(--field-label-typography-line-height);
+ font-weight: var(--field-label-typography-font-weight);
+ font-family: var(--field-typography-font-family);
+ }
+
+ .yds-field-required {
+ margin-left: var(--spacing-1);
+ color: var(--color-field-required-mark);
+ }
+
+ .yds-field-description {
+ color: var(--color-field-description-text);
+ font-size: var(--field-message-typography-font-size);
+ line-height: var(--field-message-typography-line-height);
+ font-weight: var(--field-message-typography-font-weight);
+ font-family: var(--field-typography-font-family);
+ }
+
+ .yds-field-error {
+ color: var(--color-field-error-text);
+ font-size: var(--field-message-typography-font-size);
+ line-height: var(--field-message-typography-line-height);
+ font-weight: var(--field-message-typography-font-weight);
+ font-family: var(--field-typography-font-family);
+ }
+}
diff --git a/src/styles/token.components/token.components.tabs.css b/src/styles/token.components/token.components.tabs.css
index 037e9c3..c9daaa5 100644
--- a/src/styles/token.components/token.components.tabs.css
+++ b/src/styles/token.components/token.components.tabs.css
@@ -1,7 +1,7 @@
/**
* Tabs 컴포넌트 스타일.
* 컨테이너 안에서 하나의 탭을 선택하는 탭형 토글(radiogroup)입니다.
- * sm / md / lg 사이즈를 지원하며 선택된 탭은 노란(primary) 배경 + 검정 글씨로 강조됩니다.
+ * sm / md / lg 사이즈를 지원하며 선택된 탭은 노란(primary) 글자로 강조됩니다.
*/
@layer components {
.yds-tabs {
@@ -12,31 +12,11 @@
gap: var(--tabs-gap);
padding: var(--tabs-padding);
background-color: var(--color-tabs-bg);
+ border: var(--yds-border-width) solid var(--color-tabs-border);
border-radius: var(--tabs-border-radius);
}
- /* 선택된 탭 위로 슬라이드하는 하이라이트 */
- .yds-tabs-indicator {
- position: absolute;
- top: 0;
- left: 0;
- z-index: 0;
- border-radius: var(--tabs-item-border-radius);
- background-color: var(--color-tabs-item-selected-bg);
- pointer-events: none;
- will-change: transform, width;
- }
-
- .yds-tabs-indicator-animated {
- transition:
- transform var(--tabs-indicator-transition-duration) var(--tabs-indicator-transition-easing),
- width var(--tabs-indicator-transition-duration) var(--tabs-indicator-transition-easing),
- opacity var(--tabs-indicator-transition-duration) var(--tabs-indicator-transition-easing);
- }
-
.yds-tabs-item {
- position: relative;
- z-index: 1;
display: inline-flex;
align-items: center;
justify-content: center;
@@ -72,18 +52,11 @@
cursor: not-allowed;
}
- /* 선택된 탭 텍스트 색상. 배경은 하이라이트(indicator)가 담당 */
+ /* 선택된 탭: 노란(primary) 글자로 강조 */
.yds-tabs-item-selected {
color: var(--color-tabs-item-selected-text);
}
- /* 모션 최소화 선호 시 슬라이드 애니메이션 비활성화 */
- @media (prefers-reduced-motion: reduce) {
- .yds-tabs-indicator-animated {
- transition: none;
- }
- }
-
/* Sizes */
.yds-tabs-sm .yds-tabs-item {
height: var(--tabs-item-height-sm);
diff --git a/src/styles/token.primitive.css b/src/styles/token.primitive.css
index f81fe01..d1fa83d 100644
--- a/src/styles/token.primitive.css
+++ b/src/styles/token.primitive.css
@@ -22,6 +22,18 @@
--color-white: rgb(255, 255, 255);
--color-black: rgb(0, 0, 0);
+ --color-green-50: rgb(240, 253, 244);
+ --color-green-100: rgb(220, 252, 231);
+ --color-green-200: rgb(187, 247, 208);
+ --color-green-300: rgb(134, 239, 172);
+ --color-green-400: rgb(74, 222, 128);
+
+ --color-red-50: rgb(254, 242, 242);
+ --color-red-100: rgb(254, 226, 226);
+ --color-red-200: rgb(254, 202, 202);
+ --color-red-300: rgb(252, 165, 165);
+ --color-red-400: rgb(248, 113, 113);
+
/* Typography Tokens */
--font-size-yds-h1: 48px;
@@ -55,6 +67,17 @@
/* Font Family */
--font-yds-wanted: 'Wanted Sans Variable';
+ /* Spacing Tokens (4px 단위 스케일) */
+ --spacing-1: 4px;
+ --spacing-2: 8px;
+ --spacing-3: 12px;
+ --spacing-4: 16px;
+ --spacing-5: 20px;
+ --spacing-6: 24px;
+ --spacing-8: 32px;
+ --spacing-10: 40px;
+ --spacing-12: 48px;
+
/* border Tokens */
--yds-border-width: 2px;
--yds-border-radius: 8px;
diff --git a/src/styles/token.semantic.css b/src/styles/token.semantic.css
index def62f1..5e3392d 100644
--- a/src/styles/token.semantic.css
+++ b/src/styles/token.semantic.css
@@ -33,18 +33,27 @@
--color-border-primary-deep: var(--color-primary-400);
--color-border-secondary-light: var(--color-secondary-50);
--color-border-secondary-deep: var(--color-secondary-400);
+ --color-border-divider: var(--color-secondary-100);
/* Font Tokens */
--color-font-primary-light: var(--color-primary-100);
--color-font-primary-deep: var(--color-primary-400);
+ /* System Semantic Tokens (성공·에러 등 시스템 상태 표현) */
+ --color-success: var(--color-green-400);
+ --color-error: var(--color-red-400);
+
+ /* Finance Semantic Tokens (수입/지출 등 증감 표현) */
+ --color-income: var(--color-green-400);
+ --color-expense: var(--color-red-400);
+
/* Table Tokens */
--color-table-wrapper-bg: var(--color-secondary-300);
--color-table-header-bg: var(--color-secondary-200);
--color-table-row-bg: var(--color-secondary-300);
--color-table-row-bg-striped: var(--color-secondary-200);
- --color-table-border: var(--color-secondary-100);
- --color-table-border-header: var(--color-secondary-100);
+ --color-table-border: var(--color-border-divider);
+ --color-table-border-header: var(--color-border-divider);
--color-table-text: var(--color-white);
--color-table-text-header: var(--color-primary-100);
@@ -65,6 +74,12 @@
--button-height: 48px;
--button-border-radius: var(--yds-border-radius);
+ /* Card Tokens */
+ --card-padding: var(--yds-content-padding);
+ --card-border-radius: var(--yds-border-radius);
+ --color-card-outlined-border: var(--color-secondary-50);
+ --color-card-filled-bg: var(--color-background-secondary);
+
/* Modal Spacing Tokens */
--modal-size-sm-width: 320px;
--modal-size-sm-height: 400px;
@@ -187,15 +202,13 @@
--tabs-typography-line-height: var(--line-height-yds-c1m);
--tabs-typography-font-weight: var(--font-weight-yds-c1m);
--tabs-typography-font-family: var(--font-yds-wanted);
- --tabs-indicator-transition-duration: 0.25s;
- --tabs-indicator-transition-easing: cubic-bezier(0.4, 0, 0.2, 1);
- /* Tabs Color Tokens */
+ /* Tabs Color Tokens (구분선 색 테두리, 선택은 노란 글자로 강조) */
--color-tabs-bg: var(--color-secondary-300);
- --color-tabs-item-text: var(--color-secondary-50);
- --color-tabs-item-text-hover: var(--color-white);
- --color-tabs-item-selected-bg: var(--color-primary-400);
- --color-tabs-item-selected-text: var(--color-black);
+ --color-tabs-border: var(--color-border-divider);
+ --color-tabs-item-text: var(--color-white);
+ --color-tabs-item-text-hover: var(--color-primary-100);
+ --color-tabs-item-selected-text: var(--color-primary-400);
--color-tabs-focus-ring: var(--color-white);
/* Calendar Spacing Tokens */
@@ -240,6 +253,30 @@
--color-calendar-cell-today-border: var(--color-primary-100);
--color-calendar-focus-ring: var(--color-white);
+ /* Layout(Stack/Inline) Spacing Tokens */
+ --stack-gap-sm: var(--spacing-2);
+ --stack-gap-md: var(--spacing-4);
+ --stack-gap-lg: var(--spacing-6);
+ --inline-gap-sm: var(--spacing-1);
+ --inline-gap-md: var(--spacing-2);
+ --inline-gap-lg: var(--spacing-4);
+
+ /* Field Spacing Tokens */
+ --field-gap: var(--spacing-2);
+ --field-label-typography-font-size: var(--font-size-yds-c1m);
+ --field-label-typography-line-height: var(--line-height-yds-c1m);
+ --field-label-typography-font-weight: var(--font-weight-yds-c1m);
+ --field-message-typography-font-size: var(--font-size-yds-c1r);
+ --field-message-typography-line-height: var(--line-height-yds-c1r);
+ --field-message-typography-font-weight: var(--font-weight-yds-c1r);
+ --field-typography-font-family: var(--font-yds-wanted);
+
+ /* Field Color Tokens */
+ --color-field-label-text: var(--color-font-primary-light);
+ --color-field-description-text: var(--color-secondary-50);
+ --color-field-error-text: var(--color-error);
+ --color-field-required-mark: var(--color-error);
+
/* Z-index Tokens */
--z-index-select-box-dropdown: 1000;
--z-index-calendar-panel: 1000;
diff --git a/ui-docs-site/.vitepress/config.ts b/ui-docs-site/.vitepress/config.ts
index 7faa255..142ce15 100644
--- a/ui-docs-site/.vitepress/config.ts
+++ b/ui-docs-site/.vitepress/config.ts
@@ -51,6 +51,14 @@ export default defineConfig({
{ text: 'HorizonDragScroll', link: '/components/horizon-drag-scroll' },
],
},
+ {
+ text: '레이아웃',
+ items: [
+ { text: 'Stack', link: '/components/stack' },
+ { text: 'Inline', link: '/components/inline' },
+ { text: 'Field', link: '/components/field' },
+ ],
+ },
{
text: '달력',
items: [
diff --git a/ui-docs-site/components/card.md b/ui-docs-site/components/card.md
index 4fc8575..8b76ecc 100644
--- a/ui-docs-site/components/card.md
+++ b/ui-docs-site/components/card.md
@@ -1,6 +1,6 @@
# Card
-카드 컴포넌트는 콘텐츠를 테두리와 패딩으로 감싸 보여주는 컨테이너입니다. card-navy-50 스타일을 사용하며, 디자인 토큰 기반의 border, border-radius, padding이 적용됩니다.
+카드 컴포넌트는 콘텐츠를 담는 면(surface) 컨테이너입니다. 테두리로 영역을 구분하는 outlined 와 배경색으로 구분하는 filled 두 가지 variant 를 지원하며, padding, border-radius, 색상은 디자인 토큰에서 일괄 적용됩니다.
## 기본 사용법
@@ -12,6 +12,27 @@ function App() {
}
```
+## Variants
+
+### Outlined (기본)
+
+테두리로 영역을 구분합니다. 배경과 같은 면 위에서 콘텐츠를 묶을 때 사용합니다.
+
+```tsx
+
테두리 카드
+```
+
+### Filled
+
+배경색(secondary-300)으로 영역을 구분합니다. 어두운 페이지 배경 위에 놓이는 대시보드 타일, 패널, 폼 컨테이너에 사용합니다.
+
+```tsx
+
+ 이번 달 총 예산
+ 1,200,000원
+
+```
+
## Width & Height
카드 크기는 `className`에 Tailwind 클래스를 전달하여 자유롭게 조정할 수 있습니다.
@@ -60,9 +81,17 @@ Tailwind 등 추가 클래스를 `className`으로 넘길 수 있습니다. widt
## Props
-| Prop | Type | Default | Description |
-|------------|----------------|---------|------------------|
-| `className`| `string` | `''` | 추가 CSS 클래스 |
-| `children` | `React.ReactNode` | - | 카드 내용 |
+| Prop | Type | Default | Description |
+|------------|-----------------------------|--------------|----------------------------------------|
+| `variant` | `'outlined' \| 'filled'` | `'outlined'` | outlined: 테두리 / filled: 배경색 구분 |
+| `className`| `string` | `''` | 추가 CSS 클래스 |
+| `children` | `React.ReactNode` | - | 카드 내용 |
Card는 표준 HTML div 요소의 모든 속성을 지원합니다.
+
+## 디자인 토큰
+
+- `--card-padding`: 카드 안쪽 여백 (16px)
+- `--card-border-radius`: 모서리 반경 (8px)
+- `--color-card-outlined-border`: outlined 테두리 색상 (secondary-50)
+- `--color-card-filled-bg`: filled 배경색 (secondary-300)
diff --git a/ui-docs-site/components/field.md b/ui-docs-site/components/field.md
new file mode 100644
index 0000000..7bf7283
--- /dev/null
+++ b/ui-docs-site/components/field.md
@@ -0,0 +1,72 @@
+# Field
+
+Field 컴포넌트는 폼 입력 하나를 라벨 + 입력 + 설명/에러 메시지의 표준 구조로 묶는 컴포넌트입니다. 폼을 만들 때마다 라벨 간격과 타이포그래피, 에러 표시 방식을 즉흥적으로 정하지 않도록 결정을 컴포넌트에 담았습니다.
+
+## 기본 사용법
+
+```tsx
+import { Field, Input } from '@youngduck/yd-ui'
+
+function App() {
+ return (
+
+
+
+ )
+}
+```
+
+## 주요 특징
+
+- **표준 구조**: 라벨(yds-c1m, primary-100) + 임의의 입력(children) + 설명/에러 메시지(yds-c1r)
+- **에러 표시**: `error` 지정 시 설명 대신 에러가 표시되고 `role="alert"` 로 스크린 리더에 즉시 전달됩니다.
+- **필수 표시**: `required` 지정 시 라벨 옆에 빨간 별표(*)가 붙습니다.
+- **라벨 클릭 포커스**: label 요소로 감싸므로 네이티브 input 은 라벨 클릭 시 자동으로 포커스됩니다.
+- **입력 무관**: Input / NumberInput / DatePicker / SelectBox 등 어떤 입력이든 children 으로 감쌀 수 있습니다.
+
+## 에러 상태
+
+```tsx
+
+
+
+```
+
+## 폼 조합 예시
+
+여러 Field 를 세로로 배치할 때는 [Stack](/components/stack) 으로 감쌉니다.
+
+```tsx
+
+
+
+
+
+
+
+
+ 취소
+ 저장
+
+
+```
+
+## Props
+
+| Prop | Type | Default | Description |
+|---------------|-------------------|---------|------------------------------------------|
+| `label` | `string` | - | 입력 위에 표시되는 라벨 (필수) |
+| `description` | `string` | - | 입력 아래 보조 설명 |
+| `error` | `string` | - | 에러 메시지. 지정 시 설명 대신 표시 |
+| `required` | `boolean` | `false` | 필수 입력 표시(*) 여부 |
+| `children` | `React.ReactNode` | - | 라벨이 감쌀 입력 요소 (필수) |
+
+Field는 표준 HTML label 요소의 속성을 함께 지원합니다.
+
+## 디자인 토큰
+
+- `--field-gap`: 라벨·입력·메시지 사이 간격 (spacing-2, 8px)
+- `--color-field-label-text`: 라벨 색상 (primary-100)
+- `--color-field-description-text`: 설명 색상 (secondary-50)
+- `--color-field-error-text`: 에러 메시지 색상 (error)
+- `--color-field-required-mark`: 필수 표시 색상 (error)
diff --git a/ui-docs-site/components/inline.md b/ui-docs-site/components/inline.md
new file mode 100644
index 0000000..5863acb
--- /dev/null
+++ b/ui-docs-site/components/inline.md
@@ -0,0 +1,59 @@
+# Inline
+
+Inline 컴포넌트는 자식들을 수평으로 나열(공간 부족 시 자동 줄바꿈)하고 사이 간격을 spacing 토큰으로 강제하는 레이아웃 컴포넌트입니다. 버튼 그룹, 칩 목록, 필터 바처럼 가로로 흐르는 요소 배치에 사용합니다.
+
+## 기본 사용법
+
+```tsx
+import { Inline, Chips } from '@youngduck/yd-ui'
+
+function App() {
+ return (
+
+ 식비
+ 교통비
+ 문화생활
+
+ )
+}
+```
+
+## 주요 특징
+
+- **간격 토큰 강제**: `gap` 은 sm(4px) / md(8px) / lg(16px) 세 가지만 허용합니다. (기본값 md)
+- **자동 줄바꿈**: 공간이 부족하면 flex-wrap 으로 다음 줄로 넘어갑니다.
+- **정렬 지원**: `align`(교차축) / `justify`(주축) 로 배치를 제어합니다.
+
+## 버튼 그룹 (우측 정렬)
+
+```tsx
+
+ 취소
+ 저장
+
+```
+
+## 라벨-값 양끝 배치
+
+```tsx
+
+ 이번 달 총 예산
+ 1,200,000원
+
+```
+
+## Props
+
+| Prop | Type | Default | Description |
+|-----------|-----------------------------------------------|------------|--------------------|
+| `gap` | `'sm' \| 'md' \| 'lg'` | `'md'` | 자식 사이 수평 간격 |
+| `align` | `'start' \| 'center' \| 'end'` | `'center'` | 교차축(세로) 정렬 |
+| `justify` | `'start' \| 'center' \| 'end' \| 'between'` | `'start'` | 주축(가로) 정렬 |
+
+Inline은 표준 HTML div 요소의 모든 속성을 지원합니다.
+
+## 디자인 토큰
+
+- `--inline-gap-sm` / `-md` / `-lg`: spacing-1 / spacing-2 / spacing-4 (4 / 8 / 16px)
+
+세로 나열은 [Stack](/components/stack) 을 사용합니다.
diff --git a/ui-docs-site/components/stack.md b/ui-docs-site/components/stack.md
new file mode 100644
index 0000000..6494d98
--- /dev/null
+++ b/ui-docs-site/components/stack.md
@@ -0,0 +1,51 @@
+# Stack
+
+Stack 컴포넌트는 자식들을 수직으로 나열하고 사이 간격을 spacing 토큰으로 강제하는 레이아웃 컴포넌트입니다. 화면마다 임의의 gap 값을 즉흥적으로 정하지 않도록 선택지를 sm / md / lg 세 가지로 좁혀, 어떤 화면을 만들어도 같은 간격 리듬이 나오게 하는 것이 목적입니다.
+
+## 기본 사용법
+
+```tsx
+import { Stack, Field, NumberInput, DatePicker } from '@youngduck/yd-ui'
+
+function App() {
+ return (
+
+
+
+
+
+
+
+
+ )
+}
+```
+
+## 주요 특징
+
+- **간격 토큰 강제**: `gap` 은 sm(8px) / md(16px) / lg(24px) 세 가지만 허용합니다. (기본값 md)
+- **교차축 정렬**: `align` 으로 start / center / end / stretch 를 지정합니다. (기본값 stretch)
+- **표준 div 속성 지원**: `className` 으로 너비 등 추가 스타일을 지정할 수 있습니다.
+
+## Gap
+
+```tsx
+
밀접한 요소 사이 (8px)
+
기본 수직 간격 (16px)
+
폼 필드·섹션 사이 (24px)
+```
+
+## Props
+
+| Prop | Type | Default | Description |
+|---------|---------------------------------------------|-------------|--------------------|
+| `gap` | `'sm' \| 'md' \| 'lg'` | `'md'` | 자식 사이 수직 간격 |
+| `align` | `'start' \| 'center' \| 'end' \| 'stretch'` | `'stretch'` | 교차축(가로) 정렬 |
+
+Stack은 표준 HTML div 요소의 모든 속성을 지원합니다.
+
+## 디자인 토큰
+
+- `--stack-gap-sm` / `-md` / `-lg`: spacing-2 / spacing-4 / spacing-6 (8 / 16 / 24px)
+
+가로 나열은 [Inline](/components/inline), 폼 필드 묶음은 [Field](/components/field) 를 사용합니다.
diff --git a/ui-docs-site/components/tabs.md b/ui-docs-site/components/tabs.md
index d2b1a08..7cd09e9 100644
--- a/ui-docs-site/components/tabs.md
+++ b/ui-docs-site/components/tabs.md
@@ -1,6 +1,6 @@
# Tabs
-Tabs 컴포넌트는 컨테이너 안에서 여러 항목 중 하나를 선택하는 탭형 토글입니다. 선택된 탭은 노란(primary) 배경 + 검정 글씨로 강조되며, 지역·기간 필터 같은 단일 선택 UI에 적합합니다. `value` / `onValueChange` 로 상태를 관리하는 제어 컴포넌트입니다.
+Tabs 컴포넌트는 컨테이너 안에서 여러 항목 중 하나를 선택하는 탭형 토글입니다. 구분선 색 테두리를 두른 네이비 컨테이너 안에서 선택된 탭은 노란(primary) 글자, 미선택 탭은 흰 글자로 표시되며, 지역·기간 필터 같은 단일 선택 UI에 적합합니다. `value` / `onValueChange` 로 상태를 관리하는 제어 컴포넌트입니다.
## 기본 사용법
@@ -29,8 +29,8 @@ function App() {
- **제어 컴포넌트**: `value` / `onValueChange` 로 선택 상태를 직접 관리합니다.
- **options 기반**: `{ label, value, disabled? }` 배열로 탭을 구성합니다.
-- **선택 강조**: 선택된 탭은 노란(primary-400) 배경 + 검정 글씨로 표시됩니다.
-- **슬라이드 애니메이션**: 선택이 바뀌면 노란 하이라이트가 새 탭 위치로 부드럽게 이동합니다. `prefers-reduced-motion: reduce` 환경에서는 애니메이션이 자동으로 비활성화됩니다.
+- **선택 강조**: 선택된 탭은 노란(primary-400) 글자, 미선택 탭은 흰 글자로 표시됩니다.
+- **구분선 테두리**: 컨테이너에 Table 행 구분선과 같은 `--color-border-divider` 토큰의 테두리가 적용됩니다.
- **사이즈 지원**: sm / md / lg 세 가지 사이즈 제공 (기본값 md)
- **접근성**: `role="radiogroup"` / `role="radio"`, 방향키·Home·End 키보드 탐색, 로빙 탭인덱스 적용
- **디자인 토큰**: 색상·간격·타이포그래피를 모두 토큰에서 일괄 적용
@@ -143,8 +143,6 @@ Tabs 컴포넌트는 다음 디자인 토큰을 사용합니다.
- `--tabs-item-border-radius`: 개별 탭 모서리 반경 (6px)
- `--tabs-item-padding-x`: 탭 좌우 패딩 (16px)
- `--tabs-item-height-sm` / `-md` / `-lg`: 사이즈별 탭 높이 (28 / 34 / 42px)
-- `--tabs-indicator-transition-duration`: 하이라이트 이동 시간 (0.25s)
-- `--tabs-indicator-transition-easing`: 하이라이트 이동 이징 (cubic-bezier(0.4, 0, 0.2, 1))
### Typography Tokens
- `--tabs-typography-font-size`: yds-c1m 폰트 크기
@@ -154,8 +152,8 @@ Tabs 컴포넌트는 다음 디자인 토큰을 사용합니다.
### Color Tokens
- `--color-tabs-bg`: 컨테이너 배경색 (secondary-300)
-- `--color-tabs-item-text`: 미선택 탭 텍스트 색상 (secondary-50)
-- `--color-tabs-item-text-hover`: 미선택 탭 hover 텍스트 색상 (white)
-- `--color-tabs-item-selected-bg`: 선택된 탭 배경색 (primary-400, 노란색)
-- `--color-tabs-item-selected-text`: 선택된 탭 텍스트 색상 (black)
+- `--color-tabs-border`: 컨테이너 테두리 색상 (border-divider, Table 구분선과 공유)
+- `--color-tabs-item-text`: 미선택 탭 텍스트 색상 (white)
+- `--color-tabs-item-text-hover`: 미선택 탭 hover 텍스트 색상 (primary-100)
+- `--color-tabs-item-selected-text`: 선택된 탭 텍스트 색상 (primary-400, 노란색)
- `--color-tabs-focus-ring`: 포커스 링 색상 (white)
diff --git a/ui-docs-site/tokens/color.md b/ui-docs-site/tokens/color.md
index ec69a83..06d3f62 100644
--- a/ui-docs-site/tokens/color.md
+++ b/ui-docs-site/tokens/color.md
@@ -37,6 +37,28 @@ Opacity 변형(`-opacity`)도 제공합니다 (`rgba` 0.7):
| `--color-white` | `rgb(255, 255, 255)` |
| `--color-black` | `rgb(0, 0, 0)` |
+### Green
+
+| 토큰 | 값 |
+|------|-----|
+| `--color-green-50` | `rgb(240, 253, 244)` |
+| `--color-green-100` | `rgb(220, 252, 231)` |
+| `--color-green-200` | `rgb(187, 247, 208)` |
+| `--color-green-300` | `rgb(134, 239, 172)` |
+| `--color-green-400` | `rgb(74, 222, 128)` |
+
+### Red
+
+| 토큰 | 값 |
+|------|-----|
+| `--color-red-50` | `rgb(254, 242, 242)` |
+| `--color-red-100` | `rgb(254, 226, 226)` |
+| `--color-red-200` | `rgb(254, 202, 202)` |
+| `--color-red-300` | `rgb(252, 165, 165)` |
+| `--color-red-400` | `rgb(248, 113, 113)` |
+
+> 원시 층 명명 규칙: 브랜드색은 역할명(primary/secondary), 기능색은 색상명(green/red)을 사용합니다. 색에 의미(success 등)를 부여하는 것은 Semantic 층의 몫입니다. 같은 빨강이 문맥에 따라 에러(나쁨)일 수도, 주가 상승(좋음, 한국 증시 관례)일 수도 있기 때문입니다.
+
---
## Semantic Colors
@@ -73,6 +95,26 @@ Opacity 변형(`-opacity`)도 제공합니다 (`rgba` 0.7):
| `text-primary-300` | 진한 골드 텍스트 |
| `text-primary-400` | 강조 골드 텍스트 |
+### System
+
+시스템 상태 전달용 시맨틱 토큰입니다.
+
+| 토큰 | 참조 | 용도 |
+|------|------|------|
+| `--color-success` | green-400 | 성공 상태 |
+| `--color-error` | red-400 | 에러 상태 (Field 에러 메시지 등) |
+
+### Finance
+
+수입/지출 등 금액 증감 표현용 시맨틱 토큰입니다. 금융 도메인 화면에서는 이 이름을 사용합니다.
+
+| 토큰 | 참조 | 용도 |
+|------|------|------|
+| `--color-income` | green-400 | 수입 금액 표시 |
+| `--color-expense` | red-400 | 지출 금액 표시 |
+
+> 색상만으로 수입/지출을 구분하지 말고 `+`/`-` 부호를 병행하는 것을 권장합니다. (WCAG 1.4.1)
+
### Border
| Tailwind 클래스 | 설명 |
@@ -82,6 +124,16 @@ Opacity 변형(`-opacity`)도 제공합니다 (`rgba` 0.7):
> 모든 border 클래스는 `border-width: 2px`, `border-radius: 8px`가 기본 적용됩니다.
+시맨틱 테두리 토큰:
+
+| 토큰 | 참조 | 용도 |
+|------|------|------|
+| `--color-border-primary-light` | primary-100 | Input·Calendar 트리거 등 밝은 강조 테두리 |
+| `--color-border-primary-deep` | primary-400 | Button outlined 등 진한 강조 테두리 |
+| `--color-border-secondary-light` | secondary-50 | Card outlined 등 면 구분 테두리 |
+| `--color-border-secondary-deep` | secondary-400 | 어두운 면 구분 테두리 |
+| `--color-border-divider` | secondary-100 | Table 행 구분선 · Tabs 컨테이너 테두리 |
+
### Z-index
| Tailwind 클래스 | 값 | 용도 |
diff --git a/ui-docs-site/tokens/spacing.md b/ui-docs-site/tokens/spacing.md
index 9a24771..ca70fcf 100644
--- a/ui-docs-site/tokens/spacing.md
+++ b/ui-docs-site/tokens/spacing.md
@@ -2,6 +2,36 @@
YD-Design System의 간격 및 테두리 토큰입니다.
+## Spacing Scale
+
+4px 단위 원시 간격 스케일입니다. 컴포넌트 사이 간격은 임의의 값 대신 이 스케일에서 선택합니다.
+
+| 토큰 | 값 |
+|------|-----|
+| `--spacing-1` | `4px` |
+| `--spacing-2` | `8px` |
+| `--spacing-3` | `12px` |
+| `--spacing-4` | `16px` |
+| `--spacing-5` | `20px` |
+| `--spacing-6` | `24px` |
+| `--spacing-8` | `32px` |
+| `--spacing-10` | `40px` |
+| `--spacing-12` | `48px` |
+
+## Layout Semantic 토큰
+
+Stack / Inline / Field 컴포넌트가 소비하는 용도별 간격 토큰입니다.
+
+| 토큰 | 참조 | 용도 |
+|------|------|------|
+| `--stack-gap-sm` | spacing-2 (8px) | Stack `gap="sm"` — 밀접한 요소 사이 |
+| `--stack-gap-md` | spacing-4 (16px) | Stack `gap="md"` — 기본 수직 간격 |
+| `--stack-gap-lg` | spacing-6 (24px) | Stack `gap="lg"` — 폼 필드·섹션 사이 |
+| `--inline-gap-sm` | spacing-1 (4px) | Inline `gap="sm"` — 아이콘+텍스트 |
+| `--inline-gap-md` | spacing-2 (8px) | Inline `gap="md"` — 기본 수평 간격 |
+| `--inline-gap-lg` | spacing-4 (16px) | Inline `gap="lg"` — 버튼 그룹·필터 바 |
+| `--field-gap` | spacing-2 (8px) | Field 라벨·입력·메시지 사이 |
+
## 기본 토큰
| 토큰 | 값 | 설명 |
@@ -10,6 +40,8 @@ YD-Design System의 간격 및 테두리 토큰입니다.
| `--yds-border-radius` | `8px` | 기본 모서리 반경 |
| `--yds-content-padding` | `16px` | 기본 콘텐츠 패딩 |
+시맨틱 테두리 색상 토큰(`--color-border-divider` 등)은 [Color 토큰](/tokens/color#border) 페이지를 참고하세요.
+
## 컴포넌트별 Spacing 토큰
### Button