@momo-kits/foundation 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,10 +29,10 @@ const CheckBox: FC<CheckBoxProps> = props => {
29
29
 
30
30
  if (disabled) {
31
31
  borderColor = haveValue
32
- ? theme.colors.background.disable
32
+ ? theme.colors.background.tonal
33
33
  : theme.colors.border.disable;
34
34
  backgroundColor = haveValue
35
- ? theme.colors.background.disable
35
+ ? theme.colors.background.tonal
36
36
  : theme.colors.background.surface;
37
37
  }
38
38
  const checkboxStyle = {borderColor, backgroundColor, borderWidth: 1};
@@ -3,11 +3,13 @@ import {Radius, Spacing} from '../Consts';
3
3
 
4
4
  export default StyleSheet.create({
5
5
  checkbox: {
6
- width: 24,
7
- height: 24,
6
+ width: 20,
7
+ height: 20,
8
8
  borderRadius: Radius.XS,
9
9
  borderWidth: 2,
10
10
  marginRight: Spacing.S,
11
+ justifyContent: 'center',
12
+ alignItems: 'center',
11
13
  },
12
14
  container: {flexDirection: 'row'},
13
15
  icon: {width: 20, height: 20},
package/Input/Input.tsx CHANGED
@@ -8,9 +8,8 @@ import {
8
8
  } from 'react-native';
9
9
  import {ApplicationContext} from '../Navigation';
10
10
  import styles from './styles';
11
- import {Text} from '../Text';
12
11
  import {Image} from '../Image';
13
- import {getBorderColor, renderFloatingView} from './common';
12
+ import {ErrorView, FloatingView, getBorderColor} from './common';
14
13
  import {InputProps} from './index';
15
14
  import {Icon} from '../Icon';
16
15
 
@@ -76,13 +75,14 @@ const Input: FC<InputProps> = ({
76
75
  getSizeStyle(),
77
76
  getBorderColor(focused, errorMessage, disabled),
78
77
  styles.inputWrapper,
78
+ {backgroundColor: theme.colors.background.surface},
79
79
  ]}>
80
- {renderFloatingView(
81
- floatingValue,
82
- floatingIconColor,
83
- disabled,
84
- floatingIcon,
85
- )}
80
+ <FloatingView
81
+ floatingValue={floatingValue}
82
+ floatingIconColor={floatingIconColor}
83
+ disabled={disabled}
84
+ floatingIcon={floatingIcon}
85
+ />
86
86
  <View style={styles.inputView}>
87
87
  <TextInput
88
88
  {...props}
@@ -126,35 +126,16 @@ const Input: FC<InputProps> = ({
126
126
  );
127
127
  };
128
128
 
129
- const renderErrorView = () => {
130
- if (errorMessage) {
131
- return (
132
- <View style={styles.errorView}>
133
- <View style={styles.errorIcon}>
134
- <Icon
135
- source="ic_error"
136
- size={16}
137
- color={theme.colors.error.primary}
138
- />
139
- </View>
140
- <Text color={theme.colors.error.primary} typography={'description_s'}>
141
- {errorMessage}
142
- </Text>
143
- </View>
144
- );
145
- }
146
- };
147
-
148
129
  return (
149
130
  <View style={styles.wrapper}>
150
131
  {renderInputView()}
151
- {renderErrorView()}
132
+ <ErrorView errorMessage={errorMessage} />
152
133
  </View>
153
134
  );
154
135
  };
155
136
 
156
137
  Input.defaultProps = {
157
- size: 'large',
138
+ size: 'small',
158
139
  };
159
140
 
160
141
  export default Input;
@@ -0,0 +1,153 @@
1
+ import React, {FC, useContext, useRef, useState} from 'react';
2
+ import {
3
+ NativeSyntheticEvent,
4
+ TextInput,
5
+ TextInputFocusEventData,
6
+ TouchableOpacity,
7
+ View,
8
+ } from 'react-native';
9
+ import {SearchInputProps} from './index';
10
+ import {getBorderColor} from './common';
11
+ import {ApplicationContext} from '../Navigation';
12
+ import styles from './styles';
13
+ import {Icon} from '../Icon';
14
+ import {Image} from '../Image';
15
+ import {Text} from '../Text';
16
+
17
+ const SearchInput: FC<SearchInputProps> = ({
18
+ errorMessage,
19
+ disabled,
20
+ placeholder,
21
+ onFocus,
22
+ onBlur,
23
+ iconColor,
24
+ value,
25
+ onChangeText,
26
+ icon,
27
+ buttonText = 'Hủy',
28
+ showButtonText,
29
+ showIcon = true,
30
+ ...props
31
+ }) => {
32
+ const {theme} = useContext(ApplicationContext);
33
+ const [focused, setFocused] = useState(false);
34
+ const inputRef = useRef<any>(null);
35
+ let iconTintColor = iconColor;
36
+
37
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
38
+ setFocused(true);
39
+ onFocus?.(e);
40
+ };
41
+
42
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
43
+ setFocused(false);
44
+ onBlur?.(e);
45
+ };
46
+
47
+ const onClearText = () => {
48
+ inputRef?.current?.clear();
49
+ };
50
+
51
+ const _onChangeText = (text: string) => {
52
+ onChangeText?.(text);
53
+ };
54
+
55
+ const renderInputView = () => {
56
+ const disabledColor = theme.colors.text.disable;
57
+ let textColor = theme.colors.text.default;
58
+ let placeholderColor = theme.colors.text.hint;
59
+
60
+ if (disabled) {
61
+ textColor = disabledColor;
62
+ placeholderColor = disabledColor;
63
+ iconTintColor = disabledColor;
64
+ }
65
+ return (
66
+ <View style={styles.searchInputView}>
67
+ <Icon
68
+ source={'navigation_search'}
69
+ size={24}
70
+ color={theme.colors.text.hint}
71
+ />
72
+ <TextInput
73
+ {...props}
74
+ editable={!disabled}
75
+ textAlignVertical="top"
76
+ ref={inputRef}
77
+ style={[
78
+ styles.searchInput,
79
+ {
80
+ color: textColor,
81
+ },
82
+ ]}
83
+ value={value}
84
+ onChangeText={_onChangeText}
85
+ onFocus={_onFocus}
86
+ onBlur={_onBlur}
87
+ placeholder={placeholder}
88
+ selectionColor={theme.colors.primary}
89
+ placeholderTextColor={placeholderColor}
90
+ />
91
+ </View>
92
+ );
93
+ };
94
+
95
+ const renderIconView = () => {
96
+ return (
97
+ <View
98
+ style={{
99
+ flexDirection: 'row',
100
+ }}>
101
+ {focused && (
102
+ <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
103
+ <Icon
104
+ source="24_navigation_close_circle_full"
105
+ size={16}
106
+ color={theme.colors.text.hint}
107
+ />
108
+ </TouchableOpacity>
109
+ )}
110
+ {showIcon && icon && (
111
+ <View>
112
+ <View
113
+ style={[
114
+ styles.divider,
115
+ {
116
+ backgroundColor: theme.colors.primary,
117
+ },
118
+ ]}
119
+ />
120
+
121
+ <Image
122
+ tintColor={iconTintColor}
123
+ source={{uri: icon}}
124
+ style={styles.iconSearchInput}
125
+ />
126
+ </View>
127
+ )}
128
+ </View>
129
+ );
130
+ };
131
+ return (
132
+ <View style={styles.searchInputContainer}>
133
+ <View
134
+ style={[
135
+ getBorderColor(focused, errorMessage, disabled),
136
+ styles.searchInputWrapper,
137
+ {backgroundColor: theme.colors.background.surface},
138
+ ]}>
139
+ {renderInputView()}
140
+ {renderIconView()}
141
+ </View>
142
+ {showButtonText && (
143
+ <TouchableOpacity>
144
+ <Text typography={'action_default'} style={styles.textButton}>
145
+ {buttonText}
146
+ </Text>
147
+ </TouchableOpacity>
148
+ )}
149
+ </View>
150
+ );
151
+ };
152
+
153
+ export default SearchInput;
@@ -9,13 +9,16 @@ import {
9
9
  import styles from './styles';
10
10
  import {Text} from '../Text';
11
11
  import {ApplicationContext} from '../Navigation';
12
- import {getBorderColor, renderFloatingView} from './common';
12
+ import {
13
+ DEFAULT_HEIGHT,
14
+ ErrorView,
15
+ FloatingView,
16
+ getBorderColor,
17
+ MAX_LENGTH,
18
+ } from './common';
13
19
  import {TextAreaProps} from './index';
14
20
  import {Icon} from '../Icon';
15
21
 
16
- const DEFAULT_HEIGHT = 112;
17
- const MAX_LENGTH = 300;
18
-
19
22
  const TextArea: FC<TextAreaProps> = props => {
20
23
  const {theme} = useContext(ApplicationContext);
21
24
  const {
@@ -86,12 +89,12 @@ const TextArea: FC<TextAreaProps> = props => {
86
89
  backgroundColor: theme.colors.background.surface,
87
90
  },
88
91
  ]}>
89
- {renderFloatingView(
90
- floatingValue,
91
- floatingIconColor,
92
- disabled,
93
- floatingIcon,
94
- )}
92
+ <FloatingView
93
+ floatingValue={floatingValue}
94
+ floatingIconColor={floatingIconColor}
95
+ disabled={disabled}
96
+ floatingIcon={floatingIcon}
97
+ />
95
98
  <View style={styles.rowArea}>
96
99
  <View style={styles.textAreaView}>
97
100
  <TextInput
@@ -130,28 +133,10 @@ const TextArea: FC<TextAreaProps> = props => {
130
133
  );
131
134
  };
132
135
 
133
- const renderErrorView = () => {
134
- if (errorMessage) {
135
- return (
136
- <View style={styles.errorView}>
137
- <View style={styles.errorIcon}>
138
- <Icon
139
- source="ic_error"
140
- size={16}
141
- color={theme.colors.error.primary}
142
- />
143
- </View>
144
- <Text color={theme.colors.error.primary} typography={'description_s'}>
145
- {errorMessage}
146
- </Text>
147
- </View>
148
- );
149
- }
150
- };
151
136
  return (
152
137
  <View style={styles.wrapper}>
153
138
  {renderInputView()}
154
- {renderErrorView()}
139
+ <ErrorView errorMessage={errorMessage} />
155
140
  </View>
156
141
  );
157
142
  };
package/Input/common.tsx CHANGED
@@ -2,8 +2,19 @@ import {View} from 'react-native';
2
2
  import styles from './styles';
3
3
  import {Text} from '../Text';
4
4
  import {Image} from '../Image';
5
- import React, {useContext} from 'react';
5
+ import React, {FC, useContext} from 'react';
6
6
  import {ApplicationContext} from '../Navigation';
7
+ import {Icon} from '../Icon';
8
+
9
+ type FloatingViewProps = {
10
+ floatingValue?: string;
11
+ floatingIconColor?: string;
12
+ disabled?: boolean;
13
+ floatingIcon?: string;
14
+ };
15
+
16
+ export const DEFAULT_HEIGHT = 112;
17
+ export const MAX_LENGTH = 300;
7
18
 
8
19
  export const getBorderColor = (
9
20
  focused: boolean,
@@ -29,12 +40,30 @@ export const getBorderColor = (
29
40
  return {borderColor};
30
41
  };
31
42
 
32
- export const renderFloatingView = (
33
- floatingValue?: string,
34
- floatingIconColor?: string,
35
- disabled?: boolean,
36
- floatingIcon?: string,
37
- ) => {
43
+ export const ErrorView: FC<{errorMessage?: string}> = ({errorMessage}) => {
44
+ const {theme} = useContext(ApplicationContext);
45
+ const errorColor = theme.colors.error.primary;
46
+ if (errorMessage) {
47
+ return (
48
+ <View style={styles.errorView}>
49
+ <View style={styles.errorIcon}>
50
+ <Icon color={errorColor} source="ic_error" size={16} />
51
+ </View>
52
+ <Text color={errorColor} typography={'description_s'}>
53
+ {errorMessage}
54
+ </Text>
55
+ </View>
56
+ );
57
+ }
58
+ return null;
59
+ };
60
+
61
+ export const FloatingView: FC<FloatingViewProps> = ({
62
+ floatingValue,
63
+ floatingIconColor,
64
+ disabled,
65
+ floatingIcon,
66
+ }) => {
38
67
  const {theme} = useContext(ApplicationContext);
39
68
 
40
69
  if (floatingValue) {
@@ -67,4 +96,5 @@ export const renderFloatingView = (
67
96
  </View>
68
97
  );
69
98
  }
99
+ return null;
70
100
  };
package/Input/index.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import Input from './Input';
2
2
  import TextArea from './TextArea';
3
+ import SearchInput from './SearchInput';
3
4
  import {TextInputProps} from 'react-native';
4
5
 
5
6
  export interface InputProps extends TextInputProps {
@@ -13,14 +14,18 @@ export interface InputProps extends TextInputProps {
13
14
  iconColor?: string;
14
15
  }
15
16
 
16
- export interface TextAreaProps extends TextInputProps {
17
- errorMessage: string;
18
- floatingValue: string;
19
- floatingIcon: string;
20
- disabled: boolean;
21
- floatingIconColor: string;
22
- placeholder: string;
23
- height: number;
17
+ type InputPropsWithoutSize = Omit<InputProps, 'size'>;
18
+
19
+ export interface TextAreaProps extends TextInputProps, InputPropsWithoutSize {
20
+ height?: number;
21
+ }
22
+
23
+ export interface SearchInputProps
24
+ extends TextInputProps,
25
+ InputPropsWithoutSize {
26
+ buttonText?: string;
27
+ showButtonText?: boolean;
28
+ showIcon?: boolean;
24
29
  }
25
30
 
26
- export {Input, TextArea};
31
+ export {Input, TextArea, SearchInput};
package/Input/styles.ts CHANGED
@@ -5,7 +5,6 @@ export default StyleSheet.create({
5
5
  //input style
6
6
  input: {width: '100%', paddingLeft: Spacing.M, height: '100%'},
7
7
  wrapper: {
8
- marginVertical: Spacing.M,
9
8
  width: '100%',
10
9
  },
11
10
  container: {
@@ -85,4 +84,35 @@ export default StyleSheet.create({
85
84
  flex: 1,
86
85
  marginBottom: Spacing.XS,
87
86
  },
87
+
88
+ //searchInput
89
+ searchInputWrapper: {
90
+ flexDirection: 'row',
91
+ borderRadius: Radius.XL,
92
+ borderWidth: 1,
93
+ paddingHorizontal: Spacing.S,
94
+ alignItems: 'center',
95
+ flex: 1,
96
+ },
97
+ searchInput: {
98
+ width: '100%',
99
+ height: 36,
100
+ marginLeft: Spacing.S,
101
+ },
102
+ searchInputView: {
103
+ flex: 1,
104
+ flexDirection: 'row',
105
+ alignItems: 'center',
106
+ },
107
+ iconSearchInput: {
108
+ width: 24,
109
+ height: 24,
110
+ marginLeft: Spacing.S,
111
+ },
112
+ searchInputContainer: {flexDirection: 'row', alignItems: 'center'},
113
+ textButton: {marginLeft: Spacing.L},
114
+ divider: {
115
+ width: 1,
116
+ marginLeft: Spacing.XS,
117
+ },
88
118
  });
@@ -1,5 +1,5 @@
1
1
  import React, {useContext} from 'react';
2
- import {StatusBar, StyleSheet, View} from 'react-native';
2
+ import {DeviceEventEmitter, StatusBar, StyleSheet, View} from 'react-native';
3
3
  import {ApplicationContext, NavigationButton} from './index';
4
4
  import {Colors, Styles} from '../Consts';
5
5
  import {Image} from '../Image';
@@ -31,6 +31,21 @@ const styles = StyleSheet.create({
31
31
  },
32
32
  });
33
33
 
34
+ const HeaderLeft = (props: any) => {
35
+ const {navigator} = useContext(ApplicationContext);
36
+ const goBack = () => {
37
+ const canGoBack = navigator?.ref.current?.canGoBack();
38
+ if (canGoBack) {
39
+ navigator?.ref.current?.goBack();
40
+ } else {
41
+ const currentTime = new Date().getTime();
42
+ const requestId = `navigationBackPress#${currentTime}`;
43
+ DeviceEventEmitter.emit('dismiss', {requestId});
44
+ }
45
+ };
46
+ return <NavigationButton icon="ic_back" {...props} onPress={goBack} />;
47
+ };
48
+
34
49
  const HeaderBackground: React.FC<HeaderBackgroundProps> = ({image}) => {
35
50
  const {theme} = useContext(ApplicationContext);
36
51
  return (
@@ -108,4 +123,4 @@ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
108
123
  return <View style={Styles.headerRightButton}>{renderAction()}</View>;
109
124
  };
110
125
 
111
- export {HeaderBackground, HeaderRightAction, HeaderCustom};
126
+ export {HeaderLeft, HeaderBackground, HeaderRightAction, HeaderCustom};
@@ -1,13 +1,12 @@
1
- import React, {useContext} from 'react';
1
+ import React from 'react';
2
2
  import {
3
3
  StackNavigationOptions,
4
4
  TransitionPresets,
5
5
  } from '@react-navigation/stack';
6
- import {HeaderBackground, HeaderCustom} from './Components';
6
+ import {HeaderBackground, HeaderCustom, HeaderLeft} from './Components';
7
7
  import {NavigationOptions, Theme} from './types';
8
8
  import {Colors} from '../Consts';
9
9
  import {Text} from '../Text';
10
- import {ApplicationContext, NavigationButton} from './index';
11
10
 
12
11
  const HeaderTitle = (props: any) => {
13
12
  return (
@@ -20,17 +19,6 @@ const HeaderTitle = (props: any) => {
20
19
  );
21
20
  };
22
21
 
23
- const HeaderLeft = (props: any) => {
24
- const {navigator} = useContext(ApplicationContext);
25
- const goBack = () => {
26
- const canGoBack = navigator?.ref.current?.canGoBack();
27
- if (canGoBack) {
28
- navigator?.ref.current?.goBack();
29
- }
30
- };
31
- return <NavigationButton icon="ic_back" {...props} onPress={goBack} />;
32
- };
33
-
34
22
  const getTintColor = (theme: Theme): any => {
35
23
  if (theme.assets?.headerBackground) {
36
24
  return {
@@ -93,9 +81,9 @@ const getModalOptions = (): StackNavigationOptions => {
93
81
  };
94
82
 
95
83
  const getOptions = (params: NavigationOptions, theme: Theme) => {
96
- let backTheme = {};
97
- let surfaceTheme = {};
98
- let titleTheme = {};
84
+ let backTheme: {};
85
+ let surfaceTheme: {};
86
+ let titleTheme: {};
99
87
 
100
88
  if (params.hiddenBack == true) {
101
89
  backTheme = {
@@ -126,6 +114,7 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
126
114
 
127
115
  if (params.customTitle) {
128
116
  titleTheme = {
117
+ headerTitleAlign: 'left',
129
118
  headerTitle: (props: any) => {
130
119
  return <HeaderCustom {...params.customTitle} {...props} />;
131
120
  },
@@ -7,7 +7,7 @@ import {Colors, Radius, Spacing} from '../Consts';
7
7
  import {ApplicationContext} from '../Navigation';
8
8
  import {ScreenSection, SectionItem} from '../Layout';
9
9
  import {Icon, IconSources} from '../Icon';
10
- import {string} from 'prop-types';
10
+ import {SearchInput} from '../Input';
11
11
 
12
12
  const ChooseOptionScreen = (
13
13
  data: string[] = [],
@@ -15,14 +15,22 @@ const ChooseOptionScreen = (
15
15
  onPress: (value: string) => void,
16
16
  ) => {
17
17
  const {theme} = useContext(ApplicationContext);
18
+ const [searchTerm, setSearchTerm] = useState('');
19
+ const [filteredData, setFilteredData] = useState<string[]>([]);
20
+
21
+ useEffect(() => {
22
+ let mapData = data;
23
+ if (optionType === 'color') {
24
+ mapData = Object.values(Colors);
25
+ }
26
+ if (optionType === 'icon') {
27
+ mapData = Object.keys(IconSources);
28
+ }
29
+
30
+ setFilteredData(mapData);
31
+ return () => {};
32
+ }, [filteredData]);
18
33
 
19
- let mapData = data;
20
- if (optionType === 'color') {
21
- mapData = Object.values(Colors);
22
- }
23
- if (optionType === 'icon') {
24
- mapData = Object.keys(IconSources);
25
- }
26
34
  const renderItemView = (item: string) => {
27
35
  switch (optionType) {
28
36
  case 'color': {
@@ -44,6 +52,13 @@ const ChooseOptionScreen = (
44
52
  }
45
53
  };
46
54
 
55
+ const onSearch = (text: string) => {
56
+ let newData = filteredData.map(i => i.includes(text));
57
+ if (text === '') {
58
+ newData = mapData;
59
+ }
60
+ };
61
+
47
62
  const renderItem = ({item, index}) => {
48
63
  const iconSource: {[key: string]: {uri: string}} = IconSources;
49
64
  let key = item;
@@ -58,7 +73,7 @@ const ChooseOptionScreen = (
58
73
  flexDirection: 'row',
59
74
  alignItems: 'center',
60
75
  marginBottom: Spacing.M,
61
- borderBottomWidth: index !== mapData.length - 1 ? 1 : 0,
76
+ borderBottomWidth: index !== filteredData.length - 1 ? 1 : 0,
62
77
  borderColor: theme.colors.border.default,
63
78
  paddingBottom: Spacing.M,
64
79
  }}>
@@ -70,8 +85,9 @@ const ChooseOptionScreen = (
70
85
  return (
71
86
  <ScreenSection>
72
87
  <SectionItem widthSpan={12}>
88
+ <SearchInput value={searchTerm} onChangeText={onSearch} />
73
89
  <FlatList
74
- data={mapData}
90
+ data={filteredData}
75
91
  renderItem={renderItem}
76
92
  keyExtractor={(item, index) => `${item.toString()} ${index}`}
77
93
  showsVerticalScrollIndicator={false}
@@ -138,7 +154,11 @@ const Playground: FC<PlaygroundProps> = ({params}) => {
138
154
  value={option}
139
155
  onChange={() => onChangeOptions(option, key)}
140
156
  groupValue={compProps?.[key]}
141
- style={{marginBottom: Spacing.S}}
157
+ style={{
158
+ marginBottom: Spacing.S,
159
+ marginRight: Spacing.M,
160
+ width: '25%',
161
+ }}
142
162
  />
143
163
  );
144
164
  })}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {
@@ -11,6 +11,7 @@
11
11
  ],
12
12
  "dependencies": {
13
13
  "react-native-safe-area-context": "3.1.4",
14
+ "react-native-linear-gradient": "2.5.6",
14
15
  "@react-navigation/bottom-tabs": "git+https://gitlab.com/dung.huynh1/react-navigation-bottom-tabs.git#main",
15
16
  "@react-navigation/core": "5.16.1",
16
17
  "@react-navigation/native": "5.9.8",