sellmate-design-system-react 9.0.0-beta.91 → 9.0.0-beta.93

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 (41) hide show
  1. package/AGENTS.md +27 -2
  2. package/dist/components/SBarChart/README.md +1 -0
  3. package/dist/components/SBarChart/SBarChart.d.ts +7 -0
  4. package/dist/components/SBarcodeInput/README.md +2 -0
  5. package/dist/components/SCheckbox/README.md +2 -0
  6. package/dist/components/SGhostButton/README.md +2 -0
  7. package/dist/components/SGnbSystem/README.md +6 -2
  8. package/dist/components/SGnbSystem/SGnbSystem.d.ts +3 -3
  9. package/dist/components/SGnbSystem/gnbSystem.config.d.ts +5 -3
  10. package/dist/components/SIcon/README.md +2 -0
  11. package/dist/components/SInput/README.md +2 -0
  12. package/dist/components/SLineChart/README.md +1 -0
  13. package/dist/components/SLineChart/SLineChart.d.ts +5 -0
  14. package/dist/components/SLineChart/lineChart.config.d.ts +1 -2
  15. package/dist/components/SMeatballButton/README.md +2 -0
  16. package/dist/components/SNumberInput/README.md +2 -0
  17. package/dist/components/SSelect/README.md +8 -3
  18. package/dist/components/SSelect/SSelect.d.ts +17 -3
  19. package/dist/components/SSelect/select.config.d.ts +34 -4
  20. package/dist/components/STable/README.md +1 -1
  21. package/dist/components/STable/STable.d.ts +3 -0
  22. package/dist/components/STag/README.md +8 -0
  23. package/dist/components/STimePicker/README.md +1 -1
  24. package/dist/components/STimePicker/STimePicker.d.ts +3 -7
  25. package/dist/components/STimePicker/TimeListbox.d.ts +21 -0
  26. package/dist/components/STimeRangePicker/README.md +2 -2
  27. package/dist/components/STimeRangePicker/STimeRangePicker.d.ts +5 -1
  28. package/dist/components/STreeTable/STreeTable.examples.d.ts +7 -0
  29. package/dist/index.cjs +1339 -1128
  30. package/dist/index.cjs.map +1 -1
  31. package/dist/index.js +1339 -1128
  32. package/dist/index.js.map +1 -1
  33. package/dist/lib/chart/cartesian.d.ts +1 -3
  34. package/dist/lib/chart/category-labels.d.ts +37 -0
  35. package/dist/lib/chart/use-element-size.d.ts +4 -1
  36. package/dist/lib/mode-listbox.d.ts +10 -0
  37. package/dist/lib/tree-row.d.ts +74 -0
  38. package/dist/llms-full.txt +55 -11
  39. package/dist/llms.txt +27 -2
  40. package/dist/styles.css +12 -37
  41. package/package.json +1 -1
package/AGENTS.md CHANGED
@@ -533,6 +533,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
533
533
  | 정해진 범위 안에서 수치 하나·구간을 끌어서 고르게 한다 | `SSlider` | §3-7-16 |
534
534
  | 바코드를 스캔해 받는다 | `SBarcodeInput` | |
535
535
  | 목록에서 하나 고르게 한다 | `SSelect` | §3-7-2 |
536
+ | 계층(카테고리 > 세부분류)을 접고 펴며 드롭다운에서 고르게 한다 | `SSelect` `type="tree"`·`"multi_tree"` | §3-7-2 — 계층을 늘 펼쳐 보여도 되면 `default_depth`·`multi_depth` |
536
537
  | 선택지를 항상 펼쳐 두고 하나 고르게 한다 | `SRadioGroup` | §3-7-2 |
537
538
  | 버튼 모양으로 모드를 하나 고르게 한다 | `SRadioButton` | §3-7-2 |
538
539
  | 선택지마다 설명이 붙어 한 줄로는 안 된다 | `SRadioCardGroup` | §3-7-2 |
@@ -569,13 +570,14 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
569
570
  | 대화의 메시지 한 건을 보여준다 | `SChatMessage` | |
570
571
  | 대화 중간에 시스템이 알리는 사실을 끼운다 (상담사 배정·대화 종료 등) | `SChatSystemMessage` | 사람이 보낸 말이면 `SChatMessage` |
571
572
  | 나열한 항목을 펼쳐 하위 내용을 보여준다 | `SExpansionList` + `SExpansionItem` | §3-7-7 |
572
- | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 |
573
+ | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 — 폼 값으로 드롭다운에서 고르는 것이면 `SSelect` `type="tree"` |
573
574
  | 계층을 이루는 행들을 여러 열로 보여준다 (카테고리 > 상품 > 옵션) | `STreeTable` | §3-7-7 — 한 줄에 라벨 하나면 `STree` |
574
575
  | 사용자가 순서를 드래그로 바꾸게 한다 | `SDraggableList` + `SDraggableItem` | §3-7-6 |
575
576
  | 날짜별 일정을 한 달치 격자로 펼쳐 보여준다 | `SCalendarBoard` | §3-7-4 |
576
577
  | 항목끼리 크기를 눈으로 견주게 한다 (채널별 매출·상품별 판매량) | `SBarChart` | 정확한 값을 읽어야 하면 `STable` — 그래프는 "어느 쪽이 큰가" 를 답하지 "얼마인가" 를 답하지 않는다 |
577
578
  | 순서가 있는 항목의 **추이**를 보여준다 (일·월별 매출 흐름, 기간별 방문 수) | `SLineChart` | 항목 순서에 뜻이 없으면(채널별·상품별) `SBarChart` — 선은 "이어진다" 는 뜻을 덤으로 얹어, 순서 없는 항목을 이으면 없는 흐름을 만든다. 항목이 대여섯 개 안쪽이고 크기를 견주는 것이 목적이면 막대가 낫다 |
578
579
  | 여러 항목의 추이를 **합계와 함께** 보여준다 (채널별 매출이 쌓여 전체가 되는 흐름) | `SLineChart stacked area` | 합계가 뜻을 갖는 값일 때만 쌓는다. 음수가 섞이거나 더해서 뜻이 없는 값(비율·평균)은 쌓지 말고 겹쳐 그린다 |
580
+ | 항목 이름이 길어 가로축에서 서로 겹친다 (상품명·채널명, `2026-10-01` 같은 날짜) | 순서 없는 항목은 `SBarChart direction="horizontal"` — 이름 열이 가장 긴 이름에 맞춰 넓어진다. 순서가 있어 세로 축을 지켜야 하면(날짜순 막대·`SLineChart`) `rotateCategoryLabels` | 이름이 짧아 겹치지 않으면 켜지 않는다 — 켜면 늘 기울어 읽기만 나빠진다. 기울여도 너무 긴 이름은 차트가 말줄임하고 전체 이름은 툴팁에 뜬다. 말줄임 폭·각도를 직접 주지 않는다. 나란히 놓인 차트는 켜고 끄기를 맞춰야 그림 높이가 같다 |
579
581
  | 항목의 크기와 **그 안의 구성**을 함께 보여준다 (주문 상태별 내역, 유입 경로별 몫) | `SBarChart stacked` | 계열끼리 견주는 것이 목적이면 `stacked` 없이 나란히 세운다. 더해서 뜻이 없는 값(비율·평균)은 쌓지 않는다 — 합계 라벨이 거짓말이 된다 |
580
582
  | 한 시점의 **전체를 몇 개의 몫으로** 나눠 보여준다 (채널별 매출 비중, 회원 등급 구성) | `SPieChart` | 조각이 대여섯 개를 넘거나 몫끼리 크기를 견주는 것이 목적이면 `SBarChart` — 사람은 각도보다 길이를 정확히 견준다. 순서가 있는 추이(월별)는 몫이 아니라 흐름이라 `SLineChart`. 0·음수는 그려지지 않으므로 증감은 원으로 나타내지 않는다. 조각은 큰 순으로 넘긴다. 폭은 부모를 따르고 그림은 그 폭의 정사각형이다 — 폭이 필요하면 `className` 으로 폭만 주고 높이는 주지 않는다 (`SDonutChart` 도 같다) |
581
583
  | 한 시점의 전체를 몫으로 나누되 **가운데가 빈 고리 모양**으로 보여준다 (시안이 도넛일 때) | `SDonutChart` | 쓰임·데이터 규칙은 `SPieChart` 와 같고 모양만 다르다 — 시안이 정한 쪽을 쓴다. **구멍에 합계·라벨을 겹쳐 올리지 않는다.** 합계 같은 값이 필요하면 차트 바깥(카드 제목·요약 값)에 적는다. 여러 기간에 걸친 구성 변화는 원을 여러 개 늘어놓지 말고 `SBarChart stacked` |
@@ -1768,9 +1770,25 @@ tableRef.current.scrollToRow(row); // 복원
1768
1770
  - 카드 안에 상태 배지를 넣으려면 `tag` 슬롯에 `STag` 를 준다. 라벨 문자열에 "(추천)" 처럼 섞어 쓰지 않는다.
1769
1771
  - **카드처럼 생겼다고 `SCard`/`SSectionHeaderCard` 로 감싸지 않는다.** `SRadioCard` 자체가 완결된 요소이고, 나열 간격은 `SRadioCardGroup` 의 `direction` 이 맞춘다 (§2-2).
1770
1772
 
1773
+ ##### 후보에 상하 관계가 있으면 — depth vs tree
1774
+
1775
+ 계층은 `options` 의 `children` 으로 만든다. 평평한 `default`·`multi` 에 분류명을 라벨에 섞어 늘어놓지 않는다. 남는 선택은 **계층을 어떻게 보여주는가**와 **그룹이 값이 되는가**다.
1776
+
1777
+ | 상황 | `type` |
1778
+ | --- | --- |
1779
+ | 그룹이 몇 개 안 돼 늘 펼쳐 둬도 한눈에 읽힌다. 그룹은 분류 헤더일 뿐 값이 아니다 | `default_depth` · `multi_depth` |
1780
+ | 그룹·단계가 많아 다 펼치면 목록이 길어진다 — 접어 두고 필요한 갈래만 편다 | `tree` · `multi_tree` |
1781
+ | **그룹 자체도 값**이다 (예: "패션의류" 전체를 하나의 조건으로 고른다) — 단일 선택 | `tree` |
1782
+
1783
+ - **값에 무엇이 담기는가.** `default_depth`·`multi_depth`·`multi_tree` 는 언제나 **리프만** 담긴다 — `multi_tree`·`multi_depth` 의 그룹 체크박스는 그 아래 리프를 한꺼번에 넣고 뺄 뿐, 그룹의 `value` 는 값이 되지 않는다. 그룹의 `value` 가 값으로 오는 것은 `tree` 뿐이다.
1784
+ - **펼침 상태는 `SSelect` 가 쥔다.** 열 때마다 선택값을 품은 그룹이 펼쳐지고, 검색 중에는 걸린 줄이 보이도록 결과를 전부 펼친다. 앱이 펼칠 그룹을 따로 들고 있지 않는다.
1785
+ - 그룹의 `disabled` 는 그 줄의 선택만 막는다 — 마우스(화살표)로도 키보드(→)로도 접고 펴기는 되므로 아래의 고를 수 있는 자식에 닿는 길은 남는다.
1786
+ - 하위가 전부 비활성이면 `multi_tree`·depth 타입은 그룹도 함께 잠그므로 앱이 어미에 `disabled` 를 다시 달 필요가 없다. `tree` 는 그룹 자체가 값이라 하위가 막혀도 그룹은 고를 수 있다 — 그룹까지 막으려면 그룹에 `disabled` 를 직접 준다.
1787
+ - 드롭다운 없이 화면에 계층을 펼쳐 두고 여러 개를 체크하게 하는 것이면 `SSelect` 가 아니라 `STree` 다 (§3-7-7).
1788
+
1771
1789
  ##### 여러 개 고른 값을 칩으로 보여줄 때 — `valueDisplay="chip"`
1772
1790
 
1773
- - **`type="multi"`·`"multi_depth"` 에서 `valueDisplay="chip"` 을 주면** 선택값이 트리거에 칩으로 뜨고, 칩의 × 로 하나씩 뺄 수 있다. 기본(`text`)은 라벨을 쉼표로 이어 한 줄로 말줄임한다. 고른 값 하나하나를 확인하고 바로 빼야 하는 자리면 `chip`, 몇 개 골랐는지만 보이면 되는 조회 필터면 `text` 를 쓴다.
1791
+ - **`type="multi"`·`"multi_depth"`·`"multi_tree"` 에서 `valueDisplay="chip"` 을 주면** 선택값이 트리거에 칩으로 뜨고, 칩의 × 로 하나씩 뺄 수 있다. 기본(`text`)은 라벨을 쉼표로 이어 한 줄로 말줄임한다. 고른 값 하나하나를 확인하고 바로 빼야 하는 자리면 `chip`, 몇 개 골랐는지만 보이면 되는 조회 필터면 `text` 를 쓴다.
1774
1792
  - **후보가 정해진 목록에서 고르는 것이면 `SSelect` 의 `chip` 이고, 사용자가 값을 직접 타이핑해 쌓는 것이면 `SChipInput` 이다.** 목록에서 고른 값을 `SChipInput` 에 옮겨 담거나, `SSelect` 옆에 `SChip` 을 따로 나열해 선택값을 흉내 내지 않는다.
1775
1793
  - **단일 선택 type 에는 주지 않는다.** 무시되고 `text` 로 보인다. 단일 선택의 값 비우기는 `clearable` 이 맡는다.
1776
1794
  - 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다. 높이·칩 간격은 `SSelect` 가 토큰으로 넣는다 — 직접 주지 않는다.
@@ -1888,6 +1906,13 @@ useEffect(() => {
1888
1906
 
1889
1907
  **`SKeyValueTable` 안에서는 필드마다 `maxWidth` 를 주지 않는다.** 표 안에서 이 상한이 거슬리는 이유는 대개 "같은 행의 다른 필드와 오른쪽 끝이 어긋난다" 이고, 그건 표 전체의 문제다. 표의 `fieldWidth="fill"` 로 한 번에 정한다 (§4-3). 그 표에서 한 필드만 예외로 둘 때만 `options.maxWidth` 를 쓴다.
1890
1908
 
1909
+ ##### 시간 피커 — 분 간격은 `minuteStep`, 범위 순서는 `rangeOrder`
1910
+
1911
+ `STimePicker`·`STimeRangePicker` 는 `[오전/오후] | 시 | 분` 리스트에서 고른다 (직접 타이핑하지 않는다).
1912
+
1913
+ - **분 간격은 `minuteStep` 으로 정한다.** 분 리스트에 그 간격의 분만 나열되므로, 고른 값을 앱에서 다시 반올림하거나 `rules` 로 간격을 검사하지 않는다.
1914
+ - **`STimeRangePicker` 의 "종료가 시작보다 이르면 안 된다" 는 앱이 검증하지 않는다.** 기본 `rangeOrder="strict"` 가 종료 리스트에서 그 시각을 비활성으로 막는다. 자정을 넘는 범위(야간 근무 22:00~02:00 등)를 받아야 할 때만 `rangeOrder="allow-cross-day"` 를 준다.
1915
+
1891
1916
  ##### 값을 지울 수 있게 하려면 `clearable`
1892
1917
 
1893
1918
  `SSelect` · `SDatePicker` · `SDateRangePicker` · `STimePicker` · `STimeRangePicker` 가 같은 규칙으로 갖는다. 값이 있을 때만 지우기 버튼이 나타나고, 누르면 **`onValueChange` 로 `null` 이 온다** (빈 문자열이 아니다). 받는 쪽 상태도 `null` 을 담을 수 있어야 한다.
@@ -20,6 +20,7 @@
20
20
  | `tickCount?` | `number` | `8` | 값 축 눈금 개수 |
21
21
  | `barSize?` | `number` | `BAR_SIZE_MAX` | 막대 두께 상한(px, 24~80). 낮추면 좌우 여백 상한도 같은 비율로 따라 내려온다 |
22
22
  | `showValueLabel?` | `boolean` | `true` | 막대마다 값을 적는다 |
23
+ | `rotateCategoryLabels?` | `boolean` | `false` | 항목 이름을 -45° 기울인다. 이름이 막대 묶음 폭보다 길어 서로 겹칠 때 쓴다. 기울여도 너무 긴 이름은 말줄임되고, 전체 이름은 툴팁 제목에서 읽힌다. 이름이 아주 길면 기울이기보다 `direction='horizontal'` 이 먼저다. 세로 막대에서만 쓴다 — 가로 막대는 이름 열이 가장 긴 이름에 맞춰 넓어지므로 무시한다 |
23
24
  | `showLegend?` | `boolean` | `true` | 범례를 보인다 |
24
25
  | `legendPosition?` | `SBarChartLegendPosition` | `'top'` | 범례 위치 |
25
26
  | `showTooltip?` | `boolean` | `true` | 막대에 마우스를 올리면 값 상자를 띄운다 |
@@ -70,6 +70,13 @@ export interface SBarChartProps {
70
70
  barSize?: number;
71
71
  /** 막대마다 값을 적는다 */
72
72
  showValueLabel?: boolean;
73
+ /**
74
+ * 항목 이름을 -45° 기울인다. 이름이 막대 묶음 폭보다 길어 서로 겹칠 때 쓴다.
75
+ * 기울여도 너무 긴 이름은 말줄임되고, 전체 이름은 툴팁 제목에서 읽힌다.
76
+ * 이름이 아주 길면 기울이기보다 `direction='horizontal'` 이 먼저다.
77
+ * 세로 막대에서만 쓴다 — 가로 막대는 이름 열이 가장 긴 이름에 맞춰 넓어지므로 무시한다
78
+ */
79
+ rotateCategoryLabels?: boolean;
73
80
  /** 범례를 보인다 */
74
81
  showLegend?: boolean;
75
82
  /** 범례 위치 */
@@ -63,6 +63,7 @@ export type SBarcodeInputSize = SFieldSize;
63
63
 
64
64
  - [SField](../SField)
65
65
  - [SGhostButton](../SGhostButton)
66
+ - [STag](../STag)
66
67
 
67
68
  ### Graph
68
69
 
@@ -70,5 +71,6 @@ export type SBarcodeInputSize = SFieldSize;
70
71
  graph TD;
71
72
  SBarcodeInput --> SField
72
73
  SBarcodeInput --> SGhostButton
74
+ SBarcodeInput --> STag
73
75
  style SBarcodeInput fill:#f9f,stroke:#333,stroke-width:4px
74
76
  ```
@@ -36,6 +36,7 @@ export type SCheckboxValue = boolean | unknown[] | null;
36
36
  ### Used by
37
37
 
38
38
  - [SKeyValueTable](../SKeyValueTable)
39
+ - [SSelect](../SSelect)
39
40
  - [STable](../STable)
40
41
  - [STree](../STree)
41
42
 
@@ -49,6 +50,7 @@ export type SCheckboxValue = boolean | unknown[] | null;
49
50
  graph TD;
50
51
  SCheckbox --> SIcon
51
52
  SKeyValueTable --> SCheckbox
53
+ SSelect --> SCheckbox
52
54
  STable --> SCheckbox
53
55
  STree --> SCheckbox
54
56
  style SCheckbox fill:#f9f,stroke:#333,stroke-width:4px
@@ -66,6 +66,7 @@ export type SGhostButtonIntent =
66
66
  - [SPage](../SPage)
67
67
  - [SPopover](../SPopover)
68
68
  - [SSearchInput](../SSearchInput)
69
+ - [SSelect](../SSelect)
69
70
  - [STable](../STable)
70
71
  - [STimePicker](../STimePicker)
71
72
  - [STimeRangePicker](../STimeRangePicker)
@@ -103,6 +104,7 @@ graph TD;
103
104
  SPage --> SGhostButton
104
105
  SPopover --> SGhostButton
105
106
  SSearchInput --> SGhostButton
107
+ SSelect --> SGhostButton
106
108
  STable --> SGhostButton
107
109
  STimePicker --> SGhostButton
108
110
  STimeRangePicker --> SGhostButton
@@ -52,7 +52,7 @@ export interface SGnbSystemAlert {
52
52
  /** 라벨 텍스트. 기본 `'알림'` */
53
53
  label?: string;
54
54
  /**
55
- * 읽지 않은 알림 개수. 1 이상이면 벨이 울리는 아이콘·강조색으로 바뀌고 개수가 붙는다.
55
+ * 읽지 않은 알림 개수. 1 이상이면 벨이 울리는 아이콘·강조색으로 바뀌고 개수 배지가 붙는다.
56
56
  * 개수를 적을 가로가 모자란 자리(접힌 레일 · 기본 폭보다 좁게 줄인 판)에서는 점 배지로 바뀐다.
57
57
  * 표기는 컴포넌트가 맡는다 — 세 자리마다 콤마를 넣어 그리므로 앱이 포맷한 문자열을 넘기지 않는다.
58
58
  */
@@ -154,7 +154,9 @@ export interface SGnbSystemAccount {
154
154
  * 타이포그래피는 CSS 변수가 아니라 `.typo-*` 프리셋으로 나온다.
155
155
  * domainTag.typography → typo-body-sm-medium (12/500/20)
156
156
  * item.label.typography → typo-body-sm-semibold (12/600/20)
157
- * alertButton.count → typo-body-md-bold (13/700/22)
157
+ *
158
+ * 알림 개수는 글자가 아니라 배지(`STag` xs · deep)로 그린다 — 배경·글자색·치수는 태그 토큰
159
+ * (`--cmp-tag-*`)이 쥔다.
158
160
  */
159
161
 
160
162
  /** 색상(표면). light = 흰 면, dark = 오션블루 면. GNB 의 color 를 그대로 따라간다 */
@@ -170,6 +172,7 @@ export const GNB_SYSTEM_COLORS = ['light', 'dark'] as const;
170
172
  - [SIcon](../SIcon)
171
173
  - [SPortal](../SPortal)
172
174
  - [SSystemActionButton](../SSystemActionButton)
175
+ - [STag](../STag)
173
176
  - [STooltip](../STooltip)
174
177
 
175
178
  ### Graph
@@ -181,6 +184,7 @@ graph TD;
181
184
  SGnbSystem --> SIcon
182
185
  SGnbSystem --> SPortal
183
186
  SGnbSystem --> SSystemActionButton
187
+ SGnbSystem --> STag
184
188
  SGnbSystem --> STooltip
185
189
  style SGnbSystem fill:#f9f,stroke:#333,stroke-width:4px
186
190
  ```
@@ -23,7 +23,7 @@ export interface SGnbSystemAlert {
23
23
  /** 라벨 텍스트. 기본 `'알림'` */
24
24
  label?: string;
25
25
  /**
26
- * 읽지 않은 알림 개수. 1 이상이면 벨이 울리는 아이콘·강조색으로 바뀌고 개수가 붙는다.
26
+ * 읽지 않은 알림 개수. 1 이상이면 벨이 울리는 아이콘·강조색으로 바뀌고 개수 배지가 붙는다.
27
27
  * 개수를 적을 가로가 모자란 자리(접힌 레일 · 기본 폭보다 좁게 줄인 판)에서는 점 배지로 바뀐다.
28
28
  * 표기는 컴포넌트가 맡는다 — 세 자리마다 콤마를 넣어 그리므로 앱이 포맷한 문자열을 넘기지 않는다.
29
29
  */
@@ -156,8 +156,8 @@ export interface SGnbSystemProps extends Omit<HTMLAttributes<HTMLDivElement>, 'c
156
156
  * 접힌 패널은 렌더되지 않으므로, 접힌 상태에서도 닿아야 하는 것은 SGnb 의 `foldedTop`·`foldedFooter` 에 둔다.
157
157
  * 상단바는 접어도 남으므로 `top` 에는 접힘 형태가 없다.
158
158
  *
159
- * `alert.count` 가 1 이상이면 벨이 울리는 아이콘(`bellRinging`)과 강조색으로 바뀐다 — light 는 파랑,
160
- * 어두운 면은 노랑(토큰이 정한다). 0 이거나 없으면 조용한 벨(`bell`)에 기본 색이다.
159
+ * `alert.count` 가 1 이상이면 벨이 울리는 아이콘(`bellRinging`)과 강조색으로 바뀌고 개수 배지가 붙는다 —
160
+ * light 는 파랑 배지에 흰 글자, 어두운 면은 노랑 배지에 검은 글자(토큰이 정한다). 0 이거나 없으면 조용한 벨(`bell`)에 기본 색이다.
161
161
  *
162
162
  * 안내 툴팁(`alert.tooltip`)은 문구를 받은 동안 떠 있다가 알림을 누르거나 커서를 빼면 닫힌다.
163
163
  * 다시 띄우는 신호는 문구가 **없음 → 있음** 으로 바뀌는 것이라, 같은 문구도 비웠다 다시 넘기면
@@ -13,7 +13,9 @@ import type { SSystemActionButtonColor } from '../SSystemActionButton';
13
13
  * 타이포그래피는 CSS 변수가 아니라 `.typo-*` 프리셋으로 나온다.
14
14
  * domainTag.typography → typo-body-sm-medium (12/500/20)
15
15
  * item.label.typography → typo-body-sm-semibold (12/600/20)
16
- * alertButton.count → typo-body-md-bold (13/700/22)
16
+ *
17
+ * 알림 개수는 글자가 아니라 배지(`STag` xs · deep)로 그린다 — 배경·글자색·치수는 태그 토큰
18
+ * (`--cmp-tag-*`)이 쥔다.
17
19
  */
18
20
  /** 색상(표면). light = 흰 면, dark = 오션블루 면. GNB 의 color 를 그대로 따라간다 */
19
21
  export declare const GNB_SYSTEM_COLORS: readonly ["light", "dark"];
@@ -48,7 +50,7 @@ export interface GnbSystemColorTokens {
48
50
  domainText: string;
49
51
  /** 알림이 있을 때의 벨 글리프색 */
50
52
  alertIcon: string;
51
- /** 알림 개수(펼침) · 점 배지(접힘) 색 */
53
+ /** 점 배지(접힘·좁은 판) 색 */
52
54
  alertCount: string;
53
55
  /** 알림이 있을 때의 hover 배경. 없으면 행 기본 hover 를 쓴다 */
54
56
  alertHoverBg?: string;
@@ -73,7 +75,7 @@ export interface GnbSystemTopColorTokens {
73
75
  domainText: string;
74
76
  /** 알림이 있을 때의 벨 글리프색 */
75
77
  alertIcon: string;
76
- /** 알림 개수 색 */
78
+ /** 점 배지 색 (상단바는 점 배지를 쓰지 않지만 색표를 패널과 맞춰 둔다) */
77
79
  alertCount: string;
78
80
  /** 알림이 있을 때의 hover 배경. 없으면 행 기본 hover 를 쓴다 */
79
81
  alertHoverBg?: string;
@@ -48,6 +48,7 @@
48
48
  - [SLauncherListBox](../SLauncherListBox)
49
49
  - [SListItem](../SListItem)
50
50
  - [SLoadingModal](../SLoadingModal)
51
+ - [SMeatballButton](../SMeatballButton)
51
52
  - [SNumberInput](../SNumberInput)
52
53
  - [SPagination](../SPagination)
53
54
  - [SPopover](../SPopover)
@@ -96,6 +97,7 @@ graph TD;
96
97
  SLauncherListBox --> SIcon
97
98
  SListItem --> SIcon
98
99
  SLoadingModal --> SIcon
100
+ SMeatballButton --> SIcon
99
101
  SNumberInput --> SIcon
100
102
  SPagination --> SIcon
101
103
  SPopover --> SIcon
@@ -57,6 +57,7 @@
57
57
 
58
58
  - [SField](../SField)
59
59
  - [SGhostButton](../SGhostButton)
60
+ - [STag](../STag)
60
61
 
61
62
  ### Graph
62
63
 
@@ -64,6 +65,7 @@
64
65
  graph TD;
65
66
  SInput --> SField
66
67
  SInput --> SGhostButton
68
+ SInput --> STag
67
69
  SEditor --> SInput
68
70
  SKeyValueTable --> SInput
69
71
  style SInput fill:#f9f,stroke:#333,stroke-width:4px
@@ -22,6 +22,7 @@
22
22
  | `tickCount?` | `number` | `8` | 값 축 눈금 개수 |
23
23
  | `showPoint?` | `boolean` | `true` | 데이터 지점마다 점을 찍는다. 꺼도 짚은 항목의 점은 뜬다 |
24
24
  | `showValueLabel?` | `boolean` | `false` | 점마다 값을 적는다. 기본은 끔 — 선 그래프는 항목이 많은 데이터에 쓰는 일이 잦아 숫자가 서로 붙는다. 항목이 대여섯 개 안쪽일 때만 켠다 |
25
+ | `rotateCategoryLabels?` | `boolean` | `false` | 항목 이름을 -45° 기울인다. 이름이 점 간격보다 길어 서로 겹칠 때 쓴다. 기울여도 너무 긴 이름은 말줄임되고, 전체 이름은 툴팁 제목에서 읽힌다 |
25
26
  | `showLegend?` | `boolean` | `true` | 범례를 보인다 |
26
27
  | `legendPosition?` | `SLineChartLegendPosition` | `'top'` | 범례 위치 |
27
28
  | `showTooltip?` | `boolean` | `true` | 항목에 마우스를 올리면 값 상자를 띄운다 |
@@ -78,6 +78,11 @@ export interface SLineChartProps {
78
78
  * 숫자가 서로 붙는다. 항목이 대여섯 개 안쪽일 때만 켠다
79
79
  */
80
80
  showValueLabel?: boolean;
81
+ /**
82
+ * 항목 이름을 -45° 기울인다. 이름이 점 간격보다 길어 서로 겹칠 때 쓴다.
83
+ * 기울여도 너무 긴 이름은 말줄임되고, 전체 이름은 툴팁 제목에서 읽힌다
84
+ */
85
+ rotateCategoryLabels?: boolean;
81
86
  /** 범례를 보인다 */
82
87
  showLegend?: boolean;
83
88
  /** 범례 위치 */
@@ -48,8 +48,7 @@ export declare const POINT_HOVER_RADIUS = 6;
48
48
  export declare const POINT_HALO_RADIUS = 12;
49
49
  export declare const POINT_HALO_OPACITY = "var(--cmp-chart-line-point-opacity-bg)";
50
50
  /**
51
- * 짚은 점이 실제로 차지하는 반지름 — 바탕 원까지다. 툴팁이 이만큼 비켜서고,
52
- * 양끝 점이 잘리지 않게 스크롤 컨테이너도 이만큼 넓어진다.
51
+ * 짚은 점이 실제로 차지하는 반지름 — 바탕 원까지다. 툴팁이 이만큼 비켜선다.
53
52
  */
54
53
  export declare const POINT_HOVER_EXTENT = 12;
55
54
  /**
@@ -57,11 +57,13 @@ export type SMeatballButtonItem = SDropdownButtonItem;
57
57
  ### Depends on
58
58
 
59
59
  - [SGhostButton](../SGhostButton)
60
+ - [SIcon](../SIcon)
60
61
 
61
62
  ### Graph
62
63
 
63
64
  ```mermaid
64
65
  graph TD;
65
66
  SMeatballButton --> SGhostButton
67
+ SMeatballButton --> SIcon
66
68
  style SMeatballButton fill:#f9f,stroke:#333,stroke-width:4px
67
69
  ```
@@ -73,6 +73,7 @@ export type SNumberInputSize = SFieldSize;
73
73
 
74
74
  - [SField](../SField)
75
75
  - [SIcon](../SIcon)
76
+ - [STag](../STag)
76
77
 
77
78
  ### Graph
78
79
 
@@ -80,6 +81,7 @@ export type SNumberInputSize = SFieldSize;
80
81
  graph TD;
81
82
  SNumberInput --> SField
82
83
  SNumberInput --> SIcon
84
+ SNumberInput --> STag
83
85
  SKeyValueTable --> SNumberInput
84
86
  style SNumberInput fill:#f9f,stroke:#333,stroke-width:4px
85
87
  ```
@@ -12,8 +12,8 @@
12
12
  | `valueAsPrimitive?` | `boolean` | `false` | `value`·`onValueChange` 가 옵션 객체 대신 원시값(string|number)을 주고받는다. **기본값 `false`(옵션 객체)는 유지한다** — 원본(sd-select) 호환 때문이고, 뒤집으면 이 값을 주지 않던 화면이 조용히 다른 모양의 값을 받게 되어 타입으로도 잡히지 않는다. 새로 쓰는 화면은 켜는 쪽이 다루기 쉽다 — 서버로 보내는 것도, 폼 상태에 담는 것도 결국 값 하나이기 때문이다. |
13
13
  | `name?` | `string` | — | 폼 연동용 name 속성 |
14
14
  | `options?` | `SSelectOption[]` | `[]` | 옵션 목록 (children으로 계층 표현) |
15
- | `type?` | `SSelectType` | `'default'` | 타입: default | multi | default_depth | multi_depth |
16
- | `valueDisplay?` | `SSelectValueDisplay` | `'text'` | 트리거에 선택값을 보여주는 방식. - `text`: 선택 라벨을 쉼표로 이어 한 줄로 보여준다. 넘치면 말줄임한다. - `chip`: 선택값마다 칩을 낸다. 칩의 × 를 누르면 그 값만 선택에서 빠지고, 드롭다운은 열리지 않는다. 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다. `chip` 은 `multi`·`multi_depth` 에서만 동작한다. 단일 선택 type 에서는 무시하고 `text` 로 보여준다. 전체 선택이면 칩 대신 `allSelectedLabel` 을 보여준다. `multi_depth` 에서 그룹의 하위 리프를 전부 고르면 리프 칩 대신 그룹명 칩 하나로 묶고, 그 칩의 × 는 그룹의 리프를 한꺼번에 뺀다. 비활성(select 자체나 해당 옵션)인 칩에는 × 를 내지 않는다. |
15
+ | `type?` | `SSelectType` | `'default'` | 타입 — 단일/다중 선택과 계층을 어떻게 보여주는지를 정한다. - `default` · `multi`: 평평한 목록 - `default_depth` · `multi_depth`: 계층을 늘 펼친 그룹 헤더로 보여준다. `default_depth` 의 그룹은 고를 수 없고, `multi_depth` 의 그룹 체크박스는 하위 리프를 한꺼번에 토글한다. - `tree` · `multi_tree`: 계층을 접고 펼 수 있는 트리로 보여준다. 처음에는 접혀 있고, 열 때 선택값을 품은 그룹만 펼친다. 검색 중에는 걸린 줄이 보이도록 전부 펼친다. `tree` 는 그룹(부모)도 값으로 고를 수 있다. `multi_tree` 의 그룹 체크박스는 하위 리프를 한꺼번에 토글하고, 방출값에는 리프만 담긴다(`multi_depth` 와 같다). 키보드 → 는 그룹을 펼치거나(펼쳐져 있으면 첫 자식으로 들어가고), ← 는 접거나 부모 줄로 올라간다. 검색 입력에 포커스가 있으면 커서가 그 방향 끝에 닿아 있을 때만 트리 조작으로 쓴다. 그룹의 `disabled` 는 선택만 막고 접고 펴기는 그대로 된다. `tree` 는 하위가 전부 비활성이어도 그룹을 고를 수 있다 (그룹까지 막으려면 그룹에 `disabled` 를 직접 준다). 드롭다운 안의 줄은 `STree` 와 같은 모양(연결선·화살표·체크박스·라벨 타이포)으로 그린다. |
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
19
  | `allSelectedLabel?` | `string` | `'전체'` | 전체선택 레이블 |
@@ -94,7 +94,8 @@ export interface SSelectOption {
94
94
  ### SSelectType
95
95
 
96
96
  ```ts
97
- export type SSelectType = 'default' | 'multi' | 'default_depth' | 'multi_depth';
97
+ export type SSelectType =
98
+ 'default' | 'multi' | 'default_depth' | 'multi_depth' | 'tree' | 'multi_tree';
98
99
  ```
99
100
 
100
101
  ### SSelectValueDisplay
@@ -113,8 +114,10 @@ export type SSelectValueDisplay = 'text' | 'chip';
113
114
 
114
115
  ### Depends on
115
116
 
117
+ - [SCheckbox](../SCheckbox)
116
118
  - [SCircleProgress](../SCircleProgress)
117
119
  - [SField](../SField)
120
+ - [SGhostButton](../SGhostButton)
118
121
  - [SIcon](../SIcon)
119
122
  - [SPortal](../SPortal)
120
123
  - [SSearchInput](../SSearchInput)
@@ -123,8 +126,10 @@ export type SSelectValueDisplay = 'text' | 'chip';
123
126
 
124
127
  ```mermaid
125
128
  graph TD;
129
+ SSelect --> SCheckbox
126
130
  SSelect --> SCircleProgress
127
131
  SSelect --> SField
132
+ SSelect --> SGhostButton
128
133
  SSelect --> SIcon
129
134
  SSelect --> SPortal
130
135
  SSelect --> SSearchInput
@@ -42,7 +42,21 @@ export interface SSelectProps<TValue extends SSelectChangeValue = SSelectChangeV
42
42
  name?: string;
43
43
  /** 옵션 목록 (children으로 계층 표현) */
44
44
  options?: SSelectOption[];
45
- /** 타입: default | multi | default_depth | multi_depth */
45
+ /**
46
+ * 타입 — 단일/다중 선택과 계층을 어떻게 보여주는지를 정한다.
47
+ * - `default` · `multi`: 평평한 목록
48
+ * - `default_depth` · `multi_depth`: 계층을 늘 펼친 그룹 헤더로 보여준다.
49
+ * `default_depth` 의 그룹은 고를 수 없고, `multi_depth` 의 그룹 체크박스는 하위 리프를 한꺼번에 토글한다.
50
+ * - `tree` · `multi_tree`: 계층을 접고 펼 수 있는 트리로 보여준다. 처음에는 접혀 있고, 열 때 선택값을 품은
51
+ * 그룹만 펼친다. 검색 중에는 걸린 줄이 보이도록 전부 펼친다.
52
+ * `tree` 는 그룹(부모)도 값으로 고를 수 있다. `multi_tree` 의 그룹 체크박스는 하위 리프를 한꺼번에
53
+ * 토글하고, 방출값에는 리프만 담긴다(`multi_depth` 와 같다).
54
+ * 키보드 → 는 그룹을 펼치거나(펼쳐져 있으면 첫 자식으로 들어가고), ← 는 접거나 부모 줄로 올라간다.
55
+ * 검색 입력에 포커스가 있으면 커서가 그 방향 끝에 닿아 있을 때만 트리 조작으로 쓴다.
56
+ * 그룹의 `disabled` 는 선택만 막고 접고 펴기는 그대로 된다. `tree` 는 하위가 전부 비활성이어도 그룹을 고를 수 있다
57
+ * (그룹까지 막으려면 그룹에 `disabled` 를 직접 준다).
58
+ * 드롭다운 안의 줄은 `STree` 와 같은 모양(연결선·화살표·체크박스·라벨 타이포)으로 그린다.
59
+ */
46
60
  type?: SSelectType;
47
61
  /**
48
62
  * 트리거에 선택값을 보여주는 방식.
@@ -50,9 +64,9 @@ export interface SSelectProps<TValue extends SSelectChangeValue = SSelectChangeV
50
64
  * - `chip`: 선택값마다 칩을 낸다. 칩의 × 를 누르면 그 값만 선택에서 빠지고, 드롭다운은 열리지 않는다.
51
65
  * 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다.
52
66
  *
53
- * `chip` 은 `multi`·`multi_depth` 에서만 동작한다. 단일 선택 type 에서는 무시하고 `text` 로 보여준다.
67
+ * `chip` 은 `multi`·`multi_depth`·`multi_tree` 에서만 동작한다. 단일 선택 type 에서는 무시하고 `text` 로 보여준다.
54
68
  * 전체 선택이면 칩 대신 `allSelectedLabel` 을 보여준다.
55
- * `multi_depth` 에서 그룹의 하위 리프를 전부 고르면 리프 칩 대신 그룹명 칩 하나로 묶고,
69
+ * `multi_depth`·`multi_tree` 에서 그룹의 하위 리프를 전부 고르면 리프 칩 대신 그룹명 칩 하나로 묶고,
56
70
  * 그 칩의 × 는 그룹의 리프를 한꺼번에 뺀다.
57
71
  * 비활성(select 자체나 해당 옵션)인 칩에는 × 를 내지 않는다.
58
72
  */
@@ -4,7 +4,7 @@ export interface SSelectOption {
4
4
  disabled?: boolean;
5
5
  children?: SSelectOption[];
6
6
  }
7
- export type SSelectType = 'default' | 'multi' | 'default_depth' | 'multi_depth';
7
+ export type SSelectType = 'default' | 'multi' | 'default_depth' | 'multi_depth' | 'tree' | 'multi_tree';
8
8
  /** 트리거에 선택값을 보여주는 방식 — 쉼표로 이은 텍스트 | 값마다 칩 */
9
9
  export type SSelectValueDisplay = 'text' | 'chip';
10
10
  export interface FlatOption {
@@ -12,12 +12,18 @@ export interface FlatOption {
12
12
  label: string;
13
13
  disabled: boolean;
14
14
  depth: number;
15
- /** children 을 가진 그룹(비선택) 노드 */
15
+ /** children 을 가진 그룹 노드 — 그 자체가 값이 되는 것은 `tree` 타입뿐이다 */
16
16
  isGroup: boolean;
17
17
  raw: string | number;
18
18
  }
19
- /** 트리 옵션을 depth 정보를 유지한 평탄 리스트로 변환. */
20
- export declare function flattenOptions(options: SSelectOption[], depth?: number): FlatOption[];
19
+ /**
20
+ * 트리 옵션을 depth 정보를 유지한 평탄 리스트로 변환.
21
+ *
22
+ * @param inheritDisabled 하위가 전부 비활성인 그룹을 비활성으로 칠 것인가. 그룹이 값이 아닌 타입에서는
23
+ * 고를 것이 없는 그룹이라 잠그는 게 맞지만, 그룹 자체가 값인 `tree` 에서는 자식이 막혔다고 그룹까지
24
+ * 고를 수 없게 되면 안 된다 — 그때는 그룹에 직접 준 `disabled` 만 본다.
25
+ */
26
+ export declare function flattenOptions(options: SSelectOption[], depth?: number, inheritDisabled?: boolean): FlatOption[];
21
27
  /** 선택 가능한(비그룹) 옵션만 */
22
28
  export declare const selectableOptions: (flat: FlatOption[]) => FlatOption[];
23
29
  /**
@@ -27,6 +33,30 @@ export declare const selectableOptions: (flat: FlatOption[]) => FlatOption[];
27
33
  * (multi_depth 부모 체크박스의 상태/카운트/토글 계산에 사용)
28
34
  */
29
35
  export declare function collectGroupLeafValues(flat: FlatOption[], groupIndex: number): string[];
36
+ /**
37
+ * 트리 타입에서 접힌 그룹의 자손을 걷어내고 화면에 남는 줄만 돌려준다.
38
+ * `sourceIndex[i]` 는 남은 i 번째 줄이 입력 `rows` 에서 몇 번째였는가 — 접힌 그룹의 하위 리프는
39
+ * 화면에 없어도 그룹 체크박스가 세야 하므로, 그 계산은 입력 `rows` 기준으로 한다.
40
+ */
41
+ export declare function visibleTreeRows(rows: FlatOption[], isExpanded: (group: FlatOption) => boolean): {
42
+ rows: FlatOption[];
43
+ sourceIndex: number[];
44
+ };
45
+ /**
46
+ * 트리 줄마다의 자리 정보 — 화면에 남은 줄(접힘·검색 반영 뒤) 기준이다.
47
+ * - `isLast`·`ancestorLast`: 연결선용. 자기가 같은 부모 아래 마지막 줄인가, 조상(depth 1 부터 부모까지)이
48
+ * 각자 마지막 줄인가. STree 가 재귀로 내려가며 넘기는 값과 같은 모양을 펴진 목록에서 구한다.
49
+ * - `posInSet`·`setSize`: 같은 부모 아래 몇 번째 / 형제가 모두 몇 개. 가상 스크롤로 일부 줄만 DOM 에
50
+ * 있어도 보조기기가 창 안 줄을 트리 전부로 읽지 않게 `aria-posinset`·`aria-setsize` 로 알린다.
51
+ */
52
+ export declare function treeLineInfo(rows: FlatOption[]): {
53
+ isLast: boolean;
54
+ ancestorLast: boolean[];
55
+ posInSet: number;
56
+ setSize: number;
57
+ }[];
58
+ /** 선택값을 품은 그룹들의 value — 트리를 열 때 고른 항목이 보이도록 펼쳐 둘 그룹이다 */
59
+ export declare function ancestorGroupValues(flat: FlatOption[], selected: Set<string>): Set<string>;
30
60
  /** 라벨에 HTML 태그가 있는지 (원본 isHtmlLabel) */
31
61
  export declare const isHtmlLabel: (label: string) => boolean;
32
62
  /** HTML 라벨에서 태그를 제거한 텍스트 (검색 매칭용, 원본 extractText) */
@@ -67,7 +67,7 @@
67
67
  | `getIsAllChecked` | `(rows: TRow[]) => boolean \| null` | 주어진 행들의 전체 선택 상태 (true/false/null=indeterminate) |
68
68
  | `getPaginationInfo` | `<union 2종>` | 내부 페이지네이션 정보 (internalPagination 아니면 null) |
69
69
  | `getStickyStyle` | `(colIdx: number) => CSSProperties` | 컬럼 sticky 스타일 (CSS 변수 + 고정폭) |
70
- | `getScrollElement` | `() => HTMLDivElement \| null` | 본문의 세로 스크롤 컨테이너. 본문이 슬롯으로 대체됐거나 아직 안 그려졌으면 `null`. 스크롤 위치를 읽고 되돌리거나, 표 안에서 스크롤 여지를 재야 할 때 쓴다 — **DOM 을 뒤져 컨테이너를 찾지 않는다.** 내부 구조는 예고 없이 바뀐다. ⚠️ `virtualScroll` 에서 **위치를 픽셀로 저장했다 되돌리는 것은 미덥지 않다.** 다시 그릴 때 아직 안 그려진 행은 추정 높이로 잡히므로, 실측이 쌓이기 전의 같은 `scrollTop` 이 다른 행을 가리킨다. 그 경우엔 위치가 아니라 **보고 있던 행**을 기억해 두는 편이 맞다. |
70
+ | `getScrollElement` | `() => HTMLDivElement \| null` | 본문의 세로 스크롤 컨테이너. 본문이 슬롯으로 대체됐거나 아직 안 그려졌으면 `null`. 스크롤 위치를 읽고 되돌리거나, 표 안에서 스크롤 여지를 재야 할 때 쓴다 — **DOM 을 뒤져 컨테이너를 찾지 않는다.** 내부 구조는 예고 없이 바뀐다. 헤더도 이 안에 위로 붙어(sticky) 있다 — `clientHeight` 에는 헤더 높이가 들어 있다. `scrollTop` 은 본문 기준이라 `scrollTop` 이 y 이면 본문의 y 자리가 헤더 바로 아래에 온다. ⚠️ `virtualScroll` 에서 **위치를 픽셀로 저장했다 되돌리는 것은 미덥지 않다.** 다시 그릴 때 아직 안 그려진 행은 추정 높이로 잡히므로, 실측이 쌓이기 전의 같은 `scrollTop` 이 다른 행을 가리킨다. 그 경우엔 위치가 아니라 **보고 있던 행**을 기억해 두는 편이 맞다. |
71
71
  | `getFirstVisibleRow` | `() => number` | 지금 본문 맨 위에 걸린 행의 인덱스 (`rows` 기준). 행이 없으면 `0`. **스크롤 위치를 저장할 때는 픽셀이 아니라 이 값을 저장한다** — `virtualScroll` 에서 픽셀은 좌표계가 실측으로 움직이는 값이라, 되돌릴 때 다른 행을 가리킨다. |
72
72
  | `scrollToRow` | `(index: number) => void` | 그 행이 본문 맨 위에 오도록 스크롤한다 (`rows` 기준 인덱스, 범위를 벗어나면 잘린다). `virtualScroll` 에서는 **실측이 정착할 때까지 그 행을 계속 다시 겨냥한다** — 옮기는 시점의 좌표는 아직 추정치라 한 번만 옮기면 몇 행씩 밀린다. 사용자가 직접 스크롤하면 겨냥을 놓는다. 페이지네이션을 쓰는 표에서는 **지금 페이지에 그려진 행만** 닿는다 — 다른 페이지의 행이라면 페이지를 먼저 옮긴다. |
73
73
  | `setRowCount` | `(count: number) => void` | 가상 스크롤 총 행 수 설정 |
@@ -208,6 +208,9 @@ export interface STableHandle<TRow extends SRow = SRow> {
208
208
  * 스크롤 위치를 읽고 되돌리거나, 표 안에서 스크롤 여지를 재야 할 때 쓴다 —
209
209
  * **DOM 을 뒤져 컨테이너를 찾지 않는다.** 내부 구조는 예고 없이 바뀐다.
210
210
  *
211
+ * 헤더도 이 안에 위로 붙어(sticky) 있다 — `clientHeight` 에는 헤더 높이가 들어 있다.
212
+ * `scrollTop` 은 본문 기준이라 `scrollTop` 이 y 이면 본문의 y 자리가 헤더 바로 아래에 온다.
213
+ *
211
214
  * ⚠️ `virtualScroll` 에서 **위치를 픽셀로 저장했다 되돌리는 것은 미덥지 않다.** 다시 그릴 때
212
215
  * 아직 안 그려진 행은 추정 높이로 잡히므로, 실측이 쌓이기 전의 같은 `scrollTop` 이 다른 행을
213
216
  * 가리킨다. 그 경우엔 위치가 아니라 **보고 있던 행**을 기억해 두는 편이 맞다.
@@ -69,11 +69,15 @@ export const TAG_COLORS = [
69
69
 
70
70
  ### Used by
71
71
 
72
+ - [SBarcodeInput](../SBarcodeInput)
72
73
  - [SChipFilter](../SChipFilter)
73
74
  - [SConfirmModal](../SConfirmModal)
74
75
  - [SGhostButton](../SGhostButton)
75
76
  - [SGnb](../SGnb)
77
+ - [SGnbSystem](../SGnbSystem)
78
+ - [SInput](../SInput)
76
79
  - [SLauncherListBox](../SLauncherListBox)
80
+ - [SNumberInput](../SNumberInput)
77
81
  - [SRadioCard](../SRadioCard)
78
82
  - [SSystemActionButton](../SSystemActionButton)
79
83
  - [STabs](../STabs)
@@ -88,11 +92,15 @@ export const TAG_COLORS = [
88
92
  ```mermaid
89
93
  graph TD;
90
94
  STag --> SIcon
95
+ SBarcodeInput --> STag
91
96
  SChipFilter --> STag
92
97
  SConfirmModal --> STag
93
98
  SGhostButton --> STag
94
99
  SGnb --> STag
100
+ SGnbSystem --> STag
101
+ SInput --> STag
95
102
  SLauncherListBox --> STag
103
+ SNumberInput --> STag
96
104
  SRadioCard --> STag
97
105
  SSystemActionButton --> STag
98
106
  STabs --> STag
@@ -15,7 +15,7 @@
15
15
  | `disabled?` | `boolean` | `false` | |
16
16
  | `clearable?` | `boolean` | `false` | |
17
17
  | `showMeridiem?` | `boolean` | — | 오전/오후 선택 표시 여부. 지정하지 않으면 type="midday"일 때만 켜집니다. |
18
- | `minuteStep?` | `number` | `1` | |
18
+ | `minuteStep?` | `number` | `1` | 분 리스트에 나열할 간격(분). 10 이면 `00 10 20 30 40 50` 만 고를 수 있다 |
19
19
  | `width?` | `SFieldWidth` | — | 컨트롤 너비 — 폭 등급(`'xs' | 'sm' | 'md' | 'lg' | 'xl'`) · 숫자=px · CSS 길이. 등급은 `--cmp-field-width-*` 토큰으로 풀리므로 토큰이 바뀌면 화면이 따라간다. 값 길이에 상한이 없으면 `"100%"` 로 두어 행 전체를 쓴다. |
20
20
  | `maxWidth?` | `SFieldWidth` | — | 컨트롤 최대 너비 — 폭 등급 · 숫자=px · CSS 길이. 지정하지 않으면 값 길이(`HH:mm`)에 맞춘 내장 상한(`size='md'` → `lg`, `'sm'` → `md`)이 걸려, `width="100%"` 를 받아도 행 전체로 늘어나지 않는다. 팝오버처럼 폭이 이미 좁게 정해진 자리에서 그 폭을 그대로 채워야 하면 `width="100%"` 와 함께 `maxWidth="100%"` 를 준다. `0` 은 상한을 아예 걸지 않는다 — 부모보다 넓어지는 것까지 허용해야 할 때만 쓴다. |
21
21
  | `name?` | `string` | — | |
@@ -7,6 +7,7 @@ import { type STooltipProps } from '../STooltip';
7
7
  import { type STimePickerSize, type STimePickerType } from './timepicker.config';
8
8
  import { type SFieldWidth } from '../../lib/field-width';
9
9
  export type { STimePickerSize, STimePickerType } from './timepicker.config';
10
+ export { TimeListbox } from './TimeListbox';
10
11
  export interface STimePickerProps {
11
12
  /** 선택 시간 (HH:mm) */
12
13
  value?: string | null;
@@ -22,6 +23,7 @@ export interface STimePickerProps {
22
23
  clearable?: boolean;
23
24
  /** 오전/오후 선택 표시 여부. 지정하지 않으면 type="midday"일 때만 켜집니다. */
24
25
  showMeridiem?: boolean;
26
+ /** 분 리스트에 나열할 간격(분). 10 이면 `00 10 20 30 40 50` 만 고를 수 있다 */
25
27
  minuteStep?: number;
26
28
  /**
27
29
  * 컨트롤 너비 — 폭 등급(`'xs' | 'sm' | 'md' | 'lg' | 'xl'`) · 숫자=px · CSS 길이.
@@ -70,11 +72,5 @@ export interface STimePickerProps {
70
72
  className?: string;
71
73
  style?: CSSProperties;
72
74
  }
73
- export declare function TimeSelector({ value, showMeridiem, minuteStep, onChange, }: {
74
- value?: string | null;
75
- showMeridiem: boolean;
76
- minuteStep: number;
77
- onChange: (time: string) => void;
78
- }): import("react").JSX.Element;
79
- /** STimePicker — sd-time-picker 포팅. SField + Popover(TimeSelector). */
75
+ /** STimePicker — sd-time-picker 포팅. SField + Popover(TimeListbox). */
80
76
  export declare function STimePicker({ value, onValueChange, onOpenChange, type, size, placeholder, disabled, clearable, showMeridiem, minuteStep, width, maxWidth, name, rules, status, label, labelPosition, subLabel, labelWidth, icon, iconColor, labelTooltip, labelTooltipProps, addonLabel, addonAlign, hint, error, errorMessage, className, style, }: STimePickerProps): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ /** 리스트에서 고른 열 — STimePicker 는 분을 고르면 팝오버를 닫는다 */
2
+ export type TimeListboxPart = 'meridiem' | 'hour' | 'minute';
3
+ interface TimeListboxProps {
4
+ /** 선택 시간 (HH:mm). 비어 있으면 아무것도 선택되지 않은 채 열린다 */
5
+ value?: string | null;
6
+ showMeridiem: boolean;
7
+ /** 분 열에 나열할 간격 (분) */
8
+ minuteStep: number;
9
+ /** 고를 수 없는 시각 — 자정부터 센 분(0~1439)을 받는다. 시·오전/오후 항목은 그 안의 모든
10
+ * 분을 고를 수 없을 때만 비활성이 된다 */
11
+ isDisabled?: (minutes: number) => boolean;
12
+ onChange: (time: string, part: TimeListboxPart) => void;
13
+ /** 열 접근성 레이블 앞에 붙는 말 — STimeRangePicker 의 "시작"·"종료" */
14
+ labelPrefix?: string;
15
+ /** 그림자·모서리를 두른 떠 있는 상자로 그린다. 다른 상자 안에 넣을 때는 끈다 */
16
+ elevated?: boolean;
17
+ }
18
+ /** TimeListbox — `[오전/오후] | 시 | 분` 을 세로 리스트에서 고르는 시간 선택 조각.
19
+ * SDatePickerMonthListbox(연 | 월)와 같은 스펙이며, STimePicker·STimeRangePicker 팝오버가 쓴다. */
20
+ export declare function TimeListbox({ value, showMeridiem, minuteStep, isDisabled, onChange, labelPrefix, elevated, }: TimeListboxProps): import("react").JSX.Element;
21
+ export {};
@@ -15,8 +15,8 @@
15
15
  | `disabled?` | `boolean` | `false` | |
16
16
  | `clearable?` | `boolean` | `false` | |
17
17
  | `showMeridiem?` | `boolean` | — | 오전/오후 선택 표시 여부. 지정하지 않으면 type="midday"일 때만 켜집니다. |
18
- | `minuteStep?` | `number` | `1` | |
19
- | `rangeOrder?` | `STimeRangePickerRangeOrder` | `'strict'` | 범위 순서 정책. strict는 시작 시간이 종료 시간보다 늦어지지 않도록 보정합니다. |
18
+ | `minuteStep?` | `number` | `1` | 분 리스트에 나열할 간격(분). 10 이면 `00 10 20 30 40 50` 만 고를 수 있다 |
19
+ | `rangeOrder?` | `STimeRangePickerRangeOrder` | `'strict'` | 범위 순서 정책. `strict` 는 종료 리스트에서 시작보다 이른 시각을 비활성으로 막고, 시작을 종료 뒤로 옮기면 종료가 따라온다. `allow-cross-day` 는 제약 없이 고른다(자정을 넘는 범위). |
20
20
  | `width?` | `SFieldWidth` | — | 컨트롤 너비 — 폭 등급(`'xs' | 'sm' | 'md' | 'lg' | 'xl'`) · 숫자=px · CSS 길이. 등급은 `--cmp-field-width-*` 토큰으로 풀리므로 토큰이 바뀌면 화면이 따라간다. 값 길이에 상한이 없으면 `"100%"` 로 두어 행 전체를 쓴다. |
21
21
  | `maxWidth?` | `SFieldWidth` | — | 컨트롤 최대 너비 — 폭 등급 · 숫자=px · CSS 길이. 지정하지 않으면 값 길이(`HH:mm ~ HH:mm`)에 맞춘 내장 상한이 걸려, `width="100%"` 를 받아도 행 전체로 늘어나지 않는다. 팝오버처럼 폭이 이미 좁게 정해진 자리에서 그 폭을 그대로 채워야 하면 `width="100%"` 와 함께 `maxWidth="100%"` 를 준다. `0` 은 상한을 아예 걸지 않는다 — 부모보다 넓어지는 것까지 허용해야 할 때만 쓴다. |
22
22
  | `name?` | `string` | — | |