@utilitywarehouse/hearth-react-native 0.28.0-testid-fix-1 → 0.28.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 +4 -5
- package/.turbo/turbo-lint.log +68 -70
- package/build/components/Select/Select.d.ts +1 -1
- package/build/components/Select/Select.js +4 -4
- package/build/components/Select/Select.props.d.ts +0 -4
- package/build/components/Select/SelectOption.d.ts +1 -1
- package/build/components/Select/SelectOption.js +2 -2
- package/build/components/VerificationInput/VerificationInput.js +3 -3
- package/package.json +4 -4
- package/src/components/Select/Select.props.ts +0 -4
- package/src/components/Select/Select.tsx +1 -5
- package/src/components/Select/SelectOption.tsx +0 -2
- package/src/components/VerificationInput/VerificationInput.tsx +0 -3
- 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.d.ts +0 -8
- 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/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
|
|
2
|
+
> @utilitywarehouse/hearth-react-native@0.28.0 build /home/runner/work/hearth/hearth/packages/react-native
|
|
3
|
+
> tsc
|
|
4
|
+
|
package/.turbo/turbo-lint.log
CHANGED
|
@@ -1,70 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
react-hooks/
|
|
63
|
-
no-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
no-misleading-character-class
|
|
67
|
-
|
|
68
|
-
no-
|
|
69
|
-
@typescript-eslint/triple-slash-reference | 8.378 | 1.2%
|
|
70
|
-
no-loss-of-precision | 8.049 | 1.2%
|
|
1
|
+
|
|
2
|
+
> @utilitywarehouse/hearth-react-native@0.28.0 lint /home/runner/work/hearth/hearth/packages/react-native
|
|
3
|
+
> TIMING=1 eslint .
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Carousel/Carousel.context.tsx
|
|
7
|
+
6:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
|
|
8
|
+
|
|
9
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Carousel/Carousel.tsx
|
|
10
|
+
146:6 warning React Hook useMemo has a missing dependency: 'hasCarouselControlsInTree'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
11
|
+
|
|
12
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePicker.tsx
|
|
13
|
+
109:6 warning React Hook useCallback has an unnecessary dependency: 'modalRef.current'. Either exclude it or remove the dependency array. Mutable values like 'modalRef.current' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
14
|
+
259:6 warning React Hook useEffect has a missing dependency: 'initialState'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
15
|
+
346:6 warning React Hook useEffect has a missing dependency: 'onChange'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
16
|
+
468:5 warning React Hook useCallback has a missing dependency: 'onChange'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
17
|
+
536:6 warning React Hook useEffect has a missing dependency: 'onSelectMonth'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
18
|
+
542:6 warning React Hook useEffect has a missing dependency: 'onSelectYear'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
19
|
+
|
|
20
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePickerDay.tsx
|
|
21
|
+
76:6 warning React Hook useMemo has an unnecessary dependency: 'styles.rangeRoot'. Either exclude it or remove the dependency array. Outer scope values like 'styles.rangeRoot' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
22
|
+
84:6 warning React Hook useMemo has a missing dependency: 'isSelected'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
23
|
+
|
|
24
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePickerDays.tsx
|
|
25
|
+
179:6 warning React Hook useMemo has unnecessary dependencies: 'month' and 'year'. Either exclude them or remove the dependency array react-hooks/exhaustive-deps
|
|
26
|
+
|
|
27
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/DatePicker/DatePickerYears.tsx
|
|
28
|
+
52:6 warning React Hook useCallback has a missing dependency: 'containerHeight'. Either include it or remove the dependency array. Outer scope values like 'styles' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
29
|
+
|
|
30
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Input/Input.tsx
|
|
31
|
+
78:8 warning React Hook useEffect has a missing dependency: 'formFieldContext'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
32
|
+
|
|
33
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Modal/Modal.web.tsx
|
|
34
|
+
66:6 warning React Hook useCallback has an unnecessary dependency: 'Platform.OS'. Either exclude it or remove the dependency array. Outer scope values like 'Platform.OS' aren't valid dependencies because mutating them doesn't re-render the component react-hooks/exhaustive-deps
|
|
35
|
+
|
|
36
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/PillGroup/PillGroup.tsx
|
|
37
|
+
17:9 warning The 'normalizedValue' conditional could make the dependencies of useMemo Hook (at line 33) change on every render. Move it inside the useMemo callback. Alternatively, wrap the initialization of 'normalizedValue' in its own useMemo() Hook react-hooks/exhaustive-deps
|
|
38
|
+
|
|
39
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Table/Table.context.tsx
|
|
40
|
+
23:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
|
|
41
|
+
|
|
42
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Tabs/Tabs.tsx
|
|
43
|
+
53:6 warning React Hook useEffect has a missing dependency: 'tabValues'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
44
|
+
53:7 warning React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
|
|
45
|
+
104:5 warning React Hook useMemo has an unnecessary dependency: 'tabValues'. Either exclude it or remove the dependency array react-hooks/exhaustive-deps
|
|
46
|
+
127:62 warning React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked react-hooks/exhaustive-deps
|
|
47
|
+
|
|
48
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Textarea/Textarea.tsx
|
|
49
|
+
45:6 warning React Hook useEffect has a missing dependency: 'formFieldContext'. Either include it or remove the dependency array react-hooks/exhaustive-deps
|
|
50
|
+
|
|
51
|
+
/home/runner/work/hearth/hearth/packages/react-native/src/components/Toast/Toast.context.tsx
|
|
52
|
+
14:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
|
|
53
|
+
106:14 warning Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components react-refresh/only-export-components
|
|
54
|
+
|
|
55
|
+
✖ 23 problems (0 errors, 23 warnings)
|
|
56
|
+
|
|
57
|
+
Rule | Time (ms) | Relative
|
|
58
|
+
:---------------------------------|----------:|--------:
|
|
59
|
+
@typescript-eslint/no-unused-vars | 1525.743 | 62.8%
|
|
60
|
+
react-hooks/exhaustive-deps | 120.190 | 4.9%
|
|
61
|
+
no-global-assign | 94.322 | 3.9%
|
|
62
|
+
react-hooks/rules-of-hooks | 73.690 | 3.0%
|
|
63
|
+
no-unexpected-multiline | 49.929 | 2.1%
|
|
64
|
+
@typescript-eslint/ban-ts-comment | 44.011 | 1.8%
|
|
65
|
+
no-loss-of-precision | 35.100 | 1.4%
|
|
66
|
+
no-misleading-character-class | 32.579 | 1.3%
|
|
67
|
+
no-useless-escape | 32.193 | 1.3%
|
|
68
|
+
no-control-regex | 21.498 | 0.9%
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import SelectProps from './Select.props';
|
|
2
2
|
declare const Select: {
|
|
3
|
-
({ options, value, onValueChange, label, labelVariant, placeholder, disabled, leadingIcon: LeadingIcon, validationStatus, helperText, helperIcon, invalidText, validText, required, children, bottomSheetProps, menuHeading, readonly, emptyText, listProps, searchable, searchPlaceholder,
|
|
3
|
+
({ options, value, onValueChange, label, labelVariant, placeholder, disabled, leadingIcon: LeadingIcon, validationStatus, helperText, helperIcon, invalidText, validText, required, children, bottomSheetProps, menuHeading, readonly, emptyText, listProps, searchable, searchPlaceholder, ...rest }: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
displayName: string;
|
|
5
5
|
};
|
|
6
6
|
export default Select;
|
|
@@ -12,7 +12,7 @@ import { Input } from '../Input';
|
|
|
12
12
|
import { SelectContext } from './Select.context';
|
|
13
13
|
import SelectOption from './SelectOption';
|
|
14
14
|
import { SafeAreaView } from '../SafeAreaView';
|
|
15
|
-
const Select = ({ options = [], value, onValueChange, label, labelVariant = 'body', placeholder = 'Select an option', disabled = false, leadingIcon: LeadingIcon, validationStatus = 'initial', helperText, helperIcon, invalidText, validText, required = true, children, bottomSheetProps, menuHeading, readonly = false, emptyText = 'No options available', listProps, searchable = false, searchPlaceholder = 'Search',
|
|
15
|
+
const Select = ({ options = [], value, onValueChange, label, labelVariant = 'body', placeholder = 'Select an option', disabled = false, leadingIcon: LeadingIcon, validationStatus = 'initial', helperText, helperIcon, invalidText, validText, required = true, children, bottomSheetProps, menuHeading, readonly = false, emptyText = 'No options available', listProps, searchable = false, searchPlaceholder = 'Search', ...rest }) => {
|
|
16
16
|
const formFieldContext = useFormFieldContext();
|
|
17
17
|
const validationStatusFromContext = formFieldContext?.validationStatus ?? validationStatus;
|
|
18
18
|
const isRequired = formFieldContext?.required ?? required;
|
|
@@ -65,9 +65,9 @@ const Select = ({ options = [], value, onValueChange, label, labelVariant = 'bod
|
|
|
65
65
|
setIsOpen(false);
|
|
66
66
|
setSearch('');
|
|
67
67
|
}, []);
|
|
68
|
-
const renderSelectOption = useCallback(({ item }) => (_jsx(SelectOption, { label: item.label, value: item.value, disabled: item.disabled, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon
|
|
68
|
+
const renderSelectOption = useCallback(({ item }) => (_jsx(SelectOption, { label: item.label, value: item.value, disabled: item.disabled, leadingIcon: item.leadingIcon, trailingIcon: item.trailingIcon })), []);
|
|
69
69
|
const renderEmptyComponent = useCallback(() => (_jsx(BottomSheetView, { style: styles.emptyContainer, children: _jsx(DetailText, { children: emptyText }) })), [emptyText]);
|
|
70
|
-
return (_jsxs(View, { ...rest, style: [styles.container, rest.style], children: [_jsx(FormField, { label: label, labelVariant: labelVariant, helperText: helperText, helperIcon: helperIcon, validationStatus: validationStatusFromContext, required: isRequired, disabled: isDisabled, readonly: isReadonly, invalidText: invalidText, validText: validText, children: _jsxs(Pressable, { onPress: openBottomSheet, disabled: isDisabled || isReadonly,
|
|
70
|
+
return (_jsxs(View, { ...rest, style: [styles.container, rest.style], children: [_jsx(FormField, { label: label, labelVariant: labelVariant, helperText: helperText, helperIcon: helperIcon, validationStatus: validationStatusFromContext, required: isRequired, disabled: isDisabled, readonly: isReadonly, invalidText: invalidText, validText: validText, children: _jsxs(Pressable, { onPress: openBottomSheet, disabled: isDisabled || isReadonly, style: ({ pressed }) => [
|
|
71
71
|
styles.selectContainer,
|
|
72
72
|
styles.pressedContainer(pressed || isOpen),
|
|
73
73
|
], children: [!!LeadingIcon && (_jsx(View, { children: (() => {
|
|
@@ -77,7 +77,7 @@ const Select = ({ options = [], value, onValueChange, label, labelVariant = 'bod
|
|
|
77
77
|
selectedValue: value,
|
|
78
78
|
onValueChange,
|
|
79
79
|
close: closeBottomSheet,
|
|
80
|
-
}, children: _jsxs(SafeAreaView, { edges: ['top'], style: { flex: 1 }, children: [menuHeading && (_jsx(View, { style: styles.headingContainer, children: _jsx(DetailText, { size: "lg", children: menuHeading }) })), searchable && (_jsx(View, { style: styles.searchContainer, children: _jsx(Input, { placeholder: searchPlaceholder, value: search, inBottomSheet: true, onChangeText: setSearch, type: "search"
|
|
80
|
+
}, children: _jsxs(SafeAreaView, { edges: ['top'], style: { flex: 1 }, children: [menuHeading && (_jsx(View, { style: styles.headingContainer, children: _jsx(DetailText, { size: "lg", children: menuHeading }) })), searchable && (_jsx(View, { style: styles.searchContainer, children: _jsx(Input, { placeholder: searchPlaceholder, value: search, inBottomSheet: true, onChangeText: setSearch, type: "search" }) })), children ? (_jsx(BottomSheetScrollView, { children: children })) : (_jsx(BottomSheetFlatList, { data: filteredOptions, keyExtractor: (option) => option.value, renderItem: renderSelectOption, ListEmptyComponent: renderEmptyComponent, ...listProps }))] }) }) })] }));
|
|
81
81
|
};
|
|
82
82
|
const styles = StyleSheet.create(theme => ({
|
|
83
83
|
container: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SelectOptionProps } from './Select.props';
|
|
2
2
|
declare const SelectOption: {
|
|
3
|
-
({ label, value, leadingIcon: LeftIcon, trailingIcon: RightIcon, selected, disabled, onPress,
|
|
3
|
+
({ label, value, leadingIcon: LeftIcon, trailingIcon: RightIcon, selected, disabled, onPress, }: SelectOptionProps): import("react/jsx-runtime").JSX.Element;
|
|
4
4
|
displayName: string;
|
|
5
5
|
};
|
|
6
6
|
export default SelectOption;
|
|
@@ -5,7 +5,7 @@ import { StyleSheet } from 'react-native-unistyles';
|
|
|
5
5
|
import { BodyText } from '../BodyText';
|
|
6
6
|
import { Icon } from '../Icon';
|
|
7
7
|
import { useSelectContext } from './Select.context';
|
|
8
|
-
const SelectOption = ({ label, value, leadingIcon: LeftIcon, trailingIcon: RightIcon, selected, disabled, onPress,
|
|
8
|
+
const SelectOption = ({ label, value, leadingIcon: LeftIcon, trailingIcon: RightIcon, selected, disabled, onPress, }) => {
|
|
9
9
|
const { selectedValue, onValueChange, close } = useSelectContext();
|
|
10
10
|
const isSelected = selected !== undefined ? selected : selectedValue === value;
|
|
11
11
|
styles.useVariants({ disabled });
|
|
@@ -22,7 +22,7 @@ const SelectOption = ({ label, value, leadingIcon: LeftIcon, trailingIcon: Right
|
|
|
22
22
|
close();
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
-
return (_jsxs(Pressable, { onPress: handlePress, disabled: disabled,
|
|
25
|
+
return (_jsxs(Pressable, { onPress: handlePress, disabled: disabled, style: ({ pressed }) => [styles.container, pressed && styles.pressed], children: [!!LeftIcon && (_jsx(View, { children: _jsx(Icon, { as: LeftIcon, style: styles.icon }) })), _jsx(View, { style: styles.labelContainer, children: _jsx(BodyText, { children: label }) }), isSelected && (_jsx(View, { children: _jsx(Icon, { as: TickSmallIcon, style: styles.icon }) })), !!RightIcon && !isSelected && (_jsx(View, { children: _jsx(Icon, { as: RightIcon, style: styles.icon }) }))] }));
|
|
26
26
|
};
|
|
27
27
|
const styles = StyleSheet.create(theme => ({
|
|
28
28
|
container: {
|
|
@@ -5,7 +5,7 @@ import { StyleSheet } from 'react-native-unistyles';
|
|
|
5
5
|
import { FormField } from '../FormField';
|
|
6
6
|
import { getNextIndexFromValueChange } from './VerificationInput.utils';
|
|
7
7
|
import { VerificationInputSlot } from './VerificationInputSlot';
|
|
8
|
-
const VerificationInput = forwardRef(({ value = '', onChangeText, label, labelVariant = 'body', helperText, helperIcon, validationStatus = 'initial', validText, invalidText, disabled = false, readonly = false, secureTextEntry = false, autoFocus = false, style,
|
|
8
|
+
const VerificationInput = forwardRef(({ value = '', onChangeText, label, labelVariant = 'body', helperText, helperIcon, validationStatus = 'initial', validText, invalidText, disabled = false, readonly = false, secureTextEntry = false, autoFocus = false, style, ...props }, ref) => {
|
|
9
9
|
const length = 6;
|
|
10
10
|
const inputRef = useRef(null);
|
|
11
11
|
const latestValueRef = useRef(value);
|
|
@@ -160,7 +160,7 @@ const VerificationInput = forwardRef(({ value = '', onChangeText, label, labelVa
|
|
|
160
160
|
latestSelectionRef.current = nextSelection;
|
|
161
161
|
setSelection(nextSelection);
|
|
162
162
|
setFocusedIndex(Math.min(nextSelection.start, length - 1));
|
|
163
|
-
}, onFocus: handleFocus, onBlur: handleBlur, selection: selection, keyboardType: "number-pad", textContentType: "oneTimeCode", autoComplete: "sms-otp", secureTextEntry: secureTextEntry, maxLength: length, caretHidden: true, style: styles.hiddenInput
|
|
163
|
+
}, onFocus: handleFocus, onBlur: handleBlur, selection: selection, keyboardType: "number-pad", textContentType: "oneTimeCode", autoComplete: "sms-otp", secureTextEntry: secureTextEntry, maxLength: length, caretHidden: true, style: styles.hiddenInput }), slots.map(index => {
|
|
164
164
|
const char = displayValue[index] || '';
|
|
165
165
|
const isActive = focusedIndex === index;
|
|
166
166
|
const displayChar = secureTextEntry && char ? '*' : char;
|
|
@@ -168,7 +168,7 @@ const VerificationInput = forwardRef(({ value = '', onChangeText, label, labelVa
|
|
|
168
168
|
pendingFocusIndexRef.current = index;
|
|
169
169
|
inputRef.current?.focus();
|
|
170
170
|
setSelectionIndex(index);
|
|
171
|
-
}
|
|
171
|
+
} }, index));
|
|
172
172
|
})] }) }));
|
|
173
173
|
});
|
|
174
174
|
const styles = StyleSheet.create(theme => ({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utilitywarehouse/hearth-react-native",
|
|
3
|
-
"version": "0.28.0
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Utility Warehouse React Native UI library",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -56,11 +56,11 @@
|
|
|
56
56
|
"vite": "^7.1.3",
|
|
57
57
|
"vite-plugin-svgr": "^4.5.0",
|
|
58
58
|
"vitest": "^3.2.4",
|
|
59
|
-
"@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
|
|
60
59
|
"@utilitywarehouse/hearth-fonts": "^0.0.4",
|
|
60
|
+
"@utilitywarehouse/hearth-react-icons": "^0.8.0",
|
|
61
61
|
"@utilitywarehouse/hearth-svg-assets": "^0.5.0",
|
|
62
|
-
"@utilitywarehouse/hearth-
|
|
63
|
-
"@utilitywarehouse/hearth-
|
|
62
|
+
"@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
|
|
63
|
+
"@utilitywarehouse/hearth-tokens": "^0.2.4"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
66
|
"@gorhom/bottom-sheet": "^5.0.0",
|
|
@@ -41,7 +41,6 @@ const Select = ({
|
|
|
41
41
|
listProps,
|
|
42
42
|
searchable = false,
|
|
43
43
|
searchPlaceholder = 'Search',
|
|
44
|
-
testID,
|
|
45
44
|
...rest
|
|
46
45
|
}: SelectProps) => {
|
|
47
46
|
const formFieldContext = useFormFieldContext();
|
|
@@ -111,10 +110,9 @@ const Select = ({
|
|
|
111
110
|
disabled={item.disabled}
|
|
112
111
|
leadingIcon={item.leadingIcon}
|
|
113
112
|
trailingIcon={item.trailingIcon}
|
|
114
|
-
testID={testID ? `${testID}-option-${item.label}` : undefined}
|
|
115
113
|
/>
|
|
116
114
|
),
|
|
117
|
-
[
|
|
115
|
+
[]
|
|
118
116
|
);
|
|
119
117
|
|
|
120
118
|
const renderEmptyComponent = useCallback(
|
|
@@ -143,7 +141,6 @@ const Select = ({
|
|
|
143
141
|
<Pressable
|
|
144
142
|
onPress={openBottomSheet}
|
|
145
143
|
disabled={isDisabled || isReadonly}
|
|
146
|
-
testID={testID}
|
|
147
144
|
style={({ pressed }) => [
|
|
148
145
|
styles.selectContainer,
|
|
149
146
|
styles.pressedContainer(pressed || isOpen),
|
|
@@ -197,7 +194,6 @@ const Select = ({
|
|
|
197
194
|
inBottomSheet
|
|
198
195
|
onChangeText={setSearch}
|
|
199
196
|
type="search"
|
|
200
|
-
testID={testID ? `${testID}-search` : undefined}
|
|
201
197
|
/>
|
|
202
198
|
</View>
|
|
203
199
|
)}
|
|
@@ -14,7 +14,6 @@ const SelectOption = ({
|
|
|
14
14
|
selected,
|
|
15
15
|
disabled,
|
|
16
16
|
onPress,
|
|
17
|
-
testID,
|
|
18
17
|
}: SelectOptionProps) => {
|
|
19
18
|
const { selectedValue, onValueChange, close } = useSelectContext();
|
|
20
19
|
const isSelected = selected !== undefined ? selected : selectedValue === value;
|
|
@@ -39,7 +38,6 @@ const SelectOption = ({
|
|
|
39
38
|
<Pressable
|
|
40
39
|
onPress={handlePress}
|
|
41
40
|
disabled={disabled}
|
|
42
|
-
testID={testID}
|
|
43
41
|
style={({ pressed }) => [styles.container, pressed && styles.pressed]}
|
|
44
42
|
>
|
|
45
43
|
{!!LeftIcon && (
|
|
@@ -23,7 +23,6 @@ const VerificationInput = forwardRef<VerificationInputHandle, VerificationInputP
|
|
|
23
23
|
secureTextEntry = false,
|
|
24
24
|
autoFocus = false,
|
|
25
25
|
style,
|
|
26
|
-
testID,
|
|
27
26
|
...props
|
|
28
27
|
},
|
|
29
28
|
ref
|
|
@@ -240,7 +239,6 @@ const VerificationInput = forwardRef<VerificationInputHandle, VerificationInputP
|
|
|
240
239
|
maxLength={length}
|
|
241
240
|
caretHidden
|
|
242
241
|
style={styles.hiddenInput}
|
|
243
|
-
testID={testID}
|
|
244
242
|
/>
|
|
245
243
|
{slots.map(index => {
|
|
246
244
|
const char = displayValue[index] || '';
|
|
@@ -262,7 +260,6 @@ const VerificationInput = forwardRef<VerificationInputHandle, VerificationInputP
|
|
|
262
260
|
inputRef.current?.focus();
|
|
263
261
|
setSelectionIndex(index);
|
|
264
262
|
}}
|
|
265
|
-
testID={testID ? `${testID}-${index}` : undefined}
|
|
266
263
|
/>
|
|
267
264
|
);
|
|
268
265
|
})}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import dayjs from 'dayjs';
|
|
3
|
-
import { useCallback, useMemo } from 'react';
|
|
4
|
-
import { ScrollView, View } from 'react-native';
|
|
5
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
6
|
-
import { BodyText } from '../BodyText';
|
|
7
|
-
import { useDatePickerContext } from './DatePicker.context';
|
|
8
|
-
import { CONTAINER_HEIGHT } from './enums';
|
|
9
|
-
import PeriodPicker from './time-picker/period-picker';
|
|
10
|
-
import Wheel from './time-picker/wheel';
|
|
11
|
-
import { formatNumber, getParsedDate } from './utils';
|
|
12
|
-
const createNumberList = (num, numerals, startFrom = 0) => {
|
|
13
|
-
return Array.from({ length: num }, (_, i) => ({
|
|
14
|
-
value: i + startFrom,
|
|
15
|
-
text: i + startFrom < 10
|
|
16
|
-
? `${formatNumber(0, numerals)}${formatNumber(i + startFrom, numerals)}`
|
|
17
|
-
: `${formatNumber(i + startFrom, numerals)}`,
|
|
18
|
-
}));
|
|
19
|
-
};
|
|
20
|
-
const TimePicker = () => {
|
|
21
|
-
const { currentDate, date, onSelectDate, timeZone, numerals = 'latn', use12Hours, } = useDatePickerContext();
|
|
22
|
-
const hours = useMemo(() => createNumberList(use12Hours ? 12 : 24, numerals, use12Hours ? 1 : 0), [numerals, use12Hours]);
|
|
23
|
-
const minutes = useMemo(() => createNumberList(60, numerals), [numerals]);
|
|
24
|
-
const { hour, hour12, minute, period } = getParsedDate(date || currentDate);
|
|
25
|
-
const handleChangeHour = useCallback((value) => {
|
|
26
|
-
let hour24 = value;
|
|
27
|
-
if (use12Hours) {
|
|
28
|
-
if (period === 'AM' && value === 12) {
|
|
29
|
-
hour24 = 0;
|
|
30
|
-
}
|
|
31
|
-
else if (period === 'PM' && value < 12) {
|
|
32
|
-
hour24 = value + 12;
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
hour24 = value;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const newDate = dayjs.tz(date, timeZone).hour(hour24).minute(minute);
|
|
39
|
-
onSelectDate(newDate);
|
|
40
|
-
}, [date, onSelectDate, timeZone, use12Hours, period, minute]);
|
|
41
|
-
const handleChangeMinute = useCallback((value) => {
|
|
42
|
-
const newDate = dayjs.tz(date, timeZone).minute(value);
|
|
43
|
-
onSelectDate(newDate);
|
|
44
|
-
}, [date, onSelectDate, timeZone]);
|
|
45
|
-
const handlePeriodChange = useCallback((newPeriod) => {
|
|
46
|
-
let newHour = hour12;
|
|
47
|
-
if (newPeriod === 'PM' && hour12 < 12) {
|
|
48
|
-
newHour = hour12 + 12;
|
|
49
|
-
}
|
|
50
|
-
else if (newPeriod === 'AM' && hour12 === 12) {
|
|
51
|
-
newHour = 0;
|
|
52
|
-
}
|
|
53
|
-
else if (newPeriod === 'AM' && hour >= 12) {
|
|
54
|
-
newHour = hour12;
|
|
55
|
-
}
|
|
56
|
-
const newDate = dayjs.tz(date || currentDate, timeZone).hour(newHour);
|
|
57
|
-
onSelectDate(newDate);
|
|
58
|
-
}, [date, currentDate, onSelectDate, timeZone, hour, hour12]);
|
|
59
|
-
return (_jsxs(ScrollView, { horizontal: true, scrollEnabled: false, contentContainerStyle: styles.container, testID: "time-selector", children: [_jsxs(View, { style: styles.timePickerContainer, children: [_jsx(View, { style: styles.wheelContainer, children: _jsx(Wheel, { value: use12Hours ? hour12 : hour, items: hours, setValue: handleChangeHour }) }), _jsx(BodyText, { style: styles.timeSeparator, children: ":" }), _jsx(View, { style: styles.wheelContainer, children: _jsx(Wheel, { value: minute, items: minutes, setValue: handleChangeMinute }) })] }), use12Hours && period ? (_jsx(View, { style: styles.periodContainer, children: _jsx(PeriodPicker, { value: period, setValue: handlePeriodChange }) })) : null] }));
|
|
60
|
-
};
|
|
61
|
-
const styles = StyleSheet.create({
|
|
62
|
-
container: {
|
|
63
|
-
flex: 1,
|
|
64
|
-
alignItems: 'center',
|
|
65
|
-
justifyContent: 'center',
|
|
66
|
-
},
|
|
67
|
-
wheelContainer: {
|
|
68
|
-
flex: 1,
|
|
69
|
-
},
|
|
70
|
-
timePickerContainer: {
|
|
71
|
-
alignItems: 'center',
|
|
72
|
-
justifyContent: 'center',
|
|
73
|
-
width: CONTAINER_HEIGHT / 2,
|
|
74
|
-
height: CONTAINER_HEIGHT / 2,
|
|
75
|
-
flexDirection: 'row',
|
|
76
|
-
},
|
|
77
|
-
timeSeparator: {
|
|
78
|
-
marginHorizontal: 5,
|
|
79
|
-
},
|
|
80
|
-
periodContainer: {
|
|
81
|
-
marginLeft: 10,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
export default TimePicker;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Animated } from 'react-native';
|
|
2
|
-
const FACTORIAL_3 = 3 * 2;
|
|
3
|
-
const FACTORIAL_5 = 5 * 4 * FACTORIAL_3;
|
|
4
|
-
const FACTORIAL_7 = 7 * 6 * FACTORIAL_5;
|
|
5
|
-
function sin(animated) {
|
|
6
|
-
const normalized = normalize(animated);
|
|
7
|
-
const square = Animated.multiply(normalized, normalized);
|
|
8
|
-
const pow3 = Animated.multiply(normalized, square);
|
|
9
|
-
const pow5 = Animated.multiply(pow3, square);
|
|
10
|
-
const pow7 = Animated.multiply(pow5, square);
|
|
11
|
-
return Animated.add(Animated.add(normalized, Animated.multiply(pow3, -1 / FACTORIAL_3)), Animated.add(Animated.multiply(pow5, 1 / FACTORIAL_5), Animated.multiply(pow7, -1 / FACTORIAL_7)));
|
|
12
|
-
}
|
|
13
|
-
function normalize(animated) {
|
|
14
|
-
return Animated.add(Animated.modulo(Animated.add(animated, Math.PI), Math.PI * 2), -Math.PI).interpolate({
|
|
15
|
-
inputRange: [-Math.PI, -Math.PI / 2, Math.PI / 2, Math.PI],
|
|
16
|
-
outputRange: [0, -Math.PI / 2, Math.PI / 2, 0],
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
export { sin, normalize };
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import WheelPicker from './wheel-picker';
|
|
4
|
-
const options = [
|
|
5
|
-
{ value: 'AM', text: 'AM' },
|
|
6
|
-
{ value: 'PM', text: 'PM' },
|
|
7
|
-
];
|
|
8
|
-
const PeriodNative = ({ value, setValue = () => { } }) => {
|
|
9
|
-
return (_jsx(WheelPicker, { value: value, options: options, onChange: setValue,
|
|
10
|
-
//containerStyle={defaultStyles.container}
|
|
11
|
-
itemHeight: 44, decelerationRate: "fast" }));
|
|
12
|
-
};
|
|
13
|
-
const customComparator = (prev, next) => {
|
|
14
|
-
const areEqual = prev.value === next.value && prev.setValue === next.setValue;
|
|
15
|
-
return areEqual;
|
|
16
|
-
};
|
|
17
|
-
export default memo(PeriodNative, customComparator);
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { Platform } from 'react-native';
|
|
4
|
-
import PeriodNative from './period-native';
|
|
5
|
-
import PeriodWeb from './period-web';
|
|
6
|
-
const PeriodPicker = (props) => {
|
|
7
|
-
const Component = Platform.OS === 'web' ? PeriodWeb : PeriodNative;
|
|
8
|
-
return _jsx(Component, { ...props });
|
|
9
|
-
};
|
|
10
|
-
export default memo(PeriodPicker);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { Pressable, View } from 'react-native';
|
|
4
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
5
|
-
import { BodyText } from '../../BodyText';
|
|
6
|
-
const PeriodWeb = ({ value, setValue = () => { } }) => {
|
|
7
|
-
return (_jsx(Pressable, { onPress: () => setValue(value == 'AM' ? 'PM' : 'AM'), children: _jsx(View, { style: [styles.period], children: _jsx(BodyText, { children: value }) }) }));
|
|
8
|
-
};
|
|
9
|
-
const styles = StyleSheet.create({
|
|
10
|
-
period: {
|
|
11
|
-
width: 65,
|
|
12
|
-
height: 44,
|
|
13
|
-
alignItems: 'center',
|
|
14
|
-
justifyContent: 'center',
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
const customComparator = (prev, next) => {
|
|
18
|
-
const areEqual = prev.value === next.value && prev.setValue === next.setValue;
|
|
19
|
-
return areEqual;
|
|
20
|
-
};
|
|
21
|
-
export default memo(PeriodWeb, customComparator);
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { PickerOption } from '../DatePicker.props';
|
|
2
|
-
interface WheelProps {
|
|
3
|
-
value: number | string;
|
|
4
|
-
setValue?: (value: any) => void;
|
|
5
|
-
items: PickerOption[];
|
|
6
|
-
}
|
|
7
|
-
declare const _default: import("react").MemoExoticComponent<({ value, setValue, items }: WheelProps) => import("react/jsx-runtime").JSX.Element>;
|
|
8
|
-
export default _default;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { Platform } from 'react-native';
|
|
4
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
5
|
-
import WheelPicker from './wheel-picker';
|
|
6
|
-
const WheelNative = ({ value, setValue = () => { }, items }) => {
|
|
7
|
-
return (_jsx(WheelPicker, { value: value, options: items, onChange: setValue, containerStyle: styles.container, itemHeight: 44, decelerationRate: "fast" }));
|
|
8
|
-
};
|
|
9
|
-
const styles = StyleSheet.create({
|
|
10
|
-
container: {
|
|
11
|
-
display: 'flex',
|
|
12
|
-
...Platform.select({
|
|
13
|
-
web: {
|
|
14
|
-
userSelect: 'none',
|
|
15
|
-
},
|
|
16
|
-
}),
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
export default memo(WheelNative);
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Animated, StyleProp, ViewStyle } from 'react-native';
|
|
3
|
-
import { PickerOption } from '../../DatePicker.props';
|
|
4
|
-
interface ItemProps {
|
|
5
|
-
style: StyleProp<ViewStyle>;
|
|
6
|
-
option: PickerOption | null;
|
|
7
|
-
height: number;
|
|
8
|
-
index: number;
|
|
9
|
-
currentScrollIndex: Animated.AnimatedAddition<number>;
|
|
10
|
-
visibleRest: number;
|
|
11
|
-
rotationFunction: (x: number) => number;
|
|
12
|
-
opacityFunction: (x: number) => number;
|
|
13
|
-
scaleFunction: (x: number) => number;
|
|
14
|
-
}
|
|
15
|
-
declare const _default: React.NamedExoticComponent<ItemProps>;
|
|
16
|
-
export default _default;
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { Animated } from 'react-native';
|
|
4
|
-
import { BodyText } from '../../../BodyText';
|
|
5
|
-
import styles from './wheel-picker.style';
|
|
6
|
-
const WheelPickerItem = ({ style, height, option, index, visibleRest, currentScrollIndex, opacityFunction, rotationFunction, scaleFunction, }) => {
|
|
7
|
-
const relativeScrollIndex = Animated.subtract(index, currentScrollIndex);
|
|
8
|
-
const translateY = relativeScrollIndex.interpolate({
|
|
9
|
-
inputRange: (() => {
|
|
10
|
-
const range = [0];
|
|
11
|
-
for (let i = 1; i <= visibleRest + 1; i++) {
|
|
12
|
-
range.unshift(-i);
|
|
13
|
-
range.push(i);
|
|
14
|
-
}
|
|
15
|
-
return range;
|
|
16
|
-
})(),
|
|
17
|
-
outputRange: (() => {
|
|
18
|
-
const range = [0];
|
|
19
|
-
for (let i = 1; i <= visibleRest + 1; i++) {
|
|
20
|
-
let y = (height / 2) * (1 - Math.sin(Math.PI / 2 - rotationFunction(i)));
|
|
21
|
-
for (let j = 1; j < i; j++) {
|
|
22
|
-
y += height * (1 - Math.sin(Math.PI / 2 - rotationFunction(j)));
|
|
23
|
-
}
|
|
24
|
-
range.unshift(y);
|
|
25
|
-
range.push(-y);
|
|
26
|
-
}
|
|
27
|
-
return range;
|
|
28
|
-
})(),
|
|
29
|
-
});
|
|
30
|
-
const opacity = relativeScrollIndex.interpolate({
|
|
31
|
-
inputRange: (() => {
|
|
32
|
-
const range = [0];
|
|
33
|
-
for (let i = 1; i <= visibleRest + 1; i++) {
|
|
34
|
-
range.unshift(-i);
|
|
35
|
-
range.push(i);
|
|
36
|
-
}
|
|
37
|
-
return range;
|
|
38
|
-
})(),
|
|
39
|
-
outputRange: (() => {
|
|
40
|
-
const range = [1];
|
|
41
|
-
for (let x = 1; x <= visibleRest + 1; x++) {
|
|
42
|
-
const y = opacityFunction(x);
|
|
43
|
-
range.unshift(y);
|
|
44
|
-
range.push(y);
|
|
45
|
-
}
|
|
46
|
-
return range;
|
|
47
|
-
})(),
|
|
48
|
-
});
|
|
49
|
-
const scale = relativeScrollIndex.interpolate({
|
|
50
|
-
inputRange: (() => {
|
|
51
|
-
const range = [0];
|
|
52
|
-
for (let i = 1; i <= visibleRest + 1; i++) {
|
|
53
|
-
range.unshift(-i);
|
|
54
|
-
range.push(i);
|
|
55
|
-
}
|
|
56
|
-
return range;
|
|
57
|
-
})(),
|
|
58
|
-
outputRange: (() => {
|
|
59
|
-
const range = [1.0];
|
|
60
|
-
for (let x = 1; x <= visibleRest + 1; x++) {
|
|
61
|
-
const y = scaleFunction(x);
|
|
62
|
-
range.unshift(y);
|
|
63
|
-
range.push(y);
|
|
64
|
-
}
|
|
65
|
-
return range;
|
|
66
|
-
})(),
|
|
67
|
-
});
|
|
68
|
-
const rotateX = relativeScrollIndex.interpolate({
|
|
69
|
-
inputRange: (() => {
|
|
70
|
-
const range = [0];
|
|
71
|
-
for (let i = 1; i <= visibleRest + 1; i++) {
|
|
72
|
-
range.unshift(-i);
|
|
73
|
-
range.push(i);
|
|
74
|
-
}
|
|
75
|
-
return range;
|
|
76
|
-
})(),
|
|
77
|
-
outputRange: (() => {
|
|
78
|
-
const range = ['0deg'];
|
|
79
|
-
for (let x = 1; x <= visibleRest + 1; x++) {
|
|
80
|
-
const y = rotationFunction(x);
|
|
81
|
-
range.unshift(`${y}deg`);
|
|
82
|
-
range.push(`${y}deg`);
|
|
83
|
-
}
|
|
84
|
-
return range;
|
|
85
|
-
})(),
|
|
86
|
-
});
|
|
87
|
-
return (_jsx(Animated.View, { style: [
|
|
88
|
-
styles.option,
|
|
89
|
-
style,
|
|
90
|
-
{
|
|
91
|
-
height,
|
|
92
|
-
opacity,
|
|
93
|
-
transform: [{ translateY }, { rotateX }, { scale }],
|
|
94
|
-
},
|
|
95
|
-
], children: _jsx(BodyText, { children: option?.text }) }));
|
|
96
|
-
};
|
|
97
|
-
export default React.memo(WheelPickerItem);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { FlatListProps, StyleProp, ViewProps, ViewStyle } from 'react-native';
|
|
3
|
-
import { PickerOption } from '../../DatePicker.props';
|
|
4
|
-
interface Props {
|
|
5
|
-
value: number | string;
|
|
6
|
-
options: PickerOption[];
|
|
7
|
-
onChange: (index: number | string) => void;
|
|
8
|
-
selectedIndicatorStyle?: StyleProp<ViewStyle>;
|
|
9
|
-
itemStyle?: ViewStyle;
|
|
10
|
-
itemHeight?: number;
|
|
11
|
-
containerStyle?: ViewStyle;
|
|
12
|
-
containerProps?: Omit<ViewProps, 'style'>;
|
|
13
|
-
scaleFunction?: (x: number) => number;
|
|
14
|
-
rotationFunction?: (x: number) => number;
|
|
15
|
-
opacityFunction?: (x: number) => number;
|
|
16
|
-
visibleRest?: number;
|
|
17
|
-
decelerationRate?: 'normal' | 'fast' | number;
|
|
18
|
-
flatListProps?: Omit<FlatListProps<PickerOption | null>, 'data' | 'renderItem'>;
|
|
19
|
-
}
|
|
20
|
-
declare const _default: React.NamedExoticComponent<Props>;
|
|
21
|
-
export default _default;
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { Animated, Platform, View, } from 'react-native';
|
|
4
|
-
import WheelPickerItem from './wheel-picker-item';
|
|
5
|
-
import styles from './wheel-picker.style';
|
|
6
|
-
const WheelPicker = ({ value, options, onChange, selectedIndicatorStyle = {}, containerStyle = {}, itemStyle = {}, itemHeight = 40, scaleFunction = (x) => 1.0 ** x, rotationFunction = (x) => 1 - Math.pow(1 / 2, x), opacityFunction = (x) => Math.pow(1 / 3, x), visibleRest = 2, decelerationRate = 'normal', containerProps = {}, flatListProps = {}, }) => {
|
|
7
|
-
const momentumStarted = useRef(false);
|
|
8
|
-
const selectedIndex = options.findIndex(item => item.value === value);
|
|
9
|
-
const flatListRef = useRef(null);
|
|
10
|
-
const [scrollY] = useState(new Animated.Value(selectedIndex * itemHeight));
|
|
11
|
-
const containerHeight = (1 + visibleRest * 2) * itemHeight;
|
|
12
|
-
const paddedOptions = useMemo(() => {
|
|
13
|
-
const array = [...options];
|
|
14
|
-
for (let i = 0; i < visibleRest; i++) {
|
|
15
|
-
array.unshift(null);
|
|
16
|
-
array.push(null);
|
|
17
|
-
}
|
|
18
|
-
return array;
|
|
19
|
-
}, [options, visibleRest]);
|
|
20
|
-
const offsets = useMemo(() => [...Array(paddedOptions.length)].map((_, i) => i * itemHeight), [paddedOptions, itemHeight]);
|
|
21
|
-
const currentScrollIndex = useMemo(() => Animated.add(Animated.divide(scrollY, itemHeight), visibleRest), [visibleRest, scrollY, itemHeight]);
|
|
22
|
-
const handleScrollEnd = (event) => {
|
|
23
|
-
const offsetY = Math.min(itemHeight * (options.length - 1), Math.max(event.nativeEvent.contentOffset.y, 0));
|
|
24
|
-
let index = Math.floor(offsetY / itemHeight);
|
|
25
|
-
const remainder = offsetY % itemHeight;
|
|
26
|
-
if (remainder > itemHeight / 2) {
|
|
27
|
-
index++;
|
|
28
|
-
}
|
|
29
|
-
if (index !== selectedIndex) {
|
|
30
|
-
onChange(options[index]?.value || 0);
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
const handleMomentumScrollBegin = () => {
|
|
34
|
-
momentumStarted.current = true;
|
|
35
|
-
};
|
|
36
|
-
const handleMomentumScrollEnd = (event) => {
|
|
37
|
-
momentumStarted.current = false;
|
|
38
|
-
handleScrollEnd(event);
|
|
39
|
-
};
|
|
40
|
-
const handleScrollEndDrag = (event) => {
|
|
41
|
-
// Capture the offset value immediately
|
|
42
|
-
const offsetY = event.nativeEvent.contentOffset?.y;
|
|
43
|
-
// We'll start a short timer to see if momentum scroll begins
|
|
44
|
-
setTimeout(() => {
|
|
45
|
-
// If momentum scroll hasn't started within the timeout,
|
|
46
|
-
// then it was a slow scroll that won't trigger momentum
|
|
47
|
-
if (!momentumStarted.current && offsetY !== undefined) {
|
|
48
|
-
// Create a synthetic event with just the data we need
|
|
49
|
-
const syntheticEvent = {
|
|
50
|
-
nativeEvent: {
|
|
51
|
-
contentOffset: { y: offsetY },
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
handleScrollEnd(syntheticEvent);
|
|
55
|
-
}
|
|
56
|
-
}, 50);
|
|
57
|
-
};
|
|
58
|
-
useEffect(() => {
|
|
59
|
-
if (selectedIndex < 0 || selectedIndex >= options.length) {
|
|
60
|
-
throw new Error(`Selected index ${selectedIndex} is out of bounds [0, ${options.length - 1}]`);
|
|
61
|
-
}
|
|
62
|
-
}, [selectedIndex, options]);
|
|
63
|
-
/**
|
|
64
|
-
* If selectedIndex is changed from outside (not via onChange) we need to scroll to the specified index.
|
|
65
|
-
* This ensures that what the user sees as selected in the picker always corresponds to the value state.
|
|
66
|
-
*/
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
flatListRef.current?.scrollToIndex({
|
|
69
|
-
index: selectedIndex,
|
|
70
|
-
animated: Platform.OS === 'ios',
|
|
71
|
-
});
|
|
72
|
-
}, [selectedIndex, itemHeight]);
|
|
73
|
-
return (_jsxs(View, { style: [styles.container, { height: containerHeight }, containerStyle], ...containerProps, children: [_jsx(View, { style: [
|
|
74
|
-
styles.selectedIndicator,
|
|
75
|
-
selectedIndicatorStyle,
|
|
76
|
-
{
|
|
77
|
-
transform: [{ translateY: -itemHeight / 2 }],
|
|
78
|
-
height: itemHeight,
|
|
79
|
-
},
|
|
80
|
-
] }), _jsx(Animated.FlatList, { ...flatListProps, ref: flatListRef, nestedScrollEnabled: true, style: styles.scrollView, showsVerticalScrollIndicator: false, onScroll: Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], {
|
|
81
|
-
useNativeDriver: true,
|
|
82
|
-
}), onScrollEndDrag: handleScrollEndDrag, onMomentumScrollBegin: handleMomentumScrollBegin, onMomentumScrollEnd: handleMomentumScrollEnd, snapToOffsets: offsets, decelerationRate: decelerationRate, initialScrollIndex: selectedIndex, getItemLayout: (_, index) => ({
|
|
83
|
-
length: itemHeight,
|
|
84
|
-
offset: itemHeight * index,
|
|
85
|
-
index,
|
|
86
|
-
}), data: paddedOptions, keyExtractor: (item, index) => item ? `${item.value}-${item.text}-${index}` : `null-${index}`, renderItem: ({ item: option, index }) => (_jsx(WheelPickerItem, { index: index, option: option, style: itemStyle, height: itemHeight, currentScrollIndex: currentScrollIndex, scaleFunction: scaleFunction, rotationFunction: rotationFunction, opacityFunction: opacityFunction, visibleRest: visibleRest }, `option-${index}`)) })] }));
|
|
87
|
-
};
|
|
88
|
-
export default memo(WheelPicker);
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
declare const _default: {
|
|
2
|
-
container: {
|
|
3
|
-
position: "relative";
|
|
4
|
-
};
|
|
5
|
-
selectedIndicator: {
|
|
6
|
-
position: "absolute";
|
|
7
|
-
width: "100%";
|
|
8
|
-
top: "50%";
|
|
9
|
-
};
|
|
10
|
-
scrollView: {
|
|
11
|
-
overflow: "hidden";
|
|
12
|
-
flex: number;
|
|
13
|
-
};
|
|
14
|
-
option: {
|
|
15
|
-
alignItems: "center";
|
|
16
|
-
justifyContent: "center";
|
|
17
|
-
paddingHorizontal: number;
|
|
18
|
-
zIndex: number;
|
|
19
|
-
};
|
|
20
|
-
} & {
|
|
21
|
-
useVariants: (variants: never) => void;
|
|
22
|
-
};
|
|
23
|
-
export default _default;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
2
|
-
export default StyleSheet.create({
|
|
3
|
-
container: {
|
|
4
|
-
position: 'relative',
|
|
5
|
-
},
|
|
6
|
-
selectedIndicator: {
|
|
7
|
-
position: 'absolute',
|
|
8
|
-
width: '100%',
|
|
9
|
-
top: '50%',
|
|
10
|
-
},
|
|
11
|
-
scrollView: {
|
|
12
|
-
overflow: 'hidden',
|
|
13
|
-
flex: 1,
|
|
14
|
-
},
|
|
15
|
-
option: {
|
|
16
|
-
alignItems: 'center',
|
|
17
|
-
justifyContent: 'center',
|
|
18
|
-
paddingHorizontal: 16,
|
|
19
|
-
zIndex: 100,
|
|
20
|
-
},
|
|
21
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { PickerOption } from '../DatePicker.props';
|
|
2
|
-
interface WheelProps {
|
|
3
|
-
value: number | string;
|
|
4
|
-
setValue?: (value: any) => void;
|
|
5
|
-
items: PickerOption[];
|
|
6
|
-
}
|
|
7
|
-
declare const _default: import("react").MemoExoticComponent<({ value, setValue, items }: WheelProps) => import("react/jsx-runtime").JSX.Element>;
|
|
8
|
-
export default _default;
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useMemo, useRef } from 'react';
|
|
3
|
-
import { Animated, PanResponder, Platform, View } from 'react-native';
|
|
4
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
5
|
-
import { isEqual } from '../../../utils';
|
|
6
|
-
import { BodyText } from '../../BodyText';
|
|
7
|
-
import { CONTAINER_HEIGHT } from '../enums';
|
|
8
|
-
import { sin } from './animated-math';
|
|
9
|
-
const ITEM_HEIGHT = 44;
|
|
10
|
-
const WheelWeb = ({ value, setValue = () => { }, items }) => {
|
|
11
|
-
const displayCount = 5;
|
|
12
|
-
const translateY = useRef(new Animated.Value(0)).current;
|
|
13
|
-
const renderCount = displayCount * 2 < items.length ? displayCount * 8 : displayCount * 2 - 1;
|
|
14
|
-
const circular = items.length >= displayCount;
|
|
15
|
-
const height = 140;
|
|
16
|
-
const radius = height / 2;
|
|
17
|
-
const valueIndex = useMemo(() => {
|
|
18
|
-
return Math.max(0, items.findIndex(item => item.value === value));
|
|
19
|
-
}, [items, value]);
|
|
20
|
-
const panResponder = useMemo(() => {
|
|
21
|
-
return PanResponder.create({
|
|
22
|
-
onMoveShouldSetPanResponder: () => true,
|
|
23
|
-
onStartShouldSetPanResponderCapture: () => true,
|
|
24
|
-
onPanResponderGrant: () => {
|
|
25
|
-
translateY.setValue(0);
|
|
26
|
-
},
|
|
27
|
-
onPanResponderMove: (evt, gestureState) => {
|
|
28
|
-
translateY.setValue(gestureState.dy);
|
|
29
|
-
evt.stopPropagation();
|
|
30
|
-
},
|
|
31
|
-
onPanResponderRelease: (_, gestureState) => {
|
|
32
|
-
translateY.extractOffset();
|
|
33
|
-
let newValueIndex = valueIndex - Math.round(gestureState.dy / ((radius * 2) / displayCount));
|
|
34
|
-
if (circular) {
|
|
35
|
-
newValueIndex = (newValueIndex + items.length) % items.length;
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
if (newValueIndex < 0) {
|
|
39
|
-
newValueIndex = 0;
|
|
40
|
-
}
|
|
41
|
-
else if (newValueIndex >= items.length) {
|
|
42
|
-
newValueIndex = items.length - 1;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
const newValue = items[newValueIndex];
|
|
46
|
-
if (newValue?.value === value) {
|
|
47
|
-
translateY.setOffset(0);
|
|
48
|
-
translateY.setValue(0);
|
|
49
|
-
}
|
|
50
|
-
else if (newValue?.value) {
|
|
51
|
-
setValue(newValue.value);
|
|
52
|
-
}
|
|
53
|
-
else if (items[0]?.value) {
|
|
54
|
-
setValue(items[0].value);
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
}, [circular, displayCount, radius, setValue, value, valueIndex, items, translateY]);
|
|
59
|
-
const displayValues = useMemo(() => {
|
|
60
|
-
const centerIndex = Math.floor(renderCount / 2);
|
|
61
|
-
return Array.from({ length: renderCount }, (_, index) => {
|
|
62
|
-
let targetIndex = valueIndex + index - centerIndex;
|
|
63
|
-
if (circular) {
|
|
64
|
-
targetIndex = ((targetIndex % items.length) + items.length) % items.length;
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
targetIndex = Math.max(0, Math.min(targetIndex, items.length - 1));
|
|
68
|
-
}
|
|
69
|
-
return items[targetIndex] || items[0];
|
|
70
|
-
});
|
|
71
|
-
}, [renderCount, valueIndex, items, circular]);
|
|
72
|
-
const animatedAngles = useMemo(() => {
|
|
73
|
-
//translateY.setValue(0);
|
|
74
|
-
translateY.setOffset(0);
|
|
75
|
-
const currentIndex = displayValues.findIndex(item => item?.value === value);
|
|
76
|
-
return displayValues && displayValues.length > 0
|
|
77
|
-
? displayValues.map((_, index) => translateY
|
|
78
|
-
.interpolate({
|
|
79
|
-
inputRange: [-radius, radius],
|
|
80
|
-
outputRange: [
|
|
81
|
-
-radius + ((radius * 2) / displayCount) * (index - currentIndex),
|
|
82
|
-
radius + ((radius * 2) / displayCount) * (index - currentIndex),
|
|
83
|
-
],
|
|
84
|
-
extrapolate: 'extend',
|
|
85
|
-
})
|
|
86
|
-
.interpolate({
|
|
87
|
-
inputRange: [-radius, radius],
|
|
88
|
-
outputRange: [-Math.PI / 2, Math.PI / 2],
|
|
89
|
-
extrapolate: 'clamp',
|
|
90
|
-
}))
|
|
91
|
-
: [];
|
|
92
|
-
}, [displayValues, radius, value, displayCount, translateY]);
|
|
93
|
-
return (_jsxs(View, { style: [styles.container], ...panResponder.panHandlers, children: [_jsx(View, { style: [
|
|
94
|
-
styles.selectedIndicator,
|
|
95
|
-
{
|
|
96
|
-
transform: [{ translateY: -ITEM_HEIGHT / 2 }],
|
|
97
|
-
height: ITEM_HEIGHT,
|
|
98
|
-
},
|
|
99
|
-
] }), displayValues?.map((displayValue, index) => {
|
|
100
|
-
const animatedAngle = animatedAngles[index];
|
|
101
|
-
return (_jsx(Animated.View, { style: {
|
|
102
|
-
position: 'absolute',
|
|
103
|
-
height: ITEM_HEIGHT - 10,
|
|
104
|
-
transform: animatedAngle
|
|
105
|
-
? [
|
|
106
|
-
{
|
|
107
|
-
translateY: Animated.multiply(radius, sin(animatedAngle)),
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
rotateX: animatedAngle.interpolate({
|
|
111
|
-
inputRange: [-Math.PI / 2, Math.PI / 2],
|
|
112
|
-
outputRange: ['-89deg', '89deg'],
|
|
113
|
-
extrapolate: 'clamp',
|
|
114
|
-
}),
|
|
115
|
-
},
|
|
116
|
-
]
|
|
117
|
-
: [],
|
|
118
|
-
opacity: displayValue?.value !== value ? 0.3 : 1,
|
|
119
|
-
}, children: _jsx(BodyText, { children: displayValue?.text }) }, `${displayValue?.text}-${index}`));
|
|
120
|
-
})] }));
|
|
121
|
-
};
|
|
122
|
-
const styles = StyleSheet.create({
|
|
123
|
-
container: {
|
|
124
|
-
minWidth: 30,
|
|
125
|
-
overflow: 'hidden',
|
|
126
|
-
alignItems: 'center',
|
|
127
|
-
justifyContent: 'center',
|
|
128
|
-
height: CONTAINER_HEIGHT / 2,
|
|
129
|
-
...Platform.select({
|
|
130
|
-
web: {
|
|
131
|
-
cursor: 'pointer',
|
|
132
|
-
userSelect: 'none',
|
|
133
|
-
},
|
|
134
|
-
}),
|
|
135
|
-
},
|
|
136
|
-
selectedIndicator: {
|
|
137
|
-
position: 'absolute',
|
|
138
|
-
width: '100%',
|
|
139
|
-
top: '50%',
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
const customComparator = (prev, next) => {
|
|
143
|
-
const areEqual = prev.value === next.value && prev.setValue === next.setValue && isEqual(prev.items, next.items);
|
|
144
|
-
return areEqual;
|
|
145
|
-
};
|
|
146
|
-
export default memo(WheelWeb, customComparator);
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { PickerOption } from '../DatePicker.props';
|
|
2
|
-
type WheelProps = {
|
|
3
|
-
value: number | string;
|
|
4
|
-
setValue?: (value: any) => void;
|
|
5
|
-
items: PickerOption[];
|
|
6
|
-
};
|
|
7
|
-
declare const _default: import("react").MemoExoticComponent<(props: WheelProps) => import("react/jsx-runtime").JSX.Element>;
|
|
8
|
-
export default _default;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { Platform } from 'react-native';
|
|
4
|
-
import WheelNative from './wheel-native';
|
|
5
|
-
import WheelWeb from './wheel-web';
|
|
6
|
-
const Wheel = (props) => {
|
|
7
|
-
const Component = Platform.OS === 'web' ? WheelWeb : WheelNative;
|
|
8
|
-
return _jsx(Component, { ...props });
|
|
9
|
-
};
|
|
10
|
-
export default memo(Wheel);
|