react-native-resource-calendar 1.0.19 β 1.0.20
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 +15 -4
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +57 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +57 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,8 +42,7 @@ react-native-gesture-handler \
|
|
|
42
42
|
react-native-reanimated \
|
|
43
43
|
react-native-svg \
|
|
44
44
|
@shopify/flash-list \
|
|
45
|
-
@shopify/react-native-skia
|
|
46
|
-
expo-haptics
|
|
45
|
+
@shopify/react-native-skia
|
|
47
46
|
```
|
|
48
47
|
|
|
49
48
|
If youβre using bare React Native (not Expo), install them manually:
|
|
@@ -54,8 +53,18 @@ react-native-gesture-handler \
|
|
|
54
53
|
react-native-reanimated \
|
|
55
54
|
react-native-svg \
|
|
56
55
|
@shopify/flash-list \
|
|
57
|
-
@shopify/react-native-skia
|
|
58
|
-
|
|
56
|
+
@shopify/react-native-skia
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
π¦ Optional: Haptics Support (Expo Only)
|
|
60
|
+
|
|
61
|
+
Haptic feedback is optional.
|
|
62
|
+
If you want to enable vibration feedback when interacting with components, install the Expo Haptics package and set enableHapticFeedback to true in your component config.
|
|
63
|
+
|
|
64
|
+
π¦ Install (Expo)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx expo install expo-haptics
|
|
59
68
|
```
|
|
60
69
|
|
|
61
70
|
---
|
|
@@ -264,12 +273,14 @@ The `Calendar` component accepts a flexible set of props for customizing layout,
|
|
|
264
273
|
| **`snapIntervalInMinutes`** | `number` | `5` | Drag/resize snapping granularity (in minutes). |
|
|
265
274
|
| **`overLappingLayoutMode`** | `LayoutMode` (`'stacked' \| 'columns'`) | `'stacked'` | Strategy to lay out overlapping events inside a column. |
|
|
266
275
|
| **`theme`** | `CalendarTheme` | β | Typography & palette overrides. |
|
|
276
|
+
| **`enableHapticFeedback`** | `boolean` | `false` | Enable haptic feedback. |
|
|
267
277
|
| **`eventSlots`** | `EventSlots` | β | Slot renderers to customize event content (e.g. `{ Body, TopRight }`). |
|
|
268
278
|
| **`eventStyleOverrides`** | `StyleOverrides \| ((event: Event) => StyleOverrides \| undefined)` | β | Per-event style override (object or function). |
|
|
269
279
|
| **`isEventSelected`** | `(event: Event) => boolean` | `() => false` | Marks which events are currently selected. |
|
|
270
280
|
| **`isEventDisabled`** | `(event: Event) => boolean` | `() => false` | Marks events as disabled (non-interactive). |
|
|
271
281
|
| **`onResourcePress`** | `(resource: Resource) => void` | β | Invoked when a resource header is pressed. |
|
|
272
282
|
| **`onBlockLongPress`** | `(resource: Resource, date: Date) => void` | β | Long-press on an empty block (grid). |
|
|
283
|
+
| **`onBlockTap`** | `(resource: Resource, date: Date) => void` | β | Tap on an empty block (grid). |
|
|
273
284
|
| **`onDisabledBlockPress`** | `(block: DisabledBlock) => void` | β | Tap on a disabled block (e.g., lunch). |
|
|
274
285
|
| **`onEventPress`** | `(event: Event) => void` | β | Tap on an event. |
|
|
275
286
|
| **`onEventLongPress`** | `(event: Event) => void` | β | Long-press on an event. The calendar also preps internal drag state here. |
|
package/dist/index.d.mts
CHANGED
|
@@ -86,9 +86,11 @@ interface CalendarProps {
|
|
|
86
86
|
hourHeight?: number;
|
|
87
87
|
onResourcePress?: (resource: Resource) => void;
|
|
88
88
|
onBlockLongPress?: (resource: Resource, date: Date) => void;
|
|
89
|
+
onBlockTap?: (resource: Resource, date: Date) => void;
|
|
89
90
|
onDisabledBlockPress?: (block: DisabledBlock) => void;
|
|
90
91
|
onEventPress?: (event: Event) => void;
|
|
91
92
|
onEventLongPress?: (event: Event) => void;
|
|
93
|
+
enableHapticFeedback?: boolean;
|
|
92
94
|
eventSlots?: EventSlots;
|
|
93
95
|
eventStyleOverrides?: StyleOverrides | ((event: Event) => StyleOverrides | undefined);
|
|
94
96
|
isEventSelected?: FlagFn;
|
package/dist/index.d.ts
CHANGED
|
@@ -86,9 +86,11 @@ interface CalendarProps {
|
|
|
86
86
|
hourHeight?: number;
|
|
87
87
|
onResourcePress?: (resource: Resource) => void;
|
|
88
88
|
onBlockLongPress?: (resource: Resource, date: Date) => void;
|
|
89
|
+
onBlockTap?: (resource: Resource, date: Date) => void;
|
|
89
90
|
onDisabledBlockPress?: (block: DisabledBlock) => void;
|
|
90
91
|
onEventPress?: (event: Event) => void;
|
|
91
92
|
onEventLongPress?: (event: Event) => void;
|
|
93
|
+
enableHapticFeedback?: boolean;
|
|
92
94
|
eventSlots?: EventSlots;
|
|
93
95
|
eventStyleOverrides?: StyleOverrides | ((event: Event) => StyleOverrides | undefined);
|
|
94
96
|
isEventSelected?: FlagFn;
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,6 @@ var reactNativeGestureHandler = require('react-native-gesture-handler');
|
|
|
5
5
|
var Animated2 = require('react-native-reanimated');
|
|
6
6
|
var reactNative = require('react-native');
|
|
7
7
|
var flashList = require('@shopify/flash-list');
|
|
8
|
-
var Haptics = require('expo-haptics');
|
|
9
8
|
var dateFnsTz = require('date-fns-tz');
|
|
10
9
|
var dateFns = require('date-fns');
|
|
11
10
|
var lodash = require('lodash');
|
|
@@ -39,7 +38,6 @@ function _interopNamespace(e) {
|
|
|
39
38
|
|
|
40
39
|
var React19__namespace = /*#__PURE__*/_interopNamespace(React19);
|
|
41
40
|
var Animated2__default = /*#__PURE__*/_interopDefault(Animated2);
|
|
42
|
-
var Haptics__namespace = /*#__PURE__*/_interopNamespace(Haptics);
|
|
43
41
|
var Svg__default = /*#__PURE__*/_interopDefault(Svg);
|
|
44
42
|
|
|
45
43
|
// src/components/Calendar.tsx
|
|
@@ -747,6 +745,7 @@ function StaffAvatar({
|
|
|
747
745
|
}
|
|
748
746
|
var EventGridBlocksSkia = ({
|
|
749
747
|
handleBlockPress,
|
|
748
|
+
handleBlockLongPress,
|
|
750
749
|
hourHeight,
|
|
751
750
|
APPOINTMENT_BLOCK_WIDTH
|
|
752
751
|
}) => {
|
|
@@ -788,6 +787,16 @@ var EventGridBlocksSkia = ({
|
|
|
788
787
|
},
|
|
789
788
|
[handleBlockPress, timeLabels]
|
|
790
789
|
);
|
|
790
|
+
const onSlotLongPress = React19__namespace.useCallback(
|
|
791
|
+
(row) => {
|
|
792
|
+
setPressedRow(null);
|
|
793
|
+
const slot = timeLabels[row];
|
|
794
|
+
if (slot) {
|
|
795
|
+
handleBlockLongPress(slot);
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
[timeLabels, handleBlockLongPress]
|
|
799
|
+
);
|
|
791
800
|
const onPressBegin = React19__namespace.useCallback((row) => {
|
|
792
801
|
setPressedRow(row);
|
|
793
802
|
}, []);
|
|
@@ -797,14 +806,31 @@ var EventGridBlocksSkia = ({
|
|
|
797
806
|
const longPressGesture = reactNativeGestureHandler.Gesture.LongPress().onBegin((e) => {
|
|
798
807
|
"worklet";
|
|
799
808
|
Animated2.runOnJS(onPressBegin)(Math.floor(e.y / rowHeight));
|
|
809
|
+
}).onTouchesUp(() => {
|
|
810
|
+
"worklet";
|
|
811
|
+
Animated2.runOnJS(onTouchesUp)();
|
|
812
|
+
}).onEnd((e) => {
|
|
813
|
+
"worklet";
|
|
814
|
+
Animated2.runOnJS(onSlotLongPress)(Math.floor(e.y / rowHeight));
|
|
815
|
+
}).onFinalize(() => {
|
|
816
|
+
"worklet";
|
|
817
|
+
Animated2.runOnJS(onTouchesUp)();
|
|
818
|
+
});
|
|
819
|
+
const tapGesture = reactNativeGestureHandler.Gesture.Tap().onBegin((e) => {
|
|
820
|
+
"worklet";
|
|
821
|
+
Animated2.runOnJS(onPressBegin)(Math.floor(e.y / rowHeight));
|
|
800
822
|
}).onEnd((e) => {
|
|
801
823
|
"worklet";
|
|
802
824
|
Animated2.runOnJS(onSlotPress)(Math.floor(e.y / rowHeight));
|
|
825
|
+
}).onTouchesUp(() => {
|
|
826
|
+
"worklet";
|
|
827
|
+
Animated2.runOnJS(onTouchesUp)();
|
|
803
828
|
}).onFinalize(() => {
|
|
804
829
|
"worklet";
|
|
805
830
|
Animated2.runOnJS(onTouchesUp)();
|
|
806
831
|
});
|
|
807
|
-
|
|
832
|
+
const composedGesture = reactNativeGestureHandler.Gesture.Race(longPressGesture, tapGesture);
|
|
833
|
+
return /* @__PURE__ */ React19__namespace.createElement(reactNativeGestureHandler.GestureDetector, { gesture: composedGesture }, /* @__PURE__ */ React19__namespace.createElement(reactNative.View, null, /* @__PURE__ */ React19__namespace.createElement(reactNativeSkia.Canvas, { style: { width: APPOINTMENT_BLOCK_WIDTH, height: segmentHeight } }, firstRects.map(({ x, y, width: w, height: h, row }, idx) => /* @__PURE__ */ React19__namespace.createElement(React19__namespace.Fragment, { key: idx }, /* @__PURE__ */ React19__namespace.createElement(
|
|
808
834
|
reactNativeSkia.Rect,
|
|
809
835
|
{
|
|
810
836
|
x,
|
|
@@ -1346,9 +1372,11 @@ var CalendarInner = (props) => {
|
|
|
1346
1372
|
resources,
|
|
1347
1373
|
onResourcePress,
|
|
1348
1374
|
onBlockLongPress,
|
|
1375
|
+
onBlockTap,
|
|
1349
1376
|
onEventPress,
|
|
1350
1377
|
onEventLongPress,
|
|
1351
1378
|
onDisabledBlockPress,
|
|
1379
|
+
enableHapticFeedback = false,
|
|
1352
1380
|
eventSlots,
|
|
1353
1381
|
eventStyleOverrides,
|
|
1354
1382
|
overLappingLayoutMode = "stacked",
|
|
@@ -1465,9 +1493,19 @@ var CalendarInner = (props) => {
|
|
|
1465
1493
|
const startedX = Animated2.useSharedValue(0);
|
|
1466
1494
|
const startedY = Animated2.useSharedValue(0);
|
|
1467
1495
|
const touchY = Animated2.useSharedValue(0);
|
|
1468
|
-
const triggerHaptic = React19.useCallback(
|
|
1469
|
-
|
|
1470
|
-
|
|
1496
|
+
const triggerHaptic = React19.useCallback(
|
|
1497
|
+
async (style = "Light") => {
|
|
1498
|
+
try {
|
|
1499
|
+
const Haptics = await import('expo-haptics');
|
|
1500
|
+
const feedbackStyle = Haptics.ImpactFeedbackStyle[style];
|
|
1501
|
+
if (enableHapticFeedback)
|
|
1502
|
+
await Haptics.impactAsync(feedbackStyle);
|
|
1503
|
+
} catch (e) {
|
|
1504
|
+
console.log("Haptics not available, skipping...");
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
[enableHapticFeedback]
|
|
1508
|
+
);
|
|
1471
1509
|
const resourceIds = React19.useMemo(() => {
|
|
1472
1510
|
const ids = resources?.map((item) => item?.id) || [];
|
|
1473
1511
|
if (JSON.stringify(prevResourceIdsRef.current) !== JSON.stringify(ids)) {
|
|
@@ -1628,7 +1666,7 @@ var CalendarInner = (props) => {
|
|
|
1628
1666
|
const increment = APPOINTMENT_BLOCK_WIDTH * Math.sign(autoScrollXSpeed.value);
|
|
1629
1667
|
const newScrollX = scrollX.value + increment;
|
|
1630
1668
|
Animated2.runOnJS(scrollListTo)(newScrollX);
|
|
1631
|
-
Animated2.runOnJS(
|
|
1669
|
+
Animated2.runOnJS(triggerHaptic)("Medium");
|
|
1632
1670
|
}
|
|
1633
1671
|
});
|
|
1634
1672
|
Animated2.useFrameCallback(() => {
|
|
@@ -1662,7 +1700,7 @@ var CalendarInner = (props) => {
|
|
|
1662
1700
|
const scrollDiff = Math.abs(newScrollY - lastHapticScrollY.value);
|
|
1663
1701
|
if (scrollDiff >= snapInterval) {
|
|
1664
1702
|
lastHapticScrollY.value = newScrollY;
|
|
1665
|
-
Animated2.runOnJS(
|
|
1703
|
+
Animated2.runOnJS(triggerHaptic)("Medium");
|
|
1666
1704
|
}
|
|
1667
1705
|
});
|
|
1668
1706
|
React19.useEffect(() => {
|
|
@@ -1696,7 +1734,7 @@ var CalendarInner = (props) => {
|
|
|
1696
1734
|
eventHeight.value = initialHeight;
|
|
1697
1735
|
setSelectedEvent(event);
|
|
1698
1736
|
requestAnimationFrame(() => setDragReady(true));
|
|
1699
|
-
|
|
1737
|
+
Animated2.runOnJS(triggerHaptic)("Medium");
|
|
1700
1738
|
};
|
|
1701
1739
|
}, []);
|
|
1702
1740
|
const internalStableOnLongPress = React19.useCallback((e) => {
|
|
@@ -1719,12 +1757,18 @@ var CalendarInner = (props) => {
|
|
|
1719
1757
|
}
|
|
1720
1758
|
}
|
|
1721
1759
|
});
|
|
1722
|
-
const
|
|
1723
|
-
|
|
1760
|
+
const handleBlockLongPress = React19.useCallback((resourceId, time) => {
|
|
1761
|
+
Animated2.runOnJS(triggerHaptic)("Medium");
|
|
1724
1762
|
const resource = resources.find((r) => r.id === resourceId);
|
|
1725
1763
|
if (onBlockLongPress)
|
|
1726
1764
|
onBlockLongPress(resource, new Date(time));
|
|
1727
1765
|
}, [resources, onBlockLongPress]);
|
|
1766
|
+
const handleBlockPress = React19.useCallback((resourceId, time) => {
|
|
1767
|
+
Animated2.runOnJS(triggerHaptic)("Medium");
|
|
1768
|
+
const resource = resources.find((r) => r.id === resourceId);
|
|
1769
|
+
if (onBlockTap)
|
|
1770
|
+
onBlockTap(resource, new Date(time));
|
|
1771
|
+
}, [resources, onBlockTap]);
|
|
1728
1772
|
React19.useEffect(() => {
|
|
1729
1773
|
const handleOrientationChange = () => {
|
|
1730
1774
|
if (selectedEvent) {
|
|
@@ -1748,7 +1792,8 @@ var CalendarInner = (props) => {
|
|
|
1748
1792
|
{
|
|
1749
1793
|
hourHeight,
|
|
1750
1794
|
APPOINTMENT_BLOCK_WIDTH,
|
|
1751
|
-
handleBlockPress: (time) => handleBlockPress(rid, combineDateAndTime(dayDate ?? dateRef.current, time))
|
|
1795
|
+
handleBlockPress: (time) => handleBlockPress(rid, combineDateAndTime(dayDate ?? dateRef.current, time)),
|
|
1796
|
+
handleBlockLongPress: (time) => handleBlockLongPress(rid, combineDateAndTime(dayDate ?? dateRef.current, time))
|
|
1752
1797
|
}
|
|
1753
1798
|
), /* @__PURE__ */ React19__namespace.default.createElement(
|
|
1754
1799
|
DisabledIntervals_default,
|