Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 12x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 84x 84x | import React from 'react';
import type {DateTime} from '@gravity-ui/date-utils';
import {useControlledState} from '@gravity-ui/uikit';
import type {RangeValue} from '../../types';
import {constrainValue, mergeDateTime} from '../../utils/dates';
import {useDefaultTimeZone} from '../../utils/useDefaultTimeZone';
import type {CalendarLayout, RangeCalendarState} from './types';
import {useCalendarState} from './useCalendarState';
import type {CalendarStateOptions} from './useCalendarState';
export interface RangeCalendarStateOptions extends CalendarStateOptions<RangeValue<DateTime>> {}
export type {RangeCalendarState} from './types';
export function useRangeCalendarState(props: RangeCalendarStateOptions): RangeCalendarState {
const {value: valueProp, defaultValue = null, onUpdate, ...calendarProps} = props;
const [value, setValue] = useControlledState(valueProp, defaultValue, onUpdate);
const [anchorDate, setAnchorDateState] = React.useState<DateTime>();
const inputTimeZone = useDefaultTimeZone(
valueProp?.start || defaultValue?.start || props.focusedValue || props.defaultFocusedValue,
);
const timeZone = props.timeZone || inputTimeZone;
const calendar = useCalendarState({...calendarProps, value: null, timeZone});
const highlightedRange = anchorDate
? makeRange(anchorDate, calendar.focusedDate, calendar.mode)
: ((value &&
makeRange(
value.start.timeZone(timeZone),
value.end.timeZone(timeZone),
calendar.mode,
)) ??
undefined);
const minMode = calendar.availableModes[0];
const handleSetValue = (v: RangeValue<DateTime>) => {
let {start, end} = v;
if (value) {
start = mergeDateTime(start, value.start.timeZone(timeZone));
end = mergeDateTime(end, value.end.timeZone(timeZone));
}
setValue({start: start.timeZone(inputTimeZone), end: end.timeZone(inputTimeZone)});
};
const selectDate = (date: DateTime, force = false) => {
if (props.disabled) {
return;
}
if (!force && calendar.mode !== minMode) {
calendar.zoomIn();
return;
}
if (props.readOnly) {
return;
}
const newDate = constrainValue(date, calendar.minValue, calendar.maxValue);
if (calendar.isCellUnavailable(newDate)) {
return;
}
if (anchorDate) {
const range = makeRange(anchorDate, newDate, calendar.mode);
handleSetValue(range);
setAnchorDateState(undefined);
} else {
setAnchorDateState(newDate);
}
};
return {
...calendar,
value,
setValue: handleSetValue,
selectDate,
anchorDate,
setAnchorDate: setAnchorDateState,
highlightedRange,
isSelected(date) {
Eif (!highlightedRange) {
return false;
}
return (
(date.isSame(highlightedRange.start, this.mode) ||
date.isAfter(highlightedRange.start)) &&
(date.isSame(highlightedRange.end, this.mode) ||
date.isBefore(highlightedRange.end))
);
},
highlightDate(date) {
if (anchorDate) {
this.setFocusedDate(date);
}
},
};
}
function makeRange(start: DateTime, end: DateTime, mode: CalendarLayout): RangeValue<DateTime> {
if (start.isBefore(end)) {
return {
start,
end: end.endOf(mode),
};
}
return {
start: end,
end: start.endOf(mode),
};
}
|