sellmate-design-system-react 9.0.0-beta.48 → 9.0.0-beta.49

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
@@ -18,6 +18,19 @@
18
18
 
19
19
  "비슷하게 생긴 것을 직접 만드는 것"이 어색함의 가장 큰 원인이다. 대응 컴포넌트를 쓰면 색·간격·상태·접근성이 전부 따라온다.
20
20
 
21
+ ### 0-0. 화면을 짜기 전에 — 세 가지 질문
22
+
23
+ **컴포넌트를 고르기 전에 이 세 가지에 답한다.** 요청에 답이 없으면 추측해서 채우지 말고 **되묻는다.**
24
+
25
+ 1. 이 화면에서 사용자가 하려는 **단 하나의 일**은 무엇인가
26
+ 2. 그 일을 끝내는 데 **없어도 되는 것**은 무엇인가 — 컬럼·버튼·안내 문구 중 빼도 되는 것
27
+ 3. **실패하면** 어디로 돌아가는가 — 오류·빈 목록·권한 없음일 때 무엇을 보여줄지
28
+
29
+ 요청받은 것을 그대로 다 넣지 않는다. **"있을 법한 필드를 빠짐없이 채우는 것"이 화면을 망치는 가장 흔한 방식이다.**
30
+ 목록에 컬럼을, 폼에 입력란을, 툴바에 버튼을 하나 더 넣기는 쉽고 나중에 빼기는 어렵다. 2번은 그래서 있다.
31
+
32
+ 2번에 답이 하나도 없으면 아직 화면을 이해하지 못한 것이다. 그 상태로 코드를 쓰면 미정 상태가 그대로 화면이 된다.
33
+
21
34
  ### 0-1. 전체 컴포넌트 인덱스
22
35
 
23
36
  무엇을 만들지 정했으면 **이 표에서 먼저 찾는다.** 상세 Props·Types 는 `dist/components/<이름>/README.md` 참조.
@@ -32,6 +45,7 @@
32
45
  | **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(입력창 위, 아직 보내지 않은 첨부 한 칸) `SChatFile`(대화 흐름에 선, 보낸 파일 한 칸) `SChatSystemMessage`(대화 흐름 가운데 서는 시스템 안내) `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SListItem` `SExpansionList` `SDraggableList` `SDraggableItem` `STree` |
33
46
  | **레이아웃** | `SLayout` `SGnb` `SGnbSystem` `SSystemActionButton`(GNB system 패널에 한 줄씩 쌓는 액션 행 — 버튼 고르기는 §3-5) `SAccountListBox`(계정 행을 눌러 뜨는 계정 패널) `SPage` `SPageHeader`(페이지 제목 영역 — `SLayout` 안에서 `SPage` 앞에 둔다) `SSectionHeaderCard` `SCard` `SLoginCard`(통합 계정 로그인 화면의 카드) `SDivider` `SSplitter` `SScrollArea` `SExpansionItem` |
34
47
  | **내비게이션** | `STabs` `SPagination` `SStepper` |
48
+ | **차트** | `SBarChart`(막대 그래프 — 항목끼리 크기를 견준다) |
35
49
  | **표시·상태** | `STag` `SBadge` `SIcon` `SImage` `SCallout` `SGuide` |
36
50
  | **진행·로딩** | `SLinearProgress` `SCircleProgress` `SLoadingContainer` `SLoadingModal` |
37
51
  | **오버레이** | `STooltip` `SPopover` `SPopup` `SDrawer` `SPortal` |
@@ -153,7 +167,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
153
167
  | 층 | 무엇인가 | 컴포넌트 |
154
168
  | --- | --- | --- |
155
169
  | **셸** | 앱 전체 뼈대. 페이지가 바뀌어도 남는다 | `SLayout` `SGnb` `SGnbSystem`(GNB 맨 아래 판 · 전폭 상단바 오른쪽 끝) `SPage` `SPageHeader`(`SLayout` 안에서 `SPage` 앞에 둔다) |
156
- | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `SCallout` `STabs` `SStepper` `SPagination` `SDivider` |
170
+ | **블록** | `SPage` 의 직계 자식. 페이지를 세로로 쌓는 단위 | `SSectionHeaderCard` `SCard` `SChatMessage` `SChatSystemMessage` `SChatInput` `SLoginCard`(유일하게 `SPage` 밖에 선다 — 로그인 화면 자체가 자기 자리다, §4-6) `SForm` `SSplitter` `SScrollArea` `SCalendarBoard` `STable` `STableBar` `SChipFilter` `SKeyValueTable` `SList` `SExpansionList` `SDraggableList` `STree` `SCallout` `SBarChart` `STabs` `SStepper` `SPagination` `SDivider` |
157
171
  | **요소** | 블록 **안에** 놓이는 컨트롤. 혼자 페이지에 서지 않는다 | `SButton` `SGhostButton` `SDropdownButton` `SSystemActionButton` `SField` `SInput` `SSearchInput` `SNumberInput` `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` |
158
172
  | **인라인** | 텍스트 흐름·셀·라벨 안에 섞인다. 혼자 블록이 되지 않는다 | `STag` `SBadge` `SIcon` `STextLink` `SChip` |
159
173
  | **레이어** | 문서 흐름 **밖**에 떠서 그려진다. 어느 층에서 띄우든 레이아웃에 영향이 없다 | `SModal` `SActionModal` `SConfirmModal` `SPopup` `SDrawer` `SPopover` `STooltip` `SPortal` `SAccountListBox`(계정 행에 붙어 뜬다 — 직접 띄우지 않는다) `SToast` `SLoadingModal` `SLoadingContainer` `SGuide` |
@@ -527,6 +541,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
527
541
  | 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 |
528
542
  | 사용자가 순서를 드래그로 바꾸게 한다 | `SDraggableList` + `SDraggableItem` | §3-7-6 |
529
543
  | 날짜별 일정을 한 달치 격자로 펼쳐 보여준다 | `SCalendarBoard` | §3-7-4 |
544
+ | 항목끼리 크기를 눈으로 견주게 한다 (기간별 추이·채널별 비중) | `SBarChart` | 정확한 값을 읽어야 하면 `STable` — 그래프는 "어느 쪽이 큰가" 를 답하지 "얼마인가" 를 답하지 않는다 |
530
545
  | 표 위에 건수 요약과 액션을 얹는다 | `STableBar` | §4-2 |
531
546
  | 상태·분류를 라벨로 찍는다 | `STag` | §3-1 |
532
547
  | 색 점만으로 상태를 찍는다 | `SBadge` | §3-1 |
@@ -0,0 +1,104 @@
1
+ # SBarChart
2
+
3
+ > 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
4
+
5
+ ### SBarChart
6
+
7
+ #### Props
8
+
9
+ | Prop | Type | Default | Description |
10
+ |------|------|---------|-------------|
11
+ | `categories` | `string[]` | — | 가로축(가로 막대면 세로축)에 놓일 항목 이름 |
12
+ | `series` | `SBarChartSeries[]` | — | 계열 목록. 각 `data` 는 `categories` 와 같은 순서다 |
13
+ | `direction?` | `SBarChartDirection` | `'vertical'` | 막대가 자라는 방향 |
14
+ | `palette?` | `SBarChartPalette` | `'default'` | 색 팔레트. 계열이 하나면 계열 대신 **항목**마다 색이 바뀐다. `custom` 일 때만 `colors` 를 본다 |
15
+ | `colors?` | `SBarChartColor[]` | — | `palette='custom'` 에서 쓸 색 이름을 계열 순서대로. 계열보다 짧으면 앞에서부터 순환한다 |
16
+ | `max?` | `number` | — | 값 축의 최댓값. 주지 않으면 데이터에서 읽기 좋은 값으로 정한다 |
17
+ | `tickCount?` | `number` | `8` | 값 축 눈금 개수 |
18
+ | `barSize?` | `number` | `BAR_SIZE_MAX` | 막대 두께 상한(px, 24~80). 낮추면 좌우 여백 상한도 같은 비율로 따라 내려온다 |
19
+ | `showValueLabel?` | `boolean` | `true` | 막대마다 값을 적는다 |
20
+ | `showLegend?` | `boolean` | `true` | 범례를 보인다 |
21
+ | `legendPosition?` | `SBarChartLegendPosition` | `'top'` | 범례 위치 |
22
+ | `showTooltip?` | `boolean` | `true` | 막대에 마우스를 올리면 값 상자를 띄운다 |
23
+ | `formatValue?` | `(value: number) => string` | `defaultFormat` | 값 표시 형식 |
24
+ | `height?` | `number \| string` | — | 차트 높이. **아래 축 텍스트까지 포함한 값**이다 — 그림은 그만큼 줄어든다 |
25
+ | `className?` | `string` | — | |
26
+ | `style?` | `CSSProperties` | — | |
27
+
28
+ #### Events
29
+
30
+ | Event | Type | Description |
31
+ |-------|------|-------------|
32
+ | `onBarClick` | `(point: SBarChartPoint) => void` | 막대를 눌렀을 때 |
33
+
34
+ ## Types
35
+
36
+ ### SBarChartSeries
37
+
38
+ ```ts
39
+ /** 한 계열 — 범례 한 줄에 대응한다. */
40
+ export interface SBarChartSeries {
41
+ /** 범례·툴팁에 표시할 이름 */
42
+ name: string;
43
+ /** `categories` 와 같은 순서의 값. 짧으면 남는 항목은 막대를 그리지 않는다 */
44
+ data: number[];
45
+ }
46
+ ```
47
+
48
+ ### SBarChartDirection
49
+
50
+ ```ts
51
+ /** 막대가 자라는 방향. */
52
+ export type SBarChartDirection = 'vertical' | 'horizontal';
53
+ ```
54
+
55
+ ### SBarChartPalette
56
+
57
+ ```ts
58
+ /**
59
+ * 색 팔레트.
60
+ * - `default` 파랑 한 색. 계열이 하나거나 색으로 나눌 것이 없을 때
61
+ * - `multi` 서로 무관한 항목(11색)을 순서대로
62
+ * - `gradation` 한 지표의 단계(6색)를 진한 쪽부터 순서대로
63
+ * - `custom` `colors` 로 고른 색을 순서대로
64
+ */
65
+ export type SBarChartPalette = 'default' | 'multi' | 'gradation' | 'custom';
66
+ ```
67
+
68
+ ### SBarChartColor
69
+
70
+ ```ts
71
+ /**
72
+ * `palette='custom'` 에서 고를 수 있는 색 이름.
73
+ * positive=늘어남 · negative=줄어듦 · neutral=변화 없음 을 뜻하므로 뜻에 맞게 고른다.
74
+ */
75
+ export type SBarChartColor =
76
+ | 'positivePrimary'
77
+ | 'positiveSecondary'
78
+ | 'negativePrimary'
79
+ | 'negativeSecondary'
80
+ | 'neutralPrimary'
81
+ | 'neutralSecondary';
82
+ ```
83
+
84
+ ### SBarChartLegendPosition
85
+
86
+ ```ts
87
+ /** 범례 위치. */
88
+ export type SBarChartLegendPosition = 'top' | 'bottom';
89
+ ```
90
+
91
+ ### SBarChartPoint
92
+
93
+ ```ts
94
+ /** 툴팁·클릭이 가리키는 지점. */
95
+ export interface SBarChartPoint {
96
+ /** 계열 인덱스 */
97
+ seriesIndex: number;
98
+ /** 카테고리 인덱스 */
99
+ categoryIndex: number;
100
+ /** 그 지점의 값 */
101
+ value: number;
102
+ }
103
+ ```
104
+
@@ -0,0 +1,75 @@
1
+ import { type CSSProperties } from 'react';
2
+ /** 막대가 자라는 방향. */
3
+ export type SBarChartDirection = 'vertical' | 'horizontal';
4
+ /** 범례 위치. */
5
+ export type SBarChartLegendPosition = 'top' | 'bottom';
6
+ /**
7
+ * 색 팔레트.
8
+ * - `default` 파랑 한 색. 계열이 하나거나 색으로 나눌 것이 없을 때
9
+ * - `multi` 서로 무관한 항목(11색)을 순서대로
10
+ * - `gradation` 한 지표의 단계(6색)를 진한 쪽부터 순서대로
11
+ * - `custom` `colors` 로 고른 색을 순서대로
12
+ */
13
+ export type SBarChartPalette = 'default' | 'multi' | 'gradation' | 'custom';
14
+ /**
15
+ * `palette='custom'` 에서 고를 수 있는 색 이름.
16
+ * positive=늘어남 · negative=줄어듦 · neutral=변화 없음 을 뜻하므로 뜻에 맞게 고른다.
17
+ */
18
+ export type SBarChartColor = 'positivePrimary' | 'positiveSecondary' | 'negativePrimary' | 'negativeSecondary' | 'neutralPrimary' | 'neutralSecondary';
19
+ /** 툴팁·클릭이 가리키는 지점. */
20
+ export interface SBarChartPoint {
21
+ /** 계열 인덱스 */
22
+ seriesIndex: number;
23
+ /** 카테고리 인덱스 */
24
+ categoryIndex: number;
25
+ /** 그 지점의 값 */
26
+ value: number;
27
+ }
28
+ /** 한 계열 — 범례 한 줄에 대응한다. */
29
+ export interface SBarChartSeries {
30
+ /** 범례·툴팁에 표시할 이름 */
31
+ name: string;
32
+ /** `categories` 와 같은 순서의 값. 짧으면 남는 항목은 막대를 그리지 않는다 */
33
+ data: number[];
34
+ }
35
+ export interface SBarChartProps {
36
+ /** 가로축(가로 막대면 세로축)에 놓일 항목 이름 */
37
+ categories: string[];
38
+ /** 계열 목록. 각 `data` 는 `categories` 와 같은 순서다 */
39
+ series: SBarChartSeries[];
40
+ /** 막대가 자라는 방향 */
41
+ direction?: SBarChartDirection;
42
+ /** 색 팔레트. 계열이 하나면 계열 대신 **항목**마다 색이 바뀐다. `custom` 일 때만 `colors` 를 본다 */
43
+ palette?: SBarChartPalette;
44
+ /** `palette='custom'` 에서 쓸 색 이름을 계열 순서대로. 계열보다 짧으면 앞에서부터 순환한다 */
45
+ colors?: SBarChartColor[];
46
+ /** 값 축의 최댓값. 주지 않으면 데이터에서 읽기 좋은 값으로 정한다 */
47
+ max?: number;
48
+ /** 값 축 눈금 개수 */
49
+ tickCount?: number;
50
+ /** 막대 두께 상한(px, 24~80). 낮추면 좌우 여백 상한도 같은 비율로 따라 내려온다 */
51
+ barSize?: number;
52
+ /** 막대마다 값을 적는다 */
53
+ showValueLabel?: boolean;
54
+ /** 범례를 보인다 */
55
+ showLegend?: boolean;
56
+ /** 범례 위치 */
57
+ legendPosition?: SBarChartLegendPosition;
58
+ /** 막대에 마우스를 올리면 값 상자를 띄운다 */
59
+ showTooltip?: boolean;
60
+ /** 값 표시 형식 */
61
+ formatValue?: (value: number) => string;
62
+ /** 차트 높이. **아래 축 텍스트까지 포함한 값**이다 — 그림은 그만큼 줄어든다 */
63
+ height?: number | string;
64
+ /** 막대를 눌렀을 때 */
65
+ onBarClick?: (point: SBarChartPoint) => void;
66
+ className?: string;
67
+ style?: CSSProperties;
68
+ }
69
+ /**
70
+ * SBarChart — 막대 그래프.
71
+ *
72
+ * 값은 항상 0 에서 자란다. 음수가 있으면 기준선이 축 가운데로 내려오고 막대가
73
+ * 아래(또는 왼쪽)로 자란다.
74
+ */
75
+ export declare const SBarChart: import("react").ForwardRefExoticComponent<SBarChartProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * SBarChart 의 치수·색 상수와 막대 배치 계산.
3
+ *
4
+ * ⚠️ 아래 네 값은 원래 `--cmp-chart-bar-*` 로 와야 하지만, `tokens/token.json` 의
5
+ * `chart.bar` 노드가 그룹인데 `"type": "other"` 를 달고 있어 생성기가 그 아래를 통째로
6
+ * 잘라 버린다(자식 하나의 이름이 `value` 라 leaf 로 오인된다). 토큰이 고쳐지면
7
+ * 아래 TODO 를 따라 교체한다.
8
+ */
9
+ /**
10
+ * 막대 두께 하한(px) — 시안 `bar width min : 24`.
11
+ * 이보다 얇아지지 않는다. 카테고리가 너무 많으면 막대가 겹치는데, 그건
12
+ * "얇아서 못 읽는 그래프"보다 낫다는 디자인 판단이다(그때는 가로 막대를 쓴다).
13
+ */
14
+ export declare const BAR_SIZE_MIN = 24;
15
+ /** 막대 두께 상한(px) — 시안 `bar width max : 80`. 자리가 남으면 여기까지 두꺼워진다. */
16
+ export declare const BAR_SIZE_MAX = 80;
17
+ /** 한 카테고리 안, 계열 막대 사이 간격(px) — 시안 `bar gap : 6 (fixed)`. */
18
+ export declare const BAR_GAP = 6;
19
+ /** 막대 묶음 좌우 여백의 하한(px) — 시안 `bar group paddingX min : 8`. */
20
+ export declare const GROUP_PADDING_MIN = 8;
21
+ /** 막대 묶음 좌우 여백의 상한(px) — 시안 `bar group paddingX max : 24`. */
22
+ export declare const GROUP_PADDING_MAX = 24;
23
+ /** 막대 끝과 값 라벨 사이 간격(px) — 시안 실측. */
24
+ export declare const VALUE_LABEL_GAP = 6;
25
+ /**
26
+ * 막대 모서리 반경(px). SVG 경로를 좌표로 계산하므로 `var(--radius-8)` 문자열이 아니라
27
+ * **숫자**여야 한다 — 시안의 clipPath 도 같은 이유로 8 을 좌표에 박아 두고 있다.
28
+ * TODO: 토큰 생성되면 `--cmp-chart-bar-radius` 값과 같은지 확인
29
+ */
30
+ export declare const BAR_RADIUS = 8;
31
+ /** TODO: 토큰 생성되면 `--cmp-chart-bar-opacity-default` 로 교체 */
32
+ export declare const BAR_OPACITY_DEFAULT = "var(--opacity-080)";
33
+ /** TODO: 토큰 생성되면 `--cmp-chart-bar-opacity-dimmed` 로 교체 */
34
+ export declare const BAR_OPACITY_DIMMED = "var(--opacity-060)";
35
+ /** TODO: 토큰 생성되면 `--cmp-chart-bar-value-color` 로 교체 */
36
+ export declare const BAR_VALUE_COLOR = "var(--sys-color-field-text-readOnly)";
37
+ export interface BandLayout {
38
+ /** 카테고리 하나가 차지하는 폭(px) */
39
+ band: number;
40
+ /** 막대 하나의 두께(px) */
41
+ bar: number;
42
+ /** 계열 막대 묶음 전체의 두께(px) */
43
+ group: number;
44
+ /** 묶음 좌우로 실제로 남은 여백(px) */
45
+ padding: number;
46
+ /** 카테고리가 적어 band 가 상한에 걸렸을 때, 막대 전체를 가운데로 미는 거리(px) */
47
+ offset: number;
48
+ }
49
+ /**
50
+ * 축을 카테고리 수만큼 균등하게 나누고(band), 그 가운데에 계열 막대를 모아 놓는다.
51
+ *
52
+ * band 중앙 정렬이라 카테고리 라벨도 같은 비율로 놓으면 자동으로 막대 위에 온다 —
53
+ * 라벨과 막대의 정렬을 따로 맞출 필요가 없다.
54
+ *
55
+ * **두께와 여백은 한 손잡이로 함께 움직인다.** 막대 하나가 차지할 자리는 최소
56
+ * `8+24+8`(=40px)에서 최대 `24+80+24`(=128px)까지 늘어나는데, 그 사이 어디에 있든
57
+ * 두께와 여백이 같은 비율(`t`)로 커진다. 여백만 8인 채 두께가 80이 되는 조합은 없다.
58
+ *
59
+ * bar = 24 + 56·t
60
+ * padding = 8 + 16·t (t ∈ [0, 1])
61
+ *
62
+ * 자리가 최소보다 좁으면 `t=0` 에서 멈춘다 — 더 얇아지는 대신 호출 쪽이 스크롤을
63
+ * 만든다. 반대로 자리가 남으면 `t=1` 에서 멈추고 남는 폭은 `offset` 으로 가운데 모은다.
64
+ */
65
+ export declare function bandLayout(size: number, categoryCount: number, seriesCount: number, barSizeMax?: number): BandLayout;
@@ -0,0 +1,2 @@
1
+ export { SBarChart, type SBarChartProps, type SBarChartSeries, type SBarChartPoint, type SBarChartPalette, type SBarChartColor, type SBarChartDirection, type SBarChartLegendPosition, } from './SBarChart';
2
+ export { BAR_SIZE_MIN, BAR_SIZE_MAX, BAR_GAP } from './barChart.config';
@@ -15,7 +15,7 @@
15
15
  | `avatarSrc?` | `string` | — | 아바타 이미지 경로. 없으면 사람 아이콘 자리표시가 선다. **받은 메시지에만 쓰인다** — 보낸 메시지에는 아바타가 서지 않는다(`direction` 참고). |
16
16
  | `avatarAlt?` | `string` | — | 아바타 대체 텍스트 |
17
17
  | `continued?` | `boolean` | `false` | 같은 사람이 이어서 말한 묶음인지. 켜면 **아바타와 `sender` 를 그리지 않는다** — 말풍선이 위 묶음과 같은 선에서 시작해 한 사람의 말로 이어 읽힌다. 받은 메시지에서는 아바타 자리를 비워 둔 채 남긴다 — 안 남기면 말풍선이 44px 왼쪽으로 밀려 위 묶음과 어긋난다. 보낸 메시지는 아바타가 없으므로 이름만 숨긴다. `time`·`readStatus` 는 그대로 나온다. 시간이 벌어져 묶음을 나눴어도 얼굴은 한 번만 보이면 되고 시각은 묶음마다 필요하기 때문이다. **얼마나 벌어져야 묶음을 나눌지는 앱이 정한다** — 30분이든 하루든 대화의 성격에 달렸으므로 컴포넌트는 기준을 갖지 않고 스위치만 연다. |
18
- | `variant?` | `SChatMessageVariant` | `'default'` | 말풍선 종류. `template` 이면 말풍선이 옅은 파랑 면으로 서서 미리 등록된 서식으로 보내진 메시지임을 드러낸다. **보낸 메시지(`direction="outgoing"`)에만 쓰인다** — 받은 메시지에는 넘겨도 그리지 않는다. 템플릿은 사업자가 보내는 것이라 받은 쪽에는 뜻이 없다. 앱이 메시지를 한 번만 매핑해 방향과 무관하게 넘길 수 있도록 막지 않고 무시한다. |
18
+ | `variant?` | `SChatMessageVariant` | `'default'` | 말풍선 종류. `template` 미리 등록된 서식으로, `admin` 관리자·시스템이 보낸 메시지임을 각각 다른 면으로 드러낸다. 면 색은 토큰이 정하므로 여기서 색을 정하지 않는다. **보낸 메시지(`direction="outgoing"`)에만 쓰인다** — 받은 메시지에는 넘겨도 그리지 않는다. 사업자 쪽이 보내는 것이라 받은 쪽에는 뜻이 없다. 앱이 메시지를 한 번만 매핑해 방향과 무관하게 넘길 수 있도록 막지 않고 무시한다. |
19
19
  | `actions?` | `ReactNode` | — | 시각 아래에 붙는 동작 슬롯. 없으면 그 줄이 통째로 빠진다. 「상담원 연결」처럼 **이 메시지에 이어서 할 수 있는 동작**이 오는 자리다. 무엇을 놓을지는 앱이 정하고, 메시지는 줄로 세우고 방향에 맞춰 정렬하는 것까지만 한다. 시각과 같은 선에서 시작한다 — 말풍선 끝에서 한 칸 안이다. |
20
20
  | `messages?` | `ReactNode[]` | — | 말풍선 목록. **한 항목이 말풍선 하나**가 되어 위에서 아래로 쌓인다. 한 사람이 연달아 말하면 아바타·이름·시각은 한 번만 서고 말풍선만 늘어난다 — 그 묶음이 이 컴포넌트 한 개다. 말풍선 안에는 글뿐 아니라 버튼 같은 요소도 올 수 있다. |
21
21
  | `attachments?` | `ReactNode[]` | — | 말풍선 아래에 붙는 파일 목록. **한 항목이 칸 하나**가 되어 위에서 아래로 쌓인다. `SChatFile` 을 넣는 자리다 — 말풍선과 달리 면으로 감싸지 않고 넘긴 것을 그대로 세운다. 파일 칸은 제 면·선·라운드를 이미 갖고 있어 한 번 더 감싸면 칸이 두 겹으로 보인다. **`messages` 대신 여기로 넘긴다.** `messages` 로 넘기면 말풍선 면에 감싸여 그렇게 된다. 아바타·이름·시각·읽음 표시는 글 메시지와 똑같이 이 컴포넌트가 그린다 — 파일을 보낸 것도 대화의 한 줄이므로 행 규칙을 따로 갖지 않는다. |
@@ -58,12 +58,15 @@ export const CHAT_MESSAGE_READ_STATUSES = ['read', 'unread'] as const;
58
58
 
59
59
  ```ts
60
60
  /**
61
- * 말풍선의 종류. `template` 은 미리 등록된 서식으로 보내진 메시지다.
61
+ * 말풍선의 종류.
62
+ * - `default` 사람이 직접 쓴 메시지
63
+ * - `template` 미리 등록된 서식으로 보내진 메시지
64
+ * - `admin` 관리자·시스템이 보낸 메시지
62
65
  *
63
- * **보낸 메시지에서만 면이 갈린다.** 템플릿은 사업자가 보내는 것이라 받은 메시지에는
64
- * 뜻이 없고, 받은 메시지는 템플릿이든 아니든 같은 면으로 선다.
66
+ * **보낸 메시지에서만 면이 갈린다.** 사업자 쪽이 보내는 것이라 받은 메시지에는
67
+ * 뜻이 없고, 받은 메시지는 무엇으로 보냈든 같은 면으로 선다.
65
68
  */
66
- export const CHAT_MESSAGE_VARIANTS = ['default', 'template'] as const;
69
+ export const CHAT_MESSAGE_VARIANTS = ['default', 'template', 'admin'] as const;
67
70
  ```
68
71
 
69
72
  ## Dependencies
@@ -3,12 +3,15 @@ import { type HTMLAttributes, type ReactNode } from 'react';
3
3
  export declare const CHAT_MESSAGE_DIRECTIONS: readonly ["incoming", "outgoing"];
4
4
  export type SChatMessageDirection = (typeof CHAT_MESSAGE_DIRECTIONS)[number];
5
5
  /**
6
- * 말풍선의 종류. `template` 은 미리 등록된 서식으로 보내진 메시지다.
6
+ * 말풍선의 종류.
7
+ * - `default` 사람이 직접 쓴 메시지
8
+ * - `template` 미리 등록된 서식으로 보내진 메시지
9
+ * - `admin` 관리자·시스템이 보낸 메시지
7
10
  *
8
- * **보낸 메시지에서만 면이 갈린다.** 템플릿은 사업자가 보내는 것이라 받은 메시지에는
9
- * 뜻이 없고, 받은 메시지는 템플릿이든 아니든 같은 면으로 선다.
11
+ * **보낸 메시지에서만 면이 갈린다.** 사업자 쪽이 보내는 것이라 받은 메시지에는
12
+ * 뜻이 없고, 받은 메시지는 무엇으로 보냈든 같은 면으로 선다.
10
13
  */
11
- export declare const CHAT_MESSAGE_VARIANTS: readonly ["default", "template"];
14
+ export declare const CHAT_MESSAGE_VARIANTS: readonly ["default", "template", "admin"];
12
15
  export type SChatMessageVariant = (typeof CHAT_MESSAGE_VARIANTS)[number];
13
16
  /** 상대가 내 메시지를 읽었는지. 시각 왼쪽에 붙는다. */
14
17
  export declare const CHAT_MESSAGE_READ_STATUSES: readonly ["read", "unread"];
@@ -62,11 +65,11 @@ export interface SChatMessageProps extends Omit<HTMLAttributes<HTMLDivElement>,
62
65
  */
63
66
  continued?: boolean;
64
67
  /**
65
- * 말풍선 종류. `template` 이면 말풍선이 옅은 파랑 면으로 서서 미리 등록된 서식으로 보내진
66
- * 메시지임을 드러낸다.
68
+ * 말풍선 종류. `template` 미리 등록된 서식으로, `admin` 관리자·시스템이 보낸
69
+ * 메시지임을 각각 다른 면으로 드러낸다. 면 색은 토큰이 정하므로 여기서 색을 정하지 않는다.
67
70
  *
68
71
  * **보낸 메시지(`direction="outgoing"`)에만 쓰인다** — 받은 메시지에는 넘겨도 그리지 않는다.
69
- * 템플릿은 사업자가 보내는 것이라 받은 쪽에는 뜻이 없다. 앱이 메시지를 한 번만 매핑해
72
+ * 사업자 쪽이 보내는 것이라 받은 쪽에는 뜻이 없다. 앱이 메시지를 한 번만 매핑해
70
73
  * 방향과 무관하게 넘길 수 있도록 막지 않고 무시한다.
71
74
  */
72
75
  variant?: SChatMessageVariant;