cleanhaus-calendar 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 (55) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/LICENSE +22 -0
  3. package/README.md +275 -0
  4. package/next-plugin.js +100 -0
  5. package/package.json +80 -0
  6. package/src/Calendar.tsx +279 -0
  7. package/src/CalendarFAB.tsx +116 -0
  8. package/src/DayView/components/EventBlock.tsx +306 -0
  9. package/src/DayView/components/PropertyHeader.tsx +62 -0
  10. package/src/DayView/components/PropertyLane.tsx +150 -0
  11. package/src/DayView/config/EventBlockConfig.tsx +603 -0
  12. package/src/DayView/constants.ts +39 -0
  13. package/src/DayView/hooks/useScrollSynchronization.ts +103 -0
  14. package/src/DayView/index.tsx +382 -0
  15. package/src/DayView/styles/EventBlockStyles.ts +274 -0
  16. package/src/DayView/types.ts +15 -0
  17. package/src/DayView/utils.ts +412 -0
  18. package/src/MonthView/EventBar.tsx +254 -0
  19. package/src/MonthView/OverflowIndicator.tsx +52 -0
  20. package/src/MonthView/index.tsx +299 -0
  21. package/src/MonthView/types.ts +39 -0
  22. package/src/MonthView/utils.ts +259 -0
  23. package/src/WeekView/OverflowIndicator.tsx +93 -0
  24. package/src/WeekView/components/DayColumn.tsx +236 -0
  25. package/src/WeekView/components/PropertyBar.tsx +108 -0
  26. package/src/WeekView/components/PropertyIndicator.tsx +62 -0
  27. package/src/WeekView/components/WeekHeader.tsx +142 -0
  28. package/src/WeekView/constants.ts +53 -0
  29. package/src/WeekView/index.tsx +403 -0
  30. package/src/WeekView/types.ts +38 -0
  31. package/src/WeekView/utils/indicators.ts +82 -0
  32. package/src/WeekView/utils.ts +314 -0
  33. package/src/hooks/index.ts +6 -0
  34. package/src/hooks/useSwipeGesture.ts +135 -0
  35. package/src/index.ts +21 -0
  36. package/src/shared/ErrorBoundary.tsx +130 -0
  37. package/src/shared/HourGrid.tsx +52 -0
  38. package/src/shared/NowIndicator.tsx +92 -0
  39. package/src/shared/TimeColumn.tsx +92 -0
  40. package/src/shared/TimeRail.tsx +63 -0
  41. package/src/shared/VerticalDividers.tsx +55 -0
  42. package/src/shared/index.ts +19 -0
  43. package/src/shared/useNowIndicator.ts +83 -0
  44. package/src/types/react-native.d.ts +33 -0
  45. package/src/types.ts +45 -0
  46. package/src/utils/dateUtils.ts +268 -0
  47. package/src/utils/eventHelpers.ts +425 -0
  48. package/src/utils/index.ts +27 -0
  49. package/src/utils/platform.ts +49 -0
  50. package/src/utils/propertyColors.ts +74 -0
  51. package/src/utils/reanimated.ts +127 -0
  52. package/src/utils/theme.ts +315 -0
  53. package/src/utils/weekDayUtils.ts +75 -0
  54. package/src/web/index.ts +28 -0
  55. package/tsup.config.ts +24 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,46 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2026-01-12
9
+
10
+ ### Added
11
+ - Initial release of cleanhaus-calendar package
12
+ - Cross-platform calendar component (React Native + Web)
13
+ - Three view modes: Month, Week, and Day views
14
+ - Horizontal time-based event positioning
15
+ - Multi-day event spanning with global row assignment
16
+ - Type-based event rendering (property, cleaning, service, etc.)
17
+ - Web compatibility via react-native-web
18
+ - Next.js integration via next-plugin
19
+ - SSR-safe implementation
20
+ - Platform-aware gesture handling (swipe disabled on web)
21
+ - Comprehensive TypeScript types
22
+ - Theme customization support
23
+ - Property color management
24
+ - FAB component for actions
25
+ - Error boundary for robust error handling
26
+ - Comprehensive documentation and examples
27
+
28
+ ### Features
29
+ - **MonthView**: Calendar grid with event bars, swipe navigation
30
+ - **WeekView**: 7-day view with time-based positioning
31
+ - **DayView**: Single-day view with property lanes and horizontal scrolling
32
+ - **CalendarFAB**: Floating action button component
33
+ - **Utilities**: Date helpers, event transformers, theme management
34
+ - **Hooks**: useSwipeGesture, useNowIndicator, useScrollSynchronization
35
+
36
+ ### Technical
37
+ - TypeScript-first implementation
38
+ - React Native 0.70+ support
39
+ - React 18+ and 19+ support
40
+ - React Native Reanimated 3+ for smooth animations
41
+ - Expo compatibility
42
+ - Metro bundler support
43
+ - Next.js 14+ support
44
+ - Web platform support via react-native-web
45
+ - Node.js 18+ support
46
+
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CleanHaus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,275 @@
1
+ # cleanhaus-calendar
2
+
3
+ A production-ready, cross-platform calendar component for React Native and Next.js. Features Month, Week, and Day views with horizontal time positioning and multi-day event spanning.
4
+
5
+ ## 🚀 Platform Support
6
+
7
+ - ✅ **React Native** (iOS/Android)
8
+ - ✅ **Next.js** (Web with react-native-web)
9
+
10
+ ## 📦 Installation
11
+
12
+ ```bash
13
+ npm install cleanhaus-calendar
14
+ ```
15
+
16
+ ### Peer Dependencies
17
+
18
+ ```bash
19
+ npm install react react-native react-native-web react-native-reanimated dayjs calendarize
20
+ ```
21
+
22
+ **Requirements:**
23
+ - `react`: >=18.0.0 (supports React 18 & 19)
24
+ - `react-native`: >=0.70.0
25
+ - `react-native-web`: >=0.19.0
26
+ - `react-native-reanimated`: >=3.0.0
27
+ - `dayjs`: ^1.11.0
28
+ - `calendarize`: ^1.1.0
29
+ - `node`: >=18.0.0
30
+
31
+ ## ⚙️ Setup
32
+
33
+ ### React Native (Expo/RN)
34
+
35
+ No additional configuration needed! Just install and use:
36
+
37
+ ```tsx
38
+ import { Calendar, CalendarEvent } from "cleanhaus-calendar";
39
+
40
+ const events: CalendarEvent[] = [
41
+ {
42
+ id: "1",
43
+ eventId: "property-1",
44
+ title: "Booking",
45
+ start: new Date(2025, 0, 15, 10, 0),
46
+ end: new Date(2025, 0, 20, 14, 0),
47
+ meta: { type: "property" },
48
+ },
49
+ ];
50
+
51
+ <Calendar
52
+ events={events}
53
+ view="month"
54
+ date={new Date()}
55
+ onDateChange={setDate}
56
+ onEventPress={(event) => console.log(event)}
57
+ />
58
+ ```
59
+
60
+ ### Next.js Setup
61
+
62
+ **1. Install dependencies:**
63
+ ```bash
64
+ npm install cleanhaus-calendar react react-native react-native-web react-native-reanimated dayjs calendarize
65
+ ```
66
+
67
+ **2. Update `next.config.ts`:**
68
+ ```typescript
69
+ import type { NextConfig } from "next";
70
+
71
+ const withCalendar = require("cleanhaus-calendar/next-plugin");
72
+
73
+ const nextConfig: NextConfig = {
74
+ // Your existing config
75
+ };
76
+
77
+ export default withCalendar(nextConfig);
78
+ ```
79
+
80
+ **3. Update `package.json` dev script (Next.js 16+):**
81
+ ```json
82
+ {
83
+ "scripts": {
84
+ "dev": "next dev --webpack"
85
+ }
86
+ }
87
+ ```
88
+
89
+ **4. Use the component:**
90
+ ```tsx
91
+ "use client"; // Required for App Router
92
+
93
+ import { Calendar, CalendarEvent } from "cleanhaus-calendar";
94
+ import { useState } from "react";
95
+
96
+ export default function MyPage() {
97
+ const [view, setView] = useState<ViewMode>("month");
98
+ const [date, setDate] = useState(new Date());
99
+
100
+ return (
101
+ <Calendar
102
+ events={events}
103
+ view={view}
104
+ date={date}
105
+ onDateChange={setDate}
106
+ onEventPress={(event) => console.log(event)}
107
+ onViewChange={setView}
108
+ />
109
+ );
110
+ }
111
+ ```
112
+
113
+ **Note:** Next.js 16+ uses Turbopack by default. The plugin requires webpack, so use `--webpack` flag.
114
+
115
+ ## 📖 Usage
116
+
117
+ ### Basic Example
118
+
119
+ ```tsx
120
+ import { Calendar, CalendarEvent, ViewMode } from "cleanhaus-calendar";
121
+ import { useState } from "react";
122
+
123
+ const events: CalendarEvent[] = [
124
+ {
125
+ id: "1",
126
+ eventId: "property-1",
127
+ title: "Booking",
128
+ start: new Date(2025, 0, 15, 10, 0),
129
+ end: new Date(2025, 0, 20, 14, 0),
130
+ meta: { type: "property" },
131
+ },
132
+ ];
133
+
134
+ function MyCalendar() {
135
+ const [view, setView] = useState<ViewMode>("month");
136
+ const [date, setDate] = useState(new Date());
137
+
138
+ return (
139
+ <Calendar
140
+ events={events}
141
+ view={view}
142
+ date={date}
143
+ onDateChange={setDate}
144
+ onEventPress={(event) => console.log(event)}
145
+ onViewChange={setView}
146
+ />
147
+ );
148
+ }
149
+ ```
150
+
151
+ ### Custom Cleaning Icon
152
+
153
+ The package includes a default sparkle icon (✨) for cleaning events. Override it:
154
+
155
+ ```tsx
156
+ import sparksIcon from "./assets/sparks.png";
157
+
158
+ <Calendar
159
+ events={events}
160
+ cleaningIcon={sparksIcon} // Optional: custom icon
161
+ // ... other props
162
+ />
163
+ ```
164
+
165
+ ## 🔄 Data Format
166
+
167
+ Events must follow this structure:
168
+
169
+ ```typescript
170
+ interface CalendarEvent {
171
+ id: string; // Required: Unique identifier
172
+ eventId: string; // Required: Group identifier (e.g., "property-1")
173
+ title: string; // Required: Event title
174
+ start: Date; // Required: Must be Date object (not string!)
175
+ end: Date; // Required: Must be Date object (not string!)
176
+ meta?: {
177
+ type?: "property" | "cleaning" | "service" | "otherService" | "unassigned";
178
+ jobTypeId?: number; // For cleaning: 1 = cleaning, 2-4 = service types
179
+ [key: string]: any;
180
+ };
181
+ }
182
+ ```
183
+
184
+ ### Transform API Data
185
+
186
+ ```typescript
187
+ // Transform API response to CalendarEvent format
188
+ function transformApiEvents(apiData: ApiEvent[]): CalendarEvent[] {
189
+ return apiData.map((item) => ({
190
+ id: item.id.toString(),
191
+ eventId: `entity-${item.entityId}`,
192
+ title: item.name,
193
+ start: new Date(item.startTime), // Convert ISO string to Date
194
+ end: new Date(item.endTime), // Convert ISO string to Date
195
+ meta: {
196
+ type: item.type as CalendarEvent["meta"]["type"],
197
+ },
198
+ }));
199
+ }
200
+ ```
201
+
202
+ **Important:** Always convert date strings to `Date` objects. The component does not accept string dates.
203
+
204
+ ## 🎯 Key Props
205
+
206
+ | Prop | Type | Required | Description |
207
+ |------|------|----------|-------------|
208
+ | `events` | `CalendarEvent[]` | Yes | Array of events |
209
+ | `view` | `"month" \| "week" \| "day"` | No | View mode (default: `"month"`) |
210
+ | `date` | `Date` | Yes | Current date/month |
211
+ | `onDateChange` | `(date: Date) => void` | Yes | Date navigation handler |
212
+ | `onEventPress` | `(event: CalendarEvent) => void` | Yes | Event press handler |
213
+ | `onViewChange` | `(view: ViewMode) => void` | No | View mode change handler |
214
+ | `cleaningIcon` | `any` | No | Custom icon for cleaning events |
215
+ | `theme` | `CalendarTheme` | No | Custom theme |
216
+ | `availableProperties` | `Property[]` | No | Properties for color assignment |
217
+
218
+ See [full props reference](#props-reference) below.
219
+
220
+ ## 🎨 Features
221
+
222
+ - **Month View**: Calendar grid with event bars and swipe navigation
223
+ - **Week View**: 7-day view with time-based positioning
224
+ - **Day View**: Single-day view with property lanes
225
+ - **Multi-day Events**: Continuous bars across day cells
226
+ - **Type-based Rendering**: Different styles for property, cleaning, service events
227
+ - **Built-in Assets**: Default sparkle icon (✨) for cleaning events
228
+
229
+ ## 🐛 Troubleshooting
230
+
231
+ ### Events not appearing
232
+ - ✅ Ensure `start` and `end` are `Date` objects (not strings)
233
+ - ✅ Check `eventId` is set correctly
234
+ - ✅ Verify `containerHeight` is sufficient (minimum 400px)
235
+
236
+ ### Next.js Issues
237
+
238
+ **Module not found:**
239
+ - ✅ Restart dev server: `npm run dev -- --webpack`
240
+ - ✅ Clear cache: `rm -rf .next`
241
+
242
+ **Element type is invalid:**
243
+ - ✅ Ensure `--webpack` flag is used
244
+ - ✅ Verify `react-native-web` is installed
245
+
246
+ **Turbopack error:**
247
+ - ✅ Use `npm run dev -- --webpack`
248
+ - ✅ Or add `turbopack: {}` to `next.config.ts`
249
+
250
+ ## 📚 Props Reference
251
+
252
+ ### Calendar Props
253
+
254
+ | Prop | Type | Required | Default | Description |
255
+ |------|------|----------|---------|-------------|
256
+ | `events` | `CalendarEvent[]` | Yes | - | Array of events |
257
+ | `view` | `ViewMode` | No | `"month"` | View mode |
258
+ | `date` | `Date` | Yes | - | Current date |
259
+ | `onDateChange` | `(date: Date) => void` | Yes | - | Date change handler |
260
+ | `onEventPress` | `(event: CalendarEvent) => void` | Yes | - | Event press handler |
261
+ | `onViewChange` | `(view: ViewMode) => void` | No | - | View change handler |
262
+ | `isLoading` | `boolean` | No | `false` | Show loading spinner |
263
+ | `theme` | `CalendarTheme` | No | - | Custom theme |
264
+ | `availableProperties` | `Property[]` | No | - | Properties for colors |
265
+ | `cleaningIcon` | `any` | No | - | Custom cleaning icon |
266
+ | `showFAB` | `boolean` | No | `false` | Show floating action button |
267
+ | `autoScrollToNow` | `boolean` | No | `false` | Auto-scroll to current time |
268
+
269
+ ## 📄 License
270
+
271
+ MIT
272
+
273
+ ---
274
+
275
+ **Version**: 1.0.0
package/next-plugin.js ADDED
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Next.js Plugin for cleanhaus-calendar
3
+ *
4
+ * Auto-configures Next.js webpack and transpilation for React Native Web compatibility.
5
+ *
6
+ * Usage in next.config.js:
7
+ * ```javascript
8
+ * const withCalendar = require('cleanhaus-calendar/next-plugin');
9
+ *
10
+ * module.exports = withCalendar({
11
+ * // Your existing Next.js config
12
+ * });
13
+ * ```
14
+ */
15
+
16
+ const withCalendar = (nextConfig = {}) => {
17
+ return {
18
+ ...nextConfig,
19
+ webpack: (config, options) => {
20
+ // Apply existing webpack config if any
21
+ const existingWebpack = nextConfig.webpack || ((c) => c);
22
+ config = existingWebpack(config, options);
23
+
24
+ // Add React Native Web alias
25
+ if (!config.resolve) {
26
+ config.resolve = {};
27
+ }
28
+ if (!config.resolve.alias) {
29
+ config.resolve.alias = {};
30
+ }
31
+
32
+ config.resolve.alias = {
33
+ ...config.resolve.alias,
34
+ "react-native$": "react-native-web",
35
+ };
36
+
37
+ // Handle React Native asset extensions
38
+ if (!config.resolve.extensions) {
39
+ config.resolve.extensions = [];
40
+ }
41
+
42
+ // Add React Native extensions if not already present
43
+ const extensions = [
44
+ ".web.js",
45
+ ".web.jsx",
46
+ ".web.ts",
47
+ ".web.tsx",
48
+ ...config.resolve.extensions,
49
+ ];
50
+ config.resolve.extensions = [...new Set(extensions)];
51
+
52
+ // Handle image assets - ensure node_modules are processed
53
+ if (!config.module) {
54
+ config.module = {};
55
+ }
56
+ if (!config.module.rules) {
57
+ config.module.rules = [];
58
+ }
59
+
60
+ // Find existing asset rule
61
+ const assetRuleIndex = config.module.rules.findIndex(
62
+ (rule) =>
63
+ rule && rule.test && rule.test.toString().includes("png|jpg|jpeg")
64
+ );
65
+
66
+ if (assetRuleIndex === -1) {
67
+ // Add new asset rule at the beginning to ensure it processes images
68
+ config.module.rules.unshift({
69
+ test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
70
+ type: "asset/resource",
71
+ // Explicitly include node_modules/cleanhaus-calendar
72
+ include: [/node_modules\/cleanhaus-calendar/],
73
+ });
74
+ } else {
75
+ // Update existing rule to include node_modules
76
+ const existingRule = config.module.rules[assetRuleIndex];
77
+ if (existingRule) {
78
+ // Ensure it includes our package
79
+ if (!existingRule.include) {
80
+ existingRule.include = [/node_modules\/cleanhaus-calendar/];
81
+ } else if (Array.isArray(existingRule.include)) {
82
+ if (!existingRule.include.some((inc) =>
83
+ inc.toString().includes("cleanhaus-calendar")
84
+ )) {
85
+ existingRule.include.push(/node_modules\/cleanhaus-calendar/);
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ return config;
92
+ },
93
+ transpilePackages: [
94
+ ...(nextConfig.transpilePackages || []),
95
+ "cleanhaus-calendar",
96
+ ],
97
+ };
98
+ };
99
+
100
+ module.exports = withCalendar;
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "cleanhaus-calendar",
3
+ "version": "1.0.0",
4
+ "description": "Cross-platform calendar component for React Native and Web",
5
+ "main": "src/index.ts",
6
+ "types": "src/index.ts",
7
+ "react-native": "src/index.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./src/index.ts",
11
+ "react-native": "./src/index.ts",
12
+ "import": "./src/index.ts",
13
+ "require": "./src/index.ts",
14
+ "default": "./src/index.ts"
15
+ },
16
+ "./next-plugin": "./next-plugin.js",
17
+ "./package.json": "./package.json"
18
+ },
19
+ "files": [
20
+ "**/*.ts",
21
+ "**/*.tsx",
22
+ "shared/**/*.png",
23
+ "README.md",
24
+ "LICENSE",
25
+ "CHANGELOG.md",
26
+ "next-plugin.js",
27
+ "!**/*.test.ts",
28
+ "!**/*.test.tsx",
29
+ "!**/*.spec.ts",
30
+ "!**/*.spec.tsx",
31
+ "!node_modules",
32
+ "!dist"
33
+ ],
34
+ "scripts": {
35
+ "build": "tsup",
36
+ "type-check": "tsc --noEmit",
37
+ "prepublishOnly": "npm run type-check"
38
+ },
39
+ "keywords": [
40
+ "react-native",
41
+ "calendar",
42
+ "web",
43
+ "cross-platform",
44
+ "expo",
45
+ "typescript",
46
+ "cleanhaus"
47
+ ],
48
+ "author": "CleanHaus",
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/cleanhaus/calendar-component.git"
53
+ },
54
+ "peerDependencies": {
55
+ "calendarize": "^1.1.0",
56
+ "dayjs": "^1.11.0",
57
+ "react": ">=18.0.0",
58
+ "react-native": ">=0.70.0",
59
+ "react-native-reanimated": ">=3.0.0",
60
+ "react-native-web": ">=0.19.0"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "react-native-web": {
64
+ "optional": true
65
+ },
66
+ "react-native-reanimated": {
67
+ "optional": true
68
+ }
69
+ },
70
+ "devDependencies": {
71
+ "@types/node": "^18.0.0 || ^20.0.0 || ^22.0.0",
72
+ "@types/react": "^18.0.0 || ^19.0.0",
73
+ "@types/react-native": "^0.73.0",
74
+ "tsup": "^8.5.1",
75
+ "typescript": "^5.0.0"
76
+ },
77
+ "engines": {
78
+ "node": ">=18.0.0"
79
+ }
80
+ }