@true-engineering/true-react-common-ui-kit 4.0.0-alpha3 → 4.0.0-alpha30

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 (221) hide show
  1. package/README.md +11 -607
  2. package/dist/components/Button/Button.styles.d.ts +1 -1
  3. package/dist/components/Checkbox/Checkbox.styles.d.ts +1 -1
  4. package/dist/components/ControlWrapper/ControlWrapper.d.ts +4 -2
  5. package/dist/components/ControlWrapper/ControlWrapper.styles.d.ts +2 -1
  6. package/dist/components/ControlWrapper/helpers.d.ts +4 -0
  7. package/dist/components/ControlWrapper/index.d.ts +2 -0
  8. package/dist/components/ControlWrapper/types.d.ts +12 -0
  9. package/dist/components/DatePicker/DatePicker.d.ts +3 -3
  10. package/dist/components/DatePicker/DatePicker.styles.d.ts +1 -1
  11. package/dist/components/DatePicker/components/PopperContainer/PopperContainer.d.ts +2 -4
  12. package/dist/components/DatePicker/helpers.d.ts +3 -0
  13. package/dist/components/DatePicker/types.d.ts +5 -3
  14. package/dist/components/FiltersPane/FiltersPane.d.ts +7 -2
  15. package/dist/components/FiltersPane/components/Filter/Filter.d.ts +2 -2
  16. package/dist/components/FiltersPane/components/Filter/helpers.d.ts +4 -0
  17. package/dist/components/FiltersPane/components/FilterInterval/FilterInterval.styles.d.ts +1 -1
  18. package/dist/components/FiltersPane/components/FilterSelect/FilterSelect.styles.d.ts +1 -1
  19. package/dist/components/FiltersPane/components/FilterValueView/FilterValueView.d.ts +3 -1
  20. package/dist/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.d.ts +2 -2
  21. package/dist/components/FiltersPane/components/FilterWrapper/FilterWrapper.d.ts +2 -2
  22. package/dist/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.styles.d.ts +1 -1
  23. package/dist/components/FiltersPane/types.d.ts +16 -5
  24. package/dist/components/Flag/customFlags/customFlags.d.ts +10 -0
  25. package/dist/components/Flag/customFlags/index.d.ts +1 -0
  26. package/dist/components/FlexibleTable/FlexibleTable.d.ts +4 -2
  27. package/dist/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.d.ts +4 -3
  28. package/dist/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.d.ts +6 -6
  29. package/dist/components/FlexibleTable/constants.d.ts +18 -2
  30. package/dist/components/FlexibleTable/types.d.ts +20 -12
  31. package/dist/components/Icon/icons-list.d.ts +1 -1
  32. package/dist/components/IconButton/IconButton.styles.d.ts +1 -1
  33. package/dist/components/IncrementInput/IncrementInput.styles.d.ts +1 -3
  34. package/dist/components/Input/Input.d.ts +3 -2
  35. package/dist/components/Input/InputBase.d.ts +2 -2
  36. package/dist/components/List/List.d.ts +1 -1
  37. package/dist/components/List/index.d.ts +2 -1
  38. package/dist/components/List/types.d.ts +4 -0
  39. package/dist/components/Modal/Modal.styles.d.ts +1 -1
  40. package/dist/components/Notification/Notification.styles.d.ts +1 -1
  41. package/dist/components/ScrollIntoViewIfNeeded/ScrollIntoViewIfNeeded.d.ts +1 -1
  42. package/dist/components/SearchInput/SearchInput.d.ts +2 -2
  43. package/dist/components/Select/Select.d.ts +5 -3
  44. package/dist/components/Select/Select.styles.d.ts +5 -5
  45. package/dist/components/Select/components/SelectListItem/SelectListItem.d.ts +2 -1
  46. package/dist/components/Select/index.d.ts +1 -1
  47. package/dist/components/Status/Status.styles.d.ts +3 -2
  48. package/dist/components/Status/constants.d.ts +0 -1
  49. package/dist/components/Status/index.d.ts +1 -0
  50. package/dist/components/Status/types.d.ts +5 -2
  51. package/dist/components/TextArea/TextArea.d.ts +4 -5
  52. package/dist/components/TextArea/TextArea.styles.d.ts +5 -4
  53. package/dist/components/TextArea/index.d.ts +1 -1
  54. package/dist/components/TextArea/types.d.ts +4 -2
  55. package/dist/components/TextButton/TextButton.styles.d.ts +1 -1
  56. package/dist/components/Tooltip/Tooltip.d.ts +1 -1
  57. package/dist/components/Tooltip/Tooltip.styles.d.ts +1 -1
  58. package/dist/components/WithMessages/WithMessages.styles.d.ts +1 -1
  59. package/dist/components/WithPopup/WithPopup.d.ts +11 -3
  60. package/dist/hooks/index.d.ts +2 -0
  61. package/dist/hooks/use-intersection-ref.d.ts +8 -0
  62. package/dist/hooks/use-merge.d.ts +1 -0
  63. package/dist/hooks/use-mixed-styles.d.ts +3 -1
  64. package/dist/hooks/use-tweak-styles.d.ts +5 -5
  65. package/dist/style.css +78 -142
  66. package/dist/theme/Provider.d.ts +6 -3
  67. package/dist/theme/create-themed-styles.d.ts +2 -0
  68. package/dist/theme/helpers.d.ts +9 -3
  69. package/dist/theme/index.d.ts +2 -0
  70. package/dist/theme/true-jss/ThemedStylesManager.d.ts +18 -0
  71. package/dist/theme/true-jss/TweakStylesManager.d.ts +34 -0
  72. package/dist/theme/true-jss/index.d.ts +2 -0
  73. package/dist/theme/true-jss/jss-context.d.ts +9 -0
  74. package/dist/theme/types.d.ts +5 -3
  75. package/dist/true-react-common-ui-kit.js +7593 -6483
  76. package/dist/true-react-common-ui-kit.js.map +1 -1
  77. package/dist/true-react-common-ui-kit.umd.cjs +7618 -6509
  78. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  79. package/dist/types.d.ts +10 -3
  80. package/package.json +4 -5
  81. package/src/components/ControlWrapper/ControlWrapper.stories.tsx +8 -3
  82. package/src/components/ControlWrapper/ControlWrapper.styles.ts +7 -6
  83. package/src/components/ControlWrapper/ControlWrapper.tsx +31 -20
  84. package/src/components/ControlWrapper/helpers.ts +11 -0
  85. package/src/components/ControlWrapper/index.ts +2 -0
  86. package/src/components/ControlWrapper/types.ts +16 -0
  87. package/src/components/DateInput/DateInput.stories.tsx +0 -1
  88. package/src/components/DatePicker/DatePicker.stories.tsx +24 -11
  89. package/src/components/DatePicker/DatePicker.styles.ts +3 -1
  90. package/src/components/DatePicker/DatePicker.tsx +18 -10
  91. package/src/components/DatePicker/components/PopperContainer/PopperContainer.tsx +4 -4
  92. package/src/components/DatePicker/helpers.ts +13 -1
  93. package/src/components/DatePicker/types.ts +9 -4
  94. package/src/components/FiltersPane/FiltersPane.stories.tsx +4 -2
  95. package/src/components/FiltersPane/FiltersPane.tsx +28 -19
  96. package/src/components/FiltersPane/components/Filter/Filter.tsx +36 -30
  97. package/src/components/FiltersPane/components/Filter/helpers.ts +18 -0
  98. package/src/components/FiltersPane/components/FilterSelect/FilterSelect.tsx +22 -23
  99. package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +27 -22
  100. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.ts +2 -1
  101. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.tsx +3 -4
  102. package/src/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.tsx +4 -3
  103. package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.tsx +14 -10
  104. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.styles.ts +5 -0
  105. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.tsx +16 -19
  106. package/src/components/FiltersPane/types.ts +24 -5
  107. package/src/components/Flag/Flag.stories.tsx +2 -1
  108. package/src/components/Flag/Flag.styles.ts +4 -0
  109. package/src/components/Flag/Flag.tsx +23 -9
  110. package/src/components/Flag/customFlags/AB.svg +1 -0
  111. package/src/components/Flag/customFlags/OS.svg +1 -0
  112. package/src/components/Flag/customFlags/augment.d.ts +1 -0
  113. package/src/components/Flag/customFlags/customFlags.ts +13 -0
  114. package/src/components/Flag/customFlags/index.ts +1 -0
  115. package/src/components/FlexibleTable/FlexibleTable.tsx +40 -63
  116. package/src/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.tsx +8 -5
  117. package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.tsx +13 -12
  118. package/src/components/FlexibleTable/constants.ts +6 -3
  119. package/src/components/FlexibleTable/types.ts +20 -16
  120. package/src/components/IncrementInput/IncrementInput.stories.tsx +2 -0
  121. package/src/components/IncrementInput/IncrementInput.styles.ts +31 -39
  122. package/src/components/IncrementInput/IncrementInput.tsx +28 -25
  123. package/src/components/Input/Input.stories.tsx +1 -6
  124. package/src/components/Input/Input.tsx +5 -3
  125. package/src/components/Input/InputBase.tsx +27 -25
  126. package/src/components/List/List.tsx +5 -2
  127. package/src/components/List/index.ts +2 -1
  128. package/src/components/List/types.ts +5 -0
  129. package/src/components/MultiSelectList/MultiSelectList.tsx +15 -11
  130. package/src/components/NumberInput/NumberInput.stories.tsx +5 -1
  131. package/src/components/PhoneInput/PhoneInput.stories.tsx +2 -1
  132. package/src/components/PhoneInput/PhoneInput.tsx +5 -2
  133. package/src/components/SearchInput/SearchInput.tsx +20 -29
  134. package/src/components/Select/CustomSelect.stories.tsx +1 -0
  135. package/src/components/Select/MultiSelect.stories.tsx +5 -0
  136. package/src/components/Select/Select.stories.tsx +6 -0
  137. package/src/components/Select/Select.styles.ts +5 -40
  138. package/src/components/Select/Select.tsx +36 -22
  139. package/src/components/Select/components/SelectList/SelectList.tsx +4 -2
  140. package/src/components/Select/components/SelectListItem/SelectListItem.tsx +5 -2
  141. package/src/components/Select/index.ts +1 -1
  142. package/src/components/Status/Status.stories.tsx +54 -1
  143. package/src/components/Status/Status.styles.ts +2 -37
  144. package/src/components/Status/constants.ts +0 -10
  145. package/src/components/Status/index.ts +1 -1
  146. package/src/components/Status/types.ts +7 -3
  147. package/src/components/TextArea/TextArea.stories.tsx +15 -1
  148. package/src/components/TextArea/TextArea.styles.ts +15 -8
  149. package/src/components/TextArea/TextArea.tsx +96 -62
  150. package/src/components/TextArea/index.ts +1 -1
  151. package/src/components/TextArea/types.ts +5 -5
  152. package/src/components/TextButton/TextButton.styles.ts +1 -0
  153. package/src/components/Tooltip/Tooltip.styles.ts +2 -0
  154. package/src/components/Tooltip/Tooltip.tsx +1 -1
  155. package/src/components/WithMessages/WithMessages.stories.tsx +1 -1
  156. package/src/components/WithPopup/WithPopup.tsx +36 -15
  157. package/src/constants/phone-info.ts +20 -33
  158. package/src/helpers/phone.ts +19 -15
  159. package/src/hooks/index.ts +2 -0
  160. package/src/hooks/use-intersection-ref.ts +30 -0
  161. package/src/hooks/use-merge.ts +8 -0
  162. package/src/hooks/use-mixed-styles.ts +9 -11
  163. package/src/hooks/use-tweak-styles.ts +49 -27
  164. package/src/theme/Provider.tsx +10 -5
  165. package/src/theme/create-themed-styles.ts +78 -0
  166. package/src/theme/helpers.ts +39 -39
  167. package/src/theme/index.ts +2 -0
  168. package/src/theme/true-jss/ThemedStylesManager.ts +92 -0
  169. package/src/theme/true-jss/TweakStylesManager.ts +157 -0
  170. package/src/theme/true-jss/index.ts +2 -0
  171. package/src/theme/true-jss/jss-context.tsx +34 -0
  172. package/src/theme/types.ts +5 -3
  173. package/src/types.ts +17 -4
  174. package/dist/components/AccountInfo/AccountInfo.stories.d.ts +0 -6
  175. package/dist/components/AddButton/AddButton.stories.d.ts +0 -6
  176. package/dist/components/Button/Button.stories.d.ts +0 -6
  177. package/dist/components/Checkbox/Checkbox.stories.d.ts +0 -8
  178. package/dist/components/CloseButton/CloseButton.stories.d.ts +0 -5
  179. package/dist/components/Colors/Colors.stories.d.ts +0 -5
  180. package/dist/components/ControlWrapper/ControlWrapper.stories.d.ts +0 -6
  181. package/dist/components/DateInput/DateInput.stories.d.ts +0 -7
  182. package/dist/components/DatePicker/DatePicker.stories.d.ts +0 -7
  183. package/dist/components/Description/Description.stories.d.ts +0 -16
  184. package/dist/components/FileInput/FileInput.stories.d.ts +0 -7
  185. package/dist/components/FileItem/FileItem.stories.d.ts +0 -8
  186. package/dist/components/FiltersPane/FiltersPane.stories.d.ts +0 -31
  187. package/dist/components/Flag/Flag.stories.d.ts +0 -12
  188. package/dist/components/FlexibleTable/FlexibleTable.stories.d.ts +0 -19
  189. package/dist/components/Icon/Icon.stories.d.ts +0 -6
  190. package/dist/components/IconButton/IconButton.stories.d.ts +0 -6
  191. package/dist/components/IncrementInput/IncrementInput.stories.d.ts +0 -6
  192. package/dist/components/Input/Input.stories.d.ts +0 -25
  193. package/dist/components/List/List.stories.d.ts +0 -5
  194. package/dist/components/Modal/Modal.stories.d.ts +0 -29
  195. package/dist/components/MoreMenu/MoreMenu.stories.d.ts +0 -6
  196. package/dist/components/MultiSelect/MultiSelect.stories.d.ts +0 -13
  197. package/dist/components/NewMoreMenu/NewMoreMenu.stories.d.ts +0 -12
  198. package/dist/components/Notification/Notification.stories.d.ts +0 -8
  199. package/dist/components/NumberInput/NumberInput.stories.d.ts +0 -7
  200. package/dist/components/PhoneInput/PhoneInput.stories.d.ts +0 -28
  201. package/dist/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.stories.d.ts +0 -5
  202. package/dist/components/RadioButton/RadioButton.stories.d.ts +0 -7
  203. package/dist/components/SearchInput/SearchInput.stories.d.ts +0 -6
  204. package/dist/components/Select/CustomSelect.stories.d.ts +0 -11
  205. package/dist/components/Select/MultiSelect.stories.d.ts +0 -15
  206. package/dist/components/Select/Select.stories.d.ts +0 -15
  207. package/dist/components/Selector/Selector.stories.d.ts +0 -7
  208. package/dist/components/Skeleton/Skeleton.stories.d.ts +0 -6
  209. package/dist/components/SmartInput/SmartInput.stories.d.ts +0 -18
  210. package/dist/components/Status/Status.stories.d.ts +0 -6
  211. package/dist/components/Switch/Switch.stories.d.ts +0 -16
  212. package/dist/components/TextArea/TextArea.stories.d.ts +0 -17
  213. package/dist/components/TextButton/TextButton.stories.d.ts +0 -6
  214. package/dist/components/TextWithInfo/TextWithInfo.stories.d.ts +0 -12
  215. package/dist/components/TextWithTooltip/TextWithTooltip.stories.d.ts +0 -24
  216. package/dist/components/ThemedPreloader/ThemedPreloader.stories.d.ts +0 -17
  217. package/dist/components/Toaster/Toaster.stories.d.ts +0 -5
  218. package/dist/components/Tooltip/Tooltip.stories.d.ts +0 -5
  219. package/dist/components/WithMessages/WithMessages.stories.d.ts +0 -7
  220. package/dist/components/WithPopup/WithPopup.stories.d.ts +0 -16
  221. package/dist/components/WithTooltip/WithTooltip.stories.d.ts +0 -6
@@ -1,7 +1,17 @@
1
- import { ChangeEvent, FocusEvent, FormEvent, forwardRef, useState } from 'react';
1
+ import {
2
+ ChangeEvent,
3
+ FocusEvent,
4
+ FormEvent,
5
+ forwardRef,
6
+ TextareaHTMLAttributes,
7
+ useState,
8
+ } from 'react';
9
+ import { Styles } from 'react-jss';
2
10
  import clsx from 'clsx';
3
11
  import {
4
12
  addDataAttributes,
13
+ getTestId,
14
+ isArrayLikeNotEmpty,
5
15
  isNotEmpty,
6
16
  isReactNodeNotEmpty,
7
17
  isStringNotEmpty,
@@ -10,18 +20,20 @@ import { useTweakStyles } from '../../hooks';
10
20
  import { ICommonProps } from '../../types';
11
21
  import { ControlWrapper, IControlWrapperProps } from '../ControlWrapper';
12
22
  import { IWithMessagesProps, WithMessages } from '../WithMessages';
13
- import { ITextAreaHTMLBaseProps } from './types';
14
- import { controlWrapperStyles, ITextAreaStyles, useStyles } from './TextArea.styles';
23
+ import { ITextAreaCounterPosition } from './types';
24
+ import { ITextAreaStyles, useStyles } from './TextArea.styles';
15
25
 
16
26
  export interface ITextAreaProps
17
27
  extends ICommonProps<ITextAreaStyles>,
18
- Pick<IControlWrapperProps, 'label' | 'isInvalid' | 'isRequired' | 'isDisabled'>,
19
- Pick<IWithMessagesProps, 'infoMessage' | 'errorMessage'>,
20
- Pick<ITextAreaHTMLBaseProps, 'name' | 'maxLength' | 'rows' | 'onPaste' | 'onFocus' | 'onBlur'> {
28
+ Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'onChange'>,
29
+ Pick<
30
+ IControlWrapperProps,
31
+ 'label' | 'isInvalid' | 'isRequired' | 'isDisabled' | 'size' | 'groupPlacement'
32
+ >,
33
+ Pick<IWithMessagesProps, 'infoMessage' | 'errorMessage'> {
21
34
  value?: string;
22
35
  placeholder?: string;
23
- /** @default false */
24
- isDisabled?: boolean;
36
+ counterPosition?: ITextAreaCounterPosition;
25
37
  /** @default false */
26
38
  isActive?: boolean;
27
39
  /**
@@ -40,23 +52,18 @@ export interface ITextAreaProps
40
52
  onChange: (value: string, event?: FormEvent<HTMLTextAreaElement>) => void;
41
53
  }
42
54
 
43
- const DEFAULT_VALUE = '';
44
-
45
55
  export const TextArea = forwardRef<HTMLTextAreaElement, ITextAreaProps>(
46
56
  (
47
57
  {
48
- value = DEFAULT_VALUE,
49
- label,
58
+ value = '',
50
59
  placeholder,
51
- infoMessage,
52
- errorMessage,
53
60
  name,
61
+ counterPosition = 'default',
54
62
  shouldFocusOnMount,
55
63
  hasCounter = true,
56
64
  shouldTrimAfterMaxLength,
57
65
  isAutoSized = true,
58
66
  shouldAlwaysShowPlaceholder,
59
- isDisabled,
60
67
  isActive,
61
68
  maxLength,
62
69
  rows,
@@ -67,12 +74,25 @@ export const TextArea = forwardRef<HTMLTextAreaElement, ITextAreaProps>(
67
74
  onPaste,
68
75
  onFocus,
69
76
  onBlur,
70
- ...controlProps
77
+ // Пропсы WithMessages
78
+ infoMessage,
79
+ errorMessage,
80
+ // Пропсы ControlWrapper
81
+ label,
82
+ isDisabled,
83
+ isInvalid,
84
+ isRequired,
85
+ size,
86
+ groupPlacement,
87
+ ...textAreaProps
71
88
  },
72
89
  ref,
73
90
  ) => {
74
91
  const classes = useStyles({ theme: tweakStyles });
75
92
 
93
+ const shouldShowCounter = hasCounter && isNotEmpty(maxLength);
94
+ const counterString = `${value.length} / ${maxLength}`;
95
+
76
96
  const tweakWithMessagesStyles = useTweakStyles({
77
97
  tweakStyles,
78
98
  className: 'tweakWithMessages',
@@ -80,7 +100,6 @@ export const TextArea = forwardRef<HTMLTextAreaElement, ITextAreaProps>(
80
100
  });
81
101
 
82
102
  const tweakControlWrapperStyles = useTweakStyles({
83
- innerStyles: controlWrapperStyles,
84
103
  tweakStyles,
85
104
  className: 'tweakControlWrapper',
86
105
  currentComponentName: 'TextArea',
@@ -89,8 +108,7 @@ export const TextArea = forwardRef<HTMLTextAreaElement, ITextAreaProps>(
89
108
  const [isFocused, setFocused] = useState(false);
90
109
 
91
110
  const hasFocus = isFocused || isActive;
92
- // в hasValue нельзя использовать isStringNotEmpty из-за того что isStringNotEmpty делает trim
93
- const hasValue = value !== undefined && value !== '';
111
+ const hasValue = isArrayLikeNotEmpty(value);
94
112
  const hasLabel = isReactNodeNotEmpty(label);
95
113
  const hasPlaceholder =
96
114
  (!hasLabel || hasFocus || shouldAlwaysShowPlaceholder) && isStringNotEmpty(placeholder);
@@ -110,52 +128,68 @@ export const TextArea = forwardRef<HTMLTextAreaElement, ITextAreaProps>(
110
128
  };
111
129
 
112
130
  return (
113
- <WithMessages
114
- errorMessage={errorMessage}
115
- infoMessage={infoMessage}
116
- tweakStyles={tweakWithMessagesStyles}
131
+ <div
132
+ className={clsx(classes.root, isNotEmpty(size) && classes[size])}
133
+ style={{ '--counter-length': counterString.length } as Styles}
117
134
  >
118
- <ControlWrapper
119
- label={label}
120
- tweakStyles={tweakControlWrapperStyles}
121
- isFocused={hasFocus}
122
- isDisabled={isDisabled}
123
- hasValue={hasValue}
124
- isFullWidth
125
- testId={testId}
126
- {...controlProps}
135
+ <WithMessages
136
+ errorMessage={errorMessage}
137
+ infoMessage={infoMessage}
138
+ tweakStyles={tweakWithMessagesStyles}
139
+ testId={getTestId(testId, 'wrapper')}
127
140
  >
128
- <div
129
- className={clsx(classes.wrapper, { [classes.autoSized]: isAutoSized })}
130
- {...(isAutoSized && { 'data-value': value })}
131
- >
132
- <textarea
133
- ref={ref}
134
- className={classes.textarea}
135
- value={value}
136
- disabled={isDisabled}
137
- placeholder={hasPlaceholder ? placeholder : undefined}
138
- maxLength={shouldTrimAfterMaxLength ? maxLength : undefined}
139
- name={name}
140
- rows={rows}
141
- onPaste={onPaste}
142
- onFocus={handleFocus}
143
- onBlur={handleBlur}
144
- onChange={handleChange}
145
- {...addDataAttributes(data, testId, 'control')}
146
- />
147
- </div>
148
- </ControlWrapper>
149
- {hasCounter && isNotEmpty(maxLength) && (
150
- <span
151
- className={clsx(classes.symbolsCount, {
152
- [classes.symbolsCountError]: value.length > maxLength,
153
- })}
141
+ <ControlWrapper
142
+ label={label}
143
+ tweakStyles={tweakControlWrapperStyles}
144
+ isFocused={hasFocus}
145
+ isDisabled={isDisabled}
146
+ hasValue={hasValue}
147
+ isInvalid={isInvalid}
148
+ isRequired={isRequired}
149
+ groupPlacement={groupPlacement}
150
+ size={size}
151
+ isFullWidth
154
152
  >
155
- {value.length} / {maxLength}
156
- </span>
157
- )}
158
- </WithMessages>
153
+ <div
154
+ className={clsx(classes.wrapper, {
155
+ [classes.autoSized]: isAutoSized,
156
+ [classes.withLabel]: hasLabel,
157
+ })}
158
+ // Не менять на addDataAttributes
159
+ {...(isAutoSized && { 'data-value': value })}
160
+ >
161
+ <textarea
162
+ ref={ref}
163
+ className={classes.textarea}
164
+ value={value}
165
+ disabled={isDisabled}
166
+ placeholder={hasPlaceholder ? placeholder : undefined}
167
+ maxLength={shouldTrimAfterMaxLength ? maxLength : undefined}
168
+ name={name}
169
+ rows={rows}
170
+ onPaste={onPaste}
171
+ onFocus={handleFocus}
172
+ onBlur={handleBlur}
173
+ onChange={handleChange}
174
+ autoFocus={shouldFocusOnMount}
175
+ {...addDataAttributes(data, testId)}
176
+ {...textAreaProps}
177
+ />
178
+ {shouldShowCounter && (
179
+ <span
180
+ className={clsx(classes.symbolsCount, classes[`counter-${counterPosition}`], {
181
+ [classes.symbolsCountError]: value.length > maxLength,
182
+ [classes.symbolsCountActive]: hasFocus || hasValue,
183
+ })}
184
+ {...addDataAttributes({ counterPosition })}
185
+ >
186
+ {counterString}
187
+ </span>
188
+ )}
189
+ </div>
190
+ </ControlWrapper>
191
+ </WithMessages>
192
+ </div>
159
193
  );
160
194
  },
161
195
  );
@@ -1,3 +1,3 @@
1
1
  export * from './TextArea';
2
- export * from './types';
3
2
  export type { ITextAreaStyles } from './TextArea.styles';
3
+ export * from './types';
@@ -1,6 +1,6 @@
1
- import { TextareaHTMLAttributes } from 'react';
1
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
2
+ import { IExtendableProps } from '../../types';
2
3
 
3
- export type ITextAreaHTMLBaseProps = Pick<
4
- TextareaHTMLAttributes<HTMLTextAreaElement>,
5
- 'placeholder' | 'name' | 'maxLength' | 'rows' | 'onPaste' | 'onFocus' | 'onBlur'
6
- >;
4
+ export interface ITextAreaCounterPositions extends IExtendableProps<'default'> {}
5
+
6
+ export type ITextAreaCounterPosition = keyof ITextAreaCounterPositions;
@@ -7,6 +7,7 @@ export const useStyles = createThemedStyles('TextButton', {
7
7
  alignItems: 'center',
8
8
  height: 24,
9
9
  padding: 0,
10
+ position: 'relative',
10
11
  background: 'transparent',
11
12
  border: 'none',
12
13
  borderRadius: 0,
@@ -32,6 +32,8 @@ export const useStyles = createThemedStyles('Tooltip', {
32
32
  letterSpacing: 0.2,
33
33
  },
34
34
 
35
+ custom: {},
36
+
35
37
  info: {},
36
38
 
37
39
  error: {
@@ -8,7 +8,7 @@ import { useStyles, ITooltipStyles } from './Tooltip.styles';
8
8
  export interface ITooltipProps extends ICommonProps<ITooltipStyles> {
9
9
  text: ReactNode;
10
10
  /** @default 'tooltip' */
11
- view?: 'tooltip' | 'hint';
11
+ view?: 'tooltip' | 'hint' | 'custom';
12
12
  /** @default 'info' */
13
13
  type?: 'info' | 'error';
14
14
  }
@@ -4,7 +4,7 @@ import { IInputProps, Input } from '../Input';
4
4
  import { WithMessages } from './WithMessages';
5
5
 
6
6
  export default {
7
- title: 'WithMessages',
7
+ title: 'Data Display/WithMessages',
8
8
  component: WithMessages,
9
9
  };
10
10
 
@@ -24,6 +24,10 @@ import {
24
24
  useFocus,
25
25
  FloatingArrow,
26
26
  arrow,
27
+ UseClickProps,
28
+ UseFocusProps,
29
+ UseDismissProps,
30
+ UseTransitionStatusProps,
27
31
  } from '@floating-ui/react';
28
32
  import { ICommonProps, IDataAttributes, IRenderNode } from '../../types';
29
33
  import { DEFAULT_OFFSET } from './constants';
@@ -46,8 +50,11 @@ export interface IWithPopupProps extends ICommonProps<IWithPopupStyles> {
46
50
  placement?: Placement;
47
51
  /** @default 'click' */
48
52
  eventType?: IPopupEventType;
49
- /** @default 0 */
50
- hoverDelay?: UseHoverProps['delay'];
53
+ /**
54
+ * @deprecated Используйте hoverOptions
55
+ * @default 0
56
+ */
57
+ hoverDelay?: number;
51
58
  /** @default 6 */
52
59
  popupOffset?: OffsetOptions;
53
60
  arrowProps?: IPopupArrowProps;
@@ -70,6 +77,11 @@ export interface IWithPopupProps extends ICommonProps<IWithPopupStyles> {
70
77
  /** Должна ли минимальная ширина попапа быть равна ширине триггера
71
78
  * @default false */
72
79
  isMinWidthSameAsTrigger?: boolean;
80
+ hoverOptions?: UseHoverProps;
81
+ clickOptions?: UseClickProps;
82
+ focusOptions?: UseFocusProps;
83
+ dismissOptions?: UseDismissProps;
84
+ transitionOptions?: UseTransitionStatusProps;
73
85
  onToggle?: (isActive: boolean, event?: IWithPopupToggleEvent) => void;
74
86
  }
75
87
 
@@ -91,6 +103,11 @@ export const WithPopup: FC<IWithPopupProps> = ({
91
103
  isDisabled = false,
92
104
  shouldShowArrow = false,
93
105
  isMinWidthSameAsTrigger = false,
106
+ hoverOptions,
107
+ clickOptions,
108
+ focusOptions,
109
+ dismissOptions,
110
+ transitionOptions,
94
111
  tweakStyles,
95
112
  data,
96
113
  testId,
@@ -99,15 +116,14 @@ export const WithPopup: FC<IWithPopupProps> = ({
99
116
  const classes = useStyles({ theme: tweakStyles });
100
117
 
101
118
  const [isOpen, setIsOpen] = useState(false);
119
+ const isActive = isOpen && !isDisabled;
102
120
 
103
121
  const arrowRef = useRef<SVGSVGElement>(null);
104
122
 
105
- const handleToggle = (isActive: boolean, event?: IWithPopupToggleEvent) => {
123
+ const handleToggle = (next: boolean, event?: IWithPopupToggleEvent) => {
106
124
  event?.stopPropagation();
107
- if (!isDisabled) {
108
- onToggle?.(isActive, event);
109
- setIsOpen(isActive);
110
- }
125
+ onToggle?.(next, event);
126
+ setIsOpen(next);
111
127
  };
112
128
 
113
129
  const handleClose = (event?: IWithPopupToggleEvent) => {
@@ -115,7 +131,7 @@ export const WithPopup: FC<IWithPopupProps> = ({
115
131
  };
116
132
 
117
133
  const { refs, floatingStyles, context } = useFloating({
118
- open: isOpen,
134
+ open: isActive,
119
135
  middleware: [
120
136
  offset(popupOffset),
121
137
  canBeFlipped && flip({ fallbackAxisSideDirection: 'start' }),
@@ -130,22 +146,27 @@ export const WithPopup: FC<IWithPopupProps> = ({
130
146
 
131
147
  const hover = useHover(context, {
132
148
  enabled: eventType === 'hover',
133
- delay: typeof hoverDelay === 'number' ? { open: hoverDelay, close: 0 } : hoverDelay,
149
+ delay: { open: hoverDelay, close: 0 },
134
150
  handleClose: safePolygon(),
151
+ ...hoverOptions,
135
152
  });
136
153
 
137
- const focus = useFocus(context, { enabled: eventType === 'hover' });
154
+ const focus = useFocus(context, { enabled: eventType === 'hover', ...focusOptions });
138
155
 
139
- const click = useClick(context, { enabled: eventType === 'click' });
156
+ const click = useClick(context, { enabled: eventType === 'click', ...clickOptions });
140
157
 
141
158
  const dismiss = useDismiss(context, {
142
159
  enabled: eventType === 'click',
143
160
  ancestorScroll: shouldHideOnScroll,
161
+ ...dismissOptions,
144
162
  });
145
163
 
146
164
  const { getFloatingProps, getReferenceProps } = useInteractions([hover, click, focus, dismiss]);
147
165
 
148
- const { isMounted, status } = useTransitionStatus(context, { duration: { close: 500 } });
166
+ const { isMounted, status } = useTransitionStatus(context, {
167
+ duration: { close: 500 },
168
+ ...transitionOptions,
169
+ });
149
170
 
150
171
  const referenceProps: IReferenceProps = getReferenceProps({
151
172
  ref: refs.setReference,
@@ -157,7 +178,7 @@ export const WithPopup: FC<IWithPopupProps> = ({
157
178
  const triggerElement = applyAction(trigger, {
158
179
  referenceProps: !isTriggerWrapped ? referenceProps : undefined,
159
180
  triggerProps: {
160
- isActive: isOpen,
181
+ isActive,
161
182
  isDisabled,
162
183
  ...(!isTriggerWrapped && { data, testId, ...referenceProps }),
163
184
  },
@@ -170,7 +191,7 @@ export const WithPopup: FC<IWithPopupProps> = ({
170
191
  className={clsx(classes.trigger, {
171
192
  [classes.clickable]: eventType === 'click',
172
193
  [classes.disabled]: isDisabled,
173
- [classes.active]: isOpen,
194
+ [classes.active]: isActive,
174
195
  })}
175
196
  {...referenceProps}
176
197
  {...addDataAttributes(data, testId)}
@@ -189,7 +210,7 @@ export const WithPopup: FC<IWithPopupProps> = ({
189
210
  style={floatingStyles}
190
211
  className={classes.popup}
191
212
  {...getFloatingProps()}
192
- {...addDataAttributes(popupData)}
213
+ {...addDataAttributes(popupData, testId, 'popup')}
193
214
  >
194
215
  <div className={classes[`dropdown-${status}`]}>
195
216
  {shouldShowArrow && (
@@ -1,6 +1,15 @@
1
1
  import type { IPhoneInfo } from '../components';
2
2
 
3
3
  export const phoneInfo: IPhoneInfo[] = [
4
+ {
5
+ countryEn: 'Abkhazia',
6
+ countryRu: 'Абхазия',
7
+ countryCode: 'AB',
8
+ phoneMask: '(999) 999-99-99',
9
+ dialCode: '7',
10
+ dialCodePriority: 1,
11
+ fullCodes: ['7'],
12
+ },
4
13
  {
5
14
  countryEn: 'Afghanistan',
6
15
  countryRu: 'Афганистан',
@@ -785,40 +794,9 @@ export const phoneInfo: IPhoneInfo[] = [
785
794
  countryRu: 'Казахстан',
786
795
  countryCode: 'KZ',
787
796
  dialCode: '7',
788
- phoneMask: '999 999-99-99',
797
+ phoneMask: '(999) 999-99-99',
789
798
  dialCodePriority: 1,
790
- areaCodes: [
791
- '310',
792
- '311',
793
- '312',
794
- '313',
795
- '315',
796
- '318',
797
- '321',
798
- '324',
799
- '325',
800
- '326',
801
- '327',
802
- '336',
803
- '7172',
804
- '73622',
805
- ],
806
- fullCodes: [
807
- '7310',
808
- '7311',
809
- '7312',
810
- '7313',
811
- '7315',
812
- '7318',
813
- '7321',
814
- '7324',
815
- '7325',
816
- '7326',
817
- '7327',
818
- '7336',
819
- '77172',
820
- '773622',
821
- ],
799
+ fullCodes: ['7'],
822
800
  },
823
801
  {
824
802
  countryEn: 'Kenya',
@@ -1404,6 +1382,15 @@ export const phoneInfo: IPhoneInfo[] = [
1404
1382
  phoneMask: '999 9999 9999',
1405
1383
  fullCodes: ['82'],
1406
1384
  },
1385
+ {
1386
+ countryCode: 'OS',
1387
+ countryEn: 'South Ossetia',
1388
+ countryRu: 'Южная Осетия',
1389
+ phoneMask: '(999) 999-99-99',
1390
+ dialCode: '7',
1391
+ dialCodePriority: 1,
1392
+ fullCodes: ['7'],
1393
+ },
1407
1394
  {
1408
1395
  countryEn: 'South Sudan',
1409
1396
  countryRu: 'Южный Судан',
@@ -1,4 +1,4 @@
1
- import { isNotEmpty, isEmpty } from '@true-engineering/true-react-platform-helpers';
1
+ import { isNotEmpty, isStringEmpty } from '@true-engineering/true-react-platform-helpers';
2
2
  import type { IPhoneInfo, IPhoneValue } from '../components';
3
3
  import { phoneInfo } from '../constants';
4
4
 
@@ -46,22 +46,26 @@ export const getFullPhone = (phone?: IPhoneValue): string =>
46
46
  (phone?.dialCode ?? '') + (phone?.phoneNumber ?? '');
47
47
 
48
48
  export const getCountryCodeFromPhone = (phoneWithCode: string): string | undefined => {
49
- // попробуем найти уникальный код страны fullCode (dialCode + arealCode)
50
- let countryCode = phoneInfo.find((info) =>
51
- info.fullCodes.some((code) => phoneWithCode.startsWith(code)),
52
- )?.countryCode;
53
-
54
- if (isEmpty(countryCode) && isNotEmpty(phoneWithCode)) {
55
- // если не нашли уникальный fullCode (dialCode + arealCode),
56
- // то пробуем найти dialCode и выбираем с наименьшим Priority
57
- countryCode = phoneInfo
58
- .filter((info) => phoneWithCode.startsWith(info.dialCode))
59
- .sort(
60
- (infoA, infoB) => (infoA.dialCodePriority ?? 1000) - (infoB.dialCodePriority ?? 1000),
61
- )[0]?.countryCode;
49
+ if (isStringEmpty(phoneWithCode)) {
50
+ return;
62
51
  }
63
52
 
64
- return countryCode;
53
+ // ищем страны, для которых phoneWithCode начинается с fullCode (dialCode + areaCode)
54
+ const matchedCountries = phoneInfo.filter((info) =>
55
+ info.fullCodes.some((fullCode) => phoneWithCode.startsWith(fullCode)),
56
+ );
57
+
58
+ // если нашлась всего одна — ок, выдаём её
59
+ if (matchedCountries.length === 1) {
60
+ return matchedCountries[0].countryCode;
61
+ }
62
+
63
+ // если нашлось несколько, выбираем страну с наименьшим dialCodePriority (0 — самая приоритетная)
64
+ const highestPriorityCountries = phoneInfo
65
+ .filter((info) => phoneWithCode.startsWith(info.dialCode))
66
+ .sort((a, b) => (a.dialCodePriority ?? 1000) - (b.dialCodePriority ?? 1000));
67
+
68
+ return highestPriorityCountries.at(0)?.countryCode;
65
69
  };
66
70
 
67
71
  export const getPhoneObjFromString = (fullPhone: string, countryCode?: string): IPhoneValue => {
@@ -5,3 +5,5 @@ export * from './use-tweak-styles';
5
5
  export * from './use-did-mount-effect';
6
6
  export * from './use-mixed-styles';
7
7
  export * from './use-merged-refs';
8
+ export * from './use-merge';
9
+ export * from './use-intersection-ref';
@@ -0,0 +1,30 @@
1
+ import { useRef, useMemo, RefCallback } from 'react';
2
+ import { isNotEmpty } from '@true-engineering/true-react-platform-helpers';
3
+
4
+ export interface IInsertionRefOptions {
5
+ /** @default false */
6
+ isDisabled?: boolean;
7
+ onIntersection?: VoidFunction;
8
+ onIntersectionEnd?: VoidFunction;
9
+ }
10
+
11
+ export const useIntersectionRef = (options?: IInsertionRefOptions): RefCallback<Element> => {
12
+ const optionsRef = useRef(options);
13
+ optionsRef.current = options;
14
+
15
+ return useMemo(() => {
16
+ const observer = new IntersectionObserver(([{ isIntersecting }]) => {
17
+ const { current } = optionsRef;
18
+ if (current?.isDisabled) {
19
+ return;
20
+ }
21
+ if (isIntersecting) {
22
+ current?.onIntersection?.();
23
+ } else {
24
+ current?.onIntersectionEnd?.();
25
+ }
26
+ });
27
+
28
+ return (node) => (isNotEmpty(node) ? observer.observe(node) : observer.disconnect());
29
+ }, []);
30
+ };
@@ -0,0 +1,8 @@
1
+ import { useMemo } from 'react';
2
+ import { isNotEmpty, mergeStyles } from '@true-engineering/true-react-platform-helpers';
3
+
4
+ export const useMerge = <T>(one?: T, two?: T): T | undefined =>
5
+ useMemo(
6
+ () => (isNotEmpty(one) && isNotEmpty(two) ? mergeStyles(one, two) : one ?? two),
7
+ [one, two],
8
+ );
@@ -1,14 +1,12 @@
1
1
  import { useMemo } from 'react';
2
- import { isNotEmpty, mergeStyles } from '@true-engineering/true-react-platform-helpers';
2
+ import { isObject } from '@true-engineering/true-react-platform-helpers';
3
+ import type { IMixedStyles } from '../theme';
4
+
5
+ export const mixStyles = <T>(...tweakStyles: Array<IMixedStyles<T>>): Array<NonNullable<T>> =>
6
+ tweakStyles.flat().filter(isObject) as Array<NonNullable<T>>;
3
7
 
4
8
  export const useMixedStyles = <StyleSheet>(
5
- baseStyles?: StyleSheet,
6
- tweakStyles?: StyleSheet,
7
- ): StyleSheet | undefined =>
8
- useMemo(
9
- () =>
10
- isNotEmpty(baseStyles) && isNotEmpty(tweakStyles)
11
- ? mergeStyles(baseStyles, tweakStyles)
12
- : baseStyles ?? tweakStyles,
13
- [baseStyles, tweakStyles],
14
- );
9
+ baseStyles?: IMixedStyles<StyleSheet>,
10
+ tweakStyles?: IMixedStyles<StyleSheet>,
11
+ ): Array<NonNullable<StyleSheet>> =>
12
+ useMemo(() => mixStyles(baseStyles, tweakStyles), [baseStyles, tweakStyles]);