@dreamstack-us/kaal 0.0.4 → 0.1.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/lib/module/components/CalendarGrid/CalendarGrid.js +1 -1
- package/lib/module/components/CalendarGrid/CalendarGrid.js.map +1 -1
- package/lib/module/components/CalendarGrid/CalendarGrid.web.js +1 -1
- package/lib/module/components/CalendarGrid/CalendarGrid.web.js.map +1 -1
- package/lib/module/components/CalendarGrid/DayCell.js +81 -36
- package/lib/module/components/CalendarGrid/DayCell.js.map +1 -1
- package/lib/module/components/CalendarGrid/DayCell.web.js +80 -36
- package/lib/module/components/CalendarGrid/DayCell.web.js.map +1 -1
- package/lib/module/components/TimePicker/MaterialTimePicker.web.js +67 -15
- package/lib/module/components/TimePicker/MaterialTimePicker.web.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelPicker.web.js +14 -14
- package/lib/module/components/WheelPicker/WheelPicker.web.js.map +1 -1
- package/lib/module/hooks/useCalendar.js +1 -1
- package/lib/module/hooks/useCalendar.js.map +1 -1
- package/lib/module/utils/date.js +25 -21
- package/lib/module/utils/date.js.map +1 -1
- package/lib/module/utils/validation.js +3 -3
- package/lib/module/utils/validation.js.map +1 -1
- package/lib/typescript/components/CalendarGrid/DayCell.d.ts.map +1 -1
- package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/WheelPicker.web.d.ts.map +1 -1
- package/lib/typescript/utils/date.d.ts +7 -3
- package/lib/typescript/utils/date.d.ts.map +1 -1
- package/package.json +8 -9
- package/src/components/CalendarGrid/CalendarGrid.tsx +2 -2
- package/src/components/CalendarGrid/CalendarGrid.web.tsx +2 -2
- package/src/components/CalendarGrid/DayCell.tsx +98 -47
- package/src/components/CalendarGrid/DayCell.web.tsx +105 -47
- package/src/components/TimePicker/MaterialTimePicker.web.tsx +150 -13
- package/src/components/WheelPicker/WheelPicker.web.tsx +15 -25
- package/src/hooks/useCalendar.ts +2 -2
- package/src/utils/date.ts +34 -27
- package/src/utils/validation.ts +5 -5
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Date utilities using native Date and Intl APIs
|
|
3
3
|
* Replaces @js-temporal/polyfill for lighter bundle size
|
|
4
|
+
*
|
|
5
|
+
* All date-only values use LOCAL time (not UTC). This ensures that
|
|
6
|
+
* dates displayed in the calendar match what consumers read with
|
|
7
|
+
* standard .getDate(), .getMonth(), .getFullYear() methods.
|
|
4
8
|
*/
|
|
5
9
|
/**
|
|
6
|
-
* Converts a Date to ISO date string (YYYY-MM-DD)
|
|
10
|
+
* Converts a Date to ISO date string (YYYY-MM-DD) using local time
|
|
7
11
|
*/
|
|
8
12
|
export declare const toISODateString: (date: Date) => string;
|
|
9
13
|
/**
|
|
@@ -11,7 +15,7 @@ export declare const toISODateString: (date: Date) => string;
|
|
|
11
15
|
*/
|
|
12
16
|
export declare const toISODateTimeString: (date: Date, timeZone?: string) => string;
|
|
13
17
|
/**
|
|
14
|
-
* Parses an ISO date string (YYYY-MM-DD) to Date
|
|
18
|
+
* Parses an ISO date string (YYYY-MM-DD) to a local Date
|
|
15
19
|
*/
|
|
16
20
|
export declare const parseISODate: (iso: string) => Date;
|
|
17
21
|
/**
|
|
@@ -89,7 +93,7 @@ export declare const formatWeekday: (date: Date, locale?: string, style?: "long"
|
|
|
89
93
|
*/
|
|
90
94
|
export declare const formatYearMonth: (date: Date, locale?: string) => string;
|
|
91
95
|
/**
|
|
92
|
-
* Gets today's date at midnight
|
|
96
|
+
* Gets today's date at local midnight
|
|
93
97
|
*/
|
|
94
98
|
export declare const today: () => Date;
|
|
95
99
|
//# sourceMappingURL=date.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../src/utils/date.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../../src/utils/date.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,IAAI,KAAG,MAK5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,IAAI,EAAE,WAAW,MAAM,KAAG,MAenE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,IAG1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,QARI,MAAM,KAAG,IAQE,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,IAE9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,QAPI,MAAM,KAAG,IAOM,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,IAAI,EAAE,KAAK,IAAI,KAAG,IAAI,EAUzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,IAAI,EACV,UAAU,IAAI,EACd,UAAU,IAAI,KACb,OAKF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,QAAO,MAElC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,OAAO,GAAI,MAAM,IAAI,EAAE,MAAM,MAAM,KAAG,IAIlD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,MAAM,IAAI,EAAE,QAAQ,MAAM,KAAG,IAYtD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAG,MAE/C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,GAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAG,OAE5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAG,OAE9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,IAAI,EAO9D,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,IAAI,GAAG,IAAI,GAAG,SAAS,KAAG,IAGlE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,IAAI,KAAG,IAE9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,IAAI,KAAG,MAEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,IAAI,EACV,eAAgB,EAChB,QAAO,MAAM,GAAG,OAAO,GAAG,QAAiB,KAC1C,MAIF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GACxB,MAAM,IAAI,EACV,eAAgB,EAChB,QAAO,MAAM,GAAG,OAAO,GAAG,QAAkB,KAC3C,MAIF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,IAAI,EAAE,eAAgB,KAAG,MAK9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,KAAK,QAAO,IAGxB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dreamstack-us/kaal",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "High-performance React Native DatePicker
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "High-performance React Native DatePicker and TimePicker",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/module/index.js",
|
|
7
7
|
"types": "./lib/typescript/index.d.ts",
|
|
@@ -33,12 +33,9 @@
|
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": ">=18.2.0",
|
|
35
35
|
"react-native": ">=0.78.0",
|
|
36
|
-
"react-native-unistyles": "^3.0.0",
|
|
37
|
-
"react-native-nitro-modules": "0.31.4",
|
|
38
|
-
"react-native-reanimated": ">=3.17.0",
|
|
39
|
-
"react-native-gesture-handler": ">=2.20.0",
|
|
40
36
|
"react-native-svg": ">=13.0.0",
|
|
41
|
-
"
|
|
37
|
+
"react-native-reanimated": ">=3.17.0",
|
|
38
|
+
"react-native-gesture-handler": ">=2.20.0"
|
|
42
39
|
},
|
|
43
40
|
"peerDependenciesMeta": {
|
|
44
41
|
"@expo/ui": {
|
|
@@ -46,6 +43,9 @@
|
|
|
46
43
|
},
|
|
47
44
|
"@dreamstack-us/kaal-themes": {
|
|
48
45
|
"optional": true
|
|
46
|
+
},
|
|
47
|
+
"react-native-nitro-modules": {
|
|
48
|
+
"optional": true
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
@@ -57,7 +57,6 @@
|
|
|
57
57
|
"react-native-nitro-modules": "0.31.4",
|
|
58
58
|
"react-native-reanimated": "^3.17.0",
|
|
59
59
|
"react-native-svg": "^15.15.1",
|
|
60
|
-
"react-native-unistyles": "^3.0.0",
|
|
61
60
|
"typescript": "^5.7.0"
|
|
62
61
|
},
|
|
63
62
|
"react-native-builder-bob": {
|
|
@@ -94,7 +93,7 @@
|
|
|
94
93
|
"datepicker",
|
|
95
94
|
"timepicker",
|
|
96
95
|
"calendar",
|
|
97
|
-
"
|
|
96
|
+
"expo",
|
|
98
97
|
"new-architecture"
|
|
99
98
|
],
|
|
100
99
|
"license": "MIT"
|
|
@@ -99,8 +99,8 @@ const generateMonthDays = (
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
const monthDays = getMonthDays(
|
|
102
|
-
currentMonth.
|
|
103
|
-
currentMonth.
|
|
102
|
+
currentMonth.getFullYear(),
|
|
103
|
+
currentMonth.getMonth(),
|
|
104
104
|
);
|
|
105
105
|
for (const day of monthDays) {
|
|
106
106
|
days.push(day);
|
|
@@ -109,8 +109,8 @@ const generateMonthDays = (
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
const monthDays = getMonthDays(
|
|
112
|
-
currentMonth.
|
|
113
|
-
currentMonth.
|
|
112
|
+
currentMonth.getFullYear(),
|
|
113
|
+
currentMonth.getMonth(),
|
|
114
114
|
);
|
|
115
115
|
for (const day of monthDays) {
|
|
116
116
|
days.push(day);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import { memo, useMemo } from 'react';
|
|
3
|
-
import { Pressable, StyleSheet, Text } from 'react-native';
|
|
3
|
+
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
4
4
|
import { useDatePickerOverrides } from '../../context/ThemeOverrideContext';
|
|
5
5
|
|
|
6
6
|
interface DayCellProps {
|
|
@@ -30,16 +30,51 @@ const DEFAULT_COLORS = {
|
|
|
30
30
|
cellBorderRadius: 22,
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
const CELL_SIZE = 44;
|
|
34
|
+
const BAND_HEIGHT = 28; // Narrower band for thermometer effect
|
|
35
|
+
|
|
33
36
|
const styles = StyleSheet.create({
|
|
34
37
|
cell: {
|
|
35
|
-
width:
|
|
36
|
-
height:
|
|
38
|
+
width: CELL_SIZE,
|
|
39
|
+
height: CELL_SIZE,
|
|
37
40
|
justifyContent: 'center',
|
|
38
41
|
alignItems: 'center',
|
|
39
42
|
},
|
|
43
|
+
// Thermometer band for in-range dates
|
|
44
|
+
rangeBand: {
|
|
45
|
+
position: 'absolute',
|
|
46
|
+
top: (CELL_SIZE - BAND_HEIGHT) / 2,
|
|
47
|
+
height: BAND_HEIGHT,
|
|
48
|
+
left: 0,
|
|
49
|
+
right: 0,
|
|
50
|
+
},
|
|
51
|
+
// Half band extending right from range start
|
|
52
|
+
rangeBandRight: {
|
|
53
|
+
position: 'absolute',
|
|
54
|
+
top: (CELL_SIZE - BAND_HEIGHT) / 2,
|
|
55
|
+
height: BAND_HEIGHT,
|
|
56
|
+
left: CELL_SIZE / 2,
|
|
57
|
+
right: 0,
|
|
58
|
+
},
|
|
59
|
+
// Half band extending left to range end
|
|
60
|
+
rangeBandLeft: {
|
|
61
|
+
position: 'absolute',
|
|
62
|
+
top: (CELL_SIZE - BAND_HEIGHT) / 2,
|
|
63
|
+
height: BAND_HEIGHT,
|
|
64
|
+
left: 0,
|
|
65
|
+
right: CELL_SIZE / 2,
|
|
66
|
+
},
|
|
67
|
+
// Circle overlay for selected dates
|
|
68
|
+
circleOverlay: {
|
|
69
|
+
position: 'absolute',
|
|
70
|
+
width: CELL_SIZE,
|
|
71
|
+
height: CELL_SIZE,
|
|
72
|
+
borderRadius: CELL_SIZE / 2,
|
|
73
|
+
},
|
|
40
74
|
text: {
|
|
41
75
|
fontSize: 17,
|
|
42
76
|
fontWeight: '400',
|
|
77
|
+
zIndex: 1,
|
|
43
78
|
},
|
|
44
79
|
});
|
|
45
80
|
|
|
@@ -57,48 +92,12 @@ export const DayCell: React.FC<DayCellProps> = memo(
|
|
|
57
92
|
}) => {
|
|
58
93
|
const overrides = useDatePickerOverrides();
|
|
59
94
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// Range start/end get selected styling
|
|
68
|
-
if (isRangeStart || isRangeEnd || isSelected) {
|
|
69
|
-
style.backgroundColor =
|
|
70
|
-
overrides?.cellSelectedColor ??
|
|
71
|
-
overrides?.primaryColor ??
|
|
72
|
-
DEFAULT_COLORS.cellSelected;
|
|
73
|
-
style.borderRadius =
|
|
74
|
-
overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
|
|
75
|
-
} else if (isInRange) {
|
|
76
|
-
// Dates in range get lighter background
|
|
77
|
-
style.backgroundColor =
|
|
78
|
-
overrides?.cellInRangeColor ?? DEFAULT_COLORS.cellInRange;
|
|
79
|
-
} else if (isToday) {
|
|
80
|
-
style.backgroundColor =
|
|
81
|
-
overrides?.cellTodayColor ?? DEFAULT_COLORS.cellToday;
|
|
82
|
-
style.borderRadius =
|
|
83
|
-
overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
|
|
84
|
-
style.borderWidth = 1;
|
|
85
|
-
style.borderColor = overrides?.primaryColor ?? DEFAULT_COLORS.primary;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (isDisabled) {
|
|
89
|
-
style.opacity = 0.4;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return style;
|
|
93
|
-
}, [
|
|
94
|
-
overrides,
|
|
95
|
-
isSelected,
|
|
96
|
-
isToday,
|
|
97
|
-
isDisabled,
|
|
98
|
-
isRangeStart,
|
|
99
|
-
isRangeEnd,
|
|
100
|
-
isInRange,
|
|
101
|
-
]);
|
|
95
|
+
const rangeColor =
|
|
96
|
+
overrides?.cellInRangeColor ?? DEFAULT_COLORS.cellInRange;
|
|
97
|
+
const selectedColor =
|
|
98
|
+
overrides?.cellSelectedColor ??
|
|
99
|
+
overrides?.primaryColor ??
|
|
100
|
+
DEFAULT_COLORS.cellSelected;
|
|
102
101
|
|
|
103
102
|
// Build text style based on state and overrides
|
|
104
103
|
const textStyle = useMemo(() => {
|
|
@@ -135,13 +134,36 @@ export const DayCell: React.FC<DayCellProps> = memo(
|
|
|
135
134
|
isInRange,
|
|
136
135
|
]);
|
|
137
136
|
|
|
137
|
+
// Today style (non-range)
|
|
138
|
+
const todayStyle = useMemo(() => {
|
|
139
|
+
if (
|
|
140
|
+
isToday &&
|
|
141
|
+
!isSelected &&
|
|
142
|
+
!isRangeStart &&
|
|
143
|
+
!isRangeEnd &&
|
|
144
|
+
!isInRange
|
|
145
|
+
) {
|
|
146
|
+
return {
|
|
147
|
+
backgroundColor:
|
|
148
|
+
overrides?.cellTodayColor ?? DEFAULT_COLORS.cellToday,
|
|
149
|
+
borderRadius:
|
|
150
|
+
overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius,
|
|
151
|
+
borderWidth: 1,
|
|
152
|
+
borderColor: overrides?.primaryColor ?? DEFAULT_COLORS.primary,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}, [isToday, isSelected, isRangeStart, isRangeEnd, isInRange, overrides]);
|
|
157
|
+
|
|
138
158
|
if (!date) {
|
|
139
159
|
return <Pressable style={styles.cell} disabled />;
|
|
140
160
|
}
|
|
141
161
|
|
|
162
|
+
const cellOpacity = isDisabled ? 0.4 : 1;
|
|
163
|
+
|
|
142
164
|
return (
|
|
143
165
|
<Pressable
|
|
144
|
-
style={[styles.cell,
|
|
166
|
+
style={[styles.cell, { opacity: cellOpacity }]}
|
|
145
167
|
onPress={onPress}
|
|
146
168
|
disabled={isDisabled}
|
|
147
169
|
accessibilityRole="button"
|
|
@@ -152,7 +174,36 @@ export const DayCell: React.FC<DayCellProps> = memo(
|
|
|
152
174
|
}).format(date)}
|
|
153
175
|
accessibilityState={{ selected: isSelected, disabled: isDisabled }}
|
|
154
176
|
>
|
|
155
|
-
|
|
177
|
+
{/* Thermometer band for range start (extends right) */}
|
|
178
|
+
{isRangeStart && !isRangeEnd && (
|
|
179
|
+
<View
|
|
180
|
+
style={[styles.rangeBandRight, { backgroundColor: rangeColor }]}
|
|
181
|
+
/>
|
|
182
|
+
)}
|
|
183
|
+
|
|
184
|
+
{/* Thermometer band for range end (extends left) */}
|
|
185
|
+
{isRangeEnd && !isRangeStart && (
|
|
186
|
+
<View
|
|
187
|
+
style={[styles.rangeBandLeft, { backgroundColor: rangeColor }]}
|
|
188
|
+
/>
|
|
189
|
+
)}
|
|
190
|
+
|
|
191
|
+
{/* Thermometer band for in-range dates (full width) */}
|
|
192
|
+
{isInRange && (
|
|
193
|
+
<View style={[styles.rangeBand, { backgroundColor: rangeColor }]} />
|
|
194
|
+
)}
|
|
195
|
+
|
|
196
|
+
{/* Circle for selected/range start/end */}
|
|
197
|
+
{(isRangeStart || isRangeEnd || isSelected) && (
|
|
198
|
+
<View
|
|
199
|
+
style={[styles.circleOverlay, { backgroundColor: selectedColor }]}
|
|
200
|
+
/>
|
|
201
|
+
)}
|
|
202
|
+
|
|
203
|
+
{/* Today indicator (when not in range) */}
|
|
204
|
+
{todayStyle && <View style={[styles.circleOverlay, todayStyle]} />}
|
|
205
|
+
|
|
206
|
+
<Text style={[styles.text, textStyle]}>{date.getDate()}</Text>
|
|
156
207
|
</Pressable>
|
|
157
208
|
);
|
|
158
209
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
import type React from 'react';
|
|
3
3
|
import { memo, useMemo } from 'react';
|
|
4
|
-
import { Pressable, StyleSheet, Text } from 'react-native';
|
|
4
|
+
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
5
|
import { useDatePickerOverrides } from '../../context/ThemeOverrideContext';
|
|
6
6
|
|
|
7
7
|
interface DayCellProps {
|
|
@@ -31,17 +31,52 @@ const DEFAULT_COLORS = {
|
|
|
31
31
|
cellBorderRadius: 22,
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
+
const CELL_SIZE = 44;
|
|
35
|
+
const BAND_HEIGHT = 28; // Narrower band for thermometer effect
|
|
36
|
+
|
|
34
37
|
// Web-compatible styles (no unistyles dependency)
|
|
35
38
|
const webStyles = StyleSheet.create({
|
|
36
39
|
cell: {
|
|
37
|
-
width:
|
|
38
|
-
height:
|
|
40
|
+
width: CELL_SIZE,
|
|
41
|
+
height: CELL_SIZE,
|
|
39
42
|
justifyContent: 'center',
|
|
40
43
|
alignItems: 'center',
|
|
41
44
|
},
|
|
45
|
+
// Thermometer band for in-range dates
|
|
46
|
+
rangeBand: {
|
|
47
|
+
position: 'absolute',
|
|
48
|
+
top: (CELL_SIZE - BAND_HEIGHT) / 2,
|
|
49
|
+
height: BAND_HEIGHT,
|
|
50
|
+
left: 0,
|
|
51
|
+
right: 0,
|
|
52
|
+
},
|
|
53
|
+
// Half band extending right from range start
|
|
54
|
+
rangeBandRight: {
|
|
55
|
+
position: 'absolute',
|
|
56
|
+
top: (CELL_SIZE - BAND_HEIGHT) / 2,
|
|
57
|
+
height: BAND_HEIGHT,
|
|
58
|
+
left: CELL_SIZE / 2,
|
|
59
|
+
right: 0,
|
|
60
|
+
},
|
|
61
|
+
// Half band extending left to range end
|
|
62
|
+
rangeBandLeft: {
|
|
63
|
+
position: 'absolute',
|
|
64
|
+
top: (CELL_SIZE - BAND_HEIGHT) / 2,
|
|
65
|
+
height: BAND_HEIGHT,
|
|
66
|
+
left: 0,
|
|
67
|
+
right: CELL_SIZE / 2,
|
|
68
|
+
},
|
|
69
|
+
// Circle overlay for selected dates
|
|
70
|
+
circleOverlay: {
|
|
71
|
+
position: 'absolute',
|
|
72
|
+
width: CELL_SIZE,
|
|
73
|
+
height: CELL_SIZE,
|
|
74
|
+
borderRadius: CELL_SIZE / 2,
|
|
75
|
+
},
|
|
42
76
|
text: {
|
|
43
77
|
fontSize: 17,
|
|
44
78
|
fontWeight: '400',
|
|
79
|
+
zIndex: 1,
|
|
45
80
|
},
|
|
46
81
|
});
|
|
47
82
|
|
|
@@ -59,48 +94,12 @@ export const DayCell: React.FC<DayCellProps> = memo(
|
|
|
59
94
|
}) => {
|
|
60
95
|
const overrides = useDatePickerOverrides();
|
|
61
96
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
]);
|
|
97
|
+
const rangeColor =
|
|
98
|
+
overrides?.cellInRangeColor ?? DEFAULT_COLORS.cellInRange;
|
|
99
|
+
const selectedColor =
|
|
100
|
+
overrides?.cellSelectedColor ??
|
|
101
|
+
overrides?.primaryColor ??
|
|
102
|
+
DEFAULT_COLORS.cellSelected;
|
|
104
103
|
|
|
105
104
|
// Build text style based on state and overrides
|
|
106
105
|
const textStyle = useMemo(() => {
|
|
@@ -137,13 +136,36 @@ export const DayCell: React.FC<DayCellProps> = memo(
|
|
|
137
136
|
isInRange,
|
|
138
137
|
]);
|
|
139
138
|
|
|
139
|
+
// Today style (non-range)
|
|
140
|
+
const todayStyle = useMemo(() => {
|
|
141
|
+
if (
|
|
142
|
+
isToday &&
|
|
143
|
+
!isSelected &&
|
|
144
|
+
!isRangeStart &&
|
|
145
|
+
!isRangeEnd &&
|
|
146
|
+
!isInRange
|
|
147
|
+
) {
|
|
148
|
+
return {
|
|
149
|
+
backgroundColor:
|
|
150
|
+
overrides?.cellTodayColor ?? DEFAULT_COLORS.cellToday,
|
|
151
|
+
borderRadius:
|
|
152
|
+
overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius,
|
|
153
|
+
borderWidth: 1,
|
|
154
|
+
borderColor: overrides?.primaryColor ?? DEFAULT_COLORS.primary,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}, [isToday, isSelected, isRangeStart, isRangeEnd, isInRange, overrides]);
|
|
159
|
+
|
|
140
160
|
if (!date) {
|
|
141
161
|
return <Pressable style={webStyles.cell} disabled />;
|
|
142
162
|
}
|
|
143
163
|
|
|
164
|
+
const cellOpacity = isDisabled ? 0.4 : 1;
|
|
165
|
+
|
|
144
166
|
return (
|
|
145
167
|
<Pressable
|
|
146
|
-
style={[webStyles.cell,
|
|
168
|
+
style={[webStyles.cell, { opacity: cellOpacity }]}
|
|
147
169
|
onPress={onPress}
|
|
148
170
|
disabled={isDisabled}
|
|
149
171
|
accessibilityRole="button"
|
|
@@ -154,7 +176,43 @@ export const DayCell: React.FC<DayCellProps> = memo(
|
|
|
154
176
|
}).format(date)}
|
|
155
177
|
accessibilityState={{ selected: isSelected, disabled: isDisabled }}
|
|
156
178
|
>
|
|
157
|
-
|
|
179
|
+
{/* Thermometer band for range start (extends right) */}
|
|
180
|
+
{isRangeStart && !isRangeEnd && (
|
|
181
|
+
<View
|
|
182
|
+
style={[webStyles.rangeBandRight, { backgroundColor: rangeColor }]}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
185
|
+
|
|
186
|
+
{/* Thermometer band for range end (extends left) */}
|
|
187
|
+
{isRangeEnd && !isRangeStart && (
|
|
188
|
+
<View
|
|
189
|
+
style={[webStyles.rangeBandLeft, { backgroundColor: rangeColor }]}
|
|
190
|
+
/>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
{/* Thermometer band for in-range dates (full width) */}
|
|
194
|
+
{isInRange && (
|
|
195
|
+
<View
|
|
196
|
+
style={[webStyles.rangeBand, { backgroundColor: rangeColor }]}
|
|
197
|
+
/>
|
|
198
|
+
)}
|
|
199
|
+
|
|
200
|
+
{/* Circle for selected/range start/end */}
|
|
201
|
+
{(isRangeStart || isRangeEnd || isSelected) && (
|
|
202
|
+
<View
|
|
203
|
+
style={[
|
|
204
|
+
webStyles.circleOverlay,
|
|
205
|
+
{ backgroundColor: selectedColor },
|
|
206
|
+
]}
|
|
207
|
+
/>
|
|
208
|
+
)}
|
|
209
|
+
|
|
210
|
+
{/* Today indicator (when not in range) */}
|
|
211
|
+
{todayStyle ? (
|
|
212
|
+
<View style={[webStyles.circleOverlay, todayStyle]} />
|
|
213
|
+
) : null}
|
|
214
|
+
|
|
215
|
+
<Text style={[webStyles.text, textStyle]}>{date.getDate()}</Text>
|
|
158
216
|
</Pressable>
|
|
159
217
|
);
|
|
160
218
|
},
|