react-native-ll-calendar 0.1.1

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 (50) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +13 -0
  3. package/lib/module/calendar/month-calendar/MonthCalendar.js +79 -0
  4. package/lib/module/calendar/month-calendar/MonthCalendar.js.map +1 -0
  5. package/lib/module/calendar/month-calendar/logic/useEvents.js +31 -0
  6. package/lib/module/calendar/month-calendar/logic/useEvents.js.map +1 -0
  7. package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js +101 -0
  8. package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js.map +1 -0
  9. package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js +174 -0
  10. package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js.map +1 -0
  11. package/lib/module/constants/size.js +5 -0
  12. package/lib/module/constants/size.js.map +1 -0
  13. package/lib/module/index.js +4 -0
  14. package/lib/module/index.js.map +1 -0
  15. package/lib/module/package.json +1 -0
  16. package/lib/module/types/month-calendar.js +2 -0
  17. package/lib/module/types/month-calendar.js.map +1 -0
  18. package/lib/module/utils/functions.js +76 -0
  19. package/lib/module/utils/functions.js.map +1 -0
  20. package/lib/module/utils/month-calendar-event-position.js +68 -0
  21. package/lib/module/utils/month-calendar-event-position.js.map +1 -0
  22. package/lib/typescript/package.json +1 -0
  23. package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts +10 -0
  24. package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts.map +1 -0
  25. package/lib/typescript/src/calendar/month-calendar/logic/useEvents.d.ts +8 -0
  26. package/lib/typescript/src/calendar/month-calendar/logic/useEvents.d.ts.map +1 -0
  27. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts +9 -0
  28. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts.map +1 -0
  29. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts +12 -0
  30. package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts.map +1 -0
  31. package/lib/typescript/src/constants/size.d.ts +3 -0
  32. package/lib/typescript/src/constants/size.d.ts.map +1 -0
  33. package/lib/typescript/src/index.d.ts +3 -0
  34. package/lib/typescript/src/index.d.ts.map +1 -0
  35. package/lib/typescript/src/types/month-calendar.d.ts +11 -0
  36. package/lib/typescript/src/types/month-calendar.d.ts.map +1 -0
  37. package/lib/typescript/src/utils/functions.d.ts +15 -0
  38. package/lib/typescript/src/utils/functions.d.ts.map +1 -0
  39. package/lib/typescript/src/utils/month-calendar-event-position.d.ts +22 -0
  40. package/lib/typescript/src/utils/month-calendar-event-position.d.ts.map +1 -0
  41. package/package.json +157 -0
  42. package/src/calendar/month-calendar/MonthCalendar.tsx +94 -0
  43. package/src/calendar/month-calendar/logic/useEvents.tsx +35 -0
  44. package/src/calendar/month-calendar/view/MonthCalendarViewItem.tsx +88 -0
  45. package/src/calendar/month-calendar/view/MonthCalendarWeekRow.tsx +206 -0
  46. package/src/constants/size.ts +2 -0
  47. package/src/index.tsx +2 -0
  48. package/src/types/month-calendar.ts +11 -0
  49. package/src/utils/functions.ts +79 -0
  50. package/src/utils/month-calendar-event-position.ts +68 -0
@@ -0,0 +1,10 @@
1
+ import type { CalendarEvent, WeekStartsOn } from '../../types/month-calendar';
2
+ export declare const MonthCalendar: (props: {
3
+ defaultDate: Date;
4
+ weekStartsOn?: WeekStartsOn;
5
+ onChangeDate?: (date: Date) => void;
6
+ events: CalendarEvent[];
7
+ onPressEvent?: (event: CalendarEvent) => void;
8
+ onPressCell?: (date: Date) => void;
9
+ }) => import("react/jsx-runtime").JSX.Element;
10
+ //# sourceMappingURL=MonthCalendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonthCalendar.d.ts","sourceRoot":"","sources":["../../../../../src/calendar/month-calendar/MonthCalendar.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAK9E,eAAO,MAAM,aAAa,GAAI,OAAO;IACnC,WAAW,EAAE,IAAI,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACpC,4CA8EA,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { CalendarEvent, WeekStartsOn } from '../../../types/month-calendar';
2
+ export declare const useEvents: (props: {
3
+ events: CalendarEvent[];
4
+ weekStartsOn: WeekStartsOn;
5
+ }) => {
6
+ eventsGroupByWeekId: Record<string, CalendarEvent[]>;
7
+ };
8
+ //# sourceMappingURL=useEvents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEvents.d.ts","sourceRoot":"","sources":["../../../../../../src/calendar/month-calendar/logic/useEvents.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,+BAA+B,CAAC;AAGvC,eAAO,MAAM,SAAS,GAAI,OAAO;IAC/B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;CAC5B;;CAwBA,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { CalendarEvent, WeekStartsOn } from '../../../types/month-calendar';
2
+ export declare const MonthCalendarViewItem: (props: {
3
+ month: string;
4
+ weekStartsOn: WeekStartsOn;
5
+ events: CalendarEvent[];
6
+ onPressEvent?: (event: CalendarEvent) => void;
7
+ onPressCell?: (date: Date) => void;
8
+ }) => import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=MonthCalendarViewItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonthCalendarViewItem.d.ts","sourceRoot":"","sources":["../../../../../../src/calendar/month-calendar/view/MonthCalendarViewItem.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACb,MAAM,+BAA+B,CAAC;AAMvC,eAAO,MAAM,qBAAqB,GAAI,OAAO;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACpC,4CAoDA,CAAC"}
@@ -0,0 +1,12 @@
1
+ import dayjs from 'dayjs';
2
+ import type { CalendarEvent } from '../../../types/month-calendar';
3
+ import type MonthCalendarEventPosition from '../../../utils/month-calendar-event-position';
4
+ export declare const MonthCalendarWeekRow: (props: {
5
+ dates: dayjs.Dayjs[];
6
+ isWeekdayHeader?: boolean;
7
+ events?: CalendarEvent[];
8
+ eventPosition?: MonthCalendarEventPosition;
9
+ onPressEvent?: (event: CalendarEvent) => void;
10
+ onPressCell?: (date: Date) => void;
11
+ }) => import("react/jsx-runtime").JSX.Element;
12
+ //# sourceMappingURL=MonthCalendarWeekRow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MonthCalendarWeekRow.d.ts","sourceRoot":"","sources":["../../../../../../src/calendar/month-calendar/view/MonthCalendarWeekRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,0BAA0B,MAAM,8CAA8C,CAAC;AAG3F,eAAO,MAAM,oBAAoB,GAAI,OAAO;IAC1C,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,0BAA0B,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC9C,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACpC,4CAgJA,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const CELL_BORDER_WIDTH = 0.2;
2
+ export declare const EVENT_GAP = 2;
3
+ //# sourceMappingURL=size.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"size.d.ts","sourceRoot":"","sources":["../../../../src/constants/size.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,SAAS,IAAI,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { MonthCalendar } from './calendar/month-calendar/MonthCalendar';
2
+ export type { CalendarEvent } from './types/month-calendar';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AACxE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export type WeekStartsOn = 0 | 1;
2
+ export type CalendarEvent = {
3
+ id: string;
4
+ title: string;
5
+ start: Date;
6
+ end: Date;
7
+ backgroundColor: string;
8
+ borderColor: string;
9
+ color: string;
10
+ };
11
+ //# sourceMappingURL=month-calendar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"month-calendar.d.ts","sourceRoot":"","sources":["../../../../src/types/month-calendar.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC;AAEjC,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;IACV,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { WeekStartsOn } from '../types/month-calendar';
2
+ export declare function monthlyStartDate(args: {
3
+ date: Date;
4
+ weekStartsOn: WeekStartsOn;
5
+ }): Date;
6
+ export declare function monthlyEndDate(args: {
7
+ date: Date;
8
+ weekStartsOn: WeekStartsOn;
9
+ }): Date;
10
+ export declare function getWeekIds(args: {
11
+ start: Date;
12
+ end: Date;
13
+ weekStartsOn: WeekStartsOn;
14
+ }): string[];
15
+ //# sourceMappingURL=functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../../src/utils/functions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,IAAI,EAAE,IAAI,CAAC;IACX,YAAY,EAAE,YAAY,CAAC;CAC5B,QAeA;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,IAAI,EAAE,IAAI,CAAC;IACX,YAAY,EAAE,YAAY,CAAC;CAC5B,QAaA;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE;IAC/B,KAAK,EAAE,IAAI,CAAC;IACZ,GAAG,EAAE,IAAI,CAAC;IACV,YAAY,EAAE,YAAY,CAAC;CAC5B,YAiCA"}
@@ -0,0 +1,22 @@
1
+ declare class MonthCalendarEventPosition {
2
+ record: Record<string, Record<string, number[]>>;
3
+ constructor();
4
+ private generateKey;
5
+ push(arg: {
6
+ weekId: string;
7
+ startDate: Date;
8
+ days: number;
9
+ rowNum: number;
10
+ }): void;
11
+ getMaxRowNum(arg: {
12
+ weekId: string;
13
+ date: Date;
14
+ }): number;
15
+ getRowNums(arg: {
16
+ weekId: string;
17
+ date: Date;
18
+ }): number[];
19
+ resetResource(weekId: string): void;
20
+ }
21
+ export default MonthCalendarEventPosition;
22
+ //# sourceMappingURL=month-calendar-event-position.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"month-calendar-event-position.d.ts","sourceRoot":"","sources":["../../../../src/utils/month-calendar-event-position.ts"],"names":[],"mappings":"AAAA,cAAM,0BAA0B;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAM;;IAG7D,OAAO,CAAC,WAAW;IAOZ,IAAI,CAAC,GAAG,EAAE;QACf,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,IAAI,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB;IAiBM,YAAY,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG,MAAM;IAiBzD,UAAU,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG,MAAM,EAAE;IAazD,aAAa,CAAC,MAAM,EAAE,MAAM;CAGpC;AACD,eAAe,0BAA0B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,157 @@
1
+ {
2
+ "name": "react-native-ll-calendar",
3
+ "version": "0.1.1",
4
+ "description": "ReactNative Calendar Library",
5
+ "main": "./lib/module/index.js",
6
+ "types": "./lib/typescript/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.tsx",
10
+ "types": "./lib/typescript/src/index.d.ts",
11
+ "default": "./lib/module/index.js"
12
+ },
13
+ "./package.json": "./package.json"
14
+ },
15
+ "files": [
16
+ "src",
17
+ "lib",
18
+ "android",
19
+ "ios",
20
+ "cpp",
21
+ "*.podspec",
22
+ "react-native.config.js",
23
+ "!ios/build",
24
+ "!android/build",
25
+ "!android/gradle",
26
+ "!android/gradlew",
27
+ "!android/gradlew.bat",
28
+ "!android/local.properties",
29
+ "!**/__tests__",
30
+ "!**/__fixtures__",
31
+ "!**/__mocks__",
32
+ "!**/.*"
33
+ ],
34
+ "scripts": {
35
+ "example": "yarn workspace react-native-ll-calendar-example",
36
+ "test": "jest",
37
+ "typecheck": "tsc",
38
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
39
+ "clean": "del-cli lib",
40
+ "prepare": "bob build",
41
+ "release": "release-it --only-version"
42
+ },
43
+ "keywords": [
44
+ "react-native",
45
+ "ios",
46
+ "android"
47
+ ],
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/uemura1114/react-native-ll-calendar.git"
51
+ },
52
+ "author": "Wataru Uemura <uemura1114@gmail.com> (https://github.com/uemura1114)",
53
+ "license": "MIT",
54
+ "bugs": {
55
+ "url": "https://github.com/uemura1114/react-native-ll-calendar/issues"
56
+ },
57
+ "homepage": "https://github.com/uemura1114/react-native-ll-calendar#readme",
58
+ "publishConfig": {
59
+ "registry": "https://registry.npmjs.org/"
60
+ },
61
+ "devDependencies": {
62
+ "@commitlint/config-conventional": "^19.8.1",
63
+ "@eslint/compat": "^1.3.2",
64
+ "@eslint/eslintrc": "^3.3.1",
65
+ "@eslint/js": "^9.35.0",
66
+ "@evilmartians/lefthook": "^1.12.3",
67
+ "@react-native/babel-preset": "0.81.1",
68
+ "@react-native/eslint-config": "^0.81.1",
69
+ "@release-it/conventional-changelog": "^10.0.1",
70
+ "@types/jest": "^29.5.14",
71
+ "@types/react": "^19.1.12",
72
+ "commitlint": "^19.8.1",
73
+ "del-cli": "^6.0.0",
74
+ "eslint": "^9.35.0",
75
+ "eslint-config-prettier": "^10.1.8",
76
+ "eslint-plugin-prettier": "^5.5.4",
77
+ "jest": "^29.7.0",
78
+ "prettier": "^3.6.2",
79
+ "react": "19.1.0",
80
+ "react-native": "0.81.4",
81
+ "react-native-builder-bob": "^0.40.13",
82
+ "release-it": "^19.0.4",
83
+ "typescript": "^5.9.2"
84
+ },
85
+ "peerDependencies": {
86
+ "react": "*",
87
+ "react-native": "*"
88
+ },
89
+ "workspaces": [
90
+ "example"
91
+ ],
92
+ "packageManager": "yarn@3.6.1",
93
+ "jest": {
94
+ "preset": "react-native",
95
+ "modulePathIgnorePatterns": [
96
+ "<rootDir>/example/node_modules",
97
+ "<rootDir>/lib/"
98
+ ]
99
+ },
100
+ "commitlint": {
101
+ "extends": [
102
+ "@commitlint/config-conventional"
103
+ ]
104
+ },
105
+ "release-it": {
106
+ "git": {
107
+ "commitMessage": "chore: release ${version}",
108
+ "tagName": "v${version}"
109
+ },
110
+ "npm": {
111
+ "publish": true
112
+ },
113
+ "github": {
114
+ "release": true
115
+ },
116
+ "plugins": {
117
+ "@release-it/conventional-changelog": {
118
+ "preset": {
119
+ "name": "angular"
120
+ }
121
+ }
122
+ }
123
+ },
124
+ "prettier": {
125
+ "quoteProps": "consistent",
126
+ "singleQuote": true,
127
+ "tabWidth": 2,
128
+ "trailingComma": "es5",
129
+ "useTabs": false
130
+ },
131
+ "react-native-builder-bob": {
132
+ "source": "src",
133
+ "output": "lib",
134
+ "targets": [
135
+ [
136
+ "module",
137
+ {
138
+ "esm": true
139
+ }
140
+ ],
141
+ [
142
+ "typescript",
143
+ {
144
+ "project": "tsconfig.build.json"
145
+ }
146
+ ]
147
+ ]
148
+ },
149
+ "create-react-native-library": {
150
+ "languages": "js",
151
+ "type": "library",
152
+ "version": "0.54.3"
153
+ },
154
+ "dependencies": {
155
+ "dayjs": "^1.11.18"
156
+ }
157
+ }
@@ -0,0 +1,94 @@
1
+ import { useWindowDimensions, FlatList } from 'react-native';
2
+ import dayjs from 'dayjs';
3
+ import { useState } from 'react';
4
+ import type { CalendarEvent, WeekStartsOn } from '../../types/month-calendar';
5
+ import { MonthCalendarViewItem } from './view/MonthCalendarViewItem';
6
+
7
+ const HALF_PANEL_LENGTH = 120; // 10 years
8
+
9
+ export const MonthCalendar = (props: {
10
+ defaultDate: Date;
11
+ weekStartsOn?: WeekStartsOn;
12
+ onChangeDate?: (date: Date) => void;
13
+ events: CalendarEvent[];
14
+ onPressEvent?: (event: CalendarEvent) => void;
15
+ onPressCell?: (date: Date) => void;
16
+ }) => {
17
+ const {
18
+ defaultDate,
19
+ weekStartsOn = 0,
20
+ onChangeDate,
21
+ events,
22
+ onPressEvent,
23
+ onPressCell,
24
+ } = props;
25
+ const [dateState] = useState(defaultDate);
26
+ const [_activeIndex, setActiveIndex] = useState(HALF_PANEL_LENGTH);
27
+ const defaultDateDjs = dayjs(dateState);
28
+ const startOfDefaultDateDjs = defaultDateDjs.startOf('month');
29
+ const prevPanels: string[] = Array.from(
30
+ { length: HALF_PANEL_LENGTH },
31
+ (_, i) => {
32
+ return startOfDefaultDateDjs
33
+ .subtract(HALF_PANEL_LENGTH - i, 'month')
34
+ .format('YYYY-MM');
35
+ }
36
+ );
37
+ const nextPanels: string[] = Array.from(
38
+ { length: HALF_PANEL_LENGTH },
39
+ (_, i) => {
40
+ return startOfDefaultDateDjs.add(i + 1, 'month').format('YYYY-MM');
41
+ }
42
+ );
43
+ const panels: string[] = [
44
+ ...prevPanels,
45
+ startOfDefaultDateDjs.format('YYYY-MM'),
46
+ ...nextPanels,
47
+ ];
48
+
49
+ const { width } = useWindowDimensions();
50
+
51
+ return (
52
+ <FlatList
53
+ horizontal
54
+ pagingEnabled={true}
55
+ getItemLayout={(_data, index) => {
56
+ return {
57
+ length: width,
58
+ offset: width * index,
59
+ index,
60
+ };
61
+ }}
62
+ onMomentumScrollEnd={(e) => {
63
+ const scrollX = e.nativeEvent.contentOffset.x;
64
+ const newIndex = Math.round(scrollX / width);
65
+ const month = panels[newIndex];
66
+ if (month) {
67
+ const newDate = new Date(month);
68
+ onChangeDate?.(newDate);
69
+ }
70
+ setActiveIndex(newIndex);
71
+ }}
72
+ initialScrollIndex={HALF_PANEL_LENGTH}
73
+ decelerationRate={'fast'}
74
+ data={panels}
75
+ renderItem={({ item }) => {
76
+ return (
77
+ <MonthCalendarViewItem
78
+ month={item}
79
+ weekStartsOn={weekStartsOn}
80
+ events={events}
81
+ onPressEvent={onPressEvent}
82
+ onPressCell={onPressCell}
83
+ />
84
+ );
85
+ }}
86
+ showsHorizontalScrollIndicator={false}
87
+ scrollEnabled={true}
88
+ windowSize={5}
89
+ initialNumToRender={5}
90
+ maxToRenderPerBatch={5}
91
+ removeClippedSubviews={false}
92
+ />
93
+ );
94
+ };
@@ -0,0 +1,35 @@
1
+ import { useMemo } from 'react';
2
+ import type {
3
+ CalendarEvent,
4
+ WeekStartsOn,
5
+ } from '../../../types/month-calendar';
6
+ import { getWeekIds } from '../../../utils/functions';
7
+
8
+ export const useEvents = (props: {
9
+ events: CalendarEvent[];
10
+ weekStartsOn: WeekStartsOn;
11
+ }) => {
12
+ const { events, weekStartsOn } = props;
13
+
14
+ const eventsGroupByWeekId: Record<string, CalendarEvent[]> = useMemo(() => {
15
+ const groupedEvents: Record<string, CalendarEvent[]> = {};
16
+
17
+ events.forEach((event) => {
18
+ const weekIds: string[] = getWeekIds({
19
+ start: event.start,
20
+ end: event.end,
21
+ weekStartsOn,
22
+ });
23
+ weekIds.forEach((weekId) => {
24
+ if (!groupedEvents[weekId]) {
25
+ groupedEvents[weekId] = [];
26
+ }
27
+ groupedEvents[weekId].push(event);
28
+ });
29
+ });
30
+
31
+ return groupedEvents;
32
+ }, [events, weekStartsOn]);
33
+
34
+ return { eventsGroupByWeekId };
35
+ };
@@ -0,0 +1,88 @@
1
+ import dayjs from 'dayjs';
2
+ import { StyleSheet, Text, View, useWindowDimensions } from 'react-native';
3
+ import { MonthCalendarWeekRow } from './MonthCalendarWeekRow';
4
+ import type {
5
+ CalendarEvent,
6
+ WeekStartsOn,
7
+ } from '../../../types/month-calendar';
8
+ import MonthCalendarEventPosition from '../../../utils/month-calendar-event-position';
9
+ import { monthlyEndDate, monthlyStartDate } from '../../../utils/functions';
10
+ import { useEvents } from '../logic/useEvents';
11
+ import { CELL_BORDER_WIDTH } from '../../../constants/size';
12
+
13
+ export const MonthCalendarViewItem = (props: {
14
+ month: string;
15
+ weekStartsOn: WeekStartsOn;
16
+ events: CalendarEvent[];
17
+ onPressEvent?: (event: CalendarEvent) => void;
18
+ onPressCell?: (date: Date) => void;
19
+ }) => {
20
+ const { month, weekStartsOn, events, onPressEvent, onPressCell } = props;
21
+ const { width } = useWindowDimensions();
22
+ const eventPosition = new MonthCalendarEventPosition();
23
+
24
+ const date = new Date(month);
25
+ const dateDjs = dayjs(date);
26
+ const startDate = monthlyStartDate({ date, weekStartsOn });
27
+ const endDate = monthlyEndDate({ date, weekStartsOn });
28
+ const endDjs = dayjs(endDate);
29
+ const weeks: dayjs.Dayjs[][] = [];
30
+ let currentDate = dayjs(startDate);
31
+ while (currentDate.isBefore(endDjs)) {
32
+ const week = Array.from({ length: 7 }, (_, i) => {
33
+ return currentDate.add(i, 'day');
34
+ });
35
+ weeks.push(week);
36
+ currentDate = currentDate.add(7, 'day');
37
+ }
38
+
39
+ const { eventsGroupByWeekId } = useEvents({ events, weekStartsOn });
40
+
41
+ return (
42
+ <View style={[styles.container, { width }]}>
43
+ <View style={styles.monthContainer}>
44
+ <Text style={styles.monthText}>{dateDjs.format('YYYY/MM')}</Text>
45
+ </View>
46
+ <View>
47
+ <MonthCalendarWeekRow dates={weeks[0] ?? []} isWeekdayHeader={true} />
48
+ </View>
49
+ <View>
50
+ {weeks.map((week, index) => {
51
+ const firstDayOfWeek = week[0];
52
+ if (firstDayOfWeek === undefined) {
53
+ return null;
54
+ }
55
+ const weekId = firstDayOfWeek.format('YYYY-MM-DD');
56
+ const weekEvents = eventsGroupByWeekId[weekId] || [];
57
+ return (
58
+ <MonthCalendarWeekRow
59
+ key={`row-${index}`}
60
+ dates={week}
61
+ events={weekEvents}
62
+ eventPosition={eventPosition}
63
+ onPressEvent={onPressEvent}
64
+ onPressCell={onPressCell}
65
+ />
66
+ );
67
+ })}
68
+ </View>
69
+ </View>
70
+ );
71
+ };
72
+
73
+ const styles = StyleSheet.create({
74
+ container: {
75
+ borderWidth: CELL_BORDER_WIDTH,
76
+ borderColor: 'lightslategrey',
77
+ alignSelf: 'flex-start',
78
+ },
79
+ monthContainer: {
80
+ padding: 2,
81
+ borderWidth: CELL_BORDER_WIDTH,
82
+ borderColor: 'lightslategrey',
83
+ backgroundColor: 'white',
84
+ },
85
+ monthText: {
86
+ textAlign: 'center',
87
+ },
88
+ });