@dreamstack-us/kaal 0.0.3 → 0.0.5
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 +82 -36
- package/lib/module/components/CalendarGrid/DayCell.js.map +1 -1
- package/lib/module/components/CalendarGrid/DayCell.web.js +81 -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/utils/date.js +9 -4
- package/lib/module/utils/date.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/utils/date.d.ts +2 -1
- package/lib/typescript/utils/date.d.ts.map +1 -1
- package/package.json +8 -9
- package/src/components/CalendarGrid/CalendarGrid.tsx +1 -1
- package/src/components/CalendarGrid/CalendarGrid.web.tsx +1 -1
- package/src/components/CalendarGrid/DayCell.tsx +98 -46
- package/src/components/CalendarGrid/DayCell.web.tsx +105 -46
- package/src/components/TimePicker/MaterialTimePicker.web.tsx +150 -13
- package/src/utils/date.ts +13 -4
|
@@ -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"
|
|
@@ -151,9 +173,46 @@ export const DayCell: React.FC<DayCellProps> = memo(
|
|
|
151
173
|
weekday: 'long',
|
|
152
174
|
month: 'long',
|
|
153
175
|
day: 'numeric',
|
|
176
|
+
timeZone: 'UTC',
|
|
154
177
|
}).format(date)}
|
|
155
178
|
accessibilityState={{ selected: isSelected, disabled: isDisabled }}
|
|
156
179
|
>
|
|
180
|
+
{/* Thermometer band for range start (extends right) */}
|
|
181
|
+
{isRangeStart && !isRangeEnd && (
|
|
182
|
+
<View
|
|
183
|
+
style={[webStyles.rangeBandRight, { backgroundColor: rangeColor }]}
|
|
184
|
+
/>
|
|
185
|
+
)}
|
|
186
|
+
|
|
187
|
+
{/* Thermometer band for range end (extends left) */}
|
|
188
|
+
{isRangeEnd && !isRangeStart && (
|
|
189
|
+
<View
|
|
190
|
+
style={[webStyles.rangeBandLeft, { backgroundColor: rangeColor }]}
|
|
191
|
+
/>
|
|
192
|
+
)}
|
|
193
|
+
|
|
194
|
+
{/* Thermometer band for in-range dates (full width) */}
|
|
195
|
+
{isInRange && (
|
|
196
|
+
<View
|
|
197
|
+
style={[webStyles.rangeBand, { backgroundColor: rangeColor }]}
|
|
198
|
+
/>
|
|
199
|
+
)}
|
|
200
|
+
|
|
201
|
+
{/* Circle for selected/range start/end */}
|
|
202
|
+
{(isRangeStart || isRangeEnd || isSelected) && (
|
|
203
|
+
<View
|
|
204
|
+
style={[
|
|
205
|
+
webStyles.circleOverlay,
|
|
206
|
+
{ backgroundColor: selectedColor },
|
|
207
|
+
]}
|
|
208
|
+
/>
|
|
209
|
+
)}
|
|
210
|
+
|
|
211
|
+
{/* Today indicator (when not in range) */}
|
|
212
|
+
{todayStyle ? (
|
|
213
|
+
<View style={[webStyles.circleOverlay, todayStyle]} />
|
|
214
|
+
) : null}
|
|
215
|
+
|
|
157
216
|
<Text style={[webStyles.text, textStyle]}>{date.getUTCDate()}</Text>
|
|
158
217
|
</Pressable>
|
|
159
218
|
);
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
/// <reference lib="dom" />
|
|
2
2
|
import type React from 'react';
|
|
3
|
-
import { memo, useCallback, useState } from 'react';
|
|
3
|
+
import { memo, useCallback, useMemo, useState } from 'react';
|
|
4
4
|
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
|
5
|
+
import { useTimePickerOverrides } from '../../context/ThemeOverrideContext';
|
|
5
6
|
import { to12Hour, to24Hour } from '../../hooks/useTimePicker';
|
|
6
7
|
import type { ClockMode, TimePeriod, TimeValue } from '../../types/timepicker';
|
|
7
8
|
import { ClockFace } from './ClockFace';
|
|
8
9
|
|
|
10
|
+
// Default colors (dark theme)
|
|
11
|
+
const DEFAULT_COLORS = {
|
|
12
|
+
containerBackground: '#2C2C2E',
|
|
13
|
+
headerColor: '#8E8E93',
|
|
14
|
+
timeFieldBackground: '#3A3A3C',
|
|
15
|
+
timeFieldActiveBackground: '#007AFF',
|
|
16
|
+
textColor: '#FFFFFF',
|
|
17
|
+
separatorColor: '#FFFFFF',
|
|
18
|
+
borderColor: '#48484A',
|
|
19
|
+
periodActiveBackground: 'rgba(0, 122, 255, 0.2)',
|
|
20
|
+
periodTextColor: '#8E8E93',
|
|
21
|
+
periodTextActiveColor: '#007AFF',
|
|
22
|
+
actionButtonColor: '#007AFF',
|
|
23
|
+
};
|
|
24
|
+
|
|
9
25
|
interface MaterialTimePickerProps {
|
|
10
26
|
value: TimeValue;
|
|
11
27
|
onChange: (time: TimeValue) => void;
|
|
@@ -127,6 +143,7 @@ const webStyles = StyleSheet.create({
|
|
|
127
143
|
|
|
128
144
|
export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
|
|
129
145
|
({ value, onChange, is24Hour = false, onCancel, onConfirm }) => {
|
|
146
|
+
const overrides = useTimePickerOverrides();
|
|
130
147
|
const [mode, setMode] = useState<ClockMode>('hours');
|
|
131
148
|
const { hour: hour12, period } = to12Hour(value.hours);
|
|
132
149
|
|
|
@@ -155,9 +172,95 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
|
|
|
155
172
|
: hour12.toString().padStart(2, '0');
|
|
156
173
|
const displayMinute = value.minutes.toString().padStart(2, '0');
|
|
157
174
|
|
|
175
|
+
// Build override styles from themeOverrides
|
|
176
|
+
const containerStyle = useMemo(
|
|
177
|
+
() => ({
|
|
178
|
+
backgroundColor:
|
|
179
|
+
overrides?.containerBackground ?? DEFAULT_COLORS.containerBackground,
|
|
180
|
+
}),
|
|
181
|
+
[overrides],
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const headerStyle = useMemo(
|
|
185
|
+
() => ({
|
|
186
|
+
color: overrides?.headerColor ?? DEFAULT_COLORS.headerColor,
|
|
187
|
+
}),
|
|
188
|
+
[overrides],
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const timeFieldStyle = useMemo(
|
|
192
|
+
() => ({
|
|
193
|
+
backgroundColor:
|
|
194
|
+
overrides?.timeFieldBackground ?? DEFAULT_COLORS.timeFieldBackground,
|
|
195
|
+
}),
|
|
196
|
+
[overrides],
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const timeFieldActiveStyle = useMemo(
|
|
200
|
+
() => ({
|
|
201
|
+
backgroundColor:
|
|
202
|
+
overrides?.timeFieldActiveBackground ??
|
|
203
|
+
DEFAULT_COLORS.timeFieldActiveBackground,
|
|
204
|
+
}),
|
|
205
|
+
[overrides],
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
const textStyle = useMemo(
|
|
209
|
+
() => ({
|
|
210
|
+
color: overrides?.textColor ?? DEFAULT_COLORS.textColor,
|
|
211
|
+
}),
|
|
212
|
+
[overrides],
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
const separatorStyle = useMemo(
|
|
216
|
+
() => ({
|
|
217
|
+
color: overrides?.separatorColor ?? DEFAULT_COLORS.separatorColor,
|
|
218
|
+
}),
|
|
219
|
+
[overrides],
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const periodContainerStyle = useMemo(
|
|
223
|
+
() => ({
|
|
224
|
+
borderColor: overrides?.periodBorderColor ?? DEFAULT_COLORS.borderColor,
|
|
225
|
+
}),
|
|
226
|
+
[overrides],
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
const periodActiveStyle = useMemo(
|
|
230
|
+
() => ({
|
|
231
|
+
backgroundColor:
|
|
232
|
+
overrides?.periodActiveBackground ??
|
|
233
|
+
DEFAULT_COLORS.periodActiveBackground,
|
|
234
|
+
}),
|
|
235
|
+
[overrides],
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const periodTextStyle = useMemo(
|
|
239
|
+
() => ({
|
|
240
|
+
color: overrides?.periodTextColor ?? DEFAULT_COLORS.periodTextColor,
|
|
241
|
+
}),
|
|
242
|
+
[overrides],
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const periodTextActiveStyle = useMemo(
|
|
246
|
+
() => ({
|
|
247
|
+
color:
|
|
248
|
+
overrides?.periodTextActiveColor ??
|
|
249
|
+
DEFAULT_COLORS.periodTextActiveColor,
|
|
250
|
+
}),
|
|
251
|
+
[overrides],
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const actionButtonTextStyle = useMemo(
|
|
255
|
+
() => ({
|
|
256
|
+
color: overrides?.actionButtonColor ?? DEFAULT_COLORS.actionButtonColor,
|
|
257
|
+
}),
|
|
258
|
+
[overrides],
|
|
259
|
+
);
|
|
260
|
+
|
|
158
261
|
return (
|
|
159
|
-
<View style={webStyles.materialContainer}>
|
|
160
|
-
<Text style={webStyles.materialHeader}>Select time</Text>
|
|
262
|
+
<View style={[webStyles.materialContainer, containerStyle]}>
|
|
263
|
+
<Text style={[webStyles.materialHeader, headerStyle]}>Select time</Text>
|
|
161
264
|
|
|
162
265
|
<View style={webStyles.timeInputContainer}>
|
|
163
266
|
<View style={webStyles.timeFieldsContainer}>
|
|
@@ -165,12 +268,17 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
|
|
|
165
268
|
onPress={handleHourPress}
|
|
166
269
|
style={[
|
|
167
270
|
webStyles.timeField,
|
|
168
|
-
|
|
271
|
+
timeFieldStyle,
|
|
272
|
+
mode === 'hours' && [
|
|
273
|
+
webStyles.timeFieldActive,
|
|
274
|
+
timeFieldActiveStyle,
|
|
275
|
+
],
|
|
169
276
|
]}
|
|
170
277
|
>
|
|
171
278
|
<Text
|
|
172
279
|
style={[
|
|
173
280
|
webStyles.timeFieldText,
|
|
281
|
+
textStyle,
|
|
174
282
|
mode === 'hours' && webStyles.timeFieldTextActive,
|
|
175
283
|
]}
|
|
176
284
|
>
|
|
@@ -178,18 +286,23 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
|
|
|
178
286
|
</Text>
|
|
179
287
|
</Pressable>
|
|
180
288
|
|
|
181
|
-
<Text style={webStyles.timeSeparator}>:</Text>
|
|
289
|
+
<Text style={[webStyles.timeSeparator, separatorStyle]}>:</Text>
|
|
182
290
|
|
|
183
291
|
<Pressable
|
|
184
292
|
onPress={handleMinutePress}
|
|
185
293
|
style={[
|
|
186
294
|
webStyles.timeField,
|
|
187
|
-
|
|
295
|
+
timeFieldStyle,
|
|
296
|
+
mode === 'minutes' && [
|
|
297
|
+
webStyles.timeFieldActive,
|
|
298
|
+
timeFieldActiveStyle,
|
|
299
|
+
],
|
|
188
300
|
]}
|
|
189
301
|
>
|
|
190
302
|
<Text
|
|
191
303
|
style={[
|
|
192
304
|
webStyles.timeFieldText,
|
|
305
|
+
textStyle,
|
|
193
306
|
mode === 'minutes' && webStyles.timeFieldTextActive,
|
|
194
307
|
]}
|
|
195
308
|
>
|
|
@@ -199,19 +312,28 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
|
|
|
199
312
|
</View>
|
|
200
313
|
|
|
201
314
|
{!is24Hour && (
|
|
202
|
-
<View
|
|
315
|
+
<View
|
|
316
|
+
style={[webStyles.periodToggleContainer, periodContainerStyle]}
|
|
317
|
+
>
|
|
203
318
|
<Pressable
|
|
204
319
|
onPress={() => handlePeriodChange('AM')}
|
|
205
320
|
style={[
|
|
206
321
|
webStyles.periodButton,
|
|
207
322
|
webStyles.periodButtonTop,
|
|
208
|
-
period === 'AM' &&
|
|
323
|
+
period === 'AM' && [
|
|
324
|
+
webStyles.periodButtonActive,
|
|
325
|
+
periodActiveStyle,
|
|
326
|
+
],
|
|
209
327
|
]}
|
|
210
328
|
>
|
|
211
329
|
<Text
|
|
212
330
|
style={[
|
|
213
331
|
webStyles.periodButtonText,
|
|
214
|
-
|
|
332
|
+
periodTextStyle,
|
|
333
|
+
period === 'AM' && [
|
|
334
|
+
webStyles.periodButtonTextActive,
|
|
335
|
+
periodTextActiveStyle,
|
|
336
|
+
],
|
|
215
337
|
]}
|
|
216
338
|
>
|
|
217
339
|
AM
|
|
@@ -221,13 +343,20 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
|
|
|
221
343
|
onPress={() => handlePeriodChange('PM')}
|
|
222
344
|
style={[
|
|
223
345
|
webStyles.periodButton,
|
|
224
|
-
period === 'PM' &&
|
|
346
|
+
period === 'PM' && [
|
|
347
|
+
webStyles.periodButtonActive,
|
|
348
|
+
periodActiveStyle,
|
|
349
|
+
],
|
|
225
350
|
]}
|
|
226
351
|
>
|
|
227
352
|
<Text
|
|
228
353
|
style={[
|
|
229
354
|
webStyles.periodButtonText,
|
|
230
|
-
|
|
355
|
+
periodTextStyle,
|
|
356
|
+
period === 'PM' && [
|
|
357
|
+
webStyles.periodButtonTextActive,
|
|
358
|
+
periodTextActiveStyle,
|
|
359
|
+
],
|
|
231
360
|
]}
|
|
232
361
|
>
|
|
233
362
|
PM
|
|
@@ -253,12 +382,20 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
|
|
|
253
382
|
<View style={webStyles.actionButtonsContainer}>
|
|
254
383
|
{onCancel && (
|
|
255
384
|
<Pressable style={webStyles.actionButton} onPress={onCancel}>
|
|
256
|
-
<Text
|
|
385
|
+
<Text
|
|
386
|
+
style={[webStyles.actionButtonText, actionButtonTextStyle]}
|
|
387
|
+
>
|
|
388
|
+
Cancel
|
|
389
|
+
</Text>
|
|
257
390
|
</Pressable>
|
|
258
391
|
)}
|
|
259
392
|
{onConfirm && (
|
|
260
393
|
<Pressable style={webStyles.actionButton} onPress={onConfirm}>
|
|
261
|
-
<Text
|
|
394
|
+
<Text
|
|
395
|
+
style={[webStyles.actionButtonText, actionButtonTextStyle]}
|
|
396
|
+
>
|
|
397
|
+
OK
|
|
398
|
+
</Text>
|
|
262
399
|
</Pressable>
|
|
263
400
|
)}
|
|
264
401
|
</View>
|
package/src/utils/date.ts
CHANGED
|
@@ -157,9 +157,11 @@ export const getMonthDays = (year: number, month: number): Date[] => {
|
|
|
157
157
|
|
|
158
158
|
/**
|
|
159
159
|
* Gets the first day of the month
|
|
160
|
+
* Falls back to today if date is undefined/null
|
|
160
161
|
*/
|
|
161
|
-
export const getFirstDayOfMonth = (date: Date): Date => {
|
|
162
|
-
|
|
162
|
+
export const getFirstDayOfMonth = (date: Date | null | undefined): Date => {
|
|
163
|
+
const d = date ?? today();
|
|
164
|
+
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1));
|
|
163
165
|
};
|
|
164
166
|
|
|
165
167
|
/**
|
|
@@ -184,7 +186,10 @@ export const formatMonth = (
|
|
|
184
186
|
locale = 'en-US',
|
|
185
187
|
style: 'long' | 'short' | 'narrow' = 'long',
|
|
186
188
|
): string => {
|
|
187
|
-
return new Intl.DateTimeFormat(locale, {
|
|
189
|
+
return new Intl.DateTimeFormat(locale, {
|
|
190
|
+
month: style,
|
|
191
|
+
timeZone: 'UTC',
|
|
192
|
+
}).format(date);
|
|
188
193
|
};
|
|
189
194
|
|
|
190
195
|
/**
|
|
@@ -195,7 +200,10 @@ export const formatWeekday = (
|
|
|
195
200
|
locale = 'en-US',
|
|
196
201
|
style: 'long' | 'short' | 'narrow' = 'short',
|
|
197
202
|
): string => {
|
|
198
|
-
return new Intl.DateTimeFormat(locale, {
|
|
203
|
+
return new Intl.DateTimeFormat(locale, {
|
|
204
|
+
weekday: style,
|
|
205
|
+
timeZone: 'UTC',
|
|
206
|
+
}).format(date);
|
|
199
207
|
};
|
|
200
208
|
|
|
201
209
|
/**
|
|
@@ -205,6 +213,7 @@ export const formatYearMonth = (date: Date, locale = 'en-US'): string => {
|
|
|
205
213
|
return new Intl.DateTimeFormat(locale, {
|
|
206
214
|
month: 'long',
|
|
207
215
|
year: 'numeric',
|
|
216
|
+
timeZone: 'UTC',
|
|
208
217
|
}).format(date);
|
|
209
218
|
};
|
|
210
219
|
|