@true-engineering/true-react-common-ui-kit 2.7.0 → 3.0.0-alpha.1

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 (478) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +0 -26
  3. package/dist/components/AccountInfo/AccountInfo.d.ts +2 -3
  4. package/dist/components/AccountInfo/AccountInfo.styles.d.ts +6 -64
  5. package/dist/components/AccountInfo/index.d.ts +1 -1
  6. package/dist/components/AddButton/AddButton.d.ts +2 -3
  7. package/dist/components/AddButton/AddButton.styles.d.ts +3 -28
  8. package/dist/components/AddButton/index.d.ts +1 -1
  9. package/dist/components/Button/Button.d.ts +2 -4
  10. package/dist/components/Button/Button.styles.d.ts +8 -150
  11. package/dist/components/Button/index.d.ts +1 -1
  12. package/dist/components/Checkbox/Checkbox.d.ts +3 -17
  13. package/dist/components/Checkbox/Checkbox.styles.d.ts +3 -50
  14. package/dist/components/Checkbox/index.d.ts +1 -1
  15. package/dist/components/CloseButton/CloseButton.d.ts +3 -5
  16. package/dist/components/CloseButton/CloseButton.styles.d.ts +3 -27
  17. package/dist/components/CloseButton/index.d.ts +1 -1
  18. package/dist/components/Colors/Colors.styles.d.ts +1 -32
  19. package/dist/components/Colors/index.d.ts +0 -1
  20. package/dist/components/CssBaseline/CssBaseline.d.ts +2 -4
  21. package/dist/components/CssBaseline/CssBaseline.styles.d.ts +3 -11
  22. package/dist/components/CssBaseline/index.d.ts +1 -1
  23. package/dist/components/DateInput/DateInput.d.ts +3 -3
  24. package/dist/components/DateInput/DateInput.styles.d.ts +6 -11
  25. package/dist/components/DateInput/index.d.ts +1 -1
  26. package/dist/components/DatePicker/DatePicker.d.ts +5 -7
  27. package/dist/components/DatePicker/DatePicker.styles.d.ts +6 -33
  28. package/dist/components/DatePicker/components/DatePickerHeader/DatePickerHeader.d.ts +3 -3
  29. package/dist/components/DatePicker/components/DatePickerHeader/DatePickerHeader.styles.d.ts +7 -69
  30. package/dist/components/DatePicker/components/DatePickerHeader/index.d.ts +1 -1
  31. package/dist/components/DatePicker/index.d.ts +2 -2
  32. package/dist/components/Description/Description.d.ts +2 -3
  33. package/dist/components/Description/Description.styles.d.ts +3 -24
  34. package/dist/components/Description/index.d.ts +1 -1
  35. package/dist/components/FiltersPane/FiltersPane.d.ts +6 -8
  36. package/dist/components/FiltersPane/FiltersPane.styles.d.ts +8 -56
  37. package/dist/components/FiltersPane/components/FilterInterval/FilterInterval.d.ts +2 -4
  38. package/dist/components/FiltersPane/components/FilterInterval/FilterInterval.styles.d.ts +15 -52
  39. package/dist/components/FiltersPane/components/FilterInterval/index.d.ts +1 -1
  40. package/dist/components/FiltersPane/components/FilterSelect/FilterSelect.d.ts +2 -4
  41. package/dist/components/FiltersPane/components/FilterSelect/FilterSelect.styles.d.ts +15 -124
  42. package/dist/components/FiltersPane/components/FilterSelect/index.d.ts +1 -1
  43. package/dist/components/FiltersPane/components/FilterValueView/FilterValueView.d.ts +3 -1
  44. package/dist/components/FiltersPane/components/FilterValueView/FilterValueView.styles.d.ts +3 -12
  45. package/dist/components/FiltersPane/components/FilterValueView/index.d.ts +1 -1
  46. package/dist/components/FiltersPane/components/FilterWithDates/FilterWithDates.d.ts +5 -7
  47. package/dist/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.d.ts +26 -47
  48. package/dist/components/FiltersPane/components/FilterWithDates/index.d.ts +1 -1
  49. package/dist/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.d.ts +4 -6
  50. package/dist/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.styles.d.ts +7 -12
  51. package/dist/components/FiltersPane/components/FilterWithPeriod/index.d.ts +1 -1
  52. package/dist/components/FiltersPane/components/FilterWrapper/FilterWrapper.d.ts +5 -6
  53. package/dist/components/FiltersPane/components/FilterWrapper/FilterWrapper.styles.d.ts +6 -96
  54. package/dist/components/FiltersPane/components/FilterWrapper/index.d.ts +1 -1
  55. package/dist/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.d.ts +2 -4
  56. package/dist/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.styles.d.ts +10 -91
  57. package/dist/components/FiltersPane/components/FiltersPaneSearch/index.d.ts +1 -1
  58. package/dist/components/FiltersPane/helpers.d.ts +1 -1
  59. package/dist/components/FiltersPane/index.d.ts +1 -1
  60. package/dist/components/FiltersPane/types.d.ts +1 -1
  61. package/dist/components/Flag/Flag.d.ts +2 -3
  62. package/dist/components/Flag/Flag.styles.d.ts +3 -12
  63. package/dist/components/Flag/augment.d.ts +1 -1
  64. package/dist/components/Flag/index.d.ts +1 -1
  65. package/dist/components/FlexibleTable/FlexibleTable.d.ts +4 -6
  66. package/dist/components/FlexibleTable/FlexibleTable.styles.d.ts +7 -101
  67. package/dist/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.d.ts +17 -0
  68. package/dist/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.styles.d.ts +3 -0
  69. package/dist/components/FlexibleTable/components/FlexibleTableCell/index.d.ts +2 -0
  70. package/dist/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.d.ts +19 -0
  71. package/dist/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.styles.d.ts +6 -0
  72. package/dist/components/FlexibleTable/components/FlexibleTableRow/index.d.ts +2 -0
  73. package/dist/components/FlexibleTable/components/index.d.ts +2 -2
  74. package/dist/components/FlexibleTable/index.d.ts +2 -1
  75. package/dist/components/FlexibleTable/types.d.ts +1 -1
  76. package/dist/components/Icon/Icon.d.ts +2 -3
  77. package/dist/components/Icon/Icon.styles.d.ts +3 -8
  78. package/dist/components/Icon/complexIcons/augment.d.ts +1 -1
  79. package/dist/components/Icon/icons-list.d.ts +1 -1
  80. package/dist/components/Icon/index.d.ts +1 -1
  81. package/dist/components/IncrementInput/IncrementInput.d.ts +3 -3
  82. package/dist/components/IncrementInput/IncrementInput.styles.d.ts +7 -61
  83. package/dist/components/IncrementInput/index.d.ts +1 -1
  84. package/dist/components/Input/Input.d.ts +2 -4
  85. package/dist/components/Input/Input.styles.d.ts +6 -247
  86. package/dist/components/Input/index.d.ts +1 -1
  87. package/dist/components/List/List.d.ts +3 -5
  88. package/dist/components/List/List.styles.d.ts +3 -11
  89. package/dist/components/List/index.d.ts +2 -1
  90. package/dist/components/{ListItem → List}/types.d.ts +0 -5
  91. package/dist/components/Modal/Modal.d.ts +2 -4
  92. package/dist/components/Modal/Modal.styles.d.ts +6 -239
  93. package/dist/components/Modal/index.d.ts +1 -1
  94. package/dist/components/MoreMenu/MoreMenu.d.ts +4 -6
  95. package/dist/components/MoreMenu/MoreMenu.styles.d.ts +6 -54
  96. package/dist/components/MoreMenu/index.d.ts +1 -1
  97. package/dist/components/MultiSelect/MultiSelect.d.ts +8 -8
  98. package/dist/components/MultiSelect/MultiSelect.styles.d.ts +7 -44
  99. package/dist/components/MultiSelect/components/MultiSelectInput/MultiSelectInput.d.ts +4 -4
  100. package/dist/components/MultiSelect/components/MultiSelectInput/MultiSelectInput.styles.d.ts +3 -62
  101. package/dist/components/MultiSelect/components/MultiSelectInput/index.d.ts +1 -1
  102. package/dist/components/MultiSelect/index.d.ts +2 -2
  103. package/dist/components/MultiSelect/types.d.ts +1 -1
  104. package/dist/components/MultiSelectList/MultiSelectList.d.ts +2 -4
  105. package/dist/components/MultiSelectList/MultiSelectList.styles.d.ts +13 -105
  106. package/dist/components/MultiSelectList/index.d.ts +1 -1
  107. package/dist/components/Notification/Notification.d.ts +4 -6
  108. package/dist/components/Notification/Notification.styles.d.ts +3 -37
  109. package/dist/components/Notification/index.d.ts +1 -1
  110. package/dist/components/Notification/types.d.ts +1 -1
  111. package/dist/components/PhoneInput/PhoneInput.d.ts +3 -3
  112. package/dist/components/PhoneInput/PhoneInput.styles.d.ts +9 -66
  113. package/dist/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.d.ts +2 -3
  114. package/dist/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.styles.d.ts +7 -83
  115. package/dist/components/PhoneInput/components/PhoneInputCountryList/index.d.ts +1 -1
  116. package/dist/components/PhoneInput/index.d.ts +2 -2
  117. package/dist/components/RadioButton/RadioButton.d.ts +3 -4
  118. package/dist/components/RadioButton/RadioButton.styles.d.ts +3 -30
  119. package/dist/components/RadioButton/index.d.ts +1 -1
  120. package/dist/components/ScrollIntoViewIfNeeded/ScrollIntoViewIfNeeded.d.ts +4 -4
  121. package/dist/components/SearchInput/SearchInput.d.ts +3 -4
  122. package/dist/components/SearchInput/SearchInput.styles.d.ts +7 -39
  123. package/dist/components/SearchInput/index.d.ts +1 -1
  124. package/dist/components/Select/Select.d.ts +3 -4
  125. package/dist/components/Select/Select.styles.d.ts +33 -80
  126. package/dist/components/Select/components/SelectList/SelectList.d.ts +2 -4
  127. package/dist/components/Select/components/SelectList/SelectList.styles.d.ts +3 -57
  128. package/dist/components/Select/components/SelectList/index.d.ts +1 -1
  129. package/dist/components/Select/components/SelectListItem/SelectListItem.styles.d.ts +2 -2
  130. package/dist/components/Select/index.d.ts +2 -2
  131. package/dist/components/SmartInput/SmartInput.d.ts +2 -2
  132. package/dist/components/SmartInput/helpers.d.ts +2 -2
  133. package/dist/components/SmartInput/types.d.ts +1 -1
  134. package/dist/components/Switch/Switch.d.ts +2 -4
  135. package/dist/components/Switch/Switch.styles.d.ts +3 -62
  136. package/dist/components/Switch/index.d.ts +1 -1
  137. package/dist/components/TextArea/TextArea.d.ts +2 -4
  138. package/dist/components/TextArea/TextArea.styles.d.ts +3 -128
  139. package/dist/components/TextArea/index.d.ts +1 -1
  140. package/dist/components/TextWithInfo/TextWithInfo.d.ts +2 -3
  141. package/dist/components/TextWithInfo/TextWithInfo.styles.d.ts +3 -48
  142. package/dist/components/TextWithInfo/index.d.ts +1 -1
  143. package/dist/components/TextWithTooltip/TextWithTooltip.d.ts +2 -3
  144. package/dist/components/TextWithTooltip/TextWithTooltip.styles.d.ts +6 -14
  145. package/dist/components/TextWithTooltip/index.d.ts +1 -1
  146. package/dist/components/ThemedPreloader/ThemedPreloader.d.ts +2 -3
  147. package/dist/components/ThemedPreloader/ThemedPreloader.styles.d.ts +7 -14
  148. package/dist/components/ThemedPreloader/components/DotsPreloader/DotsPreloader.d.ts +2 -4
  149. package/dist/components/ThemedPreloader/components/DotsPreloader/DotsPreloader.styles.d.ts +3 -43
  150. package/dist/components/ThemedPreloader/components/DotsPreloader/index.d.ts +1 -1
  151. package/dist/components/ThemedPreloader/components/SvgPreloader/SvgPreloader.d.ts +2 -3
  152. package/dist/components/ThemedPreloader/components/SvgPreloader/SvgPreloader.styles.d.ts +3 -9
  153. package/dist/components/ThemedPreloader/components/SvgPreloader/index.d.ts +1 -1
  154. package/dist/components/ThemedPreloader/index.d.ts +2 -2
  155. package/dist/components/Toaster/Toaster.d.ts +4 -5
  156. package/dist/components/Toaster/Toaster.styles.d.ts +6 -45
  157. package/dist/components/Toaster/index.d.ts +1 -1
  158. package/dist/components/Toaster/types.d.ts +1 -1
  159. package/dist/components/Tooltip/Tooltip.d.ts +2 -3
  160. package/dist/components/Tooltip/Tooltip.styles.d.ts +3 -35
  161. package/dist/components/Tooltip/index.d.ts +1 -1
  162. package/dist/components/index.d.ts +0 -1
  163. package/dist/helpers/index.d.ts +0 -2
  164. package/dist/helpers/phone.d.ts +3 -0
  165. package/dist/hooks/index.d.ts +0 -1
  166. package/dist/hooks/use-tweak-styles.d.ts +21 -2
  167. package/dist/index.d.ts +1 -1
  168. package/dist/theme/Provider.d.ts +11 -0
  169. package/dist/{theme.d.ts → theme/common.d.ts} +6 -10
  170. package/dist/theme/helpers.d.ts +10 -0
  171. package/dist/theme/index.d.ts +4 -0
  172. package/dist/theme/types.d.ts +72 -0
  173. package/dist/true-react-common-ui-kit.js +3074 -2663
  174. package/dist/true-react-common-ui-kit.js.map +1 -1
  175. package/dist/true-react-common-ui-kit.umd.cjs +3020 -2609
  176. package/dist/true-react-common-ui-kit.umd.cjs.map +1 -1
  177. package/dist/types.d.ts +4 -22
  178. package/dist/vite-env.d.ts +1 -1
  179. package/package.json +93 -93
  180. package/src/components/AccountInfo/AccountInfo.stories.tsx +32 -32
  181. package/src/components/AccountInfo/AccountInfo.styles.ts +51 -55
  182. package/src/components/AccountInfo/AccountInfo.tsx +79 -76
  183. package/src/components/AccountInfo/constants.ts +1 -1
  184. package/src/components/AccountInfo/index.ts +2 -2
  185. package/src/components/AddButton/AddButton.stories.tsx +21 -21
  186. package/src/components/AddButton/AddButton.styles.ts +34 -34
  187. package/src/components/AddButton/AddButton.tsx +49 -48
  188. package/src/components/AddButton/index.ts +2 -2
  189. package/src/components/Button/Button.stories.tsx +56 -56
  190. package/src/components/Button/Button.styles.ts +201 -196
  191. package/src/components/Button/Button.tsx +147 -153
  192. package/src/components/Button/constants.ts +9 -9
  193. package/src/components/Button/index.ts +3 -3
  194. package/src/components/Button/types.ts +5 -5
  195. package/src/components/Checkbox/Checkbox.stories.tsx +28 -32
  196. package/src/components/Checkbox/Checkbox.styles.ts +46 -62
  197. package/src/components/Checkbox/Checkbox.tsx +83 -105
  198. package/src/components/Checkbox/index.ts +2 -2
  199. package/src/components/CloseButton/CloseButton.styles.ts +33 -34
  200. package/src/components/CloseButton/CloseButton.tsx +33 -35
  201. package/src/components/CloseButton/index.ts +2 -2
  202. package/src/components/Colors/Colors.stories.tsx +7 -7
  203. package/src/components/Colors/Colors.styles.ts +36 -38
  204. package/src/components/Colors/Colors.tsx +26 -26
  205. package/src/components/Colors/index.ts +1 -2
  206. package/src/components/CssBaseline/CssBaseline.styles.ts +14 -15
  207. package/src/components/CssBaseline/CssBaseline.tsx +13 -15
  208. package/src/components/CssBaseline/index.ts +2 -2
  209. package/src/components/DateInput/DateInput.stories.tsx +61 -61
  210. package/src/components/DateInput/DateInput.styles.ts +18 -14
  211. package/src/components/DateInput/DateInput.tsx +95 -82
  212. package/src/components/DateInput/constants.ts +2 -2
  213. package/src/components/DateInput/index.ts +3 -3
  214. package/src/components/DatePicker/DatePicker.stories.tsx +87 -87
  215. package/src/components/DatePicker/DatePicker.styles.ts +38 -44
  216. package/src/components/DatePicker/DatePicker.tsx +308 -309
  217. package/src/components/DatePicker/components/DatePickerHeader/DatePickerHeader.styles.ts +88 -84
  218. package/src/components/DatePicker/components/DatePickerHeader/DatePickerHeader.tsx +89 -79
  219. package/src/components/DatePicker/components/DatePickerHeader/index.ts +2 -2
  220. package/src/components/DatePicker/components/PopperContainer/PopperContainer.tsx +6 -6
  221. package/src/components/DatePicker/components/PopperContainer/index.ts +1 -1
  222. package/src/components/DatePicker/components/index.ts +2 -2
  223. package/src/components/DatePicker/constants.ts +6 -6
  224. package/src/components/DatePicker/helpers.ts +23 -23
  225. package/src/components/DatePicker/index.ts +4 -4
  226. package/src/components/DatePicker/types.ts +45 -45
  227. package/src/components/Description/Description.stories.tsx +27 -27
  228. package/src/components/Description/Description.styles.ts +30 -31
  229. package/src/components/Description/Description.tsx +59 -59
  230. package/src/components/Description/constants.ts +1 -1
  231. package/src/components/Description/index.ts +2 -2
  232. package/src/components/FiltersPane/FiltersPane.stories.tsx +295 -295
  233. package/src/components/FiltersPane/FiltersPane.styles.ts +87 -71
  234. package/src/components/FiltersPane/FiltersPane.tsx +155 -150
  235. package/src/components/FiltersPane/components/Filter/Filter.tsx +203 -203
  236. package/src/components/FiltersPane/components/Filter/index.ts +1 -1
  237. package/src/components/FiltersPane/components/FilterInterval/FilterInterval.styles.ts +60 -64
  238. package/src/components/FiltersPane/components/FilterInterval/FilterInterval.tsx +154 -141
  239. package/src/components/FiltersPane/components/FilterInterval/index.ts +2 -2
  240. package/src/components/FiltersPane/components/FilterMultiSelect/FilterMultiSelect.tsx +10 -10
  241. package/src/components/FiltersPane/components/FilterMultiSelect/index.ts +1 -1
  242. package/src/components/FiltersPane/components/FilterSelect/FilterSelect.styles.ts +138 -143
  243. package/src/components/FiltersPane/components/FilterSelect/FilterSelect.tsx +359 -346
  244. package/src/components/FiltersPane/components/FilterSelect/index.ts +2 -2
  245. package/src/components/FiltersPane/components/FilterValueView/FilterValueView.styles.tsx +15 -15
  246. package/src/components/FiltersPane/components/FilterValueView/FilterValueView.tsx +165 -163
  247. package/src/components/FiltersPane/components/FilterValueView/index.tsx +2 -2
  248. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.styles.ts +67 -60
  249. package/src/components/FiltersPane/components/FilterWithDates/FilterWithDates.tsx +210 -181
  250. package/src/components/FiltersPane/components/FilterWithDates/index.ts +2 -2
  251. package/src/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.styles.ts +21 -17
  252. package/src/components/FiltersPane/components/FilterWithPeriod/FilterWithPeriod.tsx +177 -174
  253. package/src/components/FiltersPane/components/FilterWithPeriod/index.ts +2 -2
  254. package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.styles.ts +115 -110
  255. package/src/components/FiltersPane/components/FilterWrapper/FilterWrapper.tsx +167 -149
  256. package/src/components/FiltersPane/components/FilterWrapper/index.ts +2 -2
  257. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.styles.ts +116 -109
  258. package/src/components/FiltersPane/components/FiltersPaneSearch/FiltersPaneSearch.tsx +168 -155
  259. package/src/components/FiltersPane/components/FiltersPaneSearch/index.ts +2 -2
  260. package/src/components/FiltersPane/components/index.ts +9 -9
  261. package/src/components/FiltersPane/constants.ts +137 -137
  262. package/src/components/FiltersPane/helpers.ts +26 -26
  263. package/src/components/FiltersPane/index.ts +5 -5
  264. package/src/components/FiltersPane/types.ts +156 -156
  265. package/src/components/Flag/Flag.stories.tsx +29 -29
  266. package/src/components/Flag/Flag.styles.ts +17 -18
  267. package/src/components/Flag/Flag.tsx +25 -27
  268. package/src/components/Flag/augment.d.ts +1 -1
  269. package/src/components/Flag/index.ts +2 -2
  270. package/src/components/FlexibleTable/FlexibleTable.stories.tsx +350 -338
  271. package/src/components/FlexibleTable/FlexibleTable.styles.ts +104 -131
  272. package/src/components/FlexibleTable/FlexibleTable.tsx +196 -205
  273. package/src/components/FlexibleTable/components/FlexibleTableCell/FlexibleTableCell.styles.ts +28 -0
  274. package/src/components/FlexibleTable/components/{TableValue/TableValue.tsx → FlexibleTableCell/FlexibleTableCell.tsx} +73 -74
  275. package/src/components/FlexibleTable/components/FlexibleTableCell/index.ts +2 -0
  276. package/src/components/FlexibleTable/components/FlexibleTableRow/FlexibleTableRow.styles.ts +19 -0
  277. package/src/components/FlexibleTable/components/{TableRow/TableRow.tsx → FlexibleTableRow/FlexibleTableRow.tsx} +151 -152
  278. package/src/components/FlexibleTable/components/FlexibleTableRow/index.ts +2 -0
  279. package/src/components/FlexibleTable/components/index.ts +2 -2
  280. package/src/components/FlexibleTable/constants.ts +1 -1
  281. package/src/components/FlexibleTable/index.ts +4 -3
  282. package/src/components/FlexibleTable/types.ts +52 -52
  283. package/src/components/Icon/Icon.stories.tsx +86 -86
  284. package/src/components/Icon/Icon.styles.ts +10 -10
  285. package/src/components/Icon/Icon.tsx +26 -27
  286. package/src/components/Icon/complexIcons/augment.d.ts +1 -1
  287. package/src/components/Icon/complexIcons/avatarGreen.svg +57 -57
  288. package/src/components/Icon/complexIcons/icons.ts +5 -5
  289. package/src/components/Icon/complexIcons/index.ts +1 -1
  290. package/src/components/Icon/components/ComplexIconBoilerplate/ComplexIconBoilerplate.tsx +16 -16
  291. package/src/components/Icon/components/ComplexIconBoilerplate/index.ts +1 -1
  292. package/src/components/Icon/components/IconBolerplate/IconBoilerplate.tsx +43 -43
  293. package/src/components/Icon/components/IconBolerplate/index.ts +1 -1
  294. package/src/components/Icon/components/index.ts +2 -2
  295. package/src/components/Icon/helpers.ts +9 -9
  296. package/src/components/Icon/icons-list.ts +826 -856
  297. package/src/components/Icon/index.ts +4 -4
  298. package/src/components/Icon/types.ts +16 -16
  299. package/src/components/IncrementInput/IncrementInput.stories.tsx +31 -31
  300. package/src/components/IncrementInput/IncrementInput.styles.ts +77 -77
  301. package/src/components/IncrementInput/IncrementInput.tsx +104 -80
  302. package/src/components/IncrementInput/index.ts +2 -2
  303. package/src/components/Input/Input.stories.tsx +86 -86
  304. package/src/components/Input/Input.styles.ts +307 -307
  305. package/src/components/Input/Input.tsx +311 -308
  306. package/src/components/Input/constants.ts +1 -1
  307. package/src/components/Input/index.ts +3 -3
  308. package/src/components/Input/types.ts +6 -6
  309. package/src/components/List/List.stories.tsx +63 -63
  310. package/src/components/List/List.styles.ts +51 -14
  311. package/src/components/List/List.tsx +51 -36
  312. package/src/components/List/index.ts +3 -2
  313. package/src/components/{ListItem → List}/types.ts +13 -19
  314. package/src/components/Modal/Modal.stories.tsx +105 -105
  315. package/src/components/Modal/Modal.styles.ts +303 -305
  316. package/src/components/Modal/Modal.tsx +186 -184
  317. package/src/components/Modal/index.ts +3 -3
  318. package/src/components/Modal/types.ts +17 -17
  319. package/src/components/MoreMenu/MoreMenu.stories.tsx +46 -46
  320. package/src/components/MoreMenu/MoreMenu.styles.ts +68 -70
  321. package/src/components/MoreMenu/MoreMenu.tsx +93 -90
  322. package/src/components/MoreMenu/index.ts +2 -2
  323. package/src/components/MultiSelect/MultiSelect.stories.tsx +46 -46
  324. package/src/components/MultiSelect/MultiSelect.styles.ts +59 -55
  325. package/src/components/MultiSelect/MultiSelect.tsx +101 -92
  326. package/src/components/MultiSelect/components/MultiSelectInput/MultiSelectInput.styles.ts +73 -73
  327. package/src/components/MultiSelect/components/MultiSelectInput/MultiSelectInput.tsx +52 -51
  328. package/src/components/MultiSelect/components/MultiSelectInput/index.ts +2 -2
  329. package/src/components/MultiSelect/components/index.ts +1 -1
  330. package/src/components/MultiSelect/index.ts +4 -4
  331. package/src/components/MultiSelect/types.ts +1 -1
  332. package/src/components/MultiSelectList/MultiSelectList.styles.ts +132 -124
  333. package/src/components/MultiSelectList/MultiSelectList.tsx +460 -441
  334. package/src/components/MultiSelectList/constants.ts +21 -21
  335. package/src/components/MultiSelectList/helpers.ts +11 -11
  336. package/src/components/MultiSelectList/index.ts +3 -3
  337. package/src/components/MultiSelectList/types.ts +15 -15
  338. package/src/components/Notification/Notification.stories.tsx +46 -46
  339. package/src/components/Notification/Notification.styles.ts +55 -50
  340. package/src/components/Notification/Notification.tsx +75 -78
  341. package/src/components/Notification/index.ts +3 -3
  342. package/src/components/Notification/types.ts +1 -1
  343. package/src/components/NumberInput/NumberInput.stories.tsx +35 -35
  344. package/src/components/NumberInput/NumberInput.tsx +133 -133
  345. package/src/components/NumberInput/helpers.ts +86 -86
  346. package/src/components/NumberInput/index.ts +1 -1
  347. package/src/components/PhoneInput/PhoneInput.stories.tsx +70 -70
  348. package/src/components/PhoneInput/PhoneInput.styles.ts +89 -84
  349. package/src/components/PhoneInput/PhoneInput.tsx +210 -193
  350. package/src/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.stories.tsx +21 -21
  351. package/src/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.styles.ts +103 -100
  352. package/src/components/PhoneInput/components/PhoneInputCountryList/PhoneInputCountryList.tsx +155 -145
  353. package/src/components/PhoneInput/components/PhoneInputCountryList/index.ts +2 -2
  354. package/src/components/PhoneInput/components/index.ts +1 -1
  355. package/src/components/PhoneInput/constants.ts +3 -3
  356. package/src/components/PhoneInput/index.ts +5 -5
  357. package/src/components/PhoneInput/phone-info.ts +2147 -2147
  358. package/src/components/PhoneInput/types.ts +16 -16
  359. package/src/components/RadioButton/RadioButton.stories.tsx +46 -46
  360. package/src/components/RadioButton/RadioButton.styles.ts +37 -37
  361. package/src/components/RadioButton/RadioButton.tsx +55 -55
  362. package/src/components/RadioButton/index.ts +2 -2
  363. package/src/components/ScrollIntoViewIfNeeded/ScrollIntoViewIfNeeded.ts +54 -54
  364. package/src/components/ScrollIntoViewIfNeeded/constants.ts +12 -12
  365. package/src/components/ScrollIntoViewIfNeeded/index.ts +1 -1
  366. package/src/components/SearchInput/SearchInput.stories.tsx +23 -23
  367. package/src/components/SearchInput/SearchInput.styles.ts +50 -50
  368. package/src/components/SearchInput/SearchInput.tsx +56 -51
  369. package/src/components/SearchInput/index.ts +2 -2
  370. package/src/components/Select/MultiSelect.stories.tsx +240 -240
  371. package/src/components/Select/Select.stories.tsx +235 -235
  372. package/src/components/Select/Select.styles.ts +146 -96
  373. package/src/components/Select/Select.tsx +574 -574
  374. package/src/components/Select/components/SelectList/SelectList.styles.ts +71 -72
  375. package/src/components/Select/components/SelectList/SelectList.tsx +157 -158
  376. package/src/components/Select/components/SelectList/index.ts +2 -2
  377. package/src/components/Select/components/SelectListItem/SelectListItem.styles.ts +14 -14
  378. package/src/components/Select/components/SelectListItem/SelectListItem.tsx +68 -68
  379. package/src/components/Select/components/SelectListItem/index.ts +1 -1
  380. package/src/components/Select/components/index.ts +2 -2
  381. package/src/components/Select/constants.ts +2 -2
  382. package/src/components/Select/helpers.ts +27 -26
  383. package/src/components/Select/index.ts +4 -4
  384. package/src/components/Select/types.ts +1 -1
  385. package/src/components/SmartInput/SmartInput.stories.tsx +51 -51
  386. package/src/components/SmartInput/SmartInput.tsx +124 -124
  387. package/src/components/SmartInput/constants.ts +84 -84
  388. package/src/components/SmartInput/helpers.ts +13 -13
  389. package/src/components/SmartInput/index.ts +2 -2
  390. package/src/components/SmartInput/types.ts +11 -11
  391. package/src/components/Switch/Switch.stories.tsx +40 -40
  392. package/src/components/Switch/Switch.styles.ts +75 -75
  393. package/src/components/Switch/Switch.tsx +76 -79
  394. package/src/components/Switch/index.ts +3 -3
  395. package/src/components/Switch/types.ts +4 -4
  396. package/src/components/TextArea/TextArea.stories.tsx +35 -35
  397. package/src/components/TextArea/TextArea.styles.ts +153 -153
  398. package/src/components/TextArea/TextArea.tsx +171 -174
  399. package/src/components/TextArea/index.ts +2 -2
  400. package/src/components/TextWithInfo/TextWithInfo.stories.tsx +53 -53
  401. package/src/components/TextWithInfo/TextWithInfo.styles.ts +59 -60
  402. package/src/components/TextWithInfo/TextWithInfo.tsx +61 -60
  403. package/src/components/TextWithInfo/index.ts +2 -2
  404. package/src/components/TextWithTooltip/TextWithTooltip.stories.tsx +58 -58
  405. package/src/components/TextWithTooltip/TextWithTooltip.styles.ts +21 -19
  406. package/src/components/TextWithTooltip/TextWithTooltip.tsx +149 -143
  407. package/src/components/TextWithTooltip/index.ts +2 -2
  408. package/src/components/ThemedPreloader/ThemedPreloader.stories.tsx +41 -41
  409. package/src/components/ThemedPreloader/ThemedPreloader.styles.ts +26 -21
  410. package/src/components/ThemedPreloader/ThemedPreloader.tsx +55 -47
  411. package/src/components/ThemedPreloader/components/DefaultPreloader/DefaultPreloader.tsx +29 -29
  412. package/src/components/ThemedPreloader/components/DefaultPreloader/index.ts +1 -1
  413. package/src/components/ThemedPreloader/components/DotsPreloader/DotsPreloader.styles.ts +54 -54
  414. package/src/components/ThemedPreloader/components/DotsPreloader/DotsPreloader.tsx +15 -18
  415. package/src/components/ThemedPreloader/components/DotsPreloader/index.ts +2 -2
  416. package/src/components/ThemedPreloader/components/SvgPreloader/SvgPreloader.styles.ts +11 -11
  417. package/src/components/ThemedPreloader/components/SvgPreloader/SvgPreloader.tsx +24 -25
  418. package/src/components/ThemedPreloader/components/SvgPreloader/index.ts +2 -2
  419. package/src/components/ThemedPreloader/components/index.ts +3 -3
  420. package/src/components/ThemedPreloader/constants.ts +1 -1
  421. package/src/components/ThemedPreloader/index.ts +4 -4
  422. package/src/components/ThemedPreloader/types.ts +3 -3
  423. package/src/components/Toaster/Toaster.stories.tsx +30 -30
  424. package/src/components/Toaster/Toaster.styles.ts +60 -59
  425. package/src/components/Toaster/Toaster.tsx +114 -108
  426. package/src/components/Toaster/constants.ts +1 -1
  427. package/src/components/Toaster/index.ts +3 -3
  428. package/src/components/Toaster/types.ts +1 -1
  429. package/src/components/Tooltip/Tooltip.stories.tsx +19 -19
  430. package/src/components/Tooltip/Tooltip.styles.ts +49 -45
  431. package/src/components/Tooltip/Tooltip.tsx +39 -35
  432. package/src/components/Tooltip/index.ts +3 -3
  433. package/src/components/Tooltip/types.ts +1 -1
  434. package/src/components/index.ts +36 -37
  435. package/src/helpers/index.ts +3 -5
  436. package/src/helpers/misc.ts +158 -158
  437. package/src/helpers/phone.ts +90 -87
  438. package/src/helpers/popper-helpers.ts +17 -17
  439. package/src/helpers/snippets.tsx +6 -6
  440. package/src/hooks/index.ts +5 -6
  441. package/src/hooks/use-did-mount-effect.ts +18 -18
  442. package/src/hooks/use-dropdown.ts +82 -82
  443. package/src/hooks/use-is-mounted.ts +15 -15
  444. package/src/hooks/use-on-click-outside.ts +77 -77
  445. package/src/hooks/use-tweak-styles.ts +57 -13
  446. package/src/index.ts +6 -6
  447. package/src/theme/Provider.tsx +21 -0
  448. package/src/{theme.ts → theme/common.ts} +149 -149
  449. package/src/theme/helpers.ts +74 -0
  450. package/src/theme/index.ts +4 -0
  451. package/src/theme/types.ts +137 -0
  452. package/src/types.ts +30 -109
  453. package/src/vite-env.d.ts +1 -1
  454. package/dist/components/FlexibleTable/components/TableRow/TableRow.d.ts +0 -28
  455. package/dist/components/FlexibleTable/components/TableRow/index.d.ts +0 -1
  456. package/dist/components/FlexibleTable/components/TableValue/TableValue.d.ts +0 -21
  457. package/dist/components/FlexibleTable/components/TableValue/index.d.ts +0 -1
  458. package/dist/components/IncrementInput/components/ChangeButton/ChangeButton.d.ts +0 -10
  459. package/dist/components/IncrementInput/components/ChangeButton/index.d.ts +0 -1
  460. package/dist/components/IncrementInput/components/index.d.ts +0 -1
  461. package/dist/components/ListItem/ListItem.d.ts +0 -6
  462. package/dist/components/ListItem/ListItem.styles.d.ts +0 -35
  463. package/dist/components/ListItem/constants.d.ts +0 -1
  464. package/dist/components/ListItem/index.d.ts +0 -3
  465. package/dist/helpers/deprecated.d.ts +0 -12
  466. package/dist/hooks/use-theme.d.ts +0 -9
  467. package/src/components/FlexibleTable/components/TableRow/index.ts +0 -1
  468. package/src/components/FlexibleTable/components/TableValue/index.ts +0 -1
  469. package/src/components/IncrementInput/components/ChangeButton/ChangeButton.tsx +0 -33
  470. package/src/components/IncrementInput/components/ChangeButton/index.ts +0 -1
  471. package/src/components/IncrementInput/components/index.ts +0 -1
  472. package/src/components/ListItem/ListItem.stories.tsx +0 -67
  473. package/src/components/ListItem/ListItem.styles.ts +0 -48
  474. package/src/components/ListItem/ListItem.tsx +0 -44
  475. package/src/components/ListItem/constants.ts +0 -5
  476. package/src/components/ListItem/index.ts +0 -3
  477. package/src/helpers/deprecated.ts +0 -23
  478. package/src/hooks/use-theme.ts +0 -32
@@ -1,574 +1,574 @@
1
- import {
2
- ReactNode,
3
- FocusEvent,
4
- KeyboardEvent,
5
- MouseEvent,
6
- useCallback,
7
- useEffect,
8
- useMemo,
9
- useRef,
10
- useState,
11
- SyntheticEvent,
12
- } from 'react';
13
- import { Portal } from 'react-overlays';
14
- import clsx from 'clsx';
15
- import { Styles } from 'jss';
16
- import merge from 'lodash-es/merge';
17
- import { debounce } from 'ts-debounce';
18
- import {
19
- getTestId,
20
- isNotEmpty,
21
- isStringNotEmpty,
22
- createFilter,
23
- } from '@true-engineering/true-react-platform-helpers';
24
- import { hasExactParent, renderIcon } from '../../helpers';
25
- import {
26
- useIsMounted,
27
- useTheme,
28
- useOnClickOutsideWithRef,
29
- useDropdown,
30
- useTweakStyles,
31
- } from '../../hooks';
32
- import { IDropdownWithPopperOptions, IIcon } from '../../types';
33
- import { IInputProps, Input } from '../Input';
34
- import { ISearchInputProps, SearchInput } from '../SearchInput';
35
- import { SelectList } from './components';
36
- import { ALL_OPTION_INDEX, DEFAULT_OPTION_INDEX } from './constants';
37
- import {
38
- defaultConvertFunction,
39
- defaultCompareFunction,
40
- defaultIsOptionDisabled,
41
- getDefaultConvertToIdFunction,
42
- isMultiSelectValue,
43
- } from './helpers';
44
- import { IMultipleSelectValue } from './types';
45
- import { SelectStyles, styles } from './Select.styles';
46
-
47
- export interface ISelectProps<Value>
48
- extends Omit<IInputProps, 'value' | 'onChange' | 'onBlur' | 'type'> {
49
- tweakStyles?: SelectStyles;
50
- defaultOptionLabel?: string;
51
- allOptionsLabel?: string;
52
- noMatchesLabel?: string;
53
- loadingLabel?: ReactNode;
54
- optionsMode?: 'search' | 'dynamic' | 'normal';
55
- debounceTime?: number;
56
- minSymbolsCountToOpenList?: number;
57
- dropdownOptions?: IDropdownWithPopperOptions;
58
- dropdownIcon?: IIcon;
59
- options: Value[];
60
- value: Value | undefined;
61
- shouldScrollToList?: boolean;
62
- isMultiSelect?: boolean;
63
- searchInput?: { shouldRenderInList: true } & Pick<ISearchInputProps, 'placeholder'>;
64
- isOptionDisabled?(option: Value): boolean;
65
- onChange(value?: Value): void; // подумать как возвращать индекс
66
- onBlur?(event: Event | SyntheticEvent): void;
67
- onType?(value: string): Promise<void>;
68
- optionsFilter?(options: Value[], query: string): Value[];
69
- onOpen?(): void;
70
- compareValuesOnChange?(v1?: Value, v2?: Value): boolean;
71
- // Для избежания проблем юзайте useCallback на эти функции
72
- // или выносите их из компонента (чтобы не было сайдэфектов от перерендеринга их)
73
- convertValueToString?(value: Value): string | undefined;
74
- convertValueToReactNode?(value: Value, isDisabled: boolean): ReactNode;
75
- convertValueToId?(value: Value): string | undefined;
76
- }
77
-
78
- export interface IMultipleSelectProps<Value>
79
- extends Omit<ISelectProps<Value>, 'value' | 'onChange' | 'compareValuesOnChange'> {
80
- isMultiSelect: true;
81
- value: IMultipleSelectValue<Value> | undefined;
82
- onChange(value?: IMultipleSelectValue<Value>): void;
83
- compareValuesOnChange?(
84
- v1?: IMultipleSelectValue<Value>,
85
- v2?: IMultipleSelectValue<Value>,
86
- ): boolean;
87
- }
88
-
89
- export function Select<Value>(
90
- props: ISelectProps<Value> | IMultipleSelectProps<Value>,
91
- ): JSX.Element {
92
- const {
93
- options,
94
- value,
95
- defaultOptionLabel,
96
- allOptionsLabel,
97
- debounceTime = 400,
98
- optionsMode = 'normal',
99
- noMatchesLabel,
100
- loadingLabel,
101
- tweakStyles,
102
- testId,
103
- isReadonly,
104
- isDisabled,
105
- dropdownOptions,
106
- minSymbolsCountToOpenList = 0,
107
- dropdownIcon = 'chevron-down',
108
- shouldScrollToList = true,
109
- searchInput,
110
- iconType,
111
- onChange,
112
- onFocus,
113
- onBlur,
114
- onType,
115
- onOpen,
116
- isOptionDisabled = defaultIsOptionDisabled,
117
- compareValuesOnChange = defaultCompareFunction,
118
- convertValueToString = defaultConvertFunction,
119
- convertValueToId,
120
- convertValueToReactNode,
121
- optionsFilter,
122
- ...inputProps
123
- } = props;
124
- const { classes, componentStyles } = useTheme('Select', styles, tweakStyles);
125
- const isMounted = useIsMounted();
126
- const [isListOpen, setIsListOpen] = useState(false);
127
- const [areOptionsLoading, setAreOptionsLoading] = useState(false);
128
- const hasDefaultOption = isStringNotEmpty(defaultOptionLabel);
129
-
130
- const [focusedListCellIndex, setFocusedListCellIndex] = useState(DEFAULT_OPTION_INDEX);
131
- const [searchValue, setSearchValue] = useState('');
132
- // если мы ввели что то в строку поиска - то этот булеан будет отключаться
133
- // вынесен отдельно, из-за проблем с дебаунсом при динамич. опциях
134
- const [shouldShowDefaultOption, setShouldShowDefaultOption] = useState(true);
135
-
136
- const inputWrapper = useRef<HTMLDivElement>(null);
137
- const list = useRef<HTMLDivElement>(null);
138
- const input = useRef<HTMLInputElement>(null); // TODO ref снаружи?
139
-
140
- const shouldRenderSearchInputInList = searchInput?.shouldRenderInList === true;
141
- const hasSearchInputInList = optionsMode !== 'normal' && shouldRenderSearchInputInList;
142
-
143
- const isMultiSelect = isMultiSelectValue(props, value);
144
- const strValue = isMultiSelect ? value?.[0] : value;
145
- const shouldShowAllOption =
146
- isMultiSelect && isStringNotEmpty(allOptionsLabel) && searchValue === '';
147
-
148
- const filteredOptions = useMemo(() => {
149
- if (optionsMode !== 'search') {
150
- return options;
151
- }
152
-
153
- const filter =
154
- optionsFilter ?? createFilter<Value>((option) => [convertValueToString(option) ?? '']);
155
-
156
- return filter(options, searchValue);
157
- }, [optionsFilter, options, convertValueToString, searchValue, optionsMode]);
158
-
159
- const availableOptions = useMemo(
160
- () => options.filter((o) => !isOptionDisabled(o)),
161
- [options, isOptionDisabled],
162
- );
163
-
164
- const areAllOptionsSelected = isMultiSelect && value?.length === availableOptions.length;
165
- const shouldShowMultiSelectCounter =
166
- isMultiSelect && isNotEmpty(value) && value.length > 1 && !areAllOptionsSelected;
167
-
168
- const optionsIndexesForNavigation = useMemo(() => {
169
- const result: number[] = [];
170
- if (shouldShowDefaultOption && hasDefaultOption) {
171
- result.push(DEFAULT_OPTION_INDEX);
172
- }
173
- if (shouldShowAllOption) {
174
- result.push(ALL_OPTION_INDEX);
175
- }
176
- return result.concat(
177
- filteredOptions.reduce((acc, cur, i) => {
178
- if (!isOptionDisabled(cur)) {
179
- acc.push(i);
180
- }
181
- return acc;
182
- }, [] as number[]),
183
- );
184
- }, [filteredOptions]);
185
-
186
- const stringValue = isNotEmpty(strValue) ? convertValueToString(strValue) : undefined;
187
- // Для мультиселекта пытаемся показать "Все опции" если выбраны все опции
188
- const showedStringValue =
189
- areAllOptionsSelected && isNotEmpty(allOptionsLabel) ? allOptionsLabel : stringValue;
190
-
191
- const convertToId = useCallback(
192
- (v: Value) => (convertValueToId ?? getDefaultConvertToIdFunction(convertValueToString))(v),
193
- [convertValueToId, convertValueToString],
194
- );
195
-
196
- const handleListClose = useCallback(
197
- (event: Event | SyntheticEvent) => {
198
- setIsListOpen(false);
199
- setSearchValue('');
200
- setShouldShowDefaultOption(true);
201
- onBlur?.(event);
202
- },
203
- [onBlur],
204
- );
205
-
206
- const handleListOpen = () => {
207
- if (!isListOpen) {
208
- setIsListOpen(true);
209
- }
210
- };
211
-
212
- const handleFocus = (event: FocusEvent<HTMLInputElement>) => {
213
- onFocus?.(event);
214
- handleListOpen();
215
- };
216
-
217
- const handleOnClick = () => {
218
- handleListOpen();
219
- };
220
-
221
- const handleBlur = (event: FocusEvent<HTMLInputElement>) => {
222
- // Когда что-то блокирует открытие листа, но блур все равно должен сработать
223
- // например minSymbolsCount
224
- if (isListOpen && !isOpen) {
225
- handleListClose(event);
226
- return;
227
- }
228
-
229
- if (
230
- !isNotEmpty(event.relatedTarget) ||
231
- !isNotEmpty(list.current) ||
232
- !isNotEmpty(inputWrapper.current)
233
- ) {
234
- return;
235
- }
236
-
237
- const isActionInsideSelect =
238
- hasExactParent(event.relatedTarget, list.current) ||
239
- hasExactParent(event.relatedTarget, inputWrapper.current);
240
-
241
- // Ниче не делаем если клик был внутри селекта
242
- if (!isActionInsideSelect) {
243
- handleListClose(event);
244
- }
245
- };
246
-
247
- const handleOnChange = useCallback(
248
- (newValue: Value | IMultipleSelectValue<Value> | undefined) => {
249
- // Тут беда с типами, сорри
250
- if (!compareValuesOnChange(value as never, newValue as never)) {
251
- onChange(newValue as (Value & IMultipleSelectValue<Value>) | undefined);
252
- }
253
- },
254
- [value, compareValuesOnChange, onChange],
255
- );
256
-
257
- const handleOptionSelect = useCallback(
258
- (index: number, event: MouseEvent<HTMLElement> | KeyboardEvent) => {
259
- handleOnChange(index === DEFAULT_OPTION_INDEX ? undefined : filteredOptions[index]);
260
- handleListClose(event);
261
- input.current?.blur();
262
- },
263
- [handleOnChange, handleListClose, filteredOptions],
264
- );
265
-
266
- // MultiSelect
267
- const handleToggleOptionCheckbox = useCallback(
268
- (index: number, isSelected: boolean) => {
269
- if (!isMultiSelect) {
270
- return;
271
- }
272
-
273
- // Если выбрана не дефолтная опция, которая сетит андеф
274
- if (index === DEFAULT_OPTION_INDEX || (index === ALL_OPTION_INDEX && !isSelected)) {
275
- handleOnChange(undefined);
276
- return;
277
- }
278
- if (index === ALL_OPTION_INDEX && isSelected) {
279
- handleOnChange(availableOptions as IMultipleSelectValue<Value>);
280
- return;
281
- }
282
- const option = filteredOptions[index];
283
- handleOnChange(
284
- isSelected
285
- ? // Добавляем
286
- ([...(value ?? []), option] as IMultipleSelectValue<Value>)
287
- : // Убираем
288
- value?.filter((o) => convertToId(o) !== convertToId(option)),
289
- );
290
- },
291
- [handleOnChange, filteredOptions, isMultiSelect, value],
292
- );
293
-
294
- const handleOnType = useCallback(
295
- async (v: string) => {
296
- if (onType === undefined) {
297
- return;
298
- }
299
- if (isMounted()) {
300
- setAreOptionsLoading(true);
301
- }
302
- await onType(v);
303
- if (isMounted()) {
304
- setAreOptionsLoading(false);
305
- }
306
- if (optionsMode === 'dynamic') {
307
- setShouldShowDefaultOption(v === '');
308
- }
309
- },
310
- [onType, optionsMode],
311
- );
312
-
313
- const debounceHandleOnType = useCallback(debounce(handleOnType, debounceTime), [
314
- handleOnType,
315
- debounceTime,
316
- ]);
317
-
318
- const handleInputChange = (v: string) => {
319
- if (onType !== undefined) {
320
- debounceHandleOnType(v);
321
- }
322
-
323
- if (optionsMode !== 'dynamic') {
324
- setShouldShowDefaultOption(v === '');
325
- }
326
-
327
- if (v === '' && !hasSearchInputInList) {
328
- handleOnChange(undefined);
329
- }
330
-
331
- setSearchValue(v);
332
- };
333
-
334
- const handleKeyDown = (event: KeyboardEvent) => {
335
- if (!isListOpen) {
336
- return;
337
- }
338
-
339
- event.stopPropagation();
340
- const curIndexInNavigation = optionsIndexesForNavigation.findIndex(
341
- (index) => index === focusedListCellIndex,
342
- );
343
-
344
- switch (event.code) {
345
- case 'Enter':
346
- case 'NumpadEnter': {
347
- let indexToSelect = focusedListCellIndex;
348
-
349
- // если осталась одна опция в списке,
350
- // то выбираем ее нажатием на enter
351
- if (indexToSelect === DEFAULT_OPTION_INDEX && filteredOptions.length === 1) {
352
- indexToSelect = 0;
353
- }
354
-
355
- if (isMultiSelect) {
356
- let isThisValueAlreadySelected: boolean;
357
- if (indexToSelect === ALL_OPTION_INDEX) {
358
- isThisValueAlreadySelected = areAllOptionsSelected;
359
- } else {
360
- // подумать над концептом реального фокуса на опциях, а не вот эти вот focusedCell
361
- const valueIdToSelect = convertToId(filteredOptions[indexToSelect]);
362
- isThisValueAlreadySelected =
363
- value?.some((opt) => convertToId(opt) === valueIdToSelect) ?? false;
364
- }
365
- handleToggleOptionCheckbox(indexToSelect, !isThisValueAlreadySelected);
366
- } else {
367
- handleOptionSelect(indexToSelect, event);
368
- }
369
- break;
370
- }
371
-
372
- case 'ArrowDown': {
373
- // чтобы убрать перемещение курсора в инпуте
374
- event.preventDefault();
375
- const targetIndexInNavigation =
376
- (curIndexInNavigation + 1) % optionsIndexesForNavigation.length;
377
- setFocusedListCellIndex(optionsIndexesForNavigation[targetIndexInNavigation]);
378
- break;
379
- }
380
-
381
- case 'ArrowUp': {
382
- // чтобы убрать перемещение курсора в инпуте
383
- event.preventDefault();
384
- const targetIndexInNavigation =
385
- (curIndexInNavigation - 1 + optionsIndexesForNavigation.length) %
386
- optionsIndexesForNavigation.length;
387
- setFocusedListCellIndex(optionsIndexesForNavigation[targetIndexInNavigation]);
388
- break;
389
- }
390
- }
391
- };
392
-
393
- const onArrowClick = () => {
394
- if (isListOpen) {
395
- input.current?.blur();
396
- } else {
397
- input.current?.focus();
398
- }
399
- };
400
-
401
- useOnClickOutsideWithRef(list, handleListClose, inputWrapper);
402
-
403
- const hasEnoughSymbolsToSearch = searchValue.trim().length >= minSymbolsCountToOpenList;
404
-
405
- const isOpen =
406
- // Пользователь пытается открыть лист
407
- isListOpen &&
408
- // Нам есть что показать:
409
- // Есть опции
410
- (filteredOptions.length > 0 ||
411
- // Дефолтная опция
412
- (defaultOptionLabel !== undefined && !hasEnoughSymbolsToSearch) ||
413
- // Текст "Загрузка..."
414
- inputProps.isLoading ||
415
- // Текст "Совпадений не найдено"
416
- noMatchesLabel !== undefined ||
417
- // У нас есть инпут с поиском внутри листа
418
- hasSearchInputInList) &&
419
- // Последняя проверка на случай, если мы че то ищем в опциях
420
- (optionsMode === 'normal' || hasEnoughSymbolsToSearch);
421
-
422
- const hasReadonlyInput = isReadonly || optionsMode === 'normal' || shouldRenderSearchInputInList;
423
-
424
- const tweakInputStyles = useMemo(
425
- () =>
426
- merge(
427
- {},
428
- componentStyles.tweakInput,
429
- { ...(hasReadonlyInput && { input: { cursor: 'pointer' } }) },
430
- { ...(isMultiSelect && { inputIcon: { width: 'auto' } }) },
431
- tweakStyles?.tweakInput,
432
- ) as Styles,
433
- [tweakStyles?.tweakInput, hasReadonlyInput],
434
- );
435
-
436
- const tweakSearchInputStyles = useTweakStyles(componentStyles, tweakStyles, 'tweakSearchInput');
437
-
438
- // Эти значения ставятся в false по дефолту также в useDropdown
439
- const {
440
- shouldUsePopper = false,
441
- shouldRenderInBody = false,
442
- shouldHideOnScroll = false,
443
- } = dropdownOptions ?? {};
444
-
445
- const popperData = useDropdown({
446
- isOpen,
447
- onDropdownClose: handleListClose,
448
- referenceElement: inputWrapper.current,
449
- dropdownElement: list.current,
450
- options: dropdownOptions,
451
- dependenciesForPositionUpdating: [inputProps.isLoading, filteredOptions.length],
452
- });
453
-
454
- useEffect(() => {
455
- setFocusedListCellIndex(
456
- optionsIndexesForNavigation.find(
457
- (index) =>
458
- isNotEmpty(strValue) &&
459
- isNotEmpty(filteredOptions[index]) &&
460
- convertToId(filteredOptions[index]) === convertToId(strValue),
461
- ) ?? optionsIndexesForNavigation[0],
462
- );
463
- }, [strValue, filteredOptions, optionsIndexesForNavigation, convertToId]);
464
-
465
- useEffect(() => {
466
- if (isOpen) {
467
- onOpen?.();
468
- }
469
- }, [isOpen]);
470
-
471
- const listEl = (
472
- <div
473
- className={clsx(classes.listWrapper, {
474
- [classes.withoutPopper]: !shouldUsePopper,
475
- [classes.listWrapperInBody]: shouldRenderInBody,
476
- })}
477
- ref={list}
478
- style={popperData?.styles.popper as Styles}
479
- onBlur={handleBlur} // обработка для Tab из списка
480
- {...popperData?.attributes.popper}
481
- >
482
- {isOpen && (
483
- <SelectList
484
- options={filteredOptions}
485
- defaultOptionLabel={
486
- hasDefaultOption && shouldShowDefaultOption ? defaultOptionLabel : undefined
487
- }
488
- allOptionsLabel={shouldShowAllOption ? allOptionsLabel : undefined}
489
- areAllOptionsSelected={areAllOptionsSelected}
490
- customListHeader={
491
- hasSearchInputInList ? (
492
- <SearchInput
493
- value={searchValue}
494
- onChange={handleInputChange}
495
- tweakStyles={tweakSearchInputStyles}
496
- placeholder="Поиск"
497
- {...searchInput}
498
- />
499
- ) : undefined
500
- }
501
- noMatchesLabel={noMatchesLabel}
502
- focusedIndex={focusedListCellIndex}
503
- activeValue={value}
504
- isLoading={inputProps.isLoading}
505
- loadingLabel={loadingLabel}
506
- tweakStyles={tweakStyles?.tweakSelectList as Styles}
507
- testId={getTestId(testId, 'list')}
508
- // скролл не работает с включеным поппером
509
- shouldScrollToList={shouldScrollToList && !shouldUsePopper && !shouldHideOnScroll}
510
- isOptionDisabled={isOptionDisabled}
511
- convertValueToString={convertValueToString}
512
- convertValueToReactNode={convertValueToReactNode}
513
- convertValueToId={convertToId}
514
- onOptionSelect={handleOptionSelect}
515
- onToggleCheckbox={isMultiSelect ? handleToggleOptionCheckbox : undefined}
516
- />
517
- )}
518
- </div>
519
- );
520
-
521
- const multiSelectCounterWithIcon =
522
- shouldShowMultiSelectCounter || isNotEmpty(iconType) ? (
523
- <>
524
- {shouldShowMultiSelectCounter && (
525
- <div className={classes.counter}>(+{value.length - 1})</div>
526
- )}
527
- {isNotEmpty(iconType) && <div className={classes.icon}>{renderIcon(iconType)}</div>}
528
- </>
529
- ) : undefined;
530
-
531
- return (
532
- <div className={classes.root} onKeyDown={handleKeyDown}>
533
- <div
534
- className={clsx(classes.inputWrapper, isDisabled && classes.disabled)}
535
- onClick={isDisabled ? undefined : handleOnClick}
536
- ref={inputWrapper}
537
- >
538
- <Input
539
- value={
540
- searchValue !== '' && !shouldRenderSearchInputInList ? searchValue : showedStringValue
541
- }
542
- onChange={handleInputChange}
543
- isActive={isListOpen}
544
- isReadonly={hasReadonlyInput}
545
- onFocus={handleFocus}
546
- onBlur={handleBlur}
547
- isDisabled={isDisabled}
548
- ref={input}
549
- isLoading={areOptionsLoading}
550
- tweakStyles={tweakInputStyles}
551
- testId={testId}
552
- iconType={isMultiSelect ? multiSelectCounterWithIcon : iconType}
553
- {...inputProps}
554
- />
555
- <div
556
- onMouseDown={(event: MouseEvent) => {
557
- event.preventDefault();
558
- }}
559
- onClick={onArrowClick}
560
- className={clsx(classes.arrow, isOpen && classes.activeArrow)}
561
- >
562
- {renderIcon(dropdownIcon)}
563
- </div>
564
- </div>
565
- {shouldUsePopper ? (
566
- <Portal container={shouldRenderInBody ? document.body : inputWrapper.current}>
567
- <>{listEl}</>
568
- </Portal>
569
- ) : (
570
- <>{isOpen && listEl}</>
571
- )}
572
- </div>
573
- );
574
- }
1
+ import {
2
+ ReactNode,
3
+ FocusEvent,
4
+ KeyboardEvent,
5
+ MouseEvent,
6
+ useCallback,
7
+ useEffect,
8
+ useMemo,
9
+ useRef,
10
+ useState,
11
+ SyntheticEvent,
12
+ } from 'react';
13
+ import { Portal } from 'react-overlays';
14
+ import clsx from 'clsx';
15
+ import { Styles } from 'jss';
16
+ import { debounce } from 'ts-debounce';
17
+ import {
18
+ getTestId,
19
+ isNotEmpty,
20
+ isStringNotEmpty,
21
+ createFilter,
22
+ } from '@true-engineering/true-react-platform-helpers';
23
+ import { hasExactParent } from '../../helpers';
24
+ import { renderIcon } from '../../helpers/snippets';
25
+ import { useIsMounted, useOnClickOutsideWithRef, useDropdown, useTweakStyles } from '../../hooks';
26
+ import { ICommonProps, IDropdownWithPopperOptions, IIcon } from '../../types';
27
+ import { IInputProps, Input } from '../Input';
28
+ import { ISearchInputProps, SearchInput } from '../SearchInput';
29
+ import { SelectList } from './components';
30
+ import { ALL_OPTION_INDEX, DEFAULT_OPTION_INDEX } from './constants';
31
+ import {
32
+ defaultConvertFunction,
33
+ defaultCompareFunction,
34
+ defaultIsOptionDisabled,
35
+ getDefaultConvertToIdFunction,
36
+ isMultiSelectValue,
37
+ } from './helpers';
38
+ import { IMultipleSelectValue } from './types';
39
+ import { useStyles, ISelectStyles, searchInputStyles, getInputStyles } from './Select.styles';
40
+
41
+ export interface ISelectProps<Value>
42
+ extends Omit<IInputProps, 'value' | 'onChange' | 'onBlur' | 'type' | 'tweakStyles'>,
43
+ ICommonProps<ISelectStyles> {
44
+ defaultOptionLabel?: string;
45
+ allOptionsLabel?: string;
46
+ noMatchesLabel?: string;
47
+ loadingLabel?: ReactNode;
48
+ optionsMode?: 'search' | 'dynamic' | 'normal';
49
+ debounceTime?: number;
50
+ minSymbolsCountToOpenList?: number;
51
+ dropdownOptions?: IDropdownWithPopperOptions;
52
+ dropdownIcon?: IIcon;
53
+ options: Value[];
54
+ value: Value | undefined;
55
+ shouldScrollToList?: boolean;
56
+ isMultiSelect?: boolean;
57
+ searchInput?: { shouldRenderInList: true } & Pick<ISearchInputProps, 'placeholder'>;
58
+ isOptionDisabled?(option: Value): boolean;
59
+ onChange(value?: Value): void; // подумать как возвращать индекс
60
+ onBlur?(event: Event | SyntheticEvent): void;
61
+ onType?(value: string): Promise<void>;
62
+ optionsFilter?(options: Value[], query: string): Value[];
63
+ onOpen?(): void;
64
+ compareValuesOnChange?(v1?: Value, v2?: Value): boolean;
65
+ // Для избежания проблем юзайте useCallback на эти функции
66
+ // или выносите их из компонента (чтобы не было сайдэфектов от перерендеринга их)
67
+ convertValueToString?(value: Value): string | undefined;
68
+ convertValueToReactNode?(value: Value, isDisabled: boolean): ReactNode;
69
+ convertValueToId?(value: Value): string | undefined;
70
+ }
71
+
72
+ export interface IMultipleSelectProps<Value>
73
+ extends Omit<ISelectProps<Value>, 'value' | 'onChange' | 'compareValuesOnChange'> {
74
+ isMultiSelect: true;
75
+ value: IMultipleSelectValue<Value> | undefined;
76
+ onChange(value?: IMultipleSelectValue<Value>): void;
77
+ compareValuesOnChange?(
78
+ v1?: IMultipleSelectValue<Value>,
79
+ v2?: IMultipleSelectValue<Value>,
80
+ ): boolean;
81
+ }
82
+
83
+ export function Select<Value>(
84
+ props: ISelectProps<Value> | IMultipleSelectProps<Value>,
85
+ ): JSX.Element {
86
+ const {
87
+ options,
88
+ value,
89
+ defaultOptionLabel,
90
+ allOptionsLabel,
91
+ debounceTime = 400,
92
+ optionsMode = 'normal',
93
+ noMatchesLabel,
94
+ loadingLabel,
95
+ tweakStyles,
96
+ testId,
97
+ isReadonly,
98
+ isDisabled,
99
+ dropdownOptions,
100
+ minSymbolsCountToOpenList = 0,
101
+ dropdownIcon = 'chevron-down',
102
+ shouldScrollToList = true,
103
+ searchInput,
104
+ iconType,
105
+ onChange,
106
+ onFocus,
107
+ onBlur,
108
+ onType,
109
+ onOpen,
110
+ isOptionDisabled = defaultIsOptionDisabled,
111
+ compareValuesOnChange = defaultCompareFunction,
112
+ convertValueToString = defaultConvertFunction,
113
+ convertValueToId,
114
+ convertValueToReactNode,
115
+ optionsFilter,
116
+ ...inputProps
117
+ } = props;
118
+ const classes = useStyles({ theme: tweakStyles });
119
+
120
+ const shouldRenderSearchInputInList = searchInput?.shouldRenderInList === true;
121
+ const hasSearchInputInList = optionsMode !== 'normal' && shouldRenderSearchInputInList;
122
+ const isMultiSelect = isMultiSelectValue(props, value);
123
+ const hasReadonlyInput = isReadonly || optionsMode === 'normal' || shouldRenderSearchInputInList;
124
+
125
+ const tweakInputStyles = useTweakStyles({
126
+ innerStyles: getInputStyles({ hasReadonlyInput, isMultiSelect }),
127
+ tweakStyles,
128
+ className: 'tweakInput',
129
+ currentComponentName: 'Select',
130
+ });
131
+
132
+ const tweakSearchInputStyles = useTweakStyles({
133
+ innerStyles: searchInputStyles,
134
+ tweakStyles,
135
+ className: 'tweakSearchInput',
136
+ currentComponentName: 'Select',
137
+ });
138
+
139
+ const tweakSelectListStyles = useTweakStyles({
140
+ tweakStyles,
141
+ className: 'tweakSelectList',
142
+ currentComponentName: 'Select',
143
+ });
144
+
145
+ const isMounted = useIsMounted();
146
+ const [isListOpen, setIsListOpen] = useState(false);
147
+ const [areOptionsLoading, setAreOptionsLoading] = useState(false);
148
+ const hasDefaultOption = isStringNotEmpty(defaultOptionLabel);
149
+
150
+ const [focusedListCellIndex, setFocusedListCellIndex] = useState(DEFAULT_OPTION_INDEX);
151
+ const [searchValue, setSearchValue] = useState('');
152
+ // если мы ввели что то в строку поиска - то этот булеан будет отключаться
153
+ // вынесен отдельно, из-за проблем с дебаунсом при динамич. опциях
154
+ const [shouldShowDefaultOption, setShouldShowDefaultOption] = useState(true);
155
+
156
+ const inputWrapper = useRef<HTMLDivElement>(null);
157
+ const list = useRef<HTMLDivElement>(null);
158
+ const input = useRef<HTMLInputElement>(null); // TODO ref снаружи?
159
+
160
+ const strValue = isMultiSelect ? value?.[0] : value;
161
+ const shouldShowAllOption =
162
+ isMultiSelect && isStringNotEmpty(allOptionsLabel) && searchValue === '';
163
+
164
+ const filteredOptions = useMemo(() => {
165
+ if (optionsMode !== 'search') {
166
+ return options;
167
+ }
168
+
169
+ const filter =
170
+ optionsFilter ?? createFilter<Value>((option) => [convertValueToString(option) ?? '']);
171
+
172
+ return filter(options, searchValue);
173
+ }, [optionsFilter, options, convertValueToString, searchValue, optionsMode]);
174
+
175
+ const availableOptions = useMemo(
176
+ () => options.filter((o) => !isOptionDisabled(o)),
177
+ [options, isOptionDisabled],
178
+ );
179
+
180
+ const areAllOptionsSelected = isMultiSelect && value?.length === availableOptions.length;
181
+ const shouldShowMultiSelectCounter =
182
+ isMultiSelect && isNotEmpty(value) && value.length > 1 && !areAllOptionsSelected;
183
+
184
+ const optionsIndexesForNavigation = useMemo(() => {
185
+ const result: number[] = [];
186
+ if (shouldShowDefaultOption && hasDefaultOption) {
187
+ result.push(DEFAULT_OPTION_INDEX);
188
+ }
189
+ if (shouldShowAllOption) {
190
+ result.push(ALL_OPTION_INDEX);
191
+ }
192
+ return result.concat(
193
+ filteredOptions.reduce((acc, cur, i) => {
194
+ if (!isOptionDisabled(cur)) {
195
+ acc.push(i);
196
+ }
197
+ return acc;
198
+ }, [] as number[]),
199
+ );
200
+ }, [filteredOptions]);
201
+
202
+ const stringValue = isNotEmpty(strValue) ? convertValueToString(strValue) : undefined;
203
+ // Для мультиселекта пытаемся показать "Все опции" если выбраны все опции
204
+ const showedStringValue =
205
+ areAllOptionsSelected && isNotEmpty(allOptionsLabel) ? allOptionsLabel : stringValue;
206
+
207
+ const convertToId = useCallback(
208
+ (v: Value) => (convertValueToId ?? getDefaultConvertToIdFunction(convertValueToString))(v),
209
+ [convertValueToId, convertValueToString],
210
+ );
211
+
212
+ const handleListClose = useCallback(
213
+ (event: Event | SyntheticEvent) => {
214
+ setIsListOpen(false);
215
+ setSearchValue('');
216
+ setShouldShowDefaultOption(true);
217
+ onBlur?.(event);
218
+ },
219
+ [onBlur],
220
+ );
221
+
222
+ const handleListOpen = () => {
223
+ if (!isListOpen) {
224
+ setIsListOpen(true);
225
+ }
226
+ };
227
+
228
+ const handleFocus = (event: FocusEvent<HTMLInputElement>) => {
229
+ onFocus?.(event);
230
+ handleListOpen();
231
+ };
232
+
233
+ const handleOnClick = () => {
234
+ handleListOpen();
235
+ };
236
+
237
+ const handleBlur = (event: FocusEvent<HTMLInputElement>) => {
238
+ // Когда что-то блокирует открытие листа, но блур все равно должен сработать
239
+ // например minSymbolsCount
240
+ if (isListOpen && !isOpen) {
241
+ handleListClose(event);
242
+ return;
243
+ }
244
+
245
+ if (
246
+ !isNotEmpty(event.relatedTarget) ||
247
+ !isNotEmpty(list.current) ||
248
+ !isNotEmpty(inputWrapper.current)
249
+ ) {
250
+ return;
251
+ }
252
+
253
+ const isActionInsideSelect =
254
+ hasExactParent(event.relatedTarget, list.current) ||
255
+ hasExactParent(event.relatedTarget, inputWrapper.current);
256
+
257
+ // Ниче не делаем если клик был внутри селекта
258
+ if (!isActionInsideSelect) {
259
+ handleListClose(event);
260
+ }
261
+ };
262
+
263
+ const handleOnChange = useCallback(
264
+ (newValue: Value | IMultipleSelectValue<Value> | undefined) => {
265
+ // Тут беда с типами, сорри
266
+ if (!compareValuesOnChange(value as never, newValue as never)) {
267
+ onChange(newValue as (Value & IMultipleSelectValue<Value>) | undefined);
268
+ }
269
+ },
270
+ [value, compareValuesOnChange, onChange],
271
+ );
272
+
273
+ const handleOptionSelect = useCallback(
274
+ (index: number, event: MouseEvent<HTMLElement> | KeyboardEvent) => {
275
+ handleOnChange(index === DEFAULT_OPTION_INDEX ? undefined : filteredOptions[index]);
276
+ handleListClose(event);
277
+ input.current?.blur();
278
+ },
279
+ [handleOnChange, handleListClose, filteredOptions],
280
+ );
281
+
282
+ // MultiSelect
283
+ const handleToggleOptionCheckbox = useCallback(
284
+ (index: number, isSelected: boolean) => {
285
+ if (!isMultiSelect) {
286
+ return;
287
+ }
288
+
289
+ // Если выбрана не дефолтная опция, которая сетит андеф
290
+ if (index === DEFAULT_OPTION_INDEX || (index === ALL_OPTION_INDEX && !isSelected)) {
291
+ handleOnChange(undefined);
292
+ return;
293
+ }
294
+ if (index === ALL_OPTION_INDEX && isSelected) {
295
+ handleOnChange(availableOptions as IMultipleSelectValue<Value>);
296
+ return;
297
+ }
298
+ const option = filteredOptions[index];
299
+ handleOnChange(
300
+ isSelected
301
+ ? // Добавляем
302
+ ([...(value ?? []), option] as IMultipleSelectValue<Value>)
303
+ : // Убираем
304
+ value?.filter((o) => convertToId(o) !== convertToId(option)),
305
+ );
306
+ },
307
+ [handleOnChange, filteredOptions, isMultiSelect, value],
308
+ );
309
+
310
+ const handleOnType = useCallback(
311
+ async (v: string) => {
312
+ if (onType === undefined) {
313
+ return;
314
+ }
315
+ if (isMounted()) {
316
+ setAreOptionsLoading(true);
317
+ }
318
+ await onType(v);
319
+ if (isMounted()) {
320
+ setAreOptionsLoading(false);
321
+ }
322
+ if (optionsMode === 'dynamic') {
323
+ setShouldShowDefaultOption(v === '');
324
+ }
325
+ },
326
+ [onType, optionsMode],
327
+ );
328
+
329
+ const debounceHandleOnType = useCallback(debounce(handleOnType, debounceTime), [
330
+ handleOnType,
331
+ debounceTime,
332
+ ]);
333
+
334
+ const handleInputChange = (v: string) => {
335
+ if (onType !== undefined) {
336
+ debounceHandleOnType(v);
337
+ }
338
+
339
+ if (optionsMode !== 'dynamic') {
340
+ setShouldShowDefaultOption(v === '');
341
+ }
342
+
343
+ if (v === '' && !hasSearchInputInList) {
344
+ handleOnChange(undefined);
345
+ }
346
+
347
+ setSearchValue(v);
348
+ };
349
+
350
+ const handleKeyDown = (event: KeyboardEvent) => {
351
+ if (!isListOpen) {
352
+ return;
353
+ }
354
+
355
+ event.stopPropagation();
356
+ const curIndexInNavigation = optionsIndexesForNavigation.findIndex(
357
+ (index) => index === focusedListCellIndex,
358
+ );
359
+
360
+ switch (event.code) {
361
+ case 'Enter':
362
+ case 'NumpadEnter': {
363
+ let indexToSelect = focusedListCellIndex;
364
+
365
+ // если осталась одна опция в списке,
366
+ // то выбираем ее нажатием на enter
367
+ if (indexToSelect === DEFAULT_OPTION_INDEX && filteredOptions.length === 1) {
368
+ indexToSelect = 0;
369
+ }
370
+
371
+ if (isMultiSelect) {
372
+ let isThisValueAlreadySelected: boolean;
373
+ if (indexToSelect === ALL_OPTION_INDEX) {
374
+ isThisValueAlreadySelected = areAllOptionsSelected;
375
+ } else {
376
+ // подумать над концептом реального фокуса на опциях, а не вот эти вот focusedCell
377
+ const valueIdToSelect = convertToId(filteredOptions[indexToSelect]);
378
+ isThisValueAlreadySelected =
379
+ value?.some((opt) => convertToId(opt) === valueIdToSelect) ?? false;
380
+ }
381
+ handleToggleOptionCheckbox(indexToSelect, !isThisValueAlreadySelected);
382
+ } else {
383
+ handleOptionSelect(indexToSelect, event);
384
+ }
385
+ break;
386
+ }
387
+
388
+ case 'ArrowDown': {
389
+ // чтобы убрать перемещение курсора в инпуте
390
+ event.preventDefault();
391
+ const targetIndexInNavigation =
392
+ (curIndexInNavigation + 1) % optionsIndexesForNavigation.length;
393
+ setFocusedListCellIndex(optionsIndexesForNavigation[targetIndexInNavigation]);
394
+ break;
395
+ }
396
+
397
+ case 'ArrowUp': {
398
+ // чтобы убрать перемещение курсора в инпуте
399
+ event.preventDefault();
400
+ const targetIndexInNavigation =
401
+ (curIndexInNavigation - 1 + optionsIndexesForNavigation.length) %
402
+ optionsIndexesForNavigation.length;
403
+ setFocusedListCellIndex(optionsIndexesForNavigation[targetIndexInNavigation]);
404
+ break;
405
+ }
406
+ }
407
+ };
408
+
409
+ const onArrowClick = () => {
410
+ if (isListOpen) {
411
+ input.current?.blur();
412
+ } else {
413
+ input.current?.focus();
414
+ }
415
+ };
416
+
417
+ useOnClickOutsideWithRef(list, handleListClose, inputWrapper);
418
+
419
+ const hasEnoughSymbolsToSearch = searchValue.trim().length >= minSymbolsCountToOpenList;
420
+
421
+ const isOpen =
422
+ // Пользователь пытается открыть лист
423
+ isListOpen &&
424
+ // Нам есть что показать:
425
+ // Есть опции
426
+ (filteredOptions.length > 0 ||
427
+ // Дефолтная опция
428
+ (defaultOptionLabel !== undefined && !hasEnoughSymbolsToSearch) ||
429
+ // Текст "Загрузка..."
430
+ inputProps.isLoading ||
431
+ // Текст "Совпадений не найдено"
432
+ noMatchesLabel !== undefined ||
433
+ // У нас есть инпут с поиском внутри листа
434
+ hasSearchInputInList) &&
435
+ // Последняя проверка на случай, если мы че то ищем в опциях
436
+ (optionsMode === 'normal' || hasEnoughSymbolsToSearch);
437
+
438
+ // Эти значения ставятся в false по дефолту также в useDropdown
439
+ const {
440
+ shouldUsePopper = false,
441
+ shouldRenderInBody = false,
442
+ shouldHideOnScroll = false,
443
+ } = dropdownOptions ?? {};
444
+
445
+ const popperData = useDropdown({
446
+ isOpen,
447
+ onDropdownClose: handleListClose,
448
+ referenceElement: inputWrapper.current,
449
+ dropdownElement: list.current,
450
+ options: dropdownOptions,
451
+ dependenciesForPositionUpdating: [inputProps.isLoading, filteredOptions.length],
452
+ });
453
+
454
+ useEffect(() => {
455
+ setFocusedListCellIndex(
456
+ optionsIndexesForNavigation.find(
457
+ (index) =>
458
+ isNotEmpty(strValue) &&
459
+ isNotEmpty(filteredOptions[index]) &&
460
+ convertToId(filteredOptions[index]) === convertToId(strValue),
461
+ ) ?? optionsIndexesForNavigation[0],
462
+ );
463
+ }, [strValue, filteredOptions, optionsIndexesForNavigation, convertToId]);
464
+
465
+ useEffect(() => {
466
+ if (isOpen) {
467
+ onOpen?.();
468
+ }
469
+ }, [isOpen]);
470
+
471
+ const listEl = (
472
+ <div
473
+ className={clsx(classes.listWrapper, {
474
+ [classes.withoutPopper]: !shouldUsePopper,
475
+ [classes.listWrapperInBody]: shouldRenderInBody,
476
+ })}
477
+ ref={list}
478
+ style={popperData?.styles.popper as Styles}
479
+ onBlur={handleBlur} // обработка для Tab из списка
480
+ {...popperData?.attributes.popper}
481
+ >
482
+ {isOpen && (
483
+ <SelectList
484
+ options={filteredOptions}
485
+ defaultOptionLabel={
486
+ hasDefaultOption && shouldShowDefaultOption ? defaultOptionLabel : undefined
487
+ }
488
+ allOptionsLabel={shouldShowAllOption ? allOptionsLabel : undefined}
489
+ areAllOptionsSelected={areAllOptionsSelected}
490
+ customListHeader={
491
+ hasSearchInputInList ? (
492
+ <SearchInput
493
+ value={searchValue}
494
+ onChange={handleInputChange}
495
+ tweakStyles={tweakSearchInputStyles}
496
+ placeholder="Поиск"
497
+ {...searchInput}
498
+ />
499
+ ) : undefined
500
+ }
501
+ noMatchesLabel={noMatchesLabel}
502
+ focusedIndex={focusedListCellIndex}
503
+ activeValue={value}
504
+ isLoading={inputProps.isLoading}
505
+ loadingLabel={loadingLabel}
506
+ tweakStyles={tweakSelectListStyles}
507
+ testId={getTestId(testId, 'list')}
508
+ // скролл не работает с включеным поппером
509
+ shouldScrollToList={shouldScrollToList && !shouldUsePopper && !shouldHideOnScroll}
510
+ isOptionDisabled={isOptionDisabled}
511
+ convertValueToString={convertValueToString}
512
+ convertValueToReactNode={convertValueToReactNode}
513
+ convertValueToId={convertToId}
514
+ onOptionSelect={handleOptionSelect}
515
+ onToggleCheckbox={isMultiSelect ? handleToggleOptionCheckbox : undefined}
516
+ />
517
+ )}
518
+ </div>
519
+ );
520
+
521
+ const multiSelectCounterWithIcon =
522
+ shouldShowMultiSelectCounter || isNotEmpty(iconType) ? (
523
+ <>
524
+ {shouldShowMultiSelectCounter && (
525
+ <div className={classes.counter}>(+{value.length - 1})</div>
526
+ )}
527
+ {isNotEmpty(iconType) && <div className={classes.icon}>{renderIcon(iconType)}</div>}
528
+ </>
529
+ ) : undefined;
530
+
531
+ return (
532
+ <div className={classes.root} onKeyDown={handleKeyDown}>
533
+ <div
534
+ className={clsx(classes.inputWrapper, isDisabled && classes.disabled)}
535
+ onClick={isDisabled ? undefined : handleOnClick}
536
+ ref={inputWrapper}
537
+ >
538
+ <Input
539
+ value={
540
+ searchValue !== '' && !shouldRenderSearchInputInList ? searchValue : showedStringValue
541
+ }
542
+ onChange={handleInputChange}
543
+ isActive={isListOpen}
544
+ isReadonly={hasReadonlyInput}
545
+ onFocus={handleFocus}
546
+ onBlur={handleBlur}
547
+ isDisabled={isDisabled}
548
+ ref={input}
549
+ isLoading={areOptionsLoading}
550
+ tweakStyles={tweakInputStyles}
551
+ testId={testId}
552
+ iconType={isMultiSelect ? multiSelectCounterWithIcon : iconType}
553
+ {...inputProps}
554
+ />
555
+ <div
556
+ onMouseDown={(event: MouseEvent) => {
557
+ event.preventDefault();
558
+ }}
559
+ onClick={onArrowClick}
560
+ className={clsx(classes.arrow, isOpen && classes.activeArrow)}
561
+ >
562
+ {renderIcon(dropdownIcon)}
563
+ </div>
564
+ </div>
565
+ {shouldUsePopper ? (
566
+ <Portal container={shouldRenderInBody ? document.body : inputWrapper.current}>
567
+ <>{listEl}</>
568
+ </Portal>
569
+ ) : (
570
+ <>{isOpen && listEl}</>
571
+ )}
572
+ </div>
573
+ );
574
+ }