expo-2k-datetime-picker 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.
- package/LICENSE +21 -0
- package/README.md +267 -0
- package/android/build.gradle +18 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/calendar2k/Calendar2kModule.kt +15 -0
- package/android/src/main/java/expo/modules/calendar2k/Calendar2kView.kt +26 -0
- package/build/Calendar2k.types.d.ts +38 -0
- package/build/Calendar2k.types.js +2 -0
- package/build/Calendar2kModule.d.ts +8 -0
- package/build/Calendar2kModule.js +10 -0
- package/build/Calendar2kModule.web.d.ts +6 -0
- package/build/Calendar2kModule.web.js +26 -0
- package/build/Calendar2kView.d.ts +4 -0
- package/build/Calendar2kView.js +366 -0
- package/build/Calendar2kView.web.d.ts +3 -0
- package/build/Calendar2kView.web.js +49 -0
- package/build/assets/assets/images/calendar.png +0 -0
- package/build/assets/assets/images/chevron-left.png +0 -0
- package/build/assets/assets/images/chevron-right.png +0 -0
- package/build/assets/assets/images/clock.png +0 -0
- package/build/assets/assets/images/swipe.png +0 -0
- package/build/assets/images/calendar.png +0 -0
- package/build/assets/images/chevron-left.png +0 -0
- package/build/assets/images/chevron-right.png +0 -0
- package/build/assets/images/clock.png +0 -0
- package/build/assets/images/swipe.png +0 -0
- package/build/components/ArrowButton.d.ts +8 -0
- package/build/components/ArrowButton.js +19 -0
- package/build/components/Backdrop.d.ts +5 -0
- package/build/components/Backdrop.js +25 -0
- package/build/components/DayLabel.d.ts +6 -0
- package/build/components/DayLabel.js +16 -0
- package/build/components/Icon.d.ts +6 -0
- package/build/components/Icon.js +16 -0
- package/build/components/SwipeIcon.d.ts +5 -0
- package/build/components/SwipeIcon.js +8 -0
- package/build/components/Time.d.ts +11 -0
- package/build/components/Time.js +95 -0
- package/build/components/TimeView.d.ts +10 -0
- package/build/components/TimeView.js +25 -0
- package/build/hooks/useCalendarDisclose.d.ts +4 -0
- package/build/hooks/useCalendarDisclose.js +9 -0
- package/build/libs/format.d.ts +4 -0
- package/build/libs/format.js +52 -0
- package/build/libs/formatNb.d.ts +1 -0
- package/build/libs/formatNb.js +6 -0
- package/build/libs/getDayMatrix.d.ts +1 -0
- package/build/libs/getDayMatrix.js +74 -0
- package/build/libs/getStatus.d.ts +14 -0
- package/build/libs/getStatus.js +37 -0
- package/build/libs/getStyle.d.ts +14 -0
- package/build/libs/getStyle.js +35 -0
- package/build/libs/isActive.d.ts +8 -0
- package/build/libs/isActive.js +17 -0
- package/build/libs/isToday.d.ts +1 -0
- package/build/libs/isToday.js +9 -0
- package/build/libs/resetTime.d.ts +1 -0
- package/build/libs/resetTime.js +6 -0
- package/build/libs/toHexColor.d.ts +1 -0
- package/build/libs/toHexColor.js +13 -0
- package/build/ui/index.d.ts +15 -0
- package/build/ui/index.js +35 -0
- package/expo-module.config.json +9 -0
- package/ios/Calendar2k.podspec +23 -0
- package/ios/Calendar2kModule.swift +12 -0
- package/ios/Calendar2kView.swift +18 -0
- package/package.json +53 -0
- package/src/Calendar2k.types.ts +40 -0
- package/src/Calendar2kModule.ts +9 -0
- package/src/Calendar2kModule.web.ts +7 -0
- package/src/Calendar2kView.tsx +416 -0
- package/src/Calendar2kView.web.tsx +19 -0
- package/src/assets/images/calendar.png +0 -0
- package/src/assets/images/chevron-left.png +0 -0
- package/src/assets/images/chevron-right.png +0 -0
- package/src/assets/images/clock.png +0 -0
- package/src/assets/images/swipe.png +0 -0
- package/src/components/ArrowButton.tsx +40 -0
- package/src/components/Backdrop.tsx +31 -0
- package/src/components/DayLabel.tsx +20 -0
- package/src/components/Icon.tsx +24 -0
- package/src/components/SwipeIcon.tsx +13 -0
- package/src/components/Time.tsx +93 -0
- package/src/components/TimeView.tsx +64 -0
- package/src/hooks/useCalendarDisclose.ts +9 -0
- package/src/libs/format.ts +57 -0
- package/src/libs/formatNb.ts +3 -0
- package/src/libs/getDayMatrix.ts +73 -0
- package/src/libs/getStatus.ts +47 -0
- package/src/libs/getStyle.ts +53 -0
- package/src/libs/isActive.ts +20 -0
- package/src/libs/isToday.ts +9 -0
- package/src/libs/resetTime.ts +3 -0
- package/src/libs/toHexColor.ts +13 -0
- package/src/ui/index.tsx +51 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type Calendar2kModuleEvents = {
|
|
2
|
+
onChange: (params: ChangeEventPayload) => void;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
export type ChangeEventPayload = {
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type OnTapEventPayload = Record<string, never>;
|
|
10
|
+
|
|
11
|
+
export type Calendar2kViewProps = {
|
|
12
|
+
onChangeDate?: (date: DateValueType) => void;
|
|
13
|
+
value?: DateValueType;
|
|
14
|
+
locales?: Intl.LocalesArgument;
|
|
15
|
+
mode?: "date" | "time" | "datetime";
|
|
16
|
+
color?: string;
|
|
17
|
+
min?: Date;
|
|
18
|
+
max?: Date;
|
|
19
|
+
disableDate?: (date: Date) => boolean;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
customTrigger?: (onToggle: () => void) => React.ReactNode;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type DayColumnProps = {
|
|
26
|
+
label: string;
|
|
27
|
+
dayNumber: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type DayProps = {
|
|
31
|
+
date: Date;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type TimeType =
|
|
35
|
+
`${number}${number}:${number}${number}:${number}${number}`;
|
|
36
|
+
|
|
37
|
+
export type TimeRangeType = { start: TimeType; end?: TimeType };
|
|
38
|
+
export type DateRangeType = { start: Date; end?: Date };
|
|
39
|
+
export type DateValueType = Date | DateRangeType | TimeType | TimeRangeType;
|
|
40
|
+
export type DateStateType = Date | DateRangeType;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NativeModule, requireNativeModule } from "expo";
|
|
2
|
+
|
|
3
|
+
import { Calendar2kModuleEvents } from "./Calendar2k.types";
|
|
4
|
+
|
|
5
|
+
declare class Calendar2kModule extends NativeModule<Calendar2kModuleEvents> {}
|
|
6
|
+
|
|
7
|
+
export default requireNativeModule<Calendar2kModule>("Calendar2k");
|
|
8
|
+
export type { DateValueType } from "./Calendar2k.types";
|
|
9
|
+
export { default as Calendar2kView } from "./Calendar2kView";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { registerWebModule, NativeModule } from 'expo';
|
|
2
|
+
|
|
3
|
+
import { Calendar2kModuleEvents } from './Calendar2k.types';
|
|
4
|
+
|
|
5
|
+
class Calendar2kModule extends NativeModule<Calendar2kModuleEvents> {}
|
|
6
|
+
|
|
7
|
+
export default registerWebModule(Calendar2kModule, 'Calendar2kModule');
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { Modal, Pressable } from "react-native";
|
|
4
|
+
import { SafeAreaView } from "react-native-safe-area-context";
|
|
5
|
+
import ArrowButton from "./components/ArrowButton";
|
|
6
|
+
import Backdrop from "./components/Backdrop";
|
|
7
|
+
import DayLabel from "./components/DayLabel";
|
|
8
|
+
import Icon from "./components/Icon";
|
|
9
|
+
import SwipeIcon from "./components/SwipeIcon";
|
|
10
|
+
import Time from "./components/Time";
|
|
11
|
+
import TimeView from "./components/TimeView";
|
|
12
|
+
import useCalendarDisclose from "./hooks/useCalendarDisclose";
|
|
13
|
+
import { formatDate, formatMonth, getWeekDay } from "./libs/format";
|
|
14
|
+
import getDayMatrix from "./libs/getDayMatrix";
|
|
15
|
+
import getStyle from "./libs/getStyle";
|
|
16
|
+
import isActive from "./libs/isActive";
|
|
17
|
+
import { toHexColor } from "./libs/toHexColor";
|
|
18
|
+
import { KText, KTouchableOpacity, KView } from "./ui";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
DateStateType,
|
|
22
|
+
TimeType,
|
|
23
|
+
type Calendar2kViewProps,
|
|
24
|
+
type DateValueType,
|
|
25
|
+
type DayColumnProps,
|
|
26
|
+
type DayProps,
|
|
27
|
+
} from "./Calendar2k.types";
|
|
28
|
+
|
|
29
|
+
export default function Calendar2kView({
|
|
30
|
+
onChangeDate,
|
|
31
|
+
value,
|
|
32
|
+
locales,
|
|
33
|
+
color,
|
|
34
|
+
min,
|
|
35
|
+
max,
|
|
36
|
+
disableDate,
|
|
37
|
+
placeholder,
|
|
38
|
+
customTrigger,
|
|
39
|
+
mode = "datetime",
|
|
40
|
+
disabled,
|
|
41
|
+
}: Calendar2kViewProps) {
|
|
42
|
+
color = toHexColor(color);
|
|
43
|
+
|
|
44
|
+
const isValueDate = value instanceof Date;
|
|
45
|
+
const isValueTime = typeof value === "string";
|
|
46
|
+
const isValueRange = !!value && !isValueDate && typeof value === "object";
|
|
47
|
+
const isValueDateRange = isValueRange && value.start instanceof Date;
|
|
48
|
+
const isValueTimeRange = isValueRange && typeof value.start === "string";
|
|
49
|
+
|
|
50
|
+
if (isValueTime || isValueTimeRange) mode = "time";
|
|
51
|
+
|
|
52
|
+
const modeHasTime = mode?.includes("time");
|
|
53
|
+
const modeHasDate = mode?.includes("date");
|
|
54
|
+
|
|
55
|
+
const { isOpen, onToggle } = useCalendarDisclose();
|
|
56
|
+
|
|
57
|
+
const [selectedDate, setSelectedDate] = useState<DateStateType>(() => {
|
|
58
|
+
if (!value) return new Date();
|
|
59
|
+
|
|
60
|
+
if (isValueDate) return value;
|
|
61
|
+
|
|
62
|
+
if (isValueTime) return new Date(`2026-05-30 ${value}`);
|
|
63
|
+
|
|
64
|
+
if (isValueTimeRange)
|
|
65
|
+
return {
|
|
66
|
+
start: new Date(`2026-05-30 ${value.start}`),
|
|
67
|
+
end: new Date(`2026-05-30 ${value.end}`),
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return value as DateStateType;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const isStateDate = selectedDate instanceof Date;
|
|
74
|
+
const isDateRange =
|
|
75
|
+
!isStateDate &&
|
|
76
|
+
typeof selectedDate === "object" &&
|
|
77
|
+
selectedDate.start instanceof Date;
|
|
78
|
+
|
|
79
|
+
const [shortDate, setShortDate] = useState(() => {
|
|
80
|
+
if (isStateDate) return selectedDate;
|
|
81
|
+
|
|
82
|
+
return selectedDate.start;
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const matrix = getDayMatrix(shortDate);
|
|
86
|
+
|
|
87
|
+
const weekDays = Array.from({ length: 7 }).map((_, i) =>
|
|
88
|
+
getWeekDay(new Date(2026, 4, 3 + i), locales),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const datetimeOuput = useMemo(() => {
|
|
92
|
+
if (customTrigger) return "";
|
|
93
|
+
|
|
94
|
+
if (!value) {
|
|
95
|
+
if (placeholder) return placeholder;
|
|
96
|
+
|
|
97
|
+
placeholder = "Select date and time";
|
|
98
|
+
|
|
99
|
+
if (mode === "date") return "Select date";
|
|
100
|
+
if (mode === "time") return "Select time";
|
|
101
|
+
|
|
102
|
+
return placeholder;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (isValueDate) return formatDate(value, locales, mode);
|
|
106
|
+
|
|
107
|
+
if (isValueTime) return value;
|
|
108
|
+
|
|
109
|
+
if (isValueTimeRange)
|
|
110
|
+
return `${formatDate(new Date(`2026-05-30 ${value.start}`), locales, mode)} - ${formatDate(new Date(`2026-05-30 ${value.end}`), locales, mode)}`;
|
|
111
|
+
|
|
112
|
+
if (isValueDateRange) {
|
|
113
|
+
let date = formatDate(value.start as Date, locales, mode);
|
|
114
|
+
|
|
115
|
+
if (value.end)
|
|
116
|
+
date = date
|
|
117
|
+
.concat(" - ")
|
|
118
|
+
.concat(formatDate(value.end as Date, locales, mode));
|
|
119
|
+
|
|
120
|
+
return date;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return "Invalid date or time";
|
|
124
|
+
}, [value, locales, mode]);
|
|
125
|
+
|
|
126
|
+
const changeYear = async (year: number) =>
|
|
127
|
+
setShortDate((v) => new Date(year, v.getMonth(), v.getDate()));
|
|
128
|
+
|
|
129
|
+
const changeMonth = (nb: number) => async () =>
|
|
130
|
+
setShortDate(
|
|
131
|
+
(v) => new Date(v.getFullYear(), v.getMonth() + nb, v.getDate()),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const selectDate = (date: Date) => async () => {
|
|
135
|
+
const newDate = new Date(date);
|
|
136
|
+
|
|
137
|
+
if (isStateDate) {
|
|
138
|
+
if (modeHasTime) {
|
|
139
|
+
newDate.setHours(selectedDate.getHours());
|
|
140
|
+
newDate.setMinutes(selectedDate.getMinutes());
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
setSelectedDate(newDate);
|
|
144
|
+
} else {
|
|
145
|
+
const isBeforeStart = selectedDate.start.getTime() > newDate.getTime();
|
|
146
|
+
|
|
147
|
+
if (selectedDate.end || isBeforeStart) {
|
|
148
|
+
if (modeHasTime) {
|
|
149
|
+
newDate.setHours(selectedDate.start.getHours());
|
|
150
|
+
newDate.setMinutes(selectedDate.start.getMinutes());
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
setSelectedDate({ start: newDate, end: undefined });
|
|
154
|
+
} else {
|
|
155
|
+
if (modeHasTime) {
|
|
156
|
+
newDate.setHours(selectedDate.start.getHours());
|
|
157
|
+
newDate.setMinutes(selectedDate.start.getMinutes());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
setSelectedDate((v) => ({ ...v, end: newDate }));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const changeTime =
|
|
166
|
+
(key: "h" | "min" = "h", endTime?: boolean) =>
|
|
167
|
+
async (time: number) => {
|
|
168
|
+
if (isStateDate) {
|
|
169
|
+
const date = new Date(selectedDate);
|
|
170
|
+
|
|
171
|
+
if (key === "h") date.setHours(time);
|
|
172
|
+
if (key === "min") date.setMinutes(time);
|
|
173
|
+
|
|
174
|
+
setSelectedDate(date);
|
|
175
|
+
} else if (isDateRange) {
|
|
176
|
+
if (selectedDate.end && endTime) {
|
|
177
|
+
const date = new Date(selectedDate.end);
|
|
178
|
+
|
|
179
|
+
if (key === "h") date.setHours(time);
|
|
180
|
+
if (key === "min") date.setMinutes(time);
|
|
181
|
+
|
|
182
|
+
setSelectedDate((v) => ({ ...v, end: date }));
|
|
183
|
+
} else if (selectedDate.start) {
|
|
184
|
+
const date = new Date(selectedDate.start);
|
|
185
|
+
|
|
186
|
+
if (key === "h") date.setHours(time);
|
|
187
|
+
if (key === "min") date.setMinutes(time);
|
|
188
|
+
|
|
189
|
+
setSelectedDate((v) => ({ ...v, start: date }));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const save = async () => {
|
|
195
|
+
let data: DateValueType = selectedDate;
|
|
196
|
+
|
|
197
|
+
if (isStateDate && isValueTime)
|
|
198
|
+
data = formatDate(selectedDate, locales, mode) as TimeType;
|
|
199
|
+
|
|
200
|
+
if (isDateRange && isValueTimeRange)
|
|
201
|
+
data = {
|
|
202
|
+
start: formatDate(selectedDate.start, locales, mode) as TimeType,
|
|
203
|
+
end: formatDate(selectedDate.end as Date, locales, mode) as TimeType,
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
onChangeDate?.(data);
|
|
207
|
+
|
|
208
|
+
onToggle();
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
function Day({ date }: DayProps) {
|
|
212
|
+
const active = isActive({ min, max, date, disableDate });
|
|
213
|
+
|
|
214
|
+
const style = getStyle({
|
|
215
|
+
date,
|
|
216
|
+
shortDate,
|
|
217
|
+
selectedDate,
|
|
218
|
+
color,
|
|
219
|
+
active,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return (
|
|
223
|
+
<KTouchableOpacity
|
|
224
|
+
paddingHorizontal={16}
|
|
225
|
+
paddingVertical={10}
|
|
226
|
+
alignItems="center"
|
|
227
|
+
justifyContent="center"
|
|
228
|
+
nativeProps={{ onPress: selectDate(date), disabled: !active }}
|
|
229
|
+
{...style.touchableOpacity}
|
|
230
|
+
>
|
|
231
|
+
<KText textAlign="center" fontSize={16} {...style.text}>
|
|
232
|
+
{date.getDate()}
|
|
233
|
+
</KText>
|
|
234
|
+
</KTouchableOpacity>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function DayColumn({ label, dayNumber }: DayColumnProps) {
|
|
239
|
+
return (
|
|
240
|
+
<KView rowGap={3} flex={1} alignItems="stretch">
|
|
241
|
+
<DayLabel color={color}>{label}</DayLabel>
|
|
242
|
+
<Day date={matrix[dayNumber][0]} />
|
|
243
|
+
<Day date={matrix[dayNumber][1]} />
|
|
244
|
+
<Day date={matrix[dayNumber][2]} />
|
|
245
|
+
<Day date={matrix[dayNumber][3]} />
|
|
246
|
+
<Day date={matrix[dayNumber][4]} />
|
|
247
|
+
</KView>
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return (
|
|
252
|
+
<>
|
|
253
|
+
{customTrigger ? (
|
|
254
|
+
customTrigger(onToggle)
|
|
255
|
+
) : (
|
|
256
|
+
<Pressable
|
|
257
|
+
onPress={onToggle}
|
|
258
|
+
disabled={disabled}
|
|
259
|
+
style={{
|
|
260
|
+
width: "100%",
|
|
261
|
+
borderWidth: 1,
|
|
262
|
+
borderColor: "#0003",
|
|
263
|
+
paddingHorizontal: 16,
|
|
264
|
+
paddingVertical: 10,
|
|
265
|
+
borderRadius: 8,
|
|
266
|
+
backgroundColor: "white",
|
|
267
|
+
flexDirection: "row",
|
|
268
|
+
gap: 10,
|
|
269
|
+
alignItems: "center",
|
|
270
|
+
}}
|
|
271
|
+
>
|
|
272
|
+
<>
|
|
273
|
+
<Icon mode={mode} />
|
|
274
|
+
<KText fontSize={16} color={value ? undefined : "#0007"}>
|
|
275
|
+
{datetimeOuput}
|
|
276
|
+
</KText>
|
|
277
|
+
</>
|
|
278
|
+
</Pressable>
|
|
279
|
+
)}
|
|
280
|
+
<Modal
|
|
281
|
+
animationType="slide"
|
|
282
|
+
visible={isOpen}
|
|
283
|
+
transparent
|
|
284
|
+
onRequestClose={onToggle}
|
|
285
|
+
>
|
|
286
|
+
<KView flex={1} justifyContent="flex-end">
|
|
287
|
+
{isOpen && <Backdrop onPress={onToggle} />}
|
|
288
|
+
<SafeAreaView
|
|
289
|
+
style={{
|
|
290
|
+
minHeight: modeHasDate ? 470 : 200,
|
|
291
|
+
backgroundColor: "white",
|
|
292
|
+
padding: 20,
|
|
293
|
+
gap: 16,
|
|
294
|
+
}}
|
|
295
|
+
>
|
|
296
|
+
<KView
|
|
297
|
+
flexDirection="row"
|
|
298
|
+
justifyContent={modeHasTime ? "space-between" : "flex-end"}
|
|
299
|
+
alignItems="center"
|
|
300
|
+
>
|
|
301
|
+
{modeHasTime && (
|
|
302
|
+
<KView
|
|
303
|
+
flexDirection="row"
|
|
304
|
+
justifyContent="space-between"
|
|
305
|
+
alignItems="center"
|
|
306
|
+
gap={8}
|
|
307
|
+
>
|
|
308
|
+
<TimeView
|
|
309
|
+
date={isStateDate ? selectedDate : selectedDate.start}
|
|
310
|
+
onChangeHours={changeTime("h")}
|
|
311
|
+
onChangeMinutes={changeTime("min")}
|
|
312
|
+
showDate={modeHasDate}
|
|
313
|
+
color={color}
|
|
314
|
+
/>
|
|
315
|
+
{(selectedDate as any)?.end && (
|
|
316
|
+
<>
|
|
317
|
+
<KView width={10} borderWidth={2} borderColor={color} />
|
|
318
|
+
<TimeView
|
|
319
|
+
date={(selectedDate as any).end}
|
|
320
|
+
onChangeHours={changeTime("h", true)}
|
|
321
|
+
onChangeMinutes={changeTime("min", true)}
|
|
322
|
+
showDate={modeHasDate}
|
|
323
|
+
color={color}
|
|
324
|
+
/>
|
|
325
|
+
</>
|
|
326
|
+
)}
|
|
327
|
+
<SwipeIcon color={color} />
|
|
328
|
+
</KView>
|
|
329
|
+
)}
|
|
330
|
+
<KTouchableOpacity
|
|
331
|
+
nativeProps={{ onPress: save }}
|
|
332
|
+
alignItems="center"
|
|
333
|
+
justifyContent="center"
|
|
334
|
+
borderWidth={3}
|
|
335
|
+
paddingHorizontal={14}
|
|
336
|
+
paddingVertical={14}
|
|
337
|
+
borderColor={color}
|
|
338
|
+
>
|
|
339
|
+
<KText fontSize={20} fontWeight="bold" color={color}>
|
|
340
|
+
OK
|
|
341
|
+
</KText>
|
|
342
|
+
</KTouchableOpacity>
|
|
343
|
+
</KView>
|
|
344
|
+
<KView borderTopWidth={1} width="100%" borderColor={`${color}11`} />
|
|
345
|
+
{modeHasDate && (
|
|
346
|
+
<>
|
|
347
|
+
<KView
|
|
348
|
+
flexDirection="row"
|
|
349
|
+
justifyContent="space-between"
|
|
350
|
+
alignItems="center"
|
|
351
|
+
>
|
|
352
|
+
<ArrowButton
|
|
353
|
+
color={color}
|
|
354
|
+
onPress={changeMonth(-1)}
|
|
355
|
+
direction="left"
|
|
356
|
+
/>
|
|
357
|
+
<KView flexDirection="row" alignItems="center" gap={4}>
|
|
358
|
+
<KText
|
|
359
|
+
fontWeight="bold"
|
|
360
|
+
fontSize={16}
|
|
361
|
+
textTransform="capitalize"
|
|
362
|
+
color={color}
|
|
363
|
+
minWidth={100}
|
|
364
|
+
textAlign="right"
|
|
365
|
+
>
|
|
366
|
+
{formatMonth(shortDate, locales)} -
|
|
367
|
+
</KText>
|
|
368
|
+
<KView
|
|
369
|
+
height={40}
|
|
370
|
+
backgroundColor={`${color}11`}
|
|
371
|
+
paddingHorizontal={10}
|
|
372
|
+
borderColor={`${color}11`}
|
|
373
|
+
flexDirection="row"
|
|
374
|
+
alignItems="center"
|
|
375
|
+
>
|
|
376
|
+
<Time
|
|
377
|
+
length={1000}
|
|
378
|
+
index={shortDate.getFullYear()}
|
|
379
|
+
height={40}
|
|
380
|
+
start={new Date().getFullYear() - 500}
|
|
381
|
+
onScrollEnd={changeYear}
|
|
382
|
+
color={color}
|
|
383
|
+
/>
|
|
384
|
+
<SwipeIcon color={color} />
|
|
385
|
+
</KView>
|
|
386
|
+
</KView>
|
|
387
|
+
<ArrowButton
|
|
388
|
+
color={color}
|
|
389
|
+
onPress={changeMonth(1)}
|
|
390
|
+
direction="right"
|
|
391
|
+
/>
|
|
392
|
+
</KView>
|
|
393
|
+
<KView
|
|
394
|
+
borderTopWidth={1}
|
|
395
|
+
width="100%"
|
|
396
|
+
borderColor={`${color}22`}
|
|
397
|
+
/>
|
|
398
|
+
<KView flexDirection="row" flex={1}>
|
|
399
|
+
<DayColumn label={weekDays[0]} dayNumber={6} />
|
|
400
|
+
<DayColumn label={weekDays[1]} dayNumber={0} />
|
|
401
|
+
<DayColumn label={weekDays[2]} dayNumber={1} />
|
|
402
|
+
<DayColumn label={weekDays[3]} dayNumber={2} />
|
|
403
|
+
<DayColumn label={weekDays[4]} dayNumber={3} />
|
|
404
|
+
<DayColumn label={weekDays[5]} dayNumber={4} />
|
|
405
|
+
<DayColumn label={weekDays[6]} dayNumber={5} />
|
|
406
|
+
</KView>
|
|
407
|
+
</>
|
|
408
|
+
)}
|
|
409
|
+
</SafeAreaView>
|
|
410
|
+
</KView>
|
|
411
|
+
</Modal>
|
|
412
|
+
</>
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export type { Calendar2kViewProps, DateValueType };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Calendar2kViewProps } from './Calendar2k.types';
|
|
4
|
+
|
|
5
|
+
export default function Calendar2kView(_props: Calendar2kViewProps) {
|
|
6
|
+
return (
|
|
7
|
+
<div
|
|
8
|
+
style={{
|
|
9
|
+
backgroundColor: '#aabbcc',
|
|
10
|
+
flex: 1,
|
|
11
|
+
display: 'flex',
|
|
12
|
+
flexDirection: 'column',
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
justifyContent: 'center',
|
|
15
|
+
}}>
|
|
16
|
+
<span>Calendar2k - native view</span>
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PropsWithChildren } from "react";
|
|
2
|
+
import { Image } from "react-native";
|
|
3
|
+
import { KTouchableOpacity } from "../ui";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
onPress: () => void;
|
|
7
|
+
color?: string;
|
|
8
|
+
direction?: "right" | "left";
|
|
9
|
+
} & PropsWithChildren;
|
|
10
|
+
export default function ArrowButton({
|
|
11
|
+
onPress,
|
|
12
|
+
children,
|
|
13
|
+
color,
|
|
14
|
+
direction = "right",
|
|
15
|
+
}: Props) {
|
|
16
|
+
const source = () => {
|
|
17
|
+
switch (direction) {
|
|
18
|
+
case "right":
|
|
19
|
+
return require("../assets/images/chevron-right.png");
|
|
20
|
+
case "left":
|
|
21
|
+
return require("../assets/images/chevron-left.png");
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<KTouchableOpacity
|
|
27
|
+
backgroundColor={color}
|
|
28
|
+
width={35}
|
|
29
|
+
height={35}
|
|
30
|
+
alignItems="center"
|
|
31
|
+
justifyContent="center"
|
|
32
|
+
nativeProps={{ onPress }}
|
|
33
|
+
>
|
|
34
|
+
<Image
|
|
35
|
+
source={source()}
|
|
36
|
+
style={{ width: 12, height: 12, tintColor: "white" }}
|
|
37
|
+
/>
|
|
38
|
+
</KTouchableOpacity>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
|
+
import { KTouchableOpacity } from "../ui";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
onPress: () => void;
|
|
7
|
+
};
|
|
8
|
+
export default function Backdrop({ onPress }: Props) {
|
|
9
|
+
const fadeAnim = useRef(new Animated.Value(0)).current;
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
Animated.timing(fadeAnim, {
|
|
13
|
+
toValue: 1,
|
|
14
|
+
duration: 800,
|
|
15
|
+
delay: 100,
|
|
16
|
+
useNativeDriver: true,
|
|
17
|
+
}).start();
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Animated.View
|
|
22
|
+
style={{
|
|
23
|
+
opacity: fadeAnim,
|
|
24
|
+
flex: 1,
|
|
25
|
+
backgroundColor: "#0003",
|
|
26
|
+
}}
|
|
27
|
+
>
|
|
28
|
+
<KTouchableOpacity flex={1} nativeProps={{ onPress }} />
|
|
29
|
+
</Animated.View>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
|
+
import { KText, KView } from "../ui";
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
color?: string;
|
|
6
|
+
} & PropsWithChildren;
|
|
7
|
+
export default function DayLabel({ children, color }: Props) {
|
|
8
|
+
return (
|
|
9
|
+
<KView padding={4}>
|
|
10
|
+
<KText
|
|
11
|
+
textAlign="center"
|
|
12
|
+
fontWeight="bold"
|
|
13
|
+
textTransform="uppercase"
|
|
14
|
+
color={color}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</KText>
|
|
18
|
+
</KView>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Image } from "react-native";
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
color?: string;
|
|
5
|
+
mode?: "date" | "time" | "datetime";
|
|
6
|
+
};
|
|
7
|
+
export default function Icon({ color, mode }: Props) {
|
|
8
|
+
const source = () => {
|
|
9
|
+
switch (mode) {
|
|
10
|
+
case "time":
|
|
11
|
+
return require("../assets/images/clock.png");
|
|
12
|
+
|
|
13
|
+
default:
|
|
14
|
+
return require("../assets/images/calendar.png");
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Image
|
|
20
|
+
source={source()}
|
|
21
|
+
style={{ width: 25, height: 25, tintColor: "#A1A1A1" }}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Image } from "react-native";
|
|
2
|
+
|
|
3
|
+
type Props = {
|
|
4
|
+
color?: string;
|
|
5
|
+
};
|
|
6
|
+
export default function SwipeIcon({ color }: Props) {
|
|
7
|
+
return (
|
|
8
|
+
<Image
|
|
9
|
+
source={require("../assets/images/swipe.png")}
|
|
10
|
+
style={{ width: 30, height: 30, tintColor: color }}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
13
|
+
}
|