-
Notifications
You must be signed in to change notification settings - Fork 833
/
usePickerState.ts
137 lines (119 loc) · 4.17 KB
/
usePickerState.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import { useOpenState } from './useOpenState';
import { WrapperVariant } from '../../wrappers/Wrapper';
import { BasePickerProps } from '../../typings/BasePicker';
import { MaterialUiPickersDate } from '../../typings/date';
import { useUtils, useNow, MuiPickersAdapter } from './useUtils';
import { useCallback, useDebugValue, useEffect, useMemo, useState } from 'react';
export const FORCE_FINISH_PICKER = Symbol('Force closing picker, useful for accessibility');
export function usePickerState<TInput, TDateValue, TErrorReason extends string>(
props: BasePickerProps<TInput, TDateValue, TErrorReason>,
valueManager: {
parseInput: (
now: MaterialUiPickersDate,
utils: MuiPickersAdapter,
props: BasePickerProps<TInput, TDateValue>
) => TDateValue;
emptyValue: TDateValue;
areValuesEqual: (valueLeft: TDateValue, valueRight: TDateValue) => boolean;
}
) {
const { autoOk, inputFormat, disabled, readOnly, onAccept, onChange, value } = props;
if (!inputFormat) {
throw new Error('inputFormat prop is required');
}
const now = useNow();
const utils = useUtils();
const date = valueManager.parseInput(now, utils, props);
const [pickerDate, setPickerDate] = useState(date);
// Mobile keyboard view is a special case.
// When it's open picker should work like closed, cause we are just showing text field
const [isMobileKeyboardViewOpen, setMobileKeyboardViewOpen] = useState(false);
const { isOpen, setIsOpen } = useOpenState(props);
useEffect(() => {
setPickerDate(currentPickerDate => {
if (!valueManager.areValuesEqual(currentPickerDate, date)) {
return date;
}
return currentPickerDate;
});
// We need to react only on value change, because `date` could potentially return new Date() on each render
}, [value, utils]); // eslint-disable-line
const acceptDate = useCallback(
(acceptedDate: TDateValue, needClosePicker: boolean) => {
onChange(acceptedDate);
if (needClosePicker) {
setIsOpen(false);
if (onAccept) {
onAccept(acceptedDate);
}
}
},
[onAccept, onChange, setIsOpen]
);
const wrapperProps = useMemo(
() => ({
open: isOpen,
onClear: () => acceptDate(valueManager.emptyValue, true),
onAccept: () => acceptDate(pickerDate, true),
onDismiss: () => setIsOpen(false),
onSetToday: () => {
// TODO FIX ME
setPickerDate(now as any);
acceptDate(now as any, Boolean(autoOk));
},
}),
[acceptDate, autoOk, isOpen, now, pickerDate, setIsOpen, valueManager.emptyValue]
);
const pickerProps = useMemo(
() => ({
date: pickerDate,
isMobileKeyboardViewOpen,
toggleMobileKeyboardView: () => {
if (!isMobileKeyboardViewOpen) {
// accept any partial input done by user
setPickerDate(pickerDate);
}
setMobileKeyboardViewOpen(!isMobileKeyboardViewOpen);
},
onDateChange: (
newDate: TDateValue,
currentVariant: WrapperVariant,
isFinish: boolean | symbol = true
) => {
setPickerDate(newDate);
const isFinishing =
typeof isFinish === 'boolean' ? isFinish : isFinish === FORCE_FINISH_PICKER;
if (isFinishing) {
const autoAcceptRequested = Boolean(autoOk) || isFinish === FORCE_FINISH_PICKER;
if (currentVariant === 'mobile' && autoAcceptRequested) {
acceptDate(newDate, true);
}
if (currentVariant !== 'mobile') {
acceptDate(newDate, autoAcceptRequested);
}
}
},
}),
[acceptDate, autoOk, isMobileKeyboardViewOpen, pickerDate]
);
const inputProps = useMemo(
() => ({
onChange,
inputFormat,
open: isOpen,
rawValue: value,
parsedDateValue: pickerDate,
openPicker: () => !readOnly && !disabled && setIsOpen(true),
}),
[onChange, inputFormat, isOpen, value, pickerDate, readOnly, disabled, setIsOpen]
);
const pickerState = { pickerProps, inputProps, wrapperProps };
useDebugValue(pickerState, () => ({
MuiPickerState: {
pickerDate,
parsedDate: date,
other: pickerState,
},
}));
return pickerState;
}