-
Notifications
You must be signed in to change notification settings - Fork 834
/
usePickerState.ts
142 lines (123 loc) · 4.16 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
138
139
140
141
142
import * as React from 'react';
import { useOpenState } from './useOpenState';
import { WrapperVariant } from '../../wrappers/Wrapper';
import { BasePickerProps } from '../../typings/BasePicker';
import { useUtils, useNow, MuiPickersAdapter } from './useUtils';
export interface PickerStateValueManager<TInput, TDateValue> {
parseInput: (utils: MuiPickersAdapter, props: BasePickerProps<TInput, TDateValue>) => TDateValue;
emptyValue: TDateValue;
areValuesEqual: (
utils: MuiPickersAdapter,
valueLeft: TDateValue,
valueRight: TDateValue
) => boolean;
}
export type PickerSelectionState = 'partial' | 'shallow' | 'finish';
export function usePickerState<TInput, TDateValue>(
props: BasePickerProps<TInput, TDateValue>,
valueManager: PickerStateValueManager<TInput, TDateValue>
) {
const {
inputFormat,
disabled,
readOnly,
onAccept,
onChange,
disableCloseOnSelect,
value,
} = props;
if (!inputFormat) {
throw new Error('inputFormat prop is required');
}
const now = useNow();
const utils = useUtils();
const { isOpen, setIsOpen } = useOpenState(props);
const [pickerDate, setPickerDate] = React.useState(valueManager.parseInput(utils, props));
// 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] = React.useState(false);
React.useEffect(() => {
const parsedDateValue = valueManager.parseInput(utils, props);
setPickerDate((currentPickerDate) => {
if (!valueManager.areValuesEqual(utils, currentPickerDate, parsedDateValue)) {
return parsedDateValue;
}
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 = React.useCallback(
(acceptedDate: TDateValue, needClosePicker: boolean) => {
onChange(acceptedDate);
if (needClosePicker) {
setIsOpen(false);
if (onAccept) {
onAccept(acceptedDate);
}
}
},
[onAccept, onChange, setIsOpen]
);
const wrapperProps = React.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, !disableCloseOnSelect);
},
}),
[acceptDate, disableCloseOnSelect, isOpen, now, pickerDate, setIsOpen, valueManager.emptyValue]
);
const pickerProps = React.useMemo(
() => ({
// canAutoFocus,
date: pickerDate,
isMobileKeyboardViewOpen,
toggleMobileKeyboardView: () => {
if (!isMobileKeyboardViewOpen) {
// accept any partial input done by React.user
setPickerDate(pickerDate);
}
setMobileKeyboardViewOpen(!isMobileKeyboardViewOpen);
},
onDateChange: (
newDate: TDateValue,
wrapperVariant: WrapperVariant,
selectionState: PickerSelectionState = 'partial'
) => {
setPickerDate(newDate);
if (selectionState === 'partial') {
acceptDate(newDate, false);
}
if (selectionState === 'finish') {
const shouldCloseOnSelect = !(disableCloseOnSelect ?? wrapperVariant === 'mobile');
acceptDate(newDate, shouldCloseOnSelect);
}
// if selectionState === "shallow" do nothing (we already update picker state)
},
}),
[acceptDate, disableCloseOnSelect, isMobileKeyboardViewOpen, pickerDate]
);
const inputProps = React.useMemo(
() => ({
onChange,
inputFormat,
open: isOpen,
rawValue: value,
openPicker: () => !readOnly && !disabled && setIsOpen(true),
}),
[onChange, inputFormat, isOpen, value, readOnly, disabled, setIsOpen]
);
const pickerState = { pickerProps, inputProps, wrapperProps };
React.useDebugValue(pickerState, () => ({
MuiPickerState: {
pickerDate,
other: pickerState,
},
}));
return pickerState;
}