@momo-kits/foundation 0.167.2-beta.1 → 0.168.1-beta.1
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/BottomSheet.tsx +113 -14
- package/Application/BottomTab/BottomTabBar.tsx +6 -3
- package/Application/BottomTab/CustomBottomTabItem.tsx +3 -5
- package/Application/BottomTab/DuoBarCompression.tsx +135 -0
- package/Application/BottomTab/DuoTabBar.tsx +537 -0
- package/Application/BottomTab/index.tsx +145 -134
- package/Application/Components/DuoGlassBackground.tsx +158 -0
- package/Application/Components/DuoQuickReturnHeader.tsx +42 -0
- package/Application/Components/HeaderAnimated.tsx +9 -3
- package/Application/Components/HeaderExtendHeader.tsx +70 -28
- package/Application/Components/HeaderLeft.tsx +38 -0
- package/Application/Components/HeaderRight.tsx +144 -9
- package/Application/Components/HeaderTitle.tsx +43 -7
- package/Application/Components/SearchHeader.tsx +20 -15
- package/Application/Components/SideBarButton.tsx +134 -0
- package/Application/ModalScreen.tsx +16 -2
- package/Application/NavigationContainer.tsx +22 -38
- package/Application/Navigator.ts +1 -3
- package/Application/StackScreen.tsx +2 -5
- package/Application/device.ts +29 -0
- package/Application/types.ts +10 -1
- package/Application/utils.tsx +10 -7
- package/Badge/Badge.tsx +2 -3
- package/Badge/BadgeDotAnimation.tsx +3 -3
- package/Button/index.tsx +11 -11
- package/Consts/theme.ts +3 -4
- package/Input/Input.tsx +3 -4
- package/Input/InputMoney.tsx +8 -12
- package/Input/InputOTP.tsx +9 -12
- package/Input/InputPhoneNumber.tsx +3 -4
- package/Input/InputSearch.tsx +17 -14
- package/Input/InputTextArea.tsx +3 -4
- package/Input/SystemTextInput.tsx +2 -3
- package/Input/TextTyping.tsx +11 -6
- package/Input/utils.ts +2 -3
- package/Layout/Card.tsx +8 -26
- package/Layout/FloatingButton.tsx +3 -3
- package/Layout/Item.tsx +1 -10
- package/Layout/ReservedRegions.tsx +78 -0
- package/Layout/Screen.tsx +242 -48
- package/Layout/Section.tsx +5 -18
- package/Layout/index.ts +4 -4
- package/Layout/styles.ts +5 -0
- package/Layout/utils.ts +477 -5
- package/Pagination/Dot.tsx +3 -6
- package/Popup/PopupNotify.tsx +33 -22
- package/Popup/PopupPromotion.tsx +21 -8
- package/Popup/utils.ts +32 -0
- package/Radio/index.tsx +2 -3
- package/Text/utils.ts +1 -2
- package/Title/index.tsx +8 -11
- package/package.json +5 -2
- package/Layout/GridSystem.tsx +0 -137
|
@@ -6,10 +6,9 @@ import React, {
|
|
|
6
6
|
useState,
|
|
7
7
|
} from 'react';
|
|
8
8
|
import {
|
|
9
|
-
NativeSyntheticEvent,
|
|
10
9
|
StyleSheet,
|
|
11
10
|
TextInput,
|
|
12
|
-
|
|
11
|
+
TextInputFocusEvent,
|
|
13
12
|
TouchableOpacity,
|
|
14
13
|
View,
|
|
15
14
|
} from 'react-native';
|
|
@@ -93,12 +92,12 @@ const InputPhoneNumber = forwardRef(
|
|
|
93
92
|
onChangeText?.(text);
|
|
94
93
|
};
|
|
95
94
|
|
|
96
|
-
const _onFocus = (e:
|
|
95
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
97
96
|
setFocused(true);
|
|
98
97
|
onFocus?.(e);
|
|
99
98
|
};
|
|
100
99
|
|
|
101
|
-
const _onBlur = (e:
|
|
100
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
102
101
|
setFocused(false);
|
|
103
102
|
onBlur?.(e);
|
|
104
103
|
};
|
package/Input/InputSearch.tsx
CHANGED
|
@@ -10,9 +10,8 @@ import React, {
|
|
|
10
10
|
useState,
|
|
11
11
|
} from 'react';
|
|
12
12
|
import {
|
|
13
|
-
NativeSyntheticEvent,
|
|
14
13
|
TextInput,
|
|
15
|
-
|
|
14
|
+
TextInputFocusEvent,
|
|
16
15
|
TouchableOpacity,
|
|
17
16
|
View,
|
|
18
17
|
} from 'react-native';
|
|
@@ -59,9 +58,11 @@ const TextTyping: FC<any> = ({
|
|
|
59
58
|
listChar.length !== 0 && showChar(listChar?.[currentCharIndex.current]);
|
|
60
59
|
};
|
|
61
60
|
|
|
62
|
-
currentIndex.current >= data?.length
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
if (currentIndex.current >= data?.length) {
|
|
62
|
+
handleResetList();
|
|
63
|
+
} else {
|
|
64
|
+
handleAnimation();
|
|
65
|
+
}
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
const showChar = (char?: string) => {
|
|
@@ -82,9 +83,12 @@ const TextTyping: FC<any> = ({
|
|
|
82
83
|
}, timeDelayNextChar);
|
|
83
84
|
};
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
const textLength = data?.[currentIndex.current]?.length || 0;
|
|
87
|
+
if (currentCharIndex.current >= textLength) {
|
|
88
|
+
handleResetString();
|
|
89
|
+
} else {
|
|
90
|
+
handleShowChar();
|
|
91
|
+
}
|
|
88
92
|
};
|
|
89
93
|
|
|
90
94
|
const reset = () => {
|
|
@@ -166,12 +170,12 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
166
170
|
props.accessibilityLabel,
|
|
167
171
|
);
|
|
168
172
|
|
|
169
|
-
const _onFocus = (e:
|
|
173
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
170
174
|
setFocused(true);
|
|
171
175
|
onFocus?.(e);
|
|
172
176
|
};
|
|
173
177
|
|
|
174
|
-
const _onBlur = (e:
|
|
178
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
175
179
|
setFocused(false);
|
|
176
180
|
onBlur?.(e);
|
|
177
181
|
};
|
|
@@ -303,6 +307,8 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
303
307
|
inputState = 'filled';
|
|
304
308
|
}
|
|
305
309
|
|
|
310
|
+
const inputBackground = backgroundColor ?? theme.colors.background.surface;
|
|
311
|
+
|
|
306
312
|
return (
|
|
307
313
|
<ComponentContext.Provider
|
|
308
314
|
value={{
|
|
@@ -322,10 +328,7 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
322
328
|
<View
|
|
323
329
|
style={[
|
|
324
330
|
styles.searchInputWrapper,
|
|
325
|
-
{
|
|
326
|
-
backgroundColor:
|
|
327
|
-
backgroundColor ?? theme.colors.background.surface,
|
|
328
|
-
},
|
|
331
|
+
{ backgroundColor: inputBackground },
|
|
329
332
|
]}
|
|
330
333
|
>
|
|
331
334
|
<Icon
|
package/Input/InputTextArea.tsx
CHANGED
|
@@ -7,9 +7,8 @@ import React, {
|
|
|
7
7
|
useState,
|
|
8
8
|
} from 'react';
|
|
9
9
|
import {
|
|
10
|
-
NativeSyntheticEvent,
|
|
11
10
|
TextInput,
|
|
12
|
-
|
|
11
|
+
TextInputFocusEvent,
|
|
13
12
|
TouchableOpacity,
|
|
14
13
|
View,
|
|
15
14
|
} from 'react-native';
|
|
@@ -79,12 +78,12 @@ const InputTextArea = forwardRef(
|
|
|
79
78
|
setInputValue(text);
|
|
80
79
|
};
|
|
81
80
|
|
|
82
|
-
const _onFocus = (e:
|
|
81
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
83
82
|
setFocused(true);
|
|
84
83
|
onFocus?.(e);
|
|
85
84
|
};
|
|
86
85
|
|
|
87
|
-
const _onBlur = (e:
|
|
86
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
88
87
|
setFocused(false);
|
|
89
88
|
onBlur?.(e);
|
|
90
89
|
};
|
|
@@ -17,11 +17,10 @@ const SystemTextInput: FC<SystemTextInputProps> = props => {
|
|
|
17
17
|
const needsAndroidWrapper =
|
|
18
18
|
Platform.OS === 'android' && !editable && (onPressIn || onPressOut);
|
|
19
19
|
|
|
20
|
+
const noPressHandlers = { onPressIn: undefined, onPressOut: undefined };
|
|
20
21
|
const inputProps: TextInputProps = {
|
|
21
22
|
...props,
|
|
22
|
-
...(needsAndroidWrapper
|
|
23
|
-
? { onPressIn: undefined, onPressOut: undefined }
|
|
24
|
-
: null),
|
|
23
|
+
...(needsAndroidWrapper ? noPressHandlers : null),
|
|
25
24
|
...(editable === false ? { accessibilityState: undefined } : null),
|
|
26
25
|
};
|
|
27
26
|
|
package/Input/TextTyping.tsx
CHANGED
|
@@ -36,9 +36,11 @@ const TextTyping: FC<TextTypingProps> = ({
|
|
|
36
36
|
listChar.length !== 0 && showChar(listChar?.[currentCharIndex.current]);
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
currentIndex.current >= data?.length
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
if (currentIndex.current >= data?.length) {
|
|
40
|
+
handleResetList();
|
|
41
|
+
} else {
|
|
42
|
+
handleAnimation();
|
|
43
|
+
}
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
const showChar = (char?: string) => {
|
|
@@ -59,9 +61,12 @@ const TextTyping: FC<TextTypingProps> = ({
|
|
|
59
61
|
}, timeDelayNextChar);
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
const textLength = data?.[currentIndex.current]?.length || 0;
|
|
65
|
+
if (currentCharIndex.current >= textLength) {
|
|
66
|
+
handleResetString();
|
|
67
|
+
} else {
|
|
68
|
+
handleShowChar();
|
|
69
|
+
}
|
|
65
70
|
};
|
|
66
71
|
|
|
67
72
|
const reset = () => {
|
package/Input/utils.ts
CHANGED
|
@@ -15,9 +15,8 @@ const formatNumberToMoney = (number: number, currency = '') => {
|
|
|
15
15
|
|
|
16
16
|
const numberString = Math.abs(number).toString();
|
|
17
17
|
if (numberString.length < 3) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
: `${numberString}${currency}`;
|
|
18
|
+
const sign = isNegative ? '-' : '';
|
|
19
|
+
return `${sign}${numberString}${currency}`;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
let count = 0;
|
package/Layout/Card.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import React, { useContext } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { useGridSystem } from './utils';
|
|
2
|
+
import { View, ViewProps } from 'react-native';
|
|
3
|
+
import { useGridSystem, useScreenLayout } from './utils';
|
|
4
4
|
import { GridContextProps } from './types';
|
|
5
|
-
import { GridContext
|
|
5
|
+
import { GridContext } from './index';
|
|
6
6
|
import { Image } from '../Image';
|
|
7
|
-
import { ApplicationContext
|
|
7
|
+
import { ApplicationContext } from '../Context';
|
|
8
8
|
import styles from './styles';
|
|
9
|
-
import {
|
|
9
|
+
import { Radius, Shadow, Spacing } from '../Consts';
|
|
10
10
|
|
|
11
11
|
export interface CardProps extends ViewProps {
|
|
12
12
|
/**
|
|
@@ -27,12 +27,13 @@ const Card: React.FC<CardProps> = ({
|
|
|
27
27
|
useShadow = false,
|
|
28
28
|
...props
|
|
29
29
|
}) => {
|
|
30
|
-
const {
|
|
30
|
+
const { theme } = useContext(ApplicationContext);
|
|
31
31
|
const { numberOfColumns } = useGridSystem();
|
|
32
|
+
const { contentWidth } = useScreenLayout();
|
|
32
33
|
|
|
33
34
|
const gutterSize = 8;
|
|
34
35
|
const margin = 12;
|
|
35
|
-
const widthSection =
|
|
36
|
+
const widthSection = contentWidth - margin * 2;
|
|
36
37
|
let sizePerSpan =
|
|
37
38
|
(widthSection - margin * 2 - gutterSize * (numberOfColumns - 1)) /
|
|
38
39
|
numberOfColumns -
|
|
@@ -47,23 +48,6 @@ const Card: React.FC<CardProps> = ({
|
|
|
47
48
|
},
|
|
48
49
|
};
|
|
49
50
|
|
|
50
|
-
/**
|
|
51
|
-
* render overlay only dev mode
|
|
52
|
-
*/
|
|
53
|
-
const renderOverlay = () => {
|
|
54
|
-
return (
|
|
55
|
-
<>
|
|
56
|
-
<GridSystem
|
|
57
|
-
width={widthSection}
|
|
58
|
-
gutterSize={Spacing.S}
|
|
59
|
-
screenGrid={false}
|
|
60
|
-
gridColor={Colors.red_01}
|
|
61
|
-
/>
|
|
62
|
-
<View pointerEvents={'none'} style={styles.boxGridCard} />
|
|
63
|
-
</>
|
|
64
|
-
);
|
|
65
|
-
};
|
|
66
|
-
|
|
67
51
|
return (
|
|
68
52
|
<GridContext.Provider value={gridContext}>
|
|
69
53
|
<View
|
|
@@ -95,9 +79,7 @@ const Card: React.FC<CardProps> = ({
|
|
|
95
79
|
]}
|
|
96
80
|
/>
|
|
97
81
|
)}
|
|
98
|
-
{/* Render only allowed children as valid React elements */}
|
|
99
82
|
{children}
|
|
100
|
-
{showGrid && renderOverlay()}
|
|
101
83
|
</View>
|
|
102
84
|
</GridContext.Provider>
|
|
103
85
|
);
|
|
@@ -10,8 +10,8 @@ import Animated, {
|
|
|
10
10
|
useAnimatedStyle,
|
|
11
11
|
useSharedValue,
|
|
12
12
|
withTiming,
|
|
13
|
-
runOnJS,
|
|
14
13
|
} from 'react-native-reanimated';
|
|
14
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
15
15
|
import { ApplicationContext } from '../Context';
|
|
16
16
|
import { Icon } from '../Icon';
|
|
17
17
|
import { useScaleSize, exportFontFamily } from '../Text';
|
|
@@ -78,7 +78,7 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
|
|
|
78
78
|
minWidth,
|
|
79
79
|
{ duration: 100 },
|
|
80
80
|
finished => {
|
|
81
|
-
if (finished)
|
|
81
|
+
if (finished) scheduleOnRN(setShowText, false);
|
|
82
82
|
},
|
|
83
83
|
);
|
|
84
84
|
} else {
|
|
@@ -87,7 +87,7 @@ export const FloatingButton: React.FC<FloatingButtonProps> = ({
|
|
|
87
87
|
maxWidth.value,
|
|
88
88
|
{ duration: 100 },
|
|
89
89
|
finished => {
|
|
90
|
-
if (finished)
|
|
90
|
+
if (finished) scheduleOnRN(setShowText, true);
|
|
91
91
|
},
|
|
92
92
|
);
|
|
93
93
|
}
|
package/Layout/Item.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useContext } from 'react';
|
|
2
2
|
import { View, ViewProps } from 'react-native';
|
|
3
3
|
import { GridContext } from './index';
|
|
4
|
-
import {
|
|
4
|
+
import { MiniAppContext } from '../Context';
|
|
5
5
|
import styles from './styles';
|
|
6
6
|
import { SpanNumber } from './types';
|
|
7
7
|
|
|
@@ -23,19 +23,11 @@ const Item: React.FC<ItemProps> = ({
|
|
|
23
23
|
children,
|
|
24
24
|
style,
|
|
25
25
|
}) => {
|
|
26
|
-
const { showGrid } = useContext(ApplicationContext);
|
|
27
26
|
const context = useContext<any>(MiniAppContext);
|
|
28
27
|
const grid = useContext(GridContext);
|
|
29
28
|
|
|
30
29
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
31
30
|
|
|
32
|
-
/**
|
|
33
|
-
* render overlay view only dev mode
|
|
34
|
-
*/
|
|
35
|
-
const renderOverlay = () => {
|
|
36
|
-
return <View pointerEvents={'none'} style={styles.boxGrid} />;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
31
|
return (
|
|
40
32
|
<View
|
|
41
33
|
style={[
|
|
@@ -49,7 +41,6 @@ const Item: React.FC<ItemProps> = ({
|
|
|
49
41
|
]}
|
|
50
42
|
>
|
|
51
43
|
{children}
|
|
52
|
-
{showGrid && renderOverlay()}
|
|
53
44
|
</View>
|
|
54
45
|
);
|
|
55
46
|
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React, { createContext, ReactNode, useMemo } from 'react';
|
|
2
|
+
import { Platform, StyleSheet } from 'react-native';
|
|
3
|
+
|
|
4
|
+
export type ReservedRegion = {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type NativeReservedRegions = typeof import('react-native-reserved-regions');
|
|
12
|
+
|
|
13
|
+
// native lib is optional so apps without react-native-reserved-regions still bundle
|
|
14
|
+
let nativeLib: NativeReservedRegions | undefined;
|
|
15
|
+
try {
|
|
16
|
+
nativeLib = require('react-native-reserved-regions');
|
|
17
|
+
} catch {
|
|
18
|
+
nativeLib = undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* screen regions the system currently occludes, relative to the provider, which fills
|
|
23
|
+
* the root view so they line up with window coordinates
|
|
24
|
+
*/
|
|
25
|
+
const ReservedRegionsContext = createContext<ReservedRegion[]>([]);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* keeps the occlusion regions reported by the native provider, the only kind layout reads
|
|
29
|
+
*/
|
|
30
|
+
const OcclusionRegions: React.FC<{
|
|
31
|
+
useRegions: NativeReservedRegions['useReservedRegions'];
|
|
32
|
+
children: ReactNode;
|
|
33
|
+
}> = ({ useRegions, children }) => {
|
|
34
|
+
const regions = useRegions();
|
|
35
|
+
const occlusion = useMemo(
|
|
36
|
+
() =>
|
|
37
|
+
regions
|
|
38
|
+
.filter(region => region.kind === 'occlusion')
|
|
39
|
+
.map(region => region.frame),
|
|
40
|
+
[regions],
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<ReservedRegionsContext.Provider value={occlusion}>
|
|
45
|
+
{children}
|
|
46
|
+
</ReservedRegionsContext.Provider>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* tracks the system occlusion regions (iOS 27.1+), e.g. the iPhone Duo status bar
|
|
52
|
+
* cluster growing for a call or a Live Activity
|
|
53
|
+
*/
|
|
54
|
+
const ReservedRegionsProvider: React.FC<{ children: ReactNode }> = ({
|
|
55
|
+
children,
|
|
56
|
+
}) => {
|
|
57
|
+
if (Platform.OS !== 'ios' || !nativeLib) {
|
|
58
|
+
return <>{children}</>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { ReservedRegionsProvider: NativeProvider, useReservedRegions } =
|
|
62
|
+
nativeLib;
|
|
63
|
+
return (
|
|
64
|
+
<NativeProvider style={styles.container}>
|
|
65
|
+
<OcclusionRegions useRegions={useReservedRegions}>
|
|
66
|
+
{children}
|
|
67
|
+
</OcclusionRegions>
|
|
68
|
+
</NativeProvider>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const styles = StyleSheet.create({
|
|
73
|
+
container: {
|
|
74
|
+
flex: 1,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export { ReservedRegionsContext, ReservedRegionsProvider };
|