@momo-kits/foundation 0.169.5 → 0.169.6-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 +8 -8
- package/Application/BottomSheet.parts.tsx +34 -44
- package/Application/BottomSheet.tsx +26 -35
- package/Application/BottomTab/ActiveIndicator.tsx +14 -15
- package/Application/BottomTab/BottomTabBar.styles.ts +18 -1
- package/Application/BottomTab/BottomTabBar.tsx +40 -63
- package/Application/BottomTab/BottomTabInset.tsx +4 -8
- package/Application/BottomTab/CurvedContainer.tsx +20 -16
- package/Application/BottomTab/CustomBottomTabItem.tsx +13 -16
- package/Application/BottomTab/DuoBarCompression.tsx +19 -13
- package/Application/BottomTab/DuoRailTabBar.tsx +13 -17
- package/Application/BottomTab/DuoTabBar.tsx +24 -12
- package/Application/BottomTab/TabBarIcon.tsx +8 -13
- package/Application/BottomTab/TabScreen.tsx +5 -1
- package/Application/BottomTab/index.tsx +30 -38
- package/Application/BottomTab/metrics.ts +46 -24
- package/Application/BottomTab/tabItems.ts +1 -1
- package/Application/BottomTab/usePressLift.ts +2 -2
- package/Application/Components/BackgroundImageView.tsx +0 -4
- package/Application/Components/DuoGlassBackground.tsx +4 -5
- package/Application/Components/HeaderAnimated.tsx +0 -4
- package/Application/Components/HeaderBackground.tsx +0 -4
- package/Application/Components/HeaderExtendHeader.tsx +10 -11
- package/Application/Components/HeaderLeft.tsx +1 -2
- package/Application/Components/HeaderRight.tsx +1 -2
- package/Application/Components/HeaderTitle.shared.ts +9 -11
- package/Application/Components/HeaderTitle.tsx +3 -4
- package/Application/Components/HeaderToolkitAction.tsx +20 -17
- package/Application/Components/NavigationButton.tsx +1 -2
- package/Application/Components/SearchHeader.tsx +10 -17
- package/Application/Components/TitleJourney.tsx +2 -2
- package/Application/Components/TitleLocation.tsx +2 -2
- package/Application/Components/TitleUser.tsx +2 -2
- package/Application/Components/useToolkitActions.tsx +32 -17
- package/Application/Localize.ts +0 -7
- package/Application/ModalScreen.tsx +3 -9
- package/Application/Navigation.ts +16 -14
- package/Application/NavigationContainer.tsx +16 -19
- package/Application/Navigator.ts +48 -20
- package/Application/StackScreen.tracking.ts +26 -11
- package/Application/StackScreen.tsx +35 -8
- package/Application/TooltipPortal.tsx +5 -12
- package/Application/WidgetContainer.tsx +4 -10
- package/Application/__tests__/modalLayout.test.ts +128 -0
- package/Application/modalLayout.ts +14 -13
- package/Application/navigationOptions.tsx +17 -21
- package/Application/types.tabs.ts +0 -1
- package/Badge/Badge.tsx +0 -5
- package/Badge/BadgeDot.tsx +0 -1
- package/Badge/BadgeDotAnimation.tsx +7 -15
- package/Badge/BadgeRibbon.tsx +38 -46
- package/Badge/Shape.tsx +0 -2
- package/Badge/types.ts +2 -2
- package/Button/index.tsx +16 -5
- package/Button/utils.ts +15 -9
- package/CheckBox/index.tsx +0 -4
- package/Consts/theme.ts +10 -10
- package/Context/index.ts +0 -1
- package/Divider/DashDivider.tsx +0 -1
- package/Divider/index.tsx +0 -4
- package/FoundationList/index.tsx +0 -4
- package/Icon/index.tsx +6 -6
- package/Icon/types.ts +1 -1
- package/IconButton/index.tsx +12 -4
- package/Image/index.tsx +7 -9
- package/Input/Input.tsx +9 -8
- package/Input/InputDropDown.tsx +12 -10
- package/Input/InputMoney.tsx +8 -12
- package/Input/InputMoneyView.tsx +7 -14
- package/Input/InputOTP.tsx +33 -35
- package/Input/InputPhoneNumber.tsx +9 -8
- package/Input/InputSearch.tsx +6 -4
- package/Input/InputTextArea.tsx +0 -4
- package/Input/SearchTextTyping.tsx +0 -4
- package/Input/SystemTextInput.tsx +2 -7
- package/Input/TextTyping.tsx +0 -4
- package/Input/common.tsx +12 -26
- package/Input/index.tsx +20 -17
- package/Input/moneyUtils.ts +4 -10
- package/Input/styles.ts +5 -0
- package/Input/utils.ts +12 -14
- package/Layout/Card.tsx +4 -7
- package/Layout/FloatingButton.tsx +0 -4
- package/Layout/Item.tsx +2 -6
- package/Layout/ItemList.tsx +7 -9
- package/Layout/ItemSectionList.tsx +1 -2
- package/Layout/ReservedRegions.tsx +25 -25
- package/Layout/Screen.tsx +58 -56
- package/Layout/Section.tsx +5 -8
- package/Layout/TrackingScope.tsx +0 -1
- package/Layout/screenContent.tsx +2 -4
- package/Layout/screenFooter.tsx +18 -28
- package/Layout/screenHeader.tsx +31 -34
- package/Layout/screenQuickReturn.tsx +20 -17
- package/Layout/screenScroll.ts +7 -4
- package/Layout/screenTypes.ts +2 -3
- package/Layout/types.ts +4 -2
- package/Layout/utils.ts +37 -31
- package/Loader/DotLoader.tsx +0 -4
- package/Loader/Loader.tsx +0 -4
- package/Loader/ProgressBar.tsx +0 -1
- package/Loader/Spinner.tsx +0 -4
- package/Loader/utils.ts +7 -11
- package/Pagination/Dot.tsx +0 -4
- package/Pagination/PaginationDot.tsx +0 -1
- package/Pagination/PaginationNumber.tsx +3 -5
- package/Pagination/PaginationScroll.tsx +0 -5
- package/Pagination/PaginationWhiteDot.tsx +0 -1
- package/Pagination/index.tsx +0 -4
- package/Pagination/types.ts +2 -2
- package/Popup/PopupNotify.tsx +48 -44
- package/Popup/PopupPromotion.tsx +7 -4
- package/Popup/types.ts +4 -4
- package/Popup/utils.ts +0 -4
- package/Radio/index.tsx +0 -4
- package/Skeleton/index.tsx +0 -8
- package/Switch/index.tsx +0 -1
- package/Tag/index.tsx +1 -5
- package/Tag/types.ts +3 -3
- package/Text/index.tsx +3 -14
- package/Text/styles.ts +1 -1
- package/Text/types.ts +6 -1
- package/Text/utils.ts +0 -9
- package/Title/index.tsx +32 -41
- package/ViewBoundary/index.tsx +2 -4
- package/index.ts +6 -0
- package/package.json +1 -1
package/Icon/index.tsx
CHANGED
|
@@ -7,10 +7,6 @@ import { Image } from '../Image';
|
|
|
7
7
|
import { StyleSheet } from 'react-native';
|
|
8
8
|
import { Colors } from '../Consts';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Tinted icon from the bundled icon map (unknown names fall back to
|
|
12
|
-
* `ic_warning`) or from a URL. `color={null}` keeps the image's own colors.
|
|
13
|
-
*/
|
|
14
10
|
const Icon: React.FC<IconProps> = ({
|
|
15
11
|
source = 'ic_back',
|
|
16
12
|
size = 24,
|
|
@@ -23,6 +19,9 @@ const Icon: React.FC<IconProps> = ({
|
|
|
23
19
|
|
|
24
20
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
25
21
|
|
|
22
|
+
/**
|
|
23
|
+
* get icon source maps or remote http
|
|
24
|
+
*/
|
|
26
25
|
const getIconSource = (): any => {
|
|
27
26
|
if (source && !source.includes('http')) {
|
|
28
27
|
let icon: { [key: string]: { uri: string } } = IconSources;
|
|
@@ -31,8 +30,9 @@ const Icon: React.FC<IconProps> = ({
|
|
|
31
30
|
return { uri: source };
|
|
32
31
|
};
|
|
33
32
|
|
|
34
|
-
const
|
|
35
|
-
|
|
33
|
+
const tintColorProps = color !== null && {
|
|
34
|
+
tintColor: color ?? theme.colors.text.default,
|
|
35
|
+
};
|
|
36
36
|
|
|
37
37
|
return (
|
|
38
38
|
<Image
|
package/Icon/types.ts
CHANGED
package/IconButton/index.tsx
CHANGED
|
@@ -41,10 +41,6 @@ export interface IconButtonProps extends TouchableOpacityProps {
|
|
|
41
41
|
params?: any;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
/**
|
|
45
|
-
* Icon-only button. `type` sets the background and icon color; `'disabled'`
|
|
46
|
-
* also blocks presses.
|
|
47
|
-
*/
|
|
48
44
|
const IconButton: React.FC<IconButtonProps> = ({
|
|
49
45
|
type = 'primary',
|
|
50
46
|
icon,
|
|
@@ -58,6 +54,9 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
58
54
|
|
|
59
55
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
60
56
|
|
|
57
|
+
/**
|
|
58
|
+
* get size icon button
|
|
59
|
+
*/
|
|
61
60
|
const getSizeStyle = () => {
|
|
62
61
|
switch (size) {
|
|
63
62
|
case 'small':
|
|
@@ -69,10 +68,16 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
69
68
|
}
|
|
70
69
|
};
|
|
71
70
|
|
|
71
|
+
/**
|
|
72
|
+
* get shape icon button
|
|
73
|
+
*/
|
|
72
74
|
const getShapeStyle = () => {
|
|
73
75
|
return shape === 'square' ? styles.square : styles.circle;
|
|
74
76
|
};
|
|
75
77
|
|
|
78
|
+
/**
|
|
79
|
+
* get style for icon button by type
|
|
80
|
+
*/
|
|
76
81
|
const getTypeStyle = () => {
|
|
77
82
|
switch (type) {
|
|
78
83
|
case 'disabled':
|
|
@@ -106,6 +111,9 @@ const IconButton: React.FC<IconButtonProps> = ({
|
|
|
106
111
|
}
|
|
107
112
|
};
|
|
108
113
|
|
|
114
|
+
/**
|
|
115
|
+
* get color for icon
|
|
116
|
+
*/
|
|
109
117
|
const getIconColor = () => {
|
|
110
118
|
switch (type) {
|
|
111
119
|
case 'disabled':
|
package/Image/index.tsx
CHANGED
|
@@ -15,7 +15,6 @@ import { ImageProps } from './types';
|
|
|
15
15
|
|
|
16
16
|
type Status = 'success' | 'loading' | 'error';
|
|
17
17
|
|
|
18
|
-
/** Last path segment of a `{ uri }` source, used in QA labels; '' otherwise. */
|
|
19
18
|
export const getImageName = (source: any): string => {
|
|
20
19
|
const parts = source?.uri?.split?.('/');
|
|
21
20
|
if (parts?.length > 0) {
|
|
@@ -24,10 +23,6 @@ export const getImageName = (source: any): string => {
|
|
|
24
23
|
return '';
|
|
25
24
|
};
|
|
26
25
|
|
|
27
|
-
/**
|
|
28
|
-
* FastImage that shows a skeleton while loading (if `loading`) or inside a
|
|
29
|
-
* loading `SkeletonProvider`, and a fail icon on error.
|
|
30
|
-
*/
|
|
31
26
|
const Image: React.FC<ImageProps> = ({
|
|
32
27
|
style,
|
|
33
28
|
source,
|
|
@@ -49,12 +44,15 @@ const Image: React.FC<ImageProps> = ({
|
|
|
49
44
|
|
|
50
45
|
const showBaseLineDebug = context?.features?.showBaseLineDebug ?? false;
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
let accessibilityLabel: any = `img|${imageName}`;
|
|
47
|
+
let accessibilityLabel: any = `img|${getImageName(source)}`;
|
|
54
48
|
if (component?.componentId) {
|
|
55
|
-
accessibilityLabel = `${component?.componentId}|img|${
|
|
49
|
+
accessibilityLabel = `${component?.componentId}|img|${getImageName(
|
|
50
|
+
source,
|
|
51
|
+
)}`;
|
|
56
52
|
}
|
|
57
|
-
|
|
53
|
+
/**
|
|
54
|
+
* render content loading | fail | rendered
|
|
55
|
+
*/
|
|
58
56
|
const renderContent = () => {
|
|
59
57
|
if (status === 'loading' || status === 'error') {
|
|
60
58
|
let content = <Skeleton />;
|
package/Input/Input.tsx
CHANGED
|
@@ -31,8 +31,7 @@ import {
|
|
|
31
31
|
} from '../Context';
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
* hint row; controlled via `value` or uncontrolled via `defaultValue`.
|
|
34
|
+
* Input default component
|
|
36
35
|
*/
|
|
37
36
|
const Input = forwardRef(
|
|
38
37
|
(
|
|
@@ -132,17 +131,15 @@ const Input = forwardRef(
|
|
|
132
131
|
};
|
|
133
132
|
});
|
|
134
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Render input view
|
|
136
|
+
*/
|
|
135
137
|
const renderInputView = () => {
|
|
136
138
|
const disabledColor = theme.colors.text.disable;
|
|
137
139
|
const secure = secureTextEntry;
|
|
138
140
|
let textColor = theme.colors.text.default;
|
|
139
141
|
let placeholderColor = theme.colors.text.hint;
|
|
140
142
|
let iconTintColor = trailingColor;
|
|
141
|
-
let secureTextStyle = styles.secureTextLarge;
|
|
142
|
-
|
|
143
|
-
if (size === 'small') {
|
|
144
|
-
secureTextStyle = styles.secureTextSmall;
|
|
145
|
-
}
|
|
146
143
|
|
|
147
144
|
if (disabled) {
|
|
148
145
|
textColor = disabledColor;
|
|
@@ -202,7 +199,11 @@ const Input = forwardRef(
|
|
|
202
199
|
color: textColor,
|
|
203
200
|
fontFamily: exportFontFamily(fontWeight ?? 'regular'),
|
|
204
201
|
},
|
|
205
|
-
secure &&
|
|
202
|
+
secure &&
|
|
203
|
+
haveValue &&
|
|
204
|
+
(size === 'small'
|
|
205
|
+
? styles.secureTextSmall
|
|
206
|
+
: styles.secureTextLarge),
|
|
206
207
|
]}
|
|
207
208
|
defaultValue={defaultValue}
|
|
208
209
|
allowFontScaling={false}
|
package/Input/InputDropDown.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useContext } from 'react';
|
|
2
|
-
import { TouchableOpacity, View
|
|
2
|
+
import { TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import { useComponentId } from '../Application';
|
|
4
4
|
import {
|
|
5
5
|
ApplicationContext,
|
|
@@ -18,10 +18,6 @@ import { Text, useScaleSize } from '../Text';
|
|
|
18
18
|
import styles from './styles';
|
|
19
19
|
import { Spacing } from '../Consts';
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
* Pressable field styled like an input with a chevron; shows `value` or
|
|
23
|
-
* `placeholder`. Opening the picker is left to `onPress`.
|
|
24
|
-
*/
|
|
25
21
|
const InputDropDown = ({
|
|
26
22
|
value,
|
|
27
23
|
floatingValue,
|
|
@@ -54,19 +50,18 @@ const InputDropDown = ({
|
|
|
54
50
|
props.accessibilityLabel,
|
|
55
51
|
);
|
|
56
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Render the input view
|
|
55
|
+
*/
|
|
57
56
|
const renderInputView = () => {
|
|
58
57
|
const disabledColor = theme.colors.text.disable;
|
|
59
58
|
let textColor = theme.colors.text.default;
|
|
60
59
|
let placeholderColor = theme.colors.text.hint;
|
|
61
|
-
let chevronStyle: ViewStyle = styles.iconViewDropDownSingle;
|
|
62
60
|
|
|
63
61
|
if (disabled) {
|
|
64
62
|
textColor = disabledColor;
|
|
65
63
|
placeholderColor = disabledColor;
|
|
66
64
|
}
|
|
67
|
-
if (multiline) {
|
|
68
|
-
chevronStyle = styles.iconViewDropDownMultiline;
|
|
69
|
-
}
|
|
70
65
|
|
|
71
66
|
return (
|
|
72
67
|
<View
|
|
@@ -116,7 +111,14 @@ const InputDropDown = ({
|
|
|
116
111
|
</Text>
|
|
117
112
|
</View>
|
|
118
113
|
</View>
|
|
119
|
-
<View
|
|
114
|
+
<View
|
|
115
|
+
style={[
|
|
116
|
+
styles.iconViewDropDown,
|
|
117
|
+
multiline
|
|
118
|
+
? styles.iconViewDropDownMultiline
|
|
119
|
+
: styles.iconViewDropDownSingle,
|
|
120
|
+
]}
|
|
121
|
+
>
|
|
120
122
|
<Icon source={'arrow_chevron_down_small'} />
|
|
121
123
|
</View>
|
|
122
124
|
</View>
|
package/Input/InputMoney.tsx
CHANGED
|
@@ -16,11 +16,6 @@ import { InputMoneyView } from './InputMoneyView';
|
|
|
16
16
|
import { findEdit, moneyFormatter } from './moneyUtils';
|
|
17
17
|
import styles from './styles';
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
* Money input: keeps digits only, shows them grouped with a currency suffix and
|
|
21
|
-
* reports raw digits to `onChangeText`. On Android it restores the caret by the
|
|
22
|
-
* count of digits after it, since regrouping shifts positions.
|
|
23
|
-
*/
|
|
24
19
|
const InputMoney = forwardRef(
|
|
25
20
|
(
|
|
26
21
|
{
|
|
@@ -93,9 +88,9 @@ const InputMoney = forwardRef(
|
|
|
93
88
|
|
|
94
89
|
useEffect(() => {
|
|
95
90
|
if (!caretSelection) return;
|
|
96
|
-
setCaretSelection(current =>
|
|
97
|
-
|
|
98
|
-
|
|
91
|
+
setCaretSelection(current =>
|
|
92
|
+
current === caretSelection ? undefined : current,
|
|
93
|
+
);
|
|
99
94
|
}, [caretSelection]);
|
|
100
95
|
|
|
101
96
|
const updateDisplayValue = (numeric: string) => {
|
|
@@ -147,10 +142,11 @@ const InputMoney = forwardRef(
|
|
|
147
142
|
lastRawText.current = text;
|
|
148
143
|
const formattedEdit = findEdit(lastDisplayValue, text);
|
|
149
144
|
const rawEdit = findEdit(raw, text);
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
const { old, start, suffix } =
|
|
146
|
+
raw && rawEdit.size < formattedEdit.size ? rawEdit : formattedEdit;
|
|
147
|
+
caretDigitsAfter.current = parseInputText(
|
|
148
|
+
text.slice(text.length - suffix),
|
|
149
|
+
).length;
|
|
154
150
|
if (text.length < old.length && digits === numericValue) {
|
|
155
151
|
const index = parseInputText(text.slice(0, start)).length - 1;
|
|
156
152
|
if (index >= 0) {
|
package/Input/InputMoneyView.tsx
CHANGED
|
@@ -52,10 +52,6 @@ type InputMoneyViewProps = Pick<
|
|
|
52
52
|
inputProps: TextInputProps;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
/**
|
|
56
|
-
* Presentational body of InputMoney: bordered field, currency suffix (kept
|
|
57
|
-
* after a placeholder that ends with it) and the clear/trailing icons.
|
|
58
|
-
*/
|
|
59
55
|
export const InputMoneyView = ({
|
|
60
56
|
size,
|
|
61
57
|
errorMessage,
|
|
@@ -102,12 +98,9 @@ export const InputMoneyView = ({
|
|
|
102
98
|
fontFamily: inputFontFamily,
|
|
103
99
|
};
|
|
104
100
|
const placeholderHasCurrency = placeholder.endsWith(currency);
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (placeholderHasCurrency) {
|
|
109
|
-
inputPlaceholder = placeholder.slice(0, -currency.length);
|
|
110
|
-
}
|
|
101
|
+
const inputPlaceholder = placeholderHasCurrency
|
|
102
|
+
? placeholder.slice(0, -currency.length)
|
|
103
|
+
: placeholder;
|
|
111
104
|
return (
|
|
112
105
|
<View
|
|
113
106
|
style={[
|
|
@@ -154,7 +147,7 @@ export const InputMoneyView = ({
|
|
|
154
147
|
keyboardType={'numeric'}
|
|
155
148
|
maxLength={undefined}
|
|
156
149
|
/>
|
|
157
|
-
{
|
|
150
|
+
{displayValue || placeholderHasCurrency ? (
|
|
158
151
|
<Text
|
|
159
152
|
style={[
|
|
160
153
|
textStyle,
|
|
@@ -164,10 +157,10 @@ export const InputMoneyView = ({
|
|
|
164
157
|
>
|
|
165
158
|
{currency}
|
|
166
159
|
</Text>
|
|
167
|
-
)}
|
|
160
|
+
) : null}
|
|
168
161
|
</Pressable>
|
|
169
162
|
<View style={styles.iconView}>
|
|
170
|
-
{
|
|
163
|
+
{showClearIcon && focused && displayValue ? (
|
|
171
164
|
<TouchableOpacity
|
|
172
165
|
accessibilityLabel={`${componentId}|clear-icon-touch`}
|
|
173
166
|
style={styles.iconWrapper}
|
|
@@ -180,7 +173,7 @@ export const InputMoneyView = ({
|
|
|
180
173
|
accessibilityLabel={`${componentId}|clear-icon`}
|
|
181
174
|
/>
|
|
182
175
|
</TouchableOpacity>
|
|
183
|
-
)}
|
|
176
|
+
) : null}
|
|
184
177
|
<RenderTrailing
|
|
185
178
|
color={iconTintColor}
|
|
186
179
|
icon={trailing}
|
package/Input/InputOTP.tsx
CHANGED
|
@@ -38,7 +38,6 @@ import {
|
|
|
38
38
|
MiniAppContext,
|
|
39
39
|
} from '../Context';
|
|
40
40
|
|
|
41
|
-
/** Blinking caret shown in the OTP slot being typed. */
|
|
42
41
|
const OTPCaret: FC<CaretProps> = ({ index, length }) => {
|
|
43
42
|
const DURATION = 300;
|
|
44
43
|
const { theme } = useContext(ApplicationContext);
|
|
@@ -61,7 +60,9 @@ const OTPCaret: FC<CaretProps> = ({ index, length }) => {
|
|
|
61
60
|
};
|
|
62
61
|
}, [opacity]);
|
|
63
62
|
|
|
64
|
-
const animatedStyle = useAnimatedStyle(() => ({
|
|
63
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
64
|
+
opacity: opacity.value,
|
|
65
|
+
}));
|
|
65
66
|
|
|
66
67
|
const hasNextInput = !isNaN(Number(length)) && index !== Number(length) - 1;
|
|
67
68
|
const spacingStyle = hasNextInput && { marginRight: Spacing.L };
|
|
@@ -85,10 +86,6 @@ const OTPCaret: FC<CaretProps> = ({ index, length }) => {
|
|
|
85
86
|
);
|
|
86
87
|
};
|
|
87
88
|
|
|
88
|
-
/**
|
|
89
|
-
* OTP input: a hidden TextInput drives `length` slots (or a free-length row
|
|
90
|
-
* when `length` is unset) with a blinking caret; accepts at most 10 chars.
|
|
91
|
-
*/
|
|
92
89
|
const InputOTP = forwardRef(
|
|
93
90
|
(
|
|
94
91
|
{
|
|
@@ -124,16 +121,14 @@ const InputOTP = forwardRef(
|
|
|
124
121
|
props.accessibilityLabel,
|
|
125
122
|
);
|
|
126
123
|
|
|
127
|
-
useImperativeHandle(ref, () => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
};
|
|
136
|
-
});
|
|
124
|
+
useImperativeHandle(ref, () => ({
|
|
125
|
+
onChangeText: (text: string) => {
|
|
126
|
+
_onChangeText(text);
|
|
127
|
+
},
|
|
128
|
+
focus: () => inputRef.current?.focus(),
|
|
129
|
+
blur: () => inputRef.current?.blur(),
|
|
130
|
+
setText: (text: string) => _onChangeText(text),
|
|
131
|
+
}));
|
|
137
132
|
|
|
138
133
|
const onFocusInput = (e: TextInputFocusEvent) => {
|
|
139
134
|
setFocused(true);
|
|
@@ -147,10 +142,13 @@ const InputOTP = forwardRef(
|
|
|
147
142
|
|
|
148
143
|
const _onChangeText = (text: string) => {
|
|
149
144
|
if (text.length > MAX_LENGTH) return;
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
if (dataType === 'number' && isNaN(Number(text))) return;
|
|
146
|
+
if (
|
|
147
|
+
!isNaN(Number(text)) &&
|
|
148
|
+
value.length >= Number(length) &&
|
|
149
|
+
text.length >= value.length
|
|
150
|
+
)
|
|
151
|
+
return;
|
|
154
152
|
|
|
155
153
|
setValue(text);
|
|
156
154
|
onChangeText?.(text);
|
|
@@ -166,21 +164,21 @@ const InputOTP = forwardRef(
|
|
|
166
164
|
const TextInputs: React.ReactNode[] = [];
|
|
167
165
|
const textColors = theme.colors.text;
|
|
168
166
|
for (let i = 0; i < inputLength; i++) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
167
|
+
TextInputs.push(
|
|
168
|
+
<View key={`otp-input-${i}`}>
|
|
169
|
+
{focused && value.length === i ? (
|
|
170
|
+
<OTPCaret index={i} length={inputLength} />
|
|
171
|
+
) : (
|
|
172
|
+
<Text
|
|
173
|
+
style={i !== inputLength - 1 && { marginRight: Spacing.L }}
|
|
174
|
+
color={value[i] ? textColors.default : textColors.hint}
|
|
175
|
+
typography={value[i] ? 'header_m_bold' : 'body_default_regular'}
|
|
176
|
+
>
|
|
177
|
+
{value[i] || '-'}
|
|
178
|
+
</Text>
|
|
179
|
+
)}
|
|
180
|
+
</View>,
|
|
181
|
+
);
|
|
184
182
|
}
|
|
185
183
|
return TextInputs;
|
|
186
184
|
};
|
|
@@ -34,8 +34,7 @@ import { Image } from '../Image';
|
|
|
34
34
|
import { Typography } from '../Text/types';
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
38
|
-
* by default, plus clear and trailing icons.
|
|
37
|
+
* Input default component
|
|
39
38
|
*/
|
|
40
39
|
const InputPhoneNumber = forwardRef(
|
|
41
40
|
(
|
|
@@ -147,6 +146,9 @@ const InputPhoneNumber = forwardRef(
|
|
|
147
146
|
typography = 'header_m_bold';
|
|
148
147
|
}
|
|
149
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Render input view
|
|
151
|
+
*/
|
|
150
152
|
const renderInputView = () => {
|
|
151
153
|
const disabledColor = theme.colors.text.disable;
|
|
152
154
|
const secure = secureTextEntry;
|
|
@@ -154,11 +156,6 @@ const InputPhoneNumber = forwardRef(
|
|
|
154
156
|
let placeholderColor = theme.colors.text.hint;
|
|
155
157
|
let iconTintColor = trailingColor ?? theme.colors.text.default;
|
|
156
158
|
const borderWidth = focused ? 1.5 : 1;
|
|
157
|
-
let secureTextStyle = styles.secureTextLarge;
|
|
158
|
-
|
|
159
|
-
if (size === 'small') {
|
|
160
|
-
secureTextStyle = styles.secureTextSmall;
|
|
161
|
-
}
|
|
162
159
|
|
|
163
160
|
if (disabled) {
|
|
164
161
|
textColor = disabledColor;
|
|
@@ -217,7 +214,11 @@ const InputPhoneNumber = forwardRef(
|
|
|
217
214
|
color: textColor,
|
|
218
215
|
},
|
|
219
216
|
inputTextStyles,
|
|
220
|
-
secure &&
|
|
217
|
+
secure &&
|
|
218
|
+
haveValue &&
|
|
219
|
+
(size === 'small'
|
|
220
|
+
? styles.secureTextSmall
|
|
221
|
+
: styles.secureTextLarge),
|
|
221
222
|
]}
|
|
222
223
|
defaultValue={defaultValue}
|
|
223
224
|
allowFontScaling={false}
|
package/Input/InputSearch.tsx
CHANGED
|
@@ -26,10 +26,6 @@ import styles from './styles';
|
|
|
26
26
|
import { Styles } from '../Consts';
|
|
27
27
|
import SystemTextInput from './SystemTextInput';
|
|
28
28
|
|
|
29
|
-
/**
|
|
30
|
-
* Search field with search icon, clear icon, optional trailing icon and a
|
|
31
|
-
* cancel button; with `typingData` it shows an animated placeholder instead.
|
|
32
|
-
*/
|
|
33
29
|
const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
34
30
|
{
|
|
35
31
|
placeholder,
|
|
@@ -110,6 +106,9 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
110
106
|
};
|
|
111
107
|
});
|
|
112
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Render the input view
|
|
111
|
+
*/
|
|
113
112
|
const renderInputView = () => {
|
|
114
113
|
if (typingData && typingData?.length > 0) {
|
|
115
114
|
return (
|
|
@@ -150,6 +149,9 @@ const InputSearch: ForwardRefRenderFunction<InputRef, InputSearchProps> = (
|
|
|
150
149
|
);
|
|
151
150
|
};
|
|
152
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Render trailing icon or text
|
|
154
|
+
*/
|
|
153
155
|
const renderTrailing = () => {
|
|
154
156
|
return (
|
|
155
157
|
<View style={Styles.row}>
|
package/Input/InputTextArea.tsx
CHANGED
|
@@ -21,10 +21,6 @@ import styles from './styles';
|
|
|
21
21
|
import SystemTextInput from './SystemTextInput';
|
|
22
22
|
import { setAutomationID, useComponentId } from '../Application';
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* Multiline input with floating label, clear icon and a `length/maxLength`
|
|
26
|
-
* counter; the ref exposes clear, focus, blur and setText.
|
|
27
|
-
*/
|
|
28
24
|
const InputTextArea = forwardRef(
|
|
29
25
|
(
|
|
30
26
|
{
|
|
@@ -4,10 +4,6 @@ import { TextInput } from 'react-native';
|
|
|
4
4
|
import { useScaleSize, exportFontFamily } from '../Text';
|
|
5
5
|
import styles from './styles';
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Animated search placeholder: types each string of `data` char by char, then
|
|
9
|
-
* erases it, looping forever. Writes via setNativeProps to avoid re-renders.
|
|
10
|
-
*/
|
|
11
7
|
export const TextTyping: FC<any> = ({
|
|
12
8
|
data = [],
|
|
13
9
|
timeDelayEnd = 2000,
|
|
@@ -11,16 +11,11 @@ interface SystemTextInputProps extends TextInputProps {
|
|
|
11
11
|
ref?: React.RefObject<TextInput | null>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* TextInput that still fires onPressIn/onPressOut when not editable on
|
|
16
|
-
* Android, by moving them to a wrapping touchable.
|
|
17
|
-
*/
|
|
18
14
|
const SystemTextInput: FC<SystemTextInputProps> = props => {
|
|
19
15
|
const { editable, onPressIn, onPressOut, ref } = props;
|
|
20
16
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
const needsAndroidWrapper = isAndroidReadOnly && hasPressHandler;
|
|
17
|
+
const needsAndroidWrapper =
|
|
18
|
+
Platform.OS === 'android' && !editable && (onPressIn || onPressOut);
|
|
24
19
|
|
|
25
20
|
const noPressHandlers = { onPressIn: undefined, onPressOut: undefined };
|
|
26
21
|
const inputProps: TextInputProps = {
|
package/Input/TextTyping.tsx
CHANGED
|
@@ -11,10 +11,6 @@ export interface TextTypingProps {
|
|
|
11
11
|
inputStyle?: TextStyle;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* Typing placeholder: types each string of `data` char by char, then erases
|
|
16
|
-
* it, looping forever. Writes via setNativeProps to avoid re-renders.
|
|
17
|
-
*/
|
|
18
14
|
const TextTyping: FC<TextTypingProps> = ({
|
|
19
15
|
data = [],
|
|
20
16
|
timeDelayEnd = 2000,
|
package/Input/common.tsx
CHANGED
|
@@ -35,7 +35,6 @@ type TrailingProps = {
|
|
|
35
35
|
|
|
36
36
|
export const MAX_LENGTH = 300;
|
|
37
37
|
|
|
38
|
-
/** Border color by state; priority is disabled > error > focused > default. */
|
|
39
38
|
export const getBorderColor = (
|
|
40
39
|
theme: Theme,
|
|
41
40
|
focused: boolean,
|
|
@@ -59,10 +58,6 @@ export const getBorderColor = (
|
|
|
59
58
|
return { borderColor };
|
|
60
59
|
};
|
|
61
60
|
|
|
62
|
-
/**
|
|
63
|
-
* Container style for `size`; multiline uses `height` as minHeight so the
|
|
64
|
-
* field can grow with its content.
|
|
65
|
-
*/
|
|
66
61
|
export const getSizeStyle = (
|
|
67
62
|
size?: 'small' | 'large',
|
|
68
63
|
multiline: boolean = false,
|
|
@@ -73,14 +68,13 @@ export const getSizeStyle = (
|
|
|
73
68
|
scaleStyle = { height };
|
|
74
69
|
}
|
|
75
70
|
|
|
76
|
-
if (multiline)
|
|
71
|
+
if (multiline)
|
|
77
72
|
return [
|
|
78
73
|
styles.multilineContainer,
|
|
79
74
|
{
|
|
80
75
|
minHeight: height,
|
|
81
76
|
},
|
|
82
77
|
];
|
|
83
|
-
}
|
|
84
78
|
|
|
85
79
|
if (size === 'small') {
|
|
86
80
|
return [styles.smallContainer, scaleStyle];
|
|
@@ -88,10 +82,6 @@ export const getSizeStyle = (
|
|
|
88
82
|
return [styles.container, scaleStyle];
|
|
89
83
|
};
|
|
90
84
|
|
|
91
|
-
/**
|
|
92
|
-
* Error or hint row under an input (error wins); with neither, `errorSpacing`
|
|
93
|
-
* keeps an empty row so the layout doesn't jump when an error appears.
|
|
94
|
-
*/
|
|
95
85
|
export const ErrorView: FC<{
|
|
96
86
|
errorMessage?: string;
|
|
97
87
|
errorSpacing?: boolean;
|
|
@@ -105,17 +95,21 @@ export const ErrorView: FC<{
|
|
|
105
95
|
const scaledIconSize = useScaleSize(16);
|
|
106
96
|
|
|
107
97
|
if (errorMessage || hintText) {
|
|
108
|
-
const messageColor = errorMessage ? errorColor : hintColor;
|
|
109
|
-
const messageType = errorMessage ? 'error' : 'hint';
|
|
110
98
|
return (
|
|
111
99
|
<View style={styles.errorView}>
|
|
112
100
|
<View style={styles.errorIcon}>
|
|
113
|
-
<Icon
|
|
101
|
+
<Icon
|
|
102
|
+
color={errorMessage ? errorColor : hintColor}
|
|
103
|
+
source="ic_error"
|
|
104
|
+
size={scaledIconSize}
|
|
105
|
+
/>
|
|
114
106
|
</View>
|
|
115
107
|
<Text
|
|
116
|
-
accessibilityLabel={`${componentId}|${
|
|
108
|
+
accessibilityLabel={`${componentId}|${
|
|
109
|
+
errorMessage ? 'error' : 'hint'
|
|
110
|
+
}-text`}
|
|
117
111
|
style={Styles.flex}
|
|
118
|
-
color={
|
|
112
|
+
color={errorMessage ? errorColor : hintColor}
|
|
119
113
|
typography={'description_default_regular'}
|
|
120
114
|
>
|
|
121
115
|
{errorMessage ?? hintTextDefault}
|
|
@@ -129,10 +123,6 @@ export const ErrorView: FC<{
|
|
|
129
123
|
return <View />;
|
|
130
124
|
};
|
|
131
125
|
|
|
132
|
-
/**
|
|
133
|
-
* Floating label on the input's top border with a required `*` and an
|
|
134
|
-
* optional pressable icon; renders nothing without `floatingValue`.
|
|
135
|
-
*/
|
|
136
126
|
export const FloatingView: FC<FloatingViewProps> = ({
|
|
137
127
|
floatingValue,
|
|
138
128
|
floatingIconColor,
|
|
@@ -201,10 +191,6 @@ export const FloatingView: FC<FloatingViewProps> = ({
|
|
|
201
191
|
return null;
|
|
202
192
|
};
|
|
203
193
|
|
|
204
|
-
/**
|
|
205
|
-
* Trailing slot: spinner while `loading`, an icon when `icon` is a known icon
|
|
206
|
-
* name or URL, otherwise `icon` as a text action (first 15 chars).
|
|
207
|
-
*/
|
|
208
194
|
export const RenderTrailing: FC<TrailingProps> = ({
|
|
209
195
|
loading,
|
|
210
196
|
color,
|
|
@@ -218,8 +204,8 @@ export const RenderTrailing: FC<TrailingProps> = ({
|
|
|
218
204
|
}
|
|
219
205
|
|
|
220
206
|
if (icon) {
|
|
221
|
-
const
|
|
222
|
-
|
|
207
|
+
const isIcon =
|
|
208
|
+
(IconSources as any)?.[icon as string]?.uri || icon?.includes('http');
|
|
223
209
|
const renderIconTouchable = (content: ReactNode) => {
|
|
224
210
|
return (
|
|
225
211
|
<TouchableOpacity
|