@momo-kits/foundation 0.169.9 → 0.169.10-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.hooks.ts +17 -27
- package/Application/BottomSheet.tsx +27 -35
- package/Application/BottomTab/BottomTabBar.tsx +6 -6
- package/Application/BottomTab/DuoRailTabBar.tsx +5 -5
- package/Application/BottomTab/TabScreen.tsx +10 -11
- package/Application/BottomTab/index.tsx +5 -5
- package/Application/BottomTab/usePressLift.ts +3 -3
- package/Application/Components/HeaderAnimated.tsx +38 -13
- package/Application/Components/HeaderBackground.tsx +16 -3
- package/Application/Components/HeaderExtendHeader.tsx +41 -28
- package/Application/Components/HeaderLeft.tsx +4 -18
- package/Application/Components/HeaderRight.styles.ts +15 -13
- package/Application/Components/HeaderTitle.shared.ts +10 -11
- package/Application/Components/HeaderToolkitAction.tsx +21 -54
- package/Application/Components/NavigationButton.tsx +9 -6
- package/Application/Components/SearchHeader.tsx +20 -7
- package/Application/Components/useToolkitActions.tsx +21 -22
- package/Application/ModalScreen.tsx +15 -19
- package/Application/StackScreen.tsx +18 -13
- package/Application/headerLayout.ts +165 -0
- package/Application/index.ts +11 -1
- package/Application/modalLayout.ts +0 -1
- package/Application/navigationOptions.tsx +6 -15
- package/Application/types.header.ts +7 -2
- package/Application/types.ts +7 -0
- package/Context/index.ts +1 -3
- package/Image/index.tsx +6 -6
- package/Input/Input.tsx +37 -40
- package/Input/InputDropDown.tsx +10 -13
- package/Input/InputMoney.tsx +17 -17
- package/Input/InputMoneyView.tsx +12 -12
- package/Input/InputOTP.tsx +34 -46
- package/Input/InputPhoneNumber.tsx +43 -48
- package/Input/InputSearch.tsx +39 -26
- package/Input/InputTextArea.tsx +23 -29
- package/Input/common.tsx +257 -0
- package/Input/index.tsx +7 -1
- package/Input/moneyUtils.ts +23 -0
- package/Input/utils.ts +7 -126
- package/Layout/FloatingButton.tsx +24 -38
- package/Layout/Screen.tsx +3 -0
- package/Layout/layoutMetrics.ts +34 -43
- package/Layout/screenHeader.tsx +55 -52
- package/Layout/screenTypes.ts +13 -4
- package/Pagination/PaginationScroll.tsx +3 -5
- package/Pagination/types.ts +5 -3
- package/Popup/PopupNotify.tsx +14 -17
- package/Popup/PopupPromotion.tsx +4 -5
- package/Popup/types.ts +4 -2
- package/Popup/utils.ts +4 -7
- package/Skeleton/index.tsx +12 -15
- package/package.json +1 -1
- package/Input/ErrorView.tsx +0 -59
- package/Input/FloatingView.tsx +0 -101
- package/Input/RenderTrailing.tsx +0 -79
- package/Input/constants.ts +0 -8
|
@@ -20,23 +20,18 @@ import {
|
|
|
20
20
|
} from '../Context';
|
|
21
21
|
import { Colors, Spacing, Styles } from '../Consts';
|
|
22
22
|
import { Icon } from '../Icon';
|
|
23
|
-
import { Image } from '../Image';
|
|
24
23
|
import { useScaleSize, Text, exportFontFamily } from '../Text';
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
import {
|
|
25
|
+
ErrorView,
|
|
26
|
+
getBorderColor,
|
|
27
|
+
getSizeStyle,
|
|
28
|
+
RenderTrailing,
|
|
29
|
+
} from './common';
|
|
28
30
|
import { InputPhoneNumberProps } from './index';
|
|
29
|
-
import { RenderTrailing } from './RenderTrailing';
|
|
30
31
|
import styles from './styles';
|
|
31
32
|
import SystemTextInput from './SystemTextInput';
|
|
32
|
-
import {
|
|
33
|
-
|
|
34
|
-
const SMALL_FONT_SIZE = 14;
|
|
35
|
-
const LARGE_FONT_SIZE = 18;
|
|
36
|
-
const SMALL_DIVIDER_HEIGHT = 24;
|
|
37
|
-
const LARGE_DIVIDER_HEIGHT = 32;
|
|
38
|
-
const FOCUSED_BORDER_WIDTH = 1.5;
|
|
39
|
-
const FLAG_SIZE = 24;
|
|
33
|
+
import { Image } from '../Image';
|
|
34
|
+
import { Typography } from '../Text/types';
|
|
40
35
|
|
|
41
36
|
/**
|
|
42
37
|
* Vietnamese phone number input with a fixed flag and `+84` prefix, number pad
|
|
@@ -72,10 +67,10 @@ const InputPhoneNumber = forwardRef(
|
|
|
72
67
|
) => {
|
|
73
68
|
const { theme } = useContext(ApplicationContext);
|
|
74
69
|
const context = useContext<any>(MiniAppContext);
|
|
75
|
-
const scaleHeight = useScaleSize(
|
|
76
|
-
const [
|
|
70
|
+
const scaleHeight = useScaleSize(size === 'small' ? 48 : 56);
|
|
71
|
+
const [focused, setFocused] = useState(false);
|
|
77
72
|
const [internalText, setInternalText] = useState(defaultValue || '');
|
|
78
|
-
const
|
|
73
|
+
const haveValue = value !== undefined ? !!value : !!internalText;
|
|
79
74
|
const inputRef = useRef<TextInput | null>(null);
|
|
80
75
|
const componentName = 'InputPhoneNumber';
|
|
81
76
|
|
|
@@ -86,29 +81,29 @@ const InputPhoneNumber = forwardRef(
|
|
|
86
81
|
props.accessibilityLabel,
|
|
87
82
|
);
|
|
88
83
|
|
|
89
|
-
const
|
|
84
|
+
const onClearText = () => {
|
|
90
85
|
inputRef?.current?.clear();
|
|
91
|
-
|
|
86
|
+
_onChangeText('');
|
|
92
87
|
};
|
|
93
88
|
|
|
94
|
-
const
|
|
89
|
+
const _onChangeText = (text: string) => {
|
|
95
90
|
if (value === undefined) {
|
|
96
91
|
setInternalText(text);
|
|
97
92
|
}
|
|
98
93
|
onChangeText?.(text);
|
|
99
94
|
};
|
|
100
95
|
|
|
101
|
-
const
|
|
102
|
-
|
|
96
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
97
|
+
setFocused(true);
|
|
103
98
|
onFocus?.(e);
|
|
104
99
|
};
|
|
105
100
|
|
|
106
|
-
const
|
|
107
|
-
|
|
101
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
102
|
+
setFocused(false);
|
|
108
103
|
onBlur?.(e);
|
|
109
104
|
};
|
|
110
105
|
|
|
111
|
-
const
|
|
106
|
+
const _setText = (text: string) => {
|
|
112
107
|
if (__DEV__ && value !== undefined) {
|
|
113
108
|
console.error(
|
|
114
109
|
`${componentName}: calling ref.setText() on a controlled input (\`value\` is provided) is an anti-pattern. ` +
|
|
@@ -117,48 +112,48 @@ const InputPhoneNumber = forwardRef(
|
|
|
117
112
|
);
|
|
118
113
|
}
|
|
119
114
|
inputRef?.current?.setNativeProps({ text });
|
|
120
|
-
|
|
115
|
+
_onChangeText(text);
|
|
121
116
|
};
|
|
122
117
|
|
|
123
118
|
useImperativeHandle(ref, () => {
|
|
124
119
|
return {
|
|
125
|
-
clear:
|
|
120
|
+
clear: onClearText,
|
|
126
121
|
focus: () => inputRef.current?.focus(),
|
|
127
122
|
blur: () => inputRef.current?.blur(),
|
|
128
|
-
setText:
|
|
123
|
+
setText: _setText,
|
|
129
124
|
};
|
|
130
125
|
});
|
|
131
126
|
|
|
132
127
|
let inputTextStyles = {};
|
|
133
|
-
let dividerHeight =
|
|
134
|
-
|
|
135
|
-
|
|
128
|
+
let dividerHeight = 24;
|
|
129
|
+
let size14 = useScaleSize(14);
|
|
130
|
+
let size18 = useScaleSize(18);
|
|
136
131
|
const semiboldFontFamily = exportFontFamily('semibold');
|
|
137
132
|
const boldFontFamily = exportFontFamily('bold');
|
|
138
133
|
let typography: Typography;
|
|
139
134
|
if (size === 'small') {
|
|
140
135
|
inputTextStyles = {
|
|
141
|
-
fontSize:
|
|
136
|
+
fontSize: size14,
|
|
142
137
|
fontFamily: semiboldFontFamily,
|
|
143
138
|
};
|
|
144
|
-
dividerHeight =
|
|
139
|
+
dividerHeight = 24;
|
|
145
140
|
typography = 'header_s_semibold';
|
|
146
141
|
} else {
|
|
147
142
|
inputTextStyles = {
|
|
148
|
-
fontSize:
|
|
143
|
+
fontSize: size18,
|
|
149
144
|
fontFamily: boldFontFamily,
|
|
150
145
|
};
|
|
151
|
-
dividerHeight =
|
|
146
|
+
dividerHeight = 32;
|
|
152
147
|
typography = 'header_m_bold';
|
|
153
148
|
}
|
|
154
149
|
|
|
155
150
|
const renderInputView = () => {
|
|
156
151
|
const disabledColor = theme.colors.text.disable;
|
|
157
|
-
const
|
|
152
|
+
const secure = secureTextEntry;
|
|
158
153
|
let textColor = theme.colors.text.default;
|
|
159
154
|
let placeholderColor = theme.colors.text.hint;
|
|
160
155
|
let iconTintColor = trailingColor ?? theme.colors.text.default;
|
|
161
|
-
const borderWidth =
|
|
156
|
+
const borderWidth = focused ? 1.5 : 1;
|
|
162
157
|
let secureTextStyle = styles.secureTextLarge;
|
|
163
158
|
|
|
164
159
|
if (size === 'small') {
|
|
@@ -178,7 +173,7 @@ const InputPhoneNumber = forwardRef(
|
|
|
178
173
|
{ backgroundColor: theme.colors.background.surface },
|
|
179
174
|
getSizeStyle(size, undefined, scaleHeight),
|
|
180
175
|
{ borderWidth },
|
|
181
|
-
getBorderColor(theme,
|
|
176
|
+
getBorderColor(theme, focused, errorMessage, disabled),
|
|
182
177
|
]}
|
|
183
178
|
>
|
|
184
179
|
<View style={styles.inputView}>
|
|
@@ -209,7 +204,7 @@ const InputPhoneNumber = forwardRef(
|
|
|
209
204
|
{...props}
|
|
210
205
|
accessibilityLabel={`${componentId}`}
|
|
211
206
|
editable={editable && !disabled}
|
|
212
|
-
secureTextEntry={
|
|
207
|
+
secureTextEntry={secure}
|
|
213
208
|
textAlignVertical="center"
|
|
214
209
|
ref={inputRef}
|
|
215
210
|
accessibilityState={{
|
|
@@ -222,15 +217,15 @@ const InputPhoneNumber = forwardRef(
|
|
|
222
217
|
color: textColor,
|
|
223
218
|
},
|
|
224
219
|
inputTextStyles,
|
|
225
|
-
|
|
220
|
+
secure && haveValue && secureTextStyle,
|
|
226
221
|
]}
|
|
227
222
|
defaultValue={defaultValue}
|
|
228
223
|
allowFontScaling={false}
|
|
229
224
|
textBreakStrategy="highQuality"
|
|
230
225
|
value={value}
|
|
231
|
-
onChangeText={
|
|
232
|
-
onFocus={
|
|
233
|
-
onBlur={
|
|
226
|
+
onChangeText={_onChangeText}
|
|
227
|
+
onFocus={_onFocus}
|
|
228
|
+
onBlur={_onBlur}
|
|
234
229
|
placeholder={placeholder}
|
|
235
230
|
selectionColor={theme.colors.primary}
|
|
236
231
|
placeholderTextColor={placeholderColor}
|
|
@@ -238,16 +233,16 @@ const InputPhoneNumber = forwardRef(
|
|
|
238
233
|
/>
|
|
239
234
|
</View>
|
|
240
235
|
<View style={styles.iconView}>
|
|
241
|
-
{showClearIcon &&
|
|
236
|
+
{showClearIcon && focused && haveValue && (
|
|
242
237
|
<TouchableOpacity
|
|
243
238
|
accessibilityLabel={`${componentId}|clear-icon-touch`}
|
|
244
239
|
accessible={false}
|
|
245
240
|
style={styles.iconWrapper}
|
|
246
|
-
onPress={
|
|
241
|
+
onPress={onClearText}
|
|
247
242
|
>
|
|
248
243
|
<Icon
|
|
249
244
|
source="24_navigation_close_circle_full"
|
|
250
|
-
size={
|
|
245
|
+
size={16}
|
|
251
246
|
color={theme.colors.text.hint}
|
|
252
247
|
accessibilityLabel={`${componentId}|clear-icon`}
|
|
253
248
|
/>
|
|
@@ -304,9 +299,9 @@ const InputPhoneNumber = forwardRef(
|
|
|
304
299
|
|
|
305
300
|
const innerStyle = StyleSheet.create({
|
|
306
301
|
iconFlag: {
|
|
307
|
-
width:
|
|
308
|
-
height:
|
|
309
|
-
marginHorizontal:
|
|
302
|
+
width: 24,
|
|
303
|
+
height: 24,
|
|
304
|
+
marginHorizontal: 2,
|
|
310
305
|
},
|
|
311
306
|
});
|
|
312
307
|
|
package/Input/InputSearch.tsx
CHANGED
|
@@ -13,18 +13,18 @@ import {
|
|
|
13
13
|
View,
|
|
14
14
|
} from 'react-native';
|
|
15
15
|
import { useComponentId } from '../Application';
|
|
16
|
+
import { HeaderBarMetrics } from '../Application/headerLayout';
|
|
16
17
|
import {
|
|
17
18
|
ApplicationContext,
|
|
18
19
|
ComponentContext,
|
|
19
20
|
MiniAppContext,
|
|
20
21
|
} from '../Context';
|
|
21
22
|
import { Icon } from '../Icon';
|
|
22
|
-
import { Styles } from '../Consts';
|
|
23
23
|
import { Text, useScaleSize, exportFontFamily } from '../Text';
|
|
24
|
-
import { CLEAR_ICON_SIZE, INPUT_FONT_SIZE, PRESSED_OPACITY } from './constants';
|
|
25
24
|
import { InputRef, InputSearchProps } from './index';
|
|
26
25
|
import { TextTyping } from './SearchTextTyping';
|
|
27
26
|
import styles from './styles';
|
|
27
|
+
import { Styles } from '../Consts';
|
|
28
28
|
import SystemTextInput from './SystemTextInput';
|
|
29
29
|
|
|
30
30
|
const SEARCH_ICON_SIZE = 24;
|
|
@@ -52,21 +52,29 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
52
52
|
backgroundColor,
|
|
53
53
|
onPress,
|
|
54
54
|
typingData,
|
|
55
|
+
size = 'default',
|
|
55
56
|
...props
|
|
56
57
|
},
|
|
57
58
|
ref,
|
|
58
59
|
) => {
|
|
59
60
|
const { theme } = useContext(ApplicationContext);
|
|
60
61
|
const context = useContext<any>(MiniAppContext);
|
|
61
|
-
const scaledFontSize = useScaleSize(
|
|
62
|
+
const scaledFontSize = useScaleSize(14);
|
|
62
63
|
const searchFontFamily = exportFontFamily('regular');
|
|
63
64
|
|
|
64
65
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
66
|
+
const isHeaderSize = size === 'header';
|
|
67
|
+
const inputHeightStyle = isHeaderSize && {
|
|
68
|
+
height: HeaderBarMetrics.searchHeight,
|
|
69
|
+
};
|
|
70
|
+
const searchIconSize = isHeaderSize
|
|
71
|
+
? HeaderBarMetrics.iconSize
|
|
72
|
+
: SEARCH_ICON_SIZE;
|
|
65
73
|
|
|
66
|
-
const [
|
|
74
|
+
const [focused, setFocused] = useState(false);
|
|
67
75
|
const [internalText, setInternalText] = useState(defaultValue || '');
|
|
68
76
|
const currentValue = value !== undefined ? value : internalText;
|
|
69
|
-
const
|
|
77
|
+
const haveValue = !!currentValue;
|
|
70
78
|
const inputRef = useRef<TextInput | null>(null);
|
|
71
79
|
|
|
72
80
|
const componentName = 'InputSearch';
|
|
@@ -76,40 +84,40 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
76
84
|
props.accessibilityLabel,
|
|
77
85
|
);
|
|
78
86
|
|
|
79
|
-
const
|
|
80
|
-
|
|
87
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
88
|
+
setFocused(true);
|
|
81
89
|
onFocus?.(e);
|
|
82
90
|
};
|
|
83
91
|
|
|
84
|
-
const
|
|
85
|
-
|
|
92
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
93
|
+
setFocused(false);
|
|
86
94
|
onBlur?.(e);
|
|
87
95
|
};
|
|
88
96
|
|
|
89
|
-
const
|
|
97
|
+
const onClearText = () => {
|
|
90
98
|
inputRef?.current?.clear();
|
|
91
99
|
inputRef.current?.setNativeProps({ text: '' });
|
|
92
|
-
|
|
100
|
+
_onChangeText('');
|
|
93
101
|
};
|
|
94
102
|
|
|
95
|
-
const
|
|
103
|
+
const _onChangeText = (text: string) => {
|
|
96
104
|
if (value === undefined) {
|
|
97
105
|
setInternalText(text);
|
|
98
106
|
}
|
|
99
107
|
onChangeText?.(text);
|
|
100
108
|
};
|
|
101
109
|
|
|
102
|
-
const
|
|
110
|
+
const _setText = (text: string) => {
|
|
103
111
|
inputRef?.current?.setNativeProps({ text });
|
|
104
|
-
|
|
112
|
+
_onChangeText(text);
|
|
105
113
|
};
|
|
106
114
|
|
|
107
115
|
useImperativeHandle(ref, () => {
|
|
108
116
|
return {
|
|
109
|
-
clear:
|
|
117
|
+
clear: onClearText,
|
|
110
118
|
focus: () => inputRef.current?.focus(),
|
|
111
119
|
blur: () => inputRef.current?.blur(),
|
|
112
|
-
setText:
|
|
120
|
+
setText: _setText,
|
|
113
121
|
};
|
|
114
122
|
});
|
|
115
123
|
|
|
@@ -117,9 +125,13 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
117
125
|
if (typingData && typingData?.length > 0) {
|
|
118
126
|
return (
|
|
119
127
|
<TouchableOpacity
|
|
120
|
-
style={[
|
|
128
|
+
style={[
|
|
129
|
+
styles.searchInput,
|
|
130
|
+
styles.searchInputTyping,
|
|
131
|
+
inputHeightStyle,
|
|
132
|
+
]}
|
|
121
133
|
onPress={onPress}
|
|
122
|
-
activeOpacity={onPress ?
|
|
134
|
+
activeOpacity={onPress ? 0.6 : 1}
|
|
123
135
|
>
|
|
124
136
|
<TextTyping data={typingData} />
|
|
125
137
|
</TouchableOpacity>
|
|
@@ -135,6 +147,7 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
135
147
|
ref={inputRef}
|
|
136
148
|
style={[
|
|
137
149
|
styles.searchInput,
|
|
150
|
+
inputHeightStyle,
|
|
138
151
|
{
|
|
139
152
|
fontSize: scaledFontSize,
|
|
140
153
|
color: theme.colors.text.default,
|
|
@@ -142,10 +155,10 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
142
155
|
},
|
|
143
156
|
]}
|
|
144
157
|
value={value}
|
|
145
|
-
onChangeText={
|
|
158
|
+
onChangeText={_onChangeText}
|
|
146
159
|
defaultValue={defaultValue}
|
|
147
|
-
onFocus={
|
|
148
|
-
onBlur={
|
|
160
|
+
onFocus={_onFocus}
|
|
161
|
+
onBlur={_onBlur}
|
|
149
162
|
placeholder={placeholder}
|
|
150
163
|
selectionColor={theme.colors.primary}
|
|
151
164
|
placeholderTextColor={theme.colors.text.hint}
|
|
@@ -156,15 +169,15 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
156
169
|
const renderTrailing = () => {
|
|
157
170
|
return (
|
|
158
171
|
<View style={Styles.row}>
|
|
159
|
-
{
|
|
172
|
+
{haveValue && (
|
|
160
173
|
<TouchableOpacity
|
|
161
174
|
style={styles.iconWrapper}
|
|
162
|
-
onPress={
|
|
175
|
+
onPress={onClearText}
|
|
163
176
|
accessibilityLabel={`${componentId}|close-icon-touch`}
|
|
164
177
|
>
|
|
165
178
|
<Icon
|
|
166
179
|
source="24_navigation_close_circle_full"
|
|
167
|
-
size={
|
|
180
|
+
size={16}
|
|
168
181
|
color={theme.colors.text.hint}
|
|
169
182
|
/>
|
|
170
183
|
</TouchableOpacity>
|
|
@@ -195,7 +208,7 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
195
208
|
};
|
|
196
209
|
|
|
197
210
|
let inputState = 'empty';
|
|
198
|
-
if (
|
|
211
|
+
if (focused) {
|
|
199
212
|
inputState = 'focus';
|
|
200
213
|
}
|
|
201
214
|
if (value && value?.length > 0) {
|
|
@@ -228,7 +241,7 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
228
241
|
>
|
|
229
242
|
<Icon
|
|
230
243
|
source={'navigation_search'}
|
|
231
|
-
size={
|
|
244
|
+
size={searchIconSize}
|
|
232
245
|
color={theme.colors.text.hint}
|
|
233
246
|
/>
|
|
234
247
|
{renderInputView()}
|
package/Input/InputTextArea.tsx
CHANGED
|
@@ -12,20 +12,14 @@ import {
|
|
|
12
12
|
TouchableOpacity,
|
|
13
13
|
View,
|
|
14
14
|
} from 'react-native';
|
|
15
|
-
import { setAutomationID, useComponentId } from '../Application';
|
|
16
15
|
import { ApplicationContext, MiniAppContext } from '../Context';
|
|
17
16
|
import { Icon } from '../Icon';
|
|
18
17
|
import { Text, useScaleSize, exportFontFamily } from '../Text';
|
|
19
|
-
import {
|
|
20
|
-
import { ErrorView } from './ErrorView';
|
|
21
|
-
import { FloatingView } from './FloatingView';
|
|
18
|
+
import { ErrorView, FloatingView, getBorderColor, MAX_LENGTH } from './common';
|
|
22
19
|
import { InputTextAreaProps } from './index';
|
|
23
20
|
import styles from './styles';
|
|
24
21
|
import SystemTextInput from './SystemTextInput';
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
const DEFAULT_MAX_LENGTH = 300;
|
|
28
|
-
const DEFAULT_HEIGHT = 104;
|
|
22
|
+
import { setAutomationID, useComponentId } from '../Application';
|
|
29
23
|
|
|
30
24
|
/**
|
|
31
25
|
* Multiline input with floating label, clear icon and a `length/maxLength`
|
|
@@ -46,7 +40,7 @@ const InputTextArea = forwardRef(
|
|
|
46
40
|
defaultValue,
|
|
47
41
|
height,
|
|
48
42
|
placeholder,
|
|
49
|
-
maxLength =
|
|
43
|
+
maxLength = MAX_LENGTH,
|
|
50
44
|
required,
|
|
51
45
|
errorSpacing,
|
|
52
46
|
style,
|
|
@@ -63,12 +57,12 @@ const InputTextArea = forwardRef(
|
|
|
63
57
|
);
|
|
64
58
|
const { theme } = useContext(ApplicationContext);
|
|
65
59
|
const context = useContext<any>(MiniAppContext);
|
|
66
|
-
const
|
|
60
|
+
const DEFAULT_HEIGHT = useScaleSize(104);
|
|
67
61
|
|
|
68
62
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
69
|
-
const scaledFontSize = useScaleSize(
|
|
63
|
+
const scaledFontSize = useScaleSize(14);
|
|
70
64
|
const inputFontFamily = exportFontFamily('regular');
|
|
71
|
-
const [
|
|
65
|
+
const [focused, setFocused] = useState(false);
|
|
72
66
|
const [inputValue, setInputValue] = useState(defaultValue ?? '');
|
|
73
67
|
const inputRef = useRef<TextInput | null>(null);
|
|
74
68
|
|
|
@@ -76,33 +70,33 @@ const InputTextArea = forwardRef(
|
|
|
76
70
|
setInputValue(value ?? '');
|
|
77
71
|
}, [value]);
|
|
78
72
|
|
|
79
|
-
const
|
|
73
|
+
const onClearText = () => {
|
|
80
74
|
inputRef?.current?.clear();
|
|
81
75
|
inputRef.current?.setNativeProps({ text: '' });
|
|
82
|
-
|
|
76
|
+
_onChangeText('');
|
|
83
77
|
};
|
|
84
78
|
|
|
85
|
-
const
|
|
79
|
+
const _onChangeText = (text: string) => {
|
|
86
80
|
onChangeText?.(text);
|
|
87
81
|
setInputValue(text);
|
|
88
82
|
};
|
|
89
83
|
|
|
90
|
-
const
|
|
91
|
-
|
|
84
|
+
const _onFocus = (e: TextInputFocusEvent) => {
|
|
85
|
+
setFocused(true);
|
|
92
86
|
onFocus?.(e);
|
|
93
87
|
};
|
|
94
88
|
|
|
95
|
-
const
|
|
96
|
-
|
|
89
|
+
const _onBlur = (e: TextInputFocusEvent) => {
|
|
90
|
+
setFocused(false);
|
|
97
91
|
onBlur?.(e);
|
|
98
92
|
};
|
|
99
93
|
|
|
100
94
|
useImperativeHandle(ref, () => {
|
|
101
95
|
return {
|
|
102
|
-
clear:
|
|
96
|
+
clear: onClearText,
|
|
103
97
|
focus: () => inputRef.current?.focus(),
|
|
104
98
|
blur: () => inputRef.current?.blur(),
|
|
105
|
-
setText: (text: string) =>
|
|
99
|
+
setText: (text: string) => _onChangeText(text),
|
|
106
100
|
};
|
|
107
101
|
});
|
|
108
102
|
|
|
@@ -135,10 +129,10 @@ const InputTextArea = forwardRef(
|
|
|
135
129
|
style={[
|
|
136
130
|
styles.textAreaWrapper,
|
|
137
131
|
{
|
|
138
|
-
height: height ||
|
|
132
|
+
height: height || DEFAULT_HEIGHT,
|
|
139
133
|
backgroundColor: theme.colors.background.surface,
|
|
140
134
|
},
|
|
141
|
-
getBorderColor(theme,
|
|
135
|
+
getBorderColor(theme, focused, errorMessage, disabled),
|
|
142
136
|
]}
|
|
143
137
|
>
|
|
144
138
|
<FloatingView
|
|
@@ -181,23 +175,23 @@ const InputTextArea = forwardRef(
|
|
|
181
175
|
textBreakStrategy="highQuality"
|
|
182
176
|
multiline={true}
|
|
183
177
|
value={inputValue}
|
|
184
|
-
onChangeText={
|
|
185
|
-
onFocus={
|
|
186
|
-
onBlur={
|
|
178
|
+
onChangeText={_onChangeText}
|
|
179
|
+
onFocus={_onFocus}
|
|
180
|
+
onBlur={_onBlur}
|
|
187
181
|
placeholder={placeholder}
|
|
188
182
|
selectionColor={theme.colors.primary}
|
|
189
183
|
placeholderTextColor={placeholderColor}
|
|
190
184
|
/>
|
|
191
185
|
</View>
|
|
192
|
-
{
|
|
186
|
+
{focused && inputValue.length > 0 && (
|
|
193
187
|
<TouchableOpacity
|
|
194
188
|
style={styles.iconWrapper}
|
|
195
|
-
onPress={
|
|
189
|
+
onPress={onClearText}
|
|
196
190
|
accessibilityLabel={`${componentId}|clear-icon-touch`}
|
|
197
191
|
>
|
|
198
192
|
<Icon
|
|
199
193
|
source="24_navigation_close_circle_full"
|
|
200
|
-
size={
|
|
194
|
+
size={16}
|
|
201
195
|
color={theme.colors.text.hint}
|
|
202
196
|
accessibilityLabel={`${componentId}|clear-icon`}
|
|
203
197
|
/>
|