@momo-kits/foundation 0.92.21-beta.2 → 0.92.21-beta.3
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.
- package/Application/Components.tsx +38 -86
- package/Application/Navigation.ts +13 -0
- package/Application/StackScreen.tsx +4 -87
- package/Application/types.ts +6 -16
- package/Application/utils.tsx +9 -0
- package/Button/index.tsx +1 -0
- package/Input/InputMoney.tsx +3 -3
- package/Input/InputOTP.tsx +4 -4
- package/Input/InputSearch.tsx +147 -166
- package/Input/index.tsx +1 -11
- package/Layout/Screen.tsx +25 -109
- package/Layout/styles.ts +6 -0
- package/Layout/types.ts +1 -20
- package/package.json +2 -2
- package/Input/TextTyping.tsx +0 -113
- package/Layout/AnimatedInputSearch.tsx +0 -58
package/Input/InputSearch.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React, {
|
|
2
2
|
forwardRef,
|
|
3
|
-
ForwardRefRenderFunction,
|
|
4
3
|
useContext,
|
|
5
4
|
useImperativeHandle,
|
|
6
5
|
useRef,
|
|
@@ -16,195 +15,177 @@ import {
|
|
|
16
15
|
import {ApplicationContext, ComponentContext} from '../Application';
|
|
17
16
|
import {Icon} from '../Icon';
|
|
18
17
|
import {Text} from '../Text';
|
|
19
|
-
import {InputSearchProps
|
|
18
|
+
import {InputSearchProps} from './index';
|
|
20
19
|
import styles from './styles';
|
|
21
20
|
import {checkTyping} from './utils';
|
|
22
|
-
import TextTyping from './TextTyping';
|
|
23
21
|
|
|
24
|
-
const InputSearch
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const {theme} = useContext(ApplicationContext);
|
|
51
|
-
const [focused, setFocused] = useState(false);
|
|
52
|
-
const [haveValue, setHaveValue] = useState(!!value || !!defaultValue);
|
|
53
|
-
const inputRef = useRef<TextInput | null>(null);
|
|
54
|
-
|
|
55
|
-
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
56
|
-
setFocused(true);
|
|
57
|
-
onFocus?.(e);
|
|
58
|
-
};
|
|
22
|
+
const InputSearch = forwardRef(
|
|
23
|
+
(
|
|
24
|
+
{
|
|
25
|
+
placeholder,
|
|
26
|
+
onFocus,
|
|
27
|
+
onBlur,
|
|
28
|
+
iconColor,
|
|
29
|
+
value,
|
|
30
|
+
onChangeText,
|
|
31
|
+
icon,
|
|
32
|
+
buttonText = 'Hủy',
|
|
33
|
+
showButtonText = true,
|
|
34
|
+
style,
|
|
35
|
+
defaultValue,
|
|
36
|
+
onPressButtonText,
|
|
37
|
+
params,
|
|
38
|
+
hasColorBG = false,
|
|
39
|
+
accessibilityLabel,
|
|
40
|
+
...props
|
|
41
|
+
}: InputSearchProps,
|
|
42
|
+
ref,
|
|
43
|
+
) => {
|
|
44
|
+
const {theme} = useContext(ApplicationContext);
|
|
45
|
+
const [focused, setFocused] = useState(false);
|
|
46
|
+
const [haveValue, setHaveValue] = useState(!!value || !!defaultValue);
|
|
47
|
+
const inputRef = useRef<TextInput | null>(null);
|
|
59
48
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
49
|
+
const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
50
|
+
setFocused(true);
|
|
51
|
+
onFocus?.(e);
|
|
52
|
+
};
|
|
64
53
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
54
|
+
const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
55
|
+
setFocused(false);
|
|
56
|
+
onBlur?.(e);
|
|
57
|
+
};
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
59
|
+
const onClearText = () => {
|
|
60
|
+
inputRef?.current?.clear();
|
|
61
|
+
_onChangeText('');
|
|
62
|
+
};
|
|
74
63
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
focus: () => inputRef.current?.focus(),
|
|
79
|
-
blur: () => inputRef.current?.blur(),
|
|
80
|
-
setText: (text: string) => _onChangeText(text),
|
|
64
|
+
const _onChangeText = (text: string) => {
|
|
65
|
+
checkTyping(text, haveValue, setHaveValue);
|
|
66
|
+
onChangeText?.(text);
|
|
81
67
|
};
|
|
82
|
-
});
|
|
83
68
|
|
|
84
|
-
|
|
85
|
-
|
|
69
|
+
useImperativeHandle(ref, () => {
|
|
70
|
+
return {
|
|
71
|
+
clear: onClearText,
|
|
72
|
+
focus: () => inputRef.current?.focus(),
|
|
73
|
+
blur: () => inputRef.current?.blur(),
|
|
74
|
+
setText: (text: string) => _onChangeText(text),
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const renderInputView = () => {
|
|
86
79
|
return (
|
|
87
|
-
<
|
|
80
|
+
<TextInput
|
|
81
|
+
{...props}
|
|
82
|
+
accessibilityLabel={accessibilityLabel}
|
|
83
|
+
textAlignVertical="center"
|
|
84
|
+
ref={inputRef}
|
|
88
85
|
style={[
|
|
89
86
|
styles.searchInput,
|
|
90
87
|
{
|
|
91
|
-
|
|
88
|
+
color: theme.colors.text.default,
|
|
92
89
|
},
|
|
93
90
|
]}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
value={value}
|
|
92
|
+
onChangeText={_onChangeText}
|
|
93
|
+
onFocus={_onFocus}
|
|
94
|
+
onBlur={_onBlur}
|
|
95
|
+
placeholder={placeholder}
|
|
96
|
+
selectionColor={theme.colors.primary}
|
|
97
|
+
placeholderTextColor={theme.colors.text.hint}
|
|
98
|
+
/>
|
|
98
99
|
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const renderIconView = () => {
|
|
103
|
+
return (
|
|
104
|
+
<View
|
|
105
|
+
style={{
|
|
106
|
+
flexDirection: 'row',
|
|
107
|
+
}}>
|
|
108
|
+
{focused && haveValue && (
|
|
109
|
+
<TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
|
|
110
|
+
<Icon
|
|
111
|
+
source="24_navigation_close_circle_full"
|
|
112
|
+
size={16}
|
|
113
|
+
color={theme.colors.text.hint}
|
|
114
|
+
/>
|
|
115
|
+
</TouchableOpacity>
|
|
116
|
+
)}
|
|
117
|
+
{!!icon && (
|
|
118
|
+
<View style={{flexDirection: 'row'}}>
|
|
119
|
+
<View
|
|
120
|
+
style={[
|
|
121
|
+
styles.divider,
|
|
122
|
+
{
|
|
123
|
+
backgroundColor: theme.colors.primary,
|
|
124
|
+
},
|
|
125
|
+
]}
|
|
126
|
+
/>
|
|
127
|
+
<Icon
|
|
128
|
+
color={iconColor}
|
|
129
|
+
source={icon}
|
|
130
|
+
style={styles.iconSearchInput}
|
|
131
|
+
/>
|
|
132
|
+
</View>
|
|
133
|
+
)}
|
|
134
|
+
</View>
|
|
135
|
+
);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
let inputState = 'empty';
|
|
139
|
+
|
|
140
|
+
if (focused) {
|
|
141
|
+
inputState = 'focus';
|
|
99
142
|
}
|
|
100
143
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
styles.searchInput,
|
|
109
|
-
{
|
|
110
|
-
color: theme.colors.text.default,
|
|
111
|
-
},
|
|
112
|
-
]}
|
|
113
|
-
value={value}
|
|
114
|
-
onChangeText={_onChangeText}
|
|
115
|
-
onFocus={_onFocus}
|
|
116
|
-
onBlur={_onBlur}
|
|
117
|
-
placeholder={placeholder}
|
|
118
|
-
selectionColor={theme.colors.primary}
|
|
119
|
-
placeholderTextColor={theme.colors.text.hint}
|
|
120
|
-
/>
|
|
121
|
-
);
|
|
122
|
-
};
|
|
144
|
+
if (value && value?.length > 0) {
|
|
145
|
+
inputState = 'filled';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const backgroundColor = hasColorBG
|
|
149
|
+
? theme.colors.background.default
|
|
150
|
+
: theme.colors.background.surface;
|
|
123
151
|
|
|
124
|
-
const renderIconView = () => {
|
|
125
152
|
return (
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
153
|
+
<ComponentContext.Provider
|
|
154
|
+
value={{
|
|
155
|
+
componentName: 'InputSearch',
|
|
156
|
+
params,
|
|
157
|
+
state: inputState,
|
|
158
|
+
componentId: accessibilityLabel,
|
|
129
159
|
}}>
|
|
130
|
-
{
|
|
131
|
-
<
|
|
160
|
+
<View style={[style, styles.searchInputContainer]}>
|
|
161
|
+
<View
|
|
162
|
+
style={[
|
|
163
|
+
styles.searchInputWrapper,
|
|
164
|
+
{
|
|
165
|
+
backgroundColor,
|
|
166
|
+
},
|
|
167
|
+
]}>
|
|
132
168
|
<Icon
|
|
133
|
-
source=
|
|
134
|
-
size={
|
|
169
|
+
source={'navigation_search'}
|
|
170
|
+
size={24}
|
|
135
171
|
color={theme.colors.text.hint}
|
|
136
172
|
/>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
{!!icon && (
|
|
140
|
-
<View style={{flexDirection: 'row'}}>
|
|
141
|
-
<View
|
|
142
|
-
style={[
|
|
143
|
-
styles.divider,
|
|
144
|
-
{
|
|
145
|
-
backgroundColor: theme.colors.primary,
|
|
146
|
-
},
|
|
147
|
-
]}
|
|
148
|
-
/>
|
|
149
|
-
<Icon
|
|
150
|
-
color={iconColor}
|
|
151
|
-
source={icon}
|
|
152
|
-
style={styles.iconSearchInput}
|
|
153
|
-
/>
|
|
173
|
+
{renderInputView()}
|
|
174
|
+
{renderIconView()}
|
|
154
175
|
</View>
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (value && value?.length > 0) {
|
|
167
|
-
inputState = 'filled';
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const backgroundColor = hasColorBG
|
|
171
|
-
? theme.colors.background.default
|
|
172
|
-
: theme.colors.background.surface;
|
|
173
|
-
|
|
174
|
-
return (
|
|
175
|
-
<ComponentContext.Provider
|
|
176
|
-
value={{
|
|
177
|
-
componentName: 'InputSearch',
|
|
178
|
-
params,
|
|
179
|
-
state: inputState,
|
|
180
|
-
componentId: accessibilityLabel,
|
|
181
|
-
}}>
|
|
182
|
-
<View style={[style, styles.searchInputContainer]}>
|
|
183
|
-
<View
|
|
184
|
-
style={[
|
|
185
|
-
styles.searchInputWrapper,
|
|
186
|
-
{
|
|
187
|
-
backgroundColor,
|
|
188
|
-
},
|
|
189
|
-
]}>
|
|
190
|
-
<Icon
|
|
191
|
-
source={'navigation_search'}
|
|
192
|
-
size={24}
|
|
193
|
-
color={theme.colors.text.hint}
|
|
194
|
-
/>
|
|
195
|
-
{renderInputView()}
|
|
196
|
-
{renderIconView()}
|
|
176
|
+
{showButtonText && (
|
|
177
|
+
<TouchableOpacity onPress={onPressButtonText}>
|
|
178
|
+
<Text
|
|
179
|
+
typography={'action_default_bold'}
|
|
180
|
+
style={styles.textButton}>
|
|
181
|
+
{buttonText}
|
|
182
|
+
</Text>
|
|
183
|
+
</TouchableOpacity>
|
|
184
|
+
)}
|
|
197
185
|
</View>
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
</Text>
|
|
203
|
-
</TouchableOpacity>
|
|
204
|
-
)}
|
|
205
|
-
</View>
|
|
206
|
-
</ComponentContext.Provider>
|
|
207
|
-
);
|
|
208
|
-
};
|
|
186
|
+
</ComponentContext.Provider>
|
|
187
|
+
);
|
|
188
|
+
},
|
|
189
|
+
);
|
|
209
190
|
|
|
210
|
-
export default
|
|
191
|
+
export default InputSearch;
|
package/Input/index.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {TextInputProps, ViewStyle} from 'react-native';
|
|
2
2
|
import Input from './Input';
|
|
3
3
|
import InputDropDown from './InputDropDown';
|
|
4
4
|
import InputMoney from './InputMoney';
|
|
@@ -143,9 +143,6 @@ export interface InputSearchProps extends TextInputProps {
|
|
|
143
143
|
* Optional. Represents the style of the InputSearch component.
|
|
144
144
|
*/
|
|
145
145
|
params?: any;
|
|
146
|
-
|
|
147
|
-
typingData?: string[];
|
|
148
|
-
onPress?: (e: GestureResponderEvent) => void;
|
|
149
146
|
}
|
|
150
147
|
|
|
151
148
|
export interface InputMoneyProps extends Omit<InputProps, 'placeholder'> {}
|
|
@@ -285,11 +282,4 @@ export interface InputDropDownProps extends InputProps {
|
|
|
285
282
|
style?: ViewStyle | ViewStyle[];
|
|
286
283
|
}
|
|
287
284
|
|
|
288
|
-
export type InputSearchRef = {
|
|
289
|
-
clear: () => void;
|
|
290
|
-
focus: () => void | undefined;
|
|
291
|
-
blur: () => void | undefined;
|
|
292
|
-
setText: (text: string) => void;
|
|
293
|
-
};
|
|
294
|
-
|
|
295
285
|
export {Input, InputDropDown, InputMoney, InputOTP, InputSearch, InputTextArea};
|
package/Layout/Screen.tsx
CHANGED
|
@@ -2,17 +2,14 @@ import {useHeaderHeight} from '@react-navigation/stack';
|
|
|
2
2
|
import React, {
|
|
3
3
|
forwardRef,
|
|
4
4
|
Fragment,
|
|
5
|
-
LegacyRef,
|
|
6
5
|
ReactNode,
|
|
7
6
|
useContext,
|
|
8
7
|
useEffect,
|
|
9
8
|
useRef,
|
|
10
|
-
useState,
|
|
11
9
|
} from 'react';
|
|
12
10
|
import {
|
|
13
11
|
Animated,
|
|
14
12
|
KeyboardAvoidingView,
|
|
15
|
-
LayoutChangeEvent,
|
|
16
13
|
NativeScrollEvent,
|
|
17
14
|
NativeSyntheticEvent,
|
|
18
15
|
Platform,
|
|
@@ -27,20 +24,13 @@ import {
|
|
|
27
24
|
HeaderTitle,
|
|
28
25
|
} from '../Application';
|
|
29
26
|
import Navigation from '../Application/Navigation';
|
|
30
|
-
import {
|
|
31
|
-
AnimatedHeader,
|
|
32
|
-
HeaderRightActions,
|
|
33
|
-
HeaderRightToolkit,
|
|
34
|
-
NavigationOptions,
|
|
35
|
-
} from '../Application/types';
|
|
27
|
+
import {AnimatedHeader, NavigationOptions} from '../Application/types';
|
|
36
28
|
import {Colors, Spacing, Styles} from '../Consts';
|
|
37
29
|
import {FloatingButton, FloatingButtonProps} from './FloatingButton';
|
|
30
|
+
import {Image} from '../Image';
|
|
38
31
|
import {Card, Section, validateChildren} from './index';
|
|
39
32
|
import styles from './styles';
|
|
40
33
|
import {HeaderType} from './types';
|
|
41
|
-
import AnimatedInputSearch from './AnimatedInputSearch';
|
|
42
|
-
import {InputSearchProps, InputSearchRef} from '../Input';
|
|
43
|
-
import {ExtendBackground, HeaderRight} from '../Application/Components';
|
|
44
34
|
|
|
45
35
|
export interface ScreenProps extends ViewProps {
|
|
46
36
|
/**
|
|
@@ -111,15 +101,8 @@ export interface ScreenProps extends ViewProps {
|
|
|
111
101
|
* Optional. If `true`, the screen content is using grid layout by span.
|
|
112
102
|
*/
|
|
113
103
|
useGridLayout?: boolean;
|
|
114
|
-
|
|
115
|
-
inputSearchProps?: InputSearchProps;
|
|
116
|
-
|
|
117
|
-
headerRight?: HeaderRightActions | HeaderRightToolkit | CustomHeaderRight;
|
|
118
|
-
inputSearchRef?: LegacyRef<InputSearchRef>;
|
|
119
104
|
}
|
|
120
105
|
|
|
121
|
-
type CustomHeaderRight = (props: any) => Element;
|
|
122
|
-
|
|
123
106
|
const Screen = forwardRef(
|
|
124
107
|
(
|
|
125
108
|
{
|
|
@@ -137,31 +120,26 @@ const Screen = forwardRef(
|
|
|
137
120
|
floatingButtonProps,
|
|
138
121
|
useGridLayout = true,
|
|
139
122
|
keyboardVerticalOffset,
|
|
140
|
-
inputSearchProps,
|
|
141
|
-
headerRight,
|
|
142
|
-
inputSearchRef,
|
|
143
123
|
}: ScreenProps,
|
|
144
|
-
ref
|
|
124
|
+
ref,
|
|
145
125
|
) => {
|
|
146
126
|
const animatedValue = useRef<Animated.Value>(new Animated.Value(0));
|
|
147
127
|
const {theme} = useContext(ApplicationContext);
|
|
148
128
|
const insets = useSafeAreaInsets();
|
|
149
129
|
const heightHeader = useHeaderHeight();
|
|
150
|
-
const scrollViewRef = useRef<any>(ref);
|
|
151
130
|
const currentTint = useRef(Colors.black_01);
|
|
152
|
-
const isTab = navigation?.instance?.getState?.()?.type
|
|
153
|
-
const [headerRightWidth, setHeaderRightWidth] = useState(0);
|
|
131
|
+
const isTab = navigation?.instance?.getState?.()?.type == 'tab';
|
|
154
132
|
|
|
155
133
|
let styleAnimatedHeader: NavigationOptions;
|
|
156
134
|
let handleScroll;
|
|
157
135
|
let headerBackground: string | undefined = undefined;
|
|
158
136
|
let Component: any = View;
|
|
159
137
|
let keyboardOffset = heightHeader - 20;
|
|
160
|
-
if (headerType
|
|
138
|
+
if (headerType == 'extended' || animatedHeader) {
|
|
161
139
|
keyboardOffset = -20;
|
|
162
140
|
}
|
|
163
141
|
|
|
164
|
-
if (headerType
|
|
142
|
+
if (headerType == 'extended') {
|
|
165
143
|
headerBackground = theme.assets?.headerBackground;
|
|
166
144
|
}
|
|
167
145
|
|
|
@@ -179,7 +157,7 @@ const Screen = forwardRef(
|
|
|
179
157
|
<HeaderTitle {...props} animatedValue={animatedValue.current} />
|
|
180
158
|
),
|
|
181
159
|
};
|
|
182
|
-
if (animatedHeader.type
|
|
160
|
+
if (animatedHeader.type == 'surface') {
|
|
183
161
|
styleAnimatedHeader = {
|
|
184
162
|
...styleAnimatedHeader,
|
|
185
163
|
headerBackground: (props: any) => (
|
|
@@ -202,7 +180,6 @@ const Screen = forwardRef(
|
|
|
202
180
|
}),
|
|
203
181
|
};
|
|
204
182
|
}
|
|
205
|
-
|
|
206
183
|
navigation?.setOptions(styleAnimatedHeader);
|
|
207
184
|
}
|
|
208
185
|
}, [animatedHeader]);
|
|
@@ -210,22 +187,6 @@ const Screen = forwardRef(
|
|
|
210
187
|
useEffect(() => {
|
|
211
188
|
if (!animatedHeader) {
|
|
212
189
|
let headerOptions: NavigationOptions;
|
|
213
|
-
|
|
214
|
-
const interpolateConfig: Animated.InterpolationConfigType =
|
|
215
|
-
inputSearchProps
|
|
216
|
-
? {
|
|
217
|
-
inputRange: [0, 100],
|
|
218
|
-
outputRange: [1, 0],
|
|
219
|
-
extrapolate: 'clamp',
|
|
220
|
-
}
|
|
221
|
-
: {
|
|
222
|
-
inputRange: [0, 200],
|
|
223
|
-
outputRange: [0, 1],
|
|
224
|
-
extrapolate: 'clamp',
|
|
225
|
-
};
|
|
226
|
-
const titleOpacity =
|
|
227
|
-
animatedValue.current.interpolate(interpolateConfig);
|
|
228
|
-
|
|
229
190
|
switch (headerType) {
|
|
230
191
|
case 'none':
|
|
231
192
|
headerOptions = {
|
|
@@ -253,9 +214,7 @@ const Screen = forwardRef(
|
|
|
253
214
|
headerTransparent: true,
|
|
254
215
|
headerTintColor: Colors.black_01,
|
|
255
216
|
headerBackground: () => null,
|
|
256
|
-
headerTitle: (props: any) =>
|
|
257
|
-
<HeaderTitle {...props} titleOpacity={titleOpacity} />
|
|
258
|
-
),
|
|
217
|
+
headerTitle: (props: any) => <HeaderTitle {...props} />,
|
|
259
218
|
};
|
|
260
219
|
break;
|
|
261
220
|
|
|
@@ -271,33 +230,13 @@ const Screen = forwardRef(
|
|
|
271
230
|
}
|
|
272
231
|
}, [headerType]);
|
|
273
232
|
|
|
274
|
-
useEffect(() => {
|
|
275
|
-
if (headerRight) {
|
|
276
|
-
navigation?.setOptions({
|
|
277
|
-
headerRight: (props: any) => (
|
|
278
|
-
<View onLayout={onHeaderRightLayout}>
|
|
279
|
-
{typeof headerRight === 'function' ? (
|
|
280
|
-
headerRight(props)
|
|
281
|
-
) : (
|
|
282
|
-
<HeaderRight {...props} {...headerRight} />
|
|
283
|
-
)}
|
|
284
|
-
</View>
|
|
285
|
-
),
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
}, [headerRight]);
|
|
289
|
-
|
|
290
|
-
const onHeaderRightLayout = (e: LayoutChangeEvent) => {
|
|
291
|
-
setHeaderRightWidth(e.nativeEvent.layout.width);
|
|
292
|
-
};
|
|
293
|
-
|
|
294
233
|
/**
|
|
295
234
|
* animated when use scroll && animated value
|
|
296
235
|
*/
|
|
297
236
|
if (scrollable) {
|
|
298
237
|
Component = Animated.ScrollView;
|
|
299
238
|
handleScroll = scrollViewProps?.onScroll;
|
|
300
|
-
if (animatedHeader || floatingButtonProps?.icon
|
|
239
|
+
if (animatedHeader || floatingButtonProps?.icon) {
|
|
301
240
|
handleScroll = Animated.event(
|
|
302
241
|
[
|
|
303
242
|
{
|
|
@@ -310,13 +249,13 @@ const Screen = forwardRef(
|
|
|
310
249
|
useNativeDriver: true,
|
|
311
250
|
listener: (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
312
251
|
scrollViewProps?.onScroll?.(e);
|
|
313
|
-
if (animatedHeader?.type
|
|
252
|
+
if (animatedHeader?.type == 'surface') {
|
|
314
253
|
const offsetY = e.nativeEvent.contentOffset.y;
|
|
315
254
|
let color = Colors.black_01;
|
|
316
255
|
if (offsetY > 50) {
|
|
317
256
|
color = theme.colors.text.default;
|
|
318
257
|
}
|
|
319
|
-
if (color
|
|
258
|
+
if (color != currentTint.current) {
|
|
320
259
|
currentTint.current = color;
|
|
321
260
|
navigation?.setOptions({
|
|
322
261
|
headerTintColor: color,
|
|
@@ -324,26 +263,11 @@ const Screen = forwardRef(
|
|
|
324
263
|
}
|
|
325
264
|
}
|
|
326
265
|
},
|
|
327
|
-
}
|
|
266
|
+
},
|
|
328
267
|
);
|
|
329
268
|
}
|
|
330
269
|
}
|
|
331
270
|
|
|
332
|
-
const handleScrollEnd = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
333
|
-
const offsetY = e.nativeEvent.contentOffset.y;
|
|
334
|
-
|
|
335
|
-
if (inputSearchProps && offsetY < 100 && offsetY > 0) {
|
|
336
|
-
Animated.timing(animatedValue.current, {
|
|
337
|
-
toValue: 0,
|
|
338
|
-
useNativeDriver: true,
|
|
339
|
-
duration: 300,
|
|
340
|
-
}).start();
|
|
341
|
-
scrollViewRef.current?.scrollTo({y: 0, animated: true});
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
scrollViewProps?.onScrollEndDrag?.(e);
|
|
345
|
-
};
|
|
346
|
-
|
|
347
271
|
/**
|
|
348
272
|
* render top navigation banner
|
|
349
273
|
*/
|
|
@@ -363,7 +287,7 @@ const Screen = forwardRef(
|
|
|
363
287
|
if (Array.isArray(results)) {
|
|
364
288
|
return results.map((item, index) => {
|
|
365
289
|
const space = item?.props?.useMargin === false ? 0 : Spacing.M;
|
|
366
|
-
if (item?.type
|
|
290
|
+
if (item?.type == Fragment) {
|
|
367
291
|
return renderContent(item?.props?.children);
|
|
368
292
|
}
|
|
369
293
|
if (item) {
|
|
@@ -383,7 +307,7 @@ const Screen = forwardRef(
|
|
|
383
307
|
} else {
|
|
384
308
|
const item: any = children;
|
|
385
309
|
const space = item?.props?.useMargin === false ? 0 : Spacing.M;
|
|
386
|
-
if (item?.type
|
|
310
|
+
if (item?.type == Fragment) {
|
|
387
311
|
return renderContent(item?.props?.children);
|
|
388
312
|
}
|
|
389
313
|
return (
|
|
@@ -403,21 +327,15 @@ const Screen = forwardRef(
|
|
|
403
327
|
return (
|
|
404
328
|
<View style={[Styles.flex, {backgroundColor}]}>
|
|
405
329
|
{!!headerBackground && (
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
headerRightWidth={headerRightWidth}
|
|
416
|
-
headerType={headerType}
|
|
417
|
-
heightHeader={heightHeader}
|
|
418
|
-
inputSearchProps={inputSearchProps}
|
|
419
|
-
inputRef={inputSearchRef}
|
|
420
|
-
/>
|
|
330
|
+
<>
|
|
331
|
+
<Image
|
|
332
|
+
source={{
|
|
333
|
+
uri: headerBackground,
|
|
334
|
+
}}
|
|
335
|
+
style={styles.extendedHeader}
|
|
336
|
+
/>
|
|
337
|
+
<View style={{height: heightHeader}} />
|
|
338
|
+
</>
|
|
421
339
|
)}
|
|
422
340
|
<KeyboardAvoidingView
|
|
423
341
|
style={Styles.flex}
|
|
@@ -431,11 +349,9 @@ const Screen = forwardRef(
|
|
|
431
349
|
|
|
432
350
|
<Component
|
|
433
351
|
{...scrollViewProps}
|
|
434
|
-
ref={
|
|
352
|
+
ref={ref}
|
|
435
353
|
showsVerticalScrollIndicator={false}
|
|
436
354
|
onScroll={handleScroll}
|
|
437
|
-
onScrollEndDrag={handleScrollEnd}
|
|
438
|
-
scrollEventThrottle={16}
|
|
439
355
|
style={Styles.flex}>
|
|
440
356
|
<View
|
|
441
357
|
style={[styles.screenBanner, {maxHeight: 210 + layoutOffset}]}>
|
|
@@ -471,7 +387,7 @@ const Screen = forwardRef(
|
|
|
471
387
|
</KeyboardAvoidingView>
|
|
472
388
|
</View>
|
|
473
389
|
);
|
|
474
|
-
}
|
|
390
|
+
},
|
|
475
391
|
);
|
|
476
392
|
|
|
477
393
|
export default Screen;
|
package/Layout/styles.ts
CHANGED
|
@@ -2,6 +2,12 @@ import {Platform, StyleSheet} from 'react-native';
|
|
|
2
2
|
import {Colors, Radius, Spacing} from '../Consts';
|
|
3
3
|
|
|
4
4
|
export default StyleSheet.create({
|
|
5
|
+
extendedHeader: {
|
|
6
|
+
aspectRatio: 1.75,
|
|
7
|
+
position: 'absolute',
|
|
8
|
+
width: '100%',
|
|
9
|
+
height: 210,
|
|
10
|
+
},
|
|
5
11
|
screenBanner: {
|
|
6
12
|
width: '100%',
|
|
7
13
|
},
|