@janiscommerce/ui-native 1.3.0 → 1.4.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/dist/src/components/BaseButton/index.d.ts +2 -2
- package/dist/src/components/Select/Components/Dropdown/index.d.ts +7 -10
- package/dist/src/components/Select/Components/Dropdown/index.js +14 -76
- package/dist/src/components/Select/Components/Modal/index.d.ts +8 -0
- package/dist/src/components/Select/Components/Modal/index.js +65 -0
- package/dist/src/components/Select/Components/Options/index.d.ts +18 -0
- package/dist/src/components/Select/Components/Options/index.js +75 -0
- package/dist/src/components/Select/Components/SwitcherComponent/index.d.ts +13 -0
- package/dist/src/components/Select/Components/SwitcherComponent/index.js +8 -0
- package/dist/src/components/Select/index.d.ts +12 -2
- package/dist/src/components/Select/index.js +48 -30
- package/dist/src/components/Select/utils/index.d.ts +1 -1
- package/dist/src/components/Select/utils/index.js +2 -3
- package/package.json +1 -1
- package/dist/src/components/Select/Components/Icons/Chevron/index.d.ts +0 -17
- package/dist/src/components/Select/Components/Icons/Chevron/index.js +0 -20
- package/dist/src/components/Select/Components/Icons/Delete/index.d.ts +0 -17
- package/dist/src/components/Select/Components/Icons/Delete/index.js +0 -20
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { FC } from 'react';
|
|
2
|
-
import { PressableProps, ViewStyle } from 'react-native';
|
|
2
|
+
import { PressableProps, ViewStyle, TextStyle } from 'react-native';
|
|
3
3
|
interface BaseButtonProps extends PressableProps {
|
|
4
4
|
title?: string | null;
|
|
5
5
|
icon?: string;
|
|
@@ -9,7 +9,7 @@ interface BaseButtonProps extends PressableProps {
|
|
|
9
9
|
pressedColor?: string;
|
|
10
10
|
style?: ViewStyle;
|
|
11
11
|
iconStyle?: ViewStyle;
|
|
12
|
-
textStyle?:
|
|
12
|
+
textStyle?: TextStyle;
|
|
13
13
|
children?: React.ReactNode;
|
|
14
14
|
}
|
|
15
15
|
declare const BaseButton: FC<BaseButtonProps>;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
interface DropdownProps {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
optionStyles?: {};
|
|
9
|
-
callbackOption: (option: Option) => void;
|
|
10
|
-
customOptionComponent?: CustomOptionComponent | null;
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { DropdownMeasures } from '../..';
|
|
3
|
+
export interface DropdownProps {
|
|
4
|
+
show: boolean;
|
|
5
|
+
setShow: (isShowed: boolean) => void;
|
|
6
|
+
children: React.Component | React.ReactNode;
|
|
7
|
+
measures: DropdownMeasures;
|
|
11
8
|
}
|
|
12
9
|
declare const Dropdown: FC<DropdownProps>;
|
|
13
10
|
export default Dropdown;
|
|
@@ -1,85 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { horizontalScale, moderateScale, scaledForDevice } from '../../../../scale';
|
|
5
|
-
const Dropdown = (props) => {
|
|
6
|
-
const { isShowedDropdown, filteredOptions, callbackOption, selectedOptions, noOptionsMessage, optionStyles, customOptionComponent = null, } = props;
|
|
7
|
-
if (!isShowedDropdown) {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
const handleSelectedOption = (option) => callbackOption(option);
|
|
11
|
-
const validPadding = scaledForDevice(8, moderateScale);
|
|
12
|
-
const validMaxHeight = scaledForDevice(168, moderateScale);
|
|
13
|
-
const validTop = scaledForDevice(60, moderateScale);
|
|
14
|
-
const validMarginBottom = scaledForDevice(20, moderateScale);
|
|
15
|
-
const validElevation = scaledForDevice(5, moderateScale);
|
|
16
|
-
const validHeight = scaledForDevice(42, moderateScale);
|
|
17
|
-
const validLeft = scaledForDevice(8, horizontalScale);
|
|
18
|
-
const validFontSize = scaledForDevice(14, moderateScale);
|
|
19
|
-
const validPaddingVertical = scaledForDevice(10, moderateScale);
|
|
2
|
+
import { Modal, Pressable, StyleSheet, View } from 'react-native';
|
|
3
|
+
const Dropdown = ({ show, setShow, children, measures }) => {
|
|
20
4
|
const styles = StyleSheet.create({
|
|
21
|
-
|
|
5
|
+
background: {
|
|
22
6
|
width: '100%',
|
|
23
|
-
|
|
7
|
+
height: '100%',
|
|
24
8
|
},
|
|
25
|
-
|
|
9
|
+
dropdown: {
|
|
26
10
|
position: 'absolute',
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
top: validTop,
|
|
32
|
-
marginBottom: validMarginBottom,
|
|
33
|
-
elevation: validElevation,
|
|
34
|
-
zIndex: 10,
|
|
35
|
-
flex: 1,
|
|
36
|
-
},
|
|
37
|
-
option: {
|
|
38
|
-
width: '100%',
|
|
39
|
-
height: validHeight,
|
|
40
|
-
justifyContent: 'center',
|
|
41
|
-
alignItems: 'stretch',
|
|
42
|
-
paddingLeft: validLeft,
|
|
43
|
-
},
|
|
44
|
-
optionText: {
|
|
45
|
-
fontSize: validFontSize,
|
|
46
|
-
color: black.main,
|
|
47
|
-
fontWeight: '400',
|
|
48
|
-
},
|
|
49
|
-
noOptionText: {
|
|
50
|
-
fontSize: validFontSize,
|
|
51
|
-
color: grey[500],
|
|
52
|
-
fontWeight: '400',
|
|
53
|
-
paddingLeft: validLeft,
|
|
54
|
-
paddingVertical: validPaddingVertical,
|
|
11
|
+
height: '100%',
|
|
12
|
+
width: measures.width,
|
|
13
|
+
top: measures.pageY,
|
|
14
|
+
left: measures.pageX,
|
|
55
15
|
},
|
|
56
16
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
...styles.option,
|
|
63
|
-
...(isSelectedOption && { backgroundColor: white.light }),
|
|
64
|
-
};
|
|
65
|
-
const customProps = {
|
|
66
|
-
renderedOption: option,
|
|
67
|
-
filteredOptions,
|
|
68
|
-
selectedOptions,
|
|
69
|
-
callbackOptionSelected: callbackOption,
|
|
70
|
-
};
|
|
71
|
-
if (customOptionComponent) {
|
|
72
|
-
return customOptionComponent(customProps);
|
|
73
|
-
}
|
|
74
|
-
return (<TouchableOpacity style={{ ...styleOption, ...optionStyles }} key={option.label} onPress={() => handleSelectedOption(option)}>
|
|
75
|
-
<Text style={styleText}> {option.label}</Text>
|
|
76
|
-
</TouchableOpacity>);
|
|
77
|
-
});
|
|
78
|
-
const noRenderOptions = (<View aria-disabled>
|
|
79
|
-
<Text style={styles.noOptionText}> {noOptionsMessage}</Text>
|
|
80
|
-
</View>);
|
|
81
|
-
return (<ScrollView style={styles.optionWrapper} contentContainerStyle={styles.container}>
|
|
82
|
-
{filteredOptions?.length ? renderOptions : noRenderOptions}
|
|
83
|
-
</ScrollView>);
|
|
17
|
+
return (<Modal animationType="fade" transparent visible={show}>
|
|
18
|
+
<Pressable style={styles.background} onPress={() => setShow(false)}>
|
|
19
|
+
<View style={styles.dropdown}>{children}</View>
|
|
20
|
+
</Pressable>
|
|
21
|
+
</Modal>);
|
|
84
22
|
};
|
|
85
23
|
export default Dropdown;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Modal as ModalComponent, StyleSheet, View } from 'react-native';
|
|
3
|
+
import { base, primary, white } from '../../../../theme/palette';
|
|
4
|
+
import BaseButton from '../../../BaseButton';
|
|
5
|
+
import { moderateScale, scaledForDevice } from '../../../../scale';
|
|
6
|
+
const Modal = ({ show, setShow, isMulti, modalAcceptText, children }) => {
|
|
7
|
+
const validBottom = scaledForDevice(20, moderateScale);
|
|
8
|
+
const validMinWidth = scaledForDevice(270, moderateScale);
|
|
9
|
+
const validPaddingTop = scaledForDevice(24, moderateScale);
|
|
10
|
+
const validPaddingBottom = scaledForDevice(12, moderateScale);
|
|
11
|
+
const validPaddingHorizontal = scaledForDevice(20, moderateScale);
|
|
12
|
+
const validLeft = scaledForDevice(8, moderateScale);
|
|
13
|
+
const validTop = scaledForDevice(4, moderateScale);
|
|
14
|
+
const validFontSize = scaledForDevice(13, moderateScale);
|
|
15
|
+
const styles = StyleSheet.create({
|
|
16
|
+
background: {
|
|
17
|
+
display: 'flex',
|
|
18
|
+
justifyContent: 'center',
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
width: '100%',
|
|
21
|
+
height: '100%',
|
|
22
|
+
backgroundColor: '#0009',
|
|
23
|
+
},
|
|
24
|
+
containerModal: {
|
|
25
|
+
justifyContent: 'space-between',
|
|
26
|
+
},
|
|
27
|
+
contentWrapper: {
|
|
28
|
+
bottom: validBottom,
|
|
29
|
+
minWidth: validMinWidth,
|
|
30
|
+
paddingTop: validPaddingTop,
|
|
31
|
+
paddingBottom: validPaddingBottom,
|
|
32
|
+
paddingLeft: validPaddingHorizontal,
|
|
33
|
+
paddingRight: validPaddingHorizontal,
|
|
34
|
+
backgroundColor: base.white,
|
|
35
|
+
elevation: 5,
|
|
36
|
+
},
|
|
37
|
+
buttonWrapper: {
|
|
38
|
+
flexDirection: 'row',
|
|
39
|
+
justifyContent: 'flex-end',
|
|
40
|
+
flexWrap: 'wrap',
|
|
41
|
+
left: validLeft,
|
|
42
|
+
top: validTop,
|
|
43
|
+
},
|
|
44
|
+
button: {
|
|
45
|
+
backgroundColor: base.white,
|
|
46
|
+
},
|
|
47
|
+
buttonText: {
|
|
48
|
+
color: primary.main,
|
|
49
|
+
fontSize: validFontSize,
|
|
50
|
+
fontWeight: '700',
|
|
51
|
+
textTransform: 'uppercase',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return (<ModalComponent animationType="fade" transparent visible={show}>
|
|
55
|
+
<View style={styles.background}>
|
|
56
|
+
<View style={styles.contentWrapper}>
|
|
57
|
+
<View style={styles.containerModal}>{children}</View>
|
|
58
|
+
{isMulti && (<View style={styles.buttonWrapper}>
|
|
59
|
+
<BaseButton title={modalAcceptText} iconRight={false} pressedColor={white.main} style={styles.button} textStyle={styles.buttonText} onPress={() => setShow(false)}/>
|
|
60
|
+
</View>)}
|
|
61
|
+
</View>
|
|
62
|
+
</View>
|
|
63
|
+
</ModalComponent>);
|
|
64
|
+
};
|
|
65
|
+
export default Modal;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { CustomOptionComponent, DropdownMeasures, Option, VariantOptions } from '../..';
|
|
3
|
+
interface OptionsProps {
|
|
4
|
+
variantOptions: VariantOptions;
|
|
5
|
+
dropdownMeasures: DropdownMeasures;
|
|
6
|
+
isShowedOptions: boolean;
|
|
7
|
+
setIsShowedOptions: (isShowed: boolean) => void;
|
|
8
|
+
filteredOptions: Option[];
|
|
9
|
+
selectedOptions: Option[];
|
|
10
|
+
noOptionsMessage: string;
|
|
11
|
+
optionStyles?: {};
|
|
12
|
+
callbackOption: (option: Option) => void;
|
|
13
|
+
customOptionComponent?: CustomOptionComponent | null;
|
|
14
|
+
isMulti: boolean;
|
|
15
|
+
modalAcceptText: string;
|
|
16
|
+
}
|
|
17
|
+
declare const Options: FC<OptionsProps>;
|
|
18
|
+
export default Options;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, StyleSheet, TouchableOpacity, ScrollView, Text } from 'react-native';
|
|
3
|
+
import { base, black, grey, primary, white } from '../../../../theme/palette';
|
|
4
|
+
import SwitcherComponent from '../SwitcherComponent';
|
|
5
|
+
const Options = (props) => {
|
|
6
|
+
const { variantOptions, dropdownMeasures, isShowedOptions, setIsShowedOptions, filteredOptions, callbackOption, selectedOptions, noOptionsMessage, optionStyles, customOptionComponent = null, isMulti, modalAcceptText, } = props;
|
|
7
|
+
const handleSelectedOption = (option) => callbackOption(option);
|
|
8
|
+
const isModal = variantOptions === 'Modal';
|
|
9
|
+
const styles = StyleSheet.create({
|
|
10
|
+
container: {
|
|
11
|
+
position: 'relative',
|
|
12
|
+
width: '100%',
|
|
13
|
+
padding: !isModal ? 8 : 0,
|
|
14
|
+
},
|
|
15
|
+
optionWrapper: {
|
|
16
|
+
position: !isModal ? 'absolute' : 'relative',
|
|
17
|
+
maxHeight: 168,
|
|
18
|
+
minHeight: 'auto',
|
|
19
|
+
borderColor: grey[200],
|
|
20
|
+
backgroundColor: base.white,
|
|
21
|
+
width: '100%',
|
|
22
|
+
top: !isModal ? 60 : 0,
|
|
23
|
+
marginBottom: 20,
|
|
24
|
+
elevation: !isModal ? 5 : 0,
|
|
25
|
+
flex: 1,
|
|
26
|
+
},
|
|
27
|
+
option: {
|
|
28
|
+
width: '100%',
|
|
29
|
+
height: 42,
|
|
30
|
+
justifyContent: 'center',
|
|
31
|
+
alignItems: 'stretch',
|
|
32
|
+
paddingLeft: 8,
|
|
33
|
+
},
|
|
34
|
+
optionText: {
|
|
35
|
+
color: black.main,
|
|
36
|
+
fontWeight: '400',
|
|
37
|
+
},
|
|
38
|
+
noOptionText: {
|
|
39
|
+
color: grey[500],
|
|
40
|
+
fontWeight: '400',
|
|
41
|
+
paddingLeft: 8,
|
|
42
|
+
paddingVertical: 10,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
const renderOptions = filteredOptions?.length &&
|
|
46
|
+
filteredOptions.map((option) => {
|
|
47
|
+
const isSelectedOption = selectedOptions.some((selected) => selected.label === option.label);
|
|
48
|
+
const styleText = { ...styles.optionText, ...(isSelectedOption && { color: primary.main }) };
|
|
49
|
+
const styleOption = {
|
|
50
|
+
...styles.option,
|
|
51
|
+
...(isSelectedOption && { backgroundColor: white.light }),
|
|
52
|
+
};
|
|
53
|
+
const customProps = {
|
|
54
|
+
renderedOption: option,
|
|
55
|
+
filteredOptions,
|
|
56
|
+
selectedOptions,
|
|
57
|
+
callbackOptionSelected: callbackOption,
|
|
58
|
+
};
|
|
59
|
+
if (customOptionComponent) {
|
|
60
|
+
return customOptionComponent(customProps);
|
|
61
|
+
}
|
|
62
|
+
return (<TouchableOpacity style={{ ...styleOption, ...optionStyles }} key={option.label} onPress={() => handleSelectedOption(option)}>
|
|
63
|
+
<Text style={styleText}> {option.label}</Text>
|
|
64
|
+
</TouchableOpacity>);
|
|
65
|
+
});
|
|
66
|
+
const noRenderOptions = (<View aria-disabled>
|
|
67
|
+
<Text style={styles.noOptionText}> {noOptionsMessage}</Text>
|
|
68
|
+
</View>);
|
|
69
|
+
return (<SwitcherComponent measures={dropdownMeasures} variant={variantOptions} show={isShowedOptions} setShow={setIsShowedOptions} isMulti={isMulti} modalAcceptText={modalAcceptText}>
|
|
70
|
+
<ScrollView style={styles.optionWrapper} contentContainerStyle={styles.container}>
|
|
71
|
+
{filteredOptions?.length ? renderOptions : noRenderOptions}
|
|
72
|
+
</ScrollView>
|
|
73
|
+
</SwitcherComponent>);
|
|
74
|
+
};
|
|
75
|
+
export default Options;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { DropdownMeasures, VariantOptions } from '../..';
|
|
3
|
+
interface SwitcherProps {
|
|
4
|
+
show: boolean;
|
|
5
|
+
isMulti: boolean;
|
|
6
|
+
variant: VariantOptions;
|
|
7
|
+
measures: DropdownMeasures;
|
|
8
|
+
children: React.Component | React.ReactNode;
|
|
9
|
+
modalAcceptText: string;
|
|
10
|
+
setShow: (isShowed: boolean) => void;
|
|
11
|
+
}
|
|
12
|
+
declare const SwitcherComponent: FC<SwitcherProps>;
|
|
13
|
+
export default SwitcherComponent;
|
|
@@ -9,6 +9,15 @@ declare enum KeyboardTypes {
|
|
|
9
9
|
PhonePad = "phone-pad",
|
|
10
10
|
URL = "url"
|
|
11
11
|
}
|
|
12
|
+
export declare enum VariantOptions {
|
|
13
|
+
Dropdown = "Dropdown",
|
|
14
|
+
Modal = "Modal"
|
|
15
|
+
}
|
|
16
|
+
export interface DropdownMeasures {
|
|
17
|
+
width: number;
|
|
18
|
+
pageY: number;
|
|
19
|
+
pageX: number;
|
|
20
|
+
}
|
|
12
21
|
export interface Option {
|
|
13
22
|
label: string;
|
|
14
23
|
value: string | number;
|
|
@@ -23,11 +32,11 @@ export type CustomOptionComponent = (props: CustomOptionComponentProps) => React
|
|
|
23
32
|
interface SelectProps {
|
|
24
33
|
options: Option[];
|
|
25
34
|
label: string;
|
|
26
|
-
value?:
|
|
35
|
+
value?: Option[];
|
|
36
|
+
variantOptions?: VariantOptions;
|
|
27
37
|
optionStyles?: {};
|
|
28
38
|
placeholder?: string;
|
|
29
39
|
inputProps?: TextInput;
|
|
30
|
-
isSearchable?: boolean;
|
|
31
40
|
isMulti?: boolean;
|
|
32
41
|
isDisabled?: boolean;
|
|
33
42
|
noOptionsMessage?: string;
|
|
@@ -36,6 +45,7 @@ interface SelectProps {
|
|
|
36
45
|
onFocus?: () => void;
|
|
37
46
|
onSelectOption?: (selectedOptions: Option[]) => void;
|
|
38
47
|
customOptionComponent?: CustomOptionComponent | null;
|
|
48
|
+
modalAcceptText?: string;
|
|
39
49
|
}
|
|
40
50
|
declare const Select: FC<SelectProps>;
|
|
41
51
|
export default Select;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/* istanbul ignore file */
|
|
2
2
|
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
3
|
-
import { Keyboard, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
3
|
+
import { Keyboard, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
4
4
|
import { black, grey, primary } from '../../theme/palette';
|
|
5
5
|
import { formatPlaceholderMulti } from './utils';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import Dropdown from './Components/Dropdown';
|
|
6
|
+
import Options from './Components/Options';
|
|
7
|
+
import Icon from '../Icon';
|
|
9
8
|
import { horizontalScale, moderateScale, scaledForDevice } from '../../scale';
|
|
10
9
|
var KeyboardTypes;
|
|
11
10
|
(function (KeyboardTypes) {
|
|
@@ -17,16 +16,26 @@ var KeyboardTypes;
|
|
|
17
16
|
KeyboardTypes["PhonePad"] = "phone-pad";
|
|
18
17
|
KeyboardTypes["URL"] = "url";
|
|
19
18
|
})(KeyboardTypes || (KeyboardTypes = {}));
|
|
20
|
-
|
|
19
|
+
export var VariantOptions;
|
|
20
|
+
(function (VariantOptions) {
|
|
21
|
+
VariantOptions["Dropdown"] = "Dropdown";
|
|
22
|
+
VariantOptions["Modal"] = "Modal";
|
|
23
|
+
})(VariantOptions || (VariantOptions = {}));
|
|
24
|
+
const Select = ({ options, label, value = null, variantOptions = VariantOptions.Dropdown, placeholder = '', optionStyles = {}, inputProps = {}, isMulti = false, isDisabled = false, noOptionsMessage = 'no options', multiOptionsText = null, keyboardType = KeyboardTypes.Default, onFocus = () => { }, onSelectOption = () => { }, customOptionComponent = null, modalAcceptText = 'accept', ...props }) => {
|
|
21
25
|
const [inputValue, setInputValue] = useState('');
|
|
22
26
|
const [selectedOptions, setSelectedOptions] = useState([]);
|
|
23
27
|
const [filteredOptions, setFilteredOptions] = useState(options);
|
|
24
|
-
const [
|
|
28
|
+
const [isShowedOptions, setIsShowedOptions] = useState(false);
|
|
29
|
+
const [dropdownMeasures, setDropdownMeasures] = useState({
|
|
30
|
+
width: 0,
|
|
31
|
+
pageY: 0,
|
|
32
|
+
pageX: 0,
|
|
33
|
+
});
|
|
25
34
|
const inputRef = useRef(null);
|
|
26
|
-
const hasDefaultValue = value && options?.
|
|
27
|
-
const isMoveLabel =
|
|
35
|
+
const hasDefaultValue = !!value?.length && options?.some((option) => option?.label === value[0]?.label);
|
|
36
|
+
const isMoveLabel = isShowedOptions || inputValue;
|
|
28
37
|
const showDeleteIcon = isDisabled ? false : !!inputValue && !!selectedOptions?.length;
|
|
29
|
-
const isArrowRotated =
|
|
38
|
+
const isArrowRotated = isShowedOptions ? '180deg' : '0deg';
|
|
30
39
|
const filterOptions = (textValue) => {
|
|
31
40
|
if (typeof textValue !== 'string' || !textValue.length) {
|
|
32
41
|
return setFilteredOptions(options);
|
|
@@ -39,21 +48,19 @@ const Select = ({ options, label, value = null, placeholder = '', optionStyles =
|
|
|
39
48
|
filterOptions(textValue);
|
|
40
49
|
};
|
|
41
50
|
const handleOnFocus = () => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
51
|
+
Keyboard.dismiss();
|
|
52
|
+
setIsShowedOptions(true);
|
|
45
53
|
onFocus();
|
|
46
|
-
setIsShowedDropdown(true);
|
|
47
54
|
};
|
|
48
55
|
const setSingleOption = (option) => {
|
|
49
|
-
|
|
56
|
+
setIsShowedOptions(false);
|
|
50
57
|
setSelectedOptions([option]);
|
|
51
58
|
setInputValue(option.label);
|
|
52
59
|
};
|
|
53
60
|
const setMultiOptions = (option) => {
|
|
54
|
-
const optionMatcher = selectedOptions.
|
|
61
|
+
const optionMatcher = !!selectedOptions.find((previewOption) => previewOption.value === option.value);
|
|
55
62
|
const updateOption = optionMatcher
|
|
56
|
-
? selectedOptions.filter((previewOption) => previewOption !== option)
|
|
63
|
+
? selectedOptions.filter((previewOption) => previewOption.value !== option.value)
|
|
57
64
|
: [...selectedOptions, option];
|
|
58
65
|
setSelectedOptions(updateOption);
|
|
59
66
|
setInputValue(formatPlaceholderMulti(updateOption, multiOptionsText));
|
|
@@ -63,11 +70,11 @@ const Select = ({ options, label, value = null, placeholder = '', optionStyles =
|
|
|
63
70
|
if (isDisabled) {
|
|
64
71
|
return null;
|
|
65
72
|
}
|
|
66
|
-
|
|
73
|
+
setIsShowedOptions(!isShowedOptions);
|
|
67
74
|
inputRef.current?.blur();
|
|
68
75
|
};
|
|
69
76
|
const handleResetOptions = () => {
|
|
70
|
-
|
|
77
|
+
setIsShowedOptions(false);
|
|
71
78
|
setInputValue('');
|
|
72
79
|
setSelectedOptions([]);
|
|
73
80
|
};
|
|
@@ -75,16 +82,23 @@ const Select = ({ options, label, value = null, placeholder = '', optionStyles =
|
|
|
75
82
|
if (!!selectedOptions?.length && !!inputValue) {
|
|
76
83
|
onSelectOption(selectedOptions);
|
|
77
84
|
}
|
|
78
|
-
|
|
85
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
86
|
+
}, [selectedOptions]);
|
|
79
87
|
useEffect(() => {
|
|
80
88
|
memoizedSelectedOptions();
|
|
81
|
-
}, [selectedOptions,
|
|
89
|
+
}, [selectedOptions, memoizedSelectedOptions]);
|
|
82
90
|
useEffect(() => {
|
|
83
91
|
if (hasDefaultValue) {
|
|
84
|
-
setSelectedOptions(
|
|
85
|
-
setInputValue(value);
|
|
92
|
+
setSelectedOptions(value);
|
|
93
|
+
setInputValue(formatPlaceholderMulti(value, multiOptionsText));
|
|
86
94
|
}
|
|
95
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
87
96
|
}, [hasDefaultValue, value]);
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (inputRef.current) {
|
|
99
|
+
inputRef.current.measure((x, y, width, height, pageX, pageY) => setDropdownMeasures({ width, pageX, pageY: pageY - 15 }));
|
|
100
|
+
}
|
|
101
|
+
}, [isShowedOptions]);
|
|
88
102
|
const moveLabel = isMoveLabel ? 38 : 10;
|
|
89
103
|
const validFontSize = scaledForDevice(16, moderateScale);
|
|
90
104
|
const validMarginBottom = scaledForDevice(10, moderateScale);
|
|
@@ -100,7 +114,7 @@ const Select = ({ options, label, value = null, placeholder = '', optionStyles =
|
|
|
100
114
|
width: '100%',
|
|
101
115
|
marginBottom: validMarginBottom,
|
|
102
116
|
position: 'relative',
|
|
103
|
-
zIndex:
|
|
117
|
+
zIndex: isShowedOptions ? 10 : 0,
|
|
104
118
|
},
|
|
105
119
|
wrapperInput: {
|
|
106
120
|
position: 'relative',
|
|
@@ -127,7 +141,7 @@ const Select = ({ options, label, value = null, placeholder = '', optionStyles =
|
|
|
127
141
|
letterSpacing: 0,
|
|
128
142
|
borderBottomWidth: validBorderBottomWidth,
|
|
129
143
|
color: black.main,
|
|
130
|
-
borderBottomColor:
|
|
144
|
+
borderBottomColor: isShowedOptions ? primary.main : grey[200],
|
|
131
145
|
},
|
|
132
146
|
arrowIcon: {
|
|
133
147
|
position: 'absolute',
|
|
@@ -145,16 +159,20 @@ const Select = ({ options, label, value = null, placeholder = '', optionStyles =
|
|
|
145
159
|
zIndex: 1,
|
|
146
160
|
},
|
|
147
161
|
});
|
|
148
|
-
return (<View style={styles.wrapper}>
|
|
149
|
-
<View style={styles.wrapperInput}
|
|
150
|
-
{showDeleteIcon && <
|
|
151
|
-
|
|
162
|
+
return (<View style={styles.wrapper} {...props}>
|
|
163
|
+
<View style={styles.wrapperInput}>
|
|
164
|
+
{isMulti && showDeleteIcon && (<Pressable onPress={handleResetOptions} style={styles.deleteIcon}>
|
|
165
|
+
<Icon size={20} color={black.main} name="cross_circle_flat"/>
|
|
166
|
+
</Pressable>)}
|
|
167
|
+
<Pressable style={styles.arrowIcon} onPress={handleCloseDropdown}>
|
|
168
|
+
<Icon size={20} color={isDisabled ? black.main : primary.main} name="chevron_down"/>
|
|
169
|
+
</Pressable>
|
|
152
170
|
|
|
153
171
|
<Text style={styles.label}>{label}</Text>
|
|
154
|
-
<TextInput ref={inputRef} style={styles.input} value={inputValue} placeholder={isMoveLabel && placeholder} showSoftInputOnFocus={
|
|
172
|
+
<TextInput ref={inputRef} style={styles.input} value={inputValue} placeholder={isMoveLabel && placeholder} showSoftInputOnFocus={false} caretHidden={true} keyboardType={keyboardType} editable={!isDisabled} onFocus={handleOnFocus} onChangeText={handleChange} {...inputProps}/>
|
|
155
173
|
</View>
|
|
156
174
|
|
|
157
|
-
<
|
|
175
|
+
<Options variantOptions={variantOptions} dropdownMeasures={dropdownMeasures} setIsShowedOptions={setIsShowedOptions} isShowedOptions={isShowedOptions} filteredOptions={filteredOptions} selectedOptions={selectedOptions} noOptionsMessage={noOptionsMessage} optionStyles={optionStyles} callbackOption={handleSelectedOption} customOptionComponent={customOptionComponent} isMulti={isMulti} modalAcceptText={modalAcceptText}/>
|
|
158
176
|
</View>);
|
|
159
177
|
};
|
|
160
178
|
export default Select;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Option } from '..';
|
|
2
|
-
export declare const formatPlaceholderMulti: (options: Option[], optionsText: string) => string;
|
|
2
|
+
export declare const formatPlaceholderMulti: (options: Option[], optionsText: string | null) => string;
|
|
@@ -2,7 +2,6 @@ export const formatPlaceholderMulti = (options, optionsText) => {
|
|
|
2
2
|
if (!options.length) {
|
|
3
3
|
return '';
|
|
4
4
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
: options[0].label;
|
|
5
|
+
const validOptionText = `(+${options.length - 1}${optionsText ? ` ${optionsText}` : ''})`;
|
|
6
|
+
return options.length > 1 ? `${options[0].label} ${validOptionText}` : options[0].label;
|
|
8
7
|
};
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ViewStyle } from 'react-native';
|
|
3
|
-
interface IconProps {
|
|
4
|
-
color?: string;
|
|
5
|
-
size?: number;
|
|
6
|
-
iconStyles?: {};
|
|
7
|
-
style?: ViewStyle;
|
|
8
|
-
onPress?: () => void;
|
|
9
|
-
}
|
|
10
|
-
declare const Chevron: {
|
|
11
|
-
({ style, color, size, onPress, ...props }: IconProps): React.JSX.Element;
|
|
12
|
-
defaultProps: {
|
|
13
|
-
color: string;
|
|
14
|
-
onPress: () => void;
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
export default Chevron;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Pressable, View } from 'react-native';
|
|
3
|
-
import { primary } from '../../../../../theme/palette';
|
|
4
|
-
import Svg, { Path } from 'react-native-svg';
|
|
5
|
-
import { moderateScale, scaledForDevice } from '../../../../../scale';
|
|
6
|
-
const Chevron = ({ style, color, size = 21, onPress, ...props }) => {
|
|
7
|
-
const validSize = scaledForDevice(size, moderateScale);
|
|
8
|
-
return (<Pressable onPress={onPress} style={style} {...props}>
|
|
9
|
-
<View>
|
|
10
|
-
<Svg width={validSize} height={validSize} viewBox="0 0 16 16">
|
|
11
|
-
<Path d="M8.17432 11.1055L3 6.49316L4.33106 5L8.17627 8.42773L12.0132 5.01904L13.3413 6.51416L8.17432 11.1055Z" fill={color}/>
|
|
12
|
-
</Svg>
|
|
13
|
-
</View>
|
|
14
|
-
</Pressable>);
|
|
15
|
-
};
|
|
16
|
-
Chevron.defaultProps = {
|
|
17
|
-
color: primary.main,
|
|
18
|
-
onPress: () => { },
|
|
19
|
-
};
|
|
20
|
-
export default Chevron;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ViewStyle } from 'react-native';
|
|
3
|
-
interface IconProps {
|
|
4
|
-
color?: string;
|
|
5
|
-
size?: number;
|
|
6
|
-
iconStyles?: {};
|
|
7
|
-
style?: ViewStyle;
|
|
8
|
-
onPress?: () => void;
|
|
9
|
-
}
|
|
10
|
-
declare const Delete: {
|
|
11
|
-
({ style, color, size, onPress, ...props }: IconProps): React.JSX.Element;
|
|
12
|
-
defaultProps: {
|
|
13
|
-
color: string;
|
|
14
|
-
onPress: () => void;
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
export default Delete;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Pressable, View } from 'react-native';
|
|
3
|
-
import { black } from '../../../../../theme/palette';
|
|
4
|
-
import Svg, { Path } from 'react-native-svg';
|
|
5
|
-
import { moderateScale, scaledForDevice } from '../../../../../scale';
|
|
6
|
-
const Delete = ({ style, color, size = 21, onPress, ...props }) => {
|
|
7
|
-
const validSize = scaledForDevice(size, moderateScale);
|
|
8
|
-
return (<Pressable onPress={onPress} style={style} {...props}>
|
|
9
|
-
<View>
|
|
10
|
-
<Svg width={validSize} height={validSize} viewBox="0 0 16 16">
|
|
11
|
-
<Path fill-rule="evenodd" clip-rule="evenodd" d="M1 8C1 4.13403 4.13397 1 8 1C11.866 1 15 4.13403 15 8C15 11.866 11.866 15 8 15C4.13397 15 1 11.866 1 8ZM10.03 11.4441L11.4441 10.03L9.41406 8L11.4441 5.96997L10.03 4.55591L8 6.58594L5.96997 4.55591L4.55591 5.96997L6.58594 8L4.55591 10.03L5.96997 11.4441L8 9.41406L10.03 11.4441Z" fill={color}/>
|
|
12
|
-
</Svg>
|
|
13
|
-
</View>
|
|
14
|
-
</Pressable>);
|
|
15
|
-
};
|
|
16
|
-
Delete.defaultProps = {
|
|
17
|
-
color: black.main,
|
|
18
|
-
onPress: () => { },
|
|
19
|
-
};
|
|
20
|
-
export default Delete;
|