@momo-kits/foundation 0.79.6-beta.1 → 0.79.6-beta.12
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/Components.tsx +5 -1
- package/Application/ModalScreen.tsx +25 -38
- package/Application/NavigationContainer.tsx +7 -2
- package/Application/types.ts +1 -1
- package/Input/InputOTP.tsx +171 -0
- package/Input/OTPCaret.tsx +50 -0
- package/Input/common.tsx +4 -1
- package/Input/index.tsx +13 -1
- package/Input/styles.ts +24 -0
- package/Switch/index.tsx +3 -5
- package/Title/index.tsx +89 -0
- package/Title/styles.ts +46 -0
- package/Title/types.ts +11 -0
- package/index.ts +2 -0
- package/package.json +2 -2
- package/verify.js +22 -0
|
@@ -225,7 +225,11 @@ const HeaderBackground: React.FC<HeaderBackgroundProps> = ({
|
|
|
225
225
|
barStyle={headerImage || theme.dark ? 'light-content' : 'dark-content'}
|
|
226
226
|
/>
|
|
227
227
|
{!!headerImage && (
|
|
228
|
-
<Image
|
|
228
|
+
<Image
|
|
229
|
+
style={styles.headerBackground}
|
|
230
|
+
source={{uri: headerImage}}
|
|
231
|
+
loading={false}
|
|
232
|
+
/>
|
|
229
233
|
)}
|
|
230
234
|
</Animated.View>
|
|
231
235
|
);
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useCallback,
|
|
3
|
-
useContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useMemo,
|
|
6
|
-
useRef,
|
|
7
|
-
useState,
|
|
8
|
-
} from 'react';
|
|
1
|
+
import React, {useContext, useEffect, useMemo, useRef} from 'react';
|
|
9
2
|
import {
|
|
10
3
|
KeyboardAvoidingView,
|
|
11
4
|
Platform,
|
|
@@ -13,8 +6,12 @@ import {
|
|
|
13
6
|
StyleSheet,
|
|
14
7
|
View,
|
|
15
8
|
} from 'react-native';
|
|
16
|
-
import {SafeAreaView} from 'react-native-safe-area-context';
|
|
17
|
-
import {
|
|
9
|
+
import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context';
|
|
10
|
+
import {
|
|
11
|
+
BottomSheetBackdrop,
|
|
12
|
+
BottomSheetModal,
|
|
13
|
+
BottomSheetView,
|
|
14
|
+
} from '@gorhom/bottom-sheet';
|
|
18
15
|
import Navigation from './Navigation';
|
|
19
16
|
import {BottomSheetParams, ModalParams} from './types';
|
|
20
17
|
import {Radius, Spacing, Styles} from '../Consts';
|
|
@@ -90,12 +87,9 @@ const Modal: React.FC<ModalParams> = props => {
|
|
|
90
87
|
};
|
|
91
88
|
|
|
92
89
|
const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
90
|
+
const insets = useSafeAreaInsets();
|
|
93
91
|
const {theme, navigator} = useContext(ApplicationContext);
|
|
94
|
-
const {
|
|
95
|
-
screen,
|
|
96
|
-
options,
|
|
97
|
-
useSnap = true,
|
|
98
|
-
}: BottomSheetParams = props.route.params;
|
|
92
|
+
const {screen, options, snapPoint}: BottomSheetParams = props.route.params;
|
|
99
93
|
const Component = useRef(screen).current;
|
|
100
94
|
const navigation = new Navigation(props.navigation, theme);
|
|
101
95
|
const params = {
|
|
@@ -105,31 +99,16 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
105
99
|
|
|
106
100
|
delete params.screen;
|
|
107
101
|
|
|
108
|
-
const [contentHeight, setContentHeight] = useState(undefined);
|
|
109
102
|
const snapPoints = useMemo(() => {
|
|
110
|
-
if (
|
|
111
|
-
return [
|
|
103
|
+
if (snapPoint) {
|
|
104
|
+
return [snapPoint];
|
|
112
105
|
}
|
|
113
|
-
return [
|
|
114
|
-
}, [
|
|
106
|
+
return ['50%', '70%', '90%'];
|
|
107
|
+
}, []);
|
|
115
108
|
|
|
116
109
|
const bottomSheetRef = useRef<any>(null);
|
|
117
110
|
const mountedRef = useRef(true);
|
|
118
111
|
|
|
119
|
-
let handleOnLayout;
|
|
120
|
-
if (!useSnap) {
|
|
121
|
-
handleOnLayout = useCallback(
|
|
122
|
-
({
|
|
123
|
-
nativeEvent: {
|
|
124
|
-
layout: {height},
|
|
125
|
-
},
|
|
126
|
-
}) => {
|
|
127
|
-
setContentHeight(height);
|
|
128
|
-
},
|
|
129
|
-
[],
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
112
|
let backgroundColor = theme.colors.background.default;
|
|
134
113
|
if (options?.surface) {
|
|
135
114
|
backgroundColor = theme.colors.background.surface;
|
|
@@ -162,8 +141,15 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
162
141
|
}}
|
|
163
142
|
handleComponent={null}
|
|
164
143
|
backdropComponent={backdropComponent}>
|
|
165
|
-
<
|
|
166
|
-
<View
|
|
144
|
+
<BottomSheetView accessibilityLabel={'BottomSheet'}>
|
|
145
|
+
<View
|
|
146
|
+
style={[
|
|
147
|
+
styles.sheetContainer,
|
|
148
|
+
{
|
|
149
|
+
backgroundColor,
|
|
150
|
+
paddingBottom: Math.min(insets.bottom, 20) + Spacing.S,
|
|
151
|
+
},
|
|
152
|
+
]}>
|
|
167
153
|
<View style={styles.indicatorContainer}>
|
|
168
154
|
<View
|
|
169
155
|
style={[
|
|
@@ -222,7 +208,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
|
|
|
222
208
|
}}
|
|
223
209
|
/>
|
|
224
210
|
</View>
|
|
225
|
-
</
|
|
211
|
+
</BottomSheetView>
|
|
226
212
|
</BottomSheetModal>
|
|
227
213
|
</SafeAreaView>
|
|
228
214
|
);
|
|
@@ -255,11 +241,12 @@ const styles = StyleSheet.create({
|
|
|
255
241
|
indicatorContainer: {
|
|
256
242
|
width: '100%',
|
|
257
243
|
paddingTop: Spacing.S,
|
|
244
|
+
paddingBottom: Spacing.XS,
|
|
258
245
|
alignItems: 'center',
|
|
259
246
|
justifyContent: 'center',
|
|
260
247
|
},
|
|
261
248
|
indicator: {
|
|
262
|
-
width:
|
|
249
|
+
width: 40,
|
|
263
250
|
height: 4,
|
|
264
251
|
borderRadius: Radius.S,
|
|
265
252
|
},
|
|
@@ -10,9 +10,10 @@ import StackScreen from './StackScreen';
|
|
|
10
10
|
import ModalScreen from './ModalScreen';
|
|
11
11
|
import Navigator from './Navigator';
|
|
12
12
|
import {getDialogOptions, getModalOptions, getStackOptions} from './utils';
|
|
13
|
-
import {NavigationContainerProps} from './types';
|
|
13
|
+
import {LocalizationObject, NavigationContainerProps} from './types';
|
|
14
14
|
import {ApplicationContext} from './index';
|
|
15
15
|
import {DeviceEventEmitter} from 'react-native';
|
|
16
|
+
import kitLocalization from '../Assets/language.json';
|
|
16
17
|
|
|
17
18
|
const Stack = createStackNavigator();
|
|
18
19
|
|
|
@@ -52,7 +53,11 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
|
|
|
52
53
|
navigator.current.maxApi = maxApi;
|
|
53
54
|
|
|
54
55
|
const translate = (key: string) => {
|
|
55
|
-
|
|
56
|
+
const mergedLocalization: LocalizationObject = {
|
|
57
|
+
vi: {...localization?.vi, ...kitLocalization.vi},
|
|
58
|
+
en: {...localization?.en, ...kitLocalization.en},
|
|
59
|
+
};
|
|
60
|
+
return mergedLocalization?.[language]?.[key] || key;
|
|
56
61
|
};
|
|
57
62
|
|
|
58
63
|
return (
|
package/Application/types.ts
CHANGED
|
@@ -107,7 +107,7 @@ export interface ModalParams extends ScreenParams {
|
|
|
107
107
|
export interface BottomSheetParams extends ScreenParams {
|
|
108
108
|
[key: string]: any;
|
|
109
109
|
onDismiss?: () => void;
|
|
110
|
-
|
|
110
|
+
snapPoint?: '30%' | '50%' | '70%' | '90%';
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
export type NavigationButtonProps = {
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import React, {FC, useContext, useRef, useState} from 'react';
|
|
2
|
+
import {
|
|
3
|
+
KeyboardType,
|
|
4
|
+
NativeSyntheticEvent,
|
|
5
|
+
TextInput,
|
|
6
|
+
TextInputFocusEventData,
|
|
7
|
+
TouchableOpacity,
|
|
8
|
+
View,
|
|
9
|
+
} from 'react-native';
|
|
10
|
+
import {InputOTPProps} from './index';
|
|
11
|
+
import {Text} from '../Text';
|
|
12
|
+
import styles from './styles';
|
|
13
|
+
import {ErrorView, getBorderColor} from './common';
|
|
14
|
+
import {ApplicationContext} from '../Application';
|
|
15
|
+
import {Spacing} from '../Consts';
|
|
16
|
+
import OTPCaret from './OTPCaret';
|
|
17
|
+
|
|
18
|
+
const InputOTP: FC<InputOTPProps> = ({
|
|
19
|
+
length,
|
|
20
|
+
errorMessage,
|
|
21
|
+
errorSpacing,
|
|
22
|
+
floatingValue,
|
|
23
|
+
floatingIconColor,
|
|
24
|
+
floatingIcon,
|
|
25
|
+
placeholder,
|
|
26
|
+
onChangeText,
|
|
27
|
+
onFocus,
|
|
28
|
+
onBlur,
|
|
29
|
+
dataType = 'number',
|
|
30
|
+
...props
|
|
31
|
+
}) => {
|
|
32
|
+
const MAX_LENGTH = 10;
|
|
33
|
+
const [value, setValue] = useState('');
|
|
34
|
+
const [focused, setFocused] = useState(false);
|
|
35
|
+
const inputRef = useRef<TextInput>(null);
|
|
36
|
+
const {theme} = useContext(ApplicationContext);
|
|
37
|
+
|
|
38
|
+
const onFocusInput = () => {
|
|
39
|
+
setFocused(true);
|
|
40
|
+
inputRef.current?.focus();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const onBlurInput = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
44
|
+
setFocused(false);
|
|
45
|
+
onBlur?.(e);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const _onChangeText = (text: string) => {
|
|
49
|
+
if (text.length > MAX_LENGTH) return;
|
|
50
|
+
if (dataType === 'number' && isNaN(Number(text))) return;
|
|
51
|
+
if (
|
|
52
|
+
!isNaN(Number(text)) &&
|
|
53
|
+
value.length >= Number(length) &&
|
|
54
|
+
text.length >= value.length
|
|
55
|
+
)
|
|
56
|
+
return;
|
|
57
|
+
|
|
58
|
+
setValue(text);
|
|
59
|
+
onChangeText?.(text);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const renderInputs = (length: number) => {
|
|
63
|
+
const TextInputs = [];
|
|
64
|
+
for (let i = 0; i < length; i++) {
|
|
65
|
+
TextInputs.push(
|
|
66
|
+
<View>
|
|
67
|
+
{focused && value.length === i ? (
|
|
68
|
+
<OTPCaret index={i} length={length} />
|
|
69
|
+
) : (
|
|
70
|
+
<Text
|
|
71
|
+
style={i !== length - 1 && {marginRight: Spacing.L}}
|
|
72
|
+
color={
|
|
73
|
+
!!value[i] ? theme.colors.text.default : theme.colors.text.hint
|
|
74
|
+
}
|
|
75
|
+
typography={!!value[i] ? 'title_s' : 'paragraph_default'}>
|
|
76
|
+
{value[i] || '-'}
|
|
77
|
+
</Text>
|
|
78
|
+
)}
|
|
79
|
+
</View>,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
return TextInputs;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const renderUnidentifiedInputs = () => {
|
|
86
|
+
const splitValue = value.split('');
|
|
87
|
+
|
|
88
|
+
if (!focused && value.length === 0 && !!placeholder) {
|
|
89
|
+
return (
|
|
90
|
+
<Text color={theme.colors.text.hint} typography={'description_s'}>
|
|
91
|
+
{placeholder}
|
|
92
|
+
</Text>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<View style={{flexDirection: 'row'}}>
|
|
98
|
+
{splitValue.map((letter, index) => {
|
|
99
|
+
return (
|
|
100
|
+
<Text
|
|
101
|
+
style={
|
|
102
|
+
(index !== value.length - 1 ||
|
|
103
|
+
(focused && value.length !== MAX_LENGTH)) && {
|
|
104
|
+
marginRight: Spacing.L,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
typography={'title_s'}>
|
|
108
|
+
{letter}
|
|
109
|
+
</Text>
|
|
110
|
+
);
|
|
111
|
+
})}
|
|
112
|
+
{focused && value.length !== MAX_LENGTH && <OTPCaret />}
|
|
113
|
+
</View>
|
|
114
|
+
);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const renderInputView = () => {
|
|
118
|
+
let placeholderColor = theme.colors.text.hint;
|
|
119
|
+
const keyboardType: KeyboardType =
|
|
120
|
+
dataType === 'number' ? 'number-pad' : 'default';
|
|
121
|
+
return (
|
|
122
|
+
<View
|
|
123
|
+
style={[
|
|
124
|
+
styles.otpInput,
|
|
125
|
+
{backgroundColor: theme.colors.background.surface},
|
|
126
|
+
getBorderColor(theme, focused, errorMessage),
|
|
127
|
+
]}>
|
|
128
|
+
{!!floatingValue && (
|
|
129
|
+
<View
|
|
130
|
+
style={[
|
|
131
|
+
styles.otpFloatingView,
|
|
132
|
+
{backgroundColor: theme.colors.background.surface},
|
|
133
|
+
]}>
|
|
134
|
+
<Text typography={'description_s'}>{floatingValue}</Text>
|
|
135
|
+
</View>
|
|
136
|
+
)}
|
|
137
|
+
<View style={styles.otpInputsView}>
|
|
138
|
+
{length ? renderInputs(length) : renderUnidentifiedInputs()}
|
|
139
|
+
</View>
|
|
140
|
+
<View style={styles.inputView}>
|
|
141
|
+
<TextInput
|
|
142
|
+
{...props}
|
|
143
|
+
accessibilityLabel={`TextInput`}
|
|
144
|
+
ref={inputRef}
|
|
145
|
+
value={value}
|
|
146
|
+
onChangeText={_onChangeText}
|
|
147
|
+
keyboardType={keyboardType}
|
|
148
|
+
onFocus={onFocusInput}
|
|
149
|
+
onBlur={onBlurInput}
|
|
150
|
+
style={{opacity: 0}}
|
|
151
|
+
selectionColor={theme.colors.primary}
|
|
152
|
+
placeholderTextColor={placeholderColor}
|
|
153
|
+
/>
|
|
154
|
+
</View>
|
|
155
|
+
</View>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<TouchableOpacity
|
|
161
|
+
activeOpacity={1}
|
|
162
|
+
onPress={onFocusInput}
|
|
163
|
+
style={styles.otpWrapper}
|
|
164
|
+
accessibilityLabel={`Input/${floatingValue}`}>
|
|
165
|
+
{renderInputView()}
|
|
166
|
+
<ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
|
|
167
|
+
</TouchableOpacity>
|
|
168
|
+
);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export default InputOTP;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, {FC, useContext, useEffect, useRef} from 'react';
|
|
2
|
+
import {Animated, View} from 'react-native';
|
|
3
|
+
import {Spacing} from '../Consts';
|
|
4
|
+
import {scaleSize, Text} from '../Text';
|
|
5
|
+
import {ApplicationContext} from '../Application';
|
|
6
|
+
import {CaretProps} from './index';
|
|
7
|
+
|
|
8
|
+
const OtpCaret: FC<CaretProps> = ({index, length}) => {
|
|
9
|
+
const DURATION = 300;
|
|
10
|
+
const {theme} = useContext(ApplicationContext);
|
|
11
|
+
const opacity = useRef(new Animated.Value(0)).current;
|
|
12
|
+
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
Animated.loop(
|
|
15
|
+
Animated.sequence([
|
|
16
|
+
Animated.timing(opacity, {
|
|
17
|
+
toValue: 1,
|
|
18
|
+
duration: DURATION,
|
|
19
|
+
useNativeDriver: true,
|
|
20
|
+
}),
|
|
21
|
+
Animated.delay(DURATION * 2),
|
|
22
|
+
Animated.timing(opacity, {
|
|
23
|
+
toValue: 0,
|
|
24
|
+
duration: DURATION,
|
|
25
|
+
useNativeDriver: true,
|
|
26
|
+
}),
|
|
27
|
+
]),
|
|
28
|
+
).start();
|
|
29
|
+
}, []);
|
|
30
|
+
const spacingStyle = !isNaN(Number(length)) &&
|
|
31
|
+
index !== Number(length) - 1 && {marginRight: Spacing.L};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<View style={[{flexDirection: 'row', alignItems: 'center'}, spacingStyle]}>
|
|
35
|
+
<Animated.View
|
|
36
|
+
style={{
|
|
37
|
+
height: scaleSize(12),
|
|
38
|
+
width: 1,
|
|
39
|
+
backgroundColor: theme.colors.primary,
|
|
40
|
+
opacity,
|
|
41
|
+
}}
|
|
42
|
+
/>
|
|
43
|
+
<Text color={theme.colors.text.hint} typography={'paragraph_default'}>
|
|
44
|
+
-
|
|
45
|
+
</Text>
|
|
46
|
+
</View>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default OtpCaret;
|
package/Input/common.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {View} from 'react-native';
|
|
1
|
+
import {View, ViewStyle} from 'react-native';
|
|
2
2
|
import styles from './styles';
|
|
3
3
|
import {Text} from '../Text';
|
|
4
4
|
import React, {FC, useContext} from 'react';
|
|
@@ -13,6 +13,7 @@ type FloatingViewProps = {
|
|
|
13
13
|
disabled?: boolean;
|
|
14
14
|
floatingIcon?: string;
|
|
15
15
|
required?: boolean;
|
|
16
|
+
style?: ViewStyle;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
export const DEFAULT_HEIGHT = 112;
|
|
@@ -81,6 +82,7 @@ export const FloatingView: FC<FloatingViewProps> = ({
|
|
|
81
82
|
disabled,
|
|
82
83
|
floatingIcon,
|
|
83
84
|
required,
|
|
85
|
+
style,
|
|
84
86
|
}) => {
|
|
85
87
|
const {theme} = useContext(ApplicationContext);
|
|
86
88
|
|
|
@@ -100,6 +102,7 @@ export const FloatingView: FC<FloatingViewProps> = ({
|
|
|
100
102
|
backgroundColor: theme.colors.background.surface,
|
|
101
103
|
zIndex: 10,
|
|
102
104
|
},
|
|
105
|
+
style,
|
|
103
106
|
]}>
|
|
104
107
|
<Text color={floatingTextColor} typography={'label_s'}>
|
|
105
108
|
{floatingValue}
|
package/Input/index.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import Input from './Input';
|
|
|
2
2
|
import InputTextArea from './InputTextArea';
|
|
3
3
|
import InputSearch from './InputSearch';
|
|
4
4
|
import InputMoney from './InputMoney';
|
|
5
|
+
import InputOTP from './InputOTP';
|
|
5
6
|
import {TextInputProps} from 'react-native';
|
|
6
7
|
|
|
7
8
|
export interface InputProps extends TextInputProps {
|
|
@@ -109,4 +110,15 @@ export interface InputSearchProps extends InputPropsOmitForSearch {
|
|
|
109
110
|
|
|
110
111
|
export interface InputMoneyProps extends InputPropsWithoutPlaceholder {}
|
|
111
112
|
|
|
112
|
-
export
|
|
113
|
+
export type OTPInputLength = 2 | 4 | 6 | 8 | 10;
|
|
114
|
+
|
|
115
|
+
export interface InputOTPProps extends InputPropsWithoutSizeAndIcon {
|
|
116
|
+
length?: OTPInputLength;
|
|
117
|
+
dataType?: 'string' | 'number';
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export type CaretProps = {
|
|
121
|
+
index?: number;
|
|
122
|
+
length?: number;
|
|
123
|
+
};
|
|
124
|
+
export {Input, InputTextArea, InputSearch, InputMoney, InputOTP};
|
package/Input/styles.ts
CHANGED
|
@@ -142,4 +142,28 @@ export default StyleSheet.create({
|
|
|
142
142
|
paddingVertical: Spacing.S,
|
|
143
143
|
fontWeight: 'bold',
|
|
144
144
|
},
|
|
145
|
+
|
|
146
|
+
//OTP
|
|
147
|
+
otpWrapper: {
|
|
148
|
+
width: '100%',
|
|
149
|
+
marginTop: Spacing.M,
|
|
150
|
+
},
|
|
151
|
+
otpInput: {
|
|
152
|
+
height: scaleSize(56),
|
|
153
|
+
borderRadius: Radius.S,
|
|
154
|
+
borderWidth: 1,
|
|
155
|
+
},
|
|
156
|
+
otpFloatingView: {
|
|
157
|
+
position: 'absolute',
|
|
158
|
+
top: -Spacing.S,
|
|
159
|
+
alignSelf: 'center',
|
|
160
|
+
paddingHorizontal: Spacing.S,
|
|
161
|
+
},
|
|
162
|
+
otpInputsView: {
|
|
163
|
+
width: '100%',
|
|
164
|
+
height: '100%',
|
|
165
|
+
flexDirection: 'row',
|
|
166
|
+
alignItems: 'center',
|
|
167
|
+
justifyContent: 'center',
|
|
168
|
+
},
|
|
145
169
|
});
|
package/Switch/index.tsx
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import React, {FC
|
|
1
|
+
import React, {FC} from 'react';
|
|
2
2
|
import {TouchableOpacity, View} from 'react-native';
|
|
3
3
|
import {SwitchProps} from './types';
|
|
4
4
|
import styles from './styles';
|
|
5
|
-
import {ApplicationContext} from '../Application';
|
|
6
5
|
import {Colors} from '../Consts';
|
|
7
6
|
|
|
8
7
|
const Switch: FC<SwitchProps> = props => {
|
|
9
|
-
const {theme} = useContext(ApplicationContext);
|
|
10
8
|
const {value, onChange, disabled, style} = props;
|
|
11
9
|
const circleBackgroundColor = value ? Colors.black_01 : Colors.black_03;
|
|
12
10
|
const circleAlign = value ? 'flex-end' : 'flex-start';
|
|
13
11
|
|
|
14
|
-
let backgroundColor = value ?
|
|
12
|
+
let backgroundColor = value ? Colors.green_03 : Colors.black_07;
|
|
15
13
|
if (disabled) {
|
|
16
|
-
backgroundColor = value ?
|
|
14
|
+
backgroundColor = value ? Colors.green_09 : Colors.black_05;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
return (
|
package/Title/index.tsx
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React, {FC, useContext} from 'react';
|
|
2
|
+
import {Text as RNText, TouchableOpacity, View} from 'react-native';
|
|
3
|
+
import {TitleProps} from './types';
|
|
4
|
+
import {Icon} from '../Icon';
|
|
5
|
+
import styles from './styles';
|
|
6
|
+
import {ApplicationContext} from '../Application';
|
|
7
|
+
import {Colors, Spacing} from '../Consts';
|
|
8
|
+
import {Button} from '../Button';
|
|
9
|
+
import {scaleSize, Text} from '../Text';
|
|
10
|
+
|
|
11
|
+
const Title: FC<TitleProps> = ({
|
|
12
|
+
size = 'large',
|
|
13
|
+
type = 'section',
|
|
14
|
+
onPressAction,
|
|
15
|
+
actionTitle,
|
|
16
|
+
title = 'Title',
|
|
17
|
+
titleFlex = true,
|
|
18
|
+
showAction = true,
|
|
19
|
+
icon,
|
|
20
|
+
description,
|
|
21
|
+
}) => {
|
|
22
|
+
const {theme} = useContext(ApplicationContext);
|
|
23
|
+
const flexStyle = titleFlex ? {flex: 1} : {};
|
|
24
|
+
const typeStyle =
|
|
25
|
+
type === 'screen' ? styles.screen : styles[`${type}_${size}`];
|
|
26
|
+
const actionColor = titleFlex
|
|
27
|
+
? theme.colors.primary
|
|
28
|
+
: theme.colors.text.default;
|
|
29
|
+
const actionBackground = titleFlex ? Colors.pink_08 + '4D' : Colors.black_06;
|
|
30
|
+
const actionSize = titleFlex ? scaleSize(22) : scaleSize(18);
|
|
31
|
+
const titleWeight = type === 'screen' ? 'Semibold' : 'Bold';
|
|
32
|
+
const marginStyle = type === 'section' ? {marginTop: Spacing.M} : {};
|
|
33
|
+
|
|
34
|
+
const renderAction = () => {
|
|
35
|
+
return !!actionTitle && titleFlex ? (
|
|
36
|
+
<Button
|
|
37
|
+
onPress={() => onPressAction?.()}
|
|
38
|
+
type={'text'}
|
|
39
|
+
full={false}
|
|
40
|
+
size={'small'}
|
|
41
|
+
title={actionTitle}
|
|
42
|
+
/>
|
|
43
|
+
) : (
|
|
44
|
+
<TouchableOpacity
|
|
45
|
+
style={[
|
|
46
|
+
{backgroundColor: actionBackground},
|
|
47
|
+
styles.actionIcon,
|
|
48
|
+
{width: actionSize, height: actionSize},
|
|
49
|
+
]}
|
|
50
|
+
onPress={onPressAction}>
|
|
51
|
+
<Icon
|
|
52
|
+
size={actionSize}
|
|
53
|
+
color={actionColor}
|
|
54
|
+
source={'arrow_chevron_right_small'}
|
|
55
|
+
/>
|
|
56
|
+
</TouchableOpacity>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<View style={styles.wrapper}>
|
|
62
|
+
<View style={[styles.container, marginStyle]}>
|
|
63
|
+
{!!icon && type !== 'screen' && (
|
|
64
|
+
<Icon style={styles.icon} source={icon} />
|
|
65
|
+
)}
|
|
66
|
+
<RNText
|
|
67
|
+
style={[
|
|
68
|
+
typeStyle,
|
|
69
|
+
flexStyle,
|
|
70
|
+
styles.title,
|
|
71
|
+
{
|
|
72
|
+
fontFamily: `${theme.font}-${titleWeight}`,
|
|
73
|
+
},
|
|
74
|
+
]}>
|
|
75
|
+
{title}
|
|
76
|
+
</RNText>
|
|
77
|
+
{showAction && type !== 'screen' && renderAction()}
|
|
78
|
+
</View>
|
|
79
|
+
{!!description && !!icon && type !== 'screen' && (
|
|
80
|
+
<Text typography={'description_s'} color={theme.colors.text.secondary}>
|
|
81
|
+
{description}
|
|
82
|
+
</Text>
|
|
83
|
+
)}
|
|
84
|
+
</View>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export {Title};
|
|
89
|
+
export type {TitleProps};
|
package/Title/styles.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {StyleSheet} from 'react-native';
|
|
2
|
+
import {scaleSize} from '../Text';
|
|
3
|
+
import {Radius, Spacing} from '../Consts';
|
|
4
|
+
|
|
5
|
+
export default StyleSheet.create({
|
|
6
|
+
card_small: {
|
|
7
|
+
fontSize: scaleSize(16),
|
|
8
|
+
lineHeight: scaleSize(22),
|
|
9
|
+
},
|
|
10
|
+
card_large: {
|
|
11
|
+
fontSize: scaleSize(18),
|
|
12
|
+
lineHeight: scaleSize(26),
|
|
13
|
+
},
|
|
14
|
+
section_small: {
|
|
15
|
+
fontSize: scaleSize(20),
|
|
16
|
+
lineHeight: scaleSize(28),
|
|
17
|
+
},
|
|
18
|
+
section_large: {
|
|
19
|
+
fontSize: scaleSize(24),
|
|
20
|
+
lineHeight: scaleSize(34),
|
|
21
|
+
},
|
|
22
|
+
screen: {
|
|
23
|
+
fontSize: scaleSize(36),
|
|
24
|
+
lineHeight: scaleSize(44),
|
|
25
|
+
},
|
|
26
|
+
title: {
|
|
27
|
+
marginRight: Spacing.XS,
|
|
28
|
+
},
|
|
29
|
+
container: {
|
|
30
|
+
flexDirection: 'row',
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
width: '100%',
|
|
33
|
+
},
|
|
34
|
+
actionIcon: {
|
|
35
|
+
borderRadius: Radius.M,
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
},
|
|
39
|
+
icon: {
|
|
40
|
+
marginRight: Spacing.XS,
|
|
41
|
+
borderRadius: Radius.XS,
|
|
42
|
+
},
|
|
43
|
+
wrapper: {
|
|
44
|
+
width: '100%',
|
|
45
|
+
},
|
|
46
|
+
});
|
package/Title/types.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type TitleProps = {
|
|
2
|
+
type?: 'screen' | 'section' | 'card';
|
|
3
|
+
title: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
size?: 'large' | 'small';
|
|
6
|
+
icon?: string;
|
|
7
|
+
titleFlex?: boolean;
|
|
8
|
+
actionTitle?: string;
|
|
9
|
+
onPressAction?: () => void;
|
|
10
|
+
showAction?: boolean;
|
|
11
|
+
};
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@momo-kits/foundation",
|
|
3
|
-
"version": "0.79.6-beta.
|
|
3
|
+
"version": "0.79.6-beta.12",
|
|
4
4
|
"description": "React Native Component Kits",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"
|
|
7
|
+
"postinstall": "node verify.js"
|
|
8
8
|
},
|
|
9
9
|
"keywords": [
|
|
10
10
|
"@momo-kits/foundation"
|
package/verify.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
const package = path.join(`${__dirname}`, 'package.json');
|
|
6
|
+
const packageInfo = JSON.parse(fs.readFileSync(package, 'utf8'));
|
|
7
|
+
const packageVersion = parseInt(packageInfo?.version.split('.')?.[1]);
|
|
8
|
+
|
|
9
|
+
const app = path.join(`${__dirname}/../../../`, 'app.json');
|
|
10
|
+
const appInfo = JSON.parse(fs.readFileSync(app, 'utf8'));
|
|
11
|
+
const iOSAppTarget = appInfo?.client?.ios.deploymentTarget;
|
|
12
|
+
const androidAppTarget = appInfo?.client?.android.deploymentTarget;
|
|
13
|
+
|
|
14
|
+
if (packageVersion > iOSAppTarget || packageVersion > androidAppTarget) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Package ${packageInfo.name} version: ${packageInfo.version} require deploymentTarget ${packageVersion}`,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error(`Installation failed: ${error.message}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|