@janiscommerce/ui-native 1.0.3 → 1.1.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/README.md +35 -0
- package/dist/android/app/_BUCK +55 -0
- package/dist/android/app/build.gradle +230 -0
- package/dist/android/app/build_defs.bzl +19 -0
- package/dist/android/app/debug.keystore +0 -0
- package/dist/android/app/proguard-rules.pro +10 -0
- package/dist/android/app/src/debug/AndroidManifest.xml +13 -0
- package/dist/android/app/src/debug/java/com/myapp/ReactNativeFlipper.java +72 -0
- package/dist/android/app/src/main/AndroidManifest.xml +25 -0
- package/dist/android/app/src/main/assets/fonts/janis-font-icon.ttf +0 -0
- package/dist/android/app/src/main/java/com/myapp/MainActivity.java +15 -0
- package/dist/android/app/src/main/java/com/myapp/MainApplication.java +80 -0
- package/dist/android/app/src/main/res/drawable/rn_edit_text_material.xml +36 -0
- package/dist/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/dist/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/dist/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/dist/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/dist/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/dist/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/dist/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/dist/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/dist/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/dist/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/dist/android/app/src/main/res/values/strings.xml +3 -0
- package/dist/android/app/src/main/res/values/styles.xml +9 -0
- package/dist/android/build.gradle +42 -0
- package/dist/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/dist/android/gradle/wrapper/gradle-wrapper.properties +5 -0
- package/dist/android/gradle.properties +28 -0
- package/dist/android/gradlew +185 -0
- package/dist/android/gradlew.bat +89 -0
- package/dist/android/settings.gradle +6 -0
- package/dist/components/Carousel/index.d.ts +19 -0
- package/dist/components/Carousel/index.js +35 -0
- package/dist/components/Carousel/utils/index.d.ts +13 -0
- package/dist/components/Carousel/utils/index.js +102 -0
- package/dist/components/CheckBox/index.d.ts +1 -0
- package/dist/components/Icon/assets/fonts/selection.json +1 -0
- package/dist/components/Icon/index.d.ts +8 -0
- package/dist/components/Icon/index.js +12 -0
- package/dist/components/Loading/LoadingSvg/index.d.ts +8 -0
- package/dist/components/Loading/LoadingSvg/index.js +13 -0
- package/dist/components/Loading/index.d.ts +2 -2
- package/dist/components/Loading/index.js +5 -8
- package/dist/components/RadioButton/index.d.ts +22 -0
- package/dist/components/RadioButton/index.js +48 -0
- package/dist/components/Select/Components/Dropdown/index.d.ts +13 -0
- package/dist/components/Select/Components/Dropdown/index.js +73 -0
- package/dist/components/Select/Components/Icons/Chevron/index.d.ts +18 -0
- package/dist/components/Select/Components/Icons/Chevron/index.js +19 -0
- package/dist/components/Select/Components/Icons/Delete/index.d.ts +18 -0
- package/dist/components/Select/Components/Icons/Delete/index.js +19 -0
- package/dist/components/Select/index.d.ts +41 -0
- package/dist/components/Select/index.js +149 -0
- package/dist/components/Select/utils/index.d.ts +2 -0
- package/dist/components/Select/utils/index.js +8 -0
- package/dist/components/SwipeUp/childComponents/index.d.ts +11 -0
- package/dist/components/SwipeUp/childComponents/index.js +22 -0
- package/dist/components/SwipeUp/index.d.ts +10 -0
- package/dist/components/SwipeUp/index.js +11 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +7 -1
- package/dist/ios/MyApp/AppDelegate.h +8 -0
- package/dist/ios/MyApp/AppDelegate.m +58 -0
- package/dist/ios/MyApp/Images.xcassets/AppIcon.appiconset/Contents.json +38 -0
- package/dist/ios/MyApp/Images.xcassets/Contents.json +6 -0
- package/dist/ios/MyApp/Info.plist +55 -0
- package/dist/ios/MyApp/LaunchScreen.storyboard +58 -0
- package/dist/ios/MyApp/main.m +9 -0
- package/dist/ios/MyApp.xcodeproj/project.pbxproj +791 -0
- package/dist/ios/MyApp.xcodeproj/xcshareddata/xcschemes/MyApp-tvOS.xcscheme +88 -0
- package/dist/ios/MyApp.xcodeproj/xcshareddata/xcschemes/MyApp.xcscheme +88 -0
- package/dist/ios/MyAppTests/Info.plist +24 -0
- package/dist/ios/MyAppTests/MyAppTests.m +65 -0
- package/dist/ios/Podfile +33 -0
- package/package.json +11 -5
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createIconSetFromIcoMoon } from 'react-native-vector-icons';
|
|
3
|
+
import icoMoonConfig from './assets/fonts/selection.json';
|
|
4
|
+
import { primary } from '../../theme/palette';
|
|
5
|
+
const IconComponent = createIconSetFromIcoMoon(icoMoonConfig, 'janis-font-icon', 'janis-font-icon.ttf');
|
|
6
|
+
const Icon = ({ name, color = primary.main, size = 16, ...props }) => {
|
|
7
|
+
if (!name) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
return <IconComponent name={name} color={color} size={size} {...props}/>;
|
|
11
|
+
};
|
|
12
|
+
export default Icon;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Animated, ViewProps } from 'react-native';
|
|
3
|
+
interface IanimatedView extends Animated.AnimatedProps<ViewProps> {
|
|
4
|
+
size?: number;
|
|
5
|
+
color?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const LoadingSvg: ({ size, color, ...props }: IanimatedView) => React.JSX.Element;
|
|
8
|
+
export default LoadingSvg;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Svg, { Path } from 'react-native-svg';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Animated } from 'react-native';
|
|
4
|
+
import { white } from '../../../theme/palette';
|
|
5
|
+
const LoadingSvg = ({ size, color, ...props }) => {
|
|
6
|
+
return (<Animated.View {...props}>
|
|
7
|
+
<Svg x="0px" y="0px" width={size} height={size} viewBox="0 0 163 163">
|
|
8
|
+
<Path d="M134.1,136.4c-30.3,29.1-78.5,28-107.5-2.3c-29.1-30.3-28-78.5,2.3-107.5s78.5-28,107.5,2.3" fill="none" stroke={white.dark} strokeWidth="10.5546" strokeLinecap="round" strokeLinejoin="round"/>
|
|
9
|
+
<Path id="path-color" d="M78.4,5.5c42-1.7,77.4,30.9,79.1,72.9c1.7,42-30.9,77.4-72.9,79.1c-42,1.7-77.4-30.9-79.1-72.9" fill="none" stroke={color} strokeWidth="10.5546" strokeLinecap="round" strokeLinejoin="round"/>
|
|
10
|
+
</Svg>
|
|
11
|
+
</Animated.View>);
|
|
12
|
+
};
|
|
13
|
+
export default LoadingSvg;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { FC } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ViewStyle } from 'react-native';
|
|
3
3
|
interface Props {
|
|
4
4
|
isLoading: boolean;
|
|
5
|
-
color?:
|
|
5
|
+
color?: string;
|
|
6
6
|
size?: number;
|
|
7
7
|
duration?: number;
|
|
8
8
|
children?: React.ReactNode | null;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
2
|
import { StyleSheet, View, Animated, Easing } from 'react-native';
|
|
3
|
-
import
|
|
3
|
+
import LoadingSvg from './LoadingSvg';
|
|
4
|
+
import { primary } from '../../theme/palette';
|
|
4
5
|
const startRotationAnimation = ({ duration, rotationDegree, timingAnimation }) => Animated.loop(Animated.timing(rotationDegree, {
|
|
5
6
|
duration,
|
|
6
7
|
toValue: 360,
|
|
@@ -21,12 +22,8 @@ const Loading = ({ isLoading, color = primary.main, size = 64, duration = 1000,
|
|
|
21
22
|
position: 'absolute',
|
|
22
23
|
width: size,
|
|
23
24
|
height: size,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
borderRightColor: color,
|
|
27
|
-
borderBottomColor: color,
|
|
28
|
-
borderRadius: size / 2,
|
|
29
|
-
borderWidth: 3.5,
|
|
25
|
+
justifyContent: 'center',
|
|
26
|
+
alignItems: 'center',
|
|
30
27
|
},
|
|
31
28
|
});
|
|
32
29
|
const animationSpinnerStyle = {
|
|
@@ -52,7 +49,7 @@ const Loading = ({ isLoading, color = primary.main, size = 64, duration = 1000,
|
|
|
52
49
|
return <></>;
|
|
53
50
|
}
|
|
54
51
|
return (<View style={[styles.container, style]} {...props}>
|
|
55
|
-
<
|
|
52
|
+
<LoadingSvg style={[styles.spinner, { ...animationSpinnerStyle }]} size={size} color={color}/>
|
|
56
53
|
{children}
|
|
57
54
|
</View>);
|
|
58
55
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ViewStyle } from 'react-native';
|
|
3
|
+
declare const checkLocation: readonly ["left", "right"];
|
|
4
|
+
type positions = (typeof checkLocation)[number];
|
|
5
|
+
declare const CheckSizeValues: {
|
|
6
|
+
sm: number;
|
|
7
|
+
md: number;
|
|
8
|
+
lg: number;
|
|
9
|
+
};
|
|
10
|
+
type sizeType = typeof CheckSizeValues;
|
|
11
|
+
type sizeKeys = keyof sizeType;
|
|
12
|
+
interface RadioButtonProps {
|
|
13
|
+
children: React.ReactNode | string;
|
|
14
|
+
selected?: boolean;
|
|
15
|
+
onPress?: () => {};
|
|
16
|
+
checkPosition?: positions;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
checkSize?: sizeKeys;
|
|
19
|
+
style?: ViewStyle;
|
|
20
|
+
}
|
|
21
|
+
declare const RadioButton: ({ children, onPress, selected, checkPosition, checkSize, disabled, style, ...props }: RadioButtonProps) => React.JSX.Element | null;
|
|
22
|
+
export default RadioButton;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View, TouchableOpacity, StyleSheet } from 'react-native';
|
|
3
|
+
import Text from '../Text';
|
|
4
|
+
import CheckBox from '../CheckBox';
|
|
5
|
+
const checkLocation = ['left', 'right'];
|
|
6
|
+
const CheckSizeValues = {
|
|
7
|
+
sm: 16,
|
|
8
|
+
md: 24,
|
|
9
|
+
lg: 32,
|
|
10
|
+
};
|
|
11
|
+
const styles = StyleSheet.create({
|
|
12
|
+
container: {
|
|
13
|
+
alignItems: 'center',
|
|
14
|
+
paddingHorizontal: 16,
|
|
15
|
+
marginVertical: 10,
|
|
16
|
+
height: 'auto',
|
|
17
|
+
},
|
|
18
|
+
row: {
|
|
19
|
+
flexDirection: 'row',
|
|
20
|
+
justifyContent: 'flex-start',
|
|
21
|
+
},
|
|
22
|
+
reverseRow: {
|
|
23
|
+
flexDirection: 'row-reverse',
|
|
24
|
+
justifyContent: 'space-between',
|
|
25
|
+
},
|
|
26
|
+
checkToLeft: {
|
|
27
|
+
marginLeft: 15,
|
|
28
|
+
},
|
|
29
|
+
checkToRight: {
|
|
30
|
+
marginRight: 15,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
const RadioButton = ({ children, onPress, selected = false, checkPosition = 'left', checkSize = 'sm', disabled = false, style, ...props }) => {
|
|
34
|
+
if (!children) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const { container, row, reverseRow, checkToLeft, checkToRight } = styles;
|
|
38
|
+
const isStringChild = typeof children === 'string';
|
|
39
|
+
const checkLeft = checkPosition === 'left';
|
|
40
|
+
const customSize = CheckSizeValues[checkSize];
|
|
41
|
+
return (<TouchableOpacity style={[container, checkLeft ? row : reverseRow, style]} disabled={disabled} onPress={onPress} {...props}>
|
|
42
|
+
<CheckBox checked={selected} disabled={disabled} customSize={customSize} borderRadius={customSize / 2}/>
|
|
43
|
+
<View style={checkLeft ? checkToLeft : checkToRight}>
|
|
44
|
+
{isStringChild ? <Text>{children}</Text> : children}
|
|
45
|
+
</View>
|
|
46
|
+
</TouchableOpacity>);
|
|
47
|
+
};
|
|
48
|
+
export default RadioButton;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { CustomOptionComponent, Option } from '../..';
|
|
3
|
+
interface DropdownProps {
|
|
4
|
+
isShowedDropdown: boolean;
|
|
5
|
+
filteredOptions: Option[];
|
|
6
|
+
selectedOptions: Option[];
|
|
7
|
+
noOptionsMessage: string;
|
|
8
|
+
optionStyles?: {};
|
|
9
|
+
callbackOption: (option: Option) => void;
|
|
10
|
+
customOptionComponent?: CustomOptionComponent | null;
|
|
11
|
+
}
|
|
12
|
+
declare const Dropdown: FC<DropdownProps>;
|
|
13
|
+
export default Dropdown;
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
const Dropdown = (props) => {
|
|
5
|
+
const { isShowedDropdown, filteredOptions, callbackOption, selectedOptions, noOptionsMessage, optionStyles, customOptionComponent = null, } = props;
|
|
6
|
+
if (!isShowedDropdown) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const handleSelectedOption = (option) => callbackOption(option);
|
|
10
|
+
const styles = StyleSheet.create({
|
|
11
|
+
container: {
|
|
12
|
+
width: '100%',
|
|
13
|
+
padding: 8,
|
|
14
|
+
},
|
|
15
|
+
optionWrapper: {
|
|
16
|
+
position: 'absolute',
|
|
17
|
+
maxHeight: 168,
|
|
18
|
+
borderColor: grey[200],
|
|
19
|
+
backgroundColor: base.white,
|
|
20
|
+
width: '100%',
|
|
21
|
+
top: 60,
|
|
22
|
+
marginBottom: 20,
|
|
23
|
+
elevation: 5,
|
|
24
|
+
zIndex: 10,
|
|
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 (<ScrollView style={styles.optionWrapper} contentContainerStyle={styles.container}>
|
|
70
|
+
{filteredOptions?.length ? renderOptions : noRenderOptions}
|
|
71
|
+
</ScrollView>);
|
|
72
|
+
};
|
|
73
|
+
export default Dropdown;
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
size: number;
|
|
15
|
+
onPress: () => void;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export default Chevron;
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
const Chevron = ({ style, color, size, onPress, ...props }) => {
|
|
6
|
+
return (<Pressable onPress={onPress} style={style} {...props}>
|
|
7
|
+
<View>
|
|
8
|
+
<Svg width={size} height={size} viewBox="0 0 16 16">
|
|
9
|
+
<Path d="M8.17432 11.1055L3 6.49316L4.33106 5L8.17627 8.42773L12.0132 5.01904L13.3413 6.51416L8.17432 11.1055Z" fill={color}/>
|
|
10
|
+
</Svg>
|
|
11
|
+
</View>
|
|
12
|
+
</Pressable>);
|
|
13
|
+
};
|
|
14
|
+
Chevron.defaultProps = {
|
|
15
|
+
color: primary.main,
|
|
16
|
+
size: 21,
|
|
17
|
+
onPress: () => { },
|
|
18
|
+
};
|
|
19
|
+
export default Chevron;
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
size: number;
|
|
15
|
+
onPress: () => void;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export default Delete;
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
const Delete = ({ style, color, size, onPress, ...props }) => {
|
|
6
|
+
return (<Pressable onPress={onPress} style={style} {...props}>
|
|
7
|
+
<View>
|
|
8
|
+
<Svg width={size} height={size} viewBox="0 0 16 16">
|
|
9
|
+
<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}/>
|
|
10
|
+
</Svg>
|
|
11
|
+
</View>
|
|
12
|
+
</Pressable>);
|
|
13
|
+
};
|
|
14
|
+
Delete.defaultProps = {
|
|
15
|
+
color: black.main,
|
|
16
|
+
size: 21,
|
|
17
|
+
onPress: () => { },
|
|
18
|
+
};
|
|
19
|
+
export default Delete;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React, { FC } from 'react';
|
|
2
|
+
import { TextInput } from 'react-native';
|
|
3
|
+
declare enum KeyboardTypes {
|
|
4
|
+
Default = "default",
|
|
5
|
+
NumberPad = "number-pad",
|
|
6
|
+
DecimalPad = "decimal-pad",
|
|
7
|
+
Numeric = "numeric",
|
|
8
|
+
EmailAddress = "email-address",
|
|
9
|
+
PhonePad = "phone-pad",
|
|
10
|
+
URL = "url"
|
|
11
|
+
}
|
|
12
|
+
export interface Option {
|
|
13
|
+
label: string;
|
|
14
|
+
value: string | number;
|
|
15
|
+
}
|
|
16
|
+
interface CustomOptionComponentProps {
|
|
17
|
+
renderedOption: Option;
|
|
18
|
+
filteredOptions: Option[];
|
|
19
|
+
selectedOptions: Option[];
|
|
20
|
+
callbackOptionSelected: (option: Option) => void;
|
|
21
|
+
}
|
|
22
|
+
export type CustomOptionComponent = (props: CustomOptionComponentProps) => React.Component;
|
|
23
|
+
interface SelectProps {
|
|
24
|
+
options: Option[];
|
|
25
|
+
label: string;
|
|
26
|
+
value?: string;
|
|
27
|
+
optionStyles?: {};
|
|
28
|
+
placeholder?: string;
|
|
29
|
+
inputProps?: TextInput;
|
|
30
|
+
isSearchable?: boolean;
|
|
31
|
+
isMulti?: boolean;
|
|
32
|
+
isDisabled?: boolean;
|
|
33
|
+
noOptionsMessage?: string;
|
|
34
|
+
multiOptionsText?: string;
|
|
35
|
+
keyboardType?: KeyboardTypes;
|
|
36
|
+
onFocus?: () => void;
|
|
37
|
+
onSelectOption?: (selectedOptions: Option[]) => void;
|
|
38
|
+
customOptionComponent?: CustomOptionComponent | null;
|
|
39
|
+
}
|
|
40
|
+
declare const Select: FC<SelectProps>;
|
|
41
|
+
export default Select;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
+
import { Keyboard, StyleSheet, Text, TextInput, View } from 'react-native';
|
|
3
|
+
import { black, grey, primary } from '../../theme/palette';
|
|
4
|
+
import { formatPlaceholderMulti } from './utils';
|
|
5
|
+
import ChevronIcon from './Components/Icons/Chevron';
|
|
6
|
+
import DeleteIcon from './Components/Icons/Delete';
|
|
7
|
+
import Dropdown from './Components/Dropdown';
|
|
8
|
+
// eslint-disable-next-line no-shadow
|
|
9
|
+
var KeyboardTypes;
|
|
10
|
+
(function (KeyboardTypes) {
|
|
11
|
+
KeyboardTypes["Default"] = "default";
|
|
12
|
+
KeyboardTypes["NumberPad"] = "number-pad";
|
|
13
|
+
KeyboardTypes["DecimalPad"] = "decimal-pad";
|
|
14
|
+
KeyboardTypes["Numeric"] = "numeric";
|
|
15
|
+
KeyboardTypes["EmailAddress"] = "email-address";
|
|
16
|
+
KeyboardTypes["PhonePad"] = "phone-pad";
|
|
17
|
+
KeyboardTypes["URL"] = "url";
|
|
18
|
+
})(KeyboardTypes || (KeyboardTypes = {}));
|
|
19
|
+
const Select = ({ options, label, value = null, placeholder = '', optionStyles = {}, inputProps = {}, isSearchable = false, isMulti = false, isDisabled = false, noOptionsMessage = 'no options', multiOptionsText = '', keyboardType = KeyboardTypes.Default, onFocus = () => { }, onSelectOption = () => { }, customOptionComponent = null, ...props }) => {
|
|
20
|
+
const [inputValue, setInputValue] = useState('');
|
|
21
|
+
const [selectedOptions, setSelectedOptions] = useState([]);
|
|
22
|
+
const [filteredOptions, setFilteredOptions] = useState(options);
|
|
23
|
+
const [isShowedDropdown, setIsShowedDropdown] = useState(false);
|
|
24
|
+
const inputRef = useRef(null);
|
|
25
|
+
const hasDefaultValue = value && options?.find((option) => option.label === value);
|
|
26
|
+
const isMoveLabel = isShowedDropdown || inputValue;
|
|
27
|
+
const showDeleteIcon = isDisabled ? false : !!inputValue && !!selectedOptions?.length;
|
|
28
|
+
const isArrowRotated = isShowedDropdown ? '180deg' : '0deg';
|
|
29
|
+
const filterOptions = (textValue) => {
|
|
30
|
+
if (typeof textValue !== 'string' || !textValue.length) {
|
|
31
|
+
return setFilteredOptions(options);
|
|
32
|
+
}
|
|
33
|
+
const filtered = options?.filter((option) => option.label.toLowerCase().includes(textValue.toLowerCase()));
|
|
34
|
+
return setFilteredOptions(filtered);
|
|
35
|
+
};
|
|
36
|
+
const handleChange = (textValue) => {
|
|
37
|
+
setInputValue(textValue);
|
|
38
|
+
filterOptions(textValue);
|
|
39
|
+
};
|
|
40
|
+
const handleOnFocus = () => {
|
|
41
|
+
if (!isSearchable || isMulti) {
|
|
42
|
+
Keyboard.dismiss();
|
|
43
|
+
}
|
|
44
|
+
onFocus();
|
|
45
|
+
setIsShowedDropdown(true);
|
|
46
|
+
};
|
|
47
|
+
const setSingleOption = (option) => {
|
|
48
|
+
setIsShowedDropdown(false);
|
|
49
|
+
setSelectedOptions([option]);
|
|
50
|
+
setInputValue(option.label);
|
|
51
|
+
};
|
|
52
|
+
const setMultiOptions = (option) => {
|
|
53
|
+
const optionMatcher = selectedOptions.some((previewOption) => previewOption === option);
|
|
54
|
+
const updateOption = optionMatcher
|
|
55
|
+
? selectedOptions.filter((previewOption) => previewOption !== option)
|
|
56
|
+
: [...selectedOptions, option];
|
|
57
|
+
setSelectedOptions(updateOption);
|
|
58
|
+
setInputValue(formatPlaceholderMulti(updateOption, multiOptionsText));
|
|
59
|
+
};
|
|
60
|
+
const handleSelectedOption = (option) => isMulti ? setMultiOptions(option) : setSingleOption(option);
|
|
61
|
+
const handleCloseDropdown = () => {
|
|
62
|
+
if (isDisabled) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
setIsShowedDropdown(!isShowedDropdown);
|
|
66
|
+
inputRef.current?.blur();
|
|
67
|
+
};
|
|
68
|
+
const handleResetOptions = () => {
|
|
69
|
+
setIsShowedDropdown(false);
|
|
70
|
+
setInputValue('');
|
|
71
|
+
setSelectedOptions([]);
|
|
72
|
+
};
|
|
73
|
+
const memoizedSelectedOptions = useCallback(() => {
|
|
74
|
+
if (!!selectedOptions?.length && !!inputValue) {
|
|
75
|
+
onSelectOption(selectedOptions);
|
|
76
|
+
}
|
|
77
|
+
}, [inputValue, onSelectOption, selectedOptions]);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
memoizedSelectedOptions();
|
|
80
|
+
}, [selectedOptions, inputValue, memoizedSelectedOptions]);
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (hasDefaultValue) {
|
|
83
|
+
setSelectedOptions([hasDefaultValue]);
|
|
84
|
+
setInputValue(value);
|
|
85
|
+
}
|
|
86
|
+
}, [hasDefaultValue, value]);
|
|
87
|
+
const styles = StyleSheet.create({
|
|
88
|
+
wrapper: {
|
|
89
|
+
width: '100%',
|
|
90
|
+
marginBottom: 10,
|
|
91
|
+
position: 'relative',
|
|
92
|
+
zIndex: isShowedDropdown ? 10 : 0,
|
|
93
|
+
},
|
|
94
|
+
wrapperInput: {
|
|
95
|
+
position: 'relative',
|
|
96
|
+
width: '100%',
|
|
97
|
+
marginBottom: 0,
|
|
98
|
+
marginTop: 18,
|
|
99
|
+
},
|
|
100
|
+
label: {
|
|
101
|
+
position: 'absolute',
|
|
102
|
+
color: isMoveLabel && !isDisabled ? primary.main : black.main,
|
|
103
|
+
fontSize: 16,
|
|
104
|
+
lineHeight: 19,
|
|
105
|
+
letterSpacing: 0,
|
|
106
|
+
left: 0,
|
|
107
|
+
fontWeight: isMoveLabel ? '600' : '400',
|
|
108
|
+
bottom: isMoveLabel ? 38 : 10,
|
|
109
|
+
},
|
|
110
|
+
input: {
|
|
111
|
+
width: '100%',
|
|
112
|
+
height: 38,
|
|
113
|
+
padding: 0,
|
|
114
|
+
fontSize: 16,
|
|
115
|
+
lineHeight: 19,
|
|
116
|
+
letterSpacing: 0,
|
|
117
|
+
borderBottomWidth: 1,
|
|
118
|
+
color: black.main,
|
|
119
|
+
borderBottomColor: isShowedDropdown ? primary.main : grey[200],
|
|
120
|
+
},
|
|
121
|
+
arrowIcon: {
|
|
122
|
+
position: 'absolute',
|
|
123
|
+
padding: 8,
|
|
124
|
+
right: 0,
|
|
125
|
+
bottom: 0,
|
|
126
|
+
zIndex: 1,
|
|
127
|
+
transform: [{ rotate: isArrowRotated }],
|
|
128
|
+
},
|
|
129
|
+
deleteIcon: {
|
|
130
|
+
position: 'absolute',
|
|
131
|
+
padding: 8,
|
|
132
|
+
right: 30,
|
|
133
|
+
bottom: 0,
|
|
134
|
+
zIndex: 1,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
return (<View style={styles.wrapper}>
|
|
138
|
+
<View style={styles.wrapperInput} {...props}>
|
|
139
|
+
{showDeleteIcon && <DeleteIcon style={styles.deleteIcon} onPress={handleResetOptions}/>}
|
|
140
|
+
<ChevronIcon style={styles.arrowIcon} color={isDisabled ? black.main : primary.main} onPress={handleCloseDropdown}/>
|
|
141
|
+
|
|
142
|
+
<Text style={styles.label}>{label}</Text>
|
|
143
|
+
<TextInput ref={inputRef} style={styles.input} value={inputValue} placeholder={isMoveLabel && placeholder} showSoftInputOnFocus={!isMulti && isSearchable} caretHidden={!isSearchable} keyboardType={keyboardType} editable={!isDisabled} onFocus={handleOnFocus} onChangeText={handleChange} {...inputProps}/>
|
|
144
|
+
</View>
|
|
145
|
+
|
|
146
|
+
<Dropdown isShowedDropdown={isShowedDropdown} filteredOptions={filteredOptions} selectedOptions={selectedOptions} noOptionsMessage={noOptionsMessage} optionStyles={optionStyles} callbackOption={handleSelectedOption} customOptionComponent={customOptionComponent}/>
|
|
147
|
+
</View>);
|
|
148
|
+
};
|
|
149
|
+
export default Select;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React, { EffectCallback, DependencyList, JSX } from 'react';
|
|
2
|
+
import { BottomSheetFlatListMethods, BottomSheetScrollViewMethods, BottomSheetScrollableProps } from '@gorhom/bottom-sheet';
|
|
3
|
+
import { FlatListProps, ScrollViewProps, ViewProps } from 'react-native';
|
|
4
|
+
interface BottomSheetFocusProps {
|
|
5
|
+
focusHook?: (effect: EffectCallback, deps?: DependencyList) => void;
|
|
6
|
+
}
|
|
7
|
+
type SwipeUpViewProps = ViewProps & BottomSheetFocusProps;
|
|
8
|
+
export declare const SwipeUpFlatList: React.ForwardRefExoticComponent<FlatListProps<unknown> & BottomSheetScrollableProps & React.RefAttributes<BottomSheetFlatListMethods>>;
|
|
9
|
+
export declare const SwipeUpScrollView: React.ForwardRefExoticComponent<ScrollViewProps & BottomSheetScrollableProps & React.RefAttributes<BottomSheetScrollViewMethods>>;
|
|
10
|
+
export declare const SwipeUpView: ({ children, ...props }: SwipeUpViewProps) => JSX.Element | null;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BottomSheetFlatList, BottomSheetScrollView, BottomSheetView, } from '@gorhom/bottom-sheet';
|
|
3
|
+
export const SwipeUpFlatList = React.forwardRef(({ data, renderItem, ...props }, ref) => {
|
|
4
|
+
if (!data || !data.length || !renderItem) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return <BottomSheetFlatList ref={ref} data={data} renderItem={renderItem} {...props}/>;
|
|
8
|
+
});
|
|
9
|
+
export const SwipeUpScrollView = React.forwardRef(({ children, ...props }, ref) => {
|
|
10
|
+
if (!children) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
return (<BottomSheetScrollView ref={ref} {...props}>
|
|
14
|
+
{children}
|
|
15
|
+
</BottomSheetScrollView>);
|
|
16
|
+
});
|
|
17
|
+
export const SwipeUpView = ({ children, ...props }) => {
|
|
18
|
+
if (!children) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return <BottomSheetView {...props}>{children}</BottomSheetView>;
|
|
22
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BottomSheetProps } from '@gorhom/bottom-sheet';
|
|
3
|
+
import { ViewStyle } from 'react-native';
|
|
4
|
+
export interface SwipeUpProps extends BottomSheetProps {
|
|
5
|
+
onChangeSnap?: () => void;
|
|
6
|
+
swipeWrapperStyle?: ViewStyle;
|
|
7
|
+
snapPosition?: number;
|
|
8
|
+
}
|
|
9
|
+
declare const SwipeUp: React.ForwardRefExoticComponent<SwipeUpProps & React.RefAttributes<import("@gorhom/bottom-sheet/lib/typescript/types").BottomSheetMethods>>;
|
|
10
|
+
export default SwipeUp;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import BottomSheet from '@gorhom/bottom-sheet';
|
|
3
|
+
const SwipeUp = React.forwardRef(({ children, snapPoints = ['100%'], snapPosition = 0, style, onChangeSnap, backgroundStyle, swipeWrapperStyle, ...props }, ref) => {
|
|
4
|
+
if (!children) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return (<BottomSheet ref={ref} snapPoints={snapPoints} index={snapPosition} onChange={onChangeSnap} style={style} containerStyle={backgroundStyle} backgroundStyle={swipeWrapperStyle} {...props}>
|
|
8
|
+
{children}
|
|
9
|
+
</BottomSheet>);
|
|
10
|
+
});
|
|
11
|
+
export default SwipeUp;
|
package/dist/index.d.ts
CHANGED
|
@@ -7,5 +7,11 @@ import Loading from './components/Loading';
|
|
|
7
7
|
import StatusChip from './components/StatusChip';
|
|
8
8
|
import Input from './components/Input';
|
|
9
9
|
import LoadingFullScreen from './components/LoadingFullScreen';
|
|
10
|
+
import Icon from './components/Icon';
|
|
11
|
+
import Select from './components/Select';
|
|
10
12
|
import { palette } from './theme/palette';
|
|
11
|
-
|
|
13
|
+
import RadioButton from './components/RadioButton';
|
|
14
|
+
import SwipeUp from './components/SwipeUp';
|
|
15
|
+
import { SwipeUpFlatList, SwipeUpScrollView, SwipeUpView } from './components/SwipeUp/childComponents';
|
|
16
|
+
import Carousel from './components/Carousel';
|
|
17
|
+
export { Text, Avatar, CheckBox, Icon, Image, Loading, Svg, StatusChip, Input, palette, LoadingFullScreen, RadioButton, Select, SwipeUp, SwipeUpFlatList, SwipeUpScrollView, SwipeUpView, Carousel, };
|
package/dist/index.js
CHANGED
|
@@ -7,5 +7,11 @@ import Loading from './components/Loading';
|
|
|
7
7
|
import StatusChip from './components/StatusChip';
|
|
8
8
|
import Input from './components/Input';
|
|
9
9
|
import LoadingFullScreen from './components/LoadingFullScreen';
|
|
10
|
+
import Icon from './components/Icon';
|
|
11
|
+
import Select from './components/Select';
|
|
10
12
|
import { palette } from './theme/palette';
|
|
11
|
-
|
|
13
|
+
import RadioButton from './components/RadioButton';
|
|
14
|
+
import SwipeUp from './components/SwipeUp';
|
|
15
|
+
import { SwipeUpFlatList, SwipeUpScrollView, SwipeUpView, } from './components/SwipeUp/childComponents';
|
|
16
|
+
import Carousel from './components/Carousel';
|
|
17
|
+
export { Text, Avatar, CheckBox, Icon, Image, Loading, Svg, StatusChip, Input, palette, LoadingFullScreen, RadioButton, Select, SwipeUp, SwipeUpFlatList, SwipeUpScrollView, SwipeUpView, Carousel, };
|