@mui/x-date-pickers
Version:
The community edition of the MUI X Date and Time Picker components.
214 lines (209 loc) • 8.27 kB
JavaScript
;
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useValueAndOpenStates = useValueAndOpenStates;
var _formatErrorMessage2 = _interopRequireDefault(require("@mui/x-internals/formatErrorMessage"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _warning = require("@mui/x-internals/warning");
var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
var _useControlledValue = require("../../useControlledValue");
var _usePickerAdapter = require("../../../../hooks/usePickerAdapter");
var _validation = require("../../../../validation");
function useValueAndOpenStates(parameters) {
const {
props,
valueManager,
validator
} = parameters;
const {
value: valueProp,
defaultValue: defaultValueProp,
onChange,
referenceDate,
timezone: timezoneProp,
onAccept,
closeOnSelect,
open: openProp,
onOpen,
onClose
} = props;
const {
current: defaultValue
} = React.useRef(defaultValueProp);
const {
current: isValueControlled
} = React.useRef(valueProp !== undefined);
const {
current: isOpenControlled
} = React.useRef(openProp !== undefined);
const adapter = (0, _usePickerAdapter.usePickerAdapter)();
if (process.env.NODE_ENV !== 'production') {
if (props.renderInput != null) {
(0, _warning.warnOnce)(['MUI X: The `renderInput` prop has been removed in version 6.0 of the Date and Time Pickers.', 'You can replace it with the `textField` component slot in most cases.', 'For more information, please have a look at the migration guide (https://mui.com/x/migration/migration-pickers-v5/#input-renderer-required-in-v5).']);
}
}
/* eslint-disable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
if (process.env.NODE_ENV !== 'production') {
React.useEffect(() => {
if (isValueControlled !== (valueProp !== undefined)) {
console.error([`MUI X: A component is changing the ${isValueControlled ? '' : 'un'}controlled value of a Picker to be ${isValueControlled ? 'un' : ''}controlled.`, 'Elements should not switch from uncontrolled to controlled (or vice versa).', `Decide between using a controlled or uncontrolled value` + 'for the lifetime of the component.', "The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.", 'More info: https://fb.me/react-controlled-components'].join('\n'));
}
}, [valueProp]);
React.useEffect(() => {
if (!isValueControlled && defaultValue !== defaultValueProp) {
console.error([`MUI X: A component is changing the defaultValue of an uncontrolled Picker after being initialized. ` + `To suppress this warning opt to use a controlled value.`].join('\n'));
}
}, [JSON.stringify(defaultValue)]);
}
/* eslint-enable react-hooks/rules-of-hooks, react-hooks/exhaustive-deps */
const {
timezone,
value,
handleValueChange
} = (0, _useControlledValue.useControlledValue)({
name: 'a picker component',
timezone: timezoneProp,
value: valueProp,
defaultValue,
referenceDate,
onChange,
valueManager
});
const [state, setState] = React.useState(() => ({
open: false,
lastExternalValue: value,
clockShallowValue: undefined,
lastCommittedValue: value,
hasBeenModifiedSinceMount: false
}));
const {
getValidationErrorForNewValue
} = (0, _validation.useValidation)({
props,
validator,
timezone,
value,
onError: props.onError
});
const setOpen = (0, _useEventCallback.default)(action => {
const newOpen = typeof action === 'function' ? action(state.open) : action;
if (!isOpenControlled) {
setState(prevState => (0, _extends2.default)({}, prevState, {
open: newOpen
}));
}
if (newOpen && onOpen) {
onOpen();
}
if (!newOpen) {
onClose?.();
}
});
const setValue = (0, _useEventCallback.default)((newValue, options) => {
const {
changeImportance = 'accept',
skipPublicationIfPristine = false,
validationError,
shortcut,
source,
shouldClose = changeImportance === 'accept'
} = options ?? {};
let shouldFireOnChange;
let shouldFireOnAccept;
if (!skipPublicationIfPristine && !isValueControlled && !state.hasBeenModifiedSinceMount) {
// If the value is not controlled and the value has never been modified before,
// Then clicking on any value (including the one equal to `defaultValue`) should call `onChange` and `onAccept`
shouldFireOnChange = true;
shouldFireOnAccept = changeImportance === 'accept';
} else {
shouldFireOnChange = !valueManager.areValuesEqual(adapter, newValue, value);
shouldFireOnAccept = changeImportance === 'accept' && !valueManager.areValuesEqual(adapter, newValue, state.lastCommittedValue);
}
setState(prevState => (0, _extends2.default)({}, prevState, {
// We reset the shallow value whenever we fire onChange.
clockShallowValue: shouldFireOnChange ? undefined : prevState.clockShallowValue,
lastCommittedValue: shouldFireOnAccept ? newValue : prevState.lastCommittedValue,
hasBeenModifiedSinceMount: true
}));
let cachedContext = null;
const getContext = () => {
if (!cachedContext) {
let inferredSource;
if (source) {
inferredSource = source;
} else if (shortcut) {
inferredSource = 'view';
} else {
// Default to unknown when not explicitly tagged by a picker call site
inferredSource = 'unknown';
}
cachedContext = {
validationError: validationError == null ? getValidationErrorForNewValue(newValue) : validationError,
source: inferredSource
};
if (shortcut) {
cachedContext.shortcut = shortcut;
}
}
return cachedContext;
};
if (shouldFireOnChange) {
handleValueChange(newValue, getContext());
}
if (shouldFireOnAccept && onAccept) {
onAccept(newValue, getContext());
}
if (shouldClose) {
setOpen(false);
}
});
// If `prop.value` changes, we update the state to reflect the new value
if (value !== state.lastExternalValue) {
setState(prevState => (0, _extends2.default)({}, prevState, {
lastExternalValue: value,
clockShallowValue: undefined,
hasBeenModifiedSinceMount: true
}));
}
const setValueFromView = (0, _useEventCallback.default)((newValue, selectionState = 'partial') => {
// TODO: Expose a new method (private?) like `setView` that only updates the clock shallow value.
if (selectionState === 'shallow') {
setState(prev => (0, _extends2.default)({}, prev, {
clockShallowValue: newValue,
hasBeenModifiedSinceMount: true
}));
return;
}
setValue(newValue, {
changeImportance: selectionState === 'finish' && closeOnSelect ? 'accept' : 'set',
source: 'view'
});
});
// It is required to update inner state in useEffect in order to avoid situation when
// Our component is not mounted yet, but `open` state is set to `true` (for example initially opened)
React.useEffect(() => {
if (isOpenControlled) {
if (openProp === undefined) {
throw new Error(process.env.NODE_ENV !== "production" ? 'MUI X: You must not mix controlling and uncontrolled mode for `open` prop' : (0, _formatErrorMessage2.default)(160));
}
setState(prevState => (0, _extends2.default)({}, prevState, {
open: openProp
}));
}
}, [isOpenControlled, openProp]);
const viewValue = React.useMemo(() => valueManager.cleanValue(adapter, state.clockShallowValue === undefined ? value : state.clockShallowValue), [adapter, valueManager, state.clockShallowValue, value]);
return {
timezone,
state,
setValue,
setValueFromView,
setOpen,
value,
viewValue
};
}