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