@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.
Files changed (127) hide show
  1. package/Application/BottomSheet.hooks.ts +8 -8
  2. package/Application/BottomSheet.parts.tsx +34 -44
  3. package/Application/BottomSheet.tsx +26 -35
  4. package/Application/BottomTab/ActiveIndicator.tsx +14 -15
  5. package/Application/BottomTab/BottomTabBar.styles.ts +18 -1
  6. package/Application/BottomTab/BottomTabBar.tsx +40 -63
  7. package/Application/BottomTab/BottomTabInset.tsx +4 -8
  8. package/Application/BottomTab/CurvedContainer.tsx +20 -16
  9. package/Application/BottomTab/CustomBottomTabItem.tsx +13 -16
  10. package/Application/BottomTab/DuoBarCompression.tsx +19 -13
  11. package/Application/BottomTab/DuoRailTabBar.tsx +13 -17
  12. package/Application/BottomTab/DuoTabBar.tsx +24 -12
  13. package/Application/BottomTab/TabBarIcon.tsx +8 -13
  14. package/Application/BottomTab/TabScreen.tsx +5 -1
  15. package/Application/BottomTab/index.tsx +30 -38
  16. package/Application/BottomTab/metrics.ts +46 -24
  17. package/Application/BottomTab/tabItems.ts +1 -1
  18. package/Application/BottomTab/usePressLift.ts +2 -2
  19. package/Application/Components/BackgroundImageView.tsx +0 -4
  20. package/Application/Components/DuoGlassBackground.tsx +4 -5
  21. package/Application/Components/HeaderAnimated.tsx +0 -4
  22. package/Application/Components/HeaderBackground.tsx +0 -4
  23. package/Application/Components/HeaderExtendHeader.tsx +10 -11
  24. package/Application/Components/HeaderLeft.tsx +1 -2
  25. package/Application/Components/HeaderRight.tsx +1 -2
  26. package/Application/Components/HeaderTitle.shared.ts +9 -11
  27. package/Application/Components/HeaderTitle.tsx +3 -4
  28. package/Application/Components/HeaderToolkitAction.tsx +20 -17
  29. package/Application/Components/NavigationButton.tsx +1 -2
  30. package/Application/Components/SearchHeader.tsx +10 -17
  31. package/Application/Components/TitleJourney.tsx +2 -2
  32. package/Application/Components/TitleLocation.tsx +2 -2
  33. package/Application/Components/TitleUser.tsx +2 -2
  34. package/Application/Components/useToolkitActions.tsx +32 -17
  35. package/Application/Localize.ts +0 -7
  36. package/Application/ModalScreen.tsx +3 -9
  37. package/Application/Navigation.ts +16 -14
  38. package/Application/NavigationContainer.tsx +16 -19
  39. package/Application/Navigator.ts +48 -20
  40. package/Application/StackScreen.tracking.ts +26 -11
  41. package/Application/StackScreen.tsx +35 -8
  42. package/Application/TooltipPortal.tsx +5 -12
  43. package/Application/WidgetContainer.tsx +4 -10
  44. package/Application/__tests__/modalLayout.test.ts +128 -0
  45. package/Application/modalLayout.ts +14 -13
  46. package/Application/navigationOptions.tsx +17 -21
  47. package/Application/types.tabs.ts +0 -1
  48. package/Badge/Badge.tsx +0 -5
  49. package/Badge/BadgeDot.tsx +0 -1
  50. package/Badge/BadgeDotAnimation.tsx +7 -15
  51. package/Badge/BadgeRibbon.tsx +38 -46
  52. package/Badge/Shape.tsx +0 -2
  53. package/Badge/types.ts +2 -2
  54. package/Button/index.tsx +16 -5
  55. package/Button/utils.ts +15 -9
  56. package/CheckBox/index.tsx +0 -4
  57. package/Consts/theme.ts +10 -10
  58. package/Context/index.ts +0 -1
  59. package/Divider/DashDivider.tsx +0 -1
  60. package/Divider/index.tsx +0 -4
  61. package/FoundationList/index.tsx +0 -4
  62. package/Icon/index.tsx +6 -6
  63. package/Icon/types.ts +1 -1
  64. package/IconButton/index.tsx +12 -4
  65. package/Image/index.tsx +7 -9
  66. package/Input/Input.tsx +9 -8
  67. package/Input/InputDropDown.tsx +12 -10
  68. package/Input/InputMoney.tsx +8 -12
  69. package/Input/InputMoneyView.tsx +7 -14
  70. package/Input/InputOTP.tsx +33 -35
  71. package/Input/InputPhoneNumber.tsx +9 -8
  72. package/Input/InputSearch.tsx +6 -4
  73. package/Input/InputTextArea.tsx +0 -4
  74. package/Input/SearchTextTyping.tsx +0 -4
  75. package/Input/SystemTextInput.tsx +2 -7
  76. package/Input/TextTyping.tsx +0 -4
  77. package/Input/common.tsx +12 -26
  78. package/Input/index.tsx +20 -17
  79. package/Input/moneyUtils.ts +4 -10
  80. package/Input/styles.ts +5 -0
  81. package/Input/utils.ts +12 -14
  82. package/Layout/Card.tsx +4 -7
  83. package/Layout/FloatingButton.tsx +0 -4
  84. package/Layout/Item.tsx +2 -6
  85. package/Layout/ItemList.tsx +7 -9
  86. package/Layout/ItemSectionList.tsx +1 -2
  87. package/Layout/ReservedRegions.tsx +25 -25
  88. package/Layout/Screen.tsx +58 -56
  89. package/Layout/Section.tsx +5 -8
  90. package/Layout/TrackingScope.tsx +0 -1
  91. package/Layout/screenContent.tsx +2 -4
  92. package/Layout/screenFooter.tsx +18 -28
  93. package/Layout/screenHeader.tsx +31 -34
  94. package/Layout/screenQuickReturn.tsx +20 -17
  95. package/Layout/screenScroll.ts +7 -4
  96. package/Layout/screenTypes.ts +2 -3
  97. package/Layout/types.ts +4 -2
  98. package/Layout/utils.ts +37 -31
  99. package/Loader/DotLoader.tsx +0 -4
  100. package/Loader/Loader.tsx +0 -4
  101. package/Loader/ProgressBar.tsx +0 -1
  102. package/Loader/Spinner.tsx +0 -4
  103. package/Loader/utils.ts +7 -11
  104. package/Pagination/Dot.tsx +0 -4
  105. package/Pagination/PaginationDot.tsx +0 -1
  106. package/Pagination/PaginationNumber.tsx +3 -5
  107. package/Pagination/PaginationScroll.tsx +0 -5
  108. package/Pagination/PaginationWhiteDot.tsx +0 -1
  109. package/Pagination/index.tsx +0 -4
  110. package/Pagination/types.ts +2 -2
  111. package/Popup/PopupNotify.tsx +48 -44
  112. package/Popup/PopupPromotion.tsx +7 -4
  113. package/Popup/types.ts +4 -4
  114. package/Popup/utils.ts +0 -4
  115. package/Radio/index.tsx +0 -4
  116. package/Skeleton/index.tsx +0 -8
  117. package/Switch/index.tsx +0 -1
  118. package/Tag/index.tsx +1 -5
  119. package/Tag/types.ts +3 -3
  120. package/Text/index.tsx +3 -14
  121. package/Text/styles.ts +1 -1
  122. package/Text/types.ts +6 -1
  123. package/Text/utils.ts +0 -9
  124. package/Title/index.tsx +32 -41
  125. package/ViewBoundary/index.tsx +2 -4
  126. package/index.ts +6 -0
  127. 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 tintColor = color ?? theme.colors.text.default;
35
- const tintColorProps = color !== null && { tintColor };
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
@@ -15,7 +15,7 @@ export type IconProps = {
15
15
  size?: number;
16
16
 
17
17
  /**
18
- * Optional. Represents the color of the icon; `null` keeps the image colors.
18
+ * Optional. Represents the color of the icon.
19
19
  */
20
20
  color?: string | null;
21
21
 
@@ -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
- const imageName = getImageName(source);
53
- let accessibilityLabel: any = `img|${imageName}`;
47
+ let accessibilityLabel: any = `img|${getImageName(source)}`;
54
48
  if (component?.componentId) {
55
- accessibilityLabel = `${component?.componentId}|img|${imageName}`;
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
- * Text input with floating label, leading/trailing/clear icons and an error or
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 && haveValue && secureTextStyle,
202
+ secure &&
203
+ haveValue &&
204
+ (size === 'small'
205
+ ? styles.secureTextSmall
206
+ : styles.secureTextLarge),
206
207
  ]}
207
208
  defaultValue={defaultValue}
208
209
  allowFontScaling={false}
@@ -1,5 +1,5 @@
1
1
  import React, { useContext } from 'react';
2
- import { TouchableOpacity, View, type ViewStyle } from 'react-native';
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 style={[styles.iconViewDropDown, chevronStyle]}>
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>
@@ -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
- return current === caretSelection ? undefined : current;
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 isRawEditSmaller = !!raw && rawEdit.size < formattedEdit.size;
151
- const { old, start, suffix } = isRawEditSmaller ? rawEdit : formattedEdit;
152
- const textAfterEdit = text.slice(text.length - suffix);
153
- caretDigitsAfter.current = parseInputText(textAfterEdit).length;
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) {
@@ -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 shouldShowCurrency = !!displayValue || placeholderHasCurrency;
106
- const shouldShowClearIcon = !!(showClearIcon && focused && displayValue);
107
- let inputPlaceholder = placeholder;
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
- {shouldShowCurrency && (
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
- {shouldShowClearIcon && (
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}
@@ -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(() => ({ opacity: opacity.value }));
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
- return {
129
- onChangeText: (text: string) => {
130
- _onChangeText(text);
131
- },
132
- focus: () => inputRef.current?.focus(),
133
- blur: () => inputRef.current?.blur(),
134
- setText: (text: string) => _onChangeText(text),
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
- const isNumeric = !isNaN(Number(text));
151
- if (dataType === 'number' && !isNumeric) return;
152
- const isFull = value.length >= Number(length);
153
- if (isNumeric && isFull && text.length >= value.length) return;
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
- let slot: React.ReactNode;
170
- if (focused && value.length === i) {
171
- slot = <OTPCaret index={i} length={inputLength} />;
172
- } else {
173
- slot = (
174
- <Text
175
- style={i !== inputLength - 1 && { marginRight: Spacing.L }}
176
- color={value[i] ? textColors.default : textColors.hint}
177
- typography={value[i] ? 'header_m_bold' : 'body_default_regular'}
178
- >
179
- {value[i] || '-'}
180
- </Text>
181
- );
182
- }
183
- TextInputs.push(<View key={`otp-input-${i}`}>{slot}</View>);
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
- * Vietnamese phone number input with a fixed flag and `+84` prefix, number pad
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 && haveValue && secureTextStyle,
217
+ secure &&
218
+ haveValue &&
219
+ (size === 'small'
220
+ ? styles.secureTextSmall
221
+ : styles.secureTextLarge),
221
222
  ]}
222
223
  defaultValue={defaultValue}
223
224
  allowFontScaling={false}
@@ -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}>
@@ -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 isAndroidReadOnly = Platform.OS === 'android' && !editable;
22
- const hasPressHandler = !!(onPressIn || onPressOut);
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 = {
@@ -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 color={messageColor} source="ic_error" size={scaledIconSize} />
101
+ <Icon
102
+ color={errorMessage ? errorColor : hintColor}
103
+ source="ic_error"
104
+ size={scaledIconSize}
105
+ />
114
106
  </View>
115
107
  <Text
116
- accessibilityLabel={`${componentId}|${messageType}-text`}
108
+ accessibilityLabel={`${componentId}|${
109
+ errorMessage ? 'error' : 'hint'
110
+ }-text`}
117
111
  style={Styles.flex}
118
- color={messageColor}
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 isIconName = !!(IconSources as any)?.[icon]?.uri;
222
- const isIcon = isIconName || icon.includes('http');
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