react-native-ui-lib 8.3.3 → 8.3.4-snapshot.7783

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 (147) hide show
  1. package/lib/android/build.gradle +3 -3
  2. package/lib/components/HighlighterOverlayView/index.d.ts +2 -2
  3. package/lib/components/HighlighterOverlayView/index.web.d.ts +2 -2
  4. package/lib/components/Keyboard/KeyboardAccessoryView/CustomKeyboardView/CustomKeyboardViewBase.d.ts +1 -1
  5. package/lib/components/Keyboard/KeyboardAccessoryView/KeyboardRegistry/index.js +5 -1
  6. package/lib/components/Keyboard/KeyboardAccessoryView/index.d.ts +2 -2
  7. package/lib/components/Keyboard/KeyboardAccessoryView/index.js +3 -1
  8. package/lib/components/Keyboard/KeyboardTrackingView/KeyboardTrackingView.ios.js +3 -1
  9. package/lib/components/Keyboard/KeyboardTrackingView/index.d.ts +6 -2
  10. package/lib/components/Keyboard/KeyboardTrackingView/index.js +5 -4
  11. package/lib/components/Keyboard/index.d.ts +2 -1
  12. package/lib/package.json +20 -21
  13. package/lib/react-native.config.js +1 -1
  14. package/package.json +161 -164
  15. package/screenFooter.d.ts +2 -0
  16. package/screenFooter.js +1 -0
  17. package/scripts/release/prReleaseNotesCommon.js +2 -1
  18. package/src/assets/internal/images/bottomGradient.png +0 -0
  19. package/src/assets/internal/images/bottomGradient@1.5x.png +0 -0
  20. package/src/assets/internal/images/bottomGradient@2x.png +0 -0
  21. package/src/assets/internal/images/bottomGradient@3x.png +0 -0
  22. package/src/assets/internal/images/bottomGradient@4x.png +0 -0
  23. package/src/assets/internal/images/index.js +3 -0
  24. package/src/commons/asBaseComponent.js +2 -1
  25. package/src/commons/baseComponent.js +0 -8
  26. package/src/commons/forwardRef.js +1 -4
  27. package/src/commons/modifiers.d.ts +0 -6
  28. package/src/commons/modifiers.js +0 -18
  29. package/src/commons/withScrollEnabler.js +0 -4
  30. package/src/commons/withScrollReached.js +0 -4
  31. package/src/components/KeyboardAwareScrollView/KeyboardAwareBase.js +0 -7
  32. package/src/components/KeyboardAwareScrollView/KeyboardAwareFlatList.js +0 -6
  33. package/src/components/KeyboardAwareScrollView/KeyboardAwareScrollView.js +0 -6
  34. package/src/components/WheelPicker/WheelPicker.driver.d.ts +2 -2
  35. package/src/components/WheelPicker/index.d.ts +2 -2
  36. package/src/components/WheelPicker/index.js +1 -1
  37. package/src/components/WheelPicker/usePresenter.d.ts +1 -1
  38. package/src/components/actionSheet/index.d.ts +1 -1
  39. package/src/components/animatedImage/index.d.ts +1 -1
  40. package/src/components/animatedScanner/index.js +0 -37
  41. package/src/components/avatar/index.d.ts +1 -1
  42. package/src/components/badge/index.d.ts +4 -4
  43. package/src/components/baseInput/index.d.ts +0 -1
  44. package/src/components/baseInput/index.js +1 -49
  45. package/src/components/button/index.d.ts +4 -4
  46. package/src/components/button/types.d.ts +2 -2
  47. package/src/components/carousel/index.d.ts +8 -8
  48. package/src/components/carousel/types.d.ts +4 -1
  49. package/src/components/carousel/types.js +0 -2
  50. package/src/components/checkbox/index.d.ts +1 -1
  51. package/src/components/chip/index.d.ts +1 -1
  52. package/src/components/colorPalette/index.d.ts +1 -1
  53. package/src/components/dateTimePicker/index.d.ts +2 -2
  54. package/src/components/dateTimePicker/index.js +2 -2
  55. package/src/components/dialog/types.d.ts +4 -4
  56. package/src/components/dialog/useDialogContent.d.ts +1 -1
  57. package/src/components/drawer/index.d.ts +1 -1
  58. package/src/components/expandableSection/index.d.ts +2 -2
  59. package/src/components/fadedScrollView/index.js +1 -1
  60. package/src/components/featureHighlight/index.js +5 -7
  61. package/src/components/gridListItem/index.d.ts +7 -7
  62. package/src/components/gridView/index.d.ts +1 -1
  63. package/src/components/hint/HintBubble.d.ts +1 -1
  64. package/src/components/hint/HintOld.d.ts +10 -10
  65. package/src/components/hint/hooks/useHintLayout.d.ts +1 -1
  66. package/src/components/hint/index.d.ts +2 -2
  67. package/src/components/hint/types.d.ts +2 -2
  68. package/src/components/icon/index.js +0 -3
  69. package/src/components/image/index.d.ts +1 -1
  70. package/src/components/image/index.js +20 -17
  71. package/src/components/loaderScreen/index.d.ts +1 -1
  72. package/src/components/loaderScreen/types.d.ts +1 -1
  73. package/src/components/maskedInput/index.d.ts +21 -4
  74. package/src/components/maskedInput/index.js +78 -16
  75. package/src/components/maskedInput/maskedInput.api.json +0 -1
  76. package/src/components/modal/index.d.ts +3 -3
  77. package/src/components/numberInput/index.js +2 -2
  78. package/src/components/overlay/index.d.ts +1 -1
  79. package/src/components/picker/PickerDialog.android.js +0 -15
  80. package/src/components/picker/PickerDialog.js +0 -7
  81. package/src/components/picker/helpers/useImperativePickerHandle.d.ts +1 -1
  82. package/src/components/picker/helpers/useImperativePickerHandle.js +1 -1
  83. package/src/components/picker/types.d.ts +9 -9
  84. package/src/components/progressBar/index.d.ts +2 -2
  85. package/src/components/screenFooter/index.d.ts +8 -0
  86. package/src/components/screenFooter/index.js +211 -0
  87. package/src/components/screenFooter/screenFooter.api.json +262 -0
  88. package/src/components/screenFooter/types.d.ts +100 -0
  89. package/src/components/screenFooter/types.js +39 -0
  90. package/src/components/scrollBar/index.d.ts +11 -4
  91. package/src/components/searchInput/index.js +1 -1
  92. package/src/components/searchInput/types.d.ts +2 -2
  93. package/src/components/sectionsWheelPicker/SectionsWheelPicker.driver.d.ts +2 -2
  94. package/src/components/skeletonView/index.d.ts +4 -4
  95. package/src/components/slider/Thumb.d.ts +1 -1
  96. package/src/components/slider/types.d.ts +1 -1
  97. package/src/components/stackAggregator/index.d.ts +1 -1
  98. package/src/components/tabController/TabBarItem.d.ts +2 -2
  99. package/src/components/tabController/TabBarItem.js +1 -1
  100. package/src/components/tabController/TabPage.d.ts +2 -2
  101. package/src/components/tabController/useScrollToItem.d.ts +1 -1
  102. package/src/components/text/Text.driver.d.ts +1 -1
  103. package/src/components/textArea/index.js +0 -6
  104. package/src/components/textField/types.d.ts +4 -4
  105. package/src/components/textField/useImperativeInputHandle.d.ts +1 -1
  106. package/src/components/textField/useImperativeInputHandle.js +1 -1
  107. package/src/components/textField/usePreset.d.ts +36 -36
  108. package/src/components/timeline/index.js +1 -1
  109. package/src/components/toast/index.js +0 -69
  110. package/src/components/view/index.js +9 -6
  111. package/src/components/wizard/index.d.ts +1 -1
  112. package/src/components/wizard/types.d.ts +1 -1
  113. package/src/components/wizard/wizard.api.json +1 -1
  114. package/src/hooks/index.d.ts +1 -0
  115. package/src/hooks/index.js +1 -0
  116. package/src/hooks/useCombinedRefs/index.js +1 -2
  117. package/src/hooks/useDebounce/index.js +1 -1
  118. package/src/hooks/useHiddenLocation/index.js +2 -2
  119. package/src/hooks/useHiddenLocation/index.web.js +2 -2
  120. package/src/hooks/useMeasure/index.d.ts +1 -1
  121. package/src/hooks/useMeasure/index.js +1 -1
  122. package/src/hooks/useScrollTo/index.d.ts +2 -2
  123. package/src/hooks/useScrollToHide/index.d.ts +24 -0
  124. package/src/hooks/useScrollToHide/index.js +48 -0
  125. package/src/incubator/calendar/index.js +1 -1
  126. package/src/incubator/calendar/types.d.ts +2 -2
  127. package/src/incubator/expandableOverlay/index.d.ts +2 -2
  128. package/src/incubator/expandableOverlay/index.js +7 -3
  129. package/src/incubator/slider/Track.d.ts +1 -1
  130. package/src/incubator/slider/index.d.ts +1 -1
  131. package/src/incubator/toast/helpers/useToastTimer.js +1 -1
  132. package/src/incubator/toast/index.js +1 -1
  133. package/src/incubator/toast/types.d.ts +2 -2
  134. package/src/index.d.ts +1 -0
  135. package/src/index.js +70 -0
  136. package/src/testkit/Component.driver.d.ts +1 -1
  137. package/src/testkit/drivers/TestingLibraryDriver.d.ts +1 -1
  138. package/src/typings/module.d.ts +12 -3
  139. package/ReactNativeUiLib.podspec +0 -22
  140. package/src/components/maskedInput/new.d.ts +0 -22
  141. package/src/components/maskedInput/new.js +0 -85
  142. package/src/components/maskedInput/old.js +0 -95
  143. package/src/components/textFieldOld/index.d.ts +0 -71
  144. package/src/components/textFieldOld/index.js +0 -807
  145. package/src/helpers/DocsGenerator.js +0 -61
  146. package/textFieldOld.d.ts +0 -2
  147. package/textFieldOld.js +0 -1
@@ -1,807 +0,0 @@
1
- import _get from "lodash/get";
2
- import _isUndefined from "lodash/isUndefined";
3
- import _isFunction from "lodash/isFunction";
4
- import _isPlainObject from "lodash/isPlainObject";
5
- import _isString from "lodash/isString";
6
- import _invoke from "lodash/invoke";
7
- import _isEmpty from "lodash/isEmpty"; // @ts-nocheck
8
- // TODO: hideUnderline should be true by default
9
- // TODO: enableErrors should be false by default
10
- // TODO: enableErrors should derived from errorMessage prop
11
- // TODO: use forwardRef to allow access to inner TextInput API
12
- // TODO: add trailing/leading icon props
13
- // TODO: support margin modifiers
14
- import PropTypes from 'prop-types';
15
- import React from 'react';
16
- import { StyleSheet, Animated, TextInput as RNTextInput } from 'react-native';
17
- import { TextInputPropTypes, ImagePropTypes } from 'deprecated-react-native-prop-types';
18
- import memoize from 'memoize-one';
19
- import { Constants } from "../../commons/new";
20
- import { Colors, Typography, Spacings } from "../../style";
21
- import BaseInput from "../baseInput";
22
- import Modal from "../modal";
23
- import TextArea from "../textArea";
24
- import View from "../view";
25
- import Image from "../image";
26
- import Text from "../text";
27
- import TouchableOpacity from "../touchableOpacity";
28
- const COLOR_BY_STATE = {
29
- default: Colors.grey10,
30
- focus: Colors.grey10,
31
- error: Colors.grey10,
32
- disabled: Colors.grey50
33
- };
34
- const UNDERLINE_COLOR_BY_STATE = {
35
- default: Colors.grey50,
36
- focus: Colors.$outlinePrimary,
37
- error: Colors.red30
38
- };
39
- const PLACEHOLDER_COLOR_BY_STATE = {
40
- default: Colors.grey30,
41
- focus: Colors.$textPrimary
42
- };
43
- const CHAR_COUNTER_COLOR_BY_STATE = {
44
- default: Colors.grey30,
45
- error: Colors.red30
46
- };
47
- const LABEL_TYPOGRAPHY = Typography.text80;
48
- const ICON_SIZE = 24;
49
- const ICON_LEFT_PADDING = 6;
50
- const FLOATING_PLACEHOLDER_SCALE = 0.875;
51
-
52
- /**
53
- * @description: A wrapper for TextInput component with extra functionality like floating placeholder and validations (This is an uncontrolled component)
54
- * @modifiers: Typography
55
- * @extends: TextInput
56
- * @extendsLink: https://reactnative.dev/docs/textinput
57
- * @gif: https://media.giphy.com/media/xULW8su8Cs5Z9Fq4PS/giphy.gif, https://media.giphy.com/media/3ohc1dhDcLS9FvWLJu/giphy.gif, https://media.giphy.com/media/oNUSOxnHdMP5ZnKYsh/giphy.gif
58
- * @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/TextFieldScreen/BasicTextFieldScreen.js
59
- */
60
- export default class TextField extends BaseInput {
61
- static displayName = 'TextFieldOld';
62
- static propTypes = {
63
- ...TextInputPropTypes,
64
- ...BaseInput.propTypes,
65
- /**
66
- * should placeholder have floating behavior
67
- */
68
- floatingPlaceholder: PropTypes.bool,
69
- /**
70
- * floating placeholder color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue', disabled: 'grey'}
71
- */
72
- floatingPlaceholderColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
73
- /**
74
- * Custom style for floating placeholder
75
- */
76
- floatingPlaceholderStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
77
- /**
78
- * This text will appear as a placeholder when the textInput becomes focused, only when passing floatingPlaceholder
79
- * as well (NOT for expandable textInputs)
80
- */
81
- helperText: PropTypes.string,
82
- /**
83
- * hide text input underline, by default false
84
- */
85
- hideUnderline: PropTypes.bool,
86
- /**
87
- * underline color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue', disabled: 'grey'}
88
- */
89
- underlineColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
90
- /**
91
- * the color of all text when the input is disabled (if undefined will not apply color)
92
- */
93
- disabledColor: PropTypes.string,
94
- /**
95
- * should text input be align to center
96
- */
97
- centered: PropTypes.bool,
98
- /**
99
- * input error message, should be empty if no error exists
100
- */
101
- error: PropTypes.string,
102
- /**
103
- * should the input component support error messages
104
- */
105
- enableErrors: PropTypes.bool,
106
- /**
107
- * input error message's text color
108
- */
109
- errorColor: PropTypes.string,
110
- /**
111
- * should the input expand to another text area modal
112
- */
113
- expandable: PropTypes.bool,
114
- /**
115
- * Render custom expandable input (requires expandable to be true)
116
- */
117
- renderExpandableInput: PropTypes.elementType,
118
- /**
119
- * allow custom rendering of expandable content when clicking on the input (useful for pickers)
120
- * accept props and state as params, ex. (props, state) => {...}
121
- * use toggleExpandableModal(false) method to toggle off the expandable content
122
- */
123
- renderExpandable: PropTypes.elementType,
124
- /**
125
- * Callback for the modal toggle. Pass with renderExpandable to control the modal toggle
126
- */
127
- onToggleExpandableModal: PropTypes.func,
128
- /**
129
- * The picker modal top bar props
130
- */
131
- topBarProps: PropTypes.shape(Modal.TopBar.propTypes),
132
- /**
133
- * transform function executed on value and return transformed value
134
- */
135
- transformer: PropTypes.func,
136
- /**
137
- * Pass to render a prefix text as part of the input (doesn't work with floatingPlaceholder)
138
- */
139
- prefix: PropTypes.string,
140
- /**
141
- * The prefix style
142
- */
143
- prefixStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
144
- /**
145
- * Fixed title that will displayed above the input (note: floatingPlaceholder MUST be 'false')
146
- */
147
- title: PropTypes.string,
148
- /**
149
- * The title's color as a string or object of states, ex. {default: 'black', error: 'red', focus: 'blue', disabled: 'grey'}
150
- */
151
- titleColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
152
- /**
153
- * Additional styles for the title (not including 'color')
154
- */
155
- titleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
156
- /**
157
- * should the input display a character counter (only when passing 'maxLength')
158
- */
159
- showCharacterCounter: PropTypes.bool,
160
- /**
161
- * should float the placeholder when focused (instead of when typing)
162
- */
163
- floatOnFocus: PropTypes.bool,
164
- /**
165
- * should the errors be displayed at the top
166
- */
167
- useTopErrors: PropTypes.bool,
168
- /**
169
- * Icon asset source for showing on the right side, appropriate for dropdown icon and such
170
- */
171
- rightIconSource: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
172
- /**
173
- * Pass to style the right icon source
174
- */
175
- rightIconStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
176
- /**
177
- * Props for the right button {iconSource, onPress, style}
178
- */
179
- rightButtonProps: PropTypes.shape({
180
- iconSource: ImagePropTypes.source,
181
- iconColor: PropTypes.string,
182
- onPress: PropTypes.func,
183
- style: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
184
- accessibilityLabel: PropTypes.string
185
- }),
186
- /**
187
- * Pass to render a leading icon to the TextInput value. Accepts Image props (doesn't work with floatingPlaceholder)
188
- */
189
- leadingIcon: PropTypes.shape(ImagePropTypes)
190
- };
191
- static defaultProps = {
192
- enableErrors: true,
193
- validateOnBlur: true
194
- };
195
- constructor(props) {
196
- super(props);
197
- this.state = {
198
- ...this.state,
199
- value: props.value,
200
- // for floatingPlaceholder functionality
201
- floatingPlaceholderState: new Animated.Value(this.shouldFloatPlaceholder(props.value) ? 1 : 0),
202
- showExpandableModal: false,
203
- floatingPlaceholderTranslate: 0,
204
- charCountColor: CHAR_COUNTER_COLOR_BY_STATE.default
205
- };
206
- this.generatePropsWarnings(props);
207
- }
208
- UNSAFE_componentWillReceiveProps(nextProps) {
209
- if (nextProps.value !== this.props.value) {
210
- this.setState({
211
- value: nextProps.value
212
- }, () => {
213
- this.updateFloatingPlaceholderState();
214
- if (nextProps.validateOnChange) {
215
- this.validate();
216
- }
217
- });
218
- }
219
- }
220
- componentDidUpdate(_prevProps, prevState) {
221
- if (_isEmpty(prevState.value) !== _isEmpty(this.state.value) || prevState.focused !== this.state.focused) {
222
- this.updateFloatingPlaceholderState();
223
- }
224
- }
225
- onPlaceholderLayout = event => {
226
- const {
227
- width
228
- } = event.nativeEvent.layout;
229
- const translate = width / 2 - width * FLOATING_PLACEHOLDER_SCALE / 2;
230
- this.setState({
231
- floatingPlaceholderTranslate: translate / FLOATING_PLACEHOLDER_SCALE
232
- });
233
- };
234
-
235
- /** Actions */
236
- generatePropsWarnings(props) {
237
- if (props.maxLength === 0) {
238
- console.warn('Setting maxLength to zero will block typing in this input');
239
- }
240
- if (props.showCharacterCounter && !props.maxLength) {
241
- console.warn('In order to use showCharacterCount please pass \'maxLength\' prop');
242
- }
243
- }
244
- generateStyles() {
245
- this.styles = createStyles(this.getThemeProps(), this.getTopPaddings());
246
- }
247
- getAccessibilityInfo() {
248
- const {
249
- floatingPlaceholder,
250
- placeholder
251
- } = this.getThemeProps();
252
- const accessibilityState = this.isDisabled() ? {
253
- disabled: true
254
- } : undefined;
255
- let accessibilityLabel = floatingPlaceholder ? this.props.accessibilityLabel || placeholder : '';
256
- if (this.isRequiredField()) {
257
- accessibilityLabel = `${accessibilityLabel}. Mandatory`;
258
- }
259
- return {
260
- accessibilityLabel,
261
- // on Android accessibilityStates cause issues with expandable input
262
- accessibilityState: Constants.isIOS ? accessibilityState : undefined
263
- };
264
- }
265
- toggleExpandableModal = value => {
266
- this.setState({
267
- showExpandableModal: value
268
- });
269
- _invoke(this.props, 'onToggleExpandableModal', value);
270
- };
271
- updateFloatingPlaceholderState = withoutAnimation => {
272
- if (withoutAnimation) {
273
- this.state.floatingPlaceholderState.setValue(this.shouldFloatPlaceholder() ? 1 : 0);
274
- } else {
275
- Animated.spring(this.state.floatingPlaceholderState, {
276
- toValue: this.shouldFloatPlaceholder() ? 1 : 0,
277
- duration: 150,
278
- useNativeDriver: true
279
- }).start();
280
- }
281
- };
282
- getPlaceholderText = memoize((placeholder, helperText) => {
283
- // HACK: passing whitespace instead of undefined. Issue fixed in RN56
284
- const text = this.shouldFakePlaceholder() ? this.shouldShowHelperText() ? helperText : ' ' : this.shouldShowTopError() && this.shouldShowHelperText() ? helperText : this.getRequiredPlaceholder(placeholder);
285
- return text;
286
- });
287
- getStateColor(colorProp = {}) {
288
- const {
289
- focused
290
- } = this.state;
291
- const error = this.getErrorMessage();
292
- const {
293
- disabledColor
294
- } = this.getThemeProps();
295
- if (_isString(colorProp)) {
296
- return colorProp || Colors.grey10;
297
- } else if (_isPlainObject(colorProp)) {
298
- const mergedColorState = {
299
- ...COLOR_BY_STATE,
300
- ...colorProp
301
- };
302
- if (this.isDisabled()) {
303
- return disabledColor || mergedColorState.disabled;
304
- } else if (error) {
305
- return mergedColorState.error;
306
- } else if (focused) {
307
- return mergedColorState.focus;
308
- } else {
309
- return mergedColorState.default;
310
- }
311
- }
312
- return colorProp || Colors.grey10;
313
- }
314
- getCharCount() {
315
- const {
316
- value
317
- } = this.state;
318
- if (value) {
319
- return value.length;
320
- }
321
- return 0;
322
- }
323
- setCharCountColor(key) {
324
- this.maxReached = key === Constants.backspaceKey ? false : this.isCounterLimit();
325
- const color = this.state.focused && this.maxReached ? CHAR_COUNTER_COLOR_BY_STATE.error : CHAR_COUNTER_COLOR_BY_STATE.default;
326
- if (color !== this.state.charCountColor) {
327
- this.setState({
328
- charCountColor: color
329
- });
330
- }
331
- }
332
- getCharCountColor() {
333
- const {
334
- charCountColor
335
- } = this.state;
336
- const {
337
- disabledColor
338
- } = this.getThemeProps();
339
- return this.isDisabled() && disabledColor ? disabledColor : charCountColor;
340
- }
341
- getTopPaddings() {
342
- return this.shouldFakePlaceholder() ? this.shouldShowTopError() ? undefined : 25 : undefined;
343
- }
344
- getTopErrorsPosition() {
345
- return !this.props.title && this.shouldShowTopError() ? {
346
- top: Constants.isIOS ? -25 : -27
347
- } : undefined;
348
- }
349
- isDisabled() {
350
- return this.props.editable === false;
351
- }
352
- isCounterLimit() {
353
- const {
354
- maxLength
355
- } = this.getThemeProps();
356
- const counter = this.getCharCount();
357
- return counter === 0 ? false : maxLength <= counter;
358
- }
359
- hasText(value) {
360
- return !_isEmpty(value || this.state.value);
361
- }
362
- shouldShowHelperText() {
363
- const {
364
- focused
365
- } = this.state;
366
- const {
367
- helperText
368
- } = this.props;
369
- return focused && helperText;
370
- }
371
- shouldFloatOnFocus() {
372
- const {
373
- focused
374
- } = this.state;
375
- const {
376
- floatOnFocus
377
- } = this.getThemeProps();
378
- return focused && floatOnFocus;
379
- }
380
- shouldFloatPlaceholder(text) {
381
- return this.hasText(text) || this.shouldShowHelperText() || this.shouldFloatOnFocus();
382
- }
383
- shouldFakePlaceholder() {
384
- const {
385
- floatingPlaceholder,
386
- centered,
387
- leadingIcon,
388
- prefix
389
- } = this.getThemeProps();
390
- return !leadingIcon && !prefix && Boolean(floatingPlaceholder && !centered && !this.shouldShowTopError());
391
- }
392
- shouldShowError() {
393
- const {
394
- enableErrors
395
- } = this.getThemeProps();
396
- const error = this.getErrorMessage();
397
- return enableErrors && error;
398
- }
399
- getErrorMessage() {
400
- return this.props?.error || this.state?.error;
401
- }
402
- shouldShowTopError() {
403
- const {
404
- useTopErrors
405
- } = this.getThemeProps();
406
- return this.shouldShowError() && useTopErrors;
407
- }
408
- shouldDisplayRightButton() {
409
- const {
410
- rightButtonProps,
411
- expandable
412
- } = this.getThemeProps();
413
- return !expandable && rightButtonProps && rightButtonProps.iconSource;
414
- }
415
- shouldRenderTitle() {
416
- const {
417
- floatingPlaceholder,
418
- title
419
- } = this.getThemeProps();
420
- return !floatingPlaceholder && title;
421
- }
422
- onPressRightButton = () => {
423
- _invoke(this.props, 'rightButtonProps.onPress');
424
- };
425
-
426
- /** Renders */
427
- renderPlaceholder() {
428
- const {
429
- floatingPlaceholderState,
430
- floatingPlaceholderTranslate
431
- } = this.state;
432
- const {
433
- placeholder,
434
- placeholderTextColor,
435
- floatingPlaceholderColor,
436
- floatingPlaceholderStyle
437
- } = this.getThemeProps();
438
- const typography = this.getTypography();
439
- const placeholderColor = this.getStateColor(placeholderTextColor || PLACEHOLDER_COLOR_BY_STATE.default);
440
- if (this.shouldFakePlaceholder()) {
441
- return <View absF left>
442
- <Animated.Text pointerEvents="none" numberOfLines={1} suppressHighlighting accessible={false} onLayout={this.onPlaceholderLayout} style={[this.styles.placeholder, this.getTopErrorsPosition(), typography,
443
- // TODO: we need to exclude completely any dependency on line height
444
- // in this component since it always breaks alignments
445
- {
446
- lineHeight: undefined
447
- }, {
448
- transform: [{
449
- scale: floatingPlaceholderState.interpolate({
450
- inputRange: [0, 1],
451
- outputRange: [1, FLOATING_PLACEHOLDER_SCALE]
452
- })
453
- }, {
454
- translateY: floatingPlaceholderState.interpolate({
455
- inputRange: [0, 1],
456
- outputRange: [25, 0]
457
- })
458
- }, {
459
- translateX: floatingPlaceholderState.interpolate({
460
- inputRange: [0, 1],
461
- outputRange: [0, -floatingPlaceholderTranslate]
462
- })
463
- }],
464
- color: this.shouldFloatPlaceholder() ? this.getStateColor(floatingPlaceholderColor || PLACEHOLDER_COLOR_BY_STATE) : placeholderColor
465
- }, floatingPlaceholderStyle]}>
466
- {this.getRequiredPlaceholder(placeholder)}
467
- </Animated.Text>
468
- </View>;
469
- }
470
- }
471
- renderPrefix() {
472
- const {
473
- prefix,
474
- prefixStyle
475
- } = this.props;
476
- if (prefix) {
477
- const typography = this.getTypography();
478
- return <Text style={[this.styles.prefix, typography, {
479
- lineHeight: undefined
480
- }, prefixStyle]}>{prefix}</Text>;
481
- }
482
- }
483
- renderTitle() {
484
- const {
485
- title,
486
- titleColor,
487
- titleStyle
488
- } = this.getThemeProps();
489
- const color = this.getStateColor(titleColor || PLACEHOLDER_COLOR_BY_STATE);
490
- if (this.shouldRenderTitle()) {
491
- return <Text style={[{
492
- color
493
- }, this.styles.topLabel, this.styles.label, titleStyle]}>{title}</Text>;
494
- }
495
- }
496
- renderCharCounter() {
497
- const {
498
- maxLength,
499
- showCharacterCounter
500
- } = this.getThemeProps();
501
- if (maxLength && showCharacterCounter) {
502
- const counter = this.getCharCount();
503
- const color = this.getCharCountColor();
504
- return <Text style={[{
505
- color
506
- }, this.styles.bottomLabel, this.styles.label]} accessibilityLabel={`${counter} out of ${maxLength} max characters`}>
507
- {counter} / {maxLength}
508
- </Text>;
509
- }
510
- }
511
- renderError(visible) {
512
- const {
513
- enableErrors,
514
- useTopErrors,
515
- errorColor
516
- } = this.getThemeProps();
517
- const textColor = errorColor ? {
518
- color: errorColor
519
- } : undefined;
520
- const positionStyle = useTopErrors ? this.styles.topLabel : this.styles.bottomLabel;
521
- const error = this.getErrorMessage();
522
- if (visible && enableErrors) {
523
- return <Text style={[this.styles.errorMessage, this.styles.label, positionStyle, textColor]} accessible={!_isEmpty(error) && !useTopErrors}>
524
- {error}
525
- </Text>;
526
- }
527
- }
528
- renderExpandableModal() {
529
- const {
530
- renderExpandable,
531
- topBarProps
532
- } = this.getThemeProps();
533
- const {
534
- showExpandableModal
535
- } = this.state;
536
- if (_isFunction(renderExpandable) && showExpandableModal) {
537
- return renderExpandable(this.getThemeProps(), this.state);
538
- }
539
- const textInputProps = TextField.extractOwnProps(this.props, ['error', 'testID']);
540
- return <Modal animationType={'slide'} visible={showExpandableModal} onRequestClose={() => this.toggleExpandableModal(false)}>
541
- <Modal.TopBar {...topBarProps} onCancel={() => this.toggleExpandableModal(false)} onDone={this.onDoneEditingExpandableInput} />
542
- <View style={this.styles.expandableModalContent}>
543
- <TextArea ref={textarea => {
544
- this.expandableInput = textarea;
545
- }} {...textInputProps} value={this.state.value} />
546
- </View>
547
- </Modal>;
548
- }
549
- renderExpandableInput() {
550
- const {
551
- renderExpandableInput,
552
- testID
553
- } = this.getThemeProps();
554
- if (_isFunction(renderExpandableInput)) {
555
- return renderExpandableInput(this.getThemeProps(), this.toggleExpandableModal);
556
- }
557
- return <TouchableOpacity style={this.styles.expandableInput} activeOpacity={1} onPress={() => !this.isDisabled() && this.toggleExpandableModal(true)} testID={`${testID}.expandable`}
558
- // {...this.extractAccessibilityProps()}
559
- {...this.getAccessibilityInfo()}>
560
- {this.renderTextInput()}
561
- </TouchableOpacity>;
562
- }
563
- renderTextInput() {
564
- const {
565
- value
566
- } = this.state; // value set on state for floatingPlaceholder functionality
567
- const {
568
- style,
569
- placeholderTextColor,
570
- multiline,
571
- // hideUnderline,
572
- numberOfLines,
573
- expandable,
574
- rightIconSource,
575
- color,
576
- placeholder,
577
- helperText,
578
- ...others
579
- } = this.getThemeProps();
580
- const typography = this.getTypography();
581
- const {
582
- lineHeight,
583
- ...typographyStyle
584
- } = typography;
585
- const textColor = this.getStateColor(color || this.extractColorValue());
586
- const hasRightElement = this.shouldDisplayRightButton() || rightIconSource;
587
- const shouldUseMultiline = multiline /* || expandable */;
588
- const inputStyle = [hasRightElement && this.styles.rightElement, this.styles.input,
589
- // hideUnderline && this.styles.inputWithoutUnderline,
590
- {
591
- ...typographyStyle
592
- },
593
- // Constants.isAndroid && {lineHeight},
594
- expandable && {
595
- maxHeight: lineHeight * (Constants.isAndroid ? 3 : 3.3)
596
- }, Constants.isRTL && {
597
- minHeight: lineHeight + 3
598
- }, Constants.isIOS && shouldUseMultiline && {
599
- paddingTop: 0
600
- },
601
- // fix for iOS topPadding in multiline TextInput
602
- {
603
- color: textColor
604
- }, style];
605
- const placeholderText = this.getPlaceholderText(placeholder, helperText);
606
- const placeholderColor = this.getStateColor(placeholderTextColor || PLACEHOLDER_COLOR_BY_STATE.default);
607
- const isEditable = !this.isDisabled() && !expandable;
608
- return <RNTextInput {...this.getAccessibilityInfo()} pointerEvents={expandable ? 'none' : undefined} {...others} value={value} placeholder={placeholderText} placeholderTextColor={placeholderColor} underlineColorAndroid="transparent" style={inputStyle} multiline={shouldUseMultiline} numberOfLines={numberOfLines} onKeyPress={this.onKeyPress} onChangeText={this.onChangeText} onChange={this.onChange} onFocus={this.onFocus} onBlur={this.onBlur} ref={input => {
609
- this.input = input;
610
- }} editable={isEditable} />;
611
- }
612
- renderRightButton() {
613
- if (this.shouldDisplayRightButton()) {
614
- const {
615
- rightButtonProps
616
- } = this.getThemeProps();
617
- const {
618
- style,
619
- iconSource,
620
- iconColor,
621
- accessibilityLabel,
622
- ...others
623
- } = rightButtonProps;
624
- return <TouchableOpacity {...others} accessibilityLabel={accessibilityLabel} style={[this.styles.rightButton, this.getTopErrorsPosition(), style]} onPress={this.onPressRightButton}>
625
- <Image pointerEvents="none" source={iconSource} resizeMode={'contain'} style={[this.styles.rightButtonImage, {
626
- tintColor: iconColor || Colors.$iconPrimary
627
- }]} />
628
- </TouchableOpacity>;
629
- }
630
- }
631
- renderRightIcon() {
632
- const {
633
- rightIconSource,
634
- rightIconStyle
635
- } = this.getThemeProps();
636
- if (rightIconSource) {
637
- return <View style={[this.styles.rightButton, this.getTopErrorsPosition()]} pointerEvents="none">
638
- <Image source={rightIconSource} resizeMode={'center'} style={[this.styles.rightButtonImage, rightIconStyle]} />
639
- </View>;
640
- }
641
- }
642
- render() {
643
- const {
644
- expandable,
645
- containerStyle,
646
- underlineColor,
647
- useTopErrors,
648
- hideUnderline,
649
- leadingIcon
650
- } = this.getThemeProps();
651
- const underlineStateColor = this.getStateColor(underlineColor || UNDERLINE_COLOR_BY_STATE);
652
- return <View style={[this.styles.container, containerStyle]} collapsable={false}>
653
- {this.shouldShowTopError() ? this.renderError(useTopErrors) : this.renderTitle()}
654
-
655
- <View style={[this.styles.innerContainer, hideUnderline && this.styles.innerContainerWithoutUnderline, {
656
- borderColor: underlineStateColor
657
- }, {
658
- paddingTop: this.getTopPaddings()
659
- }]}>
660
- {leadingIcon && <Image {...leadingIcon} style={[this.styles.leadingIcon, leadingIcon.style]} />}
661
- {this.renderPrefix()}
662
- {this.renderPlaceholder()}
663
- {expandable ? this.renderExpandableInput() : this.renderTextInput()}
664
- {this.renderRightButton()}
665
- {this.renderRightIcon()}
666
- {expandable && this.renderExpandableModal()}
667
- </View>
668
-
669
- {!_isUndefined(this.getErrorMessage()) && useTopErrors && <View style={this.styles.accessibilityDummyErrorMessage} accessible accessibilityLabel={this.getErrorMessage()} />}
670
-
671
- <View row>
672
- <View flex>{this.renderError(!useTopErrors)}</View>
673
- {this.renderCharCounter()}
674
- </View>
675
- </View>;
676
- }
677
-
678
- /** Events */
679
- onDoneEditingExpandableInput = () => {
680
- const expandableInputValue = _get(this.expandableInput, 'state.value');
681
- this.setState({
682
- value: expandableInputValue
683
- });
684
- this.state.floatingPlaceholderState.setValue(expandableInputValue ? 1 : 0);
685
- _invoke(this.props, 'onChangeText', expandableInputValue);
686
- this.toggleExpandableModal(false);
687
- };
688
- onKeyPress = event => {
689
- this.lastKey = event.nativeEvent.key;
690
- this.setCharCountColor(this.lastKey);
691
- _invoke(this.props, 'onKeyPress', event);
692
- };
693
- onChangeText = text => {
694
- // when character count exceeds maxLength text will be empty string.
695
- // HACK: To avoid setting state value to '' we check the source of that deletion
696
- if (text === '' && this.lastKey && this.lastKey !== Constants.backspaceKey) {
697
- return;
698
- }
699
- const {
700
- transformer,
701
- validateOnChange
702
- } = this.props;
703
- let transformedText = text;
704
- if (_isFunction(transformer)) {
705
- transformedText = transformer(text);
706
- }
707
- _invoke(this.props, 'onChangeText', transformedText);
708
- this.setState({
709
- value: transformedText
710
- }, () => {
711
- if (validateOnChange) {
712
- setImmediate(this.validate);
713
- }
714
- });
715
- };
716
- }
717
- function createStyles({
718
- centered,
719
- multiline
720
- }, rightItemTopPadding = 0) {
721
- const itemTopPadding = Constants.isIOS ? rightItemTopPadding - 3 : rightItemTopPadding - 1;
722
- return StyleSheet.create({
723
- container: {},
724
- innerContainer: {
725
- // flexGrow: 1, // create bugs with lineHeight
726
- flexDirection: 'row',
727
- justifyContent: centered ? 'center' : undefined,
728
- borderBottomWidth: 1,
729
- borderColor: Colors.grey70,
730
- paddingBottom: Constants.isIOS ? 10 : 5
731
- },
732
- innerContainerWithoutUnderline: {
733
- borderBottomWidth: 0,
734
- paddingBottom: 0
735
- },
736
- input: {
737
- flexGrow: 1,
738
- textAlign: centered ? 'center' : Constants.isRTL ? 'right' : 'left',
739
- backgroundColor: 'transparent',
740
- // marginBottom: Constants.isIOS ? 10 : 5,
741
- padding: 0,
742
- // for Android
743
- // textAlignVertical: 'top', // for Android
744
- borderColor: 'transparent',
745
- // borderColor & borderWidth is a fix for collapsing issue on Android
746
- borderWidth: Constants.isAndroid ? 1 : undefined // for Android
747
- },
748
- expandableInput: {
749
- flexGrow: 1,
750
- flexDirection: 'row',
751
- alignItems: 'center'
752
- },
753
- // inputWithoutUnderline: {
754
- // marginBottom: undefined
755
- // },
756
- expandableModalContent: {
757
- flex: 1,
758
- paddingTop: 15,
759
- paddingHorizontal: 20
760
- },
761
- prefix: {
762
- color: Colors.grey30,
763
- marginRight: Spacings.s1,
764
- textAlignVertical: 'center'
765
- },
766
- placeholder: {
767
- textAlign: 'left'
768
- },
769
- errorMessage: {
770
- color: Colors.red30,
771
- textAlign: centered ? 'center' : 'left'
772
- },
773
- topLabel: {
774
- marginBottom: Constants.isIOS ? multiline ? 1 : 5 : 7
775
- },
776
- bottomLabel: {
777
- marginTop: 9
778
- },
779
- label: {
780
- ...LABEL_TYPOGRAPHY,
781
- height: LABEL_TYPOGRAPHY.lineHeight
782
- },
783
- rightElement: {
784
- paddingRight: ICON_SIZE + ICON_LEFT_PADDING
785
- },
786
- rightButton: {
787
- position: 'absolute',
788
- right: 0,
789
- alignSelf: 'flex-start',
790
- paddingTop: itemTopPadding
791
- },
792
- rightButtonImage: {
793
- width: ICON_SIZE,
794
- height: ICON_SIZE
795
- },
796
- leadingIcon: {
797
- alignSelf: 'center'
798
- },
799
- accessibilityDummyErrorMessage: {
800
- position: 'absolute',
801
- bottom: 0,
802
- left: 0,
803
- width: 1,
804
- height: 1
805
- }
806
- });
807
- }