@x-plat/design-system 0.9.0 → 0.11.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 (156) hide show
  1. package/dist/components/AutoResizeTextArea/index.cjs +14 -5
  2. package/dist/components/AutoResizeTextArea/index.css +15 -0
  3. package/dist/components/AutoResizeTextArea/index.d.cts +5 -0
  4. package/dist/components/AutoResizeTextArea/index.d.ts +5 -0
  5. package/dist/components/AutoResizeTextArea/index.js +14 -5
  6. package/dist/components/Badge/index.cjs +5 -1
  7. package/dist/components/Badge/index.css +1 -0
  8. package/dist/components/Badge/index.d.cts +1 -0
  9. package/dist/components/Badge/index.d.ts +1 -0
  10. package/dist/components/Badge/index.js +5 -1
  11. package/dist/components/Box/index.d.cts +3 -0
  12. package/dist/components/Box/index.d.ts +3 -0
  13. package/dist/components/Chart/index.cjs +7 -6
  14. package/dist/components/Chart/index.d.cts +12 -1
  15. package/dist/components/Chart/index.d.ts +12 -1
  16. package/dist/components/Chart/index.js +7 -6
  17. package/dist/components/ChatInput/index.cjs +20 -7
  18. package/dist/components/ChatInput/index.css +15 -0
  19. package/dist/components/ChatInput/index.d.cts +10 -0
  20. package/dist/components/ChatInput/index.d.ts +10 -0
  21. package/dist/components/ChatInput/index.js +20 -7
  22. package/dist/components/CheckBox/index.cjs +14 -5
  23. package/dist/components/CheckBox/index.css +17 -0
  24. package/dist/components/CheckBox/index.d.cts +10 -2
  25. package/dist/components/CheckBox/index.d.ts +10 -2
  26. package/dist/components/CheckBox/index.js +14 -5
  27. package/dist/components/Chip/index.d.cts +2 -0
  28. package/dist/components/Chip/index.d.ts +2 -0
  29. package/dist/components/DatePicker/index.cjs +181 -65
  30. package/dist/components/DatePicker/index.css +19 -0
  31. package/dist/components/DatePicker/index.js +181 -65
  32. package/dist/components/Drawer/index.cjs +83 -4
  33. package/dist/components/Drawer/index.d.cts +1 -0
  34. package/dist/components/Drawer/index.d.ts +1 -0
  35. package/dist/components/Drawer/index.js +83 -4
  36. package/dist/components/Dropdown/index.cjs +35 -7
  37. package/dist/components/Dropdown/index.js +35 -7
  38. package/dist/components/Editor/index.cjs +178 -21
  39. package/dist/components/Editor/index.js +178 -21
  40. package/dist/components/FieldMessage/index.cjs +8 -3
  41. package/dist/components/FieldMessage/index.css +15 -0
  42. package/dist/components/FieldMessage/index.d.cts +11 -4
  43. package/dist/components/FieldMessage/index.d.ts +11 -4
  44. package/dist/components/FieldMessage/index.js +8 -3
  45. package/dist/components/FileUpload/index.cjs +8 -3
  46. package/dist/components/FileUpload/index.css +15 -0
  47. package/dist/components/FileUpload/index.d.cts +6 -0
  48. package/dist/components/FileUpload/index.d.ts +6 -0
  49. package/dist/components/FileUpload/index.js +8 -3
  50. package/dist/components/ImageSelector/index.cjs +8 -3
  51. package/dist/components/ImageSelector/index.css +15 -0
  52. package/dist/components/ImageSelector/index.d.cts +3 -0
  53. package/dist/components/ImageSelector/index.d.ts +3 -0
  54. package/dist/components/ImageSelector/index.js +8 -3
  55. package/dist/components/Input/index.cjs +15 -5
  56. package/dist/components/Input/index.css +15 -0
  57. package/dist/components/Input/index.d.cts +8 -0
  58. package/dist/components/Input/index.d.ts +8 -0
  59. package/dist/components/Input/index.js +15 -5
  60. package/dist/components/Modal/index.cjs +84 -5
  61. package/dist/components/Modal/index.js +84 -5
  62. package/dist/components/NotificationBadge/index.cjs +5 -1
  63. package/dist/components/NotificationBadge/index.css +1 -0
  64. package/dist/components/NotificationBadge/index.d.cts +6 -2
  65. package/dist/components/NotificationBadge/index.d.ts +6 -2
  66. package/dist/components/NotificationBadge/index.js +5 -1
  67. package/dist/components/Pagination/index.cjs +6 -2
  68. package/dist/components/Pagination/index.css +1 -0
  69. package/dist/components/Pagination/index.d.cts +13 -2
  70. package/dist/components/Pagination/index.d.ts +13 -2
  71. package/dist/components/Pagination/index.js +6 -2
  72. package/dist/components/PopOver/index.cjs +34 -6
  73. package/dist/components/PopOver/index.js +34 -6
  74. package/dist/components/Progress/index.cjs +6 -2
  75. package/dist/components/Progress/index.css +1 -0
  76. package/dist/components/Progress/index.d.cts +11 -2
  77. package/dist/components/Progress/index.d.ts +11 -2
  78. package/dist/components/Progress/index.js +6 -2
  79. package/dist/components/Radio/index.cjs +14 -5
  80. package/dist/components/Radio/index.css +17 -0
  81. package/dist/components/Radio/index.d.cts +11 -2
  82. package/dist/components/Radio/index.d.ts +11 -2
  83. package/dist/components/Radio/index.js +14 -5
  84. package/dist/components/Select/index.cjs +99 -31
  85. package/dist/components/Select/index.css +54 -0
  86. package/dist/components/Select/index.d.cts +16 -1
  87. package/dist/components/Select/index.d.ts +16 -1
  88. package/dist/components/Select/index.js +99 -31
  89. package/dist/components/Skeleton/index.d.cts +3 -0
  90. package/dist/components/Skeleton/index.d.ts +3 -0
  91. package/dist/components/Spinner/index.cjs +6 -2
  92. package/dist/components/Spinner/index.css +1 -0
  93. package/dist/components/Spinner/index.d.cts +8 -2
  94. package/dist/components/Spinner/index.d.ts +8 -2
  95. package/dist/components/Spinner/index.js +6 -2
  96. package/dist/components/Stat/index.cjs +84 -0
  97. package/dist/components/Stat/index.css +96 -0
  98. package/dist/components/Stat/index.d.cts +37 -0
  99. package/dist/components/Stat/index.d.ts +37 -0
  100. package/dist/components/Stat/index.js +57 -0
  101. package/dist/components/Steps/index.cjs +6 -2
  102. package/dist/components/Steps/index.css +11 -0
  103. package/dist/components/Steps/index.d.cts +9 -2
  104. package/dist/components/Steps/index.d.ts +9 -2
  105. package/dist/components/Steps/index.js +6 -2
  106. package/dist/components/Switch/index.cjs +20 -7
  107. package/dist/components/Switch/index.css +17 -0
  108. package/dist/components/Switch/index.d.cts +15 -2
  109. package/dist/components/Switch/index.d.ts +15 -2
  110. package/dist/components/Switch/index.js +20 -7
  111. package/dist/components/Tab/index.cjs +51 -26
  112. package/dist/components/Tab/index.css +4 -0
  113. package/dist/components/Tab/index.d.cts +12 -1
  114. package/dist/components/Tab/index.d.ts +12 -1
  115. package/dist/components/Tab/index.js +51 -26
  116. package/dist/components/Tag/index.cjs +5 -3
  117. package/dist/components/Tag/index.d.cts +12 -2
  118. package/dist/components/Tag/index.d.ts +12 -2
  119. package/dist/components/Tag/index.js +5 -3
  120. package/dist/components/TextArea/index.cjs +14 -4
  121. package/dist/components/TextArea/index.css +15 -0
  122. package/dist/components/TextArea/index.d.cts +7 -0
  123. package/dist/components/TextArea/index.d.ts +7 -0
  124. package/dist/components/TextArea/index.js +14 -4
  125. package/dist/components/TimePicker/index.cjs +448 -0
  126. package/dist/components/TimePicker/index.css +172 -0
  127. package/dist/components/TimePicker/index.d.cts +42 -0
  128. package/dist/components/TimePicker/index.d.ts +42 -0
  129. package/dist/components/TimePicker/index.js +411 -0
  130. package/dist/components/Tooltip/index.cjs +4 -2
  131. package/dist/components/Tooltip/index.d.cts +11 -1
  132. package/dist/components/Tooltip/index.d.ts +11 -1
  133. package/dist/components/Tooltip/index.js +4 -2
  134. package/dist/components/index.cjs +916 -385
  135. package/dist/components/index.css +296 -0
  136. package/dist/components/index.d.cts +3 -0
  137. package/dist/components/index.d.ts +3 -0
  138. package/dist/components/index.js +914 -385
  139. package/dist/index.cjs +940 -409
  140. package/dist/index.css +296 -0
  141. package/dist/index.d.cts +3 -0
  142. package/dist/index.d.ts +3 -0
  143. package/dist/index.js +938 -409
  144. package/dist/status-njWqQWFV.d.cts +20 -0
  145. package/dist/status-njWqQWFV.d.ts +20 -0
  146. package/guidelines/AGENT_PROMPT.md +18 -3
  147. package/guidelines/Guidelines.md +3 -0
  148. package/guidelines/components/card.md +3 -3
  149. package/guidelines/components/editor.md +86 -0
  150. package/guidelines/components/feedback.md +1 -1
  151. package/guidelines/components/form.md +19 -0
  152. package/guidelines/components/navigation.md +16 -15
  153. package/guidelines/components/overlay.md +43 -4
  154. package/guidelines/components/stat.md +31 -0
  155. package/guidelines/components/time-picker.md +49 -0
  156. package/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { V as Validation } from '../../validation-Dqo1zqhT.js';
4
+
5
+ type TimePickerSize = "sm" | "md" | "lg";
6
+ interface TimePickerProps {
7
+ /** `"HH:mm"` 24시간 표기. 비어 있으면 placeholder 가 보인다 */
8
+ value?: string;
9
+ /** 시각을 고르면 `"HH:mm"` 로 준다 */
10
+ onChange?: (value: string) => void;
11
+ /** 목록 간격(분). 기본 30 — 30이면 하루 48개가 나온다 */
12
+ step?: number;
13
+ /** 고를 수 있는 가장 이른 시각 `"HH:mm"` */
14
+ min?: string;
15
+ /** 고를 수 있는 가장 늦은 시각 `"HH:mm"` */
16
+ max?: string;
17
+ /** 오전/오후 12시간 표기로 보여준다. onChange 는 그대로 24시간 `"HH:mm"` */
18
+ use12Hours?: boolean;
19
+ /** 비어 있을 때 표시할 안내 글자 */
20
+ placeholder?: string;
21
+ disabled?: boolean;
22
+ size?: TimePickerSize;
23
+ /** 컨트롤 위에 붙는 라벨. 클릭하면 컨트롤에 포커스가 간다 */
24
+ label?: React.ReactNode;
25
+ /** 라벨 뒤에 필수 표시(*)를 붙인다 */
26
+ required?: boolean;
27
+ /** 컨트롤 아래에 표시할 검증 메시지. DS 폼 컴포넌트 공통 */
28
+ validations?: Validation[];
29
+ }
30
+ /**
31
+ * 시각을 고르는 드롭다운.
32
+ *
33
+ * `DatePicker` 는 날짜 전용이다. 날짜와 시각이 함께 필요하면 둘을 나란히 두고
34
+ * 호출부에서 합친다 — `DatePicker` 에 시간을 끼워 넣으면 하위 4종의 날짜 전용
35
+ * 비교 로직을 전부 건드려야 해서 기존 사용처가 깨질 위험이 크다.
36
+ */
37
+ declare const TimePicker: {
38
+ (props: TimePickerProps): react_jsx_runtime.JSX.Element;
39
+ displayName: string;
40
+ };
41
+
42
+ export { TimePicker };
@@ -0,0 +1,411 @@
1
+ // src/components/TimePicker/TimePicker.tsx
2
+ import React4 from "react";
3
+
4
+ // src/tokens/hooks/Portal.tsx
5
+ import ReactDOM from "react-dom";
6
+ var Portal = ({ children }) => {
7
+ if (typeof document === "undefined") return null;
8
+ return ReactDOM.createPortal(children, document.body);
9
+ };
10
+ Portal.displayName = "Portal";
11
+ var Portal_default = Portal;
12
+
13
+ // src/tokens/hooks/useAutoPosition.ts
14
+ import React from "react";
15
+ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
16
+ const [position, setPosition] = React.useState({
17
+ position: {},
18
+ direction: "bottom"
19
+ });
20
+ const calculatePosition = React.useCallback(() => {
21
+ if (!triggerRef.current || !popRef.current) return;
22
+ const triggerRect = triggerRef.current.getBoundingClientRect();
23
+ const popW = popRef.current.offsetWidth;
24
+ const popH = popRef.current.offsetHeight;
25
+ const viewportHeight = window.innerHeight;
26
+ const viewportWidth = window.innerWidth;
27
+ if (popH === 0 || popW === 0) return;
28
+ let direction = "bottom";
29
+ let top;
30
+ let left;
31
+ if (triggerRect.bottom + popH > viewportHeight && triggerRect.top - popH > 0) {
32
+ direction = "top";
33
+ top = triggerRect.top - popH;
34
+ } else {
35
+ top = triggerRect.bottom;
36
+ }
37
+ left = triggerRect.left;
38
+ if (left + popW > viewportWidth - 8) {
39
+ left = triggerRect.right - popW;
40
+ }
41
+ if (left < 8) left = 8;
42
+ setPosition({
43
+ position: { top, left },
44
+ direction
45
+ });
46
+ }, [triggerRef, popRef]);
47
+ React.useLayoutEffect(() => {
48
+ if (!enabled) return;
49
+ calculatePosition();
50
+ const raf = requestAnimationFrame(calculatePosition);
51
+ return () => cancelAnimationFrame(raf);
52
+ }, [calculatePosition, enabled]);
53
+ React.useEffect(() => {
54
+ if (!enabled || !popRef.current) return;
55
+ const observer = new ResizeObserver(() => {
56
+ calculatePosition();
57
+ });
58
+ observer.observe(popRef.current);
59
+ return () => observer.disconnect();
60
+ }, [calculatePosition, enabled, popRef]);
61
+ React.useEffect(() => {
62
+ if (!enabled) return;
63
+ window.addEventListener("resize", calculatePosition);
64
+ window.addEventListener("scroll", calculatePosition, true);
65
+ return () => {
66
+ window.removeEventListener("resize", calculatePosition);
67
+ window.removeEventListener("scroll", calculatePosition, true);
68
+ };
69
+ }, [calculatePosition, enabled]);
70
+ return position;
71
+ };
72
+ var useAutoPosition_default = useAutoPosition;
73
+
74
+ // src/tokens/hooks/useClickOutside.ts
75
+ import React2 from "react";
76
+ var useClickOutside = (refs, handler, enabled = true) => {
77
+ React2.useEffect(() => {
78
+ if (!enabled) return;
79
+ const refArray = Array.isArray(refs) ? refs : [refs];
80
+ const listener = (event) => {
81
+ const target = event.target;
82
+ const isInside = refArray.some(
83
+ (ref) => ref.current && ref.current.contains(target)
84
+ );
85
+ if (!isInside) {
86
+ handler();
87
+ }
88
+ };
89
+ document.addEventListener("mousedown", listener);
90
+ document.addEventListener("touchstart", listener);
91
+ return () => {
92
+ document.removeEventListener("mousedown", listener);
93
+ document.removeEventListener("touchstart", listener);
94
+ };
95
+ }, [refs, handler, enabled]);
96
+ };
97
+ var useClickOutside_default = useClickOutside;
98
+
99
+ // src/tokens/hooks/useOverlayKeyboard.ts
100
+ import React3 from "react";
101
+ var FOCUSABLE = [
102
+ "a[href]",
103
+ "button:not([disabled])",
104
+ "input:not([disabled]):not([type='hidden'])",
105
+ "select:not([disabled])",
106
+ "textarea:not([disabled])",
107
+ "[tabindex]:not([tabindex='-1'])"
108
+ ].join(",");
109
+ var useEscapeKey = (enabled, onEscape) => {
110
+ React3.useEffect(() => {
111
+ if (!enabled) return;
112
+ const onKey = (e) => {
113
+ if (e.key !== "Escape") return;
114
+ if (e.defaultPrevented) return;
115
+ e.preventDefault();
116
+ onEscape();
117
+ };
118
+ document.addEventListener("keydown", onKey);
119
+ return () => document.removeEventListener("keydown", onKey);
120
+ }, [enabled, onEscape]);
121
+ };
122
+
123
+ // ../../node_modules/clsx/dist/clsx.mjs
124
+ function r(e) {
125
+ var t, f, n = "";
126
+ if ("string" == typeof e || "number" == typeof e) n += e;
127
+ else if ("object" == typeof e) if (Array.isArray(e)) {
128
+ var o = e.length;
129
+ for (t = 0; t < o; t++) e[t] && (f = r(e[t])) && (n && (n += " "), n += f);
130
+ } else for (f in e) e[f] && (n && (n += " "), n += f);
131
+ return n;
132
+ }
133
+ function clsx() {
134
+ for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
135
+ return n;
136
+ }
137
+ var clsx_default = clsx;
138
+
139
+ // src/tokens/svg/status/ErrorIcon.tsx
140
+ import { jsx, jsxs } from "react/jsx-runtime";
141
+ var ErrorIcon = () => /* @__PURE__ */ jsxs(
142
+ "svg",
143
+ {
144
+ xmlns: "http://www.w3.org/2000/svg",
145
+ width: "1em",
146
+ height: "1em",
147
+ viewBox: "0 0 16 16",
148
+ fill: "none",
149
+ children: [
150
+ /* @__PURE__ */ jsxs("g", { clipPath: "url(#clip0_1196_9603)", children: [
151
+ /* @__PURE__ */ jsx(
152
+ "path",
153
+ {
154
+ d: "M9.57588 5.57559C9.81019 5.34127 10.19 5.34127 10.4243 5.57559C10.6586 5.8099 10.6586 6.18971 10.4243 6.42402L8.84854 7.9998L10.4243 9.57559C10.6586 9.8099 10.6586 10.1897 10.4243 10.424C10.19 10.6583 9.81019 10.6583 9.57588 10.424L8.0001 8.84824L6.42432 10.424C6.19 10.6583 5.81019 10.6583 5.57588 10.424C5.34156 10.1897 5.34156 9.8099 5.57588 9.57559L7.15166 7.9998L5.57588 6.42402C5.34156 6.18971 5.34156 5.8099 5.57588 5.57559C5.81019 5.34127 6.19 5.34127 6.42432 5.57559L8.0001 7.15137L9.57588 5.57559Z",
155
+ fill: "currentColor"
156
+ }
157
+ ),
158
+ /* @__PURE__ */ jsx(
159
+ "path",
160
+ {
161
+ fillRule: "evenodd",
162
+ clipRule: "evenodd",
163
+ d: "M8.0001 0.733398C12.0131 0.73361 15.2671 3.98679 15.2673 7.9998C15.2672 12.0129 12.0131 15.2668 8.0001 15.267C3.98701 15.2669 0.733016 12.0129 0.73291 7.9998C0.733051 3.98674 3.98704 0.733539 8.0001 0.733398ZM8.0001 1.9334C4.64978 1.93354 1.93383 4.64948 1.93369 7.9998C1.9338 11.3502 4.64975 14.0669 8.0001 14.067C11.3504 14.0668 14.0672 11.3501 14.0673 7.9998C14.0671 4.64953 11.3504 1.93361 8.0001 1.9334Z",
164
+ fill: "currentColor"
165
+ }
166
+ )
167
+ ] }),
168
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("clipPath", { id: "clip0_1196_9603", children: /* @__PURE__ */ jsx("rect", { width: "16", height: "16", fill: "white" }) }) })
169
+ ]
170
+ }
171
+ );
172
+ var ErrorIcon_default = ErrorIcon;
173
+
174
+ // src/tokens/svg/status/InfoIcon.tsx
175
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
176
+ var InfoIcon = () => /* @__PURE__ */ jsxs2(
177
+ "svg",
178
+ {
179
+ xmlns: "http://www.w3.org/2000/svg",
180
+ width: "1em",
181
+ height: "1em",
182
+ viewBox: "0 0 16 16",
183
+ fill: "none",
184
+ children: [
185
+ /* @__PURE__ */ jsxs2("g", { clipPath: "url(#clip0_1188_11261)", children: [
186
+ /* @__PURE__ */ jsx2(
187
+ "path",
188
+ {
189
+ d: "M8.00156 7.39999C8.33293 7.39999 8.60156 7.66862 8.60156 7.99999V10.6664C8.60156 10.9978 8.33293 11.2664 8.00156 11.2664C7.67019 11.2664 7.40156 10.9978 7.40156 10.6664V7.99999C7.40156 7.66862 7.67019 7.39999 8.00156 7.39999Z",
190
+ fill: "currentColor"
191
+ }
192
+ ),
193
+ /* @__PURE__ */ jsx2(
194
+ "path",
195
+ {
196
+ d: "M8.00859 4.73358C8.3398 4.73378 8.60859 5.00233 8.60859 5.33358C8.60849 5.66474 8.33973 5.93338 8.00859 5.93358H8.00156C7.67026 5.93358 7.40167 5.66486 7.40156 5.33358C7.40156 5.00221 7.67019 4.73358 8.00156 4.73358H8.00859Z",
197
+ fill: "currentColor"
198
+ }
199
+ ),
200
+ /* @__PURE__ */ jsx2(
201
+ "path",
202
+ {
203
+ fillRule: "evenodd",
204
+ clipRule: "evenodd",
205
+ d: "M8.00156 0.733582C12.0146 0.733793 15.2686 3.98697 15.2688 7.99999C15.2686 12.013 12.0146 15.267 8.00156 15.2672C3.98848 15.267 0.734481 12.0131 0.734375 7.99999C0.734516 3.98693 3.9885 0.733722 8.00156 0.733582ZM8.00156 1.93358C4.65124 1.93372 1.9353 4.64967 1.93516 7.99999C1.93526 11.3503 4.65122 14.067 8.00156 14.0672C11.3518 14.067 14.0686 11.3503 14.0688 7.99999C14.0686 4.64971 11.3518 1.93379 8.00156 1.93358Z",
206
+ fill: "currentColor"
207
+ }
208
+ )
209
+ ] }),
210
+ /* @__PURE__ */ jsx2("defs", { children: /* @__PURE__ */ jsx2("clipPath", { id: "clip0_1188_11261", children: /* @__PURE__ */ jsx2("rect", { width: "16", height: "16", fill: "white" }) }) })
211
+ ]
212
+ }
213
+ );
214
+ var InfoIcon_default = InfoIcon;
215
+
216
+ // src/tokens/svg/status/SuccessIcon.tsx
217
+ import { jsx as jsx3 } from "react/jsx-runtime";
218
+ var SuccessIcon = () => /* @__PURE__ */ jsx3(
219
+ "svg",
220
+ {
221
+ xmlns: "http://www.w3.org/2000/svg",
222
+ width: "1em",
223
+ height: "1em",
224
+ viewBox: "0 0 16 16",
225
+ fill: "none",
226
+ children: /* @__PURE__ */ jsx3(
227
+ "path",
228
+ {
229
+ d: "M12.9084 3.57597C13.1426 3.34172 13.5225 3.34185 13.7568 3.57597C13.9911 3.81028 13.9911 4.19009 13.7568 4.4244L6.424 11.758C6.31157 11.8703 6.15869 11.9337 5.99978 11.9338C5.8409 11.9337 5.68798 11.8703 5.57556 11.758L2.24197 8.4244C2.00782 8.19018 2.00795 7.81028 2.24197 7.57597C2.47626 7.34167 2.85609 7.34172 3.09041 7.57597L5.999 10.4846L12.9084 3.57597Z",
230
+ fill: "currentColor"
231
+ }
232
+ )
233
+ }
234
+ );
235
+ var SuccessIcon_default = SuccessIcon;
236
+
237
+ // src/components/FieldMessage/FieldMessage.tsx
238
+ import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
239
+ var ICON = {
240
+ default: /* @__PURE__ */ jsx4(InfoIcon_default, {}),
241
+ success: /* @__PURE__ */ jsx4(SuccessIcon_default, {}),
242
+ warning: /* @__PURE__ */ jsx4(InfoIcon_default, {}),
243
+ error: /* @__PURE__ */ jsx4(ErrorIcon_default, {})
244
+ };
245
+ var FieldMessage = (props) => {
246
+ const { validations } = props;
247
+ if (!validations || validations.length === 0) return null;
248
+ return /* @__PURE__ */ jsx4("div", { className: "lib-xplat-field-message-wrap", children: validations.map((v, idx) => /* @__PURE__ */ jsxs3(
249
+ "div",
250
+ {
251
+ className: clsx_default("lib-xplat-field-message", v.status),
252
+ children: [
253
+ /* @__PURE__ */ jsx4("div", { className: "icon", children: ICON[v.status] }),
254
+ /* @__PURE__ */ jsx4("span", { children: v.message })
255
+ ]
256
+ },
257
+ `${v.message}_${idx}`
258
+ )) });
259
+ };
260
+ FieldMessage.displayName = "FieldMessage";
261
+ var Field = (props) => {
262
+ const { label, required = false, htmlFor, validations, children } = props;
263
+ const hasMessages = !!validations && validations.length > 0;
264
+ if (!label && !hasMessages) return /* @__PURE__ */ jsx4(Fragment, { children });
265
+ return /* @__PURE__ */ jsxs3("div", { className: "lib-xplat-field", children: [
266
+ label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", htmlFor, children: [
267
+ label,
268
+ required && /* @__PURE__ */ jsx4("span", { className: "required", "aria-hidden": "true", children: "*" })
269
+ ] }),
270
+ children,
271
+ hasMessages && /* @__PURE__ */ jsx4(FieldMessage, { validations })
272
+ ] });
273
+ };
274
+ Field.displayName = "Field";
275
+ var hasError = (validations) => !!validations?.some((v) => v.status === "error");
276
+
277
+ // src/components/TimePicker/TimePicker.tsx
278
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
279
+ var ANIMATION_DURATION_MS = 200;
280
+ var toMinutes = (hhmm) => {
281
+ if (!hhmm) return null;
282
+ const m = /^(\d{1,2}):(\d{2})$/.exec(hhmm.trim());
283
+ if (!m) return null;
284
+ const h = Number(m[1]);
285
+ const min = Number(m[2]);
286
+ if (h > 23 || min > 59) return null;
287
+ return h * 60 + min;
288
+ };
289
+ var toHHmm = (minutes) => `${String(Math.floor(minutes / 60)).padStart(2, "0")}:${String(minutes % 60).padStart(2, "0")}`;
290
+ var display = (hhmm, use12Hours) => {
291
+ if (!use12Hours) return hhmm;
292
+ const total = toMinutes(hhmm);
293
+ if (total === null) return hhmm;
294
+ const h24 = Math.floor(total / 60);
295
+ const mm = String(total % 60).padStart(2, "0");
296
+ const period = h24 < 12 ? "\uC624\uC804" : "\uC624\uD6C4";
297
+ const h12 = h24 % 12 === 0 ? 12 : h24 % 12;
298
+ return `${period} ${h12}:${mm}`;
299
+ };
300
+ var TimePicker = (props) => {
301
+ const {
302
+ value,
303
+ onChange,
304
+ step = 30,
305
+ min,
306
+ max,
307
+ use12Hours = false,
308
+ placeholder = "\uC2DC\uAC01 \uC120\uD0DD",
309
+ disabled = false,
310
+ size = "md",
311
+ label,
312
+ required,
313
+ validations
314
+ } = props;
315
+ const fieldId = React4.useId();
316
+ const triggerRef = React4.useRef(null);
317
+ const contentRef = React4.useRef(null);
318
+ const [isOpen, setOpen] = React4.useState(false);
319
+ const [mounted, setMounted] = React4.useState(false);
320
+ const [visible, setVisible] = React4.useState(false);
321
+ const options = React4.useMemo(() => {
322
+ const safeStep = step > 0 && step <= 720 ? step : 30;
323
+ const lo = toMinutes(min) ?? 0;
324
+ const hi = toMinutes(max) ?? 24 * 60 - 1;
325
+ const out = [];
326
+ for (let t = lo; t <= hi; t += safeStep) out.push(toHHmm(t));
327
+ return out;
328
+ }, [step, min, max]);
329
+ const close = React4.useCallback(() => setOpen(false), []);
330
+ useClickOutside_default([triggerRef, contentRef], close, isOpen);
331
+ useEscapeKey(isOpen, () => {
332
+ close();
333
+ triggerRef.current?.focus({ preventScroll: true });
334
+ });
335
+ const position = useAutoPosition_default(triggerRef, contentRef, mounted);
336
+ React4.useEffect(() => {
337
+ if (disabled && isOpen) setOpen(false);
338
+ }, [disabled, isOpen]);
339
+ React4.useEffect(() => {
340
+ if (isOpen) {
341
+ setMounted(true);
342
+ const t2 = setTimeout(() => setVisible(true), 1);
343
+ return () => clearTimeout(t2);
344
+ }
345
+ setVisible(false);
346
+ const t = setTimeout(() => setMounted(false), ANIMATION_DURATION_MS);
347
+ return () => clearTimeout(t);
348
+ }, [isOpen]);
349
+ const pick = (hhmm) => {
350
+ onChange?.(hhmm);
351
+ close();
352
+ triggerRef.current?.focus({ preventScroll: true });
353
+ };
354
+ const control = /* @__PURE__ */ jsxs4("div", { className: clsx_default("lib-xplat-time-picker", size, disabled && "disabled"), children: [
355
+ /* @__PURE__ */ jsx5(
356
+ "div",
357
+ {
358
+ id: fieldId,
359
+ ref: triggerRef,
360
+ className: clsx_default("time-picker-trigger", hasError(validations) && "error"),
361
+ role: "combobox",
362
+ "aria-expanded": isOpen,
363
+ "aria-haspopup": "listbox",
364
+ "aria-invalid": hasError(validations) || void 0,
365
+ tabIndex: disabled ? void 0 : 0,
366
+ onClick: () => !disabled && setOpen((p) => !p),
367
+ onKeyDown: (e) => {
368
+ if (disabled) return;
369
+ if (e.key === "Enter" || e.key === " " || e.key === "ArrowDown") {
370
+ e.preventDefault();
371
+ setOpen(true);
372
+ }
373
+ },
374
+ children: /* @__PURE__ */ jsx5("span", { className: clsx_default("time-picker-value", !value && "placeholder"), children: value ? display(value, use12Hours) : placeholder })
375
+ }
376
+ ),
377
+ mounted && /* @__PURE__ */ jsx5(Portal_default, { children: /* @__PURE__ */ jsx5(
378
+ "div",
379
+ {
380
+ ref: contentRef,
381
+ className: clsx_default("lib-xplat-time-picker-content", size, visible ? "enter" : "exit"),
382
+ style: { ...position.position, width: triggerRef.current?.offsetWidth },
383
+ role: "listbox",
384
+ children: options.map((t) => /* @__PURE__ */ jsx5(
385
+ "div",
386
+ {
387
+ className: clsx_default("time-picker-item", t === value && "is-selected"),
388
+ role: "option",
389
+ "aria-selected": t === value,
390
+ tabIndex: 0,
391
+ onClick: () => pick(t),
392
+ onKeyDown: (e) => {
393
+ if (e.key === "Enter" || e.key === " ") {
394
+ e.preventDefault();
395
+ pick(t);
396
+ }
397
+ },
398
+ children: display(t, use12Hours)
399
+ },
400
+ t
401
+ ))
402
+ }
403
+ ) })
404
+ ] });
405
+ return /* @__PURE__ */ jsx5(Field, { validations, label, required, htmlFor: fieldId, children: control });
406
+ };
407
+ TimePicker.displayName = "TimePicker";
408
+ var TimePicker_default = TimePicker;
409
+ export {
410
+ TimePicker_default as TimePicker
411
+ };
@@ -72,10 +72,12 @@ var Tooltip = (props) => {
72
72
  children,
73
73
  title,
74
74
  description,
75
- type = "dark",
75
+ variant,
76
+ type,
76
77
  follow = false,
77
78
  disabled = false
78
79
  } = props;
80
+ const shape = variant ?? type ?? "dark";
79
81
  const triggerRef = import_react.default.useRef(null);
80
82
  const tooltipRef = import_react.default.useRef(null);
81
83
  const [visible, setVisible] = import_react.default.useState(false);
@@ -185,7 +187,7 @@ var Tooltip = (props) => {
185
187
  {
186
188
  ref: tooltipRef,
187
189
  role: "tooltip",
188
- className: clsx_default("lib-xplat-tooltip", type),
190
+ className: clsx_default("lib-xplat-tooltip", shape),
189
191
  style: { position: "fixed", left: pos.left, top: pos.top },
190
192
  children: [
191
193
  title && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tooltip-title", children: title }),
@@ -1,10 +1,19 @@
1
1
  import React from 'react';
2
2
 
3
+ type TooltipVariant = "dark" | "light";
3
4
  interface TooltipProps {
4
5
  children: React.ReactNode;
6
+ /** 말풍선 첫 줄. 굵게 표시된다 */
5
7
  title?: React.ReactNode;
8
+ /** 말풍선 본문. title 과 둘 중 하나는 있어야 뜬다 */
6
9
  description?: React.ReactNode;
7
- type?: "dark" | "light";
10
+ /** 말풍선 배색 */
11
+ variant?: TooltipVariant;
12
+ /**
13
+ * @deprecated 모양 변형은 `variant` 로 받는다. `type` 은 상태 색 전용이다.
14
+ * 기존 사용처가 깨지지 않도록 계속 받는다 — 둘 다 주면 `variant` 가 이긴다.
15
+ */
16
+ type?: TooltipVariant;
8
17
  /**
9
18
  * 커서를 따라다닌다. 기본값은 `false` — 트리거 요소 기준으로 고정된다
10
19
  * (PopOver/Dropdown/Select 와 같은 방식).
@@ -13,6 +22,7 @@ interface TooltipProps {
13
22
  * 아이콘처럼 대상이 작은 경우는 고정이 읽기 편하다.
14
23
  */
15
24
  follow?: boolean;
25
+ /** 말풍선을 띄우지 않는다 */
16
26
  disabled?: boolean;
17
27
  }
18
28
  declare const Tooltip: React.FC<TooltipProps>;
@@ -1,10 +1,19 @@
1
1
  import React from 'react';
2
2
 
3
+ type TooltipVariant = "dark" | "light";
3
4
  interface TooltipProps {
4
5
  children: React.ReactNode;
6
+ /** 말풍선 첫 줄. 굵게 표시된다 */
5
7
  title?: React.ReactNode;
8
+ /** 말풍선 본문. title 과 둘 중 하나는 있어야 뜬다 */
6
9
  description?: React.ReactNode;
7
- type?: "dark" | "light";
10
+ /** 말풍선 배색 */
11
+ variant?: TooltipVariant;
12
+ /**
13
+ * @deprecated 모양 변형은 `variant` 로 받는다. `type` 은 상태 색 전용이다.
14
+ * 기존 사용처가 깨지지 않도록 계속 받는다 — 둘 다 주면 `variant` 가 이긴다.
15
+ */
16
+ type?: TooltipVariant;
8
17
  /**
9
18
  * 커서를 따라다닌다. 기본값은 `false` — 트리거 요소 기준으로 고정된다
10
19
  * (PopOver/Dropdown/Select 와 같은 방식).
@@ -13,6 +22,7 @@ interface TooltipProps {
13
22
  * 아이콘처럼 대상이 작은 경우는 고정이 읽기 편하다.
14
23
  */
15
24
  follow?: boolean;
25
+ /** 말풍선을 띄우지 않는다 */
16
26
  disabled?: boolean;
17
27
  }
18
28
  declare const Tooltip: React.FC<TooltipProps>;
@@ -36,10 +36,12 @@ var Tooltip = (props) => {
36
36
  children,
37
37
  title,
38
38
  description,
39
- type = "dark",
39
+ variant,
40
+ type,
40
41
  follow = false,
41
42
  disabled = false
42
43
  } = props;
44
+ const shape = variant ?? type ?? "dark";
43
45
  const triggerRef = React.useRef(null);
44
46
  const tooltipRef = React.useRef(null);
45
47
  const [visible, setVisible] = React.useState(false);
@@ -149,7 +151,7 @@ var Tooltip = (props) => {
149
151
  {
150
152
  ref: tooltipRef,
151
153
  role: "tooltip",
152
- className: clsx_default("lib-xplat-tooltip", type),
154
+ className: clsx_default("lib-xplat-tooltip", shape),
153
155
  style: { position: "fixed", left: pos.left, top: pos.top },
154
156
  children: [
155
157
  title && /* @__PURE__ */ jsx("div", { className: "tooltip-title", children: title }),