@momo-kits/foundation 0.81.27-beta.3 → 0.81.28
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/BottomTab.tsx +28 -12
- package/Application/Components.tsx +2 -2
- package/Input/Input.tsx +6 -1
- package/Input/InputOTP.tsx +165 -144
- package/Input/index.tsx +2 -0
- package/Layout/Screen.tsx +7 -16
- package/Layout/styles.ts +16 -3
- package/Layout/types.ts +2 -2
- package/package.json +1 -1
|
@@ -1,13 +1,29 @@
|
|
|
1
|
-
import React, {useContext} from 'react';
|
|
1
|
+
import React, {useContext, useEffect} from 'react';
|
|
2
2
|
import {View} from 'react-native';
|
|
3
|
-
import {BottomTabProps} from './types';
|
|
3
|
+
import {BottomTabProps, NavigationScreenProps} from './types';
|
|
4
4
|
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
|
|
5
|
+
import {createStackNavigator} from '@react-navigation/stack';
|
|
5
6
|
import {Icon} from '../Icon';
|
|
6
7
|
import {Text} from '../Text';
|
|
7
8
|
import {ApplicationContext} from './index';
|
|
9
|
+
import {getStackOptions} from './utils';
|
|
10
|
+
import StackScreen from './StackScreen';
|
|
8
11
|
|
|
9
12
|
const Tab = createBottomTabNavigator();
|
|
13
|
+
const Stack = createStackNavigator();
|
|
10
14
|
|
|
15
|
+
const TabScreen: React.FC<NavigationScreenProps> = ({route}) => {
|
|
16
|
+
return (
|
|
17
|
+
<Stack.Navigator>
|
|
18
|
+
<Stack.Screen
|
|
19
|
+
name="Stack"
|
|
20
|
+
component={StackScreen}
|
|
21
|
+
initialParams={{screen: route.params?.screen}}
|
|
22
|
+
options={{...getStackOptions(), ...route.params?.options}}
|
|
23
|
+
/>
|
|
24
|
+
</Stack.Navigator>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
11
27
|
const BottomTab: React.FC<BottomTabProps> = ({
|
|
12
28
|
tabs,
|
|
13
29
|
listeners,
|
|
@@ -16,14 +32,13 @@ const BottomTab: React.FC<BottomTabProps> = ({
|
|
|
16
32
|
}) => {
|
|
17
33
|
const {theme} = useContext(ApplicationContext);
|
|
18
34
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
};
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
navigation?.setOptions({
|
|
37
|
+
headerShown: false,
|
|
38
|
+
headerTransparent: true,
|
|
39
|
+
headerBackground: undefined,
|
|
40
|
+
});
|
|
41
|
+
}, []);
|
|
27
42
|
|
|
28
43
|
return (
|
|
29
44
|
<Tab.Navigator
|
|
@@ -34,8 +49,9 @@ const BottomTab: React.FC<BottomTabProps> = ({
|
|
|
34
49
|
<Tab.Screen
|
|
35
50
|
key={item.name}
|
|
36
51
|
name={item.name}
|
|
37
|
-
component={
|
|
38
|
-
|
|
52
|
+
component={TabScreen}
|
|
53
|
+
initialParams={item}
|
|
54
|
+
listeners={listeners}
|
|
39
55
|
options={{
|
|
40
56
|
tabBarLabel: ({color, focused}) => {
|
|
41
57
|
return (
|
package/Input/Input.tsx
CHANGED
|
@@ -36,6 +36,7 @@ const Input = forwardRef(
|
|
|
36
36
|
leadingIcon,
|
|
37
37
|
leadingIconColor,
|
|
38
38
|
fontWeight = 'Regular',
|
|
39
|
+
onPressIcon,
|
|
39
40
|
style,
|
|
40
41
|
...props
|
|
41
42
|
}: InputProps,
|
|
@@ -72,7 +73,11 @@ const Input = forwardRef(
|
|
|
72
73
|
return <Loader type={'spinner'} color={color} />;
|
|
73
74
|
}
|
|
74
75
|
if (icon) {
|
|
75
|
-
return
|
|
76
|
+
return (
|
|
77
|
+
<TouchableOpacity onPress={onPressIcon} disabled={!onPressIcon}>
|
|
78
|
+
<Icon color={color} source={icon} size={24} />
|
|
79
|
+
</TouchableOpacity>
|
|
80
|
+
);
|
|
76
81
|
}
|
|
77
82
|
};
|
|
78
83
|
|
package/Input/InputOTP.tsx
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
FC,
|
|
3
|
+
forwardRef,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
2
10
|
import {
|
|
3
11
|
Animated,
|
|
4
12
|
NativeSyntheticEvent,
|
|
@@ -56,156 +64,169 @@ const OTPCaret: FC<CaretProps> = ({index, length}) => {
|
|
|
56
64
|
);
|
|
57
65
|
};
|
|
58
66
|
|
|
59
|
-
const InputOTP
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const onBlurInput = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
87
|
-
setFocused(false);
|
|
88
|
-
onBlur?.(e);
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const _onChangeText = (text: string) => {
|
|
92
|
-
if (text.length > MAX_LENGTH) return;
|
|
93
|
-
if (dataType === 'number' && isNaN(Number(text))) return;
|
|
94
|
-
if (
|
|
95
|
-
!isNaN(Number(text)) &&
|
|
96
|
-
value.length >= Number(length) &&
|
|
97
|
-
text.length >= value.length
|
|
98
|
-
)
|
|
99
|
-
return;
|
|
100
|
-
|
|
101
|
-
setValue(text);
|
|
102
|
-
onChangeText?.(text);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const renderInputs = (length: number) => {
|
|
106
|
-
const TextInputs: React.ReactNode[] = [];
|
|
107
|
-
for (let i = 0; i < length; i++) {
|
|
108
|
-
TextInputs.push(
|
|
109
|
-
<View>
|
|
110
|
-
{focused && value.length === i ? (
|
|
111
|
-
<OTPCaret index={i} length={length} />
|
|
112
|
-
) : (
|
|
113
|
-
<Text
|
|
114
|
-
style={i !== length - 1 && {marginRight: Spacing.L}}
|
|
115
|
-
color={
|
|
116
|
-
!!value[i] ? theme.colors.text.default : theme.colors.text.hint
|
|
117
|
-
}
|
|
118
|
-
typography={!!value[i] ? 'title_s' : 'paragraph_default'}>
|
|
119
|
-
{value[i] || '-'}
|
|
120
|
-
</Text>
|
|
121
|
-
)}
|
|
122
|
-
</View>,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
return TextInputs;
|
|
126
|
-
};
|
|
67
|
+
const InputOTP = forwardRef(
|
|
68
|
+
(
|
|
69
|
+
{
|
|
70
|
+
length,
|
|
71
|
+
errorMessage,
|
|
72
|
+
errorSpacing,
|
|
73
|
+
floatingValue,
|
|
74
|
+
floatingIconColor,
|
|
75
|
+
floatingIcon,
|
|
76
|
+
placeholder,
|
|
77
|
+
onChangeText,
|
|
78
|
+
onFocus,
|
|
79
|
+
onBlur,
|
|
80
|
+
dataType = 'number',
|
|
81
|
+
style,
|
|
82
|
+
...props
|
|
83
|
+
}: InputOTPProps,
|
|
84
|
+
ref,
|
|
85
|
+
) => {
|
|
86
|
+
const MAX_LENGTH = 10;
|
|
87
|
+
const [value, setValue] = useState('');
|
|
88
|
+
const [focused, setFocused] = useState(false);
|
|
89
|
+
const inputRef = useRef<TextInput>(null);
|
|
90
|
+
const {theme} = useContext(ApplicationContext);
|
|
91
|
+
const accessibilityLabel = `InputOTP/${floatingValue ?? placeholder}`;
|
|
127
92
|
|
|
128
|
-
|
|
129
|
-
|
|
93
|
+
useImperativeHandle(ref, () => ({
|
|
94
|
+
onChangeText: (text: string) => {
|
|
95
|
+
_onChangeText(text);
|
|
96
|
+
},
|
|
97
|
+
}));
|
|
130
98
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
</Text>
|
|
136
|
-
);
|
|
137
|
-
}
|
|
99
|
+
const onFocusInput = () => {
|
|
100
|
+
setFocused(true);
|
|
101
|
+
inputRef.current?.focus();
|
|
102
|
+
};
|
|
138
103
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
104
|
+
const onBlurInput = (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
105
|
+
setFocused(false);
|
|
106
|
+
onBlur?.(e);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const _onChangeText = (text: string) => {
|
|
110
|
+
if (text.length > MAX_LENGTH) return;
|
|
111
|
+
if (dataType === 'number' && isNaN(Number(text))) return;
|
|
112
|
+
if (
|
|
113
|
+
!isNaN(Number(text)) &&
|
|
114
|
+
value.length >= Number(length) &&
|
|
115
|
+
text.length >= value.length
|
|
116
|
+
)
|
|
117
|
+
return;
|
|
118
|
+
|
|
119
|
+
setValue(text);
|
|
120
|
+
onChangeText?.(text);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const renderInputs = (length: number) => {
|
|
124
|
+
const TextInputs: React.ReactNode[] = [];
|
|
125
|
+
for (let i = 0; i < length; i++) {
|
|
126
|
+
TextInputs.push(
|
|
127
|
+
<View>
|
|
128
|
+
{focused && value.length === i ? (
|
|
129
|
+
<OTPCaret index={i} length={length} />
|
|
130
|
+
) : (
|
|
131
|
+
<Text
|
|
132
|
+
style={i !== length - 1 && {marginRight: Spacing.L}}
|
|
133
|
+
color={
|
|
134
|
+
!!value[i]
|
|
135
|
+
? theme.colors.text.default
|
|
136
|
+
: theme.colors.text.hint
|
|
148
137
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
};
|
|
138
|
+
typography={!!value[i] ? 'title_s' : 'paragraph_default'}>
|
|
139
|
+
{value[i] || '-'}
|
|
140
|
+
</Text>
|
|
141
|
+
)}
|
|
142
|
+
</View>,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return TextInputs;
|
|
146
|
+
};
|
|
159
147
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
{
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
148
|
+
const renderUnidentifiedInputs = () => {
|
|
149
|
+
const splitValue = value.split('');
|
|
150
|
+
|
|
151
|
+
if (!focused && value.length === 0 && !!placeholder) {
|
|
152
|
+
return (
|
|
153
|
+
<Text color={theme.colors.text.hint} typography={'description_s'}>
|
|
154
|
+
{placeholder}
|
|
155
|
+
</Text>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return (
|
|
160
|
+
<View style={{flexDirection: 'row'}}>
|
|
161
|
+
{splitValue.map((letter, index) => {
|
|
162
|
+
return (
|
|
163
|
+
<Text
|
|
164
|
+
style={
|
|
165
|
+
(index !== value.length - 1 ||
|
|
166
|
+
(focused && value.length !== MAX_LENGTH)) && {
|
|
167
|
+
marginRight: Spacing.L,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
typography={'title_s'}>
|
|
171
|
+
{letter}
|
|
172
|
+
</Text>
|
|
173
|
+
);
|
|
174
|
+
})}
|
|
175
|
+
{focused && value.length !== MAX_LENGTH && <OTPCaret />}
|
|
179
176
|
</View>
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
177
|
+
);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const renderInputView = () => {
|
|
181
|
+
return (
|
|
182
|
+
<View
|
|
183
|
+
style={[
|
|
184
|
+
styles.otpInput,
|
|
185
|
+
{backgroundColor: theme.colors.background.surface},
|
|
186
|
+
getBorderColor(theme, focused, errorMessage),
|
|
187
|
+
]}>
|
|
188
|
+
{!!floatingValue && (
|
|
189
|
+
<View
|
|
190
|
+
style={[
|
|
191
|
+
styles.otpFloatingView,
|
|
192
|
+
{backgroundColor: theme.colors.background.surface},
|
|
193
|
+
]}>
|
|
194
|
+
<Text typography={'description_s'}>{floatingValue}</Text>
|
|
195
|
+
</View>
|
|
196
|
+
)}
|
|
197
|
+
<View style={styles.otpInputsView}>
|
|
198
|
+
{length ? renderInputs(length) : renderUnidentifiedInputs()}
|
|
199
|
+
</View>
|
|
200
|
+
<View style={styles.inputView}>
|
|
201
|
+
<TextInput
|
|
202
|
+
{...props}
|
|
203
|
+
accessibilityLabel={accessibilityLabel}
|
|
204
|
+
ref={inputRef}
|
|
205
|
+
value={value}
|
|
206
|
+
onChangeText={_onChangeText}
|
|
207
|
+
keyboardType={dataType === 'number' ? 'number-pad' : 'default'}
|
|
208
|
+
onFocus={onFocusInput}
|
|
209
|
+
onBlur={onBlurInput}
|
|
210
|
+
style={{opacity: 0}}
|
|
211
|
+
selectionColor={theme.colors.primary}
|
|
212
|
+
placeholderTextColor={theme.colors.text.hint}
|
|
213
|
+
/>
|
|
214
|
+
</View>
|
|
194
215
|
</View>
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
};
|
|
216
|
+
);
|
|
217
|
+
};
|
|
198
218
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
219
|
+
return (
|
|
220
|
+
<TouchableOpacity
|
|
221
|
+
activeOpacity={1}
|
|
222
|
+
onPress={onFocusInput}
|
|
223
|
+
style={[style, styles.otpWrapper]}
|
|
224
|
+
accessibilityLabel={accessibilityLabel}>
|
|
225
|
+
{renderInputView()}
|
|
226
|
+
<ErrorView errorMessage={errorMessage} errorSpacing={errorSpacing} />
|
|
227
|
+
</TouchableOpacity>
|
|
228
|
+
);
|
|
229
|
+
},
|
|
230
|
+
);
|
|
210
231
|
|
|
211
232
|
export default InputOTP;
|
package/Input/index.tsx
CHANGED
package/Layout/Screen.tsx
CHANGED
|
@@ -347,22 +347,13 @@ const Screen = forwardRef(
|
|
|
347
347
|
</Component>
|
|
348
348
|
{Footer && (
|
|
349
349
|
<View
|
|
350
|
-
style={
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
},
|
|
358
|
-
ios: {
|
|
359
|
-
shadowColor: Colors.black_20,
|
|
360
|
-
shadowOffset: {width: 0, height: -2},
|
|
361
|
-
shadowOpacity: 0.1,
|
|
362
|
-
shadowRadius: 3,
|
|
363
|
-
},
|
|
364
|
-
}),
|
|
365
|
-
}}>
|
|
350
|
+
style={[
|
|
351
|
+
styles.footerContainer,
|
|
352
|
+
{
|
|
353
|
+
paddingBottom: Math.min(insets.bottom, 21) + Spacing.S,
|
|
354
|
+
backgroundColor: theme.colors.background.surface,
|
|
355
|
+
},
|
|
356
|
+
]}>
|
|
366
357
|
<Section>{Footer}</Section>
|
|
367
358
|
</View>
|
|
368
359
|
)}
|
package/Layout/styles.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {StyleSheet} from 'react-native';
|
|
2
|
-
import {Radius} from '../Consts';
|
|
1
|
+
import {Platform, StyleSheet} from 'react-native';
|
|
2
|
+
import {Colors, Radius, Spacing} from '../Consts';
|
|
3
3
|
|
|
4
4
|
export default StyleSheet.create({
|
|
5
5
|
extendedHeader: {
|
|
@@ -45,7 +45,6 @@ export default StyleSheet.create({
|
|
|
45
45
|
flexDirection: 'row',
|
|
46
46
|
flexWrap: 'wrap',
|
|
47
47
|
borderRadius: Radius.M,
|
|
48
|
-
|
|
49
48
|
padding: 12,
|
|
50
49
|
},
|
|
51
50
|
item: {
|
|
@@ -81,4 +80,18 @@ export default StyleSheet.create({
|
|
|
81
80
|
paddingHorizontal: undefined,
|
|
82
81
|
paddingVertical: undefined,
|
|
83
82
|
},
|
|
83
|
+
footerContainer: {
|
|
84
|
+
paddingTop: Spacing.S,
|
|
85
|
+
...Platform.select({
|
|
86
|
+
android: {
|
|
87
|
+
elevation: 4,
|
|
88
|
+
},
|
|
89
|
+
ios: {
|
|
90
|
+
shadowColor: Colors.black_20,
|
|
91
|
+
shadowOffset: {width: 0, height: -2},
|
|
92
|
+
shadowOpacity: 0.1,
|
|
93
|
+
shadowRadius: 3,
|
|
94
|
+
},
|
|
95
|
+
}),
|
|
96
|
+
},
|
|
84
97
|
});
|
package/Layout/types.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export type HeaderType = 'default' | 'surface' | 'extended' | 'none';
|
|
2
|
+
|
|
1
3
|
export type GridContextProps = {
|
|
2
4
|
/**
|
|
3
5
|
* Represents the number of columns in the grid.
|
|
@@ -19,5 +21,3 @@ export type GridContextProps = {
|
|
|
19
21
|
*/
|
|
20
22
|
getSizeSpan: (span: number) => number;
|
|
21
23
|
};
|
|
22
|
-
|
|
23
|
-
export type HeaderType = 'default' | 'surface' | 'extended' | 'none';
|