214 lines
6.7 KiB
JavaScript
214 lines
6.7 KiB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
import * as React from 'react';
|
|
import { useOpenState } from './useOpenState';
|
|
import { useUtils } from './useUtils';
|
|
export const usePickerState = (props, valueManager) => {
|
|
const {
|
|
onAccept,
|
|
onChange,
|
|
value,
|
|
closeOnSelect
|
|
} = props;
|
|
const utils = useUtils();
|
|
const {
|
|
isOpen,
|
|
setIsOpen
|
|
} = useOpenState(props);
|
|
const parsedDateValue = React.useMemo(() => valueManager.parseInput(utils, value), [valueManager, utils, value]);
|
|
const [lastValidDateValue, setLastValidDateValue] = React.useState(parsedDateValue);
|
|
const [dateState, setDateState] = React.useState(() => ({
|
|
committed: parsedDateValue,
|
|
draft: parsedDateValue,
|
|
resetFallback: parsedDateValue
|
|
}));
|
|
const setDate = React.useCallback(params => {
|
|
setDateState(prev => {
|
|
switch (params.action) {
|
|
case 'setAll':
|
|
case 'acceptAndClose':
|
|
{
|
|
return {
|
|
draft: params.value,
|
|
committed: params.value,
|
|
resetFallback: params.value
|
|
};
|
|
}
|
|
|
|
case 'setCommitted':
|
|
{
|
|
return _extends({}, prev, {
|
|
draft: params.value,
|
|
committed: params.value
|
|
});
|
|
}
|
|
|
|
case 'setDraft':
|
|
{
|
|
return _extends({}, prev, {
|
|
draft: params.value
|
|
});
|
|
}
|
|
|
|
default:
|
|
{
|
|
return prev;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (params.forceOnChangeCall || !params.skipOnChangeCall && !valueManager.areValuesEqual(utils, dateState.committed, params.value)) {
|
|
onChange(params.value);
|
|
}
|
|
|
|
if (params.action === 'acceptAndClose') {
|
|
setIsOpen(false);
|
|
|
|
if (onAccept && !valueManager.areValuesEqual(utils, dateState.resetFallback, params.value)) {
|
|
onAccept(params.value);
|
|
}
|
|
}
|
|
}, [onAccept, onChange, setIsOpen, dateState, utils, valueManager]);
|
|
React.useEffect(() => {
|
|
if (utils.isValid(parsedDateValue)) {
|
|
setLastValidDateValue(parsedDateValue);
|
|
}
|
|
}, [utils, parsedDateValue]);
|
|
React.useEffect(() => {
|
|
if (isOpen) {
|
|
// Update all dates in state to equal the current prop value
|
|
setDate({
|
|
action: 'setAll',
|
|
value: parsedDateValue,
|
|
skipOnChangeCall: true
|
|
});
|
|
}
|
|
}, [isOpen]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
// Set the draft and committed date to equal the new prop value.
|
|
|
|
if (!valueManager.areValuesEqual(utils, dateState.committed, parsedDateValue)) {
|
|
setDate({
|
|
action: 'setCommitted',
|
|
value: parsedDateValue,
|
|
skipOnChangeCall: true
|
|
});
|
|
}
|
|
|
|
const wrapperProps = React.useMemo(() => ({
|
|
open: isOpen,
|
|
onClear: () => {
|
|
// Reset all date in state to the empty value and close picker.
|
|
setDate({
|
|
value: valueManager.emptyValue,
|
|
action: 'acceptAndClose',
|
|
// force `onChange` in cases like input (value) === `Invalid date`
|
|
forceOnChangeCall: !valueManager.areValuesEqual(utils, value, valueManager.emptyValue)
|
|
});
|
|
},
|
|
onAccept: () => {
|
|
// Set all date in state to equal the current draft value and close picker.
|
|
setDate({
|
|
value: dateState.draft,
|
|
action: 'acceptAndClose',
|
|
// force `onChange` in cases like input (value) === `Invalid date`
|
|
forceOnChangeCall: !valueManager.areValuesEqual(utils, value, parsedDateValue)
|
|
});
|
|
},
|
|
onDismiss: () => {
|
|
// Set all dates in state to equal the last committed date.
|
|
// e.g. Reset the state to the last committed value.
|
|
setDate({
|
|
value: dateState.committed,
|
|
action: 'acceptAndClose'
|
|
});
|
|
},
|
|
onCancel: () => {
|
|
// Set all dates in state to equal the last accepted date and close picker.
|
|
// e.g. Reset the state to the last accepted value
|
|
setDate({
|
|
value: dateState.resetFallback,
|
|
action: 'acceptAndClose'
|
|
});
|
|
},
|
|
onSetToday: () => {
|
|
// Set all dates in state to equal today and close picker.
|
|
setDate({
|
|
value: valueManager.getTodayValue(utils),
|
|
action: 'acceptAndClose'
|
|
});
|
|
}
|
|
}), [setDate, isOpen, utils, dateState, valueManager, value, parsedDateValue]); // Mobile keyboard view is a special case.
|
|
// When it's open picker should work like closed, because we are just showing text field
|
|
|
|
const [isMobileKeyboardViewOpen, setMobileKeyboardViewOpen] = React.useState(false);
|
|
const pickerProps = React.useMemo(() => ({
|
|
parsedValue: dateState.draft,
|
|
isMobileKeyboardViewOpen,
|
|
toggleMobileKeyboardView: () => setMobileKeyboardViewOpen(!isMobileKeyboardViewOpen),
|
|
onDateChange: (newDate, wrapperVariant, selectionState = 'partial') => {
|
|
switch (selectionState) {
|
|
case 'shallow':
|
|
{
|
|
// Update the `draft` state but do not fire `onChange`
|
|
return setDate({
|
|
action: 'setDraft',
|
|
value: newDate,
|
|
skipOnChangeCall: true
|
|
});
|
|
}
|
|
|
|
case 'partial':
|
|
{
|
|
// Update the `draft` state and fire `onChange`
|
|
return setDate({
|
|
action: 'setDraft',
|
|
value: newDate
|
|
});
|
|
}
|
|
|
|
case 'finish':
|
|
{
|
|
if (closeOnSelect != null ? closeOnSelect : wrapperVariant === 'desktop') {
|
|
// Set all dates in state to equal the new date and close picker.
|
|
return setDate({
|
|
value: newDate,
|
|
action: 'acceptAndClose'
|
|
});
|
|
} // Updates the `committed` state and fire `onChange`
|
|
|
|
|
|
return setDate({
|
|
value: newDate,
|
|
action: 'setCommitted'
|
|
});
|
|
}
|
|
|
|
default:
|
|
{
|
|
throw new Error('MUI: Invalid selectionState passed to `onDateChange`');
|
|
}
|
|
}
|
|
}
|
|
}), [setDate, isMobileKeyboardViewOpen, dateState.draft, closeOnSelect]);
|
|
const handleInputChange = React.useCallback((newParsedValue, keyboardInputValue) => {
|
|
const cleanParsedValue = valueManager.valueReducer ? valueManager.valueReducer(utils, lastValidDateValue, newParsedValue) : newParsedValue;
|
|
onChange(cleanParsedValue, keyboardInputValue);
|
|
}, [onChange, valueManager, lastValidDateValue, utils]);
|
|
const inputProps = React.useMemo(() => ({
|
|
onChange: handleInputChange,
|
|
open: isOpen,
|
|
rawValue: value,
|
|
openPicker: () => setIsOpen(true)
|
|
}), [handleInputChange, isOpen, value, setIsOpen]);
|
|
const pickerState = {
|
|
pickerProps,
|
|
inputProps,
|
|
wrapperProps
|
|
};
|
|
React.useDebugValue(pickerState, () => ({
|
|
MuiPickerState: {
|
|
dateState,
|
|
other: pickerState
|
|
}
|
|
}));
|
|
return pickerState;
|
|
}; |