@weing-dev/ui-kit-primitive 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/README.md +50 -0
  2. package/eslint.config.js +29 -0
  3. package/index.html +13 -0
  4. package/package.json +75 -0
  5. package/public/static/icon/Add.svg +1 -0
  6. package/public/static/icon/ApprovalInactive.svg +1 -0
  7. package/public/static/icon/ArrowRight.svg +5 -0
  8. package/public/static/icon/Cancle Filled.svg +1 -0
  9. package/public/static/icon/Cancle.svg +1 -0
  10. package/public/static/icon/Cart Filled.svg +1 -0
  11. package/public/static/icon/Cart.svg +1 -0
  12. package/public/static/icon/Check.svg +1 -0
  13. package/public/static/icon/CheckBoxRound.svg +3 -0
  14. package/public/static/icon/Company.svg +1 -0
  15. package/public/static/icon/DragHandle.svg +1 -0
  16. package/public/static/icon/Eco.svg +1 -0
  17. package/public/static/icon/EditSquare.svg +1 -0
  18. package/public/static/icon/Error Filled.svg +1 -0
  19. package/public/static/icon/Error.svg +1 -0
  20. package/public/static/icon/File Upload.svg +1 -0
  21. package/public/static/icon/FilecheckInactive.svg +1 -0
  22. package/public/static/icon/Go Before.svg +1 -0
  23. package/public/static/icon/Go Next.svg +1 -0
  24. package/public/static/icon/Hamburger Menu.svg +1 -0
  25. package/public/static/icon/ImagecheckPlay.svg +4 -0
  26. package/public/static/icon/Kakao Talk.svg +1 -0
  27. package/public/static/icon/Minus.svg +1 -0
  28. package/public/static/icon/Naver Blog.svg +1 -0
  29. package/public/static/icon/Naver.svg +1 -0
  30. package/public/static/icon/OrderApprove.svg +1 -0
  31. package/public/static/icon/OrderInactive.svg +1 -0
  32. package/public/static/icon/OrderPlay.svg +1 -0
  33. package/public/static/icon/PayApprove.svg +1 -0
  34. package/public/static/icon/PayInactive.svg +1 -0
  35. package/public/static/icon/PrintInactive.svg +1 -0
  36. package/public/static/icon/PrintPlay.svg +1 -0
  37. package/public/static/icon/Search.svg +1 -0
  38. package/public/static/icon/ShippingDone.svg +1 -0
  39. package/public/static/icon/Support Agent.svg +1 -0
  40. package/public/static/icon/Task.svg +1 -0
  41. package/public/static/icon/User.svg +1 -0
  42. package/public/static/icon/Warning Filled.svg +1 -0
  43. package/public/static/icon/Warning.svg +1 -0
  44. package/public/static/icon/add_a_photo.svg +3 -0
  45. package/public/static/icon/attach_file.svg +1 -0
  46. package/public/static/icon/check_circle.svg +1 -0
  47. package/public/static/icon/close.svg +1 -0
  48. package/public/static/icon/download.svg +1 -0
  49. package/public/static/icon/expand all.svg +1 -0
  50. package/public/static/icon/expand_less.svg +1 -0
  51. package/public/static/icon/expand_more.svg +1 -0
  52. package/public/static/icon/factory.svg +1 -0
  53. package/public/static/icon/inventory.svg +1 -0
  54. package/public/static/icon/listAll.svg +1 -0
  55. package/public/static/icon/local_shipping.svg +1 -0
  56. package/public/static/icon/logout.svg +1 -0
  57. package/public/static/icon/menu.svg +1 -0
  58. package/public/static/icon/mode_edit.svg +4 -0
  59. package/public/static/icon/more.svg +1 -0
  60. package/public/static/icon/outward.svg +1 -0
  61. package/public/static/icon/personcard.svg +1 -0
  62. package/public/static/icon/product.svg +1 -0
  63. package/public/static/icon/settings.svg +1 -0
  64. package/public/static/icon/swap_vert.svg +3 -0
  65. package/public/static/icon/upload.svg +1 -0
  66. package/public/static/icon/warning_amber.svg +3 -0
  67. package/public/static/image/Thumbnail.png +0 -0
  68. package/public/vite.svg +1 -0
  69. package/public/weing_logo_final.png +0 -0
  70. package/scripts/icons/setIcon.cjs +151 -0
  71. package/scripts/icons/svg-template.cjs +18 -0
  72. package/scripts/icons/svgo-config.json +9 -0
  73. package/scripts/icons/svgr-config.json +16 -0
  74. package/src/@types/color.d.ts +51 -0
  75. package/src/@types/common.d.ts +6 -0
  76. package/src/@types/extends/react.extends.d.ts +7 -0
  77. package/src/@types/quill-image-resize-module-react/index.d.ts +1 -0
  78. package/src/App.css +0 -0
  79. package/src/App.tsx +84 -0
  80. package/src/assets/react.svg +1 -0
  81. package/src/components/Accordion/Accordion.context.tsx +62 -0
  82. package/src/components/Accordion/Accordion.module.scss +163 -0
  83. package/src/components/Accordion/Accordion.tsx +242 -0
  84. package/src/components/Accordion/README.md +408 -0
  85. package/src/components/Accordion/images/as_trigger.gif +0 -0
  86. package/src/components/Accordion/images/closed.png +0 -0
  87. package/src/components/Accordion/images/open.png +0 -0
  88. package/src/components/Accordion/images/thumbnail1.png +0 -0
  89. package/src/components/Accordion/images/thumbnail2.png +0 -0
  90. package/src/components/Accordion/images/thumbnail3.png +0 -0
  91. package/src/components/Avatar/Avatar.module.scss +47 -0
  92. package/src/components/Avatar/Avatar.tsx +230 -0
  93. package/src/components/Avatar/README.md +333 -0
  94. package/src/components/Badge/Badge.module.scss +49 -0
  95. package/src/components/Badge/Badge.tsx +87 -0
  96. package/src/components/Badge/README.md +223 -0
  97. package/src/components/BarCode/BarCode.module.scss +0 -0
  98. package/src/components/BarCode/BarCode.tsx +153 -0
  99. package/src/components/Breadcrumb/Breadcrumb.module.scss +36 -0
  100. package/src/components/Breadcrumb/Breadcrumb.tsx +114 -0
  101. package/src/components/Breadcrumb/README.md +339 -0
  102. package/src/components/Button/Button.colors.tsx +322 -0
  103. package/src/components/Button/Button.context.tsx +47 -0
  104. package/src/components/Button/Button.module.scss +156 -0
  105. package/src/components/Button/Button.tsx +190 -0
  106. package/src/components/Button/Button.type.ts +11 -0
  107. package/src/components/Calendar/Calendar.context.tsx +138 -0
  108. package/src/components/Calendar/Calendar.module.scss +116 -0
  109. package/src/components/Calendar/Calendar.tsx +440 -0
  110. package/src/components/Calendar/dayjs.util.ts +312 -0
  111. package/src/components/Cascader/Cacader.data.ts +1185 -0
  112. package/src/components/Cascader/Cascader.context.tsx +61 -0
  113. package/src/components/Cascader/Cascader.hook.ts +502 -0
  114. package/src/components/Cascader/Cascader.module.scss +143 -0
  115. package/src/components/Cascader/Cascader.tsx +281 -0
  116. package/src/components/Cascader/README.md +735 -0
  117. package/src/components/Chart/Chart.module.scss +0 -0
  118. package/src/components/Chart/Chart.tsx +230 -0
  119. package/src/components/Chart/README.md +85 -0
  120. package/src/components/Chart/images/barChart.png +0 -0
  121. package/src/components/Chips/Chips.colors.tsx +185 -0
  122. package/src/components/Chips/Chips.module.scss +49 -0
  123. package/src/components/Chips/Chips.tsx +78 -0
  124. package/src/components/Comment/Comment.module.scss +14 -0
  125. package/src/components/Comment/Comment.tsx +105 -0
  126. package/src/components/Dialog/Dialog.module.scss +0 -0
  127. package/src/components/Dialog/Dialog.tsx +12 -0
  128. package/src/components/Divider/Divider.module.scss +12 -0
  129. package/src/components/Divider/Divider.tsx +33 -0
  130. package/src/components/Editor/Editor.context.tsx +12 -0
  131. package/src/components/Editor/Editor.module.scss +40 -0
  132. package/src/components/Editor/Editor.tsx +174 -0
  133. package/src/components/Form/CheckBox/CheckBox.context.tsx +56 -0
  134. package/src/components/Form/CheckBox/CheckBox.module.scss +81 -0
  135. package/src/components/Form/CheckBox/CheckBox.tsx +196 -0
  136. package/src/components/Form/CheckBox/Checkbox.colors.tsx +42 -0
  137. package/src/components/Form/Dropdown/Dropdown.colors.tsx +125 -0
  138. package/src/components/Form/Dropdown/Dropdown.context.tsx +62 -0
  139. package/src/components/Form/Dropdown/Dropdown.module.scss +133 -0
  140. package/src/components/Form/Dropdown/Dropdown.tsx +404 -0
  141. package/src/components/Form/OTPInput/OTPInput.context.tsx +104 -0
  142. package/src/components/Form/OTPInput/OTPInput.module.scss +22 -0
  143. package/src/components/Form/OTPInput/OTPInput.tsx +67 -0
  144. package/src/components/Form/Radio/Radio.colors.tsx +42 -0
  145. package/src/components/Form/Radio/Radio.context.tsx +40 -0
  146. package/src/components/Form/Radio/Radio.module.scss +61 -0
  147. package/src/components/Form/Radio/Radio.tsx +174 -0
  148. package/src/components/Form/Switch/Switch.colors.tsx +42 -0
  149. package/src/components/Form/Switch/Switch.context.tsx +50 -0
  150. package/src/components/Form/Switch/Switch.module.scss +53 -0
  151. package/src/components/Form/Switch/Switch.tsx +151 -0
  152. package/src/components/Form/TextArea/TextArea.colors.tsx +76 -0
  153. package/src/components/Form/TextArea/TextArea.context.tsx +97 -0
  154. package/src/components/Form/TextArea/TextArea.module.scss +138 -0
  155. package/src/components/Form/TextArea/TextArea.tsx +246 -0
  156. package/src/components/Form/TextInput/TextInput.colors.tsx +76 -0
  157. package/src/components/Form/TextInput/TextInput.context.tsx +106 -0
  158. package/src/components/Form/TextInput/TextInput.module.scss +160 -0
  159. package/src/components/Form/TextInput/TextInput.tsx +225 -0
  160. package/src/components/GlobalStyle/GlobalStyle.tsx +20 -0
  161. package/src/components/HelperText/HelperText.module.scss +28 -0
  162. package/src/components/HelperText/HelperText.tsx +130 -0
  163. package/src/components/Icon/Icon.tsx +29 -0
  164. package/src/components/Icons/Add.tsx +20 -0
  165. package/src/components/Icons/AddAPhoto.tsx +21 -0
  166. package/src/components/Icons/ApprovalInactive.tsx +26 -0
  167. package/src/components/Icons/ArrowRight.tsx +24 -0
  168. package/src/components/Icons/AttachFile.tsx +20 -0
  169. package/src/components/Icons/Cancle.tsx +20 -0
  170. package/src/components/Icons/CancleFilled.tsx +20 -0
  171. package/src/components/Icons/Cart.tsx +20 -0
  172. package/src/components/Icons/CartFilled.tsx +20 -0
  173. package/src/components/Icons/Check.tsx +20 -0
  174. package/src/components/Icons/CheckBoxRound.tsx +21 -0
  175. package/src/components/Icons/CheckCircle.tsx +35 -0
  176. package/src/components/Icons/Close.tsx +20 -0
  177. package/src/components/Icons/Company.tsx +20 -0
  178. package/src/components/Icons/Download.tsx +20 -0
  179. package/src/components/Icons/DragHandle.tsx +20 -0
  180. package/src/components/Icons/Eco.tsx +20 -0
  181. package/src/components/Icons/EditSquare.tsx +20 -0
  182. package/src/components/Icons/Error.tsx +20 -0
  183. package/src/components/Icons/ErrorFilled.tsx +20 -0
  184. package/src/components/Icons/ExpandAll.tsx +20 -0
  185. package/src/components/Icons/ExpandLess.tsx +20 -0
  186. package/src/components/Icons/ExpandMore.tsx +20 -0
  187. package/src/components/Icons/Factory.tsx +20 -0
  188. package/src/components/Icons/FileUpload.tsx +20 -0
  189. package/src/components/Icons/FilecheckInactive.tsx +22 -0
  190. package/src/components/Icons/GoBefore.tsx +20 -0
  191. package/src/components/Icons/GoNext.tsx +20 -0
  192. package/src/components/Icons/HamburgerMenu.tsx +20 -0
  193. package/src/components/Icons/ImagecheckPlay.tsx +27 -0
  194. package/src/components/Icons/Inventory.tsx +20 -0
  195. package/src/components/Icons/KakaoTalk.tsx +22 -0
  196. package/src/components/Icons/ListAll.tsx +20 -0
  197. package/src/components/Icons/LocalShipping.tsx +20 -0
  198. package/src/components/Icons/Logout.tsx +20 -0
  199. package/src/components/Icons/Menu.tsx +20 -0
  200. package/src/components/Icons/Minus.tsx +18 -0
  201. package/src/components/Icons/ModeEdit.tsx +25 -0
  202. package/src/components/Icons/More.tsx +20 -0
  203. package/src/components/Icons/Naver.tsx +20 -0
  204. package/src/components/Icons/NaverBlog.tsx +22 -0
  205. package/src/components/Icons/OrderApprove.tsx +20 -0
  206. package/src/components/Icons/OrderInactive.tsx +20 -0
  207. package/src/components/Icons/OrderPlay.tsx +20 -0
  208. package/src/components/Icons/Outward.tsx +20 -0
  209. package/src/components/Icons/PayApprove.tsx +24 -0
  210. package/src/components/Icons/PayInactive.tsx +24 -0
  211. package/src/components/Icons/Personcard.tsx +20 -0
  212. package/src/components/Icons/PrintInactive.tsx +24 -0
  213. package/src/components/Icons/PrintPlay.tsx +24 -0
  214. package/src/components/Icons/Product.tsx +20 -0
  215. package/src/components/Icons/Search.tsx +20 -0
  216. package/src/components/Icons/Settings.tsx +20 -0
  217. package/src/components/Icons/ShippingDone.tsx +20 -0
  218. package/src/components/Icons/SupportAgent.tsx +20 -0
  219. package/src/components/Icons/SwapVert.tsx +21 -0
  220. package/src/components/Icons/Task.tsx +20 -0
  221. package/src/components/Icons/Upload.tsx +20 -0
  222. package/src/components/Icons/User.tsx +20 -0
  223. package/src/components/Icons/Warning.tsx +20 -0
  224. package/src/components/Icons/WarningAmber.tsx +21 -0
  225. package/src/components/Icons/WarningFilled.tsx +20 -0
  226. package/src/components/Icons/index.ts +62 -0
  227. package/src/components/LNB/LNB.context.tsx +32 -0
  228. package/src/components/LNB/LNB.module.scss +99 -0
  229. package/src/components/LNB/LNB.tsx +190 -0
  230. package/src/components/LNB/README.md +411 -0
  231. package/src/components/LNB/makeNavigation.ts +51 -0
  232. package/src/components/LNB/navigation.d.ts +15 -0
  233. package/src/components/LNB/navigation.json +211 -0
  234. package/src/components/Label/Label.colors.tsx +241 -0
  235. package/src/components/Label/Label.module.scss +31 -0
  236. package/src/components/Label/Label.tsx +54 -0
  237. package/src/components/LazyImage/LazyImage.module.scss +6 -0
  238. package/src/components/LazyImage/LazyImage.tsx +107 -0
  239. package/src/components/List/List.module.scss +81 -0
  240. package/src/components/List/List.tsx +91 -0
  241. package/src/components/List/README.md +87 -0
  242. package/src/components/MobilePicker/MobilePicker.context.tsx +22 -0
  243. package/src/components/MobilePicker/MobilePicker.module.scss +57 -0
  244. package/src/components/MobilePicker/MobilePicker.tsx +336 -0
  245. package/src/components/MobilePicker/README.md +159 -0
  246. package/src/components/Modal/Modal.tsx +77 -0
  247. package/src/components/Modal/README.md +130 -0
  248. package/src/components/Pagination/Pagination.colors.tsx +85 -0
  249. package/src/components/Pagination/Pagination.context.tsx +28 -0
  250. package/src/components/Pagination/Pagination.module.scss +60 -0
  251. package/src/components/Pagination/Pagination.tsx +234 -0
  252. package/src/components/Popup/Popup.context.tsx +15 -0
  253. package/src/components/Popup/Popup.module.scss +53 -0
  254. package/src/components/Popup/Popup.tsx +116 -0
  255. package/src/components/Popup/README.md +170 -0
  256. package/src/components/QRCode/QRCode.module.scss +2 -0
  257. package/src/components/QRCode/QRCode.tsx +61 -0
  258. package/src/components/ScrollCalendar/ScrollCalendar.context.tsx +26 -0
  259. package/src/components/ScrollCalendar/ScrollCalendar.module.scss +42 -0
  260. package/src/components/ScrollCalendar/ScrollCalendar.tsx +448 -0
  261. package/src/components/ScrollSpy/README.md +62 -0
  262. package/src/components/ScrollSpy/ScrollSpy.tsx +130 -0
  263. package/src/components/Sheet/README.md +92 -0
  264. package/src/components/Sheet/Sheet.context.tsx +23 -0
  265. package/src/components/Sheet/Sheet.module.scss +68 -0
  266. package/src/components/Sheet/Sheet.tsx +146 -0
  267. package/src/components/Slider/README.md +639 -0
  268. package/src/components/Slider/Slider.backup.tsx +477 -0
  269. package/src/components/Slider/Slider.context.tsx +67 -0
  270. package/src/components/Slider/Slider.module.scss +123 -0
  271. package/src/components/Slider/Slider.tsx +467 -0
  272. package/src/components/Stepper/README.md +320 -0
  273. package/src/components/Stepper/Stepper.context.tsx +49 -0
  274. package/src/components/Stepper/Stepper.module.scss +163 -0
  275. package/src/components/Stepper/Stepper.tsx +219 -0
  276. package/src/components/Tab/Tab.colors.tsx +54 -0
  277. package/src/components/Tab/Tab.context.tsx +64 -0
  278. package/src/components/Tab/Tab.module.scss +239 -0
  279. package/src/components/Tab/Tab.tsx +123 -0
  280. package/src/components/Tab/cx.ts +6 -0
  281. package/src/components/Table/README.md +162 -0
  282. package/src/components/Table/Table.context.tsx +23 -0
  283. package/src/components/Table/Table.hook.ts +51 -0
  284. package/src/components/Table/Table.module.scss +83 -0
  285. package/src/components/Table/Table.tsx +147 -0
  286. package/src/components/Thumbnail/README.md +302 -0
  287. package/src/components/Thumbnail/Thumbnail.context.tsx +42 -0
  288. package/src/components/Thumbnail/Thumbnail.module.scss +149 -0
  289. package/src/components/Thumbnail/Thumbnail.tsx +391 -0
  290. package/src/components/TimeInput/README.md +118 -0
  291. package/src/components/TimeInput/TimeInput.colors.tsx +76 -0
  292. package/src/components/TimeInput/TimeInput.context.tsx +58 -0
  293. package/src/components/TimeInput/TimeInput.module.scss +211 -0
  294. package/src/components/TimeInput/TimeInput.tsx +411 -0
  295. package/src/components/WeeklyCalendar/WeeklyCalendar.context.tsx +88 -0
  296. package/src/components/WeeklyCalendar/WeeklyCalendar.module.scss +225 -0
  297. package/src/components/WeeklyCalendar/WeeklyCalendar.tsx +772 -0
  298. package/src/components/WeeklyCalendar/dayjs.util.ts +336 -0
  299. package/src/components/WeeklyCalendar/weeklyCalendar.util.ts +583 -0
  300. package/src/components/WisywygEditor/Quill/Editor.tsx +148 -0
  301. package/src/constant/locale.constant.ts +6 -0
  302. package/src/globals.scss +80 -0
  303. package/src/hooks/useColorScheme.tsx +48 -0
  304. package/src/hooks/useElementRect.tsx +128 -0
  305. package/src/hooks/useIntersectionObserver.tsx +33 -0
  306. package/src/index.css +17 -0
  307. package/src/index.ts +187 -0
  308. package/src/main.tsx +10 -0
  309. package/src/styles/_fontSize.mixin.scss +57 -0
  310. package/src/styles/_fontWeight.mixin.scss +15 -0
  311. package/src/styles/_lineHeight.mixin.scss +57 -0
  312. package/src/styles/_scrollbar.mixin.scss +49 -0
  313. package/src/styles/baseColor.ts +297 -0
  314. package/src/styles/color.ts +272 -0
  315. package/src/styles/color2.ts +200 -0
  316. package/src/styles/scrollbar.README.md +72 -0
  317. package/src/styles/typography.scss +170 -0
  318. package/src/utils/aws.util.ts +180 -0
  319. package/src/utils/common.utill.ts +45 -0
  320. package/src/vite-env.d.ts +1 -0
  321. package/tsconfig.app.json +24 -0
  322. package/tsconfig.json +29 -0
  323. package/tsconfig.node.json +10 -0
  324. package/tsconfig.node.tsbuildinfo +1 -0
  325. package/tsconfig.tsbuildinfo +1 -0
  326. package/vite.config.d.ts +2 -0
  327. package/vite.config.js +47 -0
  328. package/vite.config.ts +50 -0
@@ -0,0 +1,211 @@
1
+ $Basis: 105px;
2
+
3
+ @layer TimeInput {
4
+ .InputWrapper {
5
+ display: flex;
6
+ align-items: center;
7
+ gap: 10px;
8
+ padding: 4px;
9
+ border-radius: 8px;
10
+ border: 1px solid var(--border-color, var(--componentTextfieldOutline));
11
+ color: var(--color, var(--textPrimary, #1c252e));
12
+ background-color: var(--background-color, transparent);
13
+ height: 40px;
14
+ flex: 1;
15
+ @include bodyRegularSmall;
16
+
17
+ &.row {
18
+ flex-direction: row;
19
+ flex-grow: 1;
20
+ }
21
+
22
+ &.contained {
23
+ background-color: var(--componentTextfieldFilled, #edeff2);
24
+ }
25
+
26
+ &.large {
27
+ @include bodyRegularMedium;
28
+ height: 48px;
29
+ }
30
+
31
+ &.error {
32
+ border-color: var(--textError, #f5222d);
33
+ }
34
+
35
+ &.warning {
36
+ border-color: var(--textWarning, #ffab00);
37
+ }
38
+
39
+ &.success {
40
+ border-color: var(--textSuccess, #1cc95c);
41
+ }
42
+
43
+ &.focused {
44
+ border-color: var(--border-color, var(--componentTextfieldOutline));
45
+ }
46
+
47
+ &.disabled {
48
+ cursor: not-allowed;
49
+ }
50
+
51
+ .Input {
52
+ border: none;
53
+ outline: none;
54
+ background: none;
55
+ font: inherit;
56
+ text-align: center;
57
+ appearance: none;
58
+ display: inline-block;
59
+ flex: 1;
60
+ color: var(--color, inherit);
61
+
62
+ &::-webkit-inner-spin-button {
63
+ -webkit-appearance: none;
64
+ margin: 0;
65
+ }
66
+
67
+ &::placeholder {
68
+ color: var(--placeholder-color, var(--textTertiary, #919eab));
69
+ font: inherit;
70
+ }
71
+
72
+ &.error {
73
+ color: var(--textError, #f5222d);
74
+
75
+ &::placeholder {
76
+ color: var(--textError, #f5222d);
77
+ }
78
+ }
79
+
80
+ // &.warning {
81
+ // color: var(--textWarning, #ffab00);
82
+
83
+ // &::placeholder {
84
+ // color: var(--textWarning, #ffab00);
85
+ // }
86
+ // }
87
+
88
+ // &.success {
89
+ // color: var(--textSuccess, #1cc95c);
90
+
91
+ // &::placeholder {
92
+ // color: var(--textSuccess, #1cc95c);
93
+ // }
94
+ // }
95
+
96
+ &.readOnly {
97
+ cursor: default;
98
+ }
99
+
100
+ &.disabled {
101
+ cursor: not-allowed;
102
+ color: var(--textDisabled, #c4cdd5);
103
+ &::placeholder {
104
+ color: var(--textDisabled, #c4cdd5);
105
+ }
106
+ }
107
+ }
108
+
109
+ .TimeRange {
110
+ display: flex;
111
+ align-items: center;
112
+ gap: 10px;
113
+ flex: 1;
114
+ }
115
+ }
116
+
117
+ .Colon {
118
+ color: #919eab;
119
+ &.error {
120
+ color: var(--textError, #f5222d);
121
+ }
122
+ &.warning {
123
+ color: var(--textWarning, #ffab00);
124
+ }
125
+ &.success {
126
+ color: var(--textSuccess, #1cc95c);
127
+ }
128
+ &.disabled {
129
+ color: var(--textDisabled, #c4cdd5);
130
+ }
131
+ }
132
+
133
+ .Separator {
134
+ color: #919eab;
135
+
136
+ &.error {
137
+ color: var(--textError, #f5222d);
138
+ }
139
+ &.warning {
140
+ color: var(--textWarning, #ffab00);
141
+ }
142
+ &.success {
143
+ color: var(--textSuccess, #1cc95c);
144
+ }
145
+ &.disabled {
146
+ color: var(--textDisabled, #c4cdd5);
147
+ }
148
+ }
149
+
150
+ .HelperText {
151
+ color: var(--textTertiary, #919eab);
152
+ &.error {
153
+ color: var(--textError, #f5222d);
154
+ }
155
+ &.warning {
156
+ color: var(--textWarning, #ffab00);
157
+ }
158
+ &.success {
159
+ color: var(--textSuccess, #1cc95c);
160
+ }
161
+ }
162
+
163
+ .TimeInputLabel {
164
+ @include captionBoldMedium;
165
+ color: var(--textSecondary, #637381);
166
+ margin-bottom: 4px;
167
+
168
+ &.focused {
169
+ color: var(--actionAction);
170
+ }
171
+
172
+ &.error {
173
+ color: var(--textError, #f5222d);
174
+ }
175
+
176
+ &.warning {
177
+ color: var(--textWarning, #ffab00);
178
+ }
179
+
180
+ &.success {
181
+ color: var(--textSuccess, #1cc95c);
182
+ }
183
+
184
+ &.row {
185
+ margin-bottom: 0;
186
+ margin-right: 8px;
187
+ flex: 0 0 var(--basis, $Basis);
188
+ }
189
+
190
+ &.large,
191
+ &.row.small {
192
+ @include bodyBoldSmall;
193
+ }
194
+
195
+ &.row.large {
196
+ @include bodyBoldMedium;
197
+ }
198
+ }
199
+
200
+ .TimeInputRoot {
201
+ display: flex;
202
+ flex-direction: column;
203
+ gap: 8px;
204
+ width: 100%;
205
+
206
+ &.row {
207
+ flex-direction: row;
208
+ align-items: center;
209
+ }
210
+ }
211
+ }
@@ -0,0 +1,411 @@
1
+ "use client";
2
+ import React from "react";
3
+ import styles from "./TimeInput.module.scss";
4
+ import cn from "classnames/bind";
5
+ import { TimeInputContext, TimeInputContextType } from "./TimeInput.context";
6
+ import HelperTextComponent from "../HelperText/HelperText";
7
+ import useTimeInputColors from "./TimeInput.colors";
8
+
9
+ const cx = cn.bind(styles);
10
+
11
+ type InputProps = {
12
+ index: number;
13
+ placeholder: string;
14
+ } & React.JSX.IntrinsicElements["input"];
15
+ const Input = (props: InputProps) => {
16
+ const { index, placeholder, ...rest } = props;
17
+ const {
18
+ inputRefs,
19
+ status,
20
+ disabled,
21
+ readOnly,
22
+ focused,
23
+ handleChange,
24
+ handleBlur,
25
+ handleKeyDown,
26
+ handleFocus,
27
+ } = React.use(TimeInputContext);
28
+ const max = index % 2 === 0 ? 23 : 59;
29
+
30
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
31
+ const value = e.target.value;
32
+ const numValue = parseInt(value);
33
+
34
+ // 빈 값이거나 NaN인 경우 그대로 통과
35
+ if (!value || isNaN(numValue)) {
36
+ handleChange?.(e, index);
37
+ return;
38
+ }
39
+
40
+ // 최대값을 초과하는 경우 최대값으로 설정
41
+ if (numValue > max) {
42
+ e.target.value = max.toString();
43
+ }
44
+
45
+ handleChange?.(e, index);
46
+
47
+ // 두 자리 수가 입력되면 다음 입력으로 포커스
48
+ if (value.length === 2 && index < 3) {
49
+ inputRefs?.current[index + 1]?.focus();
50
+ }
51
+ };
52
+
53
+ return (
54
+ <input
55
+ {...rest}
56
+ className={cx("Input", rest.className, status, {
57
+ disabled,
58
+ readOnly,
59
+ focused,
60
+ })}
61
+ type="number"
62
+ ref={(el) => {
63
+ if (el) inputRefs!.current[index] = el;
64
+ }}
65
+ onChange={handleInputChange}
66
+ onBlur={() => handleBlur?.(inputRefs!.current[index].value, max, index)}
67
+ onFocus={handleFocus}
68
+ placeholder={placeholder}
69
+ onKeyDown={(e) => handleKeyDown?.(e, index)}
70
+ readOnly={readOnly}
71
+ disabled={disabled}
72
+ min={0}
73
+ max={max}
74
+ />
75
+ );
76
+ };
77
+
78
+ type TimeRangeProps = React.PropsWithChildren<
79
+ React.JSX.IntrinsicElements["div"]
80
+ >;
81
+ const TimeRange = (props: TimeRangeProps) => {
82
+ const { children, ...rest } = props;
83
+ return (
84
+ <div {...rest} className={cx("TimeRange", rest.className)}>
85
+ {children}
86
+ </div>
87
+ );
88
+ };
89
+
90
+ type ColonProps = React.JSX.IntrinsicElements["span"];
91
+ const Colon = (props: ColonProps) => {
92
+ const { ...rest } = props;
93
+ const { status, disabled } = React.use(TimeInputContext);
94
+ return (
95
+ <span
96
+ {...rest}
97
+ className={cx("Colon", rest.className, status, { disabled })}
98
+ >
99
+ :
100
+ </span>
101
+ );
102
+ };
103
+
104
+ type SeparatorProps = React.JSX.IntrinsicElements["span"];
105
+ const Separator = (props: SeparatorProps) => {
106
+ const { ...rest } = props;
107
+ const { status, disabled } = React.use(TimeInputContext);
108
+ return (
109
+ <span
110
+ {...rest}
111
+ className={cx("Separator", rest.className, status, { disabled })}
112
+ >
113
+ -
114
+ </span>
115
+ );
116
+ };
117
+
118
+ type HelperTextProps = React.PropsWithChildren<{
119
+ className?: string;
120
+ warningColor?: string;
121
+ errorColor?: string;
122
+ successColor?: string;
123
+ defaultColor?: string;
124
+ infoColor?: string;
125
+ size?: number;
126
+ iconVisible?: boolean;
127
+ }>;
128
+
129
+ const HelperText = (props: HelperTextProps) => {
130
+ const { children, ...rest } = props;
131
+ const { status, disabled } = React.use(TimeInputContext);
132
+
133
+ if (!status || disabled) return null;
134
+
135
+ return (
136
+ <HelperTextComponent {...rest} status={status}>
137
+ {children ?? "종료 시간이 시작 시간보다 커야 합니다."}
138
+ </HelperTextComponent>
139
+ );
140
+ };
141
+
142
+ type InputWrapperProps = React.PropsWithChildren<
143
+ React.JSX.IntrinsicElements["div"]
144
+ >;
145
+ const InputWrapper = (props: InputWrapperProps) => {
146
+ const { children, ...rest } = props;
147
+ const { size, variant, status, focused, disabled, direction } =
148
+ React.use(TimeInputContext);
149
+ const timeInputColors = useTimeInputColors();
150
+ const colorSet = timeInputColors[variant ?? "outlined"];
151
+
152
+ return (
153
+ <div
154
+ {...rest}
155
+ className={cx(
156
+ "InputWrapper",
157
+ rest.className,
158
+ size,
159
+ variant,
160
+ status,
161
+ direction,
162
+ {
163
+ focused,
164
+ disabled,
165
+ }
166
+ )}
167
+ style={{
168
+ "--background-color": disabled
169
+ ? colorSet.disabled.backgroundColor
170
+ : colorSet.inactive.backgroundColor,
171
+ "--border-color": focused
172
+ ? colorSet.focused.borderColor
173
+ : colorSet.inactive.borderColor,
174
+ "--color": disabled ? colorSet.disabled.color : colorSet.inactive.color,
175
+ }}
176
+ >
177
+ {children}
178
+ </div>
179
+ );
180
+ };
181
+
182
+ type LabelProps = React.PropsWithChildren<{
183
+ className?: string;
184
+ focusedColor?: string;
185
+ }>;
186
+
187
+ const Label = (props: LabelProps) => {
188
+ const { className, children, focusedColor } = props;
189
+ const { focused, status, size, direction, flexBasis } =
190
+ React.use(TimeInputContext);
191
+
192
+ return (
193
+ <span
194
+ className={cx("TimeInputLabel", className, status, size, direction, {
195
+ focused,
196
+ })}
197
+ style={{
198
+ color: focused ? focusedColor : undefined,
199
+ ...(flexBasis ? { "--basis": flexBasis } : {}),
200
+ }}
201
+ >
202
+ {children}
203
+ </span>
204
+ );
205
+ };
206
+
207
+ type RootProps = React.PropsWithChildren<
208
+ Omit<
209
+ TimeInputContextType,
210
+ "inputRefs" | "handleChange" | "handleBlur" | "handleKeyDown"
211
+ > & {
212
+ className?: string;
213
+ }
214
+ >;
215
+
216
+ const Root = (props: RootProps) => {
217
+ const {
218
+ children,
219
+ className,
220
+ value = "",
221
+ size = "small",
222
+ disabled = false,
223
+ readOnly = false,
224
+ focused: externalFocused,
225
+ variant = "outlined",
226
+ direction = "column",
227
+ flexBasis,
228
+ status: externalStatus,
229
+ onChange,
230
+ } = props;
231
+
232
+ const [time, setTime] = React.useState<string>(value);
233
+ const [internalStatus, setInternalStatus] = React.useState<
234
+ "error" | "warning" | "success"
235
+ >();
236
+ const [internalFocused, setInternalFocused] = React.useState(externalFocused);
237
+ const inputRefs = React.useRef<HTMLInputElement[]>([]);
238
+
239
+ const padTime = (value: string, max: number) => {
240
+ if (!value) return "";
241
+ const numValue = parseInt(value);
242
+ return numValue <= max ? String(numValue).padStart(2, "0") : "";
243
+ };
244
+
245
+ const handleFocus = React.useCallback(() => {
246
+ if (disabled || readOnly) return;
247
+ setInternalFocused(true);
248
+ }, [disabled, readOnly]);
249
+
250
+ const handleBlur = React.useCallback(
251
+ (value: string, max: number, index: number) => {
252
+ const newTime = padTime(value, max);
253
+ setTime(newTime);
254
+ inputRefs.current[index].value = newTime;
255
+ setInternalFocused(false);
256
+ },
257
+ []
258
+ );
259
+
260
+ const handleKeyDown = React.useCallback(
261
+ (e: React.KeyboardEvent<HTMLInputElement>, index: number) => {
262
+ const currentInput = inputRefs.current[index];
263
+ const currentValue = currentInput.value;
264
+
265
+ switch (e.key) {
266
+ case "Backspace":
267
+ // 현재 입력이 비어있고, 이전 입력이 존재할 때만 이전으로 이동
268
+ if (currentValue === "" && index > 0) {
269
+ e.preventDefault();
270
+ inputRefs.current[index - 1].focus();
271
+ }
272
+ break;
273
+
274
+ case "Tab":
275
+ if (e.shiftKey) {
276
+ if (index > 0) {
277
+ e.preventDefault();
278
+ inputRefs.current[index - 1].focus();
279
+ }
280
+ } else {
281
+ if (index < 3) {
282
+ e.preventDefault();
283
+ // 현재 값이 한 자리 수일 경우 두 자리로 패딩
284
+ if (currentValue && currentValue.length === 1) {
285
+ const max = index % 2 === 0 ? 23 : 59;
286
+ handleBlur(currentValue, max, index);
287
+ }
288
+ inputRefs.current[index + 1].focus();
289
+ }
290
+ }
291
+ break;
292
+ }
293
+ },
294
+ [handleBlur]
295
+ );
296
+
297
+ const validateTimeRange = React.useCallback(() => {
298
+ const time = inputRefs.current.map((el) => el.value);
299
+ const startTime = `${time[0]}:${time[1]}`;
300
+ const endTime = `${time[2]}:${time[3]}`;
301
+
302
+ if (parseInt(time[2] + time[3]) <= parseInt(time[0] + time[1])) {
303
+ setInternalStatus("error");
304
+ } else {
305
+ setInternalStatus(undefined);
306
+ if (onChange) onChange({ start: startTime, end: endTime });
307
+ }
308
+ }, [onChange]);
309
+
310
+ const handleChange = React.useCallback(
311
+ (e: React.ChangeEvent<HTMLInputElement>, index: number) => {
312
+ const value = e.target.value;
313
+ setTime(value);
314
+
315
+ // 값이 비어있지 않고 두 자리 수인 경우에만 다음 입력으로 포커스
316
+ if (value && value.length === 2 && index < 3) {
317
+ const max = index % 2 === 0 ? 23 : 59;
318
+ const numValue = parseInt(value);
319
+
320
+ // 최대값을 초과하는 경우 최대값으로 설정
321
+ if (numValue > max) {
322
+ inputRefs.current[index].value = max.toString();
323
+ }
324
+
325
+ inputRefs.current[index + 1].focus();
326
+ }
327
+
328
+ // 모든 입력값이 있을 때만 검증 실행
329
+ if (inputRefs.current.every((input) => input.value)) {
330
+ validateTimeRange();
331
+ } else if (inputRefs.current.every((input) => input.value === "")) {
332
+ if (onChange) onChange({ start: "", end: "" });
333
+ setInternalStatus(undefined);
334
+ }
335
+ },
336
+ [validateTimeRange, onChange]
337
+ );
338
+
339
+ const contextValue = React.useMemo<TimeInputContextType>(
340
+ () => ({
341
+ value: time,
342
+ disabled,
343
+ readOnly,
344
+ inputRefs,
345
+ status: externalStatus ?? internalStatus,
346
+ size,
347
+ variant,
348
+ focused: internalFocused,
349
+ direction,
350
+ flexBasis,
351
+ onChange,
352
+ handleChange,
353
+ handleBlur,
354
+ handleKeyDown,
355
+ handleFocus,
356
+ }),
357
+ [
358
+ time,
359
+ disabled,
360
+ readOnly,
361
+ size,
362
+ variant,
363
+ internalFocused,
364
+ direction,
365
+ flexBasis,
366
+ externalStatus,
367
+ internalStatus,
368
+ onChange,
369
+ handleChange,
370
+ handleBlur,
371
+ handleKeyDown,
372
+ handleFocus,
373
+ ]
374
+ );
375
+
376
+ React.useEffect(() => {
377
+ setInternalFocused(externalFocused);
378
+ }, [externalFocused]);
379
+
380
+ return (
381
+ <TimeInputContext.Provider value={contextValue}>
382
+ <div className={cx("TimeInputRoot", className, direction)}>
383
+ {children}
384
+ </div>
385
+ </TimeInputContext.Provider>
386
+ );
387
+ };
388
+
389
+ interface ITimeInput {
390
+ Root: typeof Root;
391
+ Label: typeof Label;
392
+ Input: typeof Input;
393
+ TimeRange: typeof TimeRange;
394
+ Colon: typeof Colon;
395
+ Separator: typeof Separator;
396
+ HelperText: typeof HelperText;
397
+ InputWrapper: typeof InputWrapper;
398
+ }
399
+
400
+ const TimeInput = {
401
+ Root,
402
+ Label,
403
+ Input,
404
+ TimeRange,
405
+ Colon,
406
+ Separator,
407
+ HelperText,
408
+ InputWrapper,
409
+ } as ITimeInput;
410
+
411
+ export default TimeInput;
@@ -0,0 +1,88 @@
1
+ import React from "react";
2
+
3
+ export interface EventItem {
4
+ id: string;
5
+ startTime: string; // 예: "2025-01-15 22:00"
6
+ endTime?: string; // 예: "2025-01-16 02:00"
7
+ createdAt: string; // 예: "2025-01-10 09:00"
8
+ isAllDay?: boolean;
9
+ title?: string;
10
+ }
11
+
12
+ export type EventItemAsProps<T extends EventItem = EventItem> = {
13
+ id: string;
14
+ startTime: string;
15
+ endTime?: string;
16
+ title: string;
17
+ style?: React.CSSProperties;
18
+ onMouseEnter?: () => void;
19
+ onMouseLeave?: () => void;
20
+ ref?: React.Dispatch<React.SetStateAction<HTMLElement | null>>;
21
+ } & Omit<T, keyof EventItem>;
22
+
23
+ export type EventItemPopperAsProps<T extends EventItem = EventItem> = {
24
+ id: string;
25
+ popperRef: React.Dispatch<React.SetStateAction<HTMLDivElement | null>>;
26
+ popperStyle: React.CSSProperties;
27
+ popperAttributes: {
28
+ [key: string]: string;
29
+ };
30
+ title: string;
31
+ realStartTime?: string;
32
+ realEndTime?: string;
33
+ arrowRef: React.Dispatch<React.SetStateAction<HTMLDivElement | null>>;
34
+ arrowStyle: React.CSSProperties;
35
+ arrowAttributes: {
36
+ [key: string]: string;
37
+ };
38
+ onMouseEnter?: () => void;
39
+ onMouseLeave?: () => void;
40
+ } & Omit<T, keyof EventItem>;
41
+
42
+ export type WeeklyCalendarContextType<T extends EventItem> = {
43
+ /** start hour (하루 최소 시간)*/
44
+ minHour: number;
45
+ /** end hour (하루 최대 시간) */
46
+ maxHour: number;
47
+ /** current date */
48
+ currentDate?: string;
49
+ /** date count */
50
+ columnCount: number;
51
+ /** min step */
52
+ step: number;
53
+ /** Event List */
54
+ events?: Array<T>;
55
+ /** 새 일정 생성을 위한 드래그 기능 활성화 */
56
+ enableCreateByDrag?: boolean;
57
+ /** 기존 일정 이동을 위한 드래그 기능 활성화 */
58
+ enableMoveByDrag?: boolean;
59
+ /** 이벤트 아이템 컴포넌트 */
60
+ eventItemAs?: (props: EventItemAsProps<T>) => React.ReactNode;
61
+ /** 이벤트 아이템 popper 컴포넌트 */
62
+ eventItemPopperAs?: (props: EventItemPopperAsProps<T>) => React.ReactNode;
63
+ /** 이벤트 아이템 높이 */
64
+ itemHeight?: number;
65
+ /** 타입 */
66
+ type?: "default" | "noLines";
67
+ /** 툴팁 숨김 지연 시간 */
68
+ popperHideDelay?: number;
69
+ /** 툴팁 오프셋 */
70
+ popperOffset?: [number, number];
71
+ };
72
+
73
+ export const initialState: WeeklyCalendarContextType<EventItem> = {
74
+ minHour: 0,
75
+ maxHour: 24,
76
+ columnCount: 5,
77
+ step: 15,
78
+ enableCreateByDrag: true,
79
+ enableMoveByDrag: true,
80
+ popperHideDelay: 200,
81
+ popperOffset: [0, 0],
82
+ };
83
+
84
+ export const WeeklyCalendarContext =
85
+ React.createContext<WeeklyCalendarContextType<any>>(initialState);
86
+
87
+ export type WeeklyCalendarProviderProps<T extends EventItem> =
88
+ React.PropsWithChildren<WeeklyCalendarContextType<T>>;