sellmate-design-system-react 2.2.0 → 3.1.0
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 +661 -0
- package/README.md +85 -0
- package/dist/components/SActionModal/README.md +41 -0
- package/dist/components/SBadge/README.md +25 -0
- package/dist/components/SBarcodeInput/README.md +64 -0
- package/dist/components/SButton/README.md +49 -0
- package/dist/components/SCalendar/README.md +42 -0
- package/dist/components/SCallout/README.md +29 -0
- package/dist/components/SCallout/SCallout.cjs +76 -1
- package/dist/components/SCallout/SCallout.cjs.map +1 -1
- package/dist/components/SCallout/SCallout.d.ts +6 -2
- package/dist/components/SCallout/SCallout.js +76 -1
- package/dist/components/SCallout/SCallout.js.map +1 -1
- package/dist/components/SCard/README.md +12 -0
- package/dist/components/SCheckbox/README.md +44 -0
- package/dist/components/SChip/README.md +57 -0
- package/dist/components/SChipInput/README.md +77 -0
- package/dist/components/SCircleProgress/README.md +35 -0
- package/dist/components/SConfirmModal/README.md +61 -0
- package/dist/components/SDatePicker/README.md +62 -0
- package/dist/components/SDateRangePicker/README.md +64 -0
- package/dist/components/SDivider/README.md +25 -0
- package/dist/components/SDraggableItem/README.md +40 -0
- package/dist/components/SDraggableItem/SDraggableItem.cjs +3079 -0
- package/dist/components/SDraggableItem/SDraggableItem.cjs.map +1 -0
- package/dist/components/SDraggableItem/SDraggableItem.d.ts +33 -0
- package/dist/components/SDraggableItem/SDraggableItem.js +3077 -0
- package/dist/components/SDraggableItem/SDraggableItem.js.map +1 -0
- package/dist/components/SDraggableItem/index.d.ts +1 -0
- package/dist/components/SDropdownButton/README.md +50 -0
- package/dist/components/SExpansionItem/README.md +40 -0
- package/dist/components/SExpansionItem/SExpansionItem.cjs +6 -15
- package/dist/components/SExpansionItem/SExpansionItem.cjs.map +1 -1
- package/dist/components/SExpansionItem/SExpansionItem.js +6 -15
- package/dist/components/SExpansionItem/SExpansionItem.js.map +1 -1
- package/dist/components/SField/README.md +91 -0
- package/dist/components/SFilePicker/README.md +72 -0
- package/dist/components/SForm/README.md +31 -0
- package/dist/components/SGhostButton/README.md +76 -0
- package/dist/components/SGnb/README.md +56 -0
- package/dist/components/SGuide/README.md +34 -0
- package/dist/components/SIcon/README.md +91 -0
- package/dist/components/SInput/README.md +66 -0
- package/dist/components/SKeyValueTable/README.md +59 -0
- package/dist/components/SLayout/README.md +42 -0
- package/dist/components/SLinearProgress/README.md +17 -0
- package/dist/components/SList/README.md +14 -0
- package/dist/components/SList/SList.cjs +38 -0
- package/dist/components/SList/SList.cjs.map +1 -0
- package/dist/components/SList/SList.d.ts +10 -0
- package/dist/components/SList/SList.js +36 -0
- package/dist/components/SList/SList.js.map +1 -0
- package/dist/components/SList/index.d.ts +1 -0
- package/dist/components/SListItem/README.md +19 -0
- package/dist/components/SListItem/SListItem.cjs +83 -0
- package/dist/components/SListItem/SListItem.cjs.map +1 -0
- package/dist/components/SListItem/SListItem.d.ts +26 -0
- package/dist/components/SListItem/SListItem.js +81 -0
- package/dist/components/SListItem/SListItem.js.map +1 -0
- package/dist/components/SListItem/index.d.ts +1 -0
- package/dist/components/SLoadingContainer/README.md +29 -0
- package/dist/components/SLoadingModal/README.md +52 -0
- package/dist/components/SModal/README.md +192 -0
- package/dist/components/SModalContainer/README.md +49 -0
- package/dist/components/SNumberInput/README.md +74 -0
- package/dist/components/SPage/README.md +25 -0
- package/dist/components/SPagination/README.md +40 -0
- package/dist/components/SPopover/README.md +54 -0
- package/dist/components/SPopup/README.md +38 -0
- package/dist/components/SPortal/README.md +51 -0
- package/dist/components/SRadio/README.md +57 -0
- package/dist/components/SRadioButton/README.md +24 -0
- package/dist/components/SScrollArea/README.md +16 -0
- package/dist/components/SSectionHeaderCard/README.md +51 -0
- package/dist/components/SSectionHeaderCard/SSectionHeaderCard.cjs +3414 -0
- package/dist/components/SSectionHeaderCard/SSectionHeaderCard.cjs.map +1 -0
- package/dist/components/SSectionHeaderCard/SSectionHeaderCard.d.ts +32 -0
- package/dist/components/SSectionHeaderCard/SSectionHeaderCard.js +3392 -0
- package/dist/components/SSectionHeaderCard/SSectionHeaderCard.js.map +1 -0
- package/dist/components/SSectionHeaderCard/index.d.ts +1 -0
- package/dist/components/SSelect/README.md +79 -0
- package/dist/components/SStepper/README.md +30 -0
- package/dist/components/SSwitch/README.md +24 -0
- package/dist/components/STable/README.md +82 -0
- package/dist/components/STableBar/README.md +28 -0
- package/dist/components/STabs/README.md +37 -0
- package/dist/components/STag/README.md +44 -0
- package/dist/components/STextLink/README.md +48 -0
- package/dist/components/STextarea/README.md +60 -0
- package/dist/components/STimePicker/README.md +65 -0
- package/dist/components/STimeRangePicker/README.md +63 -0
- package/dist/components/SToast/README.md +70 -0
- package/dist/components/SToggle/README.md +22 -0
- package/dist/components/STooltip/README.md +57 -0
- package/dist/index.cjs +815 -419
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +815 -423
- package/dist/index.js.map +1 -1
- package/dist/llms.txt +3496 -0
- package/dist/styles.css +545 -19
- package/dist/theme.css +22 -0
- package/eslint/index.mjs +66 -0
- package/eslint/lib/class-names.mjs +119 -0
- package/eslint/lib/table-column.mjs +53 -0
- package/eslint/rules/no-arbitrary-class.mjs +91 -0
- package/eslint/rules/no-off-scale-spacing.mjs +67 -0
- package/eslint/rules/no-raw-html-control.mjs +117 -0
- package/eslint/rules/prefer-typo-preset.mjs +73 -0
- package/eslint/rules/require-locale-number.mjs +78 -0
- package/eslint/rules/table-numeric-align.mjs +93 -0
- package/eslint/scale.gen.mjs +16 -0
- package/package.json +9 -4
package/README.md
CHANGED
|
@@ -105,6 +105,91 @@ export function Example() {
|
|
|
105
105
|
|
|
106
106
|
`SButton` 은 텍스트를 **`label`(문자열)로만** 받습니다 — `children` 은 받지 않으며, 아이콘은 `icon`/`rightIcon` 을 씁니다. 색상 prop 은 `color` 입니다(`variant` 아님).
|
|
107
107
|
|
|
108
|
+
## 화면 작성 규칙 (AI 에이전트 포함)
|
|
109
|
+
|
|
110
|
+
컴포넌트 조합·간격·타이포 등 **화면을 만들 때 지켜야 할 규칙**은 패키지에 함께 배포됩니다.
|
|
111
|
+
|
|
112
|
+
| 파일 | 용도 |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| `node_modules/sellmate-design-system-react/AGENTS.md` | 사람이 읽는 사용 규칙서 |
|
|
115
|
+
| `node_modules/sellmate-design-system-react/dist/llms.txt` | 규칙 + 토큰 어휘 + 전체 컴포넌트 Props 를 합친 AI 참조용 단일 문서 |
|
|
116
|
+
| `node_modules/sellmate-design-system-react/dist/components/<이름>/README.md` | 컴포넌트별 Props/Events |
|
|
117
|
+
|
|
118
|
+
Claude 등 AI 에이전트를 쓴다면 소비 앱의 `CLAUDE.md` 에 다음 한 줄을 넣어두면 됩니다.
|
|
119
|
+
|
|
120
|
+
```md
|
|
121
|
+
UI 작업 전 `node_modules/sellmate-design-system-react/dist/llms.txt` 를 먼저 읽을 것.
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## ESLint 설정
|
|
125
|
+
|
|
126
|
+
위 규칙 중 **정적으로 검출 가능한 것**은 린트로 강제할 수 있습니다. 소비 앱의 `eslint.config.mjs` 에 추가하세요.
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
// eslint.config.mjs
|
|
130
|
+
import sellmate from 'sellmate-design-system-react/eslint';
|
|
131
|
+
|
|
132
|
+
export default [
|
|
133
|
+
// ... 기존 설정
|
|
134
|
+
...sellmate.configs.recommended,
|
|
135
|
+
];
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
| 규칙 | 기본 | 검출 대상 |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| `sellmate/no-raw-html-control` | error | 대응 컴포넌트가 있는 생 HTML (`<button>` `<input>` `<select>` `<textarea>` `<table>` `<form>` `<dialog>` `<hr>` `<details>` `<progress>`), `alert()`/`confirm()` |
|
|
141
|
+
| `sellmate/no-arbitrary-class` | error | **토큰이 있는 속성**(색·타이포·간격·모서리)의 임의 값 — `text-[14px]`, `bg-[#eee]`, `gap-[13px]`, `rounded-[5px]` |
|
|
142
|
+
| `sellmate/no-off-scale-spacing` | error | 스케일 밖 간격 (`gap-13`, `p-15`) — Tailwind v4 에서 **조용히 무시되는** 값이라 눈으로 찾기 어렵다 |
|
|
143
|
+
| `sellmate/table-numeric-align` | error | 숫자 컬럼(금액·수량 등)에 `align: 'right'` 누락 — **`--fix` 로 자동 교정** |
|
|
144
|
+
| `sellmate/require-locale-number` | error | 숫자 컬럼의 `toLocaleString()` 누락 — 세 자리 콤마는 필수 |
|
|
145
|
+
| `sellmate/prefer-typo-preset` | warn | `text-14 font-bold` 같은 낱개 조합 → `typo-*` 프리셋 |
|
|
146
|
+
|
|
147
|
+
`className` 뿐 아니라 `cn()`/`clsx()` 인자, 템플릿 리터럴, 객체 키 안까지 검사합니다.
|
|
148
|
+
|
|
149
|
+
### 일부러 잡지 않는 것
|
|
150
|
+
|
|
151
|
+
과검출을 피하려고 다음은 기본 설정에서 **통과**시킵니다.
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
// 디자인 토큰이 없는 앱 고유 레이아웃 치수 — 정당한 사용
|
|
155
|
+
<div className="w-[280px] max-w-[1200px] grid-cols-[200px_1fr] top-[64px]" />
|
|
156
|
+
|
|
157
|
+
// 토큰을 var() 로 참조하는 형태
|
|
158
|
+
<div className="h-[var(--sys-size-control-md-height)]" />
|
|
159
|
+
|
|
160
|
+
// 시각 요소가 없어 대체 컴포넌트가 없다
|
|
161
|
+
<input type="hidden" name="csrf" />
|
|
162
|
+
|
|
163
|
+
// 로고 SVG·본문 안 시맨틱 목록·DS 밖 컨트롤의 레이블
|
|
164
|
+
<svg viewBox="0 0 24 24" />
|
|
165
|
+
<ul><li>…</li></ul>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
핵심은 **"디자인 토큰을 하드코딩하지 마라"** 이지 "임의 값을 절대 쓰지 마라" 가 아닙니다.
|
|
169
|
+
|
|
170
|
+
### 더 엄격하게 / 더 느슨하게
|
|
171
|
+
|
|
172
|
+
`configs.strict` 는 전 규칙을 error 로 올리고 `<ul>` `<ol>` `<li>` `<svg>` `<label>` 까지 검사합니다.
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
export default [...sellmate.configs.strict];
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
규칙별 예외도 줄 수 있습니다.
|
|
179
|
+
|
|
180
|
+
```js
|
|
181
|
+
{
|
|
182
|
+
rules: {
|
|
183
|
+
// strict 를 쓰되 로고 SVG 는 허용
|
|
184
|
+
'sellmate/no-raw-html-control': ['error', { strict: true, allow: ['svg'] }],
|
|
185
|
+
// 그림자만 임의 값 허용
|
|
186
|
+
'sellmate/no-arbitrary-class': ['error', { ignorePrefixes: ['shadow'] }],
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
허용 값 스케일은 `theme.css` 에서 **빌드 시 자동 추출**되므로 토큰이 바뀌면 규칙도 따라갑니다.
|
|
192
|
+
|
|
108
193
|
## 제공 컴포넌트
|
|
109
194
|
|
|
110
195
|
분류는 `src/index.ts` 의 export 그룹과 동일합니다.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# SActionModal
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SActionModal
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `open?` | `boolean` | — | |
|
|
12
|
+
| `persistent?` | `boolean` | — | true면 백드롭·ESC로 안 닫히고 흔들림 (sd-modal-container persistent) |
|
|
13
|
+
| `modalTitle?` | `string` | `''` | |
|
|
14
|
+
| `button?` | `SActionModalButton` | — | 하단 액션 버튼 (주 액션 1개). 의도적으로 단수다 — 보조 버튼(취소·삭제 등)은 `footerLeft` 슬롯에 직접 배치한다. |
|
|
15
|
+
| `footerLeft?` | `ReactNode` | — | footer 좌측 영역 (sd-action-modal 의 bottom-sub-content 슬롯). 보조 버튼이나 안내 문구를 넣는다. 버튼을 하나 더 쓰고 싶을 때 여기에 SButton 을 넣는다. |
|
|
16
|
+
| `width?` | `number \| string` | — | |
|
|
17
|
+
| `height?` | `number \| string` | — | |
|
|
18
|
+
| `children?` | `ReactNode` | — | |
|
|
19
|
+
|
|
20
|
+
#### Events
|
|
21
|
+
|
|
22
|
+
| Event | Type | Description |
|
|
23
|
+
|-------|------|-------------|
|
|
24
|
+
| `onOpenChange` | `(open: boolean) => void` | |
|
|
25
|
+
| `onClose` | `() => void` | 닫기(X) 버튼 클릭 (sdClose) |
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
|
|
29
|
+
### Depends on
|
|
30
|
+
|
|
31
|
+
- [SButton](../SButton)
|
|
32
|
+
- [SModalContainer](../SModalContainer)
|
|
33
|
+
|
|
34
|
+
### Graph
|
|
35
|
+
|
|
36
|
+
```mermaid
|
|
37
|
+
graph TD;
|
|
38
|
+
SActionModal --> SButton
|
|
39
|
+
SActionModal --> SModalContainer
|
|
40
|
+
style SActionModal fill:#f9f,stroke:#333,stroke-width:4px
|
|
41
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# SBadge
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SBadge
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `color?` | `SBadgeColor` | `'blue'` | 뱃지 색상 |
|
|
12
|
+
|
|
13
|
+
## Dependencies
|
|
14
|
+
|
|
15
|
+
### Used by
|
|
16
|
+
|
|
17
|
+
- [SList](../SList)
|
|
18
|
+
|
|
19
|
+
### Graph
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
graph TD;
|
|
23
|
+
SList --> SBadge
|
|
24
|
+
style SBadge fill:#f9f,stroke:#333,stroke-width:4px
|
|
25
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# SBarcodeInput
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SBarcodeInput
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `value?` | `string \| number \| null` | — | |
|
|
12
|
+
| `size?` | `SBarcodeInputSize` | `'sm'` | |
|
|
13
|
+
| `clearable?` | `boolean` | `false` | |
|
|
14
|
+
| `autoFocus?` | `boolean` | — | |
|
|
15
|
+
| `name?` | `string` | — | |
|
|
16
|
+
| `placeholder?` | `string` | `'입력해 주세요.'` | |
|
|
17
|
+
| `disabled?` | `boolean` | `false` | |
|
|
18
|
+
| `readOnly?` | `boolean` | `false` | |
|
|
19
|
+
| `rules?` | `Rule[]` | — | |
|
|
20
|
+
| `status?` | `SFieldStatus` | — | |
|
|
21
|
+
| `focused?` | `boolean` | — | |
|
|
22
|
+
| `hovered?` | `boolean` | — | |
|
|
23
|
+
| `prefix?` | `ReactNode` | — | 입력 앞 슬롯 |
|
|
24
|
+
| `suffix?` | `ReactNode` | — | 입력 뒤 슬롯 |
|
|
25
|
+
| `inputClass?` | `string` | — | |
|
|
26
|
+
| `inputStyle?` | `CSSProperties` | — | |
|
|
27
|
+
| `label?` | `string` | — | |
|
|
28
|
+
| `labelWidth?` | `number \| string` | — | |
|
|
29
|
+
| `icon?` | `SIconName` | — | |
|
|
30
|
+
| `iconColor?` | `SColor` | — | |
|
|
31
|
+
| `labelTooltip?` | `string` | — | |
|
|
32
|
+
| `labelTooltipProps?` | `Partial<STooltipProps>` | — | |
|
|
33
|
+
| `addonLabel?` | `string` | — | |
|
|
34
|
+
| `addonAlign?` | `SFieldAddonAlign` | — | |
|
|
35
|
+
| `hint?` | `string` | — | |
|
|
36
|
+
| `error?` | `boolean` | — | |
|
|
37
|
+
| `errorMessage?` | `string` | — | |
|
|
38
|
+
| `width?` | `number \| string` | — | |
|
|
39
|
+
| `className?` | `string` | — | |
|
|
40
|
+
| `style?` | `CSSProperties` | — | |
|
|
41
|
+
|
|
42
|
+
#### Events
|
|
43
|
+
|
|
44
|
+
| Event | Type | Description |
|
|
45
|
+
|-------|------|-------------|
|
|
46
|
+
| `onValueChange` | `(value: string) => void` | 값 변경 (sdUpdate) |
|
|
47
|
+
| `onFocus` | `() => void` | |
|
|
48
|
+
| `onBlur` | `() => void` | |
|
|
49
|
+
|
|
50
|
+
## Dependencies
|
|
51
|
+
|
|
52
|
+
### Depends on
|
|
53
|
+
|
|
54
|
+
- [SField](../SField)
|
|
55
|
+
- [SGhostButton](../SGhostButton)
|
|
56
|
+
|
|
57
|
+
### Graph
|
|
58
|
+
|
|
59
|
+
```mermaid
|
|
60
|
+
graph TD;
|
|
61
|
+
SBarcodeInput --> SField
|
|
62
|
+
SBarcodeInput --> SGhostButton
|
|
63
|
+
style SBarcodeInput fill:#f9f,stroke:#333,stroke-width:4px
|
|
64
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# SButton
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SButton
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `color?` | `SButtonColor` | `'primary'` | 색상 — sd-button preset의 색 계열 |
|
|
12
|
+
| `outline?` | `boolean` | `false` | 아웃라인(테두리) 스타일. primary·neutral·danger 만 지원 (secondary 는 무시) |
|
|
13
|
+
| `size?` | `SButtonSize` | `'sm'` | 크기 |
|
|
14
|
+
| `icon?` | `SIconName` | — | 레이블 왼쪽 아이콘 |
|
|
15
|
+
| `rightIcon?` | `SIconName` | — | 레이블 오른쪽 아이콘 |
|
|
16
|
+
| `label?` | `string` | — | 버튼 텍스트 (문자열만 — 아이콘은 icon/rightIcon 사용) |
|
|
17
|
+
|
|
18
|
+
## Dependencies
|
|
19
|
+
|
|
20
|
+
### Used by
|
|
21
|
+
|
|
22
|
+
- [SActionModal](../SActionModal)
|
|
23
|
+
- [SConfirmModal](../SConfirmModal)
|
|
24
|
+
- [SDropdownButton](../SDropdownButton)
|
|
25
|
+
- [SKeyValueTable](../SKeyValueTable)
|
|
26
|
+
- [SLoadingModal](../SLoadingModal)
|
|
27
|
+
- [SPopover](../SPopover)
|
|
28
|
+
- [SPopup](../SPopup)
|
|
29
|
+
- [SToast](../SToast)
|
|
30
|
+
|
|
31
|
+
### Depends on
|
|
32
|
+
|
|
33
|
+
- [SIcon](../SIcon)
|
|
34
|
+
|
|
35
|
+
### Graph
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
graph TD;
|
|
39
|
+
SButton --> SIcon
|
|
40
|
+
SActionModal --> SButton
|
|
41
|
+
SConfirmModal --> SButton
|
|
42
|
+
SDropdownButton --> SButton
|
|
43
|
+
SKeyValueTable --> SButton
|
|
44
|
+
SLoadingModal --> SButton
|
|
45
|
+
SPopover --> SButton
|
|
46
|
+
SPopup --> SButton
|
|
47
|
+
SToast --> SButton
|
|
48
|
+
style SButton fill:#f9f,stroke:#333,stroke-width:4px
|
|
49
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# SCalendar
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SCalendar
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `value?` | `string \| null` | — | 선택 날짜 (YYYY-MM-DD) |
|
|
12
|
+
| `selectable?` | `[string, string]` | — | 선택 가능 범위 [시작, 종료] (빈 문자열이면 제한 없음) |
|
|
13
|
+
| `events?` | `SCalendarEventGroup[]` | — | 이벤트 그룹 (날짜별 점) |
|
|
14
|
+
| `elevated?` | `boolean` | `false` | 카드 그림자 |
|
|
15
|
+
| `className?` | `string` | — | |
|
|
16
|
+
| `style?` | `CSSProperties` | — | |
|
|
17
|
+
|
|
18
|
+
#### Events
|
|
19
|
+
|
|
20
|
+
| Event | Type | Description |
|
|
21
|
+
|-------|------|-------------|
|
|
22
|
+
| `onValueChange` | `(date: string) => void` | 선택 변경 (sdUpdate) |
|
|
23
|
+
| `onViewChange` | `(v: { year: number; month: number }) => void` | 보이는 연·월 변경 (sdViewChange) |
|
|
24
|
+
|
|
25
|
+
## Dependencies
|
|
26
|
+
|
|
27
|
+
### Used by
|
|
28
|
+
|
|
29
|
+
- [SDatePicker](../SDatePicker)
|
|
30
|
+
|
|
31
|
+
### Depends on
|
|
32
|
+
|
|
33
|
+
- [SGhostButton](../SGhostButton)
|
|
34
|
+
|
|
35
|
+
### Graph
|
|
36
|
+
|
|
37
|
+
```mermaid
|
|
38
|
+
graph TD;
|
|
39
|
+
SCalendar --> SGhostButton
|
|
40
|
+
SDatePicker --> SCalendar
|
|
41
|
+
style SCalendar fill:#f9f,stroke:#333,stroke-width:4px
|
|
42
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# SCallout
|
|
2
|
+
|
|
3
|
+
> 자동 생성 문서 — `npm run docs:gen`. 소스: 각 컴포넌트의 Props/Handle 인터페이스 + import 의존성.
|
|
4
|
+
|
|
5
|
+
### SCallout
|
|
6
|
+
|
|
7
|
+
#### Props
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
|------|------|---------|-------------|
|
|
11
|
+
| `type?` | `SCalloutType` | `'default'` | 콜아웃 타입 (색상·아이콘·타이틀 결정) |
|
|
12
|
+
| `message?` | `SCalloutMessage[]` | `[]` | 표시할 메시지 목록 (배열 중첩으로 depth 표현). 각 문자열은 인라인 HTML(`<b>`, `<a>` 등)을 허용하며 sanitizeInlineHtml 로 살균 후 렌더된다. |
|
|
13
|
+
| `children?` | `ReactNode` | — | message 대신 직접 본문을 넣을 때 |
|
|
14
|
+
| `className?` | `string` | — | |
|
|
15
|
+
| `style?` | `CSSProperties` | — | |
|
|
16
|
+
|
|
17
|
+
## Dependencies
|
|
18
|
+
|
|
19
|
+
### Depends on
|
|
20
|
+
|
|
21
|
+
- [SIcon](../SIcon)
|
|
22
|
+
|
|
23
|
+
### Graph
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
graph TD;
|
|
27
|
+
SCallout --> SIcon
|
|
28
|
+
style SCallout fill:#f9f,stroke:#333,stroke-width:4px
|
|
29
|
+
```
|
|
@@ -17,6 +17,75 @@ function cn(...inputs) {
|
|
|
17
17
|
return twMerge(clsx.clsx(inputs));
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// src/lib/sanitize-inline-html.ts
|
|
21
|
+
var ALLOWED_INLINE_TAGS = /* @__PURE__ */ new Set(["A", "B", "STRONG", "I", "EM", "BR", "SPAN"]);
|
|
22
|
+
var ALLOWED_ATTRS_BY_TAG = {
|
|
23
|
+
A: /* @__PURE__ */ new Set(["href", "target", "rel", "class"])
|
|
24
|
+
};
|
|
25
|
+
var COMMON_ALLOWED_ATTRS = /* @__PURE__ */ new Set(["class"]);
|
|
26
|
+
var SAFE_HREF_RE = /^(https?:|mailto:|tel:|\/|#|\.)/i;
|
|
27
|
+
var DROP_CONTENT_TAGS = /* @__PURE__ */ new Set([
|
|
28
|
+
"SCRIPT",
|
|
29
|
+
"STYLE",
|
|
30
|
+
"IFRAME",
|
|
31
|
+
"OBJECT",
|
|
32
|
+
"EMBED",
|
|
33
|
+
"META",
|
|
34
|
+
"LINK",
|
|
35
|
+
"BASE",
|
|
36
|
+
"NOSCRIPT",
|
|
37
|
+
// SVG/MATH 는 foreign-content 파싱 모드로 전환되어 재직렬화 시 다른 트리로
|
|
38
|
+
// 재파싱될 수 있다(mXSS 벡터). 인라인 라벨에 필요 없으므로 통째로 제거한다.
|
|
39
|
+
"SVG",
|
|
40
|
+
"MATH",
|
|
41
|
+
"TEMPLATE"
|
|
42
|
+
]);
|
|
43
|
+
var escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
44
|
+
var sanitizeNode = (node) => {
|
|
45
|
+
if (node.nodeType === Node.COMMENT_NODE) {
|
|
46
|
+
node.remove();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
50
|
+
const element = node;
|
|
51
|
+
const tagName = element.tagName;
|
|
52
|
+
if (DROP_CONTENT_TAGS.has(tagName)) {
|
|
53
|
+
element.remove();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
Array.from(element.childNodes).forEach((child) => sanitizeNode(child));
|
|
57
|
+
if (ALLOWED_INLINE_TAGS.has(tagName)) {
|
|
58
|
+
if (element.hasAttribute("className")) {
|
|
59
|
+
const val = element.getAttribute("className");
|
|
60
|
+
element.removeAttribute("className");
|
|
61
|
+
if (!element.hasAttribute("class")) element.setAttribute("class", val);
|
|
62
|
+
}
|
|
63
|
+
const allowedAttrs = ALLOWED_ATTRS_BY_TAG[tagName] ?? COMMON_ALLOWED_ATTRS;
|
|
64
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
65
|
+
if (!allowedAttrs.has(attr.name)) element.removeAttribute(attr.name);
|
|
66
|
+
});
|
|
67
|
+
if (tagName === "A") {
|
|
68
|
+
const href = element.getAttribute("href");
|
|
69
|
+
if (href !== null && href !== "" && !SAFE_HREF_RE.test(href)) element.removeAttribute("href");
|
|
70
|
+
if (element.hasAttribute("target")) {
|
|
71
|
+
element.setAttribute("rel", "noopener noreferrer");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const parent = element.parentNode;
|
|
77
|
+
if (parent == null) return;
|
|
78
|
+
while (element.firstChild) parent.insertBefore(element.firstChild, element);
|
|
79
|
+
parent.removeChild(element);
|
|
80
|
+
};
|
|
81
|
+
var sanitizeInlineHtml = (value) => {
|
|
82
|
+
if (typeof document === "undefined") return escapeHtml(value);
|
|
83
|
+
const template = document.createElement("template");
|
|
84
|
+
template.innerHTML = value;
|
|
85
|
+
Array.from(template.content.childNodes).forEach((child) => sanitizeNode(child));
|
|
86
|
+
return template.innerHTML;
|
|
87
|
+
};
|
|
88
|
+
|
|
20
89
|
// src/lib/color.ts
|
|
21
90
|
var COLOR_KEYS = [
|
|
22
91
|
"white",
|
|
@@ -2867,7 +2936,13 @@ function renderItems(message, depth = 1) {
|
|
|
2867
2936
|
className: cn("flex items-start", isDepth2 && "pl-[32px]"),
|
|
2868
2937
|
children: [
|
|
2869
2938
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-[24px] shrink-0 text-center", "aria-hidden": true, children: isDepth2 ? "\u2022" : "-" }),
|
|
2870
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2939
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2940
|
+
"p",
|
|
2941
|
+
{
|
|
2942
|
+
className: "m-0 min-w-0 flex-1 break-words",
|
|
2943
|
+
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(m) }
|
|
2944
|
+
}
|
|
2945
|
+
)
|
|
2871
2946
|
]
|
|
2872
2947
|
},
|
|
2873
2948
|
`${depth}-${i}-${out.length}`
|