@idealyst/datepicker 1.0.0 → 1.0.41
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/package.json +6 -2
- package/src/DatePicker/Calendar.native.tsx +180 -78
- package/src/DatePicker/Calendar.styles.tsx +73 -70
- package/src/DatePicker/DatePicker.native.tsx +24 -6
- package/src/DatePicker/DatePicker.styles.tsx +18 -11
- package/src/DatePicker/DatePicker.web.tsx +1 -1
- package/src/DatePicker/index.ts +1 -1
- package/src/DateRangePicker/RangeCalendar.native.tsx +143 -55
- package/src/DateRangePicker/RangeCalendar.styles.tsx +65 -39
- package/src/DateRangePicker/RangeCalendar.web.tsx +169 -60
- package/src/DateRangePicker/types.ts +9 -0
- package/src/DateTimePicker/DateTimePicker.native.tsx +11 -69
- package/src/DateTimePicker/DateTimePicker.tsx +12 -70
- package/src/DateTimePicker/DateTimePickerBase.tsx +241 -0
- package/src/DateTimePicker/TimePicker.native.tsx +9 -196
- package/src/DateTimePicker/TimePicker.styles.tsx +4 -2
- package/src/DateTimePicker/TimePicker.tsx +9 -401
- package/src/DateTimePicker/TimePickerBase.tsx +232 -0
- package/src/DateTimePicker/primitives/ClockFace.native.tsx +195 -0
- package/src/DateTimePicker/primitives/ClockFace.web.tsx +168 -0
- package/src/DateTimePicker/primitives/TimeInput.native.tsx +53 -0
- package/src/DateTimePicker/primitives/TimeInput.web.tsx +66 -0
- package/src/DateTimePicker/primitives/index.native.ts +2 -0
- package/src/DateTimePicker/primitives/index.ts +2 -0
- package/src/DateTimePicker/primitives/index.web.ts +2 -0
- package/src/DateTimePicker/types.ts +0 -4
- package/src/DateTimePicker/utils/dimensions.native.ts +9 -0
- package/src/DateTimePicker/utils/dimensions.ts +9 -0
- package/src/DateTimePicker/utils/dimensions.web.ts +33 -0
- package/src/DateTimeRangePicker/DateTimeRangePicker.native.tsx +10 -199
- package/src/DateTimeRangePicker/DateTimeRangePicker.styles.tsx +3 -0
- package/src/DateTimeRangePicker/DateTimeRangePicker.web.tsx +11 -131
- package/src/DateTimeRangePicker/DateTimeRangePickerBase.tsx +391 -0
- package/src/DateTimeRangePicker/types.ts +0 -2
- package/src/examples/DatePickerExamples.tsx +42 -118
- /package/src/DatePicker/{Calendar.tsx → Calendar.web.tsx} +0 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { View, Text, Button } from '@idealyst/components';
|
|
3
|
+
import { DateTimeRangePickerProps, DateTimeRange } from './types';
|
|
4
|
+
import { dateTimeRangePickerStyles } from './DateTimeRangePicker.styles';
|
|
5
|
+
import { timePickerStyles } from '../DateTimePicker/TimePicker.styles';
|
|
6
|
+
import { getDimensions, addEventListener } from '../DateTimePicker/utils/dimensions';
|
|
7
|
+
|
|
8
|
+
interface DateTimeRangePickerBaseProps extends DateTimeRangePickerProps {
|
|
9
|
+
renderRangeCalendar: (props: {
|
|
10
|
+
value: DateTimeRange;
|
|
11
|
+
onChange: (range: DateTimeRange) => void;
|
|
12
|
+
minDate?: Date;
|
|
13
|
+
maxDate?: Date;
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
allowSameDay: boolean;
|
|
16
|
+
maxDays?: number;
|
|
17
|
+
onDateSelected?: (type: 'start' | 'end') => void;
|
|
18
|
+
showTimes?: boolean;
|
|
19
|
+
timeMode?: '12h' | '24h';
|
|
20
|
+
}) => React.ReactNode;
|
|
21
|
+
renderTimePicker: (props: {
|
|
22
|
+
value: Date;
|
|
23
|
+
onChange: (date: Date) => void;
|
|
24
|
+
disabled: boolean;
|
|
25
|
+
mode: '12h' | '24h';
|
|
26
|
+
step: number;
|
|
27
|
+
}) => React.ReactNode;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type ViewMode = 'responsive' | 'date' | 'start-time' | 'end-time';
|
|
31
|
+
type TimeSelection = 'start' | 'end';
|
|
32
|
+
|
|
33
|
+
export const DateTimeRangePickerBase: React.FC<DateTimeRangePickerBaseProps> = ({
|
|
34
|
+
value,
|
|
35
|
+
onChange,
|
|
36
|
+
minDate,
|
|
37
|
+
maxDate,
|
|
38
|
+
disabled = false,
|
|
39
|
+
timeMode = '12h',
|
|
40
|
+
timeStep = 1,
|
|
41
|
+
allowSameDay = true,
|
|
42
|
+
maxDays,
|
|
43
|
+
style,
|
|
44
|
+
testID,
|
|
45
|
+
renderRangeCalendar,
|
|
46
|
+
renderTimePicker,
|
|
47
|
+
}) => {
|
|
48
|
+
const [screenData, setScreenData] = useState(() => getDimensions());
|
|
49
|
+
const [viewMode, setViewMode] = useState<ViewMode>('responsive');
|
|
50
|
+
const [activeTimeSelection, setActiveTimeSelection] = useState<TimeSelection>('start');
|
|
51
|
+
|
|
52
|
+
// Listen for screen dimension changes
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const subscription = addEventListener(({ window }) => {
|
|
55
|
+
setScreenData(window);
|
|
56
|
+
});
|
|
57
|
+
return () => subscription?.remove();
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
// Determine if we should use side-by-side layout
|
|
61
|
+
const shouldUseSideBySide = screenData.width >= 700; // Wider threshold for range picker
|
|
62
|
+
const canFitSideBySide = screenData.width >= 580; // Minimum for side-by-side
|
|
63
|
+
|
|
64
|
+
// Auto-adjust view mode based on screen size
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (shouldUseSideBySide) {
|
|
67
|
+
setViewMode('responsive');
|
|
68
|
+
} else if (viewMode === 'responsive' && !canFitSideBySide) {
|
|
69
|
+
setViewMode('date');
|
|
70
|
+
}
|
|
71
|
+
}, [shouldUseSideBySide, canFitSideBySide, viewMode]);
|
|
72
|
+
|
|
73
|
+
const handleDateRangeChange = useCallback((newRange: DateTimeRange) => {
|
|
74
|
+
// Preserve existing times when date changes
|
|
75
|
+
const updatedRange: DateTimeRange = { ...newRange };
|
|
76
|
+
|
|
77
|
+
if (newRange.startDate && value?.startDate) {
|
|
78
|
+
updatedRange.startDate = new Date(newRange.startDate);
|
|
79
|
+
updatedRange.startDate.setHours(
|
|
80
|
+
value.startDate.getHours(),
|
|
81
|
+
value.startDate.getMinutes(),
|
|
82
|
+
value.startDate.getSeconds()
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (newRange.endDate && value?.endDate) {
|
|
87
|
+
updatedRange.endDate = new Date(newRange.endDate);
|
|
88
|
+
updatedRange.endDate.setHours(
|
|
89
|
+
value.endDate.getHours(),
|
|
90
|
+
value.endDate.getMinutes(),
|
|
91
|
+
value.endDate.getSeconds()
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
onChange(updatedRange.startDate || updatedRange.endDate ? updatedRange : null);
|
|
96
|
+
}, [value, onChange]);
|
|
97
|
+
|
|
98
|
+
const handleDateSelected = useCallback((type: 'start' | 'end') => {
|
|
99
|
+
// Auto-focus time selection when date is selected on mobile
|
|
100
|
+
if (!canFitSideBySide) {
|
|
101
|
+
setActiveTimeSelection(type);
|
|
102
|
+
setViewMode(type === 'start' ? 'start-time' : 'end-time');
|
|
103
|
+
} else {
|
|
104
|
+
// On desktop, just switch the active time tab
|
|
105
|
+
setActiveTimeSelection(type);
|
|
106
|
+
}
|
|
107
|
+
}, [canFitSideBySide]);
|
|
108
|
+
|
|
109
|
+
const handleStartTimeChange = useCallback((newTime: Date) => {
|
|
110
|
+
if (value?.startDate) {
|
|
111
|
+
const updatedDate = new Date(value.startDate);
|
|
112
|
+
updatedDate.setHours(newTime.getHours(), newTime.getMinutes(), newTime.getSeconds());
|
|
113
|
+
onChange({ ...value, startDate: updatedDate });
|
|
114
|
+
}
|
|
115
|
+
}, [value, onChange]);
|
|
116
|
+
|
|
117
|
+
const handleEndTimeChange = useCallback((newTime: Date) => {
|
|
118
|
+
if (value?.endDate) {
|
|
119
|
+
const updatedDate = new Date(value.endDate);
|
|
120
|
+
updatedDate.setHours(newTime.getHours(), newTime.getMinutes(), newTime.getSeconds());
|
|
121
|
+
onChange({ ...value, endDate: updatedDate });
|
|
122
|
+
}
|
|
123
|
+
}, [value, onChange]);
|
|
124
|
+
|
|
125
|
+
const formatSelectedRange = () => {
|
|
126
|
+
if (!value?.startDate) return 'No date range selected';
|
|
127
|
+
|
|
128
|
+
const startStr = value.startDate.toLocaleDateString('en-US', {
|
|
129
|
+
month: 'short',
|
|
130
|
+
day: 'numeric',
|
|
131
|
+
year: 'numeric'
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const startTimeStr = value.startDate.toLocaleTimeString('en-US', {
|
|
135
|
+
hour: 'numeric',
|
|
136
|
+
minute: '2-digit',
|
|
137
|
+
hour12: timeMode === '12h'
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (!value.endDate) {
|
|
141
|
+
return `${startStr} at ${startTimeStr} - (end date not selected)`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const endStr = value.endDate.toLocaleDateString('en-US', {
|
|
145
|
+
month: 'short',
|
|
146
|
+
day: 'numeric',
|
|
147
|
+
year: 'numeric'
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const endTimeStr = value.endDate.toLocaleTimeString('en-US', {
|
|
151
|
+
hour: 'numeric',
|
|
152
|
+
minute: '2-digit',
|
|
153
|
+
hour12: timeMode === '12h'
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return `${startStr} ${startTimeStr} - ${endStr} ${endTimeStr}`;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Initialize styles
|
|
160
|
+
timePickerStyles.useVariants({});
|
|
161
|
+
|
|
162
|
+
// Side-by-side layout for larger screens
|
|
163
|
+
if (viewMode === 'responsive' && shouldUseSideBySide) {
|
|
164
|
+
return (
|
|
165
|
+
<View style={[dateTimeRangePickerStyles.container, style]} testID={testID} data-testid={testID}>
|
|
166
|
+
{/* Selected Range Header */}
|
|
167
|
+
<View style={dateTimeRangePickerStyles.selectedRangeHeader}>
|
|
168
|
+
<Text style={dateTimeRangePickerStyles.selectedRangeLabel}>Selected Date & Time Range</Text>
|
|
169
|
+
<Text style={dateTimeRangePickerStyles.selectedRangeValue}>
|
|
170
|
+
{formatSelectedRange()}
|
|
171
|
+
</Text>
|
|
172
|
+
</View>
|
|
173
|
+
|
|
174
|
+
{/* Side by side layout */}
|
|
175
|
+
<View style={{
|
|
176
|
+
flexDirection: 'row',
|
|
177
|
+
gap: 24,
|
|
178
|
+
alignItems: 'flex-start',
|
|
179
|
+
_web: {
|
|
180
|
+
display: 'flex',
|
|
181
|
+
flexDirection: 'row',
|
|
182
|
+
gap: 24,
|
|
183
|
+
alignItems: 'flex-start',
|
|
184
|
+
}
|
|
185
|
+
}}>
|
|
186
|
+
{renderRangeCalendar({
|
|
187
|
+
value: value || {},
|
|
188
|
+
onChange: handleDateRangeChange,
|
|
189
|
+
minDate,
|
|
190
|
+
maxDate,
|
|
191
|
+
disabled,
|
|
192
|
+
allowSameDay,
|
|
193
|
+
maxDays,
|
|
194
|
+
onDateSelected: handleDateSelected,
|
|
195
|
+
showTimes: true,
|
|
196
|
+
timeMode,
|
|
197
|
+
})}
|
|
198
|
+
|
|
199
|
+
{/* Time Selection Panel */}
|
|
200
|
+
{(value?.startDate || value?.endDate) && (
|
|
201
|
+
<View style={{ minWidth: 220, flexShrink: 0 }}>
|
|
202
|
+
{/* Time Selection Tabs */}
|
|
203
|
+
<View style={timePickerStyles.tabBar}>
|
|
204
|
+
<Button
|
|
205
|
+
onPress={() => setActiveTimeSelection('start')}
|
|
206
|
+
disabled={disabled || !value?.startDate}
|
|
207
|
+
style={[
|
|
208
|
+
timePickerStyles.tabButton,
|
|
209
|
+
activeTimeSelection === 'start' ? timePickerStyles.activeTab : timePickerStyles.inactiveTab
|
|
210
|
+
]}
|
|
211
|
+
>
|
|
212
|
+
Start Time
|
|
213
|
+
</Button>
|
|
214
|
+
<Button
|
|
215
|
+
onPress={() => setActiveTimeSelection('end')}
|
|
216
|
+
disabled={disabled || !value?.endDate}
|
|
217
|
+
style={[
|
|
218
|
+
timePickerStyles.tabButton,
|
|
219
|
+
activeTimeSelection === 'end' ? timePickerStyles.activeTab : timePickerStyles.inactiveTab
|
|
220
|
+
]}
|
|
221
|
+
>
|
|
222
|
+
End Time
|
|
223
|
+
</Button>
|
|
224
|
+
</View>
|
|
225
|
+
|
|
226
|
+
{/* Active Time Picker */}
|
|
227
|
+
{activeTimeSelection === 'start' && value?.startDate && (
|
|
228
|
+
renderTimePicker({
|
|
229
|
+
value: value.startDate,
|
|
230
|
+
onChange: handleStartTimeChange,
|
|
231
|
+
disabled,
|
|
232
|
+
mode: timeMode,
|
|
233
|
+
step: timeStep,
|
|
234
|
+
})
|
|
235
|
+
)}
|
|
236
|
+
|
|
237
|
+
{activeTimeSelection === 'end' && value?.endDate && (
|
|
238
|
+
renderTimePicker({
|
|
239
|
+
value: value.endDate,
|
|
240
|
+
onChange: handleEndTimeChange,
|
|
241
|
+
disabled,
|
|
242
|
+
mode: timeMode,
|
|
243
|
+
step: timeStep,
|
|
244
|
+
})
|
|
245
|
+
)}
|
|
246
|
+
</View>
|
|
247
|
+
)}
|
|
248
|
+
</View>
|
|
249
|
+
</View>
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Step-by-step layout for smaller screens
|
|
254
|
+
const isDateStep = viewMode === 'date';
|
|
255
|
+
const isStartTimeStep = viewMode === 'start-time';
|
|
256
|
+
const isEndTimeStep = viewMode === 'end-time';
|
|
257
|
+
|
|
258
|
+
return (
|
|
259
|
+
<View style={[dateTimeRangePickerStyles.container, style]} testID={testID} data-testid={testID}>
|
|
260
|
+
{/* Selected Range Header */}
|
|
261
|
+
<View style={dateTimeRangePickerStyles.selectedRangeHeader}>
|
|
262
|
+
<Text style={dateTimeRangePickerStyles.selectedRangeLabel}>
|
|
263
|
+
{isDateStep ? 'Select Date Range' :
|
|
264
|
+
isStartTimeStep ? 'Set Start Time' :
|
|
265
|
+
isEndTimeStep ? 'Set End Time' : 'Selected Date & Time Range'}
|
|
266
|
+
</Text>
|
|
267
|
+
<Text style={dateTimeRangePickerStyles.selectedRangeValue}>
|
|
268
|
+
{formatSelectedRange()}
|
|
269
|
+
</Text>
|
|
270
|
+
</View>
|
|
271
|
+
|
|
272
|
+
{/* Step Navigation */}
|
|
273
|
+
<View style={timePickerStyles.tabBar}>
|
|
274
|
+
<Button
|
|
275
|
+
onPress={() => setViewMode('date')}
|
|
276
|
+
disabled={disabled}
|
|
277
|
+
style={[
|
|
278
|
+
timePickerStyles.tabButton,
|
|
279
|
+
isDateStep ? timePickerStyles.activeTab : timePickerStyles.inactiveTab
|
|
280
|
+
]}
|
|
281
|
+
>
|
|
282
|
+
1. Dates
|
|
283
|
+
</Button>
|
|
284
|
+
<Button
|
|
285
|
+
onPress={() => setViewMode('start-time')}
|
|
286
|
+
disabled={disabled || !value?.startDate}
|
|
287
|
+
style={[
|
|
288
|
+
timePickerStyles.tabButton,
|
|
289
|
+
isStartTimeStep ? timePickerStyles.activeTab : timePickerStyles.inactiveTab
|
|
290
|
+
]}
|
|
291
|
+
>
|
|
292
|
+
2. Start Time
|
|
293
|
+
</Button>
|
|
294
|
+
<Button
|
|
295
|
+
onPress={() => setViewMode('end-time')}
|
|
296
|
+
disabled={disabled || !value?.endDate}
|
|
297
|
+
style={[
|
|
298
|
+
timePickerStyles.tabButton,
|
|
299
|
+
isEndTimeStep ? timePickerStyles.activeTab : timePickerStyles.inactiveTab
|
|
300
|
+
]}
|
|
301
|
+
>
|
|
302
|
+
3. End Time
|
|
303
|
+
</Button>
|
|
304
|
+
</View>
|
|
305
|
+
|
|
306
|
+
{/* Step Content */}
|
|
307
|
+
{isDateStep && (
|
|
308
|
+
<View>
|
|
309
|
+
{renderRangeCalendar({
|
|
310
|
+
value: value || {},
|
|
311
|
+
onChange: handleDateRangeChange,
|
|
312
|
+
minDate,
|
|
313
|
+
maxDate,
|
|
314
|
+
disabled,
|
|
315
|
+
allowSameDay,
|
|
316
|
+
maxDays,
|
|
317
|
+
onDateSelected: handleDateSelected,
|
|
318
|
+
showTimes: true,
|
|
319
|
+
timeMode,
|
|
320
|
+
})}
|
|
321
|
+
</View>
|
|
322
|
+
)}
|
|
323
|
+
|
|
324
|
+
{isStartTimeStep && value?.startDate && (
|
|
325
|
+
<View>
|
|
326
|
+
{renderTimePicker({
|
|
327
|
+
value: value.startDate,
|
|
328
|
+
onChange: handleStartTimeChange,
|
|
329
|
+
disabled,
|
|
330
|
+
mode: timeMode,
|
|
331
|
+
step: timeStep,
|
|
332
|
+
})}
|
|
333
|
+
|
|
334
|
+
{/* Navigation */}
|
|
335
|
+
<View style={{ marginTop: 12, flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
336
|
+
<Button
|
|
337
|
+
variant="text"
|
|
338
|
+
size="small"
|
|
339
|
+
onPress={() => setViewMode('date')}
|
|
340
|
+
disabled={disabled}
|
|
341
|
+
>
|
|
342
|
+
← Back to Dates
|
|
343
|
+
</Button>
|
|
344
|
+
{value.endDate && (
|
|
345
|
+
<Button
|
|
346
|
+
variant="text"
|
|
347
|
+
size="small"
|
|
348
|
+
onPress={() => setViewMode('end-time')}
|
|
349
|
+
disabled={disabled}
|
|
350
|
+
>
|
|
351
|
+
End Time →
|
|
352
|
+
</Button>
|
|
353
|
+
)}
|
|
354
|
+
</View>
|
|
355
|
+
</View>
|
|
356
|
+
)}
|
|
357
|
+
|
|
358
|
+
{isEndTimeStep && value?.endDate && (
|
|
359
|
+
<View>
|
|
360
|
+
{renderTimePicker({
|
|
361
|
+
value: value.endDate,
|
|
362
|
+
onChange: handleEndTimeChange,
|
|
363
|
+
disabled,
|
|
364
|
+
mode: timeMode,
|
|
365
|
+
step: timeStep,
|
|
366
|
+
})}
|
|
367
|
+
|
|
368
|
+
{/* Navigation */}
|
|
369
|
+
<View style={{ marginTop: 12, flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
370
|
+
<Button
|
|
371
|
+
variant="text"
|
|
372
|
+
size="small"
|
|
373
|
+
onPress={() => setViewMode('start-time')}
|
|
374
|
+
disabled={disabled}
|
|
375
|
+
>
|
|
376
|
+
← Start Time
|
|
377
|
+
</Button>
|
|
378
|
+
<Button
|
|
379
|
+
variant="text"
|
|
380
|
+
size="small"
|
|
381
|
+
onPress={() => setViewMode('date')}
|
|
382
|
+
disabled={disabled}
|
|
383
|
+
>
|
|
384
|
+
Back to Dates
|
|
385
|
+
</Button>
|
|
386
|
+
</View>
|
|
387
|
+
</View>
|
|
388
|
+
)}
|
|
389
|
+
</View>
|
|
390
|
+
);
|
|
391
|
+
};
|
|
@@ -2,7 +2,6 @@ import { useState } from 'react';
|
|
|
2
2
|
import { Screen, View, Text, Button } from '@idealyst/components';
|
|
3
3
|
import { DatePicker } from '../DatePicker';
|
|
4
4
|
import { DateTimePicker } from '../DateTimePicker';
|
|
5
|
-
import { DateRangePicker, DateRange } from '../DateRangePicker';
|
|
6
5
|
import { DateTimeRangePicker, DateTimeRange } from '../DateTimeRangePicker';
|
|
7
6
|
|
|
8
7
|
export const DatePickerExamples = () => {
|
|
@@ -11,8 +10,6 @@ export const DatePickerExamples = () => {
|
|
|
11
10
|
const [disabledDate, setDisabledDate] = useState<Date | null>(new Date());
|
|
12
11
|
const [dateTime, setDateTime] = useState<Date | null>(null);
|
|
13
12
|
const [dateTime24h, setDateTime24h] = useState<Date | null>(null);
|
|
14
|
-
const [dateRange, setDateRange] = useState<DateRange | null>(null);
|
|
15
|
-
const [restrictedRange, setRestrictedRange] = useState<DateRange | null>(null);
|
|
16
13
|
const [dateTimeRange, setDateTimeRange] = useState<DateTimeRange | null>(null);
|
|
17
14
|
|
|
18
15
|
const tomorrow = new Date();
|
|
@@ -25,9 +22,50 @@ export const DatePickerExamples = () => {
|
|
|
25
22
|
<Screen background="primary" padding="lg">
|
|
26
23
|
<View spacing="none">
|
|
27
24
|
<Text size="large" weight="bold" align="center">
|
|
28
|
-
DatePicker Examples
|
|
25
|
+
DatePicker & DateTimePicker Examples
|
|
29
26
|
</Text>
|
|
30
27
|
|
|
28
|
+
{/* DateTime Picker Examples */}
|
|
29
|
+
<View spacing="md">
|
|
30
|
+
<Text size="medium" weight="semibold">DateTimePicker Examples</Text>
|
|
31
|
+
|
|
32
|
+
{/* Basic DateTime */}
|
|
33
|
+
<View spacing="sm">
|
|
34
|
+
<Text size="small" weight="medium">Basic DateTimePicker (12-hour)</Text>
|
|
35
|
+
<DateTimePicker
|
|
36
|
+
value={dateTime}
|
|
37
|
+
onChange={setDateTime}
|
|
38
|
+
label="Select Date & Time"
|
|
39
|
+
placeholder="Choose date and time"
|
|
40
|
+
helperText="Responsive layout - side-by-side on large screens, step-by-step on mobile"
|
|
41
|
+
/>
|
|
42
|
+
{dateTime && (
|
|
43
|
+
<Text size="small" color="secondary">
|
|
44
|
+
Selected: {dateTime.toLocaleString()}
|
|
45
|
+
</Text>
|
|
46
|
+
)}
|
|
47
|
+
</View>
|
|
48
|
+
|
|
49
|
+
{/* 24-hour format */}
|
|
50
|
+
<View spacing="sm">
|
|
51
|
+
<Text size="small" weight="medium">24-hour format with seconds</Text>
|
|
52
|
+
<DateTimePicker
|
|
53
|
+
value={dateTime24h}
|
|
54
|
+
onChange={setDateTime24h}
|
|
55
|
+
label="24-hour with seconds"
|
|
56
|
+
placeholder="Choose date and time"
|
|
57
|
+
timeMode="24h"
|
|
58
|
+
timeStep={5}
|
|
59
|
+
helperText="24-hour format with seconds, 5-minute steps"
|
|
60
|
+
/>
|
|
61
|
+
{dateTime24h && (
|
|
62
|
+
<Text size="small" color="secondary">
|
|
63
|
+
Selected: {dateTime24h.toLocaleString()}
|
|
64
|
+
</Text>
|
|
65
|
+
)}
|
|
66
|
+
</View>
|
|
67
|
+
</View>
|
|
68
|
+
|
|
31
69
|
{/* Basic DatePicker */}
|
|
32
70
|
<View spacing="md">
|
|
33
71
|
<Text size="medium" weight="semibold">Basic DatePicker</Text>
|
|
@@ -77,33 +115,6 @@ export const DatePickerExamples = () => {
|
|
|
77
115
|
/>
|
|
78
116
|
</View>
|
|
79
117
|
|
|
80
|
-
{/* Size Variants */}
|
|
81
|
-
<View spacing="md">
|
|
82
|
-
<Text size="medium" weight="semibold">Size Variants</Text>
|
|
83
|
-
<View spacing="sm">
|
|
84
|
-
<DatePicker
|
|
85
|
-
value={null}
|
|
86
|
-
onChange={() => {}}
|
|
87
|
-
label="Small"
|
|
88
|
-
placeholder="Small size"
|
|
89
|
-
size="small"
|
|
90
|
-
/>
|
|
91
|
-
<DatePicker
|
|
92
|
-
value={null}
|
|
93
|
-
onChange={() => {}}
|
|
94
|
-
label="Medium"
|
|
95
|
-
placeholder="Medium size"
|
|
96
|
-
size="medium"
|
|
97
|
-
/>
|
|
98
|
-
<DatePicker
|
|
99
|
-
value={null}
|
|
100
|
-
onChange={() => {}}
|
|
101
|
-
label="Large"
|
|
102
|
-
placeholder="Large size"
|
|
103
|
-
size="large"
|
|
104
|
-
/>
|
|
105
|
-
</View>
|
|
106
|
-
</View>
|
|
107
118
|
|
|
108
119
|
{/* Actions */}
|
|
109
120
|
<View spacing="md">
|
|
@@ -127,88 +138,7 @@ export const DatePickerExamples = () => {
|
|
|
127
138
|
</View>
|
|
128
139
|
</View>
|
|
129
140
|
|
|
130
|
-
{/* DateTime Picker Examples */}
|
|
131
|
-
<View spacing="md">
|
|
132
|
-
<Text size="medium" weight="semibold">DateTimePicker Examples</Text>
|
|
133
|
-
|
|
134
|
-
{/* Basic DateTime */}
|
|
135
|
-
<View spacing="sm">
|
|
136
|
-
<Text size="small" weight="medium">12-hour format</Text>
|
|
137
|
-
<DateTimePicker
|
|
138
|
-
value={dateTime}
|
|
139
|
-
onChange={setDateTime}
|
|
140
|
-
label="Select Date & Time"
|
|
141
|
-
placeholder="Choose date and time"
|
|
142
|
-
helperText="12-hour format with AM/PM"
|
|
143
|
-
/>
|
|
144
|
-
{dateTime && (
|
|
145
|
-
<Text size="small" color="secondary">
|
|
146
|
-
Selected: {dateTime.toLocaleString()}
|
|
147
|
-
</Text>
|
|
148
|
-
)}
|
|
149
|
-
</View>
|
|
150
|
-
|
|
151
|
-
{/* 24-hour format */}
|
|
152
|
-
<View spacing="sm">
|
|
153
|
-
<Text size="small" weight="medium">24-hour format with seconds</Text>
|
|
154
|
-
<DateTimePicker
|
|
155
|
-
value={dateTime24h}
|
|
156
|
-
onChange={setDateTime24h}
|
|
157
|
-
label="24-hour with seconds"
|
|
158
|
-
placeholder="Choose date and time"
|
|
159
|
-
timeMode="24h"
|
|
160
|
-
showSeconds={true}
|
|
161
|
-
timeStep={5}
|
|
162
|
-
helperText="24-hour format with seconds, 5-minute steps"
|
|
163
|
-
/>
|
|
164
|
-
{dateTime24h && (
|
|
165
|
-
<Text size="small" color="secondary">
|
|
166
|
-
Selected: {dateTime24h.toLocaleString()}
|
|
167
|
-
</Text>
|
|
168
|
-
)}
|
|
169
|
-
</View>
|
|
170
|
-
</View>
|
|
171
|
-
|
|
172
|
-
{/* Date Range Picker Examples */}
|
|
173
|
-
<View spacing="md">
|
|
174
|
-
<Text size="medium" weight="semibold">DateRangePicker Examples</Text>
|
|
175
|
-
|
|
176
|
-
{/* Basic Range */}
|
|
177
|
-
<View spacing="sm">
|
|
178
|
-
<Text size="small" weight="medium">Basic range selection</Text>
|
|
179
|
-
<DateRangePicker
|
|
180
|
-
value={dateRange}
|
|
181
|
-
onChange={setDateRange}
|
|
182
|
-
label="Select Date Range"
|
|
183
|
-
placeholder="Choose start and end dates"
|
|
184
|
-
helperText="Click dates to select a range"
|
|
185
|
-
/>
|
|
186
|
-
{dateRange?.startDate && dateRange?.endDate && (
|
|
187
|
-
<Text size="small" color="secondary">
|
|
188
|
-
Range: {dateRange.startDate.toDateString()} to {dateRange.endDate.toDateString()}
|
|
189
|
-
</Text>
|
|
190
|
-
)}
|
|
191
|
-
</View>
|
|
192
141
|
|
|
193
|
-
{/* Restricted Range */}
|
|
194
|
-
<View spacing="sm">
|
|
195
|
-
<Text size="small" weight="medium">Max 14 days, future dates only</Text>
|
|
196
|
-
<DateRangePicker
|
|
197
|
-
value={restrictedRange}
|
|
198
|
-
onChange={setRestrictedRange}
|
|
199
|
-
label="Restricted Range"
|
|
200
|
-
placeholder="Maximum 14 days"
|
|
201
|
-
minDate={tomorrow}
|
|
202
|
-
maxDays={14}
|
|
203
|
-
helperText="Future dates only, max 14 days"
|
|
204
|
-
/>
|
|
205
|
-
{restrictedRange?.startDate && restrictedRange?.endDate && (
|
|
206
|
-
<Text size="small" color="secondary">
|
|
207
|
-
Range: {restrictedRange.startDate.toDateString()} to {restrictedRange.endDate.toDateString()}
|
|
208
|
-
</Text>
|
|
209
|
-
)}
|
|
210
|
-
</View>
|
|
211
|
-
</View>
|
|
212
142
|
|
|
213
143
|
{/* Date Time Range Picker Examples */}
|
|
214
144
|
<View spacing="md">
|
|
@@ -242,9 +172,6 @@ export const DatePickerExamples = () => {
|
|
|
242
172
|
<Text size="small" color="secondary">
|
|
243
173
|
• Date and time selection
|
|
244
174
|
</Text>
|
|
245
|
-
<Text size="small" color="secondary">
|
|
246
|
-
• Date range selection
|
|
247
|
-
</Text>
|
|
248
175
|
<Text size="small" color="secondary">
|
|
249
176
|
• Date/time range selection
|
|
250
177
|
</Text>
|
|
@@ -254,9 +181,6 @@ export const DatePickerExamples = () => {
|
|
|
254
181
|
<Text size="small" color="secondary">
|
|
255
182
|
• Min/max date restrictions
|
|
256
183
|
</Text>
|
|
257
|
-
<Text size="small" color="secondary">
|
|
258
|
-
• Multiple size variants
|
|
259
|
-
</Text>
|
|
260
184
|
<Text size="small" color="secondary">
|
|
261
185
|
• Accessible and keyboard navigable
|
|
262
186
|
</Text>
|
|
File without changes
|