@utilitywarehouse/hearth-react-native 0.23.0 → 0.25.0
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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-lint.log +13 -13
- package/CHANGELOG.md +77 -0
- package/build/components/DatePicker/DatePickerCalendar.js +4 -9
- package/build/components/Modal/Modal.js +5 -4
- package/build/components/Modal/Modal.props.d.ts +10 -4
- package/build/components/ProgressBar/ProgressBar.d.ts +6 -0
- package/build/components/ProgressBar/ProgressBar.js +35 -0
- package/build/components/ProgressBar/ProgressBar.props.d.ts +60 -0
- package/build/components/ProgressBar/ProgressBar.props.js +1 -0
- package/build/components/ProgressBar/ProgressBarCircular.d.ts +6 -0
- package/build/components/ProgressBar/ProgressBarCircular.js +115 -0
- package/build/components/ProgressBar/ProgressBarLinear.d.ts +6 -0
- package/build/components/ProgressBar/ProgressBarLinear.js +79 -0
- package/build/components/ProgressBar/index.d.ts +2 -0
- package/build/components/ProgressBar/index.js +1 -0
- package/build/components/TimePicker/TimePicker.d.ts +6 -0
- package/build/components/TimePicker/TimePicker.js +78 -0
- package/build/components/TimePicker/TimePicker.props.d.ts +45 -0
- package/build/components/TimePicker/TimePicker.props.js +1 -0
- package/build/components/TimePicker/TimePickerView.d.ts +12 -0
- package/build/components/TimePicker/TimePickerView.js +130 -0
- package/build/components/TimePicker/TimePickerWheel.d.ts +8 -0
- package/build/components/TimePicker/TimePickerWheel.js +78 -0
- package/build/components/{DatePicker/time-picker/wheel-web.d.ts → TimePicker/TimePickerWheel.web.d.ts} +4 -4
- package/build/components/TimePicker/TimePickerWheel.web.js +122 -0
- package/build/components/TimePicker/index.d.ts +6 -0
- package/build/components/TimePicker/index.js +3 -0
- package/build/components/TimePickerInput/TimePickerInput.d.ts +6 -0
- package/build/components/TimePickerInput/TimePickerInput.js +127 -0
- package/build/components/TimePickerInput/TimePickerInput.props.d.ts +52 -0
- package/build/components/TimePickerInput/TimePickerInput.props.js +1 -0
- package/build/components/TimePickerInput/TimePickerInputDoneButton.d.ts +8 -0
- package/build/components/TimePickerInput/TimePickerInputDoneButton.js +19 -0
- package/build/components/TimePickerInput/TimePickerInputDoneButton.web.d.ts +5 -0
- package/build/components/TimePickerInput/TimePickerInputDoneButton.web.js +5 -0
- package/build/components/TimePickerInput/index.d.ts +2 -0
- package/build/components/TimePickerInput/index.js +1 -0
- package/build/components/index.d.ts +3 -0
- package/build/components/index.js +3 -0
- package/docs/components/AllComponents.web.tsx +36 -0
- package/package.json +2 -1
- package/src/components/DatePicker/DatePickerCalendar.tsx +30 -13
- package/src/components/Modal/Modal.props.ts +13 -4
- package/src/components/Modal/Modal.stories.tsx +1 -1
- package/src/components/Modal/Modal.tsx +28 -11
- package/src/components/ProgressBar/ProgressBar.docs.mdx +90 -0
- package/src/components/ProgressBar/ProgressBar.figma.tsx +79 -0
- package/src/components/ProgressBar/ProgressBar.props.ts +60 -0
- package/src/components/ProgressBar/ProgressBar.stories.tsx +117 -0
- package/src/components/ProgressBar/ProgressBar.tsx +74 -0
- package/src/components/ProgressBar/ProgressBarCircular.tsx +181 -0
- package/src/components/ProgressBar/ProgressBarLinear.tsx +127 -0
- package/src/components/ProgressBar/index.ts +7 -0
- package/src/components/TimePicker/TimePicker.docs.mdx +84 -0
- package/src/components/TimePicker/TimePicker.figma.tsx +29 -0
- package/src/components/TimePicker/TimePicker.props.ts +45 -0
- package/src/components/TimePicker/TimePicker.stories.tsx +85 -0
- package/src/components/TimePicker/TimePicker.tsx +150 -0
- package/src/components/TimePicker/TimePickerView.tsx +216 -0
- package/src/components/TimePicker/TimePickerWheel.tsx +154 -0
- package/src/components/TimePicker/TimePickerWheel.web.tsx +217 -0
- package/src/components/TimePicker/index.ts +8 -0
- package/src/components/TimePickerInput/TimePickerInput.docs.mdx +135 -0
- package/src/components/TimePickerInput/TimePickerInput.figma.tsx +34 -0
- package/src/components/TimePickerInput/TimePickerInput.props.ts +55 -0
- package/src/components/TimePickerInput/TimePickerInput.stories.tsx +175 -0
- package/src/components/TimePickerInput/TimePickerInput.tsx +283 -0
- package/src/components/TimePickerInput/TimePickerInputDoneButton.tsx +42 -0
- package/src/components/TimePickerInput/TimePickerInputDoneButton.web.tsx +7 -0
- package/src/components/TimePickerInput/index.ts +2 -0
- package/src/components/index.ts +3 -0
- package/build/components/DatePicker/TimePicker.d.ts +0 -3
- package/build/components/DatePicker/TimePicker.js +0 -84
- package/build/components/DatePicker/time-picker/animated-math.d.ts +0 -4
- package/build/components/DatePicker/time-picker/animated-math.js +0 -19
- package/build/components/DatePicker/time-picker/period-native.d.ts +0 -6
- package/build/components/DatePicker/time-picker/period-native.js +0 -17
- package/build/components/DatePicker/time-picker/period-picker.d.ts +0 -6
- package/build/components/DatePicker/time-picker/period-picker.js +0 -10
- package/build/components/DatePicker/time-picker/period-web.d.ts +0 -6
- package/build/components/DatePicker/time-picker/period-web.js +0 -21
- package/build/components/DatePicker/time-picker/wheel-native.d.ts +0 -8
- package/build/components/DatePicker/time-picker/wheel-native.js +0 -19
- package/build/components/DatePicker/time-picker/wheel-picker/index.d.ts +0 -2
- package/build/components/DatePicker/time-picker/wheel-picker/index.js +0 -2
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.d.ts +0 -16
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.js +0 -97
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.d.ts +0 -21
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.js +0 -88
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.d.ts +0 -23
- package/build/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.js +0 -21
- package/build/components/DatePicker/time-picker/wheel-web.js +0 -146
- package/build/components/DatePicker/time-picker/wheel.d.ts +0 -8
- package/build/components/DatePicker/time-picker/wheel.js +0 -10
- package/src/components/DatePicker/TimePicker.tsx +0 -141
- package/src/components/DatePicker/time-picker/animated-math.ts +0 -33
- package/src/components/DatePicker/time-picker/period-native.tsx +0 -34
- package/src/components/DatePicker/time-picker/period-picker.tsx +0 -16
- package/src/components/DatePicker/time-picker/period-web.tsx +0 -36
- package/src/components/DatePicker/time-picker/wheel-native.tsx +0 -37
- package/src/components/DatePicker/time-picker/wheel-picker/index.ts +0 -3
- package/src/components/DatePicker/time-picker/wheel-picker/wheel-picker-item.tsx +0 -132
- package/src/components/DatePicker/time-picker/wheel-picker/wheel-picker.style.ts +0 -22
- package/src/components/DatePicker/time-picker/wheel-picker/wheel-picker.tsx +0 -200
- package/src/components/DatePicker/time-picker/wheel-web.tsx +0 -180
- package/src/components/DatePicker/time-picker/wheel.tsx +0 -18
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { BottomSheetModalMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
|
|
2
|
+
import type { Ref } from 'react';
|
|
3
|
+
import type { ViewStyle } from 'react-native';
|
|
4
|
+
import type { DateType, PickerOption } from '../DatePicker/DatePicker.props';
|
|
5
|
+
export interface TimePickerProps {
|
|
6
|
+
/**
|
|
7
|
+
* IANA time zone identifier applied when normalising and comparing times.
|
|
8
|
+
*/
|
|
9
|
+
timeZone?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Controlled time value.
|
|
12
|
+
*/
|
|
13
|
+
date?: DateType;
|
|
14
|
+
/**
|
|
15
|
+
* Fired whenever a time is picked.
|
|
16
|
+
*/
|
|
17
|
+
onChange?: (params: {
|
|
18
|
+
date: DateType;
|
|
19
|
+
}) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Display a 12-hour clock with AM/PM selector.
|
|
22
|
+
*/
|
|
23
|
+
use12Hours?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Step interval for minutes shown in the picker.
|
|
26
|
+
*/
|
|
27
|
+
minuteInterval?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Hide the footer actions.
|
|
30
|
+
*/
|
|
31
|
+
hideFooter?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Custom container styling for the time picker surface.
|
|
34
|
+
*/
|
|
35
|
+
style?: ViewStyle;
|
|
36
|
+
/**
|
|
37
|
+
* Gives imperative access to the bottom sheet instance.
|
|
38
|
+
*/
|
|
39
|
+
ref?: Ref<BottomSheetModalMethods<any>>;
|
|
40
|
+
/**
|
|
41
|
+
* Fired when the cancel action is triggered.
|
|
42
|
+
*/
|
|
43
|
+
onCancel?: () => void;
|
|
44
|
+
}
|
|
45
|
+
export type { DateType, PickerOption };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DateType } from './TimePicker.props';
|
|
2
|
+
export type Period = 'AM' | 'PM';
|
|
3
|
+
type TimePickerViewProps = {
|
|
4
|
+
currentDate: DateType;
|
|
5
|
+
onSelectDate: (date: DateType) => void;
|
|
6
|
+
timeZone?: string;
|
|
7
|
+
use12Hours?: boolean;
|
|
8
|
+
minuteInterval?: number;
|
|
9
|
+
containerHeight?: number;
|
|
10
|
+
};
|
|
11
|
+
declare const _default: import("react").MemoExoticComponent<({ currentDate, onSelectDate, timeZone, use12Hours, minuteInterval, }: TimePickerViewProps) => import("react/jsx-runtime").JSX.Element>;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import dayjs from 'dayjs';
|
|
3
|
+
import { memo, useCallback, useMemo } from 'react';
|
|
4
|
+
import { View } from 'react-native';
|
|
5
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
6
|
+
import { BodyText } from '../BodyText';
|
|
7
|
+
import { formatNumber, getParsedDate } from '../DatePicker/utils';
|
|
8
|
+
import TimePickerWheel from './TimePickerWheel';
|
|
9
|
+
const createNumberList = (num, numerals, startFrom = 0) => {
|
|
10
|
+
return Array.from({ length: num }, (_, i) => ({
|
|
11
|
+
value: i + startFrom,
|
|
12
|
+
text: i + startFrom < 10
|
|
13
|
+
? `${formatNumber(0, numerals)}${formatNumber(i + startFrom, numerals)}`
|
|
14
|
+
: `${formatNumber(i + startFrom, numerals)}`,
|
|
15
|
+
}));
|
|
16
|
+
};
|
|
17
|
+
const createMinuteList = (interval, numerals) => {
|
|
18
|
+
const safeInterval = Math.min(59, Math.max(1, Math.floor(interval)));
|
|
19
|
+
const values = Array.from({ length: Math.ceil(60 / safeInterval) }, (_, index) => Math.min(index * safeInterval, 59)).filter((value, index, array) => array.indexOf(value) === index && value < 60);
|
|
20
|
+
return values.map(value => ({
|
|
21
|
+
value,
|
|
22
|
+
text: value < 10
|
|
23
|
+
? `${formatNumber(0, numerals)}${formatNumber(value, numerals)}`
|
|
24
|
+
: `${formatNumber(value, numerals)}`,
|
|
25
|
+
}));
|
|
26
|
+
};
|
|
27
|
+
const getClosestMinute = (value, options) => {
|
|
28
|
+
if (!options.length)
|
|
29
|
+
return value;
|
|
30
|
+
const values = options.map(option => option.value);
|
|
31
|
+
if (values.includes(value))
|
|
32
|
+
return value;
|
|
33
|
+
let closest = values[0] ?? value;
|
|
34
|
+
let closestDiff = Math.abs(value - closest);
|
|
35
|
+
values.forEach(optionValue => {
|
|
36
|
+
const diff = Math.abs(value - optionValue);
|
|
37
|
+
if (diff < closestDiff) {
|
|
38
|
+
closestDiff = diff;
|
|
39
|
+
closest = optionValue;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return closest;
|
|
43
|
+
};
|
|
44
|
+
const TimePickerView = ({ currentDate, onSelectDate, timeZone, use12Hours, minuteInterval = 1, }) => {
|
|
45
|
+
const hours = useMemo(() => createNumberList(use12Hours ? 12 : 24, 'latn', use12Hours ? 1 : 0), [use12Hours]);
|
|
46
|
+
const minutes = useMemo(() => createMinuteList(minuteInterval, 'latn'), [minuteInterval]);
|
|
47
|
+
const periodOptions = useMemo(() => [
|
|
48
|
+
{ value: 'AM', text: 'AM' },
|
|
49
|
+
{ value: 'PM', text: 'PM' },
|
|
50
|
+
], []);
|
|
51
|
+
const baseDate = currentDate;
|
|
52
|
+
const { hour, hour12, minute, period } = getParsedDate(baseDate);
|
|
53
|
+
const minuteValue = useMemo(() => getClosestMinute(minute, minutes), [minute, minutes]);
|
|
54
|
+
const handleChangeHour = useCallback((value) => {
|
|
55
|
+
let hour24 = value;
|
|
56
|
+
if (use12Hours) {
|
|
57
|
+
if (period === 'AM' && value === 12) {
|
|
58
|
+
hour24 = 0;
|
|
59
|
+
}
|
|
60
|
+
else if (period === 'PM' && value < 12) {
|
|
61
|
+
hour24 = value + 12;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
hour24 = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const newDate = dayjs.tz(baseDate, timeZone).hour(hour24).minute(minuteValue);
|
|
68
|
+
onSelectDate(newDate);
|
|
69
|
+
}, [baseDate, onSelectDate, timeZone, use12Hours, period, minuteValue]);
|
|
70
|
+
const handleChangeMinute = useCallback((value) => {
|
|
71
|
+
const newDate = dayjs.tz(baseDate, timeZone).minute(value);
|
|
72
|
+
onSelectDate(newDate);
|
|
73
|
+
}, [baseDate, onSelectDate, timeZone]);
|
|
74
|
+
const handlePeriodChange = useCallback((newPeriod) => {
|
|
75
|
+
let newHour = hour12;
|
|
76
|
+
if (newPeriod === 'PM' && hour12 < 12) {
|
|
77
|
+
newHour = hour12 + 12;
|
|
78
|
+
}
|
|
79
|
+
else if (newPeriod === 'AM' && hour12 === 12) {
|
|
80
|
+
newHour = 0;
|
|
81
|
+
}
|
|
82
|
+
else if (newPeriod === 'AM' && hour >= 12) {
|
|
83
|
+
newHour = hour12;
|
|
84
|
+
}
|
|
85
|
+
const newDate = dayjs.tz(baseDate, timeZone).hour(newHour);
|
|
86
|
+
onSelectDate(newDate);
|
|
87
|
+
}, [baseDate, onSelectDate, timeZone, hour, hour12]);
|
|
88
|
+
return (_jsxs(View, { style: styles.container, testID: "time-selector", children: [_jsxs(View, { style: styles.timePickerContainer, children: [_jsx(View, { style: styles.wheelContainer, children: _jsx(TimePickerWheel, { value: use12Hours ? hour12 : hour, items: hours, setValue: handleChangeHour }) }), _jsx(BodyText, { style: styles.timeSeparator, size: "lg", children: ":" }), _jsx(View, { style: styles.wheelContainer, children: _jsx(TimePickerWheel, { value: minuteValue, items: minutes, setValue: handleChangeMinute }) })] }), use12Hours && period ? (_jsx(View, { style: styles.periodContainer, children: _jsx(TimePickerWheel, { value: period, items: periodOptions, setValue: handlePeriodChange }) })) : null] }));
|
|
89
|
+
};
|
|
90
|
+
const styles = StyleSheet.create({
|
|
91
|
+
container: {
|
|
92
|
+
flex: 1,
|
|
93
|
+
alignItems: 'center',
|
|
94
|
+
justifyContent: 'center',
|
|
95
|
+
flexDirection: 'row',
|
|
96
|
+
},
|
|
97
|
+
wheelContainer: {
|
|
98
|
+
flex: 1,
|
|
99
|
+
},
|
|
100
|
+
timePickerContainer: {
|
|
101
|
+
alignItems: 'center',
|
|
102
|
+
justifyContent: 'center',
|
|
103
|
+
width: 146,
|
|
104
|
+
height: 208,
|
|
105
|
+
flexDirection: 'row',
|
|
106
|
+
marginBottom: -30,
|
|
107
|
+
},
|
|
108
|
+
timeSeparator: {
|
|
109
|
+
marginHorizontal: 5,
|
|
110
|
+
},
|
|
111
|
+
periodContainer: {
|
|
112
|
+
marginLeft: 10,
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
const customComparator = (prev, next) => {
|
|
116
|
+
if (prev.onSelectDate !== next.onSelectDate) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
if (prev.timeZone !== next.timeZone) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
if (prev.use12Hours !== next.use12Hours) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
if (prev.minuteInterval !== next.minuteInterval) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
return dayjs(prev.currentDate).isSame(next.currentDate, 'minute');
|
|
129
|
+
};
|
|
130
|
+
export default memo(TimePickerView, customComparator);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PickerOption } from './TimePicker.props';
|
|
2
|
+
type TimePickerWheelProps = {
|
|
3
|
+
value: number | string;
|
|
4
|
+
setValue?: (value: any) => void;
|
|
5
|
+
items: PickerOption[];
|
|
6
|
+
};
|
|
7
|
+
declare const TimePickerWheel: ({ value, setValue, items }: TimePickerWheelProps) => import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export default TimePickerWheel;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import WheelPicker from '@quidone/react-native-wheel-picker';
|
|
3
|
+
import { useCallback, useMemo } from 'react';
|
|
4
|
+
import { View } from 'react-native';
|
|
5
|
+
import Svg, { Defs, LinearGradient, Rect, Stop } from 'react-native-svg';
|
|
6
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
7
|
+
import { useTheme } from '../../hooks';
|
|
8
|
+
import { BodyText } from '../BodyText';
|
|
9
|
+
const ITEM_HEIGHT = 40;
|
|
10
|
+
const VISIBLE_REST = 3;
|
|
11
|
+
const TimePickerWheel = ({ value, setValue = () => { }, items }) => {
|
|
12
|
+
const theme = useTheme();
|
|
13
|
+
const fadeHeight = ITEM_HEIGHT * 1.5;
|
|
14
|
+
const gradientId = useMemo(() => `wheel-fade-${Math.random().toString(36).slice(2)}`, []);
|
|
15
|
+
const displayCount = VISIBLE_REST * 2 + 1;
|
|
16
|
+
const pickerHeight = ITEM_HEIGHT * displayCount;
|
|
17
|
+
const data = useMemo(() => items.map(item => ({
|
|
18
|
+
value: item.value,
|
|
19
|
+
label: item.text,
|
|
20
|
+
})), [items]);
|
|
21
|
+
const handleValueChanged = useCallback(({ item }) => {
|
|
22
|
+
if (item?.value === value) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (item && item.value !== undefined) {
|
|
26
|
+
setValue(item.value);
|
|
27
|
+
}
|
|
28
|
+
}, [setValue, value]);
|
|
29
|
+
const renderOverlay = useCallback(() => (_jsxs(View, { style: [styles.overlayContainer], pointerEvents: "none", children: [_jsx(View, { pointerEvents: "none", style: [styles.fadeOverlay, { height: fadeHeight }], children: _jsxs(Svg, { width: "100%", height: "100%", preserveAspectRatio: "none", children: [_jsx(Defs, { children: _jsxs(LinearGradient, { id: `${gradientId}-top`, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx(Stop, { offset: "0", stopColor: theme.color.background.secondary, stopOpacity: 1 }), _jsx(Stop, { offset: "1", stopColor: theme.color.background.secondary, stopOpacity: 0 })] }) }), _jsx(Rect, { width: "100%", height: "100%", fill: `url(#${gradientId}-top)` })] }) }), _jsx(View, { pointerEvents: "none", style: [styles.fadeOverlay, styles.fadeOverlayBottom, { height: fadeHeight }], children: _jsxs(Svg, { width: "100%", height: "100%", preserveAspectRatio: "none", children: [_jsx(Defs, { children: _jsxs(LinearGradient, { id: `${gradientId}-bottom`, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx(Stop, { offset: "0", stopColor: theme.color.background.secondary, stopOpacity: 0 }), _jsx(Stop, { offset: "1", stopColor: theme.color.background.secondary, stopOpacity: 1 })] }) }), _jsx(Rect, { width: "100%", height: "100%", fill: `url(#${gradientId}-bottom)` })] }) })] })), [fadeHeight, gradientId, theme.color.background.secondary]);
|
|
30
|
+
const renderItem = useCallback(({ item }) => (_jsx(View, { style: styles.indicator, children: _jsx(BodyText, { size: "lg", children: item.label }) })), []);
|
|
31
|
+
return (_jsxs(View, { style: [styles.container, { height: pickerHeight }], children: [_jsx(View, { style: styles.overlayContainer, children: _jsx(View, { style: [styles.selection] }) }), _jsx(WheelPicker, { data: data, value: value, onValueChanged: handleValueChanged, itemHeight: ITEM_HEIGHT, visibleItemCount: displayCount, width: theme.components.timePicker.time.item.width, renderItem: renderItem, renderOverlay: renderOverlay })] }));
|
|
32
|
+
};
|
|
33
|
+
const styles = StyleSheet.create(theme => ({
|
|
34
|
+
container: {
|
|
35
|
+
minWidth: theme.components.timePicker.time.item.width,
|
|
36
|
+
overflow: 'hidden',
|
|
37
|
+
alignItems: 'center',
|
|
38
|
+
justifyContent: 'center',
|
|
39
|
+
position: 'relative',
|
|
40
|
+
},
|
|
41
|
+
overlay: {
|
|
42
|
+
position: 'absolute',
|
|
43
|
+
top: 0,
|
|
44
|
+
left: 0,
|
|
45
|
+
right: 0,
|
|
46
|
+
bottom: 0,
|
|
47
|
+
alignItems: 'center',
|
|
48
|
+
},
|
|
49
|
+
indicator: {
|
|
50
|
+
width: theme.components.timePicker.time.item.width,
|
|
51
|
+
height: theme.components.timePicker.time.item.height,
|
|
52
|
+
alignItems: 'center',
|
|
53
|
+
justifyContent: 'center',
|
|
54
|
+
},
|
|
55
|
+
overlayContainer: {
|
|
56
|
+
...StyleSheet.absoluteFillObject,
|
|
57
|
+
justifyContent: 'center',
|
|
58
|
+
alignItems: 'center',
|
|
59
|
+
},
|
|
60
|
+
selection: {
|
|
61
|
+
alignSelf: 'stretch',
|
|
62
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
|
|
63
|
+
borderRadius: theme.borderRadius.md,
|
|
64
|
+
width: theme.components.timePicker.time.item.width,
|
|
65
|
+
height: theme.components.timePicker.time.item.height,
|
|
66
|
+
},
|
|
67
|
+
fadeOverlay: {
|
|
68
|
+
position: 'absolute',
|
|
69
|
+
top: 0,
|
|
70
|
+
left: 0,
|
|
71
|
+
right: 0,
|
|
72
|
+
},
|
|
73
|
+
fadeOverlayBottom: {
|
|
74
|
+
top: undefined,
|
|
75
|
+
bottom: 0,
|
|
76
|
+
},
|
|
77
|
+
}));
|
|
78
|
+
export default TimePickerWheel;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { PickerOption } from '
|
|
2
|
-
|
|
1
|
+
import type { PickerOption } from './TimePicker.props';
|
|
2
|
+
type TimePickerWheelProps = {
|
|
3
3
|
value: number | string;
|
|
4
4
|
setValue?: (value: any) => void;
|
|
5
5
|
items: PickerOption[];
|
|
6
|
-
}
|
|
7
|
-
declare const _default: import("react").MemoExoticComponent<({ value, setValue, items }:
|
|
6
|
+
};
|
|
7
|
+
declare const _default: import("react").MemoExoticComponent<({ value, setValue, items }: TimePickerWheelProps) => import("react/jsx-runtime").JSX.Element>;
|
|
8
8
|
export default _default;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useCallback, useMemo } from 'react';
|
|
3
|
+
import { Platform, View } from 'react-native';
|
|
4
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
5
|
+
import Animated, { Extrapolate, interpolate, runOnJS, useAnimatedStyle, useSharedValue, } from 'react-native-reanimated';
|
|
6
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
7
|
+
import { isEqual } from '../../utils';
|
|
8
|
+
import { BodyText } from '../BodyText';
|
|
9
|
+
const ITEM_HEIGHT = 44;
|
|
10
|
+
const WheelWebItem = ({ displayValue, index, currentIndex, translateY, radius, displayCount, value, }) => {
|
|
11
|
+
const baseOpacity = displayValue?.value !== value ? 0.3 : 1;
|
|
12
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
13
|
+
const offset = (radius * 2) / displayCount;
|
|
14
|
+
const shifted = interpolate(translateY.value, [-radius, radius], [-radius + offset * (index - currentIndex), radius + offset * (index - currentIndex)], Extrapolate.EXTEND);
|
|
15
|
+
const angle = interpolate(shifted, [-radius, radius], [-Math.PI / 2, Math.PI / 2], Extrapolate.CLAMP);
|
|
16
|
+
const translate = radius * Math.sin(angle);
|
|
17
|
+
const rotateX = (angle * 180) / Math.PI;
|
|
18
|
+
return {
|
|
19
|
+
position: 'absolute',
|
|
20
|
+
height: ITEM_HEIGHT - 10,
|
|
21
|
+
opacity: baseOpacity,
|
|
22
|
+
alignItems: 'center',
|
|
23
|
+
justifyContent: 'center',
|
|
24
|
+
transform: [{ translateY: translate }, { rotateX: `${rotateX}deg` }],
|
|
25
|
+
};
|
|
26
|
+
}, [baseOpacity, currentIndex, displayCount, index, radius, translateY]);
|
|
27
|
+
return (_jsx(Animated.View, { style: animatedStyle, children: _jsx(BodyText, { size: "lg", children: displayValue?.text }) }));
|
|
28
|
+
};
|
|
29
|
+
const TimePickerWheel = ({ value, setValue = () => { }, items }) => {
|
|
30
|
+
const displayCount = 5;
|
|
31
|
+
const translateY = useSharedValue(0);
|
|
32
|
+
const renderCount = displayCount * 2 < items.length ? displayCount * 8 : displayCount * 2 - 1;
|
|
33
|
+
const circular = items.length >= displayCount;
|
|
34
|
+
const height = 140;
|
|
35
|
+
const radius = height / 2;
|
|
36
|
+
const valueIndex = useMemo(() => {
|
|
37
|
+
return Math.max(0, items.findIndex(item => item.value === value));
|
|
38
|
+
}, [items, value]);
|
|
39
|
+
const handlePanEnd = useCallback((deltaY) => {
|
|
40
|
+
let newValueIndex = valueIndex - Math.round(deltaY / ((radius * 2) / displayCount));
|
|
41
|
+
if (circular) {
|
|
42
|
+
newValueIndex = (newValueIndex + items.length) % items.length;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
if (newValueIndex < 0) {
|
|
46
|
+
newValueIndex = 0;
|
|
47
|
+
}
|
|
48
|
+
else if (newValueIndex >= items.length) {
|
|
49
|
+
newValueIndex = items.length - 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const newValue = items[newValueIndex];
|
|
53
|
+
if (newValue?.value === value) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (newValue?.value) {
|
|
57
|
+
setValue(newValue.value);
|
|
58
|
+
}
|
|
59
|
+
else if (items[0]?.value) {
|
|
60
|
+
setValue(items[0].value);
|
|
61
|
+
}
|
|
62
|
+
}, [circular, displayCount, items, radius, setValue, value, valueIndex]);
|
|
63
|
+
const panGesture = useMemo(() => Gesture.Pan()
|
|
64
|
+
.onUpdate(event => {
|
|
65
|
+
translateY.value = event.translationY;
|
|
66
|
+
})
|
|
67
|
+
.onEnd(event => {
|
|
68
|
+
runOnJS(handlePanEnd)(event.translationY);
|
|
69
|
+
translateY.value = 0;
|
|
70
|
+
}), [handlePanEnd, translateY]);
|
|
71
|
+
const displayValues = useMemo(() => {
|
|
72
|
+
const centerIndex = Math.floor(renderCount / 2);
|
|
73
|
+
return Array.from({ length: renderCount }, (_, index) => {
|
|
74
|
+
let targetIndex = valueIndex + index - centerIndex;
|
|
75
|
+
if (circular) {
|
|
76
|
+
targetIndex = ((targetIndex % items.length) + items.length) % items.length;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
targetIndex = Math.max(0, Math.min(targetIndex, items.length - 1));
|
|
80
|
+
}
|
|
81
|
+
return items[targetIndex] || items[0];
|
|
82
|
+
});
|
|
83
|
+
}, [renderCount, valueIndex, items, circular]);
|
|
84
|
+
const currentIndex = Math.max(0, displayValues.findIndex(item => item?.value === value));
|
|
85
|
+
return (_jsx(GestureDetector, { gesture: panGesture, children: _jsxs(View, { style: styles.container, children: [_jsx(View, { style: [
|
|
86
|
+
styles.selectedIndicator,
|
|
87
|
+
{
|
|
88
|
+
transform: [{ translateY: -ITEM_HEIGHT / 2 }],
|
|
89
|
+
height: ITEM_HEIGHT,
|
|
90
|
+
},
|
|
91
|
+
] }), displayValues?.map((displayValue, index) => (_jsx(WheelWebItem, { displayValue: displayValue, index: index, currentIndex: currentIndex, translateY: translateY, radius: radius, displayCount: displayCount, value: value }, `${displayValue?.text}-${index}`)))] }) }));
|
|
92
|
+
};
|
|
93
|
+
const styles = StyleSheet.create(theme => ({
|
|
94
|
+
container: {
|
|
95
|
+
minWidth: 30,
|
|
96
|
+
overflow: 'hidden',
|
|
97
|
+
alignItems: 'center',
|
|
98
|
+
justifyContent: 'center',
|
|
99
|
+
height: 208,
|
|
100
|
+
...Platform.select({
|
|
101
|
+
web: {
|
|
102
|
+
cursor: 'pointer',
|
|
103
|
+
userSelect: 'none',
|
|
104
|
+
},
|
|
105
|
+
}),
|
|
106
|
+
},
|
|
107
|
+
selectedIndicator: {
|
|
108
|
+
position: 'absolute',
|
|
109
|
+
width: theme.components.timePicker.time.item.width,
|
|
110
|
+
height: theme.components.timePicker.time.item.height,
|
|
111
|
+
top: '50%',
|
|
112
|
+
backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
|
|
113
|
+
borderRadius: theme.borderRadius.md,
|
|
114
|
+
alignItems: 'center',
|
|
115
|
+
justifyContent: 'center',
|
|
116
|
+
},
|
|
117
|
+
}));
|
|
118
|
+
const customComparator = (prev, next) => {
|
|
119
|
+
const areEqual = prev.value === next.value && prev.setValue === next.setValue && isEqual(prev.items, next.items);
|
|
120
|
+
return areEqual;
|
|
121
|
+
};
|
|
122
|
+
export default memo(TimePickerWheel, customComparator);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import 'dayjs/locale/en';
|
|
2
|
+
import '../DatePicker/polyfill';
|
|
3
|
+
export type { BottomSheetMethods as TimePickerMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
|
|
4
|
+
export type { DateType } from '../DatePicker/DatePicker.props';
|
|
5
|
+
export { default as TimePicker } from './TimePicker';
|
|
6
|
+
export type { TimePickerProps } from './TimePicker.props';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type TimePickerInputProps from './TimePickerInput.props';
|
|
2
|
+
declare const TimePickerInput: {
|
|
3
|
+
({ validationStatus, disabled, focused, readonly, placeholder, inBottomSheet, format, openButtonLabel, autoCloseOnSelect, label, labelVariant, helperText, helperIcon, validText, invalidText, required, onChange, onChangeText, onBlur, onFocus, value, timePickerProps, onClear, ...rest }: TimePickerInputProps): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
displayName: string;
|
|
5
|
+
};
|
|
6
|
+
export default TimePickerInput;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { CloseSmallIcon, TimeSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
5
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
+
import { Keyboard, Platform } from 'react-native';
|
|
7
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
8
|
+
import { useFormFieldContext } from '../FormField';
|
|
9
|
+
import { Input, InputField, InputSlot } from '../Input';
|
|
10
|
+
import { TimePicker } from '../TimePicker';
|
|
11
|
+
import { UnstyledIconButton } from '../UnstyledIconButton';
|
|
12
|
+
import TimePickerInputDoneButton from './TimePickerInputDoneButton';
|
|
13
|
+
dayjs.extend(customParseFormat);
|
|
14
|
+
const DEFAULT_FORMAT_24 = 'HH:mm';
|
|
15
|
+
const DEFAULT_FORMAT_12 = 'hh:mm A';
|
|
16
|
+
const maskDefaultFormat = (value) => {
|
|
17
|
+
const digitsOnly = value.replace(/\D/g, '').slice(0, 4);
|
|
18
|
+
const hours = digitsOnly.slice(0, 2);
|
|
19
|
+
const minutes = digitsOnly.slice(2, 4);
|
|
20
|
+
return [hours, minutes].filter(Boolean).join(':');
|
|
21
|
+
};
|
|
22
|
+
const TimePickerInput = ({ validationStatus = 'initial', disabled, focused, readonly, placeholder = '--:--', inBottomSheet = false, format, openButtonLabel = 'Open time picker', autoCloseOnSelect = true, label, labelVariant, helperText, helperIcon, validText, invalidText, required = true, onChange, onChangeText, onBlur, onFocus, value, timePickerProps, onClear, ...rest }) => {
|
|
23
|
+
const formFieldContext = useFormFieldContext();
|
|
24
|
+
const isDisabled = formFieldContext?.disabled ?? disabled;
|
|
25
|
+
const isReadonly = formFieldContext?.readonly ?? readonly;
|
|
26
|
+
const pickerRef = useRef(null);
|
|
27
|
+
const accessoryViewID = useMemo(() => {
|
|
28
|
+
if (Platform.OS !== 'ios')
|
|
29
|
+
return undefined;
|
|
30
|
+
return `timepicker-input-${Math.random().toString(36).slice(2)}`;
|
|
31
|
+
}, []);
|
|
32
|
+
const use12Hours = timePickerProps?.use12Hours ?? false;
|
|
33
|
+
const resolvedFormat = useMemo(() => format ?? (use12Hours ? DEFAULT_FORMAT_12 : DEFAULT_FORMAT_24), [format, use12Hours]);
|
|
34
|
+
const formatTime = useCallback((dateValue) => {
|
|
35
|
+
if (!dateValue)
|
|
36
|
+
return '';
|
|
37
|
+
const parsed = dayjs(dateValue);
|
|
38
|
+
return parsed.isValid() ? parsed.format(resolvedFormat) : '';
|
|
39
|
+
}, [resolvedFormat]);
|
|
40
|
+
const isDefaultFormat = resolvedFormat === DEFAULT_FORMAT_24;
|
|
41
|
+
const [inputValue, setInputValue] = useState(() => formatTime(value));
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
setInputValue(formatTime(value));
|
|
44
|
+
}, [value, formatTime]);
|
|
45
|
+
const handleTextChange = useCallback((text) => {
|
|
46
|
+
const nextValue = isDefaultFormat ? maskDefaultFormat(text) : text;
|
|
47
|
+
setInputValue(nextValue);
|
|
48
|
+
onChangeText?.(nextValue);
|
|
49
|
+
if (!nextValue) {
|
|
50
|
+
onChange?.({ date: undefined });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const parsed = dayjs(nextValue, resolvedFormat, true);
|
|
54
|
+
if (parsed.isValid()) {
|
|
55
|
+
onChange?.({ date: parsed.toDate() });
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
onChange?.({ date: undefined });
|
|
59
|
+
}
|
|
60
|
+
}, [isDefaultFormat, onChange, onChangeText, resolvedFormat]);
|
|
61
|
+
const handleClear = useCallback(() => {
|
|
62
|
+
setInputValue('');
|
|
63
|
+
onChange?.({ date: undefined });
|
|
64
|
+
onClear?.();
|
|
65
|
+
}, [onChange, onClear]);
|
|
66
|
+
const closeKeyboard = useCallback(() => {
|
|
67
|
+
Keyboard.dismiss();
|
|
68
|
+
}, []);
|
|
69
|
+
const openPicker = useCallback(() => {
|
|
70
|
+
if (isDisabled || isReadonly)
|
|
71
|
+
return;
|
|
72
|
+
closeKeyboard();
|
|
73
|
+
pickerRef.current?.present();
|
|
74
|
+
}, [closeKeyboard, isDisabled, isReadonly]);
|
|
75
|
+
const selectedDate = useMemo(() => {
|
|
76
|
+
if (value) {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
const parsed = dayjs(inputValue, resolvedFormat, true);
|
|
80
|
+
return parsed.isValid() ? parsed.toDate() : undefined;
|
|
81
|
+
}, [value, inputValue, resolvedFormat]);
|
|
82
|
+
const handlePickerChange = useCallback(({ date }) => {
|
|
83
|
+
if (!date) {
|
|
84
|
+
handleClear();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const formatted = formatTime(date);
|
|
88
|
+
setInputValue(formatted);
|
|
89
|
+
onChange?.({ date });
|
|
90
|
+
if (autoCloseOnSelect) {
|
|
91
|
+
pickerRef.current?.close?.();
|
|
92
|
+
}
|
|
93
|
+
}, [autoCloseOnSelect, formatTime, handleClear, onChange]);
|
|
94
|
+
const handleBlur = useCallback((event) => {
|
|
95
|
+
onBlur?.(event);
|
|
96
|
+
}, [onBlur]);
|
|
97
|
+
const handleFocus = useCallback((event) => {
|
|
98
|
+
onFocus?.(event);
|
|
99
|
+
}, [onFocus]);
|
|
100
|
+
const { onCancel: pickerOnCancel, ...restTimePickerProps } = timePickerProps ?? {};
|
|
101
|
+
const { style: inputStyle, keyboardType: keyboardTypeProp, inputMode: inputModeProp, accessibilityHint: accessibilityHintProp, accessibilityLabel: accessibilityLabelProp, accessible: accessibleProp, importantForAccessibility: importantForAccessibilityProp, ...textInputProps } = rest;
|
|
102
|
+
const resolvedKeyboardType = keyboardTypeProp ?? (isDefaultFormat ? 'number-pad' : undefined);
|
|
103
|
+
const resolvedInputMode = inputModeProp ?? (isDefaultFormat ? 'numeric' : undefined);
|
|
104
|
+
const resolvedAccessibilityHint = accessibilityHintProp ?? `Enter the time in ${resolvedFormat} format`;
|
|
105
|
+
const resolvedAccessibilityLabel = accessibilityLabelProp ?? 'Time input';
|
|
106
|
+
const resolvedAccessible = accessibleProp ?? true;
|
|
107
|
+
const resolvedImportantForAccessibility = importantForAccessibilityProp ?? 'yes';
|
|
108
|
+
const handleCancel = useCallback(() => {
|
|
109
|
+
pickerOnCancel?.();
|
|
110
|
+
pickerRef.current?.close?.();
|
|
111
|
+
}, [pickerOnCancel]);
|
|
112
|
+
const placeholderValue = placeholder;
|
|
113
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Input, { validationStatus: validationStatus, disabled: disabled, readonly: readonly, focused: focused, label: label, labelVariant: labelVariant, helperText: helperText, helperIcon: helperIcon, validText: validText, invalidText: invalidText, required: required, style: styles.wrap, accessible: false, children: [_jsx(InputField, { editable: !isReadonly && !isDisabled, value: inputValue, placeholder: placeholderValue, onChangeText: handleTextChange, onBlur: handleBlur, onFocus: handleFocus, inBottomSheet: inBottomSheet, keyboardType: resolvedKeyboardType, inputMode: resolvedInputMode, accessibilityHint: resolvedAccessibilityHint, "aria-label": "Time input", accessibilityLabel: resolvedAccessibilityLabel, accessible: resolvedAccessible, accessibilityState: {
|
|
114
|
+
disabled: isDisabled || isReadonly,
|
|
115
|
+
}, importantForAccessibility: resolvedImportantForAccessibility, inputAccessoryViewID: Platform.OS === 'ios' ? accessoryViewID : undefined, ...textInputProps, style: [styles.input, inputStyle] }), !!inputValue && onClear && !isReadonly && !isDisabled && (_jsx(InputSlot, { accessibilityElementsHidden: false, children: _jsx(UnstyledIconButton, { accessibilityLabel: "Clear time", accessibilityHint: "Removes the current time", icon: CloseSmallIcon, onPress: handleClear }) })), _jsx(InputSlot, { accessibilityElementsHidden: false, children: _jsx(UnstyledIconButton, { accessibilityLabel: openButtonLabel, accessibilityHint: "Opens the time picker", icon: TimeSmallIcon, onPress: openPicker, disabled: isDisabled || isReadonly }) })] }), _jsx(TimePicker, { ref: pickerRef, date: selectedDate, onChange: handlePickerChange, onCancel: handleCancel, ...restTimePickerProps }), Platform.OS === 'ios' && accessoryViewID && (_jsx(TimePickerInputDoneButton, { accessoryViewID: accessoryViewID, closeKeyboard: closeKeyboard }))] }));
|
|
116
|
+
};
|
|
117
|
+
TimePickerInput.displayName = 'TimePickerInput';
|
|
118
|
+
const styles = StyleSheet.create(theme => ({
|
|
119
|
+
wrap: {
|
|
120
|
+
gap: theme.components.input.date.gap,
|
|
121
|
+
},
|
|
122
|
+
input: {
|
|
123
|
+
paddingLeft: 0,
|
|
124
|
+
paddingRight: 0,
|
|
125
|
+
},
|
|
126
|
+
}));
|
|
127
|
+
export default TimePickerInput;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { TextInputProps, ViewProps } from 'react-native';
|
|
2
|
+
import type { DateType } from '../DatePicker/DatePicker.props';
|
|
3
|
+
import type { TimePickerProps } from '../TimePicker/TimePicker.props';
|
|
4
|
+
export interface TimePickerInputBaseProps {
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
validationStatus?: 'initial' | 'valid' | 'invalid';
|
|
7
|
+
readonly?: boolean;
|
|
8
|
+
focused?: boolean;
|
|
9
|
+
label?: string;
|
|
10
|
+
labelVariant?: 'heading' | 'body';
|
|
11
|
+
helperText?: string;
|
|
12
|
+
helperIcon?: React.ComponentType;
|
|
13
|
+
validText?: string;
|
|
14
|
+
invalidText?: string;
|
|
15
|
+
placeholder?: string;
|
|
16
|
+
inBottomSheet?: boolean;
|
|
17
|
+
required?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Controls how the selected time is formatted when displayed inside the input.
|
|
20
|
+
* Accepts any Day.js format string.
|
|
21
|
+
*/
|
|
22
|
+
format?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Accessible label announced when activating the time picker trigger button.
|
|
25
|
+
*/
|
|
26
|
+
openButtonLabel?: string;
|
|
27
|
+
/**
|
|
28
|
+
* When true (default), the picker sheet is dismissed as soon as a time is picked.
|
|
29
|
+
*/
|
|
30
|
+
autoCloseOnSelect?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Additional props forwarded to the underlying TimePicker instance.
|
|
33
|
+
*/
|
|
34
|
+
timePickerProps?: Omit<TimePickerProps, 'date' | 'onChange' | 'ref'>;
|
|
35
|
+
/**
|
|
36
|
+
* Handles cleared input values.
|
|
37
|
+
*/
|
|
38
|
+
onClear?: () => void;
|
|
39
|
+
}
|
|
40
|
+
export type TimePickerInputProps = TimePickerInputBaseProps & Omit<TextInputProps, 'value' | 'onChange' | 'children'> & ViewProps & {
|
|
41
|
+
/**
|
|
42
|
+
* Controlled time value. Accepts Date, string, number or Day.js instances.
|
|
43
|
+
*/
|
|
44
|
+
value?: DateType;
|
|
45
|
+
/**
|
|
46
|
+
* Fired after a valid time is parsed either from typing or the picker selection.
|
|
47
|
+
*/
|
|
48
|
+
onChange?: (params: {
|
|
49
|
+
date: DateType;
|
|
50
|
+
}) => void;
|
|
51
|
+
};
|
|
52
|
+
export default TimePickerInputProps;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { InputAccessoryView, View } from 'react-native';
|
|
3
|
+
import { StyleSheet } from 'react-native-unistyles';
|
|
4
|
+
import { Button } from '../Button';
|
|
5
|
+
const TimePickerInputDoneButton = ({ accessoryViewID, closeKeyboard, }) => {
|
|
6
|
+
return (_jsx(InputAccessoryView, { nativeID: accessoryViewID, children: _jsx(View, { style: styles.accessory, children: _jsx(Button, { accessibilityRole: "button", accessibilityLabel: "Done", onPress: closeKeyboard, variant: "ghost", colorScheme: "functional", children: "Done" }) }) }));
|
|
7
|
+
};
|
|
8
|
+
const styles = StyleSheet.create(theme => ({
|
|
9
|
+
accessory: {
|
|
10
|
+
paddingHorizontal: 16,
|
|
11
|
+
paddingVertical: 2,
|
|
12
|
+
alignItems: 'flex-end',
|
|
13
|
+
backgroundColor: theme.color.surface.neutral.strong,
|
|
14
|
+
borderTopWidth: theme.borderWidth[1],
|
|
15
|
+
borderTopColor: theme.color.border.subtle,
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
TimePickerInputDoneButton.DisplayName = 'TimePickerInputDoneButton';
|
|
19
|
+
export default TimePickerInputDoneButton;
|