cpk-ui 0.7.0 → 0.8.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -14
- package/components/modals/AlertDialog/AlertDialog.d.ts +11 -5
- package/components/modals/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/components/modals/AlertDialog/AlertDialog.js +46 -36
- package/components/uis/Button/Button.d.ts.map +1 -1
- package/components/uis/Button/Button.js +16 -13
- package/components/uis/Calendar/Calendar.d.ts +6 -0
- package/components/uis/Calendar/Calendar.d.ts.map +1 -0
- package/components/uis/Calendar/Calendar.js +482 -0
- package/components/uis/Calendar/CalendarDay.d.ts +21 -0
- package/components/uis/Calendar/CalendarDay.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarDay.js +172 -0
- package/components/uis/Calendar/CalendarHeader.d.ts +22 -0
- package/components/uis/Calendar/CalendarHeader.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarHeader.js +40 -0
- package/components/uis/Calendar/CalendarPage.d.ts +46 -0
- package/components/uis/Calendar/CalendarPage.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarPage.js +34 -0
- package/components/uis/Calendar/CalendarPager.d.ts +11 -0
- package/components/uis/Calendar/CalendarPager.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarPager.js +115 -0
- package/components/uis/Calendar/CalendarPager.web.d.ts +11 -0
- package/components/uis/Calendar/CalendarPager.web.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarPager.web.js +72 -0
- package/components/uis/Calendar/CalendarWeekRow.d.ts +20 -0
- package/components/uis/Calendar/CalendarWeekRow.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarWeekRow.js +64 -0
- package/components/uis/Calendar/CalendarWeekdayRow.d.ts +24 -0
- package/components/uis/Calendar/CalendarWeekdayRow.d.ts.map +1 -0
- package/components/uis/Calendar/CalendarWeekdayRow.js +45 -0
- package/components/uis/Calendar/intl.d.ts +18 -0
- package/components/uis/Calendar/intl.d.ts.map +1 -0
- package/components/uis/Calendar/intl.js +146 -0
- package/components/uis/Calendar/palette.d.ts +10 -0
- package/components/uis/Calendar/palette.d.ts.map +1 -0
- package/components/uis/Calendar/palette.js +93 -0
- package/components/uis/Calendar/types.d.ts +286 -0
- package/components/uis/Calendar/types.d.ts.map +1 -0
- package/components/uis/Calendar/types.js +1 -0
- package/components/uis/Calendar/useCalendarState.d.ts +66 -0
- package/components/uis/Calendar/useCalendarState.d.ts.map +1 -0
- package/components/uis/Calendar/useCalendarState.js +211 -0
- package/components/uis/Calendar/utils.d.ts +114 -0
- package/components/uis/Calendar/utils.d.ts.map +1 -0
- package/components/uis/Calendar/utils.js +429 -0
- package/components/uis/ParallaxHeader/ParallaxHeader.d.ts +44 -0
- package/components/uis/ParallaxHeader/ParallaxHeader.d.ts.map +1 -0
- package/components/uis/ParallaxHeader/ParallaxHeader.js +142 -0
- package/index.d.ts +2 -0
- package/index.d.ts.map +1 -1
- package/index.js +2 -0
- package/package.json +2 -1
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
|
|
3
|
+
import { AccessibilityInfo, I18nManager, useWindowDimensions, View, } from 'react-native';
|
|
4
|
+
import { css } from 'kstyled';
|
|
5
|
+
import { useAnimatedReaction, useSharedValue, withTiming, runOnJS, } from 'react-native-reanimated';
|
|
6
|
+
import { useTheme } from '../../../providers/ThemeProvider';
|
|
7
|
+
import { CalendarHeader } from './CalendarHeader';
|
|
8
|
+
import { CalendarPage } from './CalendarPage';
|
|
9
|
+
import { CalendarPager } from './CalendarPager';
|
|
10
|
+
import { CalendarWeekdayRow } from './CalendarWeekdayRow';
|
|
11
|
+
import { DEFAULT_FORMATTERS, getFormattersId, resolveLocale } from './intl';
|
|
12
|
+
import { isSamePalette, resolveCalendarPalette } from './palette';
|
|
13
|
+
import { resolveKeyboardAction, useControllable, useDisabledState, useReduceMotion, useShallowStable, useToday, } from './useCalendarState';
|
|
14
|
+
import { addDays, addPages, getCalendarGrid, localNoon, normalizePageKey, pageFirstDate, pageLastDate, resolveMetrics, resolveWeekStart, startOfWeek, toDateKeyInput, toDayKey, } from './utils';
|
|
15
|
+
const CONTAINER = css `
|
|
16
|
+
align-self: center;
|
|
17
|
+
width: 100%;
|
|
18
|
+
`;
|
|
19
|
+
const TWO_UP_ROW = css `
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
align-items: flex-start;
|
|
22
|
+
gap: 24px;
|
|
23
|
+
`;
|
|
24
|
+
const COLUMN = css `
|
|
25
|
+
flex: 1;
|
|
26
|
+
`;
|
|
27
|
+
const EMPTY_MARKERS = Object.freeze({});
|
|
28
|
+
const EMPTY_STYLES = Object.freeze({});
|
|
29
|
+
const DEFAULT_LABELS = Object.freeze({
|
|
30
|
+
previousMonth: 'Previous month',
|
|
31
|
+
nextMonth: 'Next month',
|
|
32
|
+
previousWeek: 'Previous week',
|
|
33
|
+
nextWeek: 'Next week',
|
|
34
|
+
today: 'Today',
|
|
35
|
+
selected: 'Selected',
|
|
36
|
+
weekNumber: 'Week',
|
|
37
|
+
pageAnnouncement: (pageTitle) => pageTitle,
|
|
38
|
+
});
|
|
39
|
+
/** A Sunday, used only to derive weekday header labels. Never rendered. */
|
|
40
|
+
const WEEKDAY_LABEL_ANCHOR = localNoon(2024, 0, 7);
|
|
41
|
+
const COLLAPSE_DURATION = 220;
|
|
42
|
+
const BADGE_FONT_SCALE_LIMIT = 1.3;
|
|
43
|
+
const SINGLE_DOT_FONT_SCALE_LIMIT = 1.5;
|
|
44
|
+
/**
|
|
45
|
+
* `onKeyDown` is forwarded by react-native-web and simply never fires on native,
|
|
46
|
+
* so one handler covers both platforms without a `.web.tsx` split.
|
|
47
|
+
*/
|
|
48
|
+
const KeyboardView = View;
|
|
49
|
+
function buildGeometry(metrics) {
|
|
50
|
+
return Object.freeze({
|
|
51
|
+
row: { height: metrics.rowHeight },
|
|
52
|
+
cell: { height: metrics.rowHeight, paddingTop: metrics.pillOffset },
|
|
53
|
+
pill: {
|
|
54
|
+
width: metrics.numberSize,
|
|
55
|
+
height: metrics.numberSize,
|
|
56
|
+
borderRadius: metrics.numberSize / 2,
|
|
57
|
+
},
|
|
58
|
+
dayText: { fontSize: metrics.dayFontSize },
|
|
59
|
+
badgeText: { fontSize: metrics.badgeFontSize },
|
|
60
|
+
dot: {
|
|
61
|
+
width: metrics.dotSize,
|
|
62
|
+
height: metrics.dotSize,
|
|
63
|
+
borderRadius: metrics.dotSize / 2,
|
|
64
|
+
},
|
|
65
|
+
dotRow: { height: metrics.dotRowHeight },
|
|
66
|
+
weekNumber: { width: metrics.weekNumberWidth },
|
|
67
|
+
weekNumberText: { fontSize: metrics.weekdayFontSize },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function CalendarContainer(props, ref) {
|
|
71
|
+
const { value, defaultValue, onChange, month, defaultMonth, onMonthChange, mode: modeProp, defaultMode, onModeChange, collapseProgress, locale: localeProp, weekStart: weekStartProp, today: todayProp, fixedWeeks = true, markers = EMPTY_MARKERS, showDots = true, maxDotsPerDay = 3, showWeekNumbers = false, showOutsideDays = true, minDate, maxDate, disabledDates, isDateDisabled, showHeader = true, showNavigationButtons = true, showWeekdayRow = true, paging = 'swipe', monthsToShow = 1, size, maxFontSizeMultiplier = 1.6, colors, styles: stylesProp = EMPTY_STYLES, style, formatters: formattersProp, renderHeader, renderWeekdayLabel, renderDay, onDayLongPress, onDisabledDayPress, labels: labelsPropInput, accessibilityLabel, testID = 'calendar', } = props;
|
|
72
|
+
const { theme, media } = useTheme();
|
|
73
|
+
const { fontScale } = useWindowDimensions();
|
|
74
|
+
const reduceMotion = useReduceMotion();
|
|
75
|
+
const locale = useMemo(() => localeProp ?? resolveLocale(), [localeProp]);
|
|
76
|
+
const weekStart = useMemo(() => weekStartProp ?? resolveWeekStart(locale), [locale, weekStartProp]);
|
|
77
|
+
const todayNoon = useToday(todayProp);
|
|
78
|
+
const todayKey = useMemo(() => toDayKey(todayNoon), [todayNoon]);
|
|
79
|
+
// Value comparison, not identity, for the three props callers almost always
|
|
80
|
+
// write as inline object literals. Without it `chrome` is rebuilt on every
|
|
81
|
+
// parent render and all 42 day cells re-render — the exact regression the
|
|
82
|
+
// memo test suite pins for `colors` but never checked for these.
|
|
83
|
+
const labelsProp = useShallowStable(labelsPropInput);
|
|
84
|
+
const styles = useShallowStable(stylesProp);
|
|
85
|
+
const formattersInput = useShallowStable(formattersProp);
|
|
86
|
+
const formatters = useMemo(() => formattersInput
|
|
87
|
+
? Object.freeze({ ...DEFAULT_FORMATTERS, ...formattersInput })
|
|
88
|
+
: DEFAULT_FORMATTERS, [formattersInput]);
|
|
89
|
+
const formattersId = getFormattersId(formatters);
|
|
90
|
+
const [mode, setModeState] = useControllable(modeProp, defaultMode ?? 'month');
|
|
91
|
+
// ── selection ───────────────────────────────────────────────────────────────
|
|
92
|
+
const isValueControlled = value !== undefined;
|
|
93
|
+
const [selectedKeyState, setSelectedKeyState] = useState(() => defaultValue == null ? null : toDateKeyInput(defaultValue));
|
|
94
|
+
const selectedKey = isValueControlled
|
|
95
|
+
? value === null
|
|
96
|
+
? null
|
|
97
|
+
: toDateKeyInput(value)
|
|
98
|
+
: selectedKeyState;
|
|
99
|
+
// ── paging ──────────────────────────────────────────────────────────────────
|
|
100
|
+
const isMonthControlled = month !== undefined;
|
|
101
|
+
const [pageKeyState, setPageKeyState] = useState(() => normalizePageKey(defaultMonth ?? selectedKeyState ?? todayNoon, defaultMode ?? 'month', weekStartProp ?? resolveWeekStart(localeProp ?? resolveLocale()), monthsToShow));
|
|
102
|
+
const pageInput = month === undefined
|
|
103
|
+
? pageKeyState
|
|
104
|
+
: typeof month === 'string'
|
|
105
|
+
? month
|
|
106
|
+
: toDayKey(month);
|
|
107
|
+
const pageKey = useMemo(() => normalizePageKey(pageInput, mode, weekStart, monthsToShow), [mode, monthsToShow, pageInput, weekStart]);
|
|
108
|
+
const [focusedKey, setFocusedKey] = useState(null);
|
|
109
|
+
// ── grids ───────────────────────────────────────────────────────────────────
|
|
110
|
+
const gridFor = useCallback((key) => getCalendarGrid({
|
|
111
|
+
pageKey: key,
|
|
112
|
+
mode,
|
|
113
|
+
weekStart,
|
|
114
|
+
fixedWeeks,
|
|
115
|
+
showWeekNumbers,
|
|
116
|
+
locale,
|
|
117
|
+
formatters,
|
|
118
|
+
formattersId,
|
|
119
|
+
}), [
|
|
120
|
+
fixedWeeks,
|
|
121
|
+
formatters,
|
|
122
|
+
formattersId,
|
|
123
|
+
locale,
|
|
124
|
+
mode,
|
|
125
|
+
showWeekNumbers,
|
|
126
|
+
weekStart,
|
|
127
|
+
]);
|
|
128
|
+
const previousPageKey = useMemo(() => addPages(pageKey, -1, mode, weekStart, monthsToShow), [mode, monthsToShow, pageKey, weekStart]);
|
|
129
|
+
const nextPageKey = useMemo(() => addPages(pageKey, 1, mode, weekStart, monthsToShow), [mode, monthsToShow, pageKey, weekStart]);
|
|
130
|
+
const currentGrid = useMemo(() => gridFor(pageKey), [gridFor, pageKey]);
|
|
131
|
+
// ── theming and geometry ────────────────────────────────────────────────────
|
|
132
|
+
// Value comparison, not identity: `theme` and an inline `colors` object are both
|
|
133
|
+
// rebuilt on every parent render, and a new palette would re-render every cell.
|
|
134
|
+
const paletteRef = useRef(null);
|
|
135
|
+
const palette = useMemo(() => {
|
|
136
|
+
const next = resolveCalendarPalette(theme, colors);
|
|
137
|
+
const previous = paletteRef.current;
|
|
138
|
+
if (previous && isSamePalette(previous, next)) {
|
|
139
|
+
return previous;
|
|
140
|
+
}
|
|
141
|
+
paletteRef.current = next;
|
|
142
|
+
return next;
|
|
143
|
+
}, [colors, theme]);
|
|
144
|
+
const resolvedSize = size ?? (media.isDesktop || media.isTablet ? 'expanded' : 'regular');
|
|
145
|
+
const metrics = useMemo(() => resolveMetrics(resolvedSize, fontScale, maxFontSizeMultiplier), [fontScale, maxFontSizeMultiplier, resolvedSize]);
|
|
146
|
+
const geometry = useMemo(() => buildGeometry(metrics), [metrics]);
|
|
147
|
+
const labels = useMemo(() => labelsProp
|
|
148
|
+
? Object.freeze({ ...DEFAULT_LABELS, ...labelsProp })
|
|
149
|
+
: DEFAULT_LABELS, [labelsProp]);
|
|
150
|
+
// ── constraints ─────────────────────────────────────────────────────────────
|
|
151
|
+
const { resolver: isDisabled, version: disabledVersion, minKey, maxKey, } = useDisabledState({ minDate, maxDate, disabledDates, isDateDisabled });
|
|
152
|
+
// ── latest-value refs, so no handler identity depends on a changing callback ─
|
|
153
|
+
const callbacksRef = useRef({
|
|
154
|
+
onChange,
|
|
155
|
+
onMonthChange,
|
|
156
|
+
onModeChange,
|
|
157
|
+
onDayLongPress,
|
|
158
|
+
onDisabledDayPress,
|
|
159
|
+
});
|
|
160
|
+
const stateRef = useRef({
|
|
161
|
+
pageKey,
|
|
162
|
+
mode,
|
|
163
|
+
weekStart,
|
|
164
|
+
monthsToShow,
|
|
165
|
+
isMonthControlled,
|
|
166
|
+
isValueControlled,
|
|
167
|
+
isModeControlled: modeProp !== undefined,
|
|
168
|
+
});
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
callbacksRef.current = {
|
|
171
|
+
onChange,
|
|
172
|
+
onMonthChange,
|
|
173
|
+
onModeChange,
|
|
174
|
+
onDayLongPress,
|
|
175
|
+
onDisabledDayPress,
|
|
176
|
+
};
|
|
177
|
+
}, [
|
|
178
|
+
onChange,
|
|
179
|
+
onDayLongPress,
|
|
180
|
+
onDisabledDayPress,
|
|
181
|
+
onModeChange,
|
|
182
|
+
onMonthChange,
|
|
183
|
+
]);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
stateRef.current = {
|
|
186
|
+
pageKey,
|
|
187
|
+
mode,
|
|
188
|
+
weekStart,
|
|
189
|
+
monthsToShow,
|
|
190
|
+
isMonthControlled,
|
|
191
|
+
isValueControlled,
|
|
192
|
+
isModeControlled: modeProp !== undefined,
|
|
193
|
+
};
|
|
194
|
+
}, [
|
|
195
|
+
isMonthControlled,
|
|
196
|
+
isValueControlled,
|
|
197
|
+
mode,
|
|
198
|
+
modeProp,
|
|
199
|
+
monthsToShow,
|
|
200
|
+
pageKey,
|
|
201
|
+
weekStart,
|
|
202
|
+
]);
|
|
203
|
+
const goToPage = useCallback((nextKey, source) => {
|
|
204
|
+
const current = stateRef.current;
|
|
205
|
+
if (!current.isMonthControlled) {
|
|
206
|
+
setPageKeyState(nextKey);
|
|
207
|
+
}
|
|
208
|
+
const first = pageFirstDate(nextKey, current.mode, current.weekStart);
|
|
209
|
+
callbacksRef.current.onMonthChange?.(new Date(first.getFullYear(), first.getMonth(), first.getDate()), nextKey, source);
|
|
210
|
+
}, []);
|
|
211
|
+
const stepPage = useCallback((delta, source) => {
|
|
212
|
+
const current = stateRef.current;
|
|
213
|
+
goToPage(addPages(current.pageKey, delta, current.mode, current.weekStart, current.monthsToShow), source);
|
|
214
|
+
}, [goToPage]);
|
|
215
|
+
const handleSwipeCommit = useCallback((delta) => stepPage(delta, 'swipe'), [stepPage]);
|
|
216
|
+
const focusKey = useCallback((key, source) => {
|
|
217
|
+
setFocusedKey(key);
|
|
218
|
+
const current = stateRef.current;
|
|
219
|
+
const targetPage = normalizePageKey(key, current.mode, current.weekStart, current.monthsToShow);
|
|
220
|
+
if (targetPage !== current.pageKey) {
|
|
221
|
+
goToPage(targetPage, source);
|
|
222
|
+
}
|
|
223
|
+
}, [goToPage]);
|
|
224
|
+
const selectKey = useCallback((key, source) => {
|
|
225
|
+
const current = stateRef.current;
|
|
226
|
+
if (!current.isValueControlled) {
|
|
227
|
+
setSelectedKeyState(key);
|
|
228
|
+
}
|
|
229
|
+
setFocusedKey(key);
|
|
230
|
+
const date = new Date(+key.slice(0, 4), +key.slice(5, 7) - 1, +key.slice(8, 10));
|
|
231
|
+
callbacksRef.current.onChange?.(date, key, source);
|
|
232
|
+
}, []);
|
|
233
|
+
// ── stable cell callbacks. No inline arrow ever reaches a day cell ───────────
|
|
234
|
+
const handleDayPress = useCallback((key) => selectKey(key, 'press'), [selectKey]);
|
|
235
|
+
const handleDayLongPress = useCallback((key) => {
|
|
236
|
+
callbacksRef.current.onDayLongPress?.(new Date(+key.slice(0, 4), +key.slice(5, 7) - 1, +key.slice(8, 10)), key);
|
|
237
|
+
}, []);
|
|
238
|
+
const handleDisabledDayPress = useCallback((key) => {
|
|
239
|
+
callbacksRef.current.onDisabledDayPress?.(new Date(+key.slice(0, 4), +key.slice(5, 7) - 1, +key.slice(8, 10)), key);
|
|
240
|
+
}, []);
|
|
241
|
+
const chrome = useMemo(() => Object.freeze({
|
|
242
|
+
palette,
|
|
243
|
+
metrics,
|
|
244
|
+
geometry,
|
|
245
|
+
showDots,
|
|
246
|
+
maxDots: fontScale > SINGLE_DOT_FONT_SCALE_LIMIT
|
|
247
|
+
? 1
|
|
248
|
+
: Math.max(maxDotsPerDay, 0),
|
|
249
|
+
showBadges: fontScale <= BADGE_FONT_SCALE_LIMIT,
|
|
250
|
+
maxFontSizeMultiplier,
|
|
251
|
+
fontScale,
|
|
252
|
+
labels,
|
|
253
|
+
styles,
|
|
254
|
+
renderDay,
|
|
255
|
+
onPress: handleDayPress,
|
|
256
|
+
onLongPress: onDayLongPress ? handleDayLongPress : undefined,
|
|
257
|
+
onDisabledPress: onDisabledDayPress
|
|
258
|
+
? handleDisabledDayPress
|
|
259
|
+
: undefined,
|
|
260
|
+
}), [
|
|
261
|
+
fontScale,
|
|
262
|
+
geometry,
|
|
263
|
+
handleDayLongPress,
|
|
264
|
+
handleDayPress,
|
|
265
|
+
handleDisabledDayPress,
|
|
266
|
+
labels,
|
|
267
|
+
maxDotsPerDay,
|
|
268
|
+
maxFontSizeMultiplier,
|
|
269
|
+
metrics,
|
|
270
|
+
onDayLongPress,
|
|
271
|
+
onDisabledDayPress,
|
|
272
|
+
palette,
|
|
273
|
+
renderDay,
|
|
274
|
+
showDots,
|
|
275
|
+
styles,
|
|
276
|
+
]);
|
|
277
|
+
// ── collapse ────────────────────────────────────────────────────────────────
|
|
278
|
+
const internalCollapse = useSharedValue(mode === 'week' ? 1 : 0);
|
|
279
|
+
const collapse = collapseProgress ?? internalCollapse;
|
|
280
|
+
const activeRow = useSharedValue(0);
|
|
281
|
+
const anchorKey = selectedKey &&
|
|
282
|
+
selectedKey >= currentGrid.firstKey &&
|
|
283
|
+
selectedKey <= currentGrid.lastKey
|
|
284
|
+
? selectedKey
|
|
285
|
+
: todayKey >= currentGrid.firstKey && todayKey <= currentGrid.lastKey
|
|
286
|
+
? todayKey
|
|
287
|
+
: currentGrid.firstKey;
|
|
288
|
+
const activeRowIndex = useMemo(() => {
|
|
289
|
+
for (let i = 0; i < currentGrid.days.length; i++) {
|
|
290
|
+
if (currentGrid.days[i].key === anchorKey) {
|
|
291
|
+
return (i / 7) | 0;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return 0;
|
|
295
|
+
}, [anchorKey, currentGrid]);
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
activeRow.value = mode === 'week' ? 0 : activeRowIndex;
|
|
298
|
+
}, [activeRow, activeRowIndex, mode]);
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
if (collapseProgress) {
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
internalCollapse.value = withTiming(mode === 'week' ? 1 : 0, {
|
|
304
|
+
duration: reduceMotion ? 0 : COLLAPSE_DURATION,
|
|
305
|
+
});
|
|
306
|
+
}, [collapseProgress, internalCollapse, mode, reduceMotion]);
|
|
307
|
+
const commitMode = useCallback((nextMode) => {
|
|
308
|
+
if (stateRef.current.mode === nextMode) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
setModeState(nextMode);
|
|
312
|
+
callbacksRef.current.onModeChange?.(nextMode);
|
|
313
|
+
}, [setModeState]);
|
|
314
|
+
useAnimatedReaction(() => collapse.value, (progress, previous) => {
|
|
315
|
+
if (previous === null) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (progress >= 0.999 && previous < 0.999) {
|
|
319
|
+
runOnJS(commitMode)('week');
|
|
320
|
+
}
|
|
321
|
+
else if (progress <= 0.001 && previous > 0.001) {
|
|
322
|
+
runOnJS(commitMode)('month');
|
|
323
|
+
}
|
|
324
|
+
}, [collapse, commitMode]);
|
|
325
|
+
// ── derived chrome values ───────────────────────────────────────────────────
|
|
326
|
+
const weekdayLabels = useMemo(() => {
|
|
327
|
+
const anchor = startOfWeek(WEEKDAY_LABEL_ANCHOR, weekStart);
|
|
328
|
+
return Object.freeze(Array.from({ length: 7 }, (_, index) => formatters.weekdayLabel(addDays(anchor, index), locale)));
|
|
329
|
+
}, [formatters, locale, weekStart]);
|
|
330
|
+
const headerDate = useMemo(() => pageFirstDate(pageKey, mode, weekStart), [mode, pageKey, weekStart]);
|
|
331
|
+
const title = useMemo(() => {
|
|
332
|
+
if (mode === 'week') {
|
|
333
|
+
return formatters.weekTitle(headerDate, addDays(headerDate, 6), locale);
|
|
334
|
+
}
|
|
335
|
+
if (monthsToShow > 1) {
|
|
336
|
+
const secondMonth = pageFirstDate(nextPageKey, mode, weekStart);
|
|
337
|
+
return `${formatters.monthTitle(headerDate, locale)} – ${formatters.monthTitle(addDays(secondMonth, -1), locale)}`;
|
|
338
|
+
}
|
|
339
|
+
return formatters.monthTitle(headerDate, locale);
|
|
340
|
+
}, [
|
|
341
|
+
formatters,
|
|
342
|
+
headerDate,
|
|
343
|
+
locale,
|
|
344
|
+
mode,
|
|
345
|
+
monthsToShow,
|
|
346
|
+
nextPageKey,
|
|
347
|
+
weekStart,
|
|
348
|
+
]);
|
|
349
|
+
// Compared against each neighbouring page's own month/week range, not against the
|
|
350
|
+
// padded grid, so a min date on the 1st really does disable the previous button.
|
|
351
|
+
const canGoPrevious = minKey === null ||
|
|
352
|
+
toDayKey(pageLastDate(previousPageKey, mode, weekStart, monthsToShow)) >=
|
|
353
|
+
minKey;
|
|
354
|
+
const canGoNext = maxKey === null ||
|
|
355
|
+
toDayKey(pageFirstDate(nextPageKey, mode, weekStart)) <= maxKey;
|
|
356
|
+
const goPrevious = useCallback(() => stepPage(-1, 'button'), [stepPage]);
|
|
357
|
+
const goNext = useCallback(() => stepPage(1, 'button'), [stepPage]);
|
|
358
|
+
const headerContext = useMemo(() => ({
|
|
359
|
+
title,
|
|
360
|
+
date: headerDate,
|
|
361
|
+
mode,
|
|
362
|
+
canGoPrevious,
|
|
363
|
+
canGoNext,
|
|
364
|
+
goPrevious,
|
|
365
|
+
goNext,
|
|
366
|
+
}), [canGoNext, canGoPrevious, goNext, goPrevious, headerDate, mode, title]);
|
|
367
|
+
const announcedTitle = useRef(null);
|
|
368
|
+
useEffect(() => {
|
|
369
|
+
if (announcedTitle.current === null) {
|
|
370
|
+
announcedTitle.current = title;
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (announcedTitle.current === title) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
announcedTitle.current = title;
|
|
377
|
+
AccessibilityInfo.announceForAccessibility(labels.pageAnnouncement(title));
|
|
378
|
+
}, [labels, title]);
|
|
379
|
+
// ── roving focus target ─────────────────────────────────────────────────────
|
|
380
|
+
const tabbableKey = useMemo(() => {
|
|
381
|
+
const inPage = (key) => key >= currentGrid.firstKey && key <= currentGrid.lastKey;
|
|
382
|
+
if (focusedKey !== null && inPage(focusedKey)) {
|
|
383
|
+
return focusedKey;
|
|
384
|
+
}
|
|
385
|
+
if (selectedKey !== null && inPage(selectedKey)) {
|
|
386
|
+
return selectedKey;
|
|
387
|
+
}
|
|
388
|
+
if (inPage(todayKey)) {
|
|
389
|
+
return todayKey;
|
|
390
|
+
}
|
|
391
|
+
for (const day of currentGrid.days) {
|
|
392
|
+
if (!day.isOutside) {
|
|
393
|
+
return day.key;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return currentGrid.firstKey;
|
|
397
|
+
}, [currentGrid, focusedKey, selectedKey, todayKey]);
|
|
398
|
+
const handleKeyDown = useCallback((event) => {
|
|
399
|
+
const action = resolveKeyboardAction({
|
|
400
|
+
key: event.key,
|
|
401
|
+
shiftKey: event.shiftKey === true,
|
|
402
|
+
focusedKey: tabbableKey,
|
|
403
|
+
weekStart: stateRef.current.weekStart,
|
|
404
|
+
isRTL: I18nManager.isRTL,
|
|
405
|
+
mode: stateRef.current.mode,
|
|
406
|
+
});
|
|
407
|
+
if (!action) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
event.preventDefault?.();
|
|
411
|
+
if (action.type === 'select') {
|
|
412
|
+
selectKey(tabbableKey, 'keyboard');
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
focusKey(action.key, 'keyboard');
|
|
416
|
+
}, [focusKey, selectKey, tabbableKey]);
|
|
417
|
+
// ── imperative API ──────────────────────────────────────────────────────────
|
|
418
|
+
useImperativeHandle(ref, () => ({
|
|
419
|
+
goToMonth: (target) => {
|
|
420
|
+
const current = stateRef.current;
|
|
421
|
+
goToPage(normalizePageKey(target, current.mode, current.weekStart, current.monthsToShow), 'imperative');
|
|
422
|
+
},
|
|
423
|
+
goToToday: () => {
|
|
424
|
+
const current = stateRef.current;
|
|
425
|
+
goToPage(normalizePageKey(todayKey, current.mode, current.weekStart, current.monthsToShow), 'imperative');
|
|
426
|
+
},
|
|
427
|
+
next: () => stepPage(1, 'imperative'),
|
|
428
|
+
previous: () => stepPage(-1, 'imperative'),
|
|
429
|
+
setMode: (nextMode) => commitMode(nextMode),
|
|
430
|
+
focusDay: (key) => focusKey(key, 'imperative'),
|
|
431
|
+
}), [commitMode, focusKey, goToPage, stepPage, todayKey]);
|
|
432
|
+
// ── page rendering ──────────────────────────────────────────────────────────
|
|
433
|
+
const rowCount = mode === 'week' ? 1 : currentGrid.rowCount;
|
|
434
|
+
const collapsible = mode === 'week' || (monthsToShow === 1 && rowCount > 1);
|
|
435
|
+
const renderGrid = useCallback((gridPageKey, gridTestID) => {
|
|
436
|
+
const grid = gridFor(gridPageKey);
|
|
437
|
+
return (_jsx(CalendarPage, { activeRow: activeRow, chrome: chrome, collapse: collapse, collapsible: collapsible, disabledVersion: disabledVersion, grid: grid, isDisabled: isDisabled, markers: markers, selectedKey: selectedKey, showOutsideDays: showOutsideDays, showWeekNumbers: showWeekNumbers, tabbableKey: tabbableKey, testID: gridTestID, todayKey: todayKey }));
|
|
438
|
+
}, [
|
|
439
|
+
activeRow,
|
|
440
|
+
chrome,
|
|
441
|
+
collapse,
|
|
442
|
+
collapsible,
|
|
443
|
+
disabledVersion,
|
|
444
|
+
gridFor,
|
|
445
|
+
isDisabled,
|
|
446
|
+
markers,
|
|
447
|
+
selectedKey,
|
|
448
|
+
showOutsideDays,
|
|
449
|
+
showWeekNumbers,
|
|
450
|
+
tabbableKey,
|
|
451
|
+
todayKey,
|
|
452
|
+
]);
|
|
453
|
+
const renderSlot = useCallback((slotPageKey) => {
|
|
454
|
+
if (monthsToShow === 1) {
|
|
455
|
+
return renderGrid(slotPageKey, `calendar-page-${slotPageKey}`);
|
|
456
|
+
}
|
|
457
|
+
const monthKeys = [slotPageKey];
|
|
458
|
+
for (let index = 1; index < monthsToShow; index++) {
|
|
459
|
+
monthKeys.push(addPages(slotPageKey, index, mode, weekStart, 1));
|
|
460
|
+
}
|
|
461
|
+
return (_jsx(View, { style: TWO_UP_ROW, children: monthKeys.map((monthKey) => (_jsx(View, { style: COLUMN, children: renderGrid(monthKey, `calendar-page-${monthKey}`) }, monthKey))) }));
|
|
462
|
+
}, [mode, monthsToShow, renderGrid, weekStart]);
|
|
463
|
+
const slots = useMemo(() => {
|
|
464
|
+
if (paging === 'none') {
|
|
465
|
+
return [{ key: pageKey, offset: 0, node: renderSlot(pageKey) }];
|
|
466
|
+
}
|
|
467
|
+
return [
|
|
468
|
+
{ key: previousPageKey, offset: -1, node: renderSlot(previousPageKey) },
|
|
469
|
+
{ key: pageKey, offset: 0, node: renderSlot(pageKey) },
|
|
470
|
+
{ key: nextPageKey, offset: 1, node: renderSlot(nextPageKey) },
|
|
471
|
+
];
|
|
472
|
+
}, [nextPageKey, pageKey, paging, previousPageKey, renderSlot]);
|
|
473
|
+
const containerStyle = useMemo(() => ({
|
|
474
|
+
backgroundColor: palette.background,
|
|
475
|
+
maxWidth: metrics.cellSize * 7 * 1.6 * monthsToShow,
|
|
476
|
+
}), [metrics.cellSize, monthsToShow, palette.background]);
|
|
477
|
+
const weekdayRow = showWeekdayRow ? (_jsx(View, { style: monthsToShow > 1 ? TWO_UP_ROW : undefined, children: Array.from({ length: monthsToShow }, (_, index) => (_jsx(View, { style: COLUMN, children: _jsx(CalendarWeekdayRow, { maxFontSizeMultiplier: maxFontSizeMultiplier, metrics: metrics, palette: palette, renderWeekdayLabel: renderWeekdayLabel, showWeekNumbers: showWeekNumbers, styles: styles, weekStart: weekStart, weekdayLabels: weekdayLabels }) }, `weekday-row-${index}`))) })) : null;
|
|
478
|
+
return (_jsxs(KeyboardView, { accessibilityLabel: accessibilityLabel ?? title, onKeyDown: handleKeyDown, style: [CONTAINER, containerStyle, styles.container, style], testID: testID, children: [showHeader ? (_jsx(CalendarHeader, { canGoNext: canGoNext, canGoPrevious: canGoPrevious, headerContext: headerContext, labels: labels, maxFontSizeMultiplier: maxFontSizeMultiplier, metrics: metrics, mode: mode, onNext: goNext, onPrevious: goPrevious, palette: palette, renderHeader: renderHeader, showNavigationButtons: showNavigationButtons, styles: styles, title: title })) : null, weekdayRow, _jsx(CalendarPager, { activeRow: activeRow, collapse: collapse, onCommit: handleSwipeCommit, reduceMotion: reduceMotion, rowCount: rowCount, rowHeight: metrics.rowHeight, slots: slots, swipeEnabled: paging === 'swipe', testID: "calendar-pager" })] }));
|
|
479
|
+
}
|
|
480
|
+
export const Calendar = React.memo(forwardRef(CalendarContainer));
|
|
481
|
+
export default Calendar;
|
|
482
|
+
export * from './types';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { type ReactElement } from 'react';
|
|
2
|
+
import type { CalendarChrome, CalendarDayModel, CalendarMarker } from './types';
|
|
3
|
+
export type CalendarDayProps = {
|
|
4
|
+
day: CalendarDayModel;
|
|
5
|
+
/** Precomputed by the grid builder. A cell never formats a date itself. */
|
|
6
|
+
dayLabel: string;
|
|
7
|
+
accessibilityLabel: string;
|
|
8
|
+
isSelected: boolean;
|
|
9
|
+
isToday: boolean;
|
|
10
|
+
isDisabled: boolean;
|
|
11
|
+
/** Roving tab index: exactly one cell per page is tabbable. */
|
|
12
|
+
isTabbable: boolean;
|
|
13
|
+
/** Inert spacer for an out of month day when `showOutsideDays` is false. */
|
|
14
|
+
isHidden: boolean;
|
|
15
|
+
marker?: CalendarMarker;
|
|
16
|
+
chrome: CalendarChrome;
|
|
17
|
+
};
|
|
18
|
+
declare function CalendarDayContainer(props: CalendarDayProps): ReactElement;
|
|
19
|
+
export declare const CalendarDay: React.MemoExoticComponent<typeof CalendarDayContainer>;
|
|
20
|
+
export default CalendarDay;
|
|
21
|
+
//# sourceMappingURL=CalendarDay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalendarDay.d.ts","sourceRoot":"","sources":["../../../../src/components/uis/Calendar/CalendarDay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuB,KAAK,YAAY,EAAC,MAAM,OAAO,CAAC;AAKrE,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAChB,cAAc,EAEf,MAAM,SAAS,CAAC;AAyCjB,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,gBAAgB,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,UAAU,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,cAAc,CAAC;CACxB,CAAC;AAoDF,iBAAS,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAsMnE;AAcD,eAAO,MAAM,WAAW,wDAAiD,CAAC;AAE1E,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useCallback, useMemo } from 'react';
|
|
3
|
+
import { Platform, Pressable, Text, View } from 'react-native';
|
|
4
|
+
import { css } from 'kstyled';
|
|
5
|
+
import { isSameMarker } from './utils';
|
|
6
|
+
const CELL = css `
|
|
7
|
+
flex: 1;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: flex-start;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
border-radius: 10px;
|
|
12
|
+
`;
|
|
13
|
+
const PILL = css `
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
`;
|
|
17
|
+
const DAY_TEXT = css `
|
|
18
|
+
text-align: center;
|
|
19
|
+
font-weight: 500;
|
|
20
|
+
`;
|
|
21
|
+
const DECORATIONS = css `
|
|
22
|
+
position: absolute;
|
|
23
|
+
bottom: 0;
|
|
24
|
+
start: 0;
|
|
25
|
+
end: 0;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: flex-end;
|
|
28
|
+
`;
|
|
29
|
+
const DOT_ROW = css `
|
|
30
|
+
flex-direction: row;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
gap: 2px;
|
|
34
|
+
`;
|
|
35
|
+
const BADGE_TEXT = css `
|
|
36
|
+
text-align: center;
|
|
37
|
+
`;
|
|
38
|
+
function resolveTextColor(args) {
|
|
39
|
+
const { palette, isSelected, isDisabled, isToday, isOutside, weekday, markerTextColor, } = args;
|
|
40
|
+
if (isSelected) {
|
|
41
|
+
return palette.selectedText;
|
|
42
|
+
}
|
|
43
|
+
if (isDisabled) {
|
|
44
|
+
return palette.disabledText;
|
|
45
|
+
}
|
|
46
|
+
if (isOutside) {
|
|
47
|
+
return palette.outsideText;
|
|
48
|
+
}
|
|
49
|
+
if (markerTextColor) {
|
|
50
|
+
return markerTextColor;
|
|
51
|
+
}
|
|
52
|
+
if (isToday) {
|
|
53
|
+
return palette.todayText;
|
|
54
|
+
}
|
|
55
|
+
if (weekday === 0) {
|
|
56
|
+
return palette.sundayText;
|
|
57
|
+
}
|
|
58
|
+
if (weekday === 6) {
|
|
59
|
+
return palette.saturdayText;
|
|
60
|
+
}
|
|
61
|
+
return palette.dayText;
|
|
62
|
+
}
|
|
63
|
+
function CalendarDayContainer(props) {
|
|
64
|
+
const { day, dayLabel, accessibilityLabel, isSelected, isToday, isDisabled, isTabbable, isHidden, marker, chrome, } = props;
|
|
65
|
+
const { palette, metrics, geometry, styles } = chrome;
|
|
66
|
+
const pillStyle = useMemo(() => {
|
|
67
|
+
if (isSelected) {
|
|
68
|
+
return {
|
|
69
|
+
backgroundColor: marker?.selectedColor ?? palette.selectedBackground,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (isToday) {
|
|
73
|
+
return { borderWidth: 1.5, borderColor: palette.todayRing };
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}, [isSelected, isToday, marker?.selectedColor, palette]);
|
|
77
|
+
const textStyle = useMemo(() => ({
|
|
78
|
+
color: resolveTextColor({
|
|
79
|
+
palette,
|
|
80
|
+
isSelected,
|
|
81
|
+
isDisabled,
|
|
82
|
+
isToday,
|
|
83
|
+
isOutside: day.isOutside,
|
|
84
|
+
weekday: day.weekday,
|
|
85
|
+
markerTextColor: marker?.textColor,
|
|
86
|
+
}),
|
|
87
|
+
opacity: isDisabled ? 0.55 : 1,
|
|
88
|
+
}), [
|
|
89
|
+
day.isOutside,
|
|
90
|
+
day.weekday,
|
|
91
|
+
isDisabled,
|
|
92
|
+
isSelected,
|
|
93
|
+
isToday,
|
|
94
|
+
marker?.textColor,
|
|
95
|
+
palette,
|
|
96
|
+
]);
|
|
97
|
+
const handlePress = useCallback(() => {
|
|
98
|
+
if (isDisabled) {
|
|
99
|
+
chrome.onDisabledPress?.(day.key);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
chrome.onPress(day.key);
|
|
103
|
+
}, [chrome, day.key, isDisabled]);
|
|
104
|
+
const handleLongPress = useCallback(() => {
|
|
105
|
+
if (isDisabled) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
chrome.onLongPress?.(day.key);
|
|
109
|
+
}, [chrome, day.key, isDisabled]);
|
|
110
|
+
const cellStyle = useCallback(({ pressed }) => pressed && !isDisabled
|
|
111
|
+
? [
|
|
112
|
+
CELL,
|
|
113
|
+
geometry.cell,
|
|
114
|
+
{ backgroundColor: palette.underlay },
|
|
115
|
+
styles.dayCell,
|
|
116
|
+
isSelected ? styles.selectedDayCell : null,
|
|
117
|
+
isToday ? styles.todayDayCell : null,
|
|
118
|
+
]
|
|
119
|
+
: [
|
|
120
|
+
CELL,
|
|
121
|
+
geometry.cell,
|
|
122
|
+
styles.dayCell,
|
|
123
|
+
isSelected ? styles.selectedDayCell : null,
|
|
124
|
+
isToday ? styles.todayDayCell : null,
|
|
125
|
+
], [geometry.cell, isDisabled, isSelected, isToday, palette.underlay, styles]);
|
|
126
|
+
if (isHidden) {
|
|
127
|
+
return (_jsx(View, { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants", style: [CELL, geometry.cell], testID: `calendar-day-${day.key}-spacer` }));
|
|
128
|
+
}
|
|
129
|
+
const dots = chrome.showDots && marker?.dots?.length
|
|
130
|
+
? marker.dots.slice(0, chrome.maxDots)
|
|
131
|
+
: null;
|
|
132
|
+
const badgeText = chrome.showBadges && marker?.badgeText ? marker.badgeText : null;
|
|
133
|
+
return (_jsx(Pressable, { accessibilityLabel: accessibilityLabel, accessibilityRole: "button", accessibilityState: { disabled: isDisabled, selected: isSelected }, "aria-disabled": isDisabled, "aria-selected": isSelected, onLongPress: chrome.onLongPress ? handleLongPress : undefined, onPress: handlePress, style: cellStyle, tabIndex: isTabbable ? 0 : -1, testID: `calendar-day-${day.key}`, children: chrome.renderDay ? (chrome.renderDay({
|
|
134
|
+
day,
|
|
135
|
+
isSelected,
|
|
136
|
+
isToday,
|
|
137
|
+
isDisabled,
|
|
138
|
+
marker,
|
|
139
|
+
palette,
|
|
140
|
+
cellSize: metrics.cellSize,
|
|
141
|
+
})) : (_jsxs(_Fragment, { children: [_jsx(View, { style: [PILL, geometry.pill, pillStyle], children: _jsx(Text, { adjustsFontSizeToFit: Platform.OS === 'ios', maxFontSizeMultiplier: chrome.maxFontSizeMultiplier, minimumFontScale: 0.8, numberOfLines: 1, style: [
|
|
142
|
+
DAY_TEXT,
|
|
143
|
+
geometry.dayText,
|
|
144
|
+
textStyle,
|
|
145
|
+
styles.dayText,
|
|
146
|
+
day.isOutside ? styles.outsideDayText : null,
|
|
147
|
+
isDisabled ? styles.disabledDayText : null,
|
|
148
|
+
isSelected ? styles.selectedDayText : null,
|
|
149
|
+
isToday ? styles.todayDayText : null,
|
|
150
|
+
], children: dayLabel }) }), dots || badgeText ? (_jsxs(View, { importantForAccessibility: "no", pointerEvents: "none", style: DECORATIONS, children: [dots ? (_jsx(View, { style: [DOT_ROW, geometry.dotRow, styles.dotRow], children: dots.map((dot) => (_jsx(View, { style: [
|
|
151
|
+
geometry.dot,
|
|
152
|
+
{ backgroundColor: dot.color ?? palette.dot },
|
|
153
|
+
styles.dot,
|
|
154
|
+
] }, dot.key))) })) : null, badgeText ? (_jsx(Text, { maxFontSizeMultiplier: chrome.maxFontSizeMultiplier, numberOfLines: 1, style: [
|
|
155
|
+
BADGE_TEXT,
|
|
156
|
+
geometry.badgeText,
|
|
157
|
+
{ color: marker?.badgeColor ?? palette.badgeText },
|
|
158
|
+
styles.badgeText,
|
|
159
|
+
], children: badgeText })) : null] })) : null] })) }));
|
|
160
|
+
}
|
|
161
|
+
const areDaysEqual = (a, b) => a.day === b.day &&
|
|
162
|
+
a.dayLabel === b.dayLabel &&
|
|
163
|
+
a.isSelected === b.isSelected &&
|
|
164
|
+
a.isToday === b.isToday &&
|
|
165
|
+
a.isDisabled === b.isDisabled &&
|
|
166
|
+
a.isTabbable === b.isTabbable &&
|
|
167
|
+
a.isHidden === b.isHidden &&
|
|
168
|
+
a.chrome === b.chrome &&
|
|
169
|
+
a.accessibilityLabel === b.accessibilityLabel &&
|
|
170
|
+
isSameMarker(a.marker, b.marker);
|
|
171
|
+
export const CalendarDay = React.memo(CalendarDayContainer, areDaysEqual);
|
|
172
|
+
export default CalendarDay;
|