@gravity-ui/date-components 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 (217) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/cjs/components/Calendar/Calendar.css +220 -0
  4. package/dist/cjs/components/Calendar/Calendar.d.ts +13 -0
  5. package/dist/cjs/components/Calendar/Calendar.js +15 -0
  6. package/dist/cjs/components/Calendar/CalendarBase.d.ts +18 -0
  7. package/dist/cjs/components/Calendar/CalendarBase.js +89 -0
  8. package/dist/cjs/components/Calendar/RangeCalendar.d.ts +13 -0
  9. package/dist/cjs/components/Calendar/RangeCalendar.js +22 -0
  10. package/dist/cjs/components/Calendar/hooks/types.d.ts +124 -0
  11. package/dist/cjs/components/Calendar/hooks/types.js +2 -0
  12. package/dist/cjs/components/Calendar/hooks/useCalendarCellProps.d.ts +19 -0
  13. package/dist/cjs/components/Calendar/hooks/useCalendarCellProps.js +98 -0
  14. package/dist/cjs/components/Calendar/hooks/useCalendarGridProps.d.ts +5 -0
  15. package/dist/cjs/components/Calendar/hooks/useCalendarGridProps.js +57 -0
  16. package/dist/cjs/components/Calendar/hooks/useCalendarProps.d.ts +10 -0
  17. package/dist/cjs/components/Calendar/hooks/useCalendarProps.js +110 -0
  18. package/dist/cjs/components/Calendar/hooks/useCalendarState.d.ts +7 -0
  19. package/dist/cjs/components/Calendar/hooks/useCalendarState.js +178 -0
  20. package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.d.ts +7 -0
  21. package/dist/cjs/components/Calendar/hooks/useRangeCalendarState.js +82 -0
  22. package/dist/cjs/components/Calendar/i18n/en.json +4 -0
  23. package/dist/cjs/components/Calendar/i18n/index.d.ts +1 -0
  24. package/dist/cjs/components/Calendar/i18n/index.js +11 -0
  25. package/dist/cjs/components/Calendar/i18n/ru.json +4 -0
  26. package/dist/cjs/components/Calendar/index.d.ts +8 -0
  27. package/dist/cjs/components/Calendar/index.js +23 -0
  28. package/dist/cjs/components/Calendar/utils.d.ts +4 -0
  29. package/dist/cjs/components/Calendar/utils.js +40 -0
  30. package/dist/cjs/components/DateField/DateField.css +4 -0
  31. package/dist/cjs/components/DateField/DateField.d.ts +6 -0
  32. package/dist/cjs/components/DateField/DateField.js +38 -0
  33. package/dist/cjs/components/DateField/hooks/useDateFieldProps.d.ts +6 -0
  34. package/dist/cjs/components/DateField/hooks/useDateFieldProps.js +203 -0
  35. package/dist/cjs/components/DateField/hooks/useDateFieldState.d.ts +67 -0
  36. package/dist/cjs/components/DateField/hooks/useDateFieldState.js +628 -0
  37. package/dist/cjs/components/DateField/i18n/en.json +10 -0
  38. package/dist/cjs/components/DateField/i18n/index.d.ts +1 -0
  39. package/dist/cjs/components/DateField/i18n/index.js +11 -0
  40. package/dist/cjs/components/DateField/i18n/ru.json +10 -0
  41. package/dist/cjs/components/DateField/index.d.ts +3 -0
  42. package/dist/cjs/components/DateField/index.js +19 -0
  43. package/dist/cjs/components/DateField/types.d.ts +67 -0
  44. package/dist/cjs/components/DateField/types.js +2 -0
  45. package/dist/cjs/components/DateField/utils.d.ts +14 -0
  46. package/dist/cjs/components/DateField/utils.js +276 -0
  47. package/dist/cjs/components/DatePicker/DatePicker.css +19 -0
  48. package/dist/cjs/components/DatePicker/DatePicker.d.ts +5 -0
  49. package/dist/cjs/components/DatePicker/DatePicker.js +66 -0
  50. package/dist/cjs/components/DatePicker/DesktopCalendar.d.ts +15 -0
  51. package/dist/cjs/components/DatePicker/DesktopCalendar.js +56 -0
  52. package/dist/cjs/components/DatePicker/MobileCalendar.css +49 -0
  53. package/dist/cjs/components/DatePicker/MobileCalendar.d.ts +14 -0
  54. package/dist/cjs/components/DatePicker/MobileCalendar.js +78 -0
  55. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.d.ts +45 -0
  56. package/dist/cjs/components/DatePicker/hooks/useDatePickerState.js +114 -0
  57. package/dist/cjs/components/DatePicker/i18n/en.json +3 -0
  58. package/dist/cjs/components/DatePicker/i18n/index.d.ts +1 -0
  59. package/dist/cjs/components/DatePicker/i18n/index.js +11 -0
  60. package/dist/cjs/components/DatePicker/i18n/ru.json +3 -0
  61. package/dist/cjs/components/DatePicker/index.d.ts +2 -0
  62. package/dist/cjs/components/DatePicker/index.js +18 -0
  63. package/dist/cjs/components/DatePicker/utils.d.ts +1 -0
  64. package/dist/cjs/components/DatePicker/utils.js +5 -0
  65. package/dist/cjs/components/RelativeDateField/RelativeDateField.css +16 -0
  66. package/dist/cjs/components/RelativeDateField/RelativeDateField.d.ts +11 -0
  67. package/dist/cjs/components/RelativeDateField/RelativeDateField.js +37 -0
  68. package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldProps.d.ts +12 -0
  69. package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldProps.js +66 -0
  70. package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldState.d.ts +30 -0
  71. package/dist/cjs/components/RelativeDateField/hooks/useRelativeDateFieldState.js +66 -0
  72. package/dist/cjs/components/RelativeDateField/index.d.ts +3 -0
  73. package/dist/cjs/components/RelativeDateField/index.js +19 -0
  74. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.css +16 -0
  75. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.d.ts +6 -0
  76. package/dist/cjs/components/RelativeDatePicker/RelativeDatePicker.js +32 -0
  77. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.d.ts +17 -0
  78. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +175 -0
  79. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerState.d.ts +36 -0
  80. package/dist/cjs/components/RelativeDatePicker/hooks/useRelativeDatePickerState.js +109 -0
  81. package/dist/cjs/components/RelativeDatePicker/i18n/en.json +4 -0
  82. package/dist/cjs/components/RelativeDatePicker/i18n/index.d.ts +1 -0
  83. package/dist/cjs/components/RelativeDatePicker/i18n/index.js +11 -0
  84. package/dist/cjs/components/RelativeDatePicker/i18n/ru.json +4 -0
  85. package/dist/cjs/components/RelativeDatePicker/index.d.ts +3 -0
  86. package/dist/cjs/components/RelativeDatePicker/index.js +19 -0
  87. package/dist/cjs/components/hooks/useControlledState.d.ts +1 -0
  88. package/dist/cjs/components/hooks/useControlledState.js +30 -0
  89. package/dist/cjs/components/index.d.ts +5 -0
  90. package/dist/cjs/components/index.js +21 -0
  91. package/dist/cjs/components/types/datePicker.d.ts +16 -0
  92. package/dist/cjs/components/types/datePicker.js +2 -0
  93. package/dist/cjs/components/types/events.d.ts +17 -0
  94. package/dist/cjs/components/types/events.js +2 -0
  95. package/dist/cjs/components/types/index.d.ts +4 -0
  96. package/dist/cjs/components/types/index.js +2 -0
  97. package/dist/cjs/components/types/inputs.d.ts +79 -0
  98. package/dist/cjs/components/types/inputs.js +2 -0
  99. package/dist/cjs/components/types/style.d.ts +7 -0
  100. package/dist/cjs/components/types/style.js +2 -0
  101. package/dist/cjs/components/utils/getButtonSizeForInput.d.ts +2 -0
  102. package/dist/cjs/components/utils/getButtonSizeForInput.js +20 -0
  103. package/dist/cjs/components/utils/mergeProps.d.ts +13 -0
  104. package/dist/cjs/components/utils/mergeProps.js +47 -0
  105. package/dist/cjs/components/variables.css +0 -0
  106. package/dist/cjs/index.d.ts +1 -0
  107. package/dist/cjs/index.js +17 -0
  108. package/dist/cjs/utils/cn.d.ts +2 -0
  109. package/dist/cjs/utils/cn.js +6 -0
  110. package/dist/esm/components/Calendar/Calendar.css +220 -0
  111. package/dist/esm/components/Calendar/Calendar.d.ts +13 -0
  112. package/dist/esm/components/Calendar/Calendar.js +9 -0
  113. package/dist/esm/components/Calendar/CalendarBase.d.ts +18 -0
  114. package/dist/esm/components/Calendar/CalendarBase.js +83 -0
  115. package/dist/esm/components/Calendar/RangeCalendar.d.ts +13 -0
  116. package/dist/esm/components/Calendar/RangeCalendar.js +16 -0
  117. package/dist/esm/components/Calendar/hooks/types.d.ts +124 -0
  118. package/dist/esm/components/Calendar/hooks/types.js +1 -0
  119. package/dist/esm/components/Calendar/hooks/useCalendarCellProps.d.ts +19 -0
  120. package/dist/esm/components/Calendar/hooks/useCalendarCellProps.js +91 -0
  121. package/dist/esm/components/Calendar/hooks/useCalendarGridProps.d.ts +5 -0
  122. package/dist/esm/components/Calendar/hooks/useCalendarGridProps.js +54 -0
  123. package/dist/esm/components/Calendar/hooks/useCalendarProps.d.ts +10 -0
  124. package/dist/esm/components/Calendar/hooks/useCalendarProps.js +103 -0
  125. package/dist/esm/components/Calendar/hooks/useCalendarState.d.ts +7 -0
  126. package/dist/esm/components/Calendar/hooks/useCalendarState.js +171 -0
  127. package/dist/esm/components/Calendar/hooks/useRangeCalendarState.d.ts +7 -0
  128. package/dist/esm/components/Calendar/hooks/useRangeCalendarState.js +75 -0
  129. package/dist/esm/components/Calendar/i18n/en.json +4 -0
  130. package/dist/esm/components/Calendar/i18n/index.d.ts +1 -0
  131. package/dist/esm/components/Calendar/i18n/index.js +5 -0
  132. package/dist/esm/components/Calendar/i18n/ru.json +4 -0
  133. package/dist/esm/components/Calendar/index.d.ts +8 -0
  134. package/dist/esm/components/Calendar/index.js +7 -0
  135. package/dist/esm/components/Calendar/utils.d.ts +4 -0
  136. package/dist/esm/components/Calendar/utils.js +34 -0
  137. package/dist/esm/components/DateField/DateField.css +4 -0
  138. package/dist/esm/components/DateField/DateField.d.ts +6 -0
  139. package/dist/esm/components/DateField/DateField.js +31 -0
  140. package/dist/esm/components/DateField/hooks/useDateFieldProps.d.ts +6 -0
  141. package/dist/esm/components/DateField/hooks/useDateFieldProps.js +196 -0
  142. package/dist/esm/components/DateField/hooks/useDateFieldState.d.ts +67 -0
  143. package/dist/esm/components/DateField/hooks/useDateFieldState.js +621 -0
  144. package/dist/esm/components/DateField/i18n/en.json +10 -0
  145. package/dist/esm/components/DateField/i18n/index.d.ts +1 -0
  146. package/dist/esm/components/DateField/i18n/index.js +5 -0
  147. package/dist/esm/components/DateField/i18n/ru.json +10 -0
  148. package/dist/esm/components/DateField/index.d.ts +3 -0
  149. package/dist/esm/components/DateField/index.js +3 -0
  150. package/dist/esm/components/DateField/types.d.ts +67 -0
  151. package/dist/esm/components/DateField/types.js +1 -0
  152. package/dist/esm/components/DateField/utils.d.ts +14 -0
  153. package/dist/esm/components/DateField/utils.js +268 -0
  154. package/dist/esm/components/DatePicker/DatePicker.css +19 -0
  155. package/dist/esm/components/DatePicker/DatePicker.d.ts +5 -0
  156. package/dist/esm/components/DatePicker/DatePicker.js +59 -0
  157. package/dist/esm/components/DatePicker/DesktopCalendar.d.ts +15 -0
  158. package/dist/esm/components/DatePicker/DesktopCalendar.js +48 -0
  159. package/dist/esm/components/DatePicker/MobileCalendar.css +49 -0
  160. package/dist/esm/components/DatePicker/MobileCalendar.d.ts +14 -0
  161. package/dist/esm/components/DatePicker/MobileCalendar.js +73 -0
  162. package/dist/esm/components/DatePicker/hooks/useDatePickerState.d.ts +45 -0
  163. package/dist/esm/components/DatePicker/hooks/useDatePickerState.js +107 -0
  164. package/dist/esm/components/DatePicker/i18n/en.json +3 -0
  165. package/dist/esm/components/DatePicker/i18n/index.d.ts +1 -0
  166. package/dist/esm/components/DatePicker/i18n/index.js +5 -0
  167. package/dist/esm/components/DatePicker/i18n/ru.json +3 -0
  168. package/dist/esm/components/DatePicker/index.d.ts +2 -0
  169. package/dist/esm/components/DatePicker/index.js +2 -0
  170. package/dist/esm/components/DatePicker/utils.d.ts +1 -0
  171. package/dist/esm/components/DatePicker/utils.js +2 -0
  172. package/dist/esm/components/RelativeDateField/RelativeDateField.css +16 -0
  173. package/dist/esm/components/RelativeDateField/RelativeDateField.d.ts +11 -0
  174. package/dist/esm/components/RelativeDateField/RelativeDateField.js +30 -0
  175. package/dist/esm/components/RelativeDateField/hooks/useRelativeDateFieldProps.d.ts +12 -0
  176. package/dist/esm/components/RelativeDateField/hooks/useRelativeDateFieldProps.js +59 -0
  177. package/dist/esm/components/RelativeDateField/hooks/useRelativeDateFieldState.d.ts +30 -0
  178. package/dist/esm/components/RelativeDateField/hooks/useRelativeDateFieldState.js +59 -0
  179. package/dist/esm/components/RelativeDateField/index.d.ts +3 -0
  180. package/dist/esm/components/RelativeDateField/index.js +3 -0
  181. package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.css +16 -0
  182. package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.d.ts +6 -0
  183. package/dist/esm/components/RelativeDatePicker/RelativeDatePicker.js +25 -0
  184. package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.d.ts +17 -0
  185. package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerProps.js +168 -0
  186. package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerState.d.ts +36 -0
  187. package/dist/esm/components/RelativeDatePicker/hooks/useRelativeDatePickerState.js +102 -0
  188. package/dist/esm/components/RelativeDatePicker/i18n/en.json +4 -0
  189. package/dist/esm/components/RelativeDatePicker/i18n/index.d.ts +1 -0
  190. package/dist/esm/components/RelativeDatePicker/i18n/index.js +5 -0
  191. package/dist/esm/components/RelativeDatePicker/i18n/ru.json +4 -0
  192. package/dist/esm/components/RelativeDatePicker/index.d.ts +3 -0
  193. package/dist/esm/components/RelativeDatePicker/index.js +3 -0
  194. package/dist/esm/components/hooks/useControlledState.d.ts +1 -0
  195. package/dist/esm/components/hooks/useControlledState.js +23 -0
  196. package/dist/esm/components/index.d.ts +5 -0
  197. package/dist/esm/components/index.js +5 -0
  198. package/dist/esm/components/types/datePicker.d.ts +16 -0
  199. package/dist/esm/components/types/datePicker.js +1 -0
  200. package/dist/esm/components/types/events.d.ts +17 -0
  201. package/dist/esm/components/types/events.js +1 -0
  202. package/dist/esm/components/types/index.d.ts +4 -0
  203. package/dist/esm/components/types/index.js +1 -0
  204. package/dist/esm/components/types/inputs.d.ts +79 -0
  205. package/dist/esm/components/types/inputs.js +1 -0
  206. package/dist/esm/components/types/style.d.ts +7 -0
  207. package/dist/esm/components/types/style.js +1 -0
  208. package/dist/esm/components/utils/getButtonSizeForInput.d.ts +2 -0
  209. package/dist/esm/components/utils/getButtonSizeForInput.js +16 -0
  210. package/dist/esm/components/utils/mergeProps.d.ts +13 -0
  211. package/dist/esm/components/utils/mergeProps.js +43 -0
  212. package/dist/esm/components/variables.css +0 -0
  213. package/dist/esm/index.d.ts +1 -0
  214. package/dist/esm/index.js +1 -0
  215. package/dist/esm/utils/cn.d.ts +2 -0
  216. package/dist/esm/utils/cn.js +3 -0
  217. package/package.json +119 -0
@@ -0,0 +1,91 @@
1
+ import React from 'react';
2
+ import { dateTime } from '@gravity-ui/date-utils';
3
+ export function useCalendarCellProps(date, state) {
4
+ const ref = React.useRef(null);
5
+ const isFocused = state.isCellFocused(date);
6
+ React.useEffect(() => {
7
+ var _a;
8
+ if (isFocused) {
9
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true });
10
+ }
11
+ }, [isFocused]);
12
+ const tabIndex = state.focusedDate.isSame(date, state.mode) ? 0 : -1;
13
+ const isDisabled = state.isCellDisabled(date);
14
+ const isSelected = state.isSelected(date);
15
+ const highlightedRange = 'highlightedRange' in state && state.highlightedRange;
16
+ const isRangeSelection = Boolean(highlightedRange && isSelected);
17
+ const isSelectionStart = isSelected && highlightedRange && date.isSame(highlightedRange.start, state.mode);
18
+ const isSelectionEnd = isSelected && highlightedRange && date.isSame(highlightedRange.end, state.mode);
19
+ const isOutsideCurrentRange = state.mode === 'days' ? !state.focusedDate.isSame(date, 'month') : false;
20
+ const isUnavailable = state.isCellUnavailable(date);
21
+ const isSelectable = !isDisabled && !isUnavailable;
22
+ const isCurrent = dateTime().isSame(date, state.mode);
23
+ const isWeekend = state.isWeekend(date);
24
+ let label = '';
25
+ if (state.mode === 'days') {
26
+ label = `${date.format('dddd')}, ${date.format('LL')}`;
27
+ }
28
+ else if (state.mode === 'months') {
29
+ label = `${date.format('MMMM YYYY')}`;
30
+ }
31
+ else if (state.mode === 'years') {
32
+ label = `${date.format('YYYY')}`;
33
+ }
34
+ const cellProps = {
35
+ role: 'gridcell',
36
+ 'aria-selected': isSelected ? 'true' : undefined,
37
+ 'aria-disabled': isDisabled ? 'true' : undefined,
38
+ };
39
+ const buttonProps = {
40
+ ref,
41
+ role: 'button',
42
+ tabIndex: isDisabled ? undefined : tabIndex,
43
+ 'aria-disabled': isSelectable ? undefined : 'true',
44
+ 'aria-label': label,
45
+ onClick: isSelectable
46
+ ? () => {
47
+ state.setFocusedDate(date);
48
+ if (state.mode === 'days') {
49
+ state.selectDate(date);
50
+ }
51
+ else {
52
+ state.zoomIn();
53
+ }
54
+ }
55
+ : undefined,
56
+ onPointerEnter() {
57
+ if ('highlightDate' in state && isSelectable) {
58
+ if (isOutsideCurrentRange) {
59
+ const newDate = date.isBefore(state.focusedDate)
60
+ ? state.focusedDate.startOf('month')
61
+ : state.focusedDate.endOf('month').startOf('date');
62
+ state.highlightDate(newDate);
63
+ }
64
+ else {
65
+ state.highlightDate(date);
66
+ }
67
+ }
68
+ },
69
+ };
70
+ let formattedDate = date.format('D');
71
+ if (state.mode === 'months') {
72
+ formattedDate = date.format('MMM');
73
+ }
74
+ else if (state.mode === 'years') {
75
+ formattedDate = date.format('YYYY');
76
+ }
77
+ return {
78
+ cellProps,
79
+ buttonProps,
80
+ formattedDate,
81
+ isDisabled,
82
+ isSelected,
83
+ isRangeSelection,
84
+ isSelectionStart,
85
+ isSelectionEnd,
86
+ isOutsideCurrentRange,
87
+ isUnavailable,
88
+ isCurrent,
89
+ isWeekend,
90
+ };
91
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { CalendarState, RangeCalendarState } from './types';
3
+ export declare function useCalendarGridProps(state: CalendarState | RangeCalendarState): {
4
+ gridProps: React.HTMLAttributes<HTMLElement>;
5
+ };
@@ -0,0 +1,54 @@
1
+ import React from 'react';
2
+ import { useFocusWithin } from '@gravity-ui/uikit';
3
+ export function useCalendarGridProps(state) {
4
+ const { focusWithinProps } = useFocusWithin({
5
+ onFocusWithinChange: (isFocused) => {
6
+ state.setFocused(isFocused);
7
+ },
8
+ });
9
+ const gridProps = Object.assign(Object.assign({ role: 'grid', 'aria-label': state.mode === 'years'
10
+ ? `${state.startDate.year()} — ${state.endDate.year()}`
11
+ : state.focusedDate.format(state.mode === 'days' ? 'MMMM YYYY' : 'YYYY'), 'aria-disabled': state.disabled ? 'true' : undefined, 'aria-readonly': state.readOnly ? 'true' : undefined }, focusWithinProps), { onKeyDown: (e) => {
12
+ if (e.key === 'ArrowRight') {
13
+ state.focusNextCell();
14
+ }
15
+ else if (e.key === 'ArrowLeft') {
16
+ state.focusPreviousCell();
17
+ }
18
+ else if (e.key === 'ArrowDown') {
19
+ state.focusNextRow();
20
+ }
21
+ else if (e.key === 'ArrowUp') {
22
+ state.focusPreviousRow();
23
+ }
24
+ else if (e.key === 'PageDown') {
25
+ state.focusNextPage(e.shiftKey);
26
+ }
27
+ else if (e.key === 'PageUp') {
28
+ state.focusPreviousPage(e.shiftKey);
29
+ }
30
+ else if (e.key === 'End') {
31
+ state.focusSectionEnd();
32
+ }
33
+ else if (e.key === 'Home') {
34
+ state.focusSectionStart();
35
+ }
36
+ else if (e.code === 'Minus') {
37
+ state.zoomOut();
38
+ }
39
+ else if (e.code === 'Equal') {
40
+ state.zoomIn();
41
+ }
42
+ else if (e.key === 'Enter' || e.key === ' ') {
43
+ if (state.mode === 'days') {
44
+ state.selectFocusedDate();
45
+ }
46
+ else {
47
+ state.setMode(state.mode === 'months' ? 'days' : 'months');
48
+ }
49
+ }
50
+ } });
51
+ return {
52
+ gridProps,
53
+ };
54
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { ButtonProps } from '@gravity-ui/uikit';
3
+ import type { CalendarProps } from '../Calendar';
4
+ import type { CalendarState, RangeCalendarState } from './types';
5
+ export declare function useCalendarProps(props: CalendarProps, state: CalendarState | RangeCalendarState): {
6
+ calendarProps: React.HTMLAttributes<HTMLElement>;
7
+ modeButtonProps: ButtonProps;
8
+ nextButtonProps: ButtonProps;
9
+ previousButtonProps: ButtonProps;
10
+ };
@@ -0,0 +1,103 @@
1
+ import React from 'react';
2
+ import { useFocusWithin } from '@gravity-ui/uikit';
3
+ import { i18n } from '../i18n';
4
+ const buttonDisabledClassName = 'yc-button_disabled g-button_disabled';
5
+ // eslint-disable-next-line complexity
6
+ export function useCalendarProps(props, state) {
7
+ const title = state.mode === 'years'
8
+ ? `${state.startDate.year()} — ${state.endDate.year()}`
9
+ : state.focusedDate.format(state.mode === 'days' ? 'MMMM YYYY' : 'YYYY');
10
+ const { focusWithinProps } = useFocusWithin({
11
+ onFocusWithin: props.onFocus,
12
+ onBlurWithin: props.onBlur,
13
+ });
14
+ const calendarProps = Object.assign({ role: 'group', id: props.id, 'aria-label': [props['aria-label'], title].filter(Boolean).join(', '), 'aria-labelledby': props['aria-labelledby'] || undefined, 'aria-describedby': props['aria-describedby'] || undefined, 'aria-details': props['aria-details'] || undefined, 'aria-disabled': state.disabled || undefined }, focusWithinProps);
15
+ const modeDisabled = state.disabled || state.mode === 'years';
16
+ const modeButtonProps = {
17
+ disabled: state.disabled,
18
+ // FIXME: do not use button class name
19
+ className: modeDisabled ? buttonDisabledClassName : undefined,
20
+ onClick: modeDisabled
21
+ ? undefined
22
+ : () => {
23
+ state.zoomOut();
24
+ if (state.mode === 'months') {
25
+ state.setFocused(true);
26
+ }
27
+ },
28
+ extraProps: {
29
+ 'aria-disabled': modeDisabled ? 'true' : undefined,
30
+ },
31
+ children: title,
32
+ };
33
+ const previousFocused = React.useRef(false);
34
+ const previousDisabled = state.disabled || state.isPreviousPageInvalid();
35
+ React.useLayoutEffect(() => {
36
+ if (previousDisabled && previousFocused.current) {
37
+ previousFocused.current = false;
38
+ state.setFocused(true);
39
+ }
40
+ });
41
+ const previousButtonProps = {
42
+ disabled: state.disabled,
43
+ // FIXME: do not use button class name
44
+ className: previousDisabled ? buttonDisabledClassName : undefined,
45
+ onClick: previousDisabled
46
+ ? undefined
47
+ : () => {
48
+ state.focusPreviousPage();
49
+ },
50
+ onFocus: previousDisabled
51
+ ? undefined
52
+ : () => {
53
+ previousFocused.current = true;
54
+ },
55
+ onBlur: previousDisabled
56
+ ? undefined
57
+ : () => {
58
+ previousFocused.current = false;
59
+ },
60
+ extraProps: {
61
+ 'aria-label': i18n('Previous'),
62
+ 'aria-disabled': previousDisabled ? 'true' : undefined,
63
+ },
64
+ };
65
+ const nextFocused = React.useRef(false);
66
+ const nextDisabled = state.disabled || state.isNextPageInvalid();
67
+ React.useLayoutEffect(() => {
68
+ if (nextDisabled && nextFocused.current) {
69
+ nextFocused.current = false;
70
+ state.setFocused(true);
71
+ }
72
+ });
73
+ const nextButtonProps = {
74
+ disabled: state.disabled,
75
+ // FIXME: do not use button class name
76
+ className: nextDisabled ? buttonDisabledClassName : undefined,
77
+ onClick: nextDisabled
78
+ ? undefined
79
+ : () => {
80
+ state.focusNextPage();
81
+ },
82
+ onFocus: nextDisabled
83
+ ? undefined
84
+ : () => {
85
+ nextFocused.current = true;
86
+ },
87
+ onBlur: nextDisabled
88
+ ? undefined
89
+ : () => {
90
+ nextFocused.current = false;
91
+ },
92
+ extraProps: {
93
+ 'aria-label': i18n('Next'),
94
+ 'aria-disabled': previousDisabled ? 'true' : undefined,
95
+ },
96
+ };
97
+ return {
98
+ calendarProps,
99
+ modeButtonProps,
100
+ nextButtonProps,
101
+ previousButtonProps,
102
+ };
103
+ }
@@ -0,0 +1,7 @@
1
+ import type { DateTime } from '@gravity-ui/date-utils';
2
+ import type { ValueBase } from '../../types';
3
+ import type { CalendarState, CalendarStateOptionsBase } from './types';
4
+ export interface CalendarStateOptions extends ValueBase<DateTime>, CalendarStateOptionsBase {
5
+ }
6
+ export type { CalendarState } from './types';
7
+ export declare function useCalendarState(props: CalendarStateOptions): CalendarState;
@@ -0,0 +1,171 @@
1
+ import React from 'react';
2
+ import { dateTime } from '@gravity-ui/date-utils';
3
+ import { useControlledState } from '../../hooks/useControlledState';
4
+ import { constrainValue } from '../utils';
5
+ export function useCalendarState(props) {
6
+ const { disabled, readOnly, minValue, maxValue, timeZone } = props;
7
+ const [value, setValue] = useControlledState(props.value, props.defaultValue, props.onUpdate);
8
+ const [mode, setMode] = useControlledState(props.mode, props.defaultMode, props.onUpdateMode);
9
+ const currentMode = mode || 'days';
10
+ const focusedValue = React.useMemo(() => {
11
+ if (!props.focusedValue) {
12
+ return props.focusedValue;
13
+ }
14
+ return constrainValue(props.focusedValue, minValue, maxValue);
15
+ }, [props.focusedValue, minValue, maxValue]);
16
+ const defaultFocusedValue = React.useMemo(() => {
17
+ const defaultValue = (props.defaultFocusedValue ? props.defaultFocusedValue : value) || dateTime({ timeZone });
18
+ return constrainValue(defaultValue, minValue, maxValue);
19
+ }, [maxValue, minValue, props.defaultFocusedValue, timeZone, value]);
20
+ const [focusedDateInner, setFocusedDate] = useControlledState(focusedValue, defaultFocusedValue, props.onFocusUpdate);
21
+ const focusedDate = focusedDateInner !== null && focusedDateInner !== void 0 ? focusedDateInner : constrainValue(dateTime({ timeZone }), minValue, maxValue);
22
+ if (isInvalid(focusedDate, minValue, maxValue)) {
23
+ // If the focused date was moved to an invalid value, it can't be focused, so constrain it.
24
+ setFocusedDate(constrainValue(focusedDate, minValue, maxValue));
25
+ }
26
+ function focusCell(date) {
27
+ setFocusedDate(constrainValue(date, minValue, maxValue));
28
+ }
29
+ const [isFocused, setFocused] = React.useState(props.autoFocus || false);
30
+ const startDate = getStartDate(focusedDate, currentMode);
31
+ const endDate = getEndDate(focusedDate, currentMode);
32
+ return {
33
+ disabled,
34
+ readOnly,
35
+ value,
36
+ setValue,
37
+ timeZone,
38
+ selectDate(date) {
39
+ if (!disabled && !readOnly) {
40
+ const newValue = constrainValue(date, minValue, maxValue);
41
+ if (this.isCellUnavailable(newValue)) {
42
+ return;
43
+ }
44
+ setValue(constrainValue(newValue, minValue, maxValue));
45
+ }
46
+ },
47
+ minValue,
48
+ maxValue,
49
+ focusedDate,
50
+ startDate,
51
+ endDate,
52
+ setFocusedDate(date) {
53
+ focusCell(date);
54
+ setFocused(true);
55
+ },
56
+ focusNextCell() {
57
+ focusCell(focusedDate.add({ [this.mode]: 1 }));
58
+ },
59
+ focusPreviousCell() {
60
+ focusCell(focusedDate.subtract({ [this.mode]: 1 }));
61
+ },
62
+ focusNextRow() {
63
+ if (this.mode === 'days') {
64
+ focusCell(focusedDate.add(1, 'week'));
65
+ }
66
+ else {
67
+ focusCell(focusedDate.add({ [this.mode]: 3 }));
68
+ }
69
+ },
70
+ focusPreviousRow() {
71
+ if (this.mode === 'days') {
72
+ focusCell(focusedDate.subtract(1, 'week'));
73
+ }
74
+ else {
75
+ focusCell(focusedDate.subtract({ [this.mode]: 3 }));
76
+ }
77
+ },
78
+ focusNextPage(larger) {
79
+ if (this.mode === 'days') {
80
+ focusCell(focusedDate.add({ months: larger ? 12 : 1 }));
81
+ }
82
+ else {
83
+ focusCell(focusedDate.add({ [this.mode]: 12 }));
84
+ }
85
+ },
86
+ focusPreviousPage(larger) {
87
+ if (this.mode === 'days') {
88
+ focusCell(focusedDate.subtract({ months: larger ? 12 : 1 }));
89
+ }
90
+ else {
91
+ focusCell(focusedDate.subtract({ [this.mode]: 12 }));
92
+ }
93
+ },
94
+ focusSectionStart() {
95
+ focusCell(getStartDate(focusedDate, this.mode));
96
+ },
97
+ focusSectionEnd() {
98
+ focusCell(getEndDate(focusedDate, this.mode));
99
+ },
100
+ zoomIn() {
101
+ this.setMode(this.mode === 'years' ? 'months' : 'days');
102
+ },
103
+ zoomOut() {
104
+ this.setMode(this.mode === 'days' ? 'months' : 'years');
105
+ },
106
+ selectFocusedDate() {
107
+ this.selectDate(focusedDate);
108
+ },
109
+ isFocused,
110
+ setFocused,
111
+ isInvalid(date) {
112
+ return isInvalid(date, this.minValue, this.maxValue, this.mode);
113
+ },
114
+ isPreviousPageInvalid() {
115
+ const prev = this.startDate.add({ days: -1 });
116
+ return this.isInvalid(prev);
117
+ },
118
+ isNextPageInvalid() {
119
+ const next = this.endDate.add({ days: 1 });
120
+ return this.isInvalid(next);
121
+ },
122
+ isSelected(date) {
123
+ return (Boolean(value) &&
124
+ date.isSame(value !== null && value !== void 0 ? value : undefined, currentMode) &&
125
+ !this.isCellDisabled(date));
126
+ },
127
+ isCellUnavailable(date) {
128
+ if (this.mode === 'days') {
129
+ return Boolean(props.isDateUnavailable && props.isDateUnavailable(date));
130
+ }
131
+ else {
132
+ return false;
133
+ }
134
+ },
135
+ isCellFocused(date) {
136
+ return this.isFocused && focusedDate && date.isSame(focusedDate, currentMode);
137
+ },
138
+ isCellDisabled(date) {
139
+ return this.disabled || this.isInvalid(date);
140
+ },
141
+ isWeekend(date) {
142
+ return this.mode === 'days' && [0, 6].includes(date.day());
143
+ },
144
+ mode: currentMode,
145
+ setMode,
146
+ };
147
+ }
148
+ function getStartDate(date, mode) {
149
+ if (mode === 'days') {
150
+ return date.startOf('month');
151
+ }
152
+ if (mode === 'months') {
153
+ return date.startOf('year');
154
+ }
155
+ const year = Math.floor(date.year() / 12) * 12;
156
+ return date.startOf('year').set('year', year);
157
+ }
158
+ function getEndDate(date, mode) {
159
+ if (mode === 'days') {
160
+ return date.endOf('month').startOf('day');
161
+ }
162
+ if (mode === 'months') {
163
+ return date.endOf('month').startOf('day');
164
+ }
165
+ const startDate = getStartDate(date, mode);
166
+ return startDate.add({ [mode]: 11 });
167
+ }
168
+ function isInvalid(date, minValue, maxValue, mode = 'days') {
169
+ const constrainedDate = constrainValue(date, minValue, maxValue);
170
+ return !constrainedDate.isSame(date, mode);
171
+ }
@@ -0,0 +1,7 @@
1
+ import type { DateTime } from '@gravity-ui/date-utils';
2
+ import type { RangeValue, ValueBase } from '../../types';
3
+ import type { CalendarStateOptionsBase, RangeCalendarState } from './types';
4
+ export interface RangeCalendarStateOptions extends ValueBase<RangeValue<DateTime>>, CalendarStateOptionsBase {
5
+ }
6
+ export type { RangeCalendarState } from './types';
7
+ export declare function useRangeCalendarState(props: RangeCalendarStateOptions): RangeCalendarState;
@@ -0,0 +1,75 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import React from 'react';
13
+ import { useControlledState } from '../../hooks/useControlledState';
14
+ import { constrainValue } from '../utils';
15
+ import { useCalendarState } from './useCalendarState';
16
+ export function useRangeCalendarState(props) {
17
+ var _a, _b;
18
+ const { value: valueProp, defaultValue, onUpdate } = props, calendarProps = __rest(props, ["value", "defaultValue", "onUpdate"]);
19
+ const [value, setValue] = useControlledState(valueProp, defaultValue, onUpdate);
20
+ const [anchorDate, setAnchorDateState] = React.useState();
21
+ const calendar = useCalendarState(Object.assign(Object.assign({}, calendarProps), { value: (_a = value === null || value === void 0 ? void 0 : value.start) !== null && _a !== void 0 ? _a : null }));
22
+ const highlightedRange = anchorDate
23
+ ? makeRange(anchorDate, calendar.focusedDate)
24
+ : (_b = (value && makeRange(value.start, value.end))) !== null && _b !== void 0 ? _b : undefined;
25
+ const selectDate = (date) => {
26
+ if (props.disabled || props.readOnly) {
27
+ return;
28
+ }
29
+ date = constrainValue(date, props.minValue, props.maxValue);
30
+ if (calendar.isCellUnavailable(date)) {
31
+ return;
32
+ }
33
+ if (anchorDate) {
34
+ const range = makeRange(anchorDate, date);
35
+ setValue(range);
36
+ setAnchorDateState(undefined);
37
+ }
38
+ else {
39
+ setAnchorDateState(date);
40
+ }
41
+ };
42
+ return Object.assign(Object.assign({}, calendar), { value,
43
+ setValue,
44
+ selectDate,
45
+ anchorDate, setAnchorDate: setAnchorDateState, highlightedRange,
46
+ selectFocusedDate() {
47
+ selectDate(calendar.focusedDate);
48
+ },
49
+ isSelected(date) {
50
+ if (!highlightedRange) {
51
+ return false;
52
+ }
53
+ return ((date.isSame(highlightedRange.start, this.mode) ||
54
+ date.isAfter(highlightedRange.start)) &&
55
+ (date.isSame(highlightedRange.end, this.mode) ||
56
+ date.isBefore(highlightedRange.end)));
57
+ },
58
+ highlightDate(date) {
59
+ if (anchorDate) {
60
+ this.setFocusedDate(date);
61
+ }
62
+ } });
63
+ }
64
+ function makeRange(start, end) {
65
+ if (start.isBefore(end)) {
66
+ return {
67
+ start,
68
+ end,
69
+ };
70
+ }
71
+ return {
72
+ start: end,
73
+ end: start,
74
+ };
75
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "Previous": "Previous",
3
+ "Next": "Next"
4
+ }
@@ -0,0 +1 @@
1
+ export declare const i18n: (key: "Previous" | "Next", params?: import("@gravity-ui/i18n").Params | undefined) => string;
@@ -0,0 +1,5 @@
1
+ import { addComponentKeysets } from '@gravity-ui/uikit/i18n';
2
+ import { NAMESPACE } from '../../../utils/cn';
3
+ import en from './en.json';
4
+ import ru from './ru.json';
5
+ export const i18n = addComponentKeysets({ en, ru }, `${NAMESPACE}calendar`);
@@ -0,0 +1,4 @@
1
+ {
2
+ "Previous": "Назад",
3
+ "Next": "Вперёд"
4
+ }
@@ -0,0 +1,8 @@
1
+ export * from './Calendar';
2
+ export * from './RangeCalendar';
3
+ export type { CalendarInstance } from './CalendarBase';
4
+ export * from './hooks/useCalendarState';
5
+ export * from './hooks/useRangeCalendarState';
6
+ export * from './hooks/useCalendarProps';
7
+ export * from './hooks/useCalendarGridProps';
8
+ export * from './hooks/useCalendarCellProps';
@@ -0,0 +1,7 @@
1
+ export * from './Calendar';
2
+ export * from './RangeCalendar';
3
+ export * from './hooks/useCalendarState';
4
+ export * from './hooks/useRangeCalendarState';
5
+ export * from './hooks/useCalendarProps';
6
+ export * from './hooks/useCalendarGridProps';
7
+ export * from './hooks/useCalendarCellProps';
@@ -0,0 +1,4 @@
1
+ import type { DateTime } from '@gravity-ui/date-utils';
2
+ export declare function constrainValue(value: DateTime, minValue: DateTime | undefined, maxValue: DateTime | undefined): DateTime;
3
+ export declare function getDaysInPeriod(startDate: DateTime, _endDate: DateTime, mode: 'days' | 'months' | 'years'): DateTime[];
4
+ export declare function getWeekDays(): DateTime[];
@@ -0,0 +1,34 @@
1
+ import { dateTime } from '@gravity-ui/date-utils';
2
+ export function constrainValue(value, minValue, maxValue) {
3
+ if (minValue && value.isBefore(minValue)) {
4
+ return minValue;
5
+ }
6
+ if (maxValue && maxValue.isBefore(value)) {
7
+ return maxValue;
8
+ }
9
+ return value;
10
+ }
11
+ export function getDaysInPeriod(startDate, _endDate, mode) {
12
+ const days = [];
13
+ if (mode === 'days') {
14
+ const currentDate = startDate.startOf('week');
15
+ for (let i = 0; i < 42; i++) {
16
+ days.push(currentDate.add({ days: i }));
17
+ }
18
+ }
19
+ else {
20
+ for (let i = 0; i < 12; i++) {
21
+ days.push(startDate.add({ [mode]: i }));
22
+ }
23
+ }
24
+ return days;
25
+ }
26
+ export function getWeekDays() {
27
+ const weekDays = [];
28
+ const weekStart = dateTime().startOf('week');
29
+ for (let i = 0; i < 7; i++) {
30
+ const date = weekStart.add({ days: i });
31
+ weekDays.push(date);
32
+ }
33
+ return weekDays;
34
+ }
@@ -0,0 +1,4 @@
1
+ .g-date-date-field {
2
+ display: inline-block;
3
+ width: auto;
4
+ }
@@ -0,0 +1,6 @@
1
+ import type { AccessibilityProps, DomProps, FocusableProps, KeyboardEvents, StyleProps, TextInputExtendProps, TextInputProps } from '../types';
2
+ import type { DateFieldStateOptions } from './hooks/useDateFieldState';
3
+ import './DateField.css';
4
+ export interface DateFieldProps extends DateFieldStateOptions, TextInputProps, TextInputExtendProps, DomProps, FocusableProps, KeyboardEvents, StyleProps, AccessibilityProps {
5
+ }
6
+ export declare function DateField({ className, ...props }: DateFieldProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,31 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ import React from 'react';
14
+ import { TextInput, useFocusWithin } from '@gravity-ui/uikit';
15
+ import { block } from '../../utils/cn';
16
+ import { useDateFieldProps } from './hooks/useDateFieldProps';
17
+ import { useDateFieldState } from './hooks/useDateFieldState';
18
+ import './DateField.css';
19
+ const b = block('date-field');
20
+ export function DateField(_a) {
21
+ var { className } = _a, props = __rest(_a, ["className"]);
22
+ const state = useDateFieldState(props);
23
+ const { inputProps } = useDateFieldProps(state, props);
24
+ const [isActive, setActive] = React.useState(false);
25
+ const { focusWithinProps } = useFocusWithin({
26
+ onFocusWithinChange(isFocusWithin) {
27
+ setActive(isFocusWithin);
28
+ },
29
+ });
30
+ return (_jsx("div", Object.assign({ className: b(null, className), style: props.style }, focusWithinProps, { children: _jsx(TextInput, Object.assign({}, inputProps, { value: state.isEmpty && !isActive && props.placeholder ? '' : inputProps.value })) })));
31
+ }
@@ -0,0 +1,6 @@
1
+ import type { TextInputProps } from '@gravity-ui/uikit';
2
+ import type { DateFieldProps } from '../DateField';
3
+ import type { DateFieldState } from './useDateFieldState';
4
+ export declare function useDateFieldProps(state: DateFieldState, props: DateFieldProps): {
5
+ inputProps: TextInputProps;
6
+ };