react-native-calendar-resource 1.0.3 → 1.1.2
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/LICENSE +1 -1
- package/README.md +126 -21
- package/dist/components/calendar/Calendar.d.ts +1 -1
- package/dist/components/calendar/Calendar.d.ts.map +1 -1
- package/dist/components/calendar/Calendar.js +108 -13
- package/dist/components/calendar/EventsLayer.d.ts +9 -7
- package/dist/components/calendar/EventsLayer.d.ts.map +1 -1
- package/dist/components/calendar/EventsLayer.js +185 -37
- package/dist/components/calendar/GridBody.d.ts +5 -5
- package/dist/components/calendar/GridBody.d.ts.map +1 -1
- package/dist/components/calendar/GridBody.js +3 -1
- package/dist/components/calendar/ResourceHeaders.d.ts +5 -5
- package/dist/components/calendar/ResourceHeaders.d.ts.map +1 -1
- package/dist/components/calendar/UnavailableLayer.d.ts +5 -5
- package/dist/components/calendar/UnavailableLayer.d.ts.map +1 -1
- package/dist/components/calendar/ZoomControls.d.ts +10 -0
- package/dist/components/calendar/ZoomControls.d.ts.map +1 -0
- package/dist/components/calendar/ZoomControls.js +63 -0
- package/dist/types/calendar.d.ts +28 -18
- package/dist/types/calendar.d.ts.map +1 -1
- package/package.json +13 -2
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ A fully customizable, type-safe resource-based calendar component for React Nati
|
|
|
14
14
|
- 🎭 **Style Customization** - Full control over colors and appearance
|
|
15
15
|
- 👆 **Interactive** - Handle slot, event, and resource press events
|
|
16
16
|
- 🔄 **Synchronized Scrolling** - Header and time column scroll with the grid
|
|
17
|
+
- 🎯 **Drag and Drop** - Long-press and drag events to reschedule (optional)
|
|
18
|
+
- 🔍 **Pinch to Zoom** - Zoom in/out with focal point support (optional)
|
|
17
19
|
|
|
18
20
|
---
|
|
19
21
|
|
|
@@ -30,9 +32,13 @@ yarn add react-native-calendar-resource
|
|
|
30
32
|
Ensure you have the required peer dependencies:
|
|
31
33
|
|
|
32
34
|
```bash
|
|
33
|
-
npm install
|
|
35
|
+
npm install date-fns
|
|
36
|
+
# or
|
|
37
|
+
yarn add date-fns
|
|
34
38
|
```
|
|
35
39
|
|
|
40
|
+
**Note:** For Expo projects, these are typically already installed. For bare React Native projects, follow the [react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation) and [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/) installation guides.
|
|
41
|
+
|
|
36
42
|
---
|
|
37
43
|
|
|
38
44
|
## Quick Start
|
|
@@ -80,26 +86,33 @@ function MyCalendar() {
|
|
|
80
86
|
|
|
81
87
|
### Optional Props
|
|
82
88
|
|
|
83
|
-
| Prop | Type
|
|
84
|
-
| ------------------------ |
|
|
85
|
-
| `unavailableSlots` | `UnavailableSlot<T>[]`
|
|
86
|
-
| `timeConfig` | `CalendarTimeConfig`
|
|
87
|
-
| `dimensions` | `Partial<CalendarDimensions>`
|
|
88
|
-
| `styles` | `CalendarStyles`
|
|
89
|
-
| `eventStyles` | `CalendarEventStyles`
|
|
90
|
-
| `unavailableStyles` | `UnavailableSlotStyles`
|
|
91
|
-
| `onSlotPress` | `(hour, resourceId, date) => void`
|
|
92
|
-
| `onEventPress` | `(event) => void`
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `
|
|
97
|
-
| `
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
89
|
+
| Prop | Type | Default | Description |
|
|
90
|
+
| ------------------------ | -------------------------------------- | ---------------------------------------------------- | ------------------------------------------- |
|
|
91
|
+
| `unavailableSlots` | `UnavailableSlot<T>[]` | `[]` | Slots that are unavailable |
|
|
92
|
+
| `timeConfig` | `CalendarTimeConfig` | `{ startHour: 9, endHour: 24, timeFormat: "HH:mm" }` | Time configuration |
|
|
93
|
+
| `dimensions` | `Partial<CalendarDimensions>` | `{ resourceWidth: 64, hourHeight: 64 }` | Grid dimensions |
|
|
94
|
+
| `styles` | `CalendarStyles` | - | Overall calendar styling |
|
|
95
|
+
| `eventStyles` | `CalendarEventStyles` | - | Event-specific styling |
|
|
96
|
+
| `unavailableStyles` | `UnavailableSlotStyles` | - | Unavailable slot styling |
|
|
97
|
+
| `onSlotPress` | `(hour, resourceId, date) => void` | - | Called when empty slot is pressed |
|
|
98
|
+
| `onEventPress` | `(event) => void` | - | Called when event is pressed |
|
|
99
|
+
| `onEventDrop` | `(droppedData, originalEvent) => void` | - | Called when event is dropped after dragging |
|
|
100
|
+
| `onResourcePress` | `(resource) => void` | - | Called when resource header is pressed |
|
|
101
|
+
| `renderEvent` | `(event, dimensions) => ReactNode` | - | Custom event renderer |
|
|
102
|
+
| `renderResourceHeader` | `(resource) => ReactNode` | - | Custom resource header renderer |
|
|
103
|
+
| `renderTimeSlot` | `(hour) => ReactNode` | - | Custom time slot renderer |
|
|
104
|
+
| `renderUnavailableSlot` | `(slot, dimensions) => ReactNode` | - | Custom unavailable slot renderer |
|
|
105
|
+
| `showHeader` | `boolean` | `true` | Show date header |
|
|
106
|
+
| `showTimeColumn` | `boolean` | `true` | Show time column |
|
|
107
|
+
| `showResourceHeaders` | `boolean` | `true` | Show resource headers |
|
|
108
|
+
| `enableHorizontalScroll` | `boolean` | `true` | Enable horizontal scrolling |
|
|
109
|
+
| `enableVerticalScroll` | `boolean` | `true` | Enable vertical scrolling |
|
|
110
|
+
| `enableDragAndDrop` | `boolean` | `false` | Enable drag and drop for events |
|
|
111
|
+
| `zoomEnabled` | `boolean` | `false` | Enable pinch-to-zoom gesture ⚠️ Experimental |
|
|
112
|
+
| `maxZoom` | `number` | `3` | Maximum zoom level (3 = 300%) |
|
|
113
|
+
| `initialZoom` | `number` | `1` | Initial zoom level (1 = 100%) |
|
|
114
|
+
| `snapBack` | `boolean` | `false` | Auto-return to initial zoom after gesture |
|
|
115
|
+
| `snapBackDelay` | `number` | `1000` | Delay before snap-back in milliseconds |
|
|
103
116
|
|
|
104
117
|
---
|
|
105
118
|
|
|
@@ -147,6 +160,98 @@ type CalendarDimensions = {
|
|
|
147
160
|
|
|
148
161
|
## Examples
|
|
149
162
|
|
|
163
|
+
### Drag and Drop Events
|
|
164
|
+
|
|
165
|
+
Enable event rescheduling by long-pressing and dragging:
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
import { useState } from "react";
|
|
169
|
+
import { Calendar, CalendarEvent } from "react-native-calendar-resource";
|
|
170
|
+
|
|
171
|
+
function MyCalendar() {
|
|
172
|
+
const [events, setEvents] = useState<CalendarEvent[]>([
|
|
173
|
+
{
|
|
174
|
+
id: "evt1",
|
|
175
|
+
title: "Team Meeting",
|
|
176
|
+
resourceId: "1",
|
|
177
|
+
startHour: 10,
|
|
178
|
+
endHour: 11.5,
|
|
179
|
+
color: "#3b82f6",
|
|
180
|
+
},
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<Calendar
|
|
185
|
+
date={new Date()}
|
|
186
|
+
resources={resources}
|
|
187
|
+
events={events}
|
|
188
|
+
enableDragAndDrop={true}
|
|
189
|
+
onEventDrop={(droppedData, originalEvent) => {
|
|
190
|
+
// Update event with new time/resource
|
|
191
|
+
setEvents((prev) =>
|
|
192
|
+
prev.map((event) =>
|
|
193
|
+
event.id === droppedData.eventId
|
|
194
|
+
? {
|
|
195
|
+
...event,
|
|
196
|
+
resourceId: droppedData.newResourceId,
|
|
197
|
+
startHour: droppedData.newStartHour,
|
|
198
|
+
endHour: droppedData.newEndHour,
|
|
199
|
+
}
|
|
200
|
+
: event,
|
|
201
|
+
),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
console.log("Event moved:", {
|
|
205
|
+
from: {
|
|
206
|
+
resource: originalEvent.resourceId,
|
|
207
|
+
time: `${originalEvent.startHour}-${originalEvent.endHour}`,
|
|
208
|
+
},
|
|
209
|
+
to: {
|
|
210
|
+
resource: droppedData.newResourceId,
|
|
211
|
+
time: `${droppedData.newStartHour}-${droppedData.newEndHour}`,
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
}}
|
|
215
|
+
/>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**How it works:**
|
|
221
|
+
|
|
222
|
+
- Long-press an event for 500ms to start dragging
|
|
223
|
+
- Drag the event to a new resource or time slot
|
|
224
|
+
- Events snap to 30-minute intervals
|
|
225
|
+
- Visual feedback shows the event being dragged (opacity, scale, border)
|
|
226
|
+
- The `onEventDrop` callback receives both the new position and original event data
|
|
227
|
+
|
|
228
|
+
### Pinch to Zoom
|
|
229
|
+
|
|
230
|
+
> **⚠️ EXPERIMENTAL FEATURE**: Pinch-to-zoom is currently experimental and may have performance or gesture detection issues. We recommend waiting for a stable release before using in production.
|
|
231
|
+
|
|
232
|
+
Enable pinch-to-zoom for better visibility of events:
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
<Calendar
|
|
236
|
+
date={new Date()}
|
|
237
|
+
resources={resources}
|
|
238
|
+
events={events}
|
|
239
|
+
zoomEnabled={true}
|
|
240
|
+
maxZoom={3}
|
|
241
|
+
initialZoom={1}
|
|
242
|
+
snapBack={true}
|
|
243
|
+
snapBackDelay={1000}
|
|
244
|
+
/>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**How it works:**
|
|
248
|
+
|
|
249
|
+
- Pinch with two fingers to zoom in/out (min: 1x, max: configurable)
|
|
250
|
+
- Zoom centers on the focal point between your fingers
|
|
251
|
+
- Scroll position adjusts automatically to keep content in view
|
|
252
|
+
- Optional snap-back returns to initial zoom after a delay
|
|
253
|
+
- Smooth animations for zoom transitions
|
|
254
|
+
|
|
150
255
|
### Custom Time Range
|
|
151
256
|
|
|
152
257
|
```tsx
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { CalendarProps } from "../../types/calendar";
|
|
2
|
-
export declare function Calendar
|
|
2
|
+
export declare function Calendar({ date, resources, events, unavailableSlots, timeConfig, dimensions, zoomEnabled, maxZoom, initialZoom, snapBack, snapBackDelay, styles, eventStyles, unavailableStyles, onSlotPress, onEventPress, onEventDrop, onResourcePress, onDateChange, minDate, maxDate, allowPastDates, renderEvent, renderResourceHeader, renderTimeSlot, renderUnavailableSlot, showHeader, showTimeColumn, showResourceHeaders, enableHorizontalScroll, enableVerticalScroll, showDateNavigation, enableDragAndDrop, dateFormat, accessibilityLabel, }: CalendarProps): import("react").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=Calendar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Calendar.d.ts","sourceRoot":"","sources":["../../../components/calendar/Calendar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Calendar.d.ts","sourceRoot":"","sources":["../../../components/calendar/Calendar.tsx"],"names":[],"mappings":"AAaA,OAAO,EAEL,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAoB9B,wBAAgB,QAAQ,CAAC,EACvB,IAAI,EACJ,SAAS,EACT,MAAM,EACN,gBAAqB,EACrB,UAAU,EACV,UAAU,EACV,WAAmB,EACnB,OAAW,EACX,WAAe,EACf,QAAgB,EAChB,aAAoB,EACpB,MAAM,EACN,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,eAAe,EACf,YAAY,EACZ,OAAO,EACP,OAAO,EACP,cAAsB,EACtB,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,qBAAqB,EACrB,UAAiB,EACjB,cAAqB,EACrB,mBAA0B,EAC1B,sBAA6B,EAC7B,oBAA2B,EAC3B,kBAAyB,EACzB,iBAAyB,EACzB,UAA+B,EAC/B,kBAA+B,GAChC,EAAE,aAAa,+BA8Pf"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { useMemo, useRef } from "react";
|
|
2
|
-
import {
|
|
1
|
+
import { useMemo, useRef, useState, useEffect } from "react";
|
|
2
|
+
import { View, } from "react-native";
|
|
3
|
+
import { Gesture, GestureDetector, ScrollView } from "react-native-gesture-handler";
|
|
4
|
+
import Animated, { useSharedValue, useAnimatedReaction, runOnJS, withTiming, } from "react-native-reanimated";
|
|
3
5
|
import { CalendarHeader } from "./CalendarHeader";
|
|
4
6
|
import { EventsLayer } from "./EventsLayer";
|
|
5
7
|
import { GridBody } from "./GridBody";
|
|
@@ -16,22 +18,111 @@ const DEFAULT_TIME_CONFIG = {
|
|
|
16
18
|
endHour: 24,
|
|
17
19
|
timeFormat: "HH:mm",
|
|
18
20
|
};
|
|
19
|
-
export function Calendar({ date, resources, events, unavailableSlots = [], timeConfig, dimensions, styles, eventStyles, unavailableStyles, onSlotPress, onEventPress, onResourcePress, onDateChange, minDate, maxDate, allowPastDates = false, renderEvent, renderResourceHeader, renderTimeSlot, renderUnavailableSlot, showHeader = true, showTimeColumn = true, showResourceHeaders = true, enableHorizontalScroll = true, enableVerticalScroll = true, showDateNavigation = true, dateFormat = "EEE, MMM d, yyyy", accessibilityLabel = "Calendar", }) {
|
|
21
|
+
export function Calendar({ date, resources, events, unavailableSlots = [], timeConfig, dimensions, zoomEnabled = false, maxZoom = 3, initialZoom = 1, snapBack = false, snapBackDelay = 1000, styles, eventStyles, unavailableStyles, onSlotPress, onEventPress, onEventDrop, onResourcePress, onDateChange, minDate, maxDate, allowPastDates = false, renderEvent, renderResourceHeader, renderTimeSlot, renderUnavailableSlot, showHeader = true, showTimeColumn = true, showResourceHeaders = true, enableHorizontalScroll = true, enableVerticalScroll = true, showDateNavigation = true, enableDragAndDrop = false, dateFormat = "EEE, MMM d, yyyy", accessibilityLabel = "Calendar", }) {
|
|
20
22
|
const headerScrollRef = useRef(null);
|
|
21
23
|
const timeColumnScrollRef = useRef(null);
|
|
24
|
+
const horizontalScrollRef = useRef(null);
|
|
25
|
+
const verticalScrollRef = useRef(null);
|
|
26
|
+
// Zoom state
|
|
27
|
+
const minZoom = 1;
|
|
28
|
+
const zoomScale = useSharedValue(initialZoom);
|
|
29
|
+
const savedZoomScale = useSharedValue(initialZoom);
|
|
30
|
+
const [currentZoom, setCurrentZoom] = useState(initialZoom);
|
|
31
|
+
const [isPinching, setIsPinching] = useState(false);
|
|
32
|
+
const snapBackTimerRef = useRef(null);
|
|
33
|
+
const focalX = useRef(0);
|
|
34
|
+
const focalY = useRef(0);
|
|
35
|
+
const lastScrollX = useRef(0);
|
|
36
|
+
const lastScrollY = useRef(0);
|
|
37
|
+
// Update state when zoom changes
|
|
38
|
+
useAnimatedReaction(() => zoomScale.value, (zoom) => {
|
|
39
|
+
runOnJS(setCurrentZoom)(zoom);
|
|
40
|
+
});
|
|
41
|
+
// Adjust scroll position for focal point zooming
|
|
42
|
+
const prevZoom = useRef(initialZoom);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (currentZoom !== prevZoom.current && horizontalScrollRef.current && verticalScrollRef.current) {
|
|
45
|
+
const zoomRatio = currentZoom / prevZoom.current;
|
|
46
|
+
// Calculate new scroll position to keep focal point in place
|
|
47
|
+
horizontalScrollRef.current.scrollTo({
|
|
48
|
+
x: (lastScrollX.current + focalX.current) * zoomRatio - focalX.current,
|
|
49
|
+
animated: false,
|
|
50
|
+
});
|
|
51
|
+
verticalScrollRef.current.scrollTo({
|
|
52
|
+
y: (lastScrollY.current + focalY.current) * zoomRatio - focalY.current,
|
|
53
|
+
animated: false,
|
|
54
|
+
});
|
|
55
|
+
lastScrollX.current = (lastScrollX.current + focalX.current) * zoomRatio - focalX.current;
|
|
56
|
+
lastScrollY.current = (lastScrollY.current + focalY.current) * zoomRatio - focalY.current;
|
|
57
|
+
prevZoom.current = currentZoom;
|
|
58
|
+
}
|
|
59
|
+
}, [currentZoom]);
|
|
22
60
|
// Merge configurations with defaults
|
|
23
|
-
const
|
|
61
|
+
const baseDimensions = useMemo(() => ({ ...DEFAULT_DIMENSIONS, ...dimensions }), [dimensions]);
|
|
24
62
|
const finalTimeConfig = useMemo(() => ({ ...DEFAULT_TIME_CONFIG, ...timeConfig }), [timeConfig]);
|
|
63
|
+
// Apply zoom to dimensions - recalculate on zoom change
|
|
64
|
+
const finalDimensions = useMemo(() => ({
|
|
65
|
+
resourceWidth: baseDimensions.resourceWidth * currentZoom,
|
|
66
|
+
hourHeight: baseDimensions.hourHeight * currentZoom,
|
|
67
|
+
}), [baseDimensions, currentZoom]);
|
|
25
68
|
// Calculate grid dimensions
|
|
26
69
|
const gridTotalWidth = resources.length * finalDimensions.resourceWidth;
|
|
27
70
|
const totalHours = finalTimeConfig.endHour - finalTimeConfig.startHour;
|
|
28
71
|
const gridTotalHeight = totalHours * finalDimensions.hourHeight;
|
|
72
|
+
// Callbacks to update focal point (avoid accessing refs in worklets)
|
|
73
|
+
const updateFocalPoint = (x, y) => {
|
|
74
|
+
focalX.current = x;
|
|
75
|
+
focalY.current = y;
|
|
76
|
+
};
|
|
77
|
+
// Pinch gesture for zoom with focal point
|
|
78
|
+
const pinchGesture = Gesture.Pinch()
|
|
79
|
+
.enabled(zoomEnabled)
|
|
80
|
+
.onBegin((e) => {
|
|
81
|
+
'worklet';
|
|
82
|
+
// Clear any pending snap-back timer
|
|
83
|
+
if (snapBackTimerRef.current) {
|
|
84
|
+
clearTimeout(snapBackTimerRef.current);
|
|
85
|
+
snapBackTimerRef.current = null;
|
|
86
|
+
}
|
|
87
|
+
runOnJS(setIsPinching)(true);
|
|
88
|
+
runOnJS(updateFocalPoint)(e.focalX, e.focalY);
|
|
89
|
+
})
|
|
90
|
+
.onUpdate((e) => {
|
|
91
|
+
'worklet';
|
|
92
|
+
const newScale = savedZoomScale.value * e.scale;
|
|
93
|
+
const clampedScale = Math.max(minZoom, Math.min(maxZoom, newScale));
|
|
94
|
+
// Update zoom
|
|
95
|
+
zoomScale.value = clampedScale;
|
|
96
|
+
// Store focal point
|
|
97
|
+
runOnJS(updateFocalPoint)(e.focalX, e.focalY);
|
|
98
|
+
})
|
|
99
|
+
.onEnd(() => {
|
|
100
|
+
'worklet';
|
|
101
|
+
savedZoomScale.value = zoomScale.value;
|
|
102
|
+
runOnJS(setIsPinching)(false);
|
|
103
|
+
// Snap back with smooth animation
|
|
104
|
+
if (snapBack && zoomScale.value !== initialZoom) {
|
|
105
|
+
snapBackTimerRef.current = setTimeout(() => {
|
|
106
|
+
zoomScale.value = withTiming(initialZoom, {
|
|
107
|
+
duration: 400,
|
|
108
|
+
// Use easeOut for smoother deceleration
|
|
109
|
+
});
|
|
110
|
+
savedZoomScale.value = initialZoom;
|
|
111
|
+
}, snapBackDelay);
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
.onFinalize(() => {
|
|
115
|
+
'worklet';
|
|
116
|
+
runOnJS(setIsPinching)(false);
|
|
117
|
+
});
|
|
29
118
|
const handleHorizontalScroll = (scrollEvent) => {
|
|
30
119
|
const horizontalOffset = scrollEvent.nativeEvent.contentOffset.x;
|
|
120
|
+
lastScrollX.current = horizontalOffset;
|
|
31
121
|
headerScrollRef.current?.scrollTo({ x: horizontalOffset, animated: false });
|
|
32
122
|
};
|
|
33
123
|
const handleVerticalScroll = (scrollEvent) => {
|
|
34
124
|
const verticalOffset = scrollEvent.nativeEvent.contentOffset.y;
|
|
125
|
+
lastScrollY.current = verticalOffset;
|
|
35
126
|
timeColumnScrollRef.current?.scrollTo({
|
|
36
127
|
y: verticalOffset,
|
|
37
128
|
animated: false,
|
|
@@ -47,22 +138,26 @@ export function Calendar({ date, resources, events, unavailableSlots = [], timeC
|
|
|
47
138
|
{showTimeColumn && (<TimeColumn scrollRef={timeColumnScrollRef} gridTotalHeight={gridTotalHeight} timeConfig={finalTimeConfig} dimensions={finalDimensions} renderTimeSlot={renderTimeSlot} styles={styles}/>)}
|
|
48
139
|
|
|
49
140
|
<View style={{ flex: 1 }}>
|
|
50
|
-
<
|
|
51
|
-
<
|
|
141
|
+
<GestureDetector gesture={pinchGesture}>
|
|
142
|
+
<Animated.View style={{ flex: 1 }}>
|
|
143
|
+
<ScrollView ref={horizontalScrollRef} horizontal={enableHorizontalScroll} showsHorizontalScrollIndicator={enableHorizontalScroll} bounces={false} onScroll={handleHorizontalScroll} scrollEventThrottle={16} nestedScrollEnabled={true} scrollEnabled={enableHorizontalScroll && !isPinching}>
|
|
144
|
+
<ScrollView ref={verticalScrollRef} showsVerticalScrollIndicator={enableVerticalScroll} bounces={false} onScroll={handleVerticalScroll} scrollEventThrottle={16} nestedScrollEnabled={true} scrollEnabled={enableVerticalScroll && !isPinching} contentContainerStyle={{
|
|
52
145
|
width: gridTotalWidth,
|
|
53
146
|
height: gridTotalHeight,
|
|
54
147
|
}}>
|
|
55
|
-
|
|
148
|
+
<View style={{
|
|
56
149
|
position: "relative",
|
|
57
150
|
width: gridTotalWidth,
|
|
58
151
|
height: gridTotalHeight,
|
|
59
152
|
}}>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
153
|
+
<GridBody resources={resources} events={events} unavailableSlots={unavailableSlots} onSlotPress={onSlotPress} date={date} timeConfig={finalTimeConfig} dimensions={finalDimensions} styles={styles}/>
|
|
154
|
+
<UnavailableLayer unavailableSlots={unavailableSlots} resources={resources} timeConfig={finalTimeConfig} dimensions={finalDimensions} unavailableStyles={unavailableStyles} renderUnavailableSlot={renderUnavailableSlot}/>
|
|
155
|
+
<EventsLayer events={events} resources={resources} onEventPress={onEventPress} onEventDrop={onEventDrop} timeConfig={finalTimeConfig} dimensions={finalDimensions} eventStyles={eventStyles} renderEvent={renderEvent} enableDragAndDrop={enableDragAndDrop}/>
|
|
156
|
+
</View>
|
|
157
|
+
</ScrollView>
|
|
158
|
+
</ScrollView>
|
|
159
|
+
</Animated.View>
|
|
160
|
+
</GestureDetector>
|
|
66
161
|
</View>
|
|
67
162
|
</View>
|
|
68
163
|
</View>);
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { CalendarDimensions, CalendarEvent, CalendarEventStyles, CalendarTimeConfig, RenderEventFunction, Resource } from "../../types/calendar";
|
|
2
|
-
type EventsLayerProps
|
|
3
|
-
events: CalendarEvent
|
|
4
|
-
resources: Resource
|
|
5
|
-
onEventPress?: (event: CalendarEvent
|
|
1
|
+
import { CalendarDimensions, CalendarEvent, CalendarEventStyles, CalendarTimeConfig, DroppedEventData, RenderEventFunction, Resource } from "../../types/calendar";
|
|
2
|
+
type EventsLayerProps = {
|
|
3
|
+
events: CalendarEvent[];
|
|
4
|
+
resources: Resource[];
|
|
5
|
+
onEventPress?: (event: CalendarEvent) => void;
|
|
6
|
+
onEventDrop?: (droppedData: DroppedEventData, originalEvent: CalendarEvent) => void;
|
|
6
7
|
timeConfig: CalendarTimeConfig;
|
|
7
8
|
dimensions: CalendarDimensions;
|
|
8
9
|
eventStyles?: CalendarEventStyles;
|
|
9
|
-
renderEvent?: RenderEventFunction
|
|
10
|
+
renderEvent?: RenderEventFunction;
|
|
11
|
+
enableDragAndDrop?: boolean;
|
|
10
12
|
};
|
|
11
|
-
export declare function EventsLayer
|
|
13
|
+
export declare function EventsLayer({ events, resources, onEventPress, onEventDrop, timeConfig, dimensions, eventStyles, renderEvent, enableDragAndDrop, }: EventsLayerProps): import("react").JSX.Element;
|
|
12
14
|
export {};
|
|
13
15
|
//# sourceMappingURL=EventsLayer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EventsLayer.d.ts","sourceRoot":"","sources":["../../../components/calendar/EventsLayer.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EventsLayer.d.ts","sourceRoot":"","sources":["../../../components/calendar/EventsLayer.tsx"],"names":[],"mappings":"AASA,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,QAAQ,EACT,MAAM,sBAAsB,CAAC;AAE9B,KAAK,gBAAgB,GAAG;IACtB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,CACZ,WAAW,EAAE,gBAAgB,EAC7B,aAAa,EAAE,aAAa,KACzB,IAAI,CAAC;IACV,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,SAAS,EACT,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,EACV,WAAW,EACX,WAAW,EACX,iBAAyB,GAC1B,EAAE,gBAAgB,+BA6RlB"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { useMemo } from "react";
|
|
1
|
+
import { useMemo, useState, useEffect } from "react";
|
|
2
2
|
import { Pressable, Text, View } from "react-native";
|
|
3
|
-
|
|
3
|
+
import { Gesture, GestureDetector } from "react-native-gesture-handler";
|
|
4
|
+
import Animated, { useAnimatedStyle, useSharedValue, withSpring, runOnJS, } from "react-native-reanimated";
|
|
5
|
+
export function EventsLayer({ events, resources, onEventPress, onEventDrop, timeConfig, dimensions, eventStyles, renderEvent, enableDragAndDrop = false, }) {
|
|
6
|
+
const [draggedEventId, setDraggedEventId] = useState(null);
|
|
7
|
+
const [dropPreview, setDropPreview] = useState(null);
|
|
4
8
|
const positionedEvents = useMemo(() => {
|
|
5
9
|
return events
|
|
6
10
|
.map((event) => {
|
|
@@ -25,7 +29,97 @@ export function EventsLayer({ events, resources, onEventPress, timeConfig, dimen
|
|
|
25
29
|
const gridTotalWidth = resources.length * dimensions.resourceWidth;
|
|
26
30
|
const gridBodyHeight = (timeConfig.endHour - timeConfig.startHour - 1) * dimensions.hourHeight;
|
|
27
31
|
const handleEventPress = (event) => {
|
|
28
|
-
|
|
32
|
+
if (!draggedEventId) {
|
|
33
|
+
onEventPress?.(event);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const updateDropPreview = (event, currentX, currentY, blockWidth, blockHeight, eventColor) => {
|
|
37
|
+
"worklet";
|
|
38
|
+
// Calculate snapped position
|
|
39
|
+
const newResourceIndex = Math.max(0, Math.min(Math.floor(currentX / dimensions.resourceWidth), resources.length - 1));
|
|
40
|
+
const hourOffset = currentY / dimensions.hourHeight;
|
|
41
|
+
const eventDuration = event.endHour - event.startHour;
|
|
42
|
+
let newStartHour = timeConfig.startHour + hourOffset;
|
|
43
|
+
// Snap to whole hour cells
|
|
44
|
+
newStartHour = Math.round(newStartHour);
|
|
45
|
+
// Clamp to valid range
|
|
46
|
+
newStartHour = Math.max(timeConfig.startHour, Math.min(timeConfig.endHour - eventDuration, newStartHour));
|
|
47
|
+
const snappedTop = (newStartHour - timeConfig.startHour - 1) * dimensions.hourHeight;
|
|
48
|
+
const snappedLeft = newResourceIndex * dimensions.resourceWidth;
|
|
49
|
+
runOnJS(setDropPreview)({
|
|
50
|
+
top: snappedTop,
|
|
51
|
+
left: snappedLeft,
|
|
52
|
+
width: blockWidth,
|
|
53
|
+
height: blockHeight,
|
|
54
|
+
color: eventColor,
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const handleEventDrop = (event, finalX, finalY) => {
|
|
58
|
+
"worklet";
|
|
59
|
+
// Calculate new resource and time
|
|
60
|
+
const newResourceIndex = Math.max(0, Math.min(Math.floor(finalX / dimensions.resourceWidth), resources.length - 1));
|
|
61
|
+
const newResource = resources[newResourceIndex];
|
|
62
|
+
const hourOffset = finalY / dimensions.hourHeight;
|
|
63
|
+
const eventDuration = event.endHour - event.startHour;
|
|
64
|
+
let newStartHour = timeConfig.startHour + hourOffset;
|
|
65
|
+
// Snap to whole hour cells
|
|
66
|
+
newStartHour = Math.round(newStartHour);
|
|
67
|
+
// Clamp to valid range
|
|
68
|
+
newStartHour = Math.max(timeConfig.startHour, Math.min(timeConfig.endHour - eventDuration, newStartHour));
|
|
69
|
+
const newEndHour = newStartHour + eventDuration;
|
|
70
|
+
// Only trigger callback if position changed significantly
|
|
71
|
+
if (newResource.id !== event.resourceId ||
|
|
72
|
+
Math.abs(newStartHour - event.startHour) > 0.1) {
|
|
73
|
+
runOnJS(onEventDrop)({
|
|
74
|
+
eventId: event.id,
|
|
75
|
+
newResourceId: newResource.id,
|
|
76
|
+
newStartHour,
|
|
77
|
+
newEndHour,
|
|
78
|
+
}, event);
|
|
79
|
+
}
|
|
80
|
+
runOnJS(setDraggedEventId)(null);
|
|
81
|
+
runOnJS(setDropPreview)(null);
|
|
82
|
+
};
|
|
83
|
+
const createGesture = (event, layoutX, layoutY, translateX, translateY, blockWidth, blockHeight, eventColor) => {
|
|
84
|
+
const longPress = Gesture.LongPress()
|
|
85
|
+
.minDuration(500)
|
|
86
|
+
.onStart(() => {
|
|
87
|
+
if (enableDragAndDrop) {
|
|
88
|
+
runOnJS(setDraggedEventId)(event.id);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const pan = Gesture.Pan()
|
|
92
|
+
.enabled(enableDragAndDrop)
|
|
93
|
+
.activeOffsetX([-5, 5])
|
|
94
|
+
.activeOffsetY([-5, 5])
|
|
95
|
+
.onUpdate((e) => {
|
|
96
|
+
translateX.value = e.translationX;
|
|
97
|
+
translateY.value = e.translationY;
|
|
98
|
+
// Update preview position
|
|
99
|
+
const currentX = layoutX + e.translationX;
|
|
100
|
+
const currentY = layoutY + e.translationY;
|
|
101
|
+
updateDropPreview(event, currentX, currentY, blockWidth, blockHeight, eventColor);
|
|
102
|
+
})
|
|
103
|
+
.onEnd(() => {
|
|
104
|
+
const finalX = layoutX + translateX.value;
|
|
105
|
+
const finalY = layoutY + translateY.value;
|
|
106
|
+
// Calculate snapped position
|
|
107
|
+
const newResourceIndex = Math.max(0, Math.min(Math.floor(finalX / dimensions.resourceWidth), resources.length - 1));
|
|
108
|
+
const hourOffset = finalY / dimensions.hourHeight;
|
|
109
|
+
const eventDuration = event.endHour - event.startHour;
|
|
110
|
+
let newStartHour = timeConfig.startHour + hourOffset;
|
|
111
|
+
newStartHour = Math.round(newStartHour);
|
|
112
|
+
newStartHour = Math.max(timeConfig.startHour, Math.min(timeConfig.endHour - eventDuration, newStartHour));
|
|
113
|
+
const snappedTop = (newStartHour - timeConfig.startHour - 1) * dimensions.hourHeight;
|
|
114
|
+
const snappedLeft = newResourceIndex * dimensions.resourceWidth;
|
|
115
|
+
// Snap instantly to final position and KEEP it there
|
|
116
|
+
translateX.value = snappedLeft - layoutX;
|
|
117
|
+
translateY.value = snappedTop - layoutY;
|
|
118
|
+
// Trigger the drop callback - React will re-render with new position
|
|
119
|
+
handleEventDrop(event, finalX, finalY);
|
|
120
|
+
// Don't reset - let React take over when it re-renders with updated event data
|
|
121
|
+
});
|
|
122
|
+
return Gesture.Simultaneous(longPress, pan);
|
|
29
123
|
};
|
|
30
124
|
const defaultColor = eventStyles?.defaultColor || "#3b82f6";
|
|
31
125
|
const borderRadius = eventStyles?.borderRadius || 8;
|
|
@@ -38,42 +132,96 @@ export function EventsLayer({ events, resources, onEventPress, timeConfig, dimen
|
|
|
38
132
|
width: gridTotalWidth,
|
|
39
133
|
height: gridBodyHeight,
|
|
40
134
|
}} pointerEvents="box-none">
|
|
135
|
+
{/* Drop preview ghost */}
|
|
136
|
+
{dropPreview && (<View style={{
|
|
137
|
+
position: "absolute",
|
|
138
|
+
top: dropPreview.top,
|
|
139
|
+
left: dropPreview.left,
|
|
140
|
+
width: dropPreview.width,
|
|
141
|
+
height: dropPreview.height,
|
|
142
|
+
backgroundColor: dropPreview.color,
|
|
143
|
+
opacity: 0.3,
|
|
144
|
+
borderRadius,
|
|
145
|
+
borderWidth: 2,
|
|
146
|
+
borderColor: "#ffffff",
|
|
147
|
+
borderStyle: "dashed",
|
|
148
|
+
zIndex: 5,
|
|
149
|
+
}}/>)}
|
|
150
|
+
|
|
41
151
|
{positionedEvents.map((item) => {
|
|
42
152
|
const eventColor = item.event.color || defaultColor;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
justifyContent: "center",
|
|
46
|
-
alignItems: "center",
|
|
47
|
-
backgroundColor: "#1a1a1a",
|
|
48
|
-
top: item.topPosition,
|
|
49
|
-
left: item.leftPosition,
|
|
50
|
-
height: item.blockHeight,
|
|
51
|
-
width: item.blockWidth,
|
|
52
|
-
}}>
|
|
53
|
-
<Pressable onPress={() => handleEventPress(item.event)} style={{
|
|
54
|
-
height: item.blockHeight - 2,
|
|
55
|
-
width: item.blockWidth - 2,
|
|
56
|
-
backgroundColor: eventColor,
|
|
57
|
-
borderRadius,
|
|
58
|
-
opacity,
|
|
59
|
-
justifyContent: "center",
|
|
60
|
-
alignItems: "center",
|
|
61
|
-
padding: 8,
|
|
62
|
-
overflow: "hidden",
|
|
63
|
-
}}>
|
|
64
|
-
{renderEvent ? (renderEvent(item.event, {
|
|
65
|
-
width: item.blockWidth - 2,
|
|
66
|
-
height: item.blockHeight - 2,
|
|
67
|
-
})) : (<Text style={{
|
|
68
|
-
color: "#ffffff",
|
|
69
|
-
fontSize: 14,
|
|
70
|
-
fontWeight: "600",
|
|
71
|
-
textAlign: "center",
|
|
72
|
-
}} numberOfLines={2}>
|
|
73
|
-
{item.event.title}
|
|
74
|
-
</Text>)}
|
|
75
|
-
</Pressable>
|
|
76
|
-
</View>);
|
|
153
|
+
const isDragging = draggedEventId === item.event.id;
|
|
154
|
+
return (<EventBlock key={item.event.id} event={item.event} topPosition={item.topPosition} leftPosition={item.leftPosition} blockHeight={item.blockHeight} blockWidth={item.blockWidth} eventColor={eventColor} isDragging={isDragging} borderRadius={borderRadius} opacity={opacity} enableDragAndDrop={enableDragAndDrop} onPress={handleEventPress} createGesture={createGesture} renderEvent={renderEvent} updateDropPreview={updateDropPreview}/>);
|
|
77
155
|
})}
|
|
78
156
|
</View>);
|
|
79
157
|
}
|
|
158
|
+
function EventBlock({ event, topPosition, leftPosition, blockHeight, blockWidth, eventColor, isDragging, borderRadius, opacity, enableDragAndDrop, onPress, createGesture, renderEvent, updateDropPreview, }) {
|
|
159
|
+
const translateX = useSharedValue(0);
|
|
160
|
+
const translateY = useSharedValue(0);
|
|
161
|
+
const scale = useSharedValue(1);
|
|
162
|
+
// Reset translation when position changes (event data updated)
|
|
163
|
+
// Use the event's position as a key to detect changes
|
|
164
|
+
const positionKey = `${topPosition}-${leftPosition}`;
|
|
165
|
+
const prevPositionKey = useSharedValue(positionKey);
|
|
166
|
+
useEffect(() => {
|
|
167
|
+
if (prevPositionKey.value !== positionKey && !isDragging) {
|
|
168
|
+
translateX.value = 0;
|
|
169
|
+
translateY.value = 0;
|
|
170
|
+
prevPositionKey.value = positionKey;
|
|
171
|
+
}
|
|
172
|
+
}, [positionKey, isDragging, prevPositionKey, translateX, translateY]);
|
|
173
|
+
const gesture = enableDragAndDrop
|
|
174
|
+
? createGesture(event, leftPosition, topPosition, translateX, translateY, blockWidth, blockHeight, eventColor)
|
|
175
|
+
: undefined;
|
|
176
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
177
|
+
transform: [
|
|
178
|
+
{ translateX: translateX.value },
|
|
179
|
+
{ translateY: translateY.value },
|
|
180
|
+
{ scale: isDragging ? withSpring(1.05) : withSpring(1) },
|
|
181
|
+
],
|
|
182
|
+
}));
|
|
183
|
+
return (<Animated.View style={[
|
|
184
|
+
{
|
|
185
|
+
position: "absolute",
|
|
186
|
+
justifyContent: "center",
|
|
187
|
+
alignItems: "center",
|
|
188
|
+
backgroundColor: "#1a1a1a",
|
|
189
|
+
top: topPosition,
|
|
190
|
+
left: leftPosition,
|
|
191
|
+
height: blockHeight,
|
|
192
|
+
width: blockWidth,
|
|
193
|
+
zIndex: isDragging ? 1000 : 10,
|
|
194
|
+
},
|
|
195
|
+
animatedStyle,
|
|
196
|
+
]}>
|
|
197
|
+
<GestureDetector gesture={gesture || Gesture.Tap()}>
|
|
198
|
+
<Animated.View style={{ width: "100%", height: "100%" }}>
|
|
199
|
+
<Pressable onPress={() => onPress(event)} style={{
|
|
200
|
+
height: blockHeight - 2,
|
|
201
|
+
width: blockWidth - 2,
|
|
202
|
+
backgroundColor: eventColor,
|
|
203
|
+
borderRadius,
|
|
204
|
+
opacity: isDragging ? 0.7 : opacity,
|
|
205
|
+
justifyContent: "center",
|
|
206
|
+
alignItems: "center",
|
|
207
|
+
padding: 8,
|
|
208
|
+
overflow: "hidden",
|
|
209
|
+
borderWidth: isDragging ? 2 : 0,
|
|
210
|
+
borderColor: "#ffffff",
|
|
211
|
+
}}>
|
|
212
|
+
{renderEvent ? (renderEvent(event, {
|
|
213
|
+
width: blockWidth - 2,
|
|
214
|
+
height: blockHeight - 2,
|
|
215
|
+
})) : (<Text style={{
|
|
216
|
+
color: "#ffffff",
|
|
217
|
+
fontSize: 14,
|
|
218
|
+
fontWeight: "600",
|
|
219
|
+
textAlign: "center",
|
|
220
|
+
}} numberOfLines={2}>
|
|
221
|
+
{event.title}
|
|
222
|
+
</Text>)}
|
|
223
|
+
</Pressable>
|
|
224
|
+
</Animated.View>
|
|
225
|
+
</GestureDetector>
|
|
226
|
+
</Animated.View>);
|
|
227
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { CalendarDimensions, CalendarEvent, CalendarStyles, CalendarTimeConfig, Resource, UnavailableSlot } from "../../types/calendar";
|
|
2
|
-
type GridBodyProps
|
|
3
|
-
resources: Resource
|
|
4
|
-
events: CalendarEvent
|
|
5
|
-
unavailableSlots: UnavailableSlot
|
|
2
|
+
type GridBodyProps = {
|
|
3
|
+
resources: Resource[];
|
|
4
|
+
events: CalendarEvent[];
|
|
5
|
+
unavailableSlots: UnavailableSlot[];
|
|
6
6
|
onSlotPress?: (hour: number, resourceId: string, date: Date) => void;
|
|
7
7
|
date: Date;
|
|
8
8
|
timeConfig: CalendarTimeConfig;
|
|
9
9
|
dimensions: CalendarDimensions;
|
|
10
10
|
styles?: CalendarStyles;
|
|
11
11
|
};
|
|
12
|
-
export declare function GridBody
|
|
12
|
+
export declare function GridBody({ resources, events, unavailableSlots, onSlotPress, date, timeConfig, dimensions, styles, }: GridBodyProps): import("react").JSX.Element;
|
|
13
13
|
export {};
|
|
14
14
|
//# sourceMappingURL=GridBody.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GridBody.d.ts","sourceRoot":"","sources":["../../../components/calendar/GridBody.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"GridBody.d.ts","sourceRoot":"","sources":["../../../components/calendar/GridBody.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,aAAa,GAAG;IACnB,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACrE,IAAI,EAAE,IAAI,CAAC;IACX,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EACvB,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,IAAI,EACJ,UAAU,EACV,UAAU,EACV,MAAM,GACP,EAAE,aAAa,+BAmGf"}
|
|
@@ -61,7 +61,9 @@ export function GridBody({ resources, events, unavailableSlots, onSlotPress, dat
|
|
|
61
61
|
justifyContent: "center",
|
|
62
62
|
alignItems: "center",
|
|
63
63
|
}}>
|
|
64
|
-
<Text style={{ color: "#474747", fontSize: 20, fontWeight: "300" }}
|
|
64
|
+
<Text style={{ color: "#474747", fontSize: 20, fontWeight: "300" }}>
|
|
65
|
+
+
|
|
66
|
+
</Text>
|
|
65
67
|
</Pressable>);
|
|
66
68
|
})}
|
|
67
69
|
</View>))}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { ScrollView } from "react-native";
|
|
3
3
|
import { CalendarDimensions, RenderResourceHeaderFunction, Resource } from "../../types/calendar";
|
|
4
|
-
type ResourceHeadersProps
|
|
5
|
-
resources: Resource
|
|
4
|
+
type ResourceHeadersProps = {
|
|
5
|
+
resources: Resource[];
|
|
6
6
|
scrollRef: React.RefObject<ScrollView | null>;
|
|
7
7
|
dimensions: CalendarDimensions;
|
|
8
|
-
renderResourceHeader?: RenderResourceHeaderFunction
|
|
9
|
-
onResourcePress?: (resource: Resource
|
|
8
|
+
renderResourceHeader?: RenderResourceHeaderFunction;
|
|
9
|
+
onResourcePress?: (resource: Resource) => void;
|
|
10
10
|
};
|
|
11
|
-
export declare function ResourceHeaders
|
|
11
|
+
export declare function ResourceHeaders({ resources, scrollRef, dimensions, renderResourceHeader, onResourcePress, }: ResourceHeadersProps): React.JSX.Element;
|
|
12
12
|
export {};
|
|
13
13
|
//# sourceMappingURL=ResourceHeaders.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ResourceHeaders.d.ts","sourceRoot":"","sources":["../../../components/calendar/ResourceHeaders.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAa,UAAU,EAAc,MAAM,cAAc,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,QAAQ,EACT,MAAM,sBAAsB,CAAC;AAE9B,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"ResourceHeaders.d.ts","sourceRoot":"","sources":["../../../components/calendar/ResourceHeaders.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAa,UAAU,EAAc,MAAM,cAAc,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,4BAA4B,EAC5B,QAAQ,EACT,MAAM,sBAAsB,CAAC;AAE9B,KAAK,oBAAoB,GAAG;IAC1B,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC9C,UAAU,EAAE,kBAAkB,CAAC;IAC/B,oBAAoB,CAAC,EAAE,4BAA4B,CAAC;IACpD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,SAAS,EACT,UAAU,EACV,oBAAoB,EACpB,eAAe,GAChB,EAAE,oBAAoB,qBAiDtB"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { CalendarDimensions, CalendarTimeConfig, RenderUnavailableSlotFunction, Resource, UnavailableSlot, UnavailableSlotStyles } from "../../types/calendar";
|
|
2
|
-
type UnavailableLayerProps
|
|
3
|
-
unavailableSlots: UnavailableSlot
|
|
4
|
-
resources: Resource
|
|
2
|
+
type UnavailableLayerProps = {
|
|
3
|
+
unavailableSlots: UnavailableSlot[];
|
|
4
|
+
resources: Resource[];
|
|
5
5
|
timeConfig: CalendarTimeConfig;
|
|
6
6
|
dimensions: CalendarDimensions;
|
|
7
7
|
unavailableStyles?: UnavailableSlotStyles;
|
|
8
|
-
renderUnavailableSlot?: RenderUnavailableSlotFunction
|
|
8
|
+
renderUnavailableSlot?: RenderUnavailableSlotFunction;
|
|
9
9
|
};
|
|
10
|
-
export declare function UnavailableLayer<TResource =
|
|
10
|
+
export declare function UnavailableLayer<TResource = unknown, TUnavailable = unknown>({ unavailableSlots, resources, timeConfig, dimensions, unavailableStyles, renderUnavailableSlot, }: UnavailableLayerProps): import("react").JSX.Element;
|
|
11
11
|
export {};
|
|
12
12
|
//# sourceMappingURL=UnavailableLayer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UnavailableLayer.d.ts","sourceRoot":"","sources":["../../../components/calendar/UnavailableLayer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,6BAA6B,EAC7B,QAAQ,EACR,eAAe,EACf,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,qBAAqB,
|
|
1
|
+
{"version":3,"file":"UnavailableLayer.d.ts","sourceRoot":"","sources":["../../../components/calendar/UnavailableLayer.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,6BAA6B,EAC7B,QAAQ,EACR,eAAe,EACf,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,qBAAqB,GAAG;IAC3B,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;IAC1C,qBAAqB,CAAC,EAAE,6BAA6B,CAAC;CACvD,CAAC;AAuDF,wBAAgB,gBAAgB,CAAC,SAAS,GAAG,OAAO,EAAE,YAAY,GAAG,OAAO,EAAE,EAC5E,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,qBAAqB,GACtB,EAAE,qBAAqB,+BAkIvB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface ZoomControlsProps {
|
|
2
|
+
currentZoom: number;
|
|
3
|
+
minZoom: number;
|
|
4
|
+
maxZoom: number;
|
|
5
|
+
onZoomIn: () => void;
|
|
6
|
+
onZoomOut: () => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function ZoomControls({ currentZoom, minZoom, maxZoom, onZoomIn, onZoomOut, }: ZoomControlsProps): import("react").JSX.Element;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=ZoomControls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ZoomControls.d.ts","sourceRoot":"","sources":["../../../components/calendar/ZoomControls.tsx"],"names":[],"mappings":"AAEA,UAAU,iBAAiB;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,EAC3B,WAAW,EACX,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,+BA6BnB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
|
2
|
+
export function ZoomControls({ currentZoom, minZoom, maxZoom, onZoomIn, onZoomOut, }) {
|
|
3
|
+
const canZoomIn = currentZoom < maxZoom;
|
|
4
|
+
const canZoomOut = currentZoom > minZoom;
|
|
5
|
+
return (<View style={styles.container}>
|
|
6
|
+
<TouchableOpacity style={[styles.button, !canZoomOut && styles.buttonDisabled]} onPress={onZoomOut} disabled={!canZoomOut} accessibilityLabel="Zoom out" accessibilityRole="button">
|
|
7
|
+
<Text style={[styles.buttonText, !canZoomOut && styles.textDisabled]}>
|
|
8
|
+
−
|
|
9
|
+
</Text>
|
|
10
|
+
</TouchableOpacity>
|
|
11
|
+
<Text style={styles.zoomText}>{Math.round(currentZoom * 100)}%</Text>
|
|
12
|
+
<TouchableOpacity style={[styles.button, !canZoomIn && styles.buttonDisabled]} onPress={onZoomIn} disabled={!canZoomIn} accessibilityLabel="Zoom in" accessibilityRole="button">
|
|
13
|
+
<Text style={[styles.buttonText, !canZoomIn && styles.textDisabled]}>
|
|
14
|
+
+
|
|
15
|
+
</Text>
|
|
16
|
+
</TouchableOpacity>
|
|
17
|
+
</View>);
|
|
18
|
+
}
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
container: {
|
|
21
|
+
position: "absolute",
|
|
22
|
+
bottom: 20,
|
|
23
|
+
right: 20,
|
|
24
|
+
flexDirection: "row",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
backgroundColor: "#2a2a2a",
|
|
27
|
+
borderRadius: 8,
|
|
28
|
+
padding: 4,
|
|
29
|
+
elevation: 4,
|
|
30
|
+
shadowColor: "#000",
|
|
31
|
+
shadowOffset: { width: 0, height: 2 },
|
|
32
|
+
shadowOpacity: 0.3,
|
|
33
|
+
shadowRadius: 4,
|
|
34
|
+
zIndex: 1000,
|
|
35
|
+
},
|
|
36
|
+
button: {
|
|
37
|
+
width: 36,
|
|
38
|
+
height: 36,
|
|
39
|
+
justifyContent: "center",
|
|
40
|
+
alignItems: "center",
|
|
41
|
+
backgroundColor: "#3a3a3a",
|
|
42
|
+
borderRadius: 6,
|
|
43
|
+
},
|
|
44
|
+
buttonDisabled: {
|
|
45
|
+
opacity: 0.3,
|
|
46
|
+
},
|
|
47
|
+
buttonText: {
|
|
48
|
+
color: "#fff",
|
|
49
|
+
fontSize: 24,
|
|
50
|
+
fontWeight: "600",
|
|
51
|
+
},
|
|
52
|
+
textDisabled: {
|
|
53
|
+
color: "#666",
|
|
54
|
+
},
|
|
55
|
+
zoomText: {
|
|
56
|
+
color: "#fff",
|
|
57
|
+
fontSize: 14,
|
|
58
|
+
fontWeight: "500",
|
|
59
|
+
marginHorizontal: 12,
|
|
60
|
+
minWidth: 45,
|
|
61
|
+
textAlign: "center",
|
|
62
|
+
},
|
|
63
|
+
});
|
package/dist/types/calendar.d.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
export type Resource
|
|
2
|
+
export type Resource = {
|
|
3
3
|
id: string;
|
|
4
4
|
label: string;
|
|
5
|
-
data?: T;
|
|
6
5
|
};
|
|
7
|
-
export type CalendarEvent
|
|
6
|
+
export type CalendarEvent = {
|
|
8
7
|
id: string;
|
|
9
8
|
title: string;
|
|
10
9
|
resourceId: string;
|
|
11
10
|
startHour: number;
|
|
12
11
|
endHour: number;
|
|
13
12
|
color?: string;
|
|
14
|
-
|
|
13
|
+
};
|
|
14
|
+
export type DroppedEventData = {
|
|
15
|
+
eventId: string;
|
|
16
|
+
newResourceId: string;
|
|
17
|
+
newStartHour: number;
|
|
18
|
+
newEndHour: number;
|
|
15
19
|
};
|
|
16
20
|
export type UnavailableType = "reserved" | "offHours" | "disabled";
|
|
17
|
-
export type UnavailableSlot
|
|
21
|
+
export type UnavailableSlot = {
|
|
18
22
|
id: string;
|
|
19
23
|
resourceId: string;
|
|
20
24
|
startHour: number;
|
|
21
25
|
endHour: number;
|
|
22
26
|
type: UnavailableType;
|
|
23
|
-
data?: T;
|
|
24
27
|
};
|
|
25
28
|
export type CalendarDimensions = {
|
|
26
29
|
/** Width of each resource column in pixels */
|
|
@@ -75,43 +78,50 @@ export type UnavailableSlotStyles = {
|
|
|
75
78
|
opacity?: number;
|
|
76
79
|
};
|
|
77
80
|
};
|
|
78
|
-
export type RenderEventFunction
|
|
81
|
+
export type RenderEventFunction = (event: CalendarEvent, dimensions: {
|
|
79
82
|
width: number;
|
|
80
83
|
height: number;
|
|
81
84
|
}) => ReactNode;
|
|
82
|
-
export type RenderResourceHeaderFunction
|
|
85
|
+
export type RenderResourceHeaderFunction = (resource: Resource) => ReactNode;
|
|
83
86
|
export type RenderTimeSlotFunction = (hour: number) => ReactNode;
|
|
84
|
-
export type RenderUnavailableSlotFunction
|
|
87
|
+
export type RenderUnavailableSlotFunction = (slot: UnavailableSlot, dimensions: {
|
|
85
88
|
width: number;
|
|
86
89
|
height: number;
|
|
87
90
|
}) => ReactNode;
|
|
88
|
-
export type CalendarProps
|
|
91
|
+
export type CalendarProps = {
|
|
89
92
|
date: Date;
|
|
90
|
-
resources: Resource
|
|
91
|
-
events: CalendarEvent
|
|
92
|
-
unavailableSlots?: UnavailableSlot
|
|
93
|
+
resources: Resource[];
|
|
94
|
+
events: CalendarEvent[];
|
|
95
|
+
unavailableSlots?: UnavailableSlot[];
|
|
93
96
|
timeConfig?: CalendarTimeConfig;
|
|
94
97
|
dimensions?: Partial<CalendarDimensions>;
|
|
95
98
|
styles?: CalendarStyles;
|
|
96
99
|
eventStyles?: CalendarEventStyles;
|
|
97
100
|
unavailableStyles?: UnavailableSlotStyles;
|
|
101
|
+
zoomEnabled?: boolean;
|
|
102
|
+
maxZoom?: number;
|
|
103
|
+
initialZoom?: number;
|
|
104
|
+
snapBack?: boolean;
|
|
105
|
+
snapBackDelay?: number;
|
|
98
106
|
onSlotPress?: (hour: number, resourceId: string, date: Date) => void;
|
|
99
|
-
onEventPress?: (event: CalendarEvent
|
|
100
|
-
onResourcePress?: (resource: Resource
|
|
107
|
+
onEventPress?: (event: CalendarEvent) => void;
|
|
108
|
+
onResourcePress?: (resource: Resource) => void;
|
|
101
109
|
onDateChange?: (date: Date) => void;
|
|
110
|
+
onEventDrop?: (droppedData: DroppedEventData, originalEvent: CalendarEvent) => void;
|
|
102
111
|
minDate?: Date;
|
|
103
112
|
maxDate?: Date;
|
|
104
113
|
allowPastDates?: boolean;
|
|
105
|
-
renderEvent?: RenderEventFunction
|
|
106
|
-
renderResourceHeader?: RenderResourceHeaderFunction
|
|
114
|
+
renderEvent?: RenderEventFunction;
|
|
115
|
+
renderResourceHeader?: RenderResourceHeaderFunction;
|
|
107
116
|
renderTimeSlot?: RenderTimeSlotFunction;
|
|
108
|
-
renderUnavailableSlot?: RenderUnavailableSlotFunction
|
|
117
|
+
renderUnavailableSlot?: RenderUnavailableSlotFunction;
|
|
109
118
|
showHeader?: boolean;
|
|
110
119
|
showTimeColumn?: boolean;
|
|
111
120
|
showResourceHeaders?: boolean;
|
|
112
121
|
enableHorizontalScroll?: boolean;
|
|
113
122
|
enableVerticalScroll?: boolean;
|
|
114
123
|
showDateNavigation?: boolean;
|
|
124
|
+
enableDragAndDrop?: boolean;
|
|
115
125
|
dateFormat?: string;
|
|
116
126
|
accessibilityLabel?: string;
|
|
117
127
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../types/calendar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGlC,MAAM,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"calendar.d.ts","sourceRoot":"","sources":["../../types/calendar.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-calendar-resource",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "A fully customizable, type-safe resource-based calendar component for React Native",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc -p tsconfig.package.json",
|
|
9
|
+
"watch": "tsc -p tsconfig.package.json --watch",
|
|
9
10
|
"prepublishOnly": "npm run build",
|
|
10
11
|
"test": "echo \"No tests yet\" && exit 0"
|
|
11
12
|
},
|
|
@@ -24,14 +25,24 @@
|
|
|
24
25
|
"type": "git",
|
|
25
26
|
"url": "https://github.com/abdosobhy1/react-native-calendar-resource"
|
|
26
27
|
},
|
|
28
|
+
"homepage": "https://github.com/abdosobhy1/react-native-calendar-resource#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/abdosobhy1/react-native-calendar-resource/issues"
|
|
31
|
+
},
|
|
27
32
|
"peerDependencies": {
|
|
28
33
|
"react": ">=18.0.0",
|
|
29
34
|
"react-native": ">=0.70.0",
|
|
30
|
-
"date-fns": ">=3.0.0"
|
|
35
|
+
"date-fns": ">=3.0.0",
|
|
36
|
+
"react-native-gesture-handler": ">=2.9.0",
|
|
37
|
+
"react-native-reanimated": ">=2.14.0"
|
|
31
38
|
},
|
|
32
39
|
"devDependencies": {
|
|
33
40
|
"@types/react": "^19.1.0",
|
|
34
41
|
"@types/react-native": "^0.73.0",
|
|
42
|
+
"react": "^18.2.0",
|
|
43
|
+
"react-native": "^0.73.0",
|
|
44
|
+
"react-native-gesture-handler": "^2.14.0",
|
|
45
|
+
"react-native-reanimated": "^3.6.0",
|
|
35
46
|
"typescript": "^5.9.2"
|
|
36
47
|
},
|
|
37
48
|
"files": [
|