@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,57 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import dayjs from 'dayjs';
4
+ import { createContext, useContext, useState } from 'react';
5
+ const DataCalendarContext = createContext(null);
6
+ export const useDataCalendarContext = () => {
7
+ const ctx = useContext(DataCalendarContext);
8
+ if (!ctx)
9
+ throw new Error('DataCalendarBase 서브컴포넌트는 DataCalendarBase.Root 내부에서 사용해야 합니다.');
10
+ return ctx;
11
+ };
12
+ const Root = ({ children, className, defaultMonth, onMonthChange, }) => {
13
+ const [month, setMonth] = useState((defaultMonth ?? dayjs()).startOf('month'));
14
+ const changeMonth = (delta) => {
15
+ const next = month.add(delta, 'month');
16
+ setMonth(next);
17
+ onMonthChange?.(next);
18
+ };
19
+ return (_jsx(DataCalendarContext, { value: { month, changeMonth }, children: _jsx("div", { className: className, children: children }) }));
20
+ };
21
+ const Title = ({ className, format = 'YYYY년 M월' }) => {
22
+ const { month } = useDataCalendarContext();
23
+ return _jsx("span", { className: className, children: month.format(format) });
24
+ };
25
+ const Prev = ({ children, className }) => {
26
+ const { changeMonth } = useDataCalendarContext();
27
+ return (_jsx("button", { type: "button", onClick: () => changeMonth(-1), className: className, children: children }));
28
+ };
29
+ const Next = ({ children, className }) => {
30
+ const { changeMonth } = useDataCalendarContext();
31
+ return (_jsx("button", { type: "button", onClick: () => changeMonth(1), className: className, children: children }));
32
+ };
33
+ // ── Grid ──
34
+ const DEFAULT_WEEKDAYS = ['일', '월', '화', '수', '목', '금', '토'];
35
+ const Grid = ({ renderCell, weekdays = DEFAULT_WEEKDAYS, className, weekdayClassName, }) => {
36
+ const { month } = useDataCalendarContext();
37
+ const startOffset = month.startOf('month').day();
38
+ const daysInMonth = month.daysInMonth();
39
+ const prevMonth = month.subtract(1, 'month');
40
+ const nextMonth = month.add(1, 'month');
41
+ const prevDays = prevMonth.daysInMonth();
42
+ const cells = Array.from({ length: startOffset + daysInMonth }, (_, i) => i < startOffset
43
+ ? prevMonth.date(prevDays - startOffset + i + 1)
44
+ : month.date(i - startOffset + 1));
45
+ let nextDay = 1;
46
+ while (cells.length % 7 !== 0)
47
+ cells.push(nextMonth.date(nextDay++));
48
+ return (_jsxs("div", { className: className, children: [_jsx("div", { className: "grid grid-cols-7", children: weekdays.map((d) => (_jsx("span", { className: weekdayClassName, children: d }, d))) }), _jsx("div", { className: "grid grid-cols-7", children: cells.map((date, i) => renderCell(date, i, !date.isSame(month, 'month'))) })] }));
49
+ };
50
+ const Cell = ({ date, isOutside, children, className, dateClassName, }) => {
51
+ const isToday = date.isSame(dayjs(), 'day');
52
+ const isWeekend = date.day() === 0 || date.day() === 6;
53
+ return (_jsxs("div", { className: className, "data-outside": isOutside || undefined, children: [_jsx("span", { "data-today": isToday || undefined, "data-outside": isOutside || undefined, "data-weekend": isWeekend || undefined, className: dateClassName, children: date.date() }), children] }));
54
+ };
55
+ // ── Export ──
56
+ const DataCalendarBase = { Root, Title, Prev, Next, Grid, Cell };
57
+ export default DataCalendarBase;
@@ -0,0 +1,34 @@
1
+ import { type ReactNode } from 'react';
2
+ export interface DatePickerProps {
3
+ /** 선택된 날짜 (controlled) */
4
+ value?: Date;
5
+ /** 초기 선택 날짜 (uncontrolled) */
6
+ defaultValue?: Date;
7
+ /** 날짜 변경 시 호출되는 콜백 */
8
+ onChange?: (value: Date | undefined) => void;
9
+ /** 미선택 시 표시할 텍스트 */
10
+ placeholder?: string;
11
+ /** 비활성화 여부 */
12
+ disabled?: boolean;
13
+ /** true 시 너비 100% */
14
+ block?: boolean;
15
+ /** 색상 테마 (danger 시 에러 스타일) */
16
+ color?: 'neutral' | 'danger';
17
+ /** 현재 시점 이후 날짜 선택 비활성화 */
18
+ isDisableAfterNow?: boolean;
19
+ /** 최소 선택 가능 날짜 */
20
+ minDate?: Date;
21
+ /** 트리거 우측 아이콘 */
22
+ trailingIcon?: ReactNode;
23
+ /** 날짜 초기화 버튼 표시 여부 */
24
+ showReset?: boolean;
25
+ /** 추가 CSS 클래스 */
26
+ className?: string;
27
+ /** 인라인 스타일 (트리거 버튼에 적용) */
28
+ style?: React.CSSProperties;
29
+ /** 트리거 버튼 className */
30
+ triggerClassName?: string;
31
+ }
32
+ declare const DatePicker: ({ value, defaultValue, onChange, placeholder, disabled, block, color, isDisableAfterNow, minDate, trailingIcon, showReset, className, style, triggerClassName, }: DatePickerProps) => import("react/jsx-runtime").JSX.Element;
33
+ export default DatePicker;
34
+ //# sourceMappingURL=DatePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/DatePicker/DatePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AASjD,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,8BAA8B;IAC9B,YAAY,CAAC,EAAE,IAAI,CAAC;IACpB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC;IAC7C,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,0BAA0B;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kBAAkB;IAClB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,iBAAiB;IACjB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,sBAAsB;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,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,kKAiBjB,eAAe,4CA4FjB,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import dayjs from 'dayjs';
5
+ import { ko } from 'react-day-picker/locale';
6
+ import PopoverBase from '../Popover/PopoverBase.js';
7
+ import Calendar from '../Calendar/Calendar.js';
8
+ import LucideIcon from '../Icon/LucideIcon.js';
9
+ import cn from '../../utils/cn.js';
10
+ const DatePicker = ({ value, defaultValue, onChange, placeholder = 'YYYY-MM-DD', disabled = false, block = false, color = 'neutral', isDisableAfterNow = false, minDate, trailingIcon = (_jsx(LucideIcon, { name: "calendar", size: 15, className: "text-mono400" })), showReset = true, className, style, triggerClassName, }) => {
11
+ const [open, setOpen] = useState(false);
12
+ const [internal, setInternal] = useState(defaultValue);
13
+ const isControlled = value !== undefined;
14
+ const resolved = isControlled ? value : internal;
15
+ const handleSelect = (date) => {
16
+ if (!isControlled)
17
+ setInternal(date);
18
+ onChange?.(date);
19
+ setOpen(false);
20
+ };
21
+ const handleReset = (e) => {
22
+ e.stopPropagation();
23
+ if (!isControlled)
24
+ setInternal(undefined);
25
+ onChange?.(undefined);
26
+ };
27
+ 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, className: cn('border border-neutral100 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'
28
+ ? 'bg-tintRed outline-red500'
29
+ : 'focus:bg-tintBlue focus:outline-lb500', triggerClassName), children: [resolved ? (_jsx("span", { children: dayjs(resolved).format('YYYY-MM-DD') })) : (_jsx("span", { className: "text-mono400", children: placeholder })), _jsxs("div", { className: "flex gap-[6px]", children: [trailingIcon, showReset && resolved && (_jsx("span", { role: "button", tabIndex: 0, className: "text-mono400 cursor-pointer", onClick: handleReset, onKeyDown: (e) => {
30
+ if (e.key === 'Enter' || e.key === ' ') {
31
+ e.preventDefault();
32
+ handleReset(e);
33
+ }
34
+ }, children: _jsx(LucideIcon, { name: "rotateCw", size: 14 }) }))] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white shadow-md p-0 min-w-[280px] w-[var(--radix-popover-trigger-width)]", children: _jsx(Calendar, { className: "w-full", captionLayout: "dropdown", mode: "single", locale: ko, selected: resolved, onSelect: handleSelect, disabled: isDisableAfterNow
35
+ ? (date) => date > new Date()
36
+ : minDate
37
+ ? (date) => {
38
+ const dateOnly = new Date(date.getFullYear(), date.getMonth(), date.getDate());
39
+ const minDateOnly = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());
40
+ return dateOnly < minDateOnly;
41
+ }
42
+ : false }) })] }) }));
43
+ };
44
+ export default DatePicker;
@@ -0,0 +1,12 @@
1
+ import { type RegisterOptions } from 'react-hook-form';
2
+ import { type DatePickerProps } from './DatePicker.js';
3
+ interface FormDatePickerProps extends Omit<DatePickerProps, 'value' | 'onChange'> {
4
+ name: string;
5
+ options?: RegisterOptions;
6
+ customErrorMessage?: string;
7
+ isHiddenErrorMessage?: boolean;
8
+ errorClassName?: string;
9
+ }
10
+ declare const FormDatePicker: ({ name, options, customErrorMessage, isHiddenErrorMessage, errorClassName, disabled, block, ...props }: FormDatePickerProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default FormDatePicker;
12
+ //# sourceMappingURL=FormDatePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormDatePicker.d.ts","sourceRoot":"","sources":["../../../src/components/DatePicker/FormDatePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAKhE,UAAU,mBAAoB,SAAQ,IAAI,CACxC,eAAe,EACf,OAAO,GAAG,UAAU,CACrB;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,cAAc,GAAI,wGASrB,mBAAmB,4CAoCrB,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,12 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import DatePicker from './DatePicker.js';
4
+ import FormField from '../Form/FormField.js';
5
+ import FormErrorMessage from '../Form/FormErrorMessage.js';
6
+ import cn from '../../utils/cn.js';
7
+ const FormDatePicker = ({ 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(DatePicker, { ...props, block: block, value: field.value ?? undefined, onChange: (date) => {
9
+ field.onChange(date);
10
+ }, disabled: disabled, color: fieldState.hasError ? 'danger' : 'neutral' }), !isHiddenErrorMessage && (_jsx(FormErrorMessage, { error: fieldState.error, disabled: disabled, className: errorClassName }))] })) }));
11
+ };
12
+ export default FormDatePicker;
@@ -0,0 +1,49 @@
1
+ import { type ReactNode } from 'react';
2
+ type DateRange = {
3
+ from: Date;
4
+ to?: Date;
5
+ };
6
+ type ViewMode = 'daily' | 'monthly' | 'yearly';
7
+ export interface DateRangePickerProps {
8
+ /** 선택된 날짜 범위 ({ from, to? }) */
9
+ value?: DateRange;
10
+ /** 날짜 범위 변경 시 호출되는 콜백 */
11
+ onChange?: (value: DateRange | undefined) => void;
12
+ /** 비활성화 여부 */
13
+ disabled?: boolean;
14
+ /** true 시 너비 100% */
15
+ block?: boolean;
16
+ /** 색상 테마 (danger 시 에러 스타일) */
17
+ color?: 'neutral' | 'danger';
18
+ /** 현재 시점 이후 날짜 선택 비활성화 */
19
+ isDisableAfterNow?: boolean;
20
+ /** 날짜 범위 완성 시 팝오버 자동 닫힘 */
21
+ isAutoClose?: boolean;
22
+ /** 선택 모드 (daily: 일별, monthly: 월별, yearly: 연별) */
23
+ viewMode?: ViewMode;
24
+ /** 초기 선택 날짜 범위 (uncontrolled) */
25
+ defaultValue?: DateRange;
26
+ /** 초기값 (리셋 시 이 값으로 복원) */
27
+ initialValue?: {
28
+ from: string;
29
+ to: string;
30
+ };
31
+ /** 트리거 우측 아이콘 */
32
+ trailingIcon?: ReactNode;
33
+ /** 날짜 범위 선택 완료 시 호출되는 콜백 */
34
+ onRangeComplete?: (range: {
35
+ from: Date;
36
+ to: Date;
37
+ }) => void;
38
+ /** 날짜 초기화 완료 시 호출되는 콜백 */
39
+ onResetComplete?: () => void;
40
+ /** 추가 CSS 클래스 */
41
+ className?: string;
42
+ /** 인라인 스타일 (트리거 버튼에 적용) */
43
+ style?: React.CSSProperties;
44
+ /** 트리거 버튼 className */
45
+ triggerClassName?: string;
46
+ }
47
+ declare const DateRangePicker: ({ value, onChange, disabled, block, color, isDisableAfterNow, isAutoClose, viewMode, defaultValue, initialValue, trailingIcon, onRangeComplete, onResetComplete, className, style, triggerClassName, }: DateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
48
+ export default DateRangePicker;
49
+ //# sourceMappingURL=DateRangePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/DateRangePicker/DateRangePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AASjD,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAC3C,KAAK,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAe/C,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,yBAAyB;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,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,0BAA0B;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,2BAA2B;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,iCAAiC;IACjC,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,0BAA0B;IAC1B,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,iBAAiB;IACjB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,IAAI,CAAC;QAAC,EAAE,EAAE,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IAC5D,0BAA0B;IAC1B,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,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,eAAe,GAAI,wMAmBtB,oBAAoB,4CAiLtB,CAAC;AA6LF,eAAe,eAAe,CAAC"}
@@ -0,0 +1,197 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import dayjs from 'dayjs';
5
+ import { ko } from 'react-day-picker/locale';
6
+ import PopoverBase from '../Popover/PopoverBase.js';
7
+ import Calendar from '../Calendar/Calendar.js';
8
+ import LucideIcon from '../Icon/LucideIcon.js';
9
+ import cn from '../../utils/cn.js';
10
+ const dateFormats = {
11
+ daily: 'YYYY-MM-DD',
12
+ monthly: 'YYYY-MM',
13
+ yearly: 'YYYY',
14
+ };
15
+ const placeholders = {
16
+ daily: 'YYYY-MM-DD ~ YYYY-MM-DD',
17
+ monthly: 'YYYY-MM ~ YYYY-MM',
18
+ yearly: 'YYYY ~ YYYY',
19
+ };
20
+ const DateRangePicker = ({ value, onChange, disabled = false, block = false, color = 'neutral', isDisableAfterNow = false, isAutoClose = false, viewMode = 'daily', defaultValue, initialValue, trailingIcon = (_jsx(LucideIcon, { name: "calendar", size: 15, className: "text-mono40" })), onRangeComplete, onResetComplete, className, style, triggerClassName, }) => {
21
+ const [open, setOpen] = useState(false);
22
+ const [internal, setInternal] = useState(defaultValue);
23
+ const isControlled = value !== undefined;
24
+ const resolved = isControlled ? value : internal;
25
+ const fmt = dateFormats[viewMode];
26
+ const renderDateRange = () => {
27
+ if (!resolved?.from) {
28
+ return _jsx("span", { className: "text-mono40", children: placeholders[viewMode] });
29
+ }
30
+ if (!resolved.to) {
31
+ return (_jsxs("span", { className: "text-mono40", children: [dayjs(resolved.from).format(fmt), " ~", ' ', placeholders[viewMode].split(' ~ ')[1]] }));
32
+ }
33
+ return (_jsxs(_Fragment, { children: [dayjs(resolved.from).format(fmt), " ~ ", dayjs(resolved.to).format(fmt)] }));
34
+ };
35
+ const handleReset = (e) => {
36
+ e.stopPropagation();
37
+ const resetValue = initialValue
38
+ ? {
39
+ from: dayjs(initialValue.from).toDate(),
40
+ to: dayjs(initialValue.to).toDate(),
41
+ }
42
+ : undefined;
43
+ if (!isControlled)
44
+ setInternal(resetValue);
45
+ onChange?.(resetValue);
46
+ onResetComplete?.();
47
+ };
48
+ const isResetAvailable = initialValue?.from
49
+ ? dayjs(resolved?.from).format(fmt) !== initialValue.from ||
50
+ dayjs(resolved?.to).format(fmt) !== initialValue.to
51
+ : !!resolved?.from;
52
+ const handleRangeSelect = (range) => {
53
+ if (!range)
54
+ return;
55
+ if (!isControlled)
56
+ setInternal(range);
57
+ onChange?.(range);
58
+ if (range.from && range.to) {
59
+ onRangeComplete?.(range);
60
+ if (isAutoClose)
61
+ setOpen(false);
62
+ }
63
+ };
64
+ const handleDailySelect = (selected) => {
65
+ if (!selected)
66
+ return;
67
+ const current = resolved;
68
+ // from만 있는 상태에서 두 번째 클릭
69
+ if (current?.from && !current?.to && selected?.from && selected?.to) {
70
+ handleRangeSelect(selected);
71
+ return;
72
+ }
73
+ // 완전한 범위가 이미 있는 상태에서 클릭
74
+ if (current?.from && current?.to) {
75
+ if (selected?.from &&
76
+ selected?.to &&
77
+ selected.from.getTime() === selected.to.getTime()) {
78
+ if (!isControlled)
79
+ setInternal({ from: selected.from, to: undefined });
80
+ onChange?.({ from: selected.from, to: undefined });
81
+ return;
82
+ }
83
+ if (selected?.from && selected?.to) {
84
+ const clickedDate = selected.from.getTime() !== current.from.getTime() &&
85
+ selected.from.getTime() !== current.to.getTime()
86
+ ? selected.from
87
+ : selected.to.getTime() !== current.from.getTime() &&
88
+ selected.to.getTime() !== current.to.getTime()
89
+ ? selected.to
90
+ : selected.from;
91
+ if (!isControlled)
92
+ setInternal({ from: clickedDate, to: undefined });
93
+ onChange?.({ from: clickedDate, to: undefined });
94
+ return;
95
+ }
96
+ }
97
+ // 기본 동작
98
+ if (selected?.from &&
99
+ selected?.to &&
100
+ selected.from.getTime() === selected.to.getTime()) {
101
+ if (!isControlled)
102
+ setInternal({ from: selected.from, to: undefined });
103
+ onChange?.({ from: selected.from, to: undefined });
104
+ }
105
+ else {
106
+ if (!isControlled)
107
+ setInternal(selected);
108
+ onChange?.(selected);
109
+ }
110
+ };
111
+ 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, className: cn('border border-neutral10 h-[38px] w-full display14 px-4 rounded-[5px]', 'flex flex-row items-center justify-between gap-4', 'whitespace-nowrap outline-2 outline-transparent ld-transition', disabled && 'cursor-not-allowed opacity-50', color === 'danger'
112
+ ? 'bg-tintRed outline-red500'
113
+ : 'focus:bg-tintBlue focus:outline-lb500', triggerClassName), children: [renderDateRange(), _jsxs("div", { className: "shrink-0 flex gap-1.5", children: [trailingIcon, isResetAvailable && (_jsx("span", { role: "button", tabIndex: 0, className: "text-mono40 cursor-pointer", onClick: handleReset, onKeyDown: (e) => {
114
+ if (e.key === 'Enter' || e.key === ' ') {
115
+ e.preventDefault();
116
+ handleReset(e);
117
+ }
118
+ }, children: _jsx(LucideIcon, { name: "rotateCw", size: 14 }) }))] })] }), _jsxs(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white shadow-md p-0", children: [viewMode === 'daily' && (_jsx(Calendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: resolved, onSelect: handleDailySelect, disabled: isDisableAfterNow ? (date) => date > new Date() : false, numberOfMonths: 2 })), viewMode === 'monthly' && (_jsx(MonthRangePicker, { value: resolved, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), viewMode === 'yearly' && (_jsx(YearRangePicker, { value: resolved, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow }))] })] }) }));
119
+ };
120
+ // ── MonthRangePicker ──
121
+ const MonthRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
122
+ const [currentYear, setCurrentYear] = useState(value?.from ? value.from.getFullYear() : new Date().getFullYear());
123
+ const now = new Date();
124
+ const handleMonthClick = (month) => {
125
+ const clickedDate = new Date(currentYear, month, 1);
126
+ if (!value?.from || (value.from && value.to)) {
127
+ onChange({ from: clickedDate, to: undefined });
128
+ }
129
+ else if (clickedDate < value.from) {
130
+ onChange({ from: clickedDate, to: undefined });
131
+ }
132
+ else {
133
+ onChange({
134
+ from: value.from,
135
+ to: dayjs(clickedDate).endOf('month').toDate(),
136
+ });
137
+ }
138
+ };
139
+ const isSelected = (month) => {
140
+ if (!value?.from)
141
+ return false;
142
+ const date = new Date(currentYear, month, 1);
143
+ if (value.to) {
144
+ return (date >= dayjs(value.from).startOf('month').toDate() && date <= value.to);
145
+ }
146
+ return (date.getFullYear() === value.from.getFullYear() &&
147
+ date.getMonth() === value.from.getMonth());
148
+ };
149
+ const isDisabled = (month) => {
150
+ if (!isDisableAfterNow)
151
+ return false;
152
+ return new Date(currentYear, month, 1) > dayjs(now).endOf('month').toDate();
153
+ };
154
+ return (_jsxs("div", { className: "p-3 w-[280px]", children: [_jsxs("div", { className: "flex items-center justify-between mb-4 px-2", children: [_jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer", onClick: () => setCurrentYear((prev) => prev - 1), children: _jsx(LucideIcon, { name: "chevronLeft", size: 16 }) }), _jsxs("span", { className: "display14 bold", children: [currentYear, "\uB144"] }), _jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed", onClick: () => setCurrentYear((prev) => prev + 1), disabled: isDisableAfterNow && currentYear >= now.getFullYear(), children: _jsx(LucideIcon, { name: "chevronRight", size: 16 }) })] }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: Array.from({ length: 12 }, (_, m) => (_jsxs("button", { type: "button", onClick: () => handleMonthClick(m), disabled: isDisabled(m), className: cn('h-10 rounded-md display12 ld-transition cursor-pointer', isSelected(m)
155
+ ? 'bg-lb500 text-white bold'
156
+ : 'hover:bg-neutral10 text-mono60', isDisabled(m) && 'opacity-30 cursor-not-allowed'), children: [m + 1, "\uC6D4"] }, m))) })] }));
157
+ };
158
+ // ── YearRangePicker ──
159
+ const YearRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
160
+ const [startYearPage, setStartYearPage] = useState(Math.floor((value?.from ? value.from.getFullYear() : new Date().getFullYear()) / 12) * 12);
161
+ const years = Array.from({ length: 12 }, (_, i) => startYearPage + i);
162
+ const now = new Date();
163
+ const handleYearClick = (year) => {
164
+ const clickedDate = new Date(year, 0, 1);
165
+ if (!value?.from || (value.from && value.to)) {
166
+ onChange({ from: clickedDate, to: undefined });
167
+ }
168
+ else if (clickedDate < value.from) {
169
+ onChange({ from: clickedDate, to: undefined });
170
+ }
171
+ else {
172
+ onChange({
173
+ from: value.from,
174
+ to: dayjs(clickedDate).endOf('year').toDate(),
175
+ });
176
+ }
177
+ };
178
+ const isSelected = (year) => {
179
+ if (!value?.from)
180
+ return false;
181
+ const date = new Date(year, 0, 1);
182
+ if (value.to) {
183
+ return (date >= dayjs(value.from).startOf('year').toDate() && date <= value.to);
184
+ }
185
+ return date.getFullYear() === value.from.getFullYear();
186
+ };
187
+ const isDisabled = (year) => {
188
+ if (!isDisableAfterNow)
189
+ return false;
190
+ return year > now.getFullYear();
191
+ };
192
+ return (_jsxs("div", { className: "p-3 w-[280px]", children: [_jsxs("div", { className: "flex items-center justify-between mb-4 px-2", children: [_jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer", onClick: () => setStartYearPage((prev) => prev - 12), children: _jsx(LucideIcon, { name: "chevronLeft", size: 16 }) }), _jsxs("span", { className: "display14 bold", children: [years[0], " - ", years[years.length - 1]] }), _jsx("button", { type: "button", className: "inline-flex items-center justify-center size-8 rounded-md hover:bg-neutral-100 cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed", onClick: () => setStartYearPage((prev) => prev + 12), disabled: isDisableAfterNow &&
193
+ (years[years.length - 1] ?? 0) >= now.getFullYear(), children: _jsx(LucideIcon, { name: "chevronRight", size: 16 }) })] }), _jsx("div", { className: "grid grid-cols-3 gap-2", children: years.map((y) => (_jsxs("button", { type: "button", onClick: () => handleYearClick(y), disabled: isDisabled(y), className: cn('h-10 rounded-md display12 ld-transition cursor-pointer', isSelected(y)
194
+ ? 'bg-lb500 text-white bold'
195
+ : 'hover:bg-neutral10 text-mono60', isDisabled(y) && 'opacity-30 cursor-not-allowed'), children: [y, "\uB144"] }, y))) })] }));
196
+ };
197
+ export default DateRangePicker;
@@ -0,0 +1,12 @@
1
+ import { type RegisterOptions } from 'react-hook-form';
2
+ import { type DateRangePickerProps } from './DateRangePicker.js';
3
+ interface FormDateRangePickerProps extends Omit<DateRangePickerProps, 'value' | 'onChange'> {
4
+ name: string;
5
+ options?: RegisterOptions;
6
+ customErrorMessage?: string;
7
+ isHiddenErrorMessage?: boolean;
8
+ errorClassName?: string;
9
+ }
10
+ declare const FormDateRangePicker: ({ name, options, customErrorMessage, isHiddenErrorMessage, errorClassName, disabled, block, ...props }: FormDateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default FormDateRangePicker;
12
+ //# sourceMappingURL=FormDateRangePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormDateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/DateRangePicker/FormDateRangePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAwB,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAK/E,UAAU,wBAAyB,SAAQ,IAAI,CAC7C,oBAAoB,EACpB,OAAO,GAAG,UAAU,CACrB;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,mBAAmB,GAAI,wGAS1B,wBAAwB,4CAkC1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,10 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import DateRangePicker from './DateRangePicker.js';
4
+ import FormField from '../Form/FormField.js';
5
+ import FormErrorMessage from '../Form/FormErrorMessage.js';
6
+ import cn from '../../utils/cn.js';
7
+ const FormDateRangePicker = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = true, 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(DateRangePicker, { ...props, block: block, value: field.value ?? undefined, onChange: field.onChange, disabled: disabled, color: fieldState.hasError ? 'danger' : 'neutral' }), !isHiddenErrorMessage && (_jsx(FormErrorMessage, { error: fieldState.error, disabled: disabled, className: errorClassName }))] })) }));
9
+ };
10
+ export default FormDateRangePicker;
@@ -0,0 +1,51 @@
1
+ import { type ReactNode } from 'react';
2
+ type DrawerDirection = 'bottom' | 'top' | 'left' | 'right';
3
+ export interface DrawerButton<T = unknown> {
4
+ /** 버튼 텍스트 */
5
+ label: string;
6
+ /** 버튼 식별 값 (onButtonClick에 전달) */
7
+ value: T;
8
+ /** 버튼 스타일 유형 */
9
+ variant?: 'solid' | 'outline' | 'ghost';
10
+ /** 버튼 색상 테마 */
11
+ color?: 'neutral' | 'point' | 'danger';
12
+ /** 클릭 핸들러 (false 반환 시 Drawer 닫힘 방지) */
13
+ onClick?: () => void | boolean | Promise<void | boolean>;
14
+ }
15
+ export interface DrawerProps {
16
+ /** Drawer 열림 상태 (제어 컴포넌트) */
17
+ open?: boolean;
18
+ /** 초기 열림 상태 (비제어 컴포넌트) */
19
+ defaultOpen?: boolean;
20
+ /** 열림 상태 변경 시 호출되는 콜백 */
21
+ onOpenChange?: (open: boolean) => void;
22
+ /** 슬라이드 방향 */
23
+ direction?: DrawerDirection;
24
+ /** 높이 스냅 포인트 (bottom/top 전용, 0~1 비율 또는 px 문자열) */
25
+ snapPoints?: (number | string)[];
26
+ /** 현재 활성 스냅 포인트 */
27
+ activeSnapPoint?: number | string | null;
28
+ /** 스냅 포인트 변경 콜백 */
29
+ setActiveSnapPoint?: (snapPoint: number | string | null) => void;
30
+ /** Drawer 제목 */
31
+ title?: string;
32
+ /** Drawer 설명 텍스트 */
33
+ description?: string;
34
+ /** 본문 콘텐츠 */
35
+ children?: ReactNode;
36
+ /** 하단 버튼 목록 */
37
+ buttons?: DrawerButton[];
38
+ /** Drawer를 여는 트리거 요소 */
39
+ trigger?: ReactNode;
40
+ /** 드래그 핸들 표시 여부 (bottom/top 방향에서 기본 true) */
41
+ showHandle?: boolean;
42
+ /** 추가 CSS 클래스 (Drawer 패널에 적용) */
43
+ className?: string;
44
+ /** 인라인 스타일 (Drawer 패널에 적용) */
45
+ style?: React.CSSProperties;
46
+ /** 버튼 클릭 시 해당 버튼의 value를 전달하는 콜백 */
47
+ onButtonClick?: (value: unknown) => void;
48
+ }
49
+ declare const Drawer: ({ open, defaultOpen, onOpenChange, direction, snapPoints, activeSnapPoint, setActiveSnapPoint, title, description, children, buttons, trigger, showHandle, className, style, onButtonClick, }: DrawerProps) => import("react/jsx-runtime").JSX.Element;
50
+ export default Drawer;
51
+ //# sourceMappingURL=Drawer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.d.ts","sourceRoot":"","sources":["../../../src/components/Drawer/Drawer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,KAAK,eAAe,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,aAAa;IACb,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,KAAK,EAAE,CAAC,CAAC;IACT,gBAAgB;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;IACxC,eAAe;IACf,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,CAAC;IACvC,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0BAA0B;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,yBAAyB;IACzB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,cAAc;IACd,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,kDAAkD;IAClD,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACjC,mBAAmB;IACnB,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACzC,mBAAmB;IACnB,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjE,gBAAgB;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oBAAoB;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,eAAe;IACf,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,wBAAwB;IACxB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAUD,QAAA,MAAM,MAAM,GAAI,+LAiBb,WAAW,4CAmFb,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import DrawerBase from './DrawerBase.js';
3
+ import LucideIcon from '../Icon/LucideIcon.js';
4
+ import Button from '../Button/Button.js';
5
+ import cn from '../../utils/cn.js';
6
+ // ── 방향별 스타일 매핑 ──
7
+ const directionClasses = {
8
+ bottom: 'bottom-0 left-0 right-0 rounded-t-2xl max-h-[95dvh] flex flex-col',
9
+ top: 'top-0 left-0 right-0 rounded-b-2xl max-h-[95dvh] flex flex-col',
10
+ left: 'left-0 top-0 bottom-0 rounded-r-2xl w-[400px] h-full flex flex-col',
11
+ right: 'right-0 top-0 bottom-0 rounded-l-2xl w-[400px] h-full flex flex-col',
12
+ };
13
+ const Drawer = ({ open, defaultOpen, onOpenChange, direction = 'bottom', snapPoints, activeSnapPoint, setActiveSnapPoint, title, description, children, buttons, trigger, showHandle, className, style, onButtonClick, }) => {
14
+ const isVertical = direction === 'bottom' || direction === 'top';
15
+ const shouldShowHandle = showHandle ?? isVertical;
16
+ const handleButtonClick = async (button) => {
17
+ let shouldClose = true;
18
+ if (button.onClick) {
19
+ const res = await button.onClick();
20
+ if (res === false)
21
+ shouldClose = false;
22
+ }
23
+ if (shouldClose) {
24
+ onButtonClick?.(button.value);
25
+ onOpenChange?.(false);
26
+ }
27
+ };
28
+ return (_jsxs(DrawerBase.Root, { open: open, defaultOpen: defaultOpen, onOpenChange: onOpenChange, direction: direction, snapPoints: snapPoints, activeSnapPoint: activeSnapPoint, setActiveSnapPoint: setActiveSnapPoint, children: [trigger && _jsx(DrawerBase.Trigger, { asChild: true, children: trigger }), _jsx(DrawerBase.Overlay, {}), _jsxs(DrawerBase.Content, { className: cn('bg-white', directionClasses[direction], className), style: style, children: [shouldShowHandle && _jsx(DrawerBase.Handle, {}), _jsxs("div", { className: "relative flex flex-col flex-1 overflow-hidden p-5 gap-6", children: [_jsx(DrawerBase.Close, { asChild: true, children: _jsx("button", { className: "absolute top-4 right-5 text-neutral500 cursor-pointer outline-hidden", children: _jsx(LucideIcon, { name: "x", size: 16 }) }) }), (title || description) && (_jsxs("div", { className: "flex flex-col gap-2 pt-2", children: [title && (_jsx(DrawerBase.Title, { className: "display20 bold", children: title })), description && (_jsx(DrawerBase.Description, { className: "display14 text-neutral500", children: description }))] })), children && _jsx("div", { className: "flex-1 overflow-auto", children: children }), buttons && buttons.length > 0 && (_jsx("div", { className: "flex gap-2", children: buttons.map((button, index) => (_jsx(Button, { block: true, variant: button.variant, color: button.color, onClick: () => handleButtonClick(button), children: button.label }, index))) }))] })] })] }));
29
+ };
30
+ export default Drawer;
@@ -0,0 +1,52 @@
1
+ import { type ReactNode } from 'react';
2
+ interface RootProps {
3
+ open?: boolean;
4
+ defaultOpen?: boolean;
5
+ onOpenChange?: (open: boolean) => void;
6
+ direction?: 'bottom' | 'top' | 'left' | 'right';
7
+ snapPoints?: (number | string)[];
8
+ activeSnapPoint?: number | string | null;
9
+ setActiveSnapPoint?: (snapPoint: number | string | null) => void;
10
+ children?: ReactNode;
11
+ }
12
+ interface TriggerProps {
13
+ asChild?: boolean;
14
+ className?: string;
15
+ children?: ReactNode;
16
+ }
17
+ interface OverlayProps {
18
+ className?: string;
19
+ }
20
+ interface ContentProps {
21
+ className?: string;
22
+ children?: ReactNode;
23
+ style?: React.CSSProperties;
24
+ }
25
+ interface HandleProps {
26
+ className?: string;
27
+ }
28
+ interface CloseProps {
29
+ asChild?: boolean;
30
+ className?: string;
31
+ children?: ReactNode;
32
+ }
33
+ interface TitleProps {
34
+ className?: string;
35
+ children?: ReactNode;
36
+ }
37
+ interface DescriptionProps {
38
+ className?: string;
39
+ children?: ReactNode;
40
+ }
41
+ export declare const DrawerBase: {
42
+ Root: ({ open, defaultOpen, onOpenChange, direction, snapPoints, activeSnapPoint, setActiveSnapPoint, children, }: RootProps) => import("react/jsx-runtime").JSX.Element;
43
+ Trigger: ({ asChild, className, children }: TriggerProps) => import("react/jsx-runtime").JSX.Element;
44
+ Overlay: ({ className }: OverlayProps) => import("react/jsx-runtime").JSX.Element;
45
+ Content: ({ className, children, style }: ContentProps) => import("react/jsx-runtime").JSX.Element;
46
+ Handle: ({ className }: HandleProps) => import("react/jsx-runtime").JSX.Element;
47
+ Close: ({ asChild, className, children }: CloseProps) => import("react/jsx-runtime").JSX.Element;
48
+ Title: ({ className, children }: TitleProps) => import("react/jsx-runtime").JSX.Element;
49
+ Description: ({ className, children }: DescriptionProps) => import("react/jsx-runtime").JSX.Element;
50
+ };
51
+ export default DrawerBase;
52
+ //# sourceMappingURL=DrawerBase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DrawerBase.d.ts","sourceRoot":"","sources":["../../../src/components/Drawer/DrawerBase.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,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,SAAS,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAAC;IAEhD,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACzC,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA4BD,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,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAaD,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAgBD,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAcD,UAAU,UAAU;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAWD,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAOD,UAAU,gBAAgB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD,eAAO,MAAM,UAAU;uHArHpB,SAAS;gDAuBuC,YAAY;6BAa/B,YAAY;8CAiBK,YAAY;4BAkB9B,WAAW;8CAkBO,UAAU;qCAcnB,UAAU;2CAUJ,gBAAgB;CAa7D,CAAC;AAEF,eAAe,UAAU,CAAC"}