@dreamstack-us/kaal 0.0.1 → 0.0.3
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/README.md +165 -0
- package/lib/module/components/CalendarGrid/CalendarGrid.js +125 -29
- package/lib/module/components/CalendarGrid/CalendarGrid.js.map +1 -1
- package/lib/module/components/CalendarGrid/CalendarGrid.styles.js +22 -17
- package/lib/module/components/CalendarGrid/CalendarGrid.styles.js.map +1 -1
- package/lib/module/components/CalendarGrid/CalendarGrid.web.js +265 -0
- package/lib/module/components/CalendarGrid/CalendarGrid.web.js.map +1 -0
- package/lib/module/components/CalendarGrid/DayCell.js +77 -53
- package/lib/module/components/CalendarGrid/DayCell.js.map +1 -1
- package/lib/module/components/CalendarGrid/DayCell.web.js +124 -0
- package/lib/module/components/CalendarGrid/DayCell.web.js.map +1 -0
- package/lib/module/components/CalendarGrid/index.js +1 -1
- package/lib/module/components/CalendarGrid/index.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.android.js +53 -21
- package/lib/module/components/DatePicker/DatePicker.android.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.ios.js +55 -23
- package/lib/module/components/DatePicker/DatePicker.ios.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.styles.js +19 -20
- package/lib/module/components/DatePicker/DatePicker.styles.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.web.js +59 -21
- package/lib/module/components/DatePicker/DatePicker.web.js.map +1 -1
- package/lib/module/components/TimePicker/ClockFace.js +27 -7
- package/lib/module/components/TimePicker/ClockFace.js.map +1 -1
- package/lib/module/components/TimePicker/ClockFace.web.js +253 -0
- package/lib/module/components/TimePicker/ClockFace.web.js.map +1 -0
- package/lib/module/components/TimePicker/MaterialTimePicker.js +68 -16
- package/lib/module/components/TimePicker/MaterialTimePicker.js.map +1 -1
- package/lib/module/components/TimePicker/MaterialTimePicker.web.js +231 -0
- package/lib/module/components/TimePicker/MaterialTimePicker.web.js.map +1 -0
- package/lib/module/components/TimePicker/TimePicker.android.js +13 -6
- package/lib/module/components/TimePicker/TimePicker.android.js.map +1 -1
- package/lib/module/components/TimePicker/TimePicker.ios.js +14 -7
- package/lib/module/components/TimePicker/TimePicker.ios.js.map +1 -1
- package/lib/module/components/TimePicker/TimePicker.styles.js +53 -45
- package/lib/module/components/TimePicker/TimePicker.styles.js.map +1 -1
- package/lib/module/components/TimePicker/TimePicker.web.js +24 -12
- package/lib/module/components/TimePicker/TimePicker.web.js.map +1 -1
- package/lib/module/components/TimePicker/TimeWheelPicker.js +45 -10
- package/lib/module/components/TimePicker/TimeWheelPicker.js.map +1 -1
- package/lib/module/components/TimePicker/TimeWheelPicker.web.js +339 -0
- package/lib/module/components/TimePicker/TimeWheelPicker.web.js.map +1 -0
- package/lib/module/components/TimePicker/index.js +3 -3
- package/lib/module/components/TimePicker/index.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelPicker.js +21 -2
- package/lib/module/components/WheelPicker/WheelPicker.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelPicker.styles.js +13 -8
- package/lib/module/components/WheelPicker/WheelPicker.styles.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelPicker.web.js +146 -57
- package/lib/module/components/WheelPicker/WheelPicker.web.js.map +1 -1
- package/lib/module/context/ThemeOverrideContext.js +34 -0
- package/lib/module/context/ThemeOverrideContext.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/validation.js +74 -34
- package/lib/module/utils/validation.js.map +1 -1
- package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts +24 -3
- package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts.map +1 -1
- package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts +12 -10
- package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts.map +1 -1
- package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts +33 -0
- package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts.map +1 -0
- package/lib/typescript/components/CalendarGrid/DayCell.d.ts +3 -0
- package/lib/typescript/components/CalendarGrid/DayCell.d.ts.map +1 -1
- package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts +15 -0
- package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts.map +1 -0
- package/lib/typescript/components/DatePicker/DatePicker.android.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.d.ts +27 -4
- package/lib/typescript/components/DatePicker/DatePicker.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.ios.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts +12 -13
- package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.web.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/ClockFace.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/ClockFace.web.d.ts +12 -0
- package/lib/typescript/components/TimePicker/ClockFace.web.d.ts.map +1 -0
- package/lib/typescript/components/TimePicker/MaterialTimePicker.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts +12 -0
- package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts.map +1 -0
- package/lib/typescript/components/TimePicker/TimePicker.android.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimePicker.ios.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts +29 -25
- package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimePicker.web.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimeWheelPicker.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts +11 -0
- package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/WheelPicker.d.ts +14 -1
- package/lib/typescript/components/WheelPicker/WheelPicker.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts +9 -7
- package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/WheelPicker.web.d.ts.map +1 -1
- package/lib/typescript/context/ThemeOverrideContext.d.ts +23 -0
- package/lib/typescript/context/ThemeOverrideContext.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types/datepicker.d.ts +78 -3
- package/lib/typescript/types/datepicker.d.ts.map +1 -1
- package/lib/typescript/types/timepicker.d.ts +62 -0
- package/lib/typescript/types/timepicker.d.ts.map +1 -1
- package/lib/typescript/utils/validation.d.ts +47 -27
- package/lib/typescript/utils/validation.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/components/CalendarGrid/CalendarGrid.styles.ts +21 -17
- package/src/components/CalendarGrid/CalendarGrid.tsx +265 -85
- package/src/components/CalendarGrid/CalendarGrid.web.tsx +396 -0
- package/src/components/CalendarGrid/DayCell.tsx +122 -61
- package/src/components/CalendarGrid/DayCell.web.tsx +171 -0
- package/src/components/DatePicker/DatePicker.android.tsx +48 -24
- package/src/components/DatePicker/DatePicker.ios.tsx +51 -27
- package/src/components/DatePicker/DatePicker.styles.ts +18 -22
- package/src/components/DatePicker/DatePicker.tsx +35 -4
- package/src/components/DatePicker/DatePicker.web.tsx +55 -23
- package/src/components/TimePicker/ClockFace.tsx +34 -8
- package/src/components/TimePicker/ClockFace.web.tsx +303 -0
- package/src/components/TimePicker/MaterialTimePicker.tsx +144 -13
- package/src/components/TimePicker/MaterialTimePicker.web.tsx +271 -0
- package/src/components/TimePicker/TimePicker.android.tsx +9 -1
- package/src/components/TimePicker/TimePicker.ios.tsx +10 -6
- package/src/components/TimePicker/TimePicker.styles.ts +52 -45
- package/src/components/TimePicker/TimePicker.web.tsx +17 -7
- package/src/components/TimePicker/TimeWheelPicker.tsx +60 -6
- package/src/components/TimePicker/TimeWheelPicker.web.tsx +401 -0
- package/src/components/WheelPicker/WheelPicker.styles.ts +12 -8
- package/src/components/WheelPicker/WheelPicker.tsx +24 -2
- package/src/components/WheelPicker/WheelPicker.web.tsx +153 -57
- package/src/context/ThemeOverrideContext.tsx +38 -0
- package/src/index.ts +13 -0
- package/src/types/datepicker.ts +87 -3
- package/src/types/timepicker.ts +74 -0
- package/src/utils/validation.ts +111 -55
- package/lib/module/unistyles.js +0 -9
- package/lib/module/unistyles.js.map +0 -1
- package/lib/typescript/unistyles.d.ts +0 -3
- package/lib/typescript/unistyles.d.ts.map +0 -1
- package/src/unistyles.ts +0 -6
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
import type React from 'react';
|
|
3
|
+
import { memo, useMemo } from 'react';
|
|
4
|
+
import { Pressable, StyleSheet, Text } from 'react-native';
|
|
5
|
+
import { useDatePickerOverrides } from '../../context/ThemeOverrideContext';
|
|
6
|
+
|
|
7
|
+
interface DayCellProps {
|
|
8
|
+
date: Date | null;
|
|
9
|
+
isSelected: boolean;
|
|
10
|
+
isToday: boolean;
|
|
11
|
+
isDisabled: boolean;
|
|
12
|
+
isWeekend: boolean;
|
|
13
|
+
isRangeStart?: boolean;
|
|
14
|
+
isRangeEnd?: boolean;
|
|
15
|
+
isInRange?: boolean;
|
|
16
|
+
onPress?: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Default colors (light theme for web)
|
|
20
|
+
const DEFAULT_COLORS = {
|
|
21
|
+
cellBackground: 'transparent',
|
|
22
|
+
cellSelected: '#007AFF',
|
|
23
|
+
cellToday: 'rgba(0, 122, 255, 0.1)',
|
|
24
|
+
cellInRange: 'rgba(0, 122, 255, 0.15)',
|
|
25
|
+
textDefault: '#1C1C1E',
|
|
26
|
+
textSelected: '#FFFFFF',
|
|
27
|
+
textDisabled: '#8E8E93',
|
|
28
|
+
textWeekend: '#8E8E93',
|
|
29
|
+
textInRange: '#1C1C1E',
|
|
30
|
+
primary: '#007AFF',
|
|
31
|
+
cellBorderRadius: 22,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Web-compatible styles (no unistyles dependency)
|
|
35
|
+
const webStyles = StyleSheet.create({
|
|
36
|
+
cell: {
|
|
37
|
+
width: 44,
|
|
38
|
+
height: 44,
|
|
39
|
+
justifyContent: 'center',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
},
|
|
42
|
+
text: {
|
|
43
|
+
fontSize: 17,
|
|
44
|
+
fontWeight: '400',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const DayCell: React.FC<DayCellProps> = memo(
|
|
49
|
+
({
|
|
50
|
+
date,
|
|
51
|
+
isSelected,
|
|
52
|
+
isToday,
|
|
53
|
+
isDisabled,
|
|
54
|
+
isWeekend,
|
|
55
|
+
isRangeStart,
|
|
56
|
+
isRangeEnd,
|
|
57
|
+
isInRange,
|
|
58
|
+
onPress,
|
|
59
|
+
}) => {
|
|
60
|
+
const overrides = useDatePickerOverrides();
|
|
61
|
+
|
|
62
|
+
// Build cell style based on state and overrides
|
|
63
|
+
// Use primaryColor as fallback for cellSelectedColor (consumer expectation)
|
|
64
|
+
const cellStyle = useMemo(() => {
|
|
65
|
+
const style: Record<string, unknown> = {
|
|
66
|
+
backgroundColor: DEFAULT_COLORS.cellBackground,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Range start/end get selected styling
|
|
70
|
+
if (isRangeStart || isRangeEnd || isSelected) {
|
|
71
|
+
style.backgroundColor =
|
|
72
|
+
overrides?.cellSelectedColor ??
|
|
73
|
+
overrides?.primaryColor ??
|
|
74
|
+
DEFAULT_COLORS.cellSelected;
|
|
75
|
+
style.borderRadius =
|
|
76
|
+
overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
|
|
77
|
+
} else if (isInRange) {
|
|
78
|
+
// Dates in range get lighter background
|
|
79
|
+
style.backgroundColor =
|
|
80
|
+
overrides?.cellInRangeColor ?? DEFAULT_COLORS.cellInRange;
|
|
81
|
+
} else if (isToday) {
|
|
82
|
+
style.backgroundColor =
|
|
83
|
+
overrides?.cellTodayColor ?? DEFAULT_COLORS.cellToday;
|
|
84
|
+
style.borderRadius =
|
|
85
|
+
overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
|
|
86
|
+
style.borderWidth = 1;
|
|
87
|
+
style.borderColor = overrides?.primaryColor ?? DEFAULT_COLORS.primary;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (isDisabled) {
|
|
91
|
+
style.opacity = 0.4;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return style;
|
|
95
|
+
}, [
|
|
96
|
+
overrides,
|
|
97
|
+
isSelected,
|
|
98
|
+
isToday,
|
|
99
|
+
isDisabled,
|
|
100
|
+
isRangeStart,
|
|
101
|
+
isRangeEnd,
|
|
102
|
+
isInRange,
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
// Build text style based on state and overrides
|
|
106
|
+
const textStyle = useMemo(() => {
|
|
107
|
+
const style: Record<string, unknown> = {
|
|
108
|
+
color: overrides?.textColor ?? DEFAULT_COLORS.textDefault,
|
|
109
|
+
fontWeight: '400' as const,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (isRangeStart || isRangeEnd || isSelected) {
|
|
113
|
+
style.color =
|
|
114
|
+
overrides?.textSelectedColor ?? DEFAULT_COLORS.textSelected;
|
|
115
|
+
style.fontWeight = '600';
|
|
116
|
+
} else if (isInRange) {
|
|
117
|
+
style.color = overrides?.textInRangeColor ?? DEFAULT_COLORS.textInRange;
|
|
118
|
+
} else if (isToday) {
|
|
119
|
+
style.color = overrides?.primaryColor ?? DEFAULT_COLORS.primary;
|
|
120
|
+
style.fontWeight = '600';
|
|
121
|
+
} else if (isDisabled) {
|
|
122
|
+
style.color =
|
|
123
|
+
overrides?.textDisabledColor ?? DEFAULT_COLORS.textDisabled;
|
|
124
|
+
} else if (isWeekend) {
|
|
125
|
+
style.color = overrides?.textWeekendColor ?? DEFAULT_COLORS.textWeekend;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return style;
|
|
129
|
+
}, [
|
|
130
|
+
overrides,
|
|
131
|
+
isSelected,
|
|
132
|
+
isToday,
|
|
133
|
+
isDisabled,
|
|
134
|
+
isWeekend,
|
|
135
|
+
isRangeStart,
|
|
136
|
+
isRangeEnd,
|
|
137
|
+
isInRange,
|
|
138
|
+
]);
|
|
139
|
+
|
|
140
|
+
if (!date) {
|
|
141
|
+
return <Pressable style={webStyles.cell} disabled />;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<Pressable
|
|
146
|
+
style={[webStyles.cell, cellStyle]}
|
|
147
|
+
onPress={onPress}
|
|
148
|
+
disabled={isDisabled}
|
|
149
|
+
accessibilityRole="button"
|
|
150
|
+
accessibilityLabel={new Intl.DateTimeFormat('en-US', {
|
|
151
|
+
weekday: 'long',
|
|
152
|
+
month: 'long',
|
|
153
|
+
day: 'numeric',
|
|
154
|
+
}).format(date)}
|
|
155
|
+
accessibilityState={{ selected: isSelected, disabled: isDisabled }}
|
|
156
|
+
>
|
|
157
|
+
<Text style={[webStyles.text, textStyle]}>{date.getUTCDate()}</Text>
|
|
158
|
+
</Pressable>
|
|
159
|
+
);
|
|
160
|
+
},
|
|
161
|
+
(prev, next) =>
|
|
162
|
+
prev.date?.getTime() === next.date?.getTime() &&
|
|
163
|
+
prev.isSelected === next.isSelected &&
|
|
164
|
+
prev.isToday === next.isToday &&
|
|
165
|
+
prev.isDisabled === next.isDisabled &&
|
|
166
|
+
prev.isRangeStart === next.isRangeStart &&
|
|
167
|
+
prev.isRangeEnd === next.isRangeEnd &&
|
|
168
|
+
prev.isInRange === next.isInRange,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
DayCell.displayName = 'DayCell';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import React, { Suspense
|
|
1
|
+
import React, { Suspense } from 'react';
|
|
2
2
|
import { ActivityIndicator, View } from 'react-native';
|
|
3
|
+
import { ThemeOverrideProvider } from '../../context/ThemeOverrideContext';
|
|
3
4
|
import { toISODateString } from '../../utils/date';
|
|
4
5
|
import { CalendarGrid } from '../CalendarGrid';
|
|
5
6
|
import type { KaalDatePickerProps } from './DatePicker';
|
|
@@ -31,39 +32,62 @@ const ExpoDatePicker = React.lazy(async () => {
|
|
|
31
32
|
}
|
|
32
33
|
});
|
|
33
34
|
|
|
34
|
-
export const DatePicker: React.FC<KaalDatePickerProps> = ({
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
35
|
+
export const DatePicker: React.FC<KaalDatePickerProps> = (props) => {
|
|
36
|
+
const {
|
|
37
|
+
theme = 'native',
|
|
38
|
+
minDate,
|
|
39
|
+
maxDate,
|
|
40
|
+
disabledDates,
|
|
41
|
+
themeOverrides,
|
|
42
|
+
weekStartsOn = 0,
|
|
43
|
+
} = props;
|
|
44
|
+
|
|
45
|
+
const themeMode = theme === 'native' ? 'android' : theme;
|
|
46
|
+
|
|
47
|
+
// Range mode
|
|
48
|
+
if (props.selectionMode === 'range') {
|
|
49
|
+
return (
|
|
50
|
+
<ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
|
|
51
|
+
<CalendarGrid
|
|
52
|
+
selectionMode="range"
|
|
53
|
+
startDate={props.startDate}
|
|
54
|
+
endDate={props.endDate}
|
|
55
|
+
onRangeChange={props.onRangeChange}
|
|
56
|
+
minDate={minDate}
|
|
57
|
+
maxDate={maxDate}
|
|
58
|
+
disabledDates={disabledDates}
|
|
59
|
+
themeMode={themeMode}
|
|
60
|
+
weekStartsOn={weekStartsOn}
|
|
61
|
+
/>
|
|
62
|
+
</ThemeOverrideProvider>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
48
65
|
|
|
66
|
+
// Single selection mode
|
|
67
|
+
// Native picker only available for single selection
|
|
49
68
|
if (theme === 'native') {
|
|
50
69
|
return (
|
|
51
70
|
<View style={styles.container}>
|
|
52
71
|
<Suspense fallback={<ActivityIndicator />}>
|
|
53
|
-
<ExpoDatePicker value={value} onChange={
|
|
72
|
+
<ExpoDatePicker value={props.value} onChange={props.onChange} />
|
|
54
73
|
</Suspense>
|
|
55
74
|
</View>
|
|
56
75
|
);
|
|
57
76
|
}
|
|
58
77
|
|
|
78
|
+
// Single selection with custom theme
|
|
59
79
|
return (
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
<ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
|
|
81
|
+
<CalendarGrid
|
|
82
|
+
selectionMode="single"
|
|
83
|
+
value={props.value}
|
|
84
|
+
onChange={props.onChange}
|
|
85
|
+
minDate={minDate}
|
|
86
|
+
maxDate={maxDate}
|
|
87
|
+
disabledDates={disabledDates}
|
|
88
|
+
themeMode={themeMode}
|
|
89
|
+
weekStartsOn={weekStartsOn}
|
|
90
|
+
/>
|
|
91
|
+
</ThemeOverrideProvider>
|
|
68
92
|
);
|
|
69
93
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import React, { Suspense
|
|
1
|
+
import React, { Suspense } from 'react';
|
|
2
2
|
import { ActivityIndicator, View } from 'react-native';
|
|
3
|
+
import { ThemeOverrideProvider } from '../../context/ThemeOverrideContext';
|
|
3
4
|
import { toISODateString } from '../../utils/date';
|
|
4
5
|
import { CalendarGrid } from '../CalendarGrid';
|
|
5
6
|
import type { KaalDatePickerProps } from './DatePicker';
|
|
@@ -34,30 +35,48 @@ const ExpoDatePicker = React.lazy(async () => {
|
|
|
34
35
|
}
|
|
35
36
|
});
|
|
36
37
|
|
|
37
|
-
export const DatePicker: React.FC<KaalDatePickerProps> = ({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
38
|
+
export const DatePicker: React.FC<KaalDatePickerProps> = (props) => {
|
|
39
|
+
const {
|
|
40
|
+
mode = 'date',
|
|
41
|
+
theme = 'native',
|
|
42
|
+
variant = 'wheel',
|
|
43
|
+
minDate,
|
|
44
|
+
maxDate,
|
|
45
|
+
disabledDates,
|
|
46
|
+
themeOverrides,
|
|
47
|
+
weekStartsOn = 0,
|
|
48
|
+
} = props;
|
|
49
|
+
|
|
50
|
+
const themeMode = theme === 'native' ? 'ios' : theme;
|
|
51
|
+
|
|
52
|
+
// Range mode
|
|
53
|
+
if (props.selectionMode === 'range') {
|
|
54
|
+
return (
|
|
55
|
+
<ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
|
|
56
|
+
<CalendarGrid
|
|
57
|
+
selectionMode="range"
|
|
58
|
+
startDate={props.startDate}
|
|
59
|
+
endDate={props.endDate}
|
|
60
|
+
onRangeChange={props.onRangeChange}
|
|
61
|
+
minDate={minDate}
|
|
62
|
+
maxDate={maxDate}
|
|
63
|
+
disabledDates={disabledDates}
|
|
64
|
+
themeMode={themeMode}
|
|
65
|
+
weekStartsOn={weekStartsOn}
|
|
66
|
+
/>
|
|
67
|
+
</ThemeOverrideProvider>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
53
70
|
|
|
71
|
+
// Single selection mode
|
|
72
|
+
// Native picker only available for single selection
|
|
54
73
|
if (theme === 'native') {
|
|
55
74
|
return (
|
|
56
75
|
<View style={styles.container}>
|
|
57
76
|
<Suspense fallback={<ActivityIndicator />}>
|
|
58
77
|
<ExpoDatePicker
|
|
59
|
-
value={value}
|
|
60
|
-
onChange={
|
|
78
|
+
value={props.value}
|
|
79
|
+
onChange={props.onChange}
|
|
61
80
|
variant={variant}
|
|
62
81
|
/>
|
|
63
82
|
</Suspense>
|
|
@@ -65,14 +84,19 @@ export const DatePicker: React.FC<KaalDatePickerProps> = ({
|
|
|
65
84
|
);
|
|
66
85
|
}
|
|
67
86
|
|
|
87
|
+
// Single selection with custom theme
|
|
68
88
|
return (
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
<ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
|
|
90
|
+
<CalendarGrid
|
|
91
|
+
selectionMode="single"
|
|
92
|
+
value={props.value}
|
|
93
|
+
onChange={props.onChange}
|
|
94
|
+
minDate={minDate}
|
|
95
|
+
maxDate={maxDate}
|
|
96
|
+
disabledDates={disabledDates}
|
|
97
|
+
themeMode={themeMode}
|
|
98
|
+
weekStartsOn={weekStartsOn}
|
|
99
|
+
/>
|
|
100
|
+
</ThemeOverrideProvider>
|
|
77
101
|
);
|
|
78
102
|
};
|
|
@@ -1,35 +1,31 @@
|
|
|
1
|
-
import { Platform } from 'react-native';
|
|
2
|
-
import { StyleSheet, type UnistylesVariants } from 'react-native-unistyles';
|
|
1
|
+
import { Platform, StyleSheet } from 'react-native';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Default styles for DatePicker using plain React Native StyleSheet.
|
|
5
|
+
* Colors use dark theme defaults - consumers override via themeOverrides prop.
|
|
6
|
+
*/
|
|
7
|
+
export const styles = StyleSheet.create({
|
|
5
8
|
container: {
|
|
6
|
-
backgroundColor:
|
|
7
|
-
borderRadius:
|
|
9
|
+
backgroundColor: '#1E1E1E',
|
|
10
|
+
borderRadius: 16,
|
|
8
11
|
overflow: 'hidden',
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
large: {
|
|
18
|
-
padding: theme.spacing(6),
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
},
|
|
12
|
+
padding: 16,
|
|
13
|
+
},
|
|
14
|
+
containerCompact: {
|
|
15
|
+
padding: 8,
|
|
16
|
+
},
|
|
17
|
+
containerLarge: {
|
|
18
|
+
padding: 24,
|
|
22
19
|
},
|
|
23
20
|
backdrop: Platform.select({
|
|
24
21
|
web: {
|
|
22
|
+
// @ts-ignore - web-only properties
|
|
25
23
|
backdropFilter: 'blur(20px) saturate(180%)',
|
|
26
24
|
WebkitBackdropFilter: 'blur(20px) saturate(180%)',
|
|
27
25
|
backgroundColor: 'rgba(255, 255, 255, 0.7)',
|
|
28
26
|
},
|
|
29
27
|
default: {
|
|
30
|
-
backgroundColor:
|
|
28
|
+
backgroundColor: '#2C2C2E',
|
|
31
29
|
},
|
|
32
30
|
}),
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
export type DatePickerVariants = UnistylesVariants<typeof styles>;
|
|
31
|
+
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
DatePickerMode,
|
|
4
|
+
DatePickerThemeOverrides,
|
|
5
|
+
DateRange,
|
|
6
|
+
} from '../../types';
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
value: Date;
|
|
6
|
-
onChange: (date: Date) => void;
|
|
8
|
+
interface KaalDatePickerBaseProps {
|
|
7
9
|
mode?: DatePickerMode;
|
|
8
10
|
theme?: 'native' | 'ios' | 'android' | 'custom';
|
|
9
11
|
variant?: 'wheel' | 'calendar' | 'compact';
|
|
@@ -11,8 +13,37 @@ export interface KaalDatePickerProps {
|
|
|
11
13
|
maxDate?: Date;
|
|
12
14
|
disabledDates?: Date[];
|
|
13
15
|
locale?: string;
|
|
16
|
+
/**
|
|
17
|
+
* First day of the week: 0 = Sunday, 1 = Monday
|
|
18
|
+
* @default 0 (Sunday)
|
|
19
|
+
*/
|
|
20
|
+
weekStartsOn?: 0 | 1;
|
|
21
|
+
/** Custom theme overrides for styling without matching Kaal's theme structure */
|
|
22
|
+
themeOverrides?: DatePickerThemeOverrides;
|
|
14
23
|
}
|
|
15
24
|
|
|
25
|
+
interface KaalDatePickerSingleProps extends KaalDatePickerBaseProps {
|
|
26
|
+
selectionMode?: 'single';
|
|
27
|
+
value: Date;
|
|
28
|
+
onChange: (date: Date) => void;
|
|
29
|
+
startDate?: never;
|
|
30
|
+
endDate?: never;
|
|
31
|
+
onRangeChange?: never;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface KaalDatePickerRangeProps extends KaalDatePickerBaseProps {
|
|
35
|
+
selectionMode: 'range';
|
|
36
|
+
startDate: Date | null;
|
|
37
|
+
endDate: Date | null;
|
|
38
|
+
onRangeChange: (range: DateRange) => void;
|
|
39
|
+
value?: never;
|
|
40
|
+
onChange?: never;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type KaalDatePickerProps =
|
|
44
|
+
| KaalDatePickerSingleProps
|
|
45
|
+
| KaalDatePickerRangeProps;
|
|
46
|
+
|
|
16
47
|
// Platform-specific implementations are handled by Metro's file resolution
|
|
17
48
|
// This file serves as the type definition and fallback
|
|
18
49
|
export const DatePicker: React.FC<KaalDatePickerProps> = (_props) => {
|
|
@@ -1,36 +1,68 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
|
+
import { ThemeOverrideProvider } from '../../context/ThemeOverrideContext';
|
|
2
3
|
import { CalendarGrid } from '../CalendarGrid';
|
|
3
4
|
import { WheelPicker } from '../WheelPicker';
|
|
4
5
|
import type { KaalDatePickerProps } from './DatePicker';
|
|
5
6
|
|
|
6
|
-
export const DatePicker: React.FC<KaalDatePickerProps> = ({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
export const DatePicker: React.FC<KaalDatePickerProps> = (props) => {
|
|
8
|
+
const {
|
|
9
|
+
theme = 'ios',
|
|
10
|
+
variant = 'calendar',
|
|
11
|
+
minDate,
|
|
12
|
+
maxDate,
|
|
13
|
+
disabledDates,
|
|
14
|
+
themeOverrides,
|
|
15
|
+
weekStartsOn = 0,
|
|
16
|
+
} = props;
|
|
17
|
+
|
|
18
|
+
const themeMode = theme === 'native' ? 'ios' : theme;
|
|
19
|
+
|
|
20
|
+
// Range mode
|
|
21
|
+
if (props.selectionMode === 'range') {
|
|
22
|
+
return (
|
|
23
|
+
<ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
|
|
24
|
+
<CalendarGrid
|
|
25
|
+
selectionMode="range"
|
|
26
|
+
startDate={props.startDate}
|
|
27
|
+
endDate={props.endDate}
|
|
28
|
+
onRangeChange={props.onRangeChange}
|
|
29
|
+
minDate={minDate}
|
|
30
|
+
maxDate={maxDate}
|
|
31
|
+
disabledDates={disabledDates}
|
|
32
|
+
themeMode={themeMode}
|
|
33
|
+
weekStartsOn={weekStartsOn}
|
|
34
|
+
/>
|
|
35
|
+
</ThemeOverrideProvider>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Single selection mode (default)
|
|
40
|
+
// Wheel picker only supports single selection
|
|
15
41
|
if (theme === 'ios' && variant === 'wheel') {
|
|
16
42
|
return (
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
43
|
+
<ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
|
|
44
|
+
<WheelPicker
|
|
45
|
+
value={props.value}
|
|
46
|
+
onChange={props.onChange}
|
|
47
|
+
minDate={minDate}
|
|
48
|
+
maxDate={maxDate}
|
|
49
|
+
/>
|
|
50
|
+
</ThemeOverrideProvider>
|
|
23
51
|
);
|
|
24
52
|
}
|
|
25
53
|
|
|
26
54
|
return (
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
55
|
+
<ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
|
|
56
|
+
<CalendarGrid
|
|
57
|
+
selectionMode="single"
|
|
58
|
+
value={props.value}
|
|
59
|
+
onChange={props.onChange}
|
|
60
|
+
minDate={minDate}
|
|
61
|
+
maxDate={maxDate}
|
|
62
|
+
disabledDates={disabledDates}
|
|
63
|
+
themeMode={themeMode}
|
|
64
|
+
weekStartsOn={weekStartsOn}
|
|
65
|
+
/>
|
|
66
|
+
</ThemeOverrideProvider>
|
|
35
67
|
);
|
|
36
68
|
};
|
|
@@ -4,8 +4,9 @@ import { View } from 'react-native';
|
|
|
4
4
|
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
5
5
|
import { runOnJS } from 'react-native-reanimated';
|
|
6
6
|
import Svg, { Circle, G, Line, Text as SvgText } from 'react-native-svg';
|
|
7
|
+
import { useTimePickerOverrides } from '../../context/ThemeOverrideContext';
|
|
7
8
|
import { to12Hour, to24Hour } from '../../hooks/useTimePicker';
|
|
8
|
-
import type { ClockMode,
|
|
9
|
+
import type { ClockMode, TimeValue } from '../../types/timepicker';
|
|
9
10
|
import { styles } from './TimePicker.styles';
|
|
10
11
|
|
|
11
12
|
// Clock dimensions
|
|
@@ -19,6 +20,15 @@ const CENTER_DOT_RADIUS = 4;
|
|
|
19
20
|
const HOURS_12 = [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
|
20
21
|
const MINUTE_LABELS = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
|
|
21
22
|
|
|
23
|
+
// Default colors (dark theme)
|
|
24
|
+
const DEFAULT_COLORS = {
|
|
25
|
+
clockBackground: '#3F384C',
|
|
26
|
+
handColor: '#4DA6FF',
|
|
27
|
+
selectionDotColor: '#4DA6FF',
|
|
28
|
+
textColor: '#E6E1E5',
|
|
29
|
+
textSelectedColor: '#FFFFFF',
|
|
30
|
+
};
|
|
31
|
+
|
|
22
32
|
/**
|
|
23
33
|
* Converts clock position (0-11 for hours, 0-59 for minutes) to angle in degrees
|
|
24
34
|
* 12 o'clock is at -90 degrees (top)
|
|
@@ -54,8 +64,24 @@ interface ClockFaceProps {
|
|
|
54
64
|
|
|
55
65
|
export const ClockFace: React.FC<ClockFaceProps> = memo(
|
|
56
66
|
({ value, onChange, mode, onModeChange, is24Hour = false }) => {
|
|
67
|
+
const overrides = useTimePickerOverrides();
|
|
57
68
|
const { hour: hour12, period } = to12Hour(value.hours);
|
|
58
69
|
|
|
70
|
+
// Build colors from overrides
|
|
71
|
+
const colors = useMemo(
|
|
72
|
+
() => ({
|
|
73
|
+
clockBackground:
|
|
74
|
+
overrides?.clockBackground ?? DEFAULT_COLORS.clockBackground,
|
|
75
|
+
handColor: overrides?.clockHandColor ?? DEFAULT_COLORS.handColor,
|
|
76
|
+
selectionDotColor:
|
|
77
|
+
overrides?.clockSelectionColor ?? DEFAULT_COLORS.selectionDotColor,
|
|
78
|
+
textColor: overrides?.clockTextColor ?? DEFAULT_COLORS.textColor,
|
|
79
|
+
textSelectedColor:
|
|
80
|
+
overrides?.clockTextSelectedColor ?? DEFAULT_COLORS.textSelectedColor,
|
|
81
|
+
}),
|
|
82
|
+
[overrides],
|
|
83
|
+
);
|
|
84
|
+
|
|
59
85
|
// Calculate hand end position based on current value
|
|
60
86
|
const handAngle = useMemo(() => {
|
|
61
87
|
if (mode === 'hours') {
|
|
@@ -149,7 +175,7 @@ export const ClockFace: React.FC<ClockFaceProps> = memo(
|
|
|
149
175
|
alignmentBaseline="central"
|
|
150
176
|
fontSize={14}
|
|
151
177
|
fontWeight={isSelected ? '500' : '400'}
|
|
152
|
-
fill={isSelected ?
|
|
178
|
+
fill={isSelected ? colors.textSelectedColor : colors.textColor}
|
|
153
179
|
>
|
|
154
180
|
{hour}
|
|
155
181
|
</SvgText>
|
|
@@ -171,13 +197,13 @@ export const ClockFace: React.FC<ClockFaceProps> = memo(
|
|
|
171
197
|
alignmentBaseline="central"
|
|
172
198
|
fontSize={14}
|
|
173
199
|
fontWeight={isSelected ? '500' : '400'}
|
|
174
|
-
fill={isSelected ?
|
|
200
|
+
fill={isSelected ? colors.textSelectedColor : colors.textColor}
|
|
175
201
|
>
|
|
176
202
|
{minute.toString().padStart(2, '0')}
|
|
177
203
|
</SvgText>
|
|
178
204
|
);
|
|
179
205
|
});
|
|
180
|
-
}, [mode, hour12, value.minutes]);
|
|
206
|
+
}, [mode, hour12, value.minutes, colors]);
|
|
181
207
|
|
|
182
208
|
return (
|
|
183
209
|
<View style={styles.clockContainer}>
|
|
@@ -192,7 +218,7 @@ export const ClockFace: React.FC<ClockFaceProps> = memo(
|
|
|
192
218
|
cx={CLOCK_CENTER}
|
|
193
219
|
cy={CLOCK_CENTER}
|
|
194
220
|
r={CLOCK_SIZE / 2 - 4}
|
|
195
|
-
fill=
|
|
221
|
+
fill={colors.clockBackground}
|
|
196
222
|
/>
|
|
197
223
|
|
|
198
224
|
{/* Selection dot (behind numbers) */}
|
|
@@ -200,7 +226,7 @@ export const ClockFace: React.FC<ClockFaceProps> = memo(
|
|
|
200
226
|
cx={handEndPos.x}
|
|
201
227
|
cy={handEndPos.y}
|
|
202
228
|
r={SELECTION_DOT_RADIUS}
|
|
203
|
-
fill=
|
|
229
|
+
fill={colors.selectionDotColor}
|
|
204
230
|
/>
|
|
205
231
|
|
|
206
232
|
{/* Clock hand */}
|
|
@@ -209,7 +235,7 @@ export const ClockFace: React.FC<ClockFaceProps> = memo(
|
|
|
209
235
|
y1={CLOCK_CENTER}
|
|
210
236
|
x2={handEndPos.x}
|
|
211
237
|
y2={handEndPos.y}
|
|
212
|
-
stroke=
|
|
238
|
+
stroke={colors.handColor}
|
|
213
239
|
strokeWidth={2}
|
|
214
240
|
/>
|
|
215
241
|
|
|
@@ -218,7 +244,7 @@ export const ClockFace: React.FC<ClockFaceProps> = memo(
|
|
|
218
244
|
cx={CLOCK_CENTER}
|
|
219
245
|
cy={CLOCK_CENTER}
|
|
220
246
|
r={CENTER_DOT_RADIUS}
|
|
221
|
-
fill=
|
|
247
|
+
fill={colors.handColor}
|
|
222
248
|
/>
|
|
223
249
|
|
|
224
250
|
{/* Numbers */}
|