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.
- package/README.md +69 -0
- package/dist/assets/error.png +0 -0
- package/dist/assets/icon-checkbox-active.svg +4 -0
- package/dist/assets/icon-checkbox.svg +3 -0
- package/dist/assets/image_default.png +0 -0
- package/dist/assets/images/error.png +0 -0
- package/dist/assets/images/image_default.png +0 -0
- package/dist/assets/images/info.png +0 -0
- package/dist/assets/images/success.png +0 -0
- package/dist/assets/images/warning.png +0 -0
- package/dist/assets/info.png +0 -0
- package/dist/assets/success.png +0 -0
- package/dist/assets/svg/icon-checkbox-active.svg +4 -0
- package/dist/assets/svg/icon-checkbox.svg +3 -0
- package/dist/assets/warning.png +0 -0
- package/dist/components/ActivityIndicator.d.ts +28 -0
- package/dist/components/Avatar/index.d.ts +17 -0
- package/dist/components/Badge/index.d.ts +13 -0
- package/dist/components/Button/index.d.ts +23 -0
- package/dist/components/ButtonIcon/index.d.ts +18 -0
- package/dist/components/Checkbox/index.d.ts +14 -0
- package/dist/components/ChipBar/index.d.ts +16 -0
- package/dist/components/CountingDot/index.d.ts +13 -0
- package/dist/components/FloatingButton/index.d.ts +17 -0
- package/dist/components/Icon/index.d.ts +17 -0
- package/dist/components/IconSvg/index.d.ts +12 -0
- package/dist/components/Image/index.d.ts +14 -0
- package/dist/components/ProgressBar.d.ts +42 -0
- package/dist/components/RadioButton/index.d.ts +13 -0
- package/dist/components/ScaleButton/index.d.ts +4 -0
- package/dist/components/SelectionField/index.d.ts +24 -0
- package/dist/components/Spacer/index.d.ts +9 -0
- package/dist/components/Switch/Switch.d.ts +47 -0
- package/dist/components/Switch/utils.d.ts +14 -0
- package/dist/components/Text/index.d.ts +14 -0
- package/dist/components/TextInput/Addons/Outline.d.ts +15 -0
- package/dist/components/TextInput/Addons/Underline.d.ts +19 -0
- package/dist/components/TextInput/Adornment/TextInputAdornment.d.ts +43 -0
- package/dist/components/TextInput/Adornment/TextInputAffix.d.ts +72 -0
- package/dist/components/TextInput/Adornment/enums.d.ts +12 -0
- package/dist/components/TextInput/Adornment/types.d.ts +11 -0
- package/dist/components/TextInput/Adornment/utils.d.ts +11 -0
- package/dist/components/TextInput/Label/InputLabel.d.ts +4 -0
- package/dist/components/TextInput/Label/LabelBackground.d.ts +4 -0
- package/dist/components/TextInput/TextInput.d.ts +171 -0
- package/dist/components/TextInput/TextInputDefault.d.ts +4 -0
- package/dist/components/TextInput/TextInputFlat.d.ts +4 -0
- package/dist/components/TextInput/constants.d.ts +31 -0
- package/dist/components/TextInput/helpers.d.ts +95 -0
- package/dist/components/TextInput/types.d.ts +154 -0
- package/dist/components/Toast/ToastProvider.d.ts +21 -0
- package/dist/components/Toast/index.d.ts +3 -0
- package/dist/components/Typography/AnimatedText.d.ts +34 -0
- package/dist/components/Typography/StyledText.d.ts +12 -0
- package/dist/components/Typography/Text.d.ts +35 -0
- package/dist/components/Typography/types.d.ts +2 -0
- package/dist/components/View/index.d.ts +38 -0
- package/dist/components/ViewVisibleAnimated/index.d.ts +25 -0
- package/dist/constants.d.ts +1 -0
- package/dist/core/theming.d.ts +43 -0
- package/dist/icons/IconArrowDown.d.ts +4 -0
- package/dist/icons/IconCheckbox.d.ts +4 -0
- package/dist/icons/IconCheckboxActive.d.ts +4 -0
- package/dist/icons/IconClearText.d.ts +4 -0
- package/dist/icons/IconRadio.d.ts +4 -0
- package/dist/icons/IconRadioActive.d.ts +4 -0
- package/dist/icons/IconRadioDisable.d.ts +4 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.esm.js +6758 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +6823 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/fonts.d.ts +78 -0
- package/dist/styles/overlay.d.ts +3 -0
- package/dist/styles/shadow.d.ts +18 -0
- package/dist/styles/themes/DarkTheme.d.ts +2 -0
- package/dist/styles/themes/LightTheme.d.ts +2 -0
- package/dist/styles/themes/index.d.ts +2 -0
- package/dist/styles/themes/tokens.d.ts +830 -0
- package/dist/theme/blue.d.ts +14 -0
- package/dist/theme/colors.d.ts +99 -0
- package/dist/theme/container-styles.d.ts +124 -0
- package/dist/theme/dimensions.d.ts +36 -0
- package/dist/theme/green.d.ts +15 -0
- package/dist/theme/icon.d.ts +5 -0
- package/dist/theme/ink.d.ts +11 -0
- package/dist/theme/orange.d.ts +14 -0
- package/dist/theme/purple.d.ts +6 -0
- package/dist/theme/red.d.ts +15 -0
- package/dist/theme/themes.d.ts +277 -0
- package/dist/theme/white.d.ts +10 -0
- package/dist/theme/yellow.d.ts +15 -0
- package/dist/types/index.d.ts +65 -0
- package/dist/types.d.ts +220 -0
- package/dist/utils/BackHandler/BackHandler.d.ts +9 -0
- package/dist/utils/BackHandler/BackHandler.native.d.ts +2 -0
- package/dist/utils/addEventListener.d.ts +12 -0
- package/dist/utils/forwardRef.d.ts +11 -0
- package/dist/utils/function-utils.d.ts +12 -0
- package/dist/utils/getContrastingColor.d.ts +2 -0
- package/dist/utils/hasTouchHandler.d.ts +5 -0
- package/dist/utils/roundLayoutSize.d.ts +1 -0
- package/dist/utils/splitStyles.d.ts +19 -0
- package/dist/utils/toast-manager.d.ts +21 -0
- package/dist/utils/useAnimatedValue.d.ts +2 -0
- package/dist/utils/useAnimatedValueArray.d.ts +2 -0
- package/dist/utils/useIsKeyboardShown.d.ts +6 -0
- package/dist/utils/useLayout.d.ts +6 -0
- package/dist/utils/useLazyRef.d.ts +2 -0
- package/package.json +104 -0
- package/src/.DS_Store +0 -0
- package/src/assets/images/error.png +0 -0
- package/src/assets/images/image_default.png +0 -0
- package/src/assets/images/info.png +0 -0
- package/src/assets/images/success.png +0 -0
- package/src/assets/images/warning.png +0 -0
- package/src/assets/svg/icon-checkbox-active.svg +4 -0
- package/src/assets/svg/icon-checkbox.svg +3 -0
- package/src/babel/.eslintrc +7 -0
- package/src/babel/index.js +63 -0
- package/src/components/.DS_Store +0 -0
- package/src/components/ActivityIndicator.tsx +238 -0
- package/src/components/Avatar/index.tsx +102 -0
- package/src/components/Badge/index.tsx +55 -0
- package/src/components/Button/index.tsx +162 -0
- package/src/components/ButtonIcon/index.tsx +98 -0
- package/src/components/Checkbox/index.tsx +107 -0
- package/src/components/ChipBar/index.tsx +112 -0
- package/src/components/CountingDot/index.tsx +63 -0
- package/src/components/FloatingButton/index.tsx +99 -0
- package/src/components/Icon/index.tsx +135 -0
- package/src/components/IconSvg/index.tsx +42 -0
- package/src/components/Image/index.tsx +127 -0
- package/src/components/ProgressBar.tsx +272 -0
- package/src/components/RadioButton/index.tsx +105 -0
- package/src/components/ScaleButton/index.tsx +17 -0
- package/src/components/SelectionField/index.tsx +166 -0
- package/src/components/Spacer/index.tsx +19 -0
- package/src/components/Switch/Switch.tsx +110 -0
- package/src/components/Switch/utils.ts +96 -0
- package/src/components/Text/index.tsx +69 -0
- package/src/components/TextInput/.DS_Store +0 -0
- package/src/components/TextInput/Addons/Outline.tsx +62 -0
- package/src/components/TextInput/Addons/Underline.tsx +71 -0
- package/src/components/TextInput/Adornment/TextInputAdornment.tsx +191 -0
- package/src/components/TextInput/Adornment/TextInputAffix.tsx +212 -0
- package/src/components/TextInput/Adornment/enums.tsx +12 -0
- package/src/components/TextInput/Adornment/types.tsx +11 -0
- package/src/components/TextInput/Adornment/utils.ts +39 -0
- package/src/components/TextInput/Label/InputLabel.tsx +216 -0
- package/src/components/TextInput/Label/LabelBackground.tsx +100 -0
- package/src/components/TextInput/TextInput.tsx +564 -0
- package/src/components/TextInput/TextInputDefault.tsx +187 -0
- package/src/components/TextInput/TextInputFlat.tsx +452 -0
- package/src/components/TextInput/constants.tsx +48 -0
- package/src/components/TextInput/helpers.tsx +546 -0
- package/src/components/TextInput/types.tsx +155 -0
- package/src/components/Toast/ToastProvider.tsx +69 -0
- package/src/components/Toast/index.tsx +239 -0
- package/src/components/Typography/AnimatedText.tsx +84 -0
- package/src/components/Typography/StyledText.tsx +53 -0
- package/src/components/Typography/Text.tsx +189 -0
- package/src/components/Typography/types.tsx +5 -0
- package/src/components/View/index.tsx +175 -0
- package/src/components/ViewVisibleAnimated/index.tsx +199 -0
- package/src/constants.tsx +16 -0
- package/src/core/theming.tsx +144 -0
- package/src/icons/IconArrowDown.tsx +14 -0
- package/src/icons/IconCheckbox.tsx +20 -0
- package/src/icons/IconCheckboxActive.tsx +18 -0
- package/src/icons/IconClearText.tsx +14 -0
- package/src/icons/IconRadio.tsx +11 -0
- package/src/icons/IconRadioActive.tsx +12 -0
- package/src/icons/IconRadioDisable.tsx +12 -0
- package/src/index.ts +51 -0
- package/src/index.tsx +50 -0
- package/src/styles/fonts.tsx +89 -0
- package/src/styles/overlay.tsx +69 -0
- package/src/styles/shadow.tsx +47 -0
- package/src/styles/themes/DarkTheme.tsx +157 -0
- package/src/styles/themes/LightTheme.tsx +160 -0
- package/src/styles/themes/index.ts +3 -0
- package/src/styles/themes/tokens.tsx +481 -0
- package/src/theme/blue.ts +25 -0
- package/src/theme/colors.ts +21 -0
- package/src/theme/container-styles.tsx +126 -0
- package/src/theme/dimensions.ts +44 -0
- package/src/theme/green.ts +27 -0
- package/src/theme/icon.ts +7 -0
- package/src/theme/ink.ts +18 -0
- package/src/theme/orange.ts +24 -0
- package/src/theme/purple.ts +8 -0
- package/src/theme/red.ts +26 -0
- package/src/theme/themes.tsx +287 -0
- package/src/theme/white.ts +16 -0
- package/src/theme/yellow.ts +26 -0
- package/src/types/index.ts +71 -0
- package/src/types/svg.d.ts +5 -0
- package/src/types.ts +259 -0
- package/src/types.tsx +284 -0
- package/src/utils/BackHandler/BackHandler.native.tsx +3 -0
- package/src/utils/BackHandler/BackHandler.tsx +11 -0
- package/src/utils/addEventListener.tsx +56 -0
- package/src/utils/forwardRef.tsx +23 -0
- package/src/utils/function-utils.tsx +108 -0
- package/src/utils/getContrastingColor.tsx +15 -0
- package/src/utils/hasTouchHandler.tsx +23 -0
- package/src/utils/roundLayoutSize.ts +2 -0
- package/src/utils/splitStyles.ts +60 -0
- package/src/utils/toast-manager.tsx +46 -0
- package/src/utils/useAnimatedValue.tsx +9 -0
- package/src/utils/useAnimatedValueArray.tsx +13 -0
- package/src/utils/useIsKeyboardShown.tsx +55 -0
- package/src/utils/useLayout.tsx +29 -0
- 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;
|