sellmate-design-system-react 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/AGENTS.md +695 -0
  2. package/README.md +106 -0
  3. package/bin/sellmate-ds.mjs +337 -0
  4. package/dist/components/SActionModal/README.md +41 -0
  5. package/dist/components/SBadge/README.md +25 -0
  6. package/dist/components/SBarcodeInput/README.md +64 -0
  7. package/dist/components/SButton/README.md +49 -0
  8. package/dist/components/SCalendar/README.md +42 -0
  9. package/dist/components/SCallout/README.md +29 -0
  10. package/dist/components/SCard/README.md +12 -0
  11. package/dist/components/SCheckbox/README.md +44 -0
  12. package/dist/components/SChip/README.md +57 -0
  13. package/dist/components/SChipInput/README.md +77 -0
  14. package/dist/components/SCircleProgress/README.md +35 -0
  15. package/dist/components/SConfirmModal/README.md +61 -0
  16. package/dist/components/SDatePicker/README.md +62 -0
  17. package/dist/components/SDateRangePicker/README.md +64 -0
  18. package/dist/components/SDivider/README.md +25 -0
  19. package/dist/components/SDraggableItem/README.md +40 -0
  20. package/dist/components/SDropdownButton/README.md +50 -0
  21. package/dist/components/SExpansionItem/README.md +40 -0
  22. package/dist/components/SField/README.md +91 -0
  23. package/dist/components/SFilePicker/README.md +72 -0
  24. package/dist/components/SForm/README.md +31 -0
  25. package/dist/components/SGhostButton/README.md +76 -0
  26. package/dist/components/SGnb/README.md +56 -0
  27. package/dist/components/SGuide/README.md +34 -0
  28. package/dist/components/SIcon/README.md +91 -0
  29. package/dist/components/SInput/README.md +66 -0
  30. package/dist/components/SKeyValueTable/README.md +59 -0
  31. package/dist/components/SLayout/README.md +42 -0
  32. package/dist/components/SLinearProgress/README.md +17 -0
  33. package/dist/components/SList/README.md +14 -0
  34. package/dist/components/SListItem/README.md +19 -0
  35. package/dist/components/SLoadingContainer/README.md +29 -0
  36. package/dist/components/SLoadingModal/README.md +52 -0
  37. package/dist/components/SModal/README.md +192 -0
  38. package/dist/components/SModalContainer/README.md +49 -0
  39. package/dist/components/SNumberInput/README.md +74 -0
  40. package/dist/components/SPage/README.md +25 -0
  41. package/dist/components/SPagination/README.md +40 -0
  42. package/dist/components/SPopover/README.md +54 -0
  43. package/dist/components/SPopup/README.md +38 -0
  44. package/dist/components/SPortal/README.md +51 -0
  45. package/dist/components/SRadio/README.md +57 -0
  46. package/dist/components/SRadioButton/README.md +24 -0
  47. package/dist/components/SScrollArea/README.md +16 -0
  48. package/dist/components/SSectionHeaderCard/README.md +51 -0
  49. package/dist/components/SSelect/README.md +79 -0
  50. package/dist/components/SStepper/README.md +30 -0
  51. package/dist/components/SSwitch/README.md +24 -0
  52. package/dist/components/STable/README.md +82 -0
  53. package/dist/components/STableBar/README.md +28 -0
  54. package/dist/components/STabs/README.md +37 -0
  55. package/dist/components/STag/README.md +44 -0
  56. package/dist/components/STextLink/README.md +48 -0
  57. package/dist/components/STextarea/README.md +60 -0
  58. package/dist/components/STimePicker/README.md +65 -0
  59. package/dist/components/STimeRangePicker/README.md +63 -0
  60. package/dist/components/SToast/README.md +70 -0
  61. package/dist/components/SToggle/README.md +22 -0
  62. package/dist/components/STooltip/README.md +57 -0
  63. package/dist/llms-full.txt +3530 -0
  64. package/dist/llms.txt +882 -0
  65. package/dist/styles.css +221 -0
  66. package/dist/theme.css +8 -0
  67. package/eslint/index.mjs +69 -0
  68. package/eslint/lib/class-names.mjs +119 -0
  69. package/eslint/lib/table-column.mjs +53 -0
  70. package/eslint/rules/component-group-gap.mjs +186 -0
  71. package/eslint/rules/no-arbitrary-class.mjs +91 -0
  72. package/eslint/rules/no-off-scale-spacing.mjs +67 -0
  73. package/eslint/rules/no-raw-html-control.mjs +117 -0
  74. package/eslint/rules/prefer-typo-preset.mjs +73 -0
  75. package/eslint/rules/require-locale-number.mjs +78 -0
  76. package/eslint/rules/table-numeric-align.mjs +93 -0
  77. package/eslint/scale.gen.mjs +16 -0
  78. package/package.json +15 -4
@@ -0,0 +1,3530 @@
1
+ <!-- 자동 생성: npm run build (scripts/gen-llms.mjs). 직접 수정 금지. -->
2
+
3
+ # sellmate-design-system-react — AI 에이전트 참조 문서
4
+
5
+ 사용 규칙(§1) · 토큰 어휘(§2) · 전체 컴포넌트 Props(§3) 를 한 파일에 담은 판본이다.
6
+
7
+ ## 1. 사용 규칙 (AGENTS.md 전문)
8
+
9
+ # sellmate-design-system-react — 사용 규칙 (AGENTS.md)
10
+
11
+ > **대상**: 이 패키지로 화면을 만드는 소비 앱의 개발자와 AI 코딩 에이전트(Claude 등).
12
+ > 이 문서는 "무엇을 언제 쓰고, 무엇을 쓰면 안 되는지"의 단일 기준이다.
13
+ > 개별 컴포넌트의 상세 Props/Events는 `node_modules/sellmate-design-system-react/dist/components/<이름>/README.md` 를 참조한다.
14
+
15
+ ## 0. 최우선 원칙 — 디자인 시스템 컴포넌트가 먼저다
16
+
17
+ **화면 요소를 만들기 전에, 그 역할을 하는 컴포넌트가 이미 있는지 먼저 확인한다.**
18
+ 있으면 반드시 그것을 쓴다. 직접 만드는 것은 대응 컴포넌트가 **없다는 것을 확인한 뒤**의 최후 수단이다.
19
+
20
+ ```tsx
21
+ ❌ <button onClick={save}>저장</button> ✅ <SButton label="저장" onClick={save} />
22
+ ❌ <table>…</table> ✅ <STable columns={columns} rows={rows} />
23
+ ❌ <div className="rounded border p-16">…</div> ✅ <SSectionHeaderCard>…</SSectionHeaderCard>
24
+ ❌ <ul><li>…</li></ul> ✅ <SList><SListItem title="…" /></SList>
25
+ ```
26
+
27
+ "비슷하게 생긴 것을 직접 만드는 것"이 어색함의 가장 큰 원인이다. 대응 컴포넌트를 쓰면 색·간격·상태·접근성이 전부 따라온다.
28
+
29
+ ### 0-1. 전체 컴포넌트 인덱스
30
+
31
+ 무엇을 만들지 정했으면 **이 표에서 먼저 찾는다.** 상세 Props 는 `dist/components/<이름>/README.md` 참조.
32
+
33
+ | 분류 | 컴포넌트 |
34
+ | --- | --- |
35
+ | **버튼·링크** | `SButton` `SGhostButton` `SDropdownButton` `STextLink` `SSwitch` `SToggle` |
36
+ | **입력 (폼)** | `SForm` `SField` `SInput` `SNumberInput` `STextarea` `SSelect` `SCheckbox` `SRadio` `SRadioButton` `SChip` `SChipInput` `SBarcodeInput` `SFilePicker` |
37
+ | **날짜·시간** | `SCalendar` `SDatePicker` `SDateRangePicker` `STimePicker` `STimeRangePicker` |
38
+ | **표·목록** | `STable` `STableBar` `SKeyValueTable` `SList` `SListItem` `SDraggableItem` |
39
+ | **레이아웃** | `SLayout` `SGnb` `SPage` `SSectionHeaderCard` `SCard` `SDivider` `SScrollArea` `SExpansionItem` |
40
+ | **내비게이션** | `STabs` `SPagination` `SStepper` |
41
+ | **표시·상태** | `STag` `SBadge` `SIcon` `SCallout` `SGuide` |
42
+ | **진행·로딩** | `SLinearProgress` `SCircleProgress` `SLoadingContainer` `SLoadingModal` |
43
+ | **오버레이** | `STooltip` `SPopover` `SPopup` `SPortal` |
44
+ | **모달** | `SModal.confirm()` `SModal.create()` + `SActionModal` `SConfirmModal` |
45
+ | **알림** | `SToast` `SToastContainer` |
46
+
47
+ 표에 없는 UI 를 만들어야 할 때만 `div` 로 직접 조립하고, 그때도 §1-2 · §2 의 토큰 규칙을 지킨다.
48
+
49
+ ### 0-2. 프로젝트 설정
50
+
51
+ 설정(Tailwind v4 `theme.css` import, `@source` 지정, Next.js 주의사항)은 패키지 [README.md](./README.md)를 따른다. 이 문서는 설정이 끝난 상태에서의 **화면 작성 규칙**만 다룬다.
52
+
53
+ ---
54
+
55
+ ## 1. 절대 규칙 (금지 목록)
56
+
57
+ AI 에이전트는 코드를 생성하기 전에 이 목록을 반드시 지킨다.
58
+
59
+ ### 1-1. 생 HTML 컨트롤 금지
60
+
61
+ §0 원칙의 구체적 목록이다. 아래 요소는 **어떤 경우에도** 생 HTML 로 만들지 않는다.
62
+
63
+ | 금지 | 대신 사용 |
64
+ | --- | --- |
65
+ | `<button>` | `SButton`, `SGhostButton`, `SDropdownButton`, `STextLink` |
66
+ | `<input type="text/password/...">` | `SInput` |
67
+ | `<input type="number">` | `SNumberInput` |
68
+ | `<input type="checkbox">` | `SCheckbox`, `SToggle`, `SSwitch` |
69
+ | `<input type="radio">` | `SRadio`, `SRadioButton` |
70
+ | `<input type="file">` | `SFilePicker` |
71
+ | `<select>` | `SSelect` |
72
+ | `<textarea>` | `STextarea` |
73
+ | `<table>` | `STable`, `SKeyValueTable` |
74
+ | `<form>` | `SForm` |
75
+ | `<dialog>`, 직접 만든 오버레이 | `SModal.confirm(...)`, `SModal.create(...)`, `SPopup` |
76
+ | `alert()`, `confirm()` | `SToast`, `SModal.confirm(...)` |
77
+ | 직접 만든 탭/페이지네이션/스텝퍼 | `STabs`, `SPagination`, `SStepper` |
78
+ | `<ul>`/`<li>` 로 만든 목록 UI | `SList` + `SListItem` (드래그 정렬은 `SDraggableItem`) |
79
+ | 직접 만든 섹션 카드(제목 바 + 본문 박스) | `SSectionHeaderCard` + `.Header` / `.Body` |
80
+ | `<svg>` 직접 삽입, 이모지 아이콘 | `SIcon` |
81
+ | `<hr>` | `SDivider` |
82
+ | `<details>` / `<summary>` | `SExpansionItem` |
83
+ | `<progress>` | `SLinearProgress`, `SCircleProgress` |
84
+ | `<label>` (폼 레이블) | `SField` 의 `label` prop |
85
+ | 직접 만든 카드·패널 박스 | `SCard`, `SSectionHeaderCard` |
86
+ | 직접 만든 스크롤 영역 | `SScrollArea` |
87
+
88
+ 예외: 순수 레이아웃 요소(`div`, `section`, 시맨틱 `h1~h6`, `p`, `span`, `a`)는 허용. 단 스타일은 아래 규칙을 따른다.
89
+
90
+ ### 1-2. 임의 값(arbitrary literal) 금지
91
+
92
+ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
93
+
94
+ ```text
95
+ ❌ text-[14px] font-[600] bg-[#eee] gap-[13px] p-[10px] rounded-[5px] text-[#333]
96
+ ✅ typo-body-sm-default text-fg-tertiary bg-bg-frame gap-12 p-8 rounded-md
97
+ ✅ w-[var(--sys-size-control-md-height)] ← 토큰을 var()로 참조하는 것은 허용
98
+ ```
99
+
100
+ - 하드코딩 hex/px/rem 리터럴은 어디에도 쓰지 않는다 (인라인 `style` 포함).
101
+ - 인라인 `style`은 런타임 계산값(동적 width 등)에만 허용한다.
102
+
103
+ **단, 디자인 토큰이 없는 속성의 임의 값은 정당하다.** 화면 고유의 레이아웃 치수가 여기 해당한다.
104
+
105
+ ```tsx
106
+ ✅ <div className="w-[280px] max-w-[1200px] grid-cols-[200px_1fr]" /> // 앱 고유 치수
107
+ ❌ <div className="text-[13px] bg-[#eee] gap-[13px] rounded-[5px]" /> // 토큰이 있는 속성
108
+ ```
109
+
110
+ 규칙은 **색 · 타이포 · 간격 · 모서리** 네 계열에만 적용된다 — 이 넷은 토큰이 이미 있으므로 임의 값은 곧 디자인 시스템 우회다.
111
+
112
+ ### 1-3. 타이포그래피는 프리셋으로만
113
+
114
+ `text-14 font-bold` 같은 조합을 즉흥으로 만들지 않는다. §2-1의 `typo-*` 프리셋 클래스를 쓴다.
115
+
116
+ ### 1-4. 숫자는 무조건 `toLocaleString()`
117
+
118
+ **숫자를 화면에 표시할 때는 예외 없이 `toLocaleString()` 을 거쳐 세 자리마다 콤마를 넣는다.**
119
+ 금액·수량·건수·재고 무엇이든, 테이블·상세·요약 문구 어디에 놓이든 같다.
120
+
121
+ ```tsx
122
+ ❌ <span>{price}원</span> ❌ {`${qty}개`} ❌ {String(count)}
123
+ ✅ <span>{price.toLocaleString()}원</span>
124
+ ✅ format: (v: number) => `${Number(v).toLocaleString()}개`
125
+ ```
126
+
127
+ 콤마 없는 `39000` 은 자릿수를 세어야 읽히지만 `39,000` 은 한눈에 읽힌다. 숫자를 그대로 출력하는 코드는 미완성으로 본다.
128
+
129
+ 전화번호·사업자번호처럼 하이픈이 들어가는 값은 애초에 숫자가 아니라 **서식이 정해진 문자열**이므로 이 규칙의 대상이 아니다.
130
+
131
+ ---
132
+
133
+ ## 2. 조합 어휘 — 컴포넌트 "사이"를 채울 때 쓰는 것들
134
+
135
+ ### 2-1. 타이포그래피 프리셋
136
+
137
+ 역할(role) → 크기 → 굵기 순으로 조합된 클래스가 이미 준비되어 있다.
138
+
139
+ | 용도 | 클래스 |
140
+ | --- | --- |
141
+ | 페이지/섹션 제목 | `typo-heading-lg`(18px) · `typo-heading-md`(16px) · `typo-heading-sm`(14px) · `typo-heading-xs`(12px) |
142
+ | 본문 | `typo-body-lg-*` (16px) · `typo-body-md-*`(14px) · `typo-body-sm-*`(12px) · `typo-body-xs-default`(11px) — `*` = `default`/`medium`/`bold` |
143
+ | 테이블 | `typo-table-header` · `typo-table-body` · `typo-table-accent` |
144
+ | 컨트롤·필드·피드백·내비 | `typo-control-*` `typo-field-*` `typo-feedback-*` `typo-navigation-*` (컴포넌트 내부용 — 직접 쓸 일은 드묾) |
145
+
146
+ **기본 선택 — 이 조합을 쓴다.** 이 서비스는 정보 밀도가 높아 본문이 12px 이다. 14px 를 본문 기본으로 쓰지 않는다.
147
+
148
+ | 역할 | 클래스 | 크기 |
149
+ | --- | --- | --- |
150
+ | 페이지 헤더 제목 (h1) | `typo-heading-lg` | 18px |
151
+ | 섹션 제목 | `typo-heading-sm` | 14px |
152
+ | 본문 | `typo-body-sm-default` | 12px |
153
+ | 보조 설명 | `typo-body-sm-default` + `text-fg-tertiary` | 12px / `grey_65` |
154
+
155
+ 페이지 제목만 18px 로 크게 두고 그 아래는 14 / 12 로 촘촘하게 간다. 중간 크기(16px)는 기본 골격에서 쓰지 않는다.
156
+
157
+ ### 2-2. 간격 (spacing)
158
+
159
+ - 유틸리티 숫자 = px. 스케일: `2 4 6 8 10 12 16 19 20 22 24 28 32 36 40 48 60`
160
+ - 형제 요소 간격은 margin 대신 부모의 `flex`/`grid` + `gap-*`으로 잡는다.
161
+ - 시맨틱 간격 토큰 (텍스트 덩어리·요소 사이 기본 리듬):
162
+
163
+ | 상황 | 값 |
164
+ | --- | --- |
165
+ | **페이지 콘텐츠 패딩** | **`p-20`** |
166
+ | **섹션 ↔ 섹션** | **`gap-12`** |
167
+ | **페이지 내 블록 ↔ 블록** (헤더·필터·툴바·테이블 사이) | **`gap-12`** |
168
+ | 요소 ↔ 요소 (기본) | `gap-8` (`--sys-space-stack-gap-element-normal`) |
169
+ | 제목 ↔ 설명 텍스트 | `gap-4` (`--sys-space-stack-gap-text-normal`) |
170
+
171
+ 정보 밀도가 높은 서비스라 블록 간격을 넓게 벌리지 않는다. `gap-16` / `gap-24` 를 페이지 골격의 기본값으로 쓰지 않는다.
172
+
173
+ #### 같은 컴포넌트를 여러 개 늘어놓을 때 (그룹 간격)
174
+
175
+ 위 "요소 ↔ 요소 `gap-8`" 은 **서로 다른 요소** 사이의 기본값이다.
176
+ **같은 컴포넌트를 여러 개 나열할 때는 컴포넌트마다 정해진 그룹 간격**이 따로 있다.
177
+
178
+ | 컴포넌트 | 수평 배열 | 수직 배열 |
179
+ | --- | --- | --- |
180
+ | `SCheckbox` | **`gap-24`** | `gap-8` |
181
+ | `SRadio` | **`gap-24`** | `gap-8` |
182
+ | `STextLink` | **`gap-16`**(sm) / **`gap-24`**(md·lg) | `gap-4` |
183
+ | `SGhostButton` | `gap-4` | `gap-4` |
184
+ | `SButton` | `gap-8` (xs·sm·md) / **`gap-12`**(lg) | 〃 |
185
+ | `STag` | `gap-8` | `gap-8` |
186
+ | `SToggle` | `gap-8` | `gap-8` |
187
+ | `SListItem` (bordered) | — | `gap-8` (+ 컨테이너 `p-16`) |
188
+
189
+ **수평·수직이 다른 것에 주의한다** — 체크박스·라디오는 가로로 놓으면 `gap-24`, 세로로 놓으면 `gap-8` 로 3배 차이다. 가로 배열에 `gap-8` 을 쓰면 항목이 붙어 보인다.
190
+
191
+ ```tsx
192
+ ✅ <div className="flex gap-24"> {/* 체크박스 가로 */}
193
+ <SCheckbox label="전체" … /><SCheckbox label="판매중" … />
194
+ </div>
195
+ ✅ <div className="flex flex-col gap-8"> {/* 체크박스 세로 */}
196
+ <SCheckbox label="전체" … /><SCheckbox label="판매중" … />
197
+ </div>
198
+ ❌ <div className="flex gap-8"> {/* 가로인데 8 — 붙어 보인다 */}
199
+ ```
200
+
201
+ - **라디오는 `SRadioGroup` 을 쓴다.** `direction="horizontal" | "vertical"` 만 주면 간격을 알아서 맞춘다 — 직접 `flex` 로 감싸지 않는다.
202
+ - `SRadioButton` 그룹의 간격은 `-1px`(테두리 겹침 처리)이라 손으로 만들지 않는다.
203
+ - 정확한 값이 필요하면 토큰을 직접 참조해도 된다: `gap-[var(--cmp-checkbox-group-gap-horizontal)]`
204
+
205
+ ### 2-3. 색상
206
+
207
+ **시맨틱 유틸리티를 우선 사용한다** — 의미가 이름에 담긴 토큰이 이미 유틸리티로 존재한다.
208
+
209
+ #### 텍스트 색은 두 단계뿐이다
210
+
211
+ | 용도 | 유틸리티 | 값 |
212
+ | --- | --- | --- |
213
+ | **본문·제목 (기본값)** | 지정하지 않는다 — 전역 기본색이 이미 적용된다 | `grey_95` `#222222` |
214
+ | **보조 설명 · 비활성** | **`text-fg-tertiary`** | `grey_65` `#888888` |
215
+
216
+ - `theme.css` 가 `body` 에 `grey_95` 를 깔아두므로 **본문에 텍스트 색 클래스를 붙이지 않는다.** `text-fg-primary` 를 매번 쓰는 것은 불필요하다.
217
+ - 흐리게 보여야 하는 것은 보조 설명이든 비활성이든 **전부 `text-fg-tertiary`** 다.
218
+ - 중간 톤(`text-fg-secondary` `#555`)은 텍스트 위계에 쓰지 않는다. 두 단계로만 간다.
219
+
220
+ ```tsx
221
+ ✅ <p>주문이 접수되었습니다.</p> // 색 지정 없음 = grey_95
222
+ ✅ <p className="text-fg-tertiary">최근 30일 기준</p> // 보조 설명
223
+ ✅ <span className="text-fg-tertiary">-</span> // 빈 값 (§3-4)
224
+ ❌ <p className="text-fg-primary">주문이 접수되었습니다.</p> // 불필요
225
+ ❌ <p className="text-fg-secondary">최근 30일 기준</p> // 중간 톤 사용
226
+ ```
227
+
228
+ #### 그 밖의 색
229
+
230
+ | 용도 | 유틸리티 |
231
+ | --- | --- |
232
+ | 상태 텍스트 | `text-fg-danger` `text-fg-success` `text-fg-warning` `text-fg-accent` `text-fg-inverse` |
233
+ | 배경 | `bg-bg-frame`(흰 콘텐츠 면) · `bg-bg-neutralLight`/`bg-bg-neutralBright`(옅은 회색 면) · `bg-bg-screen`(앱 바탕) |
234
+ | 보더/구분선 | `border-border-default` · `border-border-strong` · `border-divider-default` |
235
+ | 비활성 배경·보더 | `bg-disabled-bg` `border-disabled-border` |
236
+ | 링크 | `text-link-accent` |
237
+
238
+ - 시맨틱 토큰에 맞는 항목이 없을 때만 원색 스케일(`bg-blue-subtle` 등)을 쓴다.
239
+ - 어느 쪽이든 **토큰 유틸리티만** 사용 — 리터럴 hex 금지.
240
+
241
+ ---
242
+
243
+ ## 3. 컴포넌트 선택 규칙 — "언제 뭘 쓰나"
244
+
245
+ > ⚠️ 초안(개발 작성). <!-- TODO(디자인): 전체 검수·확정 --> 표시가 있는 행은 디자인 확정 전까지 초안 기준으로 사용.
246
+
247
+ ### 3-1. 라벨/표시류 — STag vs SBadge vs SChip
248
+
249
+ | 상황 | 사용 |
250
+ | --- | --- |
251
+ | **상태·분류를 라벨로 표시 (기본값)** | **`STag`** — `<STag size="sm" color="..." label="판매중" />`. 목록의 상태 컬럼, 상세의 분류 태그 등 대부분이 여기 해당한다 |
252
+ | 라벨 없이 **색 점만**으로 상태를 찍을 때 | `SBadge` — 점(dot)만 그리는 인디케이터. 텍스트가 이미 있고 앞에 점만 붙이는 좁은 경우에만 |
253
+ | 사용자가 입력·삭제·편집하는 **토큰** | `SChip` (단독) / `SChipInput` (입력 필드 안에서) |
254
+
255
+ > 상태 표시는 **`STag size="sm"` 이 기본**이다. 색 점 + 텍스트 조합(`SBadge`)을 기본으로 쓰지 않는다.
256
+
257
+ ### 3-2. 알림/안내류
258
+
259
+ | 상황 | 사용 |
260
+ | --- | --- |
261
+ | 화면에 **상시 노출**되는 안내·경고 문구 | `SCallout` — `type` + `message` 배열(중첩 = 들여쓰기) |
262
+ | 작업 결과를 **일시적으로** 알림 | `SToast` (+ 루트에 `SToastContainer`) |
263
+ | 진행 전 **확인/취소**를 받아야 할 때 | `SModal.confirm({...}).onOk(...)` |
264
+ | 특정 UI 요소에 대한 **온보딩·기능 안내** | `SGuide` |
265
+ | 로딩 중 화면 잠금 | `SLoadingModal` / 영역 로딩은 `SLoadingContainer` |
266
+
267
+ ### 3-3. 플로팅/오버레이류
268
+
269
+ | 상황 | 사용 |
270
+ | --- | --- |
271
+ | hover 시 **짧은 보조 설명** (상호작용 없음) | `STooltip` |
272
+ | 클릭 시 **상호작용 가능한** 콘텐츠 (메뉴·미니 폼) | `SPopover` |
273
+ | **팝업** (별도 창 성격의 가벼운 표시) | `SPopup` |
274
+ | 페이지 흐름을 끊고 **작업을 완료**시키는 창 | **`SActionModal` 로 컴포넌트를 만들고 `SModal.create` 로 띄운다** (아래 참조) |
275
+ | 확인/취소만 받는 창 | `SModal.confirm(...)` |
276
+ | 로딩 중 화면 잠금 | `SModal.loading(...)` / `SLoadingModal` |
277
+
278
+ **모달 만드는 법** — 디자인 시스템이 띄우는 모달은 `SActionModal` · `SConfirmModal` · `SLoadingModal` 3종뿐이고 `create` · `confirm` · `loading` 이 1:1로 대응한다.
279
+ 직접 오버레이를 만들지 않는다. 작업용 모달은 **`SActionModal` 을 루트로 하는 컴포넌트를 만들어 `SModal.create` 에 넘긴다.**
280
+
281
+ ```tsx
282
+ // 1) SActionModal 을 루트로 하는 컴포넌트를 만든다
283
+ // create 가 주입하는 open / onOpenChange / onClose 를 그대로 SActionModal 에 전달해야 한다
284
+ function OrderModal({ orderId, open, onOpenChange, onClose, modalRef }: OrderModalProps) {
285
+ return (
286
+ <SActionModal
287
+ open={open}
288
+ onOpenChange={onOpenChange}
289
+ onClose={onClose}
290
+ modalTitle="주문 상세"
291
+ width={720}
292
+ // 주 액션은 button(단수), 보조 버튼은 footerLeft — 하단 버튼 양끝 분리 규칙과 같다
293
+ button={{ label: '접수', onClick: () => modalRef.ok() }}
294
+ footerLeft={<SButton color="secondary" label="취소" onClick={() => modalRef.cancel()} />}
295
+ >
296
+ <SKeyValueTable fields={orderFields} values={order} />
297
+ </SActionModal>
298
+ );
299
+ }
300
+
301
+ // 2) SModal.create 로 띄운다
302
+ SModal.create({ component: OrderModal, componentProps: { orderId } })
303
+ .onOk(() => refetch())
304
+ .onDismissed(() => {});
305
+ ```
306
+
307
+ ### 3-4. 테이블 컬럼 정렬
308
+
309
+ **숫자가 들어가는 컬럼은 예외 없이 오른쪽 정렬한다** (`align: 'right'`).
310
+ 자릿수가 세로로 맞아야 값의 크기를 눈으로 비교할 수 있기 때문이다.
311
+
312
+ | 컬럼 내용 | 정렬 | 예 |
313
+ | --- | --- | --- |
314
+ | **금액·수량·개수·비율 등 단위가 붙은 숫자** | **`'right'`** | `39,000원` · `12개` · `3건` · `15%` |
315
+ | **숫자만 있는 값** | **`'right'`** | `1024` · `39000` |
316
+ | 텍스트 | 생략(기본 `left`) | 상품명, 카테고리 |
317
+ | 상태 태그·아이콘·체크박스 등 고정폭 요소 | `'center'` | `STag`, `SIcon` |
318
+
319
+ ```tsx
320
+ const columns: STableColumn[] = [
321
+ { name: 'id', label: 'ID', field: 'id', width: '80px', align: 'right' },
322
+ { name: 'name', label: '상품명', field: 'name' }, // 텍스트 → 생략
323
+ { name: 'qty', label: '수량', field: 'qty', width: '80px', align: 'right',
324
+ format: (v: number) => `${Number(v).toLocaleString()}개` },
325
+ { name: 'price', label: '판매가', field: 'price', width: '120px', align: 'right',
326
+ format: (v: number) => `${Number(v).toLocaleString()}원` },
327
+ { name: 'status', label: '상태', field: 'status', width: '100px', align: 'center',
328
+ render: () => <STag size="sm" color="green" label="판매중" /> },
329
+ ];
330
+ ```
331
+
332
+ - `format` 으로 단위를 붙이더라도 **숫자 기반이면 오른쪽 정렬**이다. 단위 때문에 문자열이 되는 것은 정렬 판단과 무관하다.
333
+ - 숫자는 §1-4 대로 **`toLocaleString()` 이 필수**다. 세 자리 콤마 없이 출력하지 않는다.
334
+ - `SKeyValueTable` 의 값 셀도 같은 기준을 따른다.
335
+
336
+ #### 값이 없는 셀은 회색 하이픈
337
+
338
+ 셀을 **빈칸으로 두지 않는다.** 값이 `null` · `undefined` · 빈 문자열이면 `-` 를 `text-fg-tertiary`(`grey_65`)로 표시한다.
339
+ 빈칸은 "데이터가 없음"인지 "렌더가 깨졌는지" 구분되지 않지만, 회색 하이픈은 없다는 사실을 명시한다.
340
+
341
+ ```tsx
342
+ // 재사용 헬퍼를 하나 두고 모든 컬럼에서 쓴다
343
+ const emptyCell = <span className="text-fg-tertiary">-</span>;
344
+ const hasValue = (v: unknown) => v !== null && v !== undefined && v !== '';
345
+
346
+ const columns: STableColumn[] = [
347
+ { name: 'memo', label: '메모', field: 'memo',
348
+ render: (row: SRow) => (hasValue(row.memo) ? row.memo : emptyCell) },
349
+ { name: 'price', label: '판매가', field: 'price', width: '120px', align: 'right',
350
+ render: (row: SRow) =>
351
+ hasValue(row.price) ? `${Number(row.price).toLocaleString()}원` : emptyCell },
352
+ ];
353
+ ```
354
+
355
+ `0` 은 값이 있는 것이므로 하이픈으로 바꾸지 않는다 — `0원` 그대로 표시한다.
356
+
357
+ ### 3-5. 버튼류
358
+
359
+ | 상황 | 사용 |
360
+ | --- | --- |
361
+ | 일반 액션 | `SButton` (`color`: `primary` / `secondary` / `neutral` / `danger`, `size`: xs~lg) |
362
+ | **삭제 등 파괴적 액션** | **`SButton color="danger"`** 또는 **`color="danger" outline`** |
363
+ | 텍스트만 있는 저강조 액션 | `SGhostButton` |
364
+ | 본문 속 이동 링크 | `STextLink` |
365
+ | 메인 액션 + 부가 메뉴 | `SDropdownButton` |
366
+
367
+ 한 화면의 primary 버튼 개수에 대한 제약은 없다. 다만 **삭제·초기화 등 되돌릴 수 없는 액션은 반드시 `danger`** 로 표시한다.
368
+
369
+ **하단 버튼 배치 (모든 화면 공통)** — 그룹을 모아 정렬하지 않고 **양끝으로 벌린다**(`justify-between`).
370
+
371
+ - **왼쪽 끝**: 취소·닫기·목록 등 되돌리는 액션
372
+ - **오른쪽 끝**: 저장·등록·수정·삭제 등 실행 액션
373
+ - 체크박스·안내 문구 등 **부가 요소는 오른쪽 그룹 안, 실행 버튼 바로 왼쪽**에 둔다
374
+
375
+ ```tsx
376
+ <div className="flex items-center justify-between">
377
+ <SButton color="secondary" label="취소" />
378
+ <div className="flex items-center gap-8">
379
+ <SCheckbox label="계속 등록하기" value={keep} onValueChange={setKeep} /> {/* 부가 요소 */}
380
+ <SButton label="저장" />
381
+ </div>
382
+ </div>
383
+ ```
384
+
385
+ ---
386
+
387
+ ## 4. 페이지 레시피 — 표준 골격
388
+
389
+ > 새 페이지는 반드시 아래 골격에서 시작한다. 임의 골격을 발명하지 않는다.
390
+ >
391
+ > **핵심 원칙 — 표 형태의 정보는 `SKeyValueTable` 로 만든다.** 필터·등록/수정 폼·상세 정보가 모두 여기 해당한다.
392
+ > `SField` 컨트롤을 `div` 로 직접 나열해 폼을 만들지 않는다.
393
+
394
+ ### 4-1. 앱 셸 (모든 페이지 공통)
395
+
396
+ ```tsx
397
+ import { SLayout, SGnb, SPage, type SGnbMenuItem } from 'sellmate-design-system-react';
398
+
399
+ const MENU: SGnbMenuItem[] = [
400
+ { label: '주문', value: 'orders', icon: 'bill' },
401
+ { label: '상품', value: 'products', icon: 'box', children: [{ label: '목록', value: 'product-list' }] },
402
+ ];
403
+
404
+ export default function AppShell({ children }: { children: React.ReactNode }) {
405
+ return (
406
+ <SLayout type="box" header="fix">
407
+ {/* type/header/folded 는 SLayout 에만 준다 — SGnb 는 context 에서 읽는다 */}
408
+ <SGnb items={MENU} value={current} onValueChange={navigate} logo={<Logo />} />
409
+ <SPage background="frame" className="p-20">{children}</SPage>
410
+ </SLayout>
411
+ );
412
+ }
413
+ ```
414
+
415
+ ### 4-2. 목록 페이지 (필터 + 테이블)
416
+
417
+ 구조: **페이지 헤더(제목 + 가이드 링크) → 필터(`SKeyValueTable`) → `STableBar` → `STable`**
418
+
419
+ 액션 버튼의 위치가 핵심이다:
420
+
421
+ - **페이지 제목 줄에는 액션 버튼을 두지 않는다.** 가이드·매뉴얼 링크 등 부가 정보만 온다.
422
+ - **주요 액션(등록 등)은 `STableBar` 의 `rightActions`** 에 둔다.
423
+ - **선택 상태 액션(선택 삭제 등)은 `STableBar` 의 `actions`** 에 둔다. `actions` 슬롯은 건수 요약이 있으면 앞에 구분선(`SDivider`)을 **자동으로** 넣으므로 직접 구분선을 만들지 않는다.
424
+
425
+ ```tsx
426
+ import {
427
+ SButton, STextLink, SKeyValueTable, STableBar, STable, STag,
428
+ type STableColumn, type SRow, type SKeyValueField,
429
+ } from 'sellmate-design-system-react';
430
+
431
+ /** 필터도 표다 — SKeyValueTable 로 만든다 (서비스 전용 전역 필터가 따로 있는 경우 제외) */
432
+ const filterFields: SKeyValueField[][] = [
433
+ [
434
+ { name: 'status', label: '상태', type: 'select',
435
+ options: { options: STATUS_OPTIONS, emitValue: true } },
436
+ { name: 'keyword', label: '검색어', type: 'input',
437
+ options: { placeholder: '상품명 / 상품코드' } },
438
+ ],
439
+ [
440
+ { name: 'period', label: '등록일', type: 'date-range-picker', tdColSpan: 3 },
441
+ ],
442
+ ];
443
+
444
+ const columns: STableColumn[] = [
445
+ // 숫자 컬럼은 전부 align: 'right' — §3-4
446
+ { name: 'id', label: 'ID', field: 'id', width: '80px', align: 'right' },
447
+ { name: 'name', label: '상품명', field: 'name' },
448
+ { name: 'stock', label: '재고', field: 'stock', width: '90px', align: 'right',
449
+ format: (v: number) => `${Number(v).toLocaleString()}개` },
450
+ { name: 'price', label: '판매가', field: 'price', width: '120px', align: 'right',
451
+ format: (v: number) => `${Number(v).toLocaleString()}원` },
452
+ // 상태 컬럼은 STag size="sm" — SBadge 색 점을 기본으로 쓰지 않는다
453
+ { name: 'status', label: '상태', field: 'status', width: '100px', align: 'center',
454
+ render: (row: SRow) =>
455
+ row.status === 'selling'
456
+ ? <STag size="sm" color="green" label="판매중" />
457
+ : <STag size="sm" color="grey" label="판매중지" /> },
458
+ ];
459
+
460
+ export default function ProductListPage() {
461
+ const [filters, setFilters] = useState<Record<string, unknown>>({});
462
+ const [selected, setSelected] = useState<SRow[]>([]);
463
+
464
+ return (
465
+ <div className="flex flex-col gap-12">
466
+ {/* 페이지 헤더 — 액션 버튼 없음. 가이드/매뉴얼 링크 자리 */}
467
+ <div className="flex items-center justify-between">
468
+ <h1 className="typo-heading-lg m-0">상품 목록</h1>
469
+ <STextLink label="이용 가이드" rightArrow="chevron" onClick={openGuide} />
470
+ </div>
471
+
472
+ {/* 필터 — search 를 켜면 우측에 검색 패널이 붙는다 */}
473
+ <SKeyValueTable
474
+ fields={filterFields}
475
+ values={filters}
476
+ search
477
+ onChange={({ values }) => setFilters(values)}
478
+ onSearch={fetchList}
479
+ />
480
+
481
+ {/* 툴바 — 좌: 건수 + (구분선 자동) + 선택 액션 / 우: 주요 액션 */}
482
+ <STableBar
483
+ total={total}
484
+ selected={selected.length}
485
+ actions={
486
+ <SButton size="sm" color="secondary" label="선택 삭제"
487
+ disabled={!selected.length} onClick={removeSelected} />
488
+ }
489
+ rightActions={<SButton size="sm" label="상품 등록" onClick={goCreate} />}
490
+ />
491
+
492
+ <STable
493
+ columns={columns}
494
+ rows={rows}
495
+ rowKey="id"
496
+ selectable
497
+ selected={selected}
498
+ onSelectedChange={setSelected}
499
+ pagination={{ currentPage, lastPage }}
500
+ isLoading={isLoading}
501
+ />
502
+ </div>
503
+ );
504
+ }
505
+ ```
506
+
507
+ ### 4-3. 폼 페이지 (등록/수정)
508
+
509
+ 구조: **페이지 제목 → `SForm` + `SKeyValueTable` → 하단 버튼**
510
+
511
+ - 필드를 `div` 로 나열하지 않고 **`SKeyValueTable` 의 행으로 구성**한다.
512
+ - 검증 규칙은 각 field 의 `options.rules` 로 넘긴다. `SForm` 이 하위 컨트롤을 자동 수집해 submit 시 일괄 검증하고, 실패 시 첫 실패 필드로 포커스를 옮긴다.
513
+ - **버튼 순서: 취소·닫기가 왼쪽, 저장·등록·수정·삭제가 오른쪽.** 이 순서는 모든 화면에서 동일하다.
514
+
515
+ ```tsx
516
+ import {
517
+ SForm, SKeyValueTable, SButton, SCheckbox,
518
+ type SFormHandle, type SKeyValueField, type Rule,
519
+ } from 'sellmate-design-system-react';
520
+
521
+ const required = (msg: string): Rule => v =>
522
+ v != null && String(v).trim() !== '' ? true : msg;
523
+
524
+ const fields: SKeyValueField[][] = [
525
+ [
526
+ { name: 'name', label: '상품명', required: true, type: 'input',
527
+ options: { placeholder: '상품명 입력', rules: [required('상품명을 입력해 주세요.')] } },
528
+ { name: 'code', label: '상품코드', type: 'input', options: { placeholder: '자동 생성' } },
529
+ ],
530
+ [
531
+ { name: 'category', label: '카테고리', required: true, type: 'select',
532
+ options: { options: CATEGORY_OPTIONS, emitValue: true,
533
+ rules: [required('카테고리를 선택해 주세요.')] } },
534
+ { name: 'price', label: '판매가', type: 'number-input' },
535
+ ],
536
+ [
537
+ { name: 'memo', label: '메모', type: 'textarea', tdColSpan: 3,
538
+ helpText: ['내부 관리용 메모입니다.'] },
539
+ ],
540
+ ];
541
+
542
+ export default function ProductCreatePage() {
543
+ const formRef = useRef<SFormHandle>(null);
544
+ const [values, setValues] = useState<Record<string, unknown>>({});
545
+
546
+ return (
547
+ <div className="flex flex-col gap-12">
548
+ <h1 className="typo-heading-lg m-0">상품 등록</h1>
549
+
550
+ <SForm ref={formRef} formClass="flex flex-col gap-12" onSubmit={save}>
551
+ <SKeyValueTable
552
+ fields={fields}
553
+ values={values}
554
+ onChange={({ values }) => setValues(values)}
555
+ />
556
+
557
+ {/* 하단 버튼은 양끝으로 벌린다. 부가 요소(체크박스 등)는 저장 바로 왼쪽 */}
558
+ <div className="flex items-center justify-between">
559
+ <SButton type="button" color="secondary" label="취소" onClick={goBack} />
560
+ <div className="flex items-center gap-8">
561
+ <SCheckbox label="계속 등록하기" value={keepOpen} onValueChange={v => setKeepOpen(v as boolean)} />
562
+ <SButton type="submit" label="저장" />
563
+ </div>
564
+ </div>
565
+ </SForm>
566
+ </div>
567
+ );
568
+ }
569
+ ```
570
+
571
+ ### 4-4. 상세(조회) 페이지
572
+
573
+ 구조: **페이지 헤더(제목) → 섹션별 `SSectionHeaderCard` + `SKeyValueTable` → 하단 버튼**
574
+
575
+ - 조회 값은 `type: 'text'` 행으로 표시한다. **상태·분류 태그도 별도 영역이 아니라 표의 한 행**으로 넣는다 (`render` 에 `STag`).
576
+ - 행이 많아지면 **유형별로 섹션을 나누고, 각 섹션을 `SSectionHeaderCard` 로 감싼다.**
577
+ 합성 컴포넌트라 `SSectionHeaderCard.Header` / `SSectionHeaderCard.Body` 를 자식으로 쓴다.
578
+ - **수정·삭제 버튼은 하단에 둔다.** 내용이 짧아 우측 상단에 두는 변형도 있으나 기본은 하단이다.
579
+
580
+ ```tsx
581
+ import {
582
+ SSectionHeaderCard, SKeyValueTable, SButton, STag, type SKeyValueField,
583
+ } from 'sellmate-design-system-react';
584
+
585
+ const basicFields: SKeyValueField[][] = [
586
+ [
587
+ { name: 'code', label: '상품코드', type: 'text' },
588
+ { name: 'createdAt', label: '등록일', type: 'text' },
589
+ ],
590
+ [
591
+ { name: 'category', label: '카테고리', type: 'text' },
592
+ // 상태 태그도 표의 한 행으로 표현한다
593
+ { name: 'status', label: '상태',
594
+ render: <STag size="sm" color="green" label="판매중" /> },
595
+ ],
596
+ ];
597
+
598
+ const priceFields: SKeyValueField[][] = [
599
+ [
600
+ { name: 'price', label: '판매가', type: 'text' },
601
+ { name: 'cost', label: '원가', type: 'text' },
602
+ ],
603
+ ];
604
+
605
+ export default function ProductDetailPage() {
606
+ return (
607
+ <div className="flex flex-col gap-12">
608
+ <h1 className="typo-heading-lg m-0">클래식 셔츠</h1>
609
+
610
+ <SSectionHeaderCard>
611
+ <SSectionHeaderCard.Header title="기본 정보" marker thickness="accent" />
612
+ <SSectionHeaderCard.Body>
613
+ <SKeyValueTable fields={basicFields} values={product} />
614
+ </SSectionHeaderCard.Body>
615
+ </SSectionHeaderCard>
616
+
617
+ <SSectionHeaderCard>
618
+ {/* 헤더 우측에 액션이 필요하면 slot 을 쓴다 */}
619
+ <SSectionHeaderCard.Header
620
+ title="가격 정보"
621
+ marker
622
+ helpText={['부가세 포함 금액입니다.']}
623
+ slot={<SButton size="sm" color="secondary" label="이력" onClick={openHistory} />}
624
+ />
625
+ <SSectionHeaderCard.Body>
626
+ <SKeyValueTable fields={priceFields} values={product} />
627
+ </SSectionHeaderCard.Body>
628
+ </SSectionHeaderCard>
629
+
630
+ {/* 액션은 하단 — 목록(되돌리기)은 왼쪽 끝, 실행 액션은 오른쪽 끝 */}
631
+ <div className="flex items-center justify-between">
632
+ <SButton color="secondary" label="목록" onClick={goList} />
633
+ <div className="flex items-center gap-8">
634
+ <SButton color="danger" outline label="삭제" onClick={confirmDelete} />
635
+ <SButton label="수정" onClick={goEdit} />
636
+ </div>
637
+ </div>
638
+ </div>
639
+ );
640
+ }
641
+ ```
642
+
643
+ ### 4-5. 섹션 카드 — SSectionHeaderCard
644
+
645
+ 폼 페이지에서도 입력 항목이 많으면 유형별로 `SSectionHeaderCard` 로 나눈다. 주요 옵션:
646
+
647
+ | Prop (Header) | 용도 |
648
+ | --- | --- |
649
+ | `title` | 섹션 제목 (필수) |
650
+ | `marker` | 제목 앞 점 표시 |
651
+ | `required` | 제목 뒤 필수(\*) 표시 — 필수 입력 섹션에 |
652
+ | `helpText` | 도움말 툴팁 (`string[]`) |
653
+ | `subtitle` | 부제 |
654
+ | `slot` | 헤더 우측 영역 (버튼 등) |
655
+ | `thickness` | 상단 강조선 — `false`(기본) / `'default'` / `'accent'` |
656
+
657
+ ---
658
+
659
+ ## 5. 자가 점검 체크리스트
660
+
661
+ 페이지를 완성하면 다음을 확인한다. 하나라도 어기면 수정 후 완료를 보고한다.
662
+
663
+ - [ ] 생 HTML 컨트롤(`<button>` `<input>` `<select>` `<table>` …)이 없는가
664
+ - [ ] `text-[14px]`, `bg-[#...]` 같은 리터럴 임의 값이 없는가 (`var(--sys-*)` 참조는 허용)
665
+ - [ ] 텍스트에 `typo-*` 프리셋을 썼는가
666
+ - [ ] 간격이 전부 토큰 스케일 값인가 (`gap-13` ❌ → `gap-12` ✅)
667
+ - [ ] 본문이 12px(`typo-body-sm-default`)이고 보조 설명이 `text-fg-tertiary` 인가 (14px 본문 ❌)
668
+ - [ ] 페이지 패딩이 `p-20`, 블록·섹션 간격이 `gap-12` 인가 (`gap-16`/`gap-24` ❌)
669
+ - [ ] 같은 컴포넌트를 나열할 때 §2-2 그룹 간격을 썼는가 (체크박스 가로 `gap-24` 등)
670
+ - [ ] 페이지가 §4의 표준 골격에서 시작했는가
671
+ - [ ] 필터·폼·상세 정보를 `SKeyValueTable` 로 만들었는가 (컨트롤을 `div` 로 나열하지 않았는가)
672
+ - [ ] 섹션 구분에 `SSectionHeaderCard` 를 썼는가 (직접 만든 카드가 아니라)
673
+ - [ ] 목록의 주요 액션이 `STableBar` 의 `rightActions` 에 있는가 (페이지 제목 줄이 아니라)
674
+ - [ ] 상태 표시에 `STag size="sm"` 을 썼는가
675
+ - [ ] 테이블의 숫자 컬럼(금액·수량·개수 등)이 전부 `align: 'right'` 인가
676
+ - [ ] 화면에 표시하는 모든 숫자에 `toLocaleString()` 을 써서 세 자리 콤마를 넣었는가
677
+ - [ ] 금액·수량 등 양을 나타내는 숫자에 `toLocaleString()` 을 썼는가 (번호·코드는 제외)
678
+ - [ ] 하단 버튼이 양끝 분리(`justify-between`)이고, 되돌리기가 왼쪽 끝 · 실행이 오른쪽 끝인가
679
+ - [ ] 삭제 등 파괴적 액션에 `color="danger"` 를 썼는가
680
+ - [ ] 작업용 모달을 `SActionModal` + `SModal.create` 로 만들었는가 (직접 오버레이 ❌)
681
+ - [ ] 상태 표시·알림·확인 다이얼로그가 §3의 선택 규칙을 따르는가
682
+
683
+ ---
684
+
685
+ ## 6. 린트로 강제되는 규칙
686
+
687
+ 위 규칙 중 일부는 소비 앱의 ESLint 로 검출된다 (`sellmate-design-system-react/eslint`).
688
+ **코드를 넘기기 전에 린트를 통과시킨다.**
689
+
690
+ | 규칙 | 잡히는 것 |
691
+ | --- | --- |
692
+ | `sellmate/no-raw-html-control` | §1-1 생 HTML 컨트롤, `alert()`/`confirm()` |
693
+ | `sellmate/no-arbitrary-class` | §1-2 토큰 있는 속성의 임의 값 (`text-[14px]`, `bg-[#eee]`) |
694
+ | `sellmate/no-off-scale-spacing` | §2-2 스케일 밖 간격 (`gap-13`) |
695
+ | `sellmate/table-numeric-align` | §3-4 숫자 컬럼의 `align: 'right'` 누락 (`--fix` 지원) |
696
+ | `sellmate/require-locale-number` | §1-4 숫자 컬럼의 `toLocaleString()` 누락 |
697
+ | `sellmate/component-group-gap` | §2-2 컴포넌트 그룹 간격 (체크박스 가로 24 / 세로 8 등) |
698
+ | `sellmate/require-locale-number` | §1-4 금액·수량 등의 `toLocaleString()` 누락 |
699
+ | `sellmate/prefer-typo-preset` | §1-3 낱개 폰트 조합 (`text-14 font-bold`) |
700
+
701
+ `gap-13` 처럼 스케일 밖 값은 Tailwind v4 에서 **에러 없이 조용히 무시된다**. "간격이 왜 안 먹지" 로만 보이므로 반드시 스케일 값을 쓴다.
702
+
703
+ 린트가 잡지 못하는 것(§3 컴포넌트 선택, §4 페이지 골격, 버튼 배치)은 §5 체크리스트로 직접 확인한다.
704
+
705
+
706
+ ## 2. 디자인 토큰 어휘 (theme.css 자동 추출)
707
+
708
+ Tailwind 유틸리티는 아래 스케일에 있는 값만 사용한다. 리터럴 임의 값(`text-[14px]`, `bg-[#eee]`)은 금지.
709
+
710
+ ### 간격 (px 단위 — gap-N, p-N, m-N 등)
711
+ 2 4 6 8 10 12 16 19 20 22 24 28 32 36 40 44 48 56 60 62 80
712
+
713
+ ### 폰트 크기 (text-N — 단, 본문 텍스트는 아래 typo-* 프리셋 우선)
714
+ 10 11 12 13 14 16 18 20 24 28 32
715
+
716
+ ### radius (rounded-*)
717
+ 2 4 6 8 full control-sm control-md feedback-xs-square feedback-sm-square feedback-pill field-sm field-md navigation item-bordered
718
+
719
+ ### 색상 팔레트 (text-{family}-{step}, bg-…, border-…)
720
+ - white
721
+ - black
722
+ - grey: 10 20 25 30 35 45 50 55 60 65 70 80 85 90 95 05 strong subtle
723
+ - red: 15 20 30 45 60 70 75 80 85 90 95 99 strong subtle
724
+ - orange: 10 20 35 45 55 60 65 75 85 90 95 99 strong subtle
725
+ - yellow: 10 20 25 30 40 45 50 60 70 80 90 95 strong moderate subtle
726
+ - olive: 10 15 20 30 45 55 65 70 80 90 95 05
727
+ - green: 15 25 45 55 65 70 75 80 85 90 95 99 strong subtle
728
+ - steelblue: 10 25 45 60 65 70 75 80 85 90 95 99
729
+ - oceanblue: 15 25 50 60 65 70 75 80 85 90 95 99
730
+ - brilliantblue: 10 20 25 40 50 60 70 75 80 85 90 95 99 05
731
+ - bg: screen frame brand subtle accent accentLight accentBright accentFaint deep danger dangerLight warning caution progress success successLight neutralLight neutralBright tableHeader
732
+ - fg: primary secondary tertiary quaternary brand subtleWarm subtleCool deep success dangerLight accent accentLight danger warning inverse
733
+ - border: default strong accent accentLight danger success
734
+ - disabled: bg text icon border
735
+ - link: accent
736
+ - divider: default
737
+ - lightblue: strong subtle
738
+ - blue: strong subtle
739
+ - darkblue: strong subtle
740
+ - indigo: strong subtle
741
+ - primary: 10 20 25 40 50 60 70 75 80 85 90 95 99 05
742
+ - danger: 15 20 30 45 60 70 75 80 85 90 95 99 strong subtle
743
+ - success: 15 25 45 55 65 70 75 80 85 90 95 99 strong subtle
744
+ - warning: 10 20 35 45 55 60 65 75 85 90 95 99 strong subtle
745
+
746
+ ### 타이포그래피 프리셋 (클래스 하나로 size/weight/line-height 적용)
747
+ | 클래스 | size | weight | line-height |
748
+ | --- | --- | --- | --- |
749
+ | typo-heading-sm | 14px | 700 | 24px |
750
+ | typo-heading-xs | 12px | 700 | 20px |
751
+ | typo-heading-md | 16px | 700 | 26px |
752
+ | typo-heading-lg | 18px | 700 | 30px |
753
+ | typo-body-xs-default | 11px | 400 | 18px |
754
+ | typo-body-sm-default | 12px | 400 | 20px |
755
+ | typo-body-sm-medium | 12px | 500 | 20px |
756
+ | typo-body-sm-bold | 12px | 700 | 20px |
757
+ | typo-body-md-default | 14px | 400 | 24px |
758
+ | typo-body-md-medium | 14px | 500 | 24px |
759
+ | typo-body-md-bold | 14px | 700 | 24px |
760
+ | typo-body-lg-default | 16px | 400 | 26px |
761
+ | typo-body-lg-medium | 16px | 500 | 26px |
762
+ | typo-body-lg-bold | 16px | 700 | 26px |
763
+ | typo-control-xs-default | 12px | 400 | 20px |
764
+ | typo-control-xs-medium | 12px | 500 | 20px |
765
+ | typo-control-xs-underline | 12px | 500 | 20px |
766
+ | typo-control-xs-bold | 12px | 700 | 20px |
767
+ | typo-control-sm-default | 14px | 500 | 24px |
768
+ | typo-control-sm-underline | 14px | 500 | 24px |
769
+ | typo-control-md-default | 16px | 500 | 26px |
770
+ | typo-control-md-underline | 16px | 500 | 26px |
771
+ | typo-control-lg | 18px | 500 | 30px |
772
+ | typo-feedback-xs | 11px | 500 | 18px |
773
+ | typo-feedback-sm-regular | 12px | 400 | 20px |
774
+ | typo-feedback-sm-medium | 12px | 500 | 20px |
775
+ | typo-feedback-sm-bold | 12px | 700 | 20px |
776
+ | typo-feedback-sm-underline | 12px | 500 | 20px |
777
+ | typo-feedback-md-bold | 14px | 700 | 24px |
778
+ | typo-feedback-md-medium | 14px | 500 | 24px |
779
+ | typo-feedback-md-underline | 14px | 700 | 24px |
780
+ | typo-field-xs-default | 11px | 400 | 18px |
781
+ | typo-field-sm-default | 12px | 400 | 20px |
782
+ | typo-field-sm-medium | 12px | 500 | 20px |
783
+ | typo-field-sm-bold | 12px | 700 | 20px |
784
+ | typo-field-md-default | 14px | 400 | 24px |
785
+ | typo-field-md-medium | 14px | 500 | 24px |
786
+ | typo-field-md-bold | 14px | 700 | 24px |
787
+ | typo-field-lg-default | 16px | 400 | 26px |
788
+ | typo-field-lg-medium | 16px | 500 | 26px |
789
+ | typo-field-lg-bold | 16px | 700 | 26px |
790
+ | typo-navigation-xs-medium | 11px | 500 | 18px |
791
+ | typo-navigation-xs-bold | 11px | 700 | 18px |
792
+ | typo-navigation-sm-default | 12px | 400 | 20px |
793
+ | typo-navigation-sm-medium | 12px | 500 | 20px |
794
+ | typo-navigation-sm-bold | 12px | 700 | 20px |
795
+ | typo-navigation-md-bold | 13px | 700 | 22px |
796
+ | typo-navigation-lg-medium | 14px | 500 | 24px |
797
+ | typo-navigation-lg-bold | 14px | 700 | 24px |
798
+ | typo-table-header | 12px | 500 | 20px |
799
+ | typo-table-body | 12px | 400 | 20px |
800
+ | typo-table-accent | 12px | 700 | 20px |
801
+
802
+ ### 시맨틱 색 토큰 (var() 참조 전용 — 예: bg-[var(--sys-color-bg-frame)])
803
+ --sys-color-bg-accent
804
+ --sys-color-bg-accentBright
805
+ --sys-color-bg-accentFaint
806
+ --sys-color-bg-accentLight
807
+ --sys-color-bg-brand
808
+ --sys-color-bg-caution
809
+ --sys-color-bg-danger
810
+ --sys-color-bg-dangerLight
811
+ --sys-color-bg-deep
812
+ --sys-color-bg-frame
813
+ --sys-color-bg-neutralBright
814
+ --sys-color-bg-neutralLight
815
+ --sys-color-bg-progress
816
+ --sys-color-bg-screen
817
+ --sys-color-bg-subtle
818
+ --sys-color-bg-success
819
+ --sys-color-bg-successLight
820
+ --sys-color-bg-tableHeader
821
+ --sys-color-bg-warning
822
+ --sys-color-blue-strong
823
+ --sys-color-blue-subtle
824
+ --sys-color-border-accent
825
+ --sys-color-border-accentLight
826
+ --sys-color-border-danger
827
+ --sys-color-border-default
828
+ --sys-color-border-strong
829
+ --sys-color-border-success
830
+ --sys-color-control-bg-inverseHover
831
+ --sys-color-darkblue-strong
832
+ --sys-color-darkblue-subtle
833
+ --sys-color-disabled-bg
834
+ --sys-color-disabled-border
835
+ --sys-color-disabled-icon
836
+ --sys-color-disabled-text
837
+ --sys-color-divider-default
838
+ --sys-color-fg-accent
839
+ --sys-color-fg-accentLight
840
+ --sys-color-fg-brand
841
+ --sys-color-fg-danger
842
+ --sys-color-fg-dangerLight
843
+ --sys-color-fg-deep
844
+ --sys-color-fg-inverse
845
+ --sys-color-fg-primary
846
+ --sys-color-fg-quaternary
847
+ --sys-color-fg-secondary
848
+ --sys-color-fg-subtleCool
849
+ --sys-color-fg-subtleWarm
850
+ --sys-color-fg-success
851
+ --sys-color-fg-tertiary
852
+ --sys-color-fg-warning
853
+ --sys-color-field-bg-default
854
+ --sys-color-field-bg-hover
855
+ --sys-color-field-bg-readOnly
856
+ --sys-color-field-border-danger
857
+ --sys-color-field-border-default
858
+ --sys-color-field-border-focus
859
+ --sys-color-field-border-hover
860
+ --sys-color-field-border-success
861
+ --sys-color-field-icon-default
862
+ --sys-color-field-text-default
863
+ --sys-color-field-text-placeholder
864
+ --sys-color-field-text-readOnly
865
+ --sys-color-indigo-strong
866
+ --sys-color-indigo-subtle
867
+ --sys-color-lightblue-strong
868
+ --sys-color-lightblue-subtle
869
+ --sys-color-link-accent
870
+ --sys-color-navigation-gnb-bg-dark
871
+
872
+ ## 3. 컴포넌트 카탈로그 (Props / Events / Methods)
873
+
874
+ # SActionModal
875
+
876
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
877
+
878
+ ### SActionModal
879
+
880
+ #### Props
881
+
882
+ | Prop | Type | Default | Description |
883
+ |------|------|---------|-------------|
884
+ | `open?` | `boolean` | — | |
885
+ | `persistent?` | `boolean` | — | true면 백드롭·ESC로 안 닫히고 흔들림 (sd-modal-container persistent) |
886
+ | `modalTitle?` | `string` | `''` | |
887
+ | `button?` | `SActionModalButton` | — | 하단 액션 버튼 (주 액션 1개). 의도적으로 단수다 — 보조 버튼(취소·삭제 등)은 `footerLeft` 슬롯에 직접 배치한다. |
888
+ | `footerLeft?` | `ReactNode` | — | footer 좌측 영역 (sd-action-modal 의 bottom-sub-content 슬롯). 보조 버튼이나 안내 문구를 넣는다. 버튼을 하나 더 쓰고 싶을 때 여기에 SButton 을 넣는다. |
889
+ | `width?` | `number \| string` | — | |
890
+ | `height?` | `number \| string` | — | |
891
+ | `children?` | `ReactNode` | — | |
892
+
893
+ #### Events
894
+
895
+ | Event | Type | Description |
896
+ |-------|------|-------------|
897
+ | `onOpenChange` | `(open: boolean) => void` | |
898
+ | `onClose` | `() => void` | 닫기(X) 버튼 클릭 (sdClose) |
899
+
900
+ ## Dependencies
901
+
902
+ ### Depends on
903
+
904
+ - [SButton](../SButton)
905
+ - [SModalContainer](../SModalContainer)
906
+
907
+ ### Graph
908
+
909
+ ---
910
+
911
+ # SBadge
912
+
913
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
914
+
915
+ ### SBadge
916
+
917
+ #### Props
918
+
919
+ | Prop | Type | Default | Description |
920
+ |------|------|---------|-------------|
921
+ | `color?` | `SBadgeColor` | `'blue'` | 뱃지 색상 |
922
+
923
+ ## Dependencies
924
+
925
+ ### Used by
926
+
927
+ - [SList](../SList)
928
+
929
+ ### Graph
930
+
931
+ ---
932
+
933
+ # SBarcodeInput
934
+
935
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
936
+
937
+ ### SBarcodeInput
938
+
939
+ #### Props
940
+
941
+ | Prop | Type | Default | Description |
942
+ |------|------|---------|-------------|
943
+ | `value?` | `string \| number \| null` | — | |
944
+ | `size?` | `SBarcodeInputSize` | `'sm'` | |
945
+ | `clearable?` | `boolean` | `false` | |
946
+ | `autoFocus?` | `boolean` | — | |
947
+ | `name?` | `string` | — | |
948
+ | `placeholder?` | `string` | `'입력해 주세요.'` | |
949
+ | `disabled?` | `boolean` | `false` | |
950
+ | `readOnly?` | `boolean` | `false` | |
951
+ | `rules?` | `Rule[]` | — | |
952
+ | `status?` | `SFieldStatus` | — | |
953
+ | `focused?` | `boolean` | — | |
954
+ | `hovered?` | `boolean` | — | |
955
+ | `prefix?` | `ReactNode` | — | 입력 앞 슬롯 |
956
+ | `suffix?` | `ReactNode` | — | 입력 뒤 슬롯 |
957
+ | `inputClass?` | `string` | — | |
958
+ | `inputStyle?` | `CSSProperties` | — | |
959
+ | `label?` | `string` | — | |
960
+ | `labelWidth?` | `number \| string` | — | |
961
+ | `icon?` | `SIconName` | — | |
962
+ | `iconColor?` | `SColor` | — | |
963
+ | `labelTooltip?` | `string` | — | |
964
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
965
+ | `addonLabel?` | `string` | — | |
966
+ | `addonAlign?` | `SFieldAddonAlign` | — | |
967
+ | `hint?` | `string` | — | |
968
+ | `error?` | `boolean` | — | |
969
+ | `errorMessage?` | `string` | — | |
970
+ | `width?` | `number \| string` | — | |
971
+ | `className?` | `string` | — | |
972
+ | `style?` | `CSSProperties` | — | |
973
+
974
+ #### Events
975
+
976
+ | Event | Type | Description |
977
+ |-------|------|-------------|
978
+ | `onValueChange` | `(value: string) => void` | 값 변경 (sdUpdate) |
979
+ | `onFocus` | `() => void` | |
980
+ | `onBlur` | `() => void` | |
981
+
982
+ ## Dependencies
983
+
984
+ ### Depends on
985
+
986
+ - [SField](../SField)
987
+ - [SGhostButton](../SGhostButton)
988
+
989
+ ### Graph
990
+
991
+ ---
992
+
993
+ # SButton
994
+
995
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
996
+
997
+ ### SButton
998
+
999
+ #### Props
1000
+
1001
+ | Prop | Type | Default | Description |
1002
+ |------|------|---------|-------------|
1003
+ | `color?` | `SButtonColor` | `'primary'` | 색상 — sd-button preset의 색 계열 |
1004
+ | `outline?` | `boolean` | `false` | 아웃라인(테두리) 스타일. primary·neutral·danger 만 지원 (secondary 는 무시) |
1005
+ | `size?` | `SButtonSize` | `'sm'` | 크기 |
1006
+ | `icon?` | `SIconName` | — | 레이블 왼쪽 아이콘 |
1007
+ | `rightIcon?` | `SIconName` | — | 레이블 오른쪽 아이콘 |
1008
+ | `label?` | `string` | — | 버튼 텍스트 (문자열만 — 아이콘은 icon/rightIcon 사용) |
1009
+
1010
+ ## Dependencies
1011
+
1012
+ ### Used by
1013
+
1014
+ - [SActionModal](../SActionModal)
1015
+ - [SConfirmModal](../SConfirmModal)
1016
+ - [SDropdownButton](../SDropdownButton)
1017
+ - [SKeyValueTable](../SKeyValueTable)
1018
+ - [SLoadingModal](../SLoadingModal)
1019
+ - [SPopover](../SPopover)
1020
+ - [SPopup](../SPopup)
1021
+ - [SToast](../SToast)
1022
+
1023
+ ### Depends on
1024
+
1025
+ - [SIcon](../SIcon)
1026
+
1027
+ ### Graph
1028
+
1029
+ ---
1030
+
1031
+ # SCalendar
1032
+
1033
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1034
+
1035
+ ### SCalendar
1036
+
1037
+ #### Props
1038
+
1039
+ | Prop | Type | Default | Description |
1040
+ |------|------|---------|-------------|
1041
+ | `value?` | `string \| null` | — | 선택 날짜 (YYYY-MM-DD) |
1042
+ | `selectable?` | `[string, string]` | — | 선택 가능 범위 [시작, 종료] (빈 문자열이면 제한 없음) |
1043
+ | `events?` | `SCalendarEventGroup[]` | — | 이벤트 그룹 (날짜별 점) |
1044
+ | `elevated?` | `boolean` | `false` | 카드 그림자 |
1045
+ | `className?` | `string` | — | |
1046
+ | `style?` | `CSSProperties` | — | |
1047
+
1048
+ #### Events
1049
+
1050
+ | Event | Type | Description |
1051
+ |-------|------|-------------|
1052
+ | `onValueChange` | `(date: string) => void` | 선택 변경 (sdUpdate) |
1053
+ | `onViewChange` | `(v: { year: number; month: number }) => void` | 보이는 연·월 변경 (sdViewChange) |
1054
+
1055
+ ## Dependencies
1056
+
1057
+ ### Used by
1058
+
1059
+ - [SDatePicker](../SDatePicker)
1060
+
1061
+ ### Depends on
1062
+
1063
+ - [SGhostButton](../SGhostButton)
1064
+
1065
+ ### Graph
1066
+
1067
+ ---
1068
+
1069
+ # SCallout
1070
+
1071
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1072
+
1073
+ ### SCallout
1074
+
1075
+ #### Props
1076
+
1077
+ | Prop | Type | Default | Description |
1078
+ |------|------|---------|-------------|
1079
+ | `type?` | `SCalloutType` | `'default'` | 콜아웃 타입 (색상·아이콘·타이틀 결정) |
1080
+ | `message?` | `SCalloutMessage[]` | `[]` | 표시할 메시지 목록 (배열 중첩으로 depth 표현). 각 문자열은 인라인 HTML(`<b>`, `<a>` 등)을 허용하며 sanitizeInlineHtml 로 살균 후 렌더된다. |
1081
+ | `children?` | `ReactNode` | — | message 대신 직접 본문을 넣을 때 |
1082
+ | `className?` | `string` | — | |
1083
+ | `style?` | `CSSProperties` | — | |
1084
+
1085
+ ## Dependencies
1086
+
1087
+ ### Depends on
1088
+
1089
+ - [SIcon](../SIcon)
1090
+
1091
+ ### Graph
1092
+
1093
+ ---
1094
+
1095
+ # SCard
1096
+
1097
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1098
+
1099
+ ### SCard
1100
+
1101
+ #### Props
1102
+
1103
+ | Prop | Type | Default | Description |
1104
+ |------|------|---------|-------------|
1105
+ | `bordered?` | `boolean` | `false` | 테두리 표시 여부 |
1106
+
1107
+ ---
1108
+
1109
+ # SCheckbox
1110
+
1111
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1112
+
1113
+ ### SCheckbox
1114
+
1115
+ #### Props
1116
+
1117
+ | Prop | Type | Default | Description |
1118
+ |------|------|---------|-------------|
1119
+ | `value?` | `SCheckboxValue` | `false` | 선택 상태. boolean(단일) / 배열(그룹) / null(indeterminate) |
1120
+ | `val?` | `unknown` | — | 배열(그룹) 모드에서 이 체크박스의 값 |
1121
+ | `label?` | `string` | `''` | 라벨 |
1122
+ | `disabled?` | `boolean` | `false` | 비활성 |
1123
+ | `inverse?` | `boolean` | `false` | 어두운 배경용 흰색 스타일 |
1124
+ | `className?` | `string` | — | |
1125
+ | `style?` | `CSSProperties` | — | |
1126
+
1127
+ #### Events
1128
+
1129
+ | Event | Type | Description |
1130
+ |-------|------|-------------|
1131
+ | `onValueChange` | `(value: boolean \| unknown[]) => void` | 값 변경 (sdUpdate) |
1132
+
1133
+ ## Dependencies
1134
+
1135
+ ### Used by
1136
+
1137
+ - [SKeyValueTable](../SKeyValueTable)
1138
+ - [STable](../STable)
1139
+
1140
+ ### Depends on
1141
+
1142
+ - [SIcon](../SIcon)
1143
+
1144
+ ### Graph
1145
+
1146
+ ---
1147
+
1148
+ # SChip
1149
+
1150
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1151
+
1152
+ ### SChip
1153
+
1154
+ #### Props
1155
+
1156
+ | Prop | Type | Default | Description |
1157
+ |------|------|---------|-------------|
1158
+ | `name?` | `string` | — | 폼 연동용 name |
1159
+ | `value?` | `string` | `''` | 칩 텍스트 값 |
1160
+ | `error?` | `boolean` | — | 에러 상태 |
1161
+ | `disabled?` | `boolean` | `false` | 비활성 |
1162
+ | `editable?` | `boolean` | `false` | 인라인 편집 가능 (기본값 false) |
1163
+ | `showRemove?` | `boolean` | `true` | 닫기 버튼 표시 |
1164
+ | `placeholder?` | `string` | `''` | 편집 중 placeholder |
1165
+ | `rules?` | `Rule[]` | — | 유효성 규칙 |
1166
+ | `className?` | `string` | — | |
1167
+ | `style?` | `CSSProperties` | — | |
1168
+
1169
+ #### Events
1170
+
1171
+ | Event | Type | Description |
1172
+ |-------|------|-------------|
1173
+ | `onValueChange` | `(value: string) => void` | 편집 완료 (sdUpdate) |
1174
+ | `onRemove` | `() => void` | 삭제 (sdRemove) |
1175
+ | `onFocus` | `() => void` | 편집 진입 (sdFocus) |
1176
+ | `onBlur` | `() => void` | 편집 이탈 (sdBlur) |
1177
+
1178
+ #### Methods (ref)
1179
+
1180
+ | Method | Type | Description |
1181
+ |--------|------|-------------|
1182
+ | `focus` | `() => void` | 편집 input에 포커스합니다. |
1183
+ | `getNativeElement` | `() => HTMLElement \| null` | 네이티브 편집 엘리먼트를 반환합니다. |
1184
+
1185
+ ## Dependencies
1186
+
1187
+ ### Used by
1188
+
1189
+ - [SChipInput](../SChipInput)
1190
+ - [SFilePicker](../SFilePicker)
1191
+
1192
+ ### Depends on
1193
+
1194
+ - [SGhostButton](../SGhostButton)
1195
+
1196
+ ### Graph
1197
+
1198
+ ---
1199
+
1200
+ # SChipInput
1201
+
1202
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1203
+
1204
+ ### SChipInput
1205
+
1206
+ #### Props
1207
+
1208
+ | Prop | Type | Default | Description |
1209
+ |------|------|---------|-------------|
1210
+ | `values?` | `string[]` | `[]` | 칩 값 목록 |
1211
+ | `errors?` | `boolean[] \| ((value: string) => boolean)` | `[]` | 칩별 에러 (배열 또는 판별 함수) |
1212
+ | `disabledChips?` | `boolean[] \| ((value: string) => boolean)` | `[]` | 칩별 비활성 (배열 또는 판별 함수) |
1213
+ | `size?` | `SChipInputSize` | `'sm'` | |
1214
+ | `disabled?` | `boolean` | `false` | |
1215
+ | `placeholder?` | `string` | `'태그 입력 (Enter로 등록 / 콤마로 구분 / 띄어쓰기 불가)'` | |
1216
+ | `name?` | `string` | — | |
1217
+ | `rules?` | `Rule[]` | — | |
1218
+ | `error?` | `boolean` | — | |
1219
+ | `useReset?` | `boolean` | `false` | 입력 초기화 버튼 표시 |
1220
+ | `maxCount?` | `number` | — | 최대 칩 개수 |
1221
+ | `metaPlacement?` | `SChipInputMetaPlacement` | `'end'` | 최대 개수·초기화 meta 위치 |
1222
+ | `duplicateLabel?` | `string` | — | 중복 에러 메시지 항목명 |
1223
+ | `suggestions?` | `string[]` | `[]` | 자동완성 후보 |
1224
+ | `loadingSuggestions?` | `boolean` | `false` | |
1225
+ | `recommendedItems?` | `string[]` | `[]` | 추천 항목 (입력값 없을 때) |
1226
+ | `loadingRecommendedItems?` | `boolean` | `false` | |
1227
+ | `dropdownMinWidth?` | `number \| string` | `200` | 드롭다운 최소 너비 (숫자=px) |
1228
+ | `label?` | `string` | — | |
1229
+ | `labelWidth?` | `number \| string` | — | |
1230
+ | `hint?` | `string` | — | |
1231
+ | `errorMessage?` | `string` | — | |
1232
+ | `width?` | `number \| string` | — | |
1233
+ | `status?` | `SFieldStatus` | — | |
1234
+ | `icon?` | `SIconName` | — | |
1235
+ | `iconColor?` | `SColor` | — | |
1236
+ | `labelTooltip?` | `string` | — | |
1237
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
1238
+ | `className?` | `string` | — | |
1239
+ | `style?` | `CSSProperties` | — | |
1240
+
1241
+ #### Events
1242
+
1243
+ | Event | Type | Description |
1244
+ |-------|------|-------------|
1245
+ | `onValueChange` | `(values: string[]) => void` | 값 변경 (sdUpdate) — 전체 배열 |
1246
+ | `onInput` | `(value: string) => void` | 입력 중 문자열 변경 (sdInput) |
1247
+ | `onFocus` | `() => void` | |
1248
+ | `onBlur` | `() => void` | |
1249
+
1250
+ #### Methods (ref)
1251
+
1252
+ | Method | Type | Description |
1253
+ |--------|------|-------------|
1254
+ | `focus` | `() => void` | 입력 필드에 포커스를 이동합니다. |
1255
+
1256
+ ## Dependencies
1257
+
1258
+ ### Depends on
1259
+
1260
+ - [SChip](../SChip)
1261
+ - [SField](../SField)
1262
+ - [SIcon](../SIcon)
1263
+ - [SPortal](../SPortal)
1264
+ - [STextLink](../STextLink)
1265
+
1266
+ ### Graph
1267
+
1268
+ ---
1269
+
1270
+ # SCircleProgress
1271
+
1272
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1273
+
1274
+ ### SCircleProgress
1275
+
1276
+ #### Props
1277
+
1278
+ | Prop | Type | Default | Description |
1279
+ |------|------|---------|-------------|
1280
+ | `value?` | `number` | `0` | 진행률 (0–100) |
1281
+ | `type?` | `SCircleProgressType` | `'primary'` | 색상 테마 |
1282
+ | `indeterminate?` | `boolean` | `false` | 불확정(스피너) 모드 — value 무시 |
1283
+ | `label?` | `string` | — | 하단 레이블 |
1284
+ | `innerValue?` | `boolean` | `false` | true면 퍼센트를 원 아래가 아닌 원 가운데에 표시 |
1285
+ | `className?` | `string` | — | |
1286
+ | `style?` | `CSSProperties` | — | |
1287
+
1288
+ ## Dependencies
1289
+
1290
+ ### Used by
1291
+
1292
+ - [SLoadingContainer](../SLoadingContainer)
1293
+ - [SLoadingModal](../SLoadingModal)
1294
+ - [STable](../STable)
1295
+
1296
+ ### Graph
1297
+
1298
+ ---
1299
+
1300
+ # SConfirmModal
1301
+
1302
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1303
+
1304
+ ### SConfirmModal
1305
+
1306
+ #### Props
1307
+
1308
+ | Prop | Type | Default | Description |
1309
+ |------|------|---------|-------------|
1310
+ | `open?` | `boolean` | — | |
1311
+ | `persistent?` | `boolean` | — | true면 백드롭·ESC로 안 닫히고 흔들림 (sd-modal-container persistent) |
1312
+ | `type?` | `SConfirmModalType` | `'positive'` | 타입 (아이콘·메인버튼 색 결정) |
1313
+ | `modalTitle?` | `string` | `''` | |
1314
+ | `titleClass?` | `string` | — | 제목 엘리먼트에 추가할 클래스 (sd-confirm-modal titleClass) |
1315
+ | `topMessage?` | `string[]` | `[]` | 콘텐츠 박스 상단 메시지 목록 (각 항목이 한 줄, HTML 문자열 허용 — innerHTML 렌더링) |
1316
+ | `bottomMessage?` | `string[]` | `[]` | 콘텐츠 박스 하단 메시지 목록 (각 항목이 한 줄, HTML 문자열 허용 — innerHTML 렌더링) |
1317
+ | `tagLabel?` | `string` | — | tag 슬롯 기본 태그 레이블 (tagSlot 미지정 시) |
1318
+ | `tagShape?` | `STagShape` | `'square'` | 태그 프리셋 (shape/size/color) — sd-confirm-modal tagPreset 대응 |
1319
+ | `tagSize?` | `STagSize` | `'sm'` | |
1320
+ | `tagColor?` | `STagColor` | `'grey'` | |
1321
+ | `slotLabel?` | `string` | — | 콘텐츠 박스에서 태그 오른쪽에 오는 텍스트 (optionSlot 미지정 시) |
1322
+ | `tagSlot?` | `ReactNode` | — | 콘텐츠 박스 tag 위치 커스텀 콘텐츠 (미지정 시 tagLabel 기반 STag) |
1323
+ | `optionSlot?` | `ReactNode` | — | 콘텐츠 박스에서 태그 오른쪽 커스텀 콘텐츠 (미지정 시 slotLabel 텍스트) |
1324
+ | `mainButtonLabel?` | `string` | `'확인'` | 메인 버튼 |
1325
+ | `mainButtonName?` | `ConfirmModalMainButton` | — | 확인 버튼 프리셋 (없으면 type에 따라 자동 결정) |
1326
+ | `subButtonLabel?` | `string` | — | 서브(취소) 버튼 |
1327
+
1328
+ #### Events
1329
+
1330
+ | Event | Type | Description |
1331
+ |-------|------|-------------|
1332
+ | `onOpenChange` | `(open: boolean) => void` | |
1333
+ | `onOk` | `() => void` | 확인 버튼 클릭 (sdOk) |
1334
+ | `onCancel` | `() => void` | |
1335
+ | `onClose` | `() => void` | 닫기(X) 버튼 클릭 (sdClose) |
1336
+
1337
+ ## Dependencies
1338
+
1339
+ ### Used by
1340
+
1341
+ - [SModal](../SModal)
1342
+
1343
+ ### Depends on
1344
+
1345
+ - [SButton](../SButton)
1346
+ - [SIcon](../SIcon)
1347
+ - [SModalContainer](../SModalContainer)
1348
+ - [STag](../STag)
1349
+
1350
+ ### Graph
1351
+
1352
+ ---
1353
+
1354
+ # SDatePicker
1355
+
1356
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1357
+
1358
+ ### SDatePicker
1359
+
1360
+ #### Props
1361
+
1362
+ | Prop | Type | Default | Description |
1363
+ |------|------|---------|-------------|
1364
+ | `value?` | `string \| null` | — | 선택 날짜 (YYYY-MM-DD) |
1365
+ | `size?` | `SDatePickerSize` | `'sm'` | |
1366
+ | `placeholder?` | `string` | `'YYYY-MM-DD'` | |
1367
+ | `selectable?` | `[string, string]` | — | 선택 가능 범위 [시작, 종료] |
1368
+ | `disabled?` | `boolean` | `false` | |
1369
+ | `width?` | `number \| string` | — | |
1370
+ | `name?` | `string` | — | |
1371
+ | `rules?` | `Rule[]` | — | |
1372
+ | `status?` | `SFieldStatus` | — | |
1373
+ | `label?` | `string` | — | |
1374
+ | `labelWidth?` | `number \| string` | — | |
1375
+ | `icon?` | `SIconName` | — | |
1376
+ | `iconColor?` | `SColor` | — | |
1377
+ | `labelTooltip?` | `string` | — | |
1378
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
1379
+ | `addonLabel?` | `string` | — | |
1380
+ | `addonAlign?` | `SFieldAddonAlign` | — | |
1381
+ | `hint?` | `string` | — | |
1382
+ | `error?` | `boolean` | — | |
1383
+ | `errorMessage?` | `string` | — | |
1384
+ | `className?` | `string` | — | |
1385
+ | `style?` | `CSSProperties` | — | |
1386
+
1387
+ #### Events
1388
+
1389
+ | Event | Type | Description |
1390
+ |-------|------|-------------|
1391
+ | `onValueChange` | `(date: string) => void` | 선택 변경 (sdUpdate) |
1392
+ | `onViewChange` | `(view: { year: number; month: number }) => void` | 보이는 연·월 변경 (sdViewChange) |
1393
+
1394
+ ## Dependencies
1395
+
1396
+ ### Used by
1397
+
1398
+ - [SKeyValueTable](../SKeyValueTable)
1399
+
1400
+ ### Depends on
1401
+
1402
+ - [SCalendar](../SCalendar)
1403
+ - [SField](../SField)
1404
+ - [SIcon](../SIcon)
1405
+
1406
+ ### Graph
1407
+
1408
+ ---
1409
+
1410
+ # SDateRangePicker
1411
+
1412
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1413
+
1414
+ ### SDateRangePicker
1415
+
1416
+ #### Props
1417
+
1418
+ | Prop | Type | Default | Description |
1419
+ |------|------|---------|-------------|
1420
+ | `value?` | `SDateRangeValue` | — | |
1421
+ | `size?` | `SDateRangePickerSize` | `'sm'` | |
1422
+ | `placeholder?` | `string` | `'YYYY-MM-DD ~ YYYY-MM-DD'` | |
1423
+ | `selectable?` | `[string, string]` | — | |
1424
+ | `maxRange?` | `number` | — | 최대 선택 일수 |
1425
+ | `useTimePicker?` | `boolean` | `false` | 시간(시:분) 선택 푸터 사용 여부. true이면 value는 "YYYY-MM-DD HH:mm" 형식이 되고, 캘린더 하단에 시작·종료 시간 입력이 표시된다. |
1426
+ | `disabled?` | `boolean` | `false` | |
1427
+ | `width?` | `number \| string` | — | |
1428
+ | `name?` | `string` | — | |
1429
+ | `rules?` | `Rule[]` | — | |
1430
+ | `status?` | `SFieldStatus` | — | |
1431
+ | `label?` | `string` | — | |
1432
+ | `labelWidth?` | `number \| string` | — | |
1433
+ | `icon?` | `SIconName` | — | |
1434
+ | `iconColor?` | `SColor` | — | |
1435
+ | `labelTooltip?` | `string` | — | |
1436
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
1437
+ | `addonLabel?` | `string` | — | |
1438
+ | `addonAlign?` | `SFieldAddonAlign` | — | |
1439
+ | `hint?` | `string` | — | |
1440
+ | `error?` | `boolean` | — | |
1441
+ | `errorMessage?` | `string` | — | |
1442
+ | `className?` | `string` | — | |
1443
+ | `style?` | `CSSProperties` | — | |
1444
+
1445
+ #### Events
1446
+
1447
+ | Event | Type | Description |
1448
+ |-------|------|-------------|
1449
+ | `onValueChange` | `(range: SDateRangeValue) => void` | 선택 변경 (sdUpdate) — [start, end] |
1450
+ | `onViewChange` | `(view: { year: number; month: number }) => void` | 보이는 연·월 변경 (sdViewChange) |
1451
+
1452
+ ## Dependencies
1453
+
1454
+ ### Used by
1455
+
1456
+ - [SKeyValueTable](../SKeyValueTable)
1457
+
1458
+ ### Depends on
1459
+
1460
+ - [SField](../SField)
1461
+ - [SGhostButton](../SGhostButton)
1462
+ - [SIcon](../SIcon)
1463
+
1464
+ ### Graph
1465
+
1466
+ ---
1467
+
1468
+ # SDivider
1469
+
1470
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1471
+
1472
+ ### SDivider
1473
+
1474
+ #### Props
1475
+
1476
+ | Prop | Type | Default | Description |
1477
+ |------|------|---------|-------------|
1478
+ | `vertical?` | `boolean` | `false` | true면 수직 분할선, false면 수평 분할선 |
1479
+
1480
+ ## Dependencies
1481
+
1482
+ ### Used by
1483
+
1484
+ - [STableBar](../STableBar)
1485
+
1486
+ ### Graph
1487
+
1488
+ ---
1489
+
1490
+ # SDraggableItem
1491
+
1492
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1493
+
1494
+ ### SDraggableItem
1495
+
1496
+ #### Props
1497
+
1498
+ | Prop | Type | Default | Description |
1499
+ |------|------|---------|-------------|
1500
+ | `title` | `SDraggableItemSlot` | — | 드래그 아이템 제목 |
1501
+ | `trailing?` | `SDraggableItemSlot` | — | 타이틀 뒤에 표시할 태그/콘텐츠 |
1502
+ | `accentStripe?` | `boolean` | `false` | 아이템 왼쪽 accent stripe 표시 여부 |
1503
+ | `bordered?` | `boolean` | `false` | 외곽 테두리 사용 여부 |
1504
+ | `selected?` | `boolean` | `false` | 선택 상태 여부 |
1505
+ | `dense?` | `boolean` | `false` | 조밀한 높이 사용 여부 |
1506
+ | `disabled?` | `boolean` | `false` | 비활성 상태 여부 |
1507
+ | `dragOverlay?` | `boolean` | `true` | 드래그 시 마우스를 따라가는 overlay 표시 여부 |
1508
+ | `dragOverlayOpacity?` | `number` | `0.75` | 드래그 overlay 투명도 |
1509
+ | `dragHandleProps?` | `HTMLAttributes<HTMLDivElement>` | — | 드래그 핸들에 전달할 속성 |
1510
+
1511
+ #### Events
1512
+
1513
+ | Event | Type | Description |
1514
+ |-------|------|-------------|
1515
+ | `onDragHandleMouseDown` | `(event: MouseEvent<HTMLDivElement>) => void` | 드래그 핸들 mouse down 이벤트 |
1516
+
1517
+ ## Dependencies
1518
+
1519
+ ### Depends on
1520
+
1521
+ - [SIcon](../SIcon)
1522
+
1523
+ ### Graph
1524
+
1525
+ ---
1526
+
1527
+ # SDropdownButton
1528
+
1529
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1530
+
1531
+ ### SDropdownButton
1532
+
1533
+ #### Props
1534
+
1535
+ | Prop | Type | Default | Description |
1536
+ |------|------|---------|-------------|
1537
+ | `color?` | `SButtonColor` | `'primary'` | 버튼 색상 |
1538
+ | `outline?` | `boolean` | `false` | 아웃라인(테두리) 스타일 |
1539
+ | `size?` | `SDropdownButtonSize` | `'sm'` | 크기 (lg 미지원) |
1540
+ | `label?` | `string` | `''` | 버튼 레이블 |
1541
+ | `items?` | `SDropdownButtonItem[]` | `[]` | 메뉴 아이템 목록 |
1542
+ | `split?` | `boolean` | `false` | split 모드 — 레이블 버튼과 토글 분리 |
1543
+ | `disabled?` | `boolean` | `false` | 비활성 |
1544
+ | `className?` | `string` | — | |
1545
+ | `style?` | `CSSProperties` | — | |
1546
+
1547
+ #### Events
1548
+
1549
+ | Event | Type | Description |
1550
+ |-------|------|-------------|
1551
+ | `onItemClick` | `(value: string \| number) => void` | 메뉴 아이템 선택 (sdClick) |
1552
+ | `onLabelClick` | `() => void` | split 레이블 버튼 클릭 (sdButtonClick) |
1553
+ | `onOpenChange` | `(open: boolean) => void` | 열림/닫힘 변경 (sdDropDownShow) |
1554
+
1555
+ #### Methods (ref)
1556
+
1557
+ | Method | Type | Description |
1558
+ |--------|------|-------------|
1559
+ | `open` | `() => void` | 드롭다운 열기 (sdOpen) |
1560
+ | `close` | `() => void` | 드롭다운 닫기 (sdClose) |
1561
+
1562
+ ## Dependencies
1563
+
1564
+ ### Depends on
1565
+
1566
+ - [SButton](../SButton)
1567
+ - [SIcon](../SIcon)
1568
+
1569
+ ### Graph
1570
+
1571
+ ---
1572
+
1573
+ # SExpansionItem
1574
+
1575
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1576
+
1577
+ ### SExpansionItem
1578
+
1579
+ #### Props
1580
+
1581
+ | Prop | Type | Default | Description |
1582
+ |------|------|---------|-------------|
1583
+ | `title` | `ReactNode` | — | |
1584
+ | `depth?` | `1 \| 2 \| 3` | `1` | 중첩 단계. Figma 기준 1~3단계 |
1585
+ | `leading?` | `ReactNode \| SExpansionItemRenderProp` | — | 타이틀 앞에 표시할 아이콘/콘텐츠 |
1586
+ | `trailing?` | `ReactNode` | — | 타이틀 뒤에 표시할 태그/콘텐츠 |
1587
+ | `bodyPadding?` | `boolean` | `true` | body 내부 패딩 사용 여부 |
1588
+ | `bordered?` | `boolean` | `false` | 외곽 테두리 사용 여부 |
1589
+ | `expanded?` | `boolean` | — | |
1590
+ | `defaultExpanded?` | `boolean` | `false` | |
1591
+ | `dense?` | `boolean` | `false` | |
1592
+ | `disabled?` | `boolean` | `false` | |
1593
+
1594
+ #### Events
1595
+
1596
+ | Event | Type | Description |
1597
+ |-------|------|-------------|
1598
+ | `onToggle` | `(expanded: boolean, event: MouseEvent<HTMLButtonElement>) => void` | |
1599
+
1600
+ ## Dependencies
1601
+
1602
+ ### Depends on
1603
+
1604
+ - [SIcon](../SIcon)
1605
+
1606
+ ### Graph
1607
+
1608
+ ---
1609
+
1610
+ # SField
1611
+
1612
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1613
+
1614
+ ### SField
1615
+
1616
+ #### Props
1617
+
1618
+ | Prop | Type | Default | Description |
1619
+ |------|------|---------|-------------|
1620
+ | `name?` | `string` | — | 폼 연동용 name 속성 |
1621
+ | `label?` | `string` | `''` | 레이블 텍스트 |
1622
+ | `icon?` | `SIconName` | — | 레이블 영역 아이콘명 (크기는 size 토큰 16px 고정) |
1623
+ | `iconColor?` | `SColor` | — | 레이블 영역 아이콘 색상. 미지정 시 currentColor 상속 |
1624
+ | `labelTooltip?` | `string` | `''` | 레이블 툴팁 텍스트 |
1625
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | 레이블 툴팁 상세 옵션 (SdTooltipProps 대응) |
1626
+ | `labelWidth?` | `number \| string` | — | 레이블/어드온 레이블 너비 (숫자=px). label·addonLabel 폭에 공통 적용 |
1627
+ | `labelHeight?` | `number \| string` | — | 레이블 박스 높이 (숫자=px). 미지정 시 size별 기본값 사용. 컨트롤 박스가 기본 필드 높이보다 큰 경우(multiline 등) 첫 행에 세로 중앙 정렬을 맞추기 위해 컨트롤 박스 높이를 넘겨받는다. |
1628
+ | `size?` | `SFieldSize` | `'sm'` | 필드 크기 |
1629
+ | `addonLabel?` | `string` | `''` | 우측 어드온 레이블 |
1630
+ | `addonAlign?` | `SFieldAddonAlign` | `'start'` | 어드온 정렬 |
1631
+ | `error?` | `boolean` | `false` | 에러 상태 |
1632
+ | `errorMessage?` | `string` | `''` | 에러 메시지 |
1633
+ | `status?` | `SFieldStatus` | — | 필드 상태 — 'error' | 'pass' | 'default'. 'pass'면 초록 테두리 |
1634
+ | `focused?` | `boolean` | `false` | 포커스 상태 (제어/반영) |
1635
+ | `hovered?` | `boolean` | `false` | 호버 상태 (제어/반영) |
1636
+ | `rules?` | `Rule[]` | — | 유효성 규칙 (검증은 컨트롤에서 수행, API 패리티) |
1637
+ | `hint?` | `string` | `''` | 하단 힌트 |
1638
+ | `disabled?` | `boolean` | `false` | 비활성 |
1639
+ | `readOnly?` | `boolean` | `false` | 읽기 전용 (회색 배경) |
1640
+ | `width?` | `number \| string` | — | 컨트롤 너비 (숫자=px). 지정하면 필드가 부모 폭을 다 먹지 않고 (레이블 + width) 만큼만 차지한다. 다른 요소와 나란히 놓으려면 부모를 flex 로 두면 된다. |
1641
+ | `minWidth?` | `number \| string` | — | 컨트롤 최소 너비 (숫자=px). 하한선만 지정하며 필드는 계속 부모 폭을 채운다 |
1642
+ | `multiline?` | `boolean` | `false` | 멀티라인(textarea) — 컨트롤 높이를 고정하지 않고 min-height만 적용 |
1643
+ | `borderless?` | `boolean` | `false` | 테두리 박스 제거 (inline 컨트롤용) — border/배경/hover·focus 강조만 사라지고 label·hint·errorMessage 등 나머지 필드 구성은 그대로 동작한다. |
1644
+ | `children?` | `ReactNode` | — | 실제 컨트롤 (input/select 등) — 테두리 없이 렌더, 테두리는 SField가 제공 |
1645
+ | `className?` | `string` | — | |
1646
+ | `style?` | `CSSProperties` | — | |
1647
+
1648
+ #### Events
1649
+
1650
+ | Event | Type | Description |
1651
+ |-------|------|-------------|
1652
+ | `onMouseEnter` | `() => void` | |
1653
+ | `onMouseLeave` | `() => void` | |
1654
+
1655
+ #### Methods (ref)
1656
+
1657
+ | Method | Type | Description |
1658
+ |--------|------|-------------|
1659
+ | `focus` | `() => void` | 내부 컨트롤에 포커스하고 필드를 화면에 스크롤합니다. |
1660
+
1661
+ ## Dependencies
1662
+
1663
+ ### Used by
1664
+
1665
+ - [SBarcodeInput](../SBarcodeInput)
1666
+ - [SChipInput](../SChipInput)
1667
+ - [SDatePicker](../SDatePicker)
1668
+ - [SDateRangePicker](../SDateRangePicker)
1669
+ - [SFilePicker](../SFilePicker)
1670
+ - [SInput](../SInput)
1671
+ - [SNumberInput](../SNumberInput)
1672
+ - [SSelect](../SSelect)
1673
+ - [STextarea](../STextarea)
1674
+ - [STimePicker](../STimePicker)
1675
+ - [STimeRangePicker](../STimeRangePicker)
1676
+
1677
+ ### Depends on
1678
+
1679
+ - [SIcon](../SIcon)
1680
+ - [STooltip](../STooltip)
1681
+
1682
+ ### Graph
1683
+
1684
+ ---
1685
+
1686
+ # SFilePicker
1687
+
1688
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1689
+
1690
+ ### SFilePicker
1691
+
1692
+ #### Props
1693
+
1694
+ | Prop | Type | Default | Description |
1695
+ |------|------|---------|-------------|
1696
+ | `value?` | `SFilePickerValue` | `null` | |
1697
+ | `placeholder?` | `string` | `'Click to upload'` | |
1698
+ | `disabled?` | `boolean` | `false` | |
1699
+ | `focused?` | `boolean` | `false` | 포커스 상태 여부 |
1700
+ | `hovered?` | `boolean` | `false` | 호버 상태 여부 |
1701
+ | `inline?` | `boolean` | `false` | 인라인 표시 — SField 테두리 박스만 사라지고 label/rules/hint 는 그대로 동작 |
1702
+ | `multiple?` | `boolean` | `false` | |
1703
+ | `useMultipleListBox?` | `boolean` | `false` | multiple 파일 목록을 필드 아래 칩 대신, caret(▼) 클릭 시 열리는 리스트박스 카드로 표시 (바깥 클릭 시 닫힘) |
1704
+ | `accept?` | `string` | — | |
1705
+ | `maxFileSize?` | `number \| string` | — | |
1706
+ | `maxTotalSize?` | `number \| string` | — | |
1707
+ | `maxFiles?` | `number \| string` | — | |
1708
+ | `name?` | `string` | — | |
1709
+ | `rules?` | `Rule[]` | — | |
1710
+ | `status?` | `SFieldStatus` | — | |
1711
+ | `size?` | `SFieldSize` | `'sm'` | |
1712
+ | `label?` | `string` | — | |
1713
+ | `labelWidth?` | `number \| string` | — | |
1714
+ | `icon?` | `SIconName` | — | |
1715
+ | `iconColor?` | `SColor` | — | |
1716
+ | `labelTooltip?` | `string` | — | |
1717
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
1718
+ | `addonLabel?` | `string` | — | |
1719
+ | `addonAlign?` | `SFieldAddonAlign` | `'start'` | |
1720
+ | `hint?` | `string` | — | |
1721
+ | `error?` | `boolean` | — | |
1722
+ | `errorMessage?` | `string` | — | |
1723
+ | `width?` | `number \| string` | — | |
1724
+ | `className?` | `string` | — | |
1725
+ | `style?` | `CSSProperties` | — | |
1726
+
1727
+ #### Events
1728
+
1729
+ | Event | Type | Description |
1730
+ |-------|------|-------------|
1731
+ | `onValueChange` | `(value: SFilePickerValue) => void` | 파일 변경 (sdUpdate) |
1732
+ | `onReject` | `(detail: { files: File[]; reason: SFilePickerRejectReason }) => void` | 제한 초과 거부 (sdReject) |
1733
+
1734
+ ## Dependencies
1735
+
1736
+ ### Used by
1737
+
1738
+ - [SKeyValueTable](../SKeyValueTable)
1739
+
1740
+ ### Depends on
1741
+
1742
+ - [SChip](../SChip)
1743
+ - [SField](../SField)
1744
+ - [SGhostButton](../SGhostButton)
1745
+ - [SIcon](../SIcon)
1746
+
1747
+ ### Graph
1748
+
1749
+ ---
1750
+
1751
+ # SForm
1752
+
1753
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1754
+
1755
+ ### SForm
1756
+
1757
+ #### Props
1758
+
1759
+ | Prop | Type | Default | Description |
1760
+ |------|------|---------|-------------|
1761
+ | `formClass?` | `string` | — | form 엘리먼트에 추가할 클래스 (sd-form formClass 대응) |
1762
+ | `children?` | `ReactNode` | — | |
1763
+ | `className?` | `string` | — | |
1764
+ | `style?` | `CSSProperties` | — | |
1765
+
1766
+ #### Events
1767
+
1768
+ | Event | Type | Description |
1769
+ |-------|------|-------------|
1770
+ | `onSubmit` | `() => void` | 모든 필드 검증 통과 후 발생 (sd-form sdSubmit 대응) |
1771
+ | `onValidationError` | `(error: SFormValidationError) => void` | 검증 실패 시 실패한 필드 name 목록 전달 (sd-form sdValidationError 대응) |
1772
+
1773
+ #### Methods (ref)
1774
+
1775
+ | Method | Type | Description |
1776
+ |--------|------|-------------|
1777
+ | `validate` | `() => boolean` | 등록된 모든 필드를 검증하고 통과 여부를 반환 |
1778
+ | `resetValidation` | `() => void` | 모든 필드의 검증 상태만 초기화 (값은 소비자 소유) |
1779
+ | `reset` | `() => void` | resetValidation 별칭 — sd-form sdReset 대응. 값 리셋은 소비자(value/onChange) 책임 |
1780
+ | `focusFirstInvalid` | `() => void` | 첫 번째 실패 필드로 포커스 이동 |
1781
+
1782
+ ---
1783
+
1784
+ # SGhostButton
1785
+
1786
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1787
+
1788
+ ### SGhostButton
1789
+
1790
+ #### Props
1791
+
1792
+ | Prop | Type | Default | Description |
1793
+ |------|------|---------|-------------|
1794
+ | `icon` | `SIconName` | — | 표시할 아이콘명 (필수) |
1795
+ | `size?` | `SGhostButtonSize` | `'sm'` | 버튼 크기 |
1796
+ | `intent?` | `SGhostButtonIntent` | `'default'` | 색상 의도 |
1797
+ | `ariaLabel?` | `string` | `''` | 스크린리더용 접근성 레이블 |
1798
+ | `ariaPressed?` | `boolean` | — | 토글 버튼일 때 눌림 상태 (aria-pressed). 미지정 시 속성 자체를 내보내지 않는다. |
1799
+ | `tooltipText?` | `string` | — | 호버 시 표시할 툴팁 텍스트 |
1800
+ | `disabled?` | `boolean` | `false` | 비활성 |
1801
+ | `anchorClassName?` | `string` | — | tooltip anchor wrapper 클래스. tooltipText가 있을 때 위치 조정용으로 사용합니다. |
1802
+ | `anchorStyle?` | `CSSProperties` | — | tooltip anchor wrapper 스타일. tooltipText가 있을 때 위치 조정용으로 사용합니다. |
1803
+ | `className?` | `string` | — | |
1804
+ | `style?` | `CSSProperties` | — | |
1805
+
1806
+ #### Events
1807
+
1808
+ | Event | Type | Description |
1809
+ |-------|------|-------------|
1810
+ | `onClick` | `(e: MouseEvent<HTMLButtonElement>) => void` | 클릭 (sdClick) |
1811
+
1812
+ ## Dependencies
1813
+
1814
+ ### Used by
1815
+
1816
+ - [SBarcodeInput](../SBarcodeInput)
1817
+ - [SCalendar](../SCalendar)
1818
+ - [SChip](../SChip)
1819
+ - [SDateRangePicker](../SDateRangePicker)
1820
+ - [SFilePicker](../SFilePicker)
1821
+ - [SGnb](../SGnb)
1822
+ - [SGuide](../SGuide)
1823
+ - [SInput](../SInput)
1824
+ - [SModalContainer](../SModalContainer)
1825
+ - [SPopover](../SPopover)
1826
+ - [SSelect](../SSelect)
1827
+ - [STimePicker](../STimePicker)
1828
+ - [STimeRangePicker](../STimeRangePicker)
1829
+ - [SToast](../SToast)
1830
+ - [STooltip](../STooltip)
1831
+
1832
+ ### Depends on
1833
+
1834
+ - [SIcon](../SIcon)
1835
+ - [STag](../STag)
1836
+
1837
+ ### Graph
1838
+
1839
+ ---
1840
+
1841
+ # SGnb
1842
+
1843
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1844
+
1845
+ ### SGnb
1846
+
1847
+ #### Props
1848
+
1849
+ | Prop | Type | Default | Description |
1850
+ |------|------|---------|-------------|
1851
+ | `type?` | `SGnbType` | — | 메뉴 스타일: box(라운드) / belt(풀폭 행). 미지정 시 SLayout 의 type 을 따른다. |
1852
+ | `header?` | `SGnbHeader` | — | 상단바 구조: fix(GNB 폭 고정) / full(레이아웃 전폭). 미지정 시 SLayout 의 header 를 따른다. 단, useRail 이고 레일에 children 없는 아이템이 있으면 메뉴 폭이 출렁이므로 full 로 강제된다. |
1853
+ | `color?` | `SGnbColor` | `'light'` | 색상 테마: light / dark |
1854
+ | `items` | `SGnbMenuItem[]` | — | 메뉴 트리 (depth1 → depth2 → depth3). useRail 이면 첫 depth 가 레일이 되고 그 children 이 depth1 이 된다. |
1855
+ | `useRail?` | `boolean` | — | 좌측 레일 사용 여부. 켜면 items 의 첫 depth 가 아이콘+라벨 버튼의 세로 레일로 서고, 선택된 레일 아이템의 children 이 오른쪽 메뉴 패널에 깔린다. 미지정 시 SLayout 의 useRail 을 따른다. children 없는 레일 아이템이 활성이면 메뉴 패널은 렌더되지 않고 레일만 남는다. |
1856
+ | `value?` | `string` | `''` | 현재 선택된 아이템 value |
1857
+ | `folded?` | `boolean` | — | 접힘(레일) 상태. 미지정 시 SLayout 의 folded 를 따른다. |
1858
+ | `logo?` | `ReactNode` | — | 상단바 로고 영역 (slot) |
1859
+ | `railFooter?` | `ReactNode` | — | 레일 하단 고정 슬롯. 레일 아이템이 많아 넘치면 아이템 목록(ul)만 스크롤되고 이 슬롯은 레일 하단에 붙어 고정된다. useRail 일 때만 렌더된다. |
1860
+ | `menuFooter?` | `ReactNode` | — | 메뉴 하단 고정 슬롯. 메뉴 아이템이 많아 넘치면 메뉴 목록(ul)만 스크롤되고 이 슬롯은 메뉴 하단에 붙어 고정된다. 메뉴가 렌더될 때만(showMenu) 나타난다. |
1861
+ | `foldedFooter?` | `ReactNode` | — | 접힘(fix 레일) 하단 고정 슬롯. 접으면 본문이 빠져나가며 rail/menu footer 도 사라지므로, 48px 폴드 레일 바닥에 붙는 별도 슬롯이다. header="fix" 로 접혔을 때만 나타난다. |
1862
+ | `ariaLabel?` | `string` | `'global navigation'` | 메뉴 landmark(nav) 의 접근성 레이블. 한 화면에 nav 가 여럿일 때 구분한다. |
1863
+
1864
+ #### Events
1865
+
1866
+ | Event | Type | Description |
1867
+ |-------|------|-------------|
1868
+ | `onValueChange` | `(value: string) => void` | 선택 변경 (sdUpdate) |
1869
+ | `onRailChange` | `(value: string) => void` | 레일 선택 변경. 레일 아이템을 눌러 패널이 바뀔 때 알린다(선택 상태는 SGnb 가 자체 관리). |
1870
+ | `onFoldChange` | `(folded: boolean) => void` | 접힘 토글 (sdFoldChange) |
1871
+ | `onLauncherClick` | `() => void` | 앱런처(그리드) 버튼 클릭. 미지정 시 런처 버튼을 렌더하지 않는다. 접힘 레일(fix)에는 폴드 버튼만 남으므로 표시되지 않는다. |
1872
+
1873
+ ## Dependencies
1874
+
1875
+ ### Used by
1876
+
1877
+ - [SLayout](../SLayout)
1878
+
1879
+ ### Depends on
1880
+
1881
+ - [SGhostButton](../SGhostButton)
1882
+ - [SIcon](../SIcon)
1883
+ - [SLayout](../SLayout)
1884
+ - [STag](../STag)
1885
+
1886
+ ### Graph
1887
+
1888
+ ---
1889
+
1890
+ # SGuide
1891
+
1892
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1893
+
1894
+ ### SGuide
1895
+
1896
+ #### Props
1897
+
1898
+ | Prop | Type | Default | Description |
1899
+ |------|------|---------|-------------|
1900
+ | `type?` | `SGuideType` | `'tip'` | 가이드 타입 (tip: 팝업, notion: 외부 링크) |
1901
+ | `label?` | `string` | `''` | 버튼 레이블 (없으면 type 기본값) |
1902
+ | `message?` | `SGuideMessage` | `''` | 팝업 메시지 (배열이면 리스트, 중첩 배열이면 depth 표현) |
1903
+ | `url?` | `string` | `''` | notion 타입 클릭 시 이동 URL |
1904
+ | `popupTitle?` | `string` | `''` | 팝업 제목 (없으면 type 기본값) |
1905
+ | `popupWidth?` | `number` | — | 팝업 너비 (px, 기본 426) |
1906
+ | `className?` | `string` | — | |
1907
+ | `style?` | `CSSProperties` | — | |
1908
+
1909
+ ## Dependencies
1910
+
1911
+ ### Depends on
1912
+
1913
+ - [SGhostButton](../SGhostButton)
1914
+ - [SIcon](../SIcon)
1915
+
1916
+ ### Graph
1917
+
1918
+ ---
1919
+
1920
+ # SIcon
1921
+
1922
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1923
+
1924
+ ### SIcon
1925
+
1926
+ #### Props
1927
+
1928
+ | Prop | Type | Default | Description |
1929
+ |------|------|---------|-------------|
1930
+ | `name` | `SIconName` | — | 아이콘명 |
1931
+ | `size?` | `number \| string` | `24` | 아이콘 크기(px 또는 CSS 길이) |
1932
+ | `color?` | `SColor` | — | 아이콘 색상. 팔레트 키(`grey_65`, `red_95` …) 또는 임의 CSS 색상. 미지정 시 currentColor 상속 |
1933
+ | `rotate?` | `0 \| 90 \| 180 \| 270` | — | 회전 각도 |
1934
+ | `label?` | `string` | — | 접근성 라벨. 없으면 aria-hidden 처리 |
1935
+ | `className?` | `string` | — | |
1936
+ | `style?` | `CSSProperties` | — | |
1937
+
1938
+ ## Dependencies
1939
+
1940
+ ### Used by
1941
+
1942
+ - [SButton](../SButton)
1943
+ - [SCallout](../SCallout)
1944
+ - [SCheckbox](../SCheckbox)
1945
+ - [SChipInput](../SChipInput)
1946
+ - [SConfirmModal](../SConfirmModal)
1947
+ - [SDatePicker](../SDatePicker)
1948
+ - [SDateRangePicker](../SDateRangePicker)
1949
+ - [SDraggableItem](../SDraggableItem)
1950
+ - [SDropdownButton](../SDropdownButton)
1951
+ - [SExpansionItem](../SExpansionItem)
1952
+ - [SField](../SField)
1953
+ - [SFilePicker](../SFilePicker)
1954
+ - [SGhostButton](../SGhostButton)
1955
+ - [SGnb](../SGnb)
1956
+ - [SGuide](../SGuide)
1957
+ - [SKeyValueTable](../SKeyValueTable)
1958
+ - [SList](../SList)
1959
+ - [SLoadingModal](../SLoadingModal)
1960
+ - [SNumberInput](../SNumberInput)
1961
+ - [SPagination](../SPagination)
1962
+ - [SPopover](../SPopover)
1963
+ - [SSectionHeaderCard](../SSectionHeaderCard)
1964
+ - [SSelect](../SSelect)
1965
+ - [SStepper](../SStepper)
1966
+ - [STable](../STable)
1967
+ - [STag](../STag)
1968
+ - [STextLink](../STextLink)
1969
+ - [STimePicker](../STimePicker)
1970
+ - [STimeRangePicker](../STimeRangePicker)
1971
+ - [SToast](../SToast)
1972
+ - [STooltip](../STooltip)
1973
+
1974
+ ### Graph
1975
+
1976
+ ---
1977
+
1978
+ # SInput
1979
+
1980
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
1981
+
1982
+ ### SInput
1983
+
1984
+ #### Props
1985
+
1986
+ | Prop | Type | Default | Description |
1987
+ |------|------|---------|-------------|
1988
+ | `value?` | `string \| number` | — | 값 (제어) |
1989
+ | `type?` | `'text' \| 'password' \| 'email' \| 'number' \| 'tel' \| 'search' \| 'url'` | `'text'` | 입력 타입 |
1990
+ | `size?` | `SFieldSize` | `'sm'` | 크기 |
1991
+ | `icon?` | `SIconName` | — | 좌측 아이콘명 |
1992
+ | `iconColor?` | `SColor` | — | 좌측 아이콘 색상 |
1993
+ | `prefix?` | `ReactNode` | — | 입력 앞(좌측) 커스텀 노드 — 원본 slot="prefix" |
1994
+ | `suffix?` | `ReactNode` | — | 입력 뒤(우측) 커스텀 노드 — 원본 slot="suffix" |
1995
+ | `clearable?` | `boolean` | `false` | 지우기 버튼 |
1996
+ | `rules?` | `Rule[]` | — | 유효성 규칙 — blur 시 자동 검증 |
1997
+ | `status?` | `SFieldStatus` | — | 필드 상태 ('default' | 'pass' | 'error') |
1998
+ | `focused?` | `boolean` | — | 포커스 상태 (제어/반영) |
1999
+ | `hovered?` | `boolean` | — | 호버 상태 (제어/반영) |
2000
+ | `inputClass?` | `string` | — | 내부 input 요소 className |
2001
+ | `inputStyle?` | `CSSProperties` | — | 내부 input 요소 style |
2002
+ | `label?` | `string` | — | |
2003
+ | `labelWidth?` | `number \| string` | — | |
2004
+ | `labelTooltip?` | `string` | — | 레이블 툴팁 텍스트 |
2005
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | 레이블 툴팁 상세 옵션 |
2006
+ | `hint?` | `string` | — | |
2007
+ | `error?` | `boolean` | — | |
2008
+ | `errorMessage?` | `string` | — | |
2009
+ | `addonLabel?` | `string` | — | |
2010
+ | `addonAlign?` | `SFieldAddonAlign` | — | 어드온 정렬 |
2011
+ | `width?` | `number \| string` | — | |
2012
+ | `disabled?` | `boolean` | `false` | |
2013
+ | `readOnly?` | `boolean` | `false` | |
2014
+ | `className?` | `string` | — | |
2015
+ | `style?` | `CSSProperties` | — | |
2016
+
2017
+ #### Events
2018
+
2019
+ | Event | Type | Description |
2020
+ |-------|------|-------------|
2021
+ | `onValueChange` | `(value: string) => void` | 값 변경 (sdUpdate) — 문자열 전달 |
2022
+ | `onChange` | `InputHTMLAttributes<HTMLInputElement>['onChange']` | 네이티브 onChange (form-agnostic 연동용, RHF 등) |
2023
+
2024
+ ## Dependencies
2025
+
2026
+ ### Used by
2027
+
2028
+ - [SKeyValueTable](../SKeyValueTable)
2029
+
2030
+ ### Depends on
2031
+
2032
+ - [SField](../SField)
2033
+ - [SGhostButton](../SGhostButton)
2034
+
2035
+ ### Graph
2036
+
2037
+ ---
2038
+
2039
+ # SKeyValueTable
2040
+
2041
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2042
+
2043
+ ### SKeyValueTable
2044
+
2045
+ #### Props
2046
+
2047
+ | Prop | Type | Default | Description |
2048
+ |------|------|---------|-------------|
2049
+ | `fields?` | `SKeyValueField[][]` | `[]` | 2차원 배열. row → [th|td] 필드들 |
2050
+ | `values?` | `Record<string, unknown>` | `{}` | field name을 key로 하는 값 객체 (`{ [name]: value }`). 지정 시 해당 field의 값으로 사용되며, field별 `options.value`보다 우선합니다. `onChange`의 `detail.values`와 함께 controlled 패턴으로 사용합니다. |
2051
+ | `search?` | `boolean` | `false` | 우측 검색 패널 |
2052
+ | `radius?` | `'default' \| 'useTop' \| 'full'` | `'default'` | border-radius 제어 |
2053
+ | `className?` | `string` | — | |
2054
+ | `style?` | `CSSProperties` | — | |
2055
+
2056
+ #### Events
2057
+
2058
+ | Event | Type | Description |
2059
+ |-------|------|-------------|
2060
+ | `onChange` | `(detail: SKeyValueChangeDetail) => void` | 값 변경 (sdChange) |
2061
+ | `onSearch` | `() => void` | 검색 클릭 (sdSearch) |
2062
+
2063
+ ## Dependencies
2064
+
2065
+ ### Depends on
2066
+
2067
+ - [SButton](../SButton)
2068
+ - [SCheckbox](../SCheckbox)
2069
+ - [SDatePicker](../SDatePicker)
2070
+ - [SDateRangePicker](../SDateRangePicker)
2071
+ - [SFilePicker](../SFilePicker)
2072
+ - [SIcon](../SIcon)
2073
+ - [SInput](../SInput)
2074
+ - [SNumberInput](../SNumberInput)
2075
+ - [SRadio](../SRadio)
2076
+ - [SSelect](../SSelect)
2077
+ - [STextarea](../STextarea)
2078
+ - [STooltip](../STooltip)
2079
+
2080
+ ### Graph
2081
+
2082
+ ---
2083
+
2084
+ # SLayout
2085
+
2086
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2087
+
2088
+ ### SLayout
2089
+
2090
+ #### Props
2091
+
2092
+ | Prop | Type | Default | Description |
2093
+ |------|------|---------|-------------|
2094
+ | `type?` | `SLayoutType` | `'box'` | 메뉴 스타일: box(라운드) / belt(풀폭 행). 자식 SGnb 가 이 값을 따른다. |
2095
+ | `header?` | `SLayoutHeader` | `'fix'` | 레이아웃 구조: fix(가로 분할) / full(풀폭 상단바). 자식 SGnb·SPage 가 이 값을 따른다. |
2096
+ | `useRail?` | `boolean` | `false` | GNB 좌측 레일 사용 여부. 자식 SGnb 가 이 값을 따르고, full 의 메뉴 열 폭도 레일만큼 넓어진다. 레일에 children 없는 아이템이 있으면 SGnb 가 header 를 full 로 강제하고, 이 레이아웃도 그에 맞춰 full 그리드로 선다. |
2097
+ | `folded?` | `boolean` | — | GNB 접힘 상태 (controlled) |
2098
+ | `defaultFolded?` | `boolean` | `false` | GNB 초기 접힘 상태 (uncontrolled) |
2099
+
2100
+ #### Events
2101
+
2102
+ | Event | Type | Description |
2103
+ |-------|------|-------------|
2104
+ | `onFoldedChange` | `(folded: boolean) => void` | 접힘 상태 변경 |
2105
+
2106
+ ## Dependencies
2107
+
2108
+ ### Used by
2109
+
2110
+ - [SGnb](../SGnb)
2111
+ - [SPage](../SPage)
2112
+
2113
+ ### Depends on
2114
+
2115
+ - [SGnb](../SGnb)
2116
+
2117
+ ### Graph
2118
+
2119
+ ---
2120
+
2121
+ # SLinearProgress
2122
+
2123
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2124
+
2125
+ ### SLinearProgress
2126
+
2127
+ #### Props
2128
+
2129
+ | Prop | Type | Default | Description |
2130
+ |------|------|---------|-------------|
2131
+ | `value?` | `number` | `0` | 진행률 (0–100) |
2132
+ | `type?` | `SLinearProgressType` | `'primary'` | 색상 타입 |
2133
+ | `indeterminate?` | `boolean` | `false` | 진행률 없이 무한 애니메이션 |
2134
+ | `label?` | `string` | — | 하단 레이블 |
2135
+ | `className?` | `string` | — | |
2136
+ | `style?` | `CSSProperties` | — | |
2137
+
2138
+ ---
2139
+
2140
+ # SList
2141
+
2142
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2143
+
2144
+ ### SList
2145
+
2146
+ #### Props
2147
+
2148
+ | Prop | Type | Default | Description |
2149
+ |------|------|---------|-------------|
2150
+ | `children?` | `ReactNode` | — | 리스트 컨테이너 내부에 렌더링할 내용 |
2151
+ | `useGap?` | `boolean` | `false` | 리스트 아이템 사이 gap 토큰 적용 여부 |
2152
+ | `usePadding?` | `boolean` | `false` | 리스트 컨테이너 padding 토큰 적용 여부 |
2153
+
2154
+ ---
2155
+
2156
+ # SListItem
2157
+
2158
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2159
+
2160
+ ### SListItem
2161
+
2162
+ #### Props
2163
+
2164
+ | Prop | Type | Default | Description |
2165
+ |------|------|---------|-------------|
2166
+ | `title` | `SListItemSlot` | — | 리스트 아이템 제목 |
2167
+ | `depth?` | `1 \| 2 \| 3` | `1` | 중첩 단계. Figma 기준 1~3단계 |
2168
+ | `leading?` | `SListItemSlot` | — | 타이틀 앞에 표시할 아이콘/콘텐츠 |
2169
+ | `trailing?` | `SListItemSlot` | — | 타이틀 뒤에 표시할 태그/콘텐츠 |
2170
+ | `bordered?` | `boolean` | `false` | 외곽 테두리 사용 여부 |
2171
+ | `accentStripe?` | `boolean` | `false` | 아이템 왼쪽 accent stripe 표시 여부 |
2172
+ | `dense?` | `boolean` | `false` | 조밀한 높이 사용 여부 |
2173
+ | `disabled?` | `boolean` | `false` | 비활성 상태 여부 |
2174
+
2175
+ ---
2176
+
2177
+ # SLoadingContainer
2178
+
2179
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2180
+
2181
+ ### SLoadingContainer
2182
+
2183
+ #### Props
2184
+
2185
+ | Prop | Type | Default | Description |
2186
+ |------|------|---------|-------------|
2187
+ | `open?` | `boolean` | `false` | 오버레이 표시 여부 (Stencil의 show()/hide() 명령형 API → 제어 prop으로 대체) |
2188
+ | `message?` | `string` | — | 스피너 하단 메시지 |
2189
+ | `zIndex?` | `number` | `1200` | z-index. 기본값(1200)은 토스트(1100)·모달(1000/1001) 위 — 전체 화면을 막는 최상단 블로킹 오버레이 |
2190
+ | `className?` | `string` | — | |
2191
+ | `style?` | `CSSProperties` | — | |
2192
+
2193
+ ## Dependencies
2194
+
2195
+ ### Depends on
2196
+
2197
+ - [SCircleProgress](../SCircleProgress)
2198
+
2199
+ ### Graph
2200
+
2201
+ ---
2202
+
2203
+ # SLoadingModal
2204
+
2205
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2206
+
2207
+ ### SLoadingModal
2208
+
2209
+ #### Props
2210
+
2211
+ | Prop | Type | Default | Description |
2212
+ |------|------|---------|-------------|
2213
+ | `open?` | `boolean` | — | |
2214
+ | `persistent?` | `boolean` | — | true면 백드롭·ESC로 안 닫히고 흔들림 (sd-modal-container persistent). 로딩 중 닫힘 방지에 유용 |
2215
+ | `state?` | `LoadingModalState` | `'loading'` | 상태 (loading: 스피너, error: 경고 아이콘) |
2216
+ | `progress?` | `number` | — | 진행률 (0–100) — 지정 시 determinate 스피너 |
2217
+ | `message?` | `string \| string[]` | — | 메시지 (없으면 state 기본값) |
2218
+ | `useButton?` | `boolean` | `false` | 하단 버튼 표시 |
2219
+ | `buttonLabel?` | `string` | — | 버튼 레이블 (없으면 state 기본값) |
2220
+ | `width?` | `number \| string` | `520` | |
2221
+ | `height?` | `number \| string` | `320` | |
2222
+
2223
+ #### Events
2224
+
2225
+ | Event | Type | Description |
2226
+ |-------|------|-------------|
2227
+ | `onOpenChange` | `(open: boolean) => void` | |
2228
+ | `onClose` | `() => void` | 닫기(X) 버튼 클릭 (sdClose) — error 상태에서만 노출 |
2229
+ | `onButtonClick` | `() => void` | 버튼 클릭 (sdClick) |
2230
+
2231
+ ## Dependencies
2232
+
2233
+ ### Used by
2234
+
2235
+ - [SModal](../SModal)
2236
+
2237
+ ### Depends on
2238
+
2239
+ - [SButton](../SButton)
2240
+ - [SCircleProgress](../SCircleProgress)
2241
+ - [SIcon](../SIcon)
2242
+ - [SModalContainer](../SModalContainer)
2243
+
2244
+ ### Graph
2245
+
2246
+ ---
2247
+
2248
+ # SModal
2249
+
2250
+ > 수작성 문서 — SModal 은 컴포넌트가 아니라 **명령형 모달 서비스**라 `docs:gen`(Props/Events 표) 대상이 아니다.
2251
+
2252
+ 버튼 핸들러에서 바로 호출해 모달을 띄우는 명령형 API. 선언형 `<SConfirmModal open>` / `<SLoadingModal open>` 을 **대체하지 않고 추가로** 제공한다. (원본 디자인 시스템 `sdModal` 파리티)
2253
+
2254
+ 호출 시마다 `document.body` 에 컨테이너를 만들어 모달을 렌더하고, 닫힘 애니메이션이 끝나면 자동으로 언마운트한다. 모든 메서드는 체이닝 핸들 [`SModalRef`](#smodalref) 를 반환한다.
2255
+
2256
+ | 메서드 | 띄우는 모달 | 용도 | 주요 콜백/제어 |
2257
+ |---|---|---|---|
2258
+ | [`SModal.confirm(options)`](#smodalconfirm) | `SConfirmModal` | 확인/취소 | `onOk` / `onCancel` / `onClose` |
2259
+ | [`SModal.loading(options?)`](#smodalloading) | `SLoadingModal` | 로딩·에러 (persistent 기본 true) | `onClick` / `update` |
2260
+ | [`SModal.create({ component })`](#smodalcreate) | `SActionModal` | 액션 모달 | `modalRef` 주입 → `ok/cancel/close/submit` |
2261
+
2262
+ > **띄울 수 있는 모달은 `SActionModal` / `SConfirmModal` / `SLoadingModal` 세 가지뿐이고, 위 메서드가 1:1 로 대응한다.** 그 밖의 스타일로 모달을 띄우는 경로는 제공하지 않는다. `create` 는 컨테이너를 덧씌우지 않고 `component` 를 **그대로** 렌더하므로, `component` 는 루트에 `SActionModal` 을 렌더해야 한다 — 그러지 않으면 딤·카드 없이 콘텐츠만 뜨며, 개발 모드에서 `console.warn` 으로 경고한다.
2263
+
2264
+ ```ts
2265
+ import { SModal } from 'sellmate-design-system-react';
2266
+ ```
2267
+
2268
+ ---
2269
+
2270
+ ## SModal.confirm
2271
+
2272
+ 아이콘 + 제목 + 메시지 + 확인/취소 버튼. `type` 에 따라 아이콘·메인 버튼 색이 결정된다.
2273
+
2274
+ ```tsx
2275
+ SModal.confirm({
2276
+ type: 'negative', // 'positive' | 'negative' | 'default'
2277
+ modalTitle: '삭제하시겠습니까?',
2278
+ topMessage: ['이 작업은 되돌릴 수 없습니다.'],
2279
+ mainButtonLabel: '삭제',
2280
+ subButtonLabel: '취소',
2281
+ })
2282
+ .onOk(() => deleteItem())
2283
+ .onCancel(() => {});
2284
+ ```
2285
+
2286
+ **옵션 (`SConfirmOptions`)** — 선언형 `SConfirmModalProps` 에서 제어 흐름 props(`open`/`onOpenChange`/`onOk`/`onCancel`/`onClose`)를 제외한 전부. 주요 키: `type`, `modalTitle`, `topMessage`/`bottomMessage`, `mainButtonLabel`/`mainButtonName`, `subButtonLabel`, `tagSlot`/`optionSlot`, `persistent`.
2287
+
2288
+ ---
2289
+
2290
+ ## SModal.loading
2291
+
2292
+ 스피너/에러 모달. 로딩 중 임의 닫힘을 막기 위해 **`persistent` 기본값이 `true`** 다(백드롭·ESC로 안 닫힘). "띄우고 → 작업 → 결과 반영" 흐름을 `update()` / `close()` 로 제어한다.
2293
+
2294
+ ```tsx
2295
+ const ref = SModal.loading({ message: '업로드 중...' });
2296
+ try {
2297
+ await upload();
2298
+ ref.close();
2299
+ } catch {
2300
+ ref.update({ state: 'error', message: '업로드 실패' }) // 표시 중 상태 갱신
2301
+ .onClick(() => retry()); // 「다시 시도」 버튼
2302
+ }
2303
+ ```
2304
+
2305
+ 진행률:
2306
+
2307
+ ```tsx
2308
+ const ref = SModal.loading({ progress: 0, message: '파일 업로드 중...' });
2309
+ ref.update({ progress: 60 }); // 0–100
2310
+ ref.update({ progress: 100 });
2311
+ ref.close();
2312
+ ```
2313
+
2314
+ > **버튼 클릭은 자동 닫힘이 아니다.** error 상태의 버튼(기본 "다시 시도")은 `onClick` 만 발화하고 모달은 유지된다. consumer 가 `update()`(다시 로딩) / `close()` 로 후속 동작을 결정한다.
2315
+
2316
+ **옵션 (`SLoadingOptions`)** — `state`('loading' | 'error'), `progress`(0–100), `message`(string | string[]), `useButton`, `buttonLabel`, `width`/`height`, `persistent`.
2317
+
2318
+ ---
2319
+
2320
+ ## SModal.create
2321
+
2322
+ **`SActionModal` 을 루트로 렌더하는 컴포넌트**를 띄운다. `create` 는 컨테이너를 덧씌우지 않고 `component` 를 **그대로** 렌더하며, 표시 제어(`open` / `onOpenChange` / `onClose`)와 [`modalRef`](#smodalref) 를 주입하고 닫힘 애니메이션 종료 후 언마운트를 담당한다.
2323
+
2324
+ 컴포넌트는 주입받은 `open` / `onOpenChange` / `onClose` 를 **SActionModal 에 그대로 전달**해야 한다. 전달하지 않으면 모달이 열리지도, 닫히지도 않는다.
2325
+
2326
+ ```tsx
2327
+ import { SModal, SActionModal, type SModalCreateComponentProps } from 'sellmate-design-system-react';
2328
+
2329
+ // componentProps 로 넘긴 값 + 주입 prop 을 함께 받는다
2330
+ interface OrderModalProps extends SModalCreateComponentProps {
2331
+ orderId: string;
2332
+ }
2333
+
2334
+ function OrderModal({ open, onOpenChange, onClose, modalRef, orderId }: OrderModalProps) {
2335
+ return (
2336
+ <SActionModal
2337
+ open={open}
2338
+ onOpenChange={onOpenChange}
2339
+ onClose={onClose}
2340
+ modalTitle="주문 처리"
2341
+ button={{ label: '처리', onClick: () => modalRef.ok() }}
2342
+ >
2343
+ <p>주문번호 {orderId} 를 접수합니다.</p>
2344
+ </SActionModal>
2345
+ );
2346
+ }
2347
+
2348
+ SModal.create({ component: OrderModal, componentProps: { orderId: 'ORD-001' } })
2349
+ .onOk(() => toast('저장 완료'))
2350
+ .onDismissed(() => cleanup());
2351
+ ```
2352
+
2353
+ **옵션 (`SCreateOptions<P>`)**
2354
+
2355
+ | 키 | 타입 | 설명 |
2356
+ |---|---|---|
2357
+ | `component` | `ComponentType<P & SModalCreateComponentProps>` | 루트에 `SActionModal` 을 렌더하는 컴포넌트 |
2358
+ | `componentProps?` | `P` | 컴포넌트에 전달할 추가 props |
2359
+
2360
+ **주입되는 prop (`SModalCreateComponentProps`)**
2361
+
2362
+ | 키 | 타입 | 설명 |
2363
+ |---|---|---|
2364
+ | `open` | `boolean` | SActionModal 의 `open` 에 그대로 전달 |
2365
+ | `onOpenChange` | `(open: boolean) => void` | SActionModal 의 `onOpenChange` 에 그대로 전달 |
2366
+ | `onClose` | `() => void` | SActionModal 의 `onClose` 에 그대로 전달 |
2367
+ | `modalRef` | `SModalRef` | `ok()`/`cancel()`/`close()`/`submit()` 으로 자기 모달 제어 |
2368
+
2369
+ ### 비동기 제출 — 응답 보고 닫기
2370
+
2371
+ SActionModal `button` 의 푸터 버튼은 클릭 시 **즉시 닫힌다**. 저장 API 응답에 따라 닫힘 여부를 정해야 하면 푸터 버튼 대신 **본문에 버튼을 두고** `modalRef` 로 닫힘 시점을 직접 제어한다.
2372
+
2373
+ ```tsx
2374
+ function OrderModal({ open, onOpenChange, onClose, modalRef, orderId }: OrderModalProps) {
2375
+ const [error, setError] = useState('');
2376
+ const handleSubmit = async () => {
2377
+ try {
2378
+ await save(orderId);
2379
+ modalRef.ok(); // 성공 → onOk + 닫기
2380
+ } catch {
2381
+ setError('저장 실패'); // 실패 → 모달 유지
2382
+ }
2383
+ };
2384
+ return (
2385
+ // button 을 주지 않으면 푸터가 렌더되지 않는다
2386
+ <SActionModal open={open} onOpenChange={onOpenChange} onClose={onClose} persistent modalTitle="주문 처리">
2387
+ {error && <p>{error}</p>}
2388
+ <SButton label="저장" onClick={handleSubmit} />
2389
+ <SButton label="취소" onClick={() => modalRef.cancel()} />
2390
+ </SActionModal>
2391
+ );
2392
+ }
2393
+ ```
2394
+
2395
+ ---
2396
+
2397
+ ## SModalRef
2398
+
2399
+ 모든 `SModal.*` 호출이 반환하고, `create` 에서는 컴포넌트 prop 으로도 주입되는 제어 핸들. 콜백 등록(체이닝)과 트리거/갱신 메서드를 함께 제공한다. 모달 종류에 따라 관련 있는 메서드만 실제로 발화한다.
2400
+
2401
+ ### 콜백 등록 (체이닝)
2402
+
2403
+ | 메서드 | 발화 시점 |
2404
+ |---|---|
2405
+ | `onOk(fn)` | 확인 버튼(confirm) 또는 `ok()` |
2406
+ | `onCancel(fn)` | 취소 버튼(confirm) 또는 `cancel()` |
2407
+ | `onClose(fn)` | 닫기(X) 버튼 또는 `close()` |
2408
+ | `onClick(fn)` | 단일 버튼 모달(loading error)의 버튼 클릭 — **닫힘 없음** |
2409
+ | `onSubmit(fn)` | create 커스텀 모달의 `submit()` — **닫힘 없음** |
2410
+ | `onDismissed(fn)` | 사유 무관 완전히 닫혀 언마운트된 뒤(백드롭·ESC 포함) |
2411
+
2412
+ ### 트리거 / 제어
2413
+
2414
+ | 메서드 | 동작 |
2415
+ |---|---|
2416
+ | `ok()` | `onOk` 발화 + 닫기 (저장/처리 성공) |
2417
+ | `cancel()` | `onCancel` 발화 + 닫기 (작업 취소) |
2418
+ | `close()` | `onClose` 발화 + 닫기 (중립적 닫기) |
2419
+ | `submit()` | `onSubmit` 발화 (닫힘 없음) |
2420
+ | `update(patch)` | 표시 중 옵션 갱신 (loading→error, progress 등). create 는 미지원. |
2421
+
2422
+ 모든 닫힘은 애니메이션 종료 후 `onDismissed` 로 수렴한다. 이미 닫힘이 시작된 뒤의 중복 트리거는 무시된다.
2423
+
2424
+ ---
2425
+
2426
+ ## 주의사항
2427
+
2428
+ - **선언형과 공존**: 서비스는 추가 API다. open 상태가 앱 상태/라우트에 묶인 경우엔 선언형 `<SConfirmModal open>` / `<SLoadingModal open>` 이 더 적합하다.
2429
+ - **백드롭·ESC = 중립적 닫힘**: 특정 콜백(onClose 등) 없이 `onDismissed` 만 발화한다. 명시적 버튼·메서드만 onOk/onCancel/onClose 를 발화한다.
2430
+ - **Context 미상속**: `create` 의 커스텀 컴포넌트는 새 React 트리(createRoot)에서 렌더되어 부모의 Context Provider(Theme·Store 등)를 상속하지 않는다. 필요하면 컴포넌트 내부에서 직접 Provider 로 감싸라. (confirm/loading 은 토큰이 `:root` CSS 변수라 무관)
2431
+ - **`create` 의 `component` 는 SActionModal 을 루트로**: `create` 는 컨테이너를 덧씌우지 않으므로, 본문만 렌더하는 컴포넌트를 넘기면 딤·카드 없이 콘텐츠가 그대로 화면에 붙는다. TypeScript 는 이를 막지 못한다(`component` 타입이 아무 컴포넌트나 허용). 개발 모드에서는 마운트 직후 렌더 결과로 이를 감지해 `console.warn` 으로 경고한다 — 세 모달은 모두 Portal 로 `body` 에 렌더되므로 `create` 가 만든 host 는 비어 있어야 하는데, host 에 엘리먼트가 남아 있으면 모달이 아닌 것으로 판정한다.
2432
+
2433
+ ## Dependencies
2434
+
2435
+ ### Depends on
2436
+
2437
+ - [SActionModal](../SActionModal)
2438
+ - [SConfirmModal](../SConfirmModal)
2439
+ - [SLoadingModal](../SLoadingModal)
2440
+
2441
+ ---
2442
+
2443
+ # SModalContainer
2444
+
2445
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2446
+
2447
+ ### SModalContainer
2448
+
2449
+ #### Props
2450
+
2451
+ | Prop | Type | Default | Description |
2452
+ |------|------|---------|-------------|
2453
+ | `open?` | `boolean` | — | 표시 여부 (제어) |
2454
+ | `ariaTitle?` | `string` | `'모달'` | 접근성 제목 (스크린리더용). 시각 제목은 children이 담당 |
2455
+ | `showClose?` | `boolean` | `false` | 우측 상단 닫기 버튼 |
2456
+ | `persistent?` | `boolean` | `false` | true면 백드롭 클릭·ESC로 닫히지 않고 흔들림(shake) 애니메이션 (sd-modal-container persistent) |
2457
+ | `width?` | `number \| string` | — | 너비/높이 |
2458
+ | `height?` | `number \| string` | — | |
2459
+ | `children?` | `ReactNode` | — | |
2460
+ | `className?` | `string` | — | |
2461
+ | `style?` | `CSSProperties` | — | |
2462
+
2463
+ #### Events
2464
+
2465
+ | Event | Type | Description |
2466
+ |-------|------|-------------|
2467
+ | `onOpenChange` | `(open: boolean) => void` | 표시 상태 변경 |
2468
+ | `onClose` | `() => void` | 닫기(X) 버튼 클릭 시 발생 (sd-modal-container 닫기 버튼 대응) |
2469
+
2470
+ ## Dependencies
2471
+
2472
+ ### Used by
2473
+
2474
+ - [SActionModal](../SActionModal)
2475
+ - [SConfirmModal](../SConfirmModal)
2476
+ - [SLoadingModal](../SLoadingModal)
2477
+
2478
+ ### Depends on
2479
+
2480
+ - [SGhostButton](../SGhostButton)
2481
+
2482
+ ### Graph
2483
+
2484
+ ---
2485
+
2486
+ # SNumberInput
2487
+
2488
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2489
+
2490
+ ### SNumberInput
2491
+
2492
+ #### Props
2493
+
2494
+ | Prop | Type | Default | Description |
2495
+ |------|------|---------|-------------|
2496
+ | `value?` | `string \| number \| null` | — | 입력 값 |
2497
+ | `size?` | `SNumberInputSize` | `'sm'` | 크기 |
2498
+ | `min?` | `number` | `Number.NEGATIVE_INFINITY` | 최솟값 |
2499
+ | `max?` | `number` | `Number.POSITIVE_INFINITY` | 최댓값 |
2500
+ | `step?` | `number` | `1` | 스텝 단위 |
2501
+ | `useButton?` | `boolean` | `false` | 증감 버튼 표시 |
2502
+ | `useDecimal?` | `boolean` | `false` | 소수점 입력 허용 |
2503
+ | `maxDecimalLength?` | `number` | — | 소수점 이하 최대 자리수 |
2504
+ | `inputPrefix?` | `string` | `''` | 입력 앞 접두 텍스트 |
2505
+ | `inputSuffix?` | `string` | `''` | 입력 뒤 접미 텍스트 |
2506
+ | `inputClass?` | `string` | — | 네이티브 input className |
2507
+ | `inputStyle?` | `CSSProperties` | — | 네이티브 input style |
2508
+ | `autoFocus?` | `boolean` | — | 마운트 시 자동 포커스 |
2509
+ | `name?` | `string` | — | 폼 연동 name |
2510
+ | `placeholder?` | `string` | `'입력해 주세요.'` | |
2511
+ | `disabled?` | `boolean` | `false` | |
2512
+ | `readOnly?` | `boolean` | `false` | |
2513
+ | `rules?` | `Rule[]` | — | 유효성 규칙 — blur 시 검증 |
2514
+ | `status?` | `SFieldStatus` | — | |
2515
+ | `focused?` | `boolean` | — | |
2516
+ | `hovered?` | `boolean` | — | |
2517
+ | `label?` | `string` | — | |
2518
+ | `labelWidth?` | `number \| string` | — | |
2519
+ | `icon?` | `SIconName` | — | |
2520
+ | `iconColor?` | `SColor` | — | |
2521
+ | `labelTooltip?` | `string` | — | |
2522
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
2523
+ | `addonLabel?` | `string` | — | |
2524
+ | `addonAlign?` | `SFieldAddonAlign` | — | |
2525
+ | `hint?` | `string` | — | |
2526
+ | `error?` | `boolean` | — | |
2527
+ | `errorMessage?` | `string` | — | |
2528
+ | `width?` | `number \| string` | — | |
2529
+ | `className?` | `string` | — | |
2530
+ | `style?` | `CSSProperties` | — | |
2531
+
2532
+ #### Events
2533
+
2534
+ | Event | Type | Description |
2535
+ |-------|------|-------------|
2536
+ | `onValueChange` | `(value: number \| null) => void` | 값 변경 (sdUpdate) — number|null 전달 |
2537
+ | `onFocus` | `(e: React.FocusEvent<HTMLInputElement>) => void` | 포커스 이벤트 (sdFocus) |
2538
+ | `onBlur` | `(e: React.FocusEvent<HTMLInputElement>) => void` | 블러 이벤트 (sdBlur) |
2539
+
2540
+ ## Dependencies
2541
+
2542
+ ### Used by
2543
+
2544
+ - [SKeyValueTable](../SKeyValueTable)
2545
+
2546
+ ### Depends on
2547
+
2548
+ - [SField](../SField)
2549
+ - [SIcon](../SIcon)
2550
+
2551
+ ### Graph
2552
+
2553
+ ---
2554
+
2555
+ # SPage
2556
+
2557
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2558
+
2559
+ ### SPage
2560
+
2561
+ #### Props
2562
+
2563
+ | Prop | Type | Default | Description |
2564
+ |------|------|---------|-------------|
2565
+ | `background?` | `SPageBackground` | `'frame'` | 페이지 배경 표면. frame=흰 콘텐츠 면, neutral=옅은 회색 면, screen=앱 바탕. 스크롤바 처리도 여기 묶여 있다 — 셋 다 구분선+트랙 배경이고, 트랙 색만 neutral 에서 흰색이 된다. |
2566
+
2567
+ ## Dependencies
2568
+
2569
+ ### Depends on
2570
+
2571
+ - [SLayout](../SLayout)
2572
+
2573
+ ### Graph
2574
+
2575
+ ---
2576
+
2577
+ # SPagination
2578
+
2579
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2580
+
2581
+ ### SPagination
2582
+
2583
+ #### Props
2584
+
2585
+ | Prop | Type | Default | Description |
2586
+ |------|------|---------|-------------|
2587
+ | `currentPage?` | `number` | `1` | 현재 페이지 |
2588
+ | `lastPage?` | `number` | `1` | 마지막 페이지 |
2589
+ | `simple?` | `boolean` | `false` | 단순 모드 (현재/마지막만 표시) |
2590
+ | `className?` | `string` | — | |
2591
+ | `style?` | `CSSProperties` | — | |
2592
+
2593
+ #### Events
2594
+
2595
+ | Event | Type | Description |
2596
+ |-------|------|-------------|
2597
+ | `onPageChange` | `(page: number) => void` | 페이지 변경 (sdPageChange) |
2598
+
2599
+ ## Dependencies
2600
+
2601
+ ### Used by
2602
+
2603
+ - [STable](../STable)
2604
+
2605
+ ### Depends on
2606
+
2607
+ - [SIcon](../SIcon)
2608
+
2609
+ ### Graph
2610
+
2611
+ ---
2612
+
2613
+ # SPopover
2614
+
2615
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2616
+
2617
+ ### SPopover
2618
+
2619
+ #### Props
2620
+
2621
+ | Prop | Type | Default | Description |
2622
+ |------|------|---------|-------------|
2623
+ | `open?` | `boolean` | — | 표시 여부 (제어). onOpenChange 와 함께 사용 |
2624
+ | `defaultOpen?` | `boolean` | — | 기본 표시 여부 (비제어) |
2625
+ | `placement?` | `SPopoverPlacement` | `'bottom'` | 표시 방향 |
2626
+ | `type?` | `SPopoverType` | `'default'` | 색상 타입 (default: 다크 / danger·warning·accent: 라이트 배경) |
2627
+ | `menuTitle` | `string` | — | 메뉴 제목 (필수) |
2628
+ | `titleIcon?` | `SIconName` | — | 제목 좌측 아이콘 (선택) |
2629
+ | `children?` | `ReactNode` | — | 본문 내용 |
2630
+ | `trigger?` | `ReactNode` | — | 커스텀 트리거. 없으면 아이콘 트리거 렌더 |
2631
+ | `icon?` | `SIconName` | `'helpOutline'` | 기본(아이콘) 트리거 설정 |
2632
+ | `iconSize?` | `number` | `12` | |
2633
+ | `color?` | `SColor` | `'#01BB4B'` | 트리거 아이콘 색상. 팔레트 키(`grey_65`, `red_95` …) 또는 임의 CSS 색상 |
2634
+ | `leftLinkLabel?` | `string` | — | 하단 좌측 링크 레이블 (선택). 스타일은 chevron 링크로 고정 |
2635
+ | `buttonLabel` | `string` | — | 하단 우측 버튼 레이블 (필수). 색상/스타일은 type 별로 고정 |
2636
+ | `ariaLabel?` | `string` | — | |
2637
+ | `menuClassName?` | `string` | — | |
2638
+ | `style?` | `CSSProperties` | — | |
2639
+
2640
+ #### Events
2641
+
2642
+ | Event | Type | Description |
2643
+ |-------|------|-------------|
2644
+ | `onOpenChange` | `(open: boolean) => void` | 표시 상태 변경 (sdShowChange) |
2645
+ | `onLeftLinkClick` | `() => void` | 하단 좌측 링크 클릭 |
2646
+ | `onButtonClick` | `() => void` | 하단 우측 버튼 클릭 |
2647
+
2648
+ ## Dependencies
2649
+
2650
+ ### Depends on
2651
+
2652
+ - [SButton](../SButton)
2653
+ - [SGhostButton](../SGhostButton)
2654
+ - [SIcon](../SIcon)
2655
+ - [STextLink](../STextLink)
2656
+
2657
+ ### Graph
2658
+
2659
+ ---
2660
+
2661
+ # SPopup
2662
+
2663
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2664
+
2665
+ ### SPopup
2666
+
2667
+ #### Props
2668
+
2669
+ | Prop | Type | Default | Description |
2670
+ |------|------|---------|-------------|
2671
+ | `popupTitle?` | `string` | `''` | 헤더 제목 |
2672
+ | `type?` | `SPopupType` | `'default'` | 타입 (헤더 색상) |
2673
+ | `useFooter?` | `boolean` | `true` | 하단 footer 표시 여부 |
2674
+ | `submitButton?` | `SPopupSubmitButton` | — | 확인 버튼 설정 |
2675
+ | `footerLeft?` | `ReactNode` | — | footer 좌측 영역 |
2676
+ | `children?` | `ReactNode` | — | 본문 |
2677
+ | `className?` | `string` | — | |
2678
+ | `style?` | `CSSProperties` | — | |
2679
+
2680
+ #### Events
2681
+
2682
+ | Event | Type | Description |
2683
+ |-------|------|-------------|
2684
+ | `onSubmit` | `() => void` | 확인 버튼 클릭 (sdSubmit) |
2685
+
2686
+ ## Dependencies
2687
+
2688
+ ### Depends on
2689
+
2690
+ - [SButton](../SButton)
2691
+
2692
+ ### Graph
2693
+
2694
+ ---
2695
+
2696
+ # SPortal
2697
+
2698
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2699
+
2700
+ ### SPortal
2701
+
2702
+ #### Props
2703
+
2704
+ | Prop | Type | Default | Description |
2705
+ |------|------|---------|-------------|
2706
+ | `open` | `boolean` | — | 표시 여부 (제어). onClose 와 함께 사용한다. |
2707
+ | `anchorRef` | `RefObject<HTMLElement \| null>` | — | 위치 기준이 되는 앵커 엘리먼트 ref (sd-portal `parentRef` 대응). 트리거 버튼 등에 그대로 걸면 그 엘리먼트에 붙어서 뜬다. |
2708
+ | `placement?` | `SPortalPlacement` | `'bottom'` | 표시 방향 (공간이 부족하면 자동으로 반대 방향으로 전환). |
2709
+ | `align?` | `SPortalAlign` | `'start'` | 교차축 정렬 (start·center·end). |
2710
+ | `offset?` | `number` | `4` | 앵커로부터의 간격 px (sd-portal offset[1]). |
2711
+ | `alignOffset?` | `number` | `0` | 정렬축 오프셋 px (sd-portal offset[0]). |
2712
+ | `fit?` | `boolean` | `false` | 앵커 너비에 맞춰 최소 너비를 잡는다. |
2713
+ | `maxHeight?` | `number` | — | 콘텐츠 최대 높이 px. 넘치면 세로 스크롤. |
2714
+ | `autoClose?` | `boolean` | `false` | 콘텐츠 내부를 클릭하면 자동으로 닫는다. |
2715
+ | `persistent?` | `boolean` | `false` | 외부 클릭 · ESC 로 닫히지 않게 한다. |
2716
+ | `viewportPadding?` | `number` | `0` | 뷰포트 경계 여백 px (충돌 회피 패딩). |
2717
+ | `children?` | `ReactNode` | — | 본문 내용 (콘텐츠 자유). |
2718
+ | `className?` | `string` | — | |
2719
+ | `style?` | `CSSProperties` | — | |
2720
+ | `ariaLabel?` | `string` | — | |
2721
+
2722
+ #### Events
2723
+
2724
+ | Event | Type | Description |
2725
+ |-------|------|-------------|
2726
+ | `onClose` | `() => void` | 외부 클릭 · ESC 등으로 닫힘이 요청될 때 (sd-portal `sdClose` 대응). |
2727
+ | `onOpenChange` | `(open: boolean) => void` | 열림/닫힘 변경 전체 콜백 (선택). |
2728
+ | `onOpenAutoFocus` | `(event: Event) => void` | 열릴 때 포커스 이동 처리 (기본은 Radix가 콘텐츠로 포커스를 옮김). e.preventDefault()로 막을 수 있다. |
2729
+ | `onCloseAutoFocus` | `(event: Event) => void` | 닫힐 때 포커스 복귀 처리 (기본은 Radix가 앵커로 포커스를 되돌림). e.preventDefault()로 막을 수 있다. |
2730
+ | `onPointerDownOutside` | `(event: Event) => void` | 바깥 영역 pointerdown 으로 닫힘이 시작될 때 (앵커 위 클릭·persistent 는 제외). |
2731
+
2732
+ ## Dependencies
2733
+
2734
+ ### Used by
2735
+
2736
+ - [SChipInput](../SChipInput)
2737
+ - [SSelect](../SSelect)
2738
+
2739
+ ### Graph
2740
+
2741
+ ---
2742
+
2743
+ # SRadio
2744
+
2745
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2746
+
2747
+ ### SRadioGroup
2748
+
2749
+ #### Props
2750
+
2751
+ | Prop | Type | Default | Description |
2752
+ |------|------|---------|-------------|
2753
+ | `options?` | `SRadioOption[]` | `[]` | 옵션 목록 |
2754
+ | `value?` | `SRadioValue \| null` | — | 현재 선택 값 |
2755
+ | `direction?` | `'vertical' \| 'horizontal'` | `'vertical'` | 배치 방향 |
2756
+ | `disabled?` | `boolean` | `false` | 전체 비활성 |
2757
+ | `groupName?` | `string` | — | 라디오 name 속성 (form-agnostic 그룹핑) |
2758
+ | `className?` | `string` | — | |
2759
+ | `style?` | `CSSProperties` | — | |
2760
+
2761
+ #### Events
2762
+
2763
+ | Event | Type | Description |
2764
+ |-------|------|-------------|
2765
+ | `onValueChange` | `(val: SRadioValue) => void` | 선택 변경 (sdUpdate) |
2766
+
2767
+ ### SRadio
2768
+
2769
+ #### Props
2770
+
2771
+ | Prop | Type | Default | Description |
2772
+ |------|------|---------|-------------|
2773
+ | `val` | `SRadioValue` | — | 이 라디오의 값 |
2774
+ | `value?` | `SRadioValue \| null` | — | 그룹의 현재 선택 값 |
2775
+ | `label?` | `string` | — | 라벨 |
2776
+ | `disabled?` | `boolean` | `false` | 비활성 |
2777
+ | `name?` | `string` | — | native radio name (form-agnostic 그룹핑) |
2778
+ | `className?` | `string` | — | |
2779
+ | `style?` | `CSSProperties` | — | |
2780
+
2781
+ #### Events
2782
+
2783
+ | Event | Type | Description |
2784
+ |-------|------|-------------|
2785
+ | `onValueChange` | `(val: SRadioValue) => void` | 선택 변경 (sdUpdate) — 선택된 val 전달 |
2786
+
2787
+ ## Dependencies
2788
+
2789
+ ### Used by
2790
+
2791
+ - [SKeyValueTable](../SKeyValueTable)
2792
+
2793
+ ### Graph
2794
+
2795
+ ---
2796
+
2797
+ # SRadioButton
2798
+
2799
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2800
+
2801
+ ### SRadioButton
2802
+
2803
+ #### Props
2804
+
2805
+ | Prop | Type | Default | Description |
2806
+ |------|------|---------|-------------|
2807
+ | `options?` | `SRadioButtonOption[]` | `[]` | 옵션 목록 |
2808
+ | `value?` | `string \| number \| null` | — | 현재 선택 값 |
2809
+ | `size?` | `SRadioButtonSize` | `'sm'` | 크기 |
2810
+ | `disabled?` | `boolean` | `false` | 전체 비활성 |
2811
+ | `name?` | `string` | — | input name 속성 |
2812
+ | `className?` | `string` | — | |
2813
+ | `style?` | `CSSProperties` | — | |
2814
+
2815
+ #### Events
2816
+
2817
+ | Event | Type | Description |
2818
+ |-------|------|-------------|
2819
+ | `onValueChange` | `(value: string \| number) => void` | 변경 (sdUpdate) |
2820
+
2821
+ ---
2822
+
2823
+ # SScrollArea
2824
+
2825
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2826
+
2827
+ ### SScrollArea
2828
+
2829
+ #### Props
2830
+
2831
+ | Prop | Type | Default | Description |
2832
+ |------|------|---------|-------------|
2833
+ | `axis?` | `SScrollAreaAxis` | `'both'` | 스크롤 방향. vertical=세로만, horizontal=가로만, both=양방향 |
2834
+ | `background?` | `boolean` | `false` | true면 스크롤바 트랙 배경을 채운다. 콘텐츠 영역 배경은 바뀌지 않는다. |
2835
+ | `bordered?` | `boolean` | `false` | true면 스크롤바와 콘텐츠 사이에 1px 구분선을 그린다. 컨테이너 테두리가 아니다. |
2836
+ | `maxHeight?` | `string` | — | viewport 최대 높이 (예: '400px'). 비우면 부모 크기를 따른다. |
2837
+ | `maxWidth?` | `string` | — | viewport 최대 너비 (예: '480px'). 비우면 부모 크기를 따른다. |
2838
+
2839
+ ---
2840
+
2841
+ # SSectionHeaderCard
2842
+
2843
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2844
+
2845
+ ### SSectionHeaderCardBody
2846
+
2847
+ #### Props
2848
+
2849
+ | Prop | Type | Default | Description |
2850
+ |------|------|---------|-------------|
2851
+ | `children?` | `SSectionHeaderCardBodyChildren` | — | 바디 슬롯. 특정 컴포넌트 타입으로 제한하지 않습니다. |
2852
+
2853
+ ### SSectionHeaderCardHeader
2854
+
2855
+ #### Props
2856
+
2857
+ | Prop | Type | Default | Description |
2858
+ |------|------|---------|-------------|
2859
+ | `title` | `ReactNode` | — | 헤더 제목 |
2860
+ | `marker?` | `boolean` | `false` | 제목 앞 점 표시 여부 |
2861
+ | `required?` | `boolean` | `false` | 제목 뒤 필수 별 표시 여부 |
2862
+ | `helpText?` | `string[]` | — | 도움말 툴팁 메시지 |
2863
+ | `subtitle?` | `ReactNode` | — | 부제 |
2864
+ | `slot?` | `ReactNode` | — | 헤더 우측 슬롯 |
2865
+ | `thickness?` | `SSectionHeaderCardThickness` | `false` | 상단 border 색상 타입. false면 표시하지 않습니다. |
2866
+
2867
+ ### SSectionHeaderCard
2868
+
2869
+ #### Props
2870
+
2871
+ | Prop | Type | Default | Description |
2872
+ |------|------|---------|-------------|
2873
+ | `children?` | `SSectionHeaderCardChildren` | — | SSectionHeaderCard 슬롯. 특정 컴포넌트 타입으로 제한하지 않습니다. |
2874
+
2875
+ ## Dependencies
2876
+
2877
+ ### Depends on
2878
+
2879
+ - [SBadge](../SBadge)
2880
+ - [SIcon](../SIcon)
2881
+ - [STooltip](../STooltip)
2882
+
2883
+ ### Graph
2884
+
2885
+ ---
2886
+
2887
+ # SSelect
2888
+
2889
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2890
+
2891
+ ### SSelect
2892
+
2893
+ #### Props
2894
+
2895
+ | Prop | Type | Default | Description |
2896
+ |------|------|---------|-------------|
2897
+ | `value?` | `(string \| number \| SSelectOption) \| (string \| number \| SSelectOption)[] \| null` | — | 선택 값. multi 타입이면 배열. emitValue=false(기본) 라운드트립을 위해 SSelectOption 객체도 허용 |
2898
+ | `emitValue?` | `boolean` | `false` | true면 SSelectOption 대신 원시값(string|number) 방출 |
2899
+ | `name?` | `string` | — | 폼 연동용 name 속성 |
2900
+ | `options?` | `SSelectOption[]` | `[]` | 옵션 목록 (children으로 계층 표현) |
2901
+ | `type?` | `SSelectType` | `'default'` | 타입: default | multi | default_depth | multi_depth |
2902
+ | `useSearch?` | `boolean` | `false` | 검색 입력 사용 |
2903
+ | `useSelectAll?` | `boolean` | `false` | 전체선택 옵션 사용 (multi 전용) |
2904
+ | `allSelectedLabel?` | `string` | `'전체'` | 전체선택 레이블 |
2905
+ | `placeholder?` | `string` | `'선택'` | placeholder |
2906
+ | `disabled?` | `boolean` | `false` | 비활성 |
2907
+ | `error?` | `boolean` | `false` | 에러 상태 |
2908
+ | `rules?` | `Rule[]` | — | 유효성 규칙 — 닫힐 때 자동 검증 |
2909
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | 레이블 툴팁 상세 옵션 |
2910
+ | `dropdownHeight?` | `string` | `'260px'` | 드롭다운 최대 높이 |
2911
+ | `dropdownWidth?` | `string` | — | 드롭다운 너비 (없으면 트리거 너비) |
2912
+ | `maxDropdownWidth?` | `string` | `'640px'` | 드롭다운 최대 너비 |
2913
+ | `label?` | `string` | — | |
2914
+ | `labelWidth?` | `number \| string` | — | |
2915
+ | `icon?` | `SIconName` | — | 레이블 영역 아이콘 |
2916
+ | `iconColor?` | `SColor` | — | |
2917
+ | `labelTooltip?` | `string` | — | 레이블 툴팁 텍스트 |
2918
+ | `addonLabel?` | `string` | — | 우측 어드온 레이블 |
2919
+ | `addonAlign?` | `SFieldAddonAlign` | — | 어드온 정렬 |
2920
+ | `hint?` | `string` | — | |
2921
+ | `errorMessage?` | `string` | — | |
2922
+ | `width?` | `number \| string` | — | |
2923
+ | `className?` | `string` | — | |
2924
+ | `style?` | `CSSProperties` | — | |
2925
+
2926
+ #### Events
2927
+
2928
+ | Event | Type | Description |
2929
+ |-------|------|-------------|
2930
+ | `onValueChange` | `(value: any) => void` | 값 변경 (sdUpdate). emitValue=false(기본)면 SSelectOption(들), true면 원시값 |
2931
+ | `onOpenChange` | `(open: boolean) => void` | 열림/닫힘 변경 (sdDropDownShow) |
2932
+
2933
+ #### Methods (ref)
2934
+
2935
+ | Method | Type | Description |
2936
+ |--------|------|-------------|
2937
+ | `focus` | `() => void` | 트리거 버튼에 포커스 (sdFocus) |
2938
+ | `open` | `() => void` | 드롭다운 열기 (sdOpen) |
2939
+
2940
+ ## Dependencies
2941
+
2942
+ ### Used by
2943
+
2944
+ - [SKeyValueTable](../SKeyValueTable)
2945
+ - [STable](../STable)
2946
+
2947
+ ### Depends on
2948
+
2949
+ - [SField](../SField)
2950
+ - [SGhostButton](../SGhostButton)
2951
+ - [SIcon](../SIcon)
2952
+ - [SPortal](../SPortal)
2953
+
2954
+ ### Graph
2955
+
2956
+ ---
2957
+
2958
+ # SStepper
2959
+
2960
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2961
+
2962
+ ### SStepper
2963
+
2964
+ #### Props
2965
+
2966
+ | Prop | Type | Default | Description |
2967
+ |------|------|---------|-------------|
2968
+ | `items` | `SStepperItem[]` | — | 단계 목록 |
2969
+ | `value?` | `string` | — | 현재 활성 단계 value |
2970
+ | `size?` | `SStepperSize` | `'sm'` | 크기 |
2971
+ | `ariaLabel?` | `string` | `'진행 단계'` | 접근성 레이블 |
2972
+ | `className?` | `string` | — | |
2973
+ | `style?` | `CSSProperties` | — | |
2974
+
2975
+ ## Dependencies
2976
+
2977
+ ### Depends on
2978
+
2979
+ - [SIcon](../SIcon)
2980
+
2981
+ ### Graph
2982
+
2983
+ ---
2984
+
2985
+ # SSwitch
2986
+
2987
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
2988
+
2989
+ ### SSwitch
2990
+
2991
+ #### Props
2992
+
2993
+ | Prop | Type | Default | Description |
2994
+ |------|------|---------|-------------|
2995
+ | `value?` | `boolean` | `false` | on/off 상태 |
2996
+ | `leftLabel?` | `string` | — | 스위치 좌측 라벨 |
2997
+ | `rightLabel?` | `string` | — | 스위치 우측 라벨 |
2998
+ | `label?` | `string` | — | |
2999
+ | `disabled?` | `boolean` | `false` | 비활성 |
3000
+ | `className?` | `string` | — | |
3001
+ | `style?` | `CSSProperties` | — | |
3002
+
3003
+ #### Events
3004
+
3005
+ | Event | Type | Description |
3006
+ |-------|------|-------------|
3007
+ | `onValueChange` | `(value: boolean) => void` | 변경 (sdUpdate) |
3008
+
3009
+ ---
3010
+
3011
+ # STable
3012
+
3013
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3014
+
3015
+ ### STable
3016
+
3017
+ #### Props
3018
+
3019
+ | Prop | Type | Default | Description |
3020
+ |------|------|---------|-------------|
3021
+ | `columns?` | `STableColumn[]` | `[]` | |
3022
+ | `rows?` | `SRow[]` | `[]` | |
3023
+ | `rowKey?` | `string` | `'id'` | 행 식별 필드 |
3024
+ | `selectable?` | `boolean` | `false` | 행 선택 체크박스 |
3025
+ | `selected?` | `SRow[]` | `[]` | |
3026
+ | `resizable?` | `boolean` | `false` | 컬럼 너비 조절 |
3027
+ | `width?` | `string` | — | |
3028
+ | `height?` | `string` | — | |
3029
+ | `stickyHeader?` | `boolean` | — | |
3030
+ | `stickyColumn?` | `STableStickyColumn` | — | 고정할 좌/우 컬럼 수 |
3031
+ | `radius?` | `'default' \| 'useTop' \| 'full'` | `'default'` | border-radius 제어 |
3032
+ | `noDataLabel?` | `string` | `'데이터가 없습니다.'` | |
3033
+ | `noDataSlot?` | `ReactNode` | — | 데이터가 없을 때 body 영역 전체를 대체하는 슬롯. 지정하면 `noDataLabel` 대신 이 콘텐츠가 헤더 아래 영역을 채우며, 버튼 등 인터랙션도 동작한다. |
3034
+ | `isLoading?` | `boolean` | `false` | |
3035
+ | `dense?` | `boolean` | `false` | |
3036
+ | `noHover?` | `boolean` | `false` | true면 행에 마우스를 올려도 hover 배경(grey_05)을 표시하지 않는다 |
3037
+ | `pagination?` | `STablePagination` | — | 페이지네이션 (있으면 하단 표시) |
3038
+ | `useInternalPagination?` | `boolean` | `false` | 테이블 내부에서 페이지네이션을 직접 관리 (rows를 내부 슬라이싱) |
3039
+ | `useRowsPerPageSelect?` | `boolean` | `false` | 페이지당 행 수 셀렉트 표시 |
3040
+ | `rowsPerPageOption?` | `SSelectOption[]` | `DEFAULT_ROWS_PER_PAGE_OPTION` | |
3041
+ | `useVirtualScroll?` | `boolean` | `false` | 가상 스크롤 |
3042
+ | `rowHeight?` | `number` | — | |
3043
+ | `virtualBuffer?` | `number` | `5` | |
3044
+ | `virtualEndThreshold?` | `number` | `10` | |
3045
+ | `tableId?` | `string` | — | 테이블 식별자 (없으면 자동 생성) |
3046
+ | `className?` | `string` | — | |
3047
+ | `style?` | `CSSProperties` | — | |
3048
+
3049
+ #### Events
3050
+
3051
+ | Event | Type | Description |
3052
+ |-------|------|-------------|
3053
+ | `onSelectedChange` | `(rows: SRow[]) => void` | |
3054
+ | `onPageChange` | `(page: number) => void` | |
3055
+ | `onRowsPerPageChange` | `(perPage: number) => void` | |
3056
+ | `onVirtualUpdate` | `(range: { from: number; to: number }) => void` | |
3057
+ | `onVirtualReachEnd` | `(info: { from: number; to: number; rowCount: number; threshold: number; }) =>…` | |
3058
+ | `onRowClick` | `(row: SRow) => void` | 행 클릭 |
3059
+
3060
+ #### Methods (ref)
3061
+
3062
+ | Method | Type | Description |
3063
+ |--------|------|-------------|
3064
+ | `isRowSelected` | `(row: SRow) => boolean` | 행 선택 여부 |
3065
+ | `getIsAllChecked` | `(rows: SRow[]) => boolean \| null` | 주어진 행들의 전체 선택 상태 (true/false/null=indeterminate) |
3066
+ | `getPaginationInfo` | `<union 2종>` | 내부 페이지네이션 정보 (useInternalPagination 아니면 null) |
3067
+ | `getStickyStyle` | `(colIdx: number) => CSSProperties` | 컬럼 sticky 스타일 (CSS 변수 + 고정폭) |
3068
+ | `setRowCount` | `(count: number) => void` | 가상 스크롤 총 행 수 설정 |
3069
+ | `updateRowSelect` | `(row: SRow) => void` | 단일 행 선택 토글 (sd-table updateRowSelect) — onSelectedChange 발생 |
3070
+ | `toggleSelectAll` | `(checked: boolean, rows: SRow[]) => void` | 주어진 행들 전체 선택/해제 (sd-table toggleSelectAll) — onSelectedChange 발생 |
3071
+
3072
+ ## Dependencies
3073
+
3074
+ ### Depends on
3075
+
3076
+ - [SCheckbox](../SCheckbox)
3077
+ - [SCircleProgress](../SCircleProgress)
3078
+ - [SIcon](../SIcon)
3079
+ - [SPagination](../SPagination)
3080
+ - [SSelect](../SSelect)
3081
+
3082
+ ### Graph
3083
+
3084
+ ---
3085
+
3086
+ # STableBar
3087
+
3088
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3089
+
3090
+ ### STableBar
3091
+
3092
+ #### Props
3093
+
3094
+ | Prop | Type | Default | Description |
3095
+ |------|------|---------|-------------|
3096
+ | `total?` | `number` | — | 전체 건수. 지정하면 "총 N 건" 을 표시한다 (천단위 구분 자동) |
3097
+ | `selected?` | `number` | — | 선택 건수. 지정하면 "N건 선택" 을 표시한다 |
3098
+ | `actions?` | `ReactNode` | — | 구분선 오른쪽 좌측 액션 영역 |
3099
+ | `rightActions?` | `ReactNode` | — | 우측 정렬 액션 영역 |
3100
+
3101
+ ## Dependencies
3102
+
3103
+ ### Depends on
3104
+
3105
+ - [SDivider](../SDivider)
3106
+
3107
+ ### Graph
3108
+
3109
+ ---
3110
+
3111
+ # STabs
3112
+
3113
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3114
+
3115
+ ### STabs
3116
+
3117
+ #### Props
3118
+
3119
+ | Prop | Type | Default | Description |
3120
+ |------|------|---------|-------------|
3121
+ | `value` | `string` | — | 현재 선택된 탭 value |
3122
+ | `tabs` | `STabOption[]` | — | 탭 옵션 목록 |
3123
+ | `size?` | `STabSize` | `'md'` | 탭 크기 (main 전용) |
3124
+ | `isSub?` | `boolean` | `false` | 서브 탭(밑줄형) 스타일 |
3125
+ | `vertical?` | `boolean` | `false` | 세로 배치 (sub 전용 — main 폴더형은 항상 가로) |
3126
+ | `className?` | `string` | — | |
3127
+ | `style?` | `CSSProperties` | — | |
3128
+
3129
+ #### Events
3130
+
3131
+ | Event | Type | Description |
3132
+ |-------|------|-------------|
3133
+ | `onValueChange` | `(value: string) => void` | 탭 변경 (sdUpdate) |
3134
+
3135
+ ## Dependencies
3136
+
3137
+ ### Depends on
3138
+
3139
+ - [STag](../STag)
3140
+
3141
+ ### Graph
3142
+
3143
+ ---
3144
+
3145
+ # STag
3146
+
3147
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3148
+
3149
+ ### STag
3150
+
3151
+ #### Props
3152
+
3153
+ | Prop | Type | Default | Description |
3154
+ |------|------|---------|-------------|
3155
+ | `shape?` | `STagShape` | `'square'` | 모양 |
3156
+ | `size?` | `STagSize` | `'sm'` | 크기 |
3157
+ | `color?` | `STagColor` | `'grey'` | 색상 |
3158
+ | `label?` | `string` | `''` | 레이블 텍스트 |
3159
+ | `icon?` | `SIconName` | — | 아이콘명 |
3160
+ | `iconLeft?` | `boolean` | `true` | 아이콘을 레이블 왼쪽에 배치 |
3161
+ | `width?` | `string \| number` | — | 태그 너비 (숫자면 px, 문자열이면 그대로 적용). 미지정 시 콘텐츠 크기 |
3162
+
3163
+ ## Dependencies
3164
+
3165
+ ### Used by
3166
+
3167
+ - [SConfirmModal](../SConfirmModal)
3168
+ - [SGhostButton](../SGhostButton)
3169
+ - [SGnb](../SGnb)
3170
+ - [STabs](../STabs)
3171
+ - [STextLink](../STextLink)
3172
+
3173
+ ### Depends on
3174
+
3175
+ - [SIcon](../SIcon)
3176
+
3177
+ ### Graph
3178
+
3179
+ ---
3180
+
3181
+ # STextLink
3182
+
3183
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3184
+
3185
+ ### STextLink
3186
+
3187
+ #### Props
3188
+
3189
+ | Prop | Type | Default | Description |
3190
+ |------|------|---------|-------------|
3191
+ | `label?` | `string` | `''` | 레이블 |
3192
+ | `icon?` | `SIconName` | — | 좌측 아이콘 |
3193
+ | `iconColor?` | `SColor` | — | 좌측 아이콘 색상. 팔레트 키(`grey_65`, `red_95` …) 또는 임의 CSS 색상 |
3194
+ | `labelClass?` | `string` | — | 레이블 span에 추가할 클래스 |
3195
+ | `rightArrow?` | `STextLinkArrow` | `'none'` | 우측 화살표 |
3196
+ | `underline?` | `boolean` | `false` | 밑줄 여부 |
3197
+ | `disabled?` | `boolean` | `false` | 비활성 |
3198
+ | `size?` | `STextLinkSize` | `'sm'` | 크기 |
3199
+ | `tooltipText?` | `string` | — | 호버 시 표시할 툴팁 텍스트 (회색 STag 스타일) |
3200
+
3201
+ #### Events
3202
+
3203
+ | Event | Type | Description |
3204
+ |-------|------|-------------|
3205
+ | `onClick` | `() => void` | |
3206
+
3207
+ ## Dependencies
3208
+
3209
+ ### Used by
3210
+
3211
+ - [SChipInput](../SChipInput)
3212
+ - [SPopover](../SPopover)
3213
+
3214
+ ### Depends on
3215
+
3216
+ - [SIcon](../SIcon)
3217
+ - [STag](../STag)
3218
+
3219
+ ### Graph
3220
+
3221
+ ---
3222
+
3223
+ # STextarea
3224
+
3225
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3226
+
3227
+ ### STextarea
3228
+
3229
+ #### Props
3230
+
3231
+ | Prop | Type | Default | Description |
3232
+ |------|------|---------|-------------|
3233
+ | `value?` | `string` | — | 값 (제어) |
3234
+ | `rows?` | `number` | `3` | 행 수 |
3235
+ | `rules?` | `Rule[]` | — | 유효성 규칙 — blur 시 자동 검증 |
3236
+ | `status?` | `SFieldStatus` | — | 필드 상태 ('default' | 'pass' | 'error') |
3237
+ | `focused?` | `boolean` | — | 포커스 상태 (제어/반영) |
3238
+ | `hovered?` | `boolean` | — | 호버 상태 (제어/반영) |
3239
+ | `textareaClass?` | `string` | — | 내부 textarea 요소 className |
3240
+ | `textareaStyle?` | `CSSProperties` | — | 내부 textarea 요소 style |
3241
+ | `label?` | `string` | — | |
3242
+ | `labelWidth?` | `number \| string` | — | |
3243
+ | `icon?` | `SIconName` | — | 레이블 영역 아이콘 |
3244
+ | `iconColor?` | `SColor` | — | |
3245
+ | `labelTooltip?` | `string` | — | 레이블 툴팁 텍스트 |
3246
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | 레이블 툴팁 상세 옵션 |
3247
+ | `addonLabel?` | `string` | — | 우측 어드온 레이블 |
3248
+ | `addonAlign?` | `SFieldAddonAlign` | — | 어드온 정렬 |
3249
+ | `hint?` | `string` | — | |
3250
+ | `error?` | `boolean` | — | |
3251
+ | `errorMessage?` | `string` | — | |
3252
+ | `width?` | `number \| string` | — | |
3253
+ | `disabled?` | `boolean` | `false` | |
3254
+ | `readOnly?` | `boolean` | `false` | |
3255
+ | `className?` | `string` | — | |
3256
+ | `style?` | `CSSProperties` | — | |
3257
+
3258
+ #### Events
3259
+
3260
+ | Event | Type | Description |
3261
+ |-------|------|-------------|
3262
+ | `onValueChange` | `(value: string) => void` | 값 변경 (sdUpdate) |
3263
+ | `onChange` | `TextareaHTMLAttributes<HTMLTextAreaElement>['onChange']` | 네이티브 onChange (form-agnostic) |
3264
+
3265
+ ## Dependencies
3266
+
3267
+ ### Used by
3268
+
3269
+ - [SKeyValueTable](../SKeyValueTable)
3270
+
3271
+ ### Depends on
3272
+
3273
+ - [SField](../SField)
3274
+
3275
+ ### Graph
3276
+
3277
+ ---
3278
+
3279
+ # STimePicker
3280
+
3281
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3282
+
3283
+ ### STimePicker
3284
+
3285
+ #### Props
3286
+
3287
+ | Prop | Type | Default | Description |
3288
+ |------|------|---------|-------------|
3289
+ | `value?` | `string \| null` | — | 선택 시간 (HH:mm) |
3290
+ | `type?` | `STimePickerType` | `'default'` | 표시 타입: default(24시간) / midday(오전·오후) |
3291
+ | `size?` | `STimePickerSize` | `'sm'` | |
3292
+ | `placeholder?` | `string` | `'00:00'` | |
3293
+ | `disabled?` | `boolean` | `false` | |
3294
+ | `clearable?` | `boolean` | `false` | |
3295
+ | `useMeridiem?` | `boolean` | — | 오전/오후 선택 표시 여부. 지정하지 않으면 type="midday"일 때만 켜집니다. |
3296
+ | `minuteStep?` | `number` | `1` | |
3297
+ | `width?` | `number \| string` | — | |
3298
+ | `name?` | `string` | — | |
3299
+ | `rules?` | `Rule[]` | — | |
3300
+ | `status?` | `SFieldStatus` | — | |
3301
+ | `label?` | `string` | — | |
3302
+ | `labelWidth?` | `number \| string` | — | |
3303
+ | `icon?` | `SIconName` | — | |
3304
+ | `iconColor?` | `SColor` | — | |
3305
+ | `labelTooltip?` | `string` | — | |
3306
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
3307
+ | `addonLabel?` | `string` | — | |
3308
+ | `addonAlign?` | `SFieldAddonAlign` | — | |
3309
+ | `hint?` | `string` | — | |
3310
+ | `error?` | `boolean` | — | |
3311
+ | `errorMessage?` | `string` | — | |
3312
+ | `className?` | `string` | — | |
3313
+ | `style?` | `CSSProperties` | — | |
3314
+
3315
+ #### Events
3316
+
3317
+ | Event | Type | Description |
3318
+ |-------|------|-------------|
3319
+ | `onValueChange` | `(time: string \| null) => void` | 선택 변경 (sdUpdate) |
3320
+ | `onOpenChange` | `(open: boolean) => void` | 열림/닫힘 변경 (sdDropDownShow) |
3321
+
3322
+ ## Dependencies
3323
+
3324
+ ### Used by
3325
+
3326
+ - [STimeRangePicker](../STimeRangePicker)
3327
+
3328
+ ### Depends on
3329
+
3330
+ - [SField](../SField)
3331
+ - [SGhostButton](../SGhostButton)
3332
+ - [SIcon](../SIcon)
3333
+
3334
+ ### Graph
3335
+
3336
+ ---
3337
+
3338
+ # STimeRangePicker
3339
+
3340
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3341
+
3342
+ ### STimeRangePicker
3343
+
3344
+ #### Props
3345
+
3346
+ | Prop | Type | Default | Description |
3347
+ |------|------|---------|-------------|
3348
+ | `value?` | `STimeRangeValue` | — | 선택 시간 범위 [시작, 종료] (HH:mm) |
3349
+ | `type?` | `STimeRangePickerType` | `'default'` | 표시 타입: default(24시간) / midday(오전·오후) |
3350
+ | `size?` | `STimeRangePickerSize` | `'sm'` | |
3351
+ | `placeholder?` | `string` | `'00:00 ~ 23:59'` | |
3352
+ | `disabled?` | `boolean` | `false` | |
3353
+ | `clearable?` | `boolean` | `false` | |
3354
+ | `useMeridiem?` | `boolean` | — | 오전/오후 선택 표시 여부. 지정하지 않으면 type="midday"일 때만 켜집니다. |
3355
+ | `minuteStep?` | `number` | `1` | |
3356
+ | `rangeOrder?` | `STimeRangePickerRangeOrder` | `'strict'` | 범위 순서 정책. strict는 시작 시간이 종료 시간보다 늦어지지 않도록 보정합니다. |
3357
+ | `width?` | `number \| string` | — | |
3358
+ | `name?` | `string` | — | |
3359
+ | `rules?` | `Rule[]` | — | |
3360
+ | `status?` | `SFieldStatus` | — | |
3361
+ | `label?` | `string` | — | |
3362
+ | `labelWidth?` | `number \| string` | — | |
3363
+ | `icon?` | `SIconName` | — | |
3364
+ | `iconColor?` | `SColor` | — | |
3365
+ | `labelTooltip?` | `string` | — | |
3366
+ | `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
3367
+ | `addonLabel?` | `string` | — | |
3368
+ | `addonAlign?` | `SFieldAddonAlign` | — | |
3369
+ | `hint?` | `string` | — | |
3370
+ | `error?` | `boolean` | — | |
3371
+ | `errorMessage?` | `string` | — | |
3372
+ | `className?` | `string` | — | |
3373
+ | `style?` | `CSSProperties` | — | |
3374
+
3375
+ #### Events
3376
+
3377
+ | Event | Type | Description |
3378
+ |-------|------|-------------|
3379
+ | `onValueChange` | `(range: STimeRangeValue) => void` | 선택 변경 (sdUpdate) |
3380
+ | `onOpenChange` | `(open: boolean) => void` | 열림/닫힘 변경 (sdDropDownShow) |
3381
+
3382
+ ## Dependencies
3383
+
3384
+ ### Depends on
3385
+
3386
+ - [SField](../SField)
3387
+ - [SGhostButton](../SGhostButton)
3388
+ - [SIcon](../SIcon)
3389
+ - [STimePicker](../STimePicker)
3390
+
3391
+ ### Graph
3392
+
3393
+ ---
3394
+
3395
+ # SToast
3396
+
3397
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3398
+
3399
+ ### SToastContainer
3400
+
3401
+ #### Props
3402
+
3403
+ | Prop | Type | Default | Description |
3404
+ |------|------|---------|-------------|
3405
+ | `position?` | `SToastPosition` | `'bottom-center'` | |
3406
+ | `maxVisible?` | `number` | `3` | |
3407
+ | `defaultDuration?` | `number` | `4000` | 자동 닫힘 기본 지연(ms) |
3408
+ | `zIndex?` | `number` | `1100` | 스택 z-index. 기본값(1100)은 모달(1000/1001) 위 — 토스트는 전역 알림이라 항상 최상단 |
3409
+
3410
+ #### Events
3411
+
3412
+ | Event | Type | Description |
3413
+ |-------|------|-------------|
3414
+ | `onShow` | `(payload: { id: string }) => void` | 토스트가 표시될 때 (sdToastShow) |
3415
+ | `onDismiss` | `(payload: { id: string }) => void` | 토스트가 제거될 때 (sdToastDismiss) |
3416
+
3417
+ #### Methods (ref)
3418
+
3419
+ | Method | Type | Description |
3420
+ |--------|------|-------------|
3421
+ | `create` | `(options: SToastNotifyOptions) => string` | |
3422
+ | `dismiss` | `(id: string) => void` | |
3423
+ | `dismissAll` | `() => void` | |
3424
+
3425
+ ### SToast
3426
+
3427
+ #### Props
3428
+
3429
+ | Prop | Type | Default | Description |
3430
+ |------|------|---------|-------------|
3431
+ | `icon?` | `SIconName` | — | 좌측 아이콘 |
3432
+ | `message` | `string` | — | 메시지 |
3433
+ | `link?` | `string` | — | 우측 링크 URL |
3434
+ | `linkLabel?` | `string` | — | 링크 레이블 (없으면 URL) |
3435
+ | `buttonLabel?` | `string` | — | 우측 버튼 레이블 |
3436
+ | `useClose?` | `boolean` | `false` | 닫기 버튼 표시 |
3437
+ | `type?` | `SToastType` | `'default'` | 타입(색상/프리셋) |
3438
+ | `className?` | `string` | — | |
3439
+ | `style?` | `CSSProperties` | — | |
3440
+
3441
+ #### Events
3442
+
3443
+ | Event | Type | Description |
3444
+ |-------|------|-------------|
3445
+ | `onClose` | `() => void` | 닫기 (sdClose) |
3446
+ | `onButtonClick` | `(e: MouseEvent) => void` | 버튼 클릭 (sdButtonClick) |
3447
+
3448
+ ## Dependencies
3449
+
3450
+ ### Depends on
3451
+
3452
+ - [SButton](../SButton)
3453
+ - [SGhostButton](../SGhostButton)
3454
+ - [SIcon](../SIcon)
3455
+
3456
+ ### Graph
3457
+
3458
+ ---
3459
+
3460
+ # SToggle
3461
+
3462
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3463
+
3464
+ ### SToggle
3465
+
3466
+ #### Props
3467
+
3468
+ | Prop | Type | Default | Description |
3469
+ |------|------|---------|-------------|
3470
+ | `value?` | `boolean` | `false` | 선택(on/off) 상태 |
3471
+ | `label?` | `string` | `''` | 라벨 |
3472
+ | `disabled?` | `boolean` | `false` | 비활성 |
3473
+ | `className?` | `string` | — | |
3474
+ | `style?` | `CSSProperties` | — | |
3475
+
3476
+ #### Events
3477
+
3478
+ | Event | Type | Description |
3479
+ |-------|------|-------------|
3480
+ | `onValueChange` | `(value: boolean) => void` | 변경 (sdUpdate) |
3481
+
3482
+ ---
3483
+
3484
+ # STooltip
3485
+
3486
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
3487
+
3488
+ ### STooltip
3489
+
3490
+ #### Props
3491
+
3492
+ | Prop | Type | Default | Description |
3493
+ |------|------|---------|-------------|
3494
+ | `content?` | `ReactNode` | — | 툴팁 본문 (ReactNode). message 보다 우선 |
3495
+ | `message?` | `string[]` | `[]` | 툴팁 본문 줄 목록 (각 항목이 한 줄, HTML 문자열 허용 — innerHTML 렌더링) |
3496
+ | `trigger?` | `STooltipTrigger` | `'hover'` | 트리거 방식 |
3497
+ | `placement?` | `STooltipPlacement` | `'top'` | 표시 방향 |
3498
+ | `tooltipType?` | `STooltipType` | `'default'` | 배경/텍스트 색상 타입 |
3499
+ | `useClose?` | `boolean` | `false` | 우측 상단 닫기 버튼. 켜면 자동 닫힘이 비활성화되고 X(또는 hide())로만 닫힘 (hover·click 공통) |
3500
+ | `disabled?` | `boolean` | `false` | 비활성 — 트리거만 렌더하고 툴팁을 열지 않음 |
3501
+ | `children?` | `ReactNode` | — | 커스텀 트리거. 없으면 아이콘 트리거를 렌더 |
3502
+ | `icon?` | `SIconName` | `'helpOutline'` | 기본(아이콘) 트리거 설정 |
3503
+ | `iconSize?` | `number` | `12` | |
3504
+ | `color?` | `SColor` | `'#01BB4B'` | 트리거 아이콘 색상. 팔레트 키(`grey_65`, `red_95` …) 또는 임의 CSS 색상 |
3505
+ | `ariaLabel?` | `string` | — | 접근성 레이블 |
3506
+ | `className?` | `string` | — | |
3507
+ | `triggerClassName?` | `string` | — | |
3508
+ | `style?` | `CSSProperties` | — | |
3509
+
3510
+ #### Methods (ref)
3511
+
3512
+ | Method | Type | Description |
3513
+ |--------|------|-------------|
3514
+ | `show` | `() => void` | 툴팁을 표시합니다. |
3515
+ | `hide` | `() => void` | 툴팁을 숨깁니다. |
3516
+
3517
+ ## Dependencies
3518
+
3519
+ ### Used by
3520
+
3521
+ - [SField](../SField)
3522
+ - [SKeyValueTable](../SKeyValueTable)
3523
+ - [SList](../SList)
3524
+
3525
+ ### Depends on
3526
+
3527
+ - [SGhostButton](../SGhostButton)
3528
+ - [SIcon](../SIcon)
3529
+
3530
+ ### Graph