@momo-kits/foundation 0.115.3-beta.4 → 0.115.3-beta.6
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 +57 -5
- package/Application/Components/HeaderRight.tsx +2 -0
- package/Application/types.ts +2 -0
- package/Divider/index.tsx +8 -32
- package/Input/InputMoney.tsx +3 -2
- package/Input/InputOTP.tsx +11 -0
- package/Input/styles.ts +6 -0
- package/Text/utils.ts +14 -5
- package/package.json +1 -1
- package/Divider/DashDivider.tsx +0 -45
|
@@ -1,23 +1,32 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import {
|
|
3
9
|
Dimensions,
|
|
10
|
+
Keyboard,
|
|
4
11
|
KeyboardAvoidingView,
|
|
12
|
+
LayoutAnimation,
|
|
5
13
|
Modal,
|
|
6
14
|
PanResponder,
|
|
7
15
|
Platform,
|
|
8
16
|
Pressable,
|
|
17
|
+
ScrollView,
|
|
9
18
|
StyleSheet,
|
|
10
19
|
TouchableOpacity,
|
|
11
20
|
View,
|
|
12
21
|
} from 'react-native';
|
|
13
22
|
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
|
23
|
+
import Animated, {Easing, Extrapolate} from 'react-native-reanimated';
|
|
24
|
+
import {useHeaderHeight} from '@react-navigation/stack';
|
|
14
25
|
import {ApplicationContext} from './index';
|
|
15
26
|
import {BottomSheetParams} from './types';
|
|
16
27
|
import {Colors, Radius, Spacing, Styles} from '../Consts';
|
|
17
28
|
import {Text} from '../Text';
|
|
18
29
|
import {Icon} from '../Icon';
|
|
19
|
-
import {useHeaderHeight} from '@react-navigation/stack';
|
|
20
|
-
import Animated, {Easing, Extrapolate} from 'react-native-reanimated';
|
|
21
30
|
|
|
22
31
|
const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
23
32
|
const {theme, navigator} = useContext(ApplicationContext);
|
|
@@ -25,6 +34,8 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
25
34
|
const action = useRef<undefined | string>();
|
|
26
35
|
const insets = useSafeAreaInsets();
|
|
27
36
|
const heightHeader = useHeaderHeight();
|
|
37
|
+
const [keyboardHeight, setKeyboardHeight] = useState(0);
|
|
38
|
+
const [contentHeight, setContentHeight] = useState(0);
|
|
28
39
|
const keyboardOffset = heightHeader - Math.min(insets.bottom, 21);
|
|
29
40
|
|
|
30
41
|
const {
|
|
@@ -36,6 +47,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
36
47
|
draggable = true,
|
|
37
48
|
useBottomInset = true,
|
|
38
49
|
useKeyboardAvoidingView = true,
|
|
50
|
+
useScrollOverflow = false,
|
|
39
51
|
keyboardVerticalOffset,
|
|
40
52
|
}: BottomSheetParams = props.route.params;
|
|
41
53
|
|
|
@@ -86,14 +98,39 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
86
98
|
).current;
|
|
87
99
|
|
|
88
100
|
let Container: any = View;
|
|
101
|
+
let Content: any = View;
|
|
89
102
|
if (useNativeModal) {
|
|
90
103
|
Container = Modal;
|
|
91
104
|
}
|
|
105
|
+
if (useScrollOverflow) {
|
|
106
|
+
Content = ScrollView;
|
|
107
|
+
}
|
|
92
108
|
let backgroundColor = theme.colors.background.default;
|
|
93
109
|
if (surface) {
|
|
94
110
|
backgroundColor = theme.colors.background.surface;
|
|
95
111
|
}
|
|
96
112
|
|
|
113
|
+
const maxContentSize = heightDevice - 52 - keyboardHeight;
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
const onKeyboardShow = (e: any) => {
|
|
117
|
+
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
118
|
+
setKeyboardHeight(e.endCoordinates.height);
|
|
119
|
+
};
|
|
120
|
+
const onKeyboardHide = () => {
|
|
121
|
+
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
122
|
+
setKeyboardHeight(0);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const showSub = Keyboard.addListener('keyboardWillShow', onKeyboardShow);
|
|
126
|
+
const hideSub = Keyboard.addListener('keyboardWillHide', onKeyboardHide);
|
|
127
|
+
|
|
128
|
+
return () => {
|
|
129
|
+
showSub.remove();
|
|
130
|
+
hideSub.remove();
|
|
131
|
+
};
|
|
132
|
+
}, []);
|
|
133
|
+
|
|
97
134
|
/**
|
|
98
135
|
* emit dismiss event
|
|
99
136
|
*/
|
|
@@ -105,6 +142,17 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
105
142
|
};
|
|
106
143
|
}, []);
|
|
107
144
|
|
|
145
|
+
/**
|
|
146
|
+
* handle content bottom sheet change
|
|
147
|
+
* @param width
|
|
148
|
+
* @param height
|
|
149
|
+
*/
|
|
150
|
+
const handleContentSizeChange = (width: number, height: number) => {
|
|
151
|
+
if (contentHeight !== height) {
|
|
152
|
+
setContentHeight(height);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
|
|
108
156
|
/**
|
|
109
157
|
* handler dismiss
|
|
110
158
|
*/
|
|
@@ -216,9 +264,13 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
216
264
|
<Animated.View
|
|
217
265
|
style={{
|
|
218
266
|
transform: [{translateY}],
|
|
267
|
+
maxHeight: maxContentSize,
|
|
219
268
|
}}>
|
|
220
269
|
{renderHeader()}
|
|
221
|
-
<
|
|
270
|
+
<Content
|
|
271
|
+
scrollEnabled={contentHeight + 20 > maxContentSize}
|
|
272
|
+
style={{backgroundColor: backgroundColor}}
|
|
273
|
+
onContentSizeChange={handleContentSizeChange}>
|
|
222
274
|
<Screen
|
|
223
275
|
{...props}
|
|
224
276
|
{...props.route.params}
|
|
@@ -227,7 +279,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
227
279
|
{useBottomInset && (
|
|
228
280
|
<View style={{height: Math.min(insets.bottom, 21)}} />
|
|
229
281
|
)}
|
|
230
|
-
</
|
|
282
|
+
</Content>
|
|
231
283
|
</Animated.View>
|
|
232
284
|
</KeyboardAvoidingView>
|
|
233
285
|
</Container>
|
|
@@ -50,6 +50,7 @@ const HeaderRight: React.FC<any> = props => {
|
|
|
50
50
|
const HeaderToolkitAction: React.FC<any> = ({
|
|
51
51
|
tintColor,
|
|
52
52
|
preventClose,
|
|
53
|
+
useSystemTools = true,
|
|
53
54
|
useShortcut = false,
|
|
54
55
|
useMore = false,
|
|
55
56
|
tools = [],
|
|
@@ -198,6 +199,7 @@ const HeaderToolkitAction: React.FC<any> = ({
|
|
|
198
199
|
navigator?.maxApi?.dispatchFunction?.(
|
|
199
200
|
'showTools',
|
|
200
201
|
{
|
|
202
|
+
useSystemTools,
|
|
201
203
|
tools,
|
|
202
204
|
context,
|
|
203
205
|
},
|
package/Application/types.ts
CHANGED
|
@@ -98,6 +98,7 @@ export type Tool = {
|
|
|
98
98
|
name: {vi: string; en: string};
|
|
99
99
|
key: string;
|
|
100
100
|
showBadge?: boolean;
|
|
101
|
+
showRightIcon?: boolean;
|
|
101
102
|
onPress: () => void;
|
|
102
103
|
};
|
|
103
104
|
|
|
@@ -150,6 +151,7 @@ export type BottomSheetParams = {
|
|
|
150
151
|
useBottomInset?: boolean;
|
|
151
152
|
useKeyboardAvoidingView?: boolean;
|
|
152
153
|
keyboardVerticalOffset?: number;
|
|
154
|
+
useScrollOverflow?: boolean;
|
|
153
155
|
};
|
|
154
156
|
|
|
155
157
|
export interface NavigationButtonProps extends TouchableOpacityProps {
|
package/Divider/index.tsx
CHANGED
|
@@ -1,43 +1,19 @@
|
|
|
1
1
|
import React, {useContext} from 'react';
|
|
2
|
-
import {View
|
|
2
|
+
import {View} from 'react-native';
|
|
3
3
|
import {ApplicationContext} from '../Application';
|
|
4
4
|
import {Spacing} from '../Consts';
|
|
5
|
-
import {DashDivider} from './DashDivider';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Custom styles for divider
|
|
10
|
-
*/
|
|
11
|
-
style?: ViewStyle;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Enable margin vertical 4px
|
|
15
|
-
*/
|
|
16
|
-
useMargin?: boolean;
|
|
17
|
-
|
|
18
|
-
type?: 'dash' | 'default';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const Divider: React.FC<DividerProps> = ({
|
|
22
|
-
style,
|
|
23
|
-
useMargin = true,
|
|
24
|
-
type = 'default',
|
|
25
|
-
}) => {
|
|
6
|
+
const Divider = () => {
|
|
26
7
|
const {theme} = useContext(ApplicationContext);
|
|
27
8
|
|
|
28
|
-
if (type === 'dash') return <DashDivider style={style} />;
|
|
29
|
-
|
|
30
9
|
return (
|
|
31
10
|
<View
|
|
32
|
-
style={
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
marginVertical: useMargin ? Spacing.XS : 0,
|
|
39
|
-
},
|
|
40
|
-
]}
|
|
11
|
+
style={{
|
|
12
|
+
height: 1,
|
|
13
|
+
width: '100%',
|
|
14
|
+
backgroundColor: theme.colors.border.default,
|
|
15
|
+
marginVertical: Spacing.XS,
|
|
16
|
+
}}
|
|
41
17
|
/>
|
|
42
18
|
);
|
|
43
19
|
};
|
package/Input/InputMoney.tsx
CHANGED
|
@@ -97,10 +97,10 @@ const InputMoney = forwardRef(
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
const onClearText = () => {
|
|
100
|
+
inputRef?.current?.clear();
|
|
100
101
|
setDisplayValue('');
|
|
101
102
|
setNumericValue('');
|
|
102
103
|
onChangeText?.('');
|
|
103
|
-
inputRef?.current?.focus();
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
const _onChangeText = (text: string) => {
|
|
@@ -113,7 +113,8 @@ const InputMoney = forwardRef(
|
|
|
113
113
|
|
|
114
114
|
if (text.length < lastDisplayValue.length) {
|
|
115
115
|
const lastChar = lastDisplayValue.charAt(lastDisplayValue.length - 1);
|
|
116
|
-
const isRemovingCurrency =
|
|
116
|
+
const isRemovingCurrency =
|
|
117
|
+
lastDisplayValue.endsWith(currency) || lastChar === ' ';
|
|
117
118
|
const isRemovingDot = lastChar === '.';
|
|
118
119
|
|
|
119
120
|
if (isRemovingCurrency || isRemovingDot) {
|
package/Input/InputOTP.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
NativeSyntheticEvent,
|
|
13
13
|
TextInput,
|
|
14
14
|
TextInputFocusEventData,
|
|
15
|
+
TouchableOpacity,
|
|
15
16
|
View,
|
|
16
17
|
} from 'react-native';
|
|
17
18
|
import {
|
|
@@ -24,6 +25,7 @@ import {scaleSize, Text} from '../Text';
|
|
|
24
25
|
import {ErrorView, getBorderColor} from './common';
|
|
25
26
|
import {CaretProps, InputOTPProps} from './index';
|
|
26
27
|
import styles from './styles';
|
|
28
|
+
import {Icon} from "../Icon";
|
|
27
29
|
|
|
28
30
|
const OTPCaret: FC<CaretProps> = ({index, length}) => {
|
|
29
31
|
const DURATION = 300;
|
|
@@ -132,6 +134,10 @@ const InputOTP = forwardRef(
|
|
|
132
134
|
onChangeText?.(text);
|
|
133
135
|
};
|
|
134
136
|
|
|
137
|
+
const onClearText = () => {
|
|
138
|
+
_onChangeText('');
|
|
139
|
+
};
|
|
140
|
+
|
|
135
141
|
const renderInputs = (inputLength: number) => {
|
|
136
142
|
const TextInputs: React.ReactNode[] = [];
|
|
137
143
|
for (let i = 0; i < inputLength; i++) {
|
|
@@ -215,6 +221,11 @@ const InputOTP = forwardRef(
|
|
|
215
221
|
</Text>
|
|
216
222
|
</View>
|
|
217
223
|
)}
|
|
224
|
+
{value.length > 0 && focused && (
|
|
225
|
+
<TouchableOpacity onPress={onClearText} style={styles.clearIcon}>
|
|
226
|
+
<Icon source={'24_navigation_close_circle_full'} size={12} />
|
|
227
|
+
</TouchableOpacity>
|
|
228
|
+
)}
|
|
218
229
|
<View style={styles.otpInputsView}>
|
|
219
230
|
{length ? renderInputs(length) : renderUnidentifiedInputs()}
|
|
220
231
|
</View>
|
package/Input/styles.ts
CHANGED
|
@@ -150,8 +150,14 @@ export default StyleSheet.create({
|
|
|
150
150
|
otpInput: {
|
|
151
151
|
height: 56,
|
|
152
152
|
borderRadius: Radius.S,
|
|
153
|
+
justifyContent: 'center',
|
|
153
154
|
borderWidth: 1,
|
|
154
155
|
},
|
|
156
|
+
clearIcon: {
|
|
157
|
+
position: 'absolute',
|
|
158
|
+
right: Spacing.M,
|
|
159
|
+
zIndex: 4,
|
|
160
|
+
},
|
|
155
161
|
otpFloatingView: {
|
|
156
162
|
position: 'absolute',
|
|
157
163
|
top: -Spacing.M + 2,
|
package/Text/utils.ts
CHANGED
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import {Dimensions} from 'react-native';
|
|
1
|
+
import {Dimensions, PixelRatio} from 'react-native';
|
|
2
2
|
|
|
3
3
|
const deviceWidth = Dimensions.get('window').width;
|
|
4
4
|
const DEFAULT_SCREEN_SIZE = 375;
|
|
5
|
+
const MAX_FONT_SCALE = 1.3;
|
|
6
|
+
const MAX_DEVICE_SCALE = 5;
|
|
7
|
+
|
|
5
8
|
const scaleSize = (size: number) => {
|
|
6
|
-
const
|
|
9
|
+
const fontScale = PixelRatio.getFontScale();
|
|
10
|
+
const deviceScale = deviceWidth / DEFAULT_SCREEN_SIZE;
|
|
11
|
+
let fontSize = size;
|
|
12
|
+
|
|
13
|
+
if (deviceScale > 1) {
|
|
14
|
+
fontSize = Math.min(fontSize * deviceScale, fontSize + MAX_DEVICE_SCALE);
|
|
15
|
+
}
|
|
7
16
|
|
|
8
|
-
if (
|
|
9
|
-
|
|
17
|
+
if (fontScale > 1) {
|
|
18
|
+
fontSize = Math.min(fontSize * fontScale, fontSize * MAX_FONT_SCALE);
|
|
10
19
|
}
|
|
11
20
|
|
|
12
|
-
return
|
|
21
|
+
return fontSize;
|
|
13
22
|
};
|
|
14
23
|
|
|
15
24
|
export {scaleSize};
|
package/package.json
CHANGED
package/Divider/DashDivider.tsx
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import React, {useContext} from 'react';
|
|
2
|
-
import {View, ViewStyle} from 'react-native';
|
|
3
|
-
import {ApplicationContext} from '../Application';
|
|
4
|
-
import {Spacing} from '../Consts';
|
|
5
|
-
import Svg, {Line} from 'react-native-svg';
|
|
6
|
-
|
|
7
|
-
export interface DashDividerProps {
|
|
8
|
-
/**
|
|
9
|
-
* Custom styles for dash divider
|
|
10
|
-
*/
|
|
11
|
-
style?: ViewStyle;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const DashDivider: React.FC<DashDividerProps> = ({style}) => {
|
|
15
|
-
const {theme} = useContext(ApplicationContext);
|
|
16
|
-
const borderColor = theme.colors.border.default;
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<View
|
|
20
|
-
style={[
|
|
21
|
-
{
|
|
22
|
-
width: '100%',
|
|
23
|
-
height: 1,
|
|
24
|
-
marginVertical: Spacing.XS,
|
|
25
|
-
},
|
|
26
|
-
style,
|
|
27
|
-
]}>
|
|
28
|
-
<Svg height="1" width="100%">
|
|
29
|
-
<Line
|
|
30
|
-
x1="0"
|
|
31
|
-
y1="0"
|
|
32
|
-
x2="100%"
|
|
33
|
-
y2="0"
|
|
34
|
-
stroke={borderColor}
|
|
35
|
-
strokeWidth="1"
|
|
36
|
-
strokeDasharray={`4, 4`}
|
|
37
|
-
strokeLinecap={'round'}
|
|
38
|
-
strokeLinejoin={'miter'}
|
|
39
|
-
/>
|
|
40
|
-
</Svg>
|
|
41
|
-
</View>
|
|
42
|
-
);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export {DashDivider};
|