@momo-kits/foundation 0.92.21-beta.0 → 0.92.21-beta.2

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/Layout/Screen.tsx CHANGED
@@ -2,14 +2,17 @@ import {useHeaderHeight} from '@react-navigation/stack';
2
2
  import React, {
3
3
  forwardRef,
4
4
  Fragment,
5
+ LegacyRef,
5
6
  ReactNode,
6
7
  useContext,
7
8
  useEffect,
8
9
  useRef,
10
+ useState,
9
11
  } from 'react';
10
12
  import {
11
13
  Animated,
12
14
  KeyboardAvoidingView,
15
+ LayoutChangeEvent,
13
16
  NativeScrollEvent,
14
17
  NativeSyntheticEvent,
15
18
  Platform,
@@ -24,13 +27,20 @@ import {
24
27
  HeaderTitle,
25
28
  } from '../Application';
26
29
  import Navigation from '../Application/Navigation';
27
- import {AnimatedHeader, NavigationOptions} from '../Application/types';
30
+ import {
31
+ AnimatedHeader,
32
+ HeaderRightActions,
33
+ HeaderRightToolkit,
34
+ NavigationOptions,
35
+ } from '../Application/types';
28
36
  import {Colors, Spacing, Styles} from '../Consts';
29
37
  import {FloatingButton, FloatingButtonProps} from './FloatingButton';
30
- import {Image} from '../Image';
31
38
  import {Card, Section, validateChildren} from './index';
32
39
  import styles from './styles';
33
40
  import {HeaderType} from './types';
41
+ import AnimatedInputSearch from './AnimatedInputSearch';
42
+ import {InputSearchProps, InputSearchRef} from '../Input';
43
+ import {ExtendBackground, HeaderRight} from '../Application/Components';
34
44
 
35
45
  export interface ScreenProps extends ViewProps {
36
46
  /**
@@ -101,8 +111,15 @@ export interface ScreenProps extends ViewProps {
101
111
  * Optional. If `true`, the screen content is using grid layout by span.
102
112
  */
103
113
  useGridLayout?: boolean;
114
+
115
+ inputSearchProps?: InputSearchProps;
116
+
117
+ headerRight?: HeaderRightActions | HeaderRightToolkit | CustomHeaderRight;
118
+ inputSearchRef?: LegacyRef<InputSearchRef>;
104
119
  }
105
120
 
121
+ type CustomHeaderRight = (props: any) => Element;
122
+
106
123
  const Screen = forwardRef(
107
124
  (
108
125
  {
@@ -120,26 +137,31 @@ const Screen = forwardRef(
120
137
  floatingButtonProps,
121
138
  useGridLayout = true,
122
139
  keyboardVerticalOffset,
140
+ inputSearchProps,
141
+ headerRight,
142
+ inputSearchRef,
123
143
  }: ScreenProps,
124
- ref,
144
+ ref
125
145
  ) => {
126
146
  const animatedValue = useRef<Animated.Value>(new Animated.Value(0));
127
147
  const {theme} = useContext(ApplicationContext);
128
148
  const insets = useSafeAreaInsets();
129
149
  const heightHeader = useHeaderHeight();
150
+ const scrollViewRef = useRef<any>(ref);
130
151
  const currentTint = useRef(Colors.black_01);
131
- const isTab = navigation?.instance?.getState?.()?.type == 'tab';
152
+ const isTab = navigation?.instance?.getState?.()?.type === 'tab';
153
+ const [headerRightWidth, setHeaderRightWidth] = useState(0);
132
154
 
133
155
  let styleAnimatedHeader: NavigationOptions;
134
156
  let handleScroll;
135
157
  let headerBackground: string | undefined = undefined;
136
158
  let Component: any = View;
137
159
  let keyboardOffset = heightHeader - 20;
138
- if (headerType == 'extended' || animatedHeader) {
160
+ if (headerType === 'extended' || animatedHeader) {
139
161
  keyboardOffset = -20;
140
162
  }
141
163
 
142
- if (headerType == 'extended') {
164
+ if (headerType === 'extended') {
143
165
  headerBackground = theme.assets?.headerBackground;
144
166
  }
145
167
 
@@ -157,7 +179,7 @@ const Screen = forwardRef(
157
179
  <HeaderTitle {...props} animatedValue={animatedValue.current} />
158
180
  ),
159
181
  };
160
- if (animatedHeader.type == 'surface') {
182
+ if (animatedHeader.type === 'surface') {
161
183
  styleAnimatedHeader = {
162
184
  ...styleAnimatedHeader,
163
185
  headerBackground: (props: any) => (
@@ -180,6 +202,7 @@ const Screen = forwardRef(
180
202
  }),
181
203
  };
182
204
  }
205
+
183
206
  navigation?.setOptions(styleAnimatedHeader);
184
207
  }
185
208
  }, [animatedHeader]);
@@ -187,6 +210,22 @@ const Screen = forwardRef(
187
210
  useEffect(() => {
188
211
  if (!animatedHeader) {
189
212
  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
+
190
229
  switch (headerType) {
191
230
  case 'none':
192
231
  headerOptions = {
@@ -214,7 +253,9 @@ const Screen = forwardRef(
214
253
  headerTransparent: true,
215
254
  headerTintColor: Colors.black_01,
216
255
  headerBackground: () => null,
217
- headerTitle: (props: any) => <HeaderTitle {...props} />,
256
+ headerTitle: (props: any) => (
257
+ <HeaderTitle {...props} titleOpacity={titleOpacity} />
258
+ ),
218
259
  };
219
260
  break;
220
261
 
@@ -230,13 +271,33 @@ const Screen = forwardRef(
230
271
  }
231
272
  }, [headerType]);
232
273
 
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
+
233
294
  /**
234
295
  * animated when use scroll && animated value
235
296
  */
236
297
  if (scrollable) {
237
298
  Component = Animated.ScrollView;
238
299
  handleScroll = scrollViewProps?.onScroll;
239
- if (animatedHeader || floatingButtonProps?.icon) {
300
+ if (animatedHeader || floatingButtonProps?.icon || inputSearchProps) {
240
301
  handleScroll = Animated.event(
241
302
  [
242
303
  {
@@ -249,13 +310,13 @@ const Screen = forwardRef(
249
310
  useNativeDriver: true,
250
311
  listener: (e: NativeSyntheticEvent<NativeScrollEvent>) => {
251
312
  scrollViewProps?.onScroll?.(e);
252
- if (animatedHeader?.type == 'surface') {
313
+ if (animatedHeader?.type === 'surface') {
253
314
  const offsetY = e.nativeEvent.contentOffset.y;
254
315
  let color = Colors.black_01;
255
316
  if (offsetY > 50) {
256
317
  color = theme.colors.text.default;
257
318
  }
258
- if (color != currentTint.current) {
319
+ if (color !== currentTint.current) {
259
320
  currentTint.current = color;
260
321
  navigation?.setOptions({
261
322
  headerTintColor: color,
@@ -263,11 +324,26 @@ const Screen = forwardRef(
263
324
  }
264
325
  }
265
326
  },
266
- },
327
+ }
267
328
  );
268
329
  }
269
330
  }
270
331
 
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
+
271
347
  /**
272
348
  * render top navigation banner
273
349
  */
@@ -287,7 +363,7 @@ const Screen = forwardRef(
287
363
  if (Array.isArray(results)) {
288
364
  return results.map((item, index) => {
289
365
  const space = item?.props?.useMargin === false ? 0 : Spacing.M;
290
- if (item?.type == Fragment) {
366
+ if (item?.type === Fragment) {
291
367
  return renderContent(item?.props?.children);
292
368
  }
293
369
  if (item) {
@@ -307,7 +383,7 @@ const Screen = forwardRef(
307
383
  } else {
308
384
  const item: any = children;
309
385
  const space = item?.props?.useMargin === false ? 0 : Spacing.M;
310
- if (item?.type == Fragment) {
386
+ if (item?.type === Fragment) {
311
387
  return renderContent(item?.props?.children);
312
388
  }
313
389
  return (
@@ -327,15 +403,21 @@ const Screen = forwardRef(
327
403
  return (
328
404
  <View style={[Styles.flex, {backgroundColor}]}>
329
405
  {!!headerBackground && (
330
- <>
331
- <Image
332
- source={{
333
- uri: headerBackground,
334
- }}
335
- style={styles.extendedHeader}
336
- />
337
- <View style={{height: heightHeader}} />
338
- </>
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
+ />
339
421
  )}
340
422
  <KeyboardAvoidingView
341
423
  style={Styles.flex}
@@ -349,9 +431,11 @@ const Screen = forwardRef(
349
431
 
350
432
  <Component
351
433
  {...scrollViewProps}
352
- ref={ref}
434
+ ref={scrollViewRef}
353
435
  showsVerticalScrollIndicator={false}
354
436
  onScroll={handleScroll}
437
+ onScrollEndDrag={handleScrollEnd}
438
+ scrollEventThrottle={16}
355
439
  style={Styles.flex}>
356
440
  <View
357
441
  style={[styles.screenBanner, {maxHeight: 210 + layoutOffset}]}>
@@ -387,7 +471,7 @@ const Screen = forwardRef(
387
471
  </KeyboardAvoidingView>
388
472
  </View>
389
473
  );
390
- },
474
+ }
391
475
  );
392
476
 
393
477
  export default Screen;
package/Layout/styles.ts CHANGED
@@ -2,12 +2,6 @@ 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
- },
11
5
  screenBanner: {
12
6
  width: '100%',
13
7
  },
package/Layout/types.ts CHANGED
@@ -1,4 +1,8 @@
1
- export type HeaderType = 'default' | 'surface' | 'extended' | 'none';
1
+ import {Animated} from 'react-native';
2
+ import {InputSearchProps, InputSearchRef} from '../Input';
3
+ import {LegacyRef} from 'react';
4
+
5
+ export type HeaderType = 'default' | 'surface' | 'extended' | 'search' | 'none';
2
6
 
3
7
  export type GridContextProps = {
4
8
  /**
@@ -21,3 +25,18 @@ export type GridContextProps = {
21
25
  */
22
26
  getSizeSpan: (span: number) => number;
23
27
  };
28
+
29
+ export type AnimatedInputSearchProps = {
30
+ animatedValue: Animated.Value;
31
+ headerRightWidth: number;
32
+ heightHeader: number;
33
+ headerType: HeaderType;
34
+ inputSearchProps?: InputSearchProps;
35
+ inputRef?: LegacyRef<InputSearchRef>;
36
+ };
37
+
38
+ export type ExtendHeaderProps = {
39
+ headerBackground: string;
40
+ animatedValue: Animated.Value;
41
+ heightHeader: number;
42
+ };
package/Title/index.tsx CHANGED
@@ -1,13 +1,16 @@
1
1
  import React, {FC, useContext, useState} from 'react';
2
2
  import {Text as RNText, TouchableOpacity, View, ViewStyle} from 'react-native';
3
- import {Icon} from '../Icon';
4
- import {scaleSize, Text} from '../Text';
5
- import {ApplicationContext} from '../Application';
6
- import {Badge} from '../Badge';
7
- import {Colors} from '../Consts';
3
+ import {
4
+ Typography,
5
+ Colors,
6
+ Icon,
7
+ Badge,
8
+ ApplicationContext,
9
+ scaleSize,
10
+ Text,
11
+ } from '@momo-kits/foundation';
8
12
  import styles from './styles';
9
13
  import {TitleProps} from './types';
10
- import {Typography} from '../Text/types';
11
14
 
12
15
  const Title: FC<TitleProps> = ({
13
16
  title = 'Title',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.92.21-beta.0",
3
+ "version": "0.92.21-beta.2",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},
@@ -43,4 +43,4 @@
43
43
  },
44
44
  "author": "@momo-kits/foundation",
45
45
  "license": "ISC"
46
- }
46
+ }
package/publish.sh CHANGED
@@ -7,16 +7,16 @@ rsync -r --exclude=/dist ./* dist
7
7
  cd dist
8
8
 
9
9
  if [ "$1" == "stable" ]; then
10
- #npm version $(npm view @momo-kits/foundation@stable version)
11
- #npm version patch
10
+ npm version $(npm view @momo-kits/foundation@stable version)
11
+ npm version patch
12
12
  npm publish --tag stable --access=public
13
13
  elif [ "$1" == "latest" ]; then
14
- #npm version $(npm view @momo-kits/foundation@latest version)
15
- #npm version prerelease --preid=rc
14
+ npm version $(npm view @momo-kits/foundation@latest version)
15
+ npm version prerelease --preid=rc
16
16
  npm publish --tag latest --access=public
17
17
  else
18
- #npm version $(npm view @momo-kits/foundation@beta version)
19
- #npm version prerelease --preid=beta
18
+ npm version $(npm view @momo-kits/foundation@beta version)
19
+ npm version prerelease --preid=beta
20
20
  npm publish --tag beta --access=public
21
21
  fi
22
22