@docsvision/material-ui-pickers 3.2.0-beta.24 → 3.2.0-beta.26

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 (150) hide show
  1. package/.size-snapshot.json +11 -11
  2. package/9db1cba1a61cb58db53f38425bbd1f95.7z +0 -0
  3. package/build/DatePicker/DatePicker.d.ts +2 -2
  4. package/build/DatePicker/DatePicker.js +1 -1
  5. package/build/DateTimePicker/DateTimePicker.js +1 -1
  6. package/build/Picker/Picker.js +1 -1
  7. package/build/TimePicker/TimePicker.js +1 -1
  8. package/build/_helpers/text-field-helper.d.ts +1 -1
  9. package/build/_shared/KeyboardDateInput.js +1 -1
  10. package/build/_shared/ModalDialog.d.ts +2 -2
  11. package/build/_shared/PureDateInput.js +1 -1
  12. package/build/_shared/ToolbarButton.d.ts +2 -2
  13. package/build/_shared/hooks/useKeyboardPickerState.js +2 -2
  14. package/build/constants/prop-types.js +2 -2
  15. package/build/dist/material-ui-pickers.esm.js +12 -12
  16. package/build/dist/material-ui-pickers.esm.js.map +1 -1
  17. package/build/dist/material-ui-pickers.js +62 -62
  18. package/build/dist/material-ui-pickers.js.map +1 -1
  19. package/build/dist/material-ui-pickers.umd.js +5790 -4511
  20. package/build/dist/material-ui-pickers.umd.min.js +1 -1
  21. package/build/package.json +1 -1
  22. package/build/views/Calendar/Calendar.js +2 -2
  23. package/build/views/Clock/Clock.d.ts +1 -1
  24. package/build/views/Clock/ClockPointer.d.ts +1 -1
  25. package/package.json +1 -1
  26. package/src/DatePicker/DatePicker.tsx +91 -0
  27. package/src/DatePicker/DatePickerToolbar.tsx +75 -0
  28. package/src/DatePicker/index.ts +7 -0
  29. package/src/DateTimePicker/DateTimePicker.tsx +72 -0
  30. package/src/DateTimePicker/DateTimePickerTabs.tsx +86 -0
  31. package/src/DateTimePicker/DateTimePickerToolbar.tsx +123 -0
  32. package/src/DateTimePicker/index.ts +7 -0
  33. package/src/MuiPickersUtilsProvider.tsx +39 -0
  34. package/src/Picker/Picker.tsx +275 -0
  35. package/src/Picker/WrappedKeyboardPicker.tsx +136 -0
  36. package/src/Picker/WrappedPurePicker.tsx +128 -0
  37. package/src/Rifm/Rifm.ts +213 -0
  38. package/src/TimePicker/TimePicker.tsx +67 -0
  39. package/src/TimePicker/TimePickerToolbar.tsx +180 -0
  40. package/src/TimePicker/index.tsx +7 -0
  41. package/src/__tests__/DatePicker/Calendar.test.tsx +51 -0
  42. package/src/__tests__/DatePicker/Month.test.tsx +36 -0
  43. package/src/__tests__/DatePicker/MonthSelection.test.tsx +37 -0
  44. package/src/__tests__/MuiPickersUtilsProvider.test.tsx +21 -0
  45. package/src/__tests__/TimePicker/Clock.test.tsx +68 -0
  46. package/src/__tests__/_helpers/date-utils.test.tsx +197 -0
  47. package/src/__tests__/_helpers/text-field-helper.test.tsx +34 -0
  48. package/src/__tests__/_shared/ModalDialog.test.tsx +109 -0
  49. package/src/__tests__/e2e/DatePicker.test.tsx +233 -0
  50. package/src/__tests__/e2e/DatePickerProps.test.tsx +18 -0
  51. package/src/__tests__/e2e/DatePickerRoot.test.tsx +154 -0
  52. package/src/__tests__/e2e/DateTimePicker.test.tsx +86 -0
  53. package/src/__tests__/e2e/DateTimePickerRoot.test.tsx +72 -0
  54. package/src/__tests__/e2e/KeyboardDatePicker.test.tsx +140 -0
  55. package/src/__tests__/e2e/KeyboardDateTimePicker.test.tsx +48 -0
  56. package/src/__tests__/e2e/Theme.test.tsx +30 -0
  57. package/src/__tests__/e2e/TimePicker.test.tsx +121 -0
  58. package/src/__tests__/e2e/commands.tsx +8 -0
  59. package/src/__tests__/setup.js +26 -0
  60. package/src/__tests__/test-utils.tsx +45 -0
  61. package/src/__tests__/tsconfig.json +5 -0
  62. package/src/_helpers/date-utils.ts +92 -0
  63. package/src/_helpers/text-field-helper.ts +239 -0
  64. package/src/_helpers/time-utils.ts +83 -0
  65. package/src/_helpers/utils.ts +8 -0
  66. package/src/_shared/KeyboardDateInput.tsx +161 -0
  67. package/src/_shared/ModalDialog.tsx +114 -0
  68. package/src/_shared/PickerToolbar.tsx +52 -0
  69. package/src/_shared/PureDateInput.tsx +45 -0
  70. package/src/_shared/ToolbarButton.tsx +63 -0
  71. package/src/_shared/ToolbarText.tsx +49 -0
  72. package/src/_shared/WithUtils.tsx +19 -0
  73. package/src/_shared/hooks/useIsLandscape.tsx +27 -0
  74. package/src/_shared/hooks/useKeyDown.ts +34 -0
  75. package/src/_shared/hooks/useKeyboardPickerState.ts +72 -0
  76. package/src/_shared/hooks/useOpenState.ts +22 -0
  77. package/src/_shared/hooks/usePickerState.ts +134 -0
  78. package/src/_shared/hooks/useUtils.ts +20 -0
  79. package/src/_shared/hooks/useViews.tsx +31 -0
  80. package/src/_shared/icons/ArrowLeftIcon.tsx +11 -0
  81. package/src/_shared/icons/ArrowRightIcon.tsx +11 -0
  82. package/src/_shared/icons/DateRangeIcon.tsx +11 -0
  83. package/src/_shared/icons/KeyboardIcon.tsx +11 -0
  84. package/src/_shared/icons/TimeIcon.tsx +12 -0
  85. package/src/constants/ClockType.ts +11 -0
  86. package/src/constants/dimensions.ts +5 -0
  87. package/src/constants/prop-types.ts +37 -0
  88. package/src/index.ts +48 -0
  89. package/src/typings/BasePicker.tsx +60 -0
  90. package/src/typings/date.ts +3 -0
  91. package/src/typings/extendMui.ts +10 -0
  92. package/src/typings/overrides.ts +44 -0
  93. package/src/views/Calendar/Calendar.tsx +361 -0
  94. package/src/views/Calendar/CalendarHeader.tsx +141 -0
  95. package/src/views/Calendar/Day.tsx +97 -0
  96. package/src/views/Calendar/DayWrapper.tsx +33 -0
  97. package/src/views/Calendar/SlideTransition.tsx +100 -0
  98. package/src/views/Clock/Clock.tsx +172 -0
  99. package/src/views/Clock/ClockNumber.tsx +91 -0
  100. package/src/views/Clock/ClockNumbers.tsx +76 -0
  101. package/src/views/Clock/ClockPointer.tsx +104 -0
  102. package/src/views/Clock/ClockView.tsx +105 -0
  103. package/src/views/Month/Month.tsx +76 -0
  104. package/src/views/Month/MonthView.tsx +94 -0
  105. package/src/views/Year/Year.tsx +77 -0
  106. package/src/views/Year/YearView.tsx +91 -0
  107. package/src/wrappers/InlineWrapper.tsx +80 -0
  108. package/src/wrappers/ModalWrapper.tsx +113 -0
  109. package/src/wrappers/StaticWrapper.tsx +22 -0
  110. package/src/wrappers/Wrapper.tsx +75 -0
  111. package/coverage/clover.xml +0 -601
  112. package/coverage/coverage-final.json +0 -22
  113. package/coverage/lcov-report/base.css +0 -224
  114. package/coverage/lcov-report/block-navigation.js +0 -79
  115. package/coverage/lcov-report/index.html +0 -201
  116. package/coverage/lcov-report/prettify.css +0 -1
  117. package/coverage/lcov-report/prettify.js +0 -2
  118. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  119. package/coverage/lcov-report/sorter.js +0 -170
  120. package/coverage/lcov-report/src/MuiPickersUtilsProvider.tsx.html +0 -186
  121. package/coverage/lcov-report/src/_helpers/date-utils.ts.html +0 -345
  122. package/coverage/lcov-report/src/_helpers/index.html +0 -123
  123. package/coverage/lcov-report/src/_helpers/time-utils.ts.html +0 -318
  124. package/coverage/lcov-report/src/_helpers/utils.ts.html +0 -93
  125. package/coverage/lcov-report/src/_shared/ModalDialog.tsx.html +0 -411
  126. package/coverage/lcov-report/src/_shared/WithUtils.tsx.html +0 -126
  127. package/coverage/lcov-report/src/_shared/hooks/index.html +0 -110
  128. package/coverage/lcov-report/src/_shared/hooks/useKeyDown.ts.html +0 -171
  129. package/coverage/lcov-report/src/_shared/hooks/useUtils.ts.html +0 -129
  130. package/coverage/lcov-report/src/_shared/icons/ArrowLeftIcon.tsx.html +0 -102
  131. package/coverage/lcov-report/src/_shared/icons/ArrowRightIcon.tsx.html +0 -102
  132. package/coverage/lcov-report/src/_shared/icons/index.html +0 -110
  133. package/coverage/lcov-report/src/_shared/index.html +0 -110
  134. package/coverage/lcov-report/src/constants/ClockType.ts.html +0 -102
  135. package/coverage/lcov-report/src/constants/dimensions.ts.html +0 -84
  136. package/coverage/lcov-report/src/constants/index.html +0 -110
  137. package/coverage/lcov-report/src/index.html +0 -97
  138. package/coverage/lcov-report/src/views/Calendar/Calendar.tsx.html +0 -1152
  139. package/coverage/lcov-report/src/views/Calendar/CalendarHeader.tsx.html +0 -492
  140. package/coverage/lcov-report/src/views/Calendar/Day.tsx.html +0 -360
  141. package/coverage/lcov-report/src/views/Calendar/DayWrapper.tsx.html +0 -168
  142. package/coverage/lcov-report/src/views/Calendar/SlideTransition.tsx.html +0 -369
  143. package/coverage/lcov-report/src/views/Calendar/index.html +0 -149
  144. package/coverage/lcov-report/src/views/Clock/Clock.tsx.html +0 -585
  145. package/coverage/lcov-report/src/views/Clock/ClockPointer.tsx.html +0 -381
  146. package/coverage/lcov-report/src/views/Clock/index.html +0 -110
  147. package/coverage/lcov-report/src/views/Month/Month.tsx.html +0 -297
  148. package/coverage/lcov-report/src/views/Month/MonthView.tsx.html +0 -351
  149. package/coverage/lcov-report/src/views/Month/index.html +0 -110
  150. package/coverage/lcov.info +0 -1094
@@ -0,0 +1,45 @@
1
+ import * as React from 'react';
2
+ import * as enzyme from 'enzyme';
3
+ import LuxonUtils from '@date-io/luxon';
4
+ import MomentUtils from '@date-io/moment';
5
+ import DateFnsUtils from '@date-io/date-fns';
6
+ import MuiPickersUtilsProvider from '../MuiPickersUtilsProvider';
7
+ import { WithUtilsProps } from '../_shared/WithUtils';
8
+
9
+ const getUtilClass = () => {
10
+ switch (process.env.UTILS) {
11
+ case 'moment':
12
+ return MomentUtils;
13
+ case 'date-fns':
14
+ return DateFnsUtils;
15
+ case 'luxon':
16
+ return LuxonUtils;
17
+ default:
18
+ return DateFnsUtils;
19
+ }
20
+ };
21
+
22
+ export const UtilClassToUse: any = getUtilClass();
23
+ export const utilsToUse = new UtilClassToUse();
24
+
25
+ const getComponentWithUtils = <P extends WithUtilsProps>(element: React.ReactElement<P>) =>
26
+ React.cloneElement(element, { utils: utilsToUse } as any);
27
+
28
+ export const shallow = <P extends WithUtilsProps>(element: React.ReactElement<P>) =>
29
+ enzyme.shallow(getComponentWithUtils(element));
30
+
31
+ export const mount = <P extends WithUtilsProps>(element: React.ReactElement<P>) =>
32
+ enzyme.mount(<MuiPickersUtilsProvider utils={UtilClassToUse}>{element}</MuiPickersUtilsProvider>);
33
+
34
+ export const shallowRender = (render: (props: any) => React.ReactElement<any>) => {
35
+ return enzyme.shallow(render({ utils: utilsToUse, classes: {} as any, theme: {} as any }));
36
+ };
37
+
38
+ // toHaveBeenCalledWith doesn't work with moment because of changing some internal props
39
+ export const toHaveBeenCalledExceptMoment = (mock: jest.Mock<any, any>, params: any[]) => {
40
+ if (process.env.UTILS === 'moment') {
41
+ return expect(mock).toHaveBeenCalled();
42
+ }
43
+
44
+ return expect(mock).toHaveBeenCalledWith(...params);
45
+ };
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "include": ["./**/*.tsx", "../../typings.d.ts"],
4
+ "exclude": []
5
+ }
@@ -0,0 +1,92 @@
1
+ import { arrayIncludes } from './utils';
2
+ import { IUtils } from '@date-io/core/IUtils';
3
+ import { MaterialUiPickersDate } from '../typings/date';
4
+ import { DatePickerView } from '../DatePicker/DatePicker';
5
+
6
+ interface FindClosestDateParams {
7
+ date: MaterialUiPickersDate;
8
+ utils: IUtils<MaterialUiPickersDate>;
9
+ minDate: MaterialUiPickersDate;
10
+ maxDate: MaterialUiPickersDate;
11
+ disableFuture: boolean;
12
+ disablePast: boolean;
13
+ shouldDisableDate: (date: MaterialUiPickersDate) => boolean;
14
+ }
15
+
16
+ export const findClosestEnabledDate = ({
17
+ date,
18
+ utils,
19
+ minDate,
20
+ maxDate,
21
+ disableFuture,
22
+ disablePast,
23
+ shouldDisableDate,
24
+ }: FindClosestDateParams) => {
25
+ const today = utils.startOfDay(utils.date());
26
+
27
+ if (disablePast && utils.isBefore(minDate!, today)) {
28
+ minDate = today;
29
+ }
30
+
31
+ if (disableFuture && utils.isAfter(maxDate, today)) {
32
+ maxDate = today;
33
+ }
34
+
35
+ let forward = date;
36
+ let backward = date;
37
+ if (utils.isBefore(date, minDate)) {
38
+ forward = utils.date(minDate);
39
+ backward = null;
40
+ }
41
+
42
+ if (utils.isAfter(date, maxDate)) {
43
+ if (backward) {
44
+ backward = utils.date(maxDate);
45
+ }
46
+
47
+ forward = null;
48
+ }
49
+
50
+ while (forward || backward) {
51
+ if (forward && utils.isAfter(forward, maxDate)) {
52
+ forward = null;
53
+ }
54
+ if (backward && utils.isBefore(backward, minDate)) {
55
+ backward = null;
56
+ }
57
+
58
+ if (forward) {
59
+ if (!shouldDisableDate(forward)) {
60
+ return forward;
61
+ }
62
+ forward = utils.addDays(forward, 1);
63
+ }
64
+
65
+ if (backward) {
66
+ if (!shouldDisableDate(backward)) {
67
+ return backward;
68
+ }
69
+ backward = utils.addDays(backward, -1);
70
+ }
71
+ }
72
+
73
+ return null;
74
+ };
75
+
76
+ export const isYearOnlyView = (views: DatePickerView[]) =>
77
+ views.length === 1 && views[0] === 'year';
78
+
79
+ export const isYearAndMonthViews = (views: DatePickerView[]) =>
80
+ views.length === 2 && arrayIncludes(views, 'month') && arrayIncludes(views, 'year');
81
+
82
+ export const getFormatByViews = (views: DatePickerView[], utils: IUtils<MaterialUiPickersDate>) => {
83
+ if (isYearOnlyView(views)) {
84
+ return utils.yearFormat;
85
+ }
86
+
87
+ if (isYearAndMonthViews(views)) {
88
+ return utils.yearMonthFormat;
89
+ }
90
+
91
+ return utils.dateFormat;
92
+ };
@@ -0,0 +1,239 @@
1
+ import { DatePickerProps } from '..';
2
+ import { Omit } from '@material-ui/core';
3
+ import { IUtils } from '@date-io/core/IUtils';
4
+ import { ParsableDate } from '../constants/prop-types';
5
+ import { BasePickerProps } from '../typings/BasePicker';
6
+
7
+ const replaceAt = (str: string, index: number, replacement: string) => {
8
+ replacement = replacement || '';
9
+ return str.substr(0, index) + replacement + str.substr(index + replacement.length);
10
+ };
11
+
12
+ export const getDisplayDate = (
13
+ value: ParsableDate,
14
+ format: string,
15
+ utils: IUtils<any>,
16
+ isEmpty: boolean,
17
+ { invalidLabel, emptyLabel, labelFunc }: Omit<BasePickerProps, 'value' | 'onChange'>
18
+ ) => {
19
+ const date = utils.date(value);
20
+ if (labelFunc) {
21
+ return labelFunc(isEmpty ? null : date, invalidLabel!);
22
+ }
23
+
24
+ if (isEmpty) {
25
+ return emptyLabel || '';
26
+ }
27
+
28
+ return utils.isValid(date) ? utils.format(date, format) : invalidLabel!;
29
+ };
30
+
31
+ export interface BaseValidationProps {
32
+ /**
33
+ * Message, appearing when date cannot be parsed
34
+ * @default 'Invalid Date Format'
35
+ */
36
+ invalidDateMessage?: React.ReactNode;
37
+ }
38
+
39
+ export interface DateValidationProps extends BaseValidationProps {
40
+ /**
41
+ * Error message, shown if date is less then minimal date
42
+ * @default 'Date should not be before minimal date'
43
+ */
44
+ minDateMessage?: React.ReactNode;
45
+ /**
46
+ * Error message, shown if date is more then maximal date
47
+ * @default 'Date should not be after maximal date'
48
+ */
49
+ maxDateMessage?: React.ReactNode;
50
+ }
51
+
52
+ const getComparisonMaxDate = (utils: IUtils<any>, strictCompareDates: boolean, date: Date) => {
53
+ if (strictCompareDates) {
54
+ return date;
55
+ }
56
+
57
+ return utils.endOfDay(date);
58
+ };
59
+
60
+ const getComparisonMinDate = (utils: IUtils<any>, strictCompareDates: boolean, date: Date) => {
61
+ if (strictCompareDates) {
62
+ return date;
63
+ }
64
+
65
+ return utils.startOfDay(date);
66
+ };
67
+
68
+ export const validate = (
69
+ value: ParsableDate,
70
+ utils: IUtils<any>,
71
+ {
72
+ maxDate,
73
+ minDate,
74
+ disablePast,
75
+ disableFuture,
76
+ maxDateMessage,
77
+ minDateMessage,
78
+ invalidDateMessage,
79
+ strictCompareDates,
80
+ }: Omit<DatePickerProps, 'views' | 'openTo'> // DateTimePicker doesn't support
81
+ ): React.ReactNode => {
82
+ const parsedValue = utils.date(value);
83
+
84
+ // if null - do not show error
85
+ if (value === null) {
86
+ return '';
87
+ }
88
+
89
+ if (!utils.isValid(value)) {
90
+ return invalidDateMessage;
91
+ }
92
+
93
+ if (
94
+ maxDate &&
95
+ utils.isAfter(
96
+ parsedValue,
97
+ getComparisonMaxDate(utils, !!strictCompareDates, utils.date(maxDate))
98
+ )
99
+ ) {
100
+ return maxDateMessage;
101
+ }
102
+
103
+ if (
104
+ disableFuture &&
105
+ utils.isAfter(parsedValue, getComparisonMaxDate(utils, !!strictCompareDates, utils.date()))
106
+ ) {
107
+ return maxDateMessage;
108
+ }
109
+
110
+ if (
111
+ minDate &&
112
+ utils.isBefore(
113
+ parsedValue,
114
+ getComparisonMinDate(utils, !!strictCompareDates, utils.date(minDate))
115
+ )
116
+ ) {
117
+ return minDateMessage;
118
+ }
119
+ if (
120
+ disablePast &&
121
+ utils.isBefore(parsedValue, getComparisonMinDate(utils, !!strictCompareDates, utils.date()))
122
+ ) {
123
+ return minDateMessage;
124
+ }
125
+
126
+ return '';
127
+ };
128
+
129
+ export function pick12hOr24hFormat(
130
+ userFormat: string | undefined,
131
+ ampm: boolean | undefined = true,
132
+ formats: { '12h': string; '24h': string }
133
+ ) {
134
+ if (userFormat) {
135
+ return userFormat;
136
+ }
137
+
138
+ return ampm ? formats['12h'] : formats['24h'];
139
+ }
140
+
141
+ export function makeMaskFromFormat(format: string, numberMaskChar: string) {
142
+ return format.replace(/[a-z]/gi, numberMaskChar);
143
+ }
144
+
145
+ export const maskedDateFormatter = (mask: string, numberMaskChar: string) => (
146
+ value: string,
147
+ oldValue: string,
148
+ currentCaretPosition?: number
149
+ ) => {
150
+ const refuse = /[^\d\w_]+/gi;
151
+
152
+ if (!value || value === '') {
153
+ return value;
154
+ }
155
+
156
+ if (!oldValue) {
157
+ oldValue = '';
158
+ }
159
+
160
+ if (value == oldValue) {
161
+ return value;
162
+ }
163
+
164
+ if (value.length < oldValue.length && currentCaretPosition != null) {
165
+ value =
166
+ value.slice(0, currentCaretPosition) +
167
+ '_' +
168
+ value.slice(currentCaretPosition, oldValue.length);
169
+ }
170
+
171
+ let refusedOldValue = oldValue.replace(refuse, '');
172
+ let refusedNewValue = value.replace(refuse, '');
173
+ let refusedMaskSymbols = mask.replace(refuse, '');
174
+
175
+ const minLength =
176
+ refusedOldValue.length > refusedNewValue.length
177
+ ? refusedNewValue.length
178
+ : refusedOldValue.length;
179
+
180
+ let startPos = 0;
181
+ let endPosShift = 0;
182
+ while (startPos < minLength) {
183
+ if (refusedNewValue[startPos] == refusedOldValue[startPos]) {
184
+ startPos++;
185
+ } else {
186
+ break;
187
+ }
188
+ }
189
+
190
+ while (
191
+ endPosShift < minLength &&
192
+ startPos < refusedNewValue.length - endPosShift &&
193
+ startPos < refusedOldValue.length - endPosShift
194
+ ) {
195
+ if (
196
+ refusedNewValue[refusedNewValue.length - endPosShift - 1] ==
197
+ refusedOldValue[refusedOldValue.length - endPosShift - 1]
198
+ ) {
199
+ endPosShift++;
200
+ } else {
201
+ break;
202
+ }
203
+ }
204
+
205
+ let endStartPos = refusedNewValue.length - endPosShift;
206
+ endStartPos = endStartPos < startPos ? startPos : endStartPos;
207
+
208
+ let firstPart = refusedNewValue.slice(0, startPos);
209
+ let addedPart = refusedNewValue.slice(startPos, endStartPos);
210
+ let endPart = refusedNewValue.slice(endStartPos, refusedNewValue.length);
211
+
212
+ let maxSymbolsInEnd = refusedMaskSymbols.length - firstPart.length - addedPart.length;
213
+ while (maxSymbolsInEnd > endPart.length) {
214
+ addedPart += numberMaskChar;
215
+ maxSymbolsInEnd--;
216
+ }
217
+ let entireRefusedString =
218
+ firstPart + addedPart + endPart.slice(endPart.length - maxSymbolsInEnd, endPart.length);
219
+
220
+ // Do nothing ?...
221
+ entireRefusedString = entireRefusedString.slice(0, refusedMaskSymbols.length);
222
+
223
+ let i = 0;
224
+ let n = 0;
225
+ let result = '';
226
+ while (i < mask.length) {
227
+ const maskChar = mask[i];
228
+ if (maskChar === numberMaskChar && n < entireRefusedString.length) {
229
+ const parsedChar = entireRefusedString[n];
230
+ result += parsedChar;
231
+ n += 1;
232
+ } else {
233
+ result += maskChar;
234
+ }
235
+ i += 1;
236
+ }
237
+
238
+ return result;
239
+ };
@@ -0,0 +1,83 @@
1
+ import { IUtils } from '@date-io/core/IUtils';
2
+ import { MaterialUiPickersDate } from '../typings/date';
3
+
4
+ const center = {
5
+ x: 260 / 2,
6
+ y: 260 / 2,
7
+ };
8
+
9
+ const basePoint = {
10
+ x: center.x,
11
+ y: 0,
12
+ };
13
+
14
+ const cx = basePoint.x - center.x;
15
+ const cy = basePoint.y - center.y;
16
+
17
+ const rad2deg = (rad: number) => rad * 57.29577951308232;
18
+
19
+ const getAngleValue = (step: number, offsetX: number, offsetY: number) => {
20
+ const x = offsetX - center.x;
21
+ const y = offsetY - center.y;
22
+
23
+ const atan = Math.atan2(cx, cy) - Math.atan2(x, y);
24
+
25
+ let deg = rad2deg(atan);
26
+ deg = Math.round(deg / step) * step;
27
+ deg %= 360;
28
+
29
+ const value = Math.floor(deg / step) || 0;
30
+ const delta = Math.pow(x, 2) + Math.pow(y, 2);
31
+ const distance = Math.sqrt(delta);
32
+
33
+ return { value, distance };
34
+ };
35
+
36
+ export const getHours = (offsetX: number, offsetY: number, ampm: boolean) => {
37
+ let { value, distance } = getAngleValue(30, offsetX, offsetY);
38
+ value = value || 12;
39
+
40
+ if (!ampm) {
41
+ if (distance < 90) {
42
+ value += 12;
43
+ value %= 24;
44
+ }
45
+ } else {
46
+ value %= 12;
47
+ }
48
+
49
+ return value;
50
+ };
51
+
52
+ export const getMinutes = (offsetX: number, offsetY: number, step = 1) => {
53
+ const angleStep = step * 6;
54
+ let { value } = getAngleValue(angleStep, offsetX, offsetY);
55
+ value = (value * step) % 60;
56
+
57
+ return value;
58
+ };
59
+
60
+ export const getMeridiem = (
61
+ date: MaterialUiPickersDate,
62
+ utils: IUtils<MaterialUiPickersDate>
63
+ ): 'am' | 'pm' => {
64
+ return utils.getHours(date) >= 12 ? 'pm' : 'am';
65
+ };
66
+
67
+ export const convertToMeridiem = (
68
+ time: MaterialUiPickersDate,
69
+ meridiem: 'am' | 'pm',
70
+ ampm: boolean,
71
+ utils: IUtils<MaterialUiPickersDate>
72
+ ) => {
73
+ if (ampm) {
74
+ const currentMeridiem = utils.getHours(time) >= 12 ? 'pm' : 'am';
75
+ if (currentMeridiem !== meridiem) {
76
+ const hours = meridiem === 'am' ? utils.getHours(time) - 12 : utils.getHours(time) + 12;
77
+
78
+ return utils.setHours(time, hours);
79
+ }
80
+ }
81
+
82
+ return time;
83
+ };
@@ -0,0 +1,8 @@
1
+ /** Use it instead of .includes method for IE support */
2
+ export function arrayIncludes<T>(array: T[], itemOrItems: T | T[]) {
3
+ if (Array.isArray(itemOrItems)) {
4
+ return itemOrItems.every(item => array.indexOf(item) !== -1);
5
+ }
6
+
7
+ return array.indexOf(itemOrItems) !== -1;
8
+ }
@@ -0,0 +1,161 @@
1
+ import * as React from 'react';
2
+ import InputAdornment, { InputAdornmentProps } from '@material-ui/core/InputAdornment';
3
+ import TextField, { BaseTextFieldProps, TextFieldProps } from '@material-ui/core/TextField';
4
+ import { IconButton } from '@material-ui/core';
5
+ import { ExtendMui } from '../typings/extendMui';
6
+ import { KeyboardIcon } from './icons/KeyboardIcon';
7
+ import { IconButtonProps } from '@material-ui/core/IconButton';
8
+ import { makeMaskFromFormat, maskedDateFormatter } from '../_helpers/text-field-helper';
9
+ import { useState } from 'react';
10
+ import { Rifm } from '../Rifm/Rifm';
11
+
12
+ export interface KeyboardDateInputProps
13
+ extends ExtendMui<BaseTextFieldProps, 'variant' | 'onError' | 'onChange' | 'value'> {
14
+ format: string;
15
+ onChange: (value: string | null) => void;
16
+ onBlur?: () => void;
17
+ onClick?: () => void;
18
+ validationError?: React.ReactNode;
19
+ inputValue: string;
20
+ InputProps?: TextFieldProps['InputProps'];
21
+ /** Override input component */
22
+ TextFieldComponent?: React.ComponentType<TextFieldProps>;
23
+ /** Icon displaying for open picker button */
24
+ keyboardIcon?: React.ReactNode;
25
+ /** Pass material-ui text field variant down, bypass internal variant prop */
26
+ inputVariant?: TextFieldProps['variant'];
27
+ /**
28
+ * Custom mask. Can be used to override generate from format. (e.g. __/__/____ __:__)
29
+ */
30
+ mask?: string;
31
+ /**
32
+ * Char string that will be replaced with number (for "_" mask will be "__/__/____")
33
+ * @default '_'
34
+ */
35
+ maskChar?: string;
36
+ /**
37
+ * Refuse values regexp
38
+ * @default /[^\d]+/gi
39
+ */
40
+ refuse?: RegExp;
41
+ /**
42
+ * Props to pass to keyboard input adornment
43
+ * @type {Partial<InputAdornmentProps>}
44
+ */
45
+ InputAdornmentProps?: Partial<InputAdornmentProps>;
46
+ /**
47
+ * Props to pass to keyboard adornment button
48
+ * @type {Partial<IconButtonProps>}
49
+ */
50
+ KeyboardButtonProps?: Partial<IconButtonProps>;
51
+ /** Custom formatter to be passed into Rifm component */
52
+ rifmFormatter?: (str: string) => string;
53
+ /**
54
+ * Show errors only when input blur
55
+ */
56
+ showErrorOnBlur?: boolean;
57
+ }
58
+
59
+ const KeyboardDateInput: React.FunctionComponent<KeyboardDateInputProps> = ({
60
+ inputValue,
61
+ showErrorOnBlur = false,
62
+ inputVariant,
63
+ validationError,
64
+ KeyboardButtonProps,
65
+ InputAdornmentProps,
66
+ onClick,
67
+ onChange,
68
+ onBlur,
69
+ onFocus,
70
+ InputProps,
71
+ mask,
72
+ maskChar = '_',
73
+ refuse = /[^\d_]+/gi,
74
+ format,
75
+ keyboardIcon,
76
+ disabled,
77
+ rifmFormatter,
78
+ TextFieldComponent = TextField,
79
+ ...other
80
+ }) => {
81
+ const inputMask = mask || makeMaskFromFormat(format, maskChar);
82
+ const letterPosition = format.indexOf('a');
83
+ // prettier-ignore
84
+ const formatter = React.useCallback(
85
+ maskedDateFormatter(inputMask, maskChar),
86
+ [mask, maskChar]
87
+ );
88
+
89
+ const position =
90
+ InputAdornmentProps && InputAdornmentProps.position ? InputAdornmentProps.position : 'end';
91
+
92
+ const handleChange = (text: string) => {
93
+ const finalString = text === '' || text === inputMask ? null : text;
94
+ onChange(finalString);
95
+ };
96
+
97
+ const replace = (text: string): string => {
98
+ return text;
99
+ };
100
+
101
+ const [showErrorFlag, handleBlur] = useState(showErrorOnBlur ? true : false);
102
+
103
+ return (
104
+ <Rifm
105
+ value={inputValue}
106
+ onChange={handleChange}
107
+ format={rifmFormatter || formatter}
108
+ replace={replace}
109
+ mask={true}
110
+ maskChar={maskChar}
111
+ letterPosition={letterPosition}
112
+ >
113
+ {({ onChange, value }) => (
114
+ <TextFieldComponent
115
+ disabled={disabled}
116
+ error={Boolean(validationError) && !showErrorFlag}
117
+ helperText={!showErrorFlag && validationError}
118
+ {...other}
119
+ value={value}
120
+ onChange={onChange}
121
+ // onInput={changeInputStringValue}
122
+ // onKeyUp={handleKeyUp}
123
+ // onMouseUp={handleClick}
124
+ onBlur={() => {
125
+ if (onBlur) {
126
+ onBlur();
127
+ }
128
+ if (showErrorOnBlur) {
129
+ handleBlur(false);
130
+ }
131
+ }}
132
+ onFocus={(ev: any) => {
133
+ if (onFocus) {
134
+ onFocus(ev);
135
+ }
136
+ if (showErrorOnBlur) {
137
+ handleBlur(true);
138
+ }
139
+ }}
140
+ variant={inputVariant as any}
141
+ InputProps={{
142
+ ...InputProps,
143
+ [`${position}Adornment`]: (
144
+ <InputAdornment position={position} {...InputAdornmentProps}>
145
+ <IconButton disabled={disabled} {...KeyboardButtonProps} onClick={onClick}>
146
+ {keyboardIcon}
147
+ </IconButton>
148
+ </InputAdornment>
149
+ ),
150
+ }}
151
+ />
152
+ )}
153
+ </Rifm>
154
+ );
155
+ };
156
+
157
+ KeyboardDateInput.defaultProps = {
158
+ keyboardIcon: <KeyboardIcon />,
159
+ };
160
+
161
+ export default KeyboardDateInput;