@momo-kits/foundation 0.80.7 → 0.80.8-beta.10

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.
@@ -1,4 +1,4 @@
1
- import React, {useContext, useEffect, useState} from 'react';
1
+ import React, {Fragment, useContext, useEffect, useState} from 'react';
2
2
  import {
3
3
  Alert,
4
4
  Animated,
@@ -6,14 +6,15 @@ import {
6
6
  Platform,
7
7
  StatusBar,
8
8
  StyleSheet,
9
+ TouchableOpacity,
9
10
  View,
10
- TouchableOpacity as TouchableRN,
11
11
  } from 'react-native';
12
12
  import {TouchableOpacity as TouchableGesture} from 'react-native-gesture-handler';
13
13
  import {ApplicationContext} from './index';
14
14
  import {Colors, Radius, Spacing, Styles} from '../Consts';
15
15
  import {Image} from '../Image';
16
16
  import {
17
+ HeaderAnimatedProps,
17
18
  HeaderBackgroundProps,
18
19
  HeaderBackProps,
19
20
  HeaderToolkitProps,
@@ -24,7 +25,8 @@ import {scaleSize, Text} from '../Text';
24
25
  import {Icon} from '../Icon';
25
26
  import {PopupNotify} from '../Popup';
26
27
 
27
- const Touchable = Platform.OS === 'android' ? TouchableGesture : TouchableRN;
28
+ const Touchable =
29
+ Platform.OS === 'android' ? TouchableGesture : TouchableOpacity;
28
30
 
29
31
  const styles = StyleSheet.create({
30
32
  navigationButton: {
@@ -271,22 +273,23 @@ const HeaderCustom: React.FC<TitleCustomProps> = ({
271
273
  };
272
274
 
273
275
  const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
274
- const validType = (item: any) => {
275
- if (__DEV__ && item.type !== NavigationButton) {
276
+ const validateType = (child: React.ReactElement) => {
277
+ const valid = child?.type === NavigationButton || child?.type == Fragment;
278
+ if (__DEV__ && !valid) {
276
279
  Alert.alert(
277
280
  'Rule',
278
281
  'HeaderRightAction contains element type of NavigationButton, Please check again.',
279
282
  );
280
- return <View />;
281
283
  }
282
- return item;
284
+ return child;
283
285
  };
286
+
284
287
  const renderAction = () => {
285
288
  if (Array.isArray(children)) {
286
289
  return children.map((child, index) => {
287
290
  return (
288
- <View key={index} style={styles.headerButton}>
289
- {React.cloneElement(validType(child), {...restProps})}
291
+ <View key={`HeaderRightAction ${index}`} style={styles.headerButton}>
292
+ {React.cloneElement(validateType(child), {...restProps})}
290
293
  </View>
291
294
  );
292
295
  });
@@ -294,7 +297,7 @@ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
294
297
 
295
298
  return (
296
299
  <View style={styles.headerButton}>
297
- {React.cloneElement(validType(children), {...restProps})}
300
+ {React.cloneElement(validateType(children), {...restProps})}
298
301
  </View>
299
302
  );
300
303
  };
@@ -415,6 +418,41 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
415
418
  return <View />;
416
419
  };
417
420
 
421
+ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
422
+ animatedValue,
423
+ image,
424
+ onPress,
425
+ }) => {
426
+ const scale = animatedValue.interpolate({
427
+ inputRange: [-300, 0, 300],
428
+ outputRange: [2, 1, 1],
429
+ extrapolate: 'clamp',
430
+ });
431
+ const opacity = animatedValue.interpolate({
432
+ inputRange: [0, 150, 300],
433
+ outputRange: [1, 0.5, 0],
434
+ extrapolate: 'clamp',
435
+ });
436
+
437
+ return (
438
+ <TouchableOpacity onPress={onPress}>
439
+ <Animated.View
440
+ style={{
441
+ aspectRatio: 1.75,
442
+ opacity: opacity,
443
+ transform: [{scale: scale}],
444
+ }}>
445
+ <Image
446
+ source={{
447
+ uri: image,
448
+ }}
449
+ style={{width: '100%', height: '100%'}}
450
+ />
451
+ </Animated.View>
452
+ </TouchableOpacity>
453
+ );
454
+ };
455
+
418
456
  export {
419
457
  NavigationButton,
420
458
  HeaderTitle,
@@ -423,4 +461,5 @@ export {
423
461
  HeaderRightAction,
424
462
  HeaderToolkitAction,
425
463
  HeaderCustom,
464
+ HeaderAnimated,
426
465
  };
@@ -193,6 +193,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
193
193
  />
194
194
  );
195
195
  },
196
+ headerTintColor: theme.colors.text.default,
196
197
  headerBackground: () => (
197
198
  <HeaderBackground backgroundColor={backgroundColor} />
198
199
  ),
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  import {NavigationProp} from '@react-navigation/native';
2
3
  import {Alert} from 'react-native';
3
4
  import {NavigationOptions, Theme} from './types';
@@ -16,7 +17,7 @@ class Navigation {
16
17
 
17
18
  private filterParams = (params: NavigationOptions) => {
18
19
  if (params.headerRight) {
19
- const headerRight = params.headerRight?.();
20
+ const headerRight = params.headerRight?.({}) as React.ReactElement;
20
21
  const type = headerRight?.type;
21
22
  if (type !== HeaderRightAction && type !== HeaderToolkitAction) {
22
23
  Alert.alert(
@@ -93,12 +93,12 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
93
93
  name="Stack"
94
94
  component={StackScreen}
95
95
  initialParams={{screen}}
96
- options={{...getStackOptions(theme), ...options}}
96
+ options={{...getStackOptions(), ...options}}
97
97
  />
98
98
  <Stack.Screen
99
99
  name="Dialog"
100
100
  component={StackScreen}
101
- options={getDialogOptions(theme)}
101
+ options={getDialogOptions()}
102
102
  initialParams={{screen}}
103
103
  />
104
104
  <Stack.Screen
@@ -1,24 +1,31 @@
1
1
  import {NavigationContainer} from './NavigationContainer';
2
2
  import Screen from '../Layout/Screen';
3
3
  import {
4
- HeaderRightAction,
5
4
  NavigationButton,
6
- HeaderToolkitAction,
7
5
  HeaderTitle,
6
+ HeaderLeft,
7
+ HeaderBackground,
8
+ HeaderRightAction,
9
+ HeaderToolkitAction,
10
+ HeaderCustom,
11
+ HeaderAnimated,
8
12
  } from './Components';
9
13
  import BottomTab from './BottomTab';
10
14
  import {createContext} from 'react';
11
15
  import {defaultContext} from '../Consts';
12
16
 
13
17
  const ApplicationContext = createContext(defaultContext);
14
-
15
18
  export {
16
19
  NavigationContainer,
17
20
  ApplicationContext,
18
21
  Screen,
22
+ BottomTab,
19
23
  NavigationButton,
24
+ HeaderTitle,
25
+ HeaderLeft,
26
+ HeaderBackground,
20
27
  HeaderRightAction,
21
28
  HeaderToolkitAction,
22
- HeaderTitle,
23
- BottomTab,
29
+ HeaderCustom,
30
+ HeaderAnimated,
24
31
  };
@@ -1,4 +1,5 @@
1
1
  import {Animated} from 'react-native';
2
+ import {StackNavigationOptions} from '@react-navigation/stack';
2
3
  import React from 'react';
3
4
  import Navigator from './Navigator';
4
5
  import {PopupNotifyProps} from '../Popup/types';
@@ -119,19 +120,15 @@ export type NavigationButtonProps = {
119
120
  accessibilityLabel?: string;
120
121
  };
121
122
 
122
- export type NavigationOptions = {
123
+ export interface NavigationOptions extends StackNavigationOptions {
123
124
  preventBack?: PopupNotifyProps;
124
125
  onPressLeftHeader?: () => void;
125
126
  surface?: boolean;
126
- headerTransparent?: boolean;
127
127
  hiddenBack?: boolean;
128
- title?: string;
129
- headerTitle?: (props?: any) => React.ReactElement;
130
128
  headerTitleAlign?: 'left' | 'center';
131
129
  customTitle?: TitleCustomProps;
132
- headerRight?: (props?: any) => React.ReactElement;
133
130
  animatedValue?: Animated.Value;
134
- };
131
+ }
135
132
 
136
133
  export interface HeaderBackProps extends NavigationButtonProps {
137
134
  preventBack?: PopupNotifyProps;
@@ -164,6 +161,12 @@ export type HeaderToolkitProps = {
164
161
  onAction?: (action: string) => void;
165
162
  };
166
163
 
164
+ export type HeaderAnimatedProps = {
165
+ animatedValue: Animated.Value;
166
+ image: string;
167
+ onPress?: () => void;
168
+ };
169
+
167
170
  export type BottomTabItemProps = {
168
171
  name: string;
169
172
  label: string;
@@ -13,35 +13,24 @@ import {
13
13
  import {NavigationOptions, Theme} from './types';
14
14
  import {Colors} from '../Consts';
15
15
 
16
- const getTintColor = (theme: Theme): any => {
17
- if (theme.assets?.headerBackground) {
18
- return {
19
- headerTintColor: Colors.black_01,
20
- };
21
- }
22
- return {
23
- headerTintColor: theme.colors.text.default,
24
- };
25
- };
26
-
27
- const getStackOptions = (theme: Theme): StackNavigationOptions => {
16
+ const getStackOptions = (): StackNavigationOptions => {
28
17
  return {
29
18
  headerTitleAlign: 'left',
30
19
  headerTitle: HeaderTitle,
31
- headerBackground: HeaderBackground,
20
+ headerBackground: (props: any) => <HeaderBackground {...props} />,
32
21
  headerLeft: (props: any) => <HeaderLeft {...props} />,
33
22
  headerRight: (props: any) => <HeaderToolkitAction {...props} />,
34
- ...getTintColor(theme),
23
+ headerTintColor: Colors.black_01,
35
24
  };
36
25
  };
37
26
 
38
- const getDialogOptions = (theme: Theme): StackNavigationOptions => {
27
+ const getDialogOptions = (): StackNavigationOptions => {
39
28
  return {
40
29
  headerTitleAlign: 'left',
41
30
  headerTitle: HeaderTitle,
42
31
  headerLeft: (props: any) => <HeaderLeft {...props} />,
43
- headerBackground: HeaderBackground,
44
- ...getTintColor(theme),
32
+ headerBackground: (props: any) => <HeaderBackground {...props} />,
33
+ headerTintColor: Colors.black_01,
45
34
  ...TransitionPresets.ModalTransition,
46
35
  };
47
36
  };
@@ -72,54 +61,47 @@ const getModalOptions = (): StackNavigationOptions => {
72
61
  };
73
62
 
74
63
  const getOptions = (params: NavigationOptions, theme: Theme) => {
75
- let backgroundProps = {};
76
- let titleProps = {};
77
64
  let options = {};
78
65
 
79
- if (typeof params.onPressLeftHeader === 'function') {
66
+ if (
67
+ typeof params.onPressLeftHeader === 'function' ||
68
+ params.preventBack !== undefined ||
69
+ typeof params.hiddenBack === 'boolean'
70
+ ) {
80
71
  options = {
81
72
  ...options,
82
- headerLeft: (props: any) => (
83
- <HeaderLeft
84
- {...props}
85
- preventBack={params.preventBack}
86
- onPressLeftHeader={params.onPressLeftHeader}
87
- />
88
- ),
73
+ headerLeft: params.hiddenBack
74
+ ? null
75
+ : (props: any) => (
76
+ <HeaderLeft
77
+ {...props}
78
+ preventBack={params.preventBack}
79
+ onPressLeftHeader={params.onPressLeftHeader}
80
+ />
81
+ ),
89
82
  };
90
83
  }
91
84
 
92
- if (params.preventBack) {
93
- options = {
94
- ...options,
95
- headerLeft: (props: any) => (
96
- <HeaderLeft {...props} preventBack={params.preventBack} />
97
- ),
98
- };
99
- }
100
-
101
- if (params.surface == true) {
102
- options = {
103
- ...options,
104
- ...getTintColor({
105
- ...theme,
106
- assets: {...theme.assets, headerBackground: undefined},
107
- }),
108
- };
109
- backgroundProps = {
110
- ...backgroundProps,
111
- image: null,
112
- backgroundColor: theme.colors.background.surface,
113
- useBorder: true,
114
- };
115
- } else {
116
- backgroundProps = {};
117
- options = {...options, ...getTintColor(theme)};
118
- }
119
-
120
- if (params.animatedValue) {
121
- backgroundProps = {...backgroundProps, animatedValue: params.animatedValue};
122
- titleProps = {...titleProps, animatedValue: params.animatedValue};
85
+ if (typeof params.surface == 'boolean') {
86
+ if (params.surface) {
87
+ options = {
88
+ ...options,
89
+ headerTintColor: theme.colors.text.default,
90
+ headerBackground: () => (
91
+ <HeaderBackground
92
+ image={null}
93
+ backgroundColor={theme.colors.background.surface}
94
+ useBorder={true}
95
+ />
96
+ ),
97
+ };
98
+ } else {
99
+ options = {
100
+ ...options,
101
+ headerTintColor: Colors.black_01,
102
+ headerBackground: HeaderBackground,
103
+ };
104
+ }
123
105
  }
124
106
 
125
107
  if (params.customTitle) {
@@ -130,26 +112,11 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
130
112
  return <HeaderCustom {...params.customTitle} {...props} />;
131
113
  },
132
114
  };
133
- } else if (!params.headerTitle) {
134
- options = {
135
- ...options,
136
- headerTitle: (props: any) => {
137
- return <HeaderTitle {...titleProps} {...props} />;
138
- },
139
- };
140
- }
141
-
142
- if (params.hiddenBack) {
143
- options = {
144
- ...options,
145
- headerLeft: null,
146
- };
147
115
  }
148
116
 
149
117
  return {
150
118
  ...params,
151
119
  ...options,
152
- headerBackground: () => <HeaderBackground {...backgroundProps} />,
153
120
  };
154
121
  };
155
122
 
package/Input/Input.tsx CHANGED
@@ -35,6 +35,7 @@ const Input = forwardRef(
35
35
  loading,
36
36
  leadingIcon,
37
37
  leadingIconColor,
38
+ style,
38
39
  ...props
39
40
  }: InputProps,
40
41
  ref,
@@ -43,6 +44,7 @@ const Input = forwardRef(
43
44
  const [focused, setFocused] = useState(false);
44
45
  const [haveValue, setHaveValue] = useState(!!value || !!props.defaultValue);
45
46
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
47
+ const accessibilityLabel = `Input/${floatingValue ?? placeholder}`;
46
48
 
47
49
  const onClearText = () => {
48
50
  inputRef?.current?.clear();
@@ -112,7 +114,7 @@ const Input = forwardRef(
112
114
  )}
113
115
  <TextInput
114
116
  {...props}
115
- accessibilityLabel={`TextInput`}
117
+ accessibilityLabel={accessibilityLabel}
116
118
  editable={!disabled}
117
119
  textAlignVertical="center"
118
120
  ref={inputRef}
@@ -153,8 +155,8 @@ const Input = forwardRef(
153
155
 
154
156
  return (
155
157
  <View
156
- style={styles.wrapper}
157
- accessibilityLabel={`Input/${floatingValue}`}>
158
+ style={[style, styles.wrapper]}
159
+ accessibilityLabel={accessibilityLabel}>
158
160
  {renderInputView()}
159
161
  <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
160
162
  </View>
@@ -1,4 +1,4 @@
1
- import React, {forwardRef, useContext, useRef} from 'react';
1
+ import React, {useContext} from 'react';
2
2
  import {TextInput, TouchableOpacity, View} from 'react-native';
3
3
  import {ApplicationContext} from '../Application';
4
4
  import styles from './styles';
@@ -8,117 +8,113 @@ import {Icon} from '../Icon';
8
8
  import {Loader} from '../Loader';
9
9
  import {Styles} from '../Consts';
10
10
 
11
- const InputDropDown = forwardRef(
12
- (
13
- {
14
- value,
15
- floatingValue,
16
- floatingIcon,
17
- size,
18
- onPress,
19
- placeholder,
20
- errorMessage,
21
- icon = 'arrow_chevron_down_small',
22
- disabled,
23
- floatingIconColor,
24
- iconColor,
25
- required,
26
- errorSpacing,
27
- loading,
28
- leadingIcon,
29
- leadingIconColor,
30
- ...props
31
- }: InputDropDownProps,
32
- ref,
33
- ) => {
34
- const {theme} = useContext(ApplicationContext);
35
- const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
36
- const full = !!value || !!placeholder;
37
- const renderIcon = (color: string | undefined) => {
38
- if (loading) {
39
- return <Loader type={'spinner'} color={color} />;
40
- }
41
- if (icon) {
42
- return <Icon color={color} source={icon} size={24} />;
43
- }
44
- };
11
+ const InputDropDown = ({
12
+ value,
13
+ floatingValue,
14
+ floatingIcon,
15
+ size,
16
+ onPress,
17
+ placeholder,
18
+ errorMessage,
19
+ icon = 'arrow_chevron_down_small',
20
+ disabled,
21
+ floatingIconColor,
22
+ iconColor,
23
+ required,
24
+ errorSpacing,
25
+ loading,
26
+ leadingIcon,
27
+ leadingIconColor,
28
+ style,
29
+ ...props
30
+ }: InputDropDownProps) => {
31
+ const {theme} = useContext(ApplicationContext);
32
+ const full = !!value || !!placeholder;
33
+ const accessibilityLabel = `InputDropDown/${floatingValue ?? placeholder}`;
45
34
 
46
- const renderInputView = () => {
47
- const disabledColor = theme.colors.text.disable;
48
- let textColor = theme.colors.text.default;
49
- let placeholderColor = theme.colors.text.hint;
50
- let iconTintColor = iconColor;
35
+ const renderIcon = (color: string | undefined) => {
36
+ if (loading) {
37
+ return <Loader type={'spinner'} color={color} />;
38
+ }
39
+ if (icon) {
40
+ return <Icon color={color} source={icon} size={24} />;
41
+ }
42
+ };
51
43
 
52
- if (disabled) {
53
- textColor = disabledColor;
54
- placeholderColor = disabledColor;
55
- iconTintColor = disabledColor;
56
- }
44
+ const renderInputView = () => {
45
+ const disabledColor = theme.colors.text.disable;
46
+ let textColor = theme.colors.text.default;
47
+ let placeholderColor = theme.colors.text.hint;
48
+ let iconTintColor = iconColor;
57
49
 
58
- return (
59
- <View
60
- style={[
61
- styles.inputWrapper,
62
- {backgroundColor: theme.colors.background.surface},
63
- getSizeStyle(size),
64
- getBorderColor(theme, false, errorMessage, disabled),
65
- ]}>
66
- <FloatingView
67
- floatingValue={floatingValue}
68
- floatingIconColor={floatingIconColor}
69
- disabled={disabled}
70
- required={required}
71
- floatingIcon={floatingIcon}
72
- />
73
- <View style={full ? styles.inputView : Styles.row}>
74
- {!!leadingIcon && (
75
- <View style={styles.leadingIconContainer}>
76
- <Icon
77
- color={leadingIconColor}
78
- source={leadingIcon}
79
- size={size === 'small' ? 24 : 32}
80
- />
81
- </View>
82
- )}
83
- {full && (
84
- <TextInput
85
- {...props}
86
- onPressIn={onPress}
87
- accessibilityLabel={`TextInput`}
88
- editable={false}
89
- textAlignVertical="top"
90
- ref={inputRef}
91
- style={[
92
- styles.input,
93
- {
94
- color: textColor,
95
- fontFamily: `${theme.font}-Regular`,
96
- },
97
- ]}
98
- textBreakStrategy="highQuality"
99
- value={value}
100
- placeholder={placeholder}
101
- selectionColor={theme.colors.primary}
102
- placeholderTextColor={placeholderColor}
103
- />
104
- )}
105
- </View>
106
- <View style={styles.iconView}>{renderIcon(iconTintColor)}</View>
107
- </View>
108
- );
109
- };
50
+ if (disabled) {
51
+ textColor = disabledColor;
52
+ placeholderColor = disabledColor;
53
+ iconTintColor = disabledColor;
54
+ }
110
55
 
111
56
  return (
112
- <TouchableOpacity
113
- onPress={onPress}
114
- style={full && styles.wrapper}
115
- accessibilityLabel={`InputDropDown/${floatingValue}`}>
116
- {renderInputView()}
117
- <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
118
- </TouchableOpacity>
57
+ <View
58
+ style={[
59
+ styles.inputWrapper,
60
+ {backgroundColor: theme.colors.background.surface},
61
+ getSizeStyle(size),
62
+ getBorderColor(theme, false, errorMessage, disabled),
63
+ ]}>
64
+ <FloatingView
65
+ floatingValue={floatingValue}
66
+ floatingIconColor={floatingIconColor}
67
+ disabled={disabled}
68
+ required={required}
69
+ floatingIcon={floatingIcon}
70
+ />
71
+ <View style={full ? styles.inputView : Styles.row}>
72
+ {!!leadingIcon && (
73
+ <View style={styles.leadingIconContainer}>
74
+ <Icon
75
+ color={leadingIconColor}
76
+ source={leadingIcon}
77
+ size={size === 'small' ? 24 : 32}
78
+ />
79
+ </View>
80
+ )}
81
+ {full && (
82
+ <TextInput
83
+ {...props}
84
+ onPressIn={onPress}
85
+ accessibilityLabel={accessibilityLabel}
86
+ editable={false}
87
+ textAlignVertical="top"
88
+ style={[
89
+ styles.input,
90
+ {
91
+ color: textColor,
92
+ fontFamily: `${theme.font}-Regular`,
93
+ },
94
+ ]}
95
+ textBreakStrategy="highQuality"
96
+ value={value}
97
+ placeholder={placeholder}
98
+ selectionColor={theme.colors.primary}
99
+ placeholderTextColor={placeholderColor}
100
+ />
101
+ )}
102
+ </View>
103
+ <View style={styles.iconView}>{renderIcon(iconTintColor)}</View>
104
+ </View>
119
105
  );
120
- },
121
- );
106
+ };
107
+
108
+ return (
109
+ <TouchableOpacity
110
+ onPress={onPress}
111
+ style={[style, full && styles.wrapper]}
112
+ accessibilityLabel={accessibilityLabel}>
113
+ {renderInputView()}
114
+ <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
115
+ </TouchableOpacity>
116
+ );
117
+ };
122
118
 
123
119
  InputDropDown.defaultProps = {
124
120
  size: 'small',