@momo-kits/foundation 0.80.8 → 0.81.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/Application/BottomSheet.tsx +212 -0
  2. package/Application/BottomTab/BottomTabBar.tsx +278 -0
  3. package/Application/BottomTab/index.tsx +143 -0
  4. package/Application/Components.tsx +384 -213
  5. package/Application/ModalScreen.tsx +14 -178
  6. package/Application/Navigation.ts +15 -19
  7. package/Application/NavigationContainer.tsx +66 -63
  8. package/Application/Navigator.ts +106 -53
  9. package/Application/StackScreen.tsx +123 -9
  10. package/Application/index.ts +19 -6
  11. package/Application/types.ts +83 -26
  12. package/Application/utils.tsx +62 -74
  13. package/Assets/icon.json +83 -5
  14. package/Assets/icon_bank.json +506 -0
  15. package/Assets/language.json +3 -1
  16. package/Badge/Badge.tsx +56 -0
  17. package/Badge/BadgeDot.tsx +11 -0
  18. package/Badge/BadgeRibbon.tsx +125 -0
  19. package/Badge/Shape.tsx +29 -0
  20. package/Badge/index.tsx +7 -0
  21. package/Badge/styles.ts +58 -0
  22. package/Badge/types.ts +63 -0
  23. package/Button/index.tsx +64 -28
  24. package/Button/styles.ts +19 -0
  25. package/CheckBox/index.tsx +37 -27
  26. package/CheckBox/types.ts +5 -3
  27. package/Consts/colors+spacing+radius.ts +18 -0
  28. package/Icon/index.tsx +14 -9
  29. package/Icon/types.ts +4 -3
  30. package/IconButton/index.tsx +24 -15
  31. package/Image/index.tsx +62 -47
  32. package/Image/styles.ts +1 -9
  33. package/Image/types.ts +5 -1
  34. package/Input/Input.tsx +104 -25
  35. package/Input/InputDropDown.tsx +115 -110
  36. package/Input/InputMoney.tsx +79 -18
  37. package/Input/InputOTP.tsx +190 -149
  38. package/Input/InputSearch.tsx +96 -44
  39. package/Input/InputTextArea.tsx +33 -17
  40. package/Input/common.tsx +26 -17
  41. package/Input/index.tsx +108 -41
  42. package/Input/styles.ts +5 -7
  43. package/Input/utils.ts +1 -1
  44. package/Layout/AnimatedInputSearch.tsx +44 -0
  45. package/Layout/Card.tsx +37 -13
  46. package/Layout/FloatingButton.tsx +168 -0
  47. package/Layout/GridSystem.tsx +2 -3
  48. package/Layout/Item.tsx +1 -2
  49. package/Layout/ItemList.tsx +55 -0
  50. package/Layout/ItemSectionList.tsx +39 -0
  51. package/Layout/Screen.tsx +404 -181
  52. package/Layout/Section.tsx +22 -22
  53. package/Layout/TextTyping.tsx +114 -0
  54. package/Layout/index.ts +12 -2
  55. package/Layout/styles.ts +46 -13
  56. package/Layout/types.ts +13 -5
  57. package/Layout/utils.ts +7 -12
  58. package/Loader/index.tsx +2 -0
  59. package/Pagination/PaginationDot.tsx +6 -1
  60. package/Pagination/PaginationNumber.tsx +7 -4
  61. package/Pagination/PaginationScroll.tsx +0 -1
  62. package/Pagination/PaginationWhiteDot.tsx +6 -1
  63. package/Pagination/styles.ts +3 -0
  64. package/Pagination/types.ts +2 -0
  65. package/Popup/PopupNotify.tsx +108 -40
  66. package/Popup/PopupPromotion.tsx +45 -10
  67. package/Popup/types.ts +13 -10
  68. package/Radio/index.tsx +35 -21
  69. package/Radio/types.ts +7 -5
  70. package/Skeleton/index.tsx +1 -1
  71. package/Switch/index.tsx +32 -19
  72. package/Switch/types.ts +5 -3
  73. package/Tag/index.tsx +2 -4
  74. package/Text/index.tsx +26 -6
  75. package/Text/styles.ts +38 -0
  76. package/Text/types.ts +25 -13
  77. package/Title/index.tsx +177 -64
  78. package/Title/styles.ts +48 -15
  79. package/Title/types.ts +16 -7
  80. package/code-scanner.js +125 -16
  81. package/index.ts +9 -0
  82. package/migrate_typo.js +56 -0
  83. package/package.json +8 -7
  84. package/publish.sh +21 -16
  85. package/tsconfig.json +1 -2
  86. package/verify.js +24 -6
  87. package/Application/BottomTab.tsx +0 -65
@@ -152,6 +152,10 @@ const Spacing = {
152
152
  M: 12,
153
153
  L: 16,
154
154
  XL: 24,
155
+ XXL: 32,
156
+ Size3XL: 48,
157
+ Size4XL: 56,
158
+ Size5XL: 64,
155
159
  };
156
160
 
157
161
  const Radius = {
@@ -209,6 +213,20 @@ const Shadow = {
209
213
  elevation: 6,
210
214
  },
211
215
  }),
216
+
217
+ Pink: Platform.select({
218
+ ios: {
219
+ shadowColor: '#e27eb5',
220
+ shadowOffset: {width: 0, height: 6},
221
+ shadowOpacity: 0.25,
222
+ shadowRadius: 8,
223
+ },
224
+ android: {
225
+ elevation: 16,
226
+ shadowColor: '#e27eb5',
227
+ shadowOpacity: 0.25,
228
+ },
229
+ }),
212
230
  };
213
231
 
214
232
  export {Colors, Spacing, Radius, Shadow};
package/Icon/index.tsx CHANGED
@@ -1,10 +1,16 @@
1
1
  import React, {useContext} from 'react';
2
2
  import IconSources from '../Assets/icon.json';
3
+ import IconBankSources from '../Assets/icon_bank.json';
3
4
  import {IconProps} from './types';
4
5
  import {ApplicationContext} from '../Application';
5
6
  import {Image} from '../Image';
6
7
 
7
- const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
8
+ const Icon: React.FC<IconProps> = ({
9
+ source = 'ic_back',
10
+ size = 24,
11
+ color,
12
+ style = {},
13
+ }) => {
8
14
  const {theme} = useContext(ApplicationContext);
9
15
 
10
16
  /**
@@ -18,20 +24,19 @@ const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
18
24
  return {uri: source};
19
25
  };
20
26
 
27
+ const tintColorProps = color !== null && {
28
+ tintColor: color ?? theme.colors.text.default,
29
+ };
30
+
21
31
  return (
22
32
  <Image
23
- accessibilityLabel={`Icon/${getIconSource()?.uri}`}
24
33
  loading={false}
25
34
  source={getIconSource()}
26
35
  style={[style, {width: size, height: size}]}
27
- tintColor={color ?? theme.colors.text.default}
36
+ resizeMode="contain"
37
+ {...tintColorProps}
28
38
  />
29
39
  );
30
40
  };
31
41
 
32
- Icon.defaultProps = {
33
- source: 'ic_back',
34
- size: 24,
35
- };
36
-
37
- export {Icon, IconSources};
42
+ export {Icon, IconSources, IconBankSources};
package/Icon/types.ts CHANGED
@@ -1,4 +1,5 @@
1
- import {ViewStyle} from 'react-native';
1
+ import {ImageStyle} from 'react-native-fast-image';
2
+ import {StyleProp} from 'react-native';
2
3
 
3
4
  export type IconProps = {
4
5
  /**
@@ -17,11 +18,11 @@ export type IconProps = {
17
18
  * Optional. Represents the color of the icon.
18
19
  * It can be any valid color in @momo-kits/foundation.
19
20
  */
20
- color?: string;
21
+ color?: string | null;
21
22
 
22
23
  /**
23
24
  * Optional. Used to apply custom styling to the Icon component.
24
25
  * Accepts an object of style properties.
25
26
  */
26
- style?: ViewStyle;
27
+ style?: StyleProp<ImageStyle>;
27
28
  };
@@ -5,7 +5,7 @@ import {
5
5
  TouchableOpacity,
6
6
  TouchableOpacityProps,
7
7
  } from 'react-native';
8
- import {ApplicationContext} from '../Application';
8
+ import {ApplicationContext, ComponentContext} from '../Application';
9
9
  import {Colors} from '../Consts';
10
10
  import {Icon} from '../Icon';
11
11
  import styles from './styles';
@@ -26,13 +26,17 @@ export interface IconButtonProps extends TouchableOpacityProps {
26
26
  * Optional. Defines the size of the IconButton.
27
27
  */
28
28
  size?: 'large' | 'small';
29
+
30
+ params?: any;
29
31
  }
30
32
 
31
33
  const IconButton: React.FC<IconButtonProps> = ({
32
- type,
34
+ type = 'primary',
33
35
  icon,
34
36
  size,
35
37
  onPress,
38
+ params,
39
+ accessibilityLabel,
36
40
  ...rest
37
41
  }) => {
38
42
  const {theme} = useContext(ApplicationContext);
@@ -121,20 +125,25 @@ const IconButton: React.FC<IconButtonProps> = ({
121
125
  const iconSize = size === 'small' ? 16 : 24;
122
126
 
123
127
  return (
124
- <TouchableOpacity
125
- {...rest}
126
- accessibilityLabel={`IconButton/${icon}`}
127
- activeOpacity={activeOpacity}
128
- onPress={onPressButton}
129
- style={buttonStyle}>
130
- <Icon size={iconSize} source={icon} color={getIconColor()} />
131
- </TouchableOpacity>
128
+ <ComponentContext.Provider
129
+ value={{
130
+ componentName: 'IconButton',
131
+ params,
132
+ state: type === 'disabled' ? 'disabled' : 'enabled',
133
+ componentId: accessibilityLabel,
134
+ componentValue: icon,
135
+ action: 'click',
136
+ }}>
137
+ <TouchableOpacity
138
+ {...rest}
139
+ accessibilityLabel={accessibilityLabel}
140
+ activeOpacity={activeOpacity}
141
+ onPress={onPressButton}
142
+ style={buttonStyle}>
143
+ <Icon size={iconSize} source={icon} color={getIconColor()} />
144
+ </TouchableOpacity>
145
+ </ComponentContext.Provider>
132
146
  );
133
147
  };
134
148
 
135
- IconButton.defaultProps = {
136
- type: 'primary',
137
- disabled: false,
138
- };
139
-
140
149
  export {IconButton};
package/Image/index.tsx CHANGED
@@ -1,82 +1,97 @@
1
- import React, {useContext, useState} from 'react';
2
- import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native';
3
- import FastImage from 'react-native-fast-image';
1
+ import React, {useContext, useEffect, useRef, useState} from 'react';
2
+ import {StyleSheet, View} from 'react-native';
3
+ import FastImage, {Source} from 'react-native-fast-image';
4
4
  import styles from './styles';
5
- import {ApplicationContext} from '../Application';
5
+ import {
6
+ ApplicationContext,
7
+ ComponentContext,
8
+ MiniAppContext,
9
+ } from '../Application';
6
10
  import {Skeleton} from '../Skeleton';
7
11
  import {Icon} from '../Icon';
8
12
  import {Styles} from '../Consts';
9
- import {FastImagePropsWithoutStyle} from './types';
13
+ import {ImageProps} from './types';
10
14
 
11
- export interface ImageProps extends FastImagePropsWithoutStyle {
12
- style?: StyleProp<ViewStyle>;
13
- loading?: boolean;
14
- accessibilityLabel?: string;
15
- }
15
+ type Status = 'success' | 'loading' | 'error';
16
16
 
17
17
  const Image: React.FC<ImageProps> = ({
18
18
  style,
19
19
  source,
20
+ loading = true,
21
+ children,
20
22
  accessibilityLabel,
21
23
  ...rest
22
24
  }) => {
23
25
  const {theme} = useContext(ApplicationContext);
24
- const [loading, setLoading] = useState(rest.loading);
25
- const [fail, setFail] = useState(false);
26
+ const app = useContext<any>(MiniAppContext);
27
+ const component = useContext<any>(ComponentContext);
28
+ const error = useRef(false);
29
+ const [status, setStatus] = useState<Status>('success');
30
+
31
+ const test: any = {
32
+ accessibilityLabel: accessibilityLabel || `img|${(source as Source).uri}`,
33
+ };
34
+
35
+ useEffect(() => {
36
+ if (app.enableAutoId) {
37
+ component?.addChildren?.(test.accessibilityLabel, 'add');
38
+ return () => component?.addChildren?.(test.accessibilityLabel, 'remove');
39
+ }
40
+ }, []);
26
41
 
27
42
  /**
28
43
  * render content loading | fail | rendered
29
- * @returns {JSX.Element}
30
44
  */
31
45
  const renderContent = () => {
32
- if (loading || fail) {
33
- let content = (
34
- <Skeleton style={[StyleSheet.absoluteFill, styles.image]} />
35
- );
36
- if (fail) {
46
+ if (status === 'loading' || status === 'error') {
47
+ let content = <Skeleton />;
48
+ if (status === 'error') {
37
49
  content = (
38
- <View style={Styles.flexCenter}>
39
- <Icon source="media_fail" color={theme.colors.text.disable} />
40
- </View>
50
+ <Icon source="media_fail" color={theme.colors.text.disable} />
41
51
  );
42
52
  }
43
53
  return (
44
- <View
45
- style={[
46
- StyleSheet.absoluteFill,
47
- styles.image,
48
- {backgroundColor: theme.colors.background.disable},
49
- ]}>
54
+ <View style={[StyleSheet.absoluteFill, Styles.flexCenter]}>
50
55
  {content}
51
56
  </View>
52
57
  );
53
58
  }
59
+ return children;
54
60
  };
55
61
 
56
62
  return (
57
- <View
63
+ <FastImage
64
+ {...rest}
65
+ {...test}
66
+ source={source}
58
67
  style={[styles.container, style]}
59
- accessibilityLabel={`Image/${
60
- accessibilityLabel ?? (typeof source === 'number' ? source : source.uri)
61
- }`}>
62
- <FastImage
63
- {...rest}
64
- source={source}
65
- style={styles.image}
66
- onLoad={() => {
67
- setFail(false);
68
- setLoading(rest.loading);
69
- }}
70
- onLoadEnd={() => setLoading(false)}
71
- onError={() => setFail(true)}
72
- />
68
+ onProgress={() => {
69
+ error.current = false;
70
+ if (status !== 'loading' && loading) {
71
+ setStatus('loading');
72
+ }
73
+ }}
74
+ onLoadStart={() => {
75
+ error.current = false;
76
+ }}
77
+ onLoad={() => {
78
+ error.current = false;
79
+ }}
80
+ onLoadEnd={() => {
81
+ let current: Status = 'success';
82
+ if (error.current) {
83
+ current = 'error';
84
+ }
85
+ if (status !== current) {
86
+ setStatus(current);
87
+ }
88
+ }}
89
+ onError={() => {
90
+ error.current = true;
91
+ }}>
73
92
  {renderContent()}
74
- </View>
93
+ </FastImage>
75
94
  );
76
95
  };
77
96
 
78
- Image.defaultProps = {
79
- loading: true,
80
- };
81
-
82
97
  export {Image};
package/Image/styles.ts CHANGED
@@ -1,13 +1,5 @@
1
1
  import {StyleSheet} from 'react-native';
2
2
 
3
3
  export default StyleSheet.create({
4
- container: {
5
- overflow: 'hidden',
6
- alignItems: 'center',
7
- justifyContent: 'center',
8
- },
9
- image: {
10
- width: '100%',
11
- height: '100%',
12
- },
4
+ container: {},
13
5
  });
package/Image/types.ts CHANGED
@@ -1,3 +1,7 @@
1
1
  import {FastImageProps} from 'react-native-fast-image';
2
2
 
3
- export type FastImagePropsWithoutStyle = Omit<FastImageProps, 'style'>;
3
+ export interface ImageProps extends FastImageProps {
4
+ loading?: boolean;
5
+ accessibilityLabel?: string;
6
+ params?: any;
7
+ }
package/Input/Input.tsx CHANGED
@@ -1,18 +1,25 @@
1
- import React, {forwardRef, useContext, useRef, useState} from 'react';
1
+ import React, {
2
+ forwardRef,
3
+ useContext,
4
+ useImperativeHandle,
5
+ useRef,
6
+ useState,
7
+ } from 'react';
2
8
  import {
3
9
  NativeSyntheticEvent,
10
+ Platform,
4
11
  TextInput,
5
12
  TextInputFocusEventData,
6
13
  TouchableOpacity,
7
14
  View,
8
15
  } from 'react-native';
9
- import {ApplicationContext} from '../Application';
10
- import styles from './styles';
16
+ import {ApplicationContext, ComponentContext} from '../Application';
17
+ import {Icon} from '../Icon';
18
+ import {Loader} from '../Loader';
11
19
  import {ErrorView, FloatingView, getBorderColor, getSizeStyle} from './common';
12
20
  import {InputProps} from './index';
13
- import {Icon} from '../Icon';
21
+ import styles from './styles';
14
22
  import {checkTyping} from './utils';
15
- import {Loader} from '../Loader';
16
23
 
17
24
  const Input = forwardRef(
18
25
  (
@@ -21,20 +28,29 @@ const Input = forwardRef(
21
28
  onChangeText,
22
29
  floatingValue,
23
30
  floatingIcon,
24
- size,
31
+ size = 'small',
25
32
  placeholder,
26
33
  onBlur,
27
34
  onFocus,
28
35
  errorMessage,
29
36
  icon,
30
- disabled,
37
+ disabled = false,
31
38
  floatingIconColor,
32
39
  iconColor,
33
- required,
40
+ required = false,
34
41
  errorSpacing,
35
- loading,
42
+ loading = false,
36
43
  leadingIcon,
37
44
  leadingIconColor,
45
+ fontWeight = 'Regular',
46
+ onPressIcon,
47
+ secureTextEntry,
48
+ keyboardType,
49
+ style,
50
+ params,
51
+ hintText,
52
+ accessibilityLabel,
53
+ editable = true,
38
54
  ...props
39
55
  }: InputProps,
40
56
  ref,
@@ -42,7 +58,8 @@ const Input = forwardRef(
42
58
  const {theme} = useContext(ApplicationContext);
43
59
  const [focused, setFocused] = useState(false);
44
60
  const [haveValue, setHaveValue] = useState(!!value || !!props.defaultValue);
45
- const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
61
+ const [secureTextInput, setSecureTextInput] = useState(secureTextEntry);
62
+ const inputRef = useRef<TextInput | null>(null);
46
63
 
47
64
  const onClearText = () => {
48
65
  inputRef?.current?.clear();
@@ -64,17 +81,49 @@ const Input = forwardRef(
64
81
  onBlur?.(e);
65
82
  };
66
83
 
84
+ useImperativeHandle(ref, () => {
85
+ return {
86
+ clear: onClearText,
87
+ focus: () => inputRef.current?.focus(),
88
+ blur: () => inputRef.current?.blur(),
89
+ setText: (text: string) => _onChangeText(text),
90
+ };
91
+ });
92
+
67
93
  const renderIcon = (color: string | undefined) => {
68
94
  if (loading) {
69
- return <Loader type={'spinner'} color={color} />;
95
+ return <Loader type={'spinner'} color={color} style={styles.icon} />;
96
+ }
97
+ if (secureTextEntry) {
98
+ return (
99
+ <TouchableOpacity
100
+ onPress={() => setSecureTextInput(!secureTextInput)}
101
+ style={styles.icon}>
102
+ <Icon
103
+ color={color}
104
+ size={24}
105
+ source={
106
+ secureTextInput ? '24_security_eye_off' : '24_security_eye_open'
107
+ }
108
+ />
109
+ </TouchableOpacity>
110
+ );
70
111
  }
71
112
  if (icon) {
72
- return <Icon color={color} source={icon} size={24} />;
113
+ return (
114
+ <TouchableOpacity
115
+ onPress={onPressIcon}
116
+ disabled={!onPressIcon}
117
+ style={styles.icon}>
118
+ <Icon color={color} source={icon} size={24} />
119
+ </TouchableOpacity>
120
+ );
73
121
  }
74
122
  };
75
123
 
76
124
  const renderInputView = () => {
77
125
  const disabledColor = theme.colors.text.disable;
126
+ const secure = secureTextInput && secureTextEntry;
78
127
  let textColor = theme.colors.text.default;
79
128
  let placeholderColor = theme.colors.text.hint;
80
129
  let iconTintColor = iconColor;
@@ -85,6 +134,13 @@ const Input = forwardRef(
85
134
  iconTintColor = disabledColor;
86
135
  }
87
136
 
137
+ if (secureTextEntry) {
138
+ keyboardType = Platform.select({
139
+ ios: 'ascii-capable',
140
+ android: 'visible-password',
141
+ });
142
+ }
143
+
88
144
  return (
89
145
  <View
90
146
  style={[
@@ -112,16 +168,18 @@ const Input = forwardRef(
112
168
  )}
113
169
  <TextInput
114
170
  {...props}
115
- accessibilityLabel={`TextInput`}
116
- editable={!disabled}
171
+ accessibilityLabel={accessibilityLabel}
172
+ editable={editable && !disabled}
173
+ secureTextEntry={secure}
117
174
  textAlignVertical="center"
118
175
  ref={inputRef}
119
176
  style={[
120
177
  styles.input,
121
178
  {
122
179
  color: textColor,
123
- fontFamily: `${theme.font}-Regular`,
180
+ fontFamily: `${theme.font}-${fontWeight}`,
124
181
  },
182
+ secure && haveValue && {fontSize: size === 'small' ? 18 : 22},
125
183
  ]}
126
184
  textBreakStrategy="highQuality"
127
185
  value={value}
@@ -131,6 +189,7 @@ const Input = forwardRef(
131
189
  placeholder={placeholder}
132
190
  selectionColor={theme.colors.primary}
133
191
  placeholderTextColor={placeholderColor}
192
+ keyboardType={keyboardType}
134
193
  />
135
194
  </View>
136
195
  <View style={styles.iconView}>
@@ -151,19 +210,39 @@ const Input = forwardRef(
151
210
  );
152
211
  };
153
212
 
213
+ let inputState = 'active';
214
+
215
+ if (value && value?.length > 0) {
216
+ inputState = 'filled';
217
+ }
218
+ if (errorMessage && errorMessage?.length > 0) {
219
+ inputState = 'error';
220
+ }
221
+
222
+ if (disabled) {
223
+ inputState = 'disabled';
224
+ }
225
+
154
226
  return (
155
- <View
156
- style={styles.wrapper}
157
- accessibilityLabel={`Input/${floatingValue}`}>
158
- {renderInputView()}
159
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
160
- </View>
227
+ <ComponentContext.Provider
228
+ value={{
229
+ componentName: 'Input',
230
+ params,
231
+ componentLabel: floatingValue,
232
+ state: inputState,
233
+ componentId: accessibilityLabel,
234
+ }}>
235
+ <View style={[style, styles.wrapper]}>
236
+ {renderInputView()}
237
+ <ErrorView
238
+ errorMessage={errorMessage}
239
+ errorSpacing={errorSpacing}
240
+ hintText={hintText}
241
+ />
242
+ </View>
243
+ </ComponentContext.Provider>
161
244
  );
162
245
  },
163
246
  );
164
247
 
165
- Input.defaultProps = {
166
- size: 'small',
167
- };
168
-
169
248
  export default Input;