react-native-ll-calendar 0.15.0 → 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 -65
  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 -105
  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,90 +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 diffDays = endDjs
146
- .startOf('day')
147
- .diff(startDjs.startOf('day'), 'day');
148
- const isPrevDateEvent =
149
- dateIndex === 0 && rawStartDjs.isBefore(djs);
150
- let width =
151
- (diffDays + 1) * dateColumnWidth -
152
- EVENT_GAP * 2 -
153
- CELL_BORDER_WIDTH * 2;
154
-
155
- if (isPrevDateEvent) {
156
- width += EVENT_GAP + 1;
157
- }
158
-
159
- const isLastRow = rowIndex === events.length - 1;
160
-
161
- if (props.eventPosition && weekId) {
162
- props.eventPosition.push({
163
- weekId,
164
- startDate: startDjs.toDate(),
165
- days: diffDays + 1,
166
- rowNum: rowIndex + 1,
167
- });
168
- }
245
+ {eventRows}
246
+ </>
247
+ );
169
248
 
170
- return (
171
- <TouchableOpacity
172
- key={event.id}
173
- style={[
174
- styles.event,
175
- {
176
- backgroundColor: event.backgroundColor,
177
- borderColor: event.borderColor,
178
- width: width,
179
- height: eventHeight,
180
- ...(event.borderStyle !== undefined && {
181
- borderStyle: event.borderStyle,
182
- }),
183
- ...(event.borderWidth !== undefined && {
184
- borderWidth: event.borderWidth,
185
- }),
186
- ...(event.borderRadius !== undefined && {
187
- borderRadius: event.borderRadius,
188
- }),
189
- },
190
- isPrevDateEvent ? styles.prevDateEvent : {},
191
- isLastRow ? styles.lastRowEvent : {},
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
- );
215
- })}
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}
216
278
  </TouchableOpacity>
217
279
  );
218
280
  })}
@@ -251,15 +313,25 @@ const styles = StyleSheet.create({
251
313
  textAlign: 'center',
252
314
  fontSize: 14,
253
315
  },
316
+ eventOuter: {
317
+ position: 'relative',
318
+ marginTop: EVENT_GAP,
319
+ marginLeft: EVENT_GAP,
320
+ },
254
321
  event: {
322
+ flex: 1,
323
+ width: '100%',
324
+ height: '100%',
255
325
  borderWidth: 0.5,
256
326
  borderRadius: 4,
257
327
  paddingHorizontal: 4,
258
328
  flexDirection: 'row',
259
329
  alignItems: 'center',
260
330
  boxShadow: '0 0 2px 0 rgba(0, 0, 0, 0.1)',
261
- marginTop: EVENT_GAP,
262
- marginLeft: EVENT_GAP,
331
+ },
332
+ eventOverlayHost: {
333
+ ...StyleSheet.absoluteFillObject,
334
+ pointerEvents: 'box-none',
263
335
  },
264
336
  prevDateEvent: {
265
337
  marginLeft: -1,
@@ -272,4 +344,13 @@ const styles = StyleSheet.create({
272
344
  eventTitle: {
273
345
  fontSize: 12,
274
346
  },
347
+ cellInteractionOverlay: {
348
+ ...StyleSheet.absoluteFillObject,
349
+ zIndex: 1000,
350
+ backgroundColor: 'transparent',
351
+ ...Platform.select({
352
+ android: { elevation: 12 },
353
+ default: {},
354
+ }),
355
+ },
275
356
  });