react-native-ll-calendar 0.15.1 → 0.16.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.
Files changed (32) hide show
  1. package/README.md +1 -0
  2. package/lib/module/calendar/month-calendar/MonthCalendar.js +3 -1
  3. package/lib/module/calendar/month-calendar/MonthCalendar.js.map +1 -1
  4. package/lib/module/calendar/month-calendar/view/MonthCalendarEventOverlay.js +21 -0
  5. package/lib/module/calendar/month-calendar/view/MonthCalendarEventOverlay.js.map +1 -0
  6. package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js +2 -0
  7. package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js.map +1 -1
  8. package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js +118 -66
  9. package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js.map +1 -1
  10. package/lib/module/calendar/resources-calendar/ResourcesCalendar.js +102 -50
  11. package/lib/module/calendar/resources-calendar/ResourcesCalendar.js.map +1 -1
  12. package/lib/module/index.js +1 -0
  13. package/lib/module/index.js.map +1 -1
  14. package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts +8 -0
  15. package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts.map +1 -1
  16. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarEventOverlay.d.ts +16 -0
  17. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarEventOverlay.d.ts.map +1 -0
  18. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts +3 -0
  19. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts.map +1 -1
  20. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts +3 -0
  21. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts.map +1 -1
  22. package/lib/typescript/src/calendar/resources-calendar/ResourcesCalendar.d.ts +8 -1
  23. package/lib/typescript/src/calendar/resources-calendar/ResourcesCalendar.d.ts.map +1 -1
  24. package/lib/typescript/src/index.d.ts +2 -0
  25. package/lib/typescript/src/index.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/calendar/month-calendar/MonthCalendar.tsx +16 -1
  28. package/src/calendar/month-calendar/view/MonthCalendarEventOverlay.tsx +37 -0
  29. package/src/calendar/month-calendar/view/MonthCalendarViewItem.tsx +5 -0
  30. package/src/calendar/month-calendar/view/MonthCalendarWeekRow.tsx +186 -113
  31. package/src/calendar/resources-calendar/ResourcesCalendar.tsx +181 -96
  32. package/src/index.tsx +2 -0
@@ -27,6 +27,7 @@ import {
27
27
  forwardRef,
28
28
  useImperativeHandle,
29
29
  useRef,
30
+ type ReactNode,
30
31
  } from 'react';
31
32
  import { MonthCalendarWeekDayRow } from './MonthCalendarWeekDayRow';
32
33
 
@@ -63,7 +64,9 @@ type MonthCalendarViewItemProps = {
63
64
  eventHeight?: number;
64
65
  eventTextStyle?: (event: CalendarEvent) => TextStyle;
65
66
  eventEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
67
+ renderEventOverlay?: (event: CalendarEvent) => ReactNode;
66
68
  bottomSpacing?: number;
69
+ prioritizeCellInteraction?: boolean;
67
70
  };
68
71
 
69
72
  export const MonthCalendarViewItem = forwardRef<
@@ -228,6 +231,8 @@ export const MonthCalendarViewItem = forwardRef<
228
231
  eventHeight={props.eventHeight}
229
232
  eventTextStyle={props.eventTextStyle}
230
233
  eventEllipsizeMode={props.eventEllipsizeMode}
234
+ renderEventOverlay={props.renderEventOverlay}
235
+ prioritizeCellInteraction={props.prioritizeCellInteraction}
231
236
  onLayout={(e) => {
232
237
  weekHeights.current.set(weekId, e.nativeEvent.layout.height);
233
238
  }}
@@ -1,5 +1,7 @@
1
1
  import dayjs from 'dayjs';
2
+ import type { ReactNode } from 'react';
2
3
  import {
4
+ Platform,
3
5
  StyleSheet,
4
6
  useWindowDimensions,
5
7
  type LayoutChangeEvent,
@@ -31,7 +33,9 @@ export const MonthCalendarWeekRow = (props: {
31
33
  eventHeight?: number;
32
34
  eventTextStyle?: (event: CalendarEvent) => TextStyle;
33
35
  eventEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
36
+ renderEventOverlay?: (event: CalendarEvent) => ReactNode;
34
37
  onLayout?: (event: LayoutChangeEvent) => void;
38
+ prioritizeCellInteraction?: boolean;
35
39
  }) => {
36
40
  const eventHeight = props.eventHeight || 26;
37
41
  const { width: screenWidth } = useWindowDimensions();
@@ -72,7 +76,7 @@ export const MonthCalendarWeekRow = (props: {
72
76
  return dayjs(a.start).diff(dayjs(b.start));
73
77
  });
74
78
 
75
- const events: (CalendarEvent | number)[] = [];
79
+ const cellEvents: (CalendarEvent | number)[] = [];
76
80
  if (weekId && props.eventPosition) {
77
81
  const rowNums = props.eventPosition.getRowNums({
78
82
  weekId,
@@ -82,33 +86,142 @@ export const MonthCalendarWeekRow = (props: {
82
86
  let eventIndex = 0;
83
87
  for (let ii = 1; ii <= rowsLength; ii++) {
84
88
  if (rowNums.includes(ii)) {
85
- events.push(ii);
89
+ cellEvents.push(ii);
86
90
  } else {
87
91
  const event = filteredEvents[eventIndex];
88
92
  if (event) {
89
- events.push(event);
93
+ cellEvents.push(event);
90
94
  }
91
95
  eventIndex++;
92
96
  }
93
97
  }
94
98
  }
95
- return (
96
- <TouchableOpacity
97
- key={djs.get('date')}
98
- style={[
99
- styles.dayCellCountainer,
100
- { minHeight: props.weekRowMinHeight },
101
- { zIndex: 7 - dateIndex },
102
- { borderColor: props.cellBorderColor ?? 'lightslategrey' },
103
- ]}
104
- onPress={() => {
105
- props.onPressCell?.(djs.toDate());
106
- }}
107
- onLongPress={() => {
108
- props.onLongPressCell?.(djs.toDate());
109
- }}
110
- delayLongPress={props.delayLongPressCell}
111
- >
99
+
100
+ const showPrioritizedCellOverlay =
101
+ props.prioritizeCellInteraction === true &&
102
+ (props.onPressCell != null || props.onLongPressCell != null);
103
+
104
+ const cellWrapperStyle = [
105
+ styles.dayCellCountainer,
106
+ { minHeight: props.weekRowMinHeight },
107
+ { zIndex: 7 - dateIndex },
108
+ { borderColor: props.cellBorderColor ?? 'lightslategrey' },
109
+ ];
110
+
111
+ const eventRows = cellEvents.map((event, rowIndex) => {
112
+ if (typeof event === 'number') {
113
+ return (
114
+ <View
115
+ key={`spacer-${rowIndex}`}
116
+ style={{ height: eventHeight, marginBottom: EVENT_GAP }}
117
+ />
118
+ );
119
+ }
120
+
121
+ const rawStartDjs = dayjs(event.start);
122
+ const startDjs = dateIndex === 0 ? djs : dayjs(event.start);
123
+ const endDjs = dayjs(event.end);
124
+ const isEndOnDayBoundary =
125
+ endDjs.hour() === 0 &&
126
+ endDjs.minute() === 0 &&
127
+ endDjs.second() === 0 &&
128
+ endDjs.millisecond() === 0;
129
+ const diffDays = Math.max(
130
+ 0,
131
+ endDjs.startOf('day').diff(startDjs.startOf('day'), 'day') -
132
+ (isEndOnDayBoundary ? 1 : 0)
133
+ );
134
+
135
+ const isPrevDateEvent = dateIndex === 0 && rawStartDjs.isBefore(djs);
136
+ let width =
137
+ (diffDays + 1) * dateColumnWidth -
138
+ EVENT_GAP * 2 -
139
+ CELL_BORDER_WIDTH * 2;
140
+
141
+ if (isPrevDateEvent) {
142
+ width += EVENT_GAP + 1;
143
+ }
144
+
145
+ const isLastRow = rowIndex === cellEvents.length - 1;
146
+
147
+ if (props.eventPosition && weekId) {
148
+ props.eventPosition.push({
149
+ weekId,
150
+ startDate: startDjs.toDate(),
151
+ days: diffDays + 1,
152
+ rowNum: rowIndex + 1,
153
+ });
154
+ }
155
+
156
+ const eventOverlayNode = props.renderEventOverlay?.(event);
157
+ const showEventOverlay =
158
+ props.renderEventOverlay != null &&
159
+ eventOverlayNode != null &&
160
+ eventOverlayNode !== false;
161
+
162
+ return (
163
+ <View
164
+ key={event.id}
165
+ pointerEvents={showPrioritizedCellOverlay ? 'none' : 'auto'}
166
+ style={[
167
+ styles.eventOuter,
168
+ {
169
+ width,
170
+ height: eventHeight,
171
+ },
172
+ isPrevDateEvent ? styles.prevDateEvent : {},
173
+ isLastRow ? styles.lastRowEvent : {},
174
+ ]}
175
+ >
176
+ <TouchableOpacity
177
+ style={[
178
+ styles.event,
179
+ {
180
+ backgroundColor: event.backgroundColor,
181
+ borderColor: event.borderColor,
182
+ ...(event.borderStyle !== undefined && {
183
+ borderStyle: event.borderStyle,
184
+ }),
185
+ ...(event.borderWidth !== undefined && {
186
+ borderWidth: event.borderWidth,
187
+ }),
188
+ ...(event.borderRadius !== undefined && {
189
+ borderRadius: event.borderRadius,
190
+ }),
191
+ },
192
+ ]}
193
+ onPress={() => {
194
+ props.onPressEvent?.(event);
195
+ }}
196
+ onLongPress={() => {
197
+ props.onLongPressEvent?.(event);
198
+ }}
199
+ delayLongPress={props.delayLongPressEvent}
200
+ >
201
+ <Text
202
+ numberOfLines={1}
203
+ ellipsizeMode={props.eventEllipsizeMode ?? 'tail'}
204
+ style={[
205
+ styles.eventTitle,
206
+ { color: event.color },
207
+ props.eventTextStyle?.(event),
208
+ ]}
209
+ allowFontScaling={props.allowFontScaling}
210
+ >
211
+ {event.title}
212
+ </Text>
213
+ </TouchableOpacity>
214
+ {showEventOverlay ? (
215
+ <View style={styles.eventOverlayHost} pointerEvents="box-none">
216
+ {eventOverlayNode}
217
+ </View>
218
+ ) : null}
219
+ </View>
220
+ );
221
+ });
222
+
223
+ const cellInner = (
224
+ <>
112
225
  <View
113
226
  style={[
114
227
  styles.dayCellInner,
@@ -129,98 +242,39 @@ export const MonthCalendarWeekRow = (props: {
129
242
  {text}
130
243
  </Text>
131
244
  </View>
132
- {events.map((event, rowIndex) => {
133
- if (typeof event === 'number') {
134
- return (
135
- <View
136
- key={event}
137
- style={{ height: eventHeight, marginBottom: EVENT_GAP }}
138
- />
139
- );
140
- }
141
-
142
- const rawStartDjs = dayjs(event.start);
143
- const startDjs = dateIndex === 0 ? djs : dayjs(event.start);
144
- const endDjs = dayjs(event.end);
145
- const isEndOnDayBoundary =
146
- endDjs.hour() === 0 &&
147
- endDjs.minute() === 0 &&
148
- endDjs.second() === 0 &&
149
- endDjs.millisecond() === 0;
150
- const diffDays = Math.max(
151
- 0,
152
- endDjs.startOf('day').diff(startDjs.startOf('day'), 'day') -
153
- (isEndOnDayBoundary ? 1 : 0)
154
- );
155
-
156
- const isPrevDateEvent =
157
- dateIndex === 0 && rawStartDjs.isBefore(djs);
158
- let width =
159
- (diffDays + 1) * dateColumnWidth -
160
- EVENT_GAP * 2 -
161
- CELL_BORDER_WIDTH * 2;
162
-
163
- if (isPrevDateEvent) {
164
- width += EVENT_GAP + 1;
165
- }
166
-
167
- const isLastRow = rowIndex === events.length - 1;
168
-
169
- if (props.eventPosition && weekId) {
170
- props.eventPosition.push({
171
- weekId,
172
- startDate: startDjs.toDate(),
173
- days: diffDays + 1,
174
- rowNum: rowIndex + 1,
175
- });
176
- }
245
+ {eventRows}
246
+ </>
247
+ );
177
248
 
178
- return (
179
- <TouchableOpacity
180
- key={event.id}
181
- style={[
182
- styles.event,
183
- {
184
- backgroundColor: event.backgroundColor,
185
- borderColor: event.borderColor,
186
- width: width,
187
- height: eventHeight,
188
- ...(event.borderStyle !== undefined && {
189
- borderStyle: event.borderStyle,
190
- }),
191
- ...(event.borderWidth !== undefined && {
192
- borderWidth: event.borderWidth,
193
- }),
194
- ...(event.borderRadius !== undefined && {
195
- borderRadius: event.borderRadius,
196
- }),
197
- },
198
- isPrevDateEvent ? styles.prevDateEvent : {},
199
- isLastRow ? styles.lastRowEvent : {},
200
- ]}
201
- onPress={() => {
202
- props.onPressEvent?.(event);
203
- }}
204
- onLongPress={() => {
205
- props.onLongPressEvent?.(event);
206
- }}
207
- delayLongPress={props.delayLongPressEvent}
208
- >
209
- <Text
210
- numberOfLines={1}
211
- ellipsizeMode={props.eventEllipsizeMode ?? 'tail'}
212
- style={[
213
- styles.eventTitle,
214
- { color: event.color },
215
- props.eventTextStyle?.(event),
216
- ]}
217
- allowFontScaling={props.allowFontScaling}
218
- >
219
- {event.title}
220
- </Text>
221
- </TouchableOpacity>
222
- );
223
- })}
249
+ return showPrioritizedCellOverlay ? (
250
+ <View key={djs.valueOf()} style={cellWrapperStyle}>
251
+ {cellInner}
252
+ <TouchableOpacity
253
+ accessible={false}
254
+ style={styles.cellInteractionOverlay}
255
+ activeOpacity={1}
256
+ onPress={() => {
257
+ props.onPressCell?.(djs.toDate());
258
+ }}
259
+ onLongPress={() => {
260
+ props.onLongPressCell?.(djs.toDate());
261
+ }}
262
+ delayLongPress={props.delayLongPressCell}
263
+ />
264
+ </View>
265
+ ) : (
266
+ <TouchableOpacity
267
+ key={djs.valueOf()}
268
+ style={cellWrapperStyle}
269
+ onPress={() => {
270
+ props.onPressCell?.(djs.toDate());
271
+ }}
272
+ onLongPress={() => {
273
+ props.onLongPressCell?.(djs.toDate());
274
+ }}
275
+ delayLongPress={props.delayLongPressCell}
276
+ >
277
+ {cellInner}
224
278
  </TouchableOpacity>
225
279
  );
226
280
  })}
@@ -259,15 +313,25 @@ const styles = StyleSheet.create({
259
313
  textAlign: 'center',
260
314
  fontSize: 14,
261
315
  },
316
+ eventOuter: {
317
+ position: 'relative',
318
+ marginTop: EVENT_GAP,
319
+ marginLeft: EVENT_GAP,
320
+ },
262
321
  event: {
322
+ flex: 1,
323
+ width: '100%',
324
+ height: '100%',
263
325
  borderWidth: 0.5,
264
326
  borderRadius: 4,
265
327
  paddingHorizontal: 4,
266
328
  flexDirection: 'row',
267
329
  alignItems: 'center',
268
330
  boxShadow: '0 0 2px 0 rgba(0, 0, 0, 0.1)',
269
- marginTop: EVENT_GAP,
270
- marginLeft: EVENT_GAP,
331
+ },
332
+ eventOverlayHost: {
333
+ ...StyleSheet.absoluteFillObject,
334
+ pointerEvents: 'box-none',
271
335
  },
272
336
  prevDateEvent: {
273
337
  marginLeft: -1,
@@ -280,4 +344,13 @@ const styles = StyleSheet.create({
280
344
  eventTitle: {
281
345
  fontSize: 12,
282
346
  },
347
+ cellInteractionOverlay: {
348
+ ...StyleSheet.absoluteFillObject,
349
+ zIndex: 1000,
350
+ backgroundColor: 'transparent',
351
+ ...Platform.select({
352
+ android: { elevation: 12 },
353
+ default: {},
354
+ }),
355
+ },
283
356
  });