@super-calendar/native 2.3.2 → 2.5.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,
@@ -358,7 +378,7 @@ const styles$2 = StyleSheet.create({
358
378
  });
359
379
  //#endregion
360
380
  //#region src/components/TimeGrid.tsx
361
- const isWeb = Platform.OS === "web";
381
+ const isWeb$1 = Platform.OS === "web";
362
382
  const MINUTES_PER_HOUR$1 = 60;
363
383
  const HOURS_PER_DAY = 24;
364
384
  const MINUTES_PER_DAY = MINUTES_PER_HOUR$1 * HOURS_PER_DAY;
@@ -373,7 +393,7 @@ const MIN_EVENT_HEIGHT = 32;
373
393
  const EVENT_GAP = 2;
374
394
  const DRAG_ACTIVATE_MS = 300;
375
395
  const MOVE_ACTIVATE_MS$1 = 500;
376
- const DRAG_ACTIVATE_PX = 8;
396
+ const DRAG_ACTIVATE_PX$1 = 8;
377
397
  const RESIZE_HANDLE_HEIGHT = 14;
378
398
  const DEFAULT_DRAG_STEP_MINUTES = 15;
379
399
  const HOUR_LABEL_TOP_INSET = 12;
@@ -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);
@@ -471,7 +492,7 @@ function AnimatedEventBox({ positioned, cellHeight, minHour, left, width, dayWid
471
492
  const totalDelta = minuteDelta + dayDelta * MINUTES_PER_DAY;
472
493
  runOnJS(commitDrag)(totalDelta, totalDelta);
473
494
  });
474
- return isWeb ? pan.activeOffsetX([-8, DRAG_ACTIVATE_PX]).activeOffsetY([-8, DRAG_ACTIVATE_PX]) : pan.activateAfterLongPress(MOVE_ACTIVATE_MS$1);
495
+ return isWeb$1 ? pan.activeOffsetX([-8, DRAG_ACTIVATE_PX$1]).activeOffsetY([-8, DRAG_ACTIVATE_PX$1]) : pan.activateAfterLongPress(MOVE_ACTIVATE_MS$1);
475
496
  }, [
476
497
  draggable,
477
498
  snapMinutes,
@@ -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);
@@ -637,14 +708,14 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
637
708
  },
638
709
  onEndDrag: (event) => {
639
710
  isDragging.value = false;
640
- if (!isWeb && isActiveShared.value) {
711
+ if (!isWeb$1 && isActiveShared.value) {
641
712
  scrollY.value = event.contentOffset.y;
642
713
  runOnJS(onSettleOffset)(event.contentOffset.y);
643
714
  }
644
715
  },
645
716
  onMomentumEnd: (event) => {
646
717
  isDragging.value = false;
647
- if (!isWeb && isActiveShared.value) {
718
+ if (!isWeb$1 && isActiveShared.value) {
648
719
  scrollY.value = event.contentOffset.y;
649
720
  runOnJS(onSettleOffset)(event.contentOffset.y);
650
721
  }
@@ -654,7 +725,7 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
654
725
  if (!isActiveShared.value && current !== previous) scrollTo(scrollRef, 0, current, false);
655
726
  });
656
727
  useAnimatedReaction(() => isActiveShared.value, (active, previous) => {
657
- if (isWeb || !active || active === previous) return;
728
+ if (isWeb$1 || !active || active === previous) return;
658
729
  scrollTo(scrollRef, 0, scrollY.value, false);
659
730
  });
660
731
  const days = useMemo(() => getViewDays$1(mode, date, weekStartsOn, numberOfDays, isRTL, weekEndsOn), [
@@ -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);
@@ -775,7 +848,7 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
775
848
  if (createCancelled.value) return;
776
849
  runOnJS(commitCreate)(createStartY.value, createStartY.value + event.translationY, createDayIndex.value);
777
850
  });
778
- return isWeb ? pan.activeOffsetY([-8, DRAG_ACTIVATE_PX]) : pan.activateAfterLongPress(DRAG_ACTIVATE_MS);
851
+ return isWeb$1 ? pan.activeOffsetY([-8, DRAG_ACTIVATE_PX$1]) : pan.activateAfterLongPress(DRAG_ACTIVATE_MS);
779
852
  }, [
780
853
  createEnabled,
781
854
  dayCount,
@@ -794,7 +867,7 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
794
867
  createCancelled
795
868
  ]);
796
869
  const backgroundGesture = useMemo(() => {
797
- const tap = isWeb && onPressCell != null ? Gesture.Tap().onEnd((event) => {
870
+ const tap = isWeb$1 && onPressCell != null ? Gesture.Tap().onEnd((event) => {
798
871
  runOnJS(tapCell)(event.x, event.y);
799
872
  }) : null;
800
873
  if (createEnabled && tap) return Gesture.Exclusive(createGesture, tap);
@@ -807,7 +880,7 @@ function TimetablePageInner({ mode, numberOfDays, date, events, cellHeight, hour
807
880
  tapCell
808
881
  ]);
809
882
  useEffect(() => {
810
- if (!isWeb || !createEnabled) return;
883
+ if (!isWeb$1 || !createEnabled) return;
811
884
  const doc = globalThis.document;
812
885
  if (!doc) return;
813
886
  const handler = (event) => {
@@ -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;
@@ -996,7 +1086,7 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
996
1086
  offsetSeedRef.current = y;
997
1087
  }, []);
998
1088
  const committedCellHeight = useSharedValue(hourHeight);
999
- useWebGridZoom(isWeb, containerRef, cellHeight, committedCellHeight, minHourHeight, maxHourHeight);
1089
+ useWebGridZoom(isWeb$1, containerRef, cellHeight, committedCellHeight, minHourHeight, maxHourHeight);
1000
1090
  const [anchorDate] = useState(date);
1001
1091
  const anchor = useMemo(() => weekAnchored ? startOfWeek(anchorDate, { weekStartsOn }) : startOfDay(anchorDate), [
1002
1092
  weekAnchored,
@@ -1026,7 +1116,7 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1026
1116
  weekEndsOn
1027
1117
  ]);
1028
1118
  const handleViewableItemsChanged = useCallback((info) => {
1029
- if (isWeb) return;
1119
+ if (isWeb$1) return;
1030
1120
  const settled = info.viewableItems.find((token) => token.isViewable);
1031
1121
  if (settled?.index == null) return;
1032
1122
  if (pendingScrollIndexRef.current != null) {
@@ -1050,7 +1140,7 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1050
1140
  });
1051
1141
  }, [activeIndex]);
1052
1142
  useEffect(() => {
1053
- if (!isWeb) return;
1143
+ if (!isWeb$1) return;
1054
1144
  const root = containerRef.current;
1055
1145
  if (!root) return;
1056
1146
  const restoreVisiblePage = () => {
@@ -1077,7 +1167,7 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1077
1167
  };
1078
1168
  }, [activeIndex, pageHeight]);
1079
1169
  useEffect(() => {
1080
- if (!isWeb) return;
1170
+ if (!isWeb$1) return;
1081
1171
  const root = containerRef.current;
1082
1172
  if (!root) return;
1083
1173
  const onScrollCapture = (event) => {
@@ -1094,7 +1184,7 @@ function TimeGridInner({ mode, numberOfDays = 1, weekEndsOn, date, events, cellH
1094
1184
  return () => root.removeEventListener("scroll", onScrollCapture, true);
1095
1185
  }, []);
1096
1186
  useEffect(() => {
1097
- if (!isWeb) return;
1187
+ if (!isWeb$1) return;
1098
1188
  const root = containerRef.current;
1099
1189
  if (!root) return;
1100
1190
  const lockHorizontal = () => {
@@ -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$1 ? [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$1 ? 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,17 +1762,23 @@ 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
  }
1631
1771
  //#endregion
1632
1772
  //#region src/components/ResourceTimeline.tsx
1633
1773
  const MOVE_ACTIVATE_MS = 250;
1774
+ const DRAG_ACTIVATE_PX = 8;
1634
1775
  const MINUTES_PER_HOUR = 60;
1776
+ const isWeb = Platform.OS === "web";
1635
1777
  const clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
1636
- function DefaultBar({ event, width }) {
1778
+ const GUTTER_WIDTH = 56;
1779
+ function DefaultBar({ event, width, height }) {
1637
1780
  const theme = useCalendarTheme();
1781
+ const showTime = height != null ? height > 34 : width > 56;
1638
1782
  const time = eventTimeLabel({
1639
1783
  mode: "day",
1640
1784
  isAllDay: false,
@@ -1654,7 +1798,7 @@ function DefaultBar({ event, width }) {
1654
1798
  style: [theme.text.eventTitle, { color: theme.colors.eventText }],
1655
1799
  allowFontScaling: false,
1656
1800
  children: event.title
1657
- }), time && width > 56 ? /* @__PURE__ */ jsx(Text, {
1801
+ }), time && showTime ? /* @__PURE__ */ jsx(Text, {
1658
1802
  numberOfLines: 1,
1659
1803
  style: [styles.barTime, { color: theme.colors.eventText }],
1660
1804
  allowFontScaling: false,
@@ -1662,7 +1806,7 @@ function DefaultBar({ event, width }) {
1662
1806
  }) : null]
1663
1807
  });
1664
1808
  }
1665
- function ResourceBar({ pe, left, width, laneHeight, hourWidth, snapMinutes, Renderer, onPress, onDragEvent, theme }) {
1809
+ function ResourceBar({ pe, vertical, hourSize, left, top, width, height, rendererSize, snapMinutes, Renderer, onPress, onLongPress, onDragEvent, theme }) {
1666
1810
  const moveX = useSharedValue(0);
1667
1811
  const resizeW = useSharedValue(0);
1668
1812
  const latest = useRef({
@@ -1696,75 +1840,236 @@ function ResourceBar({ pe, left, width, laneHeight, hourWidth, snapMinutes, Rend
1696
1840
  }
1697
1841
  if (handler(event, next.start, next.end) === false) snapBack();
1698
1842
  }, [snapMinutes, snapBack]);
1699
- const barStyle = useAnimatedStyle(() => ({
1843
+ const unit = (n) => `${n} minute${n === 1 ? "" : "s"}`;
1844
+ const barActions = draggable ? [
1845
+ {
1846
+ name: "move-later",
1847
+ label: `Move ${unit(snapMinutes)} later`
1848
+ },
1849
+ {
1850
+ name: "move-earlier",
1851
+ label: `Move ${unit(snapMinutes)} earlier`
1852
+ },
1853
+ {
1854
+ name: "extend",
1855
+ label: `Extend by ${unit(snapMinutes)}`
1856
+ },
1857
+ {
1858
+ name: "shrink",
1859
+ label: `Shorten by ${unit(snapMinutes)}`
1860
+ }
1861
+ ] : void 0;
1862
+ const onBarAction = draggable ? (e) => {
1863
+ switch (e.nativeEvent.actionName) {
1864
+ case "move-later":
1865
+ commit(snapMinutes, snapMinutes);
1866
+ break;
1867
+ case "move-earlier":
1868
+ commit(-snapMinutes, -snapMinutes);
1869
+ break;
1870
+ case "extend":
1871
+ commit(0, snapMinutes);
1872
+ break;
1873
+ case "shrink":
1874
+ commit(0, -snapMinutes);
1875
+ break;
1876
+ }
1877
+ } : void 0;
1878
+ const barStyle = useAnimatedStyle(() => vertical ? {
1879
+ transform: [{ translateY: moveX.value }],
1880
+ height: Math.max(height + resizeW.value, 2)
1881
+ } : {
1700
1882
  transform: [{ translateX: moveX.value }],
1701
1883
  width: Math.max(width + resizeW.value, 2)
1702
- }), [width]);
1884
+ }, [
1885
+ vertical,
1886
+ width,
1887
+ height
1888
+ ]);
1703
1889
  const moveGesture = useMemo(() => Gesture.Pan().enabled(draggable).activateAfterLongPress(MOVE_ACTIVATE_MS).onUpdate((e) => {
1704
- moveX.value = e.translationX;
1890
+ moveX.value = vertical ? e.translationY : e.translationX;
1705
1891
  }).onEnd((e) => {
1706
- const delta = snapDeltaMinutes(e.translationX, hourWidth, snapMinutes);
1892
+ const delta = snapDeltaMinutes(vertical ? e.translationY : e.translationX, hourSize, snapMinutes);
1707
1893
  if (delta === 0) {
1708
1894
  moveX.value = 0;
1709
1895
  return;
1710
1896
  }
1711
- moveX.value = delta / MINUTES_PER_HOUR * hourWidth;
1897
+ moveX.value = delta / MINUTES_PER_HOUR * hourSize;
1712
1898
  runOnJS(commit)(delta, delta);
1713
1899
  }), [
1714
1900
  draggable,
1715
- hourWidth,
1901
+ vertical,
1902
+ hourSize,
1716
1903
  snapMinutes,
1717
1904
  moveX,
1718
1905
  commit
1719
1906
  ]);
1720
1907
  const resizeGesture = useMemo(() => Gesture.Pan().enabled(draggable).onUpdate((e) => {
1721
- resizeW.value = e.translationX;
1908
+ resizeW.value = vertical ? e.translationY : e.translationX;
1722
1909
  }).onEnd((e) => {
1723
- const delta = snapDeltaMinutes(e.translationX, hourWidth, snapMinutes);
1910
+ const delta = snapDeltaMinutes(vertical ? e.translationY : e.translationX, hourSize, snapMinutes);
1724
1911
  if (delta === 0) {
1725
1912
  resizeW.value = 0;
1726
1913
  return;
1727
1914
  }
1728
- resizeW.value = delta / MINUTES_PER_HOUR * hourWidth;
1915
+ resizeW.value = delta / MINUTES_PER_HOUR * hourSize;
1729
1916
  runOnJS(commit)(0, delta);
1730
1917
  }), [
1731
1918
  draggable,
1732
- hourWidth,
1919
+ vertical,
1920
+ hourSize,
1733
1921
  snapMinutes,
1734
1922
  resizeW,
1735
1923
  commit
1736
1924
  ]);
1737
1925
  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],
1926
+ style: [
1927
+ {
1928
+ position: "absolute",
1929
+ left,
1930
+ top,
1931
+ padding: 1
1932
+ },
1933
+ vertical ? { width } : { height },
1934
+ barStyle
1935
+ ],
1745
1936
  children: [/* @__PURE__ */ jsx(GestureDetector, {
1746
1937
  gesture: moveGesture,
1747
1938
  children: /* @__PURE__ */ jsx(Pressable, {
1748
1939
  onPress,
1940
+ onLongPress,
1749
1941
  accessibilityRole: "button",
1750
1942
  accessibilityLabel: pe.event.title,
1943
+ accessibilityActions: barActions,
1944
+ onAccessibilityAction: onBarAction,
1751
1945
  style: styles.fill,
1752
1946
  children: /* @__PURE__ */ jsx(Renderer, {
1753
1947
  event: pe.event,
1754
- width,
1948
+ width: rendererSize.width,
1949
+ height: rendererSize.height,
1755
1950
  onPress
1756
1951
  })
1757
1952
  })
1758
1953
  }), /* @__PURE__ */ jsx(GestureDetector, {
1759
1954
  gesture: resizeGesture,
1760
1955
  children: /* @__PURE__ */ jsx(View, {
1761
- style: [styles.resizeGrip, { backgroundColor: theme.colors.eventText }],
1762
- accessibilityRole: "adjustable",
1763
- accessibilityLabel: `Resize ${pe.event.title}`
1956
+ testID: "resource-resize-grip",
1957
+ style: [vertical ? styles.resizeGripBottom : styles.resizeGrip, { backgroundColor: theme.colors.eventText }],
1958
+ accessibilityElementsHidden: true,
1959
+ importantForAccessibility: "no"
1764
1960
  })
1765
1961
  })]
1766
1962
  });
1767
1963
  }
1964
+ function LaneInteractionLayer({ resource, vertical, hourSize, startHour, date, snapMinutes, onPressCell, onLongPressCell, onCreateEvent, theme }) {
1965
+ const ghostStart = useSharedValue(0);
1966
+ const ghostSize = useSharedValue(0);
1967
+ const ghostVisible = useSharedValue(0);
1968
+ const timeAt = useCallback((px) => cellRangeFromDrag(date, px, px, hourSize, startHour, snapMinutes)?.start, [
1969
+ date,
1970
+ hourSize,
1971
+ startHour,
1972
+ snapMinutes
1973
+ ]);
1974
+ const commitCreate = useCallback((fromPx, toPx) => {
1975
+ const range = cellRangeFromDrag(date, fromPx, toPx, hourSize, startHour, snapMinutes);
1976
+ if (range) onCreateEvent?.(range.start, range.end, resource);
1977
+ }, [
1978
+ date,
1979
+ hourSize,
1980
+ startHour,
1981
+ snapMinutes,
1982
+ onCreateEvent,
1983
+ resource
1984
+ ]);
1985
+ const pressAt = useCallback((px) => {
1986
+ const at = timeAt(px);
1987
+ if (at) onPressCell?.(at, resource);
1988
+ }, [
1989
+ timeAt,
1990
+ onPressCell,
1991
+ resource
1992
+ ]);
1993
+ const laneGesture = useMemo(() => {
1994
+ const pan = onCreateEvent ? Gesture.Pan().onStart((e) => {
1995
+ ghostStart.value = vertical ? e.y : e.x;
1996
+ ghostSize.value = 0;
1997
+ ghostVisible.value = 1;
1998
+ }).onUpdate((e) => {
1999
+ ghostSize.value = (vertical ? e.y : e.x) - ghostStart.value;
2000
+ }).onEnd((e, success) => {
2001
+ ghostVisible.value = 0;
2002
+ if (success) runOnJS(commitCreate)(ghostStart.value, vertical ? e.y : e.x);
2003
+ }).onFinalize(() => {
2004
+ ghostVisible.value = 0;
2005
+ }) : null;
2006
+ const activatedPan = pan ? isWeb ? vertical ? pan.activeOffsetY([-8, DRAG_ACTIVATE_PX]) : pan.activeOffsetX([-8, DRAG_ACTIVATE_PX]) : pan.activateAfterLongPress(MOVE_ACTIVATE_MS) : null;
2007
+ const tap = isWeb && onPressCell ? Gesture.Tap().onEnd((e) => {
2008
+ runOnJS(pressAt)(vertical ? e.y : e.x);
2009
+ }) : null;
2010
+ if (activatedPan && tap) return Gesture.Exclusive(activatedPan, tap);
2011
+ return activatedPan ?? tap;
2012
+ }, [
2013
+ onCreateEvent,
2014
+ onPressCell,
2015
+ vertical,
2016
+ commitCreate,
2017
+ pressAt,
2018
+ ghostStart,
2019
+ ghostSize,
2020
+ ghostVisible
2021
+ ]);
2022
+ const ghostStyle = useAnimatedStyle(() => {
2023
+ const stepPx = snapMinutes / MINUTES_PER_HOUR * hourSize;
2024
+ const snap = (v) => stepPx > 0 ? Math.round(v / stepPx) * stepPx : v;
2025
+ const a = snap(ghostStart.value);
2026
+ const b = snap(ghostStart.value + ghostSize.value);
2027
+ const from = Math.min(a, b);
2028
+ const size = Math.max(Math.abs(b - a), 2);
2029
+ return vertical ? {
2030
+ opacity: ghostVisible.value,
2031
+ top: from,
2032
+ height: size
2033
+ } : {
2034
+ opacity: ghostVisible.value,
2035
+ left: from,
2036
+ width: size
2037
+ };
2038
+ }, [
2039
+ vertical,
2040
+ hourSize,
2041
+ snapMinutes
2042
+ ]);
2043
+ const pxOf = (e) => vertical ? e.nativeEvent.locationY : e.nativeEvent.locationX;
2044
+ const handlePress = onPressCell ? (e) => pressAt(pxOf(e)) : void 0;
2045
+ const handleLongPress = onLongPressCell && !onCreateEvent ? (e) => {
2046
+ const at = timeAt(pxOf(e));
2047
+ if (at) onLongPressCell(at, resource);
2048
+ } : void 0;
2049
+ const layer = /* @__PURE__ */ jsx(Pressable, {
2050
+ testID: "resource-cell-layer",
2051
+ style: StyleSheet.absoluteFill,
2052
+ onPress: handlePress,
2053
+ onLongPress: handleLongPress,
2054
+ accessibilityElementsHidden: true,
2055
+ importantForAccessibility: "no"
2056
+ });
2057
+ return /* @__PURE__ */ jsxs(Fragment, { children: [laneGesture ? /* @__PURE__ */ jsx(GestureDetector, {
2058
+ gesture: laneGesture,
2059
+ children: layer
2060
+ }) : layer, onCreateEvent ? /* @__PURE__ */ jsx(Animated.View, {
2061
+ testID: "resource-create-ghost",
2062
+ pointerEvents: "none",
2063
+ style: [
2064
+ vertical ? styles.vcreateGhost : styles.hcreateGhost,
2065
+ {
2066
+ backgroundColor: theme.colors.eventBackground,
2067
+ borderColor: theme.colors.todayBackground
2068
+ },
2069
+ ghostStyle
2070
+ ]
2071
+ }) : null] });
2072
+ }
1768
2073
  /**
1769
2074
  * A horizontal resource timeline: rows are resources (rooms, people, machines)
1770
2075
  * and the x-axis is one day's hours. Events sit in their resource's row, and
@@ -1783,9 +2088,11 @@ function ResourceBar({ pe, left, width, laneHeight, hourWidth, snapMinutes, Rend
1783
2088
  * />
1784
2089
  * ```
1785
2090
  */
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 }) {
2091
+ 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, onLongPressEvent, onDragEvent, onPressCell, onLongPressCell, onCreateEvent, businessHours, dragStepMinutes = 15 }) {
1787
2092
  const theme = useCalendarTheme();
1788
2093
  const Renderer = renderEvent ?? DefaultBar;
2094
+ const cellEnabled = !!onPressCell || !!onLongPressCell || !!onCreateEvent;
2095
+ const bandsFor = (resource) => businessHours ? closedHourBands(date, (d) => businessHours(d, resource), startHour, endHour) : [];
1789
2096
  const hours = useMemo(() => Array.from({ length: Math.max(0, endHour - startHour) }, (_, i) => startHour + i), [startHour, endHour]);
1790
2097
  const trackWidth = (endHour - startHour) * hourWidth;
1791
2098
  const byResource = useMemo(() => {
@@ -1801,6 +2108,127 @@ function ResourceTimeline({ date, resources, events, resourceId = (event) => eve
1801
2108
  resourceId,
1802
2109
  date
1803
2110
  ]);
2111
+ if (orientation === "vertical") {
2112
+ const trackHeight = (endHour - startHour) * hourHeight;
2113
+ return /* @__PURE__ */ jsxs(View, {
2114
+ style: styles.vroot,
2115
+ children: [/* @__PURE__ */ jsxs(View, {
2116
+ style: [styles.header, { borderBottomColor: theme.colors.gridLine }],
2117
+ children: [/* @__PURE__ */ jsx(View, { style: { width: GUTTER_WIDTH } }), resources.map((resource) => /* @__PURE__ */ jsx(View, {
2118
+ style: [styles.vheaderCell, theme.containers.resourceLabel],
2119
+ children: /* @__PURE__ */ jsx(Text, {
2120
+ numberOfLines: 1,
2121
+ style: [styles.vheaderText, { color: theme.colors.text }],
2122
+ allowFontScaling: false,
2123
+ children: resource.title ?? resource.id
2124
+ })
2125
+ }, resource.id))]
2126
+ }), /* @__PURE__ */ jsx(ScrollView, {
2127
+ showsVerticalScrollIndicator: true,
2128
+ children: /* @__PURE__ */ jsxs(View, {
2129
+ style: [styles.vbody, { height: trackHeight }],
2130
+ children: [/* @__PURE__ */ jsx(View, {
2131
+ style: { width: GUTTER_WIDTH },
2132
+ children: hours.map((h) => /* @__PURE__ */ jsx(Text, {
2133
+ allowFontScaling: false,
2134
+ style: [styles.vhourLabel, {
2135
+ top: Math.max(0, (h - startHour) * hourHeight - 6),
2136
+ color: theme.colors.textMuted
2137
+ }],
2138
+ children: formatHour(h, { ampm })
2139
+ }, h))
2140
+ }), resources.map((resource) => {
2141
+ const positioned = byResource.get(resource.id) ?? [];
2142
+ return /* @__PURE__ */ jsxs(View, {
2143
+ style: [
2144
+ styles.vcolumn,
2145
+ { borderLeftColor: theme.colors.gridLine },
2146
+ theme.containers.resourceRow
2147
+ ],
2148
+ children: [
2149
+ bandsFor(resource).map((b) => /* @__PURE__ */ jsx(View, {
2150
+ pointerEvents: "none",
2151
+ testID: "resource-hours-shade",
2152
+ style: [styles.vshadeBand, {
2153
+ top: (b.start - startHour) * hourHeight,
2154
+ height: (b.end - b.start) * hourHeight,
2155
+ backgroundColor: theme.colors.outsideHoursBackground
2156
+ }]
2157
+ }, `shade-${b.start}`)),
2158
+ hours.slice(1).map((h) => /* @__PURE__ */ jsx(View, {
2159
+ pointerEvents: "none",
2160
+ style: [styles.vgridLine, {
2161
+ top: (h - startHour) * hourHeight,
2162
+ backgroundColor: theme.colors.gridLine
2163
+ }]
2164
+ }, h)),
2165
+ cellEnabled ? /* @__PURE__ */ jsx(LaneInteractionLayer, {
2166
+ resource,
2167
+ vertical: true,
2168
+ hourSize: hourHeight,
2169
+ startHour,
2170
+ date,
2171
+ snapMinutes: dragStepMinutes,
2172
+ onPressCell,
2173
+ onLongPressCell,
2174
+ onCreateEvent,
2175
+ theme
2176
+ }) : null,
2177
+ positioned.map((pe, idx) => {
2178
+ const top = clamp(pe.startHours - startHour, 0, endHour - startHour) * hourHeight;
2179
+ const bottomPx = clamp(pe.startHours + pe.durationHours - startHour, 0, endHour - startHour) * hourHeight;
2180
+ const height = Math.max(bottomPx - top, 2);
2181
+ const lanePct = 100 / pe.columns;
2182
+ const left = `${pe.column * lanePct}%`;
2183
+ const width = `${lanePct}%`;
2184
+ const onPress = () => onPressEvent?.(pe.event);
2185
+ if (onDragEvent) return /* @__PURE__ */ jsx(ResourceBar, {
2186
+ pe,
2187
+ vertical: true,
2188
+ hourSize: hourHeight,
2189
+ left,
2190
+ top,
2191
+ width,
2192
+ height,
2193
+ rendererSize: {
2194
+ width: 0,
2195
+ height
2196
+ },
2197
+ snapMinutes: dragStepMinutes,
2198
+ Renderer,
2199
+ onPress,
2200
+ onLongPress: onLongPressEvent ? () => onLongPressEvent(pe.event) : void 0,
2201
+ onDragEvent,
2202
+ theme
2203
+ }, idx);
2204
+ return /* @__PURE__ */ jsx(Pressable, {
2205
+ onPress,
2206
+ onLongPress: onLongPressEvent ? () => onLongPressEvent(pe.event) : void 0,
2207
+ accessibilityRole: "button",
2208
+ accessibilityLabel: pe.event.title,
2209
+ style: {
2210
+ position: "absolute",
2211
+ left,
2212
+ width,
2213
+ top,
2214
+ height,
2215
+ padding: 1
2216
+ },
2217
+ children: /* @__PURE__ */ jsx(Renderer, {
2218
+ event: pe.event,
2219
+ width: 0,
2220
+ height,
2221
+ onPress
2222
+ })
2223
+ }, idx);
2224
+ })
2225
+ ]
2226
+ }, resource.id);
2227
+ })]
2228
+ })
2229
+ })]
2230
+ });
2231
+ }
1804
2232
  return /* @__PURE__ */ jsx(ScrollView, {
1805
2233
  horizontal: true,
1806
2234
  showsHorizontalScrollIndicator: true,
@@ -1851,49 +2279,78 @@ function ResourceTimeline({ date, resources, events, resourceId = (event) => eve
1851
2279
  })
1852
2280
  }), /* @__PURE__ */ jsxs(View, {
1853
2281
  style: { width: trackWidth },
1854
- children: [hours.slice(1).map((h) => /* @__PURE__ */ jsx(View, {
1855
- pointerEvents: "none",
1856
- style: [styles.gridLine, {
1857
- left: (h - startHour) * hourWidth,
1858
- backgroundColor: theme.colors.gridLine
1859
- }]
1860
- }, h)), positioned.map((pe, idx) => {
1861
- const left = clamp(pe.startHours - startHour, 0, endHour - startHour) * hourWidth;
1862
- const right = clamp(pe.startHours + pe.durationHours - startHour, 0, endHour - startHour) * hourWidth;
1863
- const width = Math.max(right - left, 2);
1864
- const laneHeight = rowHeight / pe.columns;
1865
- const onPress = () => onPressEvent?.(pe.event);
1866
- if (onDragEvent) return /* @__PURE__ */ jsx(ResourceBar, {
1867
- pe,
1868
- left,
1869
- width,
1870
- laneHeight,
1871
- hourWidth,
2282
+ children: [
2283
+ bandsFor(resource).map((b) => /* @__PURE__ */ jsx(View, {
2284
+ pointerEvents: "none",
2285
+ testID: "resource-hours-shade",
2286
+ style: [styles.hshadeBand, {
2287
+ left: (b.start - startHour) * hourWidth,
2288
+ width: (b.end - b.start) * hourWidth,
2289
+ backgroundColor: theme.colors.outsideHoursBackground
2290
+ }]
2291
+ }, `shade-${b.start}`)),
2292
+ hours.slice(1).map((h) => /* @__PURE__ */ jsx(View, {
2293
+ pointerEvents: "none",
2294
+ style: [styles.gridLine, {
2295
+ left: (h - startHour) * hourWidth,
2296
+ backgroundColor: theme.colors.gridLine
2297
+ }]
2298
+ }, h)),
2299
+ cellEnabled ? /* @__PURE__ */ jsx(LaneInteractionLayer, {
2300
+ resource,
2301
+ vertical: false,
2302
+ hourSize: hourWidth,
2303
+ startHour,
2304
+ date,
1872
2305
  snapMinutes: dragStepMinutes,
1873
- Renderer,
1874
- onPress,
1875
- onDragEvent,
2306
+ onPressCell,
2307
+ onLongPressCell,
2308
+ onCreateEvent,
1876
2309
  theme
1877
- }, idx);
1878
- return /* @__PURE__ */ jsx(Pressable, {
1879
- onPress,
1880
- accessibilityRole: "button",
1881
- accessibilityLabel: pe.event.title,
1882
- style: {
1883
- position: "absolute",
2310
+ }) : null,
2311
+ positioned.map((pe, idx) => {
2312
+ const left = clamp(pe.startHours - startHour, 0, endHour - startHour) * hourWidth;
2313
+ const right = clamp(pe.startHours + pe.durationHours - startHour, 0, endHour - startHour) * hourWidth;
2314
+ const width = Math.max(right - left, 2);
2315
+ const laneHeight = rowHeight / pe.columns;
2316
+ const onPress = () => onPressEvent?.(pe.event);
2317
+ if (onDragEvent) return /* @__PURE__ */ jsx(ResourceBar, {
2318
+ pe,
2319
+ vertical: false,
2320
+ hourSize: hourWidth,
1884
2321
  left,
1885
- width,
1886
2322
  top: pe.column * laneHeight,
1887
- height: laneHeight,
1888
- padding: 1
1889
- },
1890
- children: /* @__PURE__ */ jsx(Renderer, {
1891
- event: pe.event,
1892
2323
  width,
1893
- onPress
1894
- })
1895
- }, idx);
1896
- })]
2324
+ height: laneHeight,
2325
+ rendererSize: { width },
2326
+ snapMinutes: dragStepMinutes,
2327
+ Renderer,
2328
+ onPress,
2329
+ onLongPress: onLongPressEvent ? () => onLongPressEvent(pe.event) : void 0,
2330
+ onDragEvent,
2331
+ theme
2332
+ }, idx);
2333
+ return /* @__PURE__ */ jsx(Pressable, {
2334
+ onPress,
2335
+ onLongPress: onLongPressEvent ? () => onLongPressEvent(pe.event) : void 0,
2336
+ accessibilityRole: "button",
2337
+ accessibilityLabel: pe.event.title,
2338
+ style: {
2339
+ position: "absolute",
2340
+ left,
2341
+ width,
2342
+ top: pe.column * laneHeight,
2343
+ height: laneHeight,
2344
+ padding: 1
2345
+ },
2346
+ children: /* @__PURE__ */ jsx(Renderer, {
2347
+ event: pe.event,
2348
+ width,
2349
+ onPress
2350
+ })
2351
+ }, idx);
2352
+ })
2353
+ ]
1897
2354
  })]
1898
2355
  }, resource.id);
1899
2356
  })]
@@ -1946,7 +2403,72 @@ const styles = StyleSheet.create({
1946
2403
  width: 4,
1947
2404
  borderRadius: 2,
1948
2405
  opacity: .5
2406
+ },
2407
+ resizeGripBottom: {
2408
+ position: "absolute",
2409
+ bottom: 1,
2410
+ left: "30%",
2411
+ right: "30%",
2412
+ height: 4,
2413
+ borderRadius: 2,
2414
+ opacity: .5
2415
+ },
2416
+ vroot: { flex: 1 },
2417
+ vheaderCell: {
2418
+ flex: 1,
2419
+ paddingVertical: 6,
2420
+ paddingHorizontal: 4,
2421
+ alignItems: "center",
2422
+ borderLeftWidth: StyleSheet.hairlineWidth
2423
+ },
2424
+ vheaderText: {
2425
+ fontSize: 13,
2426
+ fontWeight: "600"
2427
+ },
2428
+ vbody: { flexDirection: "row" },
2429
+ vcolumn: {
2430
+ flex: 1,
2431
+ borderLeftWidth: StyleSheet.hairlineWidth
2432
+ },
2433
+ vhourLabel: {
2434
+ position: "absolute",
2435
+ right: 6,
2436
+ fontSize: 10
2437
+ },
2438
+ vgridLine: {
2439
+ position: "absolute",
2440
+ left: 0,
2441
+ right: 0,
2442
+ height: StyleSheet.hairlineWidth
2443
+ },
2444
+ vcreateGhost: {
2445
+ position: "absolute",
2446
+ left: 2,
2447
+ right: 2,
2448
+ borderWidth: 1,
2449
+ borderRadius: 6,
2450
+ opacity: 0,
2451
+ zIndex: 2
2452
+ },
2453
+ hcreateGhost: {
2454
+ position: "absolute",
2455
+ top: 2,
2456
+ bottom: 2,
2457
+ borderWidth: 1,
2458
+ borderRadius: 6,
2459
+ opacity: 0,
2460
+ zIndex: 2
2461
+ },
2462
+ hshadeBand: {
2463
+ position: "absolute",
2464
+ top: 0,
2465
+ bottom: 0
2466
+ },
2467
+ vshadeBand: {
2468
+ position: "absolute",
2469
+ left: 0,
2470
+ right: 0
1949
2471
  }
1950
2472
  });
1951
2473
  //#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 };
2474
+ 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 };