@mui/x-date-pickers
Version:
The community edition of the Date and Time Picker components (MUI X).
387 lines (385 loc) • 14.1 kB
JavaScript
"use strict";
'use client';
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.YearCalendar = void 0;
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _clsx = _interopRequireDefault(require("clsx"));
var _RtlProvider = require("@mui/system/RtlProvider");
var _styles = require("@mui/material/styles");
var _utils = require("@mui/utils");
var _PickersYear = require("./PickersYear");
var _useUtils = require("../internals/hooks/useUtils");
var _yearCalendarClasses = require("./yearCalendarClasses");
var _dateUtils = require("../internals/utils/date-utils");
var _valueManagers = require("../internals/utils/valueManagers");
var _getDefaultReferenceDate = require("../internals/utils/getDefaultReferenceDate");
var _useValueWithTimezone = require("../internals/hooks/useValueWithTimezone");
var _dimensions = require("../internals/constants/dimensions");
var _jsxRuntime = require("react/jsx-runtime");
const _excluded = ["autoFocus", "className", "value", "defaultValue", "referenceDate", "disabled", "disableFuture", "disablePast", "maxDate", "minDate", "onChange", "readOnly", "shouldDisableYear", "disableHighlightToday", "onYearFocus", "hasFocus", "onFocusedViewChange", "yearsOrder", "yearsPerRow", "timezone", "gridLabelId", "slots", "slotProps"];
const useUtilityClasses = ownerState => {
const {
classes
} = ownerState;
const slots = {
root: ['root']
};
return (0, _utils.unstable_composeClasses)(slots, _yearCalendarClasses.getYearCalendarUtilityClass, classes);
};
function useYearCalendarDefaultizedProps(props, name) {
const utils = (0, _useUtils.useUtils)();
const defaultDates = (0, _useUtils.useDefaultDates)();
const themeProps = (0, _styles.useThemeProps)({
props,
name
});
return (0, _extends2.default)({
disablePast: false,
disableFuture: false
}, themeProps, {
yearsPerRow: themeProps.yearsPerRow ?? 3,
minDate: (0, _dateUtils.applyDefaultDate)(utils, themeProps.minDate, defaultDates.minDate),
maxDate: (0, _dateUtils.applyDefaultDate)(utils, themeProps.maxDate, defaultDates.maxDate)
});
}
const YearCalendarRoot = (0, _styles.styled)('div', {
name: 'MuiYearCalendar',
slot: 'Root',
overridesResolver: (props, styles) => styles.root
})({
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
overflowY: 'auto',
height: '100%',
padding: '0 4px',
width: _dimensions.DIALOG_WIDTH,
maxHeight: _dimensions.MAX_CALENDAR_HEIGHT,
// avoid padding increasing width over defined
boxSizing: 'border-box',
position: 'relative'
});
/**
* Demos:
*
* - [DateCalendar](https://mui.com/x/react-date-pickers/date-calendar/)
*
* API:
*
* - [YearCalendar API](https://mui.com/x/api/date-pickers/year-calendar/)
*/
const YearCalendar = exports.YearCalendar = /*#__PURE__*/React.forwardRef(function YearCalendar(inProps, ref) {
const props = useYearCalendarDefaultizedProps(inProps, 'MuiYearCalendar');
const {
autoFocus,
className,
value: valueProp,
defaultValue,
referenceDate: referenceDateProp,
disabled,
disableFuture,
disablePast,
maxDate,
minDate,
onChange,
readOnly,
shouldDisableYear,
onYearFocus,
hasFocus,
onFocusedViewChange,
yearsOrder = 'asc',
yearsPerRow,
timezone: timezoneProp,
gridLabelId,
slots,
slotProps
} = props,
other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded);
const {
value,
handleValueChange,
timezone
} = (0, _useValueWithTimezone.useControlledValueWithTimezone)({
name: 'YearCalendar',
timezone: timezoneProp,
value: valueProp,
defaultValue,
referenceDate: referenceDateProp,
onChange,
valueManager: _valueManagers.singleItemValueManager
});
const now = (0, _useUtils.useNow)(timezone);
const isRtl = (0, _RtlProvider.useRtl)();
const utils = (0, _useUtils.useUtils)();
const referenceDate = React.useMemo(() => _valueManagers.singleItemValueManager.getInitialReferenceValue({
value,
utils,
props,
timezone,
referenceDate: referenceDateProp,
granularity: _getDefaultReferenceDate.SECTION_TYPE_GRANULARITY.year
}), [] // eslint-disable-line react-hooks/exhaustive-deps
);
const ownerState = props;
const classes = useUtilityClasses(ownerState);
const todayYear = React.useMemo(() => utils.getYear(now), [utils, now]);
const selectedYear = React.useMemo(() => {
if (value != null) {
return utils.getYear(value);
}
return null;
}, [value, utils]);
const [focusedYear, setFocusedYear] = React.useState(() => selectedYear || utils.getYear(referenceDate));
const [internalHasFocus, setInternalHasFocus] = (0, _utils.unstable_useControlled)({
name: 'YearCalendar',
state: 'hasFocus',
controlled: hasFocus,
default: autoFocus ?? false
});
const changeHasFocus = (0, _utils.unstable_useEventCallback)(newHasFocus => {
setInternalHasFocus(newHasFocus);
if (onFocusedViewChange) {
onFocusedViewChange(newHasFocus);
}
});
const isYearDisabled = React.useCallback(dateToValidate => {
if (disablePast && utils.isBeforeYear(dateToValidate, now)) {
return true;
}
if (disableFuture && utils.isAfterYear(dateToValidate, now)) {
return true;
}
if (minDate && utils.isBeforeYear(dateToValidate, minDate)) {
return true;
}
if (maxDate && utils.isAfterYear(dateToValidate, maxDate)) {
return true;
}
if (!shouldDisableYear) {
return false;
}
const yearToValidate = utils.startOfYear(dateToValidate);
return shouldDisableYear(yearToValidate);
}, [disableFuture, disablePast, maxDate, minDate, now, shouldDisableYear, utils]);
const handleYearSelection = (0, _utils.unstable_useEventCallback)((event, year) => {
if (readOnly) {
return;
}
const newDate = utils.setYear(value ?? referenceDate, year);
handleValueChange(newDate);
});
const focusYear = (0, _utils.unstable_useEventCallback)(year => {
if (!isYearDisabled(utils.setYear(value ?? referenceDate, year))) {
setFocusedYear(year);
changeHasFocus(true);
onYearFocus?.(year);
}
});
React.useEffect(() => {
setFocusedYear(prevFocusedYear => selectedYear !== null && prevFocusedYear !== selectedYear ? selectedYear : prevFocusedYear);
}, [selectedYear]);
const verticalDirection = yearsOrder !== 'desc' ? yearsPerRow * 1 : yearsPerRow * -1;
const horizontalDirection = isRtl && yearsOrder === 'asc' || !isRtl && yearsOrder === 'desc' ? -1 : 1;
const handleKeyDown = (0, _utils.unstable_useEventCallback)((event, year) => {
switch (event.key) {
case 'ArrowUp':
focusYear(year - verticalDirection);
event.preventDefault();
break;
case 'ArrowDown':
focusYear(year + verticalDirection);
event.preventDefault();
break;
case 'ArrowLeft':
focusYear(year - horizontalDirection);
event.preventDefault();
break;
case 'ArrowRight':
focusYear(year + horizontalDirection);
event.preventDefault();
break;
default:
break;
}
});
const handleYearFocus = (0, _utils.unstable_useEventCallback)((event, year) => {
focusYear(year);
});
const handleYearBlur = (0, _utils.unstable_useEventCallback)((event, year) => {
if (focusedYear === year) {
changeHasFocus(false);
}
});
const scrollerRef = React.useRef(null);
const handleRef = (0, _utils.unstable_useForkRef)(ref, scrollerRef);
React.useEffect(() => {
if (autoFocus || scrollerRef.current === null) {
return;
}
const tabbableButton = scrollerRef.current.querySelector('[tabindex="0"]');
if (!tabbableButton) {
return;
}
// Taken from useScroll in x-data-grid, but vertically centered
const offsetHeight = tabbableButton.offsetHeight;
const offsetTop = tabbableButton.offsetTop;
const clientHeight = scrollerRef.current.clientHeight;
const scrollTop = scrollerRef.current.scrollTop;
const elementBottom = offsetTop + offsetHeight;
if (offsetHeight > clientHeight || offsetTop < scrollTop) {
// Button already visible
return;
}
scrollerRef.current.scrollTop = elementBottom - clientHeight / 2 - offsetHeight / 2;
}, [autoFocus]);
const yearRange = utils.getYearRange([minDate, maxDate]);
if (yearsOrder === 'desc') {
yearRange.reverse();
}
return /*#__PURE__*/(0, _jsxRuntime.jsx)(YearCalendarRoot, (0, _extends2.default)({
ref: handleRef,
className: (0, _clsx.default)(classes.root, className),
ownerState: ownerState,
role: "radiogroup",
"aria-labelledby": gridLabelId
}, other, {
children: yearRange.map(year => {
const yearNumber = utils.getYear(year);
const isSelected = yearNumber === selectedYear;
const isDisabled = disabled || isYearDisabled(year);
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PickersYear.PickersYear, {
selected: isSelected,
value: yearNumber,
onClick: handleYearSelection,
onKeyDown: handleKeyDown,
autoFocus: internalHasFocus && yearNumber === focusedYear,
disabled: isDisabled,
tabIndex: yearNumber === focusedYear && !isDisabled ? 0 : -1,
onFocus: handleYearFocus,
onBlur: handleYearBlur,
"aria-current": todayYear === yearNumber ? 'date' : undefined,
yearsPerRow: yearsPerRow,
slots: slots,
slotProps: slotProps,
children: utils.format(year, 'year')
}, utils.format(year, 'year'));
})
}));
});
process.env.NODE_ENV !== "production" ? YearCalendar.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit the TypeScript types and run "pnpm proptypes" |
// ----------------------------------------------------------------------
autoFocus: _propTypes.default.bool,
/**
* Override or extend the styles applied to the component.
*/
classes: _propTypes.default.object,
className: _propTypes.default.string,
/**
* The default selected value.
* Used when the component is not controlled.
*/
defaultValue: _propTypes.default.object,
/**
* If `true` picker is disabled
*/
disabled: _propTypes.default.bool,
/**
* If `true`, disable values after the current date for date components, time for time components and both for date time components.
* @default false
*/
disableFuture: _propTypes.default.bool,
/**
* If `true`, today's date is rendering without highlighting with circle.
* @default false
*/
disableHighlightToday: _propTypes.default.bool,
/**
* If `true`, disable values before the current date for date components, time for time components and both for date time components.
* @default false
*/
disablePast: _propTypes.default.bool,
gridLabelId: _propTypes.default.string,
hasFocus: _propTypes.default.bool,
/**
* Maximal selectable date.
* @default 2099-12-31
*/
maxDate: _propTypes.default.object,
/**
* Minimal selectable date.
* @default 1900-01-01
*/
minDate: _propTypes.default.object,
/**
* Callback fired when the value changes.
* @template TDate
* @param {TDate} value The new value.
*/
onChange: _propTypes.default.func,
onFocusedViewChange: _propTypes.default.func,
onYearFocus: _propTypes.default.func,
/**
* If `true` picker is readonly
*/
readOnly: _propTypes.default.bool,
/**
* The date used to generate the new value when both `value` and `defaultValue` are empty.
* @default The closest valid year using the validation props, except callbacks such as `shouldDisableYear`.
*/
referenceDate: _propTypes.default.object,
/**
* Disable specific year.
* @template TDate
* @param {TDate} year The year to test.
* @returns {boolean} If `true`, the year will be disabled.
*/
shouldDisableYear: _propTypes.default.func,
/**
* The props used for each component slot.
* @default {}
*/
slotProps: _propTypes.default.object,
/**
* Overridable component slots.
* @default {}
*/
slots: _propTypes.default.object,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object, _propTypes.default.bool])), _propTypes.default.func, _propTypes.default.object]),
/**
* Choose which timezone to use for the value.
* Example: "default", "system", "UTC", "America/New_York".
* If you pass values from other timezones to some props, they will be converted to this timezone before being used.
* @see See the {@link https://mui.com/x/react-date-pickers/timezone/ timezones documentation} for more details.
* @default The timezone of the `value` or `defaultValue` prop is defined, 'default' otherwise.
*/
timezone: _propTypes.default.string,
/**
* The selected value.
* Used when the component is controlled.
*/
value: _propTypes.default.object,
/**
* Years are displayed in ascending (chronological) order by default.
* If `desc`, years are displayed in descending order.
* @default 'asc'
*/
yearsOrder: _propTypes.default.oneOf(['asc', 'desc']),
/**
* Years rendered per row.
* @default 3
*/
yearsPerRow: _propTypes.default.oneOf([3, 4])
} : void 0;