expo-calendar-2k 1.0.2

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 (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/android/build.gradle +18 -0
  4. package/android/src/main/AndroidManifest.xml +2 -0
  5. package/android/src/main/java/expo/modules/calendar2k/Calendar2kModule.kt +15 -0
  6. package/android/src/main/java/expo/modules/calendar2k/Calendar2kView.kt +26 -0
  7. package/build/Calendar2k.types.d.ts +38 -0
  8. package/build/Calendar2k.types.js +2 -0
  9. package/build/Calendar2kModule.d.ts +8 -0
  10. package/build/Calendar2kModule.js +10 -0
  11. package/build/Calendar2kModule.web.d.ts +6 -0
  12. package/build/Calendar2kModule.web.js +26 -0
  13. package/build/Calendar2kView.d.ts +4 -0
  14. package/build/Calendar2kView.js +366 -0
  15. package/build/Calendar2kView.web.d.ts +3 -0
  16. package/build/Calendar2kView.web.js +49 -0
  17. package/build/assets/assets/images/calendar.png +0 -0
  18. package/build/assets/assets/images/chevron-left.png +0 -0
  19. package/build/assets/assets/images/chevron-right.png +0 -0
  20. package/build/assets/assets/images/clock.png +0 -0
  21. package/build/assets/assets/images/swipe.png +0 -0
  22. package/build/assets/images/calendar.png +0 -0
  23. package/build/assets/images/chevron-left.png +0 -0
  24. package/build/assets/images/chevron-right.png +0 -0
  25. package/build/assets/images/clock.png +0 -0
  26. package/build/assets/images/swipe.png +0 -0
  27. package/build/components/ArrowButton.d.ts +8 -0
  28. package/build/components/ArrowButton.js +19 -0
  29. package/build/components/Backdrop.d.ts +5 -0
  30. package/build/components/Backdrop.js +25 -0
  31. package/build/components/DayLabel.d.ts +6 -0
  32. package/build/components/DayLabel.js +16 -0
  33. package/build/components/Icon.d.ts +6 -0
  34. package/build/components/Icon.js +16 -0
  35. package/build/components/SwipeIcon.d.ts +5 -0
  36. package/build/components/SwipeIcon.js +8 -0
  37. package/build/components/Time.d.ts +11 -0
  38. package/build/components/Time.js +95 -0
  39. package/build/components/TimeView.d.ts +10 -0
  40. package/build/components/TimeView.js +25 -0
  41. package/build/hooks/useCalendarDisclose.d.ts +4 -0
  42. package/build/hooks/useCalendarDisclose.js +9 -0
  43. package/build/libs/format.d.ts +4 -0
  44. package/build/libs/format.js +52 -0
  45. package/build/libs/formatNb.d.ts +1 -0
  46. package/build/libs/formatNb.js +6 -0
  47. package/build/libs/getDayMatrix.d.ts +1 -0
  48. package/build/libs/getDayMatrix.js +74 -0
  49. package/build/libs/getStatus.d.ts +14 -0
  50. package/build/libs/getStatus.js +37 -0
  51. package/build/libs/getStyle.d.ts +14 -0
  52. package/build/libs/getStyle.js +35 -0
  53. package/build/libs/isActive.d.ts +8 -0
  54. package/build/libs/isActive.js +17 -0
  55. package/build/libs/isToday.d.ts +1 -0
  56. package/build/libs/isToday.js +9 -0
  57. package/build/libs/resetTime.d.ts +1 -0
  58. package/build/libs/resetTime.js +6 -0
  59. package/build/libs/toHexColor.d.ts +1 -0
  60. package/build/libs/toHexColor.js +13 -0
  61. package/build/ui/index.d.ts +15 -0
  62. package/build/ui/index.js +35 -0
  63. package/expo-module.config.json +9 -0
  64. package/ios/Calendar2k.podspec +23 -0
  65. package/ios/Calendar2kModule.swift +12 -0
  66. package/ios/Calendar2kView.swift +18 -0
  67. package/package.json +53 -0
  68. package/src/Calendar2k.types.ts +40 -0
  69. package/src/Calendar2kModule.ts +9 -0
  70. package/src/Calendar2kModule.web.ts +7 -0
  71. package/src/Calendar2kView.tsx +416 -0
  72. package/src/Calendar2kView.web.tsx +19 -0
  73. package/src/assets/images/calendar.png +0 -0
  74. package/src/assets/images/chevron-left.png +0 -0
  75. package/src/assets/images/chevron-right.png +0 -0
  76. package/src/assets/images/clock.png +0 -0
  77. package/src/assets/images/swipe.png +0 -0
  78. package/src/components/ArrowButton.tsx +40 -0
  79. package/src/components/Backdrop.tsx +31 -0
  80. package/src/components/DayLabel.tsx +20 -0
  81. package/src/components/Icon.tsx +24 -0
  82. package/src/components/SwipeIcon.tsx +13 -0
  83. package/src/components/Time.tsx +93 -0
  84. package/src/components/TimeView.tsx +64 -0
  85. package/src/hooks/useCalendarDisclose.ts +9 -0
  86. package/src/libs/format.ts +57 -0
  87. package/src/libs/formatNb.ts +3 -0
  88. package/src/libs/getDayMatrix.ts +73 -0
  89. package/src/libs/getStatus.ts +47 -0
  90. package/src/libs/getStyle.ts +53 -0
  91. package/src/libs/isActive.ts +20 -0
  92. package/src/libs/isToday.ts +9 -0
  93. package/src/libs/resetTime.ts +3 -0
  94. package/src/libs/toHexColor.ts +13 -0
  95. package/src/ui/index.tsx +51 -0
  96. package/tsconfig.json +22 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
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.
package/README.md ADDED
@@ -0,0 +1,267 @@
1
+ # calendar-2k
2
+
3
+ The fastest fully customizable Expo date & time picker, written in TypeScript, supporting Expo Go, single date, time, date range, time range, datetime range selection, flexible date disabling, and dynamic color theming for iOS and Android.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - 📅 **Date picker** — single date selection
10
+ - 🕐 **Time picker** — single time selection
11
+ - 📆 **Date range picker** — select a start and end date
12
+ - ⏱️ **Time range picker** — select a start and end time
13
+ - 🗓️ **Datetime & datetime range** — combined date and time selection
14
+ - 🚫 **Flexible date disabling** — disable specific days by custom logic
15
+ - 🎨 **Dynamic color theming** — fully customizable accent color
16
+ - 💙 **Expo Go support** — works out of the box with Expo Go
17
+ - 📘 **Fully written in TypeScript**
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npx expo install calendar-2k
25
+ ```
26
+
27
+ ---
28
+
29
+ ## Usage
30
+
31
+ ### Example 1 — Date Picker
32
+
33
+ Single date selection with disabled days (Sunday, Wednesday, Saturday).
34
+
35
+ ```tsx
36
+ import { DateValueType } from "calendar-2k";
37
+ import Calendar2kView from "calendar-2k";
38
+ import { useState } from "react";
39
+
40
+ export default function App() {
41
+ const [date, setDate] = useState<DateValueType>(new Date());
42
+
43
+ return (
44
+ <Calendar2kView
45
+ onChangeDate={setDate}
46
+ value={date}
47
+ mode="date"
48
+ color="black"
49
+ disableDate={(date) => [0, 3, 6].includes(date.getDay())}
50
+ />
51
+ );
52
+ }
53
+ ```
54
+
55
+ ---
56
+
57
+ ### Example 2 — Datetime Picker
58
+
59
+ Combined date and time selection in a single picker.
60
+
61
+ ```tsx
62
+ import { DateValueType } from "calendar-2k";
63
+ import Calendar2kView from "calendar-2k";
64
+ import { useState } from "react";
65
+
66
+ export default function App() {
67
+ const [date, setDate] = useState<DateValueType>(new Date());
68
+
69
+ return (
70
+ <Calendar2kView
71
+ onChangeDate={setDate}
72
+ value={date}
73
+ mode="datetime"
74
+ color="black"
75
+ disableDate={(date) => [0, 3, 6].includes(date.getDay())}
76
+ />
77
+ );
78
+ }
79
+ ```
80
+
81
+ ---
82
+
83
+ ### Example 3 — Datetime Range Picker
84
+
85
+ Select a start and end datetime, useful for bookings and reservations.
86
+
87
+ ```tsx
88
+ import { DateValueType } from "calendar-2k";
89
+ import Calendar2kView from "calendar-2k";
90
+ import { useState } from "react";
91
+
92
+ export default function App() {
93
+ const [date, setDate] = useState<DateValueType>({
94
+ start: new Date(),
95
+ end: new Date(),
96
+ });
97
+
98
+ return (
99
+ <Calendar2kView
100
+ onChangeDate={setDate}
101
+ value={date}
102
+ mode="datetime"
103
+ color="black"
104
+ disableDate={(date) => [0, 3, 6].includes(date.getDay())}
105
+ />
106
+ );
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ### Example 4 — Time Range Picker
113
+
114
+ Select a start and end time, useful for timetable.
115
+
116
+ ```tsx
117
+ import { DateValueType } from "calendar-2k";
118
+ import Calendar2kView from "calendar-2k";
119
+ import { useState } from "react";
120
+
121
+ export default function App() {
122
+ const [date, setDate] = useState<DateValueType>({
123
+ start: new Date(),
124
+ end: new Date(),
125
+ });
126
+
127
+ return (
128
+ <Calendar2kView
129
+ onChangeDate={setDate}
130
+ value={date}
131
+ mode="time"
132
+ color="black"
133
+ />
134
+ );
135
+ }
136
+ ```
137
+
138
+ ---
139
+
140
+ ## Props
141
+
142
+ | Prop | Type | Required | Description |
143
+ | --------------- | ------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------- |
144
+ | `onChangeDate` | `(value: DateValueType) => void` | ❌ | Callback fired when the user selects a date or range |
145
+ | `value` | `DateValueType` | ❌ | Current selected value — a `Date` or `{ start: Date, end: Date }` object |
146
+ | `locales` | `Intl.LocalesArgument` | ❌ | Locale for displaying month/day names and time format (e.g. `"fr"`, `"en-US"`). Defaults to device locale |
147
+ | `mode` | `"date" \| "time" \| "datetime"` | ❌ | Picker mode |
148
+ | `color` | `string` | ❌ | Accent color for the picker UI (any valid CSS/RN color) |
149
+ | `min` | `Date` | ❌ | Earliest selectable date — all dates before this are automatically disabled |
150
+ | `max` | `Date` | ❌ | Latest selectable date — all dates after this are automatically disabled |
151
+ | `disableDate` | `(date: Date) => boolean` | ❌ | Function to disable specific dates — return `true` to disable |
152
+ | `placeholder` | `string` | ❌ | Text shown in the trigger button when no date is selected yet |
153
+ | `customTrigger` | `(onToggle: () => void) => React.ReactNode` | ❌ | Custom element to replace the default trigger button |
154
+ | `disabled` | `boolean` | ❌ | Disables the entire picker — the trigger becomes non-interactive |
155
+
156
+ ---
157
+
158
+ ## Types
159
+
160
+ ```ts
161
+ // Single date or datetime
162
+ type DateValueType = Date | { start: Date; end: Date };
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Working with the Selected Value
168
+
169
+ `DateValueType` is a standard JavaScript `Date` object (or a pair of them for ranges). Use the built-in `Date` methods to extract any part of the selected value:
170
+
171
+ ```tsx
172
+ const date = new Date("2025-06-15T14:30:00");
173
+
174
+ date.getFullYear(); // 2025
175
+ date.getMonth(); // 5 (0-indexed, so 5 = June)
176
+ date.getDate(); // 15
177
+ date.getDay(); // 0–6 (day of the week, 0 = Sunday)
178
+ date.getHours(); // 14
179
+ date.getMinutes(); // 30
180
+ date.getSeconds(); // 0
181
+ date.toISOString(); // "2025-06-15T14:30:00.000Z"
182
+ date.toLocaleDateString(); // "6/15/2025" (format depends on locale)
183
+ date.toLocaleTimeString(); // "2:30:00 PM"
184
+ ```
185
+
186
+ For range values, access each bound separately:
187
+
188
+ ```tsx
189
+ const [date, setDate] = useState<DateValueType>({
190
+ start: new Date(),
191
+ end: new Date(),
192
+ });
193
+
194
+ if (date && "start" in date) {
195
+ date.start.getDate(); // start day
196
+ date.end.getFullYear(); // end year
197
+ }
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Modes
203
+
204
+ | Mode | `value` type | Description |
205
+ | ---------- | -------------------------- | ------------------------- |
206
+ | `date` | `Date` or `{ start, end }` | Pick a date or a range |
207
+ | `time` | `Date` or `{ start, end }` | Pick a time or a range |
208
+ | `datetime` | `Date` or `{ start, end }` | Pick date+time or a range |
209
+
210
+ ---
211
+
212
+ ## Disabling Dates
213
+
214
+ Pass a function to `disableDate` that receives a `Date` and returns `true` to disable it:
215
+
216
+ ```tsx
217
+ // Disable weekends (Saturday = 6, Sunday = 0)
218
+ disableDate={(date) => [0, 6].includes(date.getDay())}
219
+
220
+ // Disable past dates
221
+ disableDate={(date) => date < new Date()}
222
+
223
+ // Disable a specific date
224
+ disableDate={(date) => date.toDateString() === new Date("2025-12-25").toDateString()}
225
+ ```
226
+
227
+ You can also use `min` and `max` for simpler range-based disabling:
228
+
229
+ ```tsx
230
+ // Only allow dates in 2025
231
+ <Calendar2kView
232
+ min={new Date("2025-01-01")}
233
+ max={new Date("2025-12-31")}
234
+ ...
235
+ />
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Platform Support
241
+
242
+ | Platform | Supported |
243
+ | -------- | -------------- |
244
+ | iOS | ✅ |
245
+ | Android | ✅ |
246
+ | Expo Go | ✅ |
247
+ | Web | 🚧 Coming soon |
248
+
249
+ ---
250
+
251
+ ## Support & Donation
252
+
253
+ If **calendar-2k** saved you time, consider buying me a coffee! ☕
254
+ Your support helps me maintain this project and build more free open-source tools. 🙏
255
+
256
+ ### 💛 Donate via Orange Money (Madagascar)
257
+
258
+ > Send your donation directly to my Orange Money number:
259
+ >
260
+ > **📱 +261 37 654 4250**
261
+ > Or Mvola **📱 +261 34 68 814 74**
262
+ > Or Arteil Money **📱 +261 33 36 613 20**
263
+ > _Any amount is deeply appreciated!_ 🤝
264
+
265
+ ---
266
+
267
+ MIT
@@ -0,0 +1,18 @@
1
+ plugins {
2
+ id 'com.android.library'
3
+ id 'expo-module-gradle-plugin'
4
+ }
5
+
6
+ group = 'expo.modules.calendar2k'
7
+ version = '0.1.0'
8
+
9
+ android {
10
+ namespace "expo.modules.calendar2k"
11
+ defaultConfig {
12
+ versionCode 1
13
+ versionName "0.1.0"
14
+ }
15
+ lintOptions {
16
+ abortOnError false
17
+ }
18
+ }
@@ -0,0 +1,2 @@
1
+ <manifest>
2
+ </manifest>
@@ -0,0 +1,15 @@
1
+ package expo.modules.calendar2k
2
+
3
+ import expo.modules.kotlin.modules.Module
4
+ import expo.modules.kotlin.modules.ModuleDefinition
5
+
6
+ class Calendar2kModule : Module() {
7
+ override fun definition() = ModuleDefinition {
8
+ Name("Calendar2k")
9
+
10
+ Events("onChange")
11
+
12
+ View(Calendar2kView::class) {
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,26 @@
1
+ package expo.modules.calendar2k
2
+
3
+ import android.content.Context
4
+ import android.graphics.Color
5
+ import android.view.Gravity
6
+ import android.widget.LinearLayout
7
+ import android.widget.TextView
8
+ import expo.modules.kotlin.AppContext
9
+ import expo.modules.kotlin.views.ExpoView
10
+
11
+ class Calendar2kView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
12
+ init {
13
+ val container = LinearLayout(context).apply {
14
+ layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
15
+ orientation = LinearLayout.VERTICAL
16
+ gravity = Gravity.CENTER
17
+ setBackgroundColor(Color.parseColor("#aabbcc"))
18
+ }
19
+ val label = TextView(context).apply {
20
+ text = "Calendar2k - native view"
21
+ gravity = Gravity.CENTER
22
+ }
23
+ container.addView(label)
24
+ addView(container)
25
+ }
26
+ }
@@ -0,0 +1,38 @@
1
+ export type Calendar2kModuleEvents = {
2
+ onChange: (params: ChangeEventPayload) => void;
3
+ };
4
+ export type ChangeEventPayload = {
5
+ value: string;
6
+ };
7
+ export type OnTapEventPayload = Record<string, never>;
8
+ export type Calendar2kViewProps = {
9
+ onChangeDate?: (date: DateValueType) => void;
10
+ value?: DateValueType;
11
+ locales?: Intl.LocalesArgument;
12
+ mode?: "date" | "time" | "datetime";
13
+ color?: string;
14
+ min?: Date;
15
+ max?: Date;
16
+ disableDate?: (date: Date) => boolean;
17
+ placeholder?: string;
18
+ customTrigger?: (onToggle: () => void) => React.ReactNode;
19
+ disabled?: boolean;
20
+ };
21
+ export type DayColumnProps = {
22
+ label: string;
23
+ dayNumber: number;
24
+ };
25
+ export type DayProps = {
26
+ date: Date;
27
+ };
28
+ export type TimeType = `${number}${number}:${number}${number}:${number}${number}`;
29
+ export type TimeRangeType = {
30
+ start: TimeType;
31
+ end?: TimeType;
32
+ };
33
+ export type DateRangeType = {
34
+ start: Date;
35
+ end?: Date;
36
+ };
37
+ export type DateValueType = Date | DateRangeType | TimeType | TimeRangeType;
38
+ export type DateStateType = Date | DateRangeType;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,8 @@
1
+ import { NativeModule } from "expo";
2
+ import { Calendar2kModuleEvents } from "./Calendar2k.types";
3
+ declare class Calendar2kModule extends NativeModule<Calendar2kModuleEvents> {
4
+ }
5
+ declare const _default: Calendar2kModule;
6
+ export default _default;
7
+ export type { DateValueType } from "./Calendar2k.types";
8
+ export { default as Calendar2kView } from "./Calendar2kView";
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Calendar2kView = void 0;
7
+ var expo_1 = require("expo");
8
+ exports.default = (0, expo_1.requireNativeModule)("Calendar2k");
9
+ var Calendar2kView_1 = require("./Calendar2kView");
10
+ Object.defineProperty(exports, "Calendar2kView", { enumerable: true, get: function () { return __importDefault(Calendar2kView_1).default; } });
@@ -0,0 +1,6 @@
1
+ import { NativeModule } from 'expo';
2
+ import { Calendar2kModuleEvents } from './Calendar2k.types';
3
+ declare class Calendar2kModule extends NativeModule<Calendar2kModuleEvents> {
4
+ }
5
+ declare const _default: typeof Calendar2kModule;
6
+ export default _default;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __extends = (this && this.__extends) || (function () {
3
+ var extendStatics = function (d, b) {
4
+ extendStatics = Object.setPrototypeOf ||
5
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
+ return extendStatics(d, b);
8
+ };
9
+ return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
12
+ extendStatics(d, b);
13
+ function __() { this.constructor = d; }
14
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
15
+ };
16
+ })();
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ var expo_1 = require("expo");
19
+ var Calendar2kModule = /** @class */ (function (_super) {
20
+ __extends(Calendar2kModule, _super);
21
+ function Calendar2kModule() {
22
+ return _super !== null && _super.apply(this, arguments) || this;
23
+ }
24
+ return Calendar2kModule;
25
+ }(expo_1.NativeModule));
26
+ exports.default = (0, expo_1.registerWebModule)(Calendar2kModule, 'Calendar2kModule');
@@ -0,0 +1,4 @@
1
+ import * as React from "react";
2
+ import { type Calendar2kViewProps, type DateValueType } from "./Calendar2k.types";
3
+ export default function Calendar2kView({ onChangeDate, value, locales, color, min, max, disableDate, placeholder, customTrigger, mode, disabled, }: Calendar2kViewProps): React.JSX.Element;
4
+ export type { Calendar2kViewProps, DateValueType };