@momo-kits/foundation 0.75.1-beta.9 → 0.75.3-beta.0

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.
Files changed (113) hide show
  1. package/Application/BottomSheet.tsx +225 -0
  2. package/Application/BottomTab/BottomTabBar.tsx +291 -0
  3. package/Application/BottomTab/index.tsx +138 -0
  4. package/Application/Components.tsx +555 -0
  5. package/Application/ModalScreen.tsx +97 -0
  6. package/Application/Navigation.ts +50 -0
  7. package/Application/NavigationContainer.tsx +121 -0
  8. package/Application/Navigator.ts +151 -0
  9. package/Application/StackScreen.tsx +148 -0
  10. package/Application/index.ts +37 -0
  11. package/{Navigation → Application}/types.ts +101 -33
  12. package/Application/utils.tsx +153 -0
  13. package/Assets/DotAnimation.json +256 -0
  14. package/Assets/SpinnerAnimation.json +1027 -0
  15. package/Assets/icon.json +89 -5
  16. package/Assets/icon_bank.json +506 -0
  17. package/Assets/language.json +202 -0
  18. package/Badge/Badge.tsx +56 -0
  19. package/Badge/BadgeDot.tsx +11 -0
  20. package/Badge/BadgeRibbon.tsx +125 -0
  21. package/Badge/Shape.tsx +29 -0
  22. package/Badge/index.tsx +7 -0
  23. package/Badge/styles.ts +58 -0
  24. package/Badge/types.ts +63 -0
  25. package/Button/index.tsx +91 -40
  26. package/Button/styles.ts +19 -0
  27. package/CheckBox/index.tsx +58 -43
  28. package/CheckBox/styles.ts +1 -1
  29. package/CheckBox/types.ts +6 -4
  30. package/Consts/colors+spacing+radius.ts +18 -0
  31. package/Consts/styles.ts +0 -26
  32. package/Consts/theme.ts +5 -1
  33. package/Divider/index.tsx +3 -1
  34. package/Icon/index.tsx +15 -10
  35. package/Icon/types.ts +4 -3
  36. package/IconButton/index.tsx +24 -15
  37. package/Image/index.tsx +63 -45
  38. package/Image/styles.ts +1 -9
  39. package/Image/types.ts +5 -1
  40. package/Input/Input.tsx +227 -115
  41. package/Input/InputDropDown.tsx +132 -0
  42. package/Input/InputMoney.tsx +173 -110
  43. package/Input/InputOTP.tsx +257 -0
  44. package/Input/InputSearch.tsx +160 -130
  45. package/Input/InputTextArea.tsx +149 -121
  46. package/Input/common.tsx +36 -18
  47. package/Input/index.tsx +212 -17
  48. package/Input/styles.ts +44 -7
  49. package/Input/utils.ts +2 -2
  50. package/Layout/Card.tsx +76 -37
  51. package/Layout/FloatingButton.tsx +168 -0
  52. package/Layout/GridSystem.tsx +35 -23
  53. package/Layout/Item.tsx +29 -33
  54. package/Layout/ItemList.tsx +55 -0
  55. package/Layout/ItemSectionList.tsx +39 -0
  56. package/Layout/Screen.tsx +390 -0
  57. package/Layout/Section.tsx +73 -35
  58. package/Layout/index.ts +13 -3
  59. package/Layout/styles.ts +101 -0
  60. package/Layout/types.ts +1 -37
  61. package/Layout/utils.ts +38 -43
  62. package/Loader/DotLoader.tsx +37 -0
  63. package/Loader/Loader.tsx +13 -0
  64. package/Loader/ProgressBar.tsx +44 -0
  65. package/Loader/Spinner.tsx +29 -0
  66. package/Loader/index.tsx +4 -0
  67. package/Loader/styles.ts +10 -0
  68. package/Loader/types.ts +35 -0
  69. package/Loader/utils.ts +25 -0
  70. package/Pagination/Dot.tsx +1 -1
  71. package/Pagination/PaginationDot.tsx +8 -3
  72. package/Pagination/PaginationNumber.tsx +8 -7
  73. package/Pagination/PaginationScroll.tsx +1 -1
  74. package/Pagination/PaginationWhiteDot.tsx +8 -5
  75. package/Pagination/styles.ts +3 -0
  76. package/Pagination/types.ts +2 -0
  77. package/Popup/PopupNotify.tsx +108 -46
  78. package/Popup/PopupPromotion.tsx +63 -22
  79. package/Popup/types.ts +15 -4
  80. package/Radio/index.tsx +35 -21
  81. package/Radio/types.ts +7 -5
  82. package/Skeleton/index.tsx +1 -1
  83. package/Skeleton/types.ts +3 -0
  84. package/Switch/index.tsx +35 -24
  85. package/Switch/types.ts +5 -3
  86. package/Tag/index.tsx +1 -1
  87. package/Text/index.tsx +32 -26
  88. package/Text/styles.ts +38 -0
  89. package/Text/types.ts +25 -13
  90. package/Text/utils.ts +14 -0
  91. package/Title/index.tsx +197 -0
  92. package/Title/styles.ts +79 -0
  93. package/Title/types.ts +20 -0
  94. package/code-scanner.js +143 -0
  95. package/index.ts +22 -2
  96. package/migrate_typo.js +56 -0
  97. package/package.json +44 -39
  98. package/publish.sh +2 -5
  99. package/tsconfig.json +24 -0
  100. package/verify.js +47 -0
  101. package/Assets/header-background.png +0 -0
  102. package/Layout/ScreenContainer.tsx +0 -121
  103. package/Navigation/BottomTab.tsx +0 -39
  104. package/Navigation/Components.tsx +0 -365
  105. package/Navigation/ModalScreen.tsx +0 -226
  106. package/Navigation/Navigation.ts +0 -44
  107. package/Navigation/NavigationButton.tsx +0 -54
  108. package/Navigation/NavigationContainer.tsx +0 -77
  109. package/Navigation/Navigator.ts +0 -82
  110. package/Navigation/Observer.ts +0 -79
  111. package/Navigation/StackScreen.tsx +0 -27
  112. package/Navigation/index.ts +0 -14
  113. package/Navigation/utils.tsx +0 -137
@@ -0,0 +1,555 @@
1
+ import React, {
2
+ Fragment,
3
+ useCallback,
4
+ useContext,
5
+ useEffect,
6
+ useState,
7
+ } from 'react';
8
+ import {
9
+ Animated,
10
+ BackHandler,
11
+ DeviceEventEmitter,
12
+ StatusBar,
13
+ StyleSheet,
14
+ TouchableOpacity,
15
+ View,
16
+ ViewStyle,
17
+ } from 'react-native';
18
+ import {ApplicationContext, MiniAppContext} from './index';
19
+ import {Colors, Radius, Spacing, Styles} from '../Consts';
20
+ import {Image} from '../Image';
21
+ import {
22
+ HeaderAnimatedProps,
23
+ HeaderBackgroundProps,
24
+ HeaderBackProps,
25
+ NavigationButtonProps,
26
+ TitleCustomProps,
27
+ } from './types';
28
+ import {scaleSize, Text} from '../Text';
29
+ import {Icon} from '../Icon';
30
+ import {PopupNotify} from '../Popup';
31
+ import {Badge, BadgeDot} from '../Badge';
32
+
33
+ const NavigationButton: React.FC<NavigationButtonProps> = ({
34
+ icon,
35
+ tintColor,
36
+ onPress,
37
+ useBorder = true,
38
+ badgeType,
39
+ badgeValue,
40
+ accessibilityLabel = '',
41
+ }) => {
42
+ const {theme} = useContext(ApplicationContext);
43
+ let buttonStyle: ViewStyle = {backgroundColor: '#00000066'};
44
+ if (tintColor != Colors.black_01) {
45
+ buttonStyle = {
46
+ backgroundColor: 'transparent',
47
+ borderColor: '#00000066',
48
+ borderWidth: useBorder ? 0.5 : 0,
49
+ };
50
+ }
51
+
52
+ const isNumber = (label: any) => {
53
+ const numberRegex = /^\d+$/;
54
+ return numberRegex.test(String(label));
55
+ };
56
+
57
+ const renderBadge = useCallback(() => {
58
+ if (badgeType === 'dot') {
59
+ return <BadgeDot size="small" style={styles.badgeDot} />;
60
+ }
61
+
62
+ if (isNumber(badgeValue)) {
63
+ return <Badge label={badgeValue} style={styles.badge} />;
64
+ }
65
+ }, [badgeType, badgeValue]);
66
+
67
+ return (
68
+ <View style={{width: scaleSize(28)}}>
69
+ <TouchableOpacity
70
+ accessibilityLabel={accessibilityLabel}
71
+ style={[styles.navigationButton, buttonStyle]}
72
+ onPress={onPress}>
73
+ <Icon
74
+ source={icon}
75
+ color={tintColor ?? theme.colors.text.default}
76
+ size={20}
77
+ />
78
+ </TouchableOpacity>
79
+ {renderBadge()}
80
+ </View>
81
+ );
82
+ };
83
+
84
+ const HeaderTitle: React.FC<any> = props => {
85
+ const {theme} = useContext(ApplicationContext);
86
+ const opacity = props.animatedValue?.interpolate({
87
+ inputRange: [0, 200],
88
+ outputRange: [0, 1],
89
+ extrapolate: 'clamp',
90
+ });
91
+
92
+ return (
93
+ <Animated.Text
94
+ {...props}
95
+ accessibilityLabel={'title_navigation_header'}
96
+ style={[
97
+ styles.title,
98
+ {fontFamily: `${theme.font}-Bold`, opacity, color: props.tintColor},
99
+ ]}
100
+ />
101
+ );
102
+ };
103
+
104
+ const HeaderLeft: React.FC<HeaderBackProps> = ({
105
+ tintColor,
106
+ preventBack,
107
+ onPressLeftHeader,
108
+ useBorder,
109
+ }) => {
110
+ const context = useContext<any>(MiniAppContext);
111
+ const {navigator} = useContext(ApplicationContext);
112
+
113
+ useEffect(() => {
114
+ const backHandler = BackHandler.addEventListener(
115
+ 'hardwareBackPress',
116
+ goBackSafe,
117
+ );
118
+
119
+ return () => backHandler.remove();
120
+ }, []);
121
+
122
+ const goBackSafe = () => {
123
+ const goBack = () => {
124
+ const canGoBack = navigator?.ref?.current?.canGoBack?.();
125
+ const currentRoute = navigator?.ref?.current?.getCurrentRoute?.();
126
+ const params = {
127
+ appId: context.appId,
128
+ code: context.code,
129
+ screen_name: currentRoute?.params?.screen?.name ?? currentRoute?.name,
130
+ trigger_id: '111154000000000000',
131
+ icon_name: 'back',
132
+ };
133
+ navigator?.maxApi?.showToastDebug?.({
134
+ appId: `auto - ${context.appId}`,
135
+ message: 'service_icon_clicked',
136
+ params,
137
+ });
138
+ navigator?.maxApi?.trackEvent?.('service_icon_clicked', params);
139
+ if (canGoBack) {
140
+ navigator?.ref?.current?.goBack?.();
141
+ } else if (navigator?.maxApi) {
142
+ navigator?.maxApi?.dismiss?.(navigator?.dismissData);
143
+ } else {
144
+ const currentTime = new Date().getTime();
145
+ const requestId = `navigationBackPress#${currentTime}`;
146
+ DeviceEventEmitter.emit('dismiss', {requestId});
147
+ }
148
+ onPressLeftHeader?.();
149
+ };
150
+
151
+ if (preventBack) {
152
+ navigator?.showModal({
153
+ screen: () => (
154
+ <PopupNotify
155
+ {...preventBack}
156
+ primary={{
157
+ title: preventBack.primary.title,
158
+ onPress: () => {
159
+ preventBack?.primary.onPress();
160
+ goBack();
161
+ },
162
+ }}
163
+ />
164
+ ),
165
+ });
166
+ } else {
167
+ goBack();
168
+ }
169
+ return true;
170
+ };
171
+ return (
172
+ <View style={styles.headerLeft}>
173
+ <NavigationButton
174
+ accessibilityLabel="btn_navigation_back"
175
+ icon="ic_back"
176
+ tintColor={tintColor}
177
+ onPress={goBackSafe}
178
+ useBorder={useBorder}
179
+ />
180
+ </View>
181
+ );
182
+ };
183
+
184
+ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
185
+ image,
186
+ animatedValue,
187
+ useSurface = false,
188
+ }) => {
189
+ const {theme} = useContext(ApplicationContext);
190
+ let headerImage = theme.assets?.headerBackground;
191
+ let backgroundColor;
192
+ if (image === null) {
193
+ headerImage = undefined;
194
+ }
195
+ if (useSurface) {
196
+ backgroundColor = theme.colors.background.surface;
197
+ }
198
+ const opacity = animatedValue?.interpolate({
199
+ inputRange: [0, 114],
200
+ outputRange: [0, 1],
201
+ extrapolate: 'clamp',
202
+ });
203
+
204
+ return (
205
+ <Animated.View
206
+ style={[
207
+ Styles.flex,
208
+ {
209
+ backgroundColor,
210
+ overflow: 'hidden',
211
+ borderBottomWidth: useSurface ? 1 : 0,
212
+ borderColor: theme.colors.border.default,
213
+ opacity,
214
+ },
215
+ ]}>
216
+ <StatusBar
217
+ barStyle={headerImage || theme.dark ? 'light-content' : 'dark-content'}
218
+ translucent={true}
219
+ backgroundColor={'transparent'}
220
+ />
221
+ {!!headerImage && (
222
+ <Image
223
+ style={styles.headerBackground}
224
+ source={{uri: headerImage}}
225
+ loading={false}
226
+ />
227
+ )}
228
+ </Animated.View>
229
+ );
230
+ };
231
+
232
+ const HeaderCustom: React.FC<TitleCustomProps> = ({
233
+ title,
234
+ subTitle,
235
+ image,
236
+ imageShape = 'circle',
237
+ content,
238
+ tintColor,
239
+ dotColor,
240
+ }) => {
241
+ const avatarStyle = imageShape == 'circle' ? styles.circle : styles.square;
242
+ const header = (
243
+ <View style={Styles.row}>
244
+ <View>
245
+ <Image source={{uri: image}} style={avatarStyle} />
246
+ {!!dotColor && (
247
+ <View style={[styles.dotAvatar, {backgroundColor: dotColor}]} />
248
+ )}
249
+ </View>
250
+ <View style={[Styles.flex, {paddingHorizontal: 8}]}>
251
+ <Text
252
+ accessibilityLabel={'title_navigation_header'}
253
+ typography="header_default_bold"
254
+ color={tintColor}>
255
+ {title}
256
+ </Text>
257
+ <Text typography="description_default_regular" color={tintColor}>
258
+ {subTitle}
259
+ </Text>
260
+ </View>
261
+ </View>
262
+ );
263
+ return <View style={styles.headerTitleContainer}>{content ?? header}</View>;
264
+ };
265
+
266
+ const HeaderRightAction: React.FC<any> = ({children, ...restProps}) => {
267
+ const validateType = (child: React.ReactElement) => {
268
+ const valid = child?.type === NavigationButton || child?.type == Fragment;
269
+ if (__DEV__ && !valid) {
270
+ console.warn(
271
+ 'HeaderRightAction contains element type of NavigationButton, Please check again.',
272
+ );
273
+ }
274
+ return child;
275
+ };
276
+
277
+ const renderAction = () => {
278
+ if (Array.isArray(children)) {
279
+ return children.map((child, index) => {
280
+ return (
281
+ <View key={`HeaderRightAction ${index}`} style={styles.headerButton}>
282
+ {React.cloneElement(validateType(child), {...restProps})}
283
+ </View>
284
+ );
285
+ });
286
+ }
287
+
288
+ return (
289
+ <View style={styles.headerButton}>
290
+ {React.cloneElement(validateType(children), {...restProps})}
291
+ </View>
292
+ );
293
+ };
294
+ return <View style={styles.headerRightButton}>{renderAction()}</View>;
295
+ };
296
+
297
+ const HeaderToolkitAction: React.FC<any> = ({
298
+ tintColor,
299
+ pinnedTool,
300
+ runtimeTools = [],
301
+ preventClose,
302
+ }) => {
303
+ const {navigator} = useContext(ApplicationContext);
304
+ const miniContext = useContext<any>(MiniAppContext);
305
+ const [toolConfig, setToolConfig] = useState<any>();
306
+ const {onAction} = toolConfig ?? {};
307
+
308
+ let backgroundColor;
309
+ if (tintColor != Colors.black_01) {
310
+ backgroundColor = 'transparent';
311
+ }
312
+
313
+ useEffect(() => {
314
+ if (miniContext?.toolkitConfig?.hidden === false) {
315
+ if (navigator?.toolkitConfig) {
316
+ setToolConfig(navigator?.toolkitConfig);
317
+ } else {
318
+ getToolkitConfig();
319
+ }
320
+ }
321
+ }, []);
322
+
323
+ const getToolkitConfig = () => {
324
+ navigator?.maxApi?.dispatchFunction?.(
325
+ 'getToolsConfig',
326
+ [undefined],
327
+ (config: any) => {
328
+ navigator.toolkitConfig = config;
329
+ setToolConfig(navigator?.toolkitConfig);
330
+ },
331
+ );
332
+ };
333
+
334
+ const onMore = () => {
335
+ onAction?.('onMore');
336
+ navigator?.maxApi?.dispatchFunction?.(
337
+ 'showTools',
338
+ {runtimeTools},
339
+ (res: {item: {action?: string; key: string}}) => {
340
+ const {item} = res;
341
+ navigator?.toolkitCallback?.(item);
342
+ getToolkitConfig();
343
+ },
344
+ );
345
+ };
346
+
347
+ const onClose = () => {
348
+ if (preventClose) {
349
+ navigator?.showModal({
350
+ screen: () => (
351
+ <PopupNotify
352
+ {...preventClose}
353
+ primary={{
354
+ title: preventClose.primary.title,
355
+ onPress: () => {
356
+ preventClose?.primary.onPress();
357
+ navigator?.maxApi?.dispatchFunction?.(
358
+ 'dismiss',
359
+ undefined,
360
+ undefined,
361
+ );
362
+ },
363
+ }}
364
+ />
365
+ ),
366
+ });
367
+ } else {
368
+ navigator?.maxApi?.dispatchFunction?.('dismiss', undefined, undefined);
369
+ }
370
+ };
371
+
372
+ const renderPinnedTool = () => {
373
+ const pinKey = pinnedTool?.key || toolConfig?.pinnedTool?.key;
374
+ const pinTool = toolConfig?.tools?.find((i: any) => i.key === pinKey);
375
+ const {badgeValue, badgeType} = pinnedTool ?? {};
376
+
377
+ if (pinTool)
378
+ return (
379
+ <NavigationButton
380
+ accessibilityLabel="btn_navigation_pin"
381
+ icon={pinTool.icon as string}
382
+ tintColor={tintColor}
383
+ badgeValue={badgeValue}
384
+ badgeType={badgeType}
385
+ onPress={() => {
386
+ navigator?.maxApi?.dispatchFunction?.(
387
+ 'onToolAction',
388
+ [pinTool?.key],
389
+ () => {
390
+ getToolkitConfig();
391
+ },
392
+ );
393
+ navigator?.toolkitCallback?.(pinTool.key);
394
+ }}
395
+ />
396
+ );
397
+ };
398
+ if (toolConfig) {
399
+ return (
400
+ <View style={styles.headerRightButton}>
401
+ {renderPinnedTool()}
402
+ <View
403
+ style={[
404
+ styles.toolkitContainer,
405
+ {
406
+ backgroundColor: backgroundColor ?? '#00000066',
407
+ borderWidth: backgroundColor ? 0.5 : 0,
408
+ },
409
+ ]}>
410
+ <TouchableOpacity
411
+ accessibilityLabel={'btn_navigation_more'}
412
+ onPress={onMore}>
413
+ <Icon color={tintColor} source="navigation_more_horiz" size={20} />
414
+ </TouchableOpacity>
415
+ <View style={[styles.divider, {backgroundColor: tintColor}]} />
416
+ <TouchableOpacity
417
+ accessibilityLabel={'btn_navigation_close'}
418
+ onPress={onClose}>
419
+ <Icon
420
+ color={tintColor}
421
+ source="16_navigation_close_circle"
422
+ size={20}
423
+ />
424
+ </TouchableOpacity>
425
+ </View>
426
+ </View>
427
+ );
428
+ }
429
+
430
+ return <View />;
431
+ };
432
+
433
+ const HeaderAnimated: React.FC<HeaderAnimatedProps> = ({
434
+ animatedValue,
435
+ image,
436
+ children,
437
+ }) => {
438
+ const scale = animatedValue.interpolate({
439
+ inputRange: [-300, 0, 300],
440
+ outputRange: [4, 1, 1],
441
+ extrapolate: 'clamp',
442
+ });
443
+ const opacity = animatedValue.interpolate({
444
+ inputRange: [0, 150, 300],
445
+ outputRange: [1, 0.5, 0],
446
+ extrapolate: 'clamp',
447
+ });
448
+ const translateY = animatedValue.interpolate({
449
+ inputRange: [-300, 0],
450
+ outputRange: [-80, -2],
451
+ extrapolate: 'clamp',
452
+ });
453
+
454
+ return (
455
+ <Animated.View
456
+ style={{
457
+ height: 210,
458
+ opacity: opacity,
459
+ transform: [{scale}, {translateY}],
460
+ }}>
461
+ {children ?? (
462
+ <Image
463
+ source={{
464
+ uri: image,
465
+ }}
466
+ style={{width: '100%', height: '100%'}}
467
+ />
468
+ )}
469
+ </Animated.View>
470
+ );
471
+ };
472
+
473
+ const styles = StyleSheet.create({
474
+ navigationButton: {
475
+ height: 28,
476
+ width: 28,
477
+ borderRadius: 14,
478
+ justifyContent: 'center',
479
+ alignItems: 'center',
480
+ },
481
+ headerBackground: {
482
+ width: '100%',
483
+ height: undefined,
484
+ position: 'absolute',
485
+ aspectRatio: 375 / 154,
486
+ },
487
+ headerTitleContainer: {
488
+ alignItems: 'center',
489
+ justifyContent: 'center',
490
+ width: '100%',
491
+ },
492
+ circle: {width: 36, height: 36, borderRadius: 18},
493
+ square: {width: 36, height: 36, borderRadius: Radius.XS},
494
+ dotAvatar: {
495
+ position: 'absolute',
496
+ width: 12,
497
+ height: 12,
498
+ borderRadius: 6,
499
+ bottom: 0,
500
+ right: 0,
501
+ borderWidth: 1,
502
+ borderColor: Colors.black_01,
503
+ },
504
+ headerButton: {paddingHorizontal: 4},
505
+ headerRightButton: {
506
+ flexDirection: 'row',
507
+ justifyContent: 'center',
508
+ alignItems: 'center',
509
+ paddingRight: Spacing.M,
510
+ },
511
+ toolkitContainer: {
512
+ marginLeft: Spacing.S,
513
+ padding: Spacing.XS,
514
+ height: 28,
515
+ borderRadius: 14,
516
+ borderColor: '#00000066',
517
+ justifyContent: 'center',
518
+ alignItems: 'center',
519
+ flexDirection: 'row',
520
+ },
521
+ divider: {
522
+ width: 1,
523
+ height: 12,
524
+ marginHorizontal: 4,
525
+ },
526
+ headerLeft: {
527
+ marginLeft: 12,
528
+ },
529
+ title: {
530
+ fontSize: scaleSize(15),
531
+ lineHeight: scaleSize(22),
532
+ fontWeight: 'bold',
533
+ },
534
+ badge: {
535
+ position: 'absolute',
536
+ top: -Spacing.S,
537
+ right: -6,
538
+ },
539
+ badgeDot: {
540
+ position: 'absolute',
541
+ top: -Spacing.XS,
542
+ right: -Spacing.XS,
543
+ },
544
+ });
545
+
546
+ export {
547
+ NavigationButton,
548
+ HeaderTitle,
549
+ HeaderLeft,
550
+ HeaderBackground,
551
+ HeaderRightAction,
552
+ HeaderToolkitAction,
553
+ HeaderCustom,
554
+ HeaderAnimated,
555
+ };
@@ -0,0 +1,97 @@
1
+ import React, {useContext, useEffect, useRef} from 'react';
2
+ import {
3
+ KeyboardAvoidingView,
4
+ Platform,
5
+ Pressable,
6
+ StyleSheet,
7
+ View,
8
+ } from 'react-native';
9
+
10
+ import {ApplicationContext} from './index';
11
+ import {Styles} from '../Consts';
12
+ import Navigation from './Navigation';
13
+ import {ModalParams} from './types';
14
+ import BottomSheet from './BottomSheet';
15
+
16
+ const ModalScreen: React.FC<any> = props => {
17
+ if (props.route?.params?.isBottomSheet) {
18
+ return <BottomSheet {...props} />;
19
+ }
20
+ return <Modal {...props} />;
21
+ };
22
+
23
+ const Modal: React.FC<ModalParams> = props => {
24
+ const {theme, navigator} = useContext(ApplicationContext);
25
+ const {screen, barrierDismissible} = props.route.params;
26
+ const Component = useRef(screen).current;
27
+ const navigation = new Navigation(props.navigation, theme);
28
+ const params = {
29
+ ...props.route.params,
30
+ navigation,
31
+ };
32
+ delete params.screen;
33
+
34
+ useEffect(() => {
35
+ return () => {
36
+ props.route.params?.onDismiss?.();
37
+ };
38
+ }, []);
39
+
40
+ const onDismiss = () => {
41
+ if (barrierDismissible) {
42
+ return;
43
+ }
44
+ navigator?.pop();
45
+ };
46
+
47
+ return (
48
+ <KeyboardAvoidingView
49
+ style={Styles.flex}
50
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
51
+ <View style={styles.container}>
52
+ <Pressable
53
+ style={styles.modalSpaceHorizontal}
54
+ onPress={() => onDismiss()}
55
+ />
56
+ <View style={styles.modalCenterStage}>
57
+ <Pressable
58
+ style={styles.modalSpaceVertical}
59
+ onPress={() => onDismiss()}
60
+ />
61
+ <View style={styles.modalContent}>
62
+ <Component {...params} />
63
+ </View>
64
+ <Pressable
65
+ style={styles.modalSpaceVertical}
66
+ onPress={() => onDismiss()}
67
+ />
68
+ </View>
69
+ <Pressable
70
+ style={styles.modalSpaceHorizontal}
71
+ onPress={() => onDismiss()}
72
+ />
73
+ </View>
74
+ </KeyboardAvoidingView>
75
+ );
76
+ };
77
+
78
+ const styles = StyleSheet.create({
79
+ container: {flex: 1, flexDirection: 'row'},
80
+ modalContent: {
81
+ maxWidth: '100%',
82
+ maxHeight: '80%',
83
+ },
84
+ modalCenterStage: {
85
+ maxWidth: '90%',
86
+ },
87
+ modalSpaceHorizontal: {
88
+ flex: 1,
89
+ minWidth: '5%',
90
+ },
91
+ modalSpaceVertical: {
92
+ flex: 1,
93
+ minHeight: '10%',
94
+ },
95
+ });
96
+
97
+ export default ModalScreen;
@@ -0,0 +1,50 @@
1
+ import React from 'react';
2
+ import {NavigationProp} from '@react-navigation/native';
3
+ import {NavigationOptions, Theme} from './types';
4
+ import {HeaderRightAction} from './index';
5
+ import {getOptions} from './utils';
6
+ import {HeaderToolkitAction} from './Components';
7
+
8
+ class Navigation {
9
+ instance: NavigationProp<any>;
10
+ readonly theme: Theme;
11
+
12
+ constructor(instance: any, theme: Theme) {
13
+ this.instance = instance;
14
+ this.theme = theme;
15
+ }
16
+
17
+ /**
18
+ * navigation options filter by design system rule
19
+ * @param params
20
+ */
21
+ private filterParams = (params: NavigationOptions) => {
22
+ if (params.headerRight) {
23
+ const headerRight = params.headerRight?.({}) as React.ReactElement;
24
+ const type = headerRight?.type;
25
+ if (type !== HeaderRightAction && type !== HeaderToolkitAction) {
26
+ console.warn(
27
+ 'headerRight contains element type of HeaderRightAction | HeaderToolkitAction, Please check again.',
28
+ );
29
+ }
30
+ }
31
+
32
+ if (params.headerLeft) {
33
+ console.warn('headerLeft not allow override render by design system!');
34
+ delete params.headerLeft;
35
+ }
36
+
37
+ return params;
38
+ };
39
+
40
+ /**
41
+ * navigation setOptions support props NavigationOptions base on react-navigation options
42
+ * @param params
43
+ */
44
+ setOptions = (params: NavigationOptions) => {
45
+ params = getOptions(this.filterParams(params), this.theme);
46
+ this.instance.setOptions(params);
47
+ };
48
+ }
49
+
50
+ export default Navigation;