@quillsql/react 1.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 (272) hide show
  1. package/.eslintrc.json +19 -0
  2. package/.prettierrc +11 -0
  3. package/example/README.md +46 -0
  4. package/example/package-lock.json +12111 -0
  5. package/example/package.json +43 -0
  6. package/example/public/favicon.ico +0 -0
  7. package/example/public/index.html +43 -0
  8. package/example/public/logo192.png +0 -0
  9. package/example/public/logo512.png +0 -0
  10. package/example/public/manifest.json +25 -0
  11. package/example/public/robots.txt +3 -0
  12. package/example/src/App.css +38 -0
  13. package/example/src/App.test.tsx +9 -0
  14. package/example/src/App.tsx +46 -0
  15. package/example/src/index.css +13 -0
  16. package/example/src/index.tsx +19 -0
  17. package/example/src/logo.svg +1 -0
  18. package/example/src/react-app-env.d.ts +1 -0
  19. package/example/src/reportWebVitals.ts +15 -0
  20. package/example/src/setupTests.ts +5 -0
  21. package/example/tsconfig.json +26 -0
  22. package/lib/AppContext.d.ts +29 -0
  23. package/lib/AppContext.js +94 -0
  24. package/lib/AppContext.js.map +1 -0
  25. package/lib/BarList.d.ts +17 -0
  26. package/lib/BarList.js +81 -0
  27. package/lib/BarList.js.map +1 -0
  28. package/lib/Button.d.ts +26 -0
  29. package/lib/Button.js +151 -0
  30. package/lib/Button.js.map +1 -0
  31. package/lib/Chart.d.ts +26 -0
  32. package/lib/Chart.js +532 -0
  33. package/lib/Chart.js.map +1 -0
  34. package/lib/Context.d.ts +28 -0
  35. package/lib/Context.js +126 -0
  36. package/lib/Context.js.map +1 -0
  37. package/lib/ContextProvider.d.ts +28 -0
  38. package/lib/ContextProvider.js +93 -0
  39. package/lib/ContextProvider.js.map +1 -0
  40. package/lib/Dashboard.d.ts +9 -0
  41. package/lib/Dashboard.js +271 -0
  42. package/lib/Dashboard.js.map +1 -0
  43. package/lib/DateRangePicker/Calendar.d.ts +15 -0
  44. package/lib/DateRangePicker/Calendar.js +94 -0
  45. package/lib/DateRangePicker/Calendar.js.map +1 -0
  46. package/lib/DateRangePicker/DateRangePicker.d.ts +31 -0
  47. package/lib/DateRangePicker/DateRangePicker.js +105 -0
  48. package/lib/DateRangePicker/DateRangePicker.js.map +1 -0
  49. package/lib/DateRangePicker/DateRangePickerButton.d.ts +21 -0
  50. package/lib/DateRangePicker/DateRangePickerButton.js +39 -0
  51. package/lib/DateRangePicker/DateRangePickerButton.js.map +1 -0
  52. package/lib/DateRangePicker/dateRangePickerUtils.d.ts +13 -0
  53. package/lib/DateRangePicker/dateRangePickerUtils.js +313 -0
  54. package/lib/DateRangePicker/dateRangePickerUtils.js.map +1 -0
  55. package/lib/DateRangePicker/index.d.ts +2 -0
  56. package/lib/DateRangePicker/index.js +2 -0
  57. package/lib/DateRangePicker/index.js.map +1 -0
  58. package/lib/DateRangePicker.d.ts +32 -0
  59. package/lib/DateRangePicker.js +105 -0
  60. package/lib/DateRangePicker.js.map +1 -0
  61. package/lib/PieChart.d.ts +63 -0
  62. package/lib/PieChart.js +589 -0
  63. package/lib/PieChart.js.map +1 -0
  64. package/lib/QuillProvider.d.ts +13 -0
  65. package/lib/QuillProvider.js +19 -0
  66. package/lib/QuillProvider.js.map +1 -0
  67. package/lib/assets/ArrowDownHeadIcon.d.ts +5 -0
  68. package/lib/assets/ArrowDownHeadIcon.js +29 -0
  69. package/lib/assets/ArrowDownHeadIcon.js.map +1 -0
  70. package/lib/assets/ArrowDownIcon.d.ts +5 -0
  71. package/lib/assets/ArrowDownIcon.js +29 -0
  72. package/lib/assets/ArrowDownIcon.js.map +1 -0
  73. package/lib/assets/ArrowDownRightIcon.d.ts +5 -0
  74. package/lib/assets/ArrowDownRightIcon.js +29 -0
  75. package/lib/assets/ArrowDownRightIcon.js.map +1 -0
  76. package/lib/assets/ArrowLeftHeadIcon.d.ts +5 -0
  77. package/lib/assets/ArrowLeftHeadIcon.js +29 -0
  78. package/lib/assets/ArrowLeftHeadIcon.js.map +1 -0
  79. package/lib/assets/ArrowRightHeadIcon.d.ts +5 -0
  80. package/lib/assets/ArrowRightHeadIcon.js +29 -0
  81. package/lib/assets/ArrowRightHeadIcon.js.map +1 -0
  82. package/lib/assets/ArrowRightIcon.d.ts +5 -0
  83. package/lib/assets/ArrowRightIcon.js +29 -0
  84. package/lib/assets/ArrowRightIcon.js.map +1 -0
  85. package/lib/assets/ArrowUpHeadIcon.d.ts +5 -0
  86. package/lib/assets/ArrowUpHeadIcon.js +29 -0
  87. package/lib/assets/ArrowUpHeadIcon.js.map +1 -0
  88. package/lib/assets/ArrowUpIcon.d.ts +5 -0
  89. package/lib/assets/ArrowUpIcon.js +29 -0
  90. package/lib/assets/ArrowUpIcon.js.map +1 -0
  91. package/lib/assets/ArrowUpRightIcon.d.ts +5 -0
  92. package/lib/assets/ArrowUpRightIcon.js +29 -0
  93. package/lib/assets/ArrowUpRightIcon.js.map +1 -0
  94. package/lib/assets/CalendarIcon.d.ts +5 -0
  95. package/lib/assets/CalendarIcon.js +29 -0
  96. package/lib/assets/CalendarIcon.js.map +1 -0
  97. package/lib/assets/DoubleArrowLeftHeadIcon.d.ts +5 -0
  98. package/lib/assets/DoubleArrowLeftHeadIcon.js +29 -0
  99. package/lib/assets/DoubleArrowLeftHeadIcon.js.map +1 -0
  100. package/lib/assets/DoubleArrowRightHeadIcon.d.ts +5 -0
  101. package/lib/assets/DoubleArrowRightHeadIcon.js +29 -0
  102. package/lib/assets/DoubleArrowRightHeadIcon.js.map +1 -0
  103. package/lib/assets/ExclamationFilledIcon.d.ts +5 -0
  104. package/lib/assets/ExclamationFilledIcon.js +29 -0
  105. package/lib/assets/ExclamationFilledIcon.js.map +1 -0
  106. package/lib/assets/LoadingSpinner.d.ts +5 -0
  107. package/lib/assets/LoadingSpinner.js +29 -0
  108. package/lib/assets/LoadingSpinner.js.map +1 -0
  109. package/lib/assets/SearchIcon.d.ts +5 -0
  110. package/lib/assets/SearchIcon.js +29 -0
  111. package/lib/assets/SearchIcon.js.map +1 -0
  112. package/lib/assets/XCircleIcon.d.ts +5 -0
  113. package/lib/assets/XCircleIcon.js +29 -0
  114. package/lib/assets/XCircleIcon.js.map +1 -0
  115. package/lib/assets/index.d.ts +16 -0
  116. package/lib/assets/index.js +17 -0
  117. package/lib/assets/index.js.map +1 -0
  118. package/lib/components/Dropdown/Dropdown.d.ts +12 -0
  119. package/lib/components/Dropdown/Dropdown.js +60 -0
  120. package/lib/components/Dropdown/Dropdown.js.map +1 -0
  121. package/lib/components/Dropdown/DropdownItem.d.ts +8 -0
  122. package/lib/components/Dropdown/DropdownItem.js +54 -0
  123. package/lib/components/Dropdown/DropdownItem.js.map +1 -0
  124. package/lib/components/Dropdown/index.d.ts +2 -0
  125. package/lib/components/Dropdown/index.js +3 -0
  126. package/lib/components/Dropdown/index.js.map +1 -0
  127. package/lib/components/Modal/Dropdown/Dropdown.d.ts +12 -0
  128. package/lib/components/Modal/Dropdown/Dropdown.js +52 -0
  129. package/lib/components/Modal/Dropdown/Dropdown.js.map +1 -0
  130. package/lib/components/Modal/Dropdown/DropdownItem.d.ts +8 -0
  131. package/lib/components/Modal/Dropdown/DropdownItem.js +51 -0
  132. package/lib/components/Modal/Dropdown/DropdownItem.js.map +1 -0
  133. package/lib/components/Modal/Dropdown/index.d.ts +2 -0
  134. package/lib/components/Modal/Dropdown/index.js +3 -0
  135. package/lib/components/Modal/Dropdown/index.js.map +1 -0
  136. package/lib/components/Modal/Modal.d.ts +13 -0
  137. package/lib/components/Modal/Modal.js +71 -0
  138. package/lib/components/Modal/Modal.js.map +1 -0
  139. package/lib/components/Modal/index.d.ts +1 -0
  140. package/lib/components/Modal/index.js +2 -0
  141. package/lib/components/Modal/index.js.map +1 -0
  142. package/lib/components/selectUtils.d.ts +9 -0
  143. package/lib/components/selectUtils.js +37 -0
  144. package/lib/components/selectUtils.js.map +1 -0
  145. package/lib/contexts/BaseColorContext.d.ts +3 -0
  146. package/lib/contexts/BaseColorContext.js +5 -0
  147. package/lib/contexts/BaseColorContext.js.map +1 -0
  148. package/lib/contexts/HoveredValueContext.d.ts +7 -0
  149. package/lib/contexts/HoveredValueContext.js +6 -0
  150. package/lib/contexts/HoveredValueContext.js.map +1 -0
  151. package/lib/contexts/RootStylesContext.d.ts +3 -0
  152. package/lib/contexts/RootStylesContext.js +4 -0
  153. package/lib/contexts/RootStylesContext.js.map +1 -0
  154. package/lib/contexts/SelectedValueContext.d.ts +7 -0
  155. package/lib/contexts/SelectedValueContext.js +7 -0
  156. package/lib/contexts/SelectedValueContext.js.map +1 -0
  157. package/lib/contexts/index.d.ts +4 -0
  158. package/lib/contexts/index.js +5 -0
  159. package/lib/contexts/index.js.map +1 -0
  160. package/lib/hooks/index.d.ts +4 -0
  161. package/lib/hooks/index.js +5 -0
  162. package/lib/hooks/index.js.map +1 -0
  163. package/lib/hooks/useInternalState.d.ts +3 -0
  164. package/lib/hooks/useInternalState.js +15 -0
  165. package/lib/hooks/useInternalState.js.map +1 -0
  166. package/lib/hooks/useOnClickOutside.d.ts +2 -0
  167. package/lib/hooks/useOnClickOutside.js +19 -0
  168. package/lib/hooks/useOnClickOutside.js.map +1 -0
  169. package/lib/hooks/useOnWindowResize.d.ts +4 -0
  170. package/lib/hooks/useOnWindowResize.js +15 -0
  171. package/lib/hooks/useOnWindowResize.js.map +1 -0
  172. package/lib/hooks/useSelectOnKeyDown.d.ts +2 -0
  173. package/lib/hooks/useSelectOnKeyDown.js +64 -0
  174. package/lib/hooks/useSelectOnKeyDown.js.map +1 -0
  175. package/lib/index.d.ts +3 -0
  176. package/lib/index.js +5 -0
  177. package/lib/index.js.map +1 -0
  178. package/lib/lib/colorClassNames.d.ts +19 -0
  179. package/lib/lib/colorClassNames.js +3175 -0
  180. package/lib/lib/colorClassNames.js.map +1 -0
  181. package/lib/lib/constants.d.ts +16 -0
  182. package/lib/lib/constants.js +47 -0
  183. package/lib/lib/constants.js.map +1 -0
  184. package/lib/lib/font.d.ts +13 -0
  185. package/lib/lib/font.js +14 -0
  186. package/lib/lib/font.js.map +1 -0
  187. package/lib/lib/hexColors.d.ts +3 -0
  188. package/lib/lib/hexColors.js +29 -0
  189. package/lib/lib/hexColors.js.map +1 -0
  190. package/lib/lib/index.d.ts +10 -0
  191. package/lib/lib/index.js +11 -0
  192. package/lib/lib/index.js.map +1 -0
  193. package/lib/lib/inputTypes.d.ts +20 -0
  194. package/lib/lib/inputTypes.js +37 -0
  195. package/lib/lib/inputTypes.js.map +1 -0
  196. package/lib/lib/shape.d.ts +73 -0
  197. package/lib/lib/shape.js +74 -0
  198. package/lib/lib/shape.js.map +1 -0
  199. package/lib/lib/sizing.d.ts +46 -0
  200. package/lib/lib/sizing.js +43 -0
  201. package/lib/lib/sizing.js.map +1 -0
  202. package/lib/lib/spacing.d.ts +264 -0
  203. package/lib/lib/spacing.js +265 -0
  204. package/lib/lib/spacing.js.map +1 -0
  205. package/lib/lib/theme.d.ts +22 -0
  206. package/lib/lib/theme.js +46 -0
  207. package/lib/lib/theme.js.map +1 -0
  208. package/lib/lib/utils.d.ts +12 -0
  209. package/lib/lib/utils.js +69 -0
  210. package/lib/lib/utils.js.map +1 -0
  211. package/lib/styles.css +12019 -0
  212. package/package.json +48 -0
  213. package/postcss.config.js +6 -0
  214. package/src/BarList.tsx +236 -0
  215. package/src/Chart.tsx +934 -0
  216. package/src/Context.tsx +204 -0
  217. package/src/Dashboard.tsx +379 -0
  218. package/src/DateRangePicker/Calendar.tsx +425 -0
  219. package/src/DateRangePicker/DateRangePicker.tsx +251 -0
  220. package/src/DateRangePicker/DateRangePickerButton.tsx +176 -0
  221. package/src/DateRangePicker/dateRangePickerUtils.tsx +460 -0
  222. package/src/DateRangePicker/index.ts +3 -0
  223. package/src/PieChart.tsx +838 -0
  224. package/src/QuillProvider.tsx +28 -0
  225. package/src/assets/ArrowDownHeadIcon.tsx +11 -0
  226. package/src/assets/ArrowDownIcon.tsx +14 -0
  227. package/src/assets/ArrowDownRightIcon.tsx +14 -0
  228. package/src/assets/ArrowLeftHeadIcon.tsx +11 -0
  229. package/src/assets/ArrowRightHeadIcon.tsx +11 -0
  230. package/src/assets/ArrowRightIcon.tsx +14 -0
  231. package/src/assets/ArrowUpHeadIcon.tsx +11 -0
  232. package/src/assets/ArrowUpIcon.tsx +14 -0
  233. package/src/assets/ArrowUpRightIcon.tsx +14 -0
  234. package/src/assets/CalendarIcon.tsx +14 -0
  235. package/src/assets/DoubleArrowLeftHeadIcon.tsx +18 -0
  236. package/src/assets/DoubleArrowRightHeadIcon.tsx +20 -0
  237. package/src/assets/ExclamationFilledIcon.tsx +14 -0
  238. package/src/assets/LoadingSpinner.tsx +11 -0
  239. package/src/assets/SearchIcon.tsx +14 -0
  240. package/src/assets/XCircleIcon.tsx +14 -0
  241. package/src/assets/index.ts +16 -0
  242. package/src/components/Dropdown/Dropdown.tsx +179 -0
  243. package/src/components/Dropdown/DropdownItem.tsx +86 -0
  244. package/src/components/Dropdown/index.ts +2 -0
  245. package/src/components/Modal/Modal.tsx +113 -0
  246. package/src/components/Modal/index.ts +1 -0
  247. package/src/components/selectUtils.ts +67 -0
  248. package/src/contexts/BaseColorContext.tsx +8 -0
  249. package/src/contexts/HoveredValueContext.tsx +12 -0
  250. package/src/contexts/RootStylesContext.tsx +5 -0
  251. package/src/contexts/SelectedValueContext.tsx +13 -0
  252. package/src/contexts/index.ts +4 -0
  253. package/src/hooks/index.ts +4 -0
  254. package/src/hooks/useInternalState.tsx +18 -0
  255. package/src/hooks/useOnClickOutside.tsx +23 -0
  256. package/src/hooks/useOnWindowResize.tsx +17 -0
  257. package/src/hooks/useSelectOnKeyDown.tsx +80 -0
  258. package/src/index.ts +4 -0
  259. package/src/lib/colorClassNames.ts +3191 -0
  260. package/src/lib/constants.ts +52 -0
  261. package/src/lib/font.ts +14 -0
  262. package/src/lib/hexColors.ts +28 -0
  263. package/src/lib/index.ts +10 -0
  264. package/src/lib/inputTypes.ts +62 -0
  265. package/src/lib/shape.ts +75 -0
  266. package/src/lib/sizing.ts +47 -0
  267. package/src/lib/spacing.ts +264 -0
  268. package/src/lib/theme.ts +49 -0
  269. package/src/lib/utils.tsx +81 -0
  270. package/src/styles.css +5 -0
  271. package/tailwind.config.js +16 -0
  272. package/tsconfig.json +22 -0
@@ -0,0 +1,425 @@
1
+ import React, { Dispatch, SetStateAction, useContext, useState } from 'react';
2
+ import { twMerge } from 'tailwind-merge';
3
+ import {
4
+ add,
5
+ eachDayOfInterval,
6
+ endOfMonth,
7
+ format,
8
+ getDay,
9
+ isSaturday,
10
+ isSunday,
11
+ nextSaturday,
12
+ previousSunday,
13
+ startOfMonth,
14
+ } from 'date-fns';
15
+ import { BaseColorContext } from '../contexts';
16
+
17
+ import {
18
+ ArrowLeftHeadIcon,
19
+ ArrowRightHeadIcon,
20
+ DoubleArrowLeftHeadIcon,
21
+ DoubleArrowRightHeadIcon,
22
+ } from '../assets';
23
+
24
+ import {
25
+ border,
26
+ borderRadius,
27
+ boxShadow,
28
+ fontSize,
29
+ fontWeight,
30
+ getColorClassNames,
31
+ sizing,
32
+ spacing,
33
+ } from '../lib';
34
+ import { capitalize, getDateStyles, getWeekdays } from './dateRangePickerUtils';
35
+ import { DEFAULT_COLOR, colorPalette } from '../lib/theme';
36
+ import { makeDateRangePickerClassName } from './dateRangePickerUtils';
37
+
38
+ export const colStartClasses = [
39
+ '',
40
+ 'col-start-2',
41
+ 'col-start-3',
42
+ 'col-start-4',
43
+ 'col-start-5',
44
+ 'col-start-6',
45
+ 'col-start-7',
46
+ ];
47
+
48
+ interface CalendarHeaderProps {
49
+ enableYearPagination: boolean;
50
+ anchorDate: Date;
51
+ setStartOfCurrMonth: Dispatch<SetStateAction<Date | null>>;
52
+ locale: Locale;
53
+ }
54
+
55
+ const CalendarHeader = ({
56
+ enableYearPagination,
57
+ anchorDate,
58
+ setStartOfCurrMonth,
59
+ locale,
60
+ }: CalendarHeaderProps) => {
61
+ const firstDayOfMonth = startOfMonth(anchorDate);
62
+ const handlePaginationClick = (
63
+ type: 'nextMonth' | 'prevMonth' | 'nextYear' | 'prevYear'
64
+ ) => {
65
+ switch (type) {
66
+ case 'nextMonth':
67
+ setStartOfCurrMonth(add(firstDayOfMonth, { months: 1 }));
68
+ break;
69
+ case 'prevMonth':
70
+ setStartOfCurrMonth(add(firstDayOfMonth, { months: -1 }));
71
+ break;
72
+ case 'nextYear':
73
+ setStartOfCurrMonth(add(firstDayOfMonth, { years: 1 }));
74
+ break;
75
+ case 'prevYear':
76
+ setStartOfCurrMonth(add(firstDayOfMonth, { years: -1 }));
77
+ break;
78
+ }
79
+ };
80
+
81
+ const displayedTitle = capitalize(
82
+ format(firstDayOfMonth, 'MMMM yyyy', { locale }),
83
+ locale
84
+ );
85
+
86
+ return (
87
+ <div
88
+ className={twMerge(
89
+ makeDateRangePickerClassName('calendarHeader'),
90
+ 'flex justify-between items-center',
91
+ spacing.twoXs.paddingX,
92
+ spacing.sm.paddingY
93
+ )}
94
+ >
95
+ <div
96
+ className={twMerge(
97
+ makeDateRangePickerClassName('calendarHeaderPrevSelection'),
98
+ 'flex items-center space-x-1'
99
+ )}
100
+ >
101
+ <button
102
+ type="button"
103
+ className={twMerge(
104
+ makeDateRangePickerClassName('calendarHeaderPrevYearButton'),
105
+ 'inline-flex focus:outline-none focus:ring-2',
106
+ !enableYearPagination && 'hidden',
107
+ getColorClassNames(DEFAULT_COLOR, colorPalette.canvasBackground)
108
+ .hoverBgColor,
109
+ getColorClassNames(DEFAULT_COLOR, colorPalette.ring).borderColor,
110
+ getColorClassNames('blue', colorPalette.lightRing).focusRingColor,
111
+ spacing.twoXs.paddingAll,
112
+ spacing.px.marginRight,
113
+ fontSize.sm,
114
+ fontWeight.md,
115
+ borderRadius.sm.all,
116
+ border.sm.all,
117
+ boxShadow.sm
118
+ )}
119
+ onClick={() => handlePaginationClick('prevYear')}
120
+ >
121
+ <DoubleArrowLeftHeadIcon
122
+ className={twMerge(
123
+ makeDateRangePickerClassName('calendarHeaderPrevYearIcon'),
124
+ getColorClassNames(DEFAULT_COLOR, colorPalette.darkText)
125
+ .textColor,
126
+ sizing.lg.height,
127
+ sizing.lg.width
128
+ )}
129
+ aria-hidden="true"
130
+ />
131
+ </button>
132
+ <button
133
+ type="button"
134
+ name="prevMonth"
135
+ className={twMerge(
136
+ makeDateRangePickerClassName('calendarHeaderPrevMonthButton'),
137
+ 'inline-flex focus:outline-none focus:ring-2',
138
+ getColorClassNames(DEFAULT_COLOR, colorPalette.canvasBackground)
139
+ .hoverBgColor,
140
+ getColorClassNames(DEFAULT_COLOR, colorPalette.ring).borderColor,
141
+ getColorClassNames('blue', colorPalette.lightRing).focusRingColor,
142
+ spacing.twoXs.paddingAll,
143
+ fontSize.sm,
144
+ fontWeight.md,
145
+ borderRadius.sm.all,
146
+ border.sm.all,
147
+ boxShadow.sm
148
+ )}
149
+ onClick={() => handlePaginationClick('prevMonth')}
150
+ >
151
+ <ArrowLeftHeadIcon
152
+ className={twMerge(
153
+ makeDateRangePickerClassName('calendarHeaderPrevMonthIcon'),
154
+ getColorClassNames(DEFAULT_COLOR, colorPalette.darkText)
155
+ .textColor,
156
+ sizing.lg.height,
157
+ sizing.lg.width
158
+ )}
159
+ aria-hidden="true"
160
+ />
161
+ </button>
162
+ </div>
163
+ <h2
164
+ className={twMerge(
165
+ makeDateRangePickerClassName('calendarHeaderText'),
166
+ 'text-elem',
167
+ getColorClassNames(DEFAULT_COLOR, colorPalette.darkestText).textColor,
168
+ fontSize.sm,
169
+ fontWeight.lg
170
+ )}
171
+ >
172
+ {displayedTitle}
173
+ </h2>
174
+ <div
175
+ className={twMerge(
176
+ makeDateRangePickerClassName('calendarHeaderNextSelection'),
177
+ 'flex items-center space-x-1'
178
+ )}
179
+ >
180
+ <button
181
+ type="button"
182
+ name="nextMonth"
183
+ className={twMerge(
184
+ makeDateRangePickerClassName('calendarHeaderNextMonthButton'),
185
+ 'inline-flex focus:outline-none focus:ring-2',
186
+ getColorClassNames(DEFAULT_COLOR, colorPalette.canvasBackground)
187
+ .hoverBgColor,
188
+ getColorClassNames(DEFAULT_COLOR, colorPalette.ring).borderColor,
189
+ getColorClassNames('blue', colorPalette.lightRing).focusRingColor,
190
+ spacing.twoXs.paddingAll,
191
+ fontSize.sm,
192
+ fontWeight.md,
193
+ borderRadius.sm.all,
194
+ border.sm.all,
195
+ boxShadow.sm
196
+ )}
197
+ onClick={() => handlePaginationClick('nextMonth')}
198
+ >
199
+ <ArrowRightHeadIcon
200
+ className={twMerge(
201
+ makeDateRangePickerClassName('calendarHeaderNextMonthIcon'),
202
+ getColorClassNames(DEFAULT_COLOR, colorPalette.darkText)
203
+ .textColor,
204
+ sizing.lg.height,
205
+ sizing.lg.width
206
+ )}
207
+ aria-hidden="true"
208
+ />
209
+ </button>
210
+ <button
211
+ type="button"
212
+ className={twMerge(
213
+ makeDateRangePickerClassName('calendarHeaderNextYearButton'),
214
+ 'inline-flex focus:outline-none focus:ring-2',
215
+ !enableYearPagination && 'hidden',
216
+ getColorClassNames(DEFAULT_COLOR, colorPalette.canvasBackground)
217
+ .hoverBgColor,
218
+ getColorClassNames(DEFAULT_COLOR, colorPalette.ring).borderColor,
219
+ getColorClassNames('blue', colorPalette.lightRing).focusRingColor,
220
+ spacing.twoXs.paddingAll,
221
+ spacing.px.marginLeft,
222
+ fontSize.sm,
223
+ fontWeight.md,
224
+ borderRadius.sm.all,
225
+ border.sm.all,
226
+ boxShadow.sm
227
+ )}
228
+ onClick={() => handlePaginationClick('nextYear')}
229
+ >
230
+ <DoubleArrowRightHeadIcon
231
+ className={twMerge(
232
+ makeDateRangePickerClassName('calendarHeaderNextYearIcon'),
233
+ 'shrink-0 flex-0',
234
+ getColorClassNames(DEFAULT_COLOR, colorPalette.darkText)
235
+ .textColor,
236
+ sizing.lg.height,
237
+ sizing.lg.width
238
+ )}
239
+ aria-hidden="true"
240
+ />
241
+ </button>
242
+ </div>
243
+ </div>
244
+ );
245
+ };
246
+
247
+ interface CalendarBodyProps {
248
+ anchorDate: Date;
249
+ selectedStartDate: Date | null;
250
+ selectedEndDate: Date | null;
251
+ onDateClick: (date: Date) => void;
252
+ minDate: Date | null;
253
+ maxDate: Date | null;
254
+ locale: Locale;
255
+ }
256
+
257
+ const CalendarBody = ({
258
+ anchorDate,
259
+ selectedStartDate,
260
+ selectedEndDate,
261
+ onDateClick,
262
+ minDate,
263
+ maxDate,
264
+ locale,
265
+ }: CalendarBodyProps) => {
266
+ const [hoveredDate, setHoveredDate] = useState<Date | undefined>();
267
+ const color = useContext(BaseColorContext);
268
+
269
+ const firstDayOfDisplayedMonth = startOfMonth(anchorDate);
270
+ const lastDayOfDisplayedMonth = endOfMonth(anchorDate);
271
+
272
+ const weekdays = getWeekdays(locale).map(dayName =>
273
+ capitalize(dayName, locale)
274
+ );
275
+
276
+ const displayedDates = eachDayOfInterval({
277
+ start: isSunday(firstDayOfDisplayedMonth)
278
+ ? firstDayOfDisplayedMonth
279
+ : previousSunday(firstDayOfDisplayedMonth),
280
+ end: isSaturday(lastDayOfDisplayedMonth)
281
+ ? lastDayOfDisplayedMonth
282
+ : nextSaturday(lastDayOfDisplayedMonth),
283
+ });
284
+
285
+ const isDateDisabled = (
286
+ date: Date,
287
+ minDate: Date | null,
288
+ maxDate: Date | null,
289
+ firstDayDisplayedMonth: Date,
290
+ lastDayDisplayedMonth: Date
291
+ ) => {
292
+ const isDateInDisplayedMonth =
293
+ date >= firstDayDisplayedMonth && date <= lastDayDisplayedMonth;
294
+ return (
295
+ (minDate !== null && date < minDate) ||
296
+ (maxDate !== null && date > maxDate) ||
297
+ !isDateInDisplayedMonth
298
+ );
299
+ };
300
+
301
+ return (
302
+ <>
303
+ <div
304
+ className={twMerge(
305
+ makeDateRangePickerClassName('calendarBodyWeekdays'),
306
+ 'grid grid-cols-7 text-center',
307
+ getColorClassNames(DEFAULT_COLOR, colorPalette.ring).textColor,
308
+ fontSize.xs,
309
+ fontWeight.md
310
+ )}
311
+ >
312
+ {weekdays.map(dayName => (
313
+ <div key={dayName} className="w-full flex justify-center">
314
+ <div
315
+ className={twMerge(
316
+ 'flex items-center justify-center w-full',
317
+ sizing.threeXl.height
318
+ )}
319
+ >
320
+ {dayName}
321
+ </div>
322
+ </div>
323
+ ))}
324
+ </div>
325
+ <div
326
+ className={twMerge(
327
+ makeDateRangePickerClassName('calendarBodyDatesGrid'),
328
+ 'grid grid-cols-7'
329
+ )}
330
+ >
331
+ {displayedDates.map(date => {
332
+ const isCurrentDateDisabled = isDateDisabled(
333
+ date,
334
+ minDate,
335
+ maxDate,
336
+ firstDayOfDisplayedMonth,
337
+ lastDayOfDisplayedMonth
338
+ );
339
+
340
+ return (
341
+ <div
342
+ key={date.toString()}
343
+ className={twMerge(
344
+ makeDateRangePickerClassName('calendarBodyDate'),
345
+ colStartClasses[getDay(date)],
346
+ 'w-full'
347
+ )}
348
+ >
349
+ <button
350
+ type="button"
351
+ onClick={() => onDateClick(date)}
352
+ onPointerEnter={() => setHoveredDate?.(date)}
353
+ onPointerLeave={() => setHoveredDate?.(undefined)}
354
+ className={twMerge(
355
+ 'w-full flex items-center justify-center',
356
+ sizing.threeXl.height,
357
+ fontSize.sm,
358
+ getDateStyles(
359
+ date,
360
+ selectedStartDate,
361
+ selectedEndDate,
362
+ hoveredDate,
363
+ isCurrentDateDisabled,
364
+ color
365
+ )
366
+ )}
367
+ disabled={isCurrentDateDisabled}
368
+ >
369
+ <time dateTime={format(date, 'yyyy-MM-dd', { locale })}>
370
+ {format(date, 'd', { locale })}
371
+ </time>
372
+ </button>
373
+ </div>
374
+ );
375
+ })}
376
+ </div>
377
+ </>
378
+ );
379
+ };
380
+
381
+ export interface CalendarProps {
382
+ enableYearPagination: boolean;
383
+ anchorDate: Date;
384
+ setStartOfCurrMonth: Dispatch<SetStateAction<Date | null>>;
385
+ startDate: Date | null;
386
+ endDate: Date | null;
387
+ minDate: Date | null;
388
+ maxDate: Date | null;
389
+ onDateClick: (date: Date) => void;
390
+ locale: Locale;
391
+ }
392
+
393
+ const Calendar = ({
394
+ enableYearPagination,
395
+ anchorDate,
396
+ setStartOfCurrMonth,
397
+ startDate,
398
+ endDate,
399
+ minDate,
400
+ maxDate,
401
+ onDateClick,
402
+ locale,
403
+ }: CalendarProps) => {
404
+ return (
405
+ <div className={twMerge(spacing.lg.paddingX, spacing.twoXs.paddingY)}>
406
+ <CalendarHeader
407
+ enableYearPagination={enableYearPagination}
408
+ anchorDate={anchorDate}
409
+ setStartOfCurrMonth={setStartOfCurrMonth}
410
+ locale={locale}
411
+ />
412
+ <CalendarBody
413
+ anchorDate={anchorDate}
414
+ selectedStartDate={startDate}
415
+ selectedEndDate={endDate}
416
+ onDateClick={onDateClick}
417
+ minDate={minDate}
418
+ maxDate={maxDate}
419
+ locale={locale}
420
+ />
421
+ </div>
422
+ );
423
+ };
424
+
425
+ export default Calendar;
@@ -0,0 +1,251 @@
1
+ /* eslint-disable react/display-name */
2
+ import React, { useRef, useState } from 'react';
3
+ import { twMerge } from 'tailwind-merge';
4
+
5
+ import { startOfMonth, startOfToday, sub } from 'date-fns';
6
+ import { enUS } from 'date-fns/locale';
7
+
8
+ import {
9
+ BaseColorContext,
10
+ HoveredValueContext,
11
+ SelectedValueContext,
12
+ } from '../contexts';
13
+
14
+ import { useInternalState, useSelectOnKeyDown } from '../hooks';
15
+
16
+ import {
17
+ defaultOptions,
18
+ getEndDateByDropdownValue,
19
+ getStartDateByDropdownValue,
20
+ makeDateRangePickerClassName,
21
+ parseEndDate,
22
+ parseStartDate,
23
+ } from './dateRangePickerUtils';
24
+
25
+ import Calendar from './Calendar';
26
+ import DateRangePickerButton from './DateRangePickerButton';
27
+ import { DropdownItem } from '../components/Dropdown';
28
+ import Modal from '../components/Modal';
29
+
30
+ export type Locale = typeof enUS;
31
+
32
+ export type DateRangePickerValue = [
33
+ (Date | null)?,
34
+ (Date | null)?,
35
+ (string | null)?
36
+ ];
37
+ export type DateRangePickerOption = {
38
+ value: string;
39
+ text: string;
40
+ startDate: Date;
41
+ endDate?: Date;
42
+ };
43
+
44
+ export interface DateRangePickerProps
45
+ extends Omit<React.HTMLAttributes<HTMLDivElement>, 'value' | 'defaultValue'> {
46
+ value?: DateRangePickerValue;
47
+ defaultValue?: DateRangePickerValue;
48
+ onValueChange?: (value: DateRangePickerValue) => void;
49
+ enableDropdown?: boolean;
50
+ options?: DateRangePickerOption[];
51
+ minDate?: Date | null;
52
+ maxDate?: Date | null;
53
+ placeholder?: string;
54
+ dropdownPlaceholder?: string;
55
+ enableYearPagination?: boolean;
56
+ disabled?: boolean;
57
+ color?: string;
58
+ locale?: Locale;
59
+ }
60
+
61
+ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
62
+ (props, ref) => {
63
+ const {
64
+ value,
65
+ defaultValue,
66
+ onValueChange,
67
+ enableDropdown = true,
68
+ options,
69
+ minDate = null,
70
+ maxDate = null,
71
+ placeholder = 'Select',
72
+ dropdownPlaceholder = 'Select',
73
+ disabled = false,
74
+ color = 'blue',
75
+ enableYearPagination = false,
76
+ locale = enUS,
77
+ className,
78
+ ...other
79
+ } = props;
80
+
81
+ const TODAY = startOfToday();
82
+ const calendarRef = useRef(null);
83
+ const dropdownRef = useRef(null);
84
+
85
+ const [selectedValue, setSelectedValue] = useInternalState(
86
+ defaultValue,
87
+ value
88
+ );
89
+
90
+ const [startOfCurrMonth, setStartOfCurrMonth] = useState<Date | null>(null);
91
+ const [showCalendar, setShowCalendar] = useState(false);
92
+ const [showDropdown, setShowDropdown] = useState(false);
93
+
94
+ const dropdownOptions = options ?? defaultOptions;
95
+ const selectedDropdownValue = selectedValue
96
+ ? selectedValue[2] ?? null
97
+ : null;
98
+ const selectedStartDate = selectedValue
99
+ ? parseStartDate(
100
+ selectedValue[0],
101
+ minDate,
102
+ selectedDropdownValue,
103
+ dropdownOptions
104
+ )
105
+ : null;
106
+ const selectedEndDate = selectedValue
107
+ ? parseEndDate(
108
+ selectedValue[1],
109
+ maxDate,
110
+ selectedDropdownValue,
111
+ dropdownOptions
112
+ )
113
+ : null;
114
+
115
+ const anchorDate =
116
+ startOfCurrMonth ?? selectedEndDate ?? selectedStartDate ?? TODAY;
117
+
118
+ const handleDateClick = (date: Date) => {
119
+ if (!selectedStartDate) {
120
+ onValueChange?.([date, selectedEndDate, null]);
121
+ setSelectedValue([date, selectedEndDate, null]);
122
+ } else if (selectedStartDate && !selectedEndDate) {
123
+ if (date < selectedStartDate) {
124
+ onValueChange?.([date, selectedEndDate, null]);
125
+ setSelectedValue([date, selectedEndDate, null]);
126
+ // Selection complete
127
+ } else {
128
+ onValueChange?.([selectedStartDate, date, null]);
129
+ setSelectedValue([selectedStartDate, date, null]);
130
+ setShowCalendar(false);
131
+ }
132
+ } else if (selectedStartDate && selectedEndDate) {
133
+ onValueChange?.([date, null, null]);
134
+ setSelectedValue([date, null, null]);
135
+ }
136
+ };
137
+
138
+ const handleCalendarKeyDown = (
139
+ e: React.KeyboardEvent<HTMLButtonElement>
140
+ ) => {
141
+ if (e.key === 'Escape') {
142
+ e.preventDefault();
143
+ setShowCalendar(false);
144
+ }
145
+ };
146
+
147
+ const handleDropdownOptionClick = (dropdownValue: string) => {
148
+ const selectedStartDate = getStartDateByDropdownValue(
149
+ dropdownValue,
150
+ dropdownOptions
151
+ );
152
+ const selectedEndDate = getEndDateByDropdownValue(
153
+ dropdownValue,
154
+ dropdownOptions
155
+ );
156
+
157
+ setSelectedValue([selectedStartDate, selectedEndDate, dropdownValue]);
158
+ onValueChange?.([selectedStartDate, selectedEndDate, dropdownValue]);
159
+ setStartOfCurrMonth(startOfMonth(selectedEndDate));
160
+ setShowDropdown(false);
161
+ };
162
+
163
+ const [hoveredDropdownValue, handleDropdownKeyDown] = useSelectOnKeyDown(
164
+ handleDropdownOptionClick,
165
+ dropdownOptions.map((option: DateRangePickerOption) => option.value),
166
+ showDropdown,
167
+ setShowDropdown,
168
+ selectedDropdownValue as string
169
+ );
170
+
171
+ return (
172
+ <BaseColorContext.Provider value={color}>
173
+ <div
174
+ ref={ref}
175
+ className={twMerge(
176
+ makeDateRangePickerClassName('root'),
177
+ 'relative w-full',
178
+ className
179
+ )}
180
+ {...other}
181
+ >
182
+ <DateRangePickerButton
183
+ value={[selectedStartDate, selectedEndDate, selectedDropdownValue]}
184
+ options={dropdownOptions}
185
+ placeholder={placeholder}
186
+ disabled={disabled}
187
+ calendarRef={calendarRef}
188
+ showCalendar={showCalendar}
189
+ setShowCalendar={setShowCalendar}
190
+ onCalendarKeyDown={handleCalendarKeyDown}
191
+ enableDropdown={enableDropdown}
192
+ dropdownRef={dropdownRef}
193
+ showDropdown={showDropdown}
194
+ setShowDropdown={setShowDropdown}
195
+ onDropdownKeyDown={handleDropdownKeyDown}
196
+ locale={locale}
197
+ dropdownPlaceholder={dropdownPlaceholder}
198
+ />
199
+ {/* Calendar Modal */}
200
+ <Modal
201
+ className={makeDateRangePickerClassName('calendarModal')}
202
+ showModal={showCalendar}
203
+ setShowModal={setShowCalendar}
204
+ parentRef={calendarRef}
205
+ width={288}
206
+ maxHeight="max-h-fit"
207
+ >
208
+ <Calendar
209
+ enableYearPagination={enableYearPagination}
210
+ anchorDate={anchorDate}
211
+ // setAnchorDate={setAnchorDate}
212
+ startDate={selectedStartDate}
213
+ endDate={selectedEndDate}
214
+ minDate={minDate}
215
+ maxDate={maxDate}
216
+ onDateClick={handleDateClick}
217
+ locale={locale}
218
+ setStartOfCurrMonth={setStartOfCurrMonth}
219
+ />
220
+ </Modal>
221
+ {/* Dropdpown Modal */}
222
+ <Modal
223
+ className={makeDateRangePickerClassName('dropdownModal')}
224
+ showModal={showDropdown}
225
+ setShowModal={setShowDropdown}
226
+ parentRef={dropdownRef}
227
+ >
228
+ <SelectedValueContext.Provider
229
+ value={{
230
+ selectedValue: selectedDropdownValue,
231
+ handleValueChange: handleDropdownOptionClick,
232
+ }}
233
+ >
234
+ <HoveredValueContext.Provider
235
+ value={{ hoveredValue: hoveredDropdownValue }}
236
+ >
237
+ {dropdownOptions.map(
238
+ ({ value, text }: DateRangePickerOption) => (
239
+ <DropdownItem key={value} value={value} text={text} />
240
+ )
241
+ )}
242
+ </HoveredValueContext.Provider>
243
+ </SelectedValueContext.Provider>
244
+ </Modal>
245
+ </div>
246
+ </BaseColorContext.Provider>
247
+ );
248
+ }
249
+ );
250
+
251
+ export default DateRangePicker;