@true-engineering/true-react-common-ui-kit 3.45.1 → 4.0.0-alpha0

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 (122) hide show
  1. package/README.md +0 -40
  2. package/dist/components/CloseButton/CloseButton.d.ts +1 -1
  3. package/dist/components/ControlGroup/ControlGroup.d.ts +10 -0
  4. package/dist/components/ControlGroup/ControlGroup.stories.d.ts +7 -0
  5. package/dist/components/ControlGroup/ControlGroup.styles.d.ts +3 -0
  6. package/dist/components/ControlGroup/index.d.ts +2 -0
  7. package/dist/components/ControlWrapper/ControlWrapper.d.ts +27 -0
  8. package/dist/components/ControlWrapper/ControlWrapper.stories.d.ts +6 -0
  9. package/dist/components/ControlWrapper/ControlWrapper.styles.d.ts +6 -0
  10. package/dist/components/ControlWrapper/index.d.ts +2 -0
  11. package/dist/components/DateInput/DateInput.d.ts +3 -3
  12. package/dist/components/DatePicker/components/DatePickerHeader/DatePickerHeader.styles.d.ts +1 -1
  13. package/dist/components/DatePicker/types.d.ts +1 -1
  14. package/dist/components/FiltersPane/FiltersPane.stories.d.ts +1 -2
  15. package/dist/components/FiltersPane/components/FilterWithDates/FilterWithDates.d.ts +1 -1
  16. package/dist/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.d.ts +1 -2
  17. package/dist/components/Input/Input.d.ts +5 -52
  18. package/dist/components/Input/Input.stories.d.ts +4 -13
  19. package/dist/components/Input/Input.styles.d.ts +5 -4
  20. package/dist/components/Input/InputBase.d.ts +24 -0
  21. package/dist/components/Input/index.d.ts +1 -0
  22. package/dist/components/Input/types.d.ts +3 -4
  23. package/dist/components/NumberInput/NumberInput.d.ts +3 -3
  24. package/dist/components/PhoneInput/PhoneInput.d.ts +3 -3
  25. package/dist/components/PhoneInput/PhoneInput.stories.d.ts +2 -2
  26. package/dist/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.d.ts +3 -2
  27. package/dist/components/PhoneInput/types.d.ts +2 -0
  28. package/dist/components/SearchInput/SearchInput.d.ts +1 -3
  29. package/dist/components/SearchInput/SearchInput.stories.d.ts +11 -1
  30. package/dist/components/SearchInput/SearchInput.styles.d.ts +1 -1
  31. package/dist/components/Select/Select.d.ts +5 -5
  32. package/dist/components/Select/Select.styles.d.ts +17 -16
  33. package/dist/components/Select/types.d.ts +3 -0
  34. package/dist/components/SmartInput/SmartInput.d.ts +3 -3
  35. package/dist/components/TextArea/TextArea.d.ts +5 -14
  36. package/dist/components/TextArea/TextArea.styles.d.ts +8 -2
  37. package/dist/components/WithPopup/WithPopup.d.ts +3 -10
  38. package/dist/components/WithPopup/WithPopup.styles.d.ts +1 -1
  39. package/dist/components/WithPopup/types.d.ts +0 -3
  40. package/dist/components/WithTooltip/WithTooltip.styles.d.ts +0 -1
  41. package/dist/components/index.d.ts +2 -0
  42. package/dist/theme/common.d.ts +13 -5
  43. package/dist/theme/types.d.ts +4 -2
  44. package/dist/true-react-common-ui-kit.js +1184 -1029
  45. package/dist/true-react-common-ui-kit.js.map +1 -1
  46. package/dist/true-react-common-ui-kit.umd.cjs +1164 -1009
  47. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  48. package/dist/types.d.ts +2 -1
  49. package/package.json +1 -1
  50. package/src/components/Button/Button.stories.tsx +4 -8
  51. package/src/components/CloseButton/CloseButton.tsx +4 -4
  52. package/src/components/ControlGroup/ControlGroup.stories.tsx +40 -0
  53. package/src/components/ControlGroup/ControlGroup.styles.ts +46 -0
  54. package/src/components/ControlGroup/ControlGroup.tsx +55 -0
  55. package/src/components/ControlGroup/index.ts +2 -0
  56. package/src/components/ControlWrapper/ControlWrapper.stories.tsx +45 -0
  57. package/src/components/ControlWrapper/ControlWrapper.styles.ts +185 -0
  58. package/src/components/ControlWrapper/ControlWrapper.tsx +151 -0
  59. package/src/components/ControlWrapper/index.ts +2 -0
  60. package/src/components/DateInput/DateInput.styles.ts +2 -7
  61. package/src/components/DateInput/DateInput.tsx +4 -4
  62. package/src/components/DatePicker/DatePicker.tsx +3 -3
  63. package/src/components/DatePicker/components/DatePickerHeader/DatePickerHeader.styles.ts +7 -41
  64. package/src/components/DatePicker/components/DatePickerHeader/DatePickerHeader.tsx +18 -26
  65. package/src/components/DatePicker/types.ts +1 -1
  66. package/src/components/FileItem/FileItem.stories.tsx +4 -8
  67. package/src/components/FiltersPane/FiltersPane.stories.tsx +0 -4
  68. package/src/components/FiltersPane/components/FilterInterval/FilterInterval.styles.ts +9 -7
  69. package/src/components/FiltersPane/components/FilterInterval/FilterInterval.tsx +1 -8
  70. package/src/components/FiltersPane/components/FilterSelect/FilterSelect.styles.ts +7 -5
  71. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.tsx +7 -9
  72. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.styles.ts +12 -17
  73. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.tsx +2 -5
  74. package/src/components/IconButton/IconButton.stories.tsx +5 -5
  75. package/src/components/IncrementInput/IncrementInput.stories.tsx +0 -2
  76. package/src/components/IncrementInput/IncrementInput.styles.ts +9 -9
  77. package/src/components/Input/Input.stories.tsx +17 -25
  78. package/src/components/Input/Input.styles.ts +50 -260
  79. package/src/components/Input/Input.tsx +22 -285
  80. package/src/components/Input/InputBase.tsx +250 -0
  81. package/src/components/Input/index.ts +1 -0
  82. package/src/components/Input/types.ts +3 -32
  83. package/src/components/MultiSelectList/MultiSelectList.styles.ts +7 -5
  84. package/src/components/Notification/Notification.stories.tsx +2 -6
  85. package/src/components/NumberInput/NumberInput.stories.tsx +0 -2
  86. package/src/components/NumberInput/NumberInput.tsx +4 -7
  87. package/src/components/PhoneInput/PhoneInput.stories.tsx +6 -10
  88. package/src/components/PhoneInput/PhoneInput.styles.ts +13 -10
  89. package/src/components/PhoneInput/PhoneInput.tsx +9 -12
  90. package/src/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.styles.ts +6 -4
  91. package/src/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.tsx +6 -6
  92. package/src/components/PhoneInput/types.ts +4 -0
  93. package/src/components/SearchInput/SearchInput.stories.tsx +1 -0
  94. package/src/components/SearchInput/SearchInput.styles.ts +17 -27
  95. package/src/components/SearchInput/SearchInput.tsx +13 -34
  96. package/src/components/Select/CustomSelect.stories.tsx +6 -9
  97. package/src/components/Select/MultiSelect.stories.tsx +4 -12
  98. package/src/components/Select/Select.stories.tsx +3 -11
  99. package/src/components/Select/Select.styles.ts +28 -42
  100. package/src/components/Select/Select.tsx +73 -81
  101. package/src/components/Select/types.ts +5 -0
  102. package/src/components/SmartInput/SmartInput.stories.tsx +0 -1
  103. package/src/components/SmartInput/SmartInput.tsx +4 -4
  104. package/src/components/Status/Status.stories.tsx +3 -7
  105. package/src/components/TextArea/TextArea.stories.tsx +1 -3
  106. package/src/components/TextArea/TextArea.styles.ts +27 -126
  107. package/src/components/TextArea/TextArea.tsx +86 -112
  108. package/src/components/TextButton/TextButton.stories.tsx +4 -8
  109. package/src/components/WithPopup/WithPopup.stories.tsx +0 -1
  110. package/src/components/WithPopup/WithPopup.styles.ts +0 -2
  111. package/src/components/WithPopup/WithPopup.tsx +10 -36
  112. package/src/components/WithPopup/types.ts +0 -7
  113. package/src/components/WithTooltip/WithTooltip.styles.ts +0 -6
  114. package/src/components/WithTooltip/WithTooltip.tsx +2 -7
  115. package/src/components/index.ts +2 -0
  116. package/src/theme/common.ts +15 -6
  117. package/src/theme/types.ts +8 -4
  118. package/src/types.ts +3 -0
  119. package/dist/components/Input/constants.d.ts +0 -1
  120. package/dist/components/WithPopup/helpers.d.ts +0 -2
  121. package/src/components/Input/constants.ts +0 -1
  122. package/src/components/WithPopup/helpers.ts +0 -9
@@ -1,308 +1,98 @@
1
- import { dimensions, ITweakStyles, createThemedStyles, animations } from '../../theme';
2
- import { IThemedPreloaderStyles } from '../ThemedPreloader';
1
+ import { createThemedStyles, ITweakStyles } from '../../theme';
2
+ import { IControlGroupStyles } from '../ControlGroup';
3
+ import { IControlWrapperStyles } from '../ControlWrapper';
3
4
 
4
- const PADDING_X = 12;
5
- export const AUTOSIZE_MAX_WIDTH = 480;
5
+ const PADDING_WITH_UNITS = 8;
6
6
 
7
7
  export const useStyles = createThemedStyles('Input', {
8
- root: {
9
- width: '100%',
10
- boxSizing: 'border-box',
11
- position: 'relative',
12
- },
13
-
14
- inputWrapper: {
15
- display: 'flex',
16
- width: '100%',
17
- height: dimensions.CONTROL_HEIGHT,
18
- boxSizing: 'border-box',
19
- transition: animations.defaultTransition,
20
- transitionProperty: 'border-color',
21
- backgroundColor: 'white',
22
- position: 'relative',
23
- },
24
-
25
8
  inputContent: {
9
+ height: 'var(--control-height)',
10
+ padding: [0, 'var(--control-padding)'],
26
11
  fontSize: 16,
27
12
  fontFamily: 'inherit',
28
- padding: [0, PADDING_X],
29
13
  },
30
14
 
31
15
  input: {
32
16
  extend: 'inputContent',
33
17
  width: '100%',
34
- height: '100%',
35
18
  outline: 'none',
36
- boxSizing: 'border-box',
37
19
  outlineStyle: 'none',
38
- transition: animations.defaultTransition,
39
- transitionProperty: 'background-color',
20
+ boxSizing: 'border-box',
40
21
  border: 'none',
41
22
  background: 'none',
23
+ color: 'black',
42
24
 
43
- '&::placeholder': {
44
- opacity: 1,
25
+ '&[readonly]': {
26
+ cursor: 'default',
45
27
  },
46
28
 
47
- MozAppearance: 'textfield',
48
- '&::-webkit-inner-spin-button,&::-webkit-outer-spin-button': {
49
- WebkitAppearance: 'none',
50
- margin: 0,
29
+ '&::placeholder': {
30
+ opacity: 1,
51
31
  },
52
- },
53
-
54
- autosize: {
55
- display: 'inline-grid',
56
- verticalAlign: 'top',
57
- alignItems: 'center',
58
- justifyContent: 'start',
59
32
 
60
- '&::after, input': {
61
- width: 'auto',
62
- minWidth: '1em',
63
- gridArea: '1 / 2',
64
- font: 'inherit',
65
- justifySelf: 'stretch',
33
+ '&::-webkit-date-and-time-value': {
34
+ textAlign: 'left',
66
35
  },
67
36
 
68
- '&::after': {
69
- maxWidth: AUTOSIZE_MAX_WIDTH,
70
- content: 'attr(data-value) " "',
71
- visibility: 'hidden',
72
- whiteSpace: 'pre-wrap',
73
- },
37
+ MozAppearance: 'textfield',
38
+ '&::-webkit-inner-spin-button,&::-webkit-outer-spin-button,&::-webkit-calendar-picker-indicator':
39
+ {
40
+ display: 'none',
41
+ WebkitAppearance: 'none',
42
+ margin: 0,
43
+ },
74
44
  },
75
45
 
76
- focused: {
46
+ autoSizeWrapper: {
77
47
  position: 'relative',
78
- zIndex: 1,
79
- },
80
-
81
- unitsWrapper: {
82
- extend: 'inputContent',
83
- position: 'absolute',
84
- left: 0,
85
- height: '100%',
86
- boxSizing: 'border-box',
87
48
  display: 'flex',
88
- alignItems: 'center',
89
- pointerEvents: 'none',
90
- },
91
-
92
- fakeValue: {
93
- visibility: 'hidden',
94
- },
95
-
96
- units: {
97
- paddingLeft: 4,
98
- },
99
-
100
- withFloatingLabel: {
101
- paddingTop: 18,
102
- },
103
-
104
- floatingLabelWithoutPadding: {
105
- paddingTop: 18,
106
- paddingLeft: 0,
49
+ minWidth: 0,
50
+ zIndex: 0,
51
+ flexGrow: 1,
107
52
  },
108
53
 
109
- floating: {},
110
-
111
- activeLabel: {
112
- display: 'none',
113
-
114
- '&$floating': {
115
- display: 'block',
116
- transform: 'scale(0.75) translateY(-120%)',
117
- },
118
- },
119
-
120
- required: {
121
- '&:before': {
122
- content: '""',
123
- position: 'absolute',
124
- left: -12,
125
- top: '50%',
126
- transform: 'translate(0, -50%)',
127
- width: 6,
128
- height: 6,
129
- borderRadius: '50%',
130
- },
131
- },
132
-
133
- label: {
54
+ autoSized: {
134
55
  position: 'absolute',
135
- pointerEvents: 'none',
136
- left: PADDING_X,
137
- top: '50%',
138
- transformOrigin: 'top left',
139
- transform: 'translateY(-50%)',
140
- transition: animations.defaultTransition,
141
- transitionProperty: 'transform, color',
142
- fontSize: 16,
143
- },
144
-
145
- floatingWithoutPadding: {
56
+ top: 0,
146
57
  left: 0,
58
+ height: '100%',
147
59
  },
148
60
 
149
- requiredLabel: {
150
- '&:after': {
151
- content: '""',
152
- position: 'absolute',
153
- right: -8,
154
- top: 4,
155
- transform: 'translate(0, -50%)',
156
- width: 6,
157
- height: 6,
158
- borderRadius: '50%',
159
- },
160
- },
161
-
162
- activeIcon: {
163
- cursor: 'pointer',
164
- },
165
-
166
- 'border-top': {
167
- borderRadius: 0,
168
- borderWidth: [1, 0, 0, 0],
169
- },
170
-
171
- 'border-bottom': {
172
- borderRadius: 0,
173
- borderWidth: [0, 0, 1, 0],
174
- },
175
-
176
- 'border-left': {
177
- borderRadius: 0,
178
- borderWidth: [0, 0, 0, 1],
179
- },
180
-
181
- 'border-right': {
182
- borderRadius: 0,
183
- borderWidth: [0, 1, 0, 0],
184
- },
185
-
186
- top: {
187
- borderBottomLeftRadius: 0,
188
- borderBottomRightRadius: 0,
189
- },
190
-
191
- bottom: {
192
- borderTopLeftRadius: 0,
193
- borderTopRightRadius: 0,
194
- },
195
-
196
- 'top-left': {
197
- borderTopRightRadius: 0,
198
- borderBottomLeftRadius: 0,
199
- borderBottomRightRadius: 0,
200
- },
201
-
202
- 'top-right': {
203
- borderTopLeftRadius: 0,
204
- borderBottomLeftRadius: 0,
205
- borderBottomRightRadius: 0,
206
- },
207
-
208
- 'bottom-left': {
209
- borderTopLeftRadius: 0,
210
- borderTopRightRadius: 0,
211
- borderBottomRightRadius: 0,
212
- },
213
-
214
- 'bottom-right': {
215
- borderTopLeftRadius: 0,
216
- borderTopRightRadius: 0,
217
- borderBottomLeftRadius: 0,
218
- },
219
-
220
- left: {
221
- borderTopRightRadius: 0,
222
- borderBottomRightRadius: 0,
223
- },
224
-
225
- right: {
226
- borderTopLeftRadius: 0,
227
- borderBottomLeftRadius: 0,
228
- },
229
-
230
- middle: {
231
- borderRadius: 0,
232
- },
233
-
234
- controls: {
235
- display: 'flex',
236
- gridArea: '1 / 3',
237
- },
238
-
239
- icon: {
240
- display: 'flex',
241
- alignItems: 'center',
242
- padding: [0, 4],
243
- width: 20,
244
- transition: animations.defaultTransition,
245
- transitionProperty: 'color',
246
- boxSizing: 'content-box',
61
+ withUnits: {
62
+ extend: 'autoSized',
63
+ paddingRight: `calc(${PADDING_WITH_UNITS}px + var(--units-width) - 1px)`,
247
64
 
248
- '&:last-child': {
249
- paddingRight: 8,
65
+ '& + $fakeValue': {
66
+ paddingRight: PADDING_WITH_UNITS,
250
67
  },
251
-
252
- '& + $units': {
253
- marginLeft: 4,
254
- },
255
- },
256
-
257
- clearIcon: {
258
- extend: 'icon',
259
- },
260
-
261
- inputIcon: {
262
- extend: 'icon',
263
68
  },
264
69
 
265
- withIcons: {
266
- paddingRight: 4,
267
- },
268
-
269
- withControls: {},
270
-
271
- invalid: {},
272
-
273
- disabled: {},
274
-
275
- invalidLabel: {},
276
-
277
- error: {
278
- fontSize: 12,
279
- },
70
+ withLabel: {},
280
71
 
281
- info: {
282
- fontSize: 12,
283
- paddingTop: 4,
284
- paddingLeft: 13,
72
+ fakeValue: {
73
+ extend: 'inputContent',
74
+ visibility: 'hidden',
75
+ maxWidth: '100%',
76
+ overflow: 'hidden',
77
+ minWidth: 8,
285
78
  },
286
79
 
287
- 'error-top': {
288
- position: 'absolute',
289
- top: -18,
290
- left: -1,
291
- padding: [4, 8],
292
- zIndex: 1,
80
+ units: {
81
+ alignSelf: 'center',
82
+ paddingRight: 'var(--control-padding)',
293
83
  },
294
84
 
295
- 'error-bottom': {
296
- paddingTop: 4,
297
- paddingLeft: 13,
298
- },
85
+ focusedInput: {},
299
86
 
300
- loading: {},
87
+ disabledInput: {},
301
88
 
302
- withUnits: {},
89
+ invalidInput: {},
303
90
  });
304
91
 
305
92
  export type IInputStyles = ITweakStyles<
306
93
  typeof useStyles,
307
- { tweakPreloader: IThemedPreloaderStyles }
94
+ {
95
+ tweakControlWrapper: IControlWrapperStyles;
96
+ tweakControlGroup: IControlGroupStyles;
97
+ }
308
98
  >;
@@ -1,296 +1,33 @@
1
- import {
2
- forwardRef,
3
- useRef,
4
- useState,
5
- MutableRefObject,
6
- FormEvent,
7
- FocusEvent,
8
- MouseEvent,
9
- InputHTMLAttributes,
10
- ReactNode,
11
- } from 'react';
12
- import InputMask from 'react-input-mask';
13
- import clsx from 'clsx';
14
- import {
15
- addDataTestId,
16
- isReactNodeNotEmpty,
17
- isStringNotEmpty,
18
- } from '@true-engineering/true-react-platform-helpers';
19
- import { addDataAttributes } from '../../helpers';
1
+ import { forwardRef } from 'react';
20
2
  import { useTweakStyles } from '../../hooks';
21
- import { ICommonProps } from '../../types';
22
- import { renderIcon, Icon, IIcon } from '../Icon';
23
- import { ThemedPreloader } from '../ThemedPreloader';
24
- import { DEFAULT_SIZE } from './constants';
25
- import { IInputHTMLBaseProps, IReactInputMaskProps } from './types';
26
- import { useStyles, IInputStyles } from './Input.styles';
3
+ import { ControlGroup, IControlGroupProps } from '../ControlGroup';
4
+ import { IInputBaseProps, InputBase } from './InputBase';
27
5
 
28
- export interface IInputProps
29
- extends ICommonProps<IInputStyles>,
30
- IReactInputMaskProps,
31
- IInputHTMLBaseProps {
32
- value?: string;
33
- label?: ReactNode;
34
- /** @default false */
35
- isDisabled?: boolean;
36
- /** @default true */
37
- hasFloatingLabel?: boolean;
38
- /** @default false */
39
- isReadonly?: boolean;
40
- /** @default false */
41
- isInvalid?: boolean;
42
- /** @default false */
43
- isActive?: boolean;
44
- /** @default false */
45
- isClearable?: boolean;
46
- infoMessage?: string;
47
- errorMessage?: string;
48
- /** @default 'bottom' */
49
- errorPosition?: 'top' | 'bottom';
50
- inlineStyle?:
51
- | 'top'
52
- | 'bottom'
53
- | 'top-left'
54
- | 'top-right'
55
- | 'bottom-left'
56
- | 'bottom-right'
57
- | 'left'
58
- | 'right'
59
- | 'middle';
60
- border?: 'top' | 'bottom' | 'left' | 'right';
61
- /** @default false */
62
- isRequired?: boolean;
63
- /** @default false */
64
- isLoading?: boolean;
65
- /**
66
- * Должна ли ширина input'а подстраиваться под ширину контента
67
- * @default false
68
- */
69
- isAutoSizeable?: boolean;
70
- /**
71
- * Ширина input'а по умолчанию. Используется только вместе с `isAutoSizeable` равному `true`
72
- * @default 6
73
- */
74
- defaultSize?: number;
75
- iconType?: IIcon;
76
- units?: string;
77
- /** @default false */
78
- hasRequiredLabel?: boolean;
79
- /** @default false */
80
- shouldFocusOnMount?: boolean;
81
- /** @default false */
82
- shouldAlwaysShowPlaceholder?: boolean;
83
- onChange: (value: string, event: FormEvent<HTMLInputElement>) => void;
84
- onIconClick?: () => void;
85
- }
6
+ export type IInputProps = IInputBaseProps &
7
+ Pick<IControlGroupProps, 'infoMessage' | 'errorMessage'>;
86
8
 
87
9
  export const Input = forwardRef<HTMLInputElement, IInputProps>(
88
- (
89
- {
90
- value = '',
91
- label,
92
- placeholder,
93
- type = 'text',
94
- isDisabled,
95
- isReadonly = false,
96
- hasFloatingLabel = true,
97
- isInvalid = false,
98
- isActive = false,
99
- isClearable = false,
100
- infoMessage,
101
- errorMessage,
102
- errorPosition = 'bottom',
103
- inlineStyle,
104
- border,
105
- isRequired = false,
106
- isLoading = false,
107
- isAutoSizeable = false,
108
- defaultSize = DEFAULT_SIZE,
109
- iconType,
110
- hasRequiredLabel,
111
- data,
10
+ ({ infoMessage, errorMessage, isInvalid, testId, tweakStyles, ...inputProps }, ref) => {
11
+ const tweakControlGroupStyles = useTweakStyles({
112
12
  tweakStyles,
113
- shouldFocusOnMount = false,
114
- units,
115
- testId,
116
- onChange,
117
- onFocus,
118
- onBlur,
119
- onIconClick,
120
- // Пропсы react-input-mask
121
- mask,
122
- maskPlaceholder,
123
- alwaysShowMask,
124
- shouldAlwaysShowPlaceholder = false,
125
- beforeMaskedStateChange,
126
- ...inputProps
127
- },
128
- ref,
129
- ) => {
130
- const classes = useStyles({ theme: tweakStyles });
131
-
132
- const tweakPreloaderStyles = useTweakStyles({
133
- tweakStyles,
134
- className: 'tweakPreloader',
135
- currentComponentName: 'Input',
13
+ className: 'tweakControlGroup',
136
14
  });
137
15
 
138
- const [isFocused, setFocused] = useState(false);
139
- const inputRef = useRef<HTMLInputElement>(null);
140
-
141
- const handleChange = (event: FormEvent<HTMLInputElement>) => {
142
- onChange(event.currentTarget.value, event);
143
- };
144
-
145
- const handleFocus = (event: FocusEvent<HTMLInputElement>) => {
146
- setFocused(true);
147
- onFocus?.(event);
148
- };
149
-
150
- const handleBlur = (event: FocusEvent<HTMLInputElement>) => {
151
- setFocused(false);
152
- onBlur?.(event);
153
- };
154
-
155
- // для SmartInput нужен event, иначе onChange не вызовется
156
- const handleOnInputClear = async (event: MouseEvent<HTMLDivElement>) => {
157
- // await не убирать (важно для порядка выполнения (сначала onChange, затем focus)
158
- await onChange('', event as any);
159
- const input = (ref as MutableRefObject<HTMLInputElement>) ?? inputRef;
160
- input.current?.focus();
161
- };
162
-
163
- const hasFocus = isFocused || isActive;
164
- const hasClearIcon = isClearable && value.length > 0;
165
- const hasControls = hasClearIcon || iconType !== undefined || isLoading;
166
- const hasValue = value !== undefined && value !== '';
167
- const hasUnits = units !== undefined && units !== '';
168
- const hasLabel = isReactNodeNotEmpty(label);
169
- const isLabelActive = (hasFocus && !isReadonly) || hasValue || shouldAlwaysShowPlaceholder;
170
- const hasPlaceholder = (!hasLabel || isLabelActive) && isStringNotEmpty(placeholder);
171
- const shouldShowUnits = (hasValue || (isFocused && !hasPlaceholder)) && hasUnits;
172
-
173
- const props: InputHTMLAttributes<HTMLInputElement> = {
174
- ...inputProps,
175
- ...addDataTestId(testId),
176
- className: clsx(classes.input, {
177
- [classes.withFloatingLabel]: hasFloatingLabel && hasLabel,
178
- [classes.withIcons]: hasControls,
179
- [classes.withControls]: hasControls,
180
- [classes.withUnits]: shouldShowUnits,
181
- [classes.floatingLabelWithoutPadding]: hasFloatingLabel && hasLabel && border === 'bottom',
182
- }),
183
- onFocus: handleFocus,
184
- onBlur: handleBlur,
185
- onChange: handleChange,
186
- value,
187
- type,
188
- disabled: isDisabled,
189
- placeholder: hasPlaceholder ? placeholder : undefined,
190
- autoFocus: shouldFocusOnMount,
191
- readOnly: isReadonly,
192
- size: isAutoSizeable ? defaultSize : undefined,
193
- };
194
-
195
16
  return (
196
- <div className={classes.root}>
197
- <div
198
- className={clsx(
199
- classes.inputWrapper,
200
- {
201
- [classes.required]: isRequired && !hasRequiredLabel,
202
- [classes.invalid]: isInvalid,
203
- [classes.focused]: hasFocus,
204
- [classes.disabled]: isDisabled,
205
- [classes.autosize]: isAutoSizeable,
206
- },
207
- inlineStyle !== undefined && classes[inlineStyle],
208
- border !== undefined && classes[`border-${border}`],
209
- )}
210
- data-value={isAutoSizeable ? value : undefined}
211
- {...addDataAttributes(data)}
212
- >
213
- {mask === undefined ? (
214
- <input ref={ref ?? inputRef} {...props} />
215
- ) : (
216
- <InputMask
217
- // Баг в типизации react-input-mask
218
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
219
- // @ts-ignore: No overload matches this call
220
- ref={ref ?? inputRef}
221
- mask={mask}
222
- maskPlaceholder={maskPlaceholder}
223
- alwaysShowMask={alwaysShowMask}
224
- beforeMaskedStateChange={beforeMaskedStateChange}
225
- {...props}
226
- />
227
- )}
228
- {hasLabel && (
229
- <span
230
- className={clsx(classes.label, {
231
- [classes.invalidLabel]: isInvalid,
232
- [classes.requiredLabel]: hasRequiredLabel && !isRequired,
233
- [classes.activeLabel]: isLabelActive,
234
- [classes.floating]: hasFloatingLabel,
235
- // Обсуждаемо, сделал так, потому что не хочется создавать новую пропсу, на каждый чих в стилях
236
- [classes.floatingWithoutPadding]: hasFloatingLabel && border === 'bottom',
237
- })}
238
- >
239
- {label}
240
- </span>
241
- )}
242
-
243
- {shouldShowUnits && (
244
- <div
245
- className={clsx(classes.unitsWrapper, {
246
- [classes.withFloatingLabel]: hasFloatingLabel && hasLabel,
247
- })}
248
- >
249
- <span className={classes.fakeValue}>{value}</span>
250
- <span className={classes.units}>{units}</span>
251
- </div>
252
- )}
253
-
254
- {hasControls && (
255
- <div className={classes.controls}>
256
- {isLoading && (
257
- <div className={clsx(classes.inputIcon, classes.loading)}>
258
- <ThemedPreloader tweakStyles={tweakPreloaderStyles} />
259
- </div>
260
- )}
261
-
262
- {!isDisabled && hasClearIcon && (
263
- <div
264
- // .clearIcon extend .icon
265
- className={clsx(classes.clearIcon, classes.activeIcon)}
266
- // превентим блур с инпута (важно)
267
- onMouseDown={(event) => event.preventDefault()}
268
- onClick={handleOnInputClear}
269
- >
270
- <Icon type="close" />
271
- </div>
272
- )}
273
- {isReactNodeNotEmpty(iconType) && (
274
- <div
275
- // .inputIcon extend .icon
276
- className={clsx(classes.inputIcon, {
277
- [classes.activeIcon]: !isDisabled && onIconClick !== undefined,
278
- })}
279
- onClick={!isDisabled ? onIconClick : undefined}
280
- >
281
- {renderIcon(iconType)}
282
- </div>
283
- )}
284
- </div>
285
- )}
286
- </div>
287
- {isStringNotEmpty(infoMessage) && <div className={classes.info}>{infoMessage}</div>}
288
- {isStringNotEmpty(errorMessage) && (
289
- <div className={clsx(classes.error, classes[`error-${errorPosition}`])}>
290
- {errorMessage}
291
- </div>
292
- )}
293
- </div>
17
+ <ControlGroup
18
+ errorMessage={errorMessage}
19
+ infoMessage={infoMessage}
20
+ testId={testId}
21
+ tweakStyles={tweakControlGroupStyles}
22
+ >
23
+ <InputBase
24
+ {...inputProps}
25
+ ref={ref}
26
+ testId={testId}
27
+ tweakStyles={tweakStyles}
28
+ isInvalid={isInvalid}
29
+ />
30
+ </ControlGroup>
294
31
  );
295
32
  },
296
33
  );