react-native-bigger-calendar 0.1.0 → 0.2.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 +82 -2
- package/dist/index.d.mts +289 -73
- package/dist/index.d.ts +289 -73
- package/dist/index.js +659 -150
- package/dist/index.mjs +658 -151
- package/package.json +2 -2
- package/src/components/Agenda.tsx +125 -0
- package/src/components/AllDayLane.tsx +83 -0
- package/src/components/Calendar.tsx +221 -11
- package/src/components/DefaultEvent.tsx +24 -5
- package/src/components/MonthPager.tsx +138 -26
- package/src/components/MonthView.tsx +82 -14
- package/src/components/TimeGrid.tsx +351 -62
- package/src/index.tsx +9 -2
- package/src/types.ts +23 -1
- package/src/utils/dates.ts +67 -2
- package/src/utils/layout.ts +18 -0
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { addDays, addMonths, differenceInCalendarDays, differenceInCalendarMonths, differenceInMinutes, eachDayOfInterval, endOfDay, endOfMonth, endOfWeek, format, getHours, getISOWeek, getMinutes, isSameDay, isSameMonth, isToday, max, min, startOfDay, startOfMonth, startOfWeek } from "date-fns";
|
|
1
2
|
import { createContext, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
2
3
|
import Animated, { scrollTo, useAnimatedReaction, useAnimatedRef, useAnimatedScrollHandler, useAnimatedStyle, useDerivedValue, useSharedValue } from "react-native-reanimated";
|
|
3
|
-
import {
|
|
4
|
+
import { LegendList } from "@legendapp/list/react-native";
|
|
4
5
|
import { Pressable, StyleSheet, Text, TouchableOpacity, View, useWindowDimensions } from "react-native";
|
|
5
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
-
import { LegendList } from "@legendapp/list/react-native";
|
|
7
7
|
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
8
8
|
//#region src/theme.ts
|
|
9
9
|
const defaultTheme = {
|
|
@@ -63,18 +63,169 @@ const CalendarThemeContext = createContext(defaultTheme);
|
|
|
63
63
|
const CalendarThemeProvider = CalendarThemeContext.Provider;
|
|
64
64
|
const useCalendarTheme = () => useContext(CalendarThemeContext);
|
|
65
65
|
//#endregion
|
|
66
|
+
//#region src/utils/dates.ts
|
|
67
|
+
/** The seven dates of the week containing `date`, starting on `weekStartsOn`. */
|
|
68
|
+
const getWeekDays = (date, weekStartsOn) => {
|
|
69
|
+
const start = startOfWeek(date, { weekStartsOn });
|
|
70
|
+
return Array.from({ length: 7 }, (_, index) => addDays(start, index));
|
|
71
|
+
};
|
|
72
|
+
/** How many day columns a time-grid mode shows. `custom` uses `numberOfDays`. */
|
|
73
|
+
const viewDayCount = (mode, numberOfDays = 1) => {
|
|
74
|
+
switch (mode) {
|
|
75
|
+
case "week": return 7;
|
|
76
|
+
case "3days": return 3;
|
|
77
|
+
case "custom": return Math.max(1, Math.floor(numberOfDays));
|
|
78
|
+
default: return 1;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Days in the inclusive span from `weekStartsOn` to `weekEndsOn` (1–7),
|
|
83
|
+
* wrapping when the end precedes the start (e.g. Sat→Wed). Mirrors
|
|
84
|
+
* react-native-big-calendar's `weekDaysCount`.
|
|
85
|
+
*/
|
|
86
|
+
const weekDaysCount = (weekStartsOn, weekEndsOn) => {
|
|
87
|
+
if (weekEndsOn < weekStartsOn) {
|
|
88
|
+
let count = 1;
|
|
89
|
+
let i = weekStartsOn;
|
|
90
|
+
while (i !== weekEndsOn && count <= 7) {
|
|
91
|
+
i = (i + 1) % 7;
|
|
92
|
+
count++;
|
|
93
|
+
}
|
|
94
|
+
return count;
|
|
95
|
+
}
|
|
96
|
+
if (weekEndsOn > weekStartsOn) return weekEndsOn - weekStartsOn + 1;
|
|
97
|
+
return 1;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* The day columns to render for a time-grid page. `week` spans the calendar week
|
|
101
|
+
* (honouring `weekStartsOn`). `custom` with a `weekEndsOn` spans the partial week
|
|
102
|
+
* from `weekStartsOn` to `weekEndsOn` (anchored to `date`'s week, paging by week);
|
|
103
|
+
* otherwise every mode shows `viewDayCount` consecutive days starting at `date`.
|
|
104
|
+
*/
|
|
105
|
+
const getViewDays = (mode, date, weekStartsOn, numberOfDays = 1, isRTL = false, weekEndsOn) => {
|
|
106
|
+
let days;
|
|
107
|
+
if (mode === "week") days = getWeekDays(date, weekStartsOn);
|
|
108
|
+
else if (mode === "custom" && weekEndsOn != null) {
|
|
109
|
+
const subject = startOfDay(date);
|
|
110
|
+
const offset = weekStartsOn - subject.getDay();
|
|
111
|
+
days = Array.from({ length: weekDaysCount(weekStartsOn, weekEndsOn) }, (_, index) => addDays(subject, index + offset));
|
|
112
|
+
} else days = Array.from({ length: viewDayCount(mode, numberOfDays) }, (_, index) => addDays(startOfDay(date), index));
|
|
113
|
+
return isRTL ? days.reverse() : days;
|
|
114
|
+
};
|
|
115
|
+
const isWeekend = (date) => {
|
|
116
|
+
const day = date.getDay();
|
|
117
|
+
return day === 0 || day === 6;
|
|
118
|
+
};
|
|
119
|
+
const getIsToday = (date) => isToday(date);
|
|
120
|
+
const isSameCalendarDay = (a, b) => isSameDay(a, b);
|
|
121
|
+
/** Minutes elapsed since midnight (0–1439). */
|
|
122
|
+
const minutesIntoDay = (date) => getHours(date) * 60 + getMinutes(date);
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/components/Agenda.tsx
|
|
125
|
+
/**
|
|
126
|
+
* A vertical, day-grouped list of events (no time grid). Events are sorted by
|
|
127
|
+
* start, grouped under a date header per day. The consumer controls which
|
|
128
|
+
* events (and therefore which date range) are shown.
|
|
129
|
+
*/
|
|
130
|
+
function Agenda({ events, locale, renderEvent, keyExtractor, onPressEvent, onLongPressEvent, onPressDay, activeDate, itemSeparatorComponent }) {
|
|
131
|
+
const theme = useCalendarTheme();
|
|
132
|
+
const RenderEventComponent = renderEvent;
|
|
133
|
+
const rows = useMemo(() => {
|
|
134
|
+
const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
|
|
135
|
+
const out = [];
|
|
136
|
+
let currentDay = null;
|
|
137
|
+
sorted.forEach((event, index) => {
|
|
138
|
+
if (!currentDay || !isSameDay(event.start, currentDay)) {
|
|
139
|
+
currentDay = startOfDay(event.start);
|
|
140
|
+
out.push({
|
|
141
|
+
kind: "header",
|
|
142
|
+
date: currentDay,
|
|
143
|
+
key: `h-${currentDay.toISOString()}`
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
out.push({
|
|
147
|
+
kind: "event",
|
|
148
|
+
event,
|
|
149
|
+
index,
|
|
150
|
+
key: `e-${keyExtractor(event, index)}`
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
return out;
|
|
154
|
+
}, [events, keyExtractor]);
|
|
155
|
+
const keyExtractorRow = useCallback((row) => row.key, []);
|
|
156
|
+
const renderItem = useCallback(({ item }) => {
|
|
157
|
+
if (item.kind === "header") {
|
|
158
|
+
const isHighlighted = activeDate ? isSameDay(item.date, activeDate) : getIsToday(item.date);
|
|
159
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
160
|
+
style: [
|
|
161
|
+
theme.text.weekday,
|
|
162
|
+
styles$5.header,
|
|
163
|
+
{ color: isHighlighted ? theme.colors.todayBackground : theme.colors.textMuted }
|
|
164
|
+
],
|
|
165
|
+
onPress: onPressDay ? () => onPressDay(item.date) : void 0,
|
|
166
|
+
accessibilityRole: onPressDay ? "button" : "header",
|
|
167
|
+
children: format(item.date, "EEEE, d LLLL", { locale })
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return /* @__PURE__ */ jsx(View, {
|
|
171
|
+
style: styles$5.eventRow,
|
|
172
|
+
children: /* @__PURE__ */ jsx(RenderEventComponent, {
|
|
173
|
+
event: item.event,
|
|
174
|
+
mode: "schedule",
|
|
175
|
+
onPress: () => onPressEvent(item.event),
|
|
176
|
+
onLongPress: onLongPressEvent ? () => onLongPressEvent(item.event) : void 0
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
}, [
|
|
180
|
+
theme,
|
|
181
|
+
locale,
|
|
182
|
+
activeDate,
|
|
183
|
+
onPressDay,
|
|
184
|
+
onPressEvent,
|
|
185
|
+
onLongPressEvent,
|
|
186
|
+
RenderEventComponent
|
|
187
|
+
]);
|
|
188
|
+
return /* @__PURE__ */ jsx(LegendList, {
|
|
189
|
+
style: styles$5.list,
|
|
190
|
+
data: rows,
|
|
191
|
+
keyExtractor: keyExtractorRow,
|
|
192
|
+
renderItem,
|
|
193
|
+
ItemSeparatorComponent: itemSeparatorComponent ?? void 0,
|
|
194
|
+
recycleItems: false
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
const styles$5 = StyleSheet.create({
|
|
198
|
+
list: { flex: 1 },
|
|
199
|
+
header: {
|
|
200
|
+
paddingTop: 12,
|
|
201
|
+
paddingBottom: 4,
|
|
202
|
+
paddingHorizontal: 12
|
|
203
|
+
},
|
|
204
|
+
eventRow: {
|
|
205
|
+
paddingHorizontal: 12,
|
|
206
|
+
paddingVertical: 2
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
//#endregion
|
|
66
210
|
//#region src/components/DefaultEvent.tsx
|
|
67
211
|
/**
|
|
68
212
|
* The built-in event renderer: a filled, rounded box showing the event title
|
|
69
213
|
* and (on the day/week grid) its time range. Pass your own `renderEvent` to
|
|
70
214
|
* `<Calendar>` to replace it entirely.
|
|
71
215
|
*/
|
|
72
|
-
function DefaultEvent({ event, mode, onPress }) {
|
|
216
|
+
function DefaultEvent({ event, mode, isAllDay, ampm = false, showTime = true, cellStyle, onPress, onLongPress }) {
|
|
73
217
|
const theme = useCalendarTheme();
|
|
74
|
-
const
|
|
218
|
+
const timeFormat = ampm ? "h:mm a" : "HH:mm";
|
|
219
|
+
const shouldShowTime = mode !== "month" && !isAllDay && showTime;
|
|
75
220
|
return /* @__PURE__ */ jsxs(TouchableOpacity, {
|
|
76
|
-
style: [
|
|
221
|
+
style: [
|
|
222
|
+
styles$4.box,
|
|
223
|
+
{ backgroundColor: theme.colors.eventBackground },
|
|
224
|
+
event.disabled && styles$4.disabled,
|
|
225
|
+
cellStyle
|
|
226
|
+
],
|
|
77
227
|
onPress,
|
|
228
|
+
onLongPress,
|
|
78
229
|
activeOpacity: .7,
|
|
79
230
|
accessibilityRole: "button",
|
|
80
231
|
accessibilityLabel: event.title,
|
|
@@ -84,15 +235,15 @@ function DefaultEvent({ event, mode, onPress }) {
|
|
|
84
235
|
ellipsizeMode: "tail",
|
|
85
236
|
allowFontScaling: false,
|
|
86
237
|
children: event.title
|
|
87
|
-
}) : null,
|
|
88
|
-
style: [styles$
|
|
238
|
+
}) : null, shouldShowTime ? /* @__PURE__ */ jsx(Text, {
|
|
239
|
+
style: [styles$4.time, { color: theme.colors.eventText }],
|
|
89
240
|
numberOfLines: 1,
|
|
90
241
|
allowFontScaling: false,
|
|
91
|
-
children: `${format(event.start,
|
|
242
|
+
children: `${format(event.start, timeFormat)} - ${format(event.end, timeFormat)}`
|
|
92
243
|
}) : null]
|
|
93
244
|
});
|
|
94
245
|
}
|
|
95
|
-
const styles$
|
|
246
|
+
const styles$4 = StyleSheet.create({
|
|
96
247
|
box: {
|
|
97
248
|
flex: 1,
|
|
98
249
|
borderRadius: 6,
|
|
@@ -100,24 +251,10 @@ const styles$3 = StyleSheet.create({
|
|
|
100
251
|
paddingHorizontal: 4,
|
|
101
252
|
overflow: "hidden"
|
|
102
253
|
},
|
|
103
|
-
time: { fontSize: 11 }
|
|
254
|
+
time: { fontSize: 11 },
|
|
255
|
+
disabled: { opacity: .5 }
|
|
104
256
|
});
|
|
105
257
|
//#endregion
|
|
106
|
-
//#region src/utils/dates.ts
|
|
107
|
-
/** The seven dates of the week containing `date`, starting on `weekStartsOn`. */
|
|
108
|
-
const getWeekDays = (date, weekStartsOn) => {
|
|
109
|
-
const start = startOfWeek(date, { weekStartsOn });
|
|
110
|
-
return Array.from({ length: 7 }, (_, index) => addDays(start, index));
|
|
111
|
-
};
|
|
112
|
-
const isWeekend = (date) => {
|
|
113
|
-
const day = date.getDay();
|
|
114
|
-
return day === 0 || day === 6;
|
|
115
|
-
};
|
|
116
|
-
const getIsToday = (date) => isToday(date);
|
|
117
|
-
const isSameCalendarDay = (a, b) => isSameDay(a, b);
|
|
118
|
-
/** Minutes elapsed since midnight (0–1439). */
|
|
119
|
-
const minutesIntoDay = (date) => getHours(date) * 60 + getMinutes(date);
|
|
120
|
-
//#endregion
|
|
121
258
|
//#region src/utils/layout.ts
|
|
122
259
|
const MINUTES_PER_HOUR$1 = 60;
|
|
123
260
|
const MIN_DURATION_HOURS = .25;
|
|
@@ -130,7 +267,7 @@ const MIN_DURATION_HOURS = .25;
|
|
|
130
267
|
function layoutDayEvents(events, day) {
|
|
131
268
|
const dayStart = startOfDay(day);
|
|
132
269
|
const nextDayStart = addDays(dayStart, 1);
|
|
133
|
-
const segments = events.filter((event) => event.start < nextDayStart && event.end > dayStart).map((event) => {
|
|
270
|
+
const segments = events.filter((event) => !isAllDayEvent(event)).filter((event) => event.start < nextDayStart && event.end > dayStart).map((event) => {
|
|
134
271
|
const segStart = max([event.start, dayStart]);
|
|
135
272
|
const segEnd = min([event.end, nextDayStart]);
|
|
136
273
|
return {
|
|
@@ -174,6 +311,16 @@ function layoutDayEvents(events, day) {
|
|
|
174
311
|
if (cluster.length > 0) flushCluster();
|
|
175
312
|
return positioned;
|
|
176
313
|
}
|
|
314
|
+
const atMidnight = (date) => date.getHours() === 0 && date.getMinutes() === 0 && date.getSeconds() === 0 && date.getMilliseconds() === 0;
|
|
315
|
+
/**
|
|
316
|
+
* Whether an event belongs in the all-day lane. An explicit `allDay` flag wins;
|
|
317
|
+
* otherwise it's inferred when the event spans whole days (both `start` and
|
|
318
|
+
* `end` land on midnight, e.g. an iCal-style all-day event). Pure.
|
|
319
|
+
*/
|
|
320
|
+
function isAllDayEvent(event) {
|
|
321
|
+
if (typeof event.allDay === "boolean") return event.allDay;
|
|
322
|
+
return event.end > event.start && atMidnight(event.start) && atMidnight(event.end);
|
|
323
|
+
}
|
|
177
324
|
/**
|
|
178
325
|
* The `startOfDay` ISO keys of every calendar day an event touches (inclusive).
|
|
179
326
|
* An event ending exactly at midnight does not count the following day. Used to
|
|
@@ -193,15 +340,23 @@ const chunkIntoWeeks = (days) => {
|
|
|
193
340
|
for (let index = 0; index < days.length; index += 7) weeks.push(days.slice(index, index + 7));
|
|
194
341
|
return weeks;
|
|
195
342
|
};
|
|
196
|
-
function MonthViewInner({ date, events, maxVisibleEventCount, weekStartsOn, renderEvent, keyExtractor, onPressDay, onPressEvent, onPressMore }) {
|
|
343
|
+
function MonthViewInner({ date, events, maxVisibleEventCount, weekStartsOn, locale, sortedMonthView = true, moreLabel = "{moreCount} More", showAdjacentMonths = true, disableMonthEventCellPress = false, isRTL = false, showSixWeeks = false, activeDate, calendarCellStyle, renderEvent, keyExtractor, onPressDay, onLongPressDay, onPressEvent, onLongPressEvent, onPressMore }) {
|
|
197
344
|
const theme = useCalendarTheme();
|
|
198
345
|
const RenderEventComponent = renderEvent;
|
|
199
346
|
const weeks = useMemo(() => {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
347
|
+
const start = startOfWeek(startOfMonth(date), { weekStartsOn });
|
|
348
|
+
const naturalEnd = endOfWeek(endOfMonth(date), { weekStartsOn });
|
|
349
|
+
const chunked = chunkIntoWeeks(eachDayOfInterval({
|
|
350
|
+
start,
|
|
351
|
+
end: showSixWeeks ? addDays(start, 41) : naturalEnd
|
|
203
352
|
}));
|
|
204
|
-
|
|
353
|
+
return isRTL ? chunked.map((week) => [...week].reverse()) : chunked;
|
|
354
|
+
}, [
|
|
355
|
+
date,
|
|
356
|
+
weekStartsOn,
|
|
357
|
+
isRTL,
|
|
358
|
+
showSixWeeks
|
|
359
|
+
]);
|
|
205
360
|
const eventsByDay = useMemo(() => {
|
|
206
361
|
const map = /* @__PURE__ */ new Map();
|
|
207
362
|
for (const event of events) for (const key of eventDayKeys(event)) {
|
|
@@ -209,29 +364,38 @@ function MonthViewInner({ date, events, maxVisibleEventCount, weekStartsOn, rend
|
|
|
209
364
|
if (existing) existing.push(event);
|
|
210
365
|
else map.set(key, [event]);
|
|
211
366
|
}
|
|
367
|
+
if (sortedMonthView) for (const list of map.values()) list.sort((a, b) => a.start.getTime() - b.start.getTime());
|
|
212
368
|
return map;
|
|
213
|
-
}, [events]);
|
|
369
|
+
}, [events, sortedMonthView]);
|
|
214
370
|
const renderDay = (day) => {
|
|
215
|
-
const dayEvents = eventsByDay.get(startOfDay(day).toISOString()) ?? [];
|
|
216
371
|
const isCurrentMonth = isSameMonth(day, date);
|
|
372
|
+
if (!isCurrentMonth && !showAdjacentMonths) return /* @__PURE__ */ jsx(View, { style: [
|
|
373
|
+
styles$3.dayCell,
|
|
374
|
+
{ borderColor: theme.colors.gridLine },
|
|
375
|
+
isWeekend(day) && { backgroundColor: theme.colors.weekendBackground }
|
|
376
|
+
] }, day.toISOString());
|
|
377
|
+
const dayEvents = eventsByDay.get(startOfDay(day).toISOString()) ?? [];
|
|
217
378
|
const isToday = getIsToday(day);
|
|
379
|
+
const isHighlighted = activeDate ? isSameCalendarDay(day, activeDate) : isToday;
|
|
218
380
|
const hiddenCount = dayEvents.length - maxVisibleEventCount;
|
|
219
|
-
const dateColor =
|
|
381
|
+
const dateColor = isHighlighted ? theme.colors.todayText : isCurrentMonth ? theme.colors.text : theme.colors.textDisabled;
|
|
220
382
|
const eventCount = dayEvents.length;
|
|
221
|
-
const accessibilityLabel = `${format(day, "EEEE, d LLLL yyyy")}${isToday ? ", today" : ""}, ${eventCount} ${eventCount === 1 ? "event" : "events"}`;
|
|
383
|
+
const accessibilityLabel = `${format(day, "EEEE, d LLLL yyyy", { locale })}${isToday ? ", today" : ""}, ${eventCount} ${eventCount === 1 ? "event" : "events"}`;
|
|
222
384
|
return /* @__PURE__ */ jsxs(TouchableOpacity, {
|
|
223
385
|
style: [
|
|
224
|
-
styles$
|
|
386
|
+
styles$3.dayCell,
|
|
225
387
|
{ borderColor: theme.colors.gridLine },
|
|
226
|
-
isWeekend(day) && { backgroundColor: theme.colors.weekendBackground }
|
|
388
|
+
isWeekend(day) && { backgroundColor: theme.colors.weekendBackground },
|
|
389
|
+
calendarCellStyle?.(day)
|
|
227
390
|
],
|
|
228
391
|
onPress: onPressDay ? () => onPressDay(day) : void 0,
|
|
229
|
-
|
|
392
|
+
onLongPress: onLongPressDay ? () => onLongPressDay(day) : void 0,
|
|
393
|
+
disabled: !onPressDay && !onLongPressDay,
|
|
230
394
|
accessibilityRole: onPressDay ? "button" : void 0,
|
|
231
395
|
accessibilityLabel,
|
|
232
396
|
children: [
|
|
233
397
|
/* @__PURE__ */ jsx(View, {
|
|
234
|
-
style: [styles$
|
|
398
|
+
style: [styles$3.dateBadge, isHighlighted && {
|
|
235
399
|
backgroundColor: theme.colors.todayBackground,
|
|
236
400
|
borderRadius: theme.todayBadgeRadius
|
|
237
401
|
}],
|
|
@@ -242,38 +406,40 @@ function MonthViewInner({ date, events, maxVisibleEventCount, weekStartsOn, rend
|
|
|
242
406
|
})
|
|
243
407
|
}),
|
|
244
408
|
dayEvents.slice(0, maxVisibleEventCount).map((event, index) => /* @__PURE__ */ jsx(View, {
|
|
245
|
-
style: styles$
|
|
409
|
+
style: styles$3.monthEvent,
|
|
246
410
|
children: /* @__PURE__ */ jsx(RenderEventComponent, {
|
|
247
411
|
event,
|
|
248
412
|
mode: "month",
|
|
249
|
-
|
|
413
|
+
isAllDay: isAllDayEvent(event),
|
|
414
|
+
onPress: disableMonthEventCellPress ? () => {} : () => onPressEvent(event),
|
|
415
|
+
onLongPress: disableMonthEventCellPress || !onLongPressEvent ? void 0 : () => onLongPressEvent(event)
|
|
250
416
|
})
|
|
251
417
|
}, keyExtractor(event, index))),
|
|
252
418
|
hiddenCount > 0 ? /* @__PURE__ */ jsx(Text, {
|
|
253
419
|
style: [
|
|
254
420
|
theme.text.more,
|
|
255
|
-
styles$
|
|
421
|
+
styles$3.moreLabel,
|
|
256
422
|
{ color: theme.colors.textMuted }
|
|
257
423
|
],
|
|
258
424
|
onPress: onPressMore ? () => onPressMore(dayEvents, day) : void 0,
|
|
259
425
|
accessibilityRole: "button",
|
|
260
426
|
accessibilityLabel: `Show ${hiddenCount} more events`,
|
|
261
427
|
allowFontScaling: false,
|
|
262
|
-
children:
|
|
428
|
+
children: moreLabel.replace("{moreCount}", String(hiddenCount))
|
|
263
429
|
}) : null
|
|
264
430
|
]
|
|
265
431
|
}, day.toISOString());
|
|
266
432
|
};
|
|
267
433
|
return /* @__PURE__ */ jsx(View, {
|
|
268
|
-
style: styles$
|
|
434
|
+
style: styles$3.container,
|
|
269
435
|
children: weeks.map((week) => /* @__PURE__ */ jsx(View, {
|
|
270
|
-
style: styles$
|
|
436
|
+
style: styles$3.weekRow,
|
|
271
437
|
children: week.map((day) => renderDay(day))
|
|
272
438
|
}, week[0].toISOString()))
|
|
273
439
|
});
|
|
274
440
|
}
|
|
275
441
|
const MonthView = memo(MonthViewInner);
|
|
276
|
-
const styles$
|
|
442
|
+
const styles$3 = StyleSheet.create({
|
|
277
443
|
container: { flex: 1 },
|
|
278
444
|
weekRow: {
|
|
279
445
|
flex: 1,
|
|
@@ -301,7 +467,7 @@ const styles$2 = StyleSheet.create({
|
|
|
301
467
|
//#region src/components/MonthPager.tsx
|
|
302
468
|
const PAGE_WINDOW$1 = 60;
|
|
303
469
|
const PAGE_VIEWABILITY$1 = { itemVisiblePercentThreshold: 90 };
|
|
304
|
-
function MonthPagerInner({ date, events, maxVisibleEventCount, weekStartsOn, renderEvent, keyExtractor, onPressDay, onPressEvent, onPressMore, onChangeDate, freeSwipe = false }) {
|
|
470
|
+
function MonthPagerInner({ date, events, maxVisibleEventCount, weekStartsOn, locale, sortedMonthView, moreLabel, showAdjacentMonths, disableMonthEventCellPress, isRTL, calendarCellStyle, renderEvent, keyExtractor, onPressDay, onLongPressDay, onPressEvent, onLongPressEvent, onPressMore, onChangeDate, freeSwipe = false, swipeEnabled = true, showSixWeeks = false, activeDate, renderHeaderForMonthView }) {
|
|
305
471
|
const { width, height } = useWindowDimensions();
|
|
306
472
|
const listRef = useRef(null);
|
|
307
473
|
const [pageHeight, setPageHeight] = useState(height);
|
|
@@ -324,6 +490,14 @@ function MonthPagerInner({ date, events, maxVisibleEventCount, weekStartsOn, ren
|
|
|
324
490
|
animated: false
|
|
325
491
|
});
|
|
326
492
|
}, [activeIndex]);
|
|
493
|
+
const weekDays = useMemo(() => {
|
|
494
|
+
const days = getWeekDays(anchor, weekStartsOn);
|
|
495
|
+
return isRTL ? days.reverse() : days;
|
|
496
|
+
}, [
|
|
497
|
+
anchor,
|
|
498
|
+
weekStartsOn,
|
|
499
|
+
isRTL
|
|
500
|
+
]);
|
|
327
501
|
const snapToIndices = useMemo(() => monthDates.map((_, index) => index), [monthDates]);
|
|
328
502
|
const keyExtractorList = useCallback((item) => item.toISOString(), []);
|
|
329
503
|
const getFixedItemSize = useCallback(() => width, [width]);
|
|
@@ -337,10 +511,21 @@ function MonthPagerInner({ date, events, maxVisibleEventCount, weekStartsOn, ren
|
|
|
337
511
|
events,
|
|
338
512
|
maxVisibleEventCount,
|
|
339
513
|
weekStartsOn,
|
|
514
|
+
locale,
|
|
515
|
+
sortedMonthView,
|
|
516
|
+
moreLabel,
|
|
517
|
+
showAdjacentMonths,
|
|
518
|
+
disableMonthEventCellPress,
|
|
519
|
+
isRTL,
|
|
520
|
+
showSixWeeks,
|
|
521
|
+
activeDate,
|
|
522
|
+
calendarCellStyle,
|
|
340
523
|
renderEvent,
|
|
341
524
|
keyExtractor,
|
|
342
525
|
onPressDay,
|
|
526
|
+
onLongPressDay,
|
|
343
527
|
onPressEvent,
|
|
528
|
+
onLongPressEvent,
|
|
344
529
|
onPressMore
|
|
345
530
|
})
|
|
346
531
|
}), [
|
|
@@ -349,44 +534,131 @@ function MonthPagerInner({ date, events, maxVisibleEventCount, weekStartsOn, ren
|
|
|
349
534
|
events,
|
|
350
535
|
maxVisibleEventCount,
|
|
351
536
|
weekStartsOn,
|
|
537
|
+
locale,
|
|
538
|
+
sortedMonthView,
|
|
539
|
+
moreLabel,
|
|
540
|
+
showAdjacentMonths,
|
|
541
|
+
disableMonthEventCellPress,
|
|
542
|
+
isRTL,
|
|
543
|
+
showSixWeeks,
|
|
544
|
+
activeDate,
|
|
545
|
+
calendarCellStyle,
|
|
352
546
|
renderEvent,
|
|
353
547
|
keyExtractor,
|
|
354
548
|
onPressDay,
|
|
549
|
+
onLongPressDay,
|
|
355
550
|
onPressEvent,
|
|
551
|
+
onLongPressEvent,
|
|
356
552
|
onPressMore
|
|
357
553
|
]);
|
|
358
|
-
return /* @__PURE__ */
|
|
359
|
-
style: styles$
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
554
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
555
|
+
style: styles$2.container,
|
|
556
|
+
children: [renderHeaderForMonthView ? renderHeaderForMonthView(weekDays) : /* @__PURE__ */ jsx(MonthWeekdayHeader, {
|
|
557
|
+
weekDays,
|
|
558
|
+
locale
|
|
559
|
+
}), /* @__PURE__ */ jsx(View, {
|
|
560
|
+
style: styles$2.pager,
|
|
561
|
+
onLayout: (event) => setPageHeight(event.nativeEvent.layout.height),
|
|
562
|
+
children: /* @__PURE__ */ jsx(LegendList, {
|
|
563
|
+
ref: listRef,
|
|
564
|
+
style: styles$2.pagerList,
|
|
565
|
+
data: monthDates,
|
|
566
|
+
horizontal: true,
|
|
567
|
+
recycleItems: false,
|
|
568
|
+
keyExtractor: keyExtractorList,
|
|
569
|
+
getFixedItemSize,
|
|
570
|
+
scrollEnabled: swipeEnabled,
|
|
571
|
+
pagingEnabled: !freeSwipe,
|
|
572
|
+
snapToIndices: freeSwipe ? snapToIndices : void 0,
|
|
573
|
+
initialScrollIndex: activeIndex,
|
|
574
|
+
showsHorizontalScrollIndicator: false,
|
|
575
|
+
viewabilityConfig: PAGE_VIEWABILITY$1,
|
|
576
|
+
onViewableItemsChanged: handleViewableItemsChanged,
|
|
577
|
+
renderItem
|
|
578
|
+
}, pageHeight)
|
|
579
|
+
})]
|
|
377
580
|
});
|
|
378
581
|
}
|
|
379
582
|
const MonthPager = memo(MonthPagerInner);
|
|
380
|
-
const
|
|
583
|
+
const MonthWeekdayHeader = ({ weekDays, locale }) => {
|
|
584
|
+
const theme = useCalendarTheme();
|
|
585
|
+
return /* @__PURE__ */ jsx(View, {
|
|
586
|
+
style: styles$2.weekdayHeader,
|
|
587
|
+
children: weekDays.map((day) => /* @__PURE__ */ jsx(Text, {
|
|
588
|
+
style: [
|
|
589
|
+
theme.text.weekday,
|
|
590
|
+
styles$2.weekdayLabel,
|
|
591
|
+
{ color: theme.colors.textMuted }
|
|
592
|
+
],
|
|
593
|
+
allowFontScaling: false,
|
|
594
|
+
children: format(day, "EEE", { locale })
|
|
595
|
+
}, day.toISOString()))
|
|
596
|
+
});
|
|
597
|
+
};
|
|
598
|
+
const styles$2 = StyleSheet.create({
|
|
599
|
+
container: { flex: 1 },
|
|
381
600
|
pager: { flex: 1 },
|
|
382
|
-
pagerList: { flex: 1 }
|
|
601
|
+
pagerList: { flex: 1 },
|
|
602
|
+
weekdayHeader: {
|
|
603
|
+
flexDirection: "row",
|
|
604
|
+
paddingBottom: 4
|
|
605
|
+
},
|
|
606
|
+
weekdayLabel: {
|
|
607
|
+
flex: 1,
|
|
608
|
+
textAlign: "center"
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region src/components/AllDayLane.tsx
|
|
613
|
+
/**
|
|
614
|
+
* The all-day lane that sits above the scrolling time grid. All-day events are
|
|
615
|
+
* excluded from the timed columns (see `layoutDayEvents`) and shown here,
|
|
616
|
+
* stacked under their day(s). Renders nothing when no day has an all-day event,
|
|
617
|
+
* so timed-only calendars are unaffected.
|
|
618
|
+
*/
|
|
619
|
+
function AllDayLane({ days, events, mode, hourColumnWidth, dayWidth, renderEvent, keyExtractor, onPressEvent, onLongPressEvent }) {
|
|
620
|
+
const theme = useCalendarTheme();
|
|
621
|
+
const RenderEventComponent = renderEvent;
|
|
622
|
+
const allDay = events.filter(isAllDayEvent);
|
|
623
|
+
const perDay = days.map((day) => {
|
|
624
|
+
const start = startOfDay(day);
|
|
625
|
+
const next = addDays(start, 1);
|
|
626
|
+
return allDay.filter((event) => event.start < next && event.end > start);
|
|
627
|
+
});
|
|
628
|
+
if (perDay.every((list) => list.length === 0)) return null;
|
|
629
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
630
|
+
style: [styles$1.lane, { borderBottomColor: theme.colors.gridLine }],
|
|
631
|
+
children: [/* @__PURE__ */ jsx(View, { style: { width: hourColumnWidth } }), days.map((day, dayIndex) => /* @__PURE__ */ jsx(View, {
|
|
632
|
+
style: [styles$1.column, { width: dayWidth }],
|
|
633
|
+
children: perDay[dayIndex].map((event, index) => /* @__PURE__ */ jsx(View, {
|
|
634
|
+
style: styles$1.chip,
|
|
635
|
+
children: /* @__PURE__ */ jsx(RenderEventComponent, {
|
|
636
|
+
event,
|
|
637
|
+
mode,
|
|
638
|
+
isAllDay: true,
|
|
639
|
+
onPress: () => onPressEvent(event),
|
|
640
|
+
onLongPress: onLongPressEvent ? () => onLongPressEvent(event) : void 0
|
|
641
|
+
})
|
|
642
|
+
}, keyExtractor(event, index)))
|
|
643
|
+
}, day.toISOString()))]
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
const styles$1 = StyleSheet.create({
|
|
647
|
+
lane: {
|
|
648
|
+
flexDirection: "row",
|
|
649
|
+
borderBottomWidth: StyleSheet.hairlineWidth,
|
|
650
|
+
paddingBottom: 2
|
|
651
|
+
},
|
|
652
|
+
column: {
|
|
653
|
+
paddingHorizontal: 1,
|
|
654
|
+
gap: 2
|
|
655
|
+
},
|
|
656
|
+
chip: { minHeight: 18 }
|
|
383
657
|
});
|
|
384
658
|
//#endregion
|
|
385
659
|
//#region src/components/TimeGrid.tsx
|
|
386
660
|
const MINUTES_PER_HOUR = 60;
|
|
387
661
|
const HOURS_PER_DAY = 24;
|
|
388
|
-
const DAY_VIEW_STEP = 1;
|
|
389
|
-
const WEEK_VIEW_STEP = 7;
|
|
390
662
|
const PAGE_WINDOW = 180;
|
|
391
663
|
const PAGE_VIEWABILITY = { itemVisiblePercentThreshold: 90 };
|
|
392
664
|
const DEFAULT_HOUR_HEIGHT = 64;
|
|
@@ -411,7 +683,7 @@ function formatHourLabel(hour, ampm) {
|
|
|
411
683
|
const period = hour < 12 ? "AM" : "PM";
|
|
412
684
|
return `${hour % 12 === 0 ? 12 : hour % 12} ${period}`;
|
|
413
685
|
}
|
|
414
|
-
function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, mode, renderEvent, onPress }) {
|
|
686
|
+
function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, mode, renderEvent, onPress, onLongPress }) {
|
|
415
687
|
const RenderEventComponent = renderEvent;
|
|
416
688
|
const boxHeight = useDerivedValue(() => Math.max(positioned.durationHours * cellHeight.value, MIN_EVENT_HEIGHT), [positioned.durationHours]);
|
|
417
689
|
const boxStyle = useAnimatedStyle(() => ({
|
|
@@ -423,6 +695,7 @@ function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, mode,
|
|
|
423
695
|
minHour
|
|
424
696
|
]);
|
|
425
697
|
const handlePress = () => onPress(positioned.event);
|
|
698
|
+
const handleLongPress = onLongPress ? () => onLongPress(positioned.event) : void 0;
|
|
426
699
|
return /* @__PURE__ */ jsx(Animated.View, {
|
|
427
700
|
style: [
|
|
428
701
|
styles.eventBox,
|
|
@@ -438,17 +711,21 @@ function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, mode,
|
|
|
438
711
|
boxHeight,
|
|
439
712
|
continuesBefore: positioned.continuesBefore,
|
|
440
713
|
continuesAfter: positioned.continuesAfter,
|
|
441
|
-
onPress: handlePress
|
|
714
|
+
onPress: handlePress,
|
|
715
|
+
onLongPress: handleLongPress
|
|
442
716
|
})
|
|
443
717
|
});
|
|
444
718
|
}
|
|
445
|
-
const HourRow = ({ hour, minHour, cellHeight, hourColumnWidth, label }) => {
|
|
719
|
+
const HourRow = ({ hour, minHour, cellHeight, hourColumnWidth, label, ampm, hourComponent }) => {
|
|
446
720
|
const theme = useCalendarTheme();
|
|
447
721
|
const animatedStyle = useAnimatedStyle(() => ({ top: (hour - minHour) * cellHeight.value }), [hour, minHour]);
|
|
448
722
|
return /* @__PURE__ */ jsxs(Animated.View, {
|
|
449
723
|
style: [styles.hourRow, animatedStyle],
|
|
450
724
|
pointerEvents: "none",
|
|
451
|
-
children: [/* @__PURE__ */ jsx(
|
|
725
|
+
children: [hourComponent ? /* @__PURE__ */ jsx(View, {
|
|
726
|
+
style: { width: hourColumnWidth },
|
|
727
|
+
children: hourComponent(hour, ampm)
|
|
728
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
452
729
|
style: [
|
|
453
730
|
theme.text.hourLabel,
|
|
454
731
|
styles.hourLabel,
|
|
@@ -462,6 +739,25 @@ const HourRow = ({ hour, minHour, cellHeight, hourColumnWidth, label }) => {
|
|
|
462
739
|
}), /* @__PURE__ */ jsx(View, { style: [styles.hourLine, { backgroundColor: theme.colors.gridLine }] })]
|
|
463
740
|
});
|
|
464
741
|
};
|
|
742
|
+
const TimeslotLine = ({ hour, minHour, fraction, cellHeight, hourColumnWidth }) => {
|
|
743
|
+
const theme = useCalendarTheme();
|
|
744
|
+
const animatedStyle = useAnimatedStyle(() => ({ top: (hour - minHour + fraction) * cellHeight.value }), [
|
|
745
|
+
hour,
|
|
746
|
+
minHour,
|
|
747
|
+
fraction
|
|
748
|
+
]);
|
|
749
|
+
return /* @__PURE__ */ jsx(Animated.View, {
|
|
750
|
+
style: [
|
|
751
|
+
styles.timeslotLine,
|
|
752
|
+
{
|
|
753
|
+
left: hourColumnWidth,
|
|
754
|
+
backgroundColor: theme.colors.gridLine
|
|
755
|
+
},
|
|
756
|
+
animatedStyle
|
|
757
|
+
],
|
|
758
|
+
pointerEvents: "none"
|
|
759
|
+
});
|
|
760
|
+
};
|
|
465
761
|
const NowIndicator = ({ cellHeight, nowHours, minHour, left, color }) => {
|
|
466
762
|
const animatedStyle = useAnimatedStyle(() => ({ top: (nowHours - minHour) * cellHeight.value }), [nowHours, minHour]);
|
|
467
763
|
return /* @__PURE__ */ jsx(Animated.View, {
|
|
@@ -476,7 +772,7 @@ const NowIndicator = ({ cellHeight, nowHours, minHour, left, color }) => {
|
|
|
476
772
|
pointerEvents: "none"
|
|
477
773
|
});
|
|
478
774
|
};
|
|
479
|
-
function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, committedCellHeight, scrollY, isActive, scrollOffsetMinutes, weekStartsOn, hourColumnWidth, minHour, maxHour, ampm, minHourHeight, maxHourHeight, showNowIndicator, renderEvent, keyExtractor, onPressEvent, onPressCell }) {
|
|
775
|
+
function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hourHeight, committedCellHeight, scrollY, isActive, scrollOffsetMinutes, weekStartsOn, weekEndsOn, hourColumnWidth, minHour, maxHour, ampm, timeslots, isRTL, showVerticalScrollIndicator, verticalScrollEnabled, hourComponent, calendarCellStyle, minHourHeight, maxHourHeight, showNowIndicator, renderEvent, keyExtractor, onPressEvent, onLongPressEvent, onPressCell, onLongPressCell }) {
|
|
480
776
|
const theme = useCalendarTheme();
|
|
481
777
|
const { width } = useWindowDimensions();
|
|
482
778
|
const scrollRef = useAnimatedRef();
|
|
@@ -487,24 +783,34 @@ function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, commit
|
|
|
487
783
|
useAnimatedReaction(() => scrollY.value, (current, previous) => {
|
|
488
784
|
if (!isActive && current !== previous) scrollTo(scrollRef, 0, current, false);
|
|
489
785
|
});
|
|
490
|
-
const days = useMemo(() => mode
|
|
786
|
+
const days = useMemo(() => getViewDays(mode, date, weekStartsOn, numberOfDays, isRTL, weekEndsOn), [
|
|
491
787
|
mode,
|
|
492
788
|
date,
|
|
493
|
-
weekStartsOn
|
|
789
|
+
weekStartsOn,
|
|
790
|
+
numberOfDays,
|
|
791
|
+
isRTL,
|
|
792
|
+
weekEndsOn
|
|
494
793
|
]);
|
|
495
794
|
const dayWidth = (width - hourColumnWidth) / days.length;
|
|
496
795
|
const dayLeft = (dayIndex) => hourColumnWidth + dayIndex * dayWidth;
|
|
497
796
|
const dayLayouts = useMemo(() => days.map((day) => layoutDayEvents(events, day)), [days, events]);
|
|
498
|
-
const
|
|
499
|
-
if (!onPressCell) return;
|
|
797
|
+
const cellDateFromTouch = (event) => {
|
|
500
798
|
const { locationX, locationY } = event.nativeEvent;
|
|
501
799
|
const day = days[days.length === 1 ? 0 : Math.floor(locationX / dayWidth)];
|
|
502
|
-
if (!day) return;
|
|
800
|
+
if (!day) return null;
|
|
503
801
|
const minutes = Math.round((minHour + locationY / heightSource.value) * MINUTES_PER_HOUR);
|
|
504
802
|
const pressed = new Date(day);
|
|
505
803
|
pressed.setHours(0, 0, 0, 0);
|
|
506
804
|
pressed.setMinutes(minutes);
|
|
507
|
-
|
|
805
|
+
return pressed;
|
|
806
|
+
};
|
|
807
|
+
const handleBackgroundPress = (event) => {
|
|
808
|
+
const date = onPressCell && cellDateFromTouch(event);
|
|
809
|
+
if (date) onPressCell?.(date);
|
|
810
|
+
};
|
|
811
|
+
const handleBackgroundLongPress = (event) => {
|
|
812
|
+
const date = onLongPressCell && cellDateFromTouch(event);
|
|
813
|
+
if (date) onLongPressCell?.(date);
|
|
508
814
|
};
|
|
509
815
|
const hoursRange = useMemo(() => Array.from({ length: maxHour - minHour }, (_, index) => minHour + index), [minHour, maxHour]);
|
|
510
816
|
const now = useNow(showNowIndicator && isActive);
|
|
@@ -533,13 +839,24 @@ function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, commit
|
|
|
533
839
|
minHourHeight,
|
|
534
840
|
maxHourHeight
|
|
535
841
|
]);
|
|
536
|
-
return /* @__PURE__ */
|
|
842
|
+
return /* @__PURE__ */ jsxs(View, {
|
|
537
843
|
style: styles.container,
|
|
538
|
-
children: /* @__PURE__ */ jsx(
|
|
844
|
+
children: [/* @__PURE__ */ jsx(AllDayLane, {
|
|
845
|
+
days,
|
|
846
|
+
events,
|
|
847
|
+
mode,
|
|
848
|
+
hourColumnWidth,
|
|
849
|
+
dayWidth,
|
|
850
|
+
renderEvent,
|
|
851
|
+
keyExtractor,
|
|
852
|
+
onPressEvent,
|
|
853
|
+
onLongPressEvent
|
|
854
|
+
}), /* @__PURE__ */ jsx(GestureDetector, {
|
|
539
855
|
gesture: zoomGesture,
|
|
540
856
|
children: /* @__PURE__ */ jsx(Animated.ScrollView, {
|
|
541
857
|
ref: scrollRef,
|
|
542
|
-
showsVerticalScrollIndicator:
|
|
858
|
+
showsVerticalScrollIndicator: showVerticalScrollIndicator,
|
|
859
|
+
scrollEnabled: verticalScrollEnabled,
|
|
543
860
|
onScroll: scrollHandler,
|
|
544
861
|
scrollEventThrottle: 16,
|
|
545
862
|
contentContainerStyle: { paddingTop: HOUR_LABEL_TOP_INSET },
|
|
@@ -550,9 +867,10 @@ function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, commit
|
|
|
550
867
|
children: /* @__PURE__ */ jsxs(Animated.View, {
|
|
551
868
|
style: [styles.content, fullHeightStyle],
|
|
552
869
|
children: [
|
|
553
|
-
onPressCell ? /* @__PURE__ */ jsx(Pressable, {
|
|
870
|
+
onPressCell || onLongPressCell ? /* @__PURE__ */ jsx(Pressable, {
|
|
554
871
|
style: [styles.cellPressLayer, { left: hourColumnWidth }],
|
|
555
|
-
onPress: handleBackgroundPress,
|
|
872
|
+
onPress: onPressCell ? handleBackgroundPress : void 0,
|
|
873
|
+
onLongPress: onLongPressCell ? handleBackgroundLongPress : void 0,
|
|
556
874
|
importantForAccessibility: "no",
|
|
557
875
|
accessibilityElementsHidden: true
|
|
558
876
|
}) : null,
|
|
@@ -568,6 +886,21 @@ function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, commit
|
|
|
568
886
|
],
|
|
569
887
|
pointerEvents: "none"
|
|
570
888
|
}, `weekend-${day.toISOString()}`) : null),
|
|
889
|
+
calendarCellStyle ? days.map((day, dayIndex) => {
|
|
890
|
+
const cellStyle = calendarCellStyle(day);
|
|
891
|
+
return cellStyle ? /* @__PURE__ */ jsx(Animated.View, {
|
|
892
|
+
style: [
|
|
893
|
+
styles.weekendColumn,
|
|
894
|
+
{
|
|
895
|
+
left: dayLeft(dayIndex),
|
|
896
|
+
width: dayWidth
|
|
897
|
+
},
|
|
898
|
+
cellStyle,
|
|
899
|
+
fullHeightStyle
|
|
900
|
+
],
|
|
901
|
+
pointerEvents: "none"
|
|
902
|
+
}, `cell-${day.toISOString()}`) : null;
|
|
903
|
+
}) : null,
|
|
571
904
|
days.map((day, dayIndex) => /* @__PURE__ */ jsx(Animated.View, {
|
|
572
905
|
style: [
|
|
573
906
|
styles.daySeparator,
|
|
@@ -582,8 +915,17 @@ function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, commit
|
|
|
582
915
|
minHour,
|
|
583
916
|
cellHeight: heightSource,
|
|
584
917
|
hourColumnWidth,
|
|
585
|
-
label: formatHourLabel(hour, ampm)
|
|
918
|
+
label: formatHourLabel(hour, ampm),
|
|
919
|
+
ampm,
|
|
920
|
+
hourComponent
|
|
586
921
|
}, hour)),
|
|
922
|
+
timeslots > 1 ? hoursRange.flatMap((hour) => Array.from({ length: timeslots - 1 }, (_, i) => /* @__PURE__ */ jsx(TimeslotLine, {
|
|
923
|
+
hour,
|
|
924
|
+
minHour,
|
|
925
|
+
fraction: (i + 1) / timeslots,
|
|
926
|
+
cellHeight: heightSource,
|
|
927
|
+
hourColumnWidth
|
|
928
|
+
}, `slot-${hour}-${i}`))) : null,
|
|
587
929
|
dayLayouts.flatMap((layout, dayIndex) => layout.filter((p) => p.startHours < maxHour && p.startHours + p.durationHours > minHour).map((positioned, eventIndex) => {
|
|
588
930
|
const columnWidth = dayWidth / positioned.columns;
|
|
589
931
|
return /* @__PURE__ */ jsx(AnimatedEventBox, {
|
|
@@ -594,8 +936,9 @@ function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, commit
|
|
|
594
936
|
width: columnWidth,
|
|
595
937
|
mode,
|
|
596
938
|
renderEvent,
|
|
597
|
-
onPress: onPressEvent
|
|
598
|
-
|
|
939
|
+
onPress: onPressEvent,
|
|
940
|
+
onLongPress: onLongPressEvent
|
|
941
|
+
}, `${dayIndex}:${keyExtractor(positioned.event, eventIndex)}`);
|
|
599
942
|
})),
|
|
600
943
|
showNowIndicator && nowDayIndex >= 0 && nowInWindow ? /* @__PURE__ */ jsx(NowIndicator, {
|
|
601
944
|
cellHeight: heightSource,
|
|
@@ -607,40 +950,48 @@ function TimetablePageInner({ mode, date, events, cellHeight, hourHeight, commit
|
|
|
607
950
|
]
|
|
608
951
|
})
|
|
609
952
|
})
|
|
610
|
-
})
|
|
953
|
+
})]
|
|
611
954
|
});
|
|
612
955
|
}
|
|
613
956
|
const TimetablePage = memo(TimetablePageInner);
|
|
614
|
-
function TimeGridInner({ mode, date, events, cellHeight, hourHeight = 64, weekStartsOn, renderEvent, keyExtractor, scrollOffsetMinutes = 0, hourColumnWidth = DEFAULT_HOUR_COLUMN_WIDTH, minHour = 0, maxHour = HOURS_PER_DAY, ampm = false, minHourHeight = DEFAULT_MIN_HOUR_HEIGHT, maxHourHeight = DEFAULT_MAX_HOUR_HEIGHT, showNowIndicator = true, locale, freeSwipe = false, onPressEvent, onPressCell, onChangeDate, renderHeader }) {
|
|
957
|
+
function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellHeight, hourHeight = 64, weekStartsOn, renderEvent, keyExtractor, scrollOffsetMinutes = 0, hourColumnWidth: hourColumnWidthProp = DEFAULT_HOUR_COLUMN_WIDTH, hideHours = false, timeslots = 1, calendarCellStyle, showWeekNumber = false, headerComponent, minHour = 0, maxHour = HOURS_PER_DAY, ampm = false, isRTL = false, minHourHeight = DEFAULT_MIN_HOUR_HEIGHT, maxHourHeight = DEFAULT_MAX_HOUR_HEIGHT, showNowIndicator = true, locale, freeSwipe = false, swipeEnabled = true, showVerticalScrollIndicator = true, verticalScrollEnabled = true, weekNumberPrefix = "W", hourComponent, activeDate, resetPageOnPressCell = false, onPressEvent, onLongPressEvent, onPressCell, onLongPressCell, onPressDateHeader, onChangeDate, renderHeader }) {
|
|
615
958
|
const clampedMinHour = Math.max(0, Math.min(minHour, HOURS_PER_DAY - 1));
|
|
616
959
|
const clampedMaxHour = Math.max(clampedMinHour + 1, Math.min(maxHour, HOURS_PER_DAY));
|
|
960
|
+
const hourColumnWidth = hideHours ? 0 : hourColumnWidthProp;
|
|
617
961
|
const { width, height } = useWindowDimensions();
|
|
618
962
|
const listRef = useRef(null);
|
|
619
963
|
const [pageHeight, setPageHeight] = useState(height);
|
|
620
|
-
const
|
|
964
|
+
const [measured, setMeasured] = useState(false);
|
|
965
|
+
const weekAnchored = mode === "week" || mode === "custom" && weekEndsOn != null;
|
|
966
|
+
const step = weekAnchored ? 7 : viewDayCount(mode, numberOfDays);
|
|
621
967
|
const scrollY = useSharedValue(Math.max(0, scrollOffsetMinutes / MINUTES_PER_HOUR - clampedMinHour) * hourHeight);
|
|
622
968
|
const committedCellHeight = useSharedValue(hourHeight);
|
|
623
969
|
const [anchorDate] = useState(date);
|
|
624
|
-
const anchor = useMemo(() =>
|
|
625
|
-
|
|
970
|
+
const anchor = useMemo(() => weekAnchored ? startOfWeek(anchorDate, { weekStartsOn }) : startOfDay(anchorDate), [
|
|
971
|
+
weekAnchored,
|
|
626
972
|
anchorDate,
|
|
627
973
|
weekStartsOn
|
|
628
974
|
]);
|
|
629
975
|
const pageDates = useMemo(() => Array.from({ length: 361 }, (_, i) => addDays(anchor, (i - PAGE_WINDOW) * step)), [anchor, step]);
|
|
630
976
|
const activeIndex = useCallback((target) => {
|
|
631
|
-
const aligned =
|
|
632
|
-
return Math.
|
|
977
|
+
const aligned = weekAnchored ? startOfWeek(target, { weekStartsOn }) : startOfDay(target);
|
|
978
|
+
return Math.floor(differenceInCalendarDays(aligned, anchor) / step) + PAGE_WINDOW;
|
|
633
979
|
}, [
|
|
634
980
|
anchor,
|
|
635
|
-
|
|
981
|
+
weekAnchored,
|
|
636
982
|
step,
|
|
637
983
|
weekStartsOn
|
|
638
984
|
])(date);
|
|
639
985
|
const viewedIndexRef = useRef(activeIndex);
|
|
640
|
-
const headerDays = useMemo(() => mode
|
|
986
|
+
const headerDays = useMemo(() => getViewDays(mode, pageDates[activeIndex] ?? date, weekStartsOn, numberOfDays, isRTL, weekEndsOn), [
|
|
641
987
|
mode,
|
|
988
|
+
pageDates,
|
|
989
|
+
activeIndex,
|
|
642
990
|
date,
|
|
643
|
-
weekStartsOn
|
|
991
|
+
weekStartsOn,
|
|
992
|
+
numberOfDays,
|
|
993
|
+
isRTL,
|
|
994
|
+
weekEndsOn
|
|
644
995
|
]);
|
|
645
996
|
const handleViewableItemsChanged = useCallback((info) => {
|
|
646
997
|
const settled = info.viewableItems.find((token) => token.isViewable);
|
|
@@ -656,6 +1007,21 @@ function TimeGridInner({ mode, date, events, cellHeight, hourHeight = 64, weekSt
|
|
|
656
1007
|
animated: false
|
|
657
1008
|
});
|
|
658
1009
|
}, [activeIndex]);
|
|
1010
|
+
const handlePressCell = useMemo(() => {
|
|
1011
|
+
if (!onPressCell) return void 0;
|
|
1012
|
+
if (!resetPageOnPressCell) return onPressCell;
|
|
1013
|
+
return (cellDate) => {
|
|
1014
|
+
onPressCell(cellDate);
|
|
1015
|
+
listRef.current?.scrollToIndex({
|
|
1016
|
+
index: activeIndex,
|
|
1017
|
+
animated: true
|
|
1018
|
+
});
|
|
1019
|
+
};
|
|
1020
|
+
}, [
|
|
1021
|
+
onPressCell,
|
|
1022
|
+
resetPageOnPressCell,
|
|
1023
|
+
activeIndex
|
|
1024
|
+
]);
|
|
659
1025
|
const snapToIndices = useMemo(() => pageDates.map((_, index) => index), [pageDates]);
|
|
660
1026
|
const keyExtractorList = useCallback((item) => item.toISOString(), []);
|
|
661
1027
|
const getFixedItemSize = useCallback(() => width, [width]);
|
|
@@ -666,6 +1032,7 @@ function TimeGridInner({ mode, date, events, cellHeight, hourHeight = 64, weekSt
|
|
|
666
1032
|
},
|
|
667
1033
|
children: /* @__PURE__ */ jsx(TimetablePage, {
|
|
668
1034
|
mode,
|
|
1035
|
+
numberOfDays,
|
|
669
1036
|
date: item,
|
|
670
1037
|
events,
|
|
671
1038
|
cellHeight,
|
|
@@ -675,22 +1042,32 @@ function TimeGridInner({ mode, date, events, cellHeight, hourHeight = 64, weekSt
|
|
|
675
1042
|
isActive: index === activeIndex,
|
|
676
1043
|
scrollOffsetMinutes,
|
|
677
1044
|
weekStartsOn,
|
|
1045
|
+
weekEndsOn,
|
|
678
1046
|
hourColumnWidth,
|
|
679
1047
|
minHour: clampedMinHour,
|
|
680
1048
|
maxHour: clampedMaxHour,
|
|
681
1049
|
ampm,
|
|
1050
|
+
timeslots,
|
|
1051
|
+
isRTL,
|
|
1052
|
+
showVerticalScrollIndicator,
|
|
1053
|
+
verticalScrollEnabled,
|
|
1054
|
+
hourComponent,
|
|
1055
|
+
calendarCellStyle,
|
|
682
1056
|
minHourHeight,
|
|
683
1057
|
maxHourHeight,
|
|
684
1058
|
showNowIndicator,
|
|
685
1059
|
renderEvent,
|
|
686
1060
|
keyExtractor,
|
|
687
1061
|
onPressEvent,
|
|
688
|
-
|
|
1062
|
+
onLongPressEvent,
|
|
1063
|
+
onPressCell: handlePressCell,
|
|
1064
|
+
onLongPressCell
|
|
689
1065
|
})
|
|
690
1066
|
}), [
|
|
691
1067
|
width,
|
|
692
1068
|
pageHeight,
|
|
693
1069
|
mode,
|
|
1070
|
+
numberOfDays,
|
|
694
1071
|
events,
|
|
695
1072
|
cellHeight,
|
|
696
1073
|
hourHeight,
|
|
@@ -699,79 +1076,117 @@ function TimeGridInner({ mode, date, events, cellHeight, hourHeight = 64, weekSt
|
|
|
699
1076
|
activeIndex,
|
|
700
1077
|
scrollOffsetMinutes,
|
|
701
1078
|
weekStartsOn,
|
|
1079
|
+
weekEndsOn,
|
|
702
1080
|
hourColumnWidth,
|
|
703
1081
|
clampedMinHour,
|
|
704
1082
|
clampedMaxHour,
|
|
705
1083
|
ampm,
|
|
1084
|
+
timeslots,
|
|
1085
|
+
isRTL,
|
|
1086
|
+
showVerticalScrollIndicator,
|
|
1087
|
+
verticalScrollEnabled,
|
|
1088
|
+
hourComponent,
|
|
1089
|
+
calendarCellStyle,
|
|
706
1090
|
minHourHeight,
|
|
707
1091
|
maxHourHeight,
|
|
708
1092
|
showNowIndicator,
|
|
709
1093
|
renderEvent,
|
|
710
1094
|
keyExtractor,
|
|
711
1095
|
onPressEvent,
|
|
712
|
-
|
|
1096
|
+
onLongPressEvent,
|
|
1097
|
+
handlePressCell,
|
|
1098
|
+
onLongPressCell
|
|
713
1099
|
]);
|
|
714
1100
|
return /* @__PURE__ */ jsxs(View, {
|
|
715
1101
|
style: styles.container,
|
|
716
|
-
children: [
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
1102
|
+
children: [
|
|
1103
|
+
renderHeader ? renderHeader(headerDays) : /* @__PURE__ */ jsx(DefaultHeader, {
|
|
1104
|
+
days: headerDays,
|
|
1105
|
+
mode,
|
|
1106
|
+
width,
|
|
1107
|
+
hourColumnWidth,
|
|
1108
|
+
showWeekNumber,
|
|
1109
|
+
weekNumberPrefix,
|
|
1110
|
+
locale,
|
|
1111
|
+
activeDate,
|
|
1112
|
+
onPressDateHeader
|
|
1113
|
+
}),
|
|
1114
|
+
headerComponent,
|
|
1115
|
+
/* @__PURE__ */ jsx(View, {
|
|
1116
|
+
style: styles.pager,
|
|
1117
|
+
onLayout: (event) => {
|
|
1118
|
+
setPageHeight(event.nativeEvent.layout.height);
|
|
1119
|
+
setMeasured(true);
|
|
1120
|
+
},
|
|
1121
|
+
children: /* @__PURE__ */ jsx(LegendList, {
|
|
1122
|
+
ref: listRef,
|
|
1123
|
+
style: styles.pagerList,
|
|
1124
|
+
data: pageDates,
|
|
1125
|
+
horizontal: true,
|
|
1126
|
+
recycleItems: false,
|
|
1127
|
+
keyExtractor: keyExtractorList,
|
|
1128
|
+
getFixedItemSize,
|
|
1129
|
+
scrollEnabled: swipeEnabled,
|
|
1130
|
+
pagingEnabled: !freeSwipe,
|
|
1131
|
+
snapToIndices: freeSwipe ? snapToIndices : void 0,
|
|
1132
|
+
initialScrollIndex: activeIndex,
|
|
1133
|
+
showsHorizontalScrollIndicator: false,
|
|
1134
|
+
viewabilityConfig: PAGE_VIEWABILITY,
|
|
1135
|
+
onViewableItemsChanged: handleViewableItemsChanged,
|
|
1136
|
+
renderItem
|
|
1137
|
+
}, measured ? "grid" : "grid-seed")
|
|
1138
|
+
})
|
|
1139
|
+
]
|
|
742
1140
|
});
|
|
743
1141
|
}
|
|
744
1142
|
const TimeGrid = memo(TimeGridInner);
|
|
745
|
-
const DefaultHeader = ({ days, mode, width, hourColumnWidth, locale }) => {
|
|
746
|
-
const
|
|
1143
|
+
const DefaultHeader = ({ days, mode, width, hourColumnWidth, showWeekNumber, weekNumberPrefix = "W", locale, activeDate, onPressDateHeader }) => {
|
|
1144
|
+
const theme = useCalendarTheme();
|
|
1145
|
+
const dayWidth = (width - hourColumnWidth) / days.length;
|
|
747
1146
|
return /* @__PURE__ */ jsxs(View, {
|
|
748
1147
|
style: styles.headerRow,
|
|
749
|
-
children: [
|
|
1148
|
+
children: [/* @__PURE__ */ jsx(View, {
|
|
1149
|
+
style: [styles.weekNumberGutter, { width: hourColumnWidth }],
|
|
1150
|
+
children: showWeekNumber && hourColumnWidth > 0 && days[0] ? /* @__PURE__ */ jsx(Text, {
|
|
1151
|
+
style: [theme.text.hourLabel, { color: theme.colors.textMuted }],
|
|
1152
|
+
allowFontScaling: false,
|
|
1153
|
+
children: `${weekNumberPrefix}${getISOWeek(days[0])}`
|
|
1154
|
+
}) : null
|
|
1155
|
+
}), days.map((day) => /* @__PURE__ */ jsx(DayHeader, {
|
|
750
1156
|
day,
|
|
751
1157
|
mode,
|
|
752
1158
|
width: dayWidth,
|
|
753
|
-
locale
|
|
1159
|
+
locale,
|
|
1160
|
+
activeDate,
|
|
1161
|
+
onPressDateHeader
|
|
754
1162
|
}, day.toISOString()))]
|
|
755
1163
|
});
|
|
756
1164
|
};
|
|
757
|
-
const DayHeader = ({ day, mode, width, locale }) => {
|
|
1165
|
+
const DayHeader = ({ day, mode, width, locale, activeDate, onPressDateHeader }) => {
|
|
758
1166
|
const theme = useCalendarTheme();
|
|
759
1167
|
const isToday = getIsToday(day);
|
|
1168
|
+
const isHighlighted = activeDate ? isSameCalendarDay(day, activeDate) : isToday;
|
|
760
1169
|
const badgeSize = mode === "day" ? 44 : 32;
|
|
761
|
-
return /* @__PURE__ */ jsxs(
|
|
1170
|
+
return /* @__PURE__ */ jsxs(Pressable, {
|
|
762
1171
|
style: [styles.dayHeader, {
|
|
763
1172
|
width,
|
|
764
1173
|
gap: mode === "day" ? 4 : 2
|
|
765
1174
|
}],
|
|
1175
|
+
onPress: onPressDateHeader ? () => onPressDateHeader(day) : void 0,
|
|
1176
|
+
disabled: !onPressDateHeader,
|
|
1177
|
+
accessibilityRole: onPressDateHeader ? "button" : void 0,
|
|
766
1178
|
children: [/* @__PURE__ */ jsx(View, {
|
|
767
|
-
style: [
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
1179
|
+
style: [
|
|
1180
|
+
styles.dayHeaderBadge,
|
|
1181
|
+
{
|
|
1182
|
+
width: badgeSize,
|
|
1183
|
+
height: badgeSize,
|
|
1184
|
+
borderRadius: 999
|
|
1185
|
+
},
|
|
1186
|
+
isHighlighted && { backgroundColor: theme.colors.todayBackground }
|
|
1187
|
+
],
|
|
773
1188
|
children: /* @__PURE__ */ jsx(Text, {
|
|
774
|
-
style: [theme.text.dayNumber, { color:
|
|
1189
|
+
style: [theme.text.dayNumber, { color: isHighlighted ? theme.colors.todayText : theme.colors.text }],
|
|
775
1190
|
allowFontScaling: false,
|
|
776
1191
|
...isToday && { accessibilityLabel: `Today, ${day.getDate()}` },
|
|
777
1192
|
children: day.getDate()
|
|
@@ -779,7 +1194,7 @@ const DayHeader = ({ day, mode, width, locale }) => {
|
|
|
779
1194
|
}), /* @__PURE__ */ jsx(Text, {
|
|
780
1195
|
style: [theme.text.weekday, { color: theme.colors.text }],
|
|
781
1196
|
allowFontScaling: false,
|
|
782
|
-
children: day
|
|
1197
|
+
children: format(day, "EEE", { locale })
|
|
783
1198
|
})]
|
|
784
1199
|
});
|
|
785
1200
|
};
|
|
@@ -792,6 +1207,10 @@ const styles = StyleSheet.create({
|
|
|
792
1207
|
alignItems: "center",
|
|
793
1208
|
paddingBottom: 8
|
|
794
1209
|
},
|
|
1210
|
+
weekNumberGutter: {
|
|
1211
|
+
alignItems: "center",
|
|
1212
|
+
justifyContent: "flex-end"
|
|
1213
|
+
},
|
|
795
1214
|
dayHeader: { alignItems: "center" },
|
|
796
1215
|
dayHeaderBadge: {
|
|
797
1216
|
justifyContent: "center",
|
|
@@ -831,6 +1250,12 @@ const styles = StyleSheet.create({
|
|
|
831
1250
|
flex: 1,
|
|
832
1251
|
height: StyleSheet.hairlineWidth
|
|
833
1252
|
},
|
|
1253
|
+
timeslotLine: {
|
|
1254
|
+
position: "absolute",
|
|
1255
|
+
right: 0,
|
|
1256
|
+
height: StyleSheet.hairlineWidth,
|
|
1257
|
+
opacity: .5
|
|
1258
|
+
},
|
|
834
1259
|
eventBox: {
|
|
835
1260
|
position: "absolute",
|
|
836
1261
|
overflow: "hidden"
|
|
@@ -844,9 +1269,50 @@ const styles = StyleSheet.create({
|
|
|
844
1269
|
//#endregion
|
|
845
1270
|
//#region src/components/Calendar.tsx
|
|
846
1271
|
const defaultKeyExtractor = (event) => `${event.start.toISOString()}|${event.end.toISOString()}|${event.title ?? ""}`;
|
|
847
|
-
function
|
|
1272
|
+
function visibleRange(mode, date, weekStartsOn, numberOfDays, weekEndsOn) {
|
|
1273
|
+
if (mode === "month") return [startOfWeek(startOfMonth(date), { weekStartsOn }), endOfWeek(endOfMonth(date), { weekStartsOn })];
|
|
1274
|
+
const days = getViewDays(mode, date, weekStartsOn, numberOfDays, false, weekEndsOn);
|
|
1275
|
+
return [startOfDay(days[0]), endOfDay(days[days.length - 1])];
|
|
1276
|
+
}
|
|
1277
|
+
function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPressEvent, onLongPressEvent, onPressDay, onLongPressDay, onPressMore, onPressCell, resetPageOnPressCell, onLongPressCell, onPressDateHeader, maxVisibleEventCount = 2, sortedMonthView, moreLabel, showAdjacentMonths, disableMonthEventCellPress, weekStartsOn = 0, numberOfDays, weekEndsOn, renderEvent = DefaultEvent, eventCellStyle, calendarCellStyle, keyExtractor = defaultKeyExtractor, theme, cellHeight: cellHeightProp, hourHeight = 64, minHourHeight, maxHourHeight, hourColumnWidth, hideHours, timeslots, showWeekNumber, weekNumberPrefix, hourComponent, showSixWeeks, swipeEnabled, showVerticalScrollIndicator, verticalScrollEnabled, headerComponent, minHour, maxHour, ampm, showTime, scrollOffsetMinutes, showNowIndicator, locale, activeDate, isRTL, freeSwipe, renderTimeGridHeader, renderHeaderForMonthView, itemSeparatorComponent }) {
|
|
848
1278
|
const mergedTheme = useMemo(() => mergeTheme(theme), [theme]);
|
|
849
1279
|
const internalCellHeight = useSharedValue(hourHeight);
|
|
1280
|
+
const cellHeight = cellHeightProp ?? internalCellHeight;
|
|
1281
|
+
const handlePressEvent = useCallback((event) => {
|
|
1282
|
+
if (!event.disabled) onPressEvent(event);
|
|
1283
|
+
}, [onPressEvent]);
|
|
1284
|
+
const handleLongPressEvent = useMemo(() => onLongPressEvent ? (event) => {
|
|
1285
|
+
if (!event.disabled) onLongPressEvent(event);
|
|
1286
|
+
} : void 0, [onLongPressEvent]);
|
|
1287
|
+
const handleChangeDate = useCallback((next) => {
|
|
1288
|
+
onChangeDate(next);
|
|
1289
|
+
onChangeDateRange?.(visibleRange(mode, next, weekStartsOn, numberOfDays ?? 1, weekEndsOn));
|
|
1290
|
+
}, [
|
|
1291
|
+
onChangeDate,
|
|
1292
|
+
onChangeDateRange,
|
|
1293
|
+
mode,
|
|
1294
|
+
weekStartsOn,
|
|
1295
|
+
numberOfDays,
|
|
1296
|
+
weekEndsOn
|
|
1297
|
+
]);
|
|
1298
|
+
const resolvedRenderEvent = useMemo(() => {
|
|
1299
|
+
if (eventCellStyle == null && ampm == null && showTime == null) return renderEvent;
|
|
1300
|
+
const Base = renderEvent;
|
|
1301
|
+
return function StyledEvent(props) {
|
|
1302
|
+
const cellStyle = typeof eventCellStyle === "function" ? eventCellStyle(props.event) : eventCellStyle;
|
|
1303
|
+
return /* @__PURE__ */ jsx(Base, {
|
|
1304
|
+
...props,
|
|
1305
|
+
cellStyle,
|
|
1306
|
+
ampm,
|
|
1307
|
+
showTime
|
|
1308
|
+
});
|
|
1309
|
+
};
|
|
1310
|
+
}, [
|
|
1311
|
+
renderEvent,
|
|
1312
|
+
eventCellStyle,
|
|
1313
|
+
ampm,
|
|
1314
|
+
showTime
|
|
1315
|
+
]);
|
|
850
1316
|
return /* @__PURE__ */ jsx(CalendarThemeProvider, {
|
|
851
1317
|
value: mergedTheme,
|
|
852
1318
|
children: mode === "month" ? /* @__PURE__ */ jsx(MonthPager, {
|
|
@@ -854,24 +1320,58 @@ function Calendar({ events, mode, date, onChangeDate, onPressEvent, onPressDay,
|
|
|
854
1320
|
events,
|
|
855
1321
|
maxVisibleEventCount,
|
|
856
1322
|
weekStartsOn,
|
|
857
|
-
|
|
1323
|
+
locale,
|
|
1324
|
+
sortedMonthView,
|
|
1325
|
+
moreLabel,
|
|
1326
|
+
showAdjacentMonths,
|
|
1327
|
+
disableMonthEventCellPress,
|
|
1328
|
+
isRTL,
|
|
1329
|
+
showSixWeeks,
|
|
1330
|
+
activeDate,
|
|
1331
|
+
renderHeaderForMonthView,
|
|
1332
|
+
calendarCellStyle,
|
|
1333
|
+
renderEvent: resolvedRenderEvent,
|
|
858
1334
|
keyExtractor,
|
|
859
1335
|
onPressDay,
|
|
860
|
-
|
|
1336
|
+
onLongPressDay,
|
|
1337
|
+
onPressEvent: handlePressEvent,
|
|
1338
|
+
onLongPressEvent: handleLongPressEvent,
|
|
861
1339
|
onPressMore,
|
|
862
|
-
onChangeDate,
|
|
863
|
-
freeSwipe
|
|
1340
|
+
onChangeDate: handleChangeDate,
|
|
1341
|
+
freeSwipe,
|
|
1342
|
+
swipeEnabled
|
|
1343
|
+
}) : mode === "schedule" ? /* @__PURE__ */ jsx(Agenda, {
|
|
1344
|
+
events,
|
|
1345
|
+
locale,
|
|
1346
|
+
renderEvent: resolvedRenderEvent,
|
|
1347
|
+
keyExtractor,
|
|
1348
|
+
onPressEvent: handlePressEvent,
|
|
1349
|
+
onLongPressEvent: handleLongPressEvent,
|
|
1350
|
+
onPressDay,
|
|
1351
|
+
activeDate,
|
|
1352
|
+
itemSeparatorComponent
|
|
864
1353
|
}) : /* @__PURE__ */ jsx(TimeGrid, {
|
|
865
1354
|
mode,
|
|
1355
|
+
numberOfDays,
|
|
1356
|
+
weekEndsOn,
|
|
866
1357
|
date,
|
|
867
1358
|
events,
|
|
868
|
-
cellHeight
|
|
1359
|
+
cellHeight,
|
|
869
1360
|
hourHeight,
|
|
870
1361
|
weekStartsOn,
|
|
871
|
-
renderEvent,
|
|
1362
|
+
renderEvent: resolvedRenderEvent,
|
|
872
1363
|
keyExtractor,
|
|
873
1364
|
scrollOffsetMinutes,
|
|
874
1365
|
hourColumnWidth,
|
|
1366
|
+
hideHours,
|
|
1367
|
+
timeslots,
|
|
1368
|
+
calendarCellStyle,
|
|
1369
|
+
showWeekNumber,
|
|
1370
|
+
weekNumberPrefix,
|
|
1371
|
+
hourComponent,
|
|
1372
|
+
showVerticalScrollIndicator,
|
|
1373
|
+
verticalScrollEnabled,
|
|
1374
|
+
headerComponent,
|
|
875
1375
|
minHour,
|
|
876
1376
|
maxHour,
|
|
877
1377
|
ampm,
|
|
@@ -879,13 +1379,20 @@ function Calendar({ events, mode, date, onChangeDate, onPressEvent, onPressDay,
|
|
|
879
1379
|
maxHourHeight,
|
|
880
1380
|
showNowIndicator,
|
|
881
1381
|
locale,
|
|
1382
|
+
activeDate,
|
|
1383
|
+
isRTL,
|
|
882
1384
|
freeSwipe,
|
|
883
|
-
|
|
1385
|
+
swipeEnabled,
|
|
1386
|
+
onPressEvent: handlePressEvent,
|
|
1387
|
+
onLongPressEvent: handleLongPressEvent,
|
|
884
1388
|
onPressCell,
|
|
885
|
-
|
|
1389
|
+
resetPageOnPressCell,
|
|
1390
|
+
onLongPressCell,
|
|
1391
|
+
onPressDateHeader,
|
|
1392
|
+
onChangeDate: handleChangeDate,
|
|
886
1393
|
renderHeader: renderTimeGridHeader
|
|
887
1394
|
})
|
|
888
1395
|
});
|
|
889
1396
|
}
|
|
890
1397
|
//#endregion
|
|
891
|
-
export { Calendar, CalendarThemeProvider, DEFAULT_HOUR_HEIGHT, DefaultEvent, MonthPager, MonthView, TimeGrid, defaultTheme, getIsToday, getWeekDays, isSameCalendarDay, isWeekend, layoutDayEvents, mergeTheme, minutesIntoDay, useCalendarTheme };
|
|
1398
|
+
export { Agenda, Calendar, CalendarThemeProvider, DEFAULT_HOUR_HEIGHT, DefaultEvent, MonthPager, MonthView, TimeGrid, defaultTheme, getIsToday, getWeekDays, isAllDayEvent, isSameCalendarDay, isWeekend, layoutDayEvents, mergeTheme, minutesIntoDay, useCalendarTheme };
|