@loword/loword-design-system 0.0.10 → 0.0.13

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 (266) hide show
  1. package/dist/components/LDAccordion/AccordionBase.d.ts +41 -0
  2. package/dist/components/LDAccordion/AccordionBase.d.ts.map +1 -0
  3. package/dist/components/LDAccordion/AccordionBase.js +24 -0
  4. package/dist/components/LDAccordion/LDAccordion.d.ts +31 -0
  5. package/dist/components/LDAccordion/LDAccordion.d.ts.map +1 -0
  6. package/dist/components/LDAccordion/LDAccordion.js +21 -0
  7. package/dist/components/LDAutoComplete/AutoCompleteBase.js +6 -6
  8. package/dist/components/LDAvatar/LDAvatar.d.ts +1 -1
  9. package/dist/components/LDAvatar/LDAvatar.d.ts.map +1 -1
  10. package/dist/components/LDAvatar/LDAvatar.js +19 -10
  11. package/dist/components/LDBadge/LDBadge.d.ts +5 -6
  12. package/dist/components/LDBadge/LDBadge.d.ts.map +1 -1
  13. package/dist/components/LDBadge/LDBadge.js +2 -2
  14. package/dist/components/LDBreadCrumb/LDBreadCrumb.d.ts +1 -2
  15. package/dist/components/LDBreadCrumb/LDBreadCrumb.d.ts.map +1 -1
  16. package/dist/components/LDButton/LDButton.d.ts +3 -3
  17. package/dist/components/LDButton/LDButton.d.ts.map +1 -1
  18. package/dist/components/LDButton/LDButton.js +5 -5
  19. package/dist/components/LDCalendar/CalendarBase.d.ts +17 -0
  20. package/dist/components/LDCalendar/CalendarBase.d.ts.map +1 -0
  21. package/dist/components/LDCalendar/CalendarBase.js +49 -0
  22. package/dist/components/LDCalendar/LDCalendar.d.ts +8 -14
  23. package/dist/components/LDCalendar/LDCalendar.d.ts.map +1 -1
  24. package/dist/components/LDCalendar/LDCalendar.js +51 -39
  25. package/dist/components/LDCarousel/CarouselBase.d.ts +3 -3
  26. package/dist/components/LDCarousel/CarouselBase.d.ts.map +1 -1
  27. package/dist/components/LDCarousel/CarouselBase.js +12 -6
  28. package/dist/components/LDCarousel/LDCarousel.d.ts +7 -8
  29. package/dist/components/LDCarousel/LDCarousel.d.ts.map +1 -1
  30. package/dist/components/LDCarousel/LDCarousel.js +2 -2
  31. package/dist/components/LDCheckbox/CheckboxBase.d.ts +1 -3
  32. package/dist/components/LDCheckbox/CheckboxBase.d.ts.map +1 -1
  33. package/dist/components/LDCheckbox/CheckboxBase.js +4 -4
  34. package/dist/components/LDCheckbox/LDCheckbox.d.ts +2 -5
  35. package/dist/components/LDCheckbox/LDCheckbox.d.ts.map +1 -1
  36. package/dist/components/LDCheckbox/LDCheckbox.js +66 -8
  37. package/dist/components/LDCheckbox/LDCheckboxGroup.d.ts +3 -3
  38. package/dist/components/LDCheckbox/LDCheckboxGroup.d.ts.map +1 -1
  39. package/dist/components/LDCheckbox/LDCheckboxGroup.js +11 -2
  40. package/dist/components/LDCheckbox/LDFormCheckbox.d.ts +12 -0
  41. package/dist/components/LDCheckbox/LDFormCheckbox.d.ts.map +1 -0
  42. package/dist/components/LDCheckbox/LDFormCheckbox.js +8 -0
  43. package/dist/components/LDCheckbox/LDFormCheckboxGroup.d.ts +11 -0
  44. package/dist/components/LDCheckbox/LDFormCheckboxGroup.d.ts.map +1 -0
  45. package/dist/components/LDCheckbox/LDFormCheckboxGroup.js +8 -0
  46. package/dist/components/LDDataCalendar/DataCalendarBase.d.ts +17 -1
  47. package/dist/components/LDDataCalendar/DataCalendarBase.d.ts.map +1 -1
  48. package/dist/components/LDDataCalendar/DataCalendarBase.js +34 -4
  49. package/dist/components/LDDataCalendar/LDDataCalendar.d.ts +27 -10
  50. package/dist/components/LDDataCalendar/LDDataCalendar.d.ts.map +1 -1
  51. package/dist/components/LDDataCalendar/LDDataCalendar.js +8 -8
  52. package/dist/components/LDDatePicker/LDDatePicker.d.ts +10 -4
  53. package/dist/components/LDDatePicker/LDDatePicker.d.ts.map +1 -1
  54. package/dist/components/LDDatePicker/LDDatePicker.js +95 -25
  55. package/dist/components/LDDatePicker/LDFormDatePicker.d.ts +13 -0
  56. package/dist/components/LDDatePicker/LDFormDatePicker.d.ts.map +1 -0
  57. package/dist/components/LDDatePicker/LDFormDatePicker.js +15 -0
  58. package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts +13 -6
  59. package/dist/components/LDDateRangePicker/LDDateRangePicker.d.ts.map +1 -1
  60. package/dist/components/LDDateRangePicker/LDDateRangePicker.js +143 -93
  61. package/dist/components/LDDateRangePicker/LDFormDateRangePicker.d.ts +13 -0
  62. package/dist/components/LDDateRangePicker/LDFormDateRangePicker.d.ts.map +1 -0
  63. package/dist/components/LDDateRangePicker/LDFormDateRangePicker.js +20 -0
  64. package/dist/components/LDDrawer/LDDrawer.d.ts +2 -0
  65. package/dist/components/LDDrawer/LDDrawer.d.ts.map +1 -1
  66. package/dist/components/LDDrawer/LDDrawer.js +2 -2
  67. package/dist/components/LDEditor/LDEditor.d.ts.map +1 -1
  68. package/dist/components/LDEditor/LDEditor.js +94 -54
  69. package/dist/components/LDEmpty/EmptyBase.d.ts +19 -0
  70. package/dist/components/LDEmpty/EmptyBase.d.ts.map +1 -0
  71. package/dist/components/LDEmpty/EmptyBase.js +18 -0
  72. package/dist/components/LDEmpty/LDEmpty.d.ts +35 -0
  73. package/dist/components/LDEmpty/LDEmpty.d.ts.map +1 -0
  74. package/dist/components/LDEmpty/LDEmpty.js +30 -0
  75. package/dist/components/LDFileUpload/FileUploadBase.d.ts +11 -3
  76. package/dist/components/LDFileUpload/FileUploadBase.d.ts.map +1 -1
  77. package/dist/components/LDFileUpload/FileUploadBase.js +21 -21
  78. package/dist/components/LDFileUpload/LDFileUpload.d.ts +3 -0
  79. package/dist/components/LDFileUpload/LDFileUpload.d.ts.map +1 -1
  80. package/dist/components/LDFileUpload/LDFileUpload.js +3 -3
  81. package/dist/components/LDFileUpload/LDFileUploadList.d.ts +3 -0
  82. package/dist/components/LDFileUpload/LDFileUploadList.d.ts.map +1 -1
  83. package/dist/components/LDFileUpload/LDFileUploadList.js +1 -3
  84. package/dist/components/LDFileUpload/LDImageUpload.d.ts +5 -0
  85. package/dist/components/LDFileUpload/LDImageUpload.d.ts.map +1 -1
  86. package/dist/components/LDFileUpload/LDImageUpload.js +5 -3
  87. package/dist/components/LDFileUpload/LDImageUploadList.d.ts +3 -0
  88. package/dist/components/LDFileUpload/LDImageUploadList.d.ts.map +1 -1
  89. package/dist/components/LDFileUpload/LDImageUploadList.js +1 -3
  90. package/dist/components/LDForm/LDFormErrorMessage.d.ts +3 -1
  91. package/dist/components/LDForm/LDFormErrorMessage.d.ts.map +1 -1
  92. package/dist/components/LDForm/LDFormErrorMessage.js +2 -2
  93. package/dist/components/LDInput/InputBase.d.ts +5 -3
  94. package/dist/components/LDInput/InputBase.d.ts.map +1 -1
  95. package/dist/components/LDInput/InputBase.js +4 -4
  96. package/dist/components/LDInput/LDFormInput.d.ts +1 -1
  97. package/dist/components/LDInput/LDFormInput.d.ts.map +1 -1
  98. package/dist/components/LDInput/LDFormInput.js +17 -14
  99. package/dist/components/LDInput/LDInput.d.ts +10 -3
  100. package/dist/components/LDInput/LDInput.d.ts.map +1 -1
  101. package/dist/components/LDInput/LDInput.js +114 -50
  102. package/dist/components/LDLNB/LDLNB.d.ts +42 -0
  103. package/dist/components/LDLNB/LDLNB.d.ts.map +1 -0
  104. package/dist/components/LDLNB/LDLNB.js +34 -0
  105. package/dist/components/LDLNB/LDLNBBase.d.ts +5 -13
  106. package/dist/components/LDLNB/LDLNBBase.d.ts.map +1 -1
  107. package/dist/components/LDLNB/LDLNBBase.js +52 -18
  108. package/dist/components/LDMenuBar/LDMenuBar.d.ts +33 -19
  109. package/dist/components/LDMenuBar/LDMenuBar.d.ts.map +1 -1
  110. package/dist/components/LDMenuBar/LDMenuBar.js +13 -27
  111. package/dist/components/LDMenuBar/MenuBarBase.d.ts +4 -5
  112. package/dist/components/LDMenuBar/MenuBarBase.d.ts.map +1 -1
  113. package/dist/components/LDMenuBar/MenuBarBase.js +12 -14
  114. package/dist/components/LDModal/LDModal.d.ts +20 -40
  115. package/dist/components/LDModal/LDModal.d.ts.map +1 -1
  116. package/dist/components/LDModal/LDModal.js +56 -70
  117. package/dist/components/LDModal/LDModalView.d.ts +59 -0
  118. package/dist/components/LDModal/LDModalView.d.ts.map +1 -0
  119. package/dist/components/LDModal/LDModalView.js +72 -0
  120. package/dist/components/LDNotification/LDNotification.d.ts +40 -0
  121. package/dist/components/LDNotification/LDNotification.d.ts.map +1 -0
  122. package/dist/components/LDNotification/LDNotification.js +76 -0
  123. package/dist/components/LDNotification/NotificationBase.d.ts +29 -0
  124. package/dist/components/LDNotification/NotificationBase.d.ts.map +1 -0
  125. package/dist/components/LDNotification/NotificationBase.js +27 -0
  126. package/dist/components/LDOTPInput/LDFormOTPInput.d.ts +15 -0
  127. package/dist/components/LDOTPInput/LDFormOTPInput.d.ts.map +1 -0
  128. package/dist/components/LDOTPInput/LDFormOTPInput.js +8 -0
  129. package/dist/components/LDOTPInput/LDOTPInput.d.ts +10 -22
  130. package/dist/components/LDOTPInput/LDOTPInput.d.ts.map +1 -1
  131. package/dist/components/LDOTPInput/LDOTPInput.js +44 -72
  132. package/dist/components/LDOTPInput/OTPInputBase.d.ts +46 -0
  133. package/dist/components/LDOTPInput/OTPInputBase.d.ts.map +1 -0
  134. package/dist/components/LDOTPInput/OTPInputBase.js +48 -0
  135. package/dist/components/LDPagination/LDPagination.d.ts +5 -1
  136. package/dist/components/LDPagination/LDPagination.d.ts.map +1 -1
  137. package/dist/components/LDPagination/LDPagination.js +3 -1
  138. package/dist/components/LDPagination/PaginationBase.d.ts +13 -4
  139. package/dist/components/LDPagination/PaginationBase.d.ts.map +1 -1
  140. package/dist/components/LDPagination/PaginationBase.js +8 -7
  141. package/dist/components/LDPopover/LDPopover.d.ts +1 -1
  142. package/dist/components/LDPopover/LDPopover.d.ts.map +1 -1
  143. package/dist/components/LDPopover/LDPopover.js +8 -7
  144. package/dist/components/LDProgressBar/LDProgressBar.d.ts +16 -0
  145. package/dist/components/LDProgressBar/LDProgressBar.d.ts.map +1 -0
  146. package/dist/components/LDProgressBar/LDProgressBar.js +9 -0
  147. package/dist/components/LDProgressBar/ProgressBarBase.d.ts +11 -0
  148. package/dist/components/LDProgressBar/ProgressBarBase.d.ts.map +1 -0
  149. package/dist/components/LDProgressBar/ProgressBarBase.js +10 -0
  150. package/dist/components/LDRadio/LDFormRadioGroup.d.ts +11 -0
  151. package/dist/components/LDRadio/LDFormRadioGroup.d.ts.map +1 -0
  152. package/dist/components/LDRadio/LDFormRadioGroup.js +8 -0
  153. package/dist/components/LDRadio/LDRadio.d.ts +2 -2
  154. package/dist/components/LDRadio/LDRadio.d.ts.map +1 -1
  155. package/dist/components/LDRadio/LDRadio.js +70 -15
  156. package/dist/components/LDRadio/LDRadioGroup.d.ts +5 -3
  157. package/dist/components/LDRadio/LDRadioGroup.d.ts.map +1 -1
  158. package/dist/components/LDRadio/LDRadioGroup.js +11 -2
  159. package/dist/components/LDRadio/RadioBase.d.ts +2 -3
  160. package/dist/components/LDRadio/RadioBase.d.ts.map +1 -1
  161. package/dist/components/LDRadio/RadioBase.js +7 -4
  162. package/dist/components/LDSectionNav/LDSectionNav.d.ts +11 -0
  163. package/dist/components/LDSectionNav/LDSectionNav.d.ts.map +1 -0
  164. package/dist/components/LDSectionNav/LDSectionNav.js +11 -0
  165. package/dist/components/LDSectionNav/SectionNavBase.d.ts +20 -0
  166. package/dist/components/LDSectionNav/SectionNavBase.d.ts.map +1 -0
  167. package/dist/components/LDSectionNav/SectionNavBase.js +53 -0
  168. package/dist/components/LDSelect/LDFormMultiSelect.d.ts +13 -0
  169. package/dist/components/LDSelect/LDFormMultiSelect.d.ts.map +1 -0
  170. package/dist/components/LDSelect/{FormMultiSelect.js → LDFormMultiSelect.js} +2 -2
  171. package/dist/components/LDSelect/LDFormSelect.d.ts +13 -0
  172. package/dist/components/LDSelect/LDFormSelect.d.ts.map +1 -0
  173. package/dist/components/LDSelect/LDFormSelect.js +10 -0
  174. package/dist/components/LDSelect/LDMultiSelect.d.ts +6 -3
  175. package/dist/components/LDSelect/LDMultiSelect.d.ts.map +1 -1
  176. package/dist/components/LDSelect/LDMultiSelect.js +35 -31
  177. package/dist/components/LDSelect/LDSelect.d.ts +6 -3
  178. package/dist/components/LDSelect/LDSelect.d.ts.map +1 -1
  179. package/dist/components/LDSelect/LDSelect.js +37 -30
  180. package/dist/components/LDSelect/SelectBase.d.ts.map +1 -1
  181. package/dist/components/LDSelect/SelectBase.js +21 -7
  182. package/dist/components/LDSpinner/LDSpinner.d.ts +1 -1
  183. package/dist/components/LDSpinner/LDSpinner.d.ts.map +1 -1
  184. package/dist/components/LDSpinner/LDSpinner.js +6 -6
  185. package/dist/components/LDTable/LDCollapsibleTanstackTable.d.ts.map +1 -1
  186. package/dist/components/LDTable/LDCollapsibleTanstackTable.js +12 -9
  187. package/dist/components/LDTable/LDTable.d.ts.map +1 -1
  188. package/dist/components/LDTable/LDTable.js +1 -1
  189. package/dist/components/LDTable/LDTanstackTable.d.ts.map +1 -1
  190. package/dist/components/LDTable/LDTanstackTable.js +6 -7
  191. package/dist/components/LDTable/TableField.d.ts +1 -1
  192. package/dist/components/LDTable/TableField.d.ts.map +1 -1
  193. package/dist/components/LDTextarea/LDFormTextarea.d.ts +14 -0
  194. package/dist/components/LDTextarea/LDFormTextarea.d.ts.map +1 -0
  195. package/dist/components/LDTextarea/{FormTextarea.js → LDFormTextarea.js} +2 -2
  196. package/dist/components/LDTextarea/LDTextarea.d.ts +1 -1
  197. package/dist/components/LDTextarea/LDTextarea.d.ts.map +1 -1
  198. package/dist/components/LDTextarea/LDTextarea.js +30 -30
  199. package/dist/components/LDTimePicker/LDFormTimePicker.d.ts +12 -0
  200. package/dist/components/LDTimePicker/LDFormTimePicker.d.ts.map +1 -0
  201. package/dist/components/LDTimePicker/{FormTimePicker.js → LDFormTimePicker.js} +3 -3
  202. package/dist/components/LDTimePicker/LDTimePicker.js +3 -3
  203. package/dist/components/LDToast/LDToast.js +1 -1
  204. package/dist/components/LDToast/LDToaster.d.ts +2 -1
  205. package/dist/components/LDToast/LDToaster.d.ts.map +1 -1
  206. package/dist/components/LDToast/LDToaster.js +2 -2
  207. package/dist/components/LDToggleButton/LDFormToggleButton.d.ts +10 -0
  208. package/dist/components/LDToggleButton/LDFormToggleButton.d.ts.map +1 -0
  209. package/dist/components/LDToggleButton/LDFormToggleButton.js +8 -0
  210. package/dist/components/LDTooltip/LDTooltip.js +1 -1
  211. package/dist/components/LDTooltip/TooltipBase.d.ts +6 -2
  212. package/dist/components/LDTooltip/TooltipBase.d.ts.map +1 -1
  213. package/dist/components/LDTooltip/TooltipBase.js +4 -4
  214. package/dist/index.css +913 -307
  215. package/dist/index.d.ts +28 -19
  216. package/dist/index.d.ts.map +1 -1
  217. package/dist/index.js +32 -20
  218. package/dist/utils/file.d.ts +2 -2
  219. package/dist/utils/file.d.ts.map +1 -1
  220. package/dist/utils/file.js +26 -23
  221. package/dist/utils/renderIcon.d.ts +1 -2
  222. package/dist/utils/renderIcon.d.ts.map +1 -1
  223. package/dist/utils/renderIcon.js +5 -4
  224. package/package.json +14 -2
  225. package/src/styles/carousel.css +15 -14
  226. package/src/styles/components/button.css +2 -2
  227. package/src/styles/components/editor.css +6 -0
  228. package/src/styles/components/index.css +1 -0
  229. package/src/styles/components/input.css +16 -2
  230. package/src/styles/components/select.css +61 -0
  231. package/src/styles/components/shared.css +6 -6
  232. package/src/styles/motion.css +115 -0
  233. package/src/theme.css +3 -0
  234. package/dist/components/Icon/LucideIcon.d.ts +0 -12
  235. package/dist/components/Icon/LucideIcon.d.ts.map +0 -1
  236. package/dist/components/Icon/LucideIcon.js +0 -49
  237. package/dist/components/LDCheckbox/FormCheckbox.d.ts +0 -14
  238. package/dist/components/LDCheckbox/FormCheckbox.d.ts.map +0 -1
  239. package/dist/components/LDCheckbox/FormCheckbox.js +0 -9
  240. package/dist/components/LDCheckbox/FormCheckboxGroup.d.ts +0 -13
  241. package/dist/components/LDCheckbox/FormCheckboxGroup.d.ts.map +0 -1
  242. package/dist/components/LDCheckbox/FormCheckboxGroup.js +0 -9
  243. package/dist/components/LDDatePicker/FormDatePicker.d.ts +0 -12
  244. package/dist/components/LDDatePicker/FormDatePicker.d.ts.map +0 -1
  245. package/dist/components/LDDatePicker/FormDatePicker.js +0 -12
  246. package/dist/components/LDDateRangePicker/FormDateRangePicker.d.ts +0 -12
  247. package/dist/components/LDDateRangePicker/FormDateRangePicker.d.ts.map +0 -1
  248. package/dist/components/LDDateRangePicker/FormDateRangePicker.js +0 -10
  249. package/dist/components/LDModal/openModal.d.ts +0 -24
  250. package/dist/components/LDModal/openModal.d.ts.map +0 -1
  251. package/dist/components/LDModal/openModal.js +0 -52
  252. package/dist/components/LDRadio/FormRadioGroup.d.ts +0 -13
  253. package/dist/components/LDRadio/FormRadioGroup.d.ts.map +0 -1
  254. package/dist/components/LDRadio/FormRadioGroup.js +0 -9
  255. package/dist/components/LDSelect/FormMultiSelect.d.ts +0 -13
  256. package/dist/components/LDSelect/FormMultiSelect.d.ts.map +0 -1
  257. package/dist/components/LDSelect/FormSelect.d.ts +0 -13
  258. package/dist/components/LDSelect/FormSelect.d.ts.map +0 -1
  259. package/dist/components/LDSelect/FormSelect.js +0 -10
  260. package/dist/components/LDTextarea/FormTextarea.d.ts +0 -14
  261. package/dist/components/LDTextarea/FormTextarea.d.ts.map +0 -1
  262. package/dist/components/LDTimePicker/FormTimePicker.d.ts +0 -12
  263. package/dist/components/LDTimePicker/FormTimePicker.d.ts.map +0 -1
  264. package/dist/components/LDToggleButton/FormToggleButton.d.ts +0 -12
  265. package/dist/components/LDToggleButton/FormToggleButton.d.ts.map +0 -1
  266. package/dist/components/LDToggleButton/FormToggleButton.js +0 -9
@@ -1,121 +1,171 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useState } from 'react';
3
+ import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
4
4
  import dayjs from 'dayjs';
5
5
  import { ko } from 'react-day-picker/locale';
6
6
  import PopoverBase from '../LDPopover/PopoverBase.js';
7
- import LDCalendar from '../LDCalendar/LDCalendar.js';
8
- import LucideIcon from '../Icon/LucideIcon.js';
7
+ import LDCalendar, { TimePicker } from '../LDCalendar/LDCalendar.js';
8
+ import LDButton from '../LDButton/LDButton.js';
9
9
  import cn from '../../utils/cn.js';
10
+ import { Calendar, ChevronLeft, ChevronRight, RotateCw } from 'lucide-react';
11
+ import LDDivider from '../../components/LDDivider/LDDivider.js';
10
12
  const dateFormats = {
11
- daily: 'YYYY-MM-DD',
12
- monthly: 'YYYY-MM',
13
+ daily: 'YYYYMMDD',
14
+ monthly: 'YYYYMM',
13
15
  yearly: 'YYYY',
14
16
  };
15
- const placeholders = {
16
- daily: 'YYYY-MM-DD ~ YYYY-MM-DD',
17
- monthly: 'YYYY-MM ~ YYYY-MM',
18
- yearly: 'YYYY ~ YYYY',
17
+ const timeFromDate = (date) => date ? dayjs(date).format('HH:mm:ss') : '00:00:00';
18
+ const composeDateTime = (date, time) => {
19
+ const [h, m, s] = time.split(':').map(Number);
20
+ return dayjs(date)
21
+ .hour(h ?? 0)
22
+ .minute(m ?? 0)
23
+ .second(s ?? 0)
24
+ .toDate();
19
25
  };
20
- const LDDateRangePicker = ({ 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-mono400" })), onRangeComplete, onResetComplete, className, style, triggerClassName, }) => {
26
+ const variantColorClasses = {
27
+ filled: {
28
+ neutral: 'bg-neutral50 text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] focus:bg-tintBlue focus:outline-lb500',
29
+ point: 'bg-tintBlue text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] focus:outline-lb500',
30
+ danger: 'bg-tintRed text-neutral900 border-none outline-2 outline-transparent [outline-style:solid] [outline-offset:-2px] outline-danger600',
31
+ },
32
+ outline: {
33
+ neutral: 'bg-transparent text-neutral900 border-none outline-2 outline-neutral100 [outline-style:solid] [outline-offset:-2px] focus:outline-lb500',
34
+ point: 'bg-transparent text-neutral900 border-none outline-2 outline-lb500 [outline-style:solid] [outline-offset:-2px]',
35
+ danger: 'bg-transparent text-neutral900 border-none outline-2 outline-danger600 [outline-style:solid] [outline-offset:-2px]',
36
+ },
37
+ };
38
+ const LDDateRangePicker = ({ variant = 'filled', value, onChange, disabled = false, block = false, color = 'neutral', placeholder, dateFormat, timeFormat = 'HH:MM:SS', isDisableAfterNow = false, isAutoClose = false, viewMode = 'daily', initialValue, trailingIcon = _jsx(Calendar, { size: 15, className: "text-mono400" }), onRangeComplete, onResetComplete, className, style, triggerClassName, }) => {
39
+ const fmt = dateFormat ?? dateFormats[viewMode];
40
+ const normalizedTimeFormat = timeFormat
41
+ .replaceAll('M', 'm')
42
+ .replaceAll('S', 's');
21
43
  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];
44
+ const [leftMonth, setLeftMonth] = useState(new Date());
45
+ const [rightMonth, setRightMonth] = useState(dayjs().add(1, 'month').toDate());
46
+ const [selectedRange, setSelectedRange] = useState(value);
47
+ const [fromTime, setFromTime] = useState(timeFromDate(value?.from));
48
+ const [toTime, setToTime] = useState(timeFromDate(value?.to));
49
+ // 시간은 ref로도 들고 있어 select 핸들러가 시간 변경에도 참조 안정 유지(memo 스킵용)
50
+ const fromTimeRef = useRef(fromTime);
51
+ const toTimeRef = useRef(toTime);
52
+ fromTimeRef.current = fromTime;
53
+ toTimeRef.current = toTime;
54
+ // selectedRange(날짜)와 fromTime/toTime(시간)을 병합. 커밋·표시 시점에만 사용.
55
+ const composeRange = useCallback((r) => r?.from
56
+ ? {
57
+ from: composeDateTime(r.from, fromTimeRef.current),
58
+ to: r.to ? composeDateTime(r.to, toTimeRef.current) : undefined,
59
+ }
60
+ : undefined, []);
61
+ const isDateDisabled = useMemo(() => (isDisableAfterNow ? (date) => date > new Date() : false), [isDisableAfterNow]);
62
+ const leftEndMonth = useMemo(() => dayjs(rightMonth).subtract(1, 'month').toDate(), [rightMonth]);
63
+ const rightStartMonth = useMemo(() => dayjs(leftMonth).add(1, 'month').toDate(), [leftMonth]);
64
+ const baseline = initialValue
65
+ ? {
66
+ from: dayjs(initialValue.from).toDate(),
67
+ to: initialValue.to ? dayjs(initialValue.to).toDate() : undefined,
68
+ }
69
+ : undefined;
70
+ useEffect(() => {
71
+ if (open)
72
+ return;
73
+ setSelectedRange(value);
74
+ setFromTime(timeFromDate(value?.from));
75
+ setToTime(timeFromDate(value?.to));
76
+ }, [open, value]);
77
+ const displayRange = open ? composeRange(selectedRange) : value;
78
+ const displayFmt = viewMode === 'daily' ? `${fmt} ${normalizedTimeFormat}` : fmt;
79
+ const placeholderFmt = viewMode === 'daily' ? `${fmt} ${timeFormat}` : fmt;
80
+ const placeholderText = placeholder ?? `${placeholderFmt} ~ ${placeholderFmt}`;
26
81
  const renderDateRange = () => {
27
- if (!resolved?.from) {
28
- return _jsx("span", { className: "text-mono400", children: placeholders[viewMode] });
82
+ if (!displayRange?.from) {
83
+ return (_jsx("span", { className: "text-mono400 whitespace-nowrap", children: placeholderText }));
29
84
  }
30
- if (!resolved.to) {
31
- return (_jsxs("span", { className: "text-mono400", children: [dayjs(resolved.from).format(fmt), " ~", ' ', placeholders[viewMode].split(' ~ ')[1]] }));
85
+ if (!displayRange.to) {
86
+ return (_jsxs("span", { className: "text-mono400", children: [dayjs(displayRange.from).format(displayFmt), " ~ ", placeholderFmt] }));
32
87
  }
33
- return (_jsxs(_Fragment, { children: [dayjs(resolved.from).format(fmt), " ~ ", dayjs(resolved.to).format(fmt)] }));
88
+ return (_jsxs(_Fragment, { children: [dayjs(displayRange.from).format(displayFmt), " ~", ' ', dayjs(displayRange.to).format(displayFmt)] }));
89
+ };
90
+ const reset = (r) => {
91
+ setFromTime(timeFromDate(r?.from));
92
+ setToTime(timeFromDate(r?.to));
34
93
  };
94
+ // rotate: initialValue(baseline)로 복원. 기존 동작대로 즉시 커밋한다.
35
95
  const handleReset = (e) => {
36
96
  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);
97
+ setSelectedRange(baseline);
98
+ reset(baseline);
99
+ onChange?.(baseline);
46
100
  onResetComplete?.();
47
101
  };
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)
102
+ const formatRangeDate = (date) => date ? dayjs(date).format(fmt) : '';
103
+ const isResetAvailable = baseline?.from
104
+ ? formatRangeDate(selectedRange?.from) !== formatRangeDate(baseline.from) ||
105
+ formatRangeDate(selectedRange?.to) !== formatRangeDate(baseline.to) ||
106
+ // daily 모드는 시간 차이도 리셋 대상
107
+ (viewMode === 'daily' &&
108
+ (fromTime !== timeFromDate(baseline.from) ||
109
+ toTime !== timeFromDate(baseline.to)))
110
+ : !!selectedRange?.from;
111
+ const handleConfirm = () => {
112
+ onChange?.(composeRange(selectedRange));
113
+ setOpen(false);
114
+ };
115
+ const handleCancel = () => {
116
+ setSelectedRange(value);
117
+ reset(value);
118
+ setOpen(false);
119
+ };
120
+ const handleOpenChange = (next) => {
121
+ if (next) {
122
+ setSelectedRange(value); // 열 때 현재 값으로 편집 시작
123
+ reset(value);
124
+ setOpen(true);
54
125
  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
126
  }
127
+ // overlay·ESC: 선택이 있으면 커밋, 없으면 그냥 닫기
128
+ if (selectedRange?.from)
129
+ handleConfirm();
130
+ else
131
+ setOpen(false);
63
132
  };
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);
133
+ // 시간만 갱신 (selectedRange는 안 건드림 → 캘린더 selected 불변 → 애니메이션 재실행 X)
134
+ const handleFromTime = (time) => setFromTime(time);
135
+ const handleToTime = (time) => setToTime(time);
136
+ const handleRangeSelect = useCallback((range) => {
137
+ if (!range)
71
138
  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;
139
+ setSelectedRange(range);
140
+ if (range.from && range.to) {
141
+ const composed = composeRange(range);
142
+ onRangeComplete?.(composed);
143
+ if (isAutoClose) {
144
+ onChange?.(composed);
145
+ setOpen(false);
95
146
  }
96
147
  }
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);
148
+ }, [composeRange, isAutoClose, onChange, onRangeComplete]);
149
+ const handleDailySelect = useCallback((selected, clickedDate) => {
150
+ if (selectedRange?.from &&
151
+ !selectedRange.to &&
152
+ selected?.from &&
153
+ selected?.to) {
154
+ handleRangeSelect({ from: selected.from, to: selected.to });
155
+ return;
109
156
  }
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-neutral100 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-danger600'
113
- : 'focus-visible:bg-tintBlue focus-visible: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-mono400 cursor-pointer", onClick: handleReset, onKeyDown: (e) => {
157
+ setSelectedRange({ from: clickedDate, to: undefined });
158
+ }, [selectedRange, handleRangeSelect]);
159
+ return (_jsx("div", { className: cn(block ? 'w-full' : 'w-auto', className), children: _jsxs(PopoverBase.Root, { open: open, onOpenChange: handleOpenChange, 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', 'whitespace-nowrap outline-2 outline-transparent ld-transition', disabled
160
+ ? 'cursor-not-allowed opacity-50'
161
+ : variantColorClasses[variant][color], triggerClassName), children: [renderDateRange(), _jsxs("div", { className: "shrink-0 flex items-center gap-xs", children: [_jsx("span", { role: "button", tabIndex: 0, className: cn('inline-flex items-center text-mono400 cursor-pointer transition-opacity duration-300', isResetAvailable
162
+ ? 'opacity-100'
163
+ : 'opacity-0 pointer-events-none'), onClick: handleReset, onKeyDown: (e) => {
114
164
  if (e.key === 'Enter' || e.key === ' ') {
115
165
  e.preventDefault();
116
166
  handleReset(e);
117
167
  }
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(LDCalendar, { 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 }))] })] }) }));
168
+ }, children: _jsx(RotateCw, { size: 15 }) }), trailingIcon] })] }), _jsx(PopoverBase.Content, { className: "rounded-md border border-neutral-200 bg-white shadow-md p-0", children: _jsxs("div", { className: "flex flex-col", children: [viewMode === 'daily' && (_jsxs("div", { className: "flex flex-row mobile:flex-col", children: [_jsxs("div", { className: "flex flex-row max-h-90", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: leftMonth, onMonthChange: setLeftMonth, endMonth: leftEndMonth, disabled: isDateDisabled }), _jsx(TimePicker, { value: fromTime, onChange: handleFromTime, className: "shrink-0" })] }), _jsx(LDDivider, { orientation: "vertical", className: "h-auto self-stretch inline-block mobile:hidden" }), _jsx(LDDivider, { orientation: "horizontal", className: "w-auto self-stretch hidden mobile:inline-block" }), _jsxs("div", { className: "flex flex-row max-h-90", children: [_jsx(LDCalendar, { captionLayout: "dropdown", mode: "range", locale: ko, selected: selectedRange, onSelect: handleDailySelect, month: rightMonth, onMonthChange: setRightMonth, startMonth: rightStartMonth, disabled: isDateDisabled }), _jsx(TimePicker, { value: toTime, onChange: handleToTime, className: "shrink-0" })] })] })), viewMode === 'monthly' && (_jsx(MonthRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), viewMode === 'yearly' && (_jsx(YearRangePicker, { value: selectedRange, onChange: handleRangeSelect, isDisableAfterNow: isDisableAfterNow })), _jsxs("div", { className: "flex items-center justify-end gap-sm py-xs px-sm border-t border-neutral100", children: [_jsx(LDButton, { variant: "outline", color: "neutral", onClick: handleCancel, children: "\uCDE8\uC18C" }), _jsx(LDButton, { onClick: handleConfirm, children: "\uD655\uC778" })] })] }) })] }) }));
119
169
  };
120
170
  // ── MonthRangePicker ──
121
171
  const MonthRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
@@ -151,8 +201,8 @@ const MonthRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
151
201
  return false;
152
202
  return new Date(currentYear, month, 1) > dayjs(now).endOf('month').toDate();
153
203
  };
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'
204
+ 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(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(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)
205
+ ? 'bg-tintBlue text-lb500 bold'
156
206
  : 'hover:bg-neutral100 text-mono500', isDisabled(m) && 'opacity-30 cursor-not-allowed'), children: [m + 1, "\uC6D4"] }, m))) })] }));
157
207
  };
158
208
  // ── YearRangePicker ──
@@ -189,9 +239,9 @@ const YearRangePicker = ({ value, onChange, isDisableAfterNow, }) => {
189
239
  return false;
190
240
  return year > now.getFullYear();
191
241
  };
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'
242
+ 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(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 &&
243
+ (years[years.length - 1] ?? 0) >= now.getFullYear(), children: _jsx(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)
244
+ ? 'bg-tintBlue text-lb500 bold'
195
245
  : 'hover:bg-neutral100 text-mono500', isDisabled(y) && 'opacity-30 cursor-not-allowed'), children: [y, "\uB144"] }, y))) })] }));
196
246
  };
197
247
  export default LDDateRangePicker;
@@ -0,0 +1,13 @@
1
+ import { type RegisterOptions } from 'react-hook-form';
2
+ import { type LDDateRangePickerProps } from './LDDateRangePicker.js';
3
+ interface LDFormDateRangePickerProps extends Omit<LDDateRangePickerProps, 'value' | 'onChange'> {
4
+ name: string;
5
+ options?: RegisterOptions;
6
+ customErrorMessage?: string;
7
+ isHiddenErrorMessage?: boolean;
8
+ isToastErrorMessage?: boolean;
9
+ errorClassName?: string;
10
+ }
11
+ declare const LDFormDateRangePicker: ({ name, options, customErrorMessage, isHiddenErrorMessage, errorClassName, disabled, block, ...props }: LDFormDateRangePickerProps) => import("react/jsx-runtime").JSX.Element;
12
+ export default LDFormDateRangePicker;
13
+ //# sourceMappingURL=LDFormDateRangePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LDFormDateRangePicker.d.ts","sourceRoot":"","sources":["../../../src/components/LDDateRangePicker/LDFormDateRangePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,iBAAiB,CAAC;AACvE,OAA0B,EACxB,KAAK,sBAAsB,EAC5B,MAAM,qBAAqB,CAAC;AAK7B,UAAU,0BAA2B,SAAQ,IAAI,CAC/C,sBAAsB,EACtB,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,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,QAAA,MAAM,qBAAqB,GAAI,wGAS5B,0BAA0B,4CAyC5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useFormContext } from 'react-hook-form';
4
+ import LDDateRangePicker from './LDDateRangePicker.js';
5
+ import FormField from '../LDForm/LDFormField.js';
6
+ import FormErrorMessage from '../LDForm/LDFormErrorMessage.js';
7
+ import cn from '../../utils/cn.js';
8
+ const LDFormDateRangePicker = ({ name, options, customErrorMessage = '', isHiddenErrorMessage = true, errorClassName, disabled = false, block = false, ...props }) => {
9
+ const { formState } = useFormContext();
10
+ const defaultValue = formState.defaultValues?.[name];
11
+ const initialValue = props.initialValue ??
12
+ (defaultValue?.from
13
+ ? {
14
+ from: defaultValue.from,
15
+ to: defaultValue.to,
16
+ }
17
+ : undefined);
18
+ return (_jsx(FormField, { name: name, options: options, customErrorMessage: customErrorMessage, disabled: disabled, children: ({ field, fieldState }) => (_jsxs("div", { className: cn('relative', block ? 'w-full' : 'w-auto'), children: [_jsx(LDDateRangePicker, { ...props, block: block, value: field.value ?? undefined, initialValue: initialValue, onChange: field.onChange, disabled: disabled, color: fieldState.hasError ? 'danger' : (props.color ?? 'neutral') }), _jsx(FormErrorMessage, { error: fieldState.error, disabled: disabled, className: cn(isHiddenErrorMessage && 'hidden', errorClassName) })] })) }));
19
+ };
20
+ export default LDFormDateRangePicker;
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { ButtonSize } from '../LDButton/LDButton.js';
2
3
  type DrawerDirection = 'bottom' | 'top' | 'left' | 'right';
3
4
  export interface DrawerButton<T = unknown> {
4
5
  /** 버튼 텍스트 */
@@ -10,6 +11,7 @@ export interface DrawerButton<T = unknown> {
10
11
  /** 버튼 색상 테마 */
11
12
  color?: 'neutral' | 'point' | 'danger';
12
13
  /** 클릭 핸들러 (false 반환 시 LDDrawer 닫힘 방지) */
14
+ size?: ButtonSize;
13
15
  onClick?: () => void | boolean | Promise<void | boolean>;
14
16
  }
15
17
  export interface LDDrawerProps {
@@ -1 +1 @@
1
- {"version":3,"file":"LDDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/LDDrawer/LDDrawer.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,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,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,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,eAAe;IACf,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAUD,QAAA,MAAM,QAAQ,GAAI,+LAiBf,aAAa,4CAmFf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"LDDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/LDDrawer/LDDrawer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAiB,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAK5D,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,yCAAyC;IACzC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,aAAa;IAC5B,+BAA+B;IAC/B,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,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa;IACb,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,eAAe;IACf,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,0BAA0B;IAC1B,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,oCAAoC;IACpC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAUD,QAAA,MAAM,QAAQ,GAAI,+LAiBf,aAAa,4CAoFf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import DrawerBase from './DrawerBase.js';
3
- import LucideIcon from '../Icon/LucideIcon.js';
4
3
  import LDButton from '../LDButton/LDButton.js';
5
4
  import cn from '../../utils/cn.js';
5
+ import { X } from 'lucide-react';
6
6
  // ── 방향별 스타일 매핑 ──
7
7
  const directionClasses = {
8
8
  bottom: 'bottom-0 left-0 right-0 rounded-t-2xl max-h-[95dvh] flex flex-col',
@@ -25,6 +25,6 @@ const LDDrawer = ({ open, defaultOpen, onOpenChange, direction = 'bottom', snapP
25
25
  onOpenChange?.(false);
26
26
  }
27
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(LDButton, { block: true, variant: button.variant, color: button.color, onClick: () => handleButtonClick(button), children: button.label }, index))) }))] })] })] }));
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(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(LDButton, { block: true, size: button.size, variant: button.variant, color: button.color, onClick: () => handleButtonClick(button), children: button.label }, index))) }))] })] })] }));
29
29
  };
30
30
  export default LDDrawer;
@@ -1 +1 @@
1
- {"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AA0EA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC7B,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC9B;AAED,QAAA,MAAM,QAAQ,GAAI,sDAKf,aAAa,4CAYf,CAAC;AAmXF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"LDEditor.d.ts","sourceRoot":"","sources":["../../../src/components/LDEditor/LDEditor.tsx"],"names":[],"mappings":"AA2EA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAC7B,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;KAClB,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC9B;AAED,QAAA,MAAM,QAAQ,GAAI,sDAKf,aAAa,4CAYf,CAAC;AAyhBF,eAAe,QAAQ,CAAC"}
@@ -1,8 +1,9 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { AlignCenter, AlignJustify, AlignLeft, AlignRight, Bold, ChevronDown, Image as ImageIcon, Italic, Link2, List, ListOrdered, Redo, Strikethrough, Underline, Undo, Unlink, } from 'lucide-react';
4
- import { useState } from 'react';
4
+ import { useEffect, useState } from 'react';
5
5
  import { useEditorState } from '@tiptap/react';
6
+ import { BubbleMenu } from '@tiptap/react/menus';
6
7
  import EditorBase, { useEditorContext } from './EditorBase.js';
7
8
  import { createEditorExtensions } from './extensions.js';
8
9
  import cn from '../../utils/cn.js';
@@ -42,7 +43,16 @@ const LDEditor = ({ content, onChange, className, handleImageUpload, }) => {
42
43
  };
43
44
  const EditorToolbar = ({ handleImageUpload, }) => {
44
45
  const [linkUrl, setLinkUrl] = useState('');
46
+ const [isMobile, setIsMobile] = useState(false);
45
47
  const { editor } = useEditorContext();
48
+ // 모바일(<768px)에서는 인라인 서식을 버블 메뉴로 옮기고 상단 툴바는 슬림하게.
49
+ useEffect(() => {
50
+ const mql = window.matchMedia('(max-width: 767px)');
51
+ const sync = () => setIsMobile(mql.matches);
52
+ sync();
53
+ mql.addEventListener('change', sync);
54
+ return () => mql.removeEventListener('change', sync);
55
+ }, []);
46
56
  const state = useEditorState({
47
57
  editor,
48
58
  selector: ({ editor }) => {
@@ -105,58 +115,88 @@ const EditorToolbar = ({ handleImageUpload, }) => {
105
115
  };
106
116
  if (!editor || !state)
107
117
  return null;
108
- return (_jsxs(EditorBase.Toolbar, { className: "gap-5 px-4 py-3 rounded-t-md border border-neutral200", children: [_jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg min-w-[120px]", trigger: ({ toggle }) => (_jsx(EditorBase.Toolbar.LDButton, { onClick: toggle, className: cn(iconBtn, 'flex items-center gap-5 px-2'), children: _jsx("span", { className: "whitespace-nowrap min-w-10", children: state.headingLevel ? `제목 ${state.headingLevel}` : '본문' }) })), children: ({ close }) => HEADINGS.map(({ label, level }) => (_jsx("button", { type: "button", onClick: (e) => {
109
- e.preventDefault();
110
- if (level === 0)
111
- editor.chain().focus().setParagraph().run();
112
- else
113
- editor.chain().focus().toggleHeading({ level }).run();
114
- close();
115
- }, className: "w-full px-3 py-2 cursor-pointer text-left text-sm hover:bg-mono100 first:rounded-t-lg last:rounded-b-lg", children: label }, level))) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleBold().run(), className: cn(iconBtn, state.isBold && activeBtn), children: _jsx(Bold, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleItalic().run(), className: cn(iconBtn, state.isItalic && activeBtn), children: _jsx(Italic, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleUnderline().run(), className: cn(iconBtn, state.isUnderline && activeBtn), children: _jsx(Underline, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleStrike().run(), className: cn(iconBtn, state.isStrike && activeBtn), children: _jsx(Strikethrough, { className: "w-5 h-5" }) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.Dropdown, { className: "border border-neutral200 bg-white rounded-lg shadow-lg min-w-[100px]", trigger: ({ toggle }) => (_jsxs(EditorBase.Toolbar.LDButton, { onClick: toggle, className: cn(iconBtn, 'flex items-center gap-1 px-2'), children: [_jsx("span", { className: "text-sm whitespace-nowrap", children: state.fontSize }), _jsx(ChevronDown, { className: "w-4 h-4" })] })), children: ({ close }) => FONT_SIZES.map((size) => (_jsx("button", { type: "button", onClick: (e) => {
116
- e.preventDefault();
117
- editor.chain().focus().setFontSize(size).run();
118
- close();
119
- }, className: "w-full px-3 py-2 cursor-pointer text-left text-sm hover:bg-mono100 first:rounded-t-lg last:rounded-b-lg", children: size }, size))) }), _jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg min-w-[140px]", trigger: ({ toggle }) => (_jsxs(EditorBase.Toolbar.LDButton, { onClick: toggle, className: cn(iconBtn, 'flex items-center gap-2 px-2'), children: [_jsx("span", { className: "w-4 h-4 rounded-full", style: { backgroundColor: state.color } }), state.color, _jsx(ChevronDown, { className: "w-4 h-4" })] })), children: ({ close }) => COLORS.map((color) => (_jsxs("button", { type: "button", onClick: (e) => {
120
- e.preventDefault();
121
- editor.chain().focus().setColor(color.value).run();
122
- close();
123
- }, className: "flex items-center gap-2 w-full px-3 py-2 cursor-pointer text-left text-sm hover:bg-mono100 first:rounded-t-lg last:rounded-b-lg", children: [_jsx("span", { className: "w-4 h-4 rounded-full", style: { backgroundColor: color.value } }), _jsx("span", { children: color.label })] }, color.value))) }), _jsx(LDDivider, {}), ['left', 'center', 'right', 'justify'].map((align) => {
124
- const Icon = {
125
- left: AlignLeft,
126
- center: AlignCenter,
127
- right: AlignRight,
128
- justify: AlignJustify,
129
- }[align];
130
- return (_jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().setTextAlign(align).run(), className: cn(iconBtn, state.align[align] && activeBtn), children: _jsx(Icon, { className: "w-5 h-5" }) }, align));
131
- }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleBulletList().run(), className: cn(iconBtn, state.isBulletList && activeBtn), children: _jsx(List, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleOrderedList().run(), className: cn(iconBtn, state.isOrderedList && activeBtn), children: _jsx(ListOrdered, { className: "w-5 h-5" }) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canUndo, onClick: () => editor.chain().focus().undo().run(), className: iconBtn, children: _jsx(Undo, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canRedo, onClick: () => editor.chain().focus().redo().run(), className: iconBtn, children: _jsx(Redo, { className: "w-5 h-5" }) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg p-3 min-w-[280px]", trigger: ({ toggle }) => (_jsx(EditorBase.Toolbar.LDButton, { onClick: () => {
132
- setLinkUrl(editor.getAttributes('link').href || '');
133
- toggle();
134
- }, className: cn(iconBtn, state.isLink && activeBtn), children: _jsx(Link2, { className: "w-5 h-5" }) })), children: ({ close }) => {
135
- const applyLink = () => {
136
- const chain = editor.chain().focus().extendMarkRange('link');
137
- if (linkUrl === '') {
138
- chain.unsetLink().run();
139
- }
140
- else {
141
- const url = /^https?:\/\//.test(linkUrl)
142
- ? linkUrl
143
- : `https://${linkUrl}`;
144
- chain.setLink({ href: url }).run();
145
- }
146
- setLinkUrl('');
147
- close();
148
- };
149
- return (_jsxs(_Fragment, { children: [_jsx("input", { type: "text", autoFocus: true, placeholder: "URL\uC744 \uC785\uB825\uD558\uC138\uC694", value: linkUrl, onChange: (e) => setLinkUrl(e.target.value), onKeyDown: (e) => e.key === 'Enter' && applyLink(), className: "w-full px-3 py-2 border border-neutral200 rounded-lg text-sm outline-none transition duration-300 focus:border-blue-500" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: (e) => {
150
- e.preventDefault();
151
- applyLink();
152
- }, className: "flex-1 px-3 py-1.5 bg-blue-500 text-white rounded-lg text-sm transition duration-300 hover:bg-blue-600", children: "\uC801\uC6A9" }), _jsx("button", { type: "button", onClick: (e) => {
153
- e.preventDefault();
154
- setLinkUrl('');
155
- close();
156
- }, className: "px-3 py-1.5 border border-neutral200 rounded-lg text-sm transition duration-300 hover:bg-mono100", children: "\uCDE8\uC18C" })] })] }));
157
- } }), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.isLink, onClick: () => editor.chain().focus().unsetLink().run(), className: iconBtn, children: _jsx(Unlink, { className: "w-5 h-5" }) }), _jsx(LDDivider, {}), _jsxs("label", { className: cn(iconBtn, 'relative'), children: [_jsx(ImageIcon, { className: "w-5 h-5" }), _jsx("input", { type: "file", accept: "image/*", className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer", onChange: (e) => {
158
- handleImageUploadAction(e.target.files);
159
- e.target.value = '';
160
- } })] })] }));
118
+ return (_jsxs(_Fragment, { children: [_jsxs(EditorBase.Toolbar, { className: "gap-5 px-4 py-3 rounded-t-md border border-neutral200", children: [_jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg min-w-[120px]", trigger: ({ toggle }) => (_jsx(EditorBase.Toolbar.LDButton, { onClick: toggle, className: cn(iconBtn, 'flex items-center gap-5 px-2'), children: _jsx("span", { className: "whitespace-nowrap min-w-10", children: state.headingLevel ? `제목 ${state.headingLevel}` : '본문' }) })), children: ({ close }) => HEADINGS.map(({ label, level }) => (_jsx("button", { type: "button", onClick: (e) => {
119
+ e.preventDefault();
120
+ if (level === 0)
121
+ editor.chain().focus().setParagraph().run();
122
+ else
123
+ editor.chain().focus().toggleHeading({ level }).run();
124
+ close();
125
+ }, className: "w-full px-3 py-2 cursor-pointer text-left text-sm hover:bg-mono100 first:rounded-t-lg last:rounded-b-lg", children: label }, level))) }), !isMobile && (_jsxs(_Fragment, { children: [_jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleBold().run(), className: cn(iconBtn, state.isBold && activeBtn), children: _jsx(Bold, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleItalic().run(), className: cn(iconBtn, state.isItalic && activeBtn), children: _jsx(Italic, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleUnderline().run(), className: cn(iconBtn, state.isUnderline && activeBtn), children: _jsx(Underline, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleStrike().run(), className: cn(iconBtn, state.isStrike && activeBtn), children: _jsx(Strikethrough, { className: "w-5 h-5" }) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.Dropdown, { className: "border border-neutral200 bg-white rounded-lg shadow-lg min-w-[100px]", trigger: ({ toggle }) => (_jsxs(EditorBase.Toolbar.LDButton, { onClick: toggle, className: cn(iconBtn, 'flex items-center gap-1 px-2'), children: [_jsx("span", { className: "text-sm whitespace-nowrap", children: state.fontSize }), _jsx(ChevronDown, { className: "w-4 h-4" })] })), children: ({ close }) => FONT_SIZES.map((size) => (_jsx("button", { type: "button", onClick: (e) => {
126
+ e.preventDefault();
127
+ editor.chain().focus().setFontSize(size).run();
128
+ close();
129
+ }, className: "w-full px-3 py-2 cursor-pointer text-left text-sm hover:bg-mono100 first:rounded-t-lg last:rounded-b-lg", children: size }, size))) }), _jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg min-w-[140px]", trigger: ({ toggle }) => (_jsxs(EditorBase.Toolbar.LDButton, { onClick: toggle, className: cn(iconBtn, 'flex items-center gap-2 px-2'), children: [_jsx("span", { className: "w-4 h-4 rounded-full", style: { backgroundColor: state.color } }), state.color, _jsx(ChevronDown, { className: "w-4 h-4" })] })), children: ({ close }) => COLORS.map((color) => (_jsxs("button", { type: "button", onClick: (e) => {
130
+ e.preventDefault();
131
+ editor.chain().focus().setColor(color.value).run();
132
+ close();
133
+ }, className: "flex items-center gap-2 w-full px-3 py-2 cursor-pointer text-left text-sm hover:bg-mono100 first:rounded-t-lg last:rounded-b-lg", children: [_jsx("span", { className: "w-4 h-4 rounded-full", style: { backgroundColor: color.value } }), _jsx("span", { children: color.label })] }, color.value))) }), _jsx(LDDivider, {}), ['left', 'center', 'right', 'justify'].map((align) => {
134
+ const Icon = {
135
+ left: AlignLeft,
136
+ center: AlignCenter,
137
+ right: AlignRight,
138
+ justify: AlignJustify,
139
+ }[align];
140
+ return (_jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().setTextAlign(align).run(), className: cn(iconBtn, state.align[align] && activeBtn), children: _jsx(Icon, { className: "w-5 h-5" }) }, align));
141
+ })] })), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleBulletList().run(), className: cn(iconBtn, state.isBulletList && activeBtn), children: _jsx(List, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleOrderedList().run(), className: cn(iconBtn, state.isOrderedList && activeBtn), children: _jsx(ListOrdered, { className: "w-5 h-5" }) }), _jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canUndo, onClick: () => editor.chain().focus().undo().run(), className: iconBtn, children: _jsx(Undo, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.canRedo, onClick: () => editor.chain().focus().redo().run(), className: iconBtn, children: _jsx(Redo, { className: "w-5 h-5" }) }), !isMobile && (_jsxs(_Fragment, { children: [_jsx(LDDivider, {}), _jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg p-3 min-w-[280px]", trigger: ({ toggle }) => (_jsx(EditorBase.Toolbar.LDButton, { onClick: () => {
142
+ setLinkUrl(editor.getAttributes('link').href || '');
143
+ toggle();
144
+ }, className: cn(iconBtn, state.isLink && activeBtn), children: _jsx(Link2, { className: "w-5 h-5" }) })), children: ({ close }) => {
145
+ const applyLink = () => {
146
+ const chain = editor.chain().focus().extendMarkRange('link');
147
+ if (linkUrl === '') {
148
+ chain.unsetLink().run();
149
+ }
150
+ else {
151
+ const url = /^https?:\/\//.test(linkUrl)
152
+ ? linkUrl
153
+ : `https://${linkUrl}`;
154
+ chain.setLink({ href: url }).run();
155
+ }
156
+ setLinkUrl('');
157
+ close();
158
+ };
159
+ return (_jsxs(_Fragment, { children: [_jsx("input", { type: "text", autoFocus: true, placeholder: "URL\uC744 \uC785\uB825\uD558\uC138\uC694", value: linkUrl, onChange: (e) => setLinkUrl(e.target.value), onKeyDown: (e) => e.key === 'Enter' && applyLink(), className: "w-full px-3 py-2 border border-neutral200 rounded-lg text-sm outline-none transition duration-300 focus:border-blue-500" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: (e) => {
160
+ e.preventDefault();
161
+ applyLink();
162
+ }, className: "flex-1 px-3 py-1.5 bg-blue-500 text-white rounded-lg text-sm transition duration-300 hover:bg-blue-600", children: "\uC801\uC6A9" }), _jsx("button", { type: "button", onClick: (e) => {
163
+ e.preventDefault();
164
+ setLinkUrl('');
165
+ close();
166
+ }, className: "px-3 py-1.5 border border-neutral200 rounded-lg text-sm transition duration-300 hover:bg-mono100", children: "\uCDE8\uC18C" })] })] }));
167
+ } }), _jsx(EditorBase.Toolbar.LDButton, { disabled: !state.isLink, onClick: () => editor.chain().focus().unsetLink().run(), className: iconBtn, children: _jsx(Unlink, { className: "w-5 h-5" }) })] })), _jsx(LDDivider, {}), _jsxs("label", { className: cn(iconBtn, 'relative'), children: [_jsx(ImageIcon, { className: "w-5 h-5" }), _jsx("input", { type: "file", accept: "image/*", className: "absolute inset-0 w-full h-full opacity-0 cursor-pointer", onChange: (e) => {
168
+ handleImageUploadAction(e.target.files);
169
+ e.target.value = '';
170
+ } })] })] }), isMobile && (_jsxs(BubbleMenu, { editor: editor, className: "flex items-center gap-1 rounded-lg border border-neutral200 bg-white p-1 shadow-lg", children: [_jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleBold().run(), className: cn(iconBtn, state.isBold && activeBtn), children: _jsx(Bold, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleItalic().run(), className: cn(iconBtn, state.isItalic && activeBtn), children: _jsx(Italic, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleUnderline().run(), className: cn(iconBtn, state.isUnderline && activeBtn), children: _jsx(Underline, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.LDButton, { onClick: () => editor.chain().focus().toggleStrike().run(), className: cn(iconBtn, state.isStrike && activeBtn), children: _jsx(Strikethrough, { className: "w-5 h-5" }) }), _jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg min-w-[140px]", trigger: ({ toggle }) => (_jsxs(EditorBase.Toolbar.LDButton, { onClick: toggle, className: cn(iconBtn, 'flex items-center gap-1 px-2'), children: [_jsx("span", { className: "w-4 h-4 rounded-full", style: { backgroundColor: state.color } }), _jsx(ChevronDown, { className: "w-4 h-4" })] })), children: ({ close }) => COLORS.map((color) => (_jsxs("button", { type: "button", onClick: (e) => {
171
+ e.preventDefault();
172
+ editor.chain().focus().setColor(color.value).run();
173
+ close();
174
+ }, className: "flex items-center gap-2 w-full px-3 py-2 cursor-pointer text-left text-sm hover:bg-mono100 first:rounded-t-lg last:rounded-b-lg", children: [_jsx("span", { className: "w-4 h-4 rounded-full", style: { backgroundColor: color.value } }), _jsx("span", { children: color.label })] }, color.value))) }), _jsx(EditorBase.Toolbar.Dropdown, { className: "bg-white border border-neutral200 rounded-lg shadow-lg p-3 min-w-[240px]", trigger: ({ toggle }) => (_jsx(EditorBase.Toolbar.LDButton, { onClick: () => {
175
+ setLinkUrl(editor.getAttributes('link').href || '');
176
+ toggle();
177
+ }, className: cn(iconBtn, state.isLink && activeBtn), children: _jsx(Link2, { className: "w-5 h-5" }) })), children: ({ close }) => {
178
+ const applyLink = () => {
179
+ const chain = editor.chain().focus().extendMarkRange('link');
180
+ if (linkUrl === '') {
181
+ chain.unsetLink().run();
182
+ }
183
+ else {
184
+ const url = /^https?:\/\//.test(linkUrl)
185
+ ? linkUrl
186
+ : `https://${linkUrl}`;
187
+ chain.setLink({ href: url }).run();
188
+ }
189
+ setLinkUrl('');
190
+ close();
191
+ };
192
+ return (_jsxs(_Fragment, { children: [_jsx("input", { type: "text", autoFocus: true, placeholder: "URL\uC744 \uC785\uB825\uD558\uC138\uC694", value: linkUrl, onChange: (e) => setLinkUrl(e.target.value), onKeyDown: (e) => e.key === 'Enter' && applyLink(), className: "w-full px-3 py-2 border border-neutral200 rounded-lg text-sm outline-none transition duration-300 focus:border-blue-500" }), _jsxs("div", { className: "flex gap-2 mt-2", children: [_jsx("button", { type: "button", onClick: (e) => {
193
+ e.preventDefault();
194
+ applyLink();
195
+ }, className: "flex-1 px-3 py-1.5 bg-blue-500 text-white rounded-lg text-sm transition duration-300 hover:bg-blue-600", children: "\uC801\uC6A9" }), _jsx("button", { type: "button", onClick: (e) => {
196
+ e.preventDefault();
197
+ setLinkUrl('');
198
+ close();
199
+ }, className: "px-3 py-1.5 border border-neutral200 rounded-lg text-sm transition duration-300 hover:bg-mono100", children: "\uCDE8\uC18C" })] })] }));
200
+ } })] }))] }));
161
201
  };
162
202
  export default LDEditor;