sellmate-design-system-react 9.0.0-beta.101 → 9.0.0-beta.103

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.
package/AGENTS.md CHANGED
@@ -44,7 +44,7 @@
44
44
  | **날짜·시간** | `SCalendar` `SCalendarBoard`(한 달치 일정 판) `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` |
45
45
  | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `STreeTable`(행이 부모-자식 계층을 이루는 표 — 펼치고 접는다) `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` `STimeline`(날짜로 묶인 시간순 기록 — 작업 로그·메모 이력) |
46
46
  | **레이아웃** | `SLayout` `SGnb` `SGnbSystem` `SSystemActionButton`(GNB system 패널에 한 줄씩 쌓는 액션 행 — 버튼 고르기는 §3-5) `SAccountListBox`(계정 행을 눌러 뜨는 계정 패널) `SLauncherListBox`(런처 버튼을 눌러 뜨는 서비스 목록) `SPage` `SPageHeader`(페이지 제목 영역 — `SLayout` 안에서 `SPage` 앞에 둔다) `SSectionHeaderCard` `SCard` `SLoginCard`(통합 계정 로그인 화면의 카드) `SDivider` `SSplitter` `SScrollArea` `SExpansionItem` |
47
- | **내비게이션** | `STabs` `SPagination` `SStepper` |
47
+ | **내비게이션** | `STabs` `SPagination` `SStepper` `SSectionNav`(같은 페이지의 섹션으로 스크롤해 이동하는 메뉴 — 앱 셸 좌측 내비게이션은 `SGnb`) |
48
48
  | **차트** | `SBarChart`(막대 그래프 — 항목끼리 크기를 견준다. `stacked` 로 항목 안의 구성까지) `SLineChart`(꺾은선 그래프 — 순서가 있는 항목의 추이를 본다. `area` 로 크기까지, `stacked` 로 구성까지) `SPieChart`(원그래프 — 한 시점의 전체를 몇 개의 몫으로 나눈다) `SDonutChart`(도넛 그래프 — 가운데가 빈 원그래프. 구멍에 글자를 두지 않는다) |
49
49
  | **표시·상태** | `STag` `SBadge` `SIcon` `SLogo`(셀메이트·서비스 로고를 아이콘처럼 — name 으로 서비스, mode 로 배경, direction 으로 가로·세로, size 는 높이다 — `"auto"` 면 부모 폭을 채운다) `SImage` `SCallout` `SContextAlert`(한 줄짜리 맥락 알림 — 오른쪽에 후속 동작 버튼) `SGuide` |
50
50
  | **진행·로딩** | `SLinearProgress` `SCircleProgress` `SSkeleton`(처음 불러오는 동안 콘텐츠 자리를 같은 모양으로 채운다) `SLoadingContainer` `SLoadingModal` |
@@ -87,7 +87,7 @@ AI 에이전트는 코드를 생성하기 전에 이 목록을 반드시 지킨
87
87
  | `<form>` | `SForm` |
88
88
  | `<dialog>`, 직접 만든 오버레이 | `SModal.confirm(...)`, `SModal.create(...)`, `SPopup` |
89
89
  | `alert()`, `confirm()` | `SToast`, `SModal.confirm(...)` |
90
- | 직접 만든 탭/페이지네이션/스텝퍼 | `STabs`, `SPagination`, `SStepper` |
90
+ | 직접 만든 탭/페이지네이션/스텝퍼/섹션 이동 메뉴 | `STabs`, `SPagination`, `SStepper`, `SSectionNav` |
91
91
  | `<ul>`/`<li>` 로 만든 목록 UI | `SList` + `SListItem` (드래그 정렬은 `SDraggableItem`) |
92
92
  | 직접 만든 섹션 카드(제목 바 + 본문 박스) | `SSectionHeaderCard` 의 `title` / `padding` props |
93
93
  | `<svg>` 직접 삽입, 이모지 아이콘 | `SIcon` (셀메이트·서비스 로고는 `SLogo`) |
@@ -139,6 +139,8 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
139
139
 
140
140
  콤마 없는 `39000` 은 자릿수를 세어야 읽히지만 `39,000` 은 한눈에 읽힌다. 숫자를 그대로 출력하는 코드는 미완성으로 본다.
141
141
 
142
+ **앱이 `SLocaleProvider` 로 로케일을 바꾸는 경우(§4-1)에는 `useLocale().formatNumber(v)` 로 쓴다** — 선택한 로케일의 숫자 구분을 따른다. 로케일을 바꾸지 않는 앱은 `toLocaleString()` 그대로 쓴다. **날짜는 로케일을 바꿔도 아래 `YYYY-MM-DD` 표기가 그대로다.**
143
+
142
144
  **번호·코드는 제외한다.** 전화번호·사업자번호·송장번호·상품코드처럼 대상을 가리키는 값은 크기를 비교하는 숫자가 아니라 **서식이 정해진 문자열**이다. 여기에 콤마를 넣으면 송장번호 `123456789` 가 `123,456,789` 로 보여 값 자체가 달라진다.
143
145
 
144
146
  **날짜는 `YYYY-MM-DD` 로 쓴다.** 자릿수를 채우고 하이픈으로 구분한다 — `2026-08-13`.
@@ -169,7 +171,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
169
171
  | --- | --- | --- |
170
172
  | **셸** | 앱 전체 뼈대. 페이지가 바뀌어도 남는다 | `SLayout` `SGnb` `SGnbSystem`(GNB 맨 아래 판 · 전폭 상단바 오른쪽 끝) `SPage` `SPageHeader`(`SLayout` 안에서 `SPage` 앞에 둔다) |
171
173
  | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `STreeTable` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `STimeline` `SCallout` `SContextAlert` `SBarChart` `SLineChart` `SPieChart` `SDonutChart` `STabs` `SStepper` `SPagination` `SDivider` |
172
- | **요소** | 블록 **안에** 놓이는 컨트롤. 혼자 페이지에 서지 않는다 | `SButton` `SGhostButton` `SMeatballButton` `SDropdownButton` `SSystemActionButton` `SField` `SInput` `SSearchInput` `SNumberInput` `SSlider` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SSwitch` `SToggle` `SChipInput` `SBarcodeInput` `SFilePicker` `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` `SCalendar` `SListItem` `SExpansionItem` `SDraggableItem` `SChatAttachedFile` `SChatFile` `SImage` `SLinearProgress` `SCircleProgress` `SSkeleton` |
174
+ | **요소** | 블록 **안에** 놓이는 컨트롤. 혼자 페이지에 서지 않는다 | `SButton` `SGhostButton` `SMeatballButton` `SDropdownButton` `SSystemActionButton` `SField` `SInput` `SSearchInput` `SNumberInput` `SSlider` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SSwitch` `SToggle` `SChipInput` `SBarcodeInput` `SFilePicker` `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` `SCalendar` `SListItem` `SExpansionItem` `SDraggableItem` `SChatAttachedFile` `SChatFile` `SImage` `SLinearProgress` `SCircleProgress` `SSkeleton` `SSectionNav`(본문과 좌우로 나란히 놓는 섹션 메뉴 — 혼자 페이지에 서지 않는다) |
173
175
  | **인라인** | 텍스트 흐름·셀·라벨 안에 섞인다. 혼자 블록이 되지 않는다 | `STag` `SBadge` `SIcon` `SLogo` `STextLink` `SChip` |
174
176
  | **레이어** | 문서 흐름 **밖**에 떠서 그려진다. 어느 층에서 띄우든 레이아웃에 영향이 없다 | `SModal` `SActionModal` `SConfirmModal` `SPopup` `SDrawer` `SPopover` `STooltip` `SPortal` `SAccountListBox`(계정 행에 붙어 뜬다 — 직접 띄우지 않는다) `SLauncherListBox`(런처 버튼에 붙어 뜬다 — 직접 띄우지 않는다) `SToast` `SLoadingModal` `SLoadingContainer` `SGuide` |
175
177
 
@@ -217,7 +219,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
217
219
  블록 순서는 화면 종류와 무관하게 같다. **필요한 것만 남기되 순서를 바꾸지 않는다.**
218
220
 
219
221
  ```text
220
- 1. 페이지 제목 `SPageHeader` (SGnb 와 SPage 사이. 가이드·매뉴얼 링크는 slot, 액션 버튼은 오지 않는다 §4-2)
222
+ 1. 페이지 제목 `SPageHeader` (SGnb 와 SPage 사이. 제목에 붙는 태그는 titleSlot, 가이드·매뉴얼 링크는 slot, 액션 버튼은 오지 않는다 §4-2)
221
223
  2. 상시 안내 SCallout
222
224
  3. 필터 SKeyValueTable · SChipFilter (§3-7-11)
223
225
  4. 툴바 STableBar (제목 slot + 건수 요약 + 액션)
@@ -606,13 +608,13 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
606
608
  | 하려는 일 | 컴포넌트 | 갈림 |
607
609
  | --- | --- | --- |
608
610
  | 앱 셸(상단바 + 내비 + 본문)을 세운다 | `SLayout` | §4-1 |
609
- | 좌측 내비게이션을 만든다 | `SGnb` | §4-1 |
611
+ | 앱 셸의 좌측 내비게이션을 만든다 | `SGnb` | §4-1 |
610
612
  | 좌측 내비게이션 맨 아래(또는 전폭 상단바 오른쪽 끝)에 서비스·도메인·알림·설정·계정 묶음을 붙인다 | `SGnbSystem` | §4-1 |
611
613
  | 앱 상단바 오른쪽 끝에 알림 벨·계정 이름을 둔다 | `SGnbSystem` (`SGnb` 의 `system` 슬롯 — 직접 만들지 않는다) | §4-1 |
612
614
  | 계정 이름을 눌러 이메일·권한·계정 설정·언어 변경·로그아웃을 띄운다 | `SAccountListBox` (`SGnbSystem` 의 `account.listBox` 로 넘긴다 — 직접 띄우지 않는다) | §4-1 |
613
615
  | 앱런처 버튼을 눌러 옮겨 갈 수 있는 서비스 목록을 띄운다 | `SLauncherListBox` (`SGnb` 의 `launcher.items` 로 넘긴다 — 직접 띄우지 않는다) | §4-1 |
614
616
  | 페이지 본문을 담는다 (패딩·스크롤) | `SPage` | §4-1 |
615
- | 페이지 제목(+ 서브 텍스트·뒤로가기·우측 슬롯)을 만든다 | `SPageHeader` (`SLayout` 안에서 `SPage` 앞에 둔다) | §4-1 |
617
+ | 페이지 제목(+ 서브 텍스트·제목 옆 태그·뒤로가기·우측 슬롯)을 만든다 | `SPageHeader` (`SLayout` 안에서 `SPage` 앞에 둔다) | §4-1 |
616
618
  | 제목 있는 섹션으로 묶는다 | `SSectionHeaderCard` | §3-7-8 |
617
619
  | 제목 없이 흰 면으로만 묶는다 | `SCard` | §3-7-8 |
618
620
  | 통합 계정 로그인 화면을 만든다 | `SLoginCard` | §4-6 |
@@ -629,6 +631,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
629
631
  | 하려는 일 | 컴포넌트 | 갈림 |
630
632
  | --- | --- | --- |
631
633
  | 같은 화면에서 보는 관점을 바꾼다 | `STabs` | §3-7-2 |
634
+ | 긴 페이지의 섹션 목록을 옆에 두고, 누르면 그 섹션으로 스크롤하고 스크롤하면 보이는 섹션이 선택되게 한다 | `SSectionNav` — 앱 셸의 좌측 내비게이션이 아니다(그건 `SGnb`). 항목의 `value` 는 이동할 섹션 요소의 `id` 이고, `items` 순서는 문서의 섹션 순서와 같아야 한다. 스크롤은 섹션에서 가장 가까운 스크롤 조상에서 일어나므로 `window` 스크롤을 직접 다루지 않는다. 긴 페이지에서 처음부터 특정 섹션으로 열려면 `defaultValue` 를 준다(그 섹션으로 바로 이동하고 선택한 채 시작한다 — 어떤 섹션인지는 앱이 URL 등에서 읽어 넘긴다). 같은 `id` 의 섹션이 한 문서에 둘 이상이면 `scrollContainer` 로 영역을 한정한다. 다른 화면으로 이동하는 메뉴가 아니다 | |
632
635
  | 긴 목록을 페이지로 끊는다 | `SPagination` | §4-2 |
633
636
  | 여러 단계의 진행 위치를 보여준다 | `SStepper` | |
634
637
 
@@ -1520,7 +1523,7 @@ tableRef.current.scrollToRow(row); // 복원
1520
1523
  | --- | --- |
1521
1524
  | 페이지·모달의 일반 액션 | `SButton` — 라벨 폭만큼만 차지한다 |
1522
1525
  | 목록에서 항목 하나를 고르게 한다 | `SListItem` · `STree` (§3-7-6·§3-7-7) |
1523
- | 좌측 내비게이션의 메뉴 | `SGnb` 의 `menus` (§4-1) |
1526
+ | 앱 셸 좌측 내비게이션의 메뉴 | `SGnb` 의 `menus` (§4-1) |
1524
1527
  | **GNB system 패널에서 설정·연결 상태를 한 줄씩 쌓고, 그 줄을 눌러 들어가게 한다** | **`SSystemActionButton`** |
1525
1528
 
1526
1529
  **무엇이 그려지는지는 `type` 이 정한다.** 타입마다 다른 값만 `option` 으로 받으므로, 타입에 맞지 않는 `option` 은 타입 에러가 된다.
@@ -1558,6 +1561,7 @@ tableRef.current.scrollToRow(row); // 복원
1558
1561
  - **태그의 색·이름을 밖에서 직접 주지 않는다** (`status`). `option.color`·`option.label` 은 없다 — 지금 상태가 가리키는 `options` 칸이 곧 태그다. 색이 상태의 뜻이라 둘이 어긋나면 안 되기 때문이다.
1559
1562
  - **상태 메뉴의 색은 칸마다 준다** — 점과 글자가 그 상태의 색으로 함께 물든다. 상태는 색 자체가 뜻이라 고르는 자리에서도 색을 보고 고른다.
1560
1563
  - `switch` 는 메뉴를 갖지 않는다 — 우측 문구가 "지금 값"이 아니라 보조 조작 문구라, 고를 목록이 있으면 그것은 `subSelect` 다.
1564
+ - **라벨 옆에 뱃지·카운트를 붙일 때는 `labelSlot` 을 쓴다** (`account` `select` `switch` `subSelect`). 라벨이 길면 라벨만 잘리고 슬롯은 밀리지 않는다. 행 전체가 버튼이라 **슬롯에 버튼·링크를 넣지 않는다**(button 중첩). `status` 는 태그가 라벨 자리를 차지해 받지 않는다. 텍스트를 넘기면 라벨과 같은 서체·색을 상속하고, 색을 바꿀 때는 토큰(`--sys-color-*`)으로 덮는다(고정 색은 어두운 면에서 묻힌다). 라벨 자체의 색은 바꾸지 못한다.
1561
1565
  - 높이·라운드·아이콘 크기·좌우 여백은 전부 토큰이 넣는다. 직접 주지 않는다.
1562
1566
 
1563
1567
  #### 3-5-8. `SAccountListBox` — 계정 행을 눌러 뜨는 계정 패널
@@ -2410,6 +2414,7 @@ createRoot(document.getElementById('root')!).render(
2410
2414
  - **`variant` 는 필수이고, 앱 전체에서 하나로 고정한다.** 어떤 페이지는 `"bar"`(높이 고정 + 하단 구분선), 다른 페이지는 `"plain"`(최소 높이) 로 섞어 쓰지 않는다. 프로젝트에서 하나를 고르면(예: 전부 `"bar"`) 모든 페이지 헤더가 그 값을 쓴다. **기본값이 없는 것도 이 규칙 때문이다** — 기본값이 있으면 안 준 페이지만 조용히 다른 모양이 되어 메뉴를 옮길 때마다 제목 줄이 튄다. 셸을 한 번 감싸 쓰면 지정하는 자리는 `AppShell` 한 곳이다. `SLayout` 의 `header`(`"fix" | "full"`)와는 다른 축이다 — 그쪽은 상단바가 GNB 컬럼 안에 있는지 화면 전폭인지를 정한다.
2411
2415
  - **`slot`·`onBack` 도 페이지 성격이 실제로 다른 경우가 아니면 있는 대로 통일한다.** "목록 페이지엔 없고 상세·등록 페이지엔 있다"처럼 화면 종류에 따라 갈리는 것은 허용되지만, 같은 종류의 화면끼리는 임의로 넣었다 뺐다 하지 않는다.
2412
2416
  - **`slot` 은 `ReactNode` 를 그대로 받지만, 원칙은 `size="sm"` 버튼 위주로만 채운다.** `STextLink`·복잡한 커스텀 마크업을 슬롯에 넣지 않는다 — 그 이상이 필요하면 페이지 헤더가 아니라 §4-2 의 `STableBar` 처럼 본문 쪽 액션 자리를 쓴다.
2417
+ - **제목에 붙는 태그·배지는 `slot` 이 아니라 `titleSlot` 에 둔다.** `titleSlot` 은 타이틀 바로 오른쪽(`bar`·`plain` 모두 타이틀과 같은 줄)에 놓이고 간격은 컴포넌트가 준다. `slot` 은 오른쪽 끝이라 제목과 떨어지므로 "기본 그룹" 같은 제목 수식 요소를 두면 안 된다. `subText` 에 노드를 억지로 넣지도 않는다 — `subText` 는 문자열 부제이고 `plain` 에서는 타이틀 아래로 내려간다.
2413
2418
 
2414
2419
  **셸 밖의 단독 화면(로그인·온보딩 등)에서도 같은 제목 영역을 쓸 수 있다.** 이때는 페이지 열이 없으므로 `scrolled` 가 앱 몫이 된다.
2415
2420
 
@@ -2455,6 +2460,23 @@ import { SModalOutlet } from 'sellmate-design-system-react';
2455
2460
 
2456
2461
  `SModal.confirm/loading/create` 로 띄운 모달이 그려지는 자리다. outlet 이 앱 트리 안에 있어야 모달이 앱의 Context(QueryClient·Router·Theme 등)를 상속한다 — outlet 이 없으면 모달은 뜨지만 별도 React 루트라 Provider 가 닿지 않는다(§3-3-4). 모달은 언제나 `body` 로 portal 되므로 outlet 을 어디에 두든 레이아웃에는 영향이 없고, **셸 안에 넣을 필요도 없다.** 토스트를 쓴다면 `SToastContainer` 도 같은 자리에 둔다.
2457
2462
 
2463
+ **컴포넌트가 내장한 문구(aria-label·placeholder·"전체" 등)의 언어는 `SLocaleProvider` 가 정한다 — 앱 루트에 한 번 두고, `SModalOutlet` 은 그 안쪽에 둔다.** 안쪽에 두어야 명령형 모달도 같은 로케일을 상속한다. Provider 가 없으면 한국어다.
2464
+
2465
+ ```tsx
2466
+ import { SLocaleProvider, SModalOutlet } from 'sellmate-design-system-react';
2467
+
2468
+ <SLocaleProvider locale={userLocale}>
2469
+ <RouterProvider router={router} />
2470
+ <SModalOutlet />
2471
+ </SLocaleProvider>;
2472
+ ```
2473
+
2474
+ - 지원 로케일은 `SLOCALES` 에 있다. `en-US` 처럼 지역이 붙어도 되고, **지원하지 않는 값은 예외 없이 한국어로 폴백한다.** `zh` 는 간체 문구라 `zh-TW` 도 간체로 나온다.
2475
+ - **`ja`·`zh` 문구는 원어민 검수 전 초안이다.** 사용자에게 노출하기 전에 검수한다.
2476
+ - 일부 문구만 바꾸려면 `messages` 로 덮어쓴다 — 나머지는 로케일 문구를 유지한다. `messages` 는 모듈 상수나 `useMemo` 로 안정시킨다(렌더마다 새 객체를 만들면 하위 컴포넌트가 매번 다시 그려진다).
2477
+ - 개별 prop(`placeholder` 등)을 직접 주면 로케일 문구보다 prop 이 우선한다. **내장 문구를 앱이 직접 번역해 prop 으로 넘기지 않는다** — Provider 가 이미 처리한다.
2478
+ - 아직 로케일을 따르는 컴포넌트는 `SPagination`·`SSelect` 뿐이고, 나머지는 순차로 옮기는 중이다. 로케일을 바꿔도 그 밖의 컴포넌트 문구는 한국어로 남는다.
2479
+
2458
2480
  **최소 너비는 `SLayout` 이 보장한다 — 앱이 `min-w-*` 를 직접 주지 않는다.** 창이 최소 너비(`SLAYOUT_MIN_WIDTH`, GNB 포함한 전체 기준)보다 좁아지면 GNB·상단바는 제자리에 남고 **`SPage` 안에만 가로 스크롤이 생긴다.** 문서(브라우저 창)에는 가로 스크롤이 생기지 않는다. 그래서 셸을 감싸는 요소에 `min-width` 나 `overflow-x` 를 걸지 않는다 — 걸면 창 전체가 스크롤되어 GNB 가 화면 밖으로 밀린다.
2459
2481
 
2460
2482
  **창이 최소 너비보다 넓을 때 본문을 어떻게 세울지는 `SPage` 의 `contentWidth` 가 정한다 — 폭을 직접 계산하지 않는다.** 넓은 모니터에서 본문이 끝까지 늘어나 성기어지는 화면이 있으므로 세 가지 중 하나를 고른다.
@@ -55,6 +55,7 @@ export declare const ICONS: {
55
55
  readonly coupon: (p: IconRenderProps) => import("react").JSX.Element;
56
56
  readonly dashboard: (p: IconRenderProps) => import("react").JSX.Element;
57
57
  readonly date: (p: IconRenderProps) => import("react").JSX.Element;
58
+ readonly dollar: (p: IconRenderProps) => import("react").JSX.Element;
58
59
  readonly dot: (p: IconRenderProps) => import("react").JSX.Element;
59
60
  readonly download: (p: IconRenderProps) => import("react").JSX.Element;
60
61
  readonly drag: (p: IconRenderProps) => import("react").JSX.Element;
@@ -62,6 +63,8 @@ export declare const ICONS: {
62
63
  readonly etc: (p: IconRenderProps) => import("react").JSX.Element;
63
64
  readonly event: (p: IconRenderProps) => import("react").JSX.Element;
64
65
  readonly focus: (p: IconRenderProps) => import("react").JSX.Element;
66
+ readonly fullscreen: (p: IconRenderProps) => import("react").JSX.Element;
67
+ readonly fullscreenExit: (p: IconRenderProps) => import("react").JSX.Element;
65
68
  readonly global: (p: IconRenderProps) => import("react").JSX.Element;
66
69
  readonly helpFill: (p: IconRenderProps) => import("react").JSX.Element;
67
70
  readonly helpOutline: (p: IconRenderProps) => import("react").JSX.Element;
@@ -10,6 +10,7 @@
10
10
  |------|------|---------|-------------|
11
11
  | `title` | `string` | — | 타이틀 (필수) |
12
12
  | `subText?` | `string` | — | 서브 텍스트. `bar` 면 타이틀 오른쪽에, `plain` 이면 타이틀 아래에 놓인다. |
13
+ | `titleSlot?` | `ReactNode` | — | 타이틀 바로 오른쪽 자리. 태그·배지처럼 제목에 붙는 요소가 온다. `bar`·`plain` 모두 타이틀과 같은 줄(세로 가운데)에 놓이고, `plain` 의 서브 텍스트는 그 아래에 그대로 남는다. 오른쪽 끝 액션은 `slot` 이다 — 이 자리와 헷갈리지 않는다. |
13
14
  | `variant` | `SPageHeaderVariant` | — | 제목 영역의 모양 — **필수다.** - `plain`: 최소 높이(상하 패딩 안에서 타이틀 한 줄 높이로 결정) + 구분선 없음, 서브 텍스트가 타이틀 아래로 내려간다. - `bar`: 높이 고정 + 하단 구분선, 서브 텍스트가 타이틀과 같은 줄. 기본값을 두지 않는 이유는 이 값이 **앱 전체에서 하나로 고정돼야 하는 값**이기 때문이다. 기본값이 있으면 안 준 페이지만 조용히 다른 모양이 되어, 메뉴를 옮길 때 제목 줄의 높이와 구분선이 페이지마다 튄다. 셸을 한 번 감싸 쓰면(§4-1 AppShell) 지정하는 자리도 한 곳이다. 배경은 두 베리에이션 모두 흰 면이다. `SLayout` 의 `header`(`'fix' | 'full'`)와는 다른 축이다 — 그쪽은 상단바가 GNB 컬럼 안에 있는지 화면 전폭인지를 정한다. |
14
15
  | `slot?` | `ReactNode` | — | 오른쪽 끝 커스텀 슬롯. 가이드 링크·액션 버튼 등 페이지마다 다른 것이 온다. |
15
16
  | `scrolled?` | `boolean` | — | 아래 콘텐츠가 스크롤을 시작했는지. `plain` 일 때만 의미가 있다: 스크롤이 시작되면 그림자(floating)가 들어가 스크롤되는 콘텐츠 위에 뜬 것처럼 보인다. 배경은 흰 면 그대로다 — scrolled 가 더하는 것은 그림자뿐이다. `SLayout` 안에 놓았으면 **주지 않는다** — 같은 열의 `SPage` 가 자기 스크롤 상태를 올려 자동으로 들어온다. 스크롤 컨테이너를 앱이 직접 쥔 단독 배치에서만 `onScroll` 에서 준다. |
@@ -5,6 +5,12 @@ export interface SPageHeaderProps extends Omit<HTMLAttributes<HTMLElement>, 'slo
5
5
  title: string;
6
6
  /** 서브 텍스트. `bar` 면 타이틀 오른쪽에, `plain` 이면 타이틀 아래에 놓인다. */
7
7
  subText?: string;
8
+ /**
9
+ * 타이틀 바로 오른쪽 자리. 태그·배지처럼 제목에 붙는 요소가 온다.
10
+ * `bar`·`plain` 모두 타이틀과 같은 줄(세로 가운데)에 놓이고, `plain` 의 서브 텍스트는 그 아래에 그대로 남는다.
11
+ * 오른쪽 끝 액션은 `slot` 이다 — 이 자리와 헷갈리지 않는다.
12
+ */
13
+ titleSlot?: ReactNode;
8
14
  /**
9
15
  * 제목 영역의 모양 — **필수다.**
10
16
  *
@@ -0,0 +1,32 @@
1
+ # SSectionNav
2
+
3
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
4
+
5
+ ### SSectionNav
6
+
7
+ #### Props
8
+
9
+ | Prop | Type | Default | Description |
10
+ |------|------|---------|-------------|
11
+ | `'items'` | `SSectionNavItem[]` | — | 항목 목록 — 문서에 놓인 섹션 순서와 같아야 한다 |
12
+ | `'value'?` | `string` | — | 선택된 항목의 value. 주면 제어형이고, 없으면 스크롤 위치에 따라 스스로 정한다 |
13
+ | `'defaultValue'?` | `string` | — | 비제어일 때 처음 진입할 value — 그 섹션으로 애니메이션 없이 바로 이동해 선택한 채 시작한다. 섹션이 나중에 그려지면 나타났을 때 이동한다. 그 전에 사용자가 스크롤했으면 이동하지 않는다. 이동한 뒤에는 스크롤 위치를 따라간다 |
14
+ | `'onValueChange'?` | `(value: string) => void` | — | 선택이 바뀔 때 — 항목을 눌렀을 때와 스크롤로 섹션이 바뀔 때 호출된다. 처음 보이는 섹션으로 시작할 때와 이미 선택된 항목을 눌렀을 때는 호출되지 않는다 |
15
+ | `'scrollContainer'?` | `RefObject<HTMLElement \| null>` | — | 섹션을 찾고 스크롤할 영역. 없으면 문서 전체에서 id 로 섹션을 찾고 가장 가까운 스크롤 조상을 쓴다. 같은 id 의 섹션이 한 문서에 둘 이상 있을 때(같은 화면을 여러 번 그리는 경우 등) 영역을 지정한다 |
16
+ | `'aria-label'?` | `string` | — | 내비게이션 랜드마크 이름 — 한 화면에 내비게이션이 여럿일 때 구분한다 |
17
+ | `'className'?` | `string` | — | |
18
+ | `'style'?` | `CSSProperties` | — | |
19
+
20
+ ## Types
21
+
22
+ ### SSectionNavItem
23
+
24
+ ```ts
25
+ export interface SSectionNavItem {
26
+ /** 항목에 표시할 텍스트 */
27
+ label: string;
28
+ /** 이동할 섹션 요소의 `id` — 목록 안에서 고유해야 한다 */
29
+ value: string;
30
+ }
31
+ ```
32
+
@@ -0,0 +1,40 @@
1
+ import { type CSSProperties, type RefObject } from 'react';
2
+ export interface SSectionNavItem {
3
+ /** 항목에 표시할 텍스트 */
4
+ label: string;
5
+ /** 이동할 섹션 요소의 `id` — 목록 안에서 고유해야 한다 */
6
+ value: string;
7
+ }
8
+ export interface SSectionNavProps {
9
+ /** 항목 목록 — 문서에 놓인 섹션 순서와 같아야 한다 */
10
+ 'items': SSectionNavItem[];
11
+ /** 선택된 항목의 value. 주면 제어형이고, 없으면 스크롤 위치에 따라 스스로 정한다 */
12
+ 'value'?: string;
13
+ /**
14
+ * 비제어일 때 처음 진입할 value — 그 섹션으로 애니메이션 없이 바로 이동해 선택한 채 시작한다.
15
+ * 섹션이 나중에 그려지면 나타났을 때 이동한다. 그 전에 사용자가 스크롤했으면 이동하지 않는다.
16
+ * 이동한 뒤에는 스크롤 위치를 따라간다
17
+ */
18
+ 'defaultValue'?: string;
19
+ /**
20
+ * 선택이 바뀔 때 — 항목을 눌렀을 때와 스크롤로 섹션이 바뀔 때 호출된다.
21
+ * 처음 보이는 섹션으로 시작할 때와 이미 선택된 항목을 눌렀을 때는 호출되지 않는다
22
+ */
23
+ 'onValueChange'?: (value: string) => void;
24
+ /**
25
+ * 섹션을 찾고 스크롤할 영역. 없으면 문서 전체에서 id 로 섹션을 찾고 가장 가까운 스크롤 조상을 쓴다.
26
+ * 같은 id 의 섹션이 한 문서에 둘 이상 있을 때(같은 화면을 여러 번 그리는 경우 등) 영역을 지정한다
27
+ */
28
+ 'scrollContainer'?: RefObject<HTMLElement | null>;
29
+ /** 내비게이션 랜드마크 이름 — 한 화면에 내비게이션이 여럿일 때 구분한다 */
30
+ 'aria-label'?: string;
31
+ 'className'?: string;
32
+ 'style'?: CSSProperties;
33
+ }
34
+ /**
35
+ * SSectionNav — 같은 페이지 안의 섹션으로 이동하는 사이드 메뉴.
36
+ * 항목을 누르면 해당 id 의 섹션으로 스크롤하고, 스크롤하면 보이는 섹션에 맞춰 선택이 따라간다.
37
+ * 스크롤은 섹션에서 가장 가까운 스크롤 조상(SPage 의 본문 등)에서 일어난다.
38
+ * 컴포넌트 토큰(--cmp-sideNav-*) 기반. 앱 셸의 좌측 내비게이션은 SGnb 가 맡는다.
39
+ */
40
+ export declare const SSectionNav: import("react").ForwardRefExoticComponent<SSectionNavProps & import("react").RefAttributes<HTMLElement>>;
@@ -0,0 +1 @@
1
+ export { SSectionNav, type SSectionNavProps, type SSectionNavItem } from './SSectionNav';
@@ -0,0 +1,27 @@
1
+ export interface ScrollMetrics {
2
+ clientHeight: number;
3
+ scrollTop: number;
4
+ scrollHeight: number;
5
+ }
6
+ /**
7
+ * 활성 섹션의 인덱스를 고른다.
8
+ * @param tops 각 섹션 상단의 스크롤 영역 위쪽 기준 거리(px) — 항목 순서 = 문서 순서여야 한다
9
+ * 끝까지 스크롤했고 마지막 섹션이 화면에 보이면, 그 섹션이 짧아 선에 닿지 못해도 마지막 항목을 고른다.
10
+ */
11
+ export declare function pickActiveIndex(tops: number[], m: ScrollMetrics): number;
12
+ /** id 로 섹션을 찾는다. scope 를 주면 그 안에서만 찾아 같은 id 가 문서에 또 있어도 섞이지 않는다 */
13
+ export declare function findSection(id: string, scope: HTMLElement | null): HTMLElement | null;
14
+ /**
15
+ * 요소에서 가장 가까운 세로 스크롤 조상. 없으면 문서 스크롤 요소.
16
+ * body·html 의 overflow 는 뷰포트로 전파되어 스스로 스크롤하지 않으므로 건너뛴다
17
+ */
18
+ export declare function findScrollParent(el: HTMLElement): HTMLElement;
19
+ export declare const isRootScroller: (el: HTMLElement) => boolean;
20
+ export declare const readMetrics: (container: HTMLElement) => ScrollMetrics;
21
+ /** 섹션 상단이 스크롤 영역 위쪽에서 떨어진 거리(px) */
22
+ export declare const sectionTop: (section: HTMLElement, container: HTMLElement) => number;
23
+ /**
24
+ * 섹션 상단이 스크롤 영역 위쪽에 맞도록 스크롤한다.
25
+ * 섹션의 `scroll-margin-top` 만큼 비워 고정 헤더 아래로 들어가지 않게 한다
26
+ */
27
+ export declare function scrollToSection(section: HTMLElement, container: HTMLElement, behavior?: 'smooth' | 'instant'): void;
@@ -16,8 +16,8 @@
16
16
  | `valueDisplay?` | `SSelectValueDisplay` | `'text'` | 트리거에 선택값을 보여주는 방식. - `text`: 선택 라벨을 쉼표로 이어 한 줄로 보여준다. 넘치면 말줄임한다. - `chip`: 선택값마다 칩을 낸다. 칩의 × 를 누르면 그 값만 선택에서 빠지고, 드롭다운은 열리지 않는다. 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다. `chip` 은 `multi`·`multi_depth`·`multi_tree` 에서만 동작한다. 단일 선택 type 에서는 무시하고 `text` 로 보여준다. 전체 선택이면 칩 대신 `allSelectedLabel` 을 보여준다. `multi_depth`·`multi_tree` 에서 그룹의 하위 리프를 전부 고르면 리프 칩 대신 그룹명 칩 하나로 묶고, 그 칩의 × 는 그룹의 리프를 한꺼번에 뺀다. 비활성(select 자체나 해당 옵션)인 칩에는 × 를 내지 않는다. |
17
17
  | `showSearch?` | `boolean` | `false` | 검색 입력 사용 |
18
18
  | `showSelectAll?` | `boolean` | `false` | 전체선택 옵션 사용 (multi 전용) |
19
- | `allSelectedLabel?` | `string` | `'전체'` | 전체선택 레이블 |
20
- | `placeholder?` | `string` | `'선택'` | placeholder |
19
+ | `allSelectedLabel?` | `string` | — | 전체선택 레이블. 생략하면 `SLocaleProvider` 로케일의 기본 문구(ko: "전체")를 쓴다 |
20
+ | `placeholder?` | `string` | — | placeholder. 생략하면 `SLocaleProvider` 로케일의 기본 문구(ko: "선택")를 쓴다 |
21
21
  | `disabled?` | `boolean` | `false` | 비활성 |
22
22
  | `clearable?` | `boolean` | `false` | 선택값 지우기(×) 버튼 노출. 선택값이 있고 비활성이 아닐 때만 나타나며, 누르면 드롭다운을 열지 않고 값만 비운다. |
23
23
  | `error?` | `boolean` | `false` | 에러 상태 |
@@ -75,9 +75,9 @@ export interface SSelectProps<TValue extends SSelectChangeValue = SSelectChangeV
75
75
  showSearch?: boolean;
76
76
  /** 전체선택 옵션 사용 (multi 전용) */
77
77
  showSelectAll?: boolean;
78
- /** 전체선택 레이블 */
78
+ /** 전체선택 레이블. 생략하면 `SLocaleProvider` 로케일의 기본 문구(ko: "전체")를 쓴다 */
79
79
  allSelectedLabel?: string;
80
- /** placeholder */
80
+ /** placeholder. 생략하면 `SLocaleProvider` 로케일의 기본 문구(ko: "선택")를 쓴다 */
81
81
  placeholder?: string;
82
82
  /** 비활성 */
83
83
  disabled?: boolean;
@@ -10,6 +10,7 @@
10
10
  |------|------|---------|-------------|
11
11
  | `type` | `'account'` | — | 계정 행 |
12
12
  | `label?` | `string` | — | 라벨 텍스트 |
13
+ | `labelSlot?` | `ReactNode` | — | 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다. 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다. 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩). |
13
14
  | `option` | `SSystemActionButtonAccountOption` | — | 누르면 뜨는 계정 리스트박스. **필수다** — 계정 행은 늘 이 패널의 트리거이고, 눌러도 아무것도 뜨지 않는 계정 행은 없다. 아이콘은 `user` 로 고정이라 여기서 받지 않는다. |
14
15
 
15
16
  ### SSystemActionButtonBase
@@ -29,6 +30,7 @@
29
30
  |------|------|---------|-------------|
30
31
  | `type` | `'account' \| 'select' \| 'switch' \| 'subSelect' \| 'status'` | — | 계정 행 |
31
32
  | `label?` | `string` | — | 라벨 텍스트 |
33
+ | `labelSlot?` | `ReactNode` | — | 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다. 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다. 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩). |
32
34
  | `option?` | `<union 5종>` | — | 누르면 뜨는 계정 리스트박스. **필수다** — 계정 행은 늘 이 패널의 트리거이고, 눌러도 아무것도 뜨지 않는 계정 행은 없다. 아이콘은 `user` 로 고정이라 여기서 받지 않는다. |
33
35
 
34
36
  ### SSystemActionButtonSelect
@@ -39,6 +41,7 @@
39
41
  |------|------|---------|-------------|
40
42
  | `type` | `'select'` | — | 화살표만 붙는 행 |
41
43
  | `label?` | `string` | — | 라벨 텍스트 |
44
+ | `labelSlot?` | `ReactNode` | — | 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다. 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다. 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩). |
42
45
  | `option?` | `SSystemActionButtonIconOption` | — | 선행 아이콘. 아이콘 없이 라벨만 두는 행이면 통째로 생략한다 |
43
46
 
44
47
  ### SSystemActionButtonStatus
@@ -49,6 +52,7 @@
49
52
  |------|------|---------|-------------|
50
53
  | `type` | `'status'` | — | 라벨 자리에 상태 태그가 들어가는 행 |
51
54
  | `label?` | `never` | — | 태그가 라벨 자리를 차지하므로 받지 않는다 |
55
+ | `labelSlot?` | `never` | — | 태그가 라벨 자리를 차지하므로 받지 않는다 |
52
56
  | `option` | `SSystemActionButtonStatusOption` | — | 상태 태그 + 고를 목록. **필수다** — 상태 행은 늘 그 상태를 바꾸는 메뉴의 트리거다. |
53
57
 
54
58
  ### SSystemActionButtonSubSelect
@@ -59,6 +63,7 @@
59
63
  |------|------|---------|-------------|
60
64
  | `type` | `'subSelect'` | — | 우측에 지금 선택된 값이 붙는 행 |
61
65
  | `label?` | `string` | — | 라벨 텍스트 |
66
+ | `labelSlot?` | `ReactNode` | — | 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다. 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다. 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩). |
62
67
  | `option` | `SSystemActionButtonSubSelectOption` | — | 선행 아이콘 + 우측 값 + 고를 목록 |
63
68
 
64
69
  ### SSystemActionButtonSwitch
@@ -69,6 +74,7 @@
69
74
  |------|------|---------|-------------|
70
75
  | `type` | `'switch'` | — | 우측에 보조 조작 문구가 붙는 행 |
71
76
  | `label?` | `string` | — | 라벨 텍스트 |
77
+ | `labelSlot?` | `ReactNode` | — | 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다. 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다. 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩). |
72
78
  | `option?` | `SSystemActionButtonTextOption` | — | 선행 아이콘 + 우측 액션 텍스트. 둘 다 두지 않으면 통째로 생략한다 |
73
79
 
74
80
  ### SSystemActionButtonText
@@ -79,6 +85,7 @@
79
85
  |------|------|---------|-------------|
80
86
  | `type` | `'switch' \| 'subSelect'` | — | 우측에 보조 조작 문구가 붙는 행 |
81
87
  | `label?` | `string` | — | 라벨 텍스트 |
88
+ | `labelSlot?` | `ReactNode` | — | 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다. 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다. 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩). |
82
89
  | `option?` | `SSystemActionButtonTextOption \| SSystemActionButtonSubSelectOption` | — | 선행 아이콘 + 우측 액션 텍스트. 둘 다 두지 않으면 통째로 생략한다 |
83
90
 
84
91
  ## Types
@@ -1,4 +1,4 @@
1
- import { type ButtonHTMLAttributes } from 'react';
1
+ import { type ButtonHTMLAttributes, type ReactNode } from 'react';
2
2
  import { type SAccountListBoxContent } from '../SAccountListBox';
3
3
  import { type SIconName } from '../SIcon';
4
4
  import { type STagColor } from '../STag';
@@ -93,6 +93,13 @@ export interface SSystemActionButtonAccountProps extends SSystemActionButtonBase
93
93
  type: 'account';
94
94
  /** 라벨 텍스트 */
95
95
  label?: string;
96
+ /**
97
+ * 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다.
98
+ * 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로
99
+ * 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다.
100
+ * 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩).
101
+ */
102
+ labelSlot?: ReactNode;
96
103
  /**
97
104
  * 누르면 뜨는 계정 리스트박스. **필수다** — 계정 행은 늘 이 패널의 트리거이고, 눌러도 아무것도
98
105
  * 뜨지 않는 계정 행은 없다. 아이콘은 `user` 로 고정이라 여기서 받지 않는다.
@@ -105,6 +112,13 @@ export interface SSystemActionButtonSelectProps extends SSystemActionButtonBaseP
105
112
  type: 'select';
106
113
  /** 라벨 텍스트 */
107
114
  label?: string;
115
+ /**
116
+ * 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다.
117
+ * 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로
118
+ * 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다.
119
+ * 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩).
120
+ */
121
+ labelSlot?: ReactNode;
108
122
  /** 선행 아이콘. 아이콘 없이 라벨만 두는 행이면 통째로 생략한다 */
109
123
  option?: SSystemActionButtonIconOption;
110
124
  }
@@ -114,6 +128,13 @@ export interface SSystemActionButtonSwitchProps extends SSystemActionButtonBaseP
114
128
  type: 'switch';
115
129
  /** 라벨 텍스트 */
116
130
  label?: string;
131
+ /**
132
+ * 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다.
133
+ * 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로
134
+ * 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다.
135
+ * 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩).
136
+ */
137
+ labelSlot?: ReactNode;
117
138
  /** 선행 아이콘 + 우측 액션 텍스트. 둘 다 두지 않으면 통째로 생략한다 */
118
139
  option?: SSystemActionButtonTextOption;
119
140
  }
@@ -123,6 +144,13 @@ export interface SSystemActionButtonSubSelectProps extends SSystemActionButtonBa
123
144
  type: 'subSelect';
124
145
  /** 라벨 텍스트 */
125
146
  label?: string;
147
+ /**
148
+ * 라벨 오른쪽에 붙는 표시용 요소(뱃지·카운트 등). 라벨이 길면 라벨만 잘리고 이 요소는 밀리지 않는다.
149
+ * 텍스트를 넘기면 라벨과 같은 서체·색을 상속한다 — 색을 바꾸려면 넘기는 쪽에서 토큰(`--sys-color-*`)으로
150
+ * 덮고, 고정 색은 `dark`·`darker` 면에서 묻히니 세 색 모두에서 확인한다. 라벨 자체의 색은 바꾸지 못한다.
151
+ * 행 전체가 버튼이라 **버튼·링크 같은 조작 요소는 넣지 않는다**(button 중첩).
152
+ */
153
+ labelSlot?: ReactNode;
126
154
  /** 선행 아이콘 + 우측 값 + 고를 목록 */
127
155
  option: SSystemActionButtonSubSelectOption;
128
156
  }
@@ -134,6 +162,8 @@ export interface SSystemActionButtonStatusProps extends SSystemActionButtonBaseP
134
162
  type: 'status';
135
163
  /** 태그가 라벨 자리를 차지하므로 받지 않는다 */
136
164
  label?: never;
165
+ /** 태그가 라벨 자리를 차지하므로 받지 않는다 */
166
+ labelSlot?: never;
137
167
  /**
138
168
  * 상태 태그 + 고를 목록. **필수다** — 상태 행은 늘 그 상태를 바꾸는 메뉴의 트리거다.
139
169
  */