sellmate-design-system-react 9.0.0-beta.92 → 9.0.0-beta.94

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 (49) hide show
  1. package/AGENTS.md +21 -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/SButton/button.config.d.ts +2 -1
  6. package/dist/components/SChatAttachedFile/chatAttachedFile.config.d.ts +2 -2
  7. package/dist/components/SChatFile/chatFile.config.d.ts +2 -2
  8. package/dist/components/SCheckbox/README.md +2 -0
  9. package/dist/components/SChipFilter/README.md +2 -0
  10. package/dist/components/SGhostButton/README.md +4 -0
  11. package/dist/components/SGnb/gnb.config.d.ts +6 -0
  12. package/dist/components/SIcon/README.md +5 -1
  13. package/dist/components/SIcon/SIcon.d.ts +1 -1
  14. package/dist/components/SInput/README.md +2 -0
  15. package/dist/components/SLauncherListBox/launcherListBox.config.d.ts +2 -7
  16. package/dist/components/SLineChart/README.md +1 -0
  17. package/dist/components/SLineChart/SLineChart.d.ts +5 -0
  18. package/dist/components/SLineChart/lineChart.config.d.ts +1 -2
  19. package/dist/components/SLoadingModal/README.md +2 -2
  20. package/dist/components/SMeatballButton/README.md +2 -0
  21. package/dist/components/SNumberInput/README.md +2 -0
  22. package/dist/components/SRadioCard/README.md +3 -0
  23. package/dist/components/SRadioCard/SRadioCard.d.ts +7 -2
  24. package/dist/components/SRadioCard/SRadioCardGroup.d.ts +3 -1
  25. package/dist/components/SSelect/README.md +9 -4
  26. package/dist/components/SSelect/SSelect.d.ts +18 -4
  27. package/dist/components/SSelect/select.config.d.ts +34 -4
  28. package/dist/components/SStepper/stepper.config.d.ts +9 -3
  29. package/dist/components/STable/README.md +1 -1
  30. package/dist/components/STable/STable.d.ts +3 -0
  31. package/dist/components/STabs/tabs.config.d.ts +3 -8
  32. package/dist/components/STag/README.md +8 -0
  33. package/dist/components/STag/tag.config.d.ts +10 -9
  34. package/dist/components/STimePicker/timepicker.config.d.ts +3 -0
  35. package/dist/components/STree/README.md +2 -0
  36. package/dist/components/STreeTable/STreeTable.examples.d.ts +7 -0
  37. package/dist/index.cjs +1885 -1273
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.js +1885 -1273
  40. package/dist/index.js.map +1 -1
  41. package/dist/lib/chart/cartesian.d.ts +1 -3
  42. package/dist/lib/chart/category-labels.d.ts +37 -0
  43. package/dist/lib/chart/use-element-size.d.ts +4 -1
  44. package/dist/lib/list-box-item.d.ts +16 -0
  45. package/dist/lib/tree-row.d.ts +92 -0
  46. package/dist/llms-full.txt +52 -10
  47. package/dist/llms.txt +21 -2
  48. package/dist/styles.css +237 -88
  49. package/package.json +1 -1
@@ -16,9 +16,7 @@ export declare const AXIS_LABEL_GAP = 8;
16
16
  *
17
17
  * 항목들이 나눠 갖는 자리(band) 바깥에 따로 붙는다 — 첫 항목과 마지막 항목이 차트
18
18
  * 경계에 붙어 잘린 것처럼 보이지 않게 한다. 세로 차트는 좌우, 가로 차트는 위아래다.
19
- *
20
- * **선 차트(`SLineChart`)는 쓰지 않는다.** 선은 첫 점이 왼쪽 끝, 마지막 점이 오른쪽
21
- * 끝에 서서 추이를 그림 폭 전체에 펼친다.
19
+ * 선 차트(`SLineChart`)도 같다 — 점 간격과 눈금 자리가 막대 차트와 맞는다.
22
20
  */
23
21
  export declare const AXIS_EDGE_PADDING = 24;
24
22
  export interface ChartGridProps {
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 기울인 항목 이름 — 직교 좌표 차트(세로 막대·선)의 `rotateCategoryLabels`.
3
+ *
4
+ * 기울인 글자는 눈금에서 **왼쪽 아래로** 뻗는다. 첫 항목의 글자는 그림 왼쪽 밖(눈금 열
5
+ * 아래)까지 나가야 하는데, 눈금 열 오른쪽에서 시작하는 스크롤 상자 안에 두면 그 경계에서
6
+ * 잘린다. 그래서 기울일 때는 스크롤 상자가 **눈금 열까지 감싸고**, 눈금 열은 그 안에서
7
+ * 왼쪽에 붙어(sticky) 제자리를 지킨다. 그림과 이름이 같은 스크롤로 움직이므로 서로
8
+ * 어긋나지 않는다 — scroll 이벤트로 따로 맞추면 브라우저가 스크롤을 먼저 그려 한 프레임
9
+ * 이상 늦게 따라온다.
10
+ */
11
+ import { type CSSProperties, type ReactNode, type Ref } from 'react';
12
+ /**
13
+ * 기울인 항목 이름의 최대 폭(px). 넘으면 말줄임한다 — 전체 이름은 툴팁 제목에서 읽는다.
14
+ * 상한이 없으면 긴 이름 하나가 축 높이를 그림보다 크게 만든다.
15
+ */
16
+ export declare const CATEGORY_LABEL_ROTATED_MAX = 120;
17
+ export interface ChartRotatedAxisLayoutProps {
18
+ /** 눈금 라벨(`ChartAxisLabels`) */
19
+ axis: ReactNode;
20
+ /** 눈금 열의 높이·물러남 — 그림과 같은 값 */
21
+ axisStyle: CSSProperties;
22
+ /** 그림 */
23
+ plot: ReactNode;
24
+ /** 그림이 이보다 좁아지면 가로로 스크롤한다(px) */
25
+ minPlotWidth: number;
26
+ /** 항목 이름 */
27
+ labels: string[];
28
+ /** 항목의 눈금 x(px) — 그림 왼쪽 끝 기준 */
29
+ xAt: (index: number) => number;
30
+ /** 이름 행 — 호출 쪽이 높이를 재서 차트 높이에서 뺀다 */
31
+ labelsRef?: Ref<HTMLDivElement>;
32
+ }
33
+ /**
34
+ * 눈금 열 + 그림 + 기울인 이름 행. 직교 좌표 차트 그리드(`max-content 1fr`)의 두 칸을
35
+ * 모두 차지한다.
36
+ */
37
+ export declare function ChartRotatedAxisLayout({ axis, axisStyle, plot, minPlotWidth, labels, xAt, labelsRef, }: ChartRotatedAxisLayoutProps): import("react").JSX.Element;
@@ -10,8 +10,11 @@ export interface ElementSize {
10
10
  * 그 안에 1:1 로 그린다.
11
11
  *
12
12
  * 첫 렌더에서는 `{0, 0}` 이다. 크기가 0 인 동안은 그리지 않는 쪽이 안전하다.
13
+ *
14
+ * `target` 은 ref 가 붙는 요소가 **바뀌는 조건**이다 — 같은 ref 를 조건에 따라 다른
15
+ * 요소에 붙이면, 이 값이 바뀔 때 새 요소를 다시 관찰한다. 안 주면 처음 붙은 요소만 본다.
13
16
  */
14
- export declare function useElementSize<T extends HTMLElement>(): {
17
+ export declare function useElementSize<T extends HTMLElement>(target?: unknown): {
15
18
  ref: import("react").RefObject<T | null>;
16
19
  size: ElementSize;
17
20
  };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * 드롭다운 목록 행(SSelect · SChipFilter · SChipInput 의 리스트박스 항목)이 함께 쓰는 여백.
3
+ * 스펙(`--cmp-listBoxItem-*`)이 하나라 한곳에 둔다. 행 모양 자체는 아직 컴포넌트마다 따로 그린다.
4
+ */
5
+ /** 항목 좌측 패딩 — depth1(그룹 헤더·비계층 항목) / depth2 / depth3 */
6
+ export declare const LIST_BOX_ITEM_PADDING_LEFT: {
7
+ readonly 1: "var(--cmp-listBoxItem-paddingLeft-depth1)";
8
+ readonly 2: "var(--cmp-listBoxItem-paddingLeft-depth2)";
9
+ readonly 3: "var(--cmp-listBoxItem-paddingLeft-depth3)";
10
+ };
11
+ /** 항목 상하·우측 패딩 — 모든 depth 에서 같다 */
12
+ export declare const LIST_BOX_ITEM_PADDING_Y_RIGHT: {
13
+ readonly paddingTop: "var(--cmp-listBoxItem-paddingY)";
14
+ readonly paddingBottom: "var(--cmp-listBoxItem-paddingY)";
15
+ readonly paddingRight: "var(--cmp-listBoxItem-paddingRight)";
16
+ };
@@ -0,0 +1,92 @@
1
+ import { type HTMLAttributes, type KeyboardEvent as ReactKeyboardEvent, type MouseEvent, type ReactNode } from 'react';
2
+ /**
3
+ * 트리 한 줄의 **모양**. STree 와 SSelect 의 트리 타입(`tree`·`multi_tree`)이 같은 줄을 그리도록
4
+ * 여기 한 곳에 둔다 — 두 컴포넌트의 동작(선택 규칙·포커스·가상 스크롤)은 서로 달라 컴포넌트를
5
+ * 통째로 공유할 수 없지만, 같은 계층이 화면마다 다르게 생기면 안 된다.
6
+ */
7
+ export type TreeRowSize = 'sm' | 'md';
8
+ export declare const TREE_LABEL_TYPOGRAPHY: Record<TreeRowSize, {
9
+ default: string;
10
+ selected: string;
11
+ rowHeight: string;
12
+ }>;
13
+ /** 줄 바탕 — 배경·hover·좌우 여백·연결선과 내용 사이 간격 */
14
+ export declare const TREE_ROW_CLASS = "group/tree-item box-border flex w-full items-center gap-(--cmp-tree-item-rowGap) overflow-hidden bg-(--cmp-tree-item-bg-default) px-(--cmp-tree-item-paddingX) text-left hover:bg-(--cmp-tree-item-bg-hover)";
15
+ /** 줄 아래 구분선 */
16
+ export declare const TREE_ROW_BORDER_CLASS = "border-b-(length:--cmp-tree-item-border-width-default) border-(--cmp-tree-item-border-default)";
17
+ /** 키보드가 가리키는 줄 — hover 와 같은 배경 (SSelect 처럼 포커스를 줄로 옮기지 않는 쪽이 쓴다) */
18
+ export declare const TREE_ROW_ACTIVE_CLASS = "bg-(--cmp-tree-item-bg-hover)";
19
+ /** 화살표·체크박스·라벨을 담는 칸 */
20
+ export declare const TREE_CONTENT_CLASS = "box-border flex min-w-0 flex-1 items-center gap-(--cmp-tree-item-contentGap)";
21
+ /**
22
+ * 라벨 — 고른(또는 일부 고른) 줄은 굵게, 비활성은 흐리게. 고를 수 있으면 `TreeSelectZone` 에
23
+ * 올렸을 때 밑줄이 생긴다. 글자 폭만큼만 차지한다(줄의 남은 폭은 접고 펴는 자리다)
24
+ */
25
+ export declare function treeLabelClass(size: TreeRowSize, { emphasized, disabled, selectable, }: {
26
+ emphasized: boolean;
27
+ disabled: boolean;
28
+ selectable: boolean;
29
+ }): string;
30
+ /**
31
+ * 줄에서 고르는 자리 — 체크박스(있으면)+라벨을 담는다. 글자 폭만큼만 차지해 그 오른쪽 빈 자리는
32
+ * 접고 펴는 자리로 남는다. 고를 수 있으면 올렸을 때 라벨 밑줄(`treeLabelClass`)과 chevron 이 나와
33
+ * 접고 펴는 자리와 구분된다. 줄의 클릭이 이 자리에 떨어졌는지는 `isRowSelectClick` 으로 가른다.
34
+ */
35
+ export declare function TreeSelectZone({ selectable, disabled, control, children, }: {
36
+ selectable: boolean;
37
+ disabled?: boolean;
38
+ /** 라벨 앞의 체크박스 */
39
+ control?: ReactNode;
40
+ /** 라벨 */
41
+ children: ReactNode;
42
+ }): import("react").JSX.Element;
43
+ /** 줄의 클릭이 고르는 자리(`TreeSelectZone`)에 떨어졌는가 */
44
+ export declare function isRowSelectClick(event: MouseEvent<HTMLElement>): boolean;
45
+ /**
46
+ * 줄 안의 컨트롤(체크박스·화살표)이 받은 클릭인가. 컨트롤은 스스로 값을 바꾸므로 줄의 클릭 처리는
47
+ * 손대지 않는다 — 컨트롤마다 감싸서 전파를 끊는 대신 줄 하나가 클릭을 받아 가른다.
48
+ * (체크박스는 `<label>` 이라 한 번 누르면 클릭이 두 번 올라오는데, 둘 다 여기서 걸러진다)
49
+ */
50
+ export declare function isRowControlClick(event: MouseEvent<HTMLElement>): boolean;
51
+ /** 접기·펴기 화살표. 자식이 없는 줄은 `TreeCaretSpacer` 로 같은 자리를 비운다 */
52
+ export declare function TreeCaret({ expanded, onToggle, }: {
53
+ expanded: boolean;
54
+ onToggle: (event: MouseEvent<HTMLElement>) => void;
55
+ }): import("react").JSX.Element;
56
+ /**
57
+ * 자식이 없는 줄은 펼침 버튼 자리를 빈 칸으로 남겨 라벨의 시작점을 맞춘다.
58
+ * 크기는 자리를 대신하는 그 버튼(`SGhostButton size="xxs"`)의 토큰을 그대로 쓴다 —
59
+ * 버튼 크기가 바뀌면 빈 칸도 같이 따라가야 줄이 어긋나지 않는다.
60
+ */
61
+ export declare function TreeCaretSpacer(): import("react").JSX.Element;
62
+ /**
63
+ * depth 연결선. 최상위(depth 1)는 그리지 않는다.
64
+ *
65
+ * @param ancestorLast 조상(depth 1 부터 부모까지)이 각자 마지막 자식인가 — 조상 쪽 세로선을 어디까지 잇는지 정한다
66
+ */
67
+ export declare function TreeConnector({ guideline, size, depth, hasChildren, isLast, ancestorLast, }: {
68
+ guideline: boolean;
69
+ size: TreeRowSize;
70
+ depth: number;
71
+ hasChildren: boolean;
72
+ isLast: boolean;
73
+ ancestorLast: boolean[];
74
+ }): import("react").JSX.Element | null;
75
+ /**
76
+ * 목록 맨 위의 "전체" 줄 — 체크박스 하나로 고를 수 있는 것을 전부 켜고 끈다.
77
+ * 키보드·포커스는 쓰는 쪽이 정한다: STree 는 줄로 포커스를 옮기고(`tabIndex`·`onKeyDown`),
78
+ * SSelect 는 트리거가 `aria-activedescendant` 로 가리키므로 `active` 로 강조만 받는다.
79
+ */
80
+ export declare function TreeAllRow({ label, selected, indeterminate, size, border, active, tabIndex, onKeyDown, onToggle, className, ...rest }: {
81
+ label?: ReactNode;
82
+ selected: boolean;
83
+ indeterminate?: boolean;
84
+ size?: TreeRowSize;
85
+ border?: boolean;
86
+ /** 키보드가 가리키는 줄 — hover 와 같은 배경을 깐다 */
87
+ active?: boolean;
88
+ tabIndex: number;
89
+ onKeyDown?: (event: ReactKeyboardEvent<HTMLDivElement>) => void;
90
+ /** 줄이나 체크박스를 눌렀다. 줄 클릭이면 그 이벤트가 온다 */
91
+ onToggle: (event?: MouseEvent<HTMLElement>) => void;
92
+ } & Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onClick' | 'onKeyDown' | 'onToggle' | 'tabIndex' | 'role'>): import("react").JSX.Element;
@@ -541,6 +541,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
541
541
  | 정해진 범위 안에서 수치 하나·구간을 끌어서 고르게 한다 | `SSlider` | §3-7-16 |
542
542
  | 바코드를 스캔해 받는다 | `SBarcodeInput` | |
543
543
  | 목록에서 하나 고르게 한다 | `SSelect` | §3-7-2 |
544
+ | 계층(카테고리 > 세부분류)을 접고 펴며 드롭다운에서 고르게 한다 | `SSelect` `type="tree"`·`"multi_tree"` | §3-7-2 — 계층을 늘 펼쳐 보여도 되면 `default_depth`·`multi_depth` |
544
545
  | 선택지를 항상 펼쳐 두고 하나 고르게 한다 | `SRadioGroup` | §3-7-2 |
545
546
  | 버튼 모양으로 모드를 하나 고르게 한다 | `SRadioButton` | §3-7-2 |
546
547
  | 선택지마다 설명이 붙어 한 줄로는 안 된다 | `SRadioCardGroup` | §3-7-2 |
@@ -577,13 +578,14 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
577
578
  | 대화의 메시지 한 건을 보여준다 | `SChatMessage` | |
578
579
  | 대화 중간에 시스템이 알리는 사실을 끼운다 (상담사 배정·대화 종료 등) | `SChatSystemMessage` | 사람이 보낸 말이면 `SChatMessage` |
579
580
  | 나열한 항목을 펼쳐 하위 내용을 보여준다 | `SExpansionList` + `SExpansionItem` | §3-7-7 |
580
- | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 |
581
+ | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 — 폼 값으로 드롭다운에서 고르는 것이면 `SSelect` `type="tree"` |
581
582
  | 계층을 이루는 행들을 여러 열로 보여준다 (카테고리 > 상품 > 옵션) | `STreeTable` | §3-7-7 — 한 줄에 라벨 하나면 `STree` |
582
583
  | 사용자가 순서를 드래그로 바꾸게 한다 | `SDraggableList` + `SDraggableItem` | §3-7-6 |
583
584
  | 날짜별 일정을 한 달치 격자로 펼쳐 보여준다 | `SCalendarBoard` | §3-7-4 |
584
585
  | 항목끼리 크기를 눈으로 견주게 한다 (채널별 매출·상품별 판매량) | `SBarChart` | 정확한 값을 읽어야 하면 `STable` — 그래프는 "어느 쪽이 큰가" 를 답하지 "얼마인가" 를 답하지 않는다 |
585
586
  | 순서가 있는 항목의 **추이**를 보여준다 (일·월별 매출 흐름, 기간별 방문 수) | `SLineChart` | 항목 순서에 뜻이 없으면(채널별·상품별) `SBarChart` — 선은 "이어진다" 는 뜻을 덤으로 얹어, 순서 없는 항목을 이으면 없는 흐름을 만든다. 항목이 대여섯 개 안쪽이고 크기를 견주는 것이 목적이면 막대가 낫다 |
586
587
  | 여러 항목의 추이를 **합계와 함께** 보여준다 (채널별 매출이 쌓여 전체가 되는 흐름) | `SLineChart stacked area` | 합계가 뜻을 갖는 값일 때만 쌓는다. 음수가 섞이거나 더해서 뜻이 없는 값(비율·평균)은 쌓지 말고 겹쳐 그린다 |
588
+ | 항목 이름이 길어 가로축에서 서로 겹친다 (상품명·채널명, `2026-10-01` 같은 날짜) | 순서 없는 항목은 `SBarChart direction="horizontal"` — 이름 열이 가장 긴 이름에 맞춰 넓어진다. 순서가 있어 세로 축을 지켜야 하면(날짜순 막대·`SLineChart`) `rotateCategoryLabels` | 이름이 짧아 겹치지 않으면 켜지 않는다 — 켜면 늘 기울어 읽기만 나빠진다. 기울여도 너무 긴 이름은 차트가 말줄임하고 전체 이름은 툴팁에 뜬다. 말줄임 폭·각도를 직접 주지 않는다. 나란히 놓인 차트는 켜고 끄기를 맞춰야 그림 높이가 같다 |
587
589
  | 항목의 크기와 **그 안의 구성**을 함께 보여준다 (주문 상태별 내역, 유입 경로별 몫) | `SBarChart stacked` | 계열끼리 견주는 것이 목적이면 `stacked` 없이 나란히 세운다. 더해서 뜻이 없는 값(비율·평균)은 쌓지 않는다 — 합계 라벨이 거짓말이 된다 |
588
590
  | 한 시점의 **전체를 몇 개의 몫으로** 나눠 보여준다 (채널별 매출 비중, 회원 등급 구성) | `SPieChart` | 조각이 대여섯 개를 넘거나 몫끼리 크기를 견주는 것이 목적이면 `SBarChart` — 사람은 각도보다 길이를 정확히 견준다. 순서가 있는 추이(월별)는 몫이 아니라 흐름이라 `SLineChart`. 0·음수는 그려지지 않으므로 증감은 원으로 나타내지 않는다. 조각은 큰 순으로 넘긴다. 폭은 부모를 따르고 그림은 그 폭의 정사각형이다 — 폭이 필요하면 `className` 으로 폭만 주고 높이는 주지 않는다 (`SDonutChart` 도 같다) |
589
591
  | 한 시점의 전체를 몫으로 나누되 **가운데가 빈 고리 모양**으로 보여준다 (시안이 도넛일 때) | `SDonutChart` | 쓰임·데이터 규칙은 `SPieChart` 와 같고 모양만 다르다 — 시안이 정한 쪽을 쓴다. **구멍에 합계·라벨을 겹쳐 올리지 않는다.** 합계 같은 값이 필요하면 차트 바깥(카드 제목·요약 값)에 적는다. 여러 기간에 걸친 구성 변화는 원을 여러 개 늘어놓지 말고 `SBarChart stacked` |
@@ -1774,11 +1776,28 @@ tableRef.current.scrollToRow(row); // 복원
1774
1776
  - **쓰는 자리는 설정 화면·마법사(스텝)의 소수 결정이다.** 고르고 나면 뒤 화면이 통째로 바뀌거나 되돌리기 어려운 선택 — 평가 대상자 범위(전체/특정 구성원), 상담 자동 배정 방식 같은 것. 목록 필터·표 안 조건처럼 같은 선택지가 화면마다 반복 노출되는 자리에는 `SRadioGroup` 을 쓴다.
1775
1777
  - `SRadioCard` 단독은 `SRadioCardGroup` 이 만들 수 없는 배치에만 쓴다 — 나열은 그룹이 맡는다 (§2-2).
1776
1778
  - 카드 안에 상태 배지를 넣으려면 `tag` 슬롯에 `STag` 를 준다. 라벨 문자열에 "(추천)" 처럼 섞어 쓰지 않는다.
1779
+ - **한 선택지에 딸린 추가 입력(지정일·요청 사항 등)은 그 카드의 슬롯에 넣는다** — `SRadioCard` 는 `children`, `SRadioCardGroup` 은 옵션의 `content`. 카드 아래에 따로 입력을 늘어놓지 않는다. 슬롯은 서브타이틀 아래에 들여써서 놓이고 라디오의 클릭 영역 밖이라, 입력을 눌러도 카드 선택이 바뀌지 않는다. 들여쓰기·간격은 카드가 넣으므로 직접 주지 않는다. 고른 카드에만 보여주고, 카드를 `disabled` 로 두면 슬롯의 컨트롤도 함께 `disabled` 로 둔다(카드가 대신 잠그지 않는다).
1777
1780
  - **카드처럼 생겼다고 `SCard`/`SSectionHeaderCard` 로 감싸지 않는다.** `SRadioCard` 자체가 완결된 요소이고, 나열 간격은 `SRadioCardGroup` 의 `direction` 이 맞춘다 (§2-2).
1778
1781
 
1782
+ ##### 후보에 상하 관계가 있으면 — depth vs tree
1783
+
1784
+ 계층은 `options` 의 `children` 으로 만든다. 평평한 `default`·`multi` 에 분류명을 라벨에 섞어 늘어놓지 않는다. 남는 선택은 **계층을 어떻게 보여주는가**와 **그룹이 값이 되는가**다.
1785
+
1786
+ | 상황 | `type` |
1787
+ | --- | --- |
1788
+ | 그룹이 몇 개 안 돼 늘 펼쳐 둬도 한눈에 읽힌다. 그룹은 분류 헤더일 뿐 값이 아니다 | `default_depth` · `multi_depth` |
1789
+ | 그룹·단계가 많아 다 펼치면 목록이 길어진다 — 접어 두고 필요한 갈래만 편다 | `tree` · `multi_tree` |
1790
+ | **그룹 자체도 값**이다 (예: "패션의류" 전체를 하나의 조건으로 고른다) — 단일 선택 | `tree` |
1791
+
1792
+ - **값에 무엇이 담기는가.** `default_depth`·`multi_depth`·`multi_tree` 는 언제나 **리프만** 담긴다 — `multi_tree`·`multi_depth` 의 그룹 체크박스는 그 아래 리프를 한꺼번에 넣고 뺄 뿐, 그룹의 `value` 는 값이 되지 않는다. 그룹의 `value` 가 값으로 오는 것은 `tree` 뿐이다.
1793
+ - **펼침 상태는 `SSelect` 가 쥔다.** 열 때마다 선택값을 품은 그룹이 펼쳐지고, 검색 중에는 걸린 줄이 보이도록 결과를 전부 펼친다. 앱이 펼칠 그룹을 따로 들고 있지 않는다.
1794
+ - 그룹의 `disabled` 는 그 줄의 선택만 막는다 — 마우스(화살표)로도 키보드(→)로도 접고 펴기는 되므로 아래의 고를 수 있는 자식에 닿는 길은 남는다.
1795
+ - 하위가 전부 비활성이면 `multi_tree`·depth 타입은 그룹도 함께 잠그므로 앱이 어미에 `disabled` 를 다시 달 필요가 없다. `tree` 는 그룹 자체가 값이라 하위가 막혀도 그룹은 고를 수 있다 — 그룹까지 막으려면 그룹에 `disabled` 를 직접 준다.
1796
+ - 드롭다운 없이 화면에 계층을 펼쳐 두고 여러 개를 체크하게 하는 것이면 `SSelect` 가 아니라 `STree` 다 (§3-7-7).
1797
+
1779
1798
  ##### 여러 개 고른 값을 칩으로 보여줄 때 — `valueDisplay="chip"`
1780
1799
 
1781
- - **`type="multi"`·`"multi_depth"` 에서 `valueDisplay="chip"` 을 주면** 선택값이 트리거에 칩으로 뜨고, 칩의 × 로 하나씩 뺄 수 있다. 기본(`text`)은 라벨을 쉼표로 이어 한 줄로 말줄임한다. 고른 값 하나하나를 확인하고 바로 빼야 하는 자리면 `chip`, 몇 개 골랐는지만 보이면 되는 조회 필터면 `text` 를 쓴다.
1800
+ - **`type="multi"`·`"multi_depth"`·`"multi_tree"` 에서 `valueDisplay="chip"` 을 주면** 선택값이 트리거에 칩으로 뜨고, 칩의 × 로 하나씩 뺄 수 있다. 기본(`text`)은 라벨을 쉼표로 이어 한 줄로 말줄임한다. 고른 값 하나하나를 확인하고 바로 빼야 하는 자리면 `chip`, 몇 개 골랐는지만 보이면 되는 조회 필터면 `text` 를 쓴다.
1782
1801
  - **후보가 정해진 목록에서 고르는 것이면 `SSelect` 의 `chip` 이고, 사용자가 값을 직접 타이핑해 쌓는 것이면 `SChipInput` 이다.** 목록에서 고른 값을 `SChipInput` 에 옮겨 담거나, `SSelect` 옆에 `SChip` 을 따로 나열해 선택값을 흉내 내지 않는다.
1783
1802
  - **단일 선택 type 에는 주지 않는다.** 무시되고 `text` 로 보인다. 단일 선택의 값 비우기는 `clearable` 이 맡는다.
1784
1803
  - 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다. 높이·칩 간격은 `SSelect` 가 토큰으로 넣는다 — 직접 주지 않는다.
@@ -5874,6 +5893,7 @@ export const BADGE_COLORS = [
5874
5893
  | `tickCount?` | `number` | `8` | 값 축 눈금 개수 |
5875
5894
  | `barSize?` | `number` | `BAR_SIZE_MAX` | 막대 두께 상한(px, 24~80). 낮추면 좌우 여백 상한도 같은 비율로 따라 내려온다 |
5876
5895
  | `showValueLabel?` | `boolean` | `true` | 막대마다 값을 적는다 |
5896
+ | `rotateCategoryLabels?` | `boolean` | `false` | 항목 이름을 -45° 기울인다. 이름이 막대 묶음 폭보다 길어 서로 겹칠 때 쓴다. 기울여도 너무 긴 이름은 말줄임되고, 전체 이름은 툴팁 제목에서 읽힌다. 이름이 아주 길면 기울이기보다 `direction='horizontal'` 이 먼저다. 세로 막대에서만 쓴다 — 가로 막대는 이름 열이 가장 긴 이름에 맞춰 넓어지므로 무시한다 |
5877
5897
  | `showLegend?` | `boolean` | `true` | 범례를 보인다 |
5878
5898
  | `legendPosition?` | `SBarChartLegendPosition` | `'top'` | 범례 위치 |
5879
5899
  | `showTooltip?` | `boolean` | `true` | 막대에 마우스를 올리면 값 상자를 띄운다 |
@@ -6041,6 +6061,7 @@ export type SBarcodeInputSize = SFieldSize;
6041
6061
 
6042
6062
  - [SField](../SField)
6043
6063
  - [SGhostButton](../SGhostButton)
6064
+ - [STag](../STag)
6044
6065
 
6045
6066
  ### Graph
6046
6067
 
@@ -6623,6 +6644,7 @@ export type SCheckboxValue = boolean | unknown[] | null;
6623
6644
  ### Used by
6624
6645
 
6625
6646
  - [SKeyValueTable](../SKeyValueTable)
6647
+ - [SSelect](../SSelect)
6626
6648
  - [STable](../STable)
6627
6649
  - [STree](../STree)
6628
6650
 
@@ -7113,6 +7135,7 @@ export interface SChipFilterDatePreset {
7113
7135
 
7114
7136
  - [SDatePicker](../SDatePicker)
7115
7137
  - [SDateRangePicker](../SDateRangePicker)
7138
+ - [SGhostButton](../SGhostButton)
7116
7139
  - [SIcon](../SIcon)
7117
7140
  - [SRadio](../SRadio)
7118
7141
  - [SRadioButton](../SRadioButton)
@@ -8661,6 +8684,7 @@ export type SGhostButtonIntent =
8661
8684
  - [SChatAttachedFile](../SChatAttachedFile)
8662
8685
  - [SChatInput](../SChatInput)
8663
8686
  - [SChip](../SChip)
8687
+ - [SChipFilter](../SChipFilter)
8664
8688
  - [SDatePicker](../SDatePicker)
8665
8689
  - [SDateRangePicker](../SDateRangePicker)
8666
8690
  - [SFilePicker](../SFilePicker)
@@ -8673,6 +8697,7 @@ export type SGhostButtonIntent =
8673
8697
  - [SPage](../SPage)
8674
8698
  - [SPopover](../SPopover)
8675
8699
  - [SSearchInput](../SSearchInput)
8700
+ - [SSelect](../SSelect)
8676
8701
  - [STable](../STable)
8677
8702
  - [STimePicker](../STimePicker)
8678
8703
  - [STimeRangePicker](../STimeRangePicker)
@@ -9078,7 +9103,7 @@ export type SGuideMessage = string | SGuideMessage[];
9078
9103
  | Prop | Type | Default | Description |
9079
9104
  |------|------|---------|-------------|
9080
9105
  | `name` | `SIconName` | — | 아이콘명 |
9081
- | `size?` | `number \| string` | `24` | 아이콘 크기(px 또는 CSS 길이) |
9106
+ | `size?` | `number \| string` | `24` | 아이콘 크기(px 또는 CSS 길이). 토큰 크기 `var(--cmp-…)` 도 그대로 넘긴다 |
9082
9107
  | `color?` | `SColor` | — | 아이콘 색상. 팔레트 키(`grey_65`, `red_95` …) 또는 임의 CSS 색상. 미지정 시 currentColor 상속 |
9083
9108
  | `rotate?` | `0 \| 90 \| 180 \| 270` | — | 회전 각도 |
9084
9109
  | `label?` | `string` | — | 접근성 라벨. 없으면 aria-hidden 처리 |
@@ -9117,6 +9142,7 @@ export type SGuideMessage = string | SGuideMessage[];
9117
9142
  - [SLauncherListBox](../SLauncherListBox)
9118
9143
  - [SListItem](../SListItem)
9119
9144
  - [SLoadingModal](../SLoadingModal)
9145
+ - [SMeatballButton](../SMeatballButton)
9120
9146
  - [SNumberInput](../SNumberInput)
9121
9147
  - [SPagination](../SPagination)
9122
9148
  - [SPopover](../SPopover)
@@ -9132,6 +9158,7 @@ export type SGuideMessage = string | SGuideMessage[];
9132
9158
  - [STimeRangePicker](../STimeRangePicker)
9133
9159
  - [SToast](../SToast)
9134
9160
  - [STooltip](../STooltip)
9161
+ - [STree](../STree)
9135
9162
 
9136
9163
  ### Graph
9137
9164
 
@@ -9257,6 +9284,7 @@ export const IMAGE_FITS = ['cover', 'contain', 'fill', 'none', 'scale-down'] as
9257
9284
 
9258
9285
  - [SField](../SField)
9259
9286
  - [SGhostButton](../SGhostButton)
9287
+ - [STag](../STag)
9260
9288
 
9261
9289
  ### Graph
9262
9290
 
@@ -9547,6 +9575,7 @@ export type SLayoutHeader = SGnbHeader;
9547
9575
  | `tickCount?` | `number` | `8` | 값 축 눈금 개수 |
9548
9576
  | `showPoint?` | `boolean` | `true` | 데이터 지점마다 점을 찍는다. 꺼도 짚은 항목의 점은 뜬다 |
9549
9577
  | `showValueLabel?` | `boolean` | `false` | 점마다 값을 적는다. 기본은 끔 — 선 그래프는 항목이 많은 데이터에 쓰는 일이 잦아 숫자가 서로 붙는다. 항목이 대여섯 개 안쪽일 때만 켠다 |
9578
+ | `rotateCategoryLabels?` | `boolean` | `false` | 항목 이름을 -45° 기울인다. 이름이 점 간격보다 길어 서로 겹칠 때 쓴다. 기울여도 너무 긴 이름은 말줄임되고, 전체 이름은 툴팁 제목에서 읽힌다 |
9550
9579
  | `showLegend?` | `boolean` | `true` | 범례를 보인다 |
9551
9580
  | `legendPosition?` | `SLineChartLegendPosition` | `'top'` | 범례 위치 |
9552
9581
  | `showTooltip?` | `boolean` | `true` | 항목에 마우스를 올리면 값 상자를 띄운다 |
@@ -9850,8 +9879,8 @@ export interface SListItemRenderState {
9850
9879
  | `message?` | `string \| string[]` | — | 메시지 (없으면 state 기본값) |
9851
9880
  | `showButton?` | `boolean` | `false` | 하단 버튼 표시 |
9852
9881
  | `buttonLabel?` | `string` | — | 버튼 레이블 (없으면 state 기본값) |
9853
- | `width?` | `number \| string` | `520` | |
9854
- | `height?` | `number \| string` | `320` | |
9882
+ | `width?` | `number \| string` | `'var(--cmp-modal-loading-width)'` | |
9883
+ | `height?` | `number \| string` | `'var(--cmp-modal-loading-height)'` | |
9855
9884
 
9856
9885
  #### Events
9857
9886
 
@@ -10077,6 +10106,7 @@ export type SMeatballButtonItem = SDropdownButtonItem;
10077
10106
  ### Depends on
10078
10107
 
10079
10108
  - [SGhostButton](../SGhostButton)
10109
+ - [SIcon](../SIcon)
10080
10110
 
10081
10111
  ### Graph
10082
10112
 
@@ -10440,6 +10470,7 @@ export type SNumberInputSize = SFieldSize;
10440
10470
 
10441
10471
  - [SField](../SField)
10442
10472
  - [SIcon](../SIcon)
10473
+ - [STag](../STag)
10443
10474
 
10444
10475
  ### Graph
10445
10476
 
@@ -11116,6 +11147,7 @@ export type SRadioButtonSize = 'xs' | 'sm' | 'md';
11116
11147
  | `value?` | `SRadioValue \| null` | — | 그룹의 현재 선택 값 |
11117
11148
  | `label` | `string` | — | 라벨 (첫 줄) |
11118
11149
  | `subtitle?` | `string` | — | 서브타이틀 (둘째 줄). 라벨 왼쪽 끝에 맞춰 들여쓴다 |
11150
+ | `children?` | `ReactNode` | — | 서브타이틀 아래 슬롯. 서브타이틀처럼 라벨 왼쪽 끝에 맞춰 들여쓴다. 카드 테두리 안이지만 라디오의 클릭 영역 밖이라, 입력·버튼 같은 컨트롤을 넣어도 누를 때 카드가 선택되지 않는다 |
11119
11151
  | `tag?` | `Omit<STagProps, 'size'>` | — | 라벨 오른쪽에 붙일 태그. `STag` 의 props 를 그대로 받되 크기는 `xs` 로 고정된다 |
11120
11152
  | `disabled?` | `boolean` | `false` | 비활성 |
11121
11153
  | `name?` | `string` | — | native radio name (form-agnostic 그룹핑) |
@@ -11140,6 +11172,8 @@ export interface SRadioCardOption {
11140
11172
  label: string;
11141
11173
  /** 서브타이틀 (둘째 줄) */
11142
11174
  subtitle?: string;
11175
+ /** 서브타이틀 아래 슬롯 (`SRadioCard` 의 `children`). 라디오의 클릭 영역 밖이다 */
11176
+ content?: ReactNode;
11143
11177
  /** 라벨 오른쪽에 붙일 태그 (`STag` props, 크기는 `xs` 고정) */
11144
11178
  tag?: Omit<STagProps, 'size'>;
11145
11179
  /** 이 옵션만 비활성 */
@@ -11340,8 +11374,8 @@ export type SSectionHeaderCardChildren = ReactNode;
11340
11374
  | `valueAsPrimitive?` | `boolean` | `false` | `value`·`onValueChange` 가 옵션 객체 대신 원시값(string|number)을 주고받는다. **기본값 `false`(옵션 객체)는 유지한다** — 원본(sd-select) 호환 때문이고, 뒤집으면 이 값을 주지 않던 화면이 조용히 다른 모양의 값을 받게 되어 타입으로도 잡히지 않는다. 새로 쓰는 화면은 켜는 쪽이 다루기 쉽다 — 서버로 보내는 것도, 폼 상태에 담는 것도 결국 값 하나이기 때문이다. |
11341
11375
  | `name?` | `string` | — | 폼 연동용 name 속성 |
11342
11376
  | `options?` | `SSelectOption[]` | `[]` | 옵션 목록 (children으로 계층 표현) |
11343
- | `type?` | `SSelectType` | `'default'` | 타입: default | multi | default_depth | multi_depth |
11344
- | `valueDisplay?` | `SSelectValueDisplay` | `'text'` | 트리거에 선택값을 보여주는 방식. - `text`: 선택 라벨을 쉼표로 이어 한 줄로 보여준다. 넘치면 말줄임한다. - `chip`: 선택값마다 칩을 낸다. 칩의 × 를 누르면 그 값만 선택에서 빠지고, 드롭다운은 열리지 않는다. 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다. `chip` 은 `multi`·`multi_depth` 에서만 동작한다. 단일 선택 type 에서는 무시하고 `text` 로 보여준다. 전체 선택이면 칩 대신 `allSelectedLabel` 을 보여준다. `multi_depth` 에서 그룹의 하위 리프를 전부 고르면 리프 칩 대신 그룹명 칩 하나로 묶고, 그 칩의 × 는 그룹의 리프를 한꺼번에 뺀다. 비활성(select 자체나 해당 옵션)인 칩에는 × 를 내지 않는다. |
11377
+ | `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` 와 같은 모양(연결선·화살표·체크박스·라벨 타이포)으로 그린다. |
11378
+ | `valueDisplay?` | `SSelectValueDisplay` | `'text'` | 트리거에 선택값을 보여주는 방식. - `text`: 선택 라벨을 쉼표로 이어 한 줄로 보여준다. 넘치면 말줄임한다. - `chip`: 선택값마다 칩을 낸다. 칩의 × 를 누르면 그 값만 선택에서 빠지고, 드롭다운은 열리지 않는다. 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다. `chip` 은 `multi`·`multi_depth`·`multi_tree` 에서만 동작한다. 단일 선택 type 에서는 무시하고 `text` 로 보여준다. 전체 선택이면 칩 대신 `allSelectedLabel` 을 보여준다. `multi_depth`·`multi_tree` 에서 그룹의 하위 리프를 전부 고르면 리프 칩 대신 그룹명 칩 하나로 묶고, 그 칩의 × 는 그룹의 리프를 한꺼번에 뺀다. 비활성(select 자체나 해당 옵션)인 칩에는 × 를 내지 않는다. |
11345
11379
  | `showSearch?` | `boolean` | `false` | 검색 입력 사용 |
11346
11380
  | `showSelectAll?` | `boolean` | `false` | 전체선택 옵션 사용 (multi 전용) |
11347
11381
  | `allSelectedLabel?` | `string` | `'전체'` | 전체선택 레이블 |
@@ -11389,7 +11423,7 @@ export type SSectionHeaderCardChildren = ReactNode;
11389
11423
 
11390
11424
  | Method | Type | Description |
11391
11425
  |--------|------|-------------|
11392
- | `focus` | `() => void` | 트리거 버튼에 포커스 (sdFocus) |
11426
+ | `focus` | `() => void` | 트리거(combobox)에 포커스 (sdFocus) |
11393
11427
  | `open` | `() => void` | 드롭다운 열기 (sdOpen) |
11394
11428
 
11395
11429
  ## Types
@@ -11422,7 +11456,8 @@ export interface SSelectOption {
11422
11456
  ### SSelectType
11423
11457
 
11424
11458
  ```ts
11425
- export type SSelectType = 'default' | 'multi' | 'default_depth' | 'multi_depth';
11459
+ export type SSelectType =
11460
+ 'default' | 'multi' | 'default_depth' | 'multi_depth' | 'tree' | 'multi_tree';
11426
11461
  ```
11427
11462
 
11428
11463
  ### SSelectValueDisplay
@@ -11441,8 +11476,10 @@ export type SSelectValueDisplay = 'text' | 'chip';
11441
11476
 
11442
11477
  ### Depends on
11443
11478
 
11479
+ - [SCheckbox](../SCheckbox)
11444
11480
  - [SCircleProgress](../SCircleProgress)
11445
11481
  - [SField](../SField)
11482
+ - [SGhostButton](../SGhostButton)
11446
11483
  - [SIcon](../SIcon)
11447
11484
  - [SPortal](../SPortal)
11448
11485
  - [SSearchInput](../SSearchInput)
@@ -12058,7 +12095,7 @@ export interface SSystemActionButtonMenuOption {
12058
12095
  | `getIsAllChecked` | `(rows: TRow[]) => boolean \| null` | 주어진 행들의 전체 선택 상태 (true/false/null=indeterminate) |
12059
12096
  | `getPaginationInfo` | `<union 2종>` | 내부 페이지네이션 정보 (internalPagination 아니면 null) |
12060
12097
  | `getStickyStyle` | `(colIdx: number) => CSSProperties` | 컬럼 sticky 스타일 (CSS 변수 + 고정폭) |
12061
- | `getScrollElement` | `() => HTMLDivElement \| null` | 본문의 세로 스크롤 컨테이너. 본문이 슬롯으로 대체됐거나 아직 안 그려졌으면 `null`. 스크롤 위치를 읽고 되돌리거나, 표 안에서 스크롤 여지를 재야 할 때 쓴다 — **DOM 을 뒤져 컨테이너를 찾지 않는다.** 내부 구조는 예고 없이 바뀐다. ⚠️ `virtualScroll` 에서 **위치를 픽셀로 저장했다 되돌리는 것은 미덥지 않다.** 다시 그릴 때 아직 안 그려진 행은 추정 높이로 잡히므로, 실측이 쌓이기 전의 같은 `scrollTop` 이 다른 행을 가리킨다. 그 경우엔 위치가 아니라 **보고 있던 행**을 기억해 두는 편이 맞다. |
12098
+ | `getScrollElement` | `() => HTMLDivElement \| null` | 본문의 세로 스크롤 컨테이너. 본문이 슬롯으로 대체됐거나 아직 안 그려졌으면 `null`. 스크롤 위치를 읽고 되돌리거나, 표 안에서 스크롤 여지를 재야 할 때 쓴다 — **DOM 을 뒤져 컨테이너를 찾지 않는다.** 내부 구조는 예고 없이 바뀐다. 헤더도 이 안에 위로 붙어(sticky) 있다 — `clientHeight` 에는 헤더 높이가 들어 있다. `scrollTop` 은 본문 기준이라 `scrollTop` 이 y 이면 본문의 y 자리가 헤더 바로 아래에 온다. ⚠️ `virtualScroll` 에서 **위치를 픽셀로 저장했다 되돌리는 것은 미덥지 않다.** 다시 그릴 때 아직 안 그려진 행은 추정 높이로 잡히므로, 실측이 쌓이기 전의 같은 `scrollTop` 이 다른 행을 가리킨다. 그 경우엔 위치가 아니라 **보고 있던 행**을 기억해 두는 편이 맞다. |
12062
12099
  | `getFirstVisibleRow` | `() => number` | 지금 본문 맨 위에 걸린 행의 인덱스 (`rows` 기준). 행이 없으면 `0`. **스크롤 위치를 저장할 때는 픽셀이 아니라 이 값을 저장한다** — `virtualScroll` 에서 픽셀은 좌표계가 실측으로 움직이는 값이라, 되돌릴 때 다른 행을 가리킨다. |
12063
12100
  | `scrollToRow` | `(index: number) => void` | 그 행이 본문 맨 위에 오도록 스크롤한다 (`rows` 기준 인덱스, 범위를 벗어나면 잘린다). `virtualScroll` 에서는 **실측이 정착할 때까지 그 행을 계속 다시 겨냥한다** — 옮기는 시점의 좌표는 아직 추정치라 한 번만 옮기면 몇 행씩 밀린다. 사용자가 직접 스크롤하면 겨냥을 놓는다. 페이지네이션을 쓰는 표에서는 **지금 페이지에 그려진 행만** 닿는다 — 다른 페이지의 행이라면 페이지를 먼저 옮긴다. |
12064
12101
  | `setRowCount` | `(count: number) => void` | 가상 스크롤 총 행 수 설정 |
@@ -12324,11 +12361,15 @@ export const TAG_COLORS = [
12324
12361
 
12325
12362
  ### Used by
12326
12363
 
12364
+ - [SBarcodeInput](../SBarcodeInput)
12327
12365
  - [SChipFilter](../SChipFilter)
12328
12366
  - [SConfirmModal](../SConfirmModal)
12329
12367
  - [SGhostButton](../SGhostButton)
12330
12368
  - [SGnb](../SGnb)
12369
+ - [SGnbSystem](../SGnbSystem)
12370
+ - [SInput](../SInput)
12331
12371
  - [SLauncherListBox](../SLauncherListBox)
12372
+ - [SNumberInput](../SNumberInput)
12332
12373
  - [SRadioCard](../SRadioCard)
12333
12374
  - [SSystemActionButton](../SSystemActionButton)
12334
12375
  - [STabs](../STabs)
@@ -12977,6 +13018,7 @@ export interface STreeItemRenderState {
12977
13018
 
12978
13019
  - [SCheckbox](../SCheckbox)
12979
13020
  - [SGhostButton](../SGhostButton)
13021
+ - [SIcon](../SIcon)
12980
13022
 
12981
13023
  ### Graph
12982
13024
 
package/dist/llms.txt CHANGED
@@ -542,6 +542,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
542
542
  | 정해진 범위 안에서 수치 하나·구간을 끌어서 고르게 한다 | `SSlider` | §3-7-16 |
543
543
  | 바코드를 스캔해 받는다 | `SBarcodeInput` | |
544
544
  | 목록에서 하나 고르게 한다 | `SSelect` | §3-7-2 |
545
+ | 계층(카테고리 > 세부분류)을 접고 펴며 드롭다운에서 고르게 한다 | `SSelect` `type="tree"`·`"multi_tree"` | §3-7-2 — 계층을 늘 펼쳐 보여도 되면 `default_depth`·`multi_depth` |
545
546
  | 선택지를 항상 펼쳐 두고 하나 고르게 한다 | `SRadioGroup` | §3-7-2 |
546
547
  | 버튼 모양으로 모드를 하나 고르게 한다 | `SRadioButton` | §3-7-2 |
547
548
  | 선택지마다 설명이 붙어 한 줄로는 안 된다 | `SRadioCardGroup` | §3-7-2 |
@@ -578,13 +579,14 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
578
579
  | 대화의 메시지 한 건을 보여준다 | `SChatMessage` | |
579
580
  | 대화 중간에 시스템이 알리는 사실을 끼운다 (상담사 배정·대화 종료 등) | `SChatSystemMessage` | 사람이 보낸 말이면 `SChatMessage` |
580
581
  | 나열한 항목을 펼쳐 하위 내용을 보여준다 | `SExpansionList` + `SExpansionItem` | §3-7-7 |
581
- | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 |
582
+ | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 — 폼 값으로 드롭다운에서 고르는 것이면 `SSelect` `type="tree"` |
582
583
  | 계층을 이루는 행들을 여러 열로 보여준다 (카테고리 > 상품 > 옵션) | `STreeTable` | §3-7-7 — 한 줄에 라벨 하나면 `STree` |
583
584
  | 사용자가 순서를 드래그로 바꾸게 한다 | `SDraggableList` + `SDraggableItem` | §3-7-6 |
584
585
  | 날짜별 일정을 한 달치 격자로 펼쳐 보여준다 | `SCalendarBoard` | §3-7-4 |
585
586
  | 항목끼리 크기를 눈으로 견주게 한다 (채널별 매출·상품별 판매량) | `SBarChart` | 정확한 값을 읽어야 하면 `STable` — 그래프는 "어느 쪽이 큰가" 를 답하지 "얼마인가" 를 답하지 않는다 |
586
587
  | 순서가 있는 항목의 **추이**를 보여준다 (일·월별 매출 흐름, 기간별 방문 수) | `SLineChart` | 항목 순서에 뜻이 없으면(채널별·상품별) `SBarChart` — 선은 "이어진다" 는 뜻을 덤으로 얹어, 순서 없는 항목을 이으면 없는 흐름을 만든다. 항목이 대여섯 개 안쪽이고 크기를 견주는 것이 목적이면 막대가 낫다 |
587
588
  | 여러 항목의 추이를 **합계와 함께** 보여준다 (채널별 매출이 쌓여 전체가 되는 흐름) | `SLineChart stacked area` | 합계가 뜻을 갖는 값일 때만 쌓는다. 음수가 섞이거나 더해서 뜻이 없는 값(비율·평균)은 쌓지 말고 겹쳐 그린다 |
589
+ | 항목 이름이 길어 가로축에서 서로 겹친다 (상품명·채널명, `2026-10-01` 같은 날짜) | 순서 없는 항목은 `SBarChart direction="horizontal"` — 이름 열이 가장 긴 이름에 맞춰 넓어진다. 순서가 있어 세로 축을 지켜야 하면(날짜순 막대·`SLineChart`) `rotateCategoryLabels` | 이름이 짧아 겹치지 않으면 켜지 않는다 — 켜면 늘 기울어 읽기만 나빠진다. 기울여도 너무 긴 이름은 차트가 말줄임하고 전체 이름은 툴팁에 뜬다. 말줄임 폭·각도를 직접 주지 않는다. 나란히 놓인 차트는 켜고 끄기를 맞춰야 그림 높이가 같다 |
588
590
  | 항목의 크기와 **그 안의 구성**을 함께 보여준다 (주문 상태별 내역, 유입 경로별 몫) | `SBarChart stacked` | 계열끼리 견주는 것이 목적이면 `stacked` 없이 나란히 세운다. 더해서 뜻이 없는 값(비율·평균)은 쌓지 않는다 — 합계 라벨이 거짓말이 된다 |
589
591
  | 한 시점의 **전체를 몇 개의 몫으로** 나눠 보여준다 (채널별 매출 비중, 회원 등급 구성) | `SPieChart` | 조각이 대여섯 개를 넘거나 몫끼리 크기를 견주는 것이 목적이면 `SBarChart` — 사람은 각도보다 길이를 정확히 견준다. 순서가 있는 추이(월별)는 몫이 아니라 흐름이라 `SLineChart`. 0·음수는 그려지지 않으므로 증감은 원으로 나타내지 않는다. 조각은 큰 순으로 넘긴다. 폭은 부모를 따르고 그림은 그 폭의 정사각형이다 — 폭이 필요하면 `className` 으로 폭만 주고 높이는 주지 않는다 (`SDonutChart` 도 같다) |
590
592
  | 한 시점의 전체를 몫으로 나누되 **가운데가 빈 고리 모양**으로 보여준다 (시안이 도넛일 때) | `SDonutChart` | 쓰임·데이터 규칙은 `SPieChart` 와 같고 모양만 다르다 — 시안이 정한 쪽을 쓴다. **구멍에 합계·라벨을 겹쳐 올리지 않는다.** 합계 같은 값이 필요하면 차트 바깥(카드 제목·요약 값)에 적는다. 여러 기간에 걸친 구성 변화는 원을 여러 개 늘어놓지 말고 `SBarChart stacked` |
@@ -1775,11 +1777,28 @@ tableRef.current.scrollToRow(row); // 복원
1775
1777
  - **쓰는 자리는 설정 화면·마법사(스텝)의 소수 결정이다.** 고르고 나면 뒤 화면이 통째로 바뀌거나 되돌리기 어려운 선택 — 평가 대상자 범위(전체/특정 구성원), 상담 자동 배정 방식 같은 것. 목록 필터·표 안 조건처럼 같은 선택지가 화면마다 반복 노출되는 자리에는 `SRadioGroup` 을 쓴다.
1776
1778
  - `SRadioCard` 단독은 `SRadioCardGroup` 이 만들 수 없는 배치에만 쓴다 — 나열은 그룹이 맡는다 (§2-2).
1777
1779
  - 카드 안에 상태 배지를 넣으려면 `tag` 슬롯에 `STag` 를 준다. 라벨 문자열에 "(추천)" 처럼 섞어 쓰지 않는다.
1780
+ - **한 선택지에 딸린 추가 입력(지정일·요청 사항 등)은 그 카드의 슬롯에 넣는다** — `SRadioCard` 는 `children`, `SRadioCardGroup` 은 옵션의 `content`. 카드 아래에 따로 입력을 늘어놓지 않는다. 슬롯은 서브타이틀 아래에 들여써서 놓이고 라디오의 클릭 영역 밖이라, 입력을 눌러도 카드 선택이 바뀌지 않는다. 들여쓰기·간격은 카드가 넣으므로 직접 주지 않는다. 고른 카드에만 보여주고, 카드를 `disabled` 로 두면 슬롯의 컨트롤도 함께 `disabled` 로 둔다(카드가 대신 잠그지 않는다).
1778
1781
  - **카드처럼 생겼다고 `SCard`/`SSectionHeaderCard` 로 감싸지 않는다.** `SRadioCard` 자체가 완결된 요소이고, 나열 간격은 `SRadioCardGroup` 의 `direction` 이 맞춘다 (§2-2).
1779
1782
 
1783
+ ##### 후보에 상하 관계가 있으면 — depth vs tree
1784
+
1785
+ 계층은 `options` 의 `children` 으로 만든다. 평평한 `default`·`multi` 에 분류명을 라벨에 섞어 늘어놓지 않는다. 남는 선택은 **계층을 어떻게 보여주는가**와 **그룹이 값이 되는가**다.
1786
+
1787
+ | 상황 | `type` |
1788
+ | --- | --- |
1789
+ | 그룹이 몇 개 안 돼 늘 펼쳐 둬도 한눈에 읽힌다. 그룹은 분류 헤더일 뿐 값이 아니다 | `default_depth` · `multi_depth` |
1790
+ | 그룹·단계가 많아 다 펼치면 목록이 길어진다 — 접어 두고 필요한 갈래만 편다 | `tree` · `multi_tree` |
1791
+ | **그룹 자체도 값**이다 (예: "패션의류" 전체를 하나의 조건으로 고른다) — 단일 선택 | `tree` |
1792
+
1793
+ - **값에 무엇이 담기는가.** `default_depth`·`multi_depth`·`multi_tree` 는 언제나 **리프만** 담긴다 — `multi_tree`·`multi_depth` 의 그룹 체크박스는 그 아래 리프를 한꺼번에 넣고 뺄 뿐, 그룹의 `value` 는 값이 되지 않는다. 그룹의 `value` 가 값으로 오는 것은 `tree` 뿐이다.
1794
+ - **펼침 상태는 `SSelect` 가 쥔다.** 열 때마다 선택값을 품은 그룹이 펼쳐지고, 검색 중에는 걸린 줄이 보이도록 결과를 전부 펼친다. 앱이 펼칠 그룹을 따로 들고 있지 않는다.
1795
+ - 그룹의 `disabled` 는 그 줄의 선택만 막는다 — 마우스(화살표)로도 키보드(→)로도 접고 펴기는 되므로 아래의 고를 수 있는 자식에 닿는 길은 남는다.
1796
+ - 하위가 전부 비활성이면 `multi_tree`·depth 타입은 그룹도 함께 잠그므로 앱이 어미에 `disabled` 를 다시 달 필요가 없다. `tree` 는 그룹 자체가 값이라 하위가 막혀도 그룹은 고를 수 있다 — 그룹까지 막으려면 그룹에 `disabled` 를 직접 준다.
1797
+ - 드롭다운 없이 화면에 계층을 펼쳐 두고 여러 개를 체크하게 하는 것이면 `SSelect` 가 아니라 `STree` 다 (§3-7-7).
1798
+
1780
1799
  ##### 여러 개 고른 값을 칩으로 보여줄 때 — `valueDisplay="chip"`
1781
1800
 
1782
- - **`type="multi"`·`"multi_depth"` 에서 `valueDisplay="chip"` 을 주면** 선택값이 트리거에 칩으로 뜨고, 칩의 × 로 하나씩 뺄 수 있다. 기본(`text`)은 라벨을 쉼표로 이어 한 줄로 말줄임한다. 고른 값 하나하나를 확인하고 바로 빼야 하는 자리면 `chip`, 몇 개 골랐는지만 보이면 되는 조회 필터면 `text` 를 쓴다.
1801
+ - **`type="multi"`·`"multi_depth"`·`"multi_tree"` 에서 `valueDisplay="chip"` 을 주면** 선택값이 트리거에 칩으로 뜨고, 칩의 × 로 하나씩 뺄 수 있다. 기본(`text`)은 라벨을 쉼표로 이어 한 줄로 말줄임한다. 고른 값 하나하나를 확인하고 바로 빼야 하는 자리면 `chip`, 몇 개 골랐는지만 보이면 되는 조회 필터면 `text` 를 쓴다.
1783
1802
  - **후보가 정해진 목록에서 고르는 것이면 `SSelect` 의 `chip` 이고, 사용자가 값을 직접 타이핑해 쌓는 것이면 `SChipInput` 이다.** 목록에서 고른 값을 `SChipInput` 에 옮겨 담거나, `SSelect` 옆에 `SChip` 을 따로 나열해 선택값을 흉내 내지 않는다.
1784
1803
  - **단일 선택 type 에는 주지 않는다.** 무시되고 `text` 로 보인다. 단일 선택의 값 비우기는 `clearable` 이 맡는다.
1785
1804
  - 칩이 한 줄을 넘으면 줄바꿈하고 트리거가 그만큼 높아진다. 높이·칩 간격은 `SSelect` 가 토큰으로 넣는다 — 직접 주지 않는다.