sellmate-design-system-react 9.0.0-beta.47 → 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 +21 -5
- package/dist/components/SBarChart/README.md +104 -0
- package/dist/components/SBarChart/SBarChart.d.ts +75 -0
- package/dist/components/SBarChart/barChart.config.d.ts +65 -0
- package/dist/components/SBarChart/index.d.ts +2 -0
- package/dist/components/SChatAttachedFile/README.md +3 -4
- package/dist/components/SChatAttachedFile/SChatAttachedFile.d.ts +3 -44
- package/dist/components/SChatAttachedFile/chatAttachedFile.config.d.ts +19 -39
- package/dist/components/SChatAttachedFile/index.d.ts +1 -1
- package/dist/components/SChatFile/README.md +33 -0
- package/dist/components/SChatFile/SChatFile.d.ts +37 -0
- package/dist/components/SChatFile/chatFile.config.d.ts +56 -0
- package/dist/components/SChatFile/index.d.ts +2 -0
- package/dist/components/SChatMessage/README.md +9 -5
- package/dist/components/SChatMessage/SChatMessage.d.ts +22 -7
- package/dist/components/SGhostButton/README.md +2 -0
- package/dist/components/SIcon/README.md +2 -0
- package/dist/index.cjs +944 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +939 -132
- package/dist/index.js.map +1 -1
- package/dist/lib/chart/cartesian.d.ts +46 -0
- package/dist/lib/chart/frame.d.ts +17 -0
- package/dist/lib/chart/legend.d.ts +15 -0
- package/dist/lib/chart/palette.d.ts +26 -0
- package/dist/lib/chart/scale.d.ts +26 -0
- package/dist/lib/chart/tooltip.d.ts +23 -0
- package/dist/lib/chart/types.d.ts +29 -0
- package/dist/lib/chart/use-element-size.d.ts +17 -0
- package/dist/llms-full.txt +171 -16
- package/dist/llms.txt +25 -10
- package/dist/styles.css +347 -40
- package/dist/theme.css +118 -7
- package/eslint/scale.gen.mjs +2 -2
- package/package.json +1 -1
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` 참조.
|
|
@@ -29,9 +42,10 @@
|
|
|
29
42
|
| **버튼·링크** | `SButton` `SGhostButton` `SDropdownButton` `STextLink` `SSwitch` `SToggle` |
|
|
30
43
|
| **입력 (폼)** | `SForm` `SField` `SInput` `SChatInput`(대화 입력창) `SSearchInput` `SNumberInput` `STextarea` `SEditor` `SSelect` `SCheckbox` `SRadio` `SRadioGroup` `SRadioButton` `SRadioCard` `SRadioCardGroup` `SChip` `SChipInput` `SBarcodeInput` `SFilePicker` |
|
|
31
44
|
| **날짜·시간** | `SCalendar` `SCalendarBoard`(한 달치 일정 판) `SDatePicker` `SDatePickerYearListbox` `SDatePickerMonthListbox` `SDateRangePicker` `STimePicker` `STimeRangePicker` |
|
|
32
|
-
| **표·목록** | `SChatMessage`(대화의 메시지 한 건) `SChatAttachedFile`(
|
|
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,8 +167,8 @@ 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` |
|
|
157
|
-
| **요소** | 블록 **안에** 놓이는 컨트롤. 혼자 페이지에 서지 않는다 | `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` `SImage` `SLinearProgress` `SCircleProgress` |
|
|
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` |
|
|
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` |
|
|
160
174
|
|
|
@@ -499,8 +513,9 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
|
|
|
499
513
|
| 목록을 좁히는 필터를 켜고 끄게 한다 | `SToggle` | §3-7-3 |
|
|
500
514
|
| 자유 입력값을 여러 개 쌓게 한다 | `SChipInput` | §3-1 |
|
|
501
515
|
| 입력된 값 하나를 지우거나 고치게 한다 | `SChip` | §3-1 |
|
|
502
|
-
| 파일을 받는다 (고르게 한다) | `SFilePicker` | 고른·보낸 파일을 **보여주는** 것은 `SChatAttachedFile` |
|
|
503
|
-
|
|
|
516
|
+
| 파일을 받는다 (고르게 한다) | `SFilePicker` | 고른·보낸 파일을 **보여주는** 것은 `SChatAttachedFile`·`SChatFile` |
|
|
517
|
+
| 보내기 전 첨부를 입력창 위에 보여준다 (눌러 뺀다) | `SChatAttachedFile` | 보낸 뒤는 `SChatFile` · 고르게 하는 것은 `SFilePicker` |
|
|
518
|
+
| 보낸 파일을 대화 흐름에 보여준다 (눌러 연다) | `SChatFile` | `SChatMessage` 의 `attachments` 로 넘긴다 — 직접 나열하지 않는다 |
|
|
504
519
|
| 날짜 하나를 받는다 | `SDatePicker` | §3-7-4 |
|
|
505
520
|
| 연도 선택 리스트만 커스텀 조합에 넣는다 | `SDatePickerYearListbox` | §3-7-4 |
|
|
506
521
|
| 연도+월 선택 리스트만 커스텀 조합에 넣는다 | `SDatePickerMonthListbox` | §3-7-4 |
|
|
@@ -526,6 +541,7 @@ Tailwind 유틸리티는 **토큰 스케일에 있는 값만** 사용한다.
|
|
|
526
541
|
| 부모-자식 계층을 들여쓰기로 보여준다 | `STree` | §3-7-7 |
|
|
527
542
|
| 사용자가 순서를 드래그로 바꾸게 한다 | `SDraggableList` + `SDraggableItem` | §3-7-6 |
|
|
528
543
|
| 날짜별 일정을 한 달치 격자로 펼쳐 보여준다 | `SCalendarBoard` | §3-7-4 |
|
|
544
|
+
| 항목끼리 크기를 눈으로 견주게 한다 (기간별 추이·채널별 비중) | `SBarChart` | 정확한 값을 읽어야 하면 `STable` — 그래프는 "어느 쪽이 큰가" 를 답하지 "얼마인가" 를 답하지 않는다 |
|
|
529
545
|
| 표 위에 건수 요약과 액션을 얹는다 | `STableBar` | §4-2 |
|
|
530
546
|
| 상태·분류를 라벨로 찍는다 | `STag` | §3-1 |
|
|
531
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';
|
|
@@ -9,26 +9,25 @@
|
|
|
9
9
|
| Prop | Type | Default | Description |
|
|
10
10
|
|------|------|---------|-------------|
|
|
11
11
|
| `name` | `string` | — | 파일명. 칸을 넘치면 말줄임된다 — 칸의 폭은 부모가 정한다. |
|
|
12
|
-
| `extension?` | `string` | — | 보조 줄에 쓸 형식. 주지 않으면 **파일명의 마지막 점 뒤**를 쓴다. 파일명에서 뽑는 것이 틀리는 자리에서만 준다 — 확장자가 없거나(`README`), 확장자처럼 안 생겼거나(`backup.2026` → `2026`), 두 마디인 경우(`archive.tar.gz` → `gz`). 그 밖에는 주지 않는 편이 낫다. 파일명과 어긋난 형식이 적히는 일을 막는다. 앞의 점과 대소문자는 알아서 정리한다 — `'.CSV'` 와 `'csv'` 가 같게 나온다. |
|
|
13
|
-
| `size?` | `number` | — | 파일 크기(바이트). 형식(`extension`)과 묶어 `csv / 9.4KB` 로 그린다. **바이트 수를 그대로 넘긴다** — `'9.4KB'` 같은 완성된 문자열이 아니다. 표기를 앱이 만들면 같은 파일이 화면마다 다른 크기로 읽히므로 서식은 디자인 시스템이 쥔다. `attached` 는 `File.size`, `sent` 은 서버가 준 바이트 수를 그대로 넘기면 된다. **`sent` 에서는 필수다** — 보낸 파일은 확장자와 크기를 반드시 밝힌다. `attached` 에는 넘겨도 그리지 않는다(한 줄짜리 칸이다). 앱이 데이터를 한 번만 매핑해 자리와 무관하게 넘길 수 있도록 `attached` 에서 막지는 않고 무시한다. |
|
|
14
|
-
| `variant` | `'attached' \| 'sent'` | — | 파일 칸이 서는 자리. **크기·면·선·글자·아이콘이 전부 여기서 갈린다.** `attached` 는 아직 보내지 않은 첨부다 — 입력창 위에 서는 한 줄짜리 칸이고 눌러 뺄 수 있다. `sent` 은 이미 보낸 파일이다 — 대화창에 서는 두 줄짜리 칸이고 `size` 가 **필수**다. |
|
|
15
12
|
|
|
16
13
|
#### Events
|
|
17
14
|
|
|
18
15
|
| Event | Type | Description |
|
|
19
16
|
|-------|------|-------------|
|
|
20
|
-
| `onRemove` | `() => void` | 제거 버튼을 눌렀을 때. 주지 않으면 버튼이 서지 않는다.
|
|
17
|
+
| `onRemove` | `() => void` | 제거 버튼을 눌렀을 때. 주지 않으면 버튼이 서지 않는다. 입력창 위의 첨부는 보내기 전까지 뺄 수 있어야 하므로 대개 준다 — 버튼을 세우지 않는 것은 보내는 중처럼 무를 수 없는 짧은 순간뿐이다. |
|
|
21
18
|
|
|
22
19
|
## Dependencies
|
|
23
20
|
|
|
24
21
|
### Depends on
|
|
25
22
|
|
|
23
|
+
- [SGhostButton](../SGhostButton)
|
|
26
24
|
- [SIcon](../SIcon)
|
|
27
25
|
|
|
28
26
|
### Graph
|
|
29
27
|
|
|
30
28
|
```mermaid
|
|
31
29
|
graph TD;
|
|
30
|
+
SChatAttachedFile --> SGhostButton
|
|
32
31
|
SChatAttachedFile --> SIcon
|
|
33
32
|
style SChatAttachedFile fill:#f9f,stroke:#333,stroke-width:4px
|
|
34
33
|
```
|
|
@@ -1,54 +1,13 @@
|
|
|
1
1
|
import { type HTMLAttributes } from 'react';
|
|
2
|
-
interface
|
|
2
|
+
export interface SChatAttachedFileProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
3
3
|
/** 파일명. 칸을 넘치면 말줄임된다 — 칸의 폭은 부모가 정한다. */
|
|
4
4
|
name: string;
|
|
5
|
-
/**
|
|
6
|
-
* 보조 줄에 쓸 형식. 주지 않으면 **파일명의 마지막 점 뒤**를 쓴다.
|
|
7
|
-
*
|
|
8
|
-
* 파일명에서 뽑는 것이 틀리는 자리에서만 준다 — 확장자가 없거나(`README`),
|
|
9
|
-
* 확장자처럼 안 생겼거나(`backup.2026` → `2026`), 두 마디인 경우(`archive.tar.gz` → `gz`).
|
|
10
|
-
* 그 밖에는 주지 않는 편이 낫다. 파일명과 어긋난 형식이 적히는 일을 막는다.
|
|
11
|
-
*
|
|
12
|
-
* 앞의 점과 대소문자는 알아서 정리한다 — `'.CSV'` 와 `'csv'` 가 같게 나온다.
|
|
13
|
-
*/
|
|
14
|
-
extension?: string;
|
|
15
|
-
/**
|
|
16
|
-
* 파일 크기(바이트). 형식(`extension`)과 묶어 `csv / 9.4KB` 로 그린다.
|
|
17
|
-
*
|
|
18
|
-
* **바이트 수를 그대로 넘긴다** — `'9.4KB'` 같은 완성된 문자열이 아니다. 표기를 앱이 만들면
|
|
19
|
-
* 같은 파일이 화면마다 다른 크기로 읽히므로 서식은 디자인 시스템이 쥔다.
|
|
20
|
-
* `attached` 는 `File.size`, `sent` 은 서버가 준 바이트 수를 그대로 넘기면 된다.
|
|
21
|
-
*
|
|
22
|
-
* **`sent` 에서는 필수다** — 보낸 파일은 확장자와 크기를 반드시 밝힌다.
|
|
23
|
-
* `attached` 에는 넘겨도 그리지 않는다(한 줄짜리 칸이다). 앱이 데이터를 한 번만 매핑해
|
|
24
|
-
* 자리와 무관하게 넘길 수 있도록 `attached` 에서 막지는 않고 무시한다.
|
|
25
|
-
*/
|
|
26
|
-
size?: number;
|
|
27
5
|
/**
|
|
28
6
|
* 제거 버튼을 눌렀을 때. 주지 않으면 버튼이 서지 않는다.
|
|
29
7
|
*
|
|
30
|
-
*
|
|
8
|
+
* 입력창 위의 첨부는 보내기 전까지 뺄 수 있어야 하므로 대개 준다 —
|
|
9
|
+
* 버튼을 세우지 않는 것은 보내는 중처럼 무를 수 없는 짧은 순간뿐이다.
|
|
31
10
|
*/
|
|
32
11
|
onRemove?: () => void;
|
|
33
12
|
}
|
|
34
|
-
/**
|
|
35
|
-
* 자리에 따라 필수 prop 이 갈린다.
|
|
36
|
-
*
|
|
37
|
-
* `sent` 은 `size` 가 **필수**다 — 보낸 파일은 확장자와 크기를 반드시 밝혀야 하는데,
|
|
38
|
-
* 선택으로 두면 빠뜨려도 타입이 통과하고 화면에서 보조 줄만 조용히 사라진다.
|
|
39
|
-
* `attached` 는 한 줄짜리 칸이라 필요 없다.
|
|
40
|
-
*/
|
|
41
|
-
export type SChatAttachedFileProps = (SChatAttachedFileBaseProps & {
|
|
42
|
-
/**
|
|
43
|
-
* 파일 칸이 서는 자리. **크기·면·선·글자·아이콘이 전부 여기서 갈린다.**
|
|
44
|
-
*
|
|
45
|
-
* `attached` 는 아직 보내지 않은 첨부다 — 입력창 위에 서는 한 줄짜리 칸이고 눌러 뺄 수 있다.
|
|
46
|
-
* `sent` 은 이미 보낸 파일이다 — 대화창에 서는 두 줄짜리 칸이고 `size` 가 **필수**다.
|
|
47
|
-
*/
|
|
48
|
-
variant: 'attached';
|
|
49
|
-
}) | (SChatAttachedFileBaseProps & {
|
|
50
|
-
variant: 'sent';
|
|
51
|
-
size: number;
|
|
52
|
-
});
|
|
53
13
|
export declare const SChatAttachedFile: import("react").ForwardRefExoticComponent<SChatAttachedFileProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
54
|
-
export {};
|
|
@@ -1,43 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 보내기 전 첨부 칸이 쓰는 값. `component.chatAttachedFile` 토큰 한 세트가 여백·면·선·칩을
|
|
3
|
+
* 모두 쥔다.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
5
|
+
* 높이는 고정하지 않고 세로 패딩(`paddingY`)과 내용이 정한다 — 예전에 스케일에 안 떨어져
|
|
6
|
+
* 값으로 두던 높이(30)·타일(20)은 `paddingY` + `icon.wrapper.padding` + 아이콘 크기로 따라온다.
|
|
6
7
|
*/
|
|
7
|
-
export declare const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
|
|
8
|
+
export declare const CHAT_ATTACHED_FILE_CONFIG: {
|
|
9
|
+
/** 바깥 상자 — 좌우·상하 여백·면·선·라운드 */
|
|
10
|
+
readonly box: "px-(--cmp-chatAttachedFile-paddingX) py-(--cmp-chatAttachedFile-paddingY) rounded-(--cmp-chatAttachedFile-radius) border-(length:--cmp-chatAttachedFile-border-width) border-(--cmp-chatAttachedFile-border-color) bg-(--cmp-chatAttachedFile-bg)";
|
|
11
|
+
/** 콘텐츠 묶음 ↔ 제거 버튼 간격 */
|
|
12
|
+
readonly outerGap: "gap-(--cmp-chatAttachedFile-gap)";
|
|
13
|
+
/** 아이콘 칩 ↔ 파일명 간격 */
|
|
14
|
+
readonly contentGap: "gap-(--cmp-chatAttachedFile-content-gap)";
|
|
15
|
+
/** 클립 아이콘이 앉는 칩 — 내부 패딩·면·라운드 (높이는 아이콘+패딩이 정한다) */
|
|
16
|
+
readonly tile: "p-(--cmp-chatAttachedFile-icon-wrapper-padding) rounded-(--cmp-chatAttachedFile-icon-wrapper-radius) bg-(--cmp-chatAttachedFile-icon-wrapper-bg)";
|
|
17
|
+
/** 칩 안 클립 아이콘 크기(px). SVG width/height 는 속성값이라 CSS 변수를 못 받아 값으로 둔다 (토큰 값과 동일) */
|
|
18
|
+
readonly iconSize: 16;
|
|
16
19
|
/** 파일명 타이포 프리셋 */
|
|
17
|
-
nameTypo:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* (디자인팀 토큰 추가 요청 대상). 세로 여백이 스페이싱 스케일에 떨어지지 않아
|
|
22
|
-
* 여백을 주는 대신 높이를 고정하고 세로 가운데 정렬로 세운다.
|
|
23
|
-
*/
|
|
24
|
-
export declare const CHAT_ATTACHED_FILE_CONFIG: Record<SChatAttachedFileVariant, ChatAttachedFilePreset>;
|
|
25
|
-
/**
|
|
26
|
-
* 바이트 수 → `9.4KB` 표기.
|
|
27
|
-
*
|
|
28
|
-
* **표기를 앱이 아니라 여기서 정하는 이유**: 문자열로 받으면 제품마다 `9.4KB`·`9.4 KB`·
|
|
29
|
-
* `9,626B` 로 갈린다. 같은 파일이 화면마다 다른 크기로 읽히는 것을 막으려면 한 곳에서 만든다.
|
|
30
|
-
*
|
|
31
|
-
* 1024 배수로 올리고, 바이트는 소수점이 뜻이 없어 정수로, 그 위는 한 자리까지 쓴다(시안 표기).
|
|
32
|
-
* 금액·수량의 세 자리 콤마 규칙(AGENTS.md §1-4)과는 별개다 — 용량은 단위가 자리를 대신한다.
|
|
33
|
-
*/
|
|
34
|
-
export declare function formatFileSize(bytes: number): string;
|
|
35
|
-
/** 앱이 준 확장자를 표기 형태로 맞춘다 — 앞의 점을 떼고 소문자로. `'.CSV'` → `'csv'` */
|
|
36
|
-
export declare function normalizeExtension(extension: string): string;
|
|
37
|
-
/**
|
|
38
|
-
* 파일명 → 소문자 확장자. 확장자가 없으면 빈 문자열.
|
|
39
|
-
*
|
|
40
|
-
* 맨 앞의 점은 확장자가 아니다(`.gitignore` 는 이름 전체가 이름이다).
|
|
41
|
-
*/
|
|
42
|
-
export declare function fileExtension(name: string): string;
|
|
43
|
-
export {};
|
|
20
|
+
readonly nameTypo: "typo-body-sm-default";
|
|
21
|
+
/** 파일명 텍스트색 */
|
|
22
|
+
readonly textColor: "text-(--cmp-chatAttachedFile-filename-color)";
|
|
23
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { SChatAttachedFile, type SChatAttachedFileProps } from './SChatAttachedFile';
|
|
2
|
-
export {
|
|
2
|
+
export { CHAT_ATTACHED_FILE_CONFIG } from './chatAttachedFile.config';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# SChatFile
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SChatFile
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `name` | `string` | — | 파일명. 칸을 넘치면 말줄임된다 — 칸의 폭은 부모가 정한다. |
|
|
12
|
+
| `extension?` | `string` | — | 보조 줄에 쓸 형식. 주지 않으면 **파일명의 마지막 점 뒤**를 쓴다. 파일명에서 뽑는 것이 틀리는 자리에서만 준다 — 확장자가 없거나(`README`), 확장자처럼 안 생겼거나(`backup.2026` → `2026`), 두 마디인 경우(`archive.tar.gz` → `gz`). 그 밖에는 주지 않는 편이 낫다. 파일명과 어긋난 형식이 적히는 일을 막는다. 앞의 점과 대소문자는 알아서 정리한다 — `'.CSV'` 와 `'csv'` 가 같게 나온다. |
|
|
13
|
+
| `size` | `number` | — | 파일 크기(바이트). 형식(`extension`)과 묶어 `csv / 9.4KB` 로 그린다. **바이트 수를 그대로 넘긴다** — `'9.4KB'` 같은 완성된 문자열이 아니다. 표기를 앱이 만들면 같은 파일이 화면마다 다른 크기로 읽히므로 서식은 디자인 시스템이 쥔다. 서버가 준 바이트 수를 그대로 넘기면 된다. **필수다** — 보낸 파일은 확장자와 크기를 반드시 밝힌다. 선택으로 두면 빠뜨려도 타입이 통과하고 화면에서 보조 줄만 조용히 사라진다. |
|
|
14
|
+
|
|
15
|
+
#### Events
|
|
16
|
+
|
|
17
|
+
| Event | Type | Description |
|
|
18
|
+
|-------|------|-------------|
|
|
19
|
+
| `onFileClick` | `() => void` | 칸을 눌렀을 때 — 파일을 여는 자리다. **필수다** — 보낸 파일은 언제나 열 수 있다. 선택으로 두면 빠뜨려도 타입이 통과하고, 커서·hover 면까지 갖춘 칸이 눌러도 아무 일이 없는 화면이 조용히 나간다. 루트가 `div` 라 `role="button"`·`tabIndex`·Enter/Space 를 DS 가 함께 붙인다 — 앱이 `onClick` 만 직접 달면 키보드로 닿지 않는 칸이 되므로 그 대신 이걸 쓴다. |
|
|
20
|
+
|
|
21
|
+
## Dependencies
|
|
22
|
+
|
|
23
|
+
### Depends on
|
|
24
|
+
|
|
25
|
+
- [SIcon](../SIcon)
|
|
26
|
+
|
|
27
|
+
### Graph
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
graph TD;
|
|
31
|
+
SChatFile --> SIcon
|
|
32
|
+
style SChatFile fill:#f9f,stroke:#333,stroke-width:4px
|
|
33
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
export interface SChatFileProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
3
|
+
/** 파일명. 칸을 넘치면 말줄임된다 — 칸의 폭은 부모가 정한다. */
|
|
4
|
+
name: string;
|
|
5
|
+
/**
|
|
6
|
+
* 보조 줄에 쓸 형식. 주지 않으면 **파일명의 마지막 점 뒤**를 쓴다.
|
|
7
|
+
*
|
|
8
|
+
* 파일명에서 뽑는 것이 틀리는 자리에서만 준다 — 확장자가 없거나(`README`),
|
|
9
|
+
* 확장자처럼 안 생겼거나(`backup.2026` → `2026`), 두 마디인 경우(`archive.tar.gz` → `gz`).
|
|
10
|
+
* 그 밖에는 주지 않는 편이 낫다. 파일명과 어긋난 형식이 적히는 일을 막는다.
|
|
11
|
+
*
|
|
12
|
+
* 앞의 점과 대소문자는 알아서 정리한다 — `'.CSV'` 와 `'csv'` 가 같게 나온다.
|
|
13
|
+
*/
|
|
14
|
+
extension?: string;
|
|
15
|
+
/**
|
|
16
|
+
* 파일 크기(바이트). 형식(`extension`)과 묶어 `csv / 9.4KB` 로 그린다.
|
|
17
|
+
*
|
|
18
|
+
* **바이트 수를 그대로 넘긴다** — `'9.4KB'` 같은 완성된 문자열이 아니다. 표기를 앱이 만들면
|
|
19
|
+
* 같은 파일이 화면마다 다른 크기로 읽히므로 서식은 디자인 시스템이 쥔다. 서버가 준 바이트 수를
|
|
20
|
+
* 그대로 넘기면 된다.
|
|
21
|
+
*
|
|
22
|
+
* **필수다** — 보낸 파일은 확장자와 크기를 반드시 밝힌다. 선택으로 두면 빠뜨려도 타입이
|
|
23
|
+
* 통과하고 화면에서 보조 줄만 조용히 사라진다.
|
|
24
|
+
*/
|
|
25
|
+
size: number;
|
|
26
|
+
/**
|
|
27
|
+
* 칸을 눌렀을 때 — 파일을 여는 자리다.
|
|
28
|
+
*
|
|
29
|
+
* **필수다** — 보낸 파일은 언제나 열 수 있다. 선택으로 두면 빠뜨려도 타입이 통과하고,
|
|
30
|
+
* 커서·hover 면까지 갖춘 칸이 눌러도 아무 일이 없는 화면이 조용히 나간다.
|
|
31
|
+
*
|
|
32
|
+
* 루트가 `div` 라 `role="button"`·`tabIndex`·Enter/Space 를 DS 가 함께 붙인다 — 앱이
|
|
33
|
+
* `onClick` 만 직접 달면 키보드로 닿지 않는 칸이 되므로 그 대신 이걸 쓴다.
|
|
34
|
+
*/
|
|
35
|
+
onFileClick: () => void;
|
|
36
|
+
}
|
|
37
|
+
export declare const SChatFile: import("react").ForwardRefExoticComponent<SChatFileProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 보낸 파일 칸이 쓰는 값. `component.chatFile` 토큰 한 세트가 여백·면·선·칩을 모두 쥔다.
|
|
3
|
+
*
|
|
4
|
+
* 높이는 고정하지 않고 세로 패딩(`paddingY`)과 내용이 정한다 — 예전에 스케일에 안 떨어져
|
|
5
|
+
* 값으로 두던 높이(56)·타일(28)은 `paddingY` + `icon.wrapper.padding` + 아이콘 크기로 따라온다.
|
|
6
|
+
*/
|
|
7
|
+
export declare const CHAT_FILE_CONFIG: {
|
|
8
|
+
/** 바깥 상자 — 좌우 비대칭 여백·상하 여백·면·선·라운드 */
|
|
9
|
+
readonly box: "pl-(--cmp-chatFile-paddingLeft) pr-(--cmp-chatFile-paddingRight) py-(--cmp-chatFile-paddingY) rounded-(--cmp-chatFile-radius) border-(length:--cmp-chatFile-border-width) border-(--cmp-chatFile-border-color) bg-(--cmp-chatFile-bg-default)";
|
|
10
|
+
/** 아이콘 칩 ↔ 파일명 간격 */
|
|
11
|
+
readonly contentGap: "gap-(--cmp-chatFile-gap)";
|
|
12
|
+
/**
|
|
13
|
+
* 클립 아이콘이 앉는 칩 — 내부 패딩·면·라운드 (높이는 아이콘+패딩이 정한다).
|
|
14
|
+
*
|
|
15
|
+
* hover 면은 상자가 아니라 여기에도 걸린다 — 카드가 어두워질 때 칩은 반대로 밝아져
|
|
16
|
+
* 칩이 배경에 묻히지 않는다. 상자의 hover 를 따라가야 하므로 group-hover 로 받는다.
|
|
17
|
+
*
|
|
18
|
+
* **`--sys-color-bg-frame` 은 임시다.** 시안의 hover 칩 색(`#FFFFFF`)에 대응하는
|
|
19
|
+
* 컴포넌트 토큰이 없다 — `component.chatMessage.chatFile.icon.wrapper.bg` 는 값이 하나뿐이라
|
|
20
|
+
* hover 를 담지 못한다. 상자의 `bg.default` 가 참조하는 것과 같은 시스템 토큰으로 대신 걸어 둔다.
|
|
21
|
+
* 디자인팀에 `icon.wrapper.bg.hover` 를 요청해 나오는 대로 갈아끼운다.
|
|
22
|
+
*/
|
|
23
|
+
readonly tile: "p-(--cmp-chatFile-icon-wrapper-padding) rounded-(--cmp-chatFile-icon-wrapper-radius) bg-(--cmp-chatFile-icon-wrapper-bg) group-hover/chat-file:bg-(--sys-color-bg-frame)";
|
|
24
|
+
/** 칩 안 클립 아이콘 크기(px). SVG width/height 는 속성값이라 CSS 변수를 못 받아 값으로 둔다 (토큰 값과 동일) */
|
|
25
|
+
readonly iconSize: 20;
|
|
26
|
+
/** 파일명 타이포 프리셋 */
|
|
27
|
+
readonly nameTypo: "typo-body-md-bold";
|
|
28
|
+
/** 파일명·부가정보 텍스트색 */
|
|
29
|
+
readonly textColor: "text-(--cmp-chatFile-text-color)";
|
|
30
|
+
/**
|
|
31
|
+
* 눌리는 모양 — 커서·hover 면·포커스 링. 보낸 파일은 언제나 열 수 있으므로 늘 붙는다
|
|
32
|
+
* (`onFileClick` 이 필수다).
|
|
33
|
+
*
|
|
34
|
+
* 상자의 여백·면·선과 따로 두는 이유: 이건 상호작용을 드러내는 값이라 성격이 다르다.
|
|
35
|
+
* 링은 `SExpansionItem`·`SStepper` 와 같은 accent outline.
|
|
36
|
+
*/
|
|
37
|
+
readonly interactive: "cursor-pointer hover:bg-(--cmp-chatFile-bg-hover) focus-visible:outline focus-visible:outline-2 focus-visible:outline-(--sys-color-border-accent)";
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* 바이트 수 → `9.4KB` 표기.
|
|
41
|
+
*
|
|
42
|
+
* **표기를 앱이 아니라 여기서 정하는 이유**: 문자열로 받으면 제품마다 `9.4KB`·`9.4 KB`·
|
|
43
|
+
* `9,626B` 로 갈린다. 같은 파일이 화면마다 다른 크기로 읽히는 것을 막으려면 한 곳에서 만든다.
|
|
44
|
+
*
|
|
45
|
+
* 1024 배수로 올리고, 바이트는 소수점이 뜻이 없어 정수로, 그 위는 한 자리까지 쓴다(시안 표기).
|
|
46
|
+
* 금액·수량의 세 자리 콤마 규칙(AGENTS.md §1-4)과는 별개다 — 용량은 단위가 자리를 대신한다.
|
|
47
|
+
*/
|
|
48
|
+
export declare function formatFileSize(bytes: number): string;
|
|
49
|
+
/** 앱이 준 확장자를 표기 형태로 맞춘다 — 앞의 점을 떼고 소문자로. `'.CSV'` → `'csv'` */
|
|
50
|
+
export declare function normalizeExtension(extension: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* 파일명 → 소문자 확장자. 확장자가 없으면 빈 문자열.
|
|
53
|
+
*
|
|
54
|
+
* 맨 앞의 점은 확장자가 아니다(`.gitignore` 는 이름 전체가 이름이다).
|
|
55
|
+
*/
|
|
56
|
+
export declare function fileExtension(name: string): string;
|