@x-plat/design-system 0.11.0 → 0.13.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.
Files changed (63) hide show
  1. package/dist/components/AutoResizeTextArea/index.cjs +2 -2
  2. package/dist/components/AutoResizeTextArea/index.js +2 -2
  3. package/dist/components/ChatInput/index.cjs +2 -2
  4. package/dist/components/ChatInput/index.js +2 -2
  5. package/dist/components/CheckBox/index.cjs +2 -2
  6. package/dist/components/CheckBox/index.js +2 -2
  7. package/dist/components/DatePicker/index.cjs +109 -75
  8. package/dist/components/DatePicker/index.d.cts +19 -0
  9. package/dist/components/DatePicker/index.d.ts +19 -0
  10. package/dist/components/DatePicker/index.js +109 -75
  11. package/dist/components/Dropdown/index.cjs +22 -9
  12. package/dist/components/Dropdown/index.css +3 -0
  13. package/dist/components/Dropdown/index.js +22 -9
  14. package/dist/components/Editor/index.cjs +602 -30
  15. package/dist/components/Editor/index.css +103 -0
  16. package/dist/components/Editor/index.d.cts +1 -1
  17. package/dist/components/Editor/index.d.ts +1 -1
  18. package/dist/components/Editor/index.js +602 -30
  19. package/dist/components/FieldMessage/index.cjs +2 -2
  20. package/dist/components/FieldMessage/index.d.cts +8 -0
  21. package/dist/components/FieldMessage/index.d.ts +8 -0
  22. package/dist/components/FieldMessage/index.js +2 -2
  23. package/dist/components/FileUpload/index.cjs +10 -6
  24. package/dist/components/FileUpload/index.d.cts +15 -2
  25. package/dist/components/FileUpload/index.d.ts +15 -2
  26. package/dist/components/FileUpload/index.js +10 -6
  27. package/dist/components/ImageSelector/index.cjs +7 -6
  28. package/dist/components/ImageSelector/index.d.cts +15 -2
  29. package/dist/components/ImageSelector/index.d.ts +15 -2
  30. package/dist/components/ImageSelector/index.js +7 -6
  31. package/dist/components/Input/index.cjs +2 -2
  32. package/dist/components/Input/index.d.cts +4 -0
  33. package/dist/components/Input/index.d.ts +4 -0
  34. package/dist/components/Input/index.js +2 -2
  35. package/dist/components/PopOver/index.cjs +21 -7
  36. package/dist/components/PopOver/index.css +3 -0
  37. package/dist/components/PopOver/index.js +21 -7
  38. package/dist/components/Radio/index.cjs +2 -2
  39. package/dist/components/Radio/index.js +2 -2
  40. package/dist/components/Select/index.cjs +23 -10
  41. package/dist/components/Select/index.css +3 -0
  42. package/dist/components/Select/index.d.cts +1 -2
  43. package/dist/components/Select/index.d.ts +1 -2
  44. package/dist/components/Select/index.js +23 -10
  45. package/dist/components/Switch/index.cjs +2 -2
  46. package/dist/components/Switch/index.js +2 -2
  47. package/dist/components/TextArea/index.cjs +2 -2
  48. package/dist/components/TextArea/index.js +2 -2
  49. package/dist/components/TimePicker/index.cjs +23 -10
  50. package/dist/components/TimePicker/index.css +3 -0
  51. package/dist/components/TimePicker/index.js +23 -10
  52. package/dist/components/index.cjs +751 -124
  53. package/dist/components/index.css +113 -0
  54. package/dist/components/index.js +751 -124
  55. package/dist/index.cjs +751 -124
  56. package/dist/index.css +113 -0
  57. package/dist/index.js +751 -124
  58. package/guidelines/Guidelines.md +12 -0
  59. package/guidelines/MIGRATION.md +270 -0
  60. package/guidelines/components/datepicker.md +26 -0
  61. package/guidelines/components/editor.md +58 -3
  62. package/guidelines/components/file-media.md +21 -4
  63. package/package.json +1 -1
@@ -74,3 +74,15 @@ React 기반 디자인 시스템 라이브러리이다. Figma Make Kit과 1:1
74
74
  4. **컴포지션**
75
75
  - [Grid](./composition/grid.md) - Grid 시스템, 위젯 패턴
76
76
  - [Layout](./composition/layout.md) - Layout, Header, SideBar
77
+
78
+ ---
79
+
80
+ ## 버전을 올릴 때
81
+
82
+ [마이그레이션 노트](./MIGRATION.md) — 0.5.x 이후 **실제로 깨지는 것만** 버전별로
83
+ 모아 뒀다. 자기 버전부터 아래로 읽으면 된다.
84
+
85
+ - 최신본: `https://unpkg.com/@x-plat/design-system/guidelines/MIGRATION.md`
86
+ - 커밋 제목만 보고 판단하지 말 것. `refactor!` 인데 별칭이 살아 있어 안 깨지는
87
+ 것이 있고, 평범한 `refactor` 인데 prop 이 사라진 것이 있다.
88
+
@@ -0,0 +1,270 @@
1
+ # @x-plat/design-system — 마이그레이션 노트
2
+
3
+ 버전을 올릴 때 **실제로 깨지는 것만** 모았다. 추가된 기능은 여기 적지 않는다 —
4
+ 그건 각 컴포넌트 문서에 있다.
5
+
6
+ - 최신본 URL: `https://unpkg.com/@x-plat/design-system/guidelines/MIGRATION.md`
7
+ - 자기 버전부터 아래로 읽어 내려가면 된다.
8
+
9
+ ## 이 문서를 믿어도 되는 범위
10
+
11
+ 각 항목은 **커밋 해시**를 달아 뒀다. 커밋 제목만 보고 판단하지 말 것 —
12
+ `refactor!` 라고 외치지만 별칭이 살아 있어 안 깨지는 것이 있고(0.7.1 `Badge`),
13
+ 평범한 `refactor` 인데 prop 이 사라진 것이 있다(0.8.0 `Button`).
14
+
15
+ 「실제로 걸린 것」 표는 진짜 이관에서 확인된 것이고, 나머지는 소스에서 확인한 것이다.
16
+
17
+ ---
18
+
19
+ ## 0.5.x → 0.6.0 — CSS 변수 이름 전면 교체
20
+
21
+ **`92dac35` · 가장 큰 변경이다.** Figma 변수 컬렉션 구조에 맞춰 컬러 레이어를
22
+ 4단계에서 3단계로 줄이면서 semantic 이름을 전부 바꿨다.
23
+
24
+ `var(--semantic-*)` 를 직접 쓰는 CSS 가 있으면 **조용히 깨진다** — 정의되지 않은
25
+ 변수는 오류를 내지 않고 색만 사라진다. 이관 후 화면을 눈으로 확인할 것.
26
+
27
+ | 예전 | 지금 |
28
+ |---|---|
29
+ | `--semantic-*-strong` | `--semantic-*-primary` |
30
+ | `--semantic-*-subtle` | `--semantic-*-secondary` |
31
+ | `--semantic-*-muted` | `--semantic-*-tertiary` |
32
+ | `--semantic-*-brand` | `--semantic-*-brand-primary` |
33
+ | `--semantic-*-sunday` | `--semantic-*-accent-red` |
34
+ | `--semantic-*-saturday` | `--semantic-*-accent-blue` |
35
+ | `--semantic-*-emphasis-*` | 삭제 → `--semantic-surface-*-strong` |
36
+ | `--brand-base-black-alpha-10/25` | `--brand-base-overlay-5/10/25/50/75/85` |
37
+
38
+ `color/primitive.ts` 가 삭제되고 `brand`/`system` 이 hex 실값을 직접 갖는다.
39
+ `var(--primitive-*)` 를 참조하던 곳은 전부 끊긴다.
40
+
41
+ **값이 바뀐 것 6건** (이름은 그대로인데 색이 달라진다):
42
+ `text-brand-primary` · `border-brand-primary` · `border-warning` ·
43
+ `surface-info-default` · `icon-success` · `icon-info`.
44
+ `system.link` 는 purple → deep-purple.
45
+
46
+ > 컴포넌트만 쓰고 CSS 변수를 직접 참조하지 않는다면 이 절은 건너뛰어도 된다.
47
+
48
+ ## 0.6.0 → 0.7.0 — effects · typography 토큰 정합
49
+
50
+ **`6429909`** 컴포넌트가 하드코딩하던 그림자·폰트를 토큰으로 옮겼다.
51
+ 컴포넌트를 그대로 쓰면 영향 없다. 그림자나 폰트 크기를 CSS 로 덮어쓰고 있었다면
52
+ 우선순위가 달라질 수 있다.
53
+
54
+ ## 0.7.0 → 0.7.1 — Badge 이름 변경
55
+
56
+ **`c95ee21` · `6430c9c`**
57
+
58
+ | 대상 | 깨지나 | 조치 |
59
+ |---|---|---|
60
+ | `import { Badge }` | **안 깨짐** | `Badge` 가 `@deprecated` 별칭으로 계속 나간다. 새로 쓰는 곳만 `NotificationBadge` |
61
+ | CSS 클래스 `.lib-xplat-badge` | **깨짐** | `.lib-xplat-notification-badge` 로. 별칭 없음 |
62
+
63
+ **`NotificationBadge` 는 알약(pill) 라벨이 아니다.** 아이콘 위에 올라타는 개수
64
+ 인디케이터다. `count` 도 `dot` 도 없으면 **뱃지가 렌더되지 않고 children 만 통과한다.**
65
+
66
+ ```tsx
67
+ <Badge type="error">품절</Badge> // ✗ 아무것도 안 그려지고 "품절" 만 나온다
68
+ <NotificationBadge count={3}><BellIcon /></NotificationBadge> // ○
69
+ ```
70
+
71
+ 알약 라벨이 필요하면 `Tag` 를 쓴다. 이 오용은 이름이 바뀌기 전부터 조용히
72
+ 실패하고 있었으므로, 올리기 전에 `<Badge>` 사용처를 훑어 볼 것.
73
+
74
+ ## 0.7.2 → 0.8.0 — `Button` 이 `<button>` 전용으로 복귀
75
+
76
+ **`f5668dd` · `0a4ab14` · 실제로 제일 많이 깨지는 항목이다.**
77
+
78
+ `Button` 은 이제 `<button>` 하나만 렌더한다. `href` prop 이 없다.
79
+
80
+ ```tsx
81
+ <Button href="/about">소개</Button> // ✗ 더 이상 없다
82
+ <LinkButton href="/about">소개</LinkButton> // ○
83
+ <Link href="/about">소개</Link> // ○ 본문 안 링크
84
+ ```
85
+
86
+ > ⚠ 커밋 `f5668dd` 에 나오는 **`buttonClass()` 는 쓰지 말 것.** 바로 다음 커밋
87
+ > `0a4ab14` 에서 `LinkButton` 으로 대체됐고 지금 소스에 없다(export 0건).
88
+ > 커밋을 순서대로 훑다 보면 유효한 경로로 오해하기 쉽다.
89
+
90
+ ## 0.8.0 → 0.8.1 — 오버레이가 항상 `document.body` 로 portal
91
+
92
+ **`17004e7`** Modal · Select · Dropdown · PopOver · TimePicker 의 팝업이 조상
93
+ DOM 이 아니라 항상 `body` 로 들어간다. 조상에 `transform`/`filter`/`will-change`/
94
+ `contain` 이 있으면 `position: fixed` 의 기준이 그 조상으로 바뀌어 오버레이가
95
+ 엉뚱한 자리에 뜨던 것을 고친 것이다.
96
+
97
+ **오버레이를 조상 기준으로 위치 잡는 CSS 가 있으면 깨진다.** 그런 CSS 는 지워야 한다 —
98
+ 위치는 DS 가 계산한다.
99
+
100
+ ## 0.8.1 → 0.8.2 — `modal-box` 에 `position: relative`
101
+
102
+ **`c3611ee`** 0.8.1 에서 모달의 `transform` 을 걷어내면서 모달 **안쪽**
103
+ `position: absolute` 요소들의 기준이 모달이 아니라 화면 전체(`.dim`)로 튀었다.
104
+ 그 회귀를 되돌린 것이다. 0.8.1 을 건너뛰고 0.8.2 이상으로 올리면 겪지 않는다.
105
+
106
+ ## 0.8.3 → 0.9.0 — 폼 검증 API 가 `validations` 로 통일
107
+
108
+ **`6e64fbc`** 컴포넌트마다 제각각이던 에러 표시 방식을 하나로 모았다.
109
+ **추가이므로 기존 코드를 깨지 않는다.** 다만 이제 직접 그릴 필요가 없다.
110
+
111
+ ```tsx
112
+ validations?: { status: "error" | "warning" | "success" | "default"; message: string }[]
113
+ ```
114
+
115
+ - 렌더는 `FieldMessage` 가 전담한다. 아이콘·색·간격이 DS 전체에서 같아진다.
116
+ - `aria-invalid` 도 DS 가 붙인다 — 직접 붙이던 코드는 걷어낼 것.
117
+ - `hasError(validations)` 가 배럴에서 나간다.
118
+ - `Input/InputValidations` 는 **삭제됐다.** 직접 import 하던 곳이 있으면 끊긴다.
119
+
120
+ `Select.error?: boolean` 은 하위호환으로 남아 있다. `validations` 와 OR 로
121
+ 합쳐지므로 둘 다 써도 되지만, 새로 쓰는 곳은 `validations` 를 쓴다.
122
+
123
+ ## 0.9.0 → 0.10.0 — `type` = 상태색 / `variant` = 모양 변형
124
+
125
+ **`12f4319`** 한 컴포넌트에서 `type` 이 색을 뜻하기도 하고 모양을 뜻하기도 하던
126
+ 것을 두 축으로 갈랐다. **별칭이 살아 있어 깨지지 않는다.**
127
+
128
+ | 축 | prop | 값 |
129
+ |---|---|---|
130
+ | 상태 색 | `type` | `primary` `success` `error` `warning` `info` |
131
+ | 모양 변형 | `variant` | 컴포넌트마다 다름 |
132
+
133
+ - 모양 변형을 `type` 으로 주던 곳(`Tooltip` `Chart` `Tab` `Tag`)은 `variant` 로
134
+ 옮기는 게 맞지만, `variant ?? type ?? 기본값` 으로 받으므로 **지금 동작한다.**
135
+ - `type="brand"` → `type="primary"`. `normalizeStatus()` 가 `brand` 를 계속 받는다.
136
+
137
+ **별칭 제거 시점은 아직 정해지지 않았다.** 업그레이드와 무관한 diff 를 섞기
138
+ 싫으면 나중에 한 번에 정리해도 된다. 제거가 정해지면 이 문서에 적는다.
139
+
140
+ ## 0.10.0 → 0.11.0 — 폼 컨트롤에 `label` / `required`
141
+
142
+ **`9f7700d` · 추가지만 기존 마크업과 겹칠 수 있다.**
143
+
144
+ `Field` 가 **진짜 `<label htmlFor>` 를 그린다.** 바깥에서 `<label>` 로 감싸던
145
+ 코드에 DS 의 `label` prop 을 같이 주면 `<label>` 안에 `<label>` 이 들어간다 —
146
+ 유효하지 않은 HTML 이고, 클릭 시 포커스가 어디로 갈지 브라우저마다 다르다.
147
+
148
+ > **「DS `label` 도입」과 「기존 `<label>` 제거」는 같은 커밋에 넣을 것.**
149
+ > 한쪽만 하면 중첩되거나 라벨이 사라진다.
150
+
151
+ 같이 걷어낼 것:
152
+
153
+ - `htmlFor` / `id` — DS 가 `React.useId()` 로 만들어 잇는다. 직접 넘길 필요 없다.
154
+ - `aria-invalid` — DS 가 붙인다.
155
+
156
+ `Field` 는 **붙일 게 없으면 래퍼를 만들지 않고 `children` 을 그대로 통과시킨다.**
157
+ 안 쓰는 곳의 DOM 은 늘지 않으므로 그대로 둬도 된다.
158
+
159
+ ## 0.11.0 → 0.12.0 — Editor 확충
160
+
161
+ **`7bf563f` · `97e668c` · 추가만 있다.** 되돌리기/다시하기, 표, 체크리스트,
162
+ 정렬, 문법 강조, 형광펜, 위/아래 첨자가 들어갔다.
163
+
164
+ **저장된 HTML 을 직접 다루는 쪽은 허용 태그 목록을 갱신해야 한다.**
165
+ 저장 값에 표·체크리스트·`mark`·`sub`/`sup` 이 새로 나타난다. 태그 목록을
166
+ 직접 들고 있다면(예: "이 값이 HTML 인가" 판별) 아래 **31개를 그대로** 복사할 것.
167
+
168
+ ```
169
+ p br div span
170
+ h1 h2 h3 h4 h5 h6
171
+ ul ol li
172
+ blockquote pre code
173
+ strong b em i u s strike del
174
+ a img hr
175
+ sub sup mark
176
+ table thead tbody tr th td
177
+ ```
178
+
179
+ 주의할 점 둘:
180
+
181
+ - **`b` `i` `u` `strike` 는 옛날 태그가 아니라 평상시 출력이다.** DS 는
182
+ `styleWithCSS` 를 켜지 않으므로 브라우저 `execCommand` 가 `<strong>` 이 아니라
183
+ `<b>` 를 낸다. 굵게 쓴 글이 흔하므로 이게 빠지면 자주 밟힌다.
184
+ - **`input` 은 필요 없다.** 체크리스트는 `<li data-checked>` + CSS `::before` 로
185
+ 그린다. `<input>` 은 한 번도 나오지 않는다.
186
+
187
+ 허용 목록은 `Editor.tsx` 안의 상수이고 prop 으로 열려 있지 않다. 버전을 올리면
188
+ 따라온다. `readOnly` 로 그릴 때도 같은 태그가 전부 나온다 — sanitize 경로와
189
+ 스타일이 편집 모드와 같다.
190
+
191
+ HTML 을 검색 색인에 넣는다면 **닫는 태그를 공백이나 줄바꿈으로 치환**할 것.
192
+ `</td>` `</th>` `</tr>` `</li>` `</p>` `</h1>`~`</h6>` `</blockquote>` `<br>` 을
193
+ 그냥 지우면 칸 글자가 붙어 `가격수량` 같은 낱말이 생긴다.
194
+
195
+ ## 0.12.0 → 0.13.0 — `FileUpload` / `ImageSelector` 의 `label` 뜻이 바뀜
196
+
197
+ **깨진다. 그런데 타입 오류가 나지 않는다 — 글자 위치만 바뀐다.**
198
+
199
+ 이 둘의 `label` 은 DS 안에서 혼자 다른 뜻이었다. 다른 폼 컨트롤에서는 컨트롤
200
+ **위**에 붙는 필드 라벨인데, 여기서는 상자 **안**에 찍히는 안내 문구였다.
201
+ 그 문구를 `placeholder` 로 옮기고 `label` 을 필드 라벨로 되돌렸다.
202
+
203
+ ```tsx
204
+ // 0.12.0 이하
205
+ <FileUpload label="파일을 드래그하거나 클릭하여 업로드" />
206
+
207
+ // 0.13.0 — 같은 화면을 얻으려면
208
+ <FileUpload placeholder="파일을 드래그하거나 클릭하여 업로드" />
209
+
210
+ // 이제 가능해진 것
211
+ <FileUpload label="첨부파일" required placeholder="끌어다 놓으세요" />
212
+ ```
213
+
214
+ `label` 을 그대로 두면 **그 글자가 상자 안이 아니라 상자 위 라벨로 올라간다.**
215
+ `label?: string` 에서 `label?: React.ReactNode` 로 넓어졌으므로 기존 문자열도
216
+ 타입은 통과한다. `grep -rn 'FileUpload\|ImageSelector'` 로 훑어 `label=` 이 있는
217
+ 곳을 `placeholder=` 로 바꾸면 된다.
218
+
219
+ 같이 들어간 것:
220
+
221
+ - `required` — 라벨 뒤에 `*`
222
+ - `htmlFor` 연결 — 라벨을 클릭하면 파일 선택창이 열린다
223
+ - **`ImageSelector` 의 하드코딩된 `id="image-input"` 제거.** 한 화면에 둘 이상
224
+ 놓으면 DOM id 가 겹치던 버그였다. 이제 `React.useId()` 로 만든다.
225
+ `#image-input` 을 잡는 CSS 나 테스트 셀렉터가 있으면 끊긴다.
226
+
227
+ ### 같은 릴리스: DatePicker 3종에 `label` / `required` / `validations`
228
+
229
+ **추가만 있다.** `SingleDatePicker` · `RangeDatePicker` · `InputDatePicker` 가
230
+ 다른 폼 컨트롤과 같은 방식으로 라벨·검증을 받는다.
231
+
232
+ `PopupDatePicker` 와 `Dropdown` 은 받지 않는다 — 전자는 트리거를 `component` 로
233
+ 직접 넘기는 구조라 라벨이 가리킬 대상이 없고, 후자는 `role="menu"` 인 액션
234
+ 메뉴라 검증할 값이 없다.
235
+
236
+ ---
237
+
238
+ ## 실제 이관에서 걸린 것 / 안 걸린 것
239
+
240
+ `xplat-shop-templat` (pnpm 모노레포, 워크스페이스 4개) 을 **0.6.1 → 0.12.0** 으로
241
+ 올렸을 때의 결과다. DS 를 어댑터 한 곳에서만 쓰는 구조였다.
242
+
243
+ | 항목 | 결과 | 이유 |
244
+ |---|---|---|
245
+ | `Button` href 제거 | 안 걸림 | `<Button href>` 사용 0곳 |
246
+ | `Badge` → `NotificationBadge` | 안 걸림 | `@deprecated` 별칭으로 통과 |
247
+ | CSS 클래스 rename | 안 걸림 | `.lib-xplat-*` 을 덮어쓰는 CSS 0곳 |
248
+ | 오버레이 body portal | 안 걸림 | 오버레이 기준을 잡는 CSS 없음 |
249
+ | **`label` 중첩** | **걸림** | 어댑터가 `<label htmlFor>` 를 직접 그리고 있었다 |
250
+
251
+ **목록을 훑기 전에 자기 저장소에서 먼저 세어 볼 것.** 위 표에서 보듯 대부분은
252
+ 해당 사항이 없고, 진짜 걸리는 건 한둘이다. `<Button href`, `.lib-xplat-`,
253
+ `<label` 세 가지를 grep 하는 것으로 대부분 판별된다.
254
+
255
+ 결과: 어댑터 241줄 → 216줄, 쓰이지 않던 CSS 30줄 삭제. DS 가 `label`·
256
+ `aria-invalid`·`useId`·검증 메시지를 맡으면서 어댑터가 얇아진다.
257
+
258
+ ---
259
+
260
+ ## 아직 확인되지 않은 것
261
+
262
+ **Editor 는 브라우저에서 검증되지 않았다.** `contentEditable`·`execCommand`·IME 는
263
+ 자동 테스트로 흉내 낼 수 없다. 특히 아래 넷은 직접 눌러 봐야 한다.
264
+
265
+ - 한글 조합 중 `⌘Z` / `Ctrl+Z`
266
+ - 툴바 서식 버튼
267
+ - 표 안에서 Enter · Backspace
268
+ - 체크박스 클릭 판정
269
+
270
+ 이상이 보이면 재현 조건과 함께 알려 주면 좋겠다.
@@ -50,6 +50,32 @@ Input + 드롭다운 형태이다.
50
50
  />
51
51
  ```
52
52
 
53
+ ## 라벨과 검증
54
+
55
+ `SingleDatePicker` · `RangeDatePicker` · `InputDatePicker` 는 다른 폼 컨트롤과
56
+ 똑같이 `label` · `required` · `validations` 를 받는다.
57
+
58
+ ```tsx
59
+ <InputDatePicker
60
+ value={date}
61
+ onChange={setDate}
62
+ label="계약일"
63
+ required
64
+ validations={[{ status: "error", message: "계약일을 선택하세요" }]}
65
+ />
66
+ ```
67
+
68
+ 검증 메시지는 `FieldMessage` 가 그린다 — 아이콘·색·간격이 Input·Select 와 같다.
69
+ 직접 `<p>` 로 그리지 말 것.
70
+
71
+ 달력을 펼쳐 놓는 `SingleDatePicker` · `RangeDatePicker` 는 **포커스 대상이 날짜
72
+ 칸마다 있어 `htmlFor` 로 하나를 고를 수 없다.** 그래서 `role="group"` +
73
+ `aria-labelledby` 로 라벨과 묶는다. 쓰는 쪽에서 신경 쓸 것은 없다.
74
+
75
+ `PopupDatePicker` 는 라벨·검증을 받지 않는다 — 트리거를 `component` 로 직접
76
+ 넘기는 구조라 라벨이 가리킬 대상이 정해지지 않는다. 라벨이 필요하면 트리거로
77
+ `InputDatePicker` 를 쓰거나 바깥에서 `Field` 로 감싼다.
78
+
53
79
  ---
54
80
 
55
81
  ## 의사결정
@@ -28,10 +28,20 @@ const [html, setHtml] = useState("");
28
28
 
29
29
  ## 툴바
30
30
 
31
- 기본은 13종 전부다. `toolbar` 로 골라서 줄일 수 있다.
31
+ 기본은 전부 켜져 있다. `toolbar` 로 골라서 줄일 수 있다.
32
32
 
33
- `bold` `italic` `underline` `strikethrough` `code` `heading` `list` `ordered-list`
34
- `blockquote` `code-block` `link` `image` `divider`
33
+ | 갈래 | 항목 |
34
+ |---|---|
35
+ | 인라인 | `bold` `italic` `underline` `strikethrough` `code` `highlight` `superscript` `subscript` |
36
+ | 블록 | `heading-1` `heading-2` `heading-3` `list` `ordered-list` `checklist` `blockquote` `code-block` |
37
+ | 삽입 | `link` `image` `table` `divider` |
38
+ | 정렬 | `align-left` `align-center` `align-right` |
39
+ | 기타 | `clear-format` `undo` `redo` |
40
+
41
+ - **제목은 세 단계가 따로다.** 같은 레벨을 다시 누르면 단락으로 돌아간다.
42
+ - **정렬은 `style` 이 아니라 클래스**(`align-center` 등)로 들어간다. `style` 속성을
43
+ 허용하면 붙여넣기로 아무 CSS 나 들어올 수 있다.
44
+ - `highlight` 는 `<mark>` 로 감싼다.
35
45
 
36
46
  ## 마크다운 단축키
37
47
 
@@ -54,12 +64,38 @@ const [html, setHtml] = useState("");
54
64
  여러 줄을 선택하고 코드 블록을 누르면 **하나의** `<pre><code>` 가 된다.
55
65
  블록마다 따로 만들어지지 않는다.
56
66
 
67
+ ### 문법 강조
68
+
69
+ 캐럿이 코드 블록 안에 있으면 툴바 오른쪽에 **언어 선택**이 나타난다.
70
+ `plain` `javascript` `typescript` `json` `html` `css` `python` `sql` `bash` 9종.
71
+
72
+ 외부 라이브러리를 쓰지 않는 **자체 토크나이저**다. 문자열·주석·숫자·키워드를
73
+ 구분하는 수준이고, 중첩 템플릿 리터럴이나 정규식 리터럴 같은 까다로운 것은
74
+ 일부러 다루지 않는다 — 틀리게 칠하느니 안 칠하는 쪽이 낫다.
75
+
76
+ 언어는 `<pre class="lang-javascript">` 로 저장되어 `value` 에 함께 나간다.
77
+
57
78
  ```
58
79
  Enter 코드 블록 안에서 줄바꿈 (블록이 쪼개지지 않는다)
59
80
  Tab 공백 2칸 들여쓰기 (포커스가 밖으로 나가지 않는다)
60
81
  Enter × 빈 줄 둘이 이어지면 코드 블록을 빠져나온다
61
82
  ```
62
83
 
84
+ ## 표 · 목록 · 체크리스트
85
+
86
+ ```
87
+ 목록에서 Tab / Shift+Tab 들여쓰기 / 내어쓰기
88
+ 표 안에서 Tab / Shift+Tab 다음 칸 / 이전 칸
89
+ 표 마지막 칸에서 Tab 행 추가
90
+ ```
91
+
92
+ 체크리스트는 항목 **왼쪽 체크박스 영역**을 눌러 토글한다. 실제 `<input>` 이 아니라
93
+ 가상 요소로 그린다 — contentEditable 안에 input 을 넣으면 캐럿이 그 안으로 들어간다.
94
+
95
+ ## 평문으로 붙여넣기
96
+
97
+ `⌘⇧V` (`⌃⇧V`) 는 서식 없이 글자만 넣는다. 코드 블록 안에서는 항상 평문이다.
98
+
63
99
  코드 블록 안에서 다시 코드 블록을 누르면 **해제**되어 일반 단락으로 돌아간다.
64
100
 
65
101
  ## 코드 블록 안에서는
@@ -69,6 +105,25 @@ Enter × 빈 줄 둘이 이어지면 코드 블록을 빠져나온다
69
105
  - **마크다운 단축키와 슬래시 메뉴가 뜨지 않는다.** 코드에 `# ` 이나 `/` 는 흔하다.
70
106
  - **붙여넣기는 순수 텍스트로만** 들어간다.
71
107
 
108
+ ## 되돌리기 / 다시하기
109
+
110
+ ```
111
+ ⌘Z ⌃Z 되돌리기
112
+ ⌘⇧Z ⌃⇧Z ⌃Y 다시하기
113
+ ```
114
+
115
+ 툴바에도 `undo` / `redo` 버튼이 있다. 기본 툴바에 포함되어 있고, `toolbar` 를
116
+ 직접 지정할 때는 넣어야 나온다.
117
+
118
+ - **브라우저 기본 undo 를 쓰지 않는다.** 이 에디터는 코드블럭·인라인코드·마크다운
119
+ 단축키·슬래시 명령을 DOM 직접 조작으로 처리하는데, 그런 작업은 브라우저 undo
120
+ 스택에 올라가지 않는다. 그대로 두면 ⌘Z 가 그 작업을 건너뛰고 엉뚱한 지점으로 간다.
121
+ - **연속 입력은 한 덩어리**로 묶인다(500ms). 한 글자씩 되돌아가지 않는다.
122
+ - **블록을 만드는 작업**(코드블럭·구분선)은 따로 경계를 만든다. 코드블럭을 넣은 뒤
123
+ ⌘Z 한 번이면 정확히 그것만 취소된다.
124
+ - 되돌린 뒤 새로 입력하면 앞쪽(redo) 기록은 버려진다.
125
+ - `value` 가 **밖에서** 바뀌면(폼 리셋 등) 그 지점이 새 기준이 되어 이전 기록은 사라진다.
126
+
72
127
  ## 붙여넣기
73
128
 
74
129
  붙여넣는 HTML 은 항상 정화된다. 허용 태그 밖은 자식을 살려 벗겨내고,
@@ -14,16 +14,27 @@ import { FileUpload } from "@x-plat/design-system";
14
14
  | multiple | `boolean` | `false` | 다중 파일 허용 |
15
15
  | maxSize | `number` | — | 최대 파일 크기 (bytes). 초과 파일은 자동 필터 |
16
16
  | onChange | `(files: File[]) => void` | — | 파일 선택 콜백 |
17
- | label | `string` | `"파일을 드래그하거나 클릭하여 업로드"` | 안내 텍스트 |
18
- | description | `string` | — | 부가 설명 |
17
+ | placeholder | `string` | `"파일을 드래그하거나 클릭하여 업로드"` | **상자 안** 안내 텍스트 |
18
+ | description | `string` | — | 상자 안 부가 설명 |
19
+ | label | `ReactNode` | — | **상자 위** 필드 라벨. 클릭하면 파일 선택창이 열린다 |
20
+ | required | `boolean` | `false` | 라벨 뒤에 `*` 표시 |
21
+ | validations | `Validation[]` | — | 상자 아래 검증 메시지 |
22
+
23
+ > ⚠ **0.13.0 에서 `label` 의 뜻이 바뀌었다.** 예전에는 상자 **안** 글자였고
24
+ > 지금은 상자 **위** 필드 라벨이다. 상자 안 글자는 `placeholder` 로 옮겼다.
25
+ > 타입 오류가 나지 않고 글자 위치만 바뀌므로 눈으로 확인해야 한다.
26
+ > 자세한 것은 [마이그레이션 노트](../MIGRATION.md) 참고.
19
27
 
20
28
  ```tsx
21
29
  <FileUpload
30
+ label="첨부파일"
31
+ required
22
32
  accept="image/*"
23
33
  multiple
24
34
  maxSize={5 * 1024 * 1024}
25
35
  onChange={(files) => console.log(files)}
26
36
  description="최대 5MB, 이미지만 허용"
37
+ validations={[{ status: "error", message: "파일을 첨부하세요" }]}
27
38
  />
28
39
  ```
29
40
 
@@ -40,13 +51,19 @@ import { ImageSelector } from "@x-plat/design-system";
40
51
  | Prop | 타입 | 기본값 | 설명 |
41
52
  |------|------|--------|------|
42
53
  | value | `File` | — | 선택된 이미지 파일 |
43
- | label | `string` | `"이미지 추가하기"` | 빈 상태 안내 텍스트 |
54
+ | placeholder | `string` | `"이미지 추가하기"` | **상자 안** 빈 상태 안내 텍스트 |
44
55
  | onChange | `(value: File \| undefined) => void` | — | 변경 콜백 (삭제 시 `undefined`) |
56
+ | label | `ReactNode` | — | **상자 위** 필드 라벨 |
57
+ | required | `boolean` | `false` | 라벨 뒤에 `*` 표시 |
58
+ | validations | `Validation[]` | — | 상자 아래 검증 메시지 |
59
+
60
+ > ⚠ `FileUpload` 와 같은 변경이 0.13.0 에 있었다. `label` 은 이제 필드 라벨이고,
61
+ > 상자 안 글자는 `placeholder` 다.
45
62
 
46
63
  ```tsx
47
64
  const [image, setImage] = useState<File | undefined>();
48
65
 
49
- <ImageSelector value={image} onChange={setImage} />
66
+ <ImageSelector label="대표 이미지" required value={image} onChange={setImage} />
50
67
  ```
51
68
 
52
69
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-plat/design-system",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "XPLAT UI Design System",
5
5
  "author": "XPLAT WOONG",
6
6
  "main": "dist/index.cjs",