@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.
- package/lib/module/components/CalendarGrid/CalendarGrid.js +47 -13
- package/lib/module/components/CalendarGrid/CalendarGrid.js.map +1 -1
- package/lib/module/components/CalendarGrid/CalendarGrid.styles.js +22 -17
- package/lib/module/components/CalendarGrid/CalendarGrid.styles.js.map +1 -1
- package/lib/module/components/CalendarGrid/CalendarGrid.web.js +203 -0
- package/lib/module/components/CalendarGrid/CalendarGrid.web.js.map +1 -0
- package/lib/module/components/CalendarGrid/DayCell.js +64 -52
- package/lib/module/components/CalendarGrid/DayCell.js.map +1 -1
- package/lib/module/components/CalendarGrid/DayCell.web.js +112 -0
- package/lib/module/components/CalendarGrid/DayCell.web.js.map +1 -0
- package/lib/module/components/CalendarGrid/index.js +1 -1
- package/lib/module/components/CalendarGrid/index.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.android.js +17 -8
- package/lib/module/components/DatePicker/DatePicker.android.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.ios.js +17 -8
- package/lib/module/components/DatePicker/DatePicker.ios.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.styles.js +19 -20
- package/lib/module/components/DatePicker/DatePicker.styles.js.map +1 -1
- package/lib/module/components/DatePicker/DatePicker.web.js +26 -12
- package/lib/module/components/DatePicker/DatePicker.web.js.map +1 -1
- package/lib/module/components/TimePicker/ClockFace.js +27 -7
- package/lib/module/components/TimePicker/ClockFace.js.map +1 -1
- package/lib/module/components/TimePicker/ClockFace.web.js +253 -0
- package/lib/module/components/TimePicker/ClockFace.web.js.map +1 -0
- package/lib/module/components/TimePicker/MaterialTimePicker.js +68 -16
- package/lib/module/components/TimePicker/MaterialTimePicker.js.map +1 -1
- package/lib/module/components/TimePicker/MaterialTimePicker.web.js +231 -0
- package/lib/module/components/TimePicker/MaterialTimePicker.web.js.map +1 -0
- package/lib/module/components/TimePicker/TimePicker.android.js +13 -6
- package/lib/module/components/TimePicker/TimePicker.android.js.map +1 -1
- package/lib/module/components/TimePicker/TimePicker.ios.js +14 -7
- package/lib/module/components/TimePicker/TimePicker.ios.js.map +1 -1
- package/lib/module/components/TimePicker/TimePicker.styles.js +53 -45
- package/lib/module/components/TimePicker/TimePicker.styles.js.map +1 -1
- package/lib/module/components/TimePicker/TimePicker.web.js +24 -12
- package/lib/module/components/TimePicker/TimePicker.web.js.map +1 -1
- package/lib/module/components/TimePicker/TimeWheelPicker.js +45 -10
- package/lib/module/components/TimePicker/TimeWheelPicker.js.map +1 -1
- package/lib/module/components/TimePicker/TimeWheelPicker.web.js +339 -0
- package/lib/module/components/TimePicker/TimeWheelPicker.web.js.map +1 -0
- package/lib/module/components/TimePicker/index.js +3 -3
- package/lib/module/components/TimePicker/index.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelPicker.js +21 -2
- package/lib/module/components/WheelPicker/WheelPicker.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelPicker.styles.js +13 -8
- package/lib/module/components/WheelPicker/WheelPicker.styles.js.map +1 -1
- package/lib/module/components/WheelPicker/WheelPicker.web.js +146 -57
- package/lib/module/components/WheelPicker/WheelPicker.web.js.map +1 -1
- package/lib/module/context/ThemeOverrideContext.js +34 -0
- package/lib/module/context/ThemeOverrideContext.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/validation.js +74 -34
- package/lib/module/utils/validation.js.map +1 -1
- package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts +9 -0
- package/lib/typescript/components/CalendarGrid/CalendarGrid.d.ts.map +1 -1
- package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts +12 -10
- package/lib/typescript/components/CalendarGrid/CalendarGrid.styles.d.ts.map +1 -1
- package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts +21 -0
- package/lib/typescript/components/CalendarGrid/CalendarGrid.web.d.ts.map +1 -0
- package/lib/typescript/components/CalendarGrid/DayCell.d.ts.map +1 -1
- package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts +12 -0
- package/lib/typescript/components/CalendarGrid/DayCell.web.d.ts.map +1 -0
- package/lib/typescript/components/DatePicker/DatePicker.android.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.d.ts +12 -1
- package/lib/typescript/components/DatePicker/DatePicker.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.ios.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts +12 -13
- package/lib/typescript/components/DatePicker/DatePicker.styles.d.ts.map +1 -1
- package/lib/typescript/components/DatePicker/DatePicker.web.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/ClockFace.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/ClockFace.web.d.ts +12 -0
- package/lib/typescript/components/TimePicker/ClockFace.web.d.ts.map +1 -0
- package/lib/typescript/components/TimePicker/MaterialTimePicker.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts +12 -0
- package/lib/typescript/components/TimePicker/MaterialTimePicker.web.d.ts.map +1 -0
- package/lib/typescript/components/TimePicker/TimePicker.android.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimePicker.ios.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts +29 -25
- package/lib/typescript/components/TimePicker/TimePicker.styles.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimePicker.web.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimeWheelPicker.d.ts.map +1 -1
- package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts +11 -0
- package/lib/typescript/components/TimePicker/TimeWheelPicker.web.d.ts.map +1 -0
- package/lib/typescript/components/WheelPicker/WheelPicker.d.ts +14 -1
- package/lib/typescript/components/WheelPicker/WheelPicker.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts +9 -7
- package/lib/typescript/components/WheelPicker/WheelPicker.styles.d.ts.map +1 -1
- package/lib/typescript/components/WheelPicker/WheelPicker.web.d.ts.map +1 -1
- package/lib/typescript/context/ThemeOverrideContext.d.ts +23 -0
- package/lib/typescript/context/ThemeOverrideContext.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/types/datepicker.d.ts +41 -0
- package/lib/typescript/types/datepicker.d.ts.map +1 -1
- package/lib/typescript/types/timepicker.d.ts +62 -0
- package/lib/typescript/types/timepicker.d.ts.map +1 -1
- package/lib/typescript/utils/validation.d.ts +47 -27
- package/lib/typescript/utils/validation.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/components/CalendarGrid/CalendarGrid.styles.ts +21 -17
- package/src/components/CalendarGrid/CalendarGrid.tsx +98 -12
- package/src/components/CalendarGrid/CalendarGrid.web.tsx +305 -0
- package/src/components/CalendarGrid/DayCell.tsx +78 -59
- package/src/components/CalendarGrid/DayCell.web.tsx +129 -0
- package/src/components/DatePicker/DatePicker.android.tsx +14 -8
- package/src/components/DatePicker/DatePicker.ios.tsx +14 -8
- package/src/components/DatePicker/DatePicker.styles.ts +18 -22
- package/src/components/DatePicker/DatePicker.tsx +12 -1
- package/src/components/DatePicker/DatePicker.web.tsx +21 -13
- package/src/components/TimePicker/ClockFace.tsx +34 -8
- package/src/components/TimePicker/ClockFace.web.tsx +303 -0
- package/src/components/TimePicker/MaterialTimePicker.tsx +144 -13
- package/src/components/TimePicker/MaterialTimePicker.web.tsx +271 -0
- package/src/components/TimePicker/TimePicker.android.tsx +9 -1
- package/src/components/TimePicker/TimePicker.ios.tsx +10 -6
- package/src/components/TimePicker/TimePicker.styles.ts +52 -45
- package/src/components/TimePicker/TimePicker.web.tsx +17 -7
- package/src/components/TimePicker/TimeWheelPicker.tsx +60 -6
- package/src/components/TimePicker/TimeWheelPicker.web.tsx +401 -0
- package/src/components/WheelPicker/WheelPicker.styles.ts +12 -8
- package/src/components/WheelPicker/WheelPicker.tsx +24 -2
- package/src/components/WheelPicker/WheelPicker.web.tsx +153 -57
- package/src/context/ThemeOverrideContext.tsx +38 -0
- package/src/index.ts +11 -0
- package/src/types/datepicker.ts +44 -0
- package/src/types/timepicker.ts +74 -0
- package/src/utils/validation.ts +111 -55
- package/lib/module/unistyles.js +0 -9
- package/lib/module/unistyles.js.map +0 -1
- package/lib/typescript/unistyles.d.ts +0 -3
- package/lib/typescript/unistyles.d.ts.map +0 -1
- package/src/unistyles.ts +0 -6
|
@@ -1,12 +1,7 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
1
2
|
import type React from 'react';
|
|
2
|
-
import { useCallback, useMemo } from 'react';
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
4
|
import { StyleSheet as RNStyleSheet, Text, View } from 'react-native';
|
|
4
|
-
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
5
|
-
import Animated, {
|
|
6
|
-
useAnimatedStyle,
|
|
7
|
-
useSharedValue,
|
|
8
|
-
withSpring,
|
|
9
|
-
} from 'react-native-reanimated';
|
|
10
5
|
|
|
11
6
|
const ITEM_HEIGHT = 44;
|
|
12
7
|
const VISIBLE_ITEMS = 5;
|
|
@@ -59,57 +54,162 @@ const WheelColumn: React.FC<{
|
|
|
59
54
|
items: { value: number; label: string }[];
|
|
60
55
|
selectedIndex: number;
|
|
61
56
|
onSelect: (index: number) => void;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
57
|
+
label?: string;
|
|
58
|
+
}> = ({ items, selectedIndex, onSelect, label = 'Select value' }) => {
|
|
59
|
+
const scrollRef = useRef<HTMLDivElement>(null);
|
|
60
|
+
const isScrolling = useRef(false);
|
|
61
|
+
const scrollTimeout = useRef<ReturnType<typeof setTimeout>>();
|
|
62
|
+
|
|
63
|
+
// Scroll to selected item on mount and when selection changes externally
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (scrollRef.current && !isScrolling.current) {
|
|
66
|
+
scrollRef.current.scrollTop = selectedIndex * ITEM_HEIGHT;
|
|
67
|
+
}
|
|
68
|
+
}, [selectedIndex]);
|
|
69
|
+
|
|
70
|
+
const handleScroll = useCallback(() => {
|
|
71
|
+
if (!scrollRef.current) return;
|
|
72
|
+
|
|
73
|
+
isScrolling.current = true;
|
|
74
|
+
|
|
75
|
+
// Clear existing timeout
|
|
76
|
+
if (scrollTimeout.current) {
|
|
77
|
+
clearTimeout(scrollTimeout.current);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Debounce scroll end detection
|
|
81
|
+
scrollTimeout.current = setTimeout(() => {
|
|
82
|
+
if (!scrollRef.current) return;
|
|
83
|
+
|
|
84
|
+
const scrollTop = scrollRef.current.scrollTop;
|
|
85
|
+
const newIndex = Math.round(scrollTop / ITEM_HEIGHT);
|
|
86
|
+
const clampedIndex = Math.max(0, Math.min(items.length - 1, newIndex));
|
|
87
|
+
|
|
88
|
+
// Snap to nearest item
|
|
89
|
+
scrollRef.current.scrollTop = clampedIndex * ITEM_HEIGHT;
|
|
90
|
+
|
|
91
|
+
if (clampedIndex !== selectedIndex) {
|
|
92
|
+
onSelect(clampedIndex);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
isScrolling.current = false;
|
|
96
|
+
}, 100);
|
|
97
|
+
}, [items.length, selectedIndex, onSelect]);
|
|
98
|
+
|
|
99
|
+
// Keyboard navigation for spinbutton behavior (like native input[type="time"])
|
|
100
|
+
const handleKeyDown = useCallback(
|
|
101
|
+
(e: React.KeyboardEvent) => {
|
|
102
|
+
let newIndex = selectedIndex;
|
|
103
|
+
|
|
104
|
+
switch (e.key) {
|
|
105
|
+
case 'ArrowUp':
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
newIndex = Math.max(0, selectedIndex - 1);
|
|
108
|
+
break;
|
|
109
|
+
case 'ArrowDown':
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
newIndex = Math.min(items.length - 1, selectedIndex + 1);
|
|
112
|
+
break;
|
|
113
|
+
case 'Home':
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
newIndex = 0;
|
|
116
|
+
break;
|
|
117
|
+
case 'End':
|
|
118
|
+
e.preventDefault();
|
|
119
|
+
newIndex = items.length - 1;
|
|
120
|
+
break;
|
|
121
|
+
case 'PageUp':
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
newIndex = Math.max(0, selectedIndex - 5);
|
|
124
|
+
break;
|
|
125
|
+
case 'PageDown':
|
|
126
|
+
e.preventDefault();
|
|
127
|
+
newIndex = Math.min(items.length - 1, selectedIndex + 5);
|
|
128
|
+
break;
|
|
129
|
+
default:
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (newIndex !== selectedIndex) {
|
|
134
|
+
if (scrollRef.current) {
|
|
135
|
+
scrollRef.current.scrollTop = newIndex * ITEM_HEIGHT;
|
|
136
|
+
}
|
|
137
|
+
onSelect(newIndex);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
[selectedIndex, items.length, onSelect],
|
|
90
141
|
);
|
|
91
142
|
|
|
92
|
-
const
|
|
93
|
-
transform: [{ translateY: translateY.value }],
|
|
94
|
-
}));
|
|
143
|
+
const currentItem = items[selectedIndex];
|
|
95
144
|
|
|
96
145
|
return (
|
|
97
146
|
<View style={webStyles.column}>
|
|
98
147
|
<View style={webStyles.selectionHighlight} />
|
|
99
148
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
149
|
+
{/* Spinbutton container - mimics input[type="time"] accessibility */}
|
|
150
|
+
<div
|
|
151
|
+
ref={scrollRef}
|
|
152
|
+
role="spinbutton"
|
|
153
|
+
tabIndex={0}
|
|
154
|
+
aria-label={label}
|
|
155
|
+
aria-valuenow={currentItem?.value}
|
|
156
|
+
aria-valuemin={items[0]?.value}
|
|
157
|
+
aria-valuemax={items[items.length - 1]?.value}
|
|
158
|
+
aria-valuetext={currentItem?.label}
|
|
159
|
+
onScroll={handleScroll}
|
|
160
|
+
onKeyDown={handleKeyDown}
|
|
161
|
+
onClick={(e) => {
|
|
162
|
+
const target = e.target as HTMLElement;
|
|
163
|
+
const item = target.closest('[data-index]') as HTMLElement | null;
|
|
164
|
+
if (item && scrollRef.current) {
|
|
165
|
+
const index = Number(item.dataset.index);
|
|
166
|
+
scrollRef.current.scrollTop = index * ITEM_HEIGHT;
|
|
167
|
+
onSelect(index);
|
|
168
|
+
}
|
|
169
|
+
}}
|
|
170
|
+
style={{
|
|
171
|
+
height: CONTAINER_HEIGHT,
|
|
172
|
+
overflowY: 'auto',
|
|
173
|
+
scrollSnapType: 'y mandatory',
|
|
174
|
+
scrollBehavior: 'smooth',
|
|
175
|
+
position: 'relative',
|
|
176
|
+
zIndex: 1,
|
|
177
|
+
outline: 'none',
|
|
178
|
+
// Hide scrollbar
|
|
179
|
+
scrollbarWidth: 'none',
|
|
180
|
+
msOverflowStyle: 'none',
|
|
181
|
+
}}
|
|
182
|
+
>
|
|
183
|
+
{/* @ts-ignore - webkit scrollbar hiding */}
|
|
184
|
+
<style>{`
|
|
185
|
+
div::-webkit-scrollbar {
|
|
186
|
+
display: none;
|
|
187
|
+
}
|
|
188
|
+
`}</style>
|
|
189
|
+
|
|
190
|
+
{/* Top padding */}
|
|
191
|
+
<div style={{ height: ITEM_HEIGHT * 2, flexShrink: 0 }} />
|
|
103
192
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
193
|
+
{items.map((item, index) => (
|
|
194
|
+
<div
|
|
195
|
+
key={item.value}
|
|
196
|
+
data-index={index}
|
|
197
|
+
style={{
|
|
198
|
+
height: ITEM_HEIGHT,
|
|
199
|
+
display: 'flex',
|
|
200
|
+
justifyContent: 'center',
|
|
201
|
+
alignItems: 'center',
|
|
202
|
+
scrollSnapAlign: 'center',
|
|
203
|
+
cursor: 'pointer',
|
|
204
|
+
}}
|
|
205
|
+
>
|
|
206
|
+
<Text style={webStyles.itemText}>{item.label}</Text>
|
|
207
|
+
</div>
|
|
208
|
+
))}
|
|
109
209
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
</
|
|
210
|
+
{/* Bottom padding */}
|
|
211
|
+
<div style={{ height: ITEM_HEIGHT * 2, flexShrink: 0 }} />
|
|
212
|
+
</div>
|
|
113
213
|
</View>
|
|
114
214
|
);
|
|
115
215
|
};
|
|
@@ -179,11 +279,13 @@ export const WheelPicker: React.FC<WheelPickerProps> = ({
|
|
|
179
279
|
items={months}
|
|
180
280
|
selectedIndex={value.getUTCMonth()}
|
|
181
281
|
onSelect={handleMonthChange}
|
|
282
|
+
label="Month"
|
|
182
283
|
/>
|
|
183
284
|
<WheelColumn
|
|
184
285
|
items={days}
|
|
185
286
|
selectedIndex={value.getUTCDate() - 1}
|
|
186
287
|
onSelect={handleDayChange}
|
|
288
|
+
label="Day"
|
|
187
289
|
/>
|
|
188
290
|
<WheelColumn
|
|
189
291
|
items={years}
|
|
@@ -191,6 +293,7 @@ export const WheelPicker: React.FC<WheelPickerProps> = ({
|
|
|
191
293
|
(y) => y.value === value.getUTCFullYear(),
|
|
192
294
|
)}
|
|
193
295
|
onSelect={handleYearChange}
|
|
296
|
+
label="Year"
|
|
194
297
|
/>
|
|
195
298
|
</View>
|
|
196
299
|
);
|
|
@@ -210,6 +313,7 @@ const webStyles = RNStyleSheet.create({
|
|
|
210
313
|
flex: 1,
|
|
211
314
|
height: CONTAINER_HEIGHT,
|
|
212
315
|
overflow: 'hidden',
|
|
316
|
+
position: 'relative',
|
|
213
317
|
},
|
|
214
318
|
selectionHighlight: {
|
|
215
319
|
position: 'absolute',
|
|
@@ -221,14 +325,6 @@ const webStyles = RNStyleSheet.create({
|
|
|
221
325
|
borderRadius: 8,
|
|
222
326
|
zIndex: 0,
|
|
223
327
|
},
|
|
224
|
-
itemsContainer: {
|
|
225
|
-
zIndex: 1,
|
|
226
|
-
},
|
|
227
|
-
item: {
|
|
228
|
-
height: ITEM_HEIGHT,
|
|
229
|
-
justifyContent: 'center',
|
|
230
|
-
alignItems: 'center',
|
|
231
|
-
},
|
|
232
328
|
itemText: {
|
|
233
329
|
fontSize: 21,
|
|
234
330
|
fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif',
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
import type { DatePickerThemeOverrides } from '../types/datepicker';
|
|
3
|
+
import type { TimePickerThemeOverrides } from '../types/timepicker';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Combined theme overrides context value
|
|
7
|
+
*/
|
|
8
|
+
export interface ThemeOverrideContextValue {
|
|
9
|
+
datePicker?: DatePickerThemeOverrides;
|
|
10
|
+
timePicker?: TimePickerThemeOverrides;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const ThemeOverrideContext = createContext<ThemeOverrideContextValue>({});
|
|
14
|
+
|
|
15
|
+
export const ThemeOverrideProvider = ThemeOverrideContext.Provider;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hook to access DatePicker theme overrides
|
|
19
|
+
*/
|
|
20
|
+
export function useDatePickerOverrides(): DatePickerThemeOverrides | undefined {
|
|
21
|
+
const context = useContext(ThemeOverrideContext);
|
|
22
|
+
return context.datePicker;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Hook to access TimePicker theme overrides
|
|
27
|
+
*/
|
|
28
|
+
export function useTimePickerOverrides(): TimePickerThemeOverrides | undefined {
|
|
29
|
+
const context = useContext(ThemeOverrideContext);
|
|
30
|
+
return context.timePicker;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Hook to access all theme overrides
|
|
35
|
+
*/
|
|
36
|
+
export function useThemeOverrides(): ThemeOverrideContextValue {
|
|
37
|
+
return useContext(ThemeOverrideContext);
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -65,6 +65,7 @@ export type {
|
|
|
65
65
|
DatePickerTheme,
|
|
66
66
|
DatePickerVariant,
|
|
67
67
|
DatePickerProps,
|
|
68
|
+
DatePickerThemeOverrides,
|
|
68
69
|
} from './types';
|
|
69
70
|
|
|
70
71
|
// Time picker types
|
|
@@ -74,4 +75,14 @@ export type {
|
|
|
74
75
|
Time12Hour,
|
|
75
76
|
MinuteInterval,
|
|
76
77
|
TimePickerTheme,
|
|
78
|
+
TimePickerThemeOverrides,
|
|
77
79
|
} from './types';
|
|
80
|
+
|
|
81
|
+
// Theme override context (for advanced usage)
|
|
82
|
+
export {
|
|
83
|
+
ThemeOverrideProvider,
|
|
84
|
+
useDatePickerOverrides,
|
|
85
|
+
useTimePickerOverrides,
|
|
86
|
+
useThemeOverrides,
|
|
87
|
+
} from './context/ThemeOverrideContext';
|
|
88
|
+
export type { ThemeOverrideContextValue } from './context/ThemeOverrideContext';
|
package/src/types/datepicker.ts
CHANGED
|
@@ -4,6 +4,39 @@ export type DatePickerTheme = 'native' | 'ios' | 'android' | 'custom';
|
|
|
4
4
|
|
|
5
5
|
export type DatePickerVariant = 'wheel' | 'calendar' | 'compact';
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Theme overrides for DatePicker components.
|
|
9
|
+
* These allow customizing colors without matching Kaal's internal theme structure.
|
|
10
|
+
*/
|
|
11
|
+
export interface DatePickerThemeOverrides {
|
|
12
|
+
// Calendar cell colors
|
|
13
|
+
/** Background color of selected date cell */
|
|
14
|
+
cellSelectedColor?: string;
|
|
15
|
+
/** Background color of today's date cell */
|
|
16
|
+
cellTodayColor?: string;
|
|
17
|
+
/** Default text color for dates */
|
|
18
|
+
textColor?: string;
|
|
19
|
+
/** Text color for selected date */
|
|
20
|
+
textSelectedColor?: string;
|
|
21
|
+
/** Text color for disabled dates */
|
|
22
|
+
textDisabledColor?: string;
|
|
23
|
+
/** Text color for weekend dates */
|
|
24
|
+
textWeekendColor?: string;
|
|
25
|
+
/** Primary accent color (navigation arrows, today border) */
|
|
26
|
+
primaryColor?: string;
|
|
27
|
+
/** Header background color */
|
|
28
|
+
headerBackground?: string;
|
|
29
|
+
/** Container background color */
|
|
30
|
+
backgroundColor?: string;
|
|
31
|
+
// Layout
|
|
32
|
+
/** Border radius for calendar container */
|
|
33
|
+
borderRadius?: number;
|
|
34
|
+
/** Border radius for date cells */
|
|
35
|
+
cellBorderRadius?: number;
|
|
36
|
+
/** Padding for calendar container */
|
|
37
|
+
padding?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
7
40
|
export interface DatePickerProps {
|
|
8
41
|
value: Date;
|
|
9
42
|
onChange: (date: Date) => void;
|
|
@@ -14,4 +47,15 @@ export interface DatePickerProps {
|
|
|
14
47
|
maxDate?: Date;
|
|
15
48
|
disabledDates?: Date[];
|
|
16
49
|
locale?: string;
|
|
50
|
+
/**
|
|
51
|
+
* First day of the week: 0 = Sunday, 1 = Monday
|
|
52
|
+
* @default 0 (Sunday)
|
|
53
|
+
*
|
|
54
|
+
* TODO: This is a temporary solution. In the future, we need to add full
|
|
55
|
+
* locale support to handle different calendar formats, layouts, and
|
|
56
|
+
* localized day/month names across different regions.
|
|
57
|
+
*/
|
|
58
|
+
weekStartsOn?: 0 | 1;
|
|
59
|
+
/** Custom theme overrides for styling without matching Kaal's theme structure */
|
|
60
|
+
themeOverrides?: DatePickerThemeOverrides;
|
|
17
61
|
}
|
package/src/types/timepicker.ts
CHANGED
|
@@ -18,6 +18,78 @@ export type TimePickerTheme = 'native' | 'ios' | 'android';
|
|
|
18
18
|
*/
|
|
19
19
|
export type MinuteInterval = 1 | 5 | 10 | 15 | 30;
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Theme overrides for TimePicker components.
|
|
23
|
+
* These allow customizing colors without matching Kaal's internal theme structure.
|
|
24
|
+
*/
|
|
25
|
+
export interface TimePickerThemeOverrides {
|
|
26
|
+
// Clock face (Material style)
|
|
27
|
+
/** Background color of the clock face */
|
|
28
|
+
clockBackground?: string;
|
|
29
|
+
/** Color of the clock hand */
|
|
30
|
+
clockHandColor?: string;
|
|
31
|
+
/** Color of clock numbers */
|
|
32
|
+
clockTextColor?: string;
|
|
33
|
+
/** Color of selected clock number */
|
|
34
|
+
clockTextSelectedColor?: string;
|
|
35
|
+
/** Color of the center dot */
|
|
36
|
+
clockCenterColor?: string;
|
|
37
|
+
/** Color of the selection dot on clock edge */
|
|
38
|
+
clockSelectionColor?: string;
|
|
39
|
+
|
|
40
|
+
// Period toggle (AM/PM)
|
|
41
|
+
/** Background color of period buttons */
|
|
42
|
+
periodBackground?: string;
|
|
43
|
+
/** Background color of active period button */
|
|
44
|
+
periodActiveBackground?: string;
|
|
45
|
+
/** Border color of period buttons */
|
|
46
|
+
periodBorderColor?: string;
|
|
47
|
+
/** Text color of period buttons */
|
|
48
|
+
periodTextColor?: string;
|
|
49
|
+
/** Text color of active period button */
|
|
50
|
+
periodTextActiveColor?: string;
|
|
51
|
+
|
|
52
|
+
// Time field (header display)
|
|
53
|
+
/** Background color of time fields */
|
|
54
|
+
timeFieldBackground?: string;
|
|
55
|
+
/** Background color of active time field */
|
|
56
|
+
timeFieldActiveBackground?: string;
|
|
57
|
+
/** Text color of time fields */
|
|
58
|
+
textColor?: string;
|
|
59
|
+
/** Text color of active time field */
|
|
60
|
+
textActiveColor?: string;
|
|
61
|
+
/** Color of the colon separator */
|
|
62
|
+
separatorColor?: string;
|
|
63
|
+
|
|
64
|
+
// Wheel picker (iOS style)
|
|
65
|
+
/** Background color of wheel picker */
|
|
66
|
+
wheelContainerBackground?: string;
|
|
67
|
+
/** Color of wheel selection highlight */
|
|
68
|
+
wheelSelectionHighlight?: string;
|
|
69
|
+
/** Color of wheel separator */
|
|
70
|
+
wheelSeparatorColor?: string;
|
|
71
|
+
/** Text color in wheel */
|
|
72
|
+
wheelTextColor?: string;
|
|
73
|
+
/** Text color of selected wheel item */
|
|
74
|
+
wheelTextSelectedColor?: string;
|
|
75
|
+
|
|
76
|
+
// Material container
|
|
77
|
+
/** Container background color */
|
|
78
|
+
containerBackground?: string;
|
|
79
|
+
/** Header text color */
|
|
80
|
+
headerColor?: string;
|
|
81
|
+
/** Action button text color */
|
|
82
|
+
actionButtonColor?: string;
|
|
83
|
+
|
|
84
|
+
// General
|
|
85
|
+
/** Primary accent color */
|
|
86
|
+
primaryColor?: string;
|
|
87
|
+
/** Border radius for container */
|
|
88
|
+
borderRadius?: number;
|
|
89
|
+
/** Generic background color (fallback for all container backgrounds) */
|
|
90
|
+
backgroundColor?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
21
93
|
/**
|
|
22
94
|
* Props for the TimePicker component
|
|
23
95
|
*/
|
|
@@ -36,6 +108,8 @@ export interface TimePickerProps {
|
|
|
36
108
|
minTime?: TimeValue;
|
|
37
109
|
/** Maximum selectable time */
|
|
38
110
|
maxTime?: TimeValue;
|
|
111
|
+
/** Custom theme overrides for styling without matching Kaal's theme structure */
|
|
112
|
+
themeOverrides?: TimePickerThemeOverrides;
|
|
39
113
|
}
|
|
40
114
|
|
|
41
115
|
/**
|
package/src/utils/validation.ts
CHANGED
|
@@ -1,76 +1,132 @@
|
|
|
1
|
-
import * as v from 'valibot';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Simple validation utilities for date/time pickers
|
|
3
|
+
* No external dependencies - just inline checks
|
|
6
4
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
|
|
6
|
+
// ISO date regex pattern
|
|
7
|
+
const ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
8
|
+
const ISO_DATETIME_PATTERN =
|
|
9
|
+
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?(Z|[+-]\d{2}:\d{2})?$/;
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* Validates an ISO 8601 date string (YYYY-MM-DD)
|
|
14
13
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
)
|
|
14
|
+
export function isValidISODate(value: string): boolean {
|
|
15
|
+
if (!ISO_DATE_PATTERN.test(value)) return false;
|
|
16
|
+
|
|
17
|
+
const [year, month, day] = value.split('-').map(Number) as [
|
|
18
|
+
number,
|
|
19
|
+
number,
|
|
20
|
+
number,
|
|
21
|
+
];
|
|
22
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
date.getUTCFullYear() === year &&
|
|
26
|
+
date.getUTCMonth() === month - 1 &&
|
|
27
|
+
date.getUTCDate() === day
|
|
28
|
+
);
|
|
29
|
+
}
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
|
-
* Validates an ISO 8601 datetime string
|
|
32
|
+
* Validates an ISO 8601 datetime string
|
|
31
33
|
*/
|
|
32
|
-
export
|
|
34
|
+
export function isValidISODateTime(value: string): boolean {
|
|
35
|
+
if (!ISO_DATETIME_PATTERN.test(value)) return false;
|
|
36
|
+
const date = new Date(value);
|
|
37
|
+
return !Number.isNaN(date.getTime());
|
|
38
|
+
}
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
|
-
* Validates a
|
|
41
|
+
* Validates a time value (24-hour format)
|
|
36
42
|
*/
|
|
37
|
-
export
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
43
|
+
export function isValidTime(hours: number, minutes: number): boolean {
|
|
44
|
+
return (
|
|
45
|
+
Number.isInteger(hours) &&
|
|
46
|
+
Number.isInteger(minutes) &&
|
|
47
|
+
hours >= 0 &&
|
|
48
|
+
hours <= 23 &&
|
|
49
|
+
minutes >= 0 &&
|
|
50
|
+
minutes <= 59
|
|
51
|
+
);
|
|
52
|
+
}
|
|
46
53
|
|
|
47
54
|
/**
|
|
48
|
-
* Validates date
|
|
55
|
+
* Validates a date range where start <= end
|
|
49
56
|
*/
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
disabledDates: v.optional(v.array(isoDateSchema)),
|
|
55
|
-
});
|
|
57
|
+
export function isValidDateRange(start: string, end: string): boolean {
|
|
58
|
+
if (!isValidISODate(start) || !isValidISODate(end)) return false;
|
|
59
|
+
return start <= end;
|
|
60
|
+
}
|
|
56
61
|
|
|
57
62
|
/**
|
|
58
63
|
* Parses an ISO date string to a Date object
|
|
59
|
-
*
|
|
64
|
+
* Returns null if invalid
|
|
60
65
|
*/
|
|
61
|
-
export
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
66
|
+
export function parseISODateSafe(value: string): Date | null {
|
|
67
|
+
if (!isValidISODate(value)) return null;
|
|
68
|
+
const [year, month, day] = value.split('-').map(Number) as [
|
|
69
|
+
number,
|
|
70
|
+
number,
|
|
71
|
+
number,
|
|
72
|
+
];
|
|
73
|
+
return new Date(Date.UTC(year, month - 1, day));
|
|
74
|
+
}
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
// Types for date picker values
|
|
77
|
+
export interface DatePickerValue {
|
|
78
|
+
selectedDate: string;
|
|
79
|
+
minDate?: string;
|
|
80
|
+
maxDate?: string;
|
|
81
|
+
disabledDates?: string[];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface DateRange {
|
|
85
|
+
start: string;
|
|
86
|
+
end: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Legacy schema exports for backward compatibility
|
|
90
|
+
// These are now simple validation functions, not valibot schemas
|
|
74
91
|
|
|
75
|
-
|
|
76
|
-
export
|
|
92
|
+
/** @deprecated Use isValidISODate() instead */
|
|
93
|
+
export const isoDateSchema = {
|
|
94
|
+
parse: (value: string) => {
|
|
95
|
+
if (!isValidISODate(value)) throw new Error('Invalid ISO date');
|
|
96
|
+
return value;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/** @deprecated Use isValidISODateTime() instead */
|
|
101
|
+
export const isoDateTimeSchema = {
|
|
102
|
+
parse: (value: string) => {
|
|
103
|
+
if (!isValidISODateTime(value)) throw new Error('Invalid ISO datetime');
|
|
104
|
+
return value;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/** @deprecated Use isValidDateRange() instead */
|
|
109
|
+
export const dateRangeSchema = {
|
|
110
|
+
parse: (value: DateRange) => {
|
|
111
|
+
if (!isValidDateRange(value.start, value.end))
|
|
112
|
+
throw new Error('Invalid date range');
|
|
113
|
+
return value;
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/** @deprecated Use DatePickerValue type instead */
|
|
118
|
+
export const datePickerValueSchema = {
|
|
119
|
+
parse: (value: DatePickerValue) => value,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** @deprecated Use parseISODateSafe() instead */
|
|
123
|
+
export const dateSchema = {
|
|
124
|
+
parse: (value: string) => {
|
|
125
|
+
const date = parseISODateSafe(value);
|
|
126
|
+
if (!date) throw new Error('Invalid date');
|
|
127
|
+
return date;
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/** @deprecated Alias for dateSchema */
|
|
132
|
+
export const temporalDateSchema = dateSchema;
|
package/lib/module/unistyles.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
// Re-export theme configuration from @dreamstack-us/kaal-themes
|
|
4
|
-
// This ensures the module augmentation is applied
|
|
5
|
-
export { configureKaalThemes } from '@dreamstack-us/kaal-themes';
|
|
6
|
-
|
|
7
|
-
// Import to ensure type augmentation is applied during build
|
|
8
|
-
import '@dreamstack-us/kaal-themes';
|
|
9
|
-
//# sourceMappingURL=unistyles.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"names":["configureKaalThemes"],"sourceRoot":"../../src","sources":["unistyles.ts"],"mappings":";;AAAA;AACA;AACA,SAASA,mBAAmB,QAAQ,4BAA4B;;AAEhE;AACA,OAAO,4BAA4B","ignoreList":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"unistyles.d.ts","sourceRoot":"","sources":["../../src/unistyles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGjE,OAAO,4BAA4B,CAAC"}
|