@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.
Files changed (136) hide show
  1. package/README.md +165 -0
  2. package/lib/module/components/CalendarGrid/CalendarGrid.js +125 -29
  3. package/lib/module/components/CalendarGrid/CalendarGrid.js.map +1 -1
  4. package/lib/module/components/CalendarGrid/CalendarGrid.styles.js +22 -17
  5. package/lib/module/components/CalendarGrid/CalendarGrid.styles.js.map +1 -1
  6. package/lib/module/components/CalendarGrid/CalendarGrid.web.js +265 -0
  7. package/lib/module/components/CalendarGrid/CalendarGrid.web.js.map +1 -0
  8. package/lib/module/components/CalendarGrid/DayCell.js +77 -53
  9. package/lib/module/components/CalendarGrid/DayCell.js.map +1 -1
  10. package/lib/module/components/CalendarGrid/DayCell.web.js +124 -0
  11. package/lib/module/components/CalendarGrid/DayCell.web.js.map +1 -0
  12. package/lib/module/components/CalendarGrid/index.js +1 -1
  13. package/lib/module/components/CalendarGrid/index.js.map +1 -1
  14. package/lib/module/components/DatePicker/DatePicker.android.js +53 -21
  15. package/lib/module/components/DatePicker/DatePicker.android.js.map +1 -1
  16. package/lib/module/components/DatePicker/DatePicker.ios.js +55 -23
  17. package/lib/module/components/DatePicker/DatePicker.ios.js.map +1 -1
  18. package/lib/module/components/DatePicker/DatePicker.js.map +1 -1
  19. package/lib/module/components/DatePicker/DatePicker.styles.js +19 -20
  20. package/lib/module/components/DatePicker/DatePicker.styles.js.map +1 -1
  21. package/lib/module/components/DatePicker/DatePicker.web.js +59 -21
  22. package/lib/module/components/DatePicker/DatePicker.web.js.map +1 -1
  23. package/lib/module/components/TimePicker/ClockFace.js +27 -7
  24. package/lib/module/components/TimePicker/ClockFace.js.map +1 -1
  25. package/lib/module/components/TimePicker/ClockFace.web.js +253 -0
  26. package/lib/module/components/TimePicker/ClockFace.web.js.map +1 -0
  27. package/lib/module/components/TimePicker/MaterialTimePicker.js +68 -16
  28. package/lib/module/components/TimePicker/MaterialTimePicker.js.map +1 -1
  29. package/lib/module/components/TimePicker/MaterialTimePicker.web.js +231 -0
  30. package/lib/module/components/TimePicker/MaterialTimePicker.web.js.map +1 -0
  31. package/lib/module/components/TimePicker/TimePicker.android.js +13 -6
  32. package/lib/module/components/TimePicker/TimePicker.android.js.map +1 -1
  33. package/lib/module/components/TimePicker/TimePicker.ios.js +14 -7
  34. package/lib/module/components/TimePicker/TimePicker.ios.js.map +1 -1
  35. package/lib/module/components/TimePicker/TimePicker.styles.js +53 -45
  36. package/lib/module/components/TimePicker/TimePicker.styles.js.map +1 -1
  37. package/lib/module/components/TimePicker/TimePicker.web.js +24 -12
  38. package/lib/module/components/TimePicker/TimePicker.web.js.map +1 -1
  39. package/lib/module/components/TimePicker/TimeWheelPicker.js +45 -10
  40. package/lib/module/components/TimePicker/TimeWheelPicker.js.map +1 -1
  41. package/lib/module/components/TimePicker/TimeWheelPicker.web.js +339 -0
  42. package/lib/module/components/TimePicker/TimeWheelPicker.web.js.map +1 -0
  43. package/lib/module/components/TimePicker/index.js +3 -3
  44. package/lib/module/components/TimePicker/index.js.map +1 -1
  45. package/lib/module/components/WheelPicker/WheelPicker.js +21 -2
  46. package/lib/module/components/WheelPicker/WheelPicker.js.map +1 -1
  47. package/lib/module/components/WheelPicker/WheelPicker.styles.js +13 -8
  48. package/lib/module/components/WheelPicker/WheelPicker.styles.js.map +1 -1
  49. package/lib/module/components/WheelPicker/WheelPicker.web.js +146 -57
  50. package/lib/module/components/WheelPicker/WheelPicker.web.js.map +1 -1
  51. package/lib/module/context/ThemeOverrideContext.js +34 -0
  52. package/lib/module/context/ThemeOverrideContext.js.map +1 -0
  53. package/lib/module/index.js +3 -0
  54. package/lib/module/index.js.map +1 -1
  55. package/lib/module/utils/validation.js +74 -34
  56. package/lib/module/utils/validation.js.map +1 -1
  57. package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts +24 -3
  58. package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts.map +1 -1
  59. package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts +12 -10
  60. package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts.map +1 -1
  61. package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts +33 -0
  62. package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts.map +1 -0
  63. package/lib/typescript/components/CalendarGrid/DayCell.d.ts +3 -0
  64. package/lib/typescript/components/CalendarGrid/DayCell.d.ts.map +1 -1
  65. package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts +15 -0
  66. package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts.map +1 -0
  67. package/lib/typescript/components/DatePicker/DatePicker.android.d.ts.map +1 -1
  68. package/lib/typescript/components/DatePicker/DatePicker.d.ts +27 -4
  69. package/lib/typescript/components/DatePicker/DatePicker.d.ts.map +1 -1
  70. package/lib/typescript/components/DatePicker/DatePicker.ios.d.ts.map +1 -1
  71. package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts +12 -13
  72. package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts.map +1 -1
  73. package/lib/typescript/components/DatePicker/DatePicker.web.d.ts.map +1 -1
  74. package/lib/typescript/components/TimePicker/ClockFace.d.ts.map +1 -1
  75. package/lib/typescript/components/TimePicker/ClockFace.web.d.ts +12 -0
  76. package/lib/typescript/components/TimePicker/ClockFace.web.d.ts.map +1 -0
  77. package/lib/typescript/components/TimePicker/MaterialTimePicker.d.ts.map +1 -1
  78. package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts +12 -0
  79. package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts.map +1 -0
  80. package/lib/typescript/components/TimePicker/TimePicker.android.d.ts.map +1 -1
  81. package/lib/typescript/components/TimePicker/TimePicker.ios.d.ts.map +1 -1
  82. package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts +29 -25
  83. package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts.map +1 -1
  84. package/lib/typescript/components/TimePicker/TimePicker.web.d.ts.map +1 -1
  85. package/lib/typescript/components/TimePicker/TimeWheelPicker.d.ts.map +1 -1
  86. package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts +11 -0
  87. package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts.map +1 -0
  88. package/lib/typescript/components/WheelPicker/WheelPicker.d.ts +14 -1
  89. package/lib/typescript/components/WheelPicker/WheelPicker.d.ts.map +1 -1
  90. package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts +9 -7
  91. package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts.map +1 -1
  92. package/lib/typescript/components/WheelPicker/WheelPicker.web.d.ts.map +1 -1
  93. package/lib/typescript/context/ThemeOverrideContext.d.ts +23 -0
  94. package/lib/typescript/context/ThemeOverrideContext.d.ts.map +1 -0
  95. package/lib/typescript/index.d.ts +4 -2
  96. package/lib/typescript/index.d.ts.map +1 -1
  97. package/lib/typescript/types/datepicker.d.ts +78 -3
  98. package/lib/typescript/types/datepicker.d.ts.map +1 -1
  99. package/lib/typescript/types/timepicker.d.ts +62 -0
  100. package/lib/typescript/types/timepicker.d.ts.map +1 -1
  101. package/lib/typescript/utils/validation.d.ts +47 -27
  102. package/lib/typescript/utils/validation.d.ts.map +1 -1
  103. package/package.json +8 -8
  104. package/src/components/CalendarGrid/CalendarGrid.styles.ts +21 -17
  105. package/src/components/CalendarGrid/CalendarGrid.tsx +265 -85
  106. package/src/components/CalendarGrid/CalendarGrid.web.tsx +396 -0
  107. package/src/components/CalendarGrid/DayCell.tsx +122 -61
  108. package/src/components/CalendarGrid/DayCell.web.tsx +171 -0
  109. package/src/components/DatePicker/DatePicker.android.tsx +48 -24
  110. package/src/components/DatePicker/DatePicker.ios.tsx +51 -27
  111. package/src/components/DatePicker/DatePicker.styles.ts +18 -22
  112. package/src/components/DatePicker/DatePicker.tsx +35 -4
  113. package/src/components/DatePicker/DatePicker.web.tsx +55 -23
  114. package/src/components/TimePicker/ClockFace.tsx +34 -8
  115. package/src/components/TimePicker/ClockFace.web.tsx +303 -0
  116. package/src/components/TimePicker/MaterialTimePicker.tsx +144 -13
  117. package/src/components/TimePicker/MaterialTimePicker.web.tsx +271 -0
  118. package/src/components/TimePicker/TimePicker.android.tsx +9 -1
  119. package/src/components/TimePicker/TimePicker.ios.tsx +10 -6
  120. package/src/components/TimePicker/TimePicker.styles.ts +52 -45
  121. package/src/components/TimePicker/TimePicker.web.tsx +17 -7
  122. package/src/components/TimePicker/TimeWheelPicker.tsx +60 -6
  123. package/src/components/TimePicker/TimeWheelPicker.web.tsx +401 -0
  124. package/src/components/WheelPicker/WheelPicker.styles.ts +12 -8
  125. package/src/components/WheelPicker/WheelPicker.tsx +24 -2
  126. package/src/components/WheelPicker/WheelPicker.web.tsx +153 -57
  127. package/src/context/ThemeOverrideContext.tsx +38 -0
  128. package/src/index.ts +13 -0
  129. package/src/types/datepicker.ts +87 -3
  130. package/src/types/timepicker.ts +74 -0
  131. package/src/utils/validation.ts +111 -55
  132. package/lib/module/unistyles.js +0 -9
  133. package/lib/module/unistyles.js.map +0 -1
  134. package/lib/typescript/unistyles.d.ts +0 -3
  135. package/lib/typescript/unistyles.d.ts.map +0 -1
  136. package/src/unistyles.ts +0 -6
@@ -0,0 +1,303 @@
1
+ /// <reference lib="dom" />
2
+ import type React from 'react';
3
+ import { memo, useCallback, useMemo, useRef } from 'react';
4
+ import { View } from 'react-native';
5
+ import { useTimePickerOverrides } from '../../context/ThemeOverrideContext';
6
+ import { to12Hour, to24Hour } from '../../hooks/useTimePicker';
7
+ import type { ClockMode, TimeValue } from '../../types/timepicker';
8
+ import { styles } from './TimePicker.styles';
9
+
10
+ // Clock dimensions
11
+ const CLOCK_SIZE = 256;
12
+ const CLOCK_CENTER = CLOCK_SIZE / 2;
13
+ const OUTER_RADIUS = 96;
14
+ const SELECTION_DOT_RADIUS = 20;
15
+ const CENTER_DOT_RADIUS = 4;
16
+
17
+ // Hour positions (12 at top, clockwise)
18
+ const HOURS_12 = [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
19
+ const MINUTE_LABELS = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55];
20
+
21
+ // Default colors (dark theme)
22
+ const DEFAULT_COLORS = {
23
+ clockBackground: '#3F384C',
24
+ handColor: '#4DA6FF',
25
+ selectionDotColor: '#4DA6FF',
26
+ textColor: '#E6E1E5',
27
+ textSelectedColor: '#FFFFFF',
28
+ };
29
+
30
+ /**
31
+ * Converts clock position (0-11 for hours, 0-59 for minutes) to angle in degrees
32
+ * 12 o'clock is at -90 degrees (top)
33
+ */
34
+ const positionToAngle = (position: number, isMinutes = false): number => {
35
+ if (isMinutes) {
36
+ return position * 6 - 90; // 360/60 = 6 degrees per minute
37
+ }
38
+ return position * 30 - 90; // 360/12 = 30 degrees per position
39
+ };
40
+
41
+ /**
42
+ * Gets x,y coordinates on circle from angle and radius
43
+ */
44
+ const getPointOnCircle = (
45
+ angleDegrees: number,
46
+ radius: number,
47
+ ): { x: number; y: number } => {
48
+ const rad = (angleDegrees * Math.PI) / 180;
49
+ return {
50
+ x: CLOCK_CENTER + radius * Math.cos(rad),
51
+ y: CLOCK_CENTER + radius * Math.sin(rad),
52
+ };
53
+ };
54
+
55
+ interface ClockFaceProps {
56
+ value: TimeValue;
57
+ onChange: (time: TimeValue) => void;
58
+ mode: ClockMode;
59
+ onModeChange?: (mode: ClockMode) => void;
60
+ is24Hour?: boolean;
61
+ }
62
+
63
+ export const ClockFace: React.FC<ClockFaceProps> = memo(
64
+ ({ value, onChange, mode, onModeChange, is24Hour = false }) => {
65
+ const overrides = useTimePickerOverrides();
66
+ const svgRef = useRef<SVGSVGElement>(null);
67
+ const isDragging = useRef(false);
68
+ const { hour: hour12, period } = to12Hour(value.hours);
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
+
85
+ // Calculate hand end position based on current value
86
+ const handAngle = useMemo(() => {
87
+ if (mode === 'hours') {
88
+ const hourIndex = HOURS_12.indexOf(hour12);
89
+ return positionToAngle(hourIndex >= 0 ? hourIndex : 0);
90
+ }
91
+ return positionToAngle(value.minutes, true);
92
+ }, [mode, hour12, value.minutes]);
93
+
94
+ const handEndPos = getPointOnCircle(handAngle, OUTER_RADIUS);
95
+
96
+ const handleInteraction = useCallback(
97
+ (clientX: number, clientY: number) => {
98
+ if (!svgRef.current) return;
99
+
100
+ const rect = svgRef.current.getBoundingClientRect();
101
+ const x = clientX - rect.left;
102
+ const y = clientY - rect.top;
103
+
104
+ // Convert touch coordinates to angle
105
+ const dx = x - CLOCK_CENTER;
106
+ const dy = y - CLOCK_CENTER;
107
+ const angle = Math.atan2(dy, dx) * (180 / Math.PI);
108
+
109
+ // Normalize angle to 0-360, with 0 at top (12 o'clock)
110
+ const normalized = (((angle + 90) % 360) + 360) % 360;
111
+
112
+ if (mode === 'hours') {
113
+ // Round to nearest hour position
114
+ const position = Math.round(normalized / 30) % 12;
115
+ const hour = HOURS_12[position];
116
+ if (hour !== undefined) {
117
+ const newHours = to24Hour(hour, period);
118
+ onChange({ hours: newHours, minutes: value.minutes });
119
+ }
120
+ } else {
121
+ // Round to nearest minute
122
+ const minutes = Math.round(normalized / 6) % 60;
123
+ onChange({ hours: value.hours, minutes });
124
+ }
125
+ },
126
+ [mode, period, value, onChange],
127
+ );
128
+
129
+ const handleInteractionEnd = useCallback(() => {
130
+ // Switch to minutes mode after selecting hours
131
+ if (mode === 'hours' && onModeChange) {
132
+ // Small delay for visual feedback
133
+ setTimeout(() => onModeChange('minutes'), 200);
134
+ }
135
+ }, [mode, onModeChange]);
136
+
137
+ const handleMouseDown = useCallback(
138
+ (e: React.MouseEvent<SVGSVGElement>) => {
139
+ isDragging.current = true;
140
+ handleInteraction(e.clientX, e.clientY);
141
+ },
142
+ [handleInteraction],
143
+ );
144
+
145
+ const handleMouseMove = useCallback(
146
+ (e: React.MouseEvent<SVGSVGElement>) => {
147
+ if (!isDragging.current) return;
148
+ handleInteraction(e.clientX, e.clientY);
149
+ },
150
+ [handleInteraction],
151
+ );
152
+
153
+ const handleMouseUp = useCallback(() => {
154
+ if (isDragging.current) {
155
+ isDragging.current = false;
156
+ handleInteractionEnd();
157
+ }
158
+ }, [handleInteractionEnd]);
159
+
160
+ const handleTouchStart = useCallback(
161
+ (e: React.TouchEvent<SVGSVGElement>) => {
162
+ isDragging.current = true;
163
+ const touch = e.touches[0];
164
+ if (touch) {
165
+ handleInteraction(touch.clientX, touch.clientY);
166
+ }
167
+ },
168
+ [handleInteraction],
169
+ );
170
+
171
+ const handleTouchMove = useCallback(
172
+ (e: React.TouchEvent<SVGSVGElement>) => {
173
+ if (!isDragging.current) return;
174
+ const touch = e.touches[0];
175
+ if (touch) {
176
+ handleInteraction(touch.clientX, touch.clientY);
177
+ }
178
+ },
179
+ [handleInteraction],
180
+ );
181
+
182
+ const handleTouchEnd = useCallback(() => {
183
+ if (isDragging.current) {
184
+ isDragging.current = false;
185
+ handleInteractionEnd();
186
+ }
187
+ }, [handleInteractionEnd]);
188
+
189
+ // Render clock numbers
190
+ const numbers = useMemo(() => {
191
+ if (mode === 'hours') {
192
+ return HOURS_12.map((hour, index) => {
193
+ const angle = positionToAngle(index);
194
+ const pos = getPointOnCircle(angle, OUTER_RADIUS);
195
+ const isSelected = hour12 === hour;
196
+
197
+ return (
198
+ <text
199
+ key={hour}
200
+ x={pos.x}
201
+ y={pos.y}
202
+ textAnchor="middle"
203
+ dominantBaseline="central"
204
+ fontSize={14}
205
+ fontWeight={isSelected ? '500' : '400'}
206
+ fill={isSelected ? colors.textSelectedColor : colors.textColor}
207
+ style={{ userSelect: 'none' }}
208
+ >
209
+ {hour}
210
+ </text>
211
+ );
212
+ });
213
+ }
214
+
215
+ return MINUTE_LABELS.map((minute, index) => {
216
+ const angle = positionToAngle(index);
217
+ const pos = getPointOnCircle(angle, OUTER_RADIUS);
218
+ const isSelected = value.minutes === minute;
219
+
220
+ return (
221
+ <text
222
+ key={minute}
223
+ x={pos.x}
224
+ y={pos.y}
225
+ textAnchor="middle"
226
+ dominantBaseline="central"
227
+ fontSize={14}
228
+ fontWeight={isSelected ? '500' : '400'}
229
+ fill={isSelected ? colors.textSelectedColor : colors.textColor}
230
+ style={{ userSelect: 'none' }}
231
+ >
232
+ {minute.toString().padStart(2, '0')}
233
+ </text>
234
+ );
235
+ });
236
+ }, [mode, hour12, value.minutes, colors]);
237
+
238
+ return (
239
+ <View style={styles.clockContainer}>
240
+ <svg
241
+ ref={svgRef}
242
+ width={CLOCK_SIZE}
243
+ height={CLOCK_SIZE}
244
+ viewBox={`0 0 ${CLOCK_SIZE} ${CLOCK_SIZE}`}
245
+ onMouseDown={handleMouseDown}
246
+ onMouseMove={handleMouseMove}
247
+ onMouseUp={handleMouseUp}
248
+ onMouseLeave={handleMouseUp}
249
+ onTouchStart={handleTouchStart}
250
+ onTouchMove={handleTouchMove}
251
+ onTouchEnd={handleTouchEnd}
252
+ style={{ cursor: 'pointer', touchAction: 'none' }}
253
+ role="img"
254
+ aria-label={`Clock face for selecting ${mode === 'hours' ? 'hours' : 'minutes'}`}
255
+ >
256
+ <title>
257
+ {mode === 'hours'
258
+ ? 'Hour selection clock'
259
+ : 'Minute selection clock'}
260
+ </title>
261
+ {/* Background circle */}
262
+ <circle
263
+ cx={CLOCK_CENTER}
264
+ cy={CLOCK_CENTER}
265
+ r={CLOCK_SIZE / 2 - 4}
266
+ fill={colors.clockBackground}
267
+ />
268
+
269
+ {/* Selection dot (behind numbers) */}
270
+ <circle
271
+ cx={handEndPos.x}
272
+ cy={handEndPos.y}
273
+ r={SELECTION_DOT_RADIUS}
274
+ fill={colors.selectionDotColor}
275
+ />
276
+
277
+ {/* Clock hand */}
278
+ <line
279
+ x1={CLOCK_CENTER}
280
+ y1={CLOCK_CENTER}
281
+ x2={handEndPos.x}
282
+ y2={handEndPos.y}
283
+ stroke={colors.handColor}
284
+ strokeWidth={2}
285
+ />
286
+
287
+ {/* Center dot */}
288
+ <circle
289
+ cx={CLOCK_CENTER}
290
+ cy={CLOCK_CENTER}
291
+ r={CENTER_DOT_RADIUS}
292
+ fill={colors.handColor}
293
+ />
294
+
295
+ {/* Numbers */}
296
+ <g>{numbers}</g>
297
+ </svg>
298
+ </View>
299
+ );
300
+ },
301
+ );
302
+
303
+ ClockFace.displayName = 'ClockFace';
@@ -1,11 +1,27 @@
1
1
  import type React from 'react';
2
- import { memo, useCallback, useState } from 'react';
2
+ import { memo, useCallback, useMemo, useState } from 'react';
3
3
  import { Pressable, Text, View } from 'react-native';
4
+ import { useTimePickerOverrides } from '../../context/ThemeOverrideContext';
4
5
  import { to12Hour, to24Hour } from '../../hooks/useTimePicker';
5
6
  import type { ClockMode, TimePeriod, TimeValue } from '../../types/timepicker';
6
7
  import { ClockFace } from './ClockFace';
7
8
  import { styles } from './TimePicker.styles';
8
9
 
10
+ // Default colors (dark theme)
11
+ const DEFAULT_COLORS = {
12
+ containerBackground: '#2C2C2E',
13
+ headerColor: '#8E8E93',
14
+ timeFieldBackground: '#3A3A3C',
15
+ timeFieldActiveBackground: '#4DA6FF',
16
+ textColor: '#FFFFFF',
17
+ separatorColor: '#FFFFFF',
18
+ borderColor: '#48484A',
19
+ periodActiveBackground: 'rgba(77, 166, 255, 0.2)',
20
+ periodTextColor: '#8E8E93',
21
+ periodTextActiveColor: '#4DA6FF',
22
+ actionButtonColor: '#4DA6FF',
23
+ };
24
+
9
25
  interface MaterialTimePickerProps {
10
26
  value: TimeValue;
11
27
  onChange: (time: TimeValue) => void;
@@ -16,6 +32,7 @@ interface MaterialTimePickerProps {
16
32
 
17
33
  export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
18
34
  ({ value, onChange, is24Hour = false, onCancel, onConfirm }) => {
35
+ const overrides = useTimePickerOverrides();
19
36
  const [mode, setMode] = useState<ClockMode>('hours');
20
37
  const { hour: hour12, period } = to12Hour(value.hours);
21
38
 
@@ -45,10 +62,96 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
45
62
  : hour12.toString().padStart(2, '0');
46
63
  const displayMinute = value.minutes.toString().padStart(2, '0');
47
64
 
65
+ // Build override styles
66
+ const containerStyle = useMemo(
67
+ () => ({
68
+ backgroundColor:
69
+ overrides?.containerBackground ?? DEFAULT_COLORS.containerBackground,
70
+ }),
71
+ [overrides],
72
+ );
73
+
74
+ const headerStyle = useMemo(
75
+ () => ({
76
+ color: overrides?.headerColor ?? DEFAULT_COLORS.headerColor,
77
+ }),
78
+ [overrides],
79
+ );
80
+
81
+ const timeFieldStyle = useMemo(
82
+ () => ({
83
+ backgroundColor:
84
+ overrides?.timeFieldBackground ?? DEFAULT_COLORS.timeFieldBackground,
85
+ }),
86
+ [overrides],
87
+ );
88
+
89
+ const timeFieldActiveStyle = useMemo(
90
+ () => ({
91
+ backgroundColor:
92
+ overrides?.timeFieldActiveBackground ??
93
+ DEFAULT_COLORS.timeFieldActiveBackground,
94
+ }),
95
+ [overrides],
96
+ );
97
+
98
+ const textStyle = useMemo(
99
+ () => ({
100
+ color: overrides?.textColor ?? DEFAULT_COLORS.textColor,
101
+ }),
102
+ [overrides],
103
+ );
104
+
105
+ const separatorStyle = useMemo(
106
+ () => ({
107
+ color: overrides?.separatorColor ?? DEFAULT_COLORS.separatorColor,
108
+ }),
109
+ [overrides],
110
+ );
111
+
112
+ const periodContainerStyle = useMemo(
113
+ () => ({
114
+ borderColor: overrides?.periodBorderColor ?? DEFAULT_COLORS.borderColor,
115
+ }),
116
+ [overrides],
117
+ );
118
+
119
+ const periodActiveStyle = useMemo(
120
+ () => ({
121
+ backgroundColor:
122
+ overrides?.periodActiveBackground ??
123
+ DEFAULT_COLORS.periodActiveBackground,
124
+ }),
125
+ [overrides],
126
+ );
127
+
128
+ const periodTextStyle = useMemo(
129
+ () => ({
130
+ color: overrides?.periodTextColor ?? DEFAULT_COLORS.periodTextColor,
131
+ }),
132
+ [overrides],
133
+ );
134
+
135
+ const periodTextActiveStyle = useMemo(
136
+ () => ({
137
+ color:
138
+ overrides?.periodTextActiveColor ??
139
+ DEFAULT_COLORS.periodTextActiveColor,
140
+ }),
141
+ [overrides],
142
+ );
143
+
144
+ const actionButtonTextStyle = useMemo(
145
+ () => ({
146
+ color: overrides?.actionButtonColor ?? DEFAULT_COLORS.actionButtonColor,
147
+ }),
148
+ [overrides],
149
+ );
150
+
48
151
  return (
49
- <View style={styles.materialContainer}>
152
+ <View style={[styles.materialContainer, containerStyle]}>
50
153
  {/* Header */}
51
- <Text style={styles.materialHeader}>Select time</Text>
154
+ <Text style={[styles.materialHeader, headerStyle]}>Select time</Text>
52
155
 
53
156
  {/* Time Input Display */}
54
157
  <View style={styles.timeInputContainer}>
@@ -58,12 +161,17 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
58
161
  onPress={handleHourPress}
59
162
  style={[
60
163
  styles.timeField,
61
- mode === 'hours' && styles.timeFieldActive,
164
+ timeFieldStyle,
165
+ mode === 'hours' && [
166
+ styles.timeFieldActive,
167
+ timeFieldActiveStyle,
168
+ ],
62
169
  ]}
63
170
  >
64
171
  <Text
65
172
  style={[
66
173
  styles.timeFieldText,
174
+ textStyle,
67
175
  mode === 'hours' && styles.timeFieldTextActive,
68
176
  ]}
69
177
  >
@@ -72,19 +180,24 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
72
180
  </Pressable>
73
181
 
74
182
  {/* Separator */}
75
- <Text style={styles.timeSeparator}>:</Text>
183
+ <Text style={[styles.timeSeparator, separatorStyle]}>:</Text>
76
184
 
77
185
  {/* Minute Field */}
78
186
  <Pressable
79
187
  onPress={handleMinutePress}
80
188
  style={[
81
189
  styles.timeField,
82
- mode === 'minutes' && styles.timeFieldActive,
190
+ timeFieldStyle,
191
+ mode === 'minutes' && [
192
+ styles.timeFieldActive,
193
+ timeFieldActiveStyle,
194
+ ],
83
195
  ]}
84
196
  >
85
197
  <Text
86
198
  style={[
87
199
  styles.timeFieldText,
200
+ textStyle,
88
201
  mode === 'minutes' && styles.timeFieldTextActive,
89
202
  ]}
90
203
  >
@@ -95,19 +208,26 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
95
208
 
96
209
  {/* AM/PM Toggle (only for 12-hour format) */}
97
210
  {!is24Hour && (
98
- <View style={styles.periodToggleContainer}>
211
+ <View style={[styles.periodToggleContainer, periodContainerStyle]}>
99
212
  <Pressable
100
213
  onPress={() => handlePeriodChange('AM')}
101
214
  style={[
102
215
  styles.periodButton,
103
216
  styles.periodButtonTop,
104
- period === 'AM' && styles.periodButtonActive,
217
+ period === 'AM' && [
218
+ styles.periodButtonActive,
219
+ periodActiveStyle,
220
+ ],
105
221
  ]}
106
222
  >
107
223
  <Text
108
224
  style={[
109
225
  styles.periodButtonText,
110
- period === 'AM' && styles.periodButtonTextActive,
226
+ periodTextStyle,
227
+ period === 'AM' && [
228
+ styles.periodButtonTextActive,
229
+ periodTextActiveStyle,
230
+ ],
111
231
  ]}
112
232
  >
113
233
  AM
@@ -117,13 +237,20 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
117
237
  onPress={() => handlePeriodChange('PM')}
118
238
  style={[
119
239
  styles.periodButton,
120
- period === 'PM' && styles.periodButtonActive,
240
+ period === 'PM' && [
241
+ styles.periodButtonActive,
242
+ periodActiveStyle,
243
+ ],
121
244
  ]}
122
245
  >
123
246
  <Text
124
247
  style={[
125
248
  styles.periodButtonText,
126
- period === 'PM' && styles.periodButtonTextActive,
249
+ periodTextStyle,
250
+ period === 'PM' && [
251
+ styles.periodButtonTextActive,
252
+ periodTextActiveStyle,
253
+ ],
127
254
  ]}
128
255
  >
129
256
  PM
@@ -151,12 +278,16 @@ export const MaterialTimePicker: React.FC<MaterialTimePickerProps> = memo(
151
278
  <View style={styles.actionButtonsContainer}>
152
279
  {onCancel && (
153
280
  <Pressable style={styles.actionButton} onPress={onCancel}>
154
- <Text style={styles.actionButtonText}>Cancel</Text>
281
+ <Text style={[styles.actionButtonText, actionButtonTextStyle]}>
282
+ Cancel
283
+ </Text>
155
284
  </Pressable>
156
285
  )}
157
286
  {onConfirm && (
158
287
  <Pressable style={styles.actionButton} onPress={onConfirm}>
159
- <Text style={styles.actionButtonText}>OK</Text>
288
+ <Text style={[styles.actionButtonText, actionButtonTextStyle]}>
289
+ OK
290
+ </Text>
160
291
  </Pressable>
161
292
  )}
162
293
  </View>