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/README.md +82 -2
- package/dist/index.d.mts +289 -73
- package/dist/index.d.ts +289 -73
- package/dist/index.js +650 -144
- package/dist/index.mjs +649 -145
- package/package.json +1 -1
- package/src/components/Agenda.tsx +125 -0
- package/src/components/AllDayLane.tsx +83 -0
- package/src/components/Calendar.tsx +221 -11
- package/src/components/DefaultEvent.tsx +24 -5
- package/src/components/MonthPager.tsx +138 -26
- package/src/components/MonthView.tsx +82 -14
- package/src/components/TimeGrid.tsx +344 -56
- package/src/index.tsx +9 -2
- package/src/types.ts +23 -1
- package/src/utils/dates.ts +67 -2
- package/src/utils/layout.ts +18 -0
package/src/index.tsx
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export { Calendar, type CalendarProps } from './components/Calendar';
|
|
2
|
+
export { Agenda, type AgendaProps } from './components/Agenda';
|
|
2
3
|
export { MonthView, type MonthViewProps } from './components/MonthView';
|
|
3
4
|
export { MonthPager, type MonthPagerProps } from './components/MonthPager';
|
|
4
|
-
export {
|
|
5
|
+
export {
|
|
6
|
+
TimeGrid,
|
|
7
|
+
type TimeGridProps,
|
|
8
|
+
type HourRenderer,
|
|
9
|
+
DEFAULT_HOUR_HEIGHT,
|
|
10
|
+
} from './components/TimeGrid';
|
|
5
11
|
export { DefaultEvent } from './components/DefaultEvent';
|
|
6
12
|
export {
|
|
7
13
|
type CalendarTheme,
|
|
@@ -18,6 +24,7 @@ export type {
|
|
|
18
24
|
ICalendarEvent,
|
|
19
25
|
RenderEvent,
|
|
20
26
|
RenderEventArgs,
|
|
27
|
+
TimeGridMode,
|
|
21
28
|
WeekStartsOn,
|
|
22
29
|
} from './types';
|
|
23
30
|
export {
|
|
@@ -27,4 +34,4 @@ export {
|
|
|
27
34
|
isSameCalendarDay,
|
|
28
35
|
minutesIntoDay,
|
|
29
36
|
} from './utils/dates';
|
|
30
|
-
export { layoutDayEvents, type PositionedEvent } from './utils/layout';
|
|
37
|
+
export { layoutDayEvents, isAllDayEvent, type PositionedEvent } from './utils/layout';
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { ComponentType } from 'react';
|
|
2
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
3
|
import type { SharedValue } from 'react-native-reanimated';
|
|
3
4
|
|
|
4
|
-
export type CalendarMode = 'day' | 'week' | 'month';
|
|
5
|
+
export type CalendarMode = 'day' | '3days' | 'week' | 'custom' | 'month' | 'schedule';
|
|
6
|
+
|
|
7
|
+
/** The time-grid modes (day-column views, excluding month and schedule). */
|
|
8
|
+
export type TimeGridMode = Exclude<CalendarMode, 'month' | 'schedule'>;
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* The minimal shape every calendar event must have. Layout (positioning,
|
|
@@ -13,6 +17,14 @@ export interface ICalendarEvent {
|
|
|
13
17
|
start: Date;
|
|
14
18
|
end: Date;
|
|
15
19
|
title?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Force this event into the all-day lane (above the time grid) instead of the
|
|
22
|
+
* timed columns. When omitted, an event is treated as all-day only if it spans
|
|
23
|
+
* whole days (both `start` and `end` land on midnight).
|
|
24
|
+
*/
|
|
25
|
+
allDay?: boolean;
|
|
26
|
+
/** Ignore taps/long-presses on this event (the built-in renderer also dims it). */
|
|
27
|
+
disabled?: boolean;
|
|
16
28
|
}
|
|
17
29
|
|
|
18
30
|
/**
|
|
@@ -38,7 +50,17 @@ export type RenderEventArgs<T = unknown> = {
|
|
|
38
50
|
*/
|
|
39
51
|
continuesBefore?: boolean;
|
|
40
52
|
continuesAfter?: boolean;
|
|
53
|
+
/** True when this event is rendered in the all-day lane (week/day) or is an all-day event in month view. */
|
|
54
|
+
isAllDay?: boolean;
|
|
55
|
+
/** Format the built-in renderer's time range in 12-hour AM/PM. Default false (24h). */
|
|
56
|
+
ampm?: boolean;
|
|
57
|
+
/** Show the time range in the built-in renderer (day/week/schedule). Default true. */
|
|
58
|
+
showTime?: boolean;
|
|
59
|
+
/** Per-event style resolved from `eventCellStyle`; the built-in renderer merges it onto the box. */
|
|
60
|
+
cellStyle?: StyleProp<ViewStyle>;
|
|
41
61
|
onPress: () => void;
|
|
62
|
+
/** Wired when the consumer passes `onLongPressEvent`; otherwise undefined. */
|
|
63
|
+
onLongPress?: () => void;
|
|
42
64
|
};
|
|
43
65
|
|
|
44
66
|
/**
|
package/src/utils/dates.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { addDays, getHours, getMinutes, isSameDay, isToday, startOfWeek } from 'date-fns';
|
|
2
|
-
import type { WeekStartsOn } from '../types';
|
|
1
|
+
import { addDays, getHours, getMinutes, isSameDay, isToday, startOfDay, startOfWeek } from 'date-fns';
|
|
2
|
+
import type { CalendarMode, WeekStartsOn } from '../types';
|
|
3
3
|
|
|
4
4
|
/** The seven dates of the week containing `date`, starting on `weekStartsOn`. */
|
|
5
5
|
export const getWeekDays = (date: Date, weekStartsOn: WeekStartsOn): Date[] => {
|
|
@@ -7,6 +7,71 @@ export const getWeekDays = (date: Date, weekStartsOn: WeekStartsOn): Date[] => {
|
|
|
7
7
|
return Array.from({ length: 7 }, (_, index) => addDays(start, index));
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
/** How many day columns a time-grid mode shows. `custom` uses `numberOfDays`. */
|
|
11
|
+
export const viewDayCount = (mode: CalendarMode, numberOfDays = 1): number => {
|
|
12
|
+
switch (mode) {
|
|
13
|
+
case 'week':
|
|
14
|
+
return 7;
|
|
15
|
+
case '3days':
|
|
16
|
+
return 3;
|
|
17
|
+
case 'custom':
|
|
18
|
+
return Math.max(1, Math.floor(numberOfDays));
|
|
19
|
+
default:
|
|
20
|
+
return 1; // 'day'
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Days in the inclusive span from `weekStartsOn` to `weekEndsOn` (1–7),
|
|
26
|
+
* wrapping when the end precedes the start (e.g. Sat→Wed). Mirrors
|
|
27
|
+
* react-native-big-calendar's `weekDaysCount`.
|
|
28
|
+
*/
|
|
29
|
+
export const weekDaysCount = (weekStartsOn: WeekStartsOn, weekEndsOn: WeekStartsOn): number => {
|
|
30
|
+
if (weekEndsOn < weekStartsOn) {
|
|
31
|
+
let count = 1;
|
|
32
|
+
let i = weekStartsOn;
|
|
33
|
+
while (i !== weekEndsOn && count <= 7) {
|
|
34
|
+
i = (i + 1) % 7;
|
|
35
|
+
count++;
|
|
36
|
+
}
|
|
37
|
+
return count;
|
|
38
|
+
}
|
|
39
|
+
if (weekEndsOn > weekStartsOn) return weekEndsOn - weekStartsOn + 1;
|
|
40
|
+
return 1;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The day columns to render for a time-grid page. `week` spans the calendar week
|
|
45
|
+
* (honouring `weekStartsOn`). `custom` with a `weekEndsOn` spans the partial week
|
|
46
|
+
* from `weekStartsOn` to `weekEndsOn` (anchored to `date`'s week, paging by week);
|
|
47
|
+
* otherwise every mode shows `viewDayCount` consecutive days starting at `date`.
|
|
48
|
+
*/
|
|
49
|
+
export const getViewDays = (
|
|
50
|
+
mode: CalendarMode,
|
|
51
|
+
date: Date,
|
|
52
|
+
weekStartsOn: WeekStartsOn,
|
|
53
|
+
numberOfDays = 1,
|
|
54
|
+
isRTL = false,
|
|
55
|
+
weekEndsOn?: WeekStartsOn,
|
|
56
|
+
): Date[] => {
|
|
57
|
+
let days: Date[];
|
|
58
|
+
if (mode === 'week') {
|
|
59
|
+
days = getWeekDays(date, weekStartsOn);
|
|
60
|
+
} else if (mode === 'custom' && weekEndsOn != null) {
|
|
61
|
+
// Mirror big-calendar: anchor to `date`'s week and take the partial-week span.
|
|
62
|
+
const subject = startOfDay(date);
|
|
63
|
+
const offset = weekStartsOn - subject.getDay();
|
|
64
|
+
days = Array.from({ length: weekDaysCount(weekStartsOn, weekEndsOn) }, (_, index) =>
|
|
65
|
+
addDays(subject, index + offset),
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
days = Array.from({ length: viewDayCount(mode, numberOfDays) }, (_, index) =>
|
|
69
|
+
addDays(startOfDay(date), index),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return isRTL ? days.reverse() : days;
|
|
73
|
+
};
|
|
74
|
+
|
|
10
75
|
export const isWeekend = (date: Date): boolean => {
|
|
11
76
|
const day = date.getDay();
|
|
12
77
|
return day === 0 || day === 6;
|
package/src/utils/layout.ts
CHANGED
|
@@ -43,6 +43,8 @@ export function layoutDayEvents<T>(
|
|
|
43
43
|
const nextDayStart = addDays(dayStart, 1);
|
|
44
44
|
|
|
45
45
|
const segments: Segment<T>[] = events
|
|
46
|
+
// All-day events live in the lane, not the timed columns.
|
|
47
|
+
.filter((event) => !isAllDayEvent(event))
|
|
46
48
|
// Overlaps this day if it starts before the day ends and ends after it begins.
|
|
47
49
|
.filter((event) => event.start < nextDayStart && event.end > dayStart)
|
|
48
50
|
.map((event) => {
|
|
@@ -99,6 +101,22 @@ export function layoutDayEvents<T>(
|
|
|
99
101
|
return positioned;
|
|
100
102
|
}
|
|
101
103
|
|
|
104
|
+
const atMidnight = (date: Date): boolean =>
|
|
105
|
+
date.getHours() === 0 &&
|
|
106
|
+
date.getMinutes() === 0 &&
|
|
107
|
+
date.getSeconds() === 0 &&
|
|
108
|
+
date.getMilliseconds() === 0;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Whether an event belongs in the all-day lane. An explicit `allDay` flag wins;
|
|
112
|
+
* otherwise it's inferred when the event spans whole days (both `start` and
|
|
113
|
+
* `end` land on midnight, e.g. an iCal-style all-day event). Pure.
|
|
114
|
+
*/
|
|
115
|
+
export function isAllDayEvent<T>(event: CalendarEvent<T>): boolean {
|
|
116
|
+
if (typeof event.allDay === 'boolean') return event.allDay;
|
|
117
|
+
return event.end > event.start && atMidnight(event.start) && atMidnight(event.end);
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
/**
|
|
103
121
|
* The `startOfDay` ISO keys of every calendar day an event touches (inclusive).
|
|
104
122
|
* An event ending exactly at midnight does not count the following day. Used to
|