sapo-components-ui-rn 1.0.0

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 (215) hide show
  1. package/README.md +69 -0
  2. package/dist/assets/error.png +0 -0
  3. package/dist/assets/icon-checkbox-active.svg +4 -0
  4. package/dist/assets/icon-checkbox.svg +3 -0
  5. package/dist/assets/image_default.png +0 -0
  6. package/dist/assets/images/error.png +0 -0
  7. package/dist/assets/images/image_default.png +0 -0
  8. package/dist/assets/images/info.png +0 -0
  9. package/dist/assets/images/success.png +0 -0
  10. package/dist/assets/images/warning.png +0 -0
  11. package/dist/assets/info.png +0 -0
  12. package/dist/assets/success.png +0 -0
  13. package/dist/assets/svg/icon-checkbox-active.svg +4 -0
  14. package/dist/assets/svg/icon-checkbox.svg +3 -0
  15. package/dist/assets/warning.png +0 -0
  16. package/dist/components/ActivityIndicator.d.ts +28 -0
  17. package/dist/components/Avatar/index.d.ts +17 -0
  18. package/dist/components/Badge/index.d.ts +13 -0
  19. package/dist/components/Button/index.d.ts +23 -0
  20. package/dist/components/ButtonIcon/index.d.ts +18 -0
  21. package/dist/components/Checkbox/index.d.ts +14 -0
  22. package/dist/components/ChipBar/index.d.ts +16 -0
  23. package/dist/components/CountingDot/index.d.ts +13 -0
  24. package/dist/components/FloatingButton/index.d.ts +17 -0
  25. package/dist/components/Icon/index.d.ts +17 -0
  26. package/dist/components/IconSvg/index.d.ts +12 -0
  27. package/dist/components/Image/index.d.ts +14 -0
  28. package/dist/components/ProgressBar.d.ts +42 -0
  29. package/dist/components/RadioButton/index.d.ts +13 -0
  30. package/dist/components/ScaleButton/index.d.ts +4 -0
  31. package/dist/components/SelectionField/index.d.ts +24 -0
  32. package/dist/components/Spacer/index.d.ts +9 -0
  33. package/dist/components/Switch/Switch.d.ts +47 -0
  34. package/dist/components/Switch/utils.d.ts +14 -0
  35. package/dist/components/Text/index.d.ts +14 -0
  36. package/dist/components/TextInput/Addons/Outline.d.ts +15 -0
  37. package/dist/components/TextInput/Addons/Underline.d.ts +19 -0
  38. package/dist/components/TextInput/Adornment/TextInputAdornment.d.ts +43 -0
  39. package/dist/components/TextInput/Adornment/TextInputAffix.d.ts +72 -0
  40. package/dist/components/TextInput/Adornment/enums.d.ts +12 -0
  41. package/dist/components/TextInput/Adornment/types.d.ts +11 -0
  42. package/dist/components/TextInput/Adornment/utils.d.ts +11 -0
  43. package/dist/components/TextInput/Label/InputLabel.d.ts +4 -0
  44. package/dist/components/TextInput/Label/LabelBackground.d.ts +4 -0
  45. package/dist/components/TextInput/TextInput.d.ts +171 -0
  46. package/dist/components/TextInput/TextInputDefault.d.ts +4 -0
  47. package/dist/components/TextInput/TextInputFlat.d.ts +4 -0
  48. package/dist/components/TextInput/constants.d.ts +31 -0
  49. package/dist/components/TextInput/helpers.d.ts +95 -0
  50. package/dist/components/TextInput/types.d.ts +154 -0
  51. package/dist/components/Toast/ToastProvider.d.ts +21 -0
  52. package/dist/components/Toast/index.d.ts +3 -0
  53. package/dist/components/Typography/AnimatedText.d.ts +34 -0
  54. package/dist/components/Typography/StyledText.d.ts +12 -0
  55. package/dist/components/Typography/Text.d.ts +35 -0
  56. package/dist/components/Typography/types.d.ts +2 -0
  57. package/dist/components/View/index.d.ts +38 -0
  58. package/dist/components/ViewVisibleAnimated/index.d.ts +25 -0
  59. package/dist/constants.d.ts +1 -0
  60. package/dist/core/theming.d.ts +43 -0
  61. package/dist/icons/IconArrowDown.d.ts +4 -0
  62. package/dist/icons/IconCheckbox.d.ts +4 -0
  63. package/dist/icons/IconCheckboxActive.d.ts +4 -0
  64. package/dist/icons/IconClearText.d.ts +4 -0
  65. package/dist/icons/IconRadio.d.ts +4 -0
  66. package/dist/icons/IconRadioActive.d.ts +4 -0
  67. package/dist/icons/IconRadioDisable.d.ts +4 -0
  68. package/dist/index.d.ts +33 -0
  69. package/dist/index.esm.js +6758 -0
  70. package/dist/index.esm.js.map +1 -0
  71. package/dist/index.js +6823 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/styles/fonts.d.ts +78 -0
  74. package/dist/styles/overlay.d.ts +3 -0
  75. package/dist/styles/shadow.d.ts +18 -0
  76. package/dist/styles/themes/DarkTheme.d.ts +2 -0
  77. package/dist/styles/themes/LightTheme.d.ts +2 -0
  78. package/dist/styles/themes/index.d.ts +2 -0
  79. package/dist/styles/themes/tokens.d.ts +830 -0
  80. package/dist/theme/blue.d.ts +14 -0
  81. package/dist/theme/colors.d.ts +99 -0
  82. package/dist/theme/container-styles.d.ts +124 -0
  83. package/dist/theme/dimensions.d.ts +36 -0
  84. package/dist/theme/green.d.ts +15 -0
  85. package/dist/theme/icon.d.ts +5 -0
  86. package/dist/theme/ink.d.ts +11 -0
  87. package/dist/theme/orange.d.ts +14 -0
  88. package/dist/theme/purple.d.ts +6 -0
  89. package/dist/theme/red.d.ts +15 -0
  90. package/dist/theme/themes.d.ts +277 -0
  91. package/dist/theme/white.d.ts +10 -0
  92. package/dist/theme/yellow.d.ts +15 -0
  93. package/dist/types/index.d.ts +65 -0
  94. package/dist/types.d.ts +220 -0
  95. package/dist/utils/BackHandler/BackHandler.d.ts +9 -0
  96. package/dist/utils/BackHandler/BackHandler.native.d.ts +2 -0
  97. package/dist/utils/addEventListener.d.ts +12 -0
  98. package/dist/utils/forwardRef.d.ts +11 -0
  99. package/dist/utils/function-utils.d.ts +12 -0
  100. package/dist/utils/getContrastingColor.d.ts +2 -0
  101. package/dist/utils/hasTouchHandler.d.ts +5 -0
  102. package/dist/utils/roundLayoutSize.d.ts +1 -0
  103. package/dist/utils/splitStyles.d.ts +19 -0
  104. package/dist/utils/toast-manager.d.ts +21 -0
  105. package/dist/utils/useAnimatedValue.d.ts +2 -0
  106. package/dist/utils/useAnimatedValueArray.d.ts +2 -0
  107. package/dist/utils/useIsKeyboardShown.d.ts +6 -0
  108. package/dist/utils/useLayout.d.ts +6 -0
  109. package/dist/utils/useLazyRef.d.ts +2 -0
  110. package/package.json +104 -0
  111. package/src/.DS_Store +0 -0
  112. package/src/assets/images/error.png +0 -0
  113. package/src/assets/images/image_default.png +0 -0
  114. package/src/assets/images/info.png +0 -0
  115. package/src/assets/images/success.png +0 -0
  116. package/src/assets/images/warning.png +0 -0
  117. package/src/assets/svg/icon-checkbox-active.svg +4 -0
  118. package/src/assets/svg/icon-checkbox.svg +3 -0
  119. package/src/babel/.eslintrc +7 -0
  120. package/src/babel/index.js +63 -0
  121. package/src/components/.DS_Store +0 -0
  122. package/src/components/ActivityIndicator.tsx +238 -0
  123. package/src/components/Avatar/index.tsx +102 -0
  124. package/src/components/Badge/index.tsx +55 -0
  125. package/src/components/Button/index.tsx +162 -0
  126. package/src/components/ButtonIcon/index.tsx +98 -0
  127. package/src/components/Checkbox/index.tsx +107 -0
  128. package/src/components/ChipBar/index.tsx +112 -0
  129. package/src/components/CountingDot/index.tsx +63 -0
  130. package/src/components/FloatingButton/index.tsx +99 -0
  131. package/src/components/Icon/index.tsx +135 -0
  132. package/src/components/IconSvg/index.tsx +42 -0
  133. package/src/components/Image/index.tsx +127 -0
  134. package/src/components/ProgressBar.tsx +272 -0
  135. package/src/components/RadioButton/index.tsx +105 -0
  136. package/src/components/ScaleButton/index.tsx +17 -0
  137. package/src/components/SelectionField/index.tsx +166 -0
  138. package/src/components/Spacer/index.tsx +19 -0
  139. package/src/components/Switch/Switch.tsx +110 -0
  140. package/src/components/Switch/utils.ts +96 -0
  141. package/src/components/Text/index.tsx +69 -0
  142. package/src/components/TextInput/.DS_Store +0 -0
  143. package/src/components/TextInput/Addons/Outline.tsx +62 -0
  144. package/src/components/TextInput/Addons/Underline.tsx +71 -0
  145. package/src/components/TextInput/Adornment/TextInputAdornment.tsx +191 -0
  146. package/src/components/TextInput/Adornment/TextInputAffix.tsx +212 -0
  147. package/src/components/TextInput/Adornment/enums.tsx +12 -0
  148. package/src/components/TextInput/Adornment/types.tsx +11 -0
  149. package/src/components/TextInput/Adornment/utils.ts +39 -0
  150. package/src/components/TextInput/Label/InputLabel.tsx +216 -0
  151. package/src/components/TextInput/Label/LabelBackground.tsx +100 -0
  152. package/src/components/TextInput/TextInput.tsx +564 -0
  153. package/src/components/TextInput/TextInputDefault.tsx +187 -0
  154. package/src/components/TextInput/TextInputFlat.tsx +452 -0
  155. package/src/components/TextInput/constants.tsx +48 -0
  156. package/src/components/TextInput/helpers.tsx +546 -0
  157. package/src/components/TextInput/types.tsx +155 -0
  158. package/src/components/Toast/ToastProvider.tsx +69 -0
  159. package/src/components/Toast/index.tsx +239 -0
  160. package/src/components/Typography/AnimatedText.tsx +84 -0
  161. package/src/components/Typography/StyledText.tsx +53 -0
  162. package/src/components/Typography/Text.tsx +189 -0
  163. package/src/components/Typography/types.tsx +5 -0
  164. package/src/components/View/index.tsx +175 -0
  165. package/src/components/ViewVisibleAnimated/index.tsx +199 -0
  166. package/src/constants.tsx +16 -0
  167. package/src/core/theming.tsx +144 -0
  168. package/src/icons/IconArrowDown.tsx +14 -0
  169. package/src/icons/IconCheckbox.tsx +20 -0
  170. package/src/icons/IconCheckboxActive.tsx +18 -0
  171. package/src/icons/IconClearText.tsx +14 -0
  172. package/src/icons/IconRadio.tsx +11 -0
  173. package/src/icons/IconRadioActive.tsx +12 -0
  174. package/src/icons/IconRadioDisable.tsx +12 -0
  175. package/src/index.ts +51 -0
  176. package/src/index.tsx +50 -0
  177. package/src/styles/fonts.tsx +89 -0
  178. package/src/styles/overlay.tsx +69 -0
  179. package/src/styles/shadow.tsx +47 -0
  180. package/src/styles/themes/DarkTheme.tsx +157 -0
  181. package/src/styles/themes/LightTheme.tsx +160 -0
  182. package/src/styles/themes/index.ts +3 -0
  183. package/src/styles/themes/tokens.tsx +481 -0
  184. package/src/theme/blue.ts +25 -0
  185. package/src/theme/colors.ts +21 -0
  186. package/src/theme/container-styles.tsx +126 -0
  187. package/src/theme/dimensions.ts +44 -0
  188. package/src/theme/green.ts +27 -0
  189. package/src/theme/icon.ts +7 -0
  190. package/src/theme/ink.ts +18 -0
  191. package/src/theme/orange.ts +24 -0
  192. package/src/theme/purple.ts +8 -0
  193. package/src/theme/red.ts +26 -0
  194. package/src/theme/themes.tsx +287 -0
  195. package/src/theme/white.ts +16 -0
  196. package/src/theme/yellow.ts +26 -0
  197. package/src/types/index.ts +71 -0
  198. package/src/types/svg.d.ts +5 -0
  199. package/src/types.ts +259 -0
  200. package/src/types.tsx +284 -0
  201. package/src/utils/BackHandler/BackHandler.native.tsx +3 -0
  202. package/src/utils/BackHandler/BackHandler.tsx +11 -0
  203. package/src/utils/addEventListener.tsx +56 -0
  204. package/src/utils/forwardRef.tsx +23 -0
  205. package/src/utils/function-utils.tsx +108 -0
  206. package/src/utils/getContrastingColor.tsx +15 -0
  207. package/src/utils/hasTouchHandler.tsx +23 -0
  208. package/src/utils/roundLayoutSize.ts +2 -0
  209. package/src/utils/splitStyles.ts +60 -0
  210. package/src/utils/toast-manager.tsx +46 -0
  211. package/src/utils/useAnimatedValue.tsx +9 -0
  212. package/src/utils/useAnimatedValueArray.tsx +13 -0
  213. package/src/utils/useIsKeyboardShown.tsx +55 -0
  214. package/src/utils/useLayout.tsx +29 -0
  215. package/src/utils/useLazyRef.tsx +11 -0
@@ -0,0 +1,564 @@
1
+ import React, { useRef } from "react";
2
+ import {
3
+ Animated,
4
+ LayoutChangeEvent,
5
+ StyleProp,
6
+ TextInput as NativeTextInput,
7
+ TextStyle,
8
+ ViewStyle,
9
+ NativeSyntheticEvent,
10
+ TextLayoutEventData,
11
+ } from "react-native";
12
+
13
+ import TextInputAffix, {
14
+ Props as TextInputAffixProps,
15
+ } from "./Adornment/TextInputAffix";
16
+
17
+ import TextInputFlat from "./TextInputFlat";
18
+ import TextInputDefault from "./TextInputDefault";
19
+ import type { RenderProps, TextInputLabelProp } from "./types";
20
+ import { useInternalTheme } from "../../core/theming";
21
+ import type { ThemeProp } from "../../types";
22
+ import { forwardRef } from "../../utils/forwardRef";
23
+ import { roundLayoutSize } from "../../utils/roundLayoutSize";
24
+
25
+ const BLUR_ANIMATION_DURATION = 180;
26
+ const FOCUS_ANIMATION_DURATION = 150;
27
+
28
+ export type Props = React.ComponentPropsWithRef<typeof NativeTextInput> & {
29
+ mode?: "flat" | "default";
30
+ left?: React.ReactNode;
31
+ right?: React.ReactNode;
32
+ /**
33
+ * If true, user won't be able to interact with the component.
34
+ */
35
+ disabled?: boolean;
36
+ /**
37
+ * The text or component to use for the floating label.
38
+ */
39
+ label?: TextInputLabelProp;
40
+ /**
41
+ * Placeholder for the input.
42
+ */
43
+ placeholder?: string;
44
+ /**
45
+ * Whether to style the TextInput with error style.
46
+ */
47
+ error?: boolean;
48
+ /**
49
+ * Callback that is called when the text input's text changes. Changed text is passed as an argument to the callback handler.
50
+ */
51
+ onChangeText?: Function;
52
+ /**
53
+ * Selection color of the input. On iOS, it sets both the selection color and cursor color.
54
+ * On Android, it sets only the selection color.
55
+ */
56
+ selectionColor?: string;
57
+ /**
58
+ * @platform Android only
59
+ * Cursor (or "caret") color of the input on Android.
60
+ * This property has no effect on iOS.
61
+ */
62
+ cursorColor?: string;
63
+ /**
64
+ * Inactive underline color of the input.
65
+ */
66
+ underlineColor?: string;
67
+ /**
68
+ * Active underline color of the input.
69
+ */
70
+ activeUnderlineColor?: string;
71
+ /**
72
+ * Inactive outline color of the input.
73
+ */
74
+ outlineColor?: string;
75
+ /**
76
+ * Active outline color of the input.
77
+ */
78
+ activeOutlineColor?: string;
79
+ /**
80
+ * Color of the text in the input.
81
+ */
82
+ textColor?: string;
83
+
84
+ placeholderTextColor?: string;
85
+ /**
86
+ * Sets min height with densed layout. For `TextInput` in `flat` mode
87
+ * height is `64dp` or in dense layout - `52dp` with label or `40dp` without label.
88
+ * For `TextInput` in `outlined` mode
89
+ * height is `56dp` or in dense layout - `40dp` regardless of label.
90
+ * When you apply `height` prop in style the `dense` prop affects only `paddingVertical` inside `TextInput`
91
+ */
92
+ dense?: boolean;
93
+ /**
94
+ * Whether the input can have multiple lines.
95
+ */
96
+ multiline?: boolean;
97
+ /**
98
+ * @platform Android only
99
+ * The number of lines to show in the input (Android only).
100
+ */
101
+ numberOfLines?: number;
102
+ /**
103
+ * Callback that is called when the text input is focused.
104
+ */
105
+ onFocus?: (args: any) => void;
106
+ /**
107
+ * Callback that is called when the text input is blurred.
108
+ */
109
+ onBlur?: (args: any) => void;
110
+ /**
111
+ *
112
+ * Callback to render a custom input component such as `react-native-text-input-mask`
113
+ * instead of the default `TextInput` component from `react-native`.
114
+ *
115
+ * Example:
116
+ * ```js
117
+ * <TextInput
118
+ * label="Phone number"
119
+ * render={props =>
120
+ * <TextInputMask
121
+ * {...props}
122
+ * mask="+[00] [000] [000] [000]"
123
+ * />
124
+ * }
125
+ * />
126
+ * ```
127
+ */
128
+ render?: (props: RenderProps) => React.ReactNode;
129
+ /**
130
+ * Value of the text input.
131
+ */
132
+ value?: string;
133
+ /**
134
+ * Pass `fontSize` prop to modify the font size inside `TextInput`.
135
+ * Pass `height` prop to set `TextInput` height. When `height` is passed,
136
+ * `dense` prop will affect only input's `paddingVertical`.
137
+ * Pass `paddingHorizontal` to modify horizontal padding.
138
+ * This can be used to get MD Guidelines v1 TextInput look.
139
+ */
140
+ style?: StyleProp<TextStyle>;
141
+ /**
142
+ * @optional
143
+ */
144
+ theme?: ThemeProp;
145
+ /**
146
+ * testID to be used on tests.
147
+ */
148
+ testID?: string;
149
+ /**
150
+ * Pass custom style directly to the input itself.
151
+ * Overrides input style
152
+ * Example: `paddingLeft`, `backgroundColor`
153
+ */
154
+ contentStyle?: StyleProp<TextStyle>;
155
+ /**
156
+ * Pass style to override the default style of outlined wrapper.
157
+ * Overrides style when mode is set to `outlined`
158
+ * Example: `borderRadius`, `borderColor`
159
+ */
160
+
161
+ underlineStyle?: StyleProp<ViewStyle>;
162
+ minHeight?: number;
163
+ clearButton?: boolean;
164
+ };
165
+
166
+ interface CompoundedComponent
167
+ extends React.ForwardRefExoticComponent<
168
+ Props & React.RefAttributes<TextInputHandles>
169
+ > {
170
+ Affix: React.FunctionComponent<Partial<TextInputAffixProps>>;
171
+ }
172
+
173
+ type TextInputHandles = Pick<
174
+ NativeTextInput,
175
+ "focus" | "clear" | "blur" | "isFocused" | "setNativeProps"
176
+ >;
177
+
178
+ const DefaultRenderer = (props: RenderProps) => <NativeTextInput {...props} />;
179
+
180
+ /**
181
+ * A component to allow users to input text.
182
+ *
183
+ * ## Usage
184
+ * ```js
185
+ * import * as React from 'react';
186
+ * import { TextInput } from 'react-native-paper';
187
+ *
188
+ * const MyComponent = () => {
189
+ * const [text, setText] = React.useState("");
190
+ *
191
+ * return (
192
+ * <TextInput
193
+ * label="Email"
194
+ * value={text}
195
+ * onChangeText={text => setText(text)}
196
+ * />
197
+ * );
198
+ * };
199
+ *
200
+ * export default MyComponent;
201
+ * ```
202
+ *
203
+ * @extends TextInput props https://reactnative.dev/docs/textinput#props
204
+ */
205
+ const TextInput = forwardRef<TextInputHandles, Props>(
206
+ (
207
+ {
208
+ mode = "default",
209
+ dense = false,
210
+ disabled = false,
211
+ error: errorProp = false,
212
+ multiline = false,
213
+ editable = true,
214
+ contentStyle,
215
+ render = DefaultRenderer,
216
+ theme: themeOverrides,
217
+ placeholderTextColor,
218
+ clearButton,
219
+ ...rest
220
+ }: Props,
221
+ ref
222
+ ) => {
223
+ const theme = useInternalTheme();
224
+ const isControlled = rest.value !== undefined;
225
+ const validInputValue = isControlled ? rest.value : rest.defaultValue;
226
+
227
+ const { current: labeled } = React.useRef<Animated.Value>(
228
+ new Animated.Value(validInputValue ? 0 : 1)
229
+ );
230
+ const { current: error } = React.useRef<Animated.Value>(
231
+ new Animated.Value(errorProp ? 1 : 0)
232
+ );
233
+ const [focused, setFocused] = React.useState<boolean>(false);
234
+ const [displayPlaceholder, setDisplayPlaceholder] =
235
+ React.useState<boolean>(false);
236
+ const [uncontrolledValue, setUncontrolledValue] = React.useState<
237
+ string | undefined
238
+ >(validInputValue);
239
+ // Use value from props instead of local state when input is controlled
240
+ const value = isControlled ? rest.value : uncontrolledValue;
241
+
242
+ const [labelTextLayout, setLabelTextLayout] = React.useState({
243
+ width: 33,
244
+ });
245
+
246
+ const [inputContainerLayout, setInputContainerLayout] = React.useState({
247
+ width: 65,
248
+ });
249
+
250
+ const [labelLayout, setLabelLayout] = React.useState<{
251
+ measured: boolean;
252
+ width: number;
253
+ height: number;
254
+ }>({
255
+ measured: false,
256
+ width: 0,
257
+ height: 0,
258
+ });
259
+ const [leftLayout, setLeftLayout] = React.useState<{
260
+ height: number | null;
261
+ width: number | null;
262
+ }>({
263
+ width: null,
264
+ height: null,
265
+ });
266
+ const [rightLayout, setRightLayout] = React.useState<{
267
+ height: number | null;
268
+ width: number | null;
269
+ }>({
270
+ width: null,
271
+ height: null,
272
+ });
273
+
274
+ const timer = useRef<NodeJS.Timeout | undefined>(undefined);
275
+
276
+ const root = useRef<NativeTextInput | undefined | null>(null);
277
+
278
+ const { scale } = theme.animation;
279
+
280
+ React.useImperativeHandle(ref, () => ({
281
+ focus: () => root.current?.focus(),
282
+ clear: () => root.current?.clear(),
283
+ setNativeProps: (args: Object) => root.current?.setNativeProps(args),
284
+ isFocused: () => root.current?.isFocused() || false,
285
+ blur: () => root.current?.blur(),
286
+ forceFocus: () => root.current?.focus(),
287
+ }));
288
+
289
+ React.useEffect(() => {
290
+ // When the input has an error, we wiggle the label and apply error styles
291
+ if (errorProp) {
292
+ // show error
293
+ Animated.timing(error, {
294
+ toValue: 1,
295
+ duration: FOCUS_ANIMATION_DURATION * scale,
296
+ // To prevent this - https://github.com/callstack/react-native-paper/issues/941
297
+ useNativeDriver: true,
298
+ }).start();
299
+ } else {
300
+ // hide error
301
+ {
302
+ Animated.timing(error, {
303
+ toValue: 0,
304
+ duration: BLUR_ANIMATION_DURATION * scale,
305
+ // To prevent this - https://github.com/callstack/react-native-paper/issues/941
306
+ useNativeDriver: true,
307
+ }).start();
308
+ }
309
+ }
310
+ }, [errorProp, scale, error]);
311
+
312
+ React.useEffect(() => {
313
+ // Show placeholder text only if the input is focused, or there's no label
314
+ // We don't show placeholder if there's a label because the label acts as placeholder
315
+ // When focused, the label moves up, so we can show a placeholder
316
+ if (focused || !rest.label) {
317
+ // If the user wants to use the contextMenu, when changing the placeholder, the contextMenu is closed
318
+ // This is a workaround to mitigate this behavior in scenarios where the placeholder is not specified.
319
+ if (rest.placeholder) {
320
+ // Display placeholder in a delay to offset the label animation
321
+ // If we show it immediately, they'll overlap and look ugly
322
+ timer.current = setTimeout(
323
+ () => setDisplayPlaceholder(true),
324
+ 50
325
+ ) as unknown as NodeJS.Timeout;
326
+ }
327
+ } else {
328
+ // hidePlaceholder
329
+ setDisplayPlaceholder(false);
330
+ }
331
+
332
+ return () => {
333
+ if (timer.current) {
334
+ clearTimeout(timer.current);
335
+ }
336
+ };
337
+ }, [focused, rest.label, rest.placeholder]);
338
+
339
+ React.useEffect(() => {
340
+ labeled.stopAnimation();
341
+ // The label should be minimized if the text input is focused, or has text
342
+ // In minimized mode, the label moves up and becomes small
343
+ // workaround for animated regression for react native > 0.61
344
+ // https://github.com/callstack/react-native-paper/pull/1440
345
+ if (value || focused) {
346
+ // minimize label
347
+ Animated.timing(labeled, {
348
+ toValue: 0,
349
+ duration: BLUR_ANIMATION_DURATION * scale,
350
+ // To prevent this - https://github.com/callstack/react-native-paper/issues/941
351
+ useNativeDriver: true,
352
+ }).start();
353
+ } else {
354
+ // restore label
355
+ Animated.timing(labeled, {
356
+ toValue: 1,
357
+ duration: FOCUS_ANIMATION_DURATION * scale,
358
+ // To prevent this - https://github.com/callstack/react-native-paper/issues/941
359
+ useNativeDriver: true,
360
+ }).start();
361
+ }
362
+ }, [focused, value, labeled, scale]);
363
+
364
+ const onLeftAffixLayoutChange = React.useCallback(
365
+ (event: LayoutChangeEvent) => {
366
+ const height = roundLayoutSize(event.nativeEvent.layout.height);
367
+ const width = roundLayoutSize(event.nativeEvent.layout.width);
368
+
369
+ if (width !== leftLayout.width || height !== leftLayout.height) {
370
+ setLeftLayout({
371
+ width,
372
+ height,
373
+ });
374
+ }
375
+ },
376
+ [leftLayout.height, leftLayout.width]
377
+ );
378
+
379
+ const onRightAffixLayoutChange = React.useCallback(
380
+ (event: LayoutChangeEvent) => {
381
+ const width = roundLayoutSize(event.nativeEvent.layout.width);
382
+ const height = roundLayoutSize(event.nativeEvent.layout.height);
383
+
384
+ if (width !== rightLayout.width || height !== rightLayout.height) {
385
+ setRightLayout({
386
+ width,
387
+ height,
388
+ });
389
+ }
390
+ },
391
+ [rightLayout.height, rightLayout.width]
392
+ );
393
+
394
+ const handleFocus = (args: any) => {
395
+ if (disabled || !editable) {
396
+ return;
397
+ }
398
+
399
+ setFocused(true);
400
+
401
+ rest.onFocus?.(args);
402
+ };
403
+
404
+ const handleBlur = (args: Object) => {
405
+ if (!editable) {
406
+ return;
407
+ }
408
+
409
+ setFocused(false);
410
+ rest.onBlur?.(args);
411
+ };
412
+
413
+ const handleChangeText = (value: string) => {
414
+ if (!editable || disabled) {
415
+ return;
416
+ }
417
+
418
+ if (!isControlled) {
419
+ // Keep track of value in local state when input is not controlled
420
+ setUncontrolledValue(value);
421
+ }
422
+ rest.onChangeText?.(value);
423
+ };
424
+
425
+ const handleLayoutAnimatedText = React.useCallback(
426
+ (e: LayoutChangeEvent) => {
427
+ const width = roundLayoutSize(e.nativeEvent.layout.width);
428
+ const height = roundLayoutSize(e.nativeEvent.layout.height);
429
+
430
+ if (width !== labelLayout.width || height !== labelLayout.height) {
431
+ setLabelLayout({
432
+ width,
433
+ height,
434
+ measured: true,
435
+ });
436
+ }
437
+ },
438
+ [labelLayout.height, labelLayout.width]
439
+ );
440
+
441
+ const handleLabelTextLayout = React.useCallback(
442
+ ({ nativeEvent }: NativeSyntheticEvent<TextLayoutEventData>) => {
443
+ setLabelTextLayout({
444
+ width: nativeEvent.lines.reduce(
445
+ (acc, line) => acc + Math.ceil(line.width),
446
+ 0
447
+ ),
448
+ });
449
+ },
450
+ []
451
+ );
452
+
453
+ const handleInputContainerLayout = React.useCallback(
454
+ ({ nativeEvent: { layout } }: LayoutChangeEvent) => {
455
+ setInputContainerLayout({
456
+ width: layout.width,
457
+ });
458
+ },
459
+ []
460
+ );
461
+
462
+ const forceFocus = React.useCallback(() => root.current?.focus(), []);
463
+
464
+ const { maxFontSizeMultiplier = 1.5 } = rest;
465
+
466
+ const scaledLabel = !!(value || focused);
467
+
468
+ if (mode === "default") {
469
+ return (
470
+ <TextInputDefault
471
+ dense={dense}
472
+ disabled={disabled}
473
+ error={errorProp}
474
+ multiline={multiline}
475
+ editable={editable}
476
+ render={render}
477
+ {...rest}
478
+ theme={theme}
479
+ value={value}
480
+ placeholderTextColor={placeholderTextColor}
481
+ clearButton={clearButton}
482
+ parentState={{
483
+ labeled,
484
+ error,
485
+ focused,
486
+ displayPlaceholder,
487
+ value,
488
+ labelTextLayout,
489
+ labelLayout,
490
+ leftLayout,
491
+ rightLayout,
492
+ inputContainerLayout,
493
+ }}
494
+ innerRef={(ref) => {
495
+ root.current = ref;
496
+ }}
497
+ onFocus={handleFocus}
498
+ forceFocus={forceFocus}
499
+ onBlur={handleBlur}
500
+ allowFontScaling={false}
501
+ onChangeText={handleChangeText}
502
+ onLayoutAnimatedText={handleLayoutAnimatedText}
503
+ onInputLayout={handleInputContainerLayout}
504
+ onLabelTextLayout={handleLabelTextLayout}
505
+ onLeftAffixLayoutChange={onLeftAffixLayoutChange}
506
+ onRightAffixLayoutChange={onRightAffixLayoutChange}
507
+ maxFontSizeMultiplier={maxFontSizeMultiplier}
508
+ contentStyle={contentStyle}
509
+ scaledLabel={scaledLabel}
510
+ />
511
+ );
512
+ }
513
+
514
+ return (
515
+ <TextInputFlat
516
+ dense={dense}
517
+ disabled={disabled}
518
+ error={errorProp}
519
+ multiline={false}
520
+ editable={editable}
521
+ clearButton={clearButton}
522
+ render={render}
523
+ {...rest}
524
+ theme={theme}
525
+ value={value}
526
+ parentState={{
527
+ labeled,
528
+ error,
529
+ focused,
530
+ displayPlaceholder,
531
+ value,
532
+ labelTextLayout,
533
+ labelLayout,
534
+ leftLayout,
535
+ rightLayout,
536
+ inputContainerLayout,
537
+ }}
538
+ innerRef={(ref) => {
539
+ root.current = ref;
540
+ }}
541
+ onFocus={handleFocus}
542
+ forceFocus={forceFocus}
543
+ onBlur={handleBlur}
544
+ onInputLayout={handleInputContainerLayout}
545
+ allowFontScaling={false}
546
+ onChangeText={handleChangeText}
547
+ onLayoutAnimatedText={handleLayoutAnimatedText}
548
+ onLabelTextLayout={handleLabelTextLayout}
549
+ onLeftAffixLayoutChange={onLeftAffixLayoutChange}
550
+ onRightAffixLayoutChange={onRightAffixLayoutChange}
551
+ maxFontSizeMultiplier={maxFontSizeMultiplier}
552
+ contentStyle={contentStyle}
553
+ scaledLabel={scaledLabel}
554
+ />
555
+ );
556
+ }
557
+ ) as CompoundedComponent;
558
+ // @component ./Adornment/TextInputIcon.tsx
559
+
560
+ // @component ./Adornment/TextInputAffix.tsx
561
+ // @ts-ignore Types of property 'theme' are incompatible.
562
+ TextInput.Affix = TextInputAffix;
563
+
564
+ export default TextInput;