@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,8 +1,7 @@
1
- import { rgba } from '../../helpers';
2
- import { colors, createThemedStyles, ITweakStyles } from '../../theme';
1
+ import { colors, createThemedStyles, dimensions, ITweakStyles } from '../../theme';
3
2
  import { IInputStyles } from '../Input';
4
3
 
5
- const LEFT_PADDING = 44;
4
+ const { Z_INDEX } = dimensions;
6
5
 
7
6
  export const useStyles = createThemedStyles('SearchInput', {
8
7
  root: {
@@ -16,38 +15,29 @@ export const useStyles = createThemedStyles('SearchInput', {
16
15
  left: 12,
17
16
  height: '100%',
18
17
  width: 20,
19
- zIndex: 2,
20
18
  color: colors.GREY_ACTIVE,
21
- },
22
-
23
- iconClickable: {
24
- cursor: 'pointer',
19
+ zIndex: Z_INDEX.CONTROL_FOCUS + 1,
25
20
  },
26
21
  });
27
22
 
28
23
  export const inputStyles: IInputStyles = {
29
- inputWrapper: {
30
- height: 35,
31
- borderColor: 'transparent',
32
- backgroundColor: rgba(colors.BORDER_MAIN, 0.3),
33
- borderRadius: 18,
34
- paddingLeft: LEFT_PADDING,
35
- transitionProperty: 'background-color, border-color',
36
- },
37
-
38
- focused: {
39
- backgroundColor: colors.CLASSIC_WHITE,
40
- borderColor: colors.BORDER_MAIN,
41
- },
42
-
43
- input: {
44
- fontSize: 14,
45
- paddingLeft: 0,
24
+ tweakControlWrapper: {
25
+ root: {
26
+ borderColor: 'transparent',
27
+ borderRadius: 18,
28
+ paddingLeft: 0,
29
+ transitionProperty: 'background-color, border-color',
30
+ },
31
+
32
+ focused: {
33
+ backgroundColor: colors.CLASSIC_WHITE,
34
+ borderColor: colors.BORDER_MAIN,
35
+ },
46
36
  },
47
37
 
48
- label: {
49
- left: LEFT_PADDING,
38
+ inputContent: {
50
39
  fontSize: 14,
40
+ paddingLeft: 44,
51
41
  },
52
42
  };
53
43
 
@@ -1,41 +1,25 @@
1
1
  import { FC } from 'react';
2
- import clsx from 'clsx';
3
- import {
4
- addClickHandler,
5
- addDataAttributes,
6
- getTestId,
7
- isNotEmpty,
8
- } from '@true-engineering/true-react-platform-helpers';
2
+ import { addDataTestId, getTestId } from '@true-engineering/true-react-platform-helpers';
3
+ import { addDataAttributes } from '../../helpers';
9
4
  import { useTweakStyles } from '../../hooks';
10
5
  import { ICommonProps } from '../../types';
11
6
  import { Icon } from '../Icon';
12
7
  import { IInputProps, Input } from '../Input';
13
8
  import { inputStyles, ISearchInputStyles, useStyles } from './SearchInput.styles';
14
9
 
15
- export interface ISearchInputProps
16
- extends ICommonProps<ISearchInputStyles>,
17
- Omit<
18
- IInputProps,
19
- | 'type'
20
- | 'isInvalid'
21
- | 'errorMessage'
22
- | 'label'
23
- | 'isActive'
24
- | 'errorPosition'
25
- | 'hasFloatingLabel'
26
- | 'border'
27
- | 'tweakStyles'
28
- > {
29
- // TODO: Можно будет удалить в 4й версии
30
- onSearchIconClick?: () => void;
31
- }
10
+ export type ISearchInputProps = Omit<
11
+ IInputProps,
12
+ 'type' | 'label' | 'isInvalid' | 'errorMessage' | 'isActive' | 'tweakStyles'
13
+ > &
14
+ ICommonProps<ISearchInputStyles>;
32
15
 
33
16
  export const SearchInput: FC<ISearchInputProps> = ({
34
17
  isClearable = true,
35
18
  tweakStyles,
19
+ placeholder,
20
+ value,
36
21
  testId,
37
22
  data,
38
- onSearchIconClick,
39
23
  ...props
40
24
  }) => {
41
25
  const classes = useStyles({ theme: tweakStyles });
@@ -48,21 +32,16 @@ export const SearchInput: FC<ISearchInputProps> = ({
48
32
  });
49
33
 
50
34
  return (
51
- <div className={classes.root} {...addDataAttributes(data, testId)}>
52
- <div
53
- className={clsx(classes.icon, { [classes.iconClickable]: isNotEmpty(onSearchIconClick) })}
54
- {...addClickHandler(onSearchIconClick)}
55
- >
35
+ <div className={classes.root} {...addDataTestId(testId)} {...addDataAttributes(data)}>
36
+ <div className={classes.icon}>
56
37
  <Icon type="search" />
57
38
  </div>
58
39
  <Input
59
- inputMode="search"
40
+ value={value}
41
+ placeholder={placeholder}
60
42
  isClearable={isClearable}
61
- isActive={props.value !== '' && props.value !== undefined}
62
43
  testId={getTestId(testId, 'input')}
63
44
  tweakStyles={tweakInputStyles}
64
- hasFloatingLabel={false}
65
- label={props.placeholder}
66
45
  {...props}
67
46
  />
68
47
  </div>
@@ -3,9 +3,9 @@ import { createUseStyles } from 'react-jss';
3
3
  import { isStringNotEmpty } from '@true-engineering/true-react-platform-helpers';
4
4
  import { type ComponentMeta, type ComponentStory } from '@storybook/react';
5
5
  import { Button, type IButtonStyles } from '../Button';
6
- import { Input, type IInputStyles } from '../Input';
6
+ import { type IInputStyles, Input } from '../Input';
7
7
  import { TextButton } from '../TextButton';
8
- import { Select, type ISelectProps } from './Select';
8
+ import { type ISelectProps, Select } from './Select';
9
9
 
10
10
  interface ISelectWithCustomProps<Option> extends ISelectProps<Option> {
11
11
  shouldUsePopper?: boolean;
@@ -54,8 +54,10 @@ const useCustomListFooterStyles = createUseStyles({
54
54
  });
55
55
 
56
56
  const inputTweakStyles: IInputStyles = {
57
- inputWrapper: {
58
- height: 24,
57
+ tweakControlWrapper: {
58
+ root: {
59
+ '--control-height': '24px',
60
+ }
59
61
  },
60
62
 
61
63
  input: {
@@ -102,7 +104,6 @@ function CustomListHeader({ onAdd }: ICustomListHeaderProps) {
102
104
  <div className={classes.inputView}>
103
105
  <Input
104
106
  value={inputValue}
105
- border="bottom"
106
107
  placeholder="Option Value"
107
108
  tweakStyles={inputTweakStyles}
108
109
  shouldFocusOnMount
@@ -237,13 +238,9 @@ CustomSelect.args = {
237
238
  noMatchesLabel: 'No matches',
238
239
  isInvalid: false,
239
240
  errorMessage: '',
240
- errorPosition: 'bottom',
241
- hasFloatingLabel: true,
242
- hasRequiredLabel: false,
243
241
  isDisabled: false,
244
242
  isRequired: false,
245
243
  isClearable: false,
246
-
247
244
  shouldUsePopper: false,
248
245
  shouldRenderInBody: false,
249
246
  shouldHideOnScroll: false,
@@ -1,7 +1,7 @@
1
1
  import { ReactNode, useEffect, useState } from 'react';
2
2
  import { isStringNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
3
  import { ComponentMeta, ComponentStory } from '@storybook/react';
4
- import { Select, ISelectProps, IMultipleSelectProps } from './Select';
4
+ import { IMultipleSelectProps, Select } from './Select';
5
5
 
6
6
  interface ObjectValue {
7
7
  name: string;
@@ -9,9 +9,7 @@ interface ObjectValue {
9
9
  isDisabled?: boolean;
10
10
  }
11
11
 
12
- const inlineStyles = [undefined, 'left', 'right', 'middle'];
13
- const borders: Array<ISelectProps<any>['border']> = [undefined, 'left', 'top', 'right', 'bottom'];
14
- const errorPositions: Array<ISelectProps<any>['errorPosition']> = ['bottom', 'top'];
12
+ const groupPlacements = [undefined, 'left', 'right', 'middle'];
15
13
 
16
14
  const genLetters = (qnt = 1): string =>
17
15
  Math.random()
@@ -188,9 +186,7 @@ export default {
188
186
  debounceTime: {
189
187
  control: { type: 'range', min: 0, max: 1000, step: 100 },
190
188
  },
191
- errorPosition: { control: 'inline-radio', options: errorPositions },
192
- border: { control: 'inline-radio', options: borders },
193
- inlineStyle: { control: 'select', options: inlineStyles },
189
+ groupPlacement: { control: 'select', options: groupPlacements },
194
190
  optionsMode: {
195
191
  control: 'inline-radio',
196
192
  options: ['normal', 'search', 'dynamic'],
@@ -211,13 +207,9 @@ export const MultiSelect = Template.bind({});
211
207
  MultiSelect.args = {
212
208
  label: 'Dropdown',
213
209
  noMatchesLabel: 'No matches',
214
- border: undefined,
215
210
  isInvalid: false,
216
211
  errorMessage: 'Error Text',
217
- errorPosition: 'bottom',
218
- hasFloatingLabel: true,
219
- hasRequiredLabel: true,
220
- iconType: 'document',
212
+ icon: 'document',
221
213
  defaultOptionLabel: '',
222
214
  allOptionsLabel: 'Все опции',
223
215
  isDisabled: false,
@@ -1,7 +1,7 @@
1
1
  import { ReactNode, useEffect, useState } from 'react';
2
2
  import { isStringNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
3
  import { ComponentMeta, ComponentStory } from '@storybook/react';
4
- import { Select, ISelectProps } from './Select';
4
+ import { ISelectProps, Select } from './Select';
5
5
 
6
6
  interface ObjectValue {
7
7
  name: string;
@@ -9,9 +9,7 @@ interface ObjectValue {
9
9
  isDisabled?: boolean;
10
10
  }
11
11
 
12
- const inlineStyles = [undefined, 'left', 'right', 'middle'];
13
- const borders: Array<ISelectProps<any>['border']> = [undefined, 'left', 'top', 'right', 'bottom'];
14
- const errorPositions: Array<ISelectProps<any>['errorPosition']> = ['bottom', 'top'];
12
+ const groupPlacements = [undefined, 'left', 'right', 'middle'];
15
13
 
16
14
  const genLetters = (qnt = 1): string =>
17
15
  Math.random()
@@ -185,9 +183,7 @@ export default {
185
183
  debounceTime: {
186
184
  control: { type: 'range', min: 0, max: 1000, step: 100 },
187
185
  },
188
- errorPosition: { control: 'inline-radio', options: errorPositions },
189
- border: { control: 'inline-radio', options: borders },
190
- inlineStyle: { control: 'select', options: inlineStyles },
186
+ groupPlacement: { control: 'select', options: groupPlacements },
191
187
  optionsMode: {
192
188
  control: 'inline-radio',
193
189
  options: ['normal', 'search', 'dynamic'],
@@ -209,12 +205,8 @@ Default.args = {
209
205
  label: 'Dropdown',
210
206
  defaultOptionLabel: 'Default Option',
211
207
  noMatchesLabel: 'No matches',
212
- border: undefined,
213
208
  isInvalid: false,
214
209
  errorMessage: 'Error Text',
215
- errorPosition: 'bottom',
216
- hasFloatingLabel: true,
217
- hasRequiredLabel: true,
218
210
  isDisabled: false,
219
211
  isReadonly: false,
220
212
  isRequired: false,
@@ -1,9 +1,12 @@
1
1
  import { mergeStyles } from '@true-engineering/true-react-platform-helpers';
2
- import { animations, createThemedStyles, type ITweakStyles } from '../../theme';
2
+ import { animations, createThemedStyles, dimensions, type ITweakStyles } from '../../theme';
3
+ import { IControlGroupStyles } from '../ControlGroup';
3
4
  import { type IInputStyles } from '../Input';
4
5
  import { type ISearchInputStyles } from '../SearchInput';
5
6
  import { type ISelectListStyles } from './components';
6
7
 
8
+ const { CONTROL, Z_INDEX } = dimensions;
9
+
7
10
  export const useStyles = createThemedStyles('Select', {
8
11
  root: {
9
12
  width: '100%',
@@ -26,7 +29,8 @@ export const useStyles = createThemedStyles('Select', {
26
29
 
27
30
  withoutPopper: {
28
31
  position: 'absolute',
29
- top: 'calc(var(--dropdown-offset, 100%) + 6px)',
32
+ top: '100%',
33
+ paddingTop: 4,
30
34
  },
31
35
 
32
36
  listWrapperInBody: {
@@ -38,17 +42,18 @@ export const useStyles = createThemedStyles('Select', {
38
42
  arrow: {
39
43
  position: 'absolute',
40
44
  right: 12,
41
- top: 14,
45
+ top: '50%',
42
46
  width: 20,
43
47
  height: 20,
44
48
  cursor: 'pointer',
45
- zIndex: 1,
49
+ transform: 'translateY(-50%)',
46
50
  transition: animations.defaultTransition,
47
51
  transitionProperty: 'transform',
52
+ zIndex: Z_INDEX.CONTROL_FOCUS + 1,
48
53
  },
49
54
 
50
55
  activeArrow: {
51
- transform: 'rotate(180deg)',
56
+ transform: 'translateY(-50%) rotate(180deg)',
52
57
  },
53
58
 
54
59
  disabled: {
@@ -64,24 +69,31 @@ export const useStyles = createThemedStyles('Select', {
64
69
  },
65
70
 
66
71
  icon: {
67
- width: 16,
68
- height: 16,
72
+ width: CONTROL.ICON_INNER_SIZE,
73
+ height: CONTROL.ICON_INNER_SIZE,
74
+ },
75
+
76
+ iconWrapper: {
77
+ display: 'flex',
78
+ alignItems: 'center',
69
79
  },
70
80
  });
71
81
 
72
82
  const baseInputStyles: IInputStyles = {
73
- input: {
83
+ inputContent: {
74
84
  paddingRight: 32,
75
85
  },
76
86
 
77
- disabled: {
78
- '& $input': {
79
- cursor: 'default',
87
+ tweakControlWrapper: {
88
+ controls: {
89
+ paddingRight: 40,
80
90
  },
81
- },
82
91
 
83
- controls: {
84
- paddingRight: 32,
92
+ icon: {
93
+ '&:last-child': {
94
+ paddingRight: 0,
95
+ },
96
+ },
85
97
  },
86
98
  };
87
99
 
@@ -91,21 +103,8 @@ const readonlyInputBaseStyles: IInputStyles = {
91
103
  },
92
104
  };
93
105
 
94
- const multiSelectInputBaseStyles: IInputStyles = {
95
- inputIcon: {
96
- '&:not($loading)': {
97
- width: 'auto',
98
- },
99
- },
100
- };
101
-
102
106
  export const readonlyInputStyles = mergeStyles(baseInputStyles, readonlyInputBaseStyles);
103
- export const multiSelectInputStyles = mergeStyles(baseInputStyles, multiSelectInputBaseStyles);
104
- export const readonlyMultiSelectStyles = mergeStyles(
105
- baseInputStyles,
106
- readonlyInputBaseStyles,
107
- multiSelectInputBaseStyles,
108
- );
107
+ export const readonlyMultiSelectStyles = mergeStyles(baseInputStyles, readonlyInputBaseStyles);
109
108
 
110
109
  export const getInputStyles = ({
111
110
  hasReadonlyInput,
@@ -120,26 +119,13 @@ export const getInputStyles = ({
120
119
  if (hasReadonlyInput && !isMultiSelect) {
121
120
  return readonlyInputStyles;
122
121
  }
123
- if (!hasReadonlyInput && isMultiSelect) {
124
- return multiSelectInputStyles;
125
- }
126
122
  return baseInputStyles;
127
123
  };
128
124
 
129
- export const searchInputStyles: ISearchInputStyles = {
130
- tweakInput: {
131
- inputWrapper: {
132
- height: 48,
133
- borderRadius: 0,
134
- border: 'none',
135
- backgroundColor: 'transparent',
136
- },
137
- },
138
- };
139
-
140
125
  export type ISelectStyles = ITweakStyles<
141
126
  typeof useStyles,
142
127
  {
128
+ tweakControlGroup: IControlGroupStyles;
143
129
  tweakInput: IInputStyles;
144
130
  tweakSelectList: ISelectListStyles;
145
131
  tweakSearchInput: ISearchInputStyles;
@@ -1,17 +1,16 @@
1
1
  import {
2
- useCallback,
3
- useEffect,
4
- useMemo,
5
- useRef,
6
- useState,
7
2
  ChangeEvent,
8
3
  CSSProperties,
9
4
  FocusEvent,
10
- FormEvent,
11
5
  KeyboardEvent,
12
6
  MouseEvent,
13
7
  ReactNode,
14
8
  SyntheticEvent,
9
+ useCallback,
10
+ useEffect,
11
+ useMemo,
12
+ useRef,
13
+ useState,
15
14
  } from 'react';
16
15
  import { Portal } from 'react-overlays';
17
16
  import clsx from 'clsx';
@@ -26,10 +25,11 @@ import {
26
25
  } from '@true-engineering/true-react-platform-helpers';
27
26
  import { hasExactParent } from '../../helpers';
28
27
  import { useDropdown, useIsMounted, useOnClickOutsideWithRef, useTweakStyles } from '../../hooks';
29
- import { IDropdownWithPopperOptions, ICommonProps } from '../../types';
30
- import { renderIcon, IIcon } from '../Icon';
31
- import { Input, IInputProps } from '../Input';
32
- import { SearchInput, ISearchInputProps } from '../SearchInput';
28
+ import { ICommonProps, IDropdownWithPopperOptions } from '../../types';
29
+ import { ControlGroup } from '../ControlGroup';
30
+ import { IIcon, renderIcon } from '../Icon';
31
+ import { IChangeInputEvent, IInputProps, InputBase } from '../Input';
32
+ import { ISearchInputProps, SearchInput } from '../SearchInput';
33
33
  import { SelectList } from './components';
34
34
  import { ALL_OPTION_INDEX, DEFAULT_OPTION_INDEX } from './constants';
35
35
  import {
@@ -38,8 +38,8 @@ import {
38
38
  defaultIsOptionDisabled,
39
39
  getDefaultConvertToIdFunction,
40
40
  } from './helpers';
41
- import { IMultipleSelectValue } from './types';
42
- import { getInputStyles, searchInputStyles, useStyles, ISelectStyles } from './Select.styles';
41
+ import { IChangeSelectEvent, IMultipleSelectValue } from './types';
42
+ import { getInputStyles, ISelectStyles, useStyles } from './Select.styles';
43
43
 
44
44
  export interface ISelectProps<Value>
45
45
  extends Omit<IInputProps, 'value' | 'onChange' | 'onBlur' | 'type' | 'tweakStyles'>,
@@ -66,14 +66,7 @@ export interface ISelectProps<Value>
66
66
  isMultiSelect?: false;
67
67
  searchInput?: { shouldRenderInList: true } & Pick<ISearchInputProps, 'placeholder'>;
68
68
  isOptionDisabled?: (option: Value) => boolean;
69
- onChange: (
70
- value: Value | undefined,
71
- event:
72
- | MouseEvent<HTMLElement>
73
- | KeyboardEvent
74
- | ChangeEvent<HTMLElement>
75
- | FormEvent<HTMLElement>,
76
- ) => void; // подумать как возвращать индекс
69
+ onChange: (value: Value | undefined, event: IChangeSelectEvent) => void; // подумать как возвращать индекс
77
70
  onBlur?: (event: Event | SyntheticEvent) => void;
78
71
  onType?: (value: string) => Promise<void>;
79
72
  optionsFilter?: (options: Value[], query: string) => Value[];
@@ -94,14 +87,7 @@ export interface IMultipleSelectProps<Value>
94
87
  > {
95
88
  isMultiSelect: true;
96
89
  value: IMultipleSelectValue<Value> | undefined;
97
- onChange: (
98
- value: IMultipleSelectValue<Value> | undefined,
99
- event:
100
- | MouseEvent<HTMLElement>
101
- | KeyboardEvent
102
- | ChangeEvent<HTMLElement>
103
- | FormEvent<HTMLElement>,
104
- ) => void;
90
+ onChange: (value: IMultipleSelectValue<Value> | undefined, event: IChangeSelectEvent) => void;
105
91
  compareValuesOnChange?: (
106
92
  v1?: IMultipleSelectValue<Value>,
107
93
  v2?: IMultipleSelectValue<Value>,
@@ -133,7 +119,7 @@ export function Select<Value>(
133
119
  dropdownIcon = 'chevron-down',
134
120
  shouldScrollToList = true,
135
121
  searchInput,
136
- iconType,
122
+ icon,
137
123
  onChange,
138
124
  onFocus,
139
125
  onBlur,
@@ -145,6 +131,8 @@ export function Select<Value>(
145
131
  convertValueToId,
146
132
  convertValueToReactNode,
147
133
  optionsFilter,
134
+ infoMessage,
135
+ errorMessage,
148
136
  ...inputProps
149
137
  } = props;
150
138
  const classes = useStyles({ theme: tweakStyles });
@@ -154,6 +142,12 @@ export function Select<Value>(
154
142
  const hasSearchInputInList = optionsMode !== 'normal' && shouldRenderSearchInputInList;
155
143
  const hasReadonlyInput = isReadonly || optionsMode === 'normal' || shouldRenderSearchInputInList;
156
144
 
145
+ const tweakControlGroupStyles = useTweakStyles({
146
+ tweakStyles,
147
+ className: 'tweakControlGroup',
148
+ currentComponentName: 'Select',
149
+ });
150
+
157
151
  const tweakInputStyles = useTweakStyles({
158
152
  innerStyles: getInputStyles({ hasReadonlyInput, isMultiSelect }),
159
153
  tweakStyles,
@@ -162,7 +156,6 @@ export function Select<Value>(
162
156
  });
163
157
 
164
158
  const tweakSearchInputStyles = useTweakStyles({
165
- innerStyles: searchInputStyles,
166
159
  tweakStyles,
167
160
  className: 'tweakSearchInput',
168
161
  currentComponentName: 'Select',
@@ -249,7 +242,7 @@ export function Select<Value>(
249
242
  );
250
243
 
251
244
  const getDropdownOffset = () => {
252
- if (isEmpty(input.current) || inputProps.errorPosition === 'top') {
245
+ if (isEmpty(input.current)) {
253
246
  return 0;
254
247
  }
255
248
 
@@ -325,14 +318,7 @@ export function Select<Value>(
325
318
  };
326
319
 
327
320
  const handleChange = useCallback(
328
- (
329
- newValue: Value | IMultipleSelectValue<Value> | undefined,
330
- event:
331
- | MouseEvent<HTMLElement>
332
- | KeyboardEvent
333
- | ChangeEvent<HTMLElement>
334
- | FormEvent<HTMLElement>,
335
- ) => {
321
+ (newValue: Value | IMultipleSelectValue<Value> | undefined, event: IChangeSelectEvent) => {
336
322
  // Тут беда с типами, сорри
337
323
  if (!compareValuesOnChange(value as never, newValue as never)) {
338
324
  onChange(newValue as (Value & IMultipleSelectValue<Value>) | undefined, event);
@@ -403,7 +389,7 @@ export function Select<Value>(
403
389
  [handleOnType, debounceTime],
404
390
  );
405
391
 
406
- const handleInputChange = (v: string, event: FormEvent<HTMLElement>) => {
392
+ const handleInputChange = (v: string, event: IChangeInputEvent) => {
407
393
  if (onType !== undefined) {
408
394
  debounceHandleOnType(v);
409
395
  }
@@ -603,56 +589,62 @@ export function Select<Value>(
603
589
  );
604
590
 
605
591
  const multiSelectCounterWithIcon =
606
- shouldShowMultiSelectCounter || isNotEmpty(iconType) ? (
607
- <>
592
+ shouldShowMultiSelectCounter || isNotEmpty(icon) ? (
593
+ <div className={classes.iconWrapper}>
608
594
  {shouldShowMultiSelectCounter && (
609
595
  <div className={classes.counter}>(+{value.length - 1})</div>
610
596
  )}
611
- {isNotEmpty(iconType) && <div className={classes.icon}>{renderIcon(iconType)}</div>}
612
- </>
597
+ {isNotEmpty(icon) && <div className={classes.icon}>{renderIcon(icon)}</div>}
598
+ </div>
613
599
  ) : undefined;
614
600
 
615
601
  return (
616
- <div className={classes.root} onKeyDown={handleKeyDown} ref={root}>
617
- <div
618
- className={clsx(classes.inputWrapper, isDisabled && classes.disabled)}
619
- onClick={isDisabled || isReadonly ? undefined : handleOnClick}
620
- ref={inputWrapper}
621
- >
622
- <Input
623
- value={
624
- searchValue !== '' && !shouldRenderSearchInputInList ? searchValue : showedStringValue
625
- }
626
- onChange={handleInputChange}
627
- isActive={isListOpen || isActive}
628
- isReadonly={hasReadonlyInput}
629
- onFocus={handleFocus}
630
- onBlur={handleBlur}
631
- isDisabled={isDisabled}
632
- ref={input}
633
- isLoading={areOptionsLoading}
634
- tweakStyles={tweakInputStyles}
635
- testId={testId}
636
- iconType={isMultiSelect ? multiSelectCounterWithIcon : iconType}
637
- {...inputProps}
638
- />
602
+ <ControlGroup
603
+ errorMessage={errorMessage}
604
+ infoMessage={infoMessage}
605
+ tweakStyles={tweakControlGroupStyles}
606
+ >
607
+ <div className={classes.root} onKeyDown={handleKeyDown} ref={root}>
639
608
  <div
640
- onMouseDown={(event: MouseEvent) => {
641
- event.preventDefault();
642
- }}
643
- onClick={onArrowClick}
644
- className={clsx(classes.arrow, isOpen && classes.activeArrow)}
609
+ className={clsx(classes.inputWrapper, isDisabled && classes.disabled)}
610
+ onClick={isDisabled || isReadonly ? undefined : handleOnClick}
611
+ ref={inputWrapper}
645
612
  >
646
- {renderIcon(dropdownIcon)}
613
+ <InputBase
614
+ value={
615
+ searchValue !== '' && !shouldRenderSearchInputInList ? searchValue : showedStringValue
616
+ }
617
+ onChange={handleInputChange}
618
+ isActive={isListOpen || isActive}
619
+ isReadonly={hasReadonlyInput}
620
+ onFocus={handleFocus}
621
+ onBlur={handleBlur}
622
+ isDisabled={isDisabled}
623
+ ref={input}
624
+ isLoading={areOptionsLoading}
625
+ tweakStyles={tweakInputStyles}
626
+ testId={testId}
627
+ icon={isMultiSelect ? multiSelectCounterWithIcon : icon}
628
+ {...inputProps}
629
+ />
630
+ <div
631
+ onMouseDown={(event: MouseEvent) => {
632
+ event.preventDefault();
633
+ }}
634
+ onClick={onArrowClick}
635
+ className={clsx(classes.arrow, isOpen && classes.activeArrow)}
636
+ >
637
+ {renderIcon(dropdownIcon)}
638
+ </div>
647
639
  </div>
640
+ {shouldUsePopper ? (
641
+ <Portal container={shouldRenderInBody ? document.body : inputWrapper.current}>
642
+ <>{listEl}</>
643
+ </Portal>
644
+ ) : (
645
+ <>{isOpen && listEl}</>
646
+ )}
648
647
  </div>
649
- {shouldUsePopper ? (
650
- <Portal container={shouldRenderInBody ? document.body : inputWrapper.current}>
651
- <>{listEl}</>
652
- </Portal>
653
- ) : (
654
- <>{isOpen && listEl}</>
655
- )}
656
- </div>
648
+ </ControlGroup>
657
649
  );
658
650
  }
@@ -1 +1,6 @@
1
+ import { ChangeEvent, KeyboardEvent } from 'react';
2
+ import { IChangeInputEvent } from '../Input';
3
+
1
4
  export type IMultipleSelectValue<Value> = Array<NonNullable<Value>>;
5
+
6
+ export type IChangeSelectEvent = IChangeInputEvent | ChangeEvent<HTMLElement> | KeyboardEvent;
@@ -48,5 +48,4 @@ Default.args = {
48
48
  isUpperCase: false,
49
49
  isDisabled: false,
50
50
  isTransliterationEnabled: true,
51
- hasFloatingLabel: true,
52
51
  };