@super-calendar/native 2.3.2 → 2.4.0

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/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { a as withEventAccessibilityLabel, c as darkTheme, d as useCalendarTheme, i as MonthView, l as defaultTheme, n as DefaultMonthEvent, o as useWebPagerKeys, r as MonthPager, s as CalendarThemeProvider, t as MonthList, u as mergeTheme } from "./MonthList-BidXJMfm.mjs";
2
- import { addDays, differenceInCalendarDays, endOfDay, endOfMonth, endOfWeek, format, getHours, getISOWeek, getMinutes, isSameDay, startOfDay, startOfMonth, startOfWeek } from "date-fns";
1
+ import { a as withEventAccessibilityLabel, c as createSlots, d as darkTheme, f as defaultTheme, i as MonthView, l as useSlots, m as useCalendarTheme, n as DefaultMonthEvent, o as useWebPagerKeys, p as mergeTheme, r as MonthPager, s as SlotStylesProvider, t as MonthList, u as CalendarThemeProvider } from "./MonthList-zPLklHAY.mjs";
2
+ import { addDays, addMonths, addWeeks, differenceInCalendarDays, endOfDay, endOfMonth, endOfWeek, format, getHours, getISOWeek, getMinutes, isSameDay, startOfDay, startOfMonth, startOfWeek } from "date-fns";
3
3
  import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
4
- import Animated, { runOnJS, scrollTo, useAnimatedReaction, useAnimatedRef, useAnimatedScrollHandler, useAnimatedStyle, useDerivedValue, useSharedValue } from "react-native-reanimated";
5
- import { buildMonthGrid, buildMonthWeeks, cellRangeFromDrag, closedHourBands, daySelectionState, eventAccessibilityLabel, eventChipLayout, eventTimeLabel, eventsInTimeZone, expandRecurringEvents, formatHour, getIsToday, getIsToday as getIsToday$1, getViewDays, getViewDays as getViewDays$1, getWeekDays, isAllDayEvent, isAllDayEvent as isAllDayEvent$1, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isSameCalendarDay as isSameCalendarDay$1, isWeekend, isWeekend as isWeekend$1, isWithinDateRange, layoutDayEvents, layoutDayEvents as layoutDayEvents$1, minutesIntoDay, nextDateRange, resolveDraggedBounds, snapDeltaMinutes, titleEllipsizeMode, titleNumberOfLines, toZonedTime, useDateRange, useMonthGrid, viewDayCount, weekdayFormatToken, weekdayFormatToken as weekdayFormatToken$1 } from "@super-calendar/core";
4
+ import Animated, { runOnJS, scrollTo, useAnimatedReaction, useAnimatedRef, useAnimatedScrollHandler, useAnimatedStyle, useDerivedValue, useReducedMotion, useSharedValue } from "react-native-reanimated";
5
+ import { buildMonthGrid, buildMonthWeeks, cellRangeFromDrag, closedHourBands, daySelectionState, eventAccessibilityLabel, eventChipLayout, eventTimeLabel, eventsInTimeZone, eventsInTimeZone as eventsInTimeZone$1, expandRecurringEvents, expandRecurringEvents as expandRecurringEvents$1, formatHour, getIsToday, getIsToday as getIsToday$1, getViewDays, getViewDays as getViewDays$1, getWeekDays, isAllDayEvent, isAllDayEvent as isAllDayEvent$1, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isSameCalendarDay as isSameCalendarDay$1, isWeekend, isWeekend as isWeekend$1, isWithinDateRange, layoutDayEvents, layoutDayEvents as layoutDayEvents$1, minutesIntoDay, nextDateRange, parseICalendar, resolveDraggedBounds, snapDeltaMinutes, titleEllipsizeMode, titleNumberOfLines, toICalendar, toZonedTime, useDateRange, useMonthGrid, viewDayCount, weekdayFormatToken, weekdayFormatToken as weekdayFormatToken$1 } from "@super-calendar/core";
6
6
  import { LegendList } from "@legendapp/list/react-native";
7
7
  import { Platform, Pressable, ScrollView, StyleSheet, Text, TouchableOpacity, View, useWindowDimensions } from "react-native";
8
- import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Gesture, GestureDetector } from "react-native-gesture-handler";
10
10
  //#region src/components/Agenda.tsx
11
11
  /**
@@ -13,8 +13,12 @@ import { Gesture, GestureDetector } from "react-native-gesture-handler";
13
13
  * start, grouped under a date header per day. The consumer controls which
14
14
  * events (and therefore which date range) are shown.
15
15
  */
16
- function Agenda({ events, locale, renderEvent, keyExtractor, onPressEvent, onLongPressEvent, onPressDay, activeDate, itemSeparatorComponent }) {
16
+ function Agenda({ events, locale, renderEvent, keyExtractor, onPressEvent, onLongPressEvent, onPressDay, activeDate, itemSeparatorComponent, classNames, styles: styleOverrides }) {
17
17
  const theme = useCalendarTheme();
18
+ const slot = useMemo(() => createSlots({
19
+ classNames,
20
+ styles: styleOverrides
21
+ }), [classNames, styleOverrides]);
18
22
  const RenderEventComponent = renderEvent;
19
23
  const rows = useMemo(() => {
20
24
  const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
@@ -43,14 +47,20 @@ function Agenda({ events, locale, renderEvent, keyExtractor, onPressEvent, onLon
43
47
  if (item.kind === "header") {
44
48
  const isHighlighted = activeDate ? isSameDay(item.date, activeDate) : getIsToday$1(item.date);
45
49
  return /* @__PURE__ */ jsx(Text, {
46
- style: [styles$4.header, { color: isHighlighted ? theme.colors.todayBackground : theme.colors.textMuted }],
50
+ ...slot("dayHeader", {
51
+ base: styles$4.header,
52
+ themed: [styles$4.headerText, { color: isHighlighted ? theme.colors.todayBackground : theme.colors.textMuted }]
53
+ }),
47
54
  onPress: onPressDay ? () => onPressDay(item.date) : void 0,
48
55
  accessibilityRole: onPressDay ? "button" : "header",
49
56
  children: format(item.date, "EEEE, d LLLL", { locale })
50
57
  });
51
58
  }
52
59
  return /* @__PURE__ */ jsx(View, {
53
- style: [styles$4.eventRow, theme.containers.agendaRow],
60
+ ...slot("eventRow", {
61
+ base: styles$4.eventRow,
62
+ themed: theme.containers.agendaRow
63
+ }),
54
64
  children: /* @__PURE__ */ jsx(RenderEventComponent, {
55
65
  event: item.event,
56
66
  mode: "schedule",
@@ -66,10 +76,14 @@ function Agenda({ events, locale, renderEvent, keyExtractor, onPressEvent, onLon
66
76
  onPressDay,
67
77
  onPressEvent,
68
78
  onLongPressEvent,
69
- RenderEventComponent
79
+ RenderEventComponent,
80
+ slot
70
81
  ]);
71
82
  if (rows.length === 0) return /* @__PURE__ */ jsx(Text, {
72
- style: [styles$4.empty, { color: theme.colors.textMuted }],
83
+ ...slot("empty", {
84
+ base: styles$4.empty,
85
+ themed: [styles$4.emptyText, { color: theme.colors.textMuted }]
86
+ }),
73
87
  children: "No events"
74
88
  });
75
89
  return /* @__PURE__ */ jsx(LegendList, {
@@ -84,21 +98,23 @@ function Agenda({ events, locale, renderEvent, keyExtractor, onPressEvent, onLon
84
98
  const styles$4 = StyleSheet.create({
85
99
  list: { flex: 1 },
86
100
  header: {
87
- fontSize: 13,
88
- fontWeight: "600",
89
101
  paddingTop: 12,
90
102
  paddingBottom: 4,
91
103
  paddingHorizontal: 12
92
104
  },
105
+ headerText: {
106
+ fontSize: 13,
107
+ fontWeight: "600"
108
+ },
93
109
  eventRow: {
94
110
  paddingHorizontal: 12,
95
111
  paddingVertical: 2
96
112
  },
97
113
  empty: {
98
- fontSize: 14,
99
114
  paddingVertical: 16,
100
115
  paddingHorizontal: 12
101
- }
116
+ },
117
+ emptyText: { fontSize: 14 }
102
118
  });
103
119
  //#endregion
104
120
  //#region src/components/DefaultEvent.tsx
@@ -114,7 +130,7 @@ const numericStyle = (value, fallback) => typeof value === "number" ? value : fa
114
130
  * only shows once a full line is free beneath the title. Pass your own
115
131
  * `renderEvent` to `<Calendar>` to replace it entirely.
116
132
  */
117
- function DefaultEvent({ event, mode, boxHeight, isAllDay, ampm = false, showTime = true, ellipsizeTitle = false, allDayLabel, accessibilityLabel: accessibilityLabelProp, cellStyle, onPress, onLongPress }) {
133
+ function DefaultEvent({ event, mode, boxHeight, isAllDay, ampm = false, showTime = true, ellipsizeTitle = false, allDayLabel, accessibilityLabel: accessibilityLabelProp, accessibilityActions, onAccessibilityAction, cellStyle, onPress, onLongPress }) {
118
134
  const theme = useCalendarTheme();
119
135
  const isAllDayEvent = isAllDay ?? false;
120
136
  const timeLabel = eventTimeLabel({
@@ -176,6 +192,8 @@ function DefaultEvent({ event, mode, boxHeight, isAllDay, ampm = false, showTime
176
192
  accessibilityRole: "button",
177
193
  accessibilityLabel,
178
194
  accessibilityState: { disabled: event.disabled ?? false },
195
+ accessibilityActions,
196
+ onAccessibilityAction,
179
197
  children: /* @__PURE__ */ jsxs(Animated.View, {
180
198
  testID: "event-chip-content",
181
199
  style: [styles$3.content, contentStyle],
@@ -298,6 +316,7 @@ function useWebGridZoom(enabled, target, cellHeight, committedCellHeight, minHei
298
316
  */
299
317
  function AllDayLane({ days, events, mode, hourColumnWidth, dayWidth, renderEvent, keyExtractor, onPressEvent, onLongPressEvent }) {
300
318
  const theme = useCalendarTheme();
319
+ const slot = useSlots();
301
320
  const RenderEventComponent = renderEvent;
302
321
  const allDay = events.filter(isAllDayEvent$1);
303
322
  const perDay = days.map((day) => {
@@ -307,26 +326,27 @@ function AllDayLane({ days, events, mode, hourColumnWidth, dayWidth, renderEvent
307
326
  });
308
327
  if (perDay.every((list) => list.length === 0)) return null;
309
328
  return /* @__PURE__ */ jsxs(View, {
310
- style: [
311
- styles$2.lane,
312
- { borderBottomColor: theme.colors.gridLine },
313
- theme.containers.allDayLane
314
- ],
329
+ ...slot("allDayLane", {
330
+ base: styles$2.lane,
331
+ themed: [{ borderBottomColor: theme.colors.gridLine }, theme.containers.allDayLane]
332
+ }),
315
333
  children: [/* @__PURE__ */ jsx(View, {
316
334
  style: [styles$2.gutter, { width: hourColumnWidth }],
317
335
  children: /* @__PURE__ */ jsx(Text, {
318
- style: [styles$2.label, { color: theme.colors.textMuted }],
336
+ ...slot("allDayLabel", {
337
+ base: styles$2.label,
338
+ themed: { color: theme.colors.textMuted }
339
+ }),
319
340
  allowFontScaling: false,
320
341
  children: "all-day"
321
342
  })
322
343
  }), days.map((day, dayIndex) => /* @__PURE__ */ jsx(View, {
323
- style: [
324
- styles$2.column,
325
- { width: dayWidth },
326
- theme.containers.allDayColumn
327
- ],
344
+ ...slot("allDayColumn", {
345
+ base: [styles$2.column, { width: dayWidth }],
346
+ themed: theme.containers.allDayColumn
347
+ }),
328
348
  children: perDay[dayIndex].map((event, index) => /* @__PURE__ */ jsx(View, {
329
- style: styles$2.chip,
349
+ ...slot("allDayEvent", { base: styles$2.chip }),
330
350
  children: /* @__PURE__ */ jsx(RenderEventComponent, {
331
351
  event,
332
352
  mode,
@@ -391,6 +411,7 @@ function useNow(enabled) {
391
411
  function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, dayWidth, dayIndex, dayCount, mode, renderEvent, snapMinutes, onPress, onLongPress, onDragEvent, onDragStart, showDragHandle }) {
392
412
  const RenderEventComponent = renderEvent;
393
413
  const theme = useCalendarTheme();
414
+ const slot = useSlots();
394
415
  const draggable = onDragEvent != null && !positioned.event.disabled;
395
416
  const resizable = draggable && !positioned.continuesAfter;
396
417
  const moveOffset = useSharedValue(0);
@@ -506,22 +527,58 @@ function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, dayWid
506
527
  ]);
507
528
  const handlePress = () => onPress(positioned.event);
508
529
  const handleLongPress = !draggable && onLongPress ? () => onLongPress(positioned.event) : void 0;
530
+ const unit = (n) => `${n} minute${n === 1 ? "" : "s"}`;
531
+ const accessibilityActions = draggable ? [
532
+ {
533
+ name: "move-later",
534
+ label: `Move ${unit(snapMinutes)} later`
535
+ },
536
+ {
537
+ name: "move-earlier",
538
+ label: `Move ${unit(snapMinutes)} earlier`
539
+ },
540
+ ...resizable ? [{
541
+ name: "extend",
542
+ label: `Extend by ${unit(snapMinutes)}`
543
+ }, {
544
+ name: "shrink",
545
+ label: `Shorten by ${unit(snapMinutes)}`
546
+ }] : []
547
+ ] : void 0;
548
+ const handleAccessibilityAction = draggable ? (e) => {
549
+ switch (e.nativeEvent.actionName) {
550
+ case "move-later":
551
+ commitDrag(snapMinutes, snapMinutes);
552
+ break;
553
+ case "move-earlier":
554
+ commitDrag(-snapMinutes, -snapMinutes);
555
+ break;
556
+ case "extend":
557
+ commitDrag(0, snapMinutes);
558
+ break;
559
+ case "shrink":
560
+ commitDrag(0, -snapMinutes);
561
+ break;
562
+ }
563
+ } : void 0;
564
+ const eventSlot = slot("event", {
565
+ base: [styles$1.eventBox, {
566
+ left,
567
+ width
568
+ }],
569
+ themed: theme.containers.timeGridEvent
570
+ });
509
571
  const box = /* @__PURE__ */ jsxs(Animated.View, {
510
- style: [
511
- styles$1.eventBox,
512
- {
513
- left,
514
- width
515
- },
516
- boxStyle,
517
- theme.containers.timeGridEvent
518
- ],
572
+ ...eventSlot,
573
+ style: [eventSlot.style, boxStyle],
519
574
  children: [/* @__PURE__ */ jsx(RenderEventComponent, {
520
575
  event: positioned.event,
521
576
  mode,
522
577
  boxHeight,
523
578
  continuesBefore: positioned.continuesBefore,
524
579
  continuesAfter: positioned.continuesAfter,
580
+ accessibilityActions,
581
+ onAccessibilityAction: handleAccessibilityAction,
525
582
  onPress: handlePress,
526
583
  onLongPress: handleLongPress
527
584
  }), resizable ? /* @__PURE__ */ jsx(GestureDetector, {
@@ -540,6 +597,7 @@ function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, dayWid
540
597
  }
541
598
  const HourRow = ({ hour, minHour, cellHeight, hourColumnWidth, label, ampm, hourComponent }) => {
542
599
  const theme = useCalendarTheme();
600
+ const slot = useSlots();
543
601
  const animatedStyle = useAnimatedStyle(() => ({ top: (hour - minHour) * cellHeight.value }), [hour, minHour]);
544
602
  return /* @__PURE__ */ jsxs(Animated.View, {
545
603
  style: [
@@ -551,52 +609,61 @@ const HourRow = ({ hour, minHour, cellHeight, hourColumnWidth, label, ampm, hour
551
609
  style: { width: hourColumnWidth },
552
610
  children: hourComponent(hour, ampm)
553
611
  }) : /* @__PURE__ */ jsx(Text, {
554
- style: [
555
- theme.text.hourLabel,
556
- styles$1.hourLabel,
557
- {
558
- width: hourColumnWidth,
559
- color: theme.colors.textMuted
560
- }
561
- ],
612
+ ...slot("hourLabel", {
613
+ base: [styles$1.hourLabel, { width: hourColumnWidth }],
614
+ themed: [theme.text.hourLabel, { color: theme.colors.textMuted }]
615
+ }),
562
616
  allowFontScaling: false,
563
617
  children: label
564
- }), /* @__PURE__ */ jsx(View, { style: [styles$1.hourLine, { backgroundColor: theme.colors.gridLine }] })]
618
+ }), /* @__PURE__ */ jsx(View, { ...slot("gridLines", {
619
+ base: styles$1.hourLine,
620
+ themed: { backgroundColor: theme.colors.gridLine }
621
+ }) })]
565
622
  });
566
623
  };
567
624
  const TimeslotLine = ({ hour, minHour, fraction, cellHeight, hourColumnWidth }) => {
568
625
  const theme = useCalendarTheme();
626
+ const slot = useSlots();
569
627
  const animatedStyle = useAnimatedStyle(() => ({ top: (hour - minHour + fraction) * cellHeight.value }), [
570
628
  hour,
571
629
  minHour,
572
630
  fraction
573
631
  ]);
574
- return /* @__PURE__ */ jsx(Animated.View, { style: [
575
- styles$1.timeslotLine,
576
- styles$1.nonInteractive,
577
- {
578
- left: hourColumnWidth,
579
- backgroundColor: theme.colors.gridLine
580
- },
581
- animatedStyle
582
- ] });
632
+ const lineSlot = slot("gridLines", {
633
+ base: [
634
+ styles$1.timeslotLine,
635
+ styles$1.nonInteractive,
636
+ { left: hourColumnWidth }
637
+ ],
638
+ themed: { backgroundColor: theme.colors.gridLine }
639
+ });
640
+ return /* @__PURE__ */ jsx(Animated.View, {
641
+ ...lineSlot,
642
+ style: [lineSlot.style, animatedStyle]
643
+ });
583
644
  };
584
645
  const NowIndicator = ({ cellHeight, nowHours, minHour, left, width, color }) => {
585
646
  const theme = useCalendarTheme();
647
+ const slot = useSlots();
586
648
  const animatedStyle = useAnimatedStyle(() => ({ top: (nowHours - minHour) * cellHeight.value }), [nowHours, minHour]);
587
- return /* @__PURE__ */ jsx(Animated.View, { style: [
588
- styles$1.nowIndicator,
589
- styles$1.nonInteractive,
590
- {
591
- left,
592
- width,
593
- backgroundColor: color
594
- },
595
- animatedStyle,
596
- theme.containers.nowIndicator
597
- ] });
649
+ const lineSlot = slot("nowIndicator", {
650
+ base: [
651
+ styles$1.nowIndicator,
652
+ styles$1.nonInteractive,
653
+ {
654
+ left,
655
+ width
656
+ }
657
+ ],
658
+ themed: [{ backgroundColor: color }, theme.containers.nowIndicator]
659
+ });
660
+ return /* @__PURE__ */ jsx(Animated.View, {
661
+ ...lineSlot,
662
+ style: [lineSlot.style, animatedStyle]
663
+ });
598
664
  };
599
665
  const ShadeBand = ({ cellHeight, startHour, endHour, minHour, left, width, color }) => {
666
+ const slot = useSlots();
600
667
  const animatedStyle = useAnimatedStyle(() => ({
601
668
  top: (startHour - minHour) * cellHeight.value,
602
669
  height: (endHour - startHour) * cellHeight.value
@@ -605,22 +672,26 @@ const ShadeBand = ({ cellHeight, startHour, endHour, minHour, left, width, color
605
672
  endHour,
606
673
  minHour
607
674
  ]);
608
- return /* @__PURE__ */ jsx(Animated.View, {
609
- testID: "business-hours-shade",
610
- style: [
675
+ const bandSlot = slot("businessHours", {
676
+ base: [
611
677
  styles$1.shadeBand,
612
678
  styles$1.nonInteractive,
613
679
  {
614
680
  left,
615
- width,
616
- backgroundColor: color
617
- },
618
- animatedStyle
619
- ]
681
+ width
682
+ }
683
+ ],
684
+ themed: { backgroundColor: color }
685
+ });
686
+ return /* @__PURE__ */ jsx(Animated.View, {
687
+ testID: "business-hours-shade",
688
+ ...bandSlot,
689
+ style: [bandSlot.style, animatedStyle]
620
690
  });
621
691
  };
622
692
  function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hourHeight, committedCellHeight, scrollY, isActive, initialScrollY, onSettleOffset, weekStartsOn, weekEndsOn, width, hourColumnWidth, minHour, maxHour, ampm, timeslots, isRTL, showAllDayEventCell, showVerticalScrollIndicator, verticalScrollEnabled, hourComponent, calendarCellStyle, minHourHeight, maxHourHeight, showNowIndicator, businessHours, renderEvent, keyExtractor, snapMinutes, showDragHandle, onPressEvent, onLongPressEvent, onDragEvent, onDragStart, onPressCell, onLongPressCell, onCreateEvent }) {
623
693
  const theme = useCalendarTheme();
694
+ const slot = useSlots();
624
695
  const scrollRef = useAnimatedRef();
625
696
  const heightSource = isActive ? cellHeight : committedCellHeight;
626
697
  const isDragging = useSharedValue(false);
@@ -671,7 +742,8 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
671
742
  const dayLayouts = useMemo(() => days.map((day) => layoutDayEvents$1(events, day)), [days, events]);
672
743
  const cellDateFromTouch = (event) => {
673
744
  const { locationX, locationY } = event.nativeEvent;
674
- const day = days[days.length === 1 ? 0 : Math.floor(locationX / dayWidth)];
745
+ const dayIndex = days.length === 1 ? 0 : Math.floor(locationX / dayWidth);
746
+ const day = days[dayIndex];
675
747
  if (!day) return null;
676
748
  const minutes = Math.round((minHour + locationY / heightSource.value) * MINUTES_PER_HOUR$1);
677
749
  const pressed = new Date(day);
@@ -736,7 +808,8 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
736
808
  onCreateEvent
737
809
  ]);
738
810
  const tapCell = useCallback((x, y) => {
739
- const day = days[days.length === 1 ? 0 : Math.floor(x / dayWidth)];
811
+ const dayIndex = days.length === 1 ? 0 : Math.floor(x / dayWidth);
812
+ const day = days[dayIndex];
740
813
  if (!day) return;
741
814
  const minutes = Math.round((minHour + y / heightSource.value) * MINUTES_PER_HOUR$1);
742
815
  const pressed = new Date(day);
@@ -831,6 +904,13 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
831
904
  width: createWidth.value,
832
905
  opacity: createActive.value
833
906
  }));
907
+ const ghostSlot = slot("createGhost", {
908
+ base: [styles$1.createGhost, { pointerEvents: "none" }],
909
+ themed: {
910
+ backgroundColor: theme.colors.eventBackground,
911
+ borderColor: theme.colors.todayBackground
912
+ }
913
+ });
834
914
  const cellLayer = onPressCell || onLongPressCell || createEnabled ? /* @__PURE__ */ jsx(Pressable, {
835
915
  style: [styles$1.cellPressLayer, { left: hourColumnWidth }],
836
916
  onPress: onPressCell ? handleBackgroundPress : void 0,
@@ -871,16 +951,24 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
871
951
  gesture: backgroundGesture,
872
952
  children: cellLayer
873
953
  }) : cellLayer,
874
- days.map((day, dayIndex) => isWeekend$1(day) ? /* @__PURE__ */ jsx(Animated.View, { style: [
875
- styles$1.weekendColumn,
876
- styles$1.nonInteractive,
877
- { backgroundColor: theme.colors.weekendBackground },
878
- {
879
- left: dayLeft(dayIndex),
880
- width: dayWidth
881
- },
882
- fullHeightStyle
883
- ] }, `weekend-${day.toISOString()}`) : null),
954
+ days.map((day, dayIndex) => {
955
+ if (!isWeekend$1(day)) return null;
956
+ const shadeSlot = slot("weekendShade", {
957
+ base: [
958
+ styles$1.weekendColumn,
959
+ styles$1.nonInteractive,
960
+ {
961
+ left: dayLeft(dayIndex),
962
+ width: dayWidth
963
+ }
964
+ ],
965
+ themed: { backgroundColor: theme.colors.weekendBackground }
966
+ });
967
+ return /* @__PURE__ */ jsx(Animated.View, {
968
+ ...shadeSlot,
969
+ style: [shadeSlot.style, fullHeightStyle]
970
+ }, `weekend-${day.toISOString()}`);
971
+ }),
884
972
  calendarCellStyle ? days.map((day, dayIndex) => {
885
973
  const cellStyle = calendarCellStyle(day);
886
974
  return cellStyle ? /* @__PURE__ */ jsx(Animated.View, { style: [
@@ -903,13 +991,20 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
903
991
  width: dayWidth,
904
992
  color: theme.colors.outsideHoursBackground
905
993
  }, `closed-${day.toISOString()}-${bandIndex}`))) : null,
906
- days.map((day, dayIndex) => /* @__PURE__ */ jsx(Animated.View, { style: [
907
- styles$1.daySeparator,
908
- styles$1.nonInteractive,
909
- { backgroundColor: theme.colors.gridLine },
910
- { left: dayLeft(dayIndex) },
911
- fullHeightStyle
912
- ] }, `separator-${day.toISOString()}`)),
994
+ days.map((day, dayIndex) => {
995
+ const separatorSlot = slot("daySeparator", {
996
+ base: [
997
+ styles$1.daySeparator,
998
+ styles$1.nonInteractive,
999
+ { left: dayLeft(dayIndex) }
1000
+ ],
1001
+ themed: { backgroundColor: theme.colors.gridLine }
1002
+ });
1003
+ return /* @__PURE__ */ jsx(Animated.View, {
1004
+ ...separatorSlot,
1005
+ style: [separatorSlot.style, fullHeightStyle]
1006
+ }, `separator-${day.toISOString()}`);
1007
+ }),
913
1008
  hoursRange.map((hour) => /* @__PURE__ */ jsx(HourRow, {
914
1009
  hour,
915
1010
  minHour,
@@ -955,15 +1050,10 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
955
1050
  width: dayWidth,
956
1051
  color: theme.colors.nowIndicator
957
1052
  }) : null,
958
- createEnabled ? /* @__PURE__ */ jsx(Animated.View, { style: [
959
- styles$1.createGhost,
960
- { pointerEvents: "none" },
961
- {
962
- backgroundColor: theme.colors.eventBackground,
963
- borderColor: theme.colors.todayBackground
964
- },
965
- createGhostStyle
966
- ] }) : null
1053
+ createEnabled ? /* @__PURE__ */ jsx(Animated.View, {
1054
+ ...ghostSlot,
1055
+ style: [ghostSlot.style, createGhostStyle]
1056
+ }) : null
967
1057
  ]
968
1058
  })
969
1059
  })
@@ -971,7 +1061,7 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
971
1061
  });
972
1062
  }
973
1063
  const TimetablePage = memo(TimetablePageInner);
974
- function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellHeight, hourHeight = 48, weekStartsOn, weekdayFormat = "short", renderEvent, eventAccessibilityLabel, keyExtractor, scrollOffsetMinutes = 0, hourColumnWidth: hourColumnWidthProp = DEFAULT_HOUR_COLUMN_WIDTH, hideHours = false, timeslots = 1, showAllDayEventCell = true, calendarCellStyle, businessHours, 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, dragStepMinutes = DEFAULT_DRAG_STEP_MINUTES, showDragHandle = true, onPressEvent, onLongPressEvent, onDragEvent, onDragStart, onPressCell, onLongPressCell, onCreateEvent, onPressDateHeader, onChangeDate, renderHeader }) {
1064
+ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellHeight, hourHeight = 48, weekStartsOn, weekdayFormat = "short", renderEvent, eventAccessibilityLabel, keyExtractor, scrollOffsetMinutes = 0, hourColumnWidth: hourColumnWidthProp = DEFAULT_HOUR_COLUMN_WIDTH, hideHours = false, timeslots = 1, showAllDayEventCell = true, calendarCellStyle, businessHours, 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, dragStepMinutes = DEFAULT_DRAG_STEP_MINUTES, showDragHandle = true, onPressEvent, onLongPressEvent, onDragEvent, onDragStart, onPressCell, onLongPressCell, onCreateEvent, onPressDateHeader, onChangeDate, renderHeader, classNames, styles: styleOverrides }) {
975
1065
  const clampedMinHour = Math.max(0, Math.min(minHour, HOURS_PER_DAY - 1));
976
1066
  const clampedMaxHour = Math.max(clampedMinHour + 1, Math.min(maxHour, HOURS_PER_DAY));
977
1067
  const hourColumnWidth = hideHours ? 0 : hourColumnWidthProp;
@@ -1118,6 +1208,7 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1118
1208
  activeIndex,
1119
1209
  onChangeDate
1120
1210
  ]));
1211
+ const reduceMotion = useReducedMotion();
1121
1212
  const handlePressCell = useMemo(() => {
1122
1213
  if (!onPressCell) return void 0;
1123
1214
  if (!resetPageOnPressCell) return onPressCell;
@@ -1125,13 +1216,14 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1125
1216
  onPressCell(cellDate);
1126
1217
  listRef.current?.scrollToIndex({
1127
1218
  index: activeIndex,
1128
- animated: true
1219
+ animated: !reduceMotion
1129
1220
  });
1130
1221
  };
1131
1222
  }, [
1132
1223
  onPressCell,
1133
1224
  resetPageOnPressCell,
1134
- activeIndex
1225
+ activeIndex,
1226
+ reduceMotion
1135
1227
  ]);
1136
1228
  const snapToIndices = useMemo(() => pageDates.map((_, index) => index), [pageDates]);
1137
1229
  const keyExtractorList = useCallback((item) => item.toISOString(), []);
@@ -1229,52 +1321,56 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1229
1321
  events,
1230
1322
  activeIndex
1231
1323
  }), [events, activeIndex]);
1232
- return /* @__PURE__ */ jsxs(View, {
1233
- ref: containerRef,
1234
- style: styles$1.container,
1235
- children: [
1236
- renderHeader ? renderHeader(headerDays) : /* @__PURE__ */ jsx(DefaultHeader, {
1237
- days: headerDays,
1238
- mode,
1239
- width: containerWidth,
1240
- hourColumnWidth,
1241
- showWeekNumber,
1242
- weekNumberPrefix,
1243
- weekdayFormat,
1244
- locale,
1245
- activeDate,
1246
- onPressDateHeader
1247
- }),
1248
- headerComponent,
1249
- /* @__PURE__ */ jsx(View, {
1250
- style: styles$1.pager,
1251
- onLayout: (event) => {
1252
- setPageHeight(event.nativeEvent.layout.height);
1253
- setContainerWidth(event.nativeEvent.layout.width);
1254
- setMeasured(true);
1255
- },
1256
- children: /* @__PURE__ */ jsx(LegendList, {
1257
- ref: listRef,
1258
- style: isWeb ? [styles$1.pagerList, styles$1.webNoScroll] : styles$1.pagerList,
1259
- data: pageDates,
1260
- extraData: listExtraData,
1261
- horizontal: true,
1262
- recycleItems: false,
1263
- keyExtractor: keyExtractorList,
1264
- getFixedItemSize,
1265
- ...isWeb ? null : {
1266
- scrollEnabled: swipeEnabled,
1267
- pagingEnabled: !freeSwipe,
1268
- snapToIndices: freeSwipe ? snapToIndices : void 0
1324
+ return /* @__PURE__ */ jsx(SlotStylesProvider, {
1325
+ classNames,
1326
+ styles: styleOverrides,
1327
+ children: /* @__PURE__ */ jsxs(View, {
1328
+ ref: containerRef,
1329
+ style: styles$1.container,
1330
+ children: [
1331
+ renderHeader ? renderHeader(headerDays) : /* @__PURE__ */ jsx(DefaultHeader, {
1332
+ days: headerDays,
1333
+ mode,
1334
+ width: containerWidth,
1335
+ hourColumnWidth,
1336
+ showWeekNumber,
1337
+ weekNumberPrefix,
1338
+ weekdayFormat,
1339
+ locale,
1340
+ activeDate,
1341
+ onPressDateHeader
1342
+ }),
1343
+ headerComponent,
1344
+ /* @__PURE__ */ jsx(View, {
1345
+ style: styles$1.pager,
1346
+ onLayout: (event) => {
1347
+ setPageHeight(event.nativeEvent.layout.height);
1348
+ setContainerWidth(event.nativeEvent.layout.width);
1349
+ setMeasured(true);
1269
1350
  },
1270
- initialScrollIndex: activeIndex,
1271
- showsHorizontalScrollIndicator: false,
1272
- viewabilityConfig: PAGE_VIEWABILITY,
1273
- onViewableItemsChanged: handleViewableItemsChanged,
1274
- renderItem
1275
- }, measured ? "grid" : "grid-seed")
1276
- })
1277
- ]
1351
+ children: /* @__PURE__ */ jsx(LegendList, {
1352
+ ref: listRef,
1353
+ style: isWeb ? [styles$1.pagerList, styles$1.webNoScroll] : styles$1.pagerList,
1354
+ data: pageDates,
1355
+ extraData: listExtraData,
1356
+ horizontal: true,
1357
+ recycleItems: false,
1358
+ keyExtractor: keyExtractorList,
1359
+ getFixedItemSize,
1360
+ ...isWeb ? null : {
1361
+ scrollEnabled: swipeEnabled,
1362
+ pagingEnabled: !freeSwipe,
1363
+ snapToIndices: freeSwipe ? snapToIndices : void 0
1364
+ },
1365
+ initialScrollIndex: activeIndex,
1366
+ showsHorizontalScrollIndicator: false,
1367
+ viewabilityConfig: PAGE_VIEWABILITY,
1368
+ onViewableItemsChanged: handleViewableItemsChanged,
1369
+ renderItem
1370
+ }, measured ? "grid" : "grid-seed")
1371
+ })
1372
+ ]
1373
+ })
1278
1374
  });
1279
1375
  }
1280
1376
  /**
@@ -1299,15 +1395,19 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1299
1395
  const TimeGrid = memo(TimeGridInner);
1300
1396
  const DefaultHeader = ({ days, mode, width, hourColumnWidth, showWeekNumber, weekNumberPrefix = "W", weekdayFormat, locale, activeDate, onPressDateHeader }) => {
1301
1397
  const theme = useCalendarTheme();
1398
+ const slot = useSlots();
1302
1399
  const dayWidth = (width - hourColumnWidth) / days.length;
1303
1400
  return /* @__PURE__ */ jsxs(View, {
1304
- style: [styles$1.headerRow, { borderBottomColor: theme.colors.gridLine }],
1401
+ ...slot("header", {
1402
+ base: styles$1.headerRow,
1403
+ themed: { borderBottomColor: theme.colors.gridLine }
1404
+ }),
1305
1405
  children: [/* @__PURE__ */ jsx(View, {
1306
1406
  style: [styles$1.weekNumberGutter, { width: hourColumnWidth }],
1307
1407
  children: showWeekNumber && hourColumnWidth > 0 && days[0] ? /* @__PURE__ */ jsx(Text, {
1308
- style: [theme.text.hourLabel, { color: theme.colors.textMuted }],
1408
+ ...slot("weekNumber", { themed: [theme.text.hourLabel, { color: theme.colors.textMuted }] }),
1309
1409
  allowFontScaling: false,
1310
- children: `${weekNumberPrefix}${getISOWeek(days[0])}`
1410
+ children: `${weekNumberPrefix}${getISOWeek(days.find((d) => d.getDay() === 4) ?? days[0])}`
1311
1411
  }) : null
1312
1412
  }), days.map((day) => /* @__PURE__ */ jsx(DayHeader, {
1313
1413
  day,
@@ -1322,36 +1422,42 @@ const DefaultHeader = ({ days, mode, width, hourColumnWidth, showWeekNumber, wee
1322
1422
  };
1323
1423
  const DayHeader = ({ day, width, weekdayFormat = "short", locale, activeDate, onPressDateHeader }) => {
1324
1424
  const theme = useCalendarTheme();
1425
+ const slot = useSlots();
1325
1426
  const isToday = getIsToday$1(day);
1326
1427
  const isHighlighted = activeDate ? isSameCalendarDay$1(day, activeDate) : isToday;
1327
- return /* @__PURE__ */ jsxs(Pressable, {
1328
- style: [
1329
- styles$1.dayHeader,
1330
- { width },
1331
- theme.containers.columnHeader
1332
- ],
1333
- onPress: onPressDateHeader ? () => onPressDateHeader(day) : void 0,
1334
- disabled: !onPressDateHeader,
1335
- accessibilityRole: onPressDateHeader ? "button" : void 0,
1336
- accessibilityLabel: onPressDateHeader ? format(day, "EEEE d MMMM", { locale }) : void 0,
1337
- children: [/* @__PURE__ */ jsx(Text, {
1338
- style: [{ color: theme.colors.textMuted }, theme.text.columnHeaderWeekday],
1428
+ const accessibilityLabel = `${format(day, "EEEE d MMMM", { locale })}${isToday ? ", today" : ""}`;
1429
+ const headerSlot = slot("columnHeader", {
1430
+ base: [styles$1.dayHeader, { width }],
1431
+ themed: theme.containers.columnHeader
1432
+ });
1433
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Text, {
1434
+ ...slot("columnHeaderWeekday", { themed: [{ color: theme.colors.textMuted }, theme.text.columnHeaderWeekday] }),
1435
+ allowFontScaling: false,
1436
+ children: format(day, weekdayFormatToken$1(weekdayFormat), { locale })
1437
+ }), /* @__PURE__ */ jsx(View, {
1438
+ testID: "column-header-badge",
1439
+ ...slot("columnHeaderDate", {
1440
+ base: styles$1.dayHeaderBadge,
1441
+ themed: [theme.containers.columnHeaderBadge, isHighlighted && { backgroundColor: theme.colors.todayBackground }]
1442
+ }),
1443
+ children: /* @__PURE__ */ jsx(Text, {
1444
+ ...slot("columnHeaderDateText", { themed: [theme.text.dayNumber, { color: isHighlighted ? theme.colors.todayText : theme.colors.text }] }),
1339
1445
  allowFontScaling: false,
1340
- children: format(day, weekdayFormatToken$1(weekdayFormat), { locale })
1341
- }), /* @__PURE__ */ jsx(View, {
1342
- testID: "column-header-badge",
1343
- style: [
1344
- styles$1.dayHeaderBadge,
1345
- theme.containers.columnHeaderBadge,
1346
- isHighlighted && { backgroundColor: theme.colors.todayBackground }
1347
- ],
1348
- children: /* @__PURE__ */ jsx(Text, {
1349
- style: [theme.text.dayNumber, { color: isHighlighted ? theme.colors.todayText : theme.colors.text }],
1350
- allowFontScaling: false,
1351
- ...isToday && { accessibilityLabel: `Today, ${day.getDate()}` },
1352
- children: day.getDate()
1353
- })
1354
- })]
1446
+ children: day.getDate()
1447
+ })
1448
+ })] });
1449
+ return onPressDateHeader ? /* @__PURE__ */ jsx(Pressable, {
1450
+ ...headerSlot,
1451
+ onPress: () => onPressDateHeader(day),
1452
+ accessibilityRole: "button",
1453
+ accessibilityLabel,
1454
+ children: content
1455
+ }) : /* @__PURE__ */ jsx(View, {
1456
+ ...headerSlot,
1457
+ accessible: true,
1458
+ accessibilityRole: "header",
1459
+ accessibilityLabel,
1460
+ children: content
1355
1461
  });
1356
1462
  };
1357
1463
  const styles$1 = StyleSheet.create({
@@ -1462,6 +1568,13 @@ function visibleRange(mode, date, weekStartsOn, numberOfDays, weekEndsOn) {
1462
1568
  const days = getViewDays$1(mode, date, weekStartsOn, numberOfDays, false, weekEndsOn);
1463
1569
  return [startOfDay(days[0]), endOfDay(days[days.length - 1])];
1464
1570
  }
1571
+ function expansionRange(mode, date, weekStartsOn, numberOfDays, weekEndsOn) {
1572
+ if (mode === "month") return [startOfWeek(startOfMonth(addMonths(date, -1)), { weekStartsOn }), addWeeks(endOfWeek(endOfMonth(addMonths(date, 1)), { weekStartsOn }), 1)];
1573
+ if (mode === "schedule") return [startOfDay(date), endOfDay(addMonths(date, 3))];
1574
+ const days = getViewDays$1(mode, date, weekStartsOn, numberOfDays, false, weekEndsOn);
1575
+ const span = days.length;
1576
+ return [startOfDay(addDays(days[0], -span)), endOfDay(addDays(days[days.length - 1], span))];
1577
+ }
1465
1578
  /**
1466
1579
  * The top-level calendar. Switches between month, week, day, 3days, custom, and
1467
1580
  * schedule modes, and is gesture-driven and virtualized. It is a controlled
@@ -1488,10 +1601,31 @@ function visibleRange(mode, date, weekStartsOn, numberOfDays, weekEndsOn) {
1488
1601
  * }
1489
1602
  * ```
1490
1603
  */
1491
- function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPressEvent, onLongPressEvent, onDragEvent, onDragStart, dragStepMinutes, showDragHandle, onPressDay, onLongPressDay, onPressMore, onPressCell, resetPageOnPressCell, onLongPressCell, onCreateEvent, onPressDateHeader, maxVisibleEventCount, sortedMonthView, moreLabel, showAdjacentMonths, disableMonthEventCellPress, weekStartsOn = 0, weekdayFormat, numberOfDays, weekEndsOn, renderEvent = DefaultEvent, eventAccessibilityLabel, eventCellStyle, calendarCellStyle, businessHours, keyExtractor = defaultKeyExtractor, theme, cellHeight: cellHeightProp, hourHeight = 48, minHourHeight, maxHourHeight, hourColumnWidth, hideHours, timeslots, showAllDayEventCell, showWeekNumber, weekNumberPrefix, hourComponent, showSixWeeks, swipeEnabled, showVerticalScrollIndicator, verticalScrollEnabled, headerComponent, minHour, maxHour, ampm, showTime, ellipsizeTitle, allDayLabel, scrollOffsetMinutes, showNowIndicator, locale, activeDate, isRTL, freeSwipe, renderTimeGridHeader, renderHeaderForMonthView, renderCustomDateForMonth, itemSeparatorComponent }) {
1604
+ function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPressEvent, onLongPressEvent, onDragEvent, onDragStart, dragStepMinutes, showDragHandle, onPressDay, onLongPressDay, onPressMore, onPressCell, resetPageOnPressCell, onLongPressCell, onCreateEvent, onPressDateHeader, maxVisibleEventCount, sortedMonthView, moreLabel, showAdjacentMonths, disableMonthEventCellPress, weekStartsOn = 0, weekdayFormat, numberOfDays, weekEndsOn, renderEvent = DefaultEvent, eventAccessibilityLabel, eventCellStyle, calendarCellStyle, businessHours, keyExtractor = defaultKeyExtractor, theme, cellHeight: cellHeightProp, hourHeight = 48, minHourHeight, maxHourHeight, hourColumnWidth, hideHours, timeslots, showAllDayEventCell, showWeekNumber, weekNumberPrefix, hourComponent, showSixWeeks, swipeEnabled, showVerticalScrollIndicator, verticalScrollEnabled, headerComponent, minHour, maxHour, ampm, showTime, ellipsizeTitle, allDayLabel, scrollOffsetMinutes, showNowIndicator, locale, timeZone, activeDate, isRTL, freeSwipe, renderTimeGridHeader, renderHeaderForMonthView, renderCustomDateForMonth, itemSeparatorComponent, classNames, styles: styleOverrides }) {
1492
1605
  const mergedTheme = useMemo(() => mergeTheme(theme), [theme]);
1493
1606
  const internalCellHeight = useSharedValue(hourHeight);
1494
1607
  const cellHeight = cellHeightProp ?? internalCellHeight;
1608
+ const displayEvents = useMemo(() => {
1609
+ let out = events;
1610
+ if (out.some((e) => e.recurrence)) {
1611
+ let [start, end] = expansionRange(mode, date, weekStartsOn, numberOfDays ?? 1, weekEndsOn);
1612
+ if (timeZone) {
1613
+ start = addDays(start, -1);
1614
+ end = addDays(end, 1);
1615
+ }
1616
+ out = expandRecurringEvents$1(out, start, end);
1617
+ }
1618
+ if (timeZone) out = eventsInTimeZone$1(out, timeZone);
1619
+ return out;
1620
+ }, [
1621
+ events,
1622
+ mode,
1623
+ date.getTime(),
1624
+ weekStartsOn,
1625
+ numberOfDays,
1626
+ weekEndsOn,
1627
+ timeZone
1628
+ ]);
1495
1629
  const handlePressEvent = useCallback((event) => {
1496
1630
  if (!event.disabled) onPressEvent(event);
1497
1631
  }, [onPressEvent]);
@@ -1541,7 +1675,7 @@ function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPress
1541
1675
  value: mergedTheme,
1542
1676
  children: mode === "month" ? /* @__PURE__ */ jsx(MonthPager, {
1543
1677
  date,
1544
- events,
1678
+ events: displayEvents,
1545
1679
  maxVisibleEventCount,
1546
1680
  weekStartsOn,
1547
1681
  weekdayFormat,
@@ -1565,9 +1699,11 @@ function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPress
1565
1699
  onPressMore,
1566
1700
  onChangeDate: handleChangeDate,
1567
1701
  freeSwipe,
1568
- swipeEnabled
1702
+ swipeEnabled,
1703
+ classNames,
1704
+ styles: styleOverrides
1569
1705
  }) : mode === "schedule" ? /* @__PURE__ */ jsx(Agenda, {
1570
- events,
1706
+ events: displayEvents,
1571
1707
  locale,
1572
1708
  renderEvent: resolvedRenderEvent,
1573
1709
  keyExtractor,
@@ -1575,13 +1711,15 @@ function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPress
1575
1711
  onLongPressEvent: handleLongPressEvent,
1576
1712
  onPressDay,
1577
1713
  activeDate,
1578
- itemSeparatorComponent
1714
+ itemSeparatorComponent,
1715
+ classNames,
1716
+ styles: styleOverrides
1579
1717
  }) : /* @__PURE__ */ jsx(TimeGrid, {
1580
1718
  mode,
1581
1719
  numberOfDays,
1582
1720
  weekEndsOn,
1583
1721
  date,
1584
- events,
1722
+ events: displayEvents,
1585
1723
  cellHeight,
1586
1724
  hourHeight,
1587
1725
  weekStartsOn,
@@ -1624,7 +1762,9 @@ function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPress
1624
1762
  onCreateEvent,
1625
1763
  onPressDateHeader,
1626
1764
  onChangeDate: handleChangeDate,
1627
- renderHeader: renderTimeGridHeader
1765
+ renderHeader: renderTimeGridHeader,
1766
+ classNames,
1767
+ styles: styleOverrides
1628
1768
  })
1629
1769
  });
1630
1770
  }
@@ -1633,8 +1773,10 @@ function Calendar({ events, mode, date, onChangeDate, onChangeDateRange, onPress
1633
1773
  const MOVE_ACTIVATE_MS = 250;
1634
1774
  const MINUTES_PER_HOUR = 60;
1635
1775
  const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
1636
- function DefaultBar({ event, width }) {
1776
+ const GUTTER_WIDTH = 56;
1777
+ function DefaultBar({ event, width, height }) {
1637
1778
  const theme = useCalendarTheme();
1779
+ const showTime = height != null ? height > 34 : width > 56;
1638
1780
  const time = eventTimeLabel({
1639
1781
  mode: "day",
1640
1782
  isAllDay: false,
@@ -1654,7 +1796,7 @@ function DefaultBar({ event, width }) {
1654
1796
  style: [theme.text.eventTitle, { color: theme.colors.eventText }],
1655
1797
  allowFontScaling: false,
1656
1798
  children: event.title
1657
- }), time && width > 56 ? /* @__PURE__ */ jsx(Text, {
1799
+ }), time && showTime ? /* @__PURE__ */ jsx(Text, {
1658
1800
  numberOfLines: 1,
1659
1801
  style: [styles.barTime, { color: theme.colors.eventText }],
1660
1802
  allowFontScaling: false,
@@ -1662,7 +1804,7 @@ function DefaultBar({ event, width }) {
1662
1804
  }) : null]
1663
1805
  });
1664
1806
  }
1665
- function ResourceBar({ pe, left, width, laneHeight, hourWidth, snapMinutes, Renderer, onPress, onDragEvent, theme }) {
1807
+ function ResourceBar({ pe, vertical, hourSize, left, top, width, height, rendererSize, snapMinutes, Renderer, onPress, onDragEvent, theme }) {
1666
1808
  const moveX = useSharedValue(0);
1667
1809
  const resizeW = useSharedValue(0);
1668
1810
  const latest = useRef({
@@ -1696,71 +1838,122 @@ function ResourceBar({ pe, left, width, laneHeight, hourWidth, snapMinutes, Rend
1696
1838
  }
1697
1839
  if (handler(event, next.start, next.end) === false) snapBack();
1698
1840
  }, [snapMinutes, snapBack]);
1699
- const barStyle = useAnimatedStyle(() => ({
1841
+ const unit = (n) => `${n} minute${n === 1 ? "" : "s"}`;
1842
+ const barActions = draggable ? [
1843
+ {
1844
+ name: "move-later",
1845
+ label: `Move ${unit(snapMinutes)} later`
1846
+ },
1847
+ {
1848
+ name: "move-earlier",
1849
+ label: `Move ${unit(snapMinutes)} earlier`
1850
+ },
1851
+ {
1852
+ name: "extend",
1853
+ label: `Extend by ${unit(snapMinutes)}`
1854
+ },
1855
+ {
1856
+ name: "shrink",
1857
+ label: `Shorten by ${unit(snapMinutes)}`
1858
+ }
1859
+ ] : void 0;
1860
+ const onBarAction = draggable ? (e) => {
1861
+ switch (e.nativeEvent.actionName) {
1862
+ case "move-later":
1863
+ commit(snapMinutes, snapMinutes);
1864
+ break;
1865
+ case "move-earlier":
1866
+ commit(-snapMinutes, -snapMinutes);
1867
+ break;
1868
+ case "extend":
1869
+ commit(0, snapMinutes);
1870
+ break;
1871
+ case "shrink":
1872
+ commit(0, -snapMinutes);
1873
+ break;
1874
+ }
1875
+ } : void 0;
1876
+ const barStyle = useAnimatedStyle(() => vertical ? {
1877
+ transform: [{ translateY: moveX.value }],
1878
+ height: Math.max(height + resizeW.value, 2)
1879
+ } : {
1700
1880
  transform: [{ translateX: moveX.value }],
1701
1881
  width: Math.max(width + resizeW.value, 2)
1702
- }), [width]);
1882
+ }, [
1883
+ vertical,
1884
+ width,
1885
+ height
1886
+ ]);
1703
1887
  const moveGesture = useMemo(() => Gesture.Pan().enabled(draggable).activateAfterLongPress(MOVE_ACTIVATE_MS).onUpdate((e) => {
1704
- moveX.value = e.translationX;
1888
+ moveX.value = vertical ? e.translationY : e.translationX;
1705
1889
  }).onEnd((e) => {
1706
- const delta = snapDeltaMinutes(e.translationX, hourWidth, snapMinutes);
1890
+ const delta = snapDeltaMinutes(vertical ? e.translationY : e.translationX, hourSize, snapMinutes);
1707
1891
  if (delta === 0) {
1708
1892
  moveX.value = 0;
1709
1893
  return;
1710
1894
  }
1711
- moveX.value = delta / MINUTES_PER_HOUR * hourWidth;
1895
+ moveX.value = delta / MINUTES_PER_HOUR * hourSize;
1712
1896
  runOnJS(commit)(delta, delta);
1713
1897
  }), [
1714
1898
  draggable,
1715
- hourWidth,
1899
+ vertical,
1900
+ hourSize,
1716
1901
  snapMinutes,
1717
1902
  moveX,
1718
1903
  commit
1719
1904
  ]);
1720
1905
  const resizeGesture = useMemo(() => Gesture.Pan().enabled(draggable).onUpdate((e) => {
1721
- resizeW.value = e.translationX;
1906
+ resizeW.value = vertical ? e.translationY : e.translationX;
1722
1907
  }).onEnd((e) => {
1723
- const delta = snapDeltaMinutes(e.translationX, hourWidth, snapMinutes);
1908
+ const delta = snapDeltaMinutes(vertical ? e.translationY : e.translationX, hourSize, snapMinutes);
1724
1909
  if (delta === 0) {
1725
1910
  resizeW.value = 0;
1726
1911
  return;
1727
1912
  }
1728
- resizeW.value = delta / MINUTES_PER_HOUR * hourWidth;
1913
+ resizeW.value = delta / MINUTES_PER_HOUR * hourSize;
1729
1914
  runOnJS(commit)(0, delta);
1730
1915
  }), [
1731
1916
  draggable,
1732
- hourWidth,
1917
+ vertical,
1918
+ hourSize,
1733
1919
  snapMinutes,
1734
1920
  resizeW,
1735
1921
  commit
1736
1922
  ]);
1737
1923
  return /* @__PURE__ */ jsxs(Animated.View, {
1738
- style: [{
1739
- position: "absolute",
1740
- left,
1741
- top: pe.column * laneHeight,
1742
- height: laneHeight,
1743
- padding: 1
1744
- }, barStyle],
1924
+ style: [
1925
+ {
1926
+ position: "absolute",
1927
+ left,
1928
+ top,
1929
+ padding: 1
1930
+ },
1931
+ vertical ? { width } : { height },
1932
+ barStyle
1933
+ ],
1745
1934
  children: [/* @__PURE__ */ jsx(GestureDetector, {
1746
1935
  gesture: moveGesture,
1747
1936
  children: /* @__PURE__ */ jsx(Pressable, {
1748
1937
  onPress,
1749
1938
  accessibilityRole: "button",
1750
1939
  accessibilityLabel: pe.event.title,
1940
+ accessibilityActions: barActions,
1941
+ onAccessibilityAction: onBarAction,
1751
1942
  style: styles.fill,
1752
1943
  children: /* @__PURE__ */ jsx(Renderer, {
1753
1944
  event: pe.event,
1754
- width,
1945
+ width: rendererSize.width,
1946
+ height: rendererSize.height,
1755
1947
  onPress
1756
1948
  })
1757
1949
  })
1758
1950
  }), /* @__PURE__ */ jsx(GestureDetector, {
1759
1951
  gesture: resizeGesture,
1760
1952
  children: /* @__PURE__ */ jsx(View, {
1761
- style: [styles.resizeGrip, { backgroundColor: theme.colors.eventText }],
1762
- accessibilityRole: "adjustable",
1763
- accessibilityLabel: `Resize ${pe.event.title}`
1953
+ testID: "resource-resize-grip",
1954
+ style: [vertical ? styles.resizeGripBottom : styles.resizeGrip, { backgroundColor: theme.colors.eventText }],
1955
+ accessibilityElementsHidden: true,
1956
+ importantForAccessibility: "no"
1764
1957
  })
1765
1958
  })]
1766
1959
  });
@@ -1783,7 +1976,7 @@ function ResourceBar({ pe, left, width, laneHeight, hourWidth, snapMinutes, Rend
1783
1976
  * />
1784
1977
  * ```
1785
1978
  */
1786
- function ResourceTimeline({ date, resources, events, resourceId = (event) => event.resourceId, startHour = 0, endHour = 24, hourWidth = 80, rowHeight = 56, labelWidth = 140, ampm = false, renderEvent, onPressEvent, onDragEvent, dragStepMinutes = 15 }) {
1979
+ function ResourceTimeline({ date, orientation = "horizontal", resources, events, resourceId = (event) => event.resourceId, startHour = 0, endHour = 24, hourWidth = 80, hourHeight = 48, rowHeight = 56, labelWidth = 140, ampm = false, renderEvent, onPressEvent, onDragEvent, dragStepMinutes = 15 }) {
1787
1980
  const theme = useCalendarTheme();
1788
1981
  const Renderer = renderEvent ?? DefaultBar;
1789
1982
  const hours = useMemo(() => Array.from({ length: Math.max(0, endHour - startHour) }, (_, i) => startHour + i), [startHour, endHour]);
@@ -1801,6 +1994,101 @@ function ResourceTimeline({ date, resources, events, resourceId = (event) => eve
1801
1994
  resourceId,
1802
1995
  date
1803
1996
  ]);
1997
+ if (orientation === "vertical") {
1998
+ const trackHeight = (endHour - startHour) * hourHeight;
1999
+ return /* @__PURE__ */ jsxs(View, {
2000
+ style: styles.vroot,
2001
+ children: [/* @__PURE__ */ jsxs(View, {
2002
+ style: [styles.header, { borderBottomColor: theme.colors.gridLine }],
2003
+ children: [/* @__PURE__ */ jsx(View, { style: { width: GUTTER_WIDTH } }), resources.map((resource) => /* @__PURE__ */ jsx(View, {
2004
+ style: [styles.vheaderCell, theme.containers.resourceLabel],
2005
+ children: /* @__PURE__ */ jsx(Text, {
2006
+ numberOfLines: 1,
2007
+ style: [styles.vheaderText, { color: theme.colors.text }],
2008
+ allowFontScaling: false,
2009
+ children: resource.title ?? resource.id
2010
+ })
2011
+ }, resource.id))]
2012
+ }), /* @__PURE__ */ jsx(ScrollView, {
2013
+ showsVerticalScrollIndicator: true,
2014
+ children: /* @__PURE__ */ jsxs(View, {
2015
+ style: [styles.vbody, { height: trackHeight }],
2016
+ children: [/* @__PURE__ */ jsx(View, {
2017
+ style: { width: GUTTER_WIDTH },
2018
+ children: hours.map((h) => /* @__PURE__ */ jsx(Text, {
2019
+ allowFontScaling: false,
2020
+ style: [styles.vhourLabel, {
2021
+ top: Math.max(0, (h - startHour) * hourHeight - 6),
2022
+ color: theme.colors.textMuted
2023
+ }],
2024
+ children: formatHour(h, { ampm })
2025
+ }, h))
2026
+ }), resources.map((resource) => {
2027
+ const positioned = byResource.get(resource.id) ?? [];
2028
+ return /* @__PURE__ */ jsxs(View, {
2029
+ style: [
2030
+ styles.vcolumn,
2031
+ { borderLeftColor: theme.colors.gridLine },
2032
+ theme.containers.resourceRow
2033
+ ],
2034
+ children: [hours.slice(1).map((h) => /* @__PURE__ */ jsx(View, {
2035
+ pointerEvents: "none",
2036
+ style: [styles.vgridLine, {
2037
+ top: (h - startHour) * hourHeight,
2038
+ backgroundColor: theme.colors.gridLine
2039
+ }]
2040
+ }, h)), positioned.map((pe, idx) => {
2041
+ const top = clamp(pe.startHours - startHour, 0, endHour - startHour) * hourHeight;
2042
+ const bottomPx = clamp(pe.startHours + pe.durationHours - startHour, 0, endHour - startHour) * hourHeight;
2043
+ const height = Math.max(bottomPx - top, 2);
2044
+ const lanePct = 100 / pe.columns;
2045
+ const left = `${pe.column * lanePct}%`;
2046
+ const width = `${lanePct}%`;
2047
+ const onPress = () => onPressEvent?.(pe.event);
2048
+ if (onDragEvent) return /* @__PURE__ */ jsx(ResourceBar, {
2049
+ pe,
2050
+ vertical: true,
2051
+ hourSize: hourHeight,
2052
+ left,
2053
+ top,
2054
+ width,
2055
+ height,
2056
+ rendererSize: {
2057
+ width: 0,
2058
+ height
2059
+ },
2060
+ snapMinutes: dragStepMinutes,
2061
+ Renderer,
2062
+ onPress,
2063
+ onDragEvent,
2064
+ theme
2065
+ }, idx);
2066
+ return /* @__PURE__ */ jsx(Pressable, {
2067
+ onPress,
2068
+ accessibilityRole: "button",
2069
+ accessibilityLabel: pe.event.title,
2070
+ style: {
2071
+ position: "absolute",
2072
+ left,
2073
+ width,
2074
+ top,
2075
+ height,
2076
+ padding: 1
2077
+ },
2078
+ children: /* @__PURE__ */ jsx(Renderer, {
2079
+ event: pe.event,
2080
+ width: 0,
2081
+ height,
2082
+ onPress
2083
+ })
2084
+ }, idx);
2085
+ })]
2086
+ }, resource.id);
2087
+ })]
2088
+ })
2089
+ })]
2090
+ });
2091
+ }
1804
2092
  return /* @__PURE__ */ jsx(ScrollView, {
1805
2093
  horizontal: true,
1806
2094
  showsHorizontalScrollIndicator: true,
@@ -1865,10 +2153,13 @@ function ResourceTimeline({ date, resources, events, resourceId = (event) => eve
1865
2153
  const onPress = () => onPressEvent?.(pe.event);
1866
2154
  if (onDragEvent) return /* @__PURE__ */ jsx(ResourceBar, {
1867
2155
  pe,
2156
+ vertical: false,
2157
+ hourSize: hourWidth,
1868
2158
  left,
2159
+ top: pe.column * laneHeight,
1869
2160
  width,
1870
- laneHeight,
1871
- hourWidth,
2161
+ height: laneHeight,
2162
+ rendererSize: { width },
1872
2163
  snapMinutes: dragStepMinutes,
1873
2164
  Renderer,
1874
2165
  onPress,
@@ -1946,7 +2237,44 @@ const styles = StyleSheet.create({
1946
2237
  width: 4,
1947
2238
  borderRadius: 2,
1948
2239
  opacity: .5
2240
+ },
2241
+ resizeGripBottom: {
2242
+ position: "absolute",
2243
+ bottom: 1,
2244
+ left: "30%",
2245
+ right: "30%",
2246
+ height: 4,
2247
+ borderRadius: 2,
2248
+ opacity: .5
2249
+ },
2250
+ vroot: { flex: 1 },
2251
+ vheaderCell: {
2252
+ flex: 1,
2253
+ paddingVertical: 6,
2254
+ paddingHorizontal: 4,
2255
+ alignItems: "center",
2256
+ borderLeftWidth: StyleSheet.hairlineWidth
2257
+ },
2258
+ vheaderText: {
2259
+ fontSize: 13,
2260
+ fontWeight: "600"
2261
+ },
2262
+ vbody: { flexDirection: "row" },
2263
+ vcolumn: {
2264
+ flex: 1,
2265
+ borderLeftWidth: StyleSheet.hairlineWidth
2266
+ },
2267
+ vhourLabel: {
2268
+ position: "absolute",
2269
+ right: 6,
2270
+ fontSize: 10
2271
+ },
2272
+ vgridLine: {
2273
+ position: "absolute",
2274
+ left: 0,
2275
+ right: 0,
2276
+ height: StyleSheet.hairlineWidth
1949
2277
  }
1950
2278
  });
1951
2279
  //#endregion
1952
- export { Agenda, Calendar, CalendarThemeProvider, DEFAULT_HOUR_HEIGHT, DefaultEvent, DefaultMonthEvent, MonthList, MonthPager, MonthView, ResourceTimeline, TimeGrid, buildMonthGrid, buildMonthWeeks, darkTheme, daySelectionState, defaultTheme, eventsInTimeZone, expandRecurringEvents, getIsToday, getViewDays, getWeekDays, isAllDayEvent, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isWeekend, isWithinDateRange, layoutDayEvents, mergeTheme, minutesIntoDay, nextDateRange, toZonedTime, useCalendarTheme, useDateRange, useMonthGrid, weekdayFormatToken };
2280
+ export { Agenda, Calendar, CalendarThemeProvider, DEFAULT_HOUR_HEIGHT, DefaultEvent, DefaultMonthEvent, MonthList, MonthPager, MonthView, ResourceTimeline, TimeGrid, buildMonthGrid, buildMonthWeeks, darkTheme, daySelectionState, defaultTheme, eventsInTimeZone, expandRecurringEvents, getIsToday, getViewDays, getWeekDays, isAllDayEvent, isDateSelectable, isRangeEndpoint, isSameCalendarDay, isWeekend, isWithinDateRange, layoutDayEvents, mergeTheme, minutesIntoDay, nextDateRange, parseICalendar, toICalendar, toZonedTime, useCalendarTheme, useDateRange, useMonthGrid, weekdayFormatToken };