Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ts-strict calender fix types #6201

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/@react-stately/calendar/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export interface RangeCalendarState extends CalendarStateBase {
/** Sets the anchor date that the user clicked on to begin range selection. */
setAnchorDate(date: CalendarDate | null): void,
/** The currently highlighted date range. */
readonly highlightedRange: RangeValue<CalendarDate>,
readonly highlightedRange: RangeValue<CalendarDate> | null,
/** Whether the user is currently dragging over the calendar. */
readonly isDragging: boolean,
/** Sets whether the user is dragging over the calendar. */
Expand Down
55 changes: 31 additions & 24 deletions packages/@react-stately/calendar/src/useRangeCalendarState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import {alignCenter, constrainValue, isInvalid, previousAvailableDate} from './utils';
import {Calendar, CalendarDate, DateDuration, GregorianCalendar, isEqualDay, maxDate, minDate, toCalendar, toCalendarDate} from '@internationalized/date';
import {CalendarState, RangeCalendarState} from './types';
import {DateRange, DateValue, RangeCalendarProps} from '@react-types/calendar';
import {DateValue, RangeCalendarProps} from '@react-types/calendar';
import {RangeValue, ValidationState} from '@react-types/shared';
import {useCalendarState} from './useCalendarState';
import {useControlledState} from '@react-stately/utils';
Expand Down Expand Up @@ -42,13 +42,13 @@ export interface RangeCalendarStateOptions<T extends DateValue = DateValue> exte
*/
export function useRangeCalendarState<T extends DateValue = DateValue>(props: RangeCalendarStateOptions<T>): RangeCalendarState {
let {value: valueProp, defaultValue, onChange, createCalendar, locale, visibleDuration = {months: 1}, minValue, maxValue, ...calendarProps} = props;
let [value, setValue] = useControlledState<DateRange>(
valueProp,
defaultValue || null,
let [value, setValue] = useControlledState<RangeValue<T>>(
valueProp!,
defaultValue || undefined,
onChange
);

let [anchorDate, setAnchorDateState] = useState(null);
let [anchorDate, setAnchorDateState] = useState<CalendarDate|null>(null);
let alignment: 'center' | 'start' = 'center';
if (value && value.start && value.end) {
let start = alignCenter(toCalendarDate(value.start), visibleDuration, locale, minValue, maxValue);
Expand All @@ -60,8 +60,8 @@ export function useRangeCalendarState<T extends DateValue = DateValue>(props: Ra
}

// Available range must be stored in a ref so we have access to the updated version immediately in `isInvalid`.
let availableRangeRef = useRef<RangeValue<DateValue>>(null);
let [availableRange, setAvailableRange] = useState<RangeValue<DateValue>>(null);
let availableRangeRef = useRef<RangeValue<DateValue>|null>(null);
let [availableRange, setAvailableRange] = useState<RangeValue<DateValue>|null>(null);
let min = useMemo(() => maxDate(minValue, availableRange?.start), [minValue, availableRange]);
let max = useMemo(() => minDate(maxValue, availableRange?.end), [maxValue, availableRange]);

Expand All @@ -78,10 +78,14 @@ export function useRangeCalendarState<T extends DateValue = DateValue>(props: Ra

let updateAvailableRange = (date) => {
if (date && props.isDateUnavailable && !props.allowsNonContiguousRanges) {
availableRangeRef.current = {
start: nextUnavailableDate(date, calendar, -1),
end: nextUnavailableDate(date, calendar, 1)
};
const nextAvailableStartDate = nextUnavailableDate(date, calendar, -1);
const nextAvailableEndDate = nextUnavailableDate(date, calendar, -1);
if (nextAvailableStartDate && nextAvailableEndDate) {
availableRangeRef.current = {
start: nextAvailableStartDate,
end: nextAvailableEndDate
};
}
setAvailableRange(availableRangeRef.current);
} else {
availableRangeRef.current = null;
Expand All @@ -96,7 +100,7 @@ export function useRangeCalendarState<T extends DateValue = DateValue>(props: Ra
setLastVisibleRange(calendar.visibleRange);
}

let setAnchorDate = (date: CalendarDate) => {
let setAnchorDate = (date: CalendarDate|null) => {
if (date) {
setAnchorDateState(date);
updateAvailableRange(date);
Expand All @@ -108,24 +112,27 @@ export function useRangeCalendarState<T extends DateValue = DateValue>(props: Ra

let highlightedRange = anchorDate ? makeRange(anchorDate, calendar.focusedDate) : value && makeRange(value.start, value.end);
let selectDate = (date: CalendarDate) => {

if (props.isReadOnly) {
return;
}

date = constrainValue(date, min, max);
date = previousAvailableDate(date, calendar.visibleRange.start, props.isDateUnavailable);
if (!date) {
const constrainedDate = constrainValue(date, min, max);
const previousAvailableConstrainedDate = previousAvailableDate(constrainedDate, calendar.visibleRange.start, props.isDateUnavailable);
if (!previousAvailableConstrainedDate) {
return;
}

if (!anchorDate) {
setAnchorDate(date);
setAnchorDate(previousAvailableConstrainedDate);
} else {
let range = makeRange(anchorDate, date);
setValue({
start: convertValue(range.start, value?.start),
end: convertValue(range.end, value?.end)
});
let range = makeRange(anchorDate, previousAvailableConstrainedDate);
if (range) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks icky

setValue({
start: convertValue(range.start, value?.start) as T,
end: convertValue(range.end, value?.end) as T
});
}
setAnchorDate(null);
}
};
Expand Down Expand Up @@ -167,7 +174,7 @@ export function useRangeCalendarState<T extends DateValue = DateValue>(props: Ra
}
},
isSelected(date) {
return highlightedRange && date.compare(highlightedRange.start) >= 0 && date.compare(highlightedRange.end) <= 0 && !calendar.isCellDisabled(date) && !calendar.isCellUnavailable(date);
return Boolean(highlightedRange && date.compare(highlightedRange.start) >= 0 && date.compare(highlightedRange.end) <= 0 && !calendar.isCellDisabled(date) && !calendar.isCellUnavailable(date));
},
isInvalid(date) {
return calendar.isInvalid(date) || isInvalid(date, availableRangeRef.current?.start, availableRangeRef.current?.end);
Expand All @@ -177,7 +184,7 @@ export function useRangeCalendarState<T extends DateValue = DateValue>(props: Ra
};
}

function makeRange(start: DateValue, end: DateValue): RangeValue<CalendarDate> {
function makeRange(start: DateValue, end: DateValue): RangeValue<CalendarDate>|null {
if (!start || !end) {
return null;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO null should not be used in most cases, since '?' operator of ts does not recognise it

}
Expand All @@ -189,7 +196,7 @@ function makeRange(start: DateValue, end: DateValue): RangeValue<CalendarDate> {
return {start: toCalendarDate(start), end: toCalendarDate(end)};
}

function convertValue(newValue: CalendarDate, oldValue: DateValue) {
function convertValue(newValue: CalendarDate, oldValue: DateValue) :DateValue {
// The display calendar should not have any effect on the emitted value.
// Emit dates in the same calendar as the original value, if any, otherwise gregorian.
newValue = toCalendar(newValue, oldValue?.calendar || new GregorianCalendar());
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-types/calendar/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export interface CalendarPropsBase {

export type DateRange = RangeValue<DateValue> | null;
export interface CalendarProps<T extends DateValue | null> extends CalendarPropsBase, ValueBase<T | null, MappedDateValue<T>> {}
export interface RangeCalendarProps<T extends DateValue | null> extends CalendarPropsBase, ValueBase<RangeValue<T> | null, RangeValue<MappedDateValue<T>>> {
export interface RangeCalendarProps<T extends DateValue | null> extends CalendarPropsBase, ValueBase<RangeValue<T>> {
/**
* When combined with `isDateUnavailable`, determines whether non-contiguous ranges,
* i.e. ranges containing unavailable dates, may be selected.
Expand Down