@momo-kits/foundation 0.80.8-beta.1 → 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.
@@ -6,7 +6,7 @@ import {
6
6
  Platform,
7
7
  StatusBar,
8
8
  StyleSheet,
9
- TouchableOpacity as TouchableRN,
9
+ TouchableOpacity,
10
10
  View,
11
11
  } from 'react-native';
12
12
  import {TouchableOpacity as TouchableGesture} from 'react-native-gesture-handler';
@@ -14,6 +14,7 @@ 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: {
@@ -416,6 +418,41 @@ const HeaderToolkitAction: React.FC<any> = ({tintColor}) => {
416
418
  return <View />;
417
419
  };
418
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
+
419
456
  export {
420
457
  NavigationButton,
421
458
  HeaderTitle,
@@ -424,4 +461,5 @@ export {
424
461
  HeaderRightAction,
425
462
  HeaderToolkitAction,
426
463
  HeaderCustom,
464
+ HeaderAnimated,
427
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,8 +61,6 @@ const getModalOptions = (): StackNavigationOptions => {
72
61
  };
73
62
 
74
63
  const getOptions = (params: NavigationOptions, theme: Theme) => {
75
- let backgroundProps: any;
76
- let titleProps: any;
77
64
  let options = {};
78
65
 
79
66
  if (
@@ -99,36 +86,24 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
99
86
  if (params.surface) {
100
87
  options = {
101
88
  ...options,
102
- ...getTintColor({
103
- ...theme,
104
- assets: {...theme.assets, headerBackground: undefined},
105
- }),
106
- };
107
- backgroundProps = {
108
- image: null,
109
- backgroundColor: theme.colors.background.surface,
110
- useBorder: true,
89
+ headerTintColor: theme.colors.text.default,
90
+ headerBackground: () => (
91
+ <HeaderBackground
92
+ image={null}
93
+ backgroundColor={theme.colors.background.surface}
94
+ useBorder={true}
95
+ />
96
+ ),
111
97
  };
112
98
  } else {
113
99
  options = {
114
100
  ...options,
115
- ...getTintColor(theme),
101
+ headerTintColor: Colors.black_01,
116
102
  headerBackground: HeaderBackground,
117
103
  };
118
104
  }
119
105
  }
120
106
 
121
- if (params.animatedValue) {
122
- backgroundProps = {...backgroundProps, animatedValue: params.animatedValue};
123
- titleProps = {animatedValue: params.animatedValue};
124
- options = {
125
- ...options,
126
- headerTitle: (props: any) => {
127
- return <HeaderTitle {...titleProps} {...props} />;
128
- },
129
- };
130
- }
131
-
132
107
  if (params.customTitle) {
133
108
  options = {
134
109
  ...options,
@@ -139,13 +114,6 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
139
114
  };
140
115
  }
141
116
 
142
- if (backgroundProps) {
143
- options = {
144
- ...options,
145
- headerBackground: () => <HeaderBackground {...backgroundProps} />,
146
- };
147
- }
148
-
149
117
  return {
150
118
  ...params,
151
119
  ...options,
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>
@@ -25,10 +25,13 @@ const InputDropDown = ({
25
25
  loading,
26
26
  leadingIcon,
27
27
  leadingIconColor,
28
+ style,
28
29
  ...props
29
30
  }: InputDropDownProps) => {
30
31
  const {theme} = useContext(ApplicationContext);
31
32
  const full = !!value || !!placeholder;
33
+ const accessibilityLabel = `InputDropDown/${floatingValue ?? placeholder}`;
34
+
32
35
  const renderIcon = (color: string | undefined) => {
33
36
  if (loading) {
34
37
  return <Loader type={'spinner'} color={color} />;
@@ -79,7 +82,7 @@ const InputDropDown = ({
79
82
  <TextInput
80
83
  {...props}
81
84
  onPressIn={onPress}
82
- accessibilityLabel={`TextInput`}
85
+ accessibilityLabel={accessibilityLabel}
83
86
  editable={false}
84
87
  textAlignVertical="top"
85
88
  style={[
@@ -105,8 +108,8 @@ const InputDropDown = ({
105
108
  return (
106
109
  <TouchableOpacity
107
110
  onPress={onPress}
108
- style={full && styles.wrapper}
109
- accessibilityLabel={`InputDropDown/${floatingValue}`}>
111
+ style={[style, full && styles.wrapper]}
112
+ accessibilityLabel={accessibilityLabel}>
110
113
  {renderInputView()}
111
114
  <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
112
115
  </TouchableOpacity>
@@ -29,6 +29,7 @@ const InputMoney = forwardRef(
29
29
  iconColor,
30
30
  required,
31
31
  errorSpacing,
32
+ style,
32
33
  ...props
33
34
  }: InputMoneyProps,
34
35
  ref,
@@ -37,6 +38,8 @@ const InputMoney = forwardRef(
37
38
  const [focused, setFocused] = useState(false);
38
39
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
39
40
  const [value, setValue] = useState('');
41
+ const accessibilityLabel = `InputMoney/${floatingValue}`;
42
+
40
43
  const onClearText = () => {
41
44
  inputRef?.current?.clear();
42
45
  setValue('');
@@ -91,7 +94,7 @@ const InputMoney = forwardRef(
91
94
  <View style={styles.inputView}>
92
95
  <TextInput
93
96
  {...props}
94
- accessibilityLabel={`TextInput`}
97
+ accessibilityLabel={accessibilityLabel}
95
98
  editable={!disabled}
96
99
  textAlignVertical="top"
97
100
  ref={inputRef}
@@ -131,8 +134,8 @@ const InputMoney = forwardRef(
131
134
 
132
135
  return (
133
136
  <View
134
- style={styles.wrapper}
135
- accessibilityLabel={`InputMoney/${floatingValue}`}>
137
+ style={[style, styles.wrapper]}
138
+ accessibilityLabel={accessibilityLabel}>
136
139
  {renderInputView()}
137
140
  <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
138
141
  </View>
@@ -1,7 +1,6 @@
1
1
  import React, {FC, useContext, useEffect, useRef, useState} from 'react';
2
2
  import {
3
3
  Animated,
4
- KeyboardType,
5
4
  NativeSyntheticEvent,
6
5
  TextInput,
7
6
  TextInputFocusEventData,
@@ -69,6 +68,7 @@ const InputOTP: FC<InputOTPProps> = ({
69
68
  onFocus,
70
69
  onBlur,
71
70
  dataType = 'number',
71
+ style,
72
72
  ...props
73
73
  }) => {
74
74
  const MAX_LENGTH = 10;
@@ -76,6 +76,7 @@ const InputOTP: FC<InputOTPProps> = ({
76
76
  const [focused, setFocused] = useState(false);
77
77
  const inputRef = useRef<TextInput>(null);
78
78
  const {theme} = useContext(ApplicationContext);
79
+ const accessibilityLabel = `InputOTP/${floatingValue ?? placeholder}`;
79
80
 
80
81
  const onFocusInput = () => {
81
82
  setFocused(true);
@@ -157,9 +158,6 @@ const InputOTP: FC<InputOTPProps> = ({
157
158
  };
158
159
 
159
160
  const renderInputView = () => {
160
- let placeholderColor = theme.colors.text.hint;
161
- const keyboardType: KeyboardType =
162
- dataType === 'number' ? 'number-pad' : 'default';
163
161
  return (
164
162
  <View
165
163
  style={[
@@ -182,16 +180,16 @@ const InputOTP: FC<InputOTPProps> = ({
182
180
  <View style={styles.inputView}>
183
181
  <TextInput
184
182
  {...props}
185
- accessibilityLabel={`TextInput`}
183
+ accessibilityLabel={accessibilityLabel}
186
184
  ref={inputRef}
187
185
  value={value}
188
186
  onChangeText={_onChangeText}
189
- keyboardType={keyboardType}
187
+ keyboardType={dataType === 'number' ? 'number-pad' : 'default'}
190
188
  onFocus={onFocusInput}
191
189
  onBlur={onBlurInput}
192
190
  style={{opacity: 0}}
193
191
  selectionColor={theme.colors.primary}
194
- placeholderTextColor={placeholderColor}
192
+ placeholderTextColor={theme.colors.text.hint}
195
193
  />
196
194
  </View>
197
195
  </View>
@@ -202,8 +200,8 @@ const InputOTP: FC<InputOTPProps> = ({
202
200
  <TouchableOpacity
203
201
  activeOpacity={1}
204
202
  onPress={onFocusInput}
205
- style={styles.otpWrapper}
206
- accessibilityLabel={`Input/${floatingValue}`}>
203
+ style={[style, styles.otpWrapper]}
204
+ accessibilityLabel={accessibilityLabel}>
207
205
  {renderInputView()}
208
206
  <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
209
207
  </TouchableOpacity>
@@ -37,7 +37,7 @@ const InputSearch = forwardRef(
37
37
  const [focused, setFocused] = useState(false);
38
38
  const [haveValue, setHaveValue] = useState(!!value || !!defaultValue);
39
39
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
40
- let iconTintColor = iconColor;
40
+ const accessibilityLabel = `InputMoney/${placeholder}`;
41
41
 
42
42
  const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
43
43
  setFocused(true);
@@ -60,19 +60,16 @@ const InputSearch = forwardRef(
60
60
  };
61
61
 
62
62
  const renderInputView = () => {
63
- let textColor = theme.colors.text.default;
64
- let placeholderColor = theme.colors.text.hint;
65
-
66
63
  return (
67
64
  <TextInput
68
65
  {...props}
69
- accessibilityLabel={`TextInput`}
66
+ accessibilityLabel={accessibilityLabel}
70
67
  textAlignVertical="top"
71
68
  ref={inputRef}
72
69
  style={[
73
70
  styles.searchInput,
74
71
  {
75
- color: textColor,
72
+ color: theme.colors.text.default,
76
73
  },
77
74
  ]}
78
75
  value={value}
@@ -81,7 +78,7 @@ const InputSearch = forwardRef(
81
78
  onBlur={_onBlur}
82
79
  placeholder={placeholder}
83
80
  selectionColor={theme.colors.primary}
84
- placeholderTextColor={placeholderColor}
81
+ placeholderTextColor={theme.colors.text.hint}
85
82
  />
86
83
  );
87
84
  };
@@ -112,7 +109,7 @@ const InputSearch = forwardRef(
112
109
  ]}
113
110
  />
114
111
  <Icon
115
- color={iconTintColor}
112
+ color={iconColor}
116
113
  source={icon}
117
114
  style={styles.iconSearchInput}
118
115
  />
@@ -124,7 +121,7 @@ const InputSearch = forwardRef(
124
121
  return (
125
122
  <View
126
123
  style={[style, styles.searchInputContainer]}
127
- accessibilityLabel={`InputSearch/${placeholder}`}>
124
+ accessibilityLabel={accessibilityLabel}>
128
125
  <View
129
126
  style={[
130
127
  styles.searchInputWrapper,
@@ -37,6 +37,7 @@ const InputTextArea = forwardRef(
37
37
  maxLength,
38
38
  required,
39
39
  errorSpacing,
40
+ style,
40
41
  ...props
41
42
  }: InputTextAreaProps,
42
43
  ref,
@@ -45,6 +46,7 @@ const InputTextArea = forwardRef(
45
46
  const [focused, setFocused] = useState(false);
46
47
  const [inputValue, setInputValue] = useState(defaultValue ?? '');
47
48
  const inputRef = (ref as React.RefObject<TextInput>) ?? useRef<TextInput>();
49
+ const accessibilityLabel = `InputTextArea/${floatingValue ?? placeholder}`;
48
50
 
49
51
  const onClearText = () => {
50
52
  inputRef?.current?.clear();
@@ -106,7 +108,7 @@ const InputTextArea = forwardRef(
106
108
  <View style={styles.textAreaView}>
107
109
  <TextInput
108
110
  {...props}
109
- accessibilityLabel={`TextInput`}
111
+ accessibilityLabel={accessibilityLabel}
110
112
  ref={inputRef}
111
113
  editable={!disabled}
112
114
  textAlignVertical="top"
@@ -147,8 +149,8 @@ const InputTextArea = forwardRef(
147
149
 
148
150
  return (
149
151
  <View
150
- style={styles.wrapper}
151
- accessibilityLabel={`InputTextArea/${floatingValue}`}>
152
+ style={[style, styles.wrapper]}
153
+ accessibilityLabel={accessibilityLabel}>
152
154
  {renderInputView()}
153
155
  <ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
154
156
  </View>
package/Input/common.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import {View, ViewStyle} from 'react-native';
2
2
  import styles from './styles';
3
- import {Text} from '../Text';
3
+ import {scaleSize, Text} from '../Text';
4
4
  import React, {FC, useContext} from 'react';
5
5
  import {ApplicationContext} from '../Application';
6
6
  import {Icon} from '../Icon';
@@ -16,7 +16,7 @@ type FloatingViewProps = {
16
16
  style?: ViewStyle;
17
17
  };
18
18
 
19
- export const DEFAULT_HEIGHT = 112;
19
+ export const DEFAULT_HEIGHT = scaleSize(104);
20
20
  export const MAX_LENGTH = 300;
21
21
 
22
22
  export const getBorderColor = (
package/Input/index.tsx CHANGED
@@ -4,7 +4,7 @@ import InputSearch from './InputSearch';
4
4
  import InputMoney from './InputMoney';
5
5
  import InputOTP from './InputOTP';
6
6
  import InputDropDown from './InputDropDown';
7
- import {TextInputProps} from 'react-native';
7
+ import {TextInputProps, ViewStyle} from 'react-native';
8
8
 
9
9
  export interface InputProps extends TextInputProps {
10
10
  /**
@@ -238,6 +238,8 @@ export interface InputDropDownProps {
238
238
  * Optional. Represents the color of the leading icon in the InputDropDown component.
239
239
  */
240
240
  leadingIconColor?: string;
241
+
242
+ style: ViewStyle | ViewStyle[];
241
243
  }
242
244
 
243
245
  export {Input, InputTextArea, InputSearch, InputMoney, InputOTP, InputDropDown};
package/Layout/Card.tsx CHANGED
@@ -7,16 +7,23 @@ import Item from './Item';
7
7
  import {Image} from '../Image';
8
8
  import {ApplicationContext} from '../Application';
9
9
  import styles from './styles';
10
- import {Colors, Spacing} from '../Consts';
10
+ import {Colors, Radius, Shadow, Spacing} from '../Consts';
11
11
 
12
12
  export interface CardProps extends ViewProps {
13
13
  /**
14
14
  * Optional. Background image for the card.
15
15
  */
16
16
  backgroundImage?: string;
17
+
18
+ useShadow?: boolean;
17
19
  }
18
20
 
19
- const Card: React.FC<CardProps> = ({children, style, backgroundImage}) => {
21
+ const Card: React.FC<CardProps> = ({
22
+ children,
23
+ style,
24
+ backgroundImage,
25
+ useShadow = false,
26
+ }) => {
20
27
  const {showGrid} = useContext(ApplicationContext);
21
28
  const {numberOfColumns} = useGridSystem();
22
29
 
@@ -127,22 +134,28 @@ const Card: React.FC<CardProps> = ({children, style, backgroundImage}) => {
127
134
  return element;
128
135
  };
129
136
 
137
+ const {theme} = useContext(ApplicationContext);
130
138
  return (
131
139
  <GridContext.Provider value={gridContext}>
132
140
  <View
133
141
  accessibilityLabel={`Card`}
134
142
  style={[
143
+ {
144
+ backgroundColor: theme.colors.background.surface,
145
+ borderRadius: Radius.M,
146
+ },
135
147
  style,
136
148
  styles.card,
137
149
  {
138
150
  width: widthSection,
139
151
  marginHorizontal: gridContext.margin,
140
152
  },
153
+ Shadow.Light,
141
154
  ]}>
142
155
  {!!backgroundImage && (
143
156
  <Image
144
157
  source={{uri: backgroundImage}}
145
- style={[style, styles.imageBackground]}
158
+ style={styles.imageBackground}
146
159
  />
147
160
  )}
148
161
  {renderView(validateChildren(children, [Item]))}
package/Layout/Screen.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  Animated,
3
+ Image,
3
4
  KeyboardAvoidingView,
4
5
  Platform,
5
6
  ScrollViewProps,
@@ -8,13 +9,24 @@ import {
8
9
  } from 'react-native';
9
10
  import {useHeaderHeight} from '@react-navigation/stack';
10
11
  import {useSafeAreaInsets} from 'react-native-safe-area-context';
11
- import React, {ReactNode, useContext, useEffect, useRef} from 'react';
12
+ import React, {
13
+ forwardRef,
14
+ ReactNode,
15
+ useContext,
16
+ useEffect,
17
+ useRef,
18
+ } from 'react';
12
19
  import {Spacing, Styles} from '../Consts';
13
20
  import {Card, Section, validateChildren} from './index';
14
- import {ApplicationContext, HeaderTitle} from '../Application';
21
+ import {
22
+ ApplicationContext,
23
+ HeaderBackground,
24
+ HeaderTitle,
25
+ } from '../Application';
15
26
  import Navigation from '../Application/Navigation';
16
27
 
17
28
  export interface ScreenProps extends ViewProps {
29
+ children: React.ReactNode;
18
30
  /**
19
31
  * Optional. Navigation object for handling navigation actions.
20
32
  */
@@ -25,31 +37,31 @@ export interface ScreenProps extends ViewProps {
25
37
  */
26
38
  enableKeyboardAvoidingView?: boolean;
27
39
 
28
- /**
29
- * Optional. Background color of the header.
30
- */
31
- headerBackground?: string;
32
-
33
40
  /**
34
41
  * Optional. If `true`, the screen content is scrollable.
35
42
  */
36
43
  scrollable?: boolean;
37
44
 
38
45
  /**
39
- * Optional. If `true`, use an animated header for the screen.
46
+ * Optional. If `true`, use an extended header for the screen.
40
47
  */
41
- useAnimatedHeader?: boolean;
48
+ useExtendedHeader?: boolean;
42
49
 
43
50
  /**
44
- * Optional. If `true`, use an extended header for the screen.
51
+ * Optional. Props for the animated component or bool used top navigation animated.
45
52
  */
46
- useExtendedHeader?: boolean;
53
+ animatedHeader?: boolean | ((props?: any) => React.ReactElement);
47
54
 
48
55
  /**
49
56
  * Optional. Props for the underlying ScrollView component when `scrollable` is `true`.
50
57
  */
51
58
  scrollViewProps?: ScrollViewProps;
52
59
 
60
+ /**
61
+ * Optional. ReactNode representing the header component of the screen.
62
+ */
63
+ headerComponent?: ReactNode;
64
+
53
65
  /**
54
66
  * Optional. ReactNode representing the footer component of the screen.
55
67
  */
@@ -66,191 +78,204 @@ export interface ScreenProps extends ViewProps {
66
78
  backgroundColor?: string;
67
79
  }
68
80
 
69
- const Screen: React.FC<ScreenProps> = ({
70
- children,
71
- enableKeyboardAvoidingView = false,
72
- scrollable = false,
73
- navigation,
74
- marginHeader,
75
- useAnimatedHeader,
76
- useExtendedHeader,
77
- headerBackground,
78
- scrollViewProps,
79
- footerComponent: Footer,
80
- backgroundColor,
81
- }) => {
82
- const animatedValue = useRef<Animated.Value | undefined>(undefined);
83
- const {theme} = useContext(ApplicationContext);
84
- const insets = useSafeAreaInsets();
85
- const headerTransparent = useAnimatedHeader || useExtendedHeader;
81
+ const Screen = forwardRef(
82
+ (
83
+ {
84
+ children,
85
+ enableKeyboardAvoidingView = false,
86
+ scrollable = false,
87
+ navigation,
88
+ marginHeader,
89
+ useExtendedHeader,
90
+ animatedHeader,
91
+ scrollViewProps,
92
+ headerComponent: Header,
93
+ footerComponent: Footer,
94
+ backgroundColor,
95
+ }: ScreenProps,
96
+ ref,
97
+ ) => {
98
+ const animatedValue = useRef<Animated.Value | undefined>(undefined);
99
+ const {theme} = useContext(ApplicationContext);
100
+ const insets = useSafeAreaInsets();
86
101
 
87
- let handleScroll;
88
- let imageAnimatedStyle = {};
89
- let opacity;
90
- let Component: any = View;
91
- animatedValue.current = undefined;
102
+ let handleScroll;
103
+ let headerBackground: string | undefined = undefined;
104
+ let Component: any = View;
105
+ animatedValue.current = undefined;
106
+
107
+ if (useExtendedHeader || animatedHeader) {
108
+ marginHeader = marginHeader ?? useHeaderHeight();
109
+ }
92
110
 
93
- /**
94
- * automatic margin content if use header transparent
95
- */
96
- if (headerTransparent) {
97
- animatedValue.current = new Animated.Value(0);
98
- marginHeader = marginHeader ?? useHeaderHeight();
99
111
  if (useExtendedHeader) {
100
112
  headerBackground = theme.assets?.headerBackground;
101
113
  }
102
- }
103
114
 
104
- useEffect(() => {
105
- if (useAnimatedHeader != undefined || useExtendedHeader != undefined) {
106
- let title = {};
115
+ useEffect(() => {
107
116
  if (useExtendedHeader) {
108
- title = {headerTitle: HeaderTitle};
117
+ navigation?.setOptions({
118
+ headerTransparent: true,
119
+ headerBackground: () => null,
120
+ });
109
121
  }
110
- navigation?.setOptions({
111
- animatedValue: animatedValue.current,
112
- headerTransparent: headerTransparent,
113
- ...title,
114
- });
115
- }
116
- }, [useExtendedHeader, useAnimatedHeader]);
122
+ }, [useExtendedHeader]);
117
123
 
118
- /**
119
- * animated for header stack when used bottom tab
120
- */
121
- useEffect(() => {
122
- const current: any = navigation;
123
- if (headerTransparent) {
124
- return current?.addListener?.('focus', () => {
125
- const stackNavigation = new Navigation(current?.getParent(), theme);
126
- stackNavigation?.setOptions({
127
- animatedValue: animatedValue.current,
124
+ useEffect(() => {
125
+ if (animatedHeader) {
126
+ navigation?.setOptions({
127
+ headerTransparent: true,
128
+ headerBackground: (props: any) => (
129
+ <HeaderBackground
130
+ {...props}
131
+ animatedValue={animatedValue.current}
132
+ />
133
+ ),
134
+ headerTitle: (props: any) => (
135
+ <HeaderTitle {...props} animatedValue={animatedValue.current} />
136
+ ),
128
137
  });
129
- });
130
- }
131
- }, [useAnimatedHeader, useExtendedHeader, navigation]);
138
+ const current: any = navigation;
139
+ const parent = current?.getParent?.();
140
+ if (parent) {
141
+ return current?.addListener?.('focus', () => {
142
+ const stackNavigation = new Navigation(parent, theme);
143
+ stackNavigation?.setOptions({
144
+ headerTransparent: true,
145
+ headerBackground: (props: any) => (
146
+ <HeaderBackground
147
+ {...props}
148
+ animatedValue={animatedValue.current}
149
+ />
150
+ ),
151
+ headerTitle: (props: any) => (
152
+ <HeaderTitle {...props} animatedValue={animatedValue.current} />
153
+ ),
154
+ });
155
+ });
156
+ }
157
+ }
158
+ }, [animatedHeader]);
132
159
 
133
- /**
134
- * animated when use scroll && animated value
135
- */
136
- if (scrollable) {
137
- Component = Animated.ScrollView;
138
- if (useAnimatedHeader) {
139
- opacity = animatedValue.current?.interpolate({
140
- inputRange: [0, 100],
141
- outputRange: [1, 0],
142
- extrapolate: 'clamp',
143
- });
144
- imageAnimatedStyle = {
145
- transform: [
146
- {
147
- scale: animatedValue.current?.interpolate?.({
148
- inputRange: [-300, 0, 1],
149
- outputRange: [1.75, 1, 1],
150
- extrapolate: 'clamp',
151
- }),
152
- },
153
- ],
154
- };
155
- handleScroll = Animated.event(
156
- [
157
- {
158
- nativeEvent: {
159
- contentOffset: {y: animatedValue.current as Animated.Value},
160
+ /**
161
+ * animated when use scroll && animated value
162
+ */
163
+ if (scrollable) {
164
+ Component = Animated.ScrollView;
165
+ handleScroll = scrollViewProps?.onScroll;
166
+ if (animatedHeader) {
167
+ animatedValue.current = new Animated.Value(0);
168
+ handleScroll = Animated.event(
169
+ [
170
+ {
171
+ nativeEvent: {
172
+ contentOffset: {y: animatedValue.current as Animated.Value},
173
+ },
160
174
  },
161
- },
162
- ],
163
- {useNativeDriver: true},
164
- );
165
- }
166
- }
167
-
168
- /**
169
- * build content for screen
170
- */
171
- const renderContent = () => {
172
- const results = validateChildren(children, [Section, Card]);
173
- if (Array.isArray(results)) {
174
- return results.map((item, index) => {
175
- const space = item.props?.useMargin === false ? 0 : Spacing.M;
176
- return (
177
- <View
178
- key={`ScreenItem${index}`}
179
- style={{
180
- marginTop: space,
181
- flex: item.props?.expanded ? 1 : undefined,
182
- }}>
183
- {item}
184
- </View>
175
+ ],
176
+ {useNativeDriver: true, listener: scrollViewProps?.onScroll},
185
177
  );
186
- });
187
- } else {
188
- const item: any = children;
189
- const space = item?.props?.useMargin === false ? 0 : Spacing.M;
190
- return (
191
- <View
192
- key={`ScreenItem`}
193
- style={{
194
- marginTop: space,
195
- flex: item?.props?.expanded ? 1 : undefined,
196
- }}>
197
- {children}
198
- </View>
199
- );
178
+ }
200
179
  }
201
- };
202
180
 
203
- return (
204
- <View
205
- style={[Styles.flex, {backgroundColor}]}
206
- accessibilityLabel={`ScreenContainer`}>
207
- <View
208
- style={{
209
- position: 'absolute',
210
- maxHeight: 215,
211
- width: '100%',
212
- overflow: 'hidden',
213
- }}>
214
- {!!headerBackground && (
215
- <Animated.Image
181
+ /**
182
+ * render top navigation banner
183
+ */
184
+ const renderHeader = () => {
185
+ if (headerBackground != undefined) {
186
+ return (
187
+ <Image
216
188
  source={{
217
189
  uri: headerBackground,
218
190
  }}
219
191
  style={{
220
- opacity: opacity ?? 1,
221
192
  aspectRatio: 1.75,
222
- ...imageAnimatedStyle,
223
193
  }}
224
194
  />
225
- )}
226
- </View>
227
- <KeyboardAvoidingView
228
- style={Styles.flex}
229
- enabled={enableKeyboardAvoidingView}
230
- behavior={Platform.select({
231
- ios: 'padding',
232
- android: undefined,
233
- })}>
234
- <Component
235
- {...scrollViewProps}
236
- showsVerticalScrollIndicator={false}
237
- onScroll={handleScroll}
238
- style={[Styles.flex, {marginTop: marginHeader}]}>
239
- {renderContent()}
240
- </Component>
241
- {Footer && (
195
+ );
196
+ }
197
+ if (typeof animatedHeader === 'function') {
198
+ return animatedHeader({animatedValue: animatedValue.current});
199
+ }
200
+ };
201
+
202
+ /**
203
+ * build content for screen
204
+ */
205
+ const renderContent = () => {
206
+ const results = validateChildren(children, [Section, Card]);
207
+ if (Array.isArray(results)) {
208
+ return results.map((item, index) => {
209
+ const space = item.props?.useMargin === false ? 0 : Spacing.M;
210
+ return (
211
+ <View
212
+ key={`ScreenItem${index}`}
213
+ style={{
214
+ marginTop: space,
215
+ flex: item.props?.expanded ? 1 : undefined,
216
+ }}>
217
+ {item}
218
+ </View>
219
+ );
220
+ });
221
+ } else {
222
+ const item: any = children;
223
+ const space = item?.props?.useMargin === false ? 0 : Spacing.M;
224
+ return (
242
225
  <View
226
+ key={`ScreenItem`}
243
227
  style={{
244
- paddingTop: Spacing.S,
245
- paddingBottom: Math.min(insets.bottom, 20) + Spacing.S,
246
- backgroundColor: theme.colors.background.surface,
228
+ marginTop: space,
229
+ flex: item?.props?.expanded ? 1 : undefined,
247
230
  }}>
248
- <Section>{Footer}</Section>
231
+ {children}
249
232
  </View>
250
- )}
251
- </KeyboardAvoidingView>
252
- </View>
253
- );
254
- };
233
+ );
234
+ }
235
+ };
236
+
237
+ return (
238
+ <View
239
+ style={[Styles.flex, {backgroundColor}]}
240
+ accessibilityLabel={`ScreenContainer`}>
241
+ <View
242
+ style={{
243
+ position: 'absolute',
244
+ width: '100%',
245
+ maxHeight: 215,
246
+ }}>
247
+ {renderHeader()}
248
+ </View>
249
+ <KeyboardAvoidingView
250
+ style={[Styles.flex, {paddingTop: marginHeader}]}
251
+ enabled={enableKeyboardAvoidingView}
252
+ behavior={Platform.select({
253
+ ios: 'padding',
254
+ android: undefined,
255
+ })}>
256
+ {Header}
257
+ <Component
258
+ {...scrollViewProps}
259
+ ref={ref}
260
+ showsVerticalScrollIndicator={false}
261
+ onScroll={handleScroll}
262
+ style={Styles.flex}>
263
+ {renderContent()}
264
+ </Component>
265
+ {Footer && (
266
+ <View
267
+ style={{
268
+ paddingTop: Spacing.S,
269
+ paddingBottom: Math.min(insets.bottom, 20) + Spacing.S,
270
+ backgroundColor: theme.colors.background.surface,
271
+ }}>
272
+ <Section>{Footer}</Section>
273
+ </View>
274
+ )}
275
+ </KeyboardAvoidingView>
276
+ </View>
277
+ );
278
+ },
279
+ );
255
280
 
256
281
  export default Screen;
package/Layout/styles.ts CHANGED
@@ -47,6 +47,7 @@ export default StyleSheet.create({
47
47
  marginLeft: undefined,
48
48
  marginRight: undefined,
49
49
  marginVertical: undefined,
50
+ overflow: 'hidden',
50
51
  },
51
52
  item: {
52
53
  overflow: 'hidden',
@@ -9,6 +9,7 @@ import {ApplicationContext} from '../Application';
9
9
  const PaginationDot: FC<ChildPaginationProps> = ({
10
10
  dataLength = 2,
11
11
  activeIndex = 0,
12
+ style,
12
13
  }) => {
13
14
  const {theme} = useContext(ApplicationContext);
14
15
  const renderDots = () => {
@@ -27,7 +28,11 @@ const PaginationDot: FC<ChildPaginationProps> = ({
27
28
  }
28
29
  return dots;
29
30
  };
30
- return <View style={styles.paginationPinkContainer}>{renderDots()}</View>;
31
+ return (
32
+ <View style={[style, styles.row]}>
33
+ <View style={styles.paginationPinkContainer}>{renderDots()}</View>
34
+ </View>
35
+ );
31
36
  };
32
37
 
33
38
  export default PaginationDot;
@@ -8,12 +8,15 @@ import {Colors} from '../Consts';
8
8
  const PaginationNumber: FC<ChildPaginationProps> = ({
9
9
  activeIndex = 0,
10
10
  dataLength = 2,
11
+ style,
11
12
  }) => {
12
13
  return (
13
- <View style={[styles.paginationNumberContainer]}>
14
- <Text color={Colors.black_01} typography={'label_default'}>{`${
15
- activeIndex + 1
16
- }/${dataLength}`}</Text>
14
+ <View style={[style, styles.row]}>
15
+ <View style={styles.paginationNumberContainer}>
16
+ <Text color={Colors.black_01} typography={'label_default'}>{`${
17
+ activeIndex + 1
18
+ }/${dataLength}`}</Text>
19
+ </View>
17
20
  </View>
18
21
  );
19
22
  };
@@ -8,6 +8,7 @@ import {Colors, Spacing} from '../Consts';
8
8
  const PaginationWhiteDot: FC<ChildPaginationProps> = ({
9
9
  dataLength = 2,
10
10
  activeIndex = 0,
11
+ style,
11
12
  }) => {
12
13
  const renderDots = () => {
13
14
  const dots: React.ReactElement[] = [];
@@ -24,7 +25,11 @@ const PaginationWhiteDot: FC<ChildPaginationProps> = ({
24
25
  }
25
26
  return dots;
26
27
  };
27
- return <View style={[styles.paginationWhiteContainer]}>{renderDots()}</View>;
28
+ return (
29
+ <View style={[style, styles.row]}>
30
+ <View style={styles.paginationWhiteContainer}>{renderDots()}</View>
31
+ </View>
32
+ );
28
33
  };
29
34
 
30
35
  export default PaginationWhiteDot;
@@ -25,6 +25,8 @@ export default StyleSheet.create({
25
25
  paddingHorizontal: Spacing.S,
26
26
  borderRadius: Radius.L,
27
27
  backgroundColor: Colors.black_20 + '33',
28
+ alignItems: 'center',
29
+ justifyContent: 'center',
28
30
  },
29
31
  scrollContainer: {
30
32
  alignItems: 'center',
@@ -44,4 +46,5 @@ export default StyleSheet.create({
44
46
  height: 4,
45
47
  borderRadius: Radius.XS,
46
48
  },
49
+ row: {flexDirection: 'row'},
47
50
  });
@@ -20,6 +20,8 @@ export type PaginationProps = {
20
20
  * Represents the total number of items (pages) in the Pagination component.
21
21
  */
22
22
  dataLength: number;
23
+
24
+ style?: ViewStyle | ViewStyle[];
23
25
  };
24
26
 
25
27
  export type DotProps = {
package/Radio/types.ts CHANGED
@@ -5,7 +5,7 @@ export type RadioProps = {
5
5
  * `value`: Represents the value associated with the Radio component.
6
6
  * It is used to determine whether the Radio component is selected or not in comparison with the `groupValue`.
7
7
  */
8
- value: string;
8
+ value: any;
9
9
 
10
10
  /**
11
11
  * `disabled`: Optional. If `true`, the user won't be able to interact with the Radio component.
@@ -28,7 +28,7 @@ export type RadioProps = {
28
28
  * `groupValue`: Represents the value of the selected Radio component within a group of Radio components.
29
29
  * The Radio component for which `value` equals `groupValue` will be selected.
30
30
  */
31
- groupValue: string;
31
+ groupValue: any;
32
32
 
33
33
  /**
34
34
  * `style`: Optional. Used to apply custom styling to the Radio component.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.80.8-beta.1",
3
+ "version": "0.80.8-beta.10",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {