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.
- package/README.md +1 -0
- package/lib/module/calendar/month-calendar/MonthCalendar.js +3 -1
- package/lib/module/calendar/month-calendar/MonthCalendar.js.map +1 -1
- package/lib/module/calendar/month-calendar/view/MonthCalendarEventOverlay.js +21 -0
- package/lib/module/calendar/month-calendar/view/MonthCalendarEventOverlay.js.map +1 -0
- package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js +2 -0
- package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js.map +1 -1
- package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js +118 -66
- package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js.map +1 -1
- package/lib/module/calendar/resources-calendar/ResourcesCalendar.js +102 -50
- package/lib/module/calendar/resources-calendar/ResourcesCalendar.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts +8 -0
- package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts.map +1 -1
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarEventOverlay.d.ts +16 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarEventOverlay.d.ts.map +1 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts +3 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts.map +1 -1
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts +3 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts.map +1 -1
- package/lib/typescript/src/calendar/resources-calendar/ResourcesCalendar.d.ts +8 -1
- package/lib/typescript/src/calendar/resources-calendar/ResourcesCalendar.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/calendar/month-calendar/MonthCalendar.tsx +16 -1
- package/src/calendar/month-calendar/view/MonthCalendarEventOverlay.tsx +37 -0
- package/src/calendar/month-calendar/view/MonthCalendarViewItem.tsx +5 -0
- package/src/calendar/month-calendar/view/MonthCalendarWeekRow.tsx +186 -113
- package/src/calendar/resources-calendar/ResourcesCalendar.tsx +181 -96
- package/src/index.tsx +2 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useMemo,
|
|
4
|
+
useRef,
|
|
5
|
+
useState,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import type {
|
|
3
9
|
CalendarEvent,
|
|
4
10
|
CalendarResource,
|
|
@@ -8,6 +14,7 @@ import {
|
|
|
8
14
|
type NativeSyntheticEvent,
|
|
9
15
|
type TextStyle,
|
|
10
16
|
type ViewStyle,
|
|
17
|
+
Platform,
|
|
11
18
|
RefreshControl,
|
|
12
19
|
ScrollView,
|
|
13
20
|
StyleSheet,
|
|
@@ -43,11 +50,18 @@ type ResourcesCalendarProps = {
|
|
|
43
50
|
bottomSpacing?: number;
|
|
44
51
|
eventTextStyle?: (event: CalendarEvent) => TextStyle;
|
|
45
52
|
eventEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
|
|
53
|
+
renderEventOverlay?: (event: CalendarEvent) => ReactNode;
|
|
46
54
|
dateCellContainerStyle?: (date: Date) => ViewStyle;
|
|
47
55
|
cellContainerStyle?: (resource: CalendarResource, date: Date) => ViewStyle;
|
|
48
56
|
hiddenMonth?: boolean;
|
|
49
57
|
allowFontScaling?: boolean;
|
|
50
58
|
resourceNameLayout?: 'fixed-column' | 'inline-band';
|
|
59
|
+
/**
|
|
60
|
+
* When true, a transparent layer is placed above events in each cell so
|
|
61
|
+
* `onPressCell` / `onLongPressCell` receive touches for the full cell area.
|
|
62
|
+
* Event taps are disabled while this is on (overlay captures the gesture).
|
|
63
|
+
*/
|
|
64
|
+
prioritizeCellInteraction?: boolean;
|
|
51
65
|
};
|
|
52
66
|
|
|
53
67
|
const DEFAULT_DATE_COLUMN_WIDTH = 60;
|
|
@@ -69,6 +83,7 @@ type ResourceRowProps = {
|
|
|
69
83
|
eventHeight: number;
|
|
70
84
|
eventTextStyle?: (event: CalendarEvent) => TextStyle;
|
|
71
85
|
eventEllipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
|
|
86
|
+
renderEventOverlay?: (event: CalendarEvent) => ReactNode;
|
|
72
87
|
cellContainerStyle?: (resource: CalendarResource, date: Date) => ViewStyle;
|
|
73
88
|
allowFontScaling?: boolean;
|
|
74
89
|
onLayout?: (height: number) => void;
|
|
@@ -76,6 +91,7 @@ type ResourceRowProps = {
|
|
|
76
91
|
scrollOffset: number;
|
|
77
92
|
renderResourceNameLabel?: (resource: CalendarResource) => React.JSX.Element;
|
|
78
93
|
};
|
|
94
|
+
prioritizeCellInteraction?: boolean;
|
|
79
95
|
};
|
|
80
96
|
|
|
81
97
|
function ResourceRow({
|
|
@@ -92,10 +108,12 @@ function ResourceRow({
|
|
|
92
108
|
eventHeight,
|
|
93
109
|
eventTextStyle,
|
|
94
110
|
eventEllipsizeMode,
|
|
111
|
+
renderEventOverlay,
|
|
95
112
|
cellContainerStyle,
|
|
96
113
|
allowFontScaling,
|
|
97
114
|
onLayout,
|
|
98
115
|
inlineBand,
|
|
116
|
+
prioritizeCellInteraction,
|
|
99
117
|
}: ResourceRowProps) {
|
|
100
118
|
const resourceEvents = eventsByResourceId.get(resource.id) ?? [];
|
|
101
119
|
const eventPosition = new ResourcesCalendarEventPosition();
|
|
@@ -169,106 +187,152 @@ function ResourceRow({
|
|
|
169
187
|
}
|
|
170
188
|
}
|
|
171
189
|
|
|
172
|
-
|
|
190
|
+
const showPrioritizedCellOverlay =
|
|
191
|
+
prioritizeCellInteraction === true &&
|
|
192
|
+
(onPressCell != null || onLongPressCell != null);
|
|
193
|
+
|
|
194
|
+
const cellWrapperStyle = [
|
|
195
|
+
styles.contentCellContainer,
|
|
196
|
+
{ width: dateColumnWidth },
|
|
197
|
+
{ zIndex: dates.length - dateIndex },
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
const eventRows = cellEvents.map((event, rowIndex) => {
|
|
201
|
+
if (typeof event === 'number') {
|
|
202
|
+
return (
|
|
203
|
+
<View
|
|
204
|
+
key={`spacer-${rowIndex}`}
|
|
205
|
+
style={{
|
|
206
|
+
height: eventHeight,
|
|
207
|
+
marginBottom: EVENT_GAP,
|
|
208
|
+
}}
|
|
209
|
+
/>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const rawStartDjs = dayjs(event.start);
|
|
214
|
+
const startDjs = dateIndex === 0 ? djs : dayjs(event.start);
|
|
215
|
+
const endDjs = dayjs(event.end);
|
|
216
|
+
const diffDays = endDjs
|
|
217
|
+
.startOf('day')
|
|
218
|
+
.diff(startDjs.startOf('day'), 'day');
|
|
219
|
+
const isPrevDateEvent =
|
|
220
|
+
dateIndex === 0 && rawStartDjs.isBefore(djs);
|
|
221
|
+
|
|
222
|
+
// Calculate event width based on the number of days it spans
|
|
223
|
+
let width =
|
|
224
|
+
(diffDays + 1) * dateColumnWidth -
|
|
225
|
+
EVENT_GAP * 2 -
|
|
226
|
+
CELL_BORDER_WIDTH * 2;
|
|
227
|
+
if (isPrevDateEvent) {
|
|
228
|
+
width += EVENT_GAP + 1;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Record position info
|
|
232
|
+
eventPosition.push({
|
|
233
|
+
resourceId: resource.id,
|
|
234
|
+
startDate: startDjs.toDate(),
|
|
235
|
+
days: diffDays + 1,
|
|
236
|
+
rowNum: rowIndex + 1,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const eventOverlayNode = renderEventOverlay?.(event);
|
|
240
|
+
const showEventOverlay =
|
|
241
|
+
renderEventOverlay != null &&
|
|
242
|
+
eventOverlayNode != null &&
|
|
243
|
+
eventOverlayNode !== false;
|
|
244
|
+
|
|
245
|
+
return (
|
|
246
|
+
<View
|
|
247
|
+
key={event.id}
|
|
248
|
+
pointerEvents={showPrioritizedCellOverlay ? 'none' : 'auto'}
|
|
249
|
+
style={[
|
|
250
|
+
styles.eventOuter,
|
|
251
|
+
{ width, height: eventHeight },
|
|
252
|
+
isPrevDateEvent ? styles.prevDateEvent : {},
|
|
253
|
+
]}
|
|
254
|
+
>
|
|
255
|
+
<TouchableOpacity
|
|
256
|
+
data-component-name="resources-calendar-event"
|
|
257
|
+
style={[
|
|
258
|
+
styles.event,
|
|
259
|
+
{
|
|
260
|
+
backgroundColor: event.backgroundColor,
|
|
261
|
+
borderColor: event.borderColor,
|
|
262
|
+
...(event.borderStyle !== undefined && {
|
|
263
|
+
borderStyle: event.borderStyle,
|
|
264
|
+
}),
|
|
265
|
+
...(event.borderWidth !== undefined && {
|
|
266
|
+
borderWidth: event.borderWidth,
|
|
267
|
+
}),
|
|
268
|
+
...(event.borderRadius !== undefined && {
|
|
269
|
+
borderRadius: event.borderRadius,
|
|
270
|
+
}),
|
|
271
|
+
},
|
|
272
|
+
]}
|
|
273
|
+
onPress={() => onPressEvent?.(event)}
|
|
274
|
+
onLongPress={() => onLongPressEvent?.(event)}
|
|
275
|
+
delayLongPress={delayLongPressEvent}
|
|
276
|
+
>
|
|
277
|
+
<Text
|
|
278
|
+
numberOfLines={1}
|
|
279
|
+
ellipsizeMode={eventEllipsizeMode ?? 'tail'}
|
|
280
|
+
allowFontScaling={allowFontScaling}
|
|
281
|
+
style={[
|
|
282
|
+
styles.eventTitle,
|
|
283
|
+
{ color: event.color },
|
|
284
|
+
eventTextStyle?.(event),
|
|
285
|
+
]}
|
|
286
|
+
>
|
|
287
|
+
{event.title}
|
|
288
|
+
</Text>
|
|
289
|
+
</TouchableOpacity>
|
|
290
|
+
{showEventOverlay ? (
|
|
291
|
+
<View
|
|
292
|
+
style={styles.eventOverlayHost}
|
|
293
|
+
pointerEvents="box-none"
|
|
294
|
+
>
|
|
295
|
+
{eventOverlayNode}
|
|
296
|
+
</View>
|
|
297
|
+
) : null}
|
|
298
|
+
</View>
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
const cellInner = (
|
|
303
|
+
<>
|
|
304
|
+
<View
|
|
305
|
+
style={[
|
|
306
|
+
styles.contentCellContainerInner,
|
|
307
|
+
cellContainerStyle?.(resource, date),
|
|
308
|
+
]}
|
|
309
|
+
/>
|
|
310
|
+
{eventRows}
|
|
311
|
+
</>
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
return showPrioritizedCellOverlay ? (
|
|
315
|
+
<View key={date.getTime()} style={cellWrapperStyle}>
|
|
316
|
+
{cellInner}
|
|
317
|
+
<TouchableOpacity
|
|
318
|
+
accessible={false}
|
|
319
|
+
style={styles.cellInteractionOverlay}
|
|
320
|
+
activeOpacity={1}
|
|
321
|
+
onPress={() => onPressCell?.(resource, date)}
|
|
322
|
+
onLongPress={() => onLongPressCell?.(resource, date)}
|
|
323
|
+
delayLongPress={delayLongPressCell}
|
|
324
|
+
/>
|
|
325
|
+
</View>
|
|
326
|
+
) : (
|
|
173
327
|
<TouchableOpacity
|
|
174
328
|
key={date.getTime()}
|
|
175
|
-
style={
|
|
176
|
-
styles.contentCellContainer,
|
|
177
|
-
{ width: dateColumnWidth },
|
|
178
|
-
{ zIndex: dates.length - dateIndex },
|
|
179
|
-
]}
|
|
329
|
+
style={cellWrapperStyle}
|
|
180
330
|
onPress={() => onPressCell?.(resource, date)}
|
|
181
331
|
onLongPress={() => onLongPressCell?.(resource, date)}
|
|
182
332
|
delayLongPress={delayLongPressCell}
|
|
183
333
|
activeOpacity={1}
|
|
184
334
|
>
|
|
185
|
-
|
|
186
|
-
style={[
|
|
187
|
-
styles.contentCellContainerInner,
|
|
188
|
-
cellContainerStyle?.(resource, date),
|
|
189
|
-
]}
|
|
190
|
-
/>
|
|
191
|
-
{cellEvents.map((event, rowIndex) => {
|
|
192
|
-
if (typeof event === 'number') {
|
|
193
|
-
return (
|
|
194
|
-
<View
|
|
195
|
-
key={`spacer-${rowIndex}`}
|
|
196
|
-
style={{
|
|
197
|
-
height: eventHeight,
|
|
198
|
-
marginBottom: EVENT_GAP,
|
|
199
|
-
}}
|
|
200
|
-
/>
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const rawStartDjs = dayjs(event.start);
|
|
205
|
-
const startDjs = dateIndex === 0 ? djs : dayjs(event.start);
|
|
206
|
-
const endDjs = dayjs(event.end);
|
|
207
|
-
const diffDays = endDjs
|
|
208
|
-
.startOf('day')
|
|
209
|
-
.diff(startDjs.startOf('day'), 'day');
|
|
210
|
-
const isPrevDateEvent =
|
|
211
|
-
dateIndex === 0 && rawStartDjs.isBefore(djs);
|
|
212
|
-
|
|
213
|
-
// Calculate event width based on the number of days it spans
|
|
214
|
-
let width =
|
|
215
|
-
(diffDays + 1) * dateColumnWidth -
|
|
216
|
-
EVENT_GAP * 2 -
|
|
217
|
-
CELL_BORDER_WIDTH * 2;
|
|
218
|
-
if (isPrevDateEvent) {
|
|
219
|
-
width += EVENT_GAP + 1;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Record position info
|
|
223
|
-
eventPosition.push({
|
|
224
|
-
resourceId: resource.id,
|
|
225
|
-
startDate: startDjs.toDate(),
|
|
226
|
-
days: diffDays + 1,
|
|
227
|
-
rowNum: rowIndex + 1,
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
return (
|
|
231
|
-
<TouchableOpacity
|
|
232
|
-
data-component-name="resources-calendar-event"
|
|
233
|
-
key={event.id}
|
|
234
|
-
style={[
|
|
235
|
-
styles.event,
|
|
236
|
-
{
|
|
237
|
-
backgroundColor: event.backgroundColor,
|
|
238
|
-
borderColor: event.borderColor,
|
|
239
|
-
width,
|
|
240
|
-
height: eventHeight,
|
|
241
|
-
...(event.borderStyle !== undefined && {
|
|
242
|
-
borderStyle: event.borderStyle,
|
|
243
|
-
}),
|
|
244
|
-
...(event.borderWidth !== undefined && {
|
|
245
|
-
borderWidth: event.borderWidth,
|
|
246
|
-
}),
|
|
247
|
-
...(event.borderRadius !== undefined && {
|
|
248
|
-
borderRadius: event.borderRadius,
|
|
249
|
-
}),
|
|
250
|
-
},
|
|
251
|
-
isPrevDateEvent ? styles.prevDateEvent : {},
|
|
252
|
-
]}
|
|
253
|
-
onPress={() => onPressEvent?.(event)}
|
|
254
|
-
onLongPress={() => onLongPressEvent?.(event)}
|
|
255
|
-
delayLongPress={delayLongPressEvent}
|
|
256
|
-
>
|
|
257
|
-
<Text
|
|
258
|
-
numberOfLines={1}
|
|
259
|
-
ellipsizeMode={eventEllipsizeMode ?? 'tail'}
|
|
260
|
-
allowFontScaling={allowFontScaling}
|
|
261
|
-
style={[
|
|
262
|
-
styles.eventTitle,
|
|
263
|
-
{ color: event.color },
|
|
264
|
-
eventTextStyle?.(event),
|
|
265
|
-
]}
|
|
266
|
-
>
|
|
267
|
-
{event.title}
|
|
268
|
-
</Text>
|
|
269
|
-
</TouchableOpacity>
|
|
270
|
-
);
|
|
271
|
-
})}
|
|
335
|
+
{cellInner}
|
|
272
336
|
</TouchableOpacity>
|
|
273
337
|
);
|
|
274
338
|
})}
|
|
@@ -421,6 +485,7 @@ export function ResourcesCalendar(props: ResourcesCalendarProps) {
|
|
|
421
485
|
eventHeight: props.eventHeight ?? DEFAULT_EVENT_HEIGHT,
|
|
422
486
|
eventTextStyle: props.eventTextStyle,
|
|
423
487
|
eventEllipsizeMode: props.eventEllipsizeMode,
|
|
488
|
+
renderEventOverlay: props.renderEventOverlay,
|
|
424
489
|
cellContainerStyle: props.cellContainerStyle,
|
|
425
490
|
allowFontScaling: props.allowFontScaling,
|
|
426
491
|
inlineBand: isInlineBand
|
|
@@ -429,6 +494,7 @@ export function ResourcesCalendar(props: ResourcesCalendarProps) {
|
|
|
429
494
|
renderResourceNameLabel: props.renderResourceNameLabel,
|
|
430
495
|
}
|
|
431
496
|
: undefined,
|
|
497
|
+
prioritizeCellInteraction: props.prioritizeCellInteraction,
|
|
432
498
|
};
|
|
433
499
|
|
|
434
500
|
const resourceNameColumn = !isInlineBand ? (
|
|
@@ -696,6 +762,15 @@ const styles = StyleSheet.create({
|
|
|
696
762
|
right: 0,
|
|
697
763
|
bottom: 0,
|
|
698
764
|
},
|
|
765
|
+
cellInteractionOverlay: {
|
|
766
|
+
...StyleSheet.absoluteFillObject,
|
|
767
|
+
zIndex: 1000,
|
|
768
|
+
backgroundColor: 'transparent',
|
|
769
|
+
...Platform.select({
|
|
770
|
+
android: { elevation: 12 },
|
|
771
|
+
default: {},
|
|
772
|
+
}),
|
|
773
|
+
},
|
|
699
774
|
container: {
|
|
700
775
|
flex: 1,
|
|
701
776
|
flexDirection: 'row',
|
|
@@ -739,14 +814,24 @@ const styles = StyleSheet.create({
|
|
|
739
814
|
fontSize: 12,
|
|
740
815
|
color: 'black',
|
|
741
816
|
},
|
|
817
|
+
eventOuter: {
|
|
818
|
+
position: 'relative',
|
|
819
|
+
marginTop: EVENT_GAP,
|
|
820
|
+
marginLeft: EVENT_GAP,
|
|
821
|
+
},
|
|
742
822
|
event: {
|
|
823
|
+
flex: 1,
|
|
824
|
+
width: '100%',
|
|
825
|
+
height: '100%',
|
|
743
826
|
borderWidth: 0.5,
|
|
744
827
|
borderRadius: 4,
|
|
745
828
|
paddingHorizontal: 4,
|
|
746
829
|
flexDirection: 'row',
|
|
747
830
|
alignItems: 'center',
|
|
748
|
-
|
|
749
|
-
|
|
831
|
+
},
|
|
832
|
+
eventOverlayHost: {
|
|
833
|
+
...StyleSheet.absoluteFillObject,
|
|
834
|
+
pointerEvents: 'box-none',
|
|
750
835
|
},
|
|
751
836
|
prevDateEvent: {
|
|
752
837
|
marginLeft: -1,
|
package/src/index.tsx
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { MonthCalendar } from './calendar/month-calendar/MonthCalendar';
|
|
2
|
+
export { MonthCalendarEventOverlay } from './calendar/month-calendar/view/MonthCalendarEventOverlay';
|
|
2
3
|
export type { CalendarEvent } from './types/month-calendar';
|
|
3
4
|
export type { MonthCalendarRef } from './calendar/month-calendar/MonthCalendar';
|
|
5
|
+
export type { MonthCalendarEventOverlayPosition } from './calendar/month-calendar/view/MonthCalendarEventOverlay';
|
|
4
6
|
|
|
5
7
|
export { ResourcesCalendar } from './calendar/resources-calendar/ResourcesCalendar';
|
|
6
8
|
export type {
|