-
-
Notifications
You must be signed in to change notification settings - Fork 696
/
useDayRender.tsx
129 lines (115 loc) · 3.84 KB
/
useDayRender.tsx
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
121
122
123
124
125
126
127
128
129
import React, { useEffect } from 'react';
import isSameDay from 'date-fns/isSameDay';
import { ButtonProps } from 'components/Button';
import { DayContent } from 'components/DayContent';
import { useDayPicker } from 'contexts/DayPicker';
import { useFocusContext } from 'contexts/Focus';
import { useActiveModifiers } from 'hooks/useActiveModifiers';
import {
DayEventHandlers,
useDayEventHandlers
} from 'hooks/useDayEventHandlers';
import { SelectedDays, useSelectedDays } from 'hooks/useSelectedDays';
import { ActiveModifiers } from 'types/Modifiers';
import { StyledComponent } from 'types/Styles';
import { getDayClassNames } from './utils/getDayClassNames';
import { getDayStyle } from './utils/getDayStyle';
export type DayRender = {
/** Whether the day should be rendered a `button` instead of a `div` */
isButton: boolean;
/** Whether the day should be hidden. */
isHidden: boolean;
/** The modifiers active for the given day. */
activeModifiers: ActiveModifiers;
/** The props to apply to the button element (when `isButton` is true). */
buttonProps: StyledComponent &
Pick<ButtonProps, 'disabled' | 'aria-pressed' | 'tabIndex'> &
DayEventHandlers;
/** The props to apply to the div element (when `isButton` is false). */
divProps: StyledComponent;
selectedDays: SelectedDays;
};
/**
* Return props and data used to render the {@link Day} component.
*
* Use this hook when creating a component to replace the built-in `Day`
* component.
*/
export function useDayRender(
/** The date to render. */
day: Date,
/** The month where the date is displayed (if not the same as `date`, it means it is an "outside" day). */
displayMonth: Date,
/** A ref to the button element that will be target of focus when rendered (if required). */
buttonRef: React.RefObject<HTMLButtonElement>
): DayRender {
const dayPicker = useDayPicker();
const focusContext = useFocusContext();
const activeModifiers = useActiveModifiers(day, displayMonth);
const eventHandlers = useDayEventHandlers(day, activeModifiers);
const selectedDays = useSelectedDays();
const isButton = Boolean(
dayPicker.onDayClick || dayPicker.mode !== 'default'
);
// Focus the button if the day is focused according to the focus context
useEffect(() => {
if (activeModifiers.outside) return;
if (!focusContext.focusedDay) return;
if (!isButton) return;
if (isSameDay(focusContext.focusedDay, day)) {
buttonRef.current?.focus();
}
}, [
focusContext.focusedDay,
day,
buttonRef,
isButton,
activeModifiers.outside
]);
const className = getDayClassNames(dayPicker, activeModifiers).join(' ');
const style = getDayStyle(dayPicker, activeModifiers);
const ariaLabel = dayPicker.labels.labelDay(day, activeModifiers, {
locale: dayPicker.locale
});
const isHidden = Boolean(
(activeModifiers.outside && !dayPicker.showOutsideDays) ||
activeModifiers.hidden
);
const DayContentComponent = dayPicker.components?.DayContent ?? DayContent;
const children = (
<DayContentComponent
date={day}
displayMonth={displayMonth}
activeModifiers={activeModifiers}
/>
);
const divProps = {
style,
className,
children,
'aria-label': ariaLabel
};
const isFocusTarget =
focusContext.focusTarget &&
isSameDay(focusContext.focusTarget, day) &&
!activeModifiers.outside;
const isFocused =
focusContext.focusedDay && isSameDay(focusContext.focusedDay, day);
const buttonProps = {
...divProps,
disabled: activeModifiers.disabled,
['aria-pressed']: activeModifiers.selected,
['aria-label']: ariaLabel,
tabIndex: isFocused || isFocusTarget ? 0 : -1,
...eventHandlers
};
const dayRender: DayRender = {
isButton,
isHidden,
activeModifiers: activeModifiers,
selectedDays,
buttonProps,
divProps
};
return dayRender;
}