@dreamstack-us/kaal 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/lib/module/components/CalendarGrid/CalendarGrid.js +47 -13
  2. package/lib/module/components/CalendarGrid/CalendarGrid.js.map +1 -1
  3. package/lib/module/components/CalendarGrid/CalendarGrid.styles.js +22 -17
  4. package/lib/module/components/CalendarGrid/CalendarGrid.styles.js.map +1 -1
  5. package/lib/module/components/CalendarGrid/CalendarGrid.web.js +203 -0
  6. package/lib/module/components/CalendarGrid/CalendarGrid.web.js.map +1 -0
  7. package/lib/module/components/CalendarGrid/DayCell.js +64 -52
  8. package/lib/module/components/CalendarGrid/DayCell.js.map +1 -1
  9. package/lib/module/components/CalendarGrid/DayCell.web.js +112 -0
  10. package/lib/module/components/CalendarGrid/DayCell.web.js.map +1 -0
  11. package/lib/module/components/CalendarGrid/index.js +1 -1
  12. package/lib/module/components/CalendarGrid/index.js.map +1 -1
  13. package/lib/module/components/DatePicker/DatePicker.android.js +17 -8
  14. package/lib/module/components/DatePicker/DatePicker.android.js.map +1 -1
  15. package/lib/module/components/DatePicker/DatePicker.ios.js +17 -8
  16. package/lib/module/components/DatePicker/DatePicker.ios.js.map +1 -1
  17. package/lib/module/components/DatePicker/DatePicker.js.map +1 -1
  18. package/lib/module/components/DatePicker/DatePicker.styles.js +19 -20
  19. package/lib/module/components/DatePicker/DatePicker.styles.js.map +1 -1
  20. package/lib/module/components/DatePicker/DatePicker.web.js +26 -12
  21. package/lib/module/components/DatePicker/DatePicker.web.js.map +1 -1
  22. package/lib/module/components/TimePicker/ClockFace.js +27 -7
  23. package/lib/module/components/TimePicker/ClockFace.js.map +1 -1
  24. package/lib/module/components/TimePicker/ClockFace.web.js +253 -0
  25. package/lib/module/components/TimePicker/ClockFace.web.js.map +1 -0
  26. package/lib/module/components/TimePicker/MaterialTimePicker.js +68 -16
  27. package/lib/module/components/TimePicker/MaterialTimePicker.js.map +1 -1
  28. package/lib/module/components/TimePicker/MaterialTimePicker.web.js +231 -0
  29. package/lib/module/components/TimePicker/MaterialTimePicker.web.js.map +1 -0
  30. package/lib/module/components/TimePicker/TimePicker.android.js +13 -6
  31. package/lib/module/components/TimePicker/TimePicker.android.js.map +1 -1
  32. package/lib/module/components/TimePicker/TimePicker.ios.js +14 -7
  33. package/lib/module/components/TimePicker/TimePicker.ios.js.map +1 -1
  34. package/lib/module/components/TimePicker/TimePicker.styles.js +53 -45
  35. package/lib/module/components/TimePicker/TimePicker.styles.js.map +1 -1
  36. package/lib/module/components/TimePicker/TimePicker.web.js +24 -12
  37. package/lib/module/components/TimePicker/TimePicker.web.js.map +1 -1
  38. package/lib/module/components/TimePicker/TimeWheelPicker.js +45 -10
  39. package/lib/module/components/TimePicker/TimeWheelPicker.js.map +1 -1
  40. package/lib/module/components/TimePicker/TimeWheelPicker.web.js +339 -0
  41. package/lib/module/components/TimePicker/TimeWheelPicker.web.js.map +1 -0
  42. package/lib/module/components/TimePicker/index.js +3 -3
  43. package/lib/module/components/TimePicker/index.js.map +1 -1
  44. package/lib/module/components/WheelPicker/WheelPicker.js +21 -2
  45. package/lib/module/components/WheelPicker/WheelPicker.js.map +1 -1
  46. package/lib/module/components/WheelPicker/WheelPicker.styles.js +13 -8
  47. package/lib/module/components/WheelPicker/WheelPicker.styles.js.map +1 -1
  48. package/lib/module/components/WheelPicker/WheelPicker.web.js +146 -57
  49. package/lib/module/components/WheelPicker/WheelPicker.web.js.map +1 -1
  50. package/lib/module/context/ThemeOverrideContext.js +34 -0
  51. package/lib/module/context/ThemeOverrideContext.js.map +1 -0
  52. package/lib/module/index.js +3 -0
  53. package/lib/module/index.js.map +1 -1
  54. package/lib/module/utils/validation.js +74 -34
  55. package/lib/module/utils/validation.js.map +1 -1
  56. package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts +9 -0
  57. package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts.map +1 -1
  58. package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts +12 -10
  59. package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts.map +1 -1
  60. package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts +21 -0
  61. package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts.map +1 -0
  62. package/lib/typescript/components/CalendarGrid/DayCell.d.ts.map +1 -1
  63. package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts +12 -0
  64. package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts.map +1 -0
  65. package/lib/typescript/components/DatePicker/DatePicker.android.d.ts.map +1 -1
  66. package/lib/typescript/components/DatePicker/DatePicker.d.ts +12 -1
  67. package/lib/typescript/components/DatePicker/DatePicker.d.ts.map +1 -1
  68. package/lib/typescript/components/DatePicker/DatePicker.ios.d.ts.map +1 -1
  69. package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts +12 -13
  70. package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts.map +1 -1
  71. package/lib/typescript/components/DatePicker/DatePicker.web.d.ts.map +1 -1
  72. package/lib/typescript/components/TimePicker/ClockFace.d.ts.map +1 -1
  73. package/lib/typescript/components/TimePicker/ClockFace.web.d.ts +12 -0
  74. package/lib/typescript/components/TimePicker/ClockFace.web.d.ts.map +1 -0
  75. package/lib/typescript/components/TimePicker/MaterialTimePicker.d.ts.map +1 -1
  76. package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts +12 -0
  77. package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts.map +1 -0
  78. package/lib/typescript/components/TimePicker/TimePicker.android.d.ts.map +1 -1
  79. package/lib/typescript/components/TimePicker/TimePicker.ios.d.ts.map +1 -1
  80. package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts +29 -25
  81. package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts.map +1 -1
  82. package/lib/typescript/components/TimePicker/TimePicker.web.d.ts.map +1 -1
  83. package/lib/typescript/components/TimePicker/TimeWheelPicker.d.ts.map +1 -1
  84. package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts +11 -0
  85. package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts.map +1 -0
  86. package/lib/typescript/components/WheelPicker/WheelPicker.d.ts +14 -1
  87. package/lib/typescript/components/WheelPicker/WheelPicker.d.ts.map +1 -1
  88. package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts +9 -7
  89. package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts.map +1 -1
  90. package/lib/typescript/components/WheelPicker/WheelPicker.web.d.ts.map +1 -1
  91. package/lib/typescript/context/ThemeOverrideContext.d.ts +23 -0
  92. package/lib/typescript/context/ThemeOverrideContext.d.ts.map +1 -0
  93. package/lib/typescript/index.d.ts +4 -2
  94. package/lib/typescript/index.d.ts.map +1 -1
  95. package/lib/typescript/types/datepicker.d.ts +41 -0
  96. package/lib/typescript/types/datepicker.d.ts.map +1 -1
  97. package/lib/typescript/types/timepicker.d.ts +62 -0
  98. package/lib/typescript/types/timepicker.d.ts.map +1 -1
  99. package/lib/typescript/utils/validation.d.ts +47 -27
  100. package/lib/typescript/utils/validation.d.ts.map +1 -1
  101. package/package.json +8 -8
  102. package/src/components/CalendarGrid/CalendarGrid.styles.ts +21 -17
  103. package/src/components/CalendarGrid/CalendarGrid.tsx +98 -12
  104. package/src/components/CalendarGrid/CalendarGrid.web.tsx +305 -0
  105. package/src/components/CalendarGrid/DayCell.tsx +78 -59
  106. package/src/components/CalendarGrid/DayCell.web.tsx +129 -0
  107. package/src/components/DatePicker/DatePicker.android.tsx +14 -8
  108. package/src/components/DatePicker/DatePicker.ios.tsx +14 -8
  109. package/src/components/DatePicker/DatePicker.styles.ts +18 -22
  110. package/src/components/DatePicker/DatePicker.tsx +12 -1
  111. package/src/components/DatePicker/DatePicker.web.tsx +21 -13
  112. package/src/components/TimePicker/ClockFace.tsx +34 -8
  113. package/src/components/TimePicker/ClockFace.web.tsx +303 -0
  114. package/src/components/TimePicker/MaterialTimePicker.tsx +144 -13
  115. package/src/components/TimePicker/MaterialTimePicker.web.tsx +271 -0
  116. package/src/components/TimePicker/TimePicker.android.tsx +9 -1
  117. package/src/components/TimePicker/TimePicker.ios.tsx +10 -6
  118. package/src/components/TimePicker/TimePicker.styles.ts +52 -45
  119. package/src/components/TimePicker/TimePicker.web.tsx +17 -7
  120. package/src/components/TimePicker/TimeWheelPicker.tsx +60 -6
  121. package/src/components/TimePicker/TimeWheelPicker.web.tsx +401 -0
  122. package/src/components/WheelPicker/WheelPicker.styles.ts +12 -8
  123. package/src/components/WheelPicker/WheelPicker.tsx +24 -2
  124. package/src/components/WheelPicker/WheelPicker.web.tsx +153 -57
  125. package/src/context/ThemeOverrideContext.tsx +38 -0
  126. package/src/index.ts +11 -0
  127. package/src/types/datepicker.ts +44 -0
  128. package/src/types/timepicker.ts +74 -0
  129. package/src/utils/validation.ts +111 -55
  130. package/lib/module/unistyles.js +0 -9
  131. package/lib/module/unistyles.js.map +0 -1
  132. package/lib/typescript/unistyles.d.ts +0 -3
  133. package/lib/typescript/unistyles.d.ts.map +0 -1
  134. package/src/unistyles.ts +0 -6
@@ -0,0 +1,305 @@
1
+ /// <reference lib="dom" />
2
+ import React, { memo, useCallback, useMemo } from 'react';
3
+ import { FlatList, Pressable, StyleSheet, Text, View } from 'react-native';
4
+ import { useDatePickerOverrides } from '../../context/ThemeOverrideContext';
5
+ import {
6
+ addMonths,
7
+ compareDates,
8
+ formatYearMonth,
9
+ getDayOfWeek,
10
+ getFirstDayOfMonth,
11
+ getMonthDays,
12
+ isSameDay,
13
+ today,
14
+ } from '../../utils/date';
15
+ import { DayCell } from './DayCell';
16
+
17
+ interface CalendarGridProps {
18
+ value: Date;
19
+ onChange: (date: Date) => void;
20
+ minDate?: Date;
21
+ maxDate?: Date;
22
+ disabledDates?: Date[];
23
+ themeMode: 'ios' | 'android' | 'custom';
24
+ /**
25
+ * First day of the week: 0 = Sunday, 1 = Monday
26
+ * @default 0 (Sunday)
27
+ *
28
+ * TODO: This is a temporary solution. In the future, we need to add full
29
+ * locale support to handle different calendar formats, layouts, and
30
+ * localized day/month names across different regions.
31
+ */
32
+ weekStartsOn?: 0 | 1;
33
+ }
34
+
35
+ const CELL_SIZE = 44;
36
+
37
+ // Week day labels starting from Sunday
38
+ const WEEK_DAYS_SUNDAY_START = [
39
+ 'Sun',
40
+ 'Mon',
41
+ 'Tue',
42
+ 'Wed',
43
+ 'Thu',
44
+ 'Fri',
45
+ 'Sat',
46
+ ];
47
+ const WEEK_DAYS_MONDAY_START = [
48
+ 'Mon',
49
+ 'Tue',
50
+ 'Wed',
51
+ 'Thu',
52
+ 'Fri',
53
+ 'Sat',
54
+ 'Sun',
55
+ ];
56
+
57
+ // Default colors (light theme for web)
58
+ const DEFAULT_COLORS = {
59
+ backgroundColor: '#FFFFFF',
60
+ primaryColor: '#007AFF',
61
+ textColor: '#1C1C1E',
62
+ weekdayColor: '#8E8E93',
63
+ borderRadius: 14,
64
+ padding: 16,
65
+ };
66
+
67
+ /**
68
+ * Generate padding days for the month grid based on week start day
69
+ * TODO: This logic should be refactored when adding locale support
70
+ */
71
+ const generateMonthDays = (
72
+ currentMonth: Date,
73
+ weekStartsOn: 0 | 1,
74
+ ): (Date | null)[] => {
75
+ const firstDay = getFirstDayOfMonth(currentMonth);
76
+ // getDayOfWeek returns 0 for Sunday, 1 for Monday, etc.
77
+ const dayOfWeek = getDayOfWeek(firstDay);
78
+
79
+ // Calculate padding days based on week start
80
+ let paddingDays: number;
81
+ if (weekStartsOn === 0) {
82
+ // Sunday start: Sunday = 0 padding, Monday = 1, etc.
83
+ paddingDays = dayOfWeek;
84
+ } else {
85
+ // Monday start: Monday = 0 padding, Sunday = 6 padding
86
+ paddingDays = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
87
+ }
88
+
89
+ const days: (Date | null)[] = [];
90
+
91
+ for (let i = 0; i < paddingDays; i++) {
92
+ days.push(null);
93
+ }
94
+
95
+ const monthDays = getMonthDays(
96
+ currentMonth.getUTCFullYear(),
97
+ currentMonth.getUTCMonth(),
98
+ );
99
+ for (const day of monthDays) {
100
+ days.push(day);
101
+ }
102
+
103
+ const remaining = 7 - (days.length % 7);
104
+ if (remaining < 7) {
105
+ for (let i = 0; i < remaining; i++) {
106
+ days.push(null);
107
+ }
108
+ }
109
+
110
+ return days;
111
+ };
112
+
113
+ // Web-compatible styles (no unistyles dependency)
114
+ const webStyles = StyleSheet.create({
115
+ container: {
116
+ backgroundColor: '#FFFFFF',
117
+ borderRadius: 14,
118
+ padding: 16,
119
+ },
120
+ header: {
121
+ flexDirection: 'row',
122
+ justifyContent: 'space-between',
123
+ alignItems: 'center',
124
+ marginBottom: 16,
125
+ paddingHorizontal: 8,
126
+ },
127
+ navButton: {
128
+ width: 40,
129
+ height: 40,
130
+ justifyContent: 'center',
131
+ alignItems: 'center',
132
+ borderRadius: 8,
133
+ },
134
+ navText: {
135
+ fontSize: 24,
136
+ color: '#007AFF',
137
+ fontWeight: '600',
138
+ },
139
+ monthTitle: {
140
+ fontSize: 17,
141
+ fontWeight: '600',
142
+ color: '#1C1C1E',
143
+ },
144
+ weekDays: {
145
+ flexDirection: 'row',
146
+ marginBottom: 8,
147
+ },
148
+ weekDayText: {
149
+ flex: 1,
150
+ textAlign: 'center',
151
+ fontSize: 13,
152
+ fontWeight: '600',
153
+ color: '#8E8E93',
154
+ },
155
+ });
156
+
157
+ export const CalendarGrid: React.FC<CalendarGridProps> = memo(
158
+ ({
159
+ value,
160
+ onChange,
161
+ minDate,
162
+ maxDate,
163
+ disabledDates,
164
+ themeMode,
165
+ weekStartsOn = 0,
166
+ }) => {
167
+ const overrides = useDatePickerOverrides();
168
+ const [currentMonth, setCurrentMonth] = React.useState(() =>
169
+ getFirstDayOfMonth(value),
170
+ );
171
+
172
+ const days = useMemo(
173
+ () => generateMonthDays(currentMonth, weekStartsOn),
174
+ [currentMonth, weekStartsOn],
175
+ );
176
+
177
+ const weekDays =
178
+ weekStartsOn === 0 ? WEEK_DAYS_SUNDAY_START : WEEK_DAYS_MONDAY_START;
179
+
180
+ const todayDate = useMemo(() => today(), []);
181
+
182
+ const isDisabled = useCallback(
183
+ (date: Date | null): boolean => {
184
+ if (!date) return true;
185
+ if (minDate && compareDates(date, minDate) < 0) return true;
186
+ if (maxDate && compareDates(date, maxDate) > 0) return true;
187
+ if (disabledDates?.some((d) => isSameDay(date, d))) return true;
188
+ return false;
189
+ },
190
+ [minDate, maxDate, disabledDates],
191
+ );
192
+
193
+ const navigateMonth = useCallback((direction: 1 | -1) => {
194
+ setCurrentMonth((prev) => addMonths(prev, direction));
195
+ }, []);
196
+
197
+ const renderDay = useCallback(
198
+ ({ item }: { item: Date | null }) => (
199
+ <DayCell
200
+ date={item}
201
+ isSelected={item ? isSameDay(item, value) : false}
202
+ isToday={item ? isSameDay(item, todayDate) : false}
203
+ isDisabled={isDisabled(item)}
204
+ isWeekend={
205
+ item ? getDayOfWeek(item) === 0 || getDayOfWeek(item) === 6 : false
206
+ }
207
+ onPress={item && !isDisabled(item) ? () => onChange(item) : undefined}
208
+ />
209
+ ),
210
+ [value, todayDate, isDisabled, onChange],
211
+ );
212
+
213
+ const keyExtractor = useCallback(
214
+ (item: Date | null, index: number) =>
215
+ item?.toISOString() ?? `empty-${index}`,
216
+ [],
217
+ );
218
+
219
+ const getItemLayout = useCallback(
220
+ (_data: ArrayLike<Date | null> | null | undefined, index: number) => ({
221
+ length: CELL_SIZE,
222
+ offset: CELL_SIZE * Math.floor(index / 7),
223
+ index,
224
+ }),
225
+ [],
226
+ );
227
+
228
+ // Build override styles
229
+ const containerStyle = useMemo(
230
+ () => ({
231
+ backgroundColor:
232
+ overrides?.backgroundColor ?? DEFAULT_COLORS.backgroundColor,
233
+ borderRadius: overrides?.borderRadius ?? DEFAULT_COLORS.borderRadius,
234
+ padding: overrides?.padding ?? DEFAULT_COLORS.padding,
235
+ }),
236
+ [overrides],
237
+ );
238
+
239
+ const navTextStyle = useMemo(
240
+ () => ({
241
+ color: overrides?.primaryColor ?? DEFAULT_COLORS.primaryColor,
242
+ }),
243
+ [overrides],
244
+ );
245
+
246
+ const monthTitleStyle = useMemo(
247
+ () => ({
248
+ color: overrides?.textColor ?? DEFAULT_COLORS.textColor,
249
+ }),
250
+ [overrides],
251
+ );
252
+
253
+ const weekDayTextStyle = useMemo(
254
+ () => ({
255
+ color: overrides?.textWeekendColor ?? DEFAULT_COLORS.weekdayColor,
256
+ }),
257
+ [overrides],
258
+ );
259
+
260
+ return (
261
+ <View style={[webStyles.container, containerStyle]}>
262
+ <View style={webStyles.header}>
263
+ <Pressable
264
+ onPress={() => navigateMonth(-1)}
265
+ style={webStyles.navButton}
266
+ >
267
+ <Text style={[webStyles.navText, navTextStyle]}>‹</Text>
268
+ </Pressable>
269
+ <Text style={[webStyles.monthTitle, monthTitleStyle]}>
270
+ {formatYearMonth(currentMonth)}
271
+ </Text>
272
+ <Pressable
273
+ onPress={() => navigateMonth(1)}
274
+ style={webStyles.navButton}
275
+ >
276
+ <Text style={[webStyles.navText, navTextStyle]}>›</Text>
277
+ </Pressable>
278
+ </View>
279
+
280
+ <View style={webStyles.weekDays}>
281
+ {weekDays.map((day) => (
282
+ <Text key={day} style={[webStyles.weekDayText, weekDayTextStyle]}>
283
+ {day}
284
+ </Text>
285
+ ))}
286
+ </View>
287
+
288
+ <FlatList
289
+ data={days}
290
+ renderItem={renderDay}
291
+ keyExtractor={keyExtractor}
292
+ getItemLayout={getItemLayout}
293
+ numColumns={7}
294
+ scrollEnabled={false}
295
+ removeClippedSubviews={true}
296
+ maxToRenderPerBatch={14}
297
+ windowSize={3}
298
+ initialNumToRender={42}
299
+ />
300
+ </View>
301
+ );
302
+ },
303
+ );
304
+
305
+ CalendarGrid.displayName = 'CalendarGrid';
@@ -1,7 +1,7 @@
1
1
  import type React from 'react';
2
- import { memo } from 'react';
3
- import { Pressable, Text } from 'react-native';
4
- import { StyleSheet } from 'react-native-unistyles';
2
+ import { memo, useMemo } from 'react';
3
+ import { Pressable, StyleSheet, Text } from 'react-native';
4
+ import { useDatePickerOverrides } from '../../context/ThemeOverrideContext';
5
5
 
6
6
  interface DayCellProps {
7
7
  date: Date | null;
@@ -12,78 +12,97 @@ interface DayCellProps {
12
12
  onPress?: () => void;
13
13
  }
14
14
 
15
- const styles = StyleSheet.create((theme) => ({
15
+ // Default colors (dark theme)
16
+ const DEFAULT_COLORS = {
17
+ cellBackground: 'transparent',
18
+ cellSelected: '#4DA6FF',
19
+ cellToday: '#1E3A5F',
20
+ textDefault: '#FFFFFF',
21
+ textSelected: '#FFFFFF',
22
+ textDisabled: '#555555',
23
+ textWeekend: '#8E8E93',
24
+ primary: '#4DA6FF',
25
+ cellBorderRadius: 22,
26
+ };
27
+
28
+ const styles = StyleSheet.create({
16
29
  cell: {
17
30
  width: 44,
18
31
  height: 44,
19
32
  justifyContent: 'center',
20
33
  alignItems: 'center',
21
- backgroundColor: theme.colors.datepicker.cellBackground,
22
- variants: {
23
- state: {
24
- selected: {
25
- backgroundColor: theme.colors.datepicker.cellSelected,
26
- borderRadius: theme.radii.cell,
27
- },
28
- today: {
29
- backgroundColor: theme.colors.datepicker.cellToday,
30
- borderRadius: theme.radii.cell,
31
- borderWidth: 1,
32
- borderColor: theme.colors.primary.default,
33
- },
34
- disabled: {
35
- opacity: 0.4,
36
- },
37
- weekend: {},
38
- },
39
- },
40
34
  },
41
35
  text: {
42
- fontSize: theme.typography.dayCell.fontSize,
43
- fontWeight: theme.typography.dayCell.fontWeight,
44
- color: theme.colors.datepicker.textDefault,
45
- variants: {
46
- state: {
47
- selected: {
48
- color: theme.colors.datepicker.textSelected,
49
- fontWeight: '600',
50
- },
51
- today: {
52
- color: theme.colors.primary.default,
53
- fontWeight: '600',
54
- },
55
- disabled: {
56
- color: theme.colors.datepicker.textDisabled,
57
- },
58
- weekend: {
59
- color: theme.colors.datepicker.textWeekend,
60
- },
61
- },
62
- },
36
+ fontSize: 17,
37
+ fontWeight: '400',
63
38
  },
64
- }));
39
+ });
65
40
 
66
41
  export const DayCell: React.FC<DayCellProps> = memo(
67
42
  ({ date, isSelected, isToday, isDisabled, isWeekend, onPress }) => {
43
+ const overrides = useDatePickerOverrides();
44
+
45
+ // Build cell style based on state and overrides
46
+ // Use primaryColor as fallback for cellSelectedColor (consumer expectation)
47
+ const cellStyle = useMemo(() => {
48
+ const style: Record<string, unknown> = {
49
+ backgroundColor: DEFAULT_COLORS.cellBackground,
50
+ };
51
+
52
+ if (isSelected) {
53
+ style.backgroundColor =
54
+ overrides?.cellSelectedColor ??
55
+ overrides?.primaryColor ??
56
+ DEFAULT_COLORS.cellSelected;
57
+ style.borderRadius =
58
+ overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
59
+ } else if (isToday) {
60
+ style.backgroundColor =
61
+ overrides?.cellTodayColor ?? DEFAULT_COLORS.cellToday;
62
+ style.borderRadius =
63
+ overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
64
+ style.borderWidth = 1;
65
+ style.borderColor = overrides?.primaryColor ?? DEFAULT_COLORS.primary;
66
+ }
67
+
68
+ if (isDisabled) {
69
+ style.opacity = 0.4;
70
+ }
71
+
72
+ return style;
73
+ }, [overrides, isSelected, isToday, isDisabled]);
74
+
75
+ // Build text style based on state and overrides
76
+ const textStyle = useMemo(() => {
77
+ const style: Record<string, unknown> = {
78
+ color: overrides?.textColor ?? DEFAULT_COLORS.textDefault,
79
+ fontWeight: '400' as const,
80
+ };
81
+
82
+ if (isSelected) {
83
+ style.color =
84
+ overrides?.textSelectedColor ?? DEFAULT_COLORS.textSelected;
85
+ style.fontWeight = '600';
86
+ } else if (isToday) {
87
+ style.color = overrides?.primaryColor ?? DEFAULT_COLORS.primary;
88
+ style.fontWeight = '600';
89
+ } else if (isDisabled) {
90
+ style.color =
91
+ overrides?.textDisabledColor ?? DEFAULT_COLORS.textDisabled;
92
+ } else if (isWeekend) {
93
+ style.color = overrides?.textWeekendColor ?? DEFAULT_COLORS.textWeekend;
94
+ }
95
+
96
+ return style;
97
+ }, [overrides, isSelected, isToday, isDisabled, isWeekend]);
98
+
68
99
  if (!date) {
69
100
  return <Pressable style={styles.cell} disabled />;
70
101
  }
71
102
 
72
- const state = isDisabled
73
- ? 'disabled'
74
- : isSelected
75
- ? 'selected'
76
- : isToday
77
- ? 'today'
78
- : isWeekend
79
- ? 'weekend'
80
- : undefined;
81
-
82
- styles.useVariants({ state });
83
-
84
103
  return (
85
104
  <Pressable
86
- style={styles.cell}
105
+ style={[styles.cell, cellStyle]}
87
106
  onPress={onPress}
88
107
  disabled={isDisabled}
89
108
  accessibilityRole="button"
@@ -94,7 +113,7 @@ export const DayCell: React.FC<DayCellProps> = memo(
94
113
  }).format(date)}
95
114
  accessibilityState={{ selected: isSelected, disabled: isDisabled }}
96
115
  >
97
- <Text style={styles.text}>{date.getUTCDate()}</Text>
116
+ <Text style={[styles.text, textStyle]}>{date.getUTCDate()}</Text>
98
117
  </Pressable>
99
118
  );
100
119
  },
@@ -0,0 +1,129 @@
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
+ onPress?: () => void;
14
+ }
15
+
16
+ // Default colors (light theme for web)
17
+ const DEFAULT_COLORS = {
18
+ cellBackground: 'transparent',
19
+ cellSelected: '#007AFF',
20
+ cellToday: 'rgba(0, 122, 255, 0.1)',
21
+ textDefault: '#1C1C1E',
22
+ textSelected: '#FFFFFF',
23
+ textDisabled: '#8E8E93',
24
+ textWeekend: '#8E8E93',
25
+ primary: '#007AFF',
26
+ cellBorderRadius: 22,
27
+ };
28
+
29
+ // Web-compatible styles (no unistyles dependency)
30
+ const webStyles = StyleSheet.create({
31
+ cell: {
32
+ width: 44,
33
+ height: 44,
34
+ justifyContent: 'center',
35
+ alignItems: 'center',
36
+ },
37
+ text: {
38
+ fontSize: 17,
39
+ fontWeight: '400',
40
+ },
41
+ });
42
+
43
+ export const DayCell: React.FC<DayCellProps> = memo(
44
+ ({ date, isSelected, isToday, isDisabled, isWeekend, onPress }) => {
45
+ const overrides = useDatePickerOverrides();
46
+
47
+ // Build cell style based on state and overrides
48
+ // Use primaryColor as fallback for cellSelectedColor (consumer expectation)
49
+ const cellStyle = useMemo(() => {
50
+ const style: Record<string, unknown> = {
51
+ backgroundColor: DEFAULT_COLORS.cellBackground,
52
+ };
53
+
54
+ if (isSelected) {
55
+ style.backgroundColor =
56
+ overrides?.cellSelectedColor ??
57
+ overrides?.primaryColor ??
58
+ DEFAULT_COLORS.cellSelected;
59
+ style.borderRadius =
60
+ overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
61
+ } else if (isToday) {
62
+ style.backgroundColor =
63
+ overrides?.cellTodayColor ?? DEFAULT_COLORS.cellToday;
64
+ style.borderRadius =
65
+ overrides?.cellBorderRadius ?? DEFAULT_COLORS.cellBorderRadius;
66
+ style.borderWidth = 1;
67
+ style.borderColor = overrides?.primaryColor ?? DEFAULT_COLORS.primary;
68
+ }
69
+
70
+ if (isDisabled) {
71
+ style.opacity = 0.4;
72
+ }
73
+
74
+ return style;
75
+ }, [overrides, isSelected, isToday, isDisabled]);
76
+
77
+ // Build text style based on state and overrides
78
+ const textStyle = useMemo(() => {
79
+ const style: Record<string, unknown> = {
80
+ color: overrides?.textColor ?? DEFAULT_COLORS.textDefault,
81
+ fontWeight: '400' as const,
82
+ };
83
+
84
+ if (isSelected) {
85
+ style.color =
86
+ overrides?.textSelectedColor ?? DEFAULT_COLORS.textSelected;
87
+ style.fontWeight = '600';
88
+ } else if (isToday) {
89
+ style.color = overrides?.primaryColor ?? DEFAULT_COLORS.primary;
90
+ style.fontWeight = '600';
91
+ } else if (isDisabled) {
92
+ style.color =
93
+ overrides?.textDisabledColor ?? DEFAULT_COLORS.textDisabled;
94
+ } else if (isWeekend) {
95
+ style.color = overrides?.textWeekendColor ?? DEFAULT_COLORS.textWeekend;
96
+ }
97
+
98
+ return style;
99
+ }, [overrides, isSelected, isToday, isDisabled, isWeekend]);
100
+
101
+ if (!date) {
102
+ return <Pressable style={webStyles.cell} disabled />;
103
+ }
104
+
105
+ return (
106
+ <Pressable
107
+ style={[webStyles.cell, cellStyle]}
108
+ onPress={onPress}
109
+ disabled={isDisabled}
110
+ accessibilityRole="button"
111
+ accessibilityLabel={new Intl.DateTimeFormat('en-US', {
112
+ weekday: 'long',
113
+ month: 'long',
114
+ day: 'numeric',
115
+ }).format(date)}
116
+ accessibilityState={{ selected: isSelected, disabled: isDisabled }}
117
+ >
118
+ <Text style={[webStyles.text, textStyle]}>{date.getUTCDate()}</Text>
119
+ </Pressable>
120
+ );
121
+ },
122
+ (prev, next) =>
123
+ prev.date?.getTime() === next.date?.getTime() &&
124
+ prev.isSelected === next.isSelected &&
125
+ prev.isToday === next.isToday &&
126
+ prev.isDisabled === next.isDisabled,
127
+ );
128
+
129
+ DayCell.displayName = 'DayCell';
@@ -1,5 +1,6 @@
1
1
  import React, { Suspense, useCallback } 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';
@@ -38,6 +39,8 @@ export const DatePicker: React.FC<KaalDatePickerProps> = ({
38
39
  minDate,
39
40
  maxDate,
40
41
  disabledDates,
42
+ themeOverrides,
43
+ weekStartsOn = 0,
41
44
  }) => {
42
45
  const handleDateChange = useCallback(
43
46
  (date: Date) => {
@@ -57,13 +60,16 @@ export const DatePicker: React.FC<KaalDatePickerProps> = ({
57
60
  }
58
61
 
59
62
  return (
60
- <CalendarGrid
61
- value={value}
62
- onChange={onChange}
63
- minDate={minDate}
64
- maxDate={maxDate}
65
- disabledDates={disabledDates}
66
- themeMode={theme}
67
- />
63
+ <ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
64
+ <CalendarGrid
65
+ value={value}
66
+ onChange={onChange}
67
+ minDate={minDate}
68
+ maxDate={maxDate}
69
+ disabledDates={disabledDates}
70
+ themeMode={theme}
71
+ weekStartsOn={weekStartsOn}
72
+ />
73
+ </ThemeOverrideProvider>
68
74
  );
69
75
  };
@@ -1,5 +1,6 @@
1
1
  import React, { Suspense, useCallback } 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';
@@ -43,6 +44,8 @@ export const DatePicker: React.FC<KaalDatePickerProps> = ({
43
44
  minDate,
44
45
  maxDate,
45
46
  disabledDates,
47
+ themeOverrides,
48
+ weekStartsOn = 0,
46
49
  }) => {
47
50
  const handleDateChange = useCallback(
48
51
  (date: Date) => {
@@ -66,13 +69,16 @@ export const DatePicker: React.FC<KaalDatePickerProps> = ({
66
69
  }
67
70
 
68
71
  return (
69
- <CalendarGrid
70
- value={value}
71
- onChange={onChange}
72
- minDate={minDate}
73
- maxDate={maxDate}
74
- disabledDates={disabledDates}
75
- themeMode={theme}
76
- />
72
+ <ThemeOverrideProvider value={{ datePicker: themeOverrides }}>
73
+ <CalendarGrid
74
+ value={value}
75
+ onChange={onChange}
76
+ minDate={minDate}
77
+ maxDate={maxDate}
78
+ disabledDates={disabledDates}
79
+ themeMode={theme}
80
+ weekStartsOn={weekStartsOn}
81
+ />
82
+ </ThemeOverrideProvider>
77
83
  );
78
84
  };