react-native-calendar-resource 1.0.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 (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +403 -0
  3. package/dist/components/calendar/Calendar.d.ts +3 -0
  4. package/dist/components/calendar/Calendar.d.ts.map +1 -0
  5. package/dist/components/calendar/Calendar.js +69 -0
  6. package/dist/components/calendar/CalendarHeader.d.ts +14 -0
  7. package/dist/components/calendar/CalendarHeader.d.ts.map +1 -0
  8. package/dist/components/calendar/CalendarHeader.js +113 -0
  9. package/dist/components/calendar/EventsLayer.d.ts +13 -0
  10. package/dist/components/calendar/EventsLayer.d.ts.map +1 -0
  11. package/dist/components/calendar/EventsLayer.js +79 -0
  12. package/dist/components/calendar/GridBody.d.ts +14 -0
  13. package/dist/components/calendar/GridBody.d.ts.map +1 -0
  14. package/dist/components/calendar/GridBody.js +70 -0
  15. package/dist/components/calendar/ResourceHeaders.d.ts +13 -0
  16. package/dist/components/calendar/ResourceHeaders.d.ts.map +1 -0
  17. package/dist/components/calendar/ResourceHeaders.js +32 -0
  18. package/dist/components/calendar/TimeColumn.d.ts +14 -0
  19. package/dist/components/calendar/TimeColumn.d.ts.map +1 -0
  20. package/dist/components/calendar/TimeColumn.js +56 -0
  21. package/dist/components/calendar/UnavailableLayer.d.ts +12 -0
  22. package/dist/components/calendar/UnavailableLayer.d.ts.map +1 -0
  23. package/dist/components/calendar/UnavailableLayer.js +122 -0
  24. package/dist/components/calendar/dateUtils.d.ts +37 -0
  25. package/dist/components/calendar/dateUtils.d.ts.map +1 -0
  26. package/dist/components/calendar/dateUtils.js +128 -0
  27. package/dist/components/calendar/index.d.ts +9 -0
  28. package/dist/components/calendar/index.d.ts.map +1 -0
  29. package/dist/components/calendar/index.js +7 -0
  30. package/dist/index.d.ts +9 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +9 -0
  33. package/dist/types/calendar.d.ts +118 -0
  34. package/dist/types/calendar.d.ts.map +1 -0
  35. package/dist/types/calendar.js +1 -0
  36. package/package.json +38 -0
@@ -0,0 +1,79 @@
1
+ import { useMemo } from "react";
2
+ import { Pressable, Text, View } from "react-native";
3
+ export function EventsLayer({ events, resources, onEventPress, timeConfig, dimensions, eventStyles, renderEvent, }) {
4
+ const positionedEvents = useMemo(() => {
5
+ return events
6
+ .map((event) => {
7
+ const resourceIndex = resources.findIndex((resource) => resource.id === event.resourceId);
8
+ if (resourceIndex === -1) {
9
+ return null;
10
+ }
11
+ const topPosition = (event.startHour - timeConfig.startHour - 1) * dimensions.hourHeight;
12
+ const blockHeight = (event.endHour - event.startHour) * dimensions.hourHeight;
13
+ const leftPosition = resourceIndex * dimensions.resourceWidth;
14
+ const blockWidth = dimensions.resourceWidth;
15
+ return {
16
+ event,
17
+ topPosition,
18
+ leftPosition,
19
+ blockWidth,
20
+ blockHeight,
21
+ };
22
+ })
23
+ .filter(Boolean);
24
+ }, [events, resources, timeConfig.startHour, dimensions]);
25
+ const gridTotalWidth = resources.length * dimensions.resourceWidth;
26
+ const gridBodyHeight = (timeConfig.endHour - timeConfig.startHour - 1) * dimensions.hourHeight;
27
+ const handleEventPress = (event) => {
28
+ onEventPress?.(event);
29
+ };
30
+ const defaultColor = eventStyles?.defaultColor || "#3b82f6";
31
+ const borderRadius = eventStyles?.borderRadius || 8;
32
+ const opacity = eventStyles?.opacity || 1;
33
+ return (<View style={{
34
+ position: "absolute",
35
+ top: 0,
36
+ left: 0,
37
+ zIndex: 10,
38
+ width: gridTotalWidth,
39
+ height: gridBodyHeight,
40
+ }} pointerEvents="box-none">
41
+ {positionedEvents.map((item) => {
42
+ const eventColor = item.event.color || defaultColor;
43
+ return (<View key={item.event.id} style={{
44
+ position: "absolute",
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>);
77
+ })}
78
+ </View>);
79
+ }
@@ -0,0 +1,14 @@
1
+ import { CalendarDimensions, CalendarEvent, CalendarStyles, CalendarTimeConfig, Resource, UnavailableSlot } from "../../types/calendar";
2
+ type GridBodyProps<TEvent = any, TResource = any, TUnavailable = any> = {
3
+ resources: Resource<TResource>[];
4
+ events: CalendarEvent<TEvent>[];
5
+ unavailableSlots: UnavailableSlot<TUnavailable>[];
6
+ onSlotPress?: (hour: number, resourceId: string, date: Date) => void;
7
+ date: Date;
8
+ timeConfig: CalendarTimeConfig;
9
+ dimensions: CalendarDimensions;
10
+ styles?: CalendarStyles;
11
+ };
12
+ export declare function GridBody<TEvent = any, TResource = any, TUnavailable = any>({ resources, events, unavailableSlots, onSlotPress, date, timeConfig, dimensions, styles, }: GridBodyProps<TEvent, TResource, TUnavailable>): import("react").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=GridBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GridBody.d.ts","sourceRoot":"","sources":["../../../components/calendar/GridBody.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,aAAa,CAAC,MAAM,GAAG,GAAG,EAAE,SAAS,GAAG,GAAG,EAAE,YAAY,GAAG,GAAG,IAAI;IACtE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;IACjC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;IAChC,gBAAgB,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;IAClD,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,MAAM,GAAG,GAAG,EAAE,SAAS,GAAG,GAAG,EAAE,YAAY,GAAG,GAAG,EAAE,EAC1E,SAAS,EACT,MAAM,EACN,gBAAgB,EAChB,WAAW,EACX,IAAI,EACJ,UAAU,EACV,UAAU,EACV,MAAM,GACP,EAAE,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,YAAY,CAAC,+BAgGhD"}
@@ -0,0 +1,70 @@
1
+ import { MaterialIcons } from "@expo/vector-icons";
2
+ import { useMemo } from "react";
3
+ import { Pressable, View } from "react-native";
4
+ export function GridBody({ resources, events, unavailableSlots, onSlotPress, date, timeConfig, dimensions, styles, }) {
5
+ const hoursArray = useMemo(() => {
6
+ const result = [];
7
+ for (let hour = timeConfig.startHour + 1; hour <= timeConfig.endHour; hour++) {
8
+ result.push(hour);
9
+ }
10
+ return result;
11
+ }, [timeConfig.startHour, timeConfig.endHour]);
12
+ const occupiedSlots = useMemo(() => {
13
+ const occupied = new Set();
14
+ events.forEach((event) => {
15
+ for (let hour = event.startHour; hour < event.endHour; hour++) {
16
+ occupied.add(`${event.resourceId}-${hour}`);
17
+ }
18
+ });
19
+ unavailableSlots.forEach((slot) => {
20
+ for (let hour = slot.startHour; hour < slot.endHour; hour++) {
21
+ occupied.add(`${slot.resourceId}-${hour}`);
22
+ }
23
+ });
24
+ return occupied;
25
+ }, [events, unavailableSlots]);
26
+ const gridTotalWidth = resources.length * dimensions.resourceWidth;
27
+ const gridBodyHeight = (timeConfig.endHour - timeConfig.startHour - 1) * dimensions.hourHeight;
28
+ const handleSlotPress = (hour, resourceId) => {
29
+ onSlotPress?.(hour, resourceId, date);
30
+ };
31
+ const slotBgColor = styles?.slotBackgroundColor || "#1f1f1f";
32
+ const gridLineColor = styles?.gridColor || "#333";
33
+ return (<View style={{
34
+ flexDirection: "row",
35
+ width: gridTotalWidth,
36
+ height: gridBodyHeight,
37
+ }}>
38
+ {resources.map((resource, resourceIndex) => (<View key={resource.id}>
39
+ {hoursArray.map((hour) => {
40
+ const slotKey = `${resource.id}-${hour}`;
41
+ const isSlotOccupied = occupiedSlots.has(slotKey);
42
+ const isLastColumn = resourceIndex === resources.length - 1;
43
+ const isFirstColumn = resourceIndex === 0;
44
+ if (isSlotOccupied) {
45
+ return (<View key={slotKey} style={{
46
+ width: dimensions.resourceWidth,
47
+ height: dimensions.hourHeight,
48
+ borderLeftWidth: 1,
49
+ borderBottomWidth: 1,
50
+ borderRightWidth: isLastColumn ? 1 : 0,
51
+ borderColor: gridLineColor,
52
+ }}/>);
53
+ }
54
+ return (<Pressable key={slotKey} onPress={() => handleSlotPress(hour, resource.id)} style={{
55
+ width: dimensions.resourceWidth,
56
+ height: dimensions.hourHeight,
57
+ backgroundColor: slotBgColor,
58
+ borderLeftWidth: isFirstColumn ? 0 : 1,
59
+ borderBottomWidth: 1,
60
+ borderRightWidth: isLastColumn ? 1 : 0,
61
+ borderColor: gridLineColor,
62
+ justifyContent: "center",
63
+ alignItems: "center",
64
+ }}>
65
+ <MaterialIcons name="add" size={14} color="#474747"/>
66
+ </Pressable>);
67
+ })}
68
+ </View>))}
69
+ </View>);
70
+ }
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { ScrollView } from "react-native";
3
+ import { CalendarDimensions, RenderResourceHeaderFunction, Resource } from "../../types/calendar";
4
+ type ResourceHeadersProps<T = any> = {
5
+ resources: Resource<T>[];
6
+ scrollRef: React.RefObject<ScrollView | null>;
7
+ dimensions: CalendarDimensions;
8
+ renderResourceHeader?: RenderResourceHeaderFunction<T>;
9
+ onResourcePress?: (resource: Resource<T>) => void;
10
+ };
11
+ export declare function ResourceHeaders<T = any>({ resources, scrollRef, dimensions, renderResourceHeader, onResourcePress, }: ResourceHeadersProps<T>): React.JSX.Element;
12
+ export {};
13
+ //# sourceMappingURL=ResourceHeaders.d.ts.map
@@ -0,0 +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,CAAC,CAAC,GAAG,GAAG,IAAI;IACnC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACzB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC9C,UAAU,EAAE,kBAAkB,CAAC;IAC/B,oBAAoB,CAAC,EAAE,4BAA4B,CAAC,CAAC,CAAC,CAAC;IACvD,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;CACnD,CAAC;AAEF,wBAAgB,eAAe,CAAC,CAAC,GAAG,GAAG,EAAE,EACvC,SAAS,EACT,SAAS,EACT,UAAU,EACV,oBAAoB,EACpB,eAAe,GAChB,EAAE,oBAAoB,CAAC,CAAC,CAAC,qBAiDzB"}
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import { Pressable, ScrollView, Text, View } from "react-native";
3
+ export function ResourceHeaders({ resources, scrollRef, dimensions, renderResourceHeader, onResourcePress, }) {
4
+ return (<View style={{ flexDirection: "row", zIndex: 10 }}>
5
+ <View style={{
6
+ backgroundColor: "#262626",
7
+ borderBottomWidth: 1,
8
+ borderBottomColor: "#333",
9
+ zIndex: 20,
10
+ width: dimensions.resourceWidth,
11
+ }}/>
12
+ <ScrollView ref={scrollRef} horizontal showsHorizontalScrollIndicator={false} scrollEnabled={false} bounces={false} style={{ flex: 1 }}>
13
+ <View style={{ flexDirection: "row" }}>
14
+ {resources.map((resource) => (<Pressable key={resource.id} onPress={() => onResourcePress?.(resource)} style={{
15
+ justifyContent: "center",
16
+ backgroundColor: "#262626",
17
+ borderLeftWidth: 1,
18
+ borderBottomWidth: 1,
19
+ borderColor: "#333",
20
+ paddingVertical: 16,
21
+ paddingHorizontal: 10,
22
+ width: dimensions.resourceWidth,
23
+ height: dimensions.resourceWidth,
24
+ }}>
25
+ {renderResourceHeader ? (renderResourceHeader(resource)) : (<Text style={{ color: "#fefefe", fontSize: 14, textAlign: "left" }}>
26
+ {resource.label}
27
+ </Text>)}
28
+ </Pressable>))}
29
+ </View>
30
+ </ScrollView>
31
+ </View>);
32
+ }
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import { ScrollView } from "react-native";
3
+ import { CalendarDimensions, CalendarStyles, CalendarTimeConfig, RenderTimeSlotFunction } from "../../types/calendar";
4
+ type TimeColumnProps = {
5
+ scrollRef: React.RefObject<ScrollView | null>;
6
+ gridTotalHeight: number;
7
+ timeConfig: CalendarTimeConfig;
8
+ dimensions: CalendarDimensions;
9
+ renderTimeSlot?: RenderTimeSlotFunction;
10
+ styles?: CalendarStyles;
11
+ };
12
+ export declare function TimeColumn({ scrollRef, gridTotalHeight, timeConfig, dimensions, renderTimeSlot, styles, }: TimeColumnProps): React.JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=TimeColumn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimeColumn.d.ts","sourceRoot":"","sources":["../../../components/calendar/TimeColumn.tsx"],"names":[],"mappings":"AACA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,UAAU,EAAc,MAAM,cAAc,CAAC;AACtD,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,sBAAsB,CAAC;AAE9B,KAAK,eAAe,GAAG;IACrB,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB,CAAC;AAQF,wBAAgB,UAAU,CAAC,EACzB,SAAS,EACT,eAAe,EACf,UAAU,EACV,UAAU,EACV,cAAc,EACd,MAAM,GACP,EAAE,eAAe,qBAsEjB"}
@@ -0,0 +1,56 @@
1
+ import { format } from "date-fns";
2
+ import React, { useMemo } from "react";
3
+ import { ScrollView, Text, View } from "react-native";
4
+ function formatHour(hour, timeFormat) {
5
+ const date = new Date();
6
+ date.setHours(hour, 0, 0, 0);
7
+ return format(date, timeFormat);
8
+ }
9
+ export function TimeColumn({ scrollRef, gridTotalHeight, timeConfig, dimensions, renderTimeSlot, styles, }) {
10
+ const hoursArray = useMemo(() => {
11
+ const result = [];
12
+ for (let hour = timeConfig.startHour + 1; hour <= timeConfig.endHour; hour++) {
13
+ result.push(hour);
14
+ }
15
+ return result;
16
+ }, [timeConfig.startHour, timeConfig.endHour]);
17
+ const bgColor = styles?.timeColumnBackgroundColor || "#262626";
18
+ return (<View style={{
19
+ zIndex: 10,
20
+ position: "relative",
21
+ borderRightWidth: 1,
22
+ borderRightColor: "#333",
23
+ shadowColor: "#000",
24
+ shadowOffset: { width: 0, height: 2 },
25
+ shadowOpacity: 0.25,
26
+ shadowRadius: 3.84,
27
+ elevation: 5,
28
+ width: dimensions.resourceWidth,
29
+ backgroundColor: bgColor,
30
+ }}>
31
+ <ScrollView ref={scrollRef} showsVerticalScrollIndicator={false} scrollEnabled={false} bounces={false} contentContainerStyle={{ minHeight: gridTotalHeight }}>
32
+ <View style={{
33
+ position: "relative",
34
+ width: dimensions.resourceWidth,
35
+ height: gridTotalHeight,
36
+ }}>
37
+ {hoursArray.map((hour, hourIndex) => {
38
+ const topPosition = hourIndex * dimensions.hourHeight;
39
+ return (<View key={hour} style={{
40
+ position: "absolute",
41
+ left: 0,
42
+ justifyContent: "center",
43
+ alignItems: "center",
44
+ top: topPosition,
45
+ width: dimensions.resourceWidth,
46
+ height: dimensions.hourHeight,
47
+ }}>
48
+ {renderTimeSlot ? (renderTimeSlot(hour)) : (<Text style={{ color: "#fefefe", fontSize: 14 }}>
49
+ {formatHour(hour, timeConfig.timeFormat || "HH:mm")}
50
+ </Text>)}
51
+ </View>);
52
+ })}
53
+ </View>
54
+ </ScrollView>
55
+ </View>);
56
+ }
@@ -0,0 +1,12 @@
1
+ import { CalendarDimensions, CalendarTimeConfig, RenderUnavailableSlotFunction, Resource, UnavailableSlot, UnavailableSlotStyles } from "../../types/calendar";
2
+ type UnavailableLayerProps<TResource = any, TUnavailable = any> = {
3
+ unavailableSlots: UnavailableSlot<TUnavailable>[];
4
+ resources: Resource<TResource>[];
5
+ timeConfig: CalendarTimeConfig;
6
+ dimensions: CalendarDimensions;
7
+ unavailableStyles?: UnavailableSlotStyles;
8
+ renderUnavailableSlot?: RenderUnavailableSlotFunction<TUnavailable>;
9
+ };
10
+ export declare function UnavailableLayer<TResource = any, TUnavailable = any>({ unavailableSlots, resources, timeConfig, dimensions, unavailableStyles, renderUnavailableSlot, }: UnavailableLayerProps<TResource, TUnavailable>): import("react").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=UnavailableLayer.d.ts.map
@@ -0,0 +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,CAAC,SAAS,GAAG,GAAG,EAAE,YAAY,GAAG,GAAG,IAAI;IAChE,gBAAgB,EAAE,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;IAClD,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;IACjC,UAAU,EAAE,kBAAkB,CAAC;IAC/B,UAAU,EAAE,kBAAkB,CAAC;IAC/B,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;IAC1C,qBAAqB,CAAC,EAAE,6BAA6B,CAAC,YAAY,CAAC,CAAC;CACrE,CAAC;AAuDF,wBAAgB,gBAAgB,CAAC,SAAS,GAAG,GAAG,EAAE,YAAY,GAAG,GAAG,EAAE,EACpE,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,qBAAqB,GACtB,EAAE,qBAAqB,CAAC,SAAS,EAAE,YAAY,CAAC,+BAkIhD"}
@@ -0,0 +1,122 @@
1
+ import { useMemo } from "react";
2
+ import { View } from "react-native";
3
+ function DiagonalStripes({ color, width, height, }) {
4
+ const stripeWidth = 1;
5
+ const gapBetweenStripes = 5;
6
+ const stripeSpacing = stripeWidth + gapBetweenStripes;
7
+ const diagonalLength = Math.sqrt(width * width + height * height);
8
+ const numberOfStripes = Math.ceil(diagonalLength / stripeSpacing);
9
+ const stripes = [];
10
+ for (let stripeIndex = -numberOfStripes; stripeIndex < numberOfStripes; stripeIndex++) {
11
+ stripes.push(<View key={stripeIndex} style={{
12
+ position: "absolute",
13
+ backgroundColor: color,
14
+ left: stripeIndex * stripeSpacing,
15
+ top: -width,
16
+ width: stripeWidth,
17
+ height: diagonalLength * 2.1,
18
+ transform: [{ rotate: "45deg" }],
19
+ }}/>);
20
+ }
21
+ return (<View style={{
22
+ position: "absolute",
23
+ top: 0,
24
+ left: 0,
25
+ right: 0,
26
+ bottom: 0,
27
+ overflow: "hidden",
28
+ }}>
29
+ {stripes}
30
+ </View>);
31
+ }
32
+ export function UnavailableLayer({ unavailableSlots, resources, timeConfig, dimensions, unavailableStyles, renderUnavailableSlot, }) {
33
+ const positionedSlots = useMemo(() => {
34
+ return unavailableSlots
35
+ .map((slot) => {
36
+ const resourceIndex = resources.findIndex((resource) => resource.id === slot.resourceId);
37
+ if (resourceIndex === -1) {
38
+ return null;
39
+ }
40
+ const topPosition = (slot.startHour - timeConfig.startHour - 1) * dimensions.hourHeight;
41
+ const blockHeight = (slot.endHour - slot.startHour) * dimensions.hourHeight;
42
+ const leftPosition = resourceIndex * dimensions.resourceWidth;
43
+ const blockWidth = dimensions.resourceWidth;
44
+ return { slot, topPosition, leftPosition, blockWidth, blockHeight };
45
+ })
46
+ .filter(Boolean);
47
+ }, [unavailableSlots, resources, timeConfig.startHour, dimensions]);
48
+ const gridTotalWidth = resources.length * dimensions.resourceWidth;
49
+ const gridBodyHeight = (timeConfig.endHour - timeConfig.startHour - 1) * dimensions.hourHeight;
50
+ // Default styles
51
+ const getSlotStyle = (type) => {
52
+ switch (type) {
53
+ case "reserved":
54
+ return {
55
+ backgroundColor: unavailableStyles?.reserved?.backgroundColor || "#7f1d1d",
56
+ opacity: unavailableStyles?.reserved?.opacity || 0.3,
57
+ };
58
+ case "offHours":
59
+ return {
60
+ backgroundColor: unavailableStyles?.offHours?.backgroundColor || "#404040",
61
+ opacity: unavailableStyles?.offHours?.opacity || 0.5,
62
+ };
63
+ case "disabled":
64
+ return {
65
+ backgroundColor: unavailableStyles?.disabled?.backgroundColor || "#525252",
66
+ opacity: unavailableStyles?.disabled?.opacity || 0.6,
67
+ };
68
+ default:
69
+ return {
70
+ backgroundColor: "#404040",
71
+ opacity: 0.5,
72
+ };
73
+ }
74
+ };
75
+ const getStripeColor = (type) => {
76
+ if (type === "reserved")
77
+ return "#dc2626";
78
+ return "#737373";
79
+ };
80
+ return (<View style={{
81
+ position: "absolute",
82
+ top: 0,
83
+ left: 0,
84
+ width: gridTotalWidth,
85
+ height: gridBodyHeight,
86
+ zIndex: 1,
87
+ }} pointerEvents="none">
88
+ {positionedSlots.map((item) => {
89
+ const showStripes = item.slot.type !== "disabled";
90
+ const slotStyle = getSlotStyle(item.slot.type);
91
+ const stripeColor = getStripeColor(item.slot.type);
92
+ if (renderUnavailableSlot) {
93
+ return (<View key={item.slot.id} style={{
94
+ position: "absolute",
95
+ top: item.topPosition,
96
+ left: item.leftPosition,
97
+ width: item.blockWidth,
98
+ height: item.blockHeight,
99
+ }}>
100
+ {renderUnavailableSlot(item.slot, {
101
+ width: item.blockWidth,
102
+ height: item.blockHeight,
103
+ })}
104
+ </View>);
105
+ }
106
+ return (<View key={item.slot.id} style={{
107
+ position: "absolute",
108
+ overflow: "hidden",
109
+ top: item.topPosition,
110
+ left: item.leftPosition,
111
+ width: item.blockWidth,
112
+ height: item.blockHeight,
113
+ backgroundColor: slotStyle.backgroundColor,
114
+ opacity: slotStyle.opacity,
115
+ borderWidth: 1,
116
+ borderColor: "#333",
117
+ }}>
118
+ {showStripes && (<DiagonalStripes color={stripeColor} width={item.blockWidth} height={item.blockHeight}/>)}
119
+ </View>);
120
+ })}
121
+ </View>);
122
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Native date utility functions to replace date-fns
3
+ * Zero external dependencies
4
+ */
5
+ /**
6
+ * Add days to a date
7
+ */
8
+ export declare function addDays(date: Date, days: number): Date;
9
+ /**
10
+ * Subtract days from a date
11
+ */
12
+ export declare function subDays(date: Date, days: number): Date;
13
+ /**
14
+ * Format a date according to a format string
15
+ * Supports common tokens:
16
+ * - EEE: Short weekday name (Mon, Tue, etc.)
17
+ * - EEEE: Full weekday name (Monday, Tuesday, etc.)
18
+ * - MMM: Short month name (Jan, Feb, etc.)
19
+ * - MMMM: Full month name (January, February, etc.)
20
+ * - MM: Month as 2 digits (01-12)
21
+ * - M: Month as 1-2 digits (1-12)
22
+ * - dd: Day as 2 digits (01-31)
23
+ * - d: Day as 1-2 digits (1-31)
24
+ * - yyyy: Full year (2026)
25
+ * - yy: 2-digit year (26)
26
+ * - HH: Hour in 24h format with leading zero (00-23)
27
+ * - H: Hour in 24h format (0-23)
28
+ * - hh: Hour in 12h format with leading zero (01-12)
29
+ * - h: Hour in 12h format (1-12)
30
+ * - mm: Minutes with leading zero (00-59)
31
+ * - m: Minutes (0-59)
32
+ * - ss: Seconds with leading zero (00-59)
33
+ * - s: Seconds (0-59)
34
+ * - a: AM/PM
35
+ */
36
+ export declare function formatDate(date: Date, formatString: string): string;
37
+ //# sourceMappingURL=dateUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dateUtils.d.ts","sourceRoot":"","sources":["../../../components/calendar/dateUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAItD;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAItD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CA+FnE"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Native date utility functions to replace date-fns
3
+ * Zero external dependencies
4
+ */
5
+ /**
6
+ * Add days to a date
7
+ */
8
+ export function addDays(date, days) {
9
+ const result = new Date(date);
10
+ result.setDate(result.getDate() + days);
11
+ return result;
12
+ }
13
+ /**
14
+ * Subtract days from a date
15
+ */
16
+ export function subDays(date, days) {
17
+ const result = new Date(date);
18
+ result.setDate(result.getDate() - days);
19
+ return result;
20
+ }
21
+ /**
22
+ * Format a date according to a format string
23
+ * Supports common tokens:
24
+ * - EEE: Short weekday name (Mon, Tue, etc.)
25
+ * - EEEE: Full weekday name (Monday, Tuesday, etc.)
26
+ * - MMM: Short month name (Jan, Feb, etc.)
27
+ * - MMMM: Full month name (January, February, etc.)
28
+ * - MM: Month as 2 digits (01-12)
29
+ * - M: Month as 1-2 digits (1-12)
30
+ * - dd: Day as 2 digits (01-31)
31
+ * - d: Day as 1-2 digits (1-31)
32
+ * - yyyy: Full year (2026)
33
+ * - yy: 2-digit year (26)
34
+ * - HH: Hour in 24h format with leading zero (00-23)
35
+ * - H: Hour in 24h format (0-23)
36
+ * - hh: Hour in 12h format with leading zero (01-12)
37
+ * - h: Hour in 12h format (1-12)
38
+ * - mm: Minutes with leading zero (00-59)
39
+ * - m: Minutes (0-59)
40
+ * - ss: Seconds with leading zero (00-59)
41
+ * - s: Seconds (0-59)
42
+ * - a: AM/PM
43
+ */
44
+ export function formatDate(date, formatString) {
45
+ const weekdaysShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
46
+ const weekdaysFull = [
47
+ "Sunday",
48
+ "Monday",
49
+ "Tuesday",
50
+ "Wednesday",
51
+ "Thursday",
52
+ "Friday",
53
+ "Saturday",
54
+ ];
55
+ const monthsShort = [
56
+ "Jan",
57
+ "Feb",
58
+ "Mar",
59
+ "Apr",
60
+ "May",
61
+ "Jun",
62
+ "Jul",
63
+ "Aug",
64
+ "Sep",
65
+ "Oct",
66
+ "Nov",
67
+ "Dec",
68
+ ];
69
+ const monthsFull = [
70
+ "January",
71
+ "February",
72
+ "March",
73
+ "April",
74
+ "May",
75
+ "June",
76
+ "July",
77
+ "August",
78
+ "September",
79
+ "October",
80
+ "November",
81
+ "December",
82
+ ];
83
+ const day = date.getDate();
84
+ const month = date.getMonth();
85
+ const year = date.getFullYear();
86
+ const weekday = date.getDay();
87
+ const hours = date.getHours();
88
+ const minutes = date.getMinutes();
89
+ const seconds = date.getSeconds();
90
+ const pad = (num, size = 2) => {
91
+ return num.toString().padStart(size, "0");
92
+ };
93
+ const tokens = {
94
+ EEEE: weekdaysFull[weekday],
95
+ EEE: weekdaysShort[weekday],
96
+ MMMM: monthsFull[month],
97
+ MMM: monthsShort[month],
98
+ MM: pad(month + 1),
99
+ M: (month + 1).toString(),
100
+ dd: pad(day),
101
+ d: day.toString(),
102
+ yyyy: year.toString(),
103
+ yy: year.toString().slice(-2),
104
+ HH: pad(hours),
105
+ H: hours.toString(),
106
+ hh: pad(hours % 12 || 12),
107
+ h: (hours % 12 || 12).toString(),
108
+ mm: pad(minutes),
109
+ m: minutes.toString(),
110
+ ss: pad(seconds),
111
+ s: seconds.toString(),
112
+ a: hours >= 12 ? "PM" : "AM",
113
+ };
114
+ let result = formatString;
115
+ // Sort by length descending to replace longer tokens first (e.g., MMMM before MMM)
116
+ const sortedTokens = Object.keys(tokens).sort((a, b) => b.length - a.length);
117
+ for (const token of sortedTokens) {
118
+ // Use a unique placeholder to avoid re-replacement issues
119
+ const placeholder = `\x00${token}\x00`;
120
+ result = result.replace(new RegExp(token, "g"), placeholder);
121
+ }
122
+ // Replace placeholders with actual values
123
+ for (const token of sortedTokens) {
124
+ const placeholder = `\x00${token}\x00`;
125
+ result = result.replace(new RegExp(placeholder.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), tokens[token]);
126
+ }
127
+ return result;
128
+ }
@@ -0,0 +1,9 @@
1
+ export { Calendar } from "./Calendar";
2
+ export { CalendarHeader } from "./CalendarHeader";
3
+ export { EventsLayer } from "./EventsLayer";
4
+ export { GridBody } from "./GridBody";
5
+ export { ResourceHeaders } from "./ResourceHeaders";
6
+ export { TimeColumn } from "./TimeColumn";
7
+ export { UnavailableLayer } from "./UnavailableLayer";
8
+ export type { CalendarDimensions, CalendarEvent, CalendarEventStyles, CalendarProps, CalendarStyles, CalendarTimeConfig, RenderEventFunction, RenderResourceHeaderFunction, RenderTimeSlotFunction, RenderUnavailableSlotFunction, Resource, UnavailableSlot, UnavailableSlotStyles, UnavailableType, } from "../../types/calendar";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/calendar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,4BAA4B,EAC5B,sBAAsB,EACtB,6BAA6B,EAC7B,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,eAAe,GAChB,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { Calendar } from "./Calendar";
2
+ export { CalendarHeader } from "./CalendarHeader";
3
+ export { EventsLayer } from "./EventsLayer";
4
+ export { GridBody } from "./GridBody";
5
+ export { ResourceHeaders } from "./ResourceHeaders";
6
+ export { TimeColumn } from "./TimeColumn";
7
+ export { UnavailableLayer } from "./UnavailableLayer";
@@ -0,0 +1,9 @@
1
+ export { Calendar } from "./components/calendar/Calendar";
2
+ export { CalendarHeader } from "./components/calendar/CalendarHeader";
3
+ export { EventsLayer } from "./components/calendar/EventsLayer";
4
+ export { GridBody } from "./components/calendar/GridBody";
5
+ export { ResourceHeaders } from "./components/calendar/ResourceHeaders";
6
+ export { TimeColumn } from "./components/calendar/TimeColumn";
7
+ export { UnavailableLayer } from "./components/calendar/UnavailableLayer";
8
+ export type { CalendarDimensions, CalendarEvent, CalendarEventStyles, CalendarProps, CalendarStyles, CalendarTimeConfig, RenderEventFunction, RenderResourceHeaderFunction, RenderTimeSlotFunction, RenderUnavailableSlotFunction, Resource, UnavailableSlot, UnavailableSlotStyles, UnavailableType, } from "./types/calendar";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAG1D,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAG1E,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,4BAA4B,EAC5B,sBAAsB,EACtB,6BAA6B,EAC7B,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,eAAe,GAChB,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ // Main package entry point
2
+ export { Calendar } from "./components/calendar/Calendar";
3
+ // Sub-components
4
+ export { CalendarHeader } from "./components/calendar/CalendarHeader";
5
+ export { EventsLayer } from "./components/calendar/EventsLayer";
6
+ export { GridBody } from "./components/calendar/GridBody";
7
+ export { ResourceHeaders } from "./components/calendar/ResourceHeaders";
8
+ export { TimeColumn } from "./components/calendar/TimeColumn";
9
+ export { UnavailableLayer } from "./components/calendar/UnavailableLayer";