@loword/loword-design-system 0.0.1

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 (246) hide show
  1. package/README.md +20 -0
  2. package/dist/components/Avatar/Avatar.d.ts +11 -0
  3. package/dist/components/Avatar/Avatar.d.ts.map +1 -0
  4. package/dist/components/Avatar/Avatar.js +24 -0
  5. package/dist/components/Avatar/AvatarBase.d.ts +32 -0
  6. package/dist/components/Avatar/AvatarBase.d.ts.map +1 -0
  7. package/dist/components/Avatar/AvatarBase.js +49 -0
  8. package/dist/components/Badge/Badge.d.ts +25 -0
  9. package/dist/components/Badge/Badge.d.ts.map +1 -0
  10. package/dist/components/Badge/Badge.js +36 -0
  11. package/dist/components/Badge/BadgeBase.d.ts +10 -0
  12. package/dist/components/Badge/BadgeBase.d.ts.map +1 -0
  13. package/dist/components/Badge/BadgeBase.js +9 -0
  14. package/dist/components/Button/Button.d.ts +26 -0
  15. package/dist/components/Button/Button.d.ts.map +1 -0
  16. package/dist/components/Button/Button.js +102 -0
  17. package/dist/components/Button/ButtonBase.d.ts +5 -0
  18. package/dist/components/Button/ButtonBase.d.ts.map +1 -0
  19. package/dist/components/Button/ButtonBase.js +10 -0
  20. package/dist/components/Button/ButtonSpinner.d.ts +9 -0
  21. package/dist/components/Button/ButtonSpinner.d.ts.map +1 -0
  22. package/dist/components/Button/ButtonSpinner.js +14 -0
  23. package/dist/components/Calendar/Calendar.d.ts +16 -0
  24. package/dist/components/Calendar/Calendar.d.ts.map +1 -0
  25. package/dist/components/Calendar/Calendar.js +75 -0
  26. package/dist/components/Carousel/Carousel.d.ts +50 -0
  27. package/dist/components/Carousel/Carousel.d.ts.map +1 -0
  28. package/dist/components/Carousel/Carousel.js +22 -0
  29. package/dist/components/Carousel/CarouselBase.d.ts +98 -0
  30. package/dist/components/Carousel/CarouselBase.d.ts.map +1 -0
  31. package/dist/components/Carousel/CarouselBase.js +144 -0
  32. package/dist/components/Checkbox/Checkbox.d.ts +27 -0
  33. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
  34. package/dist/components/Checkbox/Checkbox.js +30 -0
  35. package/dist/components/Checkbox/CheckboxBase.d.ts +40 -0
  36. package/dist/components/Checkbox/CheckboxBase.d.ts.map +1 -0
  37. package/dist/components/Checkbox/CheckboxBase.js +57 -0
  38. package/dist/components/Checkbox/CheckboxGroup.d.ts +22 -0
  39. package/dist/components/Checkbox/CheckboxGroup.d.ts.map +1 -0
  40. package/dist/components/Checkbox/CheckboxGroup.js +13 -0
  41. package/dist/components/Checkbox/FormCheckbox.d.ts +14 -0
  42. package/dist/components/Checkbox/FormCheckbox.d.ts.map +1 -0
  43. package/dist/components/Checkbox/FormCheckbox.js +9 -0
  44. package/dist/components/Checkbox/FormCheckboxGroup.d.ts +13 -0
  45. package/dist/components/Checkbox/FormCheckboxGroup.d.ts.map +1 -0
  46. package/dist/components/Checkbox/FormCheckboxGroup.js +9 -0
  47. package/dist/components/DataCalendar/DataCalendar.d.ts +12 -0
  48. package/dist/components/DataCalendar/DataCalendar.d.ts.map +1 -0
  49. package/dist/components/DataCalendar/DataCalendar.js +13 -0
  50. package/dist/components/DataCalendar/DataCalendarBase.d.ts +45 -0
  51. package/dist/components/DataCalendar/DataCalendarBase.d.ts.map +1 -0
  52. package/dist/components/DataCalendar/DataCalendarBase.js +57 -0
  53. package/dist/components/DatePicker/DatePicker.d.ts +34 -0
  54. package/dist/components/DatePicker/DatePicker.d.ts.map +1 -0
  55. package/dist/components/DatePicker/DatePicker.js +44 -0
  56. package/dist/components/DatePicker/FormDatePicker.d.ts +12 -0
  57. package/dist/components/DatePicker/FormDatePicker.d.ts.map +1 -0
  58. package/dist/components/DatePicker/FormDatePicker.js +12 -0
  59. package/dist/components/DateRangePicker/DateRangePicker.d.ts +49 -0
  60. package/dist/components/DateRangePicker/DateRangePicker.d.ts.map +1 -0
  61. package/dist/components/DateRangePicker/DateRangePicker.js +197 -0
  62. package/dist/components/DateRangePicker/FormDateRangePicker.d.ts +12 -0
  63. package/dist/components/DateRangePicker/FormDateRangePicker.d.ts.map +1 -0
  64. package/dist/components/DateRangePicker/FormDateRangePicker.js +10 -0
  65. package/dist/components/Drawer/Drawer.d.ts +51 -0
  66. package/dist/components/Drawer/Drawer.d.ts.map +1 -0
  67. package/dist/components/Drawer/Drawer.js +30 -0
  68. package/dist/components/Drawer/DrawerBase.d.ts +52 -0
  69. package/dist/components/Drawer/DrawerBase.d.ts.map +1 -0
  70. package/dist/components/Drawer/DrawerBase.js +38 -0
  71. package/dist/components/Editor/Editor.d.ts +12 -0
  72. package/dist/components/Editor/Editor.d.ts.map +1 -0
  73. package/dist/components/Editor/Editor.js +162 -0
  74. package/dist/components/Editor/EditorBase.d.ts +52 -0
  75. package/dist/components/Editor/EditorBase.d.ts.map +1 -0
  76. package/dist/components/Editor/EditorBase.js +89 -0
  77. package/dist/components/Editor/Viewer.d.ts +7 -0
  78. package/dist/components/Editor/Viewer.d.ts.map +1 -0
  79. package/dist/components/Editor/Viewer.js +9 -0
  80. package/dist/components/Editor/extensions.d.ts +6 -0
  81. package/dist/components/Editor/extensions.d.ts.map +1 -0
  82. package/dist/components/Editor/extensions.js +38 -0
  83. package/dist/components/FileUpload/FileUploadBase.d.ts +50 -0
  84. package/dist/components/FileUpload/FileUploadBase.d.ts.map +1 -0
  85. package/dist/components/FileUpload/FileUploadBase.js +102 -0
  86. package/dist/components/Form/Form.d.ts +21 -0
  87. package/dist/components/Form/Form.d.ts.map +1 -0
  88. package/dist/components/Form/Form.js +18 -0
  89. package/dist/components/Form/FormErrorMessage.d.ts +9 -0
  90. package/dist/components/Form/FormErrorMessage.d.ts.map +1 -0
  91. package/dist/components/Form/FormErrorMessage.js +6 -0
  92. package/dist/components/Form/FormField.d.ts +55 -0
  93. package/dist/components/Form/FormField.d.ts.map +1 -0
  94. package/dist/components/Form/FormField.js +43 -0
  95. package/dist/components/Icon/LucideIcon.d.ts +11 -0
  96. package/dist/components/Icon/LucideIcon.d.ts.map +1 -0
  97. package/dist/components/Icon/LucideIcon.js +41 -0
  98. package/dist/components/Input/FormInput.d.ts +15 -0
  99. package/dist/components/Input/FormInput.d.ts.map +1 -0
  100. package/dist/components/Input/FormInput.js +19 -0
  101. package/dist/components/Input/Input.d.ts +24 -0
  102. package/dist/components/Input/Input.d.ts.map +1 -0
  103. package/dist/components/Input/Input.js +71 -0
  104. package/dist/components/Input/InputBase.d.ts +22 -0
  105. package/dist/components/Input/InputBase.d.ts.map +1 -0
  106. package/dist/components/Input/InputBase.js +17 -0
  107. package/dist/components/LNB/LNBBase.d.ts +82 -0
  108. package/dist/components/LNB/LNBBase.d.ts.map +1 -0
  109. package/dist/components/LNB/LNBBase.js +108 -0
  110. package/dist/components/LoadingDots/LoadingDots.d.ts +8 -0
  111. package/dist/components/LoadingDots/LoadingDots.d.ts.map +1 -0
  112. package/dist/components/LoadingDots/LoadingDots.js +29 -0
  113. package/dist/components/MenuBar/MenuBar.d.ts +21 -0
  114. package/dist/components/MenuBar/MenuBar.d.ts.map +1 -0
  115. package/dist/components/MenuBar/MenuBar.js +33 -0
  116. package/dist/components/MenuBar/MenuBarBase.d.ts +43 -0
  117. package/dist/components/MenuBar/MenuBarBase.d.ts.map +1 -0
  118. package/dist/components/MenuBar/MenuBarBase.js +69 -0
  119. package/dist/components/Modal/Modal.d.ts +51 -0
  120. package/dist/components/Modal/Modal.d.ts.map +1 -0
  121. package/dist/components/Modal/Modal.js +72 -0
  122. package/dist/components/Modal/ModalBase.d.ts +42 -0
  123. package/dist/components/Modal/ModalBase.d.ts.map +1 -0
  124. package/dist/components/Modal/ModalBase.js +30 -0
  125. package/dist/components/Modal/openModal.d.ts +24 -0
  126. package/dist/components/Modal/openModal.d.ts.map +1 -0
  127. package/dist/components/Modal/openModal.js +52 -0
  128. package/dist/components/OTPInput/OTPInput.d.ts +46 -0
  129. package/dist/components/OTPInput/OTPInput.d.ts.map +1 -0
  130. package/dist/components/OTPInput/OTPInput.js +87 -0
  131. package/dist/components/Pagination/Pagination.d.ts +12 -0
  132. package/dist/components/Pagination/Pagination.d.ts.map +1 -0
  133. package/dist/components/Pagination/Pagination.js +5 -0
  134. package/dist/components/Pagination/PaginationBase.d.ts +36 -0
  135. package/dist/components/Pagination/PaginationBase.d.ts.map +1 -0
  136. package/dist/components/Pagination/PaginationBase.js +44 -0
  137. package/dist/components/Pagination/paginationUtils.d.ts +2 -0
  138. package/dist/components/Pagination/paginationUtils.d.ts.map +1 -0
  139. package/dist/components/Pagination/paginationUtils.js +18 -0
  140. package/dist/components/Popover/Popover.d.ts +42 -0
  141. package/dist/components/Popover/Popover.d.ts.map +1 -0
  142. package/dist/components/Popover/Popover.js +31 -0
  143. package/dist/components/Popover/PopoverBase.d.ts +31 -0
  144. package/dist/components/Popover/PopoverBase.d.ts.map +1 -0
  145. package/dist/components/Popover/PopoverBase.js +18 -0
  146. package/dist/components/Radio/FormRadioGroup.d.ts +13 -0
  147. package/dist/components/Radio/FormRadioGroup.d.ts.map +1 -0
  148. package/dist/components/Radio/FormRadioGroup.js +9 -0
  149. package/dist/components/Radio/Radio.d.ts +24 -0
  150. package/dist/components/Radio/Radio.d.ts.map +1 -0
  151. package/dist/components/Radio/Radio.js +39 -0
  152. package/dist/components/Radio/RadioBase.d.ts +38 -0
  153. package/dist/components/Radio/RadioBase.d.ts.map +1 -0
  154. package/dist/components/Radio/RadioBase.js +46 -0
  155. package/dist/components/Radio/RadioGroup.d.ts +22 -0
  156. package/dist/components/Radio/RadioGroup.d.ts.map +1 -0
  157. package/dist/components/Radio/RadioGroup.js +7 -0
  158. package/dist/components/ScrollArea/ScrollArea.d.ts +15 -0
  159. package/dist/components/ScrollArea/ScrollArea.d.ts.map +1 -0
  160. package/dist/components/ScrollArea/ScrollArea.js +10 -0
  161. package/dist/components/Select/FormMultiSelect.d.ts +13 -0
  162. package/dist/components/Select/FormMultiSelect.d.ts.map +1 -0
  163. package/dist/components/Select/FormMultiSelect.js +14 -0
  164. package/dist/components/Select/FormSelect.d.ts +13 -0
  165. package/dist/components/Select/FormSelect.d.ts.map +1 -0
  166. package/dist/components/Select/FormSelect.js +10 -0
  167. package/dist/components/Select/MultiSelect.d.ts +31 -0
  168. package/dist/components/Select/MultiSelect.d.ts.map +1 -0
  169. package/dist/components/Select/MultiSelect.js +59 -0
  170. package/dist/components/Select/Select.d.ts +41 -0
  171. package/dist/components/Select/Select.d.ts.map +1 -0
  172. package/dist/components/Select/Select.js +55 -0
  173. package/dist/components/Select/SelectBase.d.ts +59 -0
  174. package/dist/components/Select/SelectBase.d.ts.map +1 -0
  175. package/dist/components/Select/SelectBase.js +211 -0
  176. package/dist/components/Skeleton/Skeleton.d.ts +10 -0
  177. package/dist/components/Skeleton/Skeleton.d.ts.map +1 -0
  178. package/dist/components/Skeleton/Skeleton.js +8 -0
  179. package/dist/components/Slider/Slider.d.ts +23 -0
  180. package/dist/components/Slider/Slider.d.ts.map +1 -0
  181. package/dist/components/Slider/Slider.js +195 -0
  182. package/dist/components/Spinner/Spinner.d.ts +25 -0
  183. package/dist/components/Spinner/Spinner.d.ts.map +1 -0
  184. package/dist/components/Spinner/Spinner.js +20 -0
  185. package/dist/components/Table/Table.d.ts +34 -0
  186. package/dist/components/Table/Table.d.ts.map +1 -0
  187. package/dist/components/Table/Table.js +29 -0
  188. package/dist/components/Table/TableBase.d.ts +37 -0
  189. package/dist/components/Table/TableBase.d.ts.map +1 -0
  190. package/dist/components/Table/TableBase.js +39 -0
  191. package/dist/components/Table/TableField.d.ts +64 -0
  192. package/dist/components/Table/TableField.d.ts.map +1 -0
  193. package/dist/components/Table/TableField.js +87 -0
  194. package/dist/components/Table/TanstackTable.d.ts +23 -0
  195. package/dist/components/Table/TanstackTable.d.ts.map +1 -0
  196. package/dist/components/Table/TanstackTable.js +35 -0
  197. package/dist/components/TimePicker/FormTimePicker.d.ts +12 -0
  198. package/dist/components/TimePicker/FormTimePicker.d.ts.map +1 -0
  199. package/dist/components/TimePicker/FormTimePicker.js +12 -0
  200. package/dist/components/TimePicker/TimePicker.d.ts +27 -0
  201. package/dist/components/TimePicker/TimePicker.d.ts.map +1 -0
  202. package/dist/components/TimePicker/TimePicker.js +120 -0
  203. package/dist/components/Toast/Toast.d.ts +18 -0
  204. package/dist/components/Toast/Toast.d.ts.map +1 -0
  205. package/dist/components/Toast/Toast.js +42 -0
  206. package/dist/components/Toast/Toaster.d.ts +7 -0
  207. package/dist/components/Toast/Toaster.d.ts.map +1 -0
  208. package/dist/components/Toast/Toaster.js +7 -0
  209. package/dist/components/ToggleButton/FormToggleButton.d.ts +12 -0
  210. package/dist/components/ToggleButton/FormToggleButton.d.ts.map +1 -0
  211. package/dist/components/ToggleButton/FormToggleButton.js +9 -0
  212. package/dist/components/ToggleButton/ToggleButton.d.ts +31 -0
  213. package/dist/components/ToggleButton/ToggleButton.d.ts.map +1 -0
  214. package/dist/components/ToggleButton/ToggleButton.js +42 -0
  215. package/dist/components/ToggleButton/ToggleButtonBase.d.ts +41 -0
  216. package/dist/components/ToggleButton/ToggleButtonBase.d.ts.map +1 -0
  217. package/dist/components/ToggleButton/ToggleButtonBase.js +59 -0
  218. package/dist/components/Tooltip/Tooltip.d.ts +18 -0
  219. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -0
  220. package/dist/components/Tooltip/Tooltip.js +13 -0
  221. package/dist/components/Tooltip/TooltipBase.d.ts +39 -0
  222. package/dist/components/Tooltip/TooltipBase.d.ts.map +1 -0
  223. package/dist/components/Tooltip/TooltipBase.js +46 -0
  224. package/dist/constants/file.d.ts +42 -0
  225. package/dist/constants/file.d.ts.map +1 -0
  226. package/dist/constants/file.js +47 -0
  227. package/dist/index.css +4061 -0
  228. package/dist/index.d.ts +54 -0
  229. package/dist/index.d.ts.map +1 -0
  230. package/dist/index.js +88 -0
  231. package/dist/types/polymorphic.d.ts +19 -0
  232. package/dist/types/polymorphic.d.ts.map +1 -0
  233. package/dist/types/polymorphic.js +1 -0
  234. package/dist/utils/cn.d.ts +4 -0
  235. package/dist/utils/cn.d.ts.map +1 -0
  236. package/dist/utils/cn.js +6 -0
  237. package/dist/utils/file.d.ts +16 -0
  238. package/dist/utils/file.d.ts.map +1 -0
  239. package/dist/utils/file.js +58 -0
  240. package/dist/utils/renderIcon.d.ts +4 -0
  241. package/dist/utils/renderIcon.d.ts.map +1 -0
  242. package/dist/utils/renderIcon.js +11 -0
  243. package/dist/utils/utils.d.ts +2 -0
  244. package/dist/utils/utils.d.ts.map +1 -0
  245. package/dist/utils/utils.js +5 -0
  246. package/package.json +239 -0
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import TimePicker from './TimePicker.js';
4
+ import FormField from '../Form/FormField.js';
5
+ import FormErrorMessage from '../Form/FormErrorMessage.js';
6
+ import cn from '../../utils/cn.js';
7
+ const FormTimePicker = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = false, errorClassName, disabled = false, block = false, ...props }) => {
8
+ return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, children: ({ field, fieldState }) => (_jsxs("div", { className: cn('relative border-2 border-transparent', block ? 'w-full' : 'w-auto'), children: [_jsx(TimePicker, { ...props, block: block, value: field.value ?? '', onChange: (time) => {
9
+ field.onChange(time);
10
+ }, disabled: disabled, color: fieldState.hasError ? 'danger' : 'neutral' }), !isHiddenErrorMessage && (_jsx(FormErrorMessage, { error: fieldState.error, disabled: disabled, className: errorClassName }))] })) }));
11
+ };
12
+ export default FormTimePicker;
@@ -0,0 +1,27 @@
1
+ export interface TimePickerProps {
2
+ /** 선택된 시간 (HH:MM 형식) */
3
+ value?: string;
4
+ /** 초기 선택 시간 (uncontrolled) */
5
+ defaultValue?: string;
6
+ /** 시간 변경 시 호출되는 콜백 */
7
+ onChange?: (value: string) => void;
8
+ /** 미선택 시 표시할 텍스트 */
9
+ placeholder?: string;
10
+ /** 비활성화 여부 */
11
+ disabled?: boolean;
12
+ /** true 시 너비 100% */
13
+ block?: boolean;
14
+ /** 색상 테마 (danger 시 에러 스타일) */
15
+ color?: 'neutral' | 'danger';
16
+ /** 최소 선택 가능 시간 (HH:MM 형식, 이전 시간 비활성화) */
17
+ minTime?: string;
18
+ /** 추가 CSS 클래스 */
19
+ className?: string;
20
+ /** 인라인 스타일 (트리거 버튼에 적용) */
21
+ style?: React.CSSProperties;
22
+ /** 트리거 버튼 className */
23
+ triggerClassName?: string;
24
+ }
25
+ declare const TimePicker: ({ value, defaultValue, onChange, placeholder, disabled, block, color, minTime, className, style, triggerClassName, }: TimePickerProps) => import("react/jsx-runtime").JSX.Element;
26
+ export default TimePicker;
27
+ //# sourceMappingURL=TimePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimePicker.d.ts","sourceRoot":"","sources":["../../../src/components/TimePicker/TimePicker.tsx"],"names":[],"mappings":"AAsCA,MAAM,WAAW,eAAe;IAC9B,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,uBAAuB;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,QAAA,MAAM,UAAU,GAAI,sHAYjB,eAAe,4CA4KjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -0,0 +1,120 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMemo, useState, useRef } from 'react';
4
+ import PopoverBase from '../Popover/PopoverBase.js';
5
+ import LucideIcon from '../Icon/LucideIcon.js';
6
+ import cn from '../../utils/cn.js';
7
+ /** 시간 입력 자동 포맷팅 (1212 -> 12:12) */
8
+ const formatTimeInput = (value) => {
9
+ const numbers = value.replace(/\D/g, '');
10
+ if (!numbers)
11
+ return '';
12
+ const limitedNumbers = numbers.slice(0, 4);
13
+ if (limitedNumbers.length <= 2)
14
+ return limitedNumbers;
15
+ const hours = limitedNumbers.slice(0, 2);
16
+ const minutes = limitedNumbers.slice(2);
17
+ const hoursNum = parseInt(hours, 10);
18
+ if (hoursNum > 23)
19
+ return hours.slice(0, 1);
20
+ if (minutes) {
21
+ const minutesNum = parseInt(minutes, 10);
22
+ if (minutesNum > 59)
23
+ return `${hours}:${minutes.slice(0, 1)}`;
24
+ }
25
+ return `${hours}:${minutes}`;
26
+ };
27
+ // ── 시간 옵션 생성 (00:00 ~ 23:30, 30분 간격) ──
28
+ const generateTimeOptions = (minTime) => {
29
+ const options = [];
30
+ for (let hour = 0; hour < 24; hour++) {
31
+ for (let minute = 0; minute < 60; minute += 30) {
32
+ const timeString = `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`;
33
+ if (minTime && timeString < minTime)
34
+ continue;
35
+ options.push(timeString);
36
+ }
37
+ }
38
+ return options;
39
+ };
40
+ const TimePicker = ({ value, defaultValue, onChange, placeholder = 'HH:MM', disabled = false, block = false, color = 'neutral', minTime, className, style, triggerClassName, }) => {
41
+ const [open, setOpen] = useState(false);
42
+ const [internal, setInternal] = useState(defaultValue);
43
+ const [isEditable, setIsEditable] = useState(false);
44
+ const inputRef = useRef(null);
45
+ const isControlled = value !== undefined;
46
+ const resolved = isControlled ? value : internal;
47
+ const timeOptions = useMemo(() => generateTimeOptions(minTime), [minTime]);
48
+ const handleTimeSelect = (time) => {
49
+ if (!isControlled)
50
+ setInternal(time);
51
+ onChange?.(time);
52
+ setOpen(false);
53
+ };
54
+ const handleInputChange = (e) => {
55
+ const formatted = formatTimeInput(e.target.value);
56
+ if (!isControlled)
57
+ setInternal(formatted);
58
+ onChange?.(formatted);
59
+ };
60
+ const handlePencilClick = (e) => {
61
+ e.stopPropagation();
62
+ e.preventDefault();
63
+ if (isEditable) {
64
+ setIsEditable(false);
65
+ inputRef.current?.blur();
66
+ }
67
+ else {
68
+ setIsEditable(true);
69
+ setTimeout(() => {
70
+ inputRef.current?.focus();
71
+ }, 0);
72
+ }
73
+ };
74
+ const handleInputBlur = (e) => {
75
+ const relatedTarget = e.relatedTarget;
76
+ if (relatedTarget?.closest('[data-pencil-button]'))
77
+ return;
78
+ setIsEditable(false);
79
+ };
80
+ return (_jsx("div", { className: cn(block ? 'w-full' : 'w-auto', className), children: _jsxs(PopoverBase.Root, { open: open, onOpenChange: setOpen, children: [_jsxs(PopoverBase.Trigger, { disabled: disabled, style: style, onClick: (e) => {
81
+ if (isEditable)
82
+ e.preventDefault();
83
+ }, className: cn('border border-neutral10 h-[38px] w-full display14 px-4 rounded-[5px]', 'flex flex-row items-center justify-between gap-4', 'outline-2 outline-transparent ld-transition', disabled && 'cursor-not-allowed opacity-50', color === 'danger'
84
+ ? 'bg-tintRed outline-red500'
85
+ : 'focus:bg-tintBlue focus:outline-lb500', triggerClassName), children: [_jsx("input", { ref: inputRef, type: "text", value: resolved ?? '', onChange: handleInputChange, onBlur: handleInputBlur, onKeyDown: (e) => {
86
+ if (e.key === 'ArrowDown') {
87
+ e.preventDefault();
88
+ setOpen(true);
89
+ }
90
+ }, placeholder: placeholder, "aria-label": "\uC2DC\uAC04 \uC785\uB825", disabled: disabled, readOnly: !isEditable, className: cn('flex-1 bg-transparent outline-none min-w-0', !resolved && 'text-neutral40', !isEditable && 'cursor-pointer') }), _jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [_jsx("span", { "data-pencil-button": true, role: "button", tabIndex: 0, "aria-label": "\uC9C1\uC811 \uC785\uB825 \uBAA8\uB4DC \uC804\uD658", onClick: handlePencilClick, onKeyDown: (e) => {
91
+ if (e.key === 'Enter' || e.key === ' ') {
92
+ e.preventDefault();
93
+ handlePencilClick(e);
94
+ }
95
+ }, className: cn('p-0 transition-colors cursor-pointer', isEditable ? 'text-lb500' : 'text-neutral40'), children: _jsx(LucideIcon, { name: "pencil", size: 15 }) }), _jsx(LucideIcon, { name: "clock", size: 15, className: "text-neutral40" })] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white shadow-md p-0", style: { width: 'var(--radix-popover-trigger-width)' }, onOpenAutoFocus: (e) => {
96
+ e.preventDefault();
97
+ const targetTime = timeOptions.find((t) => t >= (resolved || '00:00')) ||
98
+ timeOptions[0];
99
+ setTimeout(() => {
100
+ const targetButton = document.querySelector(`[data-time-picker-list] button[data-time="${targetTime}"]`);
101
+ if (targetButton) {
102
+ targetButton.focus();
103
+ targetButton.scrollIntoView({ block: 'nearest' });
104
+ }
105
+ }, 0);
106
+ }, children: _jsx("div", { "data-time-picker-list": true, role: "listbox", "aria-label": "\uC2DC\uAC04 \uC120\uD0DD \uBAA9\uB85D", className: "max-h-[240px] overflow-y-auto scrollbar-hide p-2", children: timeOptions.map((time) => (_jsx("button", { "data-time": time, type: "button", role: "option", "aria-selected": resolved === time, "aria-label": `${time.split(':')[0]}시 ${time.split(':')[1]}분`, onClick: () => handleTimeSelect(time), onKeyDown: (e) => {
107
+ const target = e.currentTarget;
108
+ if (e.key === 'ArrowDown') {
109
+ e.preventDefault();
110
+ target.nextElementSibling?.focus();
111
+ }
112
+ else if (e.key === 'ArrowUp') {
113
+ e.preventDefault();
114
+ target.previousElementSibling?.focus();
115
+ }
116
+ }, className: cn('w-full text-left px-3 py-2 rounded-[5px] display14 transition-all cursor-pointer outline-none', 'hover:bg-lb50 hover:text-lb500', 'focus:bg-lb50 focus:text-lb500 focus:ring-1 focus:ring-inset focus:ring-lb500', resolved === time
117
+ ? 'bg-neutral10 font-bold'
118
+ : 'text-neutral800'), children: time }, time))) }) })] }) }));
119
+ };
120
+ export default TimePicker;
@@ -0,0 +1,18 @@
1
+ export declare const Toast: {
2
+ /** 성공 메시지를 표시합니다 */
3
+ success: (content: string) => string;
4
+ /** 에러 메시지를 표시합니다 */
5
+ error: (content: string) => string;
6
+ /** 일반 알림 메시지를 표시합니다 */
7
+ info: (content: string) => string;
8
+ /** 경고 메시지를 표시합니다 */
9
+ warning: (content: string) => string;
10
+ /** 로딩 상태 메시지를 표시합니다 */
11
+ loading: (content: string) => string;
12
+ /** 현재 표시 중인 토스트를 모두 닫습니다 */
13
+ dismiss: () => void;
14
+ /** 인사 메시지를 표시합니다 */
15
+ hello: (content: string) => string;
16
+ };
17
+ export default Toast;
18
+ //# sourceMappingURL=Toast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toast.d.ts","sourceRoot":"","sources":["../../../src/components/Toast/Toast.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,KAAK;IAChB,oBAAoB;uBACD,MAAM;IAIzB,oBAAoB;qBACH,MAAM;IAIvB,uBAAuB;oBACP,MAAM;IAItB,oBAAoB;uBACD,MAAM;IAUzB,uBAAuB;uBACJ,MAAM;IAIzB,4BAA4B;;IAE5B,oBAAoB;qBACH,MAAM;CAMxB,CAAC;AAEF,eAAe,KAAK,CAAC"}
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import toast from 'react-hot-toast';
4
+ export const Toast = {
5
+ /** 성공 메시지를 표시합니다 */
6
+ success: (content) => {
7
+ toast.dismiss();
8
+ return toast.success(content);
9
+ },
10
+ /** 에러 메시지를 표시합니다 */
11
+ error: (content) => {
12
+ toast.dismiss();
13
+ return toast.error(content);
14
+ },
15
+ /** 일반 알림 메시지를 표시합니다 */
16
+ info: (content) => {
17
+ toast.dismiss();
18
+ return toast(content);
19
+ },
20
+ /** 경고 메시지를 표시합니다 */
21
+ warning: (content) => {
22
+ toast.dismiss();
23
+ return toast(content, {
24
+ icon: (_jsx("div", { className: "flex justify-center items-center w-5 h-5 bg-yellow-400 rounded-full text-mono5", children: "!" })),
25
+ });
26
+ },
27
+ /** 로딩 상태 메시지를 표시합니다 */
28
+ loading: (content) => {
29
+ toast.dismiss();
30
+ return toast.loading(content);
31
+ },
32
+ /** 현재 표시 중인 토스트를 모두 닫습니다 */
33
+ dismiss: () => toast.dismiss(),
34
+ /** 인사 메시지를 표시합니다 */
35
+ hello: (content) => {
36
+ toast.dismiss();
37
+ return toast(content, {
38
+ icon: _jsx("div", { className: "flex justify-center items-center w-5 h-5", children: "\uD83D\uDC4B" }),
39
+ });
40
+ },
41
+ };
42
+ export default Toast;
@@ -0,0 +1,7 @@
1
+ interface ToasterProps {
2
+ position?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
3
+ duration?: number;
4
+ }
5
+ declare const Toaster: ({ position, duration, }: ToasterProps) => import("react/jsx-runtime").JSX.Element;
6
+ export default Toaster;
7
+ //# sourceMappingURL=Toaster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toaster.d.ts","sourceRoot":"","sources":["../../../src/components/Toast/Toaster.tsx"],"names":[],"mappings":"AAIA,UAAU,YAAY;IACpB,QAAQ,CAAC,EACL,UAAU,GACV,YAAY,GACZ,WAAW,GACX,aAAa,GACb,eAAe,GACf,cAAc,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,QAAA,MAAM,OAAO,GAAI,yBAGd,YAAY,4CAEd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Toaster as HotToaster } from 'react-hot-toast';
4
+ const Toaster = ({ position = 'top-center', duration = 2500, }) => {
5
+ return _jsx(HotToaster, { position: position, toastOptions: { duration } });
6
+ };
7
+ export default Toaster;
@@ -0,0 +1,12 @@
1
+ import { type RegisterOptions } from 'react-hook-form';
2
+ import { type ToggleButtonProps } from './ToggleButton.js';
3
+ interface FormToggleButtonProps extends Omit<ToggleButtonProps, 'checked' | 'name' | 'onCheckedChange'> {
4
+ name: string;
5
+ options?: RegisterOptions;
6
+ customErrorMessage?: string;
7
+ isHiddenErrorMessage?: boolean;
8
+ errorClassName?: string;
9
+ }
10
+ declare const FormToggleButton: ({ name, options, customErrorMessage, isHiddenErrorMessage, errorClassName, disabled, ...props }: FormToggleButtonProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default FormToggleButton;
12
+ //# sourceMappingURL=FormToggleButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormToggleButton.d.ts","sourceRoot":"","sources":["../../../src/components/ToggleButton/FormToggleButton.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAItE,UAAU,qBAAsB,SAAQ,IAAI,CAC1C,iBAAiB,EACjB,SAAS,GAAG,MAAM,GAAG,iBAAiB,CACvC;IACC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,QAAA,MAAM,gBAAgB,GAAI,iGAQvB,qBAAqB,4CAgCvB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import ToggleButton from './ToggleButton.js';
4
+ import FormField from '../Form/FormField.js';
5
+ import FormErrorMessage from '../Form/FormErrorMessage.js';
6
+ const FormToggleButton = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = false, errorClassName, disabled = false, ...props }) => {
7
+ return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, children: ({ field, fieldState }) => (_jsxs("div", { className: "relative", children: [_jsx(ToggleButton, { ...props, checked: !!field.value, onCheckedChange: field.onChange, onBlur: field.onBlur, disabled: disabled, ref: field.ref, "aria-invalid": field['aria-invalid'], "aria-describedby": field['aria-describedby'] }), !isHiddenErrorMessage && (_jsx(FormErrorMessage, { id: fieldState.errorId, error: fieldState.error, disabled: disabled, className: errorClassName }))] })) }));
8
+ };
9
+ export default FormToggleButton;
@@ -0,0 +1,31 @@
1
+ import { type Ref } from 'react';
2
+ type ButtonSize = 'small' | 'medium' | 'large' | 'xlarge';
3
+ export interface ToggleButtonProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
4
+ /** controlled 체크 상태 */
5
+ checked?: boolean;
6
+ /** 초기 체크 상태 (uncontrolled) */
7
+ defaultChecked?: boolean;
8
+ /** 체크 상태 변경 콜백 */
9
+ onCheckedChange?: (checked: boolean) => void;
10
+ /** 비활성화 여부 */
11
+ disabled?: boolean;
12
+ /** 크기 */
13
+ size?: ButtonSize;
14
+ /** input name */
15
+ name?: string;
16
+ /** input value */
17
+ value?: string;
18
+ /** input id */
19
+ id?: string;
20
+ /** 토글 옆에 표시할 라벨 텍스트 */
21
+ label?: string;
22
+ /** 추가 CSS 클래스 */
23
+ className?: string;
24
+ /** 인라인 스타일 */
25
+ style?: React.CSSProperties;
26
+ /** input 요소 ref */
27
+ ref?: Ref<HTMLInputElement>;
28
+ }
29
+ declare const ToggleButton: ({ checked, defaultChecked, onCheckedChange, disabled, size, label, className, style, ref, name, id, value, ...props }: ToggleButtonProps) => import("react/jsx-runtime").JSX.Element;
30
+ export default ToggleButton;
31
+ //# sourceMappingURL=ToggleButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleButton.d.ts","sourceRoot":"","sources":["../../../src/components/ToggleButton/ToggleButton.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAKjC,KAAK,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAsC1D,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAC3C,MAAM,CACP;IACC,uBAAuB;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8BAA8B;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kBAAkB;IAClB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,cAAc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS;IACT,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,iBAAiB;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uBAAuB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc;IACd,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,mBAAmB;IACnB,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAmDD,QAAA,MAAM,YAAY,GAAI,uHAcnB,iBAAiB,4CAqBnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import ToggleButtonBase, { useToggleButtonContext } from './ToggleButtonBase.js';
3
+ import cn from '../../utils/cn.js';
4
+ const trackClass = {
5
+ small: 'toggle-track-sm',
6
+ medium: 'toggle-track-md',
7
+ large: 'toggle-track-lg',
8
+ xlarge: 'toggle-track-xl',
9
+ };
10
+ const thumbClass = {
11
+ small: 'toggle-thumb-sm',
12
+ medium: 'toggle-thumb-md',
13
+ large: 'toggle-thumb-lg',
14
+ xlarge: 'toggle-thumb-xl',
15
+ };
16
+ const thumbOffClass = {
17
+ small: 'toggle-thumb-off-sm',
18
+ medium: 'toggle-thumb-off-md',
19
+ large: 'toggle-thumb-off-lg',
20
+ xlarge: 'toggle-thumb-off-xl',
21
+ };
22
+ const thumbOnClass = {
23
+ small: 'toggle-thumb-on-sm',
24
+ medium: 'toggle-thumb-on-md',
25
+ large: 'toggle-thumb-on-lg',
26
+ xlarge: 'toggle-thumb-on-xl',
27
+ };
28
+ const rootClass = {
29
+ small: 'toggle-sm',
30
+ medium: 'toggle-md',
31
+ large: 'toggle-lg',
32
+ xlarge: 'toggle-xl',
33
+ };
34
+ // ── Inner: Context에서 checked/disabled 읽어 스타일 적용 ──
35
+ const ToggleInner = ({ label, ref, name, id, value, size, ...props }) => {
36
+ const { checked, disabled } = useToggleButtonContext();
37
+ return (_jsxs(_Fragment, { children: [_jsx(ToggleButtonBase.HiddenInput, { ref: ref, name: name, id: id, value: value, ...props }), _jsx(ToggleButtonBase.Track, { className: cn(trackClass[size], checked ? 'bg-lb500' : 'bg-mono300', disabled ? 'opacity-50' : 'cursor-pointer', 'peer-focus-visible:ring-2 peer-focus-visible:ring-lb500 peer-focus-visible:ring-offset-2'), children: _jsx(ToggleButtonBase.Thumb, { className: cn(thumbClass[size], 'bg-white ld-transition', checked ? thumbOnClass[size] : thumbOffClass[size]) }) }), label && (_jsx(ToggleButtonBase.Label, { className: "select-none", children: label }))] }));
38
+ };
39
+ const ToggleButton = ({ checked, defaultChecked, onCheckedChange, disabled = false, size = 'medium', label, className, style, ref, name, id, value, ...props }) => {
40
+ return (_jsx(ToggleButtonBase.Root, { checked: checked, defaultChecked: defaultChecked, onCheckedChange: onCheckedChange, disabled: disabled, style: style, className: cn(rootClass[size], className), children: _jsx(ToggleInner, { label: label, ref: ref, name: name, value: value, id: id, size: size, ...props }) }));
41
+ };
42
+ export default ToggleButton;
@@ -0,0 +1,41 @@
1
+ import { type ReactNode, type Ref } from 'react';
2
+ interface ToggleButtonContextType {
3
+ checked: boolean;
4
+ onCheckedChange: (checked: boolean) => void;
5
+ disabled: boolean;
6
+ isFocused: boolean;
7
+ setIsFocused: (focused: boolean) => void;
8
+ }
9
+ export declare const useToggleButtonContext: () => ToggleButtonContextType;
10
+ interface RootProps {
11
+ checked?: boolean;
12
+ defaultChecked?: boolean;
13
+ onCheckedChange?: (checked: boolean) => void;
14
+ disabled?: boolean;
15
+ className?: string;
16
+ style?: React.CSSProperties;
17
+ children?: ReactNode;
18
+ }
19
+ interface HiddenInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
20
+ ref?: Ref<HTMLInputElement>;
21
+ }
22
+ interface TrackProps {
23
+ className?: string;
24
+ children?: ReactNode;
25
+ }
26
+ interface ThumbProps {
27
+ className?: string;
28
+ }
29
+ interface LabelProps {
30
+ className?: string;
31
+ children?: ReactNode;
32
+ }
33
+ export declare const ToggleButtonBase: {
34
+ Root: ({ checked, defaultChecked, onCheckedChange, disabled, className, style, children, }: RootProps) => import("react/jsx-runtime").JSX.Element;
35
+ HiddenInput: ({ ref, onFocus, onBlur, onChange, ...props }: HiddenInputProps) => import("react/jsx-runtime").JSX.Element;
36
+ Track: ({ className, children }: TrackProps) => import("react/jsx-runtime").JSX.Element;
37
+ Thumb: ({ className }: ThumbProps) => import("react/jsx-runtime").JSX.Element;
38
+ Label: ({ className, children }: LabelProps) => import("react/jsx-runtime").JSX.Element;
39
+ };
40
+ export default ToggleButtonBase;
41
+ //# sourceMappingURL=ToggleButtonBase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToggleButtonBase.d.ts","sourceRoot":"","sources":["../../../src/components/ToggleButton/ToggleButtonBase.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,GAAG,EAIT,MAAM,OAAO,CAAC;AAIf,UAAU,uBAAuB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAID,eAAO,MAAM,sBAAsB,+BAOlC,CAAC;AAGF,UAAU,SAAS;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA+CD,UAAU,gBAAiB,SAAQ,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC;IAC5E,GAAG,CAAC,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC;CAC7B;AAuCD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAgBD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAcD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD,eAAO,MAAM,gBAAgB;gGA1H1B,SAAS;gEA+CT,gBAAgB;qCAoCqB,UAAU;2BAkBpB,UAAU;qCAiBA,UAAU;CAUjD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useState, } from 'react';
3
+ import cn from '../../utils/cn.js';
4
+ const ToggleButtonContext = createContext(null);
5
+ export const useToggleButtonContext = () => {
6
+ const ctx = useContext(ToggleButtonContext);
7
+ if (!ctx)
8
+ throw new Error('ToggleButtonBase 하위 컴포넌트는 Root 내부에서 사용해야 합니다.');
9
+ return ctx;
10
+ };
11
+ const Root = ({ checked, defaultChecked = false, onCheckedChange, disabled = false, className, style, children, }) => {
12
+ const [internal, setInternal] = useState(defaultChecked);
13
+ const [isFocused, setIsFocused] = useState(false);
14
+ const isControlled = checked !== undefined;
15
+ const resolved = isControlled ? checked : internal;
16
+ const handleChange = (val) => {
17
+ if (!isControlled)
18
+ setInternal(val);
19
+ onCheckedChange?.(val);
20
+ };
21
+ return (_jsx(ToggleButtonContext, { value: {
22
+ checked: resolved,
23
+ onCheckedChange: handleChange,
24
+ disabled,
25
+ isFocused,
26
+ setIsFocused,
27
+ }, children: _jsx("label", { style: style, onClick: (e) => e.stopPropagation(), className: cn('flex items-center gap-sm', disabled ? 'cursor-not-allowed' : 'cursor-pointer', className), children: children }) }));
28
+ };
29
+ const HiddenInput = ({ ref, onFocus, onBlur, onChange, ...props }) => {
30
+ const { checked, onCheckedChange, disabled, setIsFocused } = useToggleButtonContext();
31
+ return (_jsx("input", { type: "checkbox", role: "switch", "aria-checked": checked, ref: ref, className: "sr-only peer", checked: checked, disabled: disabled, onChange: (e) => {
32
+ e.stopPropagation();
33
+ onCheckedChange(e.target.checked);
34
+ onChange?.(e);
35
+ }, onFocus: (e) => {
36
+ setIsFocused(true);
37
+ onFocus?.(e);
38
+ }, onBlur: (e) => {
39
+ setIsFocused(false);
40
+ onBlur?.(e);
41
+ }, ...props }));
42
+ };
43
+ const Track = ({ className, children }) => {
44
+ return (_jsx("span", { className: cn('relative flex items-center rounded-full shrink-0', className), children: children }));
45
+ };
46
+ const Thumb = ({ className }) => {
47
+ return (_jsx("span", { className: cn('absolute rounded-full top-1/2 -translate-y-1/2', className) }));
48
+ };
49
+ const Label = ({ className, children }) => {
50
+ return _jsx("span", { className: className, children: children });
51
+ };
52
+ export const ToggleButtonBase = {
53
+ Root,
54
+ HiddenInput,
55
+ Track,
56
+ Thumb,
57
+ Label,
58
+ };
59
+ export default ToggleButtonBase;
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ export interface TooltipProps {
3
+ /** 툴팁이 표시될 트리거 요소 */
4
+ children: React.ReactElement;
5
+ /** 툴팁 내용 (생략 시 children 텍스트가 잘릴 때만 자동 표시) */
6
+ content?: React.ReactNode;
7
+ /** 툴팁 표시 위치 */
8
+ side?: 'top' | 'right' | 'bottom' | 'left';
9
+ /** 툴팁 정렬 */
10
+ align?: 'start' | 'center' | 'end';
11
+ /** 추가 CSS 클래스 */
12
+ className?: string;
13
+ /** 인라인 스타일 */
14
+ style?: React.CSSProperties;
15
+ }
16
+ declare const Tooltip: ({ children, content, side, align, className, style, }: TooltipProps) => import("react/jsx-runtime").JSX.Element;
17
+ export default Tooltip;
18
+ //# sourceMappingURL=Tooltip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,MAAM,WAAW,YAAY;IAC3B,qBAAqB;IACrB,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC;IAC7B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,eAAe;IACf,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,YAAY;IACZ,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,iBAAiB;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc;IACd,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,QAAA,MAAM,OAAO,GAAI,uDAOd,YAAY,4CA8Bd,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import TooltipBase from './TooltipBase.js';
4
+ import cn from '../../utils/cn.js';
5
+ const Tooltip = ({ children, content, side = 'top', align = 'center', className, style, }) => {
6
+ const { ref: textRef, isTruncated } = TooltipBase.useTruncation([children]);
7
+ const tooltipContent = content ?? textRef.current?.textContent ?? '';
8
+ const shouldShow = content ? true : isTruncated;
9
+ return (_jsx(TooltipBase.Provider, { children: _jsxs(TooltipBase.Root, { children: [_jsx(TooltipBase.Trigger, { asChild: true, children: _jsx("div", { className: cn('relative w-full', className), style: style, children: React.cloneElement(children, {
10
+ ref: textRef,
11
+ }) }) }), shouldShow && (_jsxs(TooltipBase.Content, { side: side, align: align, className: "px-2 py-1 text-xs text-white whitespace-nowrap bg-gray-900 rounded", children: [tooltipContent, _jsx(TooltipBase.Arrow, { className: "fill-gray-900" })] }))] }) }));
12
+ };
13
+ export default Tooltip;
@@ -0,0 +1,39 @@
1
+ import { type ReactNode } from 'react';
2
+ interface ProviderProps {
3
+ delayDuration?: number;
4
+ children?: ReactNode;
5
+ }
6
+ interface RootProps {
7
+ open?: boolean;
8
+ defaultOpen?: boolean;
9
+ onOpenChange?: (open: boolean) => void;
10
+ children?: ReactNode;
11
+ }
12
+ interface TriggerProps {
13
+ asChild?: boolean;
14
+ className?: string;
15
+ children?: ReactNode;
16
+ }
17
+ interface ContentProps {
18
+ side?: 'top' | 'right' | 'bottom' | 'left';
19
+ sideOffset?: number;
20
+ align?: 'start' | 'center' | 'end';
21
+ className?: string;
22
+ children?: ReactNode;
23
+ }
24
+ interface ArrowProps {
25
+ className?: string;
26
+ }
27
+ export declare const TooltipBase: {
28
+ Provider: ({ delayDuration, children }: ProviderProps) => import("react/jsx-runtime").JSX.Element;
29
+ Root: ({ open, defaultOpen, onOpenChange, children }: RootProps) => import("react/jsx-runtime").JSX.Element;
30
+ Trigger: ({ asChild, className, children }: TriggerProps) => import("react/jsx-runtime").JSX.Element;
31
+ Content: ({ side, sideOffset, align, className, children, }: ContentProps) => import("react/jsx-runtime").JSX.Element;
32
+ Arrow: ({ className }: ArrowProps) => import("react/jsx-runtime").JSX.Element;
33
+ useTruncation: (deps?: React.DependencyList) => {
34
+ ref: import("react").RefObject<HTMLElement | null>;
35
+ isTruncated: boolean;
36
+ };
37
+ };
38
+ export default TooltipBase;
39
+ //# sourceMappingURL=TooltipBase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TooltipBase.d.ts","sourceRoot":"","sources":["../../../src/components/Tooltip/TooltipBase.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAA+B,MAAM,OAAO,CAAC;AA2BpE,UAAU,aAAa;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD,UAAU,SAAS;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAeD,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA4BD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,eAAO,MAAM,WAAW;4CAtF6B,aAAa;0DAgBL,SAAS;gDAmBnB,YAAY;iEAuB5D,YAAY;2BAwBe,UAAU;2BA7GX,KAAK,CAAC,cAAc;;;;CAwHhD,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useRef, useEffect, useState } from 'react';
3
+ import * as RadixTooltip from '@radix-ui/react-tooltip';
4
+ import cn from '../../utils/cn.js';
5
+ // ── 말줄임 감지 Hook ──
6
+ const useTruncation = (deps = []) => {
7
+ const ref = useRef(null);
8
+ const [isTruncated, setIsTruncated] = useState(false);
9
+ useEffect(() => {
10
+ const element = ref.current;
11
+ if (!element)
12
+ return;
13
+ const checkTruncation = () => {
14
+ setIsTruncated(element.scrollWidth > element.clientWidth);
15
+ };
16
+ checkTruncation();
17
+ window.addEventListener('resize', checkTruncation);
18
+ return () => window.removeEventListener('resize', checkTruncation);
19
+ // eslint-disable-next-line react-hooks/exhaustive-deps
20
+ }, deps);
21
+ return { ref, isTruncated };
22
+ };
23
+ const Provider = ({ delayDuration = 200, children }) => {
24
+ return (_jsx(RadixTooltip.Provider, { delayDuration: delayDuration, children: children }));
25
+ };
26
+ const Root = ({ open, defaultOpen, onOpenChange, children }) => {
27
+ return (_jsx(RadixTooltip.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, children: children }));
28
+ };
29
+ const Trigger = ({ asChild, className, children }) => {
30
+ return (_jsx(RadixTooltip.Trigger, { asChild: asChild, className: className, children: children }));
31
+ };
32
+ const Content = ({ side = 'top', sideOffset = 8, align = 'center', className, children, }) => {
33
+ return (_jsx(RadixTooltip.Portal, { children: _jsx(RadixTooltip.Content, { side: side, sideOffset: sideOffset, align: align, className: cn('z-50 outline-hidden', 'animate-in fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0', className), children: children }) }));
34
+ };
35
+ const Arrow = ({ className }) => {
36
+ return _jsx(RadixTooltip.Arrow, { className: className });
37
+ };
38
+ export const TooltipBase = {
39
+ Provider,
40
+ Root,
41
+ Trigger,
42
+ Content,
43
+ Arrow,
44
+ useTruncation,
45
+ };
46
+ export default TooltipBase;