├── .gitignore ├── README.md ├── documents ├── Checkbox.md ├── Countdown.md ├── CurtainView.md ├── Dropdown.md ├── Hierarchy.md ├── Image.md ├── Modal.md ├── MultiSelect.md ├── Progress.md ├── TextInput.md └── Timer.md ├── index.ts ├── package.json └── src └── components ├── Button ├── index.tsx ├── styles.ts └── type.ts ├── Checkbox ├── icon │ ├── checkbox-check.png │ ├── checkbox-uncheck.png │ ├── radio-check.png │ └── radio-uncheck.png ├── index.tsx ├── styles.ts └── type.ts ├── CountDown ├── index.tsx ├── styles.ts └── type.ts ├── CurtainView ├── index.tsx ├── styles.ts └── type.ts ├── Dropdown ├── icon │ └── down.png ├── index.tsx ├── styles.ts └── type.ts ├── Hierarchy ├── index.tsx ├── styles.ts └── type.ts ├── Image ├── index.tsx └── type.ts ├── Modal ├── index.tsx ├── styles.ts └── type.ts ├── MultiSelect ├── icon │ └── down.png ├── index.tsx ├── styles.ts └── type.ts ├── Progress ├── index.tsx ├── styles.ts └── type.ts ├── StepProgress ├── icon │ └── check.png ├── index.tsx ├── styles.ts └── type.ts ├── Text ├── index.tsx └── type.ts ├── TextInput ├── icon │ ├── close.png │ ├── eye.png │ └── uneye.png ├── index.tsx ├── styles.ts └── type.ts ├── Timer ├── index.tsx ├── styles.ts └── type.ts ├── TooltipProgress ├── index.tsx ├── styles.ts └── type.ts ├── ZoomView ├── index.tsx └── type.ts └── setup.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # node.js 6 | # 7 | node_modules/ 8 | npm-debug.log 9 | yarn-error.log 10 | 11 | # Xcode 12 | # 13 | build/ 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata 23 | *.xccheckout 24 | *.moved-aside 25 | DerivedData 26 | *.hmap 27 | *.ipa 28 | *.xcuserstate 29 | project.xcworkspace 30 | 31 | # Android/IntelliJ 32 | # 33 | build/ 34 | .idea 35 | .gradle 36 | local.properties 37 | *.iml 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-utils-components -------------------------------------------------------------------------------- /documents/Checkbox.md: -------------------------------------------------------------------------------- 1 | ## Checkbox 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/checkbox.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | style | ViewStyle | No | | 9 | | fontFamily | String | No | | 10 | | labelStyle | TextStyle | No | | 11 | | label | String | No | | 12 | | type | 'checkbox' or 'radio'| No | | 13 | | check | Boolean | No | | 14 | | size | Number | No | | 15 | | color | String | No | | 16 | 17 | #### Example 18 | ```js 19 | import React, { useState } from 'react'; 20 | import { StyleSheet, View } from 'react-native'; 21 | import { Checkbox } from 'react-native-utils-components'; 22 | 23 | export interface Props { 24 | name?: string; 25 | } 26 | 27 | const CheckboxScreen: React.FC = _props => { 28 | const [checkbox1, setCheckbox1] = useState(false); 29 | const [checkbox2, setCheckbox2] = useState(false); 30 | const [checkbox3, setCheckbox3] = useState(false); 31 | const [checkbox4, setCheckbox4] = useState(false); 32 | 33 | return ( 34 | 35 | setCheckbox1(!checkbox1)} 39 | /> 40 | setCheckbox2(!checkbox2)} 45 | /> 46 | setCheckbox3(!checkbox3)} 53 | /> 54 | setCheckbox4(!checkbox4)} 61 | /> 62 | 63 | ); 64 | }; 65 | 66 | export default CheckboxScreen; 67 | 68 | const styles = StyleSheet.create({ 69 | container: { 70 | flex: 1, 71 | }, 72 | main: { 73 | flex: 1, 74 | justifyContent: 'center', 75 | alignItems: 'center', 76 | padding: 10, 77 | }, 78 | }); 79 | ``` -------------------------------------------------------------------------------- /documents/Countdown.md: -------------------------------------------------------------------------------- 1 | ## Countdown 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/countdown.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | start | ref.start() | Yes | | 9 | | pause | ref.pause() | Yes | | 10 | | resume | ref.resume() | Yes | | 11 | | stop | ref.stop() | Yes | | 12 | | seconds | Number | Yes | | 13 | | style | ViewStyle | No | | 14 | | fontFamily | String | No | | 15 | | textStyle | TextStyle | No | | 16 | | onTimes | (seconds) => void | No | | 17 | | onEnd | (seconds) => void | No | | 18 | 19 | #### Example 20 | ```js 21 | import { CButton } from 'components'; 22 | import React, { useRef, useEffect } from 'react'; 23 | import { StyleSheet, View } from 'react-native'; 24 | import { Countdown } from 'react-native-utils-components'; 25 | import { useScale } from 'react-native-utils-toolkit'; 26 | 27 | const { scale } = useScale; 28 | 29 | export interface Props { 30 | name: string; 31 | } 32 | 33 | const CountdownScreen: React.FC = _props => { 34 | const countdownRef: any = useRef(null); 35 | 36 | return ( 37 | 38 | {}} 44 | onEnd={() => { 45 | }} 46 | /> 47 | { 51 | countdownRef.current.start(); 52 | }} 53 | /> 54 | { 58 | countdownRef.current.pause(); 59 | }} 60 | /> 61 | { 65 | countdownRef.current.resume(); 66 | }} 67 | /> 68 | { 72 | countdownRef.current.stop(); 73 | }} 74 | /> 75 | 76 | ); 77 | }; 78 | 79 | export default CountdownScreen; 80 | 81 | const styles = StyleSheet.create({ 82 | container: { 83 | flex: 1, 84 | alignItems: 'center', 85 | padding: scale(20), 86 | }, 87 | timer: { 88 | marginVertical: scale(20), 89 | }, 90 | timerText: { 91 | fontSize: scale(22), 92 | }, 93 | button: { 94 | marginVertical: scale(5), 95 | backgroundColor: 'white', 96 | borderRadius: scale(24), 97 | width: scale(100), 98 | height: scale(50), 99 | }, 100 | }); 101 | ``` -------------------------------------------------------------------------------- /documents/CurtainView.md: -------------------------------------------------------------------------------- 1 | ## CurtainView 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/curtainview.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | show | Boolean | No | false | 9 | | style | ViewStyle | No | | 10 | | backgroundColor | String | No | transparent | 11 | | maxHeight | Number | Yes | | 12 | | position | 'top' or 'bottom' | No | 'top' | 13 | | renderHeader | () => JSX.Element | No | | 14 | | onShow | (status)=> void | No | | 15 | 16 | #### Example 17 | ```js 18 | import { COLORS } from 'config'; 19 | import React from 'react'; 20 | import { StyleSheet, View, SafeAreaView } from 'react-native'; 21 | import { CurtainView } from 'react-native-utils-components'; 22 | import AntDesign from 'react-native-vector-icons/AntDesign'; 23 | import { useScale } from 'react-native-utils-toolkit'; 24 | 25 | const { scale } = useScale; 26 | 27 | export interface Props { 28 | name?: string; 29 | } 30 | 31 | const CurtainScreen: React.FC = _props => { 32 | const _renderHeaderTop = () => { 33 | return ( 34 | 35 | 36 | 37 | ); 38 | }; 39 | 40 | const _renderHeaderBottom = () => { 41 | return ( 42 | 43 | 44 | 45 | ); 46 | }; 47 | 48 | return ( 49 | 50 | 56 | 57 | 58 | 59 | 60 | 61 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | ); 82 | }; 83 | 84 | export default CurtainScreen; 85 | 86 | const styles = StyleSheet.create({ 87 | container: { 88 | flex: 1, 89 | }, 90 | curtainView: { 91 | width: '100%', 92 | }, 93 | curtainContainer: { 94 | flex: 1, 95 | backgroundColor: COLORS.SECONDARY, 96 | }, 97 | row: { 98 | flex: 1, 99 | flexDirection: 'row', 100 | justifyContent: 'space-between', 101 | padding: scale(20), 102 | }, 103 | headerTop: { 104 | flex: 1, 105 | backgroundColor: 'transparent', 106 | justifyContent: 'center', 107 | alignItems: 'center', 108 | }, 109 | headerBottom: { 110 | flex: 1, 111 | backgroundColor: 'black', 112 | borderTopLeftRadius: scale(22), 113 | borderTopRightRadius: scale(22), 114 | justifyContent: 'center', 115 | alignItems: 'center', 116 | }, 117 | lineTop: { 118 | width: scale(40), 119 | height: scale(6), 120 | backgroundColor: COLORS.SECONDARY, 121 | }, 122 | lineBottom: { 123 | width: scale(40), 124 | height: scale(6), 125 | backgroundColor: 'white', 126 | }, 127 | }); 128 | ``` -------------------------------------------------------------------------------- /documents/Dropdown.md: -------------------------------------------------------------------------------- 1 | ## Dropdown 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/dropdown.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | data | Array | Yes | | 9 | | labelField | String | Yes | | 10 | | valueField | String | Yes | | 11 | | onChange | (item) => void | Yes | | 12 | | style | ViewStyle | No | | 13 | | fontFamily | String | No | | 14 | | labelStyle | TextStyle | No | | 15 | | textStyle | TextStyle | No | | 16 | | iconColor | String | No | | 17 | | activeColor | String | No | | 18 | | backgroundColor | String | No | | 19 | | headerStyle | ViewStyle | No | | 20 | | value | Item | No | | 21 | | label | String | No | | 22 | | placeholder | String | No | | 23 | | maxHeight | Number | No | | 24 | | search | Boolean | No | false | 25 | | searchStyle | ViewStyle | No | | 26 | | searchPlaceholder | String | No | | 27 | | textError | String | No | | 28 | | textErrorStyle | TextStyle | No | | 29 | | renderLeftIcon | () => JSX.Element | No | | 30 | | renderTickIcon | () => JSX.Element | No | | 31 | | renderHeader | () => JSX.Element | No | | 32 | 33 | #### Example 34 | ```js 35 | import React, { useState } from 'react'; 36 | import { StyleSheet, View } from 'react-native'; 37 | import { Dropdown } from 'react-native-utils-components'; 38 | import { useScale } from 'react-native-utils-toolkit'; 39 | import AntDesign from 'react-native-vector-icons/AntDesign'; 40 | 41 | const { scale } = useScale; 42 | const data = [ 43 | { label: 'Item 1', value: '1' }, 44 | { label: 'Item 2', value: '2' }, 45 | { label: 'Item 3', value: '3' }, 46 | { label: 'Item 4', value: '4' }, 47 | { label: 'Item 5', value: '5' }, 48 | { label: 'Item 6', value: '6' }, 49 | { label: 'Item 7', value: '7' }, 50 | { label: 'Item 8', value: '8' }, 51 | ]; 52 | 53 | export interface Props { 54 | name: string; 55 | } 56 | 57 | const DropdownScreen: React.FC = _props => { 58 | const [dropdown, setDropdown] = useState(null); 59 | const [dropdown1, setDropdown1] = useState(null); 60 | const [dropdown2, setDropdown2] = useState(null); 61 | 62 | return ( 63 | 64 | { 72 | setDropdown(item); 73 | }} 74 | /> 75 | 76 | { 85 | setDropdown1(item); 86 | }} 87 | renderLeftIcon={() => ( 88 | 94 | )} 95 | renderTickIcon={() => ( 96 | 102 | )} 103 | textError="Error" 104 | /> 105 | 106 | ( 121 | 127 | )} 128 | renderTickIcon={() => ( 129 | 135 | )} 136 | onChange={item => { 137 | setDropdown2(item); 138 | }} 139 | textError="Error" 140 | /> 141 | 142 | ); 143 | }; 144 | 145 | export default DropdownScreen; 146 | 147 | const styles = StyleSheet.create({ 148 | container: { 149 | flex: 1, 150 | padding: scale(20), 151 | }, 152 | dropdown: { 153 | marginTop: scale(20), 154 | backgroundColor: 'white', 155 | borderRadius: scale(12), 156 | padding: scale(12), 157 | }, 158 | dropdown2: { 159 | backgroundColor: 'transparent', 160 | borderBottomColor: 'gray', 161 | borderBottomWidth: scale(0.5), 162 | marginTop: scale(20), 163 | }, 164 | icon: { 165 | marginRight: scale(5), 166 | }, 167 | }); 168 | ``` -------------------------------------------------------------------------------- /documents/Hierarchy.md: -------------------------------------------------------------------------------- 1 | ## Hierarchy 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/hierarchy.png) 4 | 5 | #### Props 6 | 7 | | Props | Params | isRequire | default | 8 | | ------------------ | -------------------- | --------- | ---------------- | 9 | | data | Array | Yes | | 10 | | textField | String | Yes | | 11 | | childField | String | Yes | | 12 | | onSelect | ()=> void | Yes | | 13 | | buttonName | String | No | | 14 | | style | ViewStyle | No | | 15 | | fontFamily | String | No | | 16 | | buttonStyle | ViewStyle | No | | 17 | | buttonTextStyle | TextStyle | No | | 18 | | textStyle | TextStyle | No | | 19 | | iconColor | String | No | black | 20 | 21 | ### Example 22 | 23 | ```js 24 | import React from 'react'; 25 | import { StyleSheet, View } from 'react-native'; 26 | import { Hierarchy } from 'react-native-utils-components'; 27 | import { useScale } from 'react-native-utils-toolkit'; 28 | 29 | const { scale } = useScale; 30 | 31 | export interface Props { 32 | name: string; 33 | } 34 | 35 | const recursiveData = [ 36 | { 37 | shopReportName: 'HCM1', 38 | shopCode: '2MFHCM1', 39 | shopType: '2', 40 | shopId: 1, 41 | shopName: 'MobiFone HCM1', 42 | childs: [ 43 | { 44 | shopReportName: 'LQTĐ', 45 | shopCode: '2MFH10038', 46 | shopType: '3', 47 | shopId: 2, 48 | shopName: 'MBF Liên Quận Thủ Đức: Q.TĐ, Q.2, Q9, Q.Bình Thạnh', 49 | childs: [ 50 | { 51 | shopReportName: 'Q.TĐức', 52 | shopCode: 'HCM_TDU', 53 | shopType: '4', 54 | shopId: 3, 55 | shopName: 'Q.Thủ Đức', 56 | childs: [ 57 | { 58 | shopReportName: 'Q.BThạnh', 59 | shopCode: 'HCM_BTH', 60 | shopType: '4', 61 | shopId: 4, 62 | shopName: 'Q.Bình Thạnh', 63 | }, 64 | { 65 | shopReportName: 'Q.02', 66 | shopCode: 'HCM_002', 67 | shopType: '4', 68 | shopId: 5, 69 | shopName: 'Q.02', 70 | childs: [ 71 | { 72 | shopReportName: 'Q.09', 73 | shopCode: 'HCM_0099', 74 | shopType: '4', 75 | shopId: 7, 76 | shopName: 'Q.09', 77 | childs: [ 78 | { 79 | shopReportName: 'Q.09', 80 | shopCode: 'HCM_00999', 81 | shopType: '4', 82 | shopId: 7, 83 | shopName: 'Q.09', 84 | }, 85 | ], 86 | }, 87 | ], 88 | }, 89 | { 90 | shopReportName: 'Q.09', 91 | shopCode: 'HCM_0099999', 92 | shopType: '4', 93 | shopId: 8, 94 | shopName: 'Q.09', 95 | }, 96 | ], 97 | }, 98 | ], 99 | }, 100 | ], 101 | }, 102 | ]; 103 | 104 | const RecursiveScreen: React.FC = _props => { 105 | return ( 106 | 107 | { 114 | console.log(`Selected ${item.length} item`); 115 | }} 116 | /> 117 | 118 | ); 119 | }; 120 | 121 | export default RecursiveScreen; 122 | 123 | const styles = StyleSheet.create({ 124 | container: { 125 | flex: 1, 126 | padding: scale(20), 127 | }, 128 | text: { 129 | color: 'black' 130 | } 131 | }); 132 | ``` -------------------------------------------------------------------------------- /documents/Image.md: -------------------------------------------------------------------------------- 1 | ## Image 2 | 3 | #### Props 4 | | Props | Params | isRequire | default | 5 | | ------------------ | -------------------- | --------- | ---------------- | 6 | | source | ImageSourcePropType | No | | 7 | | width | Number | No | | 8 | | height | Number | No | | 9 | | background | Boolean | No | | 10 | | onSize | (size) => void | No | | 11 | -------------------------------------------------------------------------------- /documents/Modal.md: -------------------------------------------------------------------------------- 1 | ## Modal 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/modal.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | visible | Boolean | Yes | | 9 | | style | ViewStyle | No | | 10 | | headerStyle | ViewStyle | No | | 11 | | backgroundColor | String | No | | 12 | | transparent | Boolean | No | | 13 | | maxHeight | Number | No | | 14 | |supportedOrientations| Array | No | | 15 | | onRequestClose | () => void | No | | 16 | | renderHeader | () => JSX.Element | No | | 17 | 18 | #### Example 19 | ```js 20 | import React, { useState } from 'react'; 21 | import { CButton } from 'components'; 22 | import { StyleSheet, View } from 'react-native'; 23 | import { Modal } from 'react-native-utils-components'; 24 | import { useScale } from 'react-native-utils-toolkit'; 25 | 26 | const { scale } = useScale; 27 | 28 | export interface Props { 29 | name?: string; 30 | } 31 | 32 | const ModalScreen: React.FC = _props => { 33 | const [visible, setVisible] = useState(false); 34 | return ( 35 | 36 | { 40 | setVisible(!visible); 41 | }} 42 | /> 43 | setVisible(false)}> 54 | 55 | 56 | 57 | ); 58 | }; 59 | 60 | export default ModalScreen; 61 | 62 | const styles = StyleSheet.create({ 63 | container: { 64 | flex: 1, 65 | justifyContent: 'center', 66 | alignItems: 'center', 67 | }, 68 | button: { 69 | marginVertical: scale(5), 70 | backgroundColor: 'white', 71 | borderRadius: scale(24), 72 | width: scale(150), 73 | }, 74 | }); 75 | ``` -------------------------------------------------------------------------------- /documents/MultiSelect.md: -------------------------------------------------------------------------------- 1 | ## MultiSelect 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/multiselect.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | data | Array | Yes | | 9 | | labelField | String | Yes | | 10 | | valueField | String | Yes | | 11 | | onChange | (item) => void | Yes | | 12 | | style | ViewStyle | No | | 13 | | fontFamily | String | No | | 14 | | labelStyle | TextStyle | No | | 15 | | textStyle | TextStyle | No | | 16 | | iconColor | String | No | | 17 | | activeColor | String | No | | 18 | | backgroundColor | String | No | | 19 | | headerStyle | ViewStyle | No | | 20 | | value | Item | No | | 21 | | label | String | No | | 22 | | placeholder | String | No | | 23 | | maxHeight | Number | No | | 24 | | selectedStyle | ViewStyle | No | | 25 | | selectedTextStyle | TextStyle | No | | 26 | | search | Boolean | No | false | 27 | | searchStyle | ViewStyle | No | | 28 | | searchPlaceholder | String | No | | 29 | | textError | String | No | | 30 | | textErrorStyle | TextStyle | No | | 31 | | renderLeftIcon | () => JSX.Element | No | | 32 | | renderTickIcon | () => JSX.Element | No | | 33 | | renderHeader | () => JSX.Element | No | | 34 | 35 | #### Example 36 | ```js 37 | import { COLORS } from 'config'; 38 | import React, { useState } from 'react'; 39 | import { StyleSheet, View } from 'react-native'; 40 | import { MultiSelect } from 'react-native-utils-components'; 41 | import { useScale } from 'react-native-utils-toolkit'; 42 | import AntDesign from 'react-native-vector-icons/AntDesign'; 43 | 44 | const { scale } = useScale; 45 | const data = [ 46 | { label: 'Item 1', value: '1' }, 47 | { label: 'Item 2', value: '2' }, 48 | { label: 'Item 3', value: '3' }, 49 | { label: 'Item 4', value: '4' }, 50 | { label: 'Item 5', value: '5' }, 51 | { label: 'Item 6', value: '6' }, 52 | { label: 'Item 7', value: '7' }, 53 | { label: 'Item 8', value: '8' }, 54 | ]; 55 | 56 | export interface Props { 57 | name: string; 58 | } 59 | 60 | const MultiSelectScreen: React.FC = _props => { 61 | const [selected, setSelected] = useState([]); 62 | const [selected1, setSelected1] = useState([]); 63 | const [selected2, setSelected2] = useState([]); 64 | 65 | return ( 66 | 67 | { 75 | setSelected(item); 76 | console.log('selected', item); 77 | }} 78 | /> 79 | 80 | { 89 | setSelected1(item); 90 | console.log('selected', item); 91 | }} 92 | renderLeftIcon={() => ( 93 | 99 | )} 100 | renderTickIcon={() => ( 101 | 107 | )} 108 | /> 109 | 110 | ( 126 | 132 | )} 133 | renderTickIcon={() => ( 134 | 140 | )} 141 | onChange={item => { 142 | setSelected2(item); 143 | console.log('selected', item); 144 | }} 145 | /> 146 | 147 | ); 148 | }; 149 | 150 | export default MultiSelectScreen; 151 | 152 | const styles = StyleSheet.create({ 153 | container: { 154 | flex: 1, 155 | padding: scale(20), 156 | }, 157 | dropdown: { 158 | marginTop: scale(20), 159 | backgroundColor: 'white', 160 | borderRadius: scale(12), 161 | padding: scale(12), 162 | }, 163 | dropdown2: { 164 | backgroundColor: 'transparent', 165 | borderBottomColor: 'gray', 166 | borderBottomWidth: scale(0.5), 167 | marginTop: scale(20), 168 | }, 169 | icon: { 170 | marginRight: scale(5), 171 | }, 172 | }); 173 | ``` -------------------------------------------------------------------------------- /documents/Progress.md: -------------------------------------------------------------------------------- 1 | ## StepProgress, TooltipProgress, Progress 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/progress.png) 4 | 5 | #### StepProgress 6 | 7 | | Props | Params | isRequire | default | 8 | | ------------------ | -------------------- | --------- | ---------------- | 9 | | data | Array | Yes | | 10 | | style | ViewStyle | No | | 11 | | activeColor | String | No | #32C5FF | 12 | | inActiveColor | String | No | #C6CDD8 | 13 | | textColor | String | No | #C6CDD8 | 14 | | selectColor | String | No | #FF9900 | 15 | | textSize | Number | No | 16 | 16 | | fontFamily | String | No | | 17 | | selectIndex | Number | No | 0 | 18 | | onSelectIndex | (index)=> Void | No | | 19 | | iconTick | Path | No | | 20 | 21 | #### TooltipProgress 22 | 23 | | Props | Params | isRequire | default | 24 | | ------------------ | -------------------- | --------- | ---------------- | 25 | | data | Array | Yes | | 26 | | style | ViewStyle | No | | 27 | | tooltipStyle | ViewStyle | No | | 28 | | activeColor | String | No | #32C5FF | 29 | | inActiveColor | String | No | #C6CDD8 | 30 | | selectColor | String | No | #FF9900 | 31 | | textSize | Number | No | 16 | 32 | | fontFamily | String | No | | 33 | | selectIndex | Number | No | 0 | 34 | | onSelectIndex | (index)=> Void | No | | 35 | 36 | #### Progress 37 | 38 | | Props | Params | isRequire | default | 39 | | ------------------ | -------------------- | --------- | ---------------- | 40 | | data | Array | Yes | | 41 | | percent | Number | Yes | | 42 | | style | ViewStyle | No | | 43 | | height | String | No | 6 | 44 | | border | String | No | false | 45 | 46 | #### Example 47 | ```js 48 | import React, { useState } from 'react'; 49 | import { StyleSheet, Text, View } from 'react-native'; 50 | import { 51 | Progress, 52 | StepProgress, 53 | TooltipProgress, 54 | } from 'react-native-utils-components'; 55 | import { useScale } from 'react-native-utils-toolkit'; 56 | 57 | const ic_step1 = require('./icons/step1.png'); 58 | const ic_step2 = require('./icons/step2.png'); 59 | const ic_step3 = require('./icons/step3.png'); 60 | const ic_step4 = require('./icons/step4.png'); 61 | 62 | const { scale, fontScale } = useScale; 63 | 64 | const data = [ 65 | { text: 'Step 1', status: true }, 66 | { text: 'Step 2', status: true }, 67 | { text: 'Step 3', status: true }, 68 | { text: 'Step 4', status: false }, 69 | ]; 70 | const data2 = [ 71 | { text: 'Step 1', icon: ic_step1, status: true }, 72 | { text: 'Step 2', icon: ic_step2, status: true }, 73 | { text: 'Step 3', icon: ic_step3, status: true }, 74 | { text: 'Step 4', icon: ic_step4, status: false }, 75 | ]; 76 | const data3 = [ 77 | { stage: 'S1', text: 'Hello S1', status: true }, 78 | { stage: 'S2', text: 'Hello S2', status: true }, 79 | { stage: 'S3', text: 'Hello S3', status: true }, 80 | { stage: 'S4', text: 'Hello S4', status: false }, 81 | ]; 82 | const data4 = [ 83 | { icon: ic_step1, text: 'Hello S1', status: true }, 84 | { icon: ic_step2, text: 'Hello S2', status: true }, 85 | { icon: ic_step3, text: 'Hello S3', status: true }, 86 | { icon: ic_step4, text: 'Hello S4', status: false }, 87 | ]; 88 | 89 | export interface Props { 90 | name: string; 91 | } 92 | 93 | const ProgressScreen: React.FC = _props => { 94 | const [step, setStep] = useState(2); 95 | const [step2, setStep2] = useState(2); 96 | const [stage, setStage] = useState(2); 97 | const [stage2, setStage2] = useState(2); 98 | 99 | return ( 100 | 101 | 102 | Step Progress 103 | { 107 | setStep(index); 108 | }} 109 | activeColor="#32C5FF" 110 | inActiveColor="#C6CDD8" 111 | selectColor="#32C5FF" 112 | textColor="gray" 113 | textSize={15} 114 | /> 115 | 116 | { 121 | setStep2(index); 122 | }} 123 | activeColor='#F4A460' 124 | inActiveColor="#C6CDD8" 125 | selectColor='#F4A460' 126 | textColor="gray" 127 | textSize={scale(15)} 128 | /> 129 | 130 | 131 | 132 | Tooltip Progress 133 | { 140 | setStage(index); 141 | }} 142 | /> 143 | 144 | { 152 | setStage2(index); 153 | }} 154 | /> 155 | 156 | 157 | 158 | Progress 159 | 168 | 169 | 170 | ); 171 | }; 172 | 173 | export default ProgressScreen; 174 | 175 | const styles = StyleSheet.create({ 176 | container: { 177 | flex: 1, 178 | padding: scale(20), 179 | }, 180 | row: { 181 | marginVertical: scale(20), 182 | }, 183 | title: { 184 | fontSize: fontScale(18), 185 | marginBottom: scale(16), 186 | }, 187 | }); 188 | 189 | ``` -------------------------------------------------------------------------------- /documents/TextInput.md: -------------------------------------------------------------------------------- 1 | ## TextInput 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/textinput.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | value | String | No | | 9 | | label | String | No | | 10 | | style | ViewStyle | No | | 11 | | fontFamily | String | No | | 12 | | labelStyle | TextStyle | No | | 13 | | inputStyle | TextStyle | No | | 14 | | iconStyle | ImageStyle | No | | 15 | | textErrorStyle | TextStyle | No | | 16 | | showIcon | Boolean | No | true | 17 | | currency | Boolean | No | | 18 | | unitCurrency | String | No | | 19 | | numeric | Boolean | No | | 20 | | onChangeText | (text) => void | Yes | | 21 | | renderLeftIcon | () => JSX.Element | No | | 22 | | renderRightIcon | () => JSX.Element | No | | 23 | 24 | #### Example 25 | ```js 26 | import React from 'react'; 27 | import { StyleSheet, View } from 'react-native'; 28 | import { TextInput } from 'react-native-utils-components'; 29 | import { useScale } from 'react-native-utils-toolkit'; 30 | import AntDesign from 'react-native-vector-icons/AntDesign'; 31 | 32 | const { scale } = useScale; 33 | 34 | export interface Props { 35 | name: string; 36 | } 37 | 38 | const TextInputScreen: React.FC = _props => { 39 | return ( 40 | 41 | { 46 | console.log(text); 47 | }} 48 | /> 49 | 50 | { 57 | console.log(text); 58 | }} 59 | textError="Error" 60 | renderLeftIcon={() => ( 61 | 67 | )} 68 | iconStyle={{ tintColor: 'gray' }} 69 | /> 70 | 71 | { 79 | console.log(text); 80 | }} 81 | /> 82 | 83 | { 93 | console.log(text); 94 | }} 95 | renderLeftIcon={() => ( 96 | 102 | )} 103 | textError="Error" 104 | /> 105 | 106 | ); 107 | }; 108 | 109 | export default TextInputScreen; 110 | 111 | const styles = StyleSheet.create({ 112 | container: { 113 | flex: 1, 114 | padding: scale(20), 115 | }, 116 | textinput: { 117 | marginTop: scale(20), 118 | borderBottomWidth: scale(0.5), 119 | borderBottomColor: 'gray', 120 | }, 121 | textinput2: { 122 | marginTop: scale(20), 123 | backgroundColor: 'white', 124 | borderRadius: scale(8), 125 | padding: scale(12), 126 | }, 127 | icon: { 128 | marginRight: scale(5), 129 | }, 130 | }); 131 | ``` -------------------------------------------------------------------------------- /documents/Timer.md: -------------------------------------------------------------------------------- 1 | ## Timer 2 | #### Demo 3 | ![](https://github.com/hoaphantn7604/file-upload/blob/master/document/component/timer.png) 4 | 5 | #### Props 6 | | Props | Params | isRequire | default | 7 | | ------------------ | -------------------- | --------- | ---------------- | 8 | | start | ref.start() | Yes | | 9 | | pause | ref.pause() | Yes | | 10 | | resume | ref.resume() | Yes | | 11 | | stop | ref.stop() | Yes | | 12 | | style | ViewStyle | No | | 13 | | fontFamily | String | No | | 14 | | textStyle | TextStyle | No | | 15 | | onTimes | (seconds) => void | No | | 16 | | onEnd | (seconds) => void | No | | 17 | 18 | #### Example 19 | ```js 20 | import { CButton } from 'components'; 21 | import React, { useRef } from 'react'; 22 | import { StyleSheet, View } from 'react-native'; 23 | import { Timer } from 'react-native-utils-components'; 24 | import { useScale } from 'react-native-utils-toolkit'; 25 | 26 | const { scale } = useScale; 27 | 28 | export interface Props { 29 | name: string; 30 | } 31 | 32 | const TimerScreen: React.FC = _props => { 33 | const timerRef: any = useRef(null); 34 | 35 | return ( 36 | 37 | {}} 42 | onEnd={e => {}} 43 | /> 44 | { 48 | timerRef.current.start(); 49 | }} 50 | /> 51 | { 55 | timerRef.current.pause(); 56 | }} 57 | /> 58 | { 62 | timerRef.current.resume(); 63 | }} 64 | /> 65 | { 69 | timerRef.current.stop(); 70 | }} 71 | /> 72 | 73 | ); 74 | }; 75 | 76 | export default TimerScreen; 77 | 78 | const styles = StyleSheet.create({ 79 | container: { 80 | flex: 1, 81 | alignItems: 'center', 82 | padding: scale(20), 83 | }, 84 | timer: { 85 | marginVertical: scale(20), 86 | }, 87 | timerText: { 88 | fontSize: scale(22), 89 | }, 90 | button: { 91 | marginVertical: scale(5), 92 | backgroundColor: 'white', 93 | borderRadius: scale(24), 94 | width: scale(100), 95 | }, 96 | }); 97 | ``` -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import Hierarchy from './src/components/Hierarchy'; 2 | import Timer from './src/components/Timer'; 3 | import Countdown from './src/components/CountDown'; 4 | import StepProgress from './src/components/StepProgress'; 5 | import TooltipProgress from './src/components/TooltipProgress'; 6 | import Progress from './src/components/Progress'; 7 | import Dropdown from './src/components/Dropdown'; 8 | import TextInput from './src/components/TextInput'; 9 | import ZoomView from './src/components/ZoomView'; 10 | import Modal from './src/components/Modal'; 11 | import CurtainView from './src/components/CurtainView'; 12 | import MultiSelect from './src/components/MultiSelect'; 13 | import Checkbox from './src/components/Checkbox'; 14 | import Image from './src/components/Image'; 15 | import Text from './src/components/Text'; 16 | import Button from './src/components/Button'; 17 | 18 | export { 19 | Text, 20 | Button, 21 | Timer, 22 | Countdown, 23 | Hierarchy, 24 | StepProgress, 25 | TooltipProgress, 26 | Progress, 27 | Dropdown, 28 | MultiSelect, 29 | TextInput, 30 | ZoomView, 31 | Modal, 32 | CurtainView, 33 | Checkbox, 34 | Image 35 | }; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-utils-components", 3 | "title": "TODO", 4 | "version": "2.7.4", 5 | "description": "TODO", 6 | "main": "index.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/hoaphantn7604/react-native-utils-components.git", 13 | "baseUrl": "https://github.com/hoaphantn7604/react-native-utils-components" 14 | }, 15 | "keywords": [ 16 | "react-native" 17 | ], 18 | "author": { 19 | "name": "Hoa Phan", 20 | "email": "hoaphantn7604@gmail.com" 21 | }, 22 | "license": "MIT", 23 | "licenseFilename": "LICENSE", 24 | "readmeFilename": "README.md", 25 | "peerDependencies": { 26 | "react": ">=16.8.1", 27 | "react-native": ">=0.60.0-rc.0 <1.0.x" 28 | }, 29 | "devDependencies": { 30 | "react": "^16.9.0", 31 | "react-native": "^0.61.5" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/Button/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TouchableOpacity } from 'react-native'; 3 | import { useScale } from 'react-native-utils-toolkit'; 4 | import { styles } from './styles'; 5 | import { ButtonProps } from './type'; 6 | import Text from '../Text'; 7 | import { COLORS } from '../setup'; 8 | const { scale } = useScale; 9 | 10 | const defaultProps = { 11 | bgColor: '', 12 | style: {}, 13 | textColor: '', 14 | fontSize: null, 15 | border: false, 16 | onPress: () => { }, 17 | }; 18 | 19 | const ButtonComponent: ButtonProps = props => { 20 | const { 21 | fontSize, 22 | bgColor, 23 | style, 24 | textColor, 25 | title, 26 | onPress, 27 | border = false, 28 | } = props; 29 | if (border) { 30 | return ( 31 | 42 | 50 | {title} 51 | 52 | 53 | ); 54 | } 55 | return ( 56 | 63 | 69 | {title} 70 | 71 | 72 | ); 73 | }; 74 | 75 | ButtonComponent.defaultProps = defaultProps; 76 | 77 | export default ButtonComponent; 78 | -------------------------------------------------------------------------------- /src/components/Button/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | const { scale } = useScale; 4 | 5 | export const styles = StyleSheet.create({ 6 | container: { 7 | width: '100%', 8 | height: scale(40), 9 | justifyContent: 'center', 10 | alignItems: 'center', 11 | borderRadius: scale(5), 12 | paddingHorizontal: scale(10), 13 | flexDirection: 'row', 14 | }, 15 | text: { 16 | color: 'white', 17 | fontSize: scale(16), 18 | fontWeight: 'bold', 19 | marginLeft: scale(5), 20 | textAlign: 'center', 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /src/components/Button/type.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ViewStyle } from 'react-native'; 3 | 4 | interface Props { 5 | title?: string; 6 | textColor?: string; 7 | bgColor?: string; 8 | style?: ViewStyle; 9 | fontSize?: number | any; 10 | onPress?: () => void; 11 | border?: boolean; 12 | } 13 | 14 | export type ButtonProps = React.FC; 15 | -------------------------------------------------------------------------------- /src/components/Checkbox/icon/checkbox-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/Checkbox/icon/checkbox-check.png -------------------------------------------------------------------------------- /src/components/Checkbox/icon/checkbox-uncheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/Checkbox/icon/checkbox-uncheck.png -------------------------------------------------------------------------------- /src/components/Checkbox/icon/radio-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/Checkbox/icon/radio-check.png -------------------------------------------------------------------------------- /src/components/Checkbox/icon/radio-uncheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/Checkbox/icon/radio-uncheck.png -------------------------------------------------------------------------------- /src/components/Checkbox/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | TouchableWithoutFeedback, 4 | View, 5 | Image 6 | } from 'react-native'; 7 | import { Checkbox } from './type'; 8 | import { useScale } from 'react-native-utils-toolkit'; 9 | import { styles } from './styles'; 10 | import Text from '../Text'; 11 | 12 | const { scale, fontScale } = useScale; 13 | const checkbox_check = require('./icon/checkbox-check.png'); 14 | const checkbox_uncheck = require('./icon/checkbox-uncheck.png'); 15 | const radio_check = require('./icon/radio-check.png'); 16 | const radio_uncheck = require('./icon/radio-uncheck.png'); 17 | 18 | const defaultProps = { 19 | check: false, 20 | style: undefined, 21 | labelStyle: {}, 22 | color: 'black', 23 | label: undefined, 24 | onPress: () => { }, 25 | }; 26 | 27 | const CheckComponent: Checkbox = (props) => { 28 | const { 29 | style, 30 | size = 25, 31 | type = 'checkbox', 32 | color, 33 | check, 34 | label, 35 | labelStyle, 36 | fontFamily, 37 | onPress, 38 | } = props; 39 | 40 | const font = () => { 41 | if (fontFamily) { 42 | return { 43 | fontFamily: fontFamily 44 | } 45 | } else { 46 | return {} 47 | } 48 | } 49 | 50 | return ( 51 | 52 | 53 | 61 | {label && {label}} 62 | 63 | 64 | ); 65 | }; 66 | 67 | CheckComponent.defaultProps = defaultProps; 68 | 69 | export default CheckComponent; 70 | -------------------------------------------------------------------------------- /src/components/Checkbox/styles.ts: -------------------------------------------------------------------------------- 1 | import { 2 | StyleSheet 3 | } from 'react-native'; 4 | import { useScale } from 'react-native-utils-toolkit'; 5 | const { scale } = useScale; 6 | 7 | 8 | export const styles = StyleSheet.create({ 9 | container: { 10 | padding: scale(5), 11 | flexDirection: 'row', 12 | alignItems: 'center', 13 | }, 14 | text: { 15 | marginLeft: scale(10), 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /src/components/Checkbox/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, TextStyle, ViewStyle } from "react-native"; 2 | 3 | interface Props { 4 | 5 | style?: StyleProp; 6 | labelStyle?: StyleProp; 7 | fontFamily?: string; 8 | type?: 'checkbox' | 'radio'; 9 | label?: string; 10 | check?: boolean; 11 | size?: number; 12 | color?: string; 13 | onPress?: () => void; 14 | } 15 | 16 | export type Checkbox = React.FC 17 | -------------------------------------------------------------------------------- /src/components/CountDown/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useImperativeHandle, useState } from 'react'; 2 | import { View } from 'react-native'; 3 | import Text from '../Text'; 4 | import { styles } from './styles'; 5 | import { Props } from './type'; 6 | 7 | const defaulProps = { 8 | style: {}, 9 | textStyle: {}, 10 | onTimes: (seconds: number) => { }, 11 | onEnd: () => { } 12 | }; 13 | 14 | let interval: any = null; 15 | let hours = 0; 16 | let minute = 0; 17 | let seconds = 0; 18 | let currentSeconds = 0; 19 | 20 | const CountdownComponent = React.forwardRef((props: Props, ref) => { 21 | const { style, textStyle, fontFamily, onEnd, onTimes } = props; 22 | const [key, setKey] = useState(Math.random()); 23 | 24 | useImperativeHandle(ref, () => { 25 | return { start, pause, resume, stop }; 26 | }); 27 | 28 | useEffect(() => { 29 | init(); 30 | return () => { 31 | stop(); 32 | } 33 | }, []) 34 | 35 | const init = () => { 36 | if (props.seconds) { 37 | currentSeconds = props.seconds; 38 | hours = ~~(currentSeconds / 3600); 39 | minute = ~~((currentSeconds % 3600) / 60); 40 | seconds = ~~currentSeconds % 60; 41 | } 42 | clear(); 43 | setKey(Math.random()); 44 | } 45 | 46 | 47 | const timer = () => { 48 | interval = setInterval(() => { 49 | if (currentSeconds > 0) { 50 | currentSeconds = currentSeconds - 1; 51 | hours = ~~(currentSeconds / 3600); 52 | minute = ~~((currentSeconds % 3600) / 60); 53 | seconds = ~~currentSeconds % 60; 54 | 55 | if (onTimes) { 56 | onTimes(currentSeconds); 57 | } 58 | 59 | } 60 | if (currentSeconds <= 0) { 61 | if (onEnd) { 62 | onEnd(); 63 | } 64 | clear(); 65 | } 66 | setKey(Math.random()); 67 | }, 1000); 68 | }; 69 | 70 | const start = () => { 71 | init(); 72 | 73 | if (!interval) { 74 | timer(); 75 | } 76 | } 77 | 78 | const pause = () => { 79 | clear(); 80 | } 81 | 82 | const resume = () => { 83 | if (!interval) { 84 | timer(); 85 | } 86 | } 87 | 88 | const stop = () => { 89 | if (onEnd) { 90 | onEnd(); 91 | } 92 | 93 | init(); 94 | clear(); 95 | } 96 | 97 | const clear = () => { 98 | if (interval) { 99 | clearInterval(interval); 100 | interval = null; 101 | } 102 | } 103 | 104 | const font = () => { 105 | if (fontFamily) { 106 | return { 107 | fontFamily: fontFamily 108 | } 109 | } else { 110 | return {} 111 | } 112 | } 113 | 114 | return ( 115 | 116 | {`${hours}:${minute.toString().length === 1 ? '0' : ''}${minute}:${seconds.toString().length === 1 ? '0' : '' 117 | }${seconds}`} 118 | 119 | ); 120 | }); 121 | 122 | CountdownComponent.defaultProps = defaulProps; 123 | 124 | export default CountdownComponent; 125 | -------------------------------------------------------------------------------- /src/components/CountDown/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | export const styles = StyleSheet.create({ 5 | text: { 6 | fontSize: useScale.fontScale(20), 7 | color: 'black', 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /src/components/CountDown/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, TextStyle, ViewStyle } from 'react-native'; 2 | 3 | export interface Props { 4 | style?: StyleProp; 5 | textStyle?: StyleProp; 6 | fontFamily?: string; 7 | seconds: number; 8 | onTimes?: (seconds: number) => void 9 | onEnd?: () => void 10 | } 11 | -------------------------------------------------------------------------------- /src/components/CurtainView/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from 'react'; 2 | import { Easing, PanResponder, View } from 'react-native'; 3 | import { Animated } from 'react-native'; 4 | import { styles } from './styles'; 5 | import { CurtainView } from './type'; 6 | 7 | const CurtainViewComponent: CurtainView = props => { 8 | const { style, headerStyle, backgroundColor= 'transparent', maxHeight = 180, renderHeader, position = 'top', show = false, onShow } = props; 9 | const minHeight = 0; 10 | const [viewHeight] = useState(new Animated.Value(minHeight)); 11 | let currentHeight = 0; 12 | 13 | useEffect(() => { 14 | if (show) { 15 | checkshow(show); 16 | } 17 | }, [show]) 18 | 19 | const checkshow = (status: boolean) => { 20 | Animated.timing(viewHeight, { 21 | toValue: status ? maxHeight : minHeight, 22 | duration: 180, 23 | easing: Easing.linear, 24 | useNativeDriver: false, 25 | }).start(() => { currentHeight = status ? maxHeight : minHeight }); 26 | }; 27 | 28 | const handlerShow = (status: boolean) => { 29 | if (onShow) { 30 | onShow(status); 31 | } 32 | } 33 | 34 | const panResponder = useRef( 35 | PanResponder.create({ 36 | onStartShouldSetPanResponder: (evt, gestureState) => { 37 | return true; 38 | }, 39 | onPanResponderEnd: (evt, gestureState) => { 40 | return true; 41 | }, 42 | onMoveShouldSetPanResponder: () => true, 43 | onPanResponderMove: (evt, gestureState) => { 44 | const { dy } = gestureState; 45 | 46 | if (position === 'top') { 47 | if (dy > 0) { 48 | if (currentHeight < maxHeight) { 49 | currentHeight = dy; 50 | } 51 | } else { 52 | currentHeight = maxHeight + dy; 53 | } 54 | } else { 55 | if (dy < 0) { 56 | if (currentHeight < maxHeight) { 57 | currentHeight = minHeight - dy; 58 | } 59 | } else { 60 | currentHeight = maxHeight - dy; 61 | } 62 | } 63 | 64 | if (currentHeight < maxHeight && currentHeight > 0) { 65 | Animated.timing(viewHeight, { 66 | toValue: currentHeight, 67 | duration: 80, 68 | easing: Easing.linear, 69 | useNativeDriver: false, 70 | }).start(() => { }); 71 | } 72 | }, 73 | onPanResponderRelease: (evt, gestureState) => { 74 | const { dy } = gestureState; 75 | if (dy !== 0) { 76 | if (position === 'top') { 77 | if (dy > 0) { 78 | Animated.timing(viewHeight, { 79 | toValue: maxHeight, 80 | duration: 180, 81 | easing: Easing.linear, 82 | useNativeDriver: false, 83 | }).start(() => { 84 | currentHeight = maxHeight; 85 | handlerShow(true); 86 | }); 87 | } else { 88 | Animated.timing(viewHeight, { 89 | toValue: minHeight, 90 | duration: 180, 91 | easing: Easing.linear, 92 | useNativeDriver: false, 93 | }).start(() => { 94 | currentHeight = minHeight; 95 | handlerShow(false); 96 | }); 97 | } 98 | } else { 99 | if (dy < 0) { 100 | Animated.timing(viewHeight, { 101 | toValue: maxHeight, 102 | duration: 180, 103 | easing: Easing.linear, 104 | useNativeDriver: false, 105 | }).start(() => { 106 | currentHeight = maxHeight; 107 | handlerShow(true); 108 | }); 109 | } else { 110 | Animated.timing(viewHeight, { 111 | toValue: minHeight, 112 | duration: 180, 113 | easing: Easing.linear, 114 | useNativeDriver: false, 115 | }).start(() => { 116 | currentHeight = minHeight; 117 | handlerShow(false); 118 | }); 119 | } 120 | } 121 | } 122 | }, 123 | }), 124 | ).current; 125 | 126 | const _renderTop = () => { 127 | return ( 128 | 129 | 134 | {props?.children} 135 | 136 | 137 | {renderHeader ? renderHeader() : } 138 | 139 | 140 | ); 141 | }; 142 | 143 | const _renderBottom = () => { 144 | return ( 145 | 146 | 147 | {renderHeader ? renderHeader() : } 148 | 149 | 154 | {props?.children} 155 | 156 | 157 | ); 158 | }; 159 | 160 | if (position === 'top') { 161 | return _renderTop(); 162 | } 163 | return _renderBottom(); 164 | }; 165 | 166 | export default CurtainViewComponent; 167 | -------------------------------------------------------------------------------- /src/components/CurtainView/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | const { scale } = useScale; 5 | 6 | export const styles = StyleSheet.create({ 7 | containerTop: {}, 8 | containerBottom: { 9 | justifyContent: 'flex-end', 10 | }, 11 | header: { 12 | backgroundColor: '#BBBBBB', 13 | height: scale(40), 14 | justifyContent: 'center', 15 | }, 16 | pan: { 17 | width: scale(40), 18 | height: scale(5), 19 | borderRadius: scale(5), 20 | backgroundColor: 'white', 21 | alignSelf: 'center', 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/CurtainView/type.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, ViewStyle } from 'react-native'; 3 | 4 | interface Props { 5 | style?: StyleProp; 6 | headerStyle?: StyleProp; 7 | backgroundColor?: string; 8 | maxHeight: number; 9 | position?: 'top' | 'bottom'; 10 | show?: boolean; 11 | renderHeader?: () => JSX.Element; 12 | onShow?: (status: boolean)=> void; 13 | } 14 | 15 | export type CurtainView = React.FC; 16 | -------------------------------------------------------------------------------- /src/components/Dropdown/icon/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/Dropdown/icon/down.png -------------------------------------------------------------------------------- /src/components/Dropdown/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { 3 | FlatList, 4 | Image, 5 | TouchableOpacity, 6 | TouchableWithoutFeedback, 7 | View, 8 | SafeAreaView 9 | } from 'react-native'; 10 | import Text from '../Text'; 11 | import { styles } from './styles'; 12 | import { Dropdown } from './type'; 13 | import CModal from '../Modal'; 14 | import CInput from '../TextInput'; 15 | import { useScale } from 'react-native-utils-toolkit'; 16 | 17 | const { scale } = useScale; 18 | 19 | const ic_down = require('./icon/down.png'); 20 | 21 | const defaultProps = { 22 | placeholder: 'Select item', 23 | activeColor: '#F6F7F8', 24 | backgroundColor: 'white', 25 | data: [], 26 | style: {}, 27 | } 28 | 29 | const DropdownComponent: Dropdown = (props) => { 30 | 31 | const { 32 | onChange, 33 | data, 34 | label, 35 | value, 36 | style, 37 | labelField, 38 | valueField, 39 | textErrorStyle, 40 | activeColor, 41 | backgroundColor, 42 | fontFamily, 43 | textStyle, 44 | textError, 45 | iconColor, 46 | headerStyle, 47 | labelStyle, 48 | searchStyle, 49 | searchPlaceholder, 50 | placeholder, 51 | maxHeight = scale(400), 52 | search = false, 53 | renderTickIcon, 54 | renderLeftIcon, 55 | renderHeader 56 | } = props; 57 | 58 | const [visible, setVisible] = useState(false); 59 | const [currentValue, setCurrentValue] = useState(null); 60 | const [textSearch, setTextSearch] = useState(''); 61 | const [listData, setListData] = useState(data); 62 | 63 | useEffect(() => { 64 | getValue(); 65 | }, []); 66 | 67 | const font = () => { 68 | if (fontFamily) { 69 | return { 70 | fontFamily: fontFamily 71 | } 72 | } else { 73 | return {} 74 | } 75 | } 76 | 77 | const showOrClose = () => { 78 | setVisible(!visible); 79 | } 80 | 81 | const scrollToIndex = (ref: any) => { 82 | if(textSearch.length === 0){ 83 | const index = data.findIndex(e => value === e[valueField]); 84 | if (index !== -1 && ref) { 85 | setTimeout(() => { 86 | ref.scrollToIndex({ index: index, animated: true }) 87 | }, 300); 88 | } 89 | } 90 | } 91 | 92 | const getValue = () => { 93 | const getItem = data.filter(e => value === e[valueField]); 94 | if (getItem.length > 0) { 95 | setCurrentValue((e: any) => e = getItem[0]); 96 | } 97 | } 98 | 99 | const onSelect = (item: any) => { 100 | onSearch(''); 101 | setCurrentValue((e: any) => e = item); 102 | onChange(item[valueField]); 103 | setVisible(false); 104 | } 105 | 106 | const _renderTitle = () => { 107 | if (label) { 108 | return ( 109 | 110 | {label} 111 | 112 | ) 113 | } 114 | } 115 | 116 | const _renderDropdown = () => { 117 | return ( 118 | 119 | 120 | {renderLeftIcon?.()} 121 | 122 | {currentValue && currentValue[labelField] || placeholder} 123 | 124 | 125 | 126 | 127 | ) 128 | } 129 | 130 | const renderItem = ({ item, index }: { item: any; index: number }) => { 131 | return ( 132 | onSelect(item)}> 133 | 134 | {item[labelField]} 136 | {item[valueField] === (currentValue && currentValue[valueField]) && 137 | renderTickIcon?.() 138 | } 139 | 140 | 141 | ); 142 | }; 143 | 144 | const onSearch = (text: string) => { 145 | setTextSearch(text); 146 | if (text.length > 0) { 147 | const dataSearch = data.filter(e => { 148 | const item = e[labelField].toLowerCase().replace(' ', ''); 149 | const key = text.toLowerCase().replace(' ', ''); 150 | 151 | return item.indexOf(key) >= 0 152 | }); 153 | setListData(dataSearch); 154 | } else { 155 | setListData(data); 156 | } 157 | } 158 | 159 | const _renderList = () => { 160 | return 161 | {search && } 169 | scrollToIndex(e)} 171 | data={listData} 172 | renderItem={renderItem} 173 | keyExtractor={(item, index) => index.toString()} 174 | showsVerticalScrollIndicator={false} 175 | /> 176 | 177 | } 178 | 179 | const _header = () => { 180 | return ( 181 | 182 | 183 | ) 184 | } 185 | 186 | const _renderModal = () => { 187 | if (visible) { 188 | return renderHeader ? renderHeader() : _header()} 196 | supportedOrientations={['landscape', 'portrait']} 197 | > 198 | {_renderList()} 199 | 200 | } 201 | return null 202 | } 203 | 204 | return ( 205 | 206 | 207 | {_renderTitle()} 208 | {_renderDropdown()} 209 | {_renderModal()} 210 | 211 | {textError && {textError}} 212 | 213 | ); 214 | }; 215 | 216 | DropdownComponent.defaultProps = defaultProps; 217 | 218 | export default DropdownComponent; 219 | 220 | -------------------------------------------------------------------------------- /src/components/Dropdown/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | const { scale, fontScale } = useScale; 5 | 6 | export const styles = StyleSheet.create({ 7 | container: { 8 | backgroundColor: 'white', 9 | borderRadius: scale(8), 10 | padding: scale(12), 11 | justifyContent: 'center' 12 | }, 13 | main: { 14 | flex: 1, 15 | backgroundColor: 'rgba(0,0,0,0.6)', 16 | }, 17 | modalContent: { 18 | backgroundColor: 'white', 19 | width: '100%', 20 | borderTopLeftRadius: scale(16), 21 | borderTopRightRadius: scale(16), 22 | }, 23 | header: { 24 | height: scale(40), 25 | width: '100%', 26 | borderTopLeftRadius: scale(16), 27 | borderTopRightRadius: scale(16), 28 | justifyContent: 'center', 29 | alignItems: 'center', 30 | borderBottomWidth: scale(0.3), 31 | borderBottomColor: '#DDDDDD', 32 | backgroundColor: 'white' 33 | }, 34 | pan:{ 35 | width: scale(40), 36 | height: scale(6), 37 | borderRadius: scale(6), 38 | backgroundColor: '#DDDDDD' 39 | }, 40 | closeIcon: { 41 | width: scale(45), 42 | height: scale(45), 43 | alignItems: 'center', 44 | justifyContent: 'center', 45 | }, 46 | dropdown: { 47 | flexDirection: 'row', 48 | justifyContent: 'space-between', 49 | alignItems: 'center', 50 | height: scale(35) 51 | }, 52 | title: { 53 | marginVertical: scale(5), 54 | fontSize: fontScale(16) 55 | }, 56 | list: { 57 | maxHeight: scale(300) 58 | }, 59 | item: { 60 | padding: scale(17), 61 | flexDirection: 'row', 62 | justifyContent: 'space-between', 63 | alignItems: 'center' 64 | }, 65 | textItem: { 66 | flex:1, 67 | fontSize: fontScale(16) 68 | }, 69 | icon: { 70 | width: scale(24), 71 | height: scale(24), 72 | }, 73 | textError: { 74 | color: 'red', 75 | fontSize: fontScale(14), 76 | marginTop: scale(10) 77 | }, 78 | input: { 79 | borderWidth: scale(0.5), 80 | borderColor: '#DDDDDD', 81 | borderRadius: scale(12), 82 | margin: scale(8), 83 | paddingHorizontal: scale(8), 84 | }, 85 | }); 86 | -------------------------------------------------------------------------------- /src/components/Dropdown/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, TextStyle, ViewStyle } from 'react-native'; 2 | 3 | interface Props { 4 | style?: StyleProp; 5 | labelStyle?: StyleProp; 6 | textStyle?: StyleProp; 7 | headerStyle?: StyleProp; 8 | textErrorStyle?: StyleProp; 9 | searchStyle?: StyleProp; 10 | fontFamily?: string; 11 | backgroundColor?: string; 12 | iconColor?: string 13 | activeColor?: string 14 | data: any[]; 15 | value?: any | null; 16 | textError?: string; 17 | label?: string; 18 | placeholder?: string; 19 | labelField: string; 20 | valueField: string; 21 | maxHeight?: number; 22 | search?: boolean; 23 | searchPlaceholder?: string 24 | onChange: (item: any) => void; 25 | renderLeftIcon?: () => JSX.Element | null | undefined; 26 | renderTickIcon?: () => JSX.Element | null | undefined; 27 | renderHeader?: () => JSX.Element; 28 | } 29 | 30 | export type Dropdown = React.FC 31 | -------------------------------------------------------------------------------- /src/components/Hierarchy/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { FlatList, TouchableOpacity, View } from 'react-native'; 3 | import Text from '../Text'; 4 | import { useDetectDevice, useScale } from 'react-native-utils-toolkit'; 5 | import { styles } from './styles'; 6 | import { Hierarchy } from './type'; 7 | 8 | const { scale } = useScale; 9 | const {isAndroid, isIOS} = useDetectDevice; 10 | 11 | const defaultProps = { 12 | style: {}, 13 | textStyle: {}, 14 | buttonStyle: {}, 15 | buttonTextStyle: {}, 16 | iconColor: 'black' 17 | } 18 | 19 | let selectItem: any = []; 20 | 21 | const HierarchyComponent: Hierarchy = (props) => { 22 | const { 23 | data, 24 | textField, 25 | childField, 26 | style, 27 | textStyle, 28 | fontFamily, 29 | buttonStyle, 30 | buttonTextStyle, 31 | iconColor, 32 | } = props; 33 | 34 | const [listData] = useState(data); 35 | const [key, setKey] = useState(Math.random()); 36 | 37 | const parent = (item: any) => { 38 | if (item && item[childField]) { 39 | const check = item[childField].filter((child: any) => !child.tick); 40 | if (check.length === 0) { 41 | item.tick = true; 42 | } else { 43 | item.tick = false; 44 | } 45 | parent(item.parent); 46 | reload(); 47 | } 48 | }; 49 | 50 | const onTick = (item: any) => { 51 | item.tick = true; 52 | parent(item.parent); 53 | if (item[childField]) { 54 | item[childField].map((child: any) => onTick(child)); 55 | } 56 | reload(); 57 | }; 58 | 59 | const onUnTick = (item: any) => { 60 | item.tick = false; 61 | parent(item.parent); 62 | if (item[childField]) { 63 | item[childField].map((child: any) => onUnTick(child)); 64 | } 65 | reload(); 66 | }; 67 | 68 | const showChild = (item: any) => { 69 | item.show = !item.show; 70 | reload(); 71 | }; 72 | 73 | const reload = () => { 74 | setKey(Math.random()); 75 | selectItem = []; 76 | selectItemTick(listData); 77 | }; 78 | 79 | const selectItemTick = (data: any) => { 80 | data.map((item: any) => { 81 | if (item.tick) { 82 | selectItem.push(item); 83 | } 84 | if (item[childField]) { 85 | selectItemTick(item[childField]); 86 | } 87 | }); 88 | }; 89 | 90 | useEffect(() => { 91 | if(!props?.buttonName){ 92 | props.onSelect(selectItem); 93 | } 94 | 95 | }, [selectItem]); 96 | 97 | const font = () => { 98 | if (fontFamily) { 99 | return { 100 | fontFamily: fontFamily 101 | } 102 | } else { 103 | return {} 104 | } 105 | } 106 | 107 | const renderList = (item: any, childs: any, index: number) => { 108 | if (!item.show) { 109 | item.show = false; 110 | } 111 | if (!item.tick) { 112 | item.tick = false; 113 | } 114 | return ( 115 | 116 | 117 | {childs && childs.length > 0 ? ( 118 | { 120 | showChild(item); 121 | }}> 122 | {item.show ? '-' : '+'} 123 | 124 | ) : {` `}} 125 | { 128 | if (!item.tick) { 129 | onTick(item); 130 | } else { 131 | onUnTick(item); 132 | } 133 | }}> 134 | 135 | {item.tick ? : } 136 | {item[textField]} 137 | 138 | 139 | 140 | 141 | {childs && 142 | childs.map((data: any, index: number) => { 143 | if (!data.parent) { 144 | data.parent = item; 145 | } 146 | return renderList(data, data[childField], index); 147 | })} 148 | 149 | 150 | ); 151 | }; 152 | 153 | return ( 154 | 155 | renderList(item, item[childField], index)} 158 | keyExtractor={(item, index) => index.toString()} 159 | showsVerticalScrollIndicator={false} 160 | extraData={key} 161 | /> 162 | {props?.buttonName ? { 163 | props.onSelect(selectItem); 164 | }}> 165 | {props.buttonName} 166 | : null} 167 | 168 | ); 169 | }; 170 | 171 | HierarchyComponent.defaultProps = defaultProps; 172 | 173 | export default HierarchyComponent; 174 | 175 | 176 | -------------------------------------------------------------------------------- /src/components/Hierarchy/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | const { scale, fontScale } = useScale; 5 | 6 | export const styles = StyleSheet.create({ 7 | container: { 8 | marginLeft: - scale(20) 9 | }, 10 | item: { 11 | marginLeft: scale(30), 12 | }, 13 | rowItem: { 14 | flexDirection: 'row', 15 | marginHorizontal: scale(5), 16 | alignItems: 'center', 17 | }, 18 | center: { 19 | flexDirection: 'row', 20 | alignItems: 'center', 21 | }, 22 | showIcon: { 23 | fontSize: scale(30), 24 | marginBottom: scale(5), 25 | width: scale(15), 26 | }, 27 | name: { 28 | fontSize: fontScale(16), 29 | flex: 1 30 | }, 31 | tick: { 32 | marginHorizontal: scale(13), 33 | fontSize: scale(25), 34 | }, 35 | unTick: { 36 | marginHorizontal: scale(13), 37 | fontSize: scale(30), 38 | marginTop: 3 39 | }, 40 | btn: { 41 | alignSelf: 'center', 42 | alignItems: 'center', 43 | justifyContent: 'center', 44 | backgroundColor: 'black', 45 | borderRadius: scale(24), 46 | marginTop: scale(10), 47 | padding: scale(14) 48 | }, 49 | btnName: { 50 | fontSize: fontScale(20), 51 | color: 'white', 52 | fontWeight: 'bold', 53 | }, 54 | }); -------------------------------------------------------------------------------- /src/components/Hierarchy/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, TextStyle, ViewStyle } from 'react-native'; 2 | 3 | interface Props { 4 | style?: StyleProp; 5 | buttonStyle?: StyleProp; 6 | buttonTextStyle?: StyleProp; 7 | textStyle: StyleProp; 8 | fontFamily?: string; 9 | iconColor: string; 10 | data: any[]; 11 | textField: string; 12 | childField: string; 13 | buttonName?: string; 14 | onSelect: (data: any) => void; 15 | } 16 | 17 | export type Hierarchy = React.FC 18 | -------------------------------------------------------------------------------- /src/components/Image/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef, useState } from 'react'; 2 | import { Image, ImageBackground } from 'react-native'; 3 | import { PropsImage } from './type'; 4 | 5 | const resolveAssetSource = Image.resolveAssetSource; 6 | 7 | const CImage: PropsImage = props => { 8 | const { style, onSize, background } = props; 9 | const [autoWidth, setAutoWidth] = useState(null); 10 | const [autoHeight, setAutoHeight] = useState(null); 11 | const mounted = useRef(false); 12 | 13 | useEffect(() => { 14 | mounted.current = true; 15 | 16 | return () => { 17 | mounted.current = false; 18 | }; 19 | }, []); 20 | 21 | useEffect(() => { 22 | onProps(props); 23 | }); 24 | 25 | const onProps = (localProps: any) => { 26 | const { source } = localProps; 27 | if (source.uri) { 28 | const sourceToUse = source.uri ? source.uri : source; 29 | 30 | Image.getSize( 31 | sourceToUse, 32 | (width, height) => adjustSize(width, height, props), 33 | console.log, 34 | ); 35 | } else { 36 | const sourceToUse = resolveAssetSource(source); 37 | adjustSize(sourceToUse.width, sourceToUse.height, props); 38 | } 39 | }; 40 | 41 | const adjustSize = ( 42 | sourceWidth: number, 43 | sourceHeight: number, 44 | localProps: any, 45 | ) => { 46 | const { width, height } = localProps; 47 | 48 | let ratio = 1; 49 | 50 | if (width && height) { 51 | ratio = Math.min(width / sourceWidth, height / sourceHeight); 52 | } else if (width) { 53 | ratio = width / sourceWidth; 54 | } else if (height) { 55 | ratio = height / sourceHeight; 56 | } 57 | 58 | if (mounted.current) { 59 | const ratioWidth = sourceWidth * ratio; 60 | const ratioHeight = sourceHeight * ratio; 61 | 62 | setAutoWidth(ratioWidth); 63 | setAutoHeight(ratioHeight); 64 | if (onSize) { 65 | onSize({ width: ratioWidth, height: ratioHeight }); 66 | } 67 | } 68 | }; 69 | 70 | if (autoWidth && autoHeight) { 71 | if (background) { 72 | return ; 76 | } 77 | return 78 | } 79 | return null; 80 | }; 81 | 82 | CImage.defaultProps = { 83 | background: false, 84 | onSize: size => { }, 85 | }; 86 | 87 | export default CImage; 88 | -------------------------------------------------------------------------------- /src/components/Image/type.ts: -------------------------------------------------------------------------------- 1 | import { ImageBackgroundProps } from 'react-native'; 2 | import React from 'react'; 3 | 4 | interface onSize { 5 | width: number; 6 | height: number; 7 | } 8 | 9 | interface Props extends ImageBackgroundProps { 10 | height?: number; 11 | width?: number; 12 | background?: boolean; 13 | onSize?: (size: onSize) => void; 14 | } 15 | 16 | export type PropsImage = React.FC; 17 | -------------------------------------------------------------------------------- /src/components/Modal/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | Modal, 4 | View 5 | } from 'react-native'; 6 | import { useDetectDevice } from 'react-native-utils-toolkit'; 7 | import CurtainView from '../CurtainView'; 8 | import { CModal } from './type'; 9 | 10 | const { height: h } = useDetectDevice; 11 | 12 | const defaultProps = { 13 | visible: false, 14 | transparent: false, 15 | height: h / 2, 16 | styles: {}, 17 | headerStyle: {}, 18 | backgroundColor: 'white', 19 | }; 20 | 21 | const ModalComponent: CModal = props => { 22 | const { 23 | visible, 24 | maxHeight = h / 2, 25 | onRequestClose, 26 | style, 27 | backgroundColor, 28 | headerStyle, 29 | renderHeader, 30 | } = props; 31 | 32 | return ( 33 | 38 | 47 | { 55 | if(!status){ 56 | if (onRequestClose) { 57 | onRequestClose(); 58 | } 59 | } 60 | }} 61 | >{props?.children} 62 | 63 | 64 | 65 | ); 66 | }; 67 | 68 | ModalComponent.defaultProps = defaultProps; 69 | export default ModalComponent; 70 | -------------------------------------------------------------------------------- /src/components/Modal/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | const { scale } = useScale; 5 | 6 | export const styles = StyleSheet.create({ 7 | container: { 8 | flex: 1, 9 | }, 10 | main: { 11 | flex: 1, 12 | justifyContent: 'center', 13 | alignItems: 'center', 14 | padding: scale(10), 15 | }, 16 | header: { 17 | width: '100%', 18 | backgroundColor: 'gray', 19 | height: scale(40), 20 | }, 21 | pan: { 22 | width: scale(40), 23 | height: scale(5), 24 | borderRadius: scale(5), 25 | backgroundColor: 'white', 26 | alignSelf: 'center', 27 | marginTop: scale(12), 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /src/components/Modal/type.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { StyleProp, ModalProps, ViewStyle } from 'react-native'; 3 | 4 | export interface Props extends ModalProps { 5 | visible: boolean; 6 | style?: StyleProp; 7 | headerStyle?: StyleProp; 8 | backgroundColor?: string; 9 | transparent?: boolean; 10 | maxHeight?: number; 11 | supportedOrientations?: Array< 12 | 'portrait' | 'portrait-upside-down' | 'landscape' | 'landscape-left' | 'landscape-right' 13 | >; 14 | onRequestClose?: () => void; 15 | renderHeader?: () => JSX.Element; 16 | } 17 | 18 | export type CModal = React.FC; 19 | -------------------------------------------------------------------------------- /src/components/MultiSelect/icon/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/MultiSelect/icon/down.png -------------------------------------------------------------------------------- /src/components/MultiSelect/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { 3 | FlatList, 4 | Image, 5 | TouchableOpacity, 6 | TouchableWithoutFeedback, 7 | View, 8 | SafeAreaView 9 | } from 'react-native'; 10 | import Text from '../Text'; 11 | import { styles } from './styles'; 12 | import { MultiSelect } from 'react-native-utils-components/src/components/MultiSelect/type'; 13 | import CModal from 'react-native-utils-components/src/components/Modal'; 14 | import CInput from 'react-native-utils-components/src/components/TextInput'; 15 | import { useScale } from 'react-native-utils-toolkit'; 16 | 17 | const { scale, fontScale } = useScale; 18 | 19 | const ic_down = require('./icon/down.png'); 20 | 21 | const defaultProps = { 22 | placeholder: 'Select item', 23 | activeColor: '#F6F7F8', 24 | backgroundColor: 'white', 25 | data: [], 26 | style: {}, 27 | } 28 | 29 | const MultiSelectComponent: MultiSelect = (props) => { 30 | 31 | const { 32 | onChange, 33 | data, 34 | label, 35 | value, 36 | style, 37 | labelField, 38 | valueField, 39 | textErrorStyle, 40 | selectedStyle, 41 | selectedTextStyle, 42 | activeColor, 43 | backgroundColor, 44 | fontFamily, 45 | textStyle, 46 | textError, 47 | iconColor, 48 | headerStyle, 49 | labelStyle, 50 | searchStyle, 51 | searchPlaceholder, 52 | placeholder, 53 | maxHeight = scale(400), 54 | search = false, 55 | renderTickIcon, 56 | renderLeftIcon, 57 | renderHeader 58 | } = props; 59 | 60 | const [visible, setVisible] = useState(false); 61 | const [currentValue, setCurrentValue] = useState([]); 62 | const [textSearch, setTextSearch] = useState(''); 63 | const [listData, setListData] = useState(data); 64 | const [key, setKey] = useState(Math.random()); 65 | 66 | useEffect(() => { 67 | getValue(); 68 | }, []); 69 | 70 | const font = () => { 71 | if (fontFamily) { 72 | return { 73 | fontFamily: fontFamily 74 | } 75 | } else { 76 | return {} 77 | } 78 | } 79 | 80 | const showOrClose = () => { 81 | setVisible(!visible); 82 | } 83 | 84 | const scrollToIndex = (ref: any) => { 85 | if (textSearch.length === 0) { 86 | const index = data.findIndex(e => value === e[valueField]); 87 | if (index !== -1 && ref) { 88 | setTimeout(() => { 89 | ref.scrollToIndex({ index: index, animated: true }) 90 | }, 300); 91 | } 92 | } 93 | } 94 | 95 | const getValue = () => { 96 | setCurrentValue(value); 97 | } 98 | 99 | const onSelect = (item: any) => { 100 | onSearch(''); 101 | 102 | const index = currentValue.findIndex(e => e === item[valueField]); 103 | if (index > -1) { 104 | currentValue.splice(index, 1); 105 | } else { 106 | currentValue.push(item[valueField]); 107 | } 108 | onChange(currentValue); 109 | setKey(Math.random()); 110 | } 111 | 112 | const _renderTitle = () => { 113 | if (label) { 114 | return ( 115 | 116 | {label} 117 | 118 | ) 119 | } 120 | } 121 | 122 | const _renderDropdown = () => { 123 | return ( 124 | 125 | 126 | {renderLeftIcon?.()} 127 | 128 | {placeholder} 129 | 130 | 131 | 132 | 133 | ) 134 | } 135 | 136 | const checkSelected = (item: any) => { 137 | const index = currentValue.findIndex(e => e === item[valueField]); 138 | return index > -1; 139 | } 140 | 141 | const renderItem = ({ item, index }: { item: any; index: number }) => { 142 | return ( 143 | onSelect(item)}> 144 | 145 | {item[labelField]} 147 | {checkSelected(item) && 148 | renderTickIcon?.() 149 | } 150 | 151 | 152 | ); 153 | }; 154 | 155 | const onSearch = (text: string) => { 156 | setTextSearch(text); 157 | if (text.length > 0) { 158 | const dataSearch = data.filter(e => { 159 | const item = e[labelField].toLowerCase().replace(' ', ''); 160 | const key = text.toLowerCase().replace(' ', ''); 161 | 162 | return item.indexOf(key) >= 0 163 | }); 164 | setListData(dataSearch); 165 | } else { 166 | setListData(data); 167 | } 168 | } 169 | 170 | const _renderList = () => { 171 | return 172 | {search && } 180 | scrollToIndex(e)} 182 | data={listData} 183 | renderItem={renderItem} 184 | keyExtractor={(item, index) => index.toString()} 185 | showsVerticalScrollIndicator={false} 186 | extraData={key} 187 | /> 188 | 189 | } 190 | 191 | const _header = () => { 192 | return ( 193 | 194 | 195 | ) 196 | } 197 | 198 | const _renderModal = () => { 199 | if (visible) { 200 | return renderHeader ? renderHeader(): _header()} 208 | supportedOrientations={['landscape', 'portrait']} 209 | > 210 | {_renderList()} 211 | 212 | } 213 | return null 214 | } 215 | 216 | const unSelect = (item: any) => { 217 | const index = currentValue.indexOf(item[valueField]); 218 | currentValue.splice(index, 1); 219 | setKey(Math.random()); 220 | } 221 | 222 | const _renderItemSelected = () => { 223 | const list = data.filter((e: any) => { 224 | const check = currentValue.indexOf(e[valueField]); 225 | if (check !== -1) { 226 | return e; 227 | } 228 | }); 229 | 230 | return ( 231 | 232 | {list.map(e => { 233 | return ( 234 | unSelect(e)} 238 | > 239 | {e[labelField]} 240 | 241 | 242 | ) 243 | })} 244 | ) 245 | } 246 | 247 | return ( 248 | 249 | 250 | {_renderTitle()} 251 | {_renderDropdown()} 252 | {_renderModal()} 253 | 254 | {textError && {textError}} 255 | {_renderItemSelected()} 256 | 257 | ); 258 | }; 259 | 260 | MultiSelectComponent.defaultProps = defaultProps; 261 | 262 | export default MultiSelectComponent; 263 | 264 | -------------------------------------------------------------------------------- /src/components/MultiSelect/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | const { scale, fontScale } = useScale; 5 | 6 | export const styles = StyleSheet.create({ 7 | container: { 8 | backgroundColor: 'white', 9 | borderRadius: scale(8), 10 | padding: scale(12), 11 | justifyContent: 'center' 12 | }, 13 | main: { 14 | flex: 1, 15 | backgroundColor: 'rgba(0,0,0,0.6)', 16 | }, 17 | modalContent: { 18 | backgroundColor: 'white', 19 | width: '100%', 20 | borderTopLeftRadius: scale(16), 21 | borderTopRightRadius: scale(16), 22 | }, 23 | header: { 24 | height: scale(40), 25 | width: '100%', 26 | borderTopLeftRadius: scale(16), 27 | borderTopRightRadius: scale(16), 28 | justifyContent: 'center', 29 | alignItems: 'center', 30 | borderBottomWidth: scale(0.3), 31 | borderBottomColor: '#DDDDDD', 32 | backgroundColor: 'white' 33 | }, 34 | pan: { 35 | width: scale(40), 36 | height: scale(6), 37 | borderRadius: scale(6), 38 | backgroundColor: '#DDDDDD' 39 | }, 40 | closeIcon: { 41 | width: scale(45), 42 | height: scale(45), 43 | alignItems: 'center', 44 | justifyContent: 'center', 45 | }, 46 | dropdown: { 47 | flexDirection: 'row', 48 | justifyContent: 'space-between', 49 | alignItems: 'center', 50 | height: scale(35) 51 | }, 52 | title: { 53 | marginVertical: scale(5), 54 | fontSize: fontScale(16) 55 | }, 56 | list: { 57 | maxHeight: scale(300) 58 | }, 59 | item: { 60 | padding: scale(17), 61 | flexDirection: 'row', 62 | justifyContent: 'space-between', 63 | alignItems: 'center' 64 | }, 65 | textItem: { 66 | flex: 1, 67 | fontSize: fontScale(16) 68 | }, 69 | icon: { 70 | width: scale(24), 71 | height: scale(24), 72 | }, 73 | textError: { 74 | color: 'red', 75 | fontSize: fontScale(14), 76 | marginTop: scale(10) 77 | }, 78 | input: { 79 | borderWidth: scale(0.5), 80 | borderColor: '#DDDDDD', 81 | borderRadius: scale(12), 82 | margin: scale(8), 83 | paddingHorizontal: scale(8), 84 | }, 85 | selectedItem: { 86 | height: scale(30), 87 | alignItems: 'center', 88 | justifyContent: 'center', 89 | borderWidth: scale(0.5), 90 | borderColor: 'gray', 91 | paddingHorizontal: scale(8), 92 | marginTop: scale(12), 93 | marginRight: scale(8), 94 | borderRadius: scale(10), 95 | flexDirection: 'row' 96 | }, 97 | selectedTextItem: { 98 | marginLeft: scale(5), 99 | color: 'gray', 100 | fontSize: fontScale(16) 101 | } 102 | }); 103 | -------------------------------------------------------------------------------- /src/components/MultiSelect/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, TextStyle, ViewStyle } from 'react-native'; 2 | 3 | interface Props { 4 | style?: StyleProp; 5 | labelStyle?: StyleProp; 6 | textStyle?: StyleProp; 7 | headerStyle?: StyleProp; 8 | textErrorStyle?: StyleProp; 9 | searchStyle?: StyleProp; 10 | selectedStyle?: StyleProp; 11 | selectedTextStyle?: StyleProp; 12 | fontFamily?: string; 13 | backgroundColor?: string; 14 | iconColor?: string 15 | activeColor?: string 16 | data: any[]; 17 | value?: any | null; 18 | textError?: string; 19 | label?: string; 20 | placeholder?: string; 21 | labelField: string; 22 | valueField: string; 23 | maxHeight?: number; 24 | search?: boolean; 25 | searchPlaceholder?: string 26 | onChange: (item: any) => void; 27 | renderLeftIcon?: () => JSX.Element | null | undefined; 28 | renderTickIcon?: () => JSX.Element | null | undefined; 29 | renderHeader?: () => JSX.Element; 30 | } 31 | 32 | export type MultiSelect = React.FC 33 | -------------------------------------------------------------------------------- /src/components/Progress/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { View } from 'react-native'; 3 | import Text from '../Text'; 4 | import { useScale } from 'react-native-utils-toolkit'; 5 | import { styles } from './styles'; 6 | import { Progress } from './type'; 7 | 8 | const { scale } = useScale; 9 | 10 | const defaultProps = { 11 | style: {}, 12 | data: [ 13 | { color: 'red', percent: 33.33 }, 14 | { color: 'gray', percent: 33.33 }, 15 | { color: 'green', percent: 33.33 }, 16 | ], 17 | border: false, 18 | height: scale(6), 19 | }; 20 | 21 | let iPercent = 100; 22 | 23 | const ProgressComponent: Progress = (props) => { 24 | const { percent, data, height, border, style } = props; 25 | const [controlColor, setControlColor] = useState('black'); 26 | 27 | useEffect(() => { 28 | if (data) { 29 | iPercent = 100 / data.length; 30 | const index = Math.ceil(percent / iPercent); 31 | const findColor = data[index - 1].color; 32 | setControlColor(findColor); 33 | } 34 | }, [percent, data]); 35 | 36 | return ( 37 | 38 | 45 | 46 | {percent} 47 | 48 | 49 | 50 | 51 | 52 | {data && 53 | data.map((item, index) => ( 54 | 66 | ))} 67 | 68 | 69 | ); 70 | }; 71 | 72 | ProgressComponent.defaultProps = defaultProps; 73 | 74 | export default ProgressComponent; 75 | -------------------------------------------------------------------------------- /src/components/Progress/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | const { scale } = useScale; 5 | 6 | export const styles = StyleSheet.create({ 7 | main: { 8 | justifyContent: 'flex-end', 9 | minHeight: scale(44) 10 | }, 11 | container: { 12 | width: '100%', 13 | backgroundColor: 'white', 14 | flexDirection: 'row', 15 | borderRadius: scale(5), 16 | opacity: 0.5, 17 | }, 18 | controlBox: { 19 | position: 'absolute', 20 | width: scale(30), 21 | height: scale(30), 22 | zIndex: 9999, 23 | justifyContent: 'flex-end', 24 | alignItems: 'center', 25 | }, 26 | control: { 27 | backgroundColor: 'black', 28 | borderWidth: scale(2), 29 | borderColor: 'white', 30 | height: scale(30), 31 | width: scale(30), 32 | borderRadius: scale(15), 33 | alignItems: 'center', 34 | justifyContent: 'center', 35 | marginBottom: scale(1), 36 | opacity: 0.5, 37 | }, 38 | tick: { 39 | backgroundColor: 'black', 40 | borderWidth: scale(2), 41 | borderColor: 'white', 42 | height: scale(10), 43 | width: scale(10), 44 | borderRadius: scale(5), 45 | }, 46 | triangle: { 47 | width: 0, 48 | height: 0, 49 | backgroundColor: 'transparent', 50 | borderStyle: 'solid', 51 | borderTopWidth: scale(5), 52 | borderRightWidth: scale(5), 53 | borderBottomWidth: 0, 54 | borderLeftWidth: scale(5), 55 | borderRightColor: 'transparent', 56 | borderBottomColor: 'transparent', 57 | borderLeftColor: 'transparent', 58 | opacity: scale(0.5), 59 | }, 60 | }); 61 | -------------------------------------------------------------------------------- /src/components/Progress/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, ViewStyle } from 'react-native'; 2 | 3 | interface Props { 4 | style?: StyleProp; 5 | percent: number; 6 | data: { color: string; percent: number }[]; 7 | border?: boolean; 8 | height?: number; 9 | } 10 | 11 | export type Progress = React.FC -------------------------------------------------------------------------------- /src/components/StepProgress/icon/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/StepProgress/icon/check.png -------------------------------------------------------------------------------- /src/components/StepProgress/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Image, TouchableOpacity, View } from 'react-native'; 3 | import Text from '../Text'; 4 | import { useScale } from 'react-native-utils-toolkit'; 5 | import { styles } from './styles'; 6 | import { StepProgress, Item } from './type'; 7 | 8 | const ic_check = require('./icon/check.png'); 9 | const { scale, fontScale } = useScale; 10 | 11 | const defaultProps = { 12 | style: {}, 13 | data: [ 14 | { text: 'Step 1', status: false }, 15 | { text: 'Step 2', status: false }, 16 | { text: 'Step 3', status: false }, 17 | { text: 'Step 4', status: false }, 18 | { text: 'Step 5', status: false }, 19 | { text: 'Step 6', status: false }, 20 | ], 21 | activeColor: '#32C5FF', 22 | inActiveColor: '#C6CDD8', 23 | selectColor: '#FF9900', 24 | textColor: '#C6CDD8', 25 | selectIndex: 0, 26 | textSize: 16, 27 | onSelectIndex: (index: number) => { }, 28 | iconTick: null 29 | }; 30 | 31 | const StepProgressComponent: StepProgress = (props) => { 32 | const { 33 | style, 34 | fontFamily, 35 | data, 36 | activeColor, 37 | inActiveColor, 38 | textColor, 39 | selectIndex, 40 | textSize = 16, 41 | selectColor, 42 | onSelectIndex, 43 | iconTick 44 | } = props; 45 | 46 | const font = () => { 47 | if (fontFamily) { 48 | return { 49 | fontFamily: fontFamily 50 | } 51 | } else { 52 | return {} 53 | } 54 | } 55 | 56 | const renderItem = (item: Item, index: number) => { 57 | return ( 58 | 63 | 64 | {index !== 0 && ( 65 | 74 | )} 75 | { 77 | if (onSelectIndex) { 78 | if (index > 0 && data[index - 1].status) { 79 | onSelectIndex(index); 80 | } else { 81 | if (index === 0) { 82 | onSelectIndex(index); 83 | } 84 | } 85 | } 86 | }}> 87 | 95 | {item.status ? 96 | 103 | : item.icon ? : {index + 1}} 110 | 111 | 112 | 113 | 114 | ); 115 | }; 116 | 117 | const renderText = (item: Item, index: number) => { 118 | return ( 119 | 120 | {item?.text} 121 | 122 | ); 123 | }; 124 | 125 | return ( 126 | 127 | 129 | {data.map((item, index) => renderItem(item, index))} 130 | 131 | 132 | {data.map((item, index) => renderText(item, index))} 133 | 134 | 135 | ); 136 | }; 137 | 138 | StepProgressComponent.defaultProps = defaultProps; 139 | 140 | export default StepProgressComponent; 141 | -------------------------------------------------------------------------------- /src/components/StepProgress/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | const { scale } = useScale; 5 | 6 | export const styles = StyleSheet.create({ 7 | container: {}, 8 | radius: { 9 | width: scale(30), 10 | height: scale(30), 11 | borderRadius: scale(15), 12 | borderWidth: scale(2), 13 | backgroundColor: 'white', 14 | alignItems: 'center', 15 | justifyContent: 'center', 16 | }, 17 | line: { 18 | flex: 1, 19 | height: scale(3), 20 | marginTop: scale(15), 21 | }, 22 | wrapTick: { 23 | flexDirection: 'row', 24 | justifyContent: 'space-between' 25 | }, 26 | row: { 27 | flexDirection: 'row', 28 | justifyContent: 'center' 29 | }, 30 | wrapText: { 31 | flexDirection: 'row', 32 | justifyContent: 'space-between' 33 | }, 34 | text: { 35 | marginTop: scale(10), 36 | textAlign: 'center', 37 | fontWeight: '500' 38 | }, 39 | icon: { 40 | width: scale(20), 41 | height: scale(20), 42 | }, 43 | }); -------------------------------------------------------------------------------- /src/components/StepProgress/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, ViewStyle } from 'react-native'; 2 | 3 | export interface Item { 4 | text?: string; 5 | status: boolean; 6 | icon?: any; 7 | } 8 | 9 | export interface Props { 10 | style?: StyleProp; 11 | fontFamily?: string; 12 | data: Item[]; 13 | activeColor?: string; 14 | inActiveColor?: string; 15 | textColor?: string; 16 | selectIndex?: number; 17 | onSelectIndex?: (index: number) => void; 18 | selectColor?: string; 19 | textSize?: number; 20 | iconTick?: any; 21 | } 22 | 23 | export type StepProgress = React.FC 24 | -------------------------------------------------------------------------------- /src/components/Text/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Text, TouchableWithoutFeedback } from 'react-native'; 3 | import { useScale } from 'react-native-utils-toolkit'; 4 | import { PropsText } from './type'; 5 | import { COLORS } from '../setup'; 6 | const { fontScale } = useScale; 7 | 8 | const defaultProps = { 9 | style: {}, 10 | fontSize: undefined, 11 | bold: false, 12 | color: undefined, 13 | }; 14 | 15 | const TextComponent: PropsText = props => { 16 | const { numberOfLines, onPress, fontSize, bold, color, style, children } = 17 | props; 18 | 19 | let FONTSIZE: number = 12; 20 | if (fontSize) { 21 | FONTSIZE = fontSize; 22 | } 23 | if (onPress) { 24 | return ( 25 | 26 | 37 | {children} 38 | 39 | 40 | ); 41 | } else { 42 | return ( 43 | 54 | {children} 55 | 56 | ); 57 | } 58 | }; 59 | 60 | TextComponent.defaultProps = defaultProps; 61 | 62 | export default TextComponent; 63 | -------------------------------------------------------------------------------- /src/components/Text/type.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TextProps, TextStyle } from 'react-native'; 3 | interface Props extends TextProps { 4 | fontSize?: number | undefined; 5 | bold?: boolean; 6 | color?: string | undefined; 7 | style?: TextStyle | TextStyle[]; 8 | onPress?: () => void; 9 | } 10 | 11 | export type PropsText = React.FC; 12 | -------------------------------------------------------------------------------- /src/components/TextInput/icon/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/TextInput/icon/close.png -------------------------------------------------------------------------------- /src/components/TextInput/icon/eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/TextInput/icon/eye.png -------------------------------------------------------------------------------- /src/components/TextInput/icon/uneye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoaphantn7604/react-native-utils-components/d909550dc92e348032719228a24251263d0a413c/src/components/TextInput/icon/uneye.png -------------------------------------------------------------------------------- /src/components/TextInput/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { 3 | Image, TextInput, 4 | TouchableOpacity, View 5 | } from 'react-native'; 6 | import Text from '../Text'; 7 | import { CTextInput } from './type'; 8 | import { useScale } from 'react-native-utils-toolkit'; 9 | import { styles } from './styles'; 10 | 11 | const { scale } = useScale; 12 | const ic_eye = require('./icon/eye.png'); 13 | const ic_uneye = require('./icon/uneye.png'); 14 | const ic_close= require('./icon/close.png'); 15 | 16 | const defaultProps = { 17 | style: {}, 18 | value: '', 19 | showIcon: true, 20 | currency: false, 21 | numeric: false, 22 | }; 23 | 24 | const TextInputComponent: CTextInput = (props) => { 25 | const { 26 | fontFamily, 27 | style, 28 | value, 29 | label, 30 | secureTextEntry, 31 | placeholderTextColor = '#000', 32 | placeholder = '', 33 | showIcon, 34 | inputStyle, 35 | iconStyle, 36 | currency, 37 | numeric, 38 | labelStyle, 39 | unitCurrency, 40 | textErrorStyle, 41 | textError, 42 | onChangeText = (value: string) => {}, 43 | renderLeftIcon, 44 | renderRightIcon, 45 | } = props; 46 | 47 | const [text, setText] = useState(''); 48 | const [textEntry, setTextEntry] = useState(secureTextEntry ? true : false); 49 | 50 | useEffect(() => { 51 | if (value) { 52 | if (currency || numeric) { 53 | setText(formatCurrency(value)); 54 | } else { 55 | setText(value); 56 | } 57 | } 58 | }, []); 59 | 60 | const formatCurrency = (num: string) => { 61 | const values = num.toString().replace(/\D/g, ''); 62 | return values.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '.'); 63 | }; 64 | 65 | const reConvertCurrency = (x: string) => { 66 | let s; 67 | s = x.split('.'); 68 | s = s.join(''); 69 | return s; 70 | }; 71 | 72 | const onChange = (text: string) => { 73 | if (currency || numeric) { 74 | setText(formatCurrency(text)); 75 | onChangeText(reConvertCurrency(text)); 76 | } else { 77 | setText(text); 78 | onChangeText(text); 79 | } 80 | }; 81 | 82 | const onChangeTextEntry = () => { 83 | setTextEntry(!textEntry); 84 | }; 85 | 86 | const _renderRightIcon = () => { 87 | if (showIcon) { 88 | if (renderRightIcon) { 89 | return ( 90 | renderRightIcon() 91 | ); 92 | } 93 | if (secureTextEntry) { 94 | return ( 95 | 96 | 97 | 98 | ); 99 | } else { 100 | return ( 101 | onChange('')}> 102 | 103 | ) 104 | } 105 | } 106 | return null; 107 | }; 108 | 109 | const font = () => { 110 | if (fontFamily) { 111 | return { 112 | fontFamily: fontFamily 113 | } 114 | } else { 115 | return {} 116 | } 117 | } 118 | 119 | return ( 120 | 121 | 122 | {label && ( 123 | 124 | {label} 125 | 126 | )} 127 | 128 | {renderLeftIcon?.()} 129 | {currency && unitCurrency && ( 130 | 131 | {unitCurrency} 132 | 133 | )} 134 | 143 | {_renderRightIcon()} 144 | 145 | 146 | {textError && {textError}} 147 | 148 | ); 149 | }; 150 | 151 | TextInputComponent.defaultProps = defaultProps; 152 | 153 | export default TextInputComponent; 154 | -------------------------------------------------------------------------------- /src/components/TextInput/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | const { scale, fontScale } = useScale; 4 | 5 | export const styles = StyleSheet.create({ 6 | container: { 7 | backgroundColor: 'white', 8 | borderRadius: scale(8), 9 | padding: scale(12), 10 | justifyContent: 'center', 11 | }, 12 | textInput: { 13 | flexDirection: 'row', 14 | alignItems: 'center', 15 | height: scale(40), 16 | }, 17 | input: { 18 | fontSize: fontScale(16), 19 | flex:1 20 | }, 21 | label: { 22 | marginBottom: scale(4), 23 | fontSize: fontScale(16) 24 | }, 25 | row: { 26 | flexDirection: 'row', 27 | }, 28 | icon: { 29 | width: scale(20), 30 | height: scale(20), 31 | }, 32 | textError: { 33 | color: 'red', 34 | fontSize: fontScale(14), 35 | marginTop: scale(10) 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /src/components/TextInput/type.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ImageStyle, 3 | StyleProp, 4 | TextInputProps, 5 | TextStyle, 6 | ViewStyle 7 | } from 'react-native'; 8 | 9 | interface Props extends TextInputProps { 10 | fontFamily?: string; 11 | style?: StyleProp; 12 | inputStyle?: StyleProp; 13 | labelStyle?: StyleProp; 14 | iconStyle?: StyleProp; 15 | textErrorStyle?: StyleProp; 16 | textError?: string; 17 | label?: string; 18 | showIcon?: boolean; 19 | currency?: boolean; 20 | numeric?: boolean; 21 | unitCurrency?: string; 22 | renderRightIcon?: () => JSX.Element | null | undefined; 23 | renderLeftIcon?: () => JSX.Element | null | undefined; 24 | } 25 | 26 | export type CTextInput = React.FC 27 | -------------------------------------------------------------------------------- /src/components/Timer/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useImperativeHandle, useState } from 'react'; 2 | import { View } from 'react-native'; 3 | import Text from '../Text'; 4 | import { styles } from './styles'; 5 | import { Props } from './type'; 6 | 7 | const defaulProps = { 8 | style: {}, 9 | textStyle: {}, 10 | onTimes: (seconds: number) => { }, 11 | onEnd: (seconds: number) => { } 12 | }; 13 | 14 | let interval: any = null; 15 | let hours = 0; 16 | let minute = 0; 17 | let seconds = 0; 18 | let currentSeconds = 0; 19 | 20 | const TimerComponent = React.forwardRef((props: Props, ref) => { 21 | const { style, textStyle, fontFamily, onEnd, onTimes } = props; 22 | const [key, setKey] = useState(Math.random()); 23 | 24 | useImperativeHandle(ref, () => { 25 | return { start, pause, resume, stop }; 26 | }); 27 | 28 | useEffect(() => { 29 | return () => { 30 | stop(); 31 | } 32 | }, []) 33 | 34 | const timer = () => { 35 | interval = setInterval(() => { 36 | currentSeconds = currentSeconds + 1; 37 | if (seconds < 60) { 38 | seconds = seconds + 1; 39 | } else { 40 | seconds = 0; 41 | minute = minute + 1; 42 | } 43 | if (minute === 60) { 44 | minute = 0; 45 | hours = hours + 1; 46 | } 47 | if (onTimes) { 48 | onTimes(currentSeconds); 49 | } 50 | setKey(Math.random()); 51 | }, 1000); 52 | 53 | }; 54 | 55 | const init = () => { 56 | currentSeconds = 0; 57 | hours = 0; 58 | minute = 0; 59 | seconds = 0; 60 | clear(); 61 | setKey(Math.random()); 62 | } 63 | 64 | const start = () => { 65 | init(); 66 | 67 | if (!interval) { 68 | timer(); 69 | } 70 | } 71 | 72 | const pause = () => { 73 | clear(); 74 | } 75 | 76 | const resume = () => { 77 | if (!interval) { 78 | timer(); 79 | } 80 | } 81 | 82 | const stop = () => { 83 | if (onEnd) { 84 | onEnd(currentSeconds); 85 | } 86 | 87 | init(); 88 | setKey(Math.random()); 89 | clear(); 90 | } 91 | 92 | const clear = () => { 93 | if (interval) { 94 | clearInterval(interval); 95 | interval = null; 96 | } 97 | } 98 | 99 | const font = () => { 100 | if (fontFamily) { 101 | return { 102 | fontFamily: fontFamily 103 | } 104 | } else { 105 | return {} 106 | } 107 | } 108 | 109 | return ( 110 | 111 | {`${hours}:${minute.toString().length === 1 ? '0' : ''}${minute}:${seconds.toString().length === 1 ? '0' : '' 112 | }${seconds}`} 113 | 114 | ); 115 | }); 116 | 117 | TimerComponent.defaultProps = defaulProps; 118 | 119 | export default TimerComponent; 120 | -------------------------------------------------------------------------------- /src/components/Timer/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | 4 | export const styles = StyleSheet.create({ 5 | text: { 6 | fontSize: useScale.fontScale(20), 7 | color: 'black', 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /src/components/Timer/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, TextStyle, ViewStyle } from 'react-native'; 2 | 3 | export interface Props { 4 | style?: StyleProp; 5 | textStyle?: StyleProp; 6 | fontFamily?: string; 7 | onTimes?: (seconds: number) => void 8 | onEnd?: (seconds: number) => void 9 | } 10 | -------------------------------------------------------------------------------- /src/components/TooltipProgress/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { TouchableOpacity, View, Image } from 'react-native'; 3 | import Text from '../Text'; 4 | import { useScale } from 'react-native-utils-toolkit'; 5 | import { styles } from './styles'; 6 | import { Item, TooltipProgress } from './type'; 7 | 8 | const { scale, fontScale } = useScale; 9 | 10 | const defaultProps = { 11 | style: {}, 12 | tooltipStyle: {}, 13 | data: [ 14 | { stage: 'S1', text: 'S1', status: false }, 15 | { stage: 'S2', text: 'S2', status: false }, 16 | { stage: 'S3', text: 'S3', status: false }, 17 | { stage: 'S4', text: 'S4', status: false }, 18 | { stage: 'S5', text: 'S5', status: false }, 19 | { stage: 'S6', text: 'S6', status: false }, 20 | ], 21 | activeColor: '#32C5FF', 22 | inActiveColor: '#C6CDD8', 23 | selectColor: '#FF9900', 24 | selectIndex: 0, 25 | textSize: 16, 26 | onSelectIndex: (index: number) => { }, 27 | }; 28 | 29 | const CTooltipProgressComponent: TooltipProgress = (props) => { 30 | const { 31 | style, 32 | fontFamily, 33 | data, 34 | activeColor, 35 | inActiveColor, 36 | selectIndex, 37 | textSize, 38 | selectColor, 39 | tooltipStyle, 40 | onSelectIndex, 41 | } = props; 42 | 43 | const font = () => { 44 | if (fontFamily) { 45 | return { 46 | fontFamily: fontFamily 47 | } 48 | } else { 49 | return {} 50 | } 51 | } 52 | 53 | const renderItem = (item: Item, index: number) => { 54 | return ( 55 | 56 | 57 | {index !== 0 && ( 58 | 67 | )} 68 | { 70 | if (onSelectIndex) { 71 | if (index > 0 && data[index - 1].status) { 72 | onSelectIndex(index); 73 | } else { 74 | if (index === 0) { 75 | onSelectIndex(index); 76 | } 77 | } 78 | } 79 | }}> 80 | 88 | {item.icon ? : 102 | {item?.stage} 103 | } 104 | 105 | {index === selectIndex && ( 106 | 107 | )} 108 | 109 | 110 | 111 | ); 112 | }; 113 | 114 | const renderText = (item: Item, index: number) => { 115 | return ( 116 | 117 | {index === selectIndex && ( 118 | 120 | {item.text} 121 | 122 | )} 123 | 124 | ); 125 | }; 126 | 127 | return ( 128 | 129 | 134 | {data.map((item, index) => renderItem(item, index))} 135 | 136 | 137 | {data.map((item, index) => renderText(item, index))} 138 | 139 | 140 | ); 141 | }; 142 | 143 | CTooltipProgressComponent.defaultProps = defaultProps; 144 | 145 | export default CTooltipProgressComponent; 146 | -------------------------------------------------------------------------------- /src/components/TooltipProgress/styles.ts: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | import { useScale } from 'react-native-utils-toolkit'; 3 | const { scale, fontScale } = useScale; 4 | 5 | export const styles = StyleSheet.create({ 6 | container: {}, 7 | radius: { 8 | width: scale(30), 9 | height: scale(30), 10 | borderRadius: scale(15), 11 | backgroundColor: 'white', 12 | alignItems: 'center', 13 | justifyContent: 'center', 14 | }, 15 | line: { 16 | flex: 1, 17 | height: scale(3), 18 | marginTop: scale(15), 19 | }, 20 | text: { color: 'white', fontSize: fontScale(16) }, 21 | icon: { 22 | width: scale(20), 23 | height: scale(20), 24 | }, 25 | tag: { 26 | paddingHorizontal: scale(12), 27 | paddingVertical: scale(6), 28 | borderRadius: scale(5), 29 | justifyContent: 'center', 30 | alignItems: 'center', 31 | }, 32 | triangle: { 33 | marginTop: scale(10), 34 | marginLeft: scale(10), 35 | width: 0, 36 | height: 0, 37 | backgroundColor: 'transparent', 38 | borderStyle: 'solid', 39 | borderTopWidth: 0, 40 | borderRightWidth: scale(5), 41 | borderBottomWidth: scale(10), 42 | borderLeftWidth: scale(5), 43 | borderRightColor: 'transparent', 44 | borderTopColor: 'transparent', 45 | borderLeftColor: 'transparent', 46 | opacity: 1, 47 | }, 48 | }); 49 | -------------------------------------------------------------------------------- /src/components/TooltipProgress/type.ts: -------------------------------------------------------------------------------- 1 | import { StyleProp, ViewStyle } from 'react-native'; 2 | 3 | interface Props { 4 | style?: StyleProp; 5 | tooltipStyle?: StyleProp; 6 | fontFamily?: string; 7 | data: Item[]; 8 | activeColor?: string; 9 | inActiveColor?: string; 10 | selectIndex?: number; 11 | onSelectIndex?: (index: number) => void; 12 | selectColor?: string; 13 | textSize?: number; 14 | } 15 | 16 | export interface Item { 17 | stage?: string; 18 | text: string; 19 | status: boolean; 20 | icon?: any; 21 | } 22 | 23 | export type TooltipProgress = React.FC 24 | -------------------------------------------------------------------------------- /src/components/ZoomView/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from 'react'; 2 | import { ScrollView } from 'react-native'; 3 | import { ZoomView } from './type'; 4 | 5 | const defaultProps = { 6 | maximumZoomScale: 2, 7 | minimumZoomScale: 1, 8 | autoZoom: false, 9 | } 10 | 11 | const ZoomViewComponent: ZoomView = (props) => { 12 | const { maximumZoomScale, minimumZoomScale, autoZoom } = props; 13 | const scrollRef = useRef(null); 14 | 15 | const onDefault = () => { 16 | if (scrollRef.current) { 17 | scrollRef.current.getScrollResponder().scrollResponderZoomTo({ animated: false }); 18 | } 19 | } 20 | 21 | useEffect(() => { 22 | if (autoZoom) { 23 | setTimeout(() => { 24 | onDefault(); 25 | }, 50); 26 | } 27 | }, []); 28 | 29 | return ( 30 | {props.children} 37 | ); 38 | }; 39 | 40 | ZoomViewComponent.defaultProps = defaultProps; 41 | 42 | export default ZoomViewComponent; 43 | -------------------------------------------------------------------------------- /src/components/ZoomView/type.ts: -------------------------------------------------------------------------------- 1 | interface Props { 2 | maximumZoomScale?: number; 3 | minimumZoomScale?: number; 4 | autoZoom?: boolean; 5 | } 6 | 7 | export type ZoomView = React.FC 8 | -------------------------------------------------------------------------------- /src/components/setup.ts: -------------------------------------------------------------------------------- 1 | 2 | export type COLOR = { 3 | PRIMARY: string; 4 | SECONDARY: string; 5 | BUTTON: string; 6 | BUTTON_TEXT: string; 7 | TEXT: string; 8 | }; 9 | 10 | const COLORS: COLOR = { 11 | PRIMARY: '#FF3030', 12 | SECONDARY: '#F4A460', 13 | BUTTON: 'white', 14 | BUTTON_TEXT: 'gray', 15 | TEXT: 'black', 16 | }; 17 | 18 | export { COLORS }; 19 | --------------------------------------------------------------------------------