react-native-bigger-calendar 0.1.0 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-bigger-calendar",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A generic, themeable month/week/day calendar for React Native with pinch-to-zoom, virtualized paging, and a render-prop event API.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -0,0 +1,125 @@
1
+ import { LegendList, type LegendListRenderItemProps } from '@legendapp/list/react-native';
2
+ import { format, isSameDay, type Locale, startOfDay } from 'date-fns';
3
+ import { type ComponentType, useCallback, useMemo } from 'react';
4
+ import { StyleSheet, Text, View } from 'react-native';
5
+ import { useCalendarTheme } from '../theme';
6
+ import type { CalendarEvent, EventKeyExtractor, RenderEvent } from '../types';
7
+ import { getIsToday } from '../utils/dates';
8
+
9
+ export type AgendaProps<T> = {
10
+ events: CalendarEvent<T>[];
11
+ locale?: Locale;
12
+ renderEvent: RenderEvent<T>;
13
+ keyExtractor: EventKeyExtractor<T>;
14
+ onPressEvent: (event: CalendarEvent<T>) => void;
15
+ onLongPressEvent?: (event: CalendarEvent<T>) => void;
16
+ onPressDay?: (date: Date) => void;
17
+ /** Highlight this date's header instead of the real "today". */
18
+ activeDate?: Date;
19
+ /** Drawn between rows of the agenda list. */
20
+ itemSeparatorComponent?: ComponentType<unknown> | null;
21
+ };
22
+
23
+ type Row<T> =
24
+ | { kind: 'header'; date: Date; key: string }
25
+ | { kind: 'event'; event: CalendarEvent<T>; index: number; key: string };
26
+
27
+ /**
28
+ * A vertical, day-grouped list of events (no time grid). Events are sorted by
29
+ * start, grouped under a date header per day. The consumer controls which
30
+ * events (and therefore which date range) are shown.
31
+ */
32
+ export function Agenda<T>({
33
+ events,
34
+ locale,
35
+ renderEvent,
36
+ keyExtractor,
37
+ onPressEvent,
38
+ onLongPressEvent,
39
+ onPressDay,
40
+ activeDate,
41
+ itemSeparatorComponent,
42
+ }: AgendaProps<T>) {
43
+ const theme = useCalendarTheme();
44
+ const RenderEventComponent = renderEvent;
45
+
46
+ const rows = useMemo<Row<T>[]>(() => {
47
+ const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime());
48
+ const out: Row<T>[] = [];
49
+ let currentDay: Date | null = null;
50
+ sorted.forEach((event, index) => {
51
+ if (!currentDay || !isSameDay(event.start, currentDay)) {
52
+ currentDay = startOfDay(event.start);
53
+ out.push({ kind: 'header', date: currentDay, key: `h-${currentDay.toISOString()}` });
54
+ }
55
+ out.push({ kind: 'event', event, index, key: `e-${keyExtractor(event, index)}` });
56
+ });
57
+ return out;
58
+ }, [events, keyExtractor]);
59
+
60
+ const keyExtractorRow = useCallback((row: Row<T>) => row.key, []);
61
+ const renderItem = useCallback(
62
+ ({ item }: LegendListRenderItemProps<Row<T>>) => {
63
+ if (item.kind === 'header') {
64
+ const isHighlighted = activeDate
65
+ ? isSameDay(item.date, activeDate)
66
+ : getIsToday(item.date);
67
+ return (
68
+ <Text
69
+ style={[
70
+ theme.text.weekday,
71
+ styles.header,
72
+ { color: isHighlighted ? theme.colors.todayBackground : theme.colors.textMuted },
73
+ ]}
74
+ onPress={onPressDay ? () => onPressDay(item.date) : undefined}
75
+ accessibilityRole={onPressDay ? 'button' : 'header'}
76
+ >
77
+ {format(item.date, 'EEEE, d LLLL', { locale })}
78
+ </Text>
79
+ );
80
+ }
81
+ return (
82
+ <View style={styles.eventRow}>
83
+ <RenderEventComponent
84
+ event={item.event}
85
+ mode="schedule"
86
+ onPress={() => onPressEvent(item.event)}
87
+ onLongPress={onLongPressEvent ? () => onLongPressEvent(item.event) : undefined}
88
+ />
89
+ </View>
90
+ );
91
+ },
92
+ [theme, locale, activeDate, onPressDay, onPressEvent, onLongPressEvent, RenderEventComponent],
93
+ );
94
+
95
+ return (
96
+ <LegendList
97
+ style={styles.list}
98
+ data={rows}
99
+ keyExtractor={keyExtractorRow}
100
+ renderItem={renderItem}
101
+ // The public prop is data-agnostic; LegendList types the separator by row.
102
+ ItemSeparatorComponent={
103
+ (itemSeparatorComponent ?? undefined) as
104
+ | ComponentType<{ leadingItem: Row<T> }>
105
+ | undefined
106
+ }
107
+ recycleItems={false}
108
+ />
109
+ );
110
+ }
111
+
112
+ const styles = StyleSheet.create({
113
+ list: {
114
+ flex: 1,
115
+ },
116
+ header: {
117
+ paddingTop: 12,
118
+ paddingBottom: 4,
119
+ paddingHorizontal: 12,
120
+ },
121
+ eventRow: {
122
+ paddingHorizontal: 12,
123
+ paddingVertical: 2,
124
+ },
125
+ });
@@ -0,0 +1,83 @@
1
+ import { addDays, startOfDay } from 'date-fns';
2
+ import { StyleSheet, View } from 'react-native';
3
+ import { useCalendarTheme } from '../theme';
4
+ import type { CalendarEvent, CalendarMode, EventKeyExtractor, RenderEvent } from '../types';
5
+ import { isAllDayEvent } from '../utils/layout';
6
+
7
+ type AllDayLaneProps<T> = {
8
+ days: Date[];
9
+ events: CalendarEvent<T>[];
10
+ mode: CalendarMode;
11
+ hourColumnWidth: number;
12
+ dayWidth: number;
13
+ renderEvent: RenderEvent<T>;
14
+ keyExtractor: EventKeyExtractor<T>;
15
+ onPressEvent: (event: CalendarEvent<T>) => void;
16
+ onLongPressEvent?: (event: CalendarEvent<T>) => void;
17
+ };
18
+
19
+ /**
20
+ * The all-day lane that sits above the scrolling time grid. All-day events are
21
+ * excluded from the timed columns (see `layoutDayEvents`) and shown here,
22
+ * stacked under their day(s). Renders nothing when no day has an all-day event,
23
+ * so timed-only calendars are unaffected.
24
+ */
25
+ export function AllDayLane<T>({
26
+ days,
27
+ events,
28
+ mode,
29
+ hourColumnWidth,
30
+ dayWidth,
31
+ renderEvent,
32
+ keyExtractor,
33
+ onPressEvent,
34
+ onLongPressEvent,
35
+ }: AllDayLaneProps<T>) {
36
+ const theme = useCalendarTheme();
37
+ const RenderEventComponent = renderEvent;
38
+
39
+ const allDay = events.filter(isAllDayEvent);
40
+ const perDay = days.map((day) => {
41
+ const start = startOfDay(day);
42
+ const next = addDays(start, 1);
43
+ return allDay.filter((event) => event.start < next && event.end > start);
44
+ });
45
+
46
+ if (perDay.every((list) => list.length === 0)) return null;
47
+
48
+ return (
49
+ <View style={[styles.lane, { borderBottomColor: theme.colors.gridLine }]}>
50
+ <View style={{ width: hourColumnWidth }} />
51
+ {days.map((day, dayIndex) => (
52
+ <View key={day.toISOString()} style={[styles.column, { width: dayWidth }]}>
53
+ {perDay[dayIndex].map((event, index) => (
54
+ <View key={keyExtractor(event, index)} style={styles.chip}>
55
+ <RenderEventComponent
56
+ event={event}
57
+ mode={mode}
58
+ isAllDay
59
+ onPress={() => onPressEvent(event)}
60
+ onLongPress={onLongPressEvent ? () => onLongPressEvent(event) : undefined}
61
+ />
62
+ </View>
63
+ ))}
64
+ </View>
65
+ ))}
66
+ </View>
67
+ );
68
+ }
69
+
70
+ const styles = StyleSheet.create({
71
+ lane: {
72
+ flexDirection: 'row',
73
+ borderBottomWidth: StyleSheet.hairlineWidth,
74
+ paddingBottom: 2,
75
+ },
76
+ column: {
77
+ paddingHorizontal: 1,
78
+ gap: 2,
79
+ },
80
+ chip: {
81
+ minHeight: 18,
82
+ },
83
+ });
@@ -1,4 +1,14 @@
1
- import { useMemo } from 'react';
1
+ import {
2
+ endOfDay,
3
+ endOfMonth,
4
+ endOfWeek,
5
+ type Locale,
6
+ startOfDay,
7
+ startOfMonth,
8
+ startOfWeek,
9
+ } from 'date-fns';
10
+ import { useCallback, useMemo } from 'react';
11
+ import type { StyleProp, ViewStyle } from 'react-native';
2
12
  import { useSharedValue } from 'react-native-reanimated';
3
13
  import { CalendarThemeProvider, mergeTheme, type PartialCalendarTheme } from '../theme';
4
14
  import type {
@@ -6,30 +16,65 @@ import type {
6
16
  CalendarMode,
7
17
  EventKeyExtractor,
8
18
  RenderEvent,
19
+ RenderEventArgs,
9
20
  WeekStartsOn,
10
21
  } from '../types';
22
+ import { getViewDays } from '../utils/dates';
23
+ import { Agenda } from './Agenda';
11
24
  import { DefaultEvent } from './DefaultEvent';
12
25
  import { MonthPager } from './MonthPager';
13
- import { DEFAULT_HOUR_HEIGHT, TimeGrid } from './TimeGrid';
26
+ import { DEFAULT_HOUR_HEIGHT, type HourRenderer, TimeGrid } from './TimeGrid';
14
27
 
15
28
  export type CalendarProps<T> = {
16
29
  events: CalendarEvent<T>[];
17
30
  mode: CalendarMode;
18
31
  date: Date;
19
32
  onChangeDate: (date: Date) => void;
33
+ /** Fired alongside `onChangeDate` with the `[start, end]` of the newly-visible range. */
34
+ onChangeDateRange?: (range: [Date, Date]) => void;
20
35
  onPressEvent: (event: CalendarEvent<T>) => void;
36
+ /** Long-press an event (month/week/day). */
37
+ onLongPressEvent?: (event: CalendarEvent<T>) => void;
21
38
  /** Tap a day cell (month mode) — e.g. drill into the day view. */
22
39
  onPressDay?: (date: Date) => void;
40
+ /** Long-press a day cell (month mode). */
41
+ onLongPressDay?: (date: Date) => void;
23
42
  /** Tap the "+N more" overflow label in a month cell. */
24
43
  onPressMore?: (events: CalendarEvent<T>[], date: Date) => void;
25
44
  /** Tap empty space on the week/day grid; receives the date+time pressed. */
26
45
  onPressCell?: (date: Date) => void;
46
+ /** After an empty-cell press, snap the pager back to the active page. Default false. */
47
+ resetPageOnPressCell?: boolean;
48
+ /** Long-press empty space on the week/day grid; receives the date+time. */
49
+ onLongPressCell?: (date: Date) => void;
50
+ /** Tap a day's column header on the week/day grid (default header only). */
51
+ onPressDateHeader?: (date: Date) => void;
27
52
  /** Max events shown per month cell before they collapse into "+N more". */
28
53
  maxVisibleEventCount?: number;
54
+ /** Sort each month day's events by start. Default true. */
55
+ sortedMonthView?: boolean;
56
+ /** Month overflow label template; `{moreCount}` is replaced. Default "{moreCount} More". */
57
+ moreLabel?: string;
58
+ /** Show dimmed adjacent-month days in the month grid. Default true. */
59
+ showAdjacentMonths?: boolean;
60
+ /** Ignore taps on month-cell events (day taps still fire). Default false. */
61
+ disableMonthEventCellPress?: boolean;
29
62
  /** First day of the week. Sunday = 0 (default) … Saturday = 6. */
30
63
  weekStartsOn?: WeekStartsOn;
64
+ /** Number of day columns when `mode="custom"`. Ignored by other modes. Default 1. */
65
+ numberOfDays?: number;
66
+ /**
67
+ * Last weekday of a `custom` partial-week view (0–6). When set, `custom` shows
68
+ * `weekStartsOn`…`weekEndsOn` of the visible week and pages by week, taking
69
+ * precedence over `numberOfDays`. Ignored by other modes.
70
+ */
71
+ weekEndsOn?: WeekStartsOn;
31
72
  /** Replace the built-in event box. Return a `flex: 1` element. */
32
73
  renderEvent?: RenderEvent<T>;
74
+ /** Per-event style merged onto the built-in event box (static or a function of the event). */
75
+ eventCellStyle?: StyleProp<ViewStyle> | ((event: CalendarEvent<T>) => StyleProp<ViewStyle>);
76
+ /** Per-date style for month cells and week/day columns (e.g. shade specific dates). */
77
+ calendarCellStyle?: (date: Date) => StyleProp<ViewStyle>;
33
78
  /** Stable key per event. Defaults to start-time + index. */
34
79
  keyExtractor?: EventKeyExtractor<T>;
35
80
  /** Partial theme merged over the defaults. */
@@ -41,18 +86,49 @@ export type CalendarProps<T> = {
41
86
  minHourHeight?: number;
42
87
  maxHourHeight?: number;
43
88
  hourColumnWidth?: number;
89
+ /** Hide the left hour-axis column on the week/day grid. Default false. */
90
+ hideHours?: boolean;
91
+ /** Sub-hour divider lines per hour on the week/day grid (e.g. 2 = half-hours). Default 1. */
92
+ timeslots?: number;
93
+ /** Show the ISO week number in the week/day header gutter. Default false. */
94
+ showWeekNumber?: boolean;
95
+ /** Prefix for the week-number label (e.g. "W"). Default "W". */
96
+ weekNumberPrefix?: string;
97
+ /** Replace the hour-axis label on the week/day grid. Receives the hour (0–23) and `ampm`. */
98
+ hourComponent?: HourRenderer;
99
+ /** Always render six week rows in month view, for a fixed-height grid. Default false. */
100
+ showSixWeeks?: boolean;
101
+ /** Allow swiping between pages (all modes). Default true. */
102
+ swipeEnabled?: boolean;
103
+ /** Show the vertical scroll indicator on the week/day grid. Default true. */
104
+ showVerticalScrollIndicator?: boolean;
105
+ /** Allow vertical scrolling of the week/day grid. Default true. */
106
+ verticalScrollEnabled?: boolean;
107
+ /** Element rendered between the day header and the week/day grid. */
108
+ headerComponent?: React.ReactNode;
44
109
  /** First hour shown on the week/day grid (0–23). Default 0. */
45
110
  minHour?: number;
46
111
  /** Last hour shown on the week/day grid, exclusive (1–24). Default 24. */
47
112
  maxHour?: number;
48
- /** Show hour labels in 12-hour AM/PM form. Default false (24h). */
113
+ /** Show hour labels (and built-in event times) in 12-hour AM/PM form. Default false (24h). */
49
114
  ampm?: boolean;
115
+ /** Show the time range in the built-in event renderer (day/week/schedule). Default true. */
116
+ showTime?: boolean;
50
117
  /** Initial vertical scroll, in minutes from midnight (week/day). */
51
118
  scrollOffsetMinutes?: number;
52
119
  /** Show the current-time line on the week/day grid. Default true. */
53
120
  showNowIndicator?: boolean;
54
- /** BCP-47 locale for weekday labels. Defaults to the device locale. */
55
- locale?: string;
121
+ /** A date-fns `Locale` for weekday/date labels. Defaults to English. */
122
+ locale?: Locale;
123
+ /** Highlight this date (header/cell/agenda) instead of the real "today". */
124
+ activeDate?: Date;
125
+ /**
126
+ * Lay the day columns out right-to-left (month, week/day grid and all-day lane).
127
+ * Cosmetic only: the hour gutter stays on the left and paging still advances
128
+ * with the system scroll direction. Default false. For full RTL (including
129
+ * scroll direction), also enable React Native's `I18nManager`.
130
+ */
131
+ isRTL?: boolean;
56
132
  /**
57
133
  * Allow a fling to carry across several pages before snapping. Default false:
58
134
  * one day/week/month per swipe.
@@ -60,6 +136,10 @@ export type CalendarProps<T> = {
60
136
  freeSwipe?: boolean;
61
137
  /** Custom header above the week/day grid. Receives the visible days. */
62
138
  renderTimeGridHeader?: (days: Date[]) => React.ReactNode;
139
+ /** Replace the weekday-label header above the month grid. Return `null` to hide it. */
140
+ renderHeaderForMonthView?: (weekDays: Date[]) => React.ReactNode;
141
+ /** Drawn between rows of the `schedule` (agenda) list. */
142
+ itemSeparatorComponent?: React.ComponentType<unknown> | null;
63
143
  };
64
144
 
65
145
  // Derive a key purely from event data so identity is stable across reorders and
@@ -68,18 +148,51 @@ export type CalendarProps<T> = {
68
148
  const defaultKeyExtractor: EventKeyExtractor<unknown> = (event) =>
69
149
  `${event.start.toISOString()}|${event.end.toISOString()}|${event.title ?? ''}`;
70
150
 
151
+ // The [start, end] of the dates a given mode shows around `date`. Month spans the
152
+ // padded grid (whole weeks); time-grid modes span their day columns.
153
+ function visibleRange(
154
+ mode: CalendarMode,
155
+ date: Date,
156
+ weekStartsOn: WeekStartsOn,
157
+ numberOfDays: number,
158
+ weekEndsOn?: WeekStartsOn,
159
+ ): [Date, Date] {
160
+ if (mode === 'month') {
161
+ return [
162
+ startOfWeek(startOfMonth(date), { weekStartsOn }),
163
+ endOfWeek(endOfMonth(date), { weekStartsOn }),
164
+ ];
165
+ }
166
+ const days = getViewDays(mode, date, weekStartsOn, numberOfDays, false, weekEndsOn);
167
+ return [startOfDay(days[0]), endOfDay(days[days.length - 1])];
168
+ }
169
+
71
170
  export function Calendar<T>({
72
171
  events,
73
172
  mode,
74
173
  date,
75
174
  onChangeDate,
175
+ onChangeDateRange,
76
176
  onPressEvent,
177
+ onLongPressEvent,
77
178
  onPressDay,
179
+ onLongPressDay,
78
180
  onPressMore,
79
181
  onPressCell,
182
+ resetPageOnPressCell,
183
+ onLongPressCell,
184
+ onPressDateHeader,
80
185
  maxVisibleEventCount = 2,
186
+ sortedMonthView,
187
+ moreLabel,
188
+ showAdjacentMonths,
189
+ disableMonthEventCellPress,
81
190
  weekStartsOn = 0,
191
+ numberOfDays,
192
+ weekEndsOn,
82
193
  renderEvent = DefaultEvent,
194
+ eventCellStyle,
195
+ calendarCellStyle,
83
196
  keyExtractor = defaultKeyExtractor as EventKeyExtractor<T>,
84
197
  theme,
85
198
  cellHeight: cellHeightProp,
@@ -87,19 +200,73 @@ export function Calendar<T>({
87
200
  minHourHeight,
88
201
  maxHourHeight,
89
202
  hourColumnWidth,
203
+ hideHours,
204
+ timeslots,
205
+ showWeekNumber,
206
+ weekNumberPrefix,
207
+ hourComponent,
208
+ showSixWeeks,
209
+ swipeEnabled,
210
+ showVerticalScrollIndicator,
211
+ verticalScrollEnabled,
212
+ headerComponent,
90
213
  minHour,
91
214
  maxHour,
92
215
  ampm,
216
+ showTime,
93
217
  scrollOffsetMinutes,
94
218
  showNowIndicator,
95
219
  locale,
220
+ activeDate,
221
+ isRTL,
96
222
  freeSwipe,
97
223
  renderTimeGridHeader,
224
+ renderHeaderForMonthView,
225
+ itemSeparatorComponent,
98
226
  }: CalendarProps<T>) {
99
227
  const mergedTheme = useMemo(() => mergeTheme(theme), [theme]);
100
228
  const internalCellHeight = useSharedValue(hourHeight);
101
229
  const cellHeight = cellHeightProp ?? internalCellHeight;
102
230
 
231
+ // Swallow presses on disabled events once, so every view inherits the guard.
232
+ const handlePressEvent = useCallback(
233
+ (event: CalendarEvent<T>) => {
234
+ if (!event.disabled) onPressEvent(event);
235
+ },
236
+ [onPressEvent],
237
+ );
238
+ const handleLongPressEvent = useMemo(
239
+ () =>
240
+ onLongPressEvent
241
+ ? (event: CalendarEvent<T>) => {
242
+ if (!event.disabled) onLongPressEvent(event);
243
+ }
244
+ : undefined,
245
+ [onLongPressEvent],
246
+ );
247
+
248
+ // Echo every date change and, when asked, the full visible range derived from it.
249
+ const handleChangeDate = useCallback(
250
+ (next: Date) => {
251
+ onChangeDate(next);
252
+ onChangeDateRange?.(visibleRange(mode, next, weekStartsOn, numberOfDays ?? 1, weekEndsOn));
253
+ },
254
+ [onChangeDate, onChangeDateRange, mode, weekStartsOn, numberOfDays, weekEndsOn],
255
+ );
256
+
257
+ // Inject `eventCellStyle`, `ampm` and `showTime` into the renderer once, so
258
+ // every view gets them for free without threading the props through each
259
+ // component. Skip the wrapper entirely when none are set.
260
+ const resolvedRenderEvent = useMemo<RenderEvent<T>>(() => {
261
+ if (eventCellStyle == null && ampm == null && showTime == null) return renderEvent;
262
+ const Base = renderEvent;
263
+ return function StyledEvent(props: RenderEventArgs<T>) {
264
+ const cellStyle =
265
+ typeof eventCellStyle === 'function' ? eventCellStyle(props.event) : eventCellStyle;
266
+ return <Base {...props} cellStyle={cellStyle} ampm={ampm} showTime={showTime} />;
267
+ };
268
+ }, [renderEvent, eventCellStyle, ampm, showTime]);
269
+
103
270
  return (
104
271
  <CalendarThemeProvider value={mergedTheme}>
105
272
  {mode === 'month' ? (
@@ -108,26 +275,62 @@ export function Calendar<T>({
108
275
  events={events}
109
276
  maxVisibleEventCount={maxVisibleEventCount}
110
277
  weekStartsOn={weekStartsOn}
111
- renderEvent={renderEvent}
278
+ locale={locale}
279
+ sortedMonthView={sortedMonthView}
280
+ moreLabel={moreLabel}
281
+ showAdjacentMonths={showAdjacentMonths}
282
+ disableMonthEventCellPress={disableMonthEventCellPress}
283
+ isRTL={isRTL}
284
+ showSixWeeks={showSixWeeks}
285
+ activeDate={activeDate}
286
+ renderHeaderForMonthView={renderHeaderForMonthView}
287
+ calendarCellStyle={calendarCellStyle}
288
+ renderEvent={resolvedRenderEvent}
112
289
  keyExtractor={keyExtractor}
113
290
  onPressDay={onPressDay}
114
- onPressEvent={onPressEvent}
291
+ onLongPressDay={onLongPressDay}
292
+ onPressEvent={handlePressEvent}
293
+ onLongPressEvent={handleLongPressEvent}
115
294
  onPressMore={onPressMore}
116
- onChangeDate={onChangeDate}
295
+ onChangeDate={handleChangeDate}
117
296
  freeSwipe={freeSwipe}
297
+ swipeEnabled={swipeEnabled}
298
+ />
299
+ ) : mode === 'schedule' ? (
300
+ <Agenda
301
+ events={events}
302
+ locale={locale}
303
+ renderEvent={resolvedRenderEvent}
304
+ keyExtractor={keyExtractor}
305
+ onPressEvent={handlePressEvent}
306
+ onLongPressEvent={handleLongPressEvent}
307
+ onPressDay={onPressDay}
308
+ activeDate={activeDate}
309
+ itemSeparatorComponent={itemSeparatorComponent}
118
310
  />
119
311
  ) : (
120
312
  <TimeGrid
121
313
  mode={mode}
314
+ numberOfDays={numberOfDays}
315
+ weekEndsOn={weekEndsOn}
122
316
  date={date}
123
317
  events={events}
124
318
  cellHeight={cellHeight}
125
319
  hourHeight={hourHeight}
126
320
  weekStartsOn={weekStartsOn}
127
- renderEvent={renderEvent}
321
+ renderEvent={resolvedRenderEvent}
128
322
  keyExtractor={keyExtractor}
129
323
  scrollOffsetMinutes={scrollOffsetMinutes}
130
324
  hourColumnWidth={hourColumnWidth}
325
+ hideHours={hideHours}
326
+ timeslots={timeslots}
327
+ calendarCellStyle={calendarCellStyle}
328
+ showWeekNumber={showWeekNumber}
329
+ weekNumberPrefix={weekNumberPrefix}
330
+ hourComponent={hourComponent}
331
+ showVerticalScrollIndicator={showVerticalScrollIndicator}
332
+ verticalScrollEnabled={verticalScrollEnabled}
333
+ headerComponent={headerComponent}
131
334
  minHour={minHour}
132
335
  maxHour={maxHour}
133
336
  ampm={ampm}
@@ -135,10 +338,17 @@ export function Calendar<T>({
135
338
  maxHourHeight={maxHourHeight}
136
339
  showNowIndicator={showNowIndicator}
137
340
  locale={locale}
341
+ activeDate={activeDate}
342
+ isRTL={isRTL}
138
343
  freeSwipe={freeSwipe}
139
- onPressEvent={onPressEvent}
344
+ swipeEnabled={swipeEnabled}
345
+ onPressEvent={handlePressEvent}
346
+ onLongPressEvent={handleLongPressEvent}
140
347
  onPressCell={onPressCell}
141
- onChangeDate={onChangeDate}
348
+ resetPageOnPressCell={resetPageOnPressCell}
349
+ onLongPressCell={onLongPressCell}
350
+ onPressDateHeader={onPressDateHeader}
351
+ onChangeDate={handleChangeDate}
142
352
  renderHeader={renderTimeGridHeader}
143
353
  />
144
354
  )}
@@ -8,14 +8,30 @@ import type { RenderEventArgs } from '../types';
8
8
  * and (on the day/week grid) its time range. Pass your own `renderEvent` to
9
9
  * `<Calendar>` to replace it entirely.
10
10
  */
11
- export function DefaultEvent<T>({ event, mode, onPress }: RenderEventArgs<T>) {
11
+ export function DefaultEvent<T>({
12
+ event,
13
+ mode,
14
+ isAllDay,
15
+ ampm = false,
16
+ showTime = true,
17
+ cellStyle,
18
+ onPress,
19
+ onLongPress,
20
+ }: RenderEventArgs<T>) {
12
21
  const theme = useCalendarTheme();
13
- const showTime = mode !== 'month';
22
+ const timeFormat = ampm ? 'h:mm a' : 'HH:mm';
23
+ const shouldShowTime = mode !== 'month' && !isAllDay && showTime;
14
24
 
15
25
  return (
16
26
  <TouchableOpacity
17
- style={[styles.box, { backgroundColor: theme.colors.eventBackground }]}
27
+ style={[
28
+ styles.box,
29
+ { backgroundColor: theme.colors.eventBackground },
30
+ event.disabled && styles.disabled,
31
+ cellStyle,
32
+ ]}
18
33
  onPress={onPress}
34
+ onLongPress={onLongPress}
19
35
  activeOpacity={0.7}
20
36
  accessibilityRole="button"
21
37
  accessibilityLabel={event.title}
@@ -30,13 +46,13 @@ export function DefaultEvent<T>({ event, mode, onPress }: RenderEventArgs<T>) {
30
46
  {event.title}
31
47
  </Text>
32
48
  ) : null}
33
- {showTime ? (
49
+ {shouldShowTime ? (
34
50
  <Text
35
51
  style={[styles.time, { color: theme.colors.eventText }]}
36
52
  numberOfLines={1}
37
53
  allowFontScaling={false}
38
54
  >
39
- {`${format(event.start, 'HH:mm')} - ${format(event.end, 'HH:mm')}`}
55
+ {`${format(event.start, timeFormat)} - ${format(event.end, timeFormat)}`}
40
56
  </Text>
41
57
  ) : null}
42
58
  </TouchableOpacity>
@@ -54,4 +70,7 @@ const styles = StyleSheet.create({
54
70
  time: {
55
71
  fontSize: 11,
56
72
  },
73
+ disabled: {
74
+ opacity: 0.5,
75
+ },
57
76
  });