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.
- package/LICENSE +20 -0
- package/README.md +13 -0
- package/lib/module/calendar/month-calendar/MonthCalendar.js +79 -0
- package/lib/module/calendar/month-calendar/MonthCalendar.js.map +1 -0
- package/lib/module/calendar/month-calendar/logic/useEvents.js +31 -0
- package/lib/module/calendar/month-calendar/logic/useEvents.js.map +1 -0
- package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js +101 -0
- package/lib/module/calendar/month-calendar/view/MonthCalendarViewItem.js.map +1 -0
- package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js +174 -0
- package/lib/module/calendar/month-calendar/view/MonthCalendarWeekRow.js.map +1 -0
- package/lib/module/constants/size.js +5 -0
- package/lib/module/constants/size.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types/month-calendar.js +2 -0
- package/lib/module/types/month-calendar.js.map +1 -0
- package/lib/module/utils/functions.js +76 -0
- package/lib/module/utils/functions.js.map +1 -0
- package/lib/module/utils/month-calendar-event-position.js +68 -0
- package/lib/module/utils/month-calendar-event-position.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts +10 -0
- package/lib/typescript/src/calendar/month-calendar/MonthCalendar.d.ts.map +1 -0
- package/lib/typescript/src/calendar/month-calendar/logic/useEvents.d.ts +8 -0
- package/lib/typescript/src/calendar/month-calendar/logic/useEvents.d.ts.map +1 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts +9 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarViewItem.d.ts.map +1 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts +12 -0
- package/lib/typescript/src/calendar/month-calendar/view/MonthCalendarWeekRow.d.ts.map +1 -0
- package/lib/typescript/src/constants/size.d.ts +3 -0
- package/lib/typescript/src/constants/size.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/types/month-calendar.d.ts +11 -0
- package/lib/typescript/src/types/month-calendar.d.ts.map +1 -0
- package/lib/typescript/src/utils/functions.d.ts +15 -0
- package/lib/typescript/src/utils/functions.d.ts.map +1 -0
- package/lib/typescript/src/utils/month-calendar-event-position.d.ts +22 -0
- package/lib/typescript/src/utils/month-calendar-event-position.d.ts.map +1 -0
- package/package.json +157 -0
- package/src/calendar/month-calendar/MonthCalendar.tsx +94 -0
- package/src/calendar/month-calendar/logic/useEvents.tsx +35 -0
- package/src/calendar/month-calendar/view/MonthCalendarViewItem.tsx +88 -0
- package/src/calendar/month-calendar/view/MonthCalendarWeekRow.tsx +206 -0
- package/src/constants/size.ts +2 -0
- package/src/index.tsx +2 -0
- package/src/types/month-calendar.ts +11 -0
- package/src/utils/functions.ts +79 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
+
});
|