@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.
@@ -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, InputSearchRef} from './index';
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: ForwardRefRenderFunction<
25
- InputSearchRef,
26
- InputSearchProps
27
- > = (
28
- {
29
- placeholder,
30
- onFocus,
31
- onBlur,
32
- iconColor,
33
- value,
34
- onChangeText,
35
- icon,
36
- buttonText = 'Hủy',
37
- showButtonText = true,
38
- style,
39
- defaultValue,
40
- onPressButtonText,
41
- params,
42
- hasColorBG = false,
43
- accessibilityLabel,
44
- typingData = [],
45
- onPress,
46
- ...props
47
- },
48
- ref
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
- const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
61
- setFocused(false);
62
- onBlur?.(e);
63
- };
49
+ const _onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
50
+ setFocused(true);
51
+ onFocus?.(e);
52
+ };
64
53
 
65
- const onClearText = () => {
66
- inputRef?.current?.clear();
67
- _onChangeText('');
68
- };
54
+ const _onBlur = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
55
+ setFocused(false);
56
+ onBlur?.(e);
57
+ };
69
58
 
70
- const _onChangeText = (text: string) => {
71
- checkTyping(text, haveValue, setHaveValue);
72
- onChangeText?.(text);
73
- };
59
+ const onClearText = () => {
60
+ inputRef?.current?.clear();
61
+ _onChangeText('');
62
+ };
74
63
 
75
- useImperativeHandle(ref, () => {
76
- return {
77
- clear: onClearText,
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
- const renderInputView = () => {
85
- if (typingData?.length > 0) {
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
- <TouchableOpacity
80
+ <TextInput
81
+ {...props}
82
+ accessibilityLabel={accessibilityLabel}
83
+ textAlignVertical="center"
84
+ ref={inputRef}
88
85
  style={[
89
86
  styles.searchInput,
90
87
  {
91
- justifyContent: 'center',
88
+ color: theme.colors.text.default,
92
89
  },
93
90
  ]}
94
- onPress={onPress}
95
- activeOpacity={onPress ? 0.6 : 1}>
96
- <TextTyping data={typingData} />
97
- </TouchableOpacity>
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
- return (
102
- <TextInput
103
- {...props}
104
- accessibilityLabel={accessibilityLabel}
105
- textAlignVertical="center"
106
- ref={inputRef}
107
- style={[
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
- <View
127
- style={{
128
- flexDirection: 'row',
153
+ <ComponentContext.Provider
154
+ value={{
155
+ componentName: 'InputSearch',
156
+ params,
157
+ state: inputState,
158
+ componentId: accessibilityLabel,
129
159
  }}>
130
- {focused && haveValue && (
131
- <TouchableOpacity style={styles.iconWrapper} onPress={onClearText}>
160
+ <View style={[style, styles.searchInputContainer]}>
161
+ <View
162
+ style={[
163
+ styles.searchInputWrapper,
164
+ {
165
+ backgroundColor,
166
+ },
167
+ ]}>
132
168
  <Icon
133
- source="24_navigation_close_circle_full"
134
- size={16}
169
+ source={'navigation_search'}
170
+ size={24}
135
171
  color={theme.colors.text.hint}
136
172
  />
137
- </TouchableOpacity>
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
- </View>
157
- );
158
- };
159
-
160
- let inputState = 'empty';
161
-
162
- if (focused) {
163
- inputState = 'focus';
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
- {showButtonText && (
199
- <TouchableOpacity onPress={onPressButtonText}>
200
- <Text typography={'action_default_bold'} style={styles.textButton}>
201
- {buttonText}
202
- </Text>
203
- </TouchableOpacity>
204
- )}
205
- </View>
206
- </ComponentContext.Provider>
207
- );
208
- };
186
+ </ComponentContext.Provider>
187
+ );
188
+ },
189
+ );
209
190
 
210
- export default forwardRef(InputSearch);
191
+ export default InputSearch;
package/Input/index.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import {GestureResponderEvent, TextInputProps, ViewStyle} from 'react-native';
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 === 'tab';
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 === 'extended' || animatedHeader) {
138
+ if (headerType == 'extended' || animatedHeader) {
161
139
  keyboardOffset = -20;
162
140
  }
163
141
 
164
- if (headerType === 'extended') {
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 === 'surface') {
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 || inputSearchProps) {
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 === 'surface') {
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 !== currentTint.current) {
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 === Fragment) {
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 === Fragment) {
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
- <ExtendBackground
407
- headerBackground={headerBackground}
408
- heightHeader={heightHeader}
409
- animatedValue={animatedValue.current}
410
- />
411
- )}
412
- {inputSearchProps && (
413
- <AnimatedInputSearch
414
- animatedValue={animatedValue.current}
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={scrollViewRef}
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
  },