@vkontakte/vkui 7.5.4 → 7.6.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 (489) hide show
  1. package/dist/components/Calendar/Calendar.js +6 -6
  2. package/dist/components/Calendar/Calendar.js.map +1 -1
  3. package/dist/components/CalendarDays/CalendarDays.js +3 -3
  4. package/dist/components/CalendarDays/CalendarDays.js.map +1 -1
  5. package/dist/components/CalendarRange/CalendarRange.d.ts.map +1 -1
  6. package/dist/components/CalendarRange/CalendarRange.js +16 -14
  7. package/dist/components/CalendarRange/CalendarRange.js.map +1 -1
  8. package/dist/components/CalendarRange/utils.d.ts.map +1 -1
  9. package/dist/components/CalendarRange/utils.js +6 -5
  10. package/dist/components/CalendarRange/utils.js.map +1 -1
  11. package/dist/components/Cell/Cell.d.ts.map +1 -1
  12. package/dist/components/Cell/Cell.js +6 -3
  13. package/dist/components/Cell/Cell.js.map +1 -1
  14. package/dist/components/CellButtonGroup/CellButtonGroup.d.ts +5 -3
  15. package/dist/components/CellButtonGroup/CellButtonGroup.d.ts.map +1 -1
  16. package/dist/components/Checkbox/Checkbox.d.ts +4 -0
  17. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  18. package/dist/components/Checkbox/Checkbox.js +4 -2
  19. package/dist/components/Checkbox/Checkbox.js.map +1 -1
  20. package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.d.ts +1 -1
  21. package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.d.ts.map +1 -1
  22. package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.js +6 -3
  23. package/dist/components/Checkbox/CheckboxSimple/CheckboxSimple.js.map +1 -1
  24. package/dist/components/ChipsInputBase/Chip/Chip.d.ts +41 -2
  25. package/dist/components/ChipsInputBase/Chip/Chip.d.ts.map +1 -1
  26. package/dist/components/ChipsInputBase/Chip/Chip.js +7 -2
  27. package/dist/components/ChipsInputBase/Chip/Chip.js.map +1 -1
  28. package/dist/components/ChipsInputBase/types.d.ts +2 -35
  29. package/dist/components/ChipsInputBase/types.d.ts.map +1 -1
  30. package/dist/components/ChipsInputBase/types.js.map +1 -1
  31. package/dist/components/ContentBadge/ContentBadge.d.ts +1 -1
  32. package/dist/components/ContentBadge/ContentBadge.d.ts.map +1 -1
  33. package/dist/components/ContentBadge/ContentBadge.js +15 -9
  34. package/dist/components/ContentBadge/ContentBadge.js.map +1 -1
  35. package/dist/components/ContentCard/ContentCard.d.ts +1 -1
  36. package/dist/components/ContentCard/ContentCard.d.ts.map +1 -1
  37. package/dist/components/ContentCard/ContentCard.js.map +1 -1
  38. package/dist/components/CustomSelect/CustomSelect.d.ts +16 -27
  39. package/dist/components/CustomSelect/CustomSelect.d.ts.map +1 -1
  40. package/dist/components/CustomSelect/CustomSelect.js +161 -428
  41. package/dist/components/CustomSelect/CustomSelect.js.map +1 -1
  42. package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.d.ts +3 -1
  43. package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.d.ts.map +1 -1
  44. package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.js +25 -5
  45. package/dist/components/CustomSelect/CustomSelectInput/CustomSelectInput.js.map +1 -1
  46. package/dist/components/CustomSelect/helpers.d.ts +12 -0
  47. package/dist/components/CustomSelect/helpers.d.ts.map +1 -0
  48. package/dist/components/CustomSelect/helpers.js +63 -0
  49. package/dist/components/CustomSelect/helpers.js.map +1 -0
  50. package/dist/components/CustomSelect/hooks/useAfterItems.d.ts +11 -0
  51. package/dist/components/CustomSelect/hooks/useAfterItems.d.ts.map +1 -0
  52. package/dist/components/CustomSelect/hooks/useAfterItems.js +57 -0
  53. package/dist/components/CustomSelect/hooks/useAfterItems.js.map +1 -0
  54. package/dist/components/CustomSelect/hooks/useDropdownOpenedController.d.ts +13 -0
  55. package/dist/components/CustomSelect/hooks/useDropdownOpenedController.d.ts.map +1 -0
  56. package/dist/components/CustomSelect/hooks/useDropdownOpenedController.js +60 -0
  57. package/dist/components/CustomSelect/hooks/useDropdownOpenedController.js.map +1 -0
  58. package/dist/components/CustomSelect/hooks/useFocusedOptionController.d.ts +20 -0
  59. package/dist/components/CustomSelect/hooks/useFocusedOptionController.d.ts.map +1 -0
  60. package/dist/components/CustomSelect/hooks/useFocusedOptionController.js +52 -0
  61. package/dist/components/CustomSelect/hooks/useFocusedOptionController.js.map +1 -0
  62. package/dist/components/CustomSelect/hooks/useInputKeyboardController.d.ts +13 -0
  63. package/dist/components/CustomSelect/hooks/useInputKeyboardController.d.ts.map +1 -0
  64. package/dist/components/CustomSelect/hooks/useInputKeyboardController.js +78 -0
  65. package/dist/components/CustomSelect/hooks/useInputKeyboardController.js.map +1 -0
  66. package/dist/components/CustomSelect/hooks/useInputValueController.d.ts +15 -0
  67. package/dist/components/CustomSelect/hooks/useInputValueController.d.ts.map +1 -0
  68. package/dist/components/CustomSelect/hooks/useInputValueController.js +43 -0
  69. package/dist/components/CustomSelect/hooks/useInputValueController.js.map +1 -0
  70. package/dist/components/CustomSelect/hooks/useScrollListController.d.ts +9 -0
  71. package/dist/components/CustomSelect/hooks/useScrollListController.d.ts.map +1 -0
  72. package/dist/components/CustomSelect/hooks/useScrollListController.js +37 -0
  73. package/dist/components/CustomSelect/hooks/useScrollListController.js.map +1 -0
  74. package/dist/components/CustomSelect/hooks/useSelectedOptionController.d.ts +18 -0
  75. package/dist/components/CustomSelect/hooks/useSelectedOptionController.d.ts.map +1 -0
  76. package/dist/components/CustomSelect/hooks/useSelectedOptionController.js +81 -0
  77. package/dist/components/CustomSelect/hooks/useSelectedOptionController.js.map +1 -0
  78. package/dist/components/CustomSelect/types.d.ts +33 -0
  79. package/dist/components/CustomSelect/types.d.ts.map +1 -0
  80. package/dist/components/CustomSelect/types.js +3 -0
  81. package/dist/components/CustomSelect/types.js.map +1 -0
  82. package/dist/components/CustomSelectDropdown/CustomSelectDropdown.d.ts.map +1 -1
  83. package/dist/components/CustomSelectDropdown/CustomSelectDropdown.js +1 -0
  84. package/dist/components/CustomSelectDropdown/CustomSelectDropdown.js.map +1 -1
  85. package/dist/components/DateInput/DateInput.d.ts.map +1 -1
  86. package/dist/components/DateInput/DateInput.js +3 -2
  87. package/dist/components/DateInput/DateInput.js.map +1 -1
  88. package/dist/components/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  89. package/dist/components/DateRangeInput/DateRangeInput.js +4 -4
  90. package/dist/components/DateRangeInput/DateRangeInput.js.map +1 -1
  91. package/dist/components/ImageBase/ImageBaseBadge/ImageBaseBadge.d.ts +1 -1
  92. package/dist/components/ImageBase/ImageBaseBadge/ImageBaseBadge.js.map +1 -1
  93. package/dist/components/MiniInfoCell/MiniInfoCell.d.ts +3 -2
  94. package/dist/components/MiniInfoCell/MiniInfoCell.d.ts.map +1 -1
  95. package/dist/components/MiniInfoCell/MiniInfoCell.js.map +1 -1
  96. package/dist/components/ModalCard/ModalCard.d.ts +1 -1
  97. package/dist/components/ModalCard/ModalCard.d.ts.map +1 -1
  98. package/dist/components/ModalCard/ModalCard.js +4 -2
  99. package/dist/components/ModalCard/ModalCard.js.map +1 -1
  100. package/dist/components/ModalCard/ModalCardInternal.d.ts +1 -1
  101. package/dist/components/ModalCard/ModalCardInternal.d.ts.map +1 -1
  102. package/dist/components/ModalCard/ModalCardInternal.js +5 -3
  103. package/dist/components/ModalCard/ModalCardInternal.js.map +1 -1
  104. package/dist/components/ModalCard/types.d.ts +8 -0
  105. package/dist/components/ModalCard/types.d.ts.map +1 -1
  106. package/dist/components/ModalCard/types.js.map +1 -1
  107. package/dist/components/ModalOutlet/ModalOutlet.d.ts +2 -1
  108. package/dist/components/ModalOutlet/ModalOutlet.d.ts.map +1 -1
  109. package/dist/components/ModalOutlet/ModalOutlet.js +4 -3
  110. package/dist/components/ModalOutlet/ModalOutlet.js.map +1 -1
  111. package/dist/components/ModalPage/ModalPage.d.ts +1 -1
  112. package/dist/components/ModalPage/ModalPage.d.ts.map +1 -1
  113. package/dist/components/ModalPage/ModalPage.js +3 -1
  114. package/dist/components/ModalPage/ModalPage.js.map +1 -1
  115. package/dist/components/ModalPage/ModalPageInternal.d.ts +1 -1
  116. package/dist/components/ModalPage/ModalPageInternal.d.ts.map +1 -1
  117. package/dist/components/ModalPage/ModalPageInternal.js +5 -3
  118. package/dist/components/ModalPage/ModalPageInternal.js.map +1 -1
  119. package/dist/components/ModalPage/types.d.ts +8 -0
  120. package/dist/components/ModalPage/types.d.ts.map +1 -1
  121. package/dist/components/ModalPage/types.js.map +1 -1
  122. package/dist/components/ModalRoot/ModalRoot.d.ts +1 -1
  123. package/dist/components/ModalRoot/ModalRoot.d.ts.map +1 -1
  124. package/dist/components/ModalRoot/ModalRoot.js +4 -2
  125. package/dist/components/ModalRoot/ModalRoot.js.map +1 -1
  126. package/dist/components/ModalRoot/types.d.ts +6 -0
  127. package/dist/components/ModalRoot/types.d.ts.map +1 -1
  128. package/dist/components/ModalRoot/types.js.map +1 -1
  129. package/dist/components/ModalRoot/useModalManager.d.ts +3 -1
  130. package/dist/components/ModalRoot/useModalManager.d.ts.map +1 -1
  131. package/dist/components/ModalRoot/useModalManager.js +2 -1
  132. package/dist/components/ModalRoot/useModalManager.js.map +1 -1
  133. package/dist/components/OnboardingTooltip/OnboardingTooltip.d.ts +2 -2
  134. package/dist/components/OnboardingTooltip/OnboardingTooltip.d.ts.map +1 -1
  135. package/dist/components/OnboardingTooltip/OnboardingTooltip.js +4 -2
  136. package/dist/components/OnboardingTooltip/OnboardingTooltip.js.map +1 -1
  137. package/dist/components/Popover/Popover.d.ts +1 -1
  138. package/dist/components/Popover/Popover.d.ts.map +1 -1
  139. package/dist/components/Popover/Popover.js.map +1 -1
  140. package/dist/components/Popover/usePopover.d.ts +1 -1
  141. package/dist/components/Popover/usePopover.d.ts.map +1 -1
  142. package/dist/components/Popover/usePopover.js +3 -1
  143. package/dist/components/Popover/usePopover.js.map +1 -1
  144. package/dist/components/Popper/Popper.d.ts +2 -2
  145. package/dist/components/Popper/Popper.d.ts.map +1 -1
  146. package/dist/components/Popper/Popper.js +3 -1
  147. package/dist/components/Popper/Popper.js.map +1 -1
  148. package/dist/components/Select/Select.d.ts +2 -1
  149. package/dist/components/Select/Select.d.ts.map +1 -1
  150. package/dist/components/Select/Select.js +5 -2
  151. package/dist/components/Select/Select.js.map +1 -1
  152. package/dist/components/SelectionControl/SelectionControl.d.ts +5 -1
  153. package/dist/components/SelectionControl/SelectionControl.d.ts.map +1 -1
  154. package/dist/components/SelectionControl/SelectionControl.js +22 -6
  155. package/dist/components/SelectionControl/SelectionControl.js.map +1 -1
  156. package/dist/components/SelectionControl/SelectionControlContext.d.ts +7 -0
  157. package/dist/components/SelectionControl/SelectionControlContext.d.ts.map +1 -0
  158. package/dist/components/SelectionControl/SelectionControlContext.js +7 -0
  159. package/dist/components/SelectionControl/SelectionControlContext.js.map +1 -0
  160. package/dist/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.d.ts.map +1 -1
  161. package/dist/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js +3 -1
  162. package/dist/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js.map +1 -1
  163. package/dist/components/SimpleCell/SimpleCell.d.ts.map +1 -1
  164. package/dist/components/SimpleCell/SimpleCell.js +29 -8
  165. package/dist/components/SimpleCell/SimpleCell.js.map +1 -1
  166. package/dist/components/Skeleton/Skeleton.js +1 -1
  167. package/dist/components/Skeleton/Skeleton.js.map +1 -1
  168. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  169. package/dist/components/Tabs/Tabs.js +19 -9
  170. package/dist/components/Tabs/Tabs.js.map +1 -1
  171. package/dist/components/Tabs/TabsController.d.ts +2 -2
  172. package/dist/components/Tabs/TabsController.d.ts.map +1 -1
  173. package/dist/components/Tabs/TabsController.js.map +1 -1
  174. package/dist/components/Tabs/TabsControllerContext.d.ts +5 -0
  175. package/dist/components/Tabs/TabsControllerContext.d.ts.map +1 -0
  176. package/dist/components/Tabs/TabsControllerContext.js +4 -0
  177. package/dist/components/Tabs/TabsControllerContext.js.map +1 -0
  178. package/dist/components/Tabs/TabsModeContext.d.ts +0 -2
  179. package/dist/components/Tabs/TabsModeContext.d.ts.map +1 -1
  180. package/dist/components/Tabs/TabsModeContext.js +1 -2
  181. package/dist/components/Tabs/TabsModeContext.js.map +1 -1
  182. package/dist/components/TabsItem/TabsItem.d.ts.map +1 -1
  183. package/dist/components/TabsItem/TabsItem.js +3 -1
  184. package/dist/components/TabsItem/TabsItem.js.map +1 -1
  185. package/dist/components/Tooltip/Tooltip.d.ts +1 -1
  186. package/dist/components/Tooltip/Tooltip.d.ts.map +1 -1
  187. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  188. package/dist/components/Tooltip/useTooltip.d.ts +1 -1
  189. package/dist/components/Tooltip/useTooltip.d.ts.map +1 -1
  190. package/dist/components/Tooltip/useTooltip.js +3 -1
  191. package/dist/components/Tooltip/useTooltip.js.map +1 -1
  192. package/dist/components/Typography/Caption/Caption.d.ts +2 -0
  193. package/dist/components/Typography/Caption/Caption.d.ts.map +1 -1
  194. package/dist/components/Typography/Caption/Caption.js +4 -1
  195. package/dist/components/Typography/Caption/Caption.js.map +1 -1
  196. package/dist/components/Typography/Footnote/Footnote.d.ts +2 -0
  197. package/dist/components/Typography/Footnote/Footnote.d.ts.map +1 -1
  198. package/dist/components/Typography/Footnote/Footnote.js +4 -1
  199. package/dist/components/Typography/Footnote/Footnote.js.map +1 -1
  200. package/dist/components/Typography/Typography.d.ts +1 -0
  201. package/dist/components/Typography/Typography.d.ts.map +1 -1
  202. package/dist/components/Typography/Typography.js +7 -1
  203. package/dist/components/Typography/Typography.js.map +1 -1
  204. package/dist/components/View/View.d.ts.map +1 -1
  205. package/dist/components/View/View.js +2 -1
  206. package/dist/components/View/View.js.map +1 -1
  207. package/dist/components/View/ViewInfinite.d.ts.map +1 -1
  208. package/dist/components/View/ViewInfinite.js +2 -1
  209. package/dist/components/View/ViewInfinite.js.map +1 -1
  210. package/dist/components.css +1 -1
  211. package/dist/components.css.map +1 -1
  212. package/dist/cssm/components/Banner/Banner.module.css +1 -6
  213. package/dist/cssm/components/Calendar/Calendar.js +6 -6
  214. package/dist/cssm/components/Calendar/Calendar.js.map +1 -1
  215. package/dist/cssm/components/CalendarDays/CalendarDays.js +3 -3
  216. package/dist/cssm/components/CalendarDays/CalendarDays.js.map +1 -1
  217. package/dist/cssm/components/CalendarRange/CalendarRange.js +16 -14
  218. package/dist/cssm/components/CalendarRange/CalendarRange.js.map +1 -1
  219. package/dist/cssm/components/CalendarRange/utils.js +6 -5
  220. package/dist/cssm/components/CalendarRange/utils.js.map +1 -1
  221. package/dist/cssm/components/Cell/Cell.js +3 -1
  222. package/dist/cssm/components/Cell/Cell.js.map +1 -1
  223. package/dist/cssm/components/Checkbox/Checkbox.js +2 -1
  224. package/dist/cssm/components/Checkbox/Checkbox.js.map +1 -1
  225. package/dist/cssm/components/Checkbox/CheckboxSimple/CheckboxSimple.js +4 -2
  226. package/dist/cssm/components/Checkbox/CheckboxSimple/CheckboxSimple.js.map +1 -1
  227. package/dist/cssm/components/Checkbox/CheckboxSimple/CheckboxSimple.module.css +11 -2
  228. package/dist/cssm/components/ChipsInputBase/Chip/Chip.js +6 -2
  229. package/dist/cssm/components/ChipsInputBase/Chip/Chip.js.map +1 -1
  230. package/dist/cssm/components/ChipsInputBase/Chip/Chip.module.css +8 -1
  231. package/dist/cssm/components/ChipsInputBase/types.js.map +1 -1
  232. package/dist/cssm/components/ContentBadge/ContentBadge.js +14 -8
  233. package/dist/cssm/components/ContentBadge/ContentBadge.js.map +1 -1
  234. package/dist/cssm/components/ContentCard/ContentCard.js.map +1 -1
  235. package/dist/cssm/components/CustomSelect/CustomSelect.js +154 -421
  236. package/dist/cssm/components/CustomSelect/CustomSelect.js.map +1 -1
  237. package/dist/cssm/components/CustomSelect/CustomSelectInput/CustomSelectInput.js +22 -4
  238. package/dist/cssm/components/CustomSelect/CustomSelectInput/CustomSelectInput.js.map +1 -1
  239. package/dist/cssm/components/CustomSelect/CustomSelectInput/CustomSelectInput.module.css +12 -0
  240. package/dist/cssm/components/CustomSelect/helpers.js +62 -0
  241. package/dist/cssm/components/CustomSelect/helpers.js.map +1 -0
  242. package/dist/cssm/components/CustomSelect/hooks/useAfterItems.js +58 -0
  243. package/dist/cssm/components/CustomSelect/hooks/useAfterItems.js.map +1 -0
  244. package/dist/cssm/components/CustomSelect/hooks/useDropdownOpenedController.js +60 -0
  245. package/dist/cssm/components/CustomSelect/hooks/useDropdownOpenedController.js.map +1 -0
  246. package/dist/cssm/components/CustomSelect/hooks/useFocusedOptionController.js +52 -0
  247. package/dist/cssm/components/CustomSelect/hooks/useFocusedOptionController.js.map +1 -0
  248. package/dist/cssm/components/CustomSelect/hooks/useInputKeyboardController.js +78 -0
  249. package/dist/cssm/components/CustomSelect/hooks/useInputKeyboardController.js.map +1 -0
  250. package/dist/cssm/components/CustomSelect/hooks/useInputValueController.js +43 -0
  251. package/dist/cssm/components/CustomSelect/hooks/useInputValueController.js.map +1 -0
  252. package/dist/cssm/components/CustomSelect/hooks/useScrollListController.js +37 -0
  253. package/dist/cssm/components/CustomSelect/hooks/useScrollListController.js.map +1 -0
  254. package/dist/cssm/components/CustomSelect/hooks/useSelectedOptionController.js +81 -0
  255. package/dist/cssm/components/CustomSelect/hooks/useSelectedOptionController.js.map +1 -0
  256. package/dist/cssm/components/CustomSelect/types.js +3 -0
  257. package/dist/cssm/components/CustomSelect/types.js.map +1 -0
  258. package/dist/cssm/components/CustomSelectDropdown/CustomSelectDropdown.js +1 -0
  259. package/dist/cssm/components/CustomSelectDropdown/CustomSelectDropdown.js.map +1 -1
  260. package/dist/cssm/components/DateInput/DateInput.js +3 -2
  261. package/dist/cssm/components/DateInput/DateInput.js.map +1 -1
  262. package/dist/cssm/components/DateRangeInput/DateRangeInput.js +4 -4
  263. package/dist/cssm/components/DateRangeInput/DateRangeInput.js.map +1 -1
  264. package/dist/cssm/components/ImageBase/ImageBaseBadge/ImageBaseBadge.js.map +1 -1
  265. package/dist/cssm/components/MiniInfoCell/MiniInfoCell.js.map +1 -1
  266. package/dist/cssm/components/ModalCard/ModalCard.js +2 -1
  267. package/dist/cssm/components/ModalCard/ModalCard.js.map +1 -1
  268. package/dist/cssm/components/ModalCard/ModalCardInternal.js +3 -2
  269. package/dist/cssm/components/ModalCard/ModalCardInternal.js.map +1 -1
  270. package/dist/cssm/components/ModalCard/types.js.map +1 -1
  271. package/dist/cssm/components/ModalOutlet/ModalOutlet.js +2 -2
  272. package/dist/cssm/components/ModalOutlet/ModalOutlet.js.map +1 -1
  273. package/dist/cssm/components/ModalOutlet/ModalOutlet.module.css +4 -0
  274. package/dist/cssm/components/ModalOverlay/ModalOverlay.module.css +1 -1
  275. package/dist/cssm/components/ModalPage/ModalPage.js +2 -1
  276. package/dist/cssm/components/ModalPage/ModalPage.js.map +1 -1
  277. package/dist/cssm/components/ModalPage/ModalPage.module.css +1 -0
  278. package/dist/cssm/components/ModalPage/ModalPageInternal.js +3 -2
  279. package/dist/cssm/components/ModalPage/ModalPageInternal.js.map +1 -1
  280. package/dist/cssm/components/ModalPage/types.js.map +1 -1
  281. package/dist/cssm/components/ModalRoot/ModalRoot.js +4 -2
  282. package/dist/cssm/components/ModalRoot/ModalRoot.js.map +1 -1
  283. package/dist/cssm/components/ModalRoot/types.js.map +1 -1
  284. package/dist/cssm/components/ModalRoot/useModalManager.js +2 -1
  285. package/dist/cssm/components/ModalRoot/useModalManager.js.map +1 -1
  286. package/dist/cssm/components/OnboardingTooltip/OnboardingTooltip.js +3 -2
  287. package/dist/cssm/components/OnboardingTooltip/OnboardingTooltip.js.map +1 -1
  288. package/dist/cssm/components/Popover/Popover.js.map +1 -1
  289. package/dist/cssm/components/Popover/usePopover.js +2 -1
  290. package/dist/cssm/components/Popover/usePopover.js.map +1 -1
  291. package/dist/cssm/components/Popper/Popper.js +2 -1
  292. package/dist/cssm/components/Popper/Popper.js.map +1 -1
  293. package/dist/cssm/components/RichCell/RichCell.module.css +4 -2
  294. package/dist/cssm/components/Select/Select.js +1 -1
  295. package/dist/cssm/components/Select/Select.js.map +1 -1
  296. package/dist/cssm/components/SelectionControl/SelectionControl.js +16 -6
  297. package/dist/cssm/components/SelectionControl/SelectionControl.js.map +1 -1
  298. package/dist/cssm/components/SelectionControl/SelectionControl.module.css +6 -3
  299. package/dist/cssm/components/SelectionControl/SelectionControlContext.js +7 -0
  300. package/dist/cssm/components/SelectionControl/SelectionControlContext.js.map +1 -0
  301. package/dist/cssm/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js +3 -1
  302. package/dist/cssm/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.js.map +1 -1
  303. package/dist/cssm/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.module.css +6 -3
  304. package/dist/cssm/components/SimpleCell/SimpleCell.js +29 -8
  305. package/dist/cssm/components/SimpleCell/SimpleCell.js.map +1 -1
  306. package/dist/cssm/components/Skeleton/Skeleton.js +1 -1
  307. package/dist/cssm/components/Skeleton/Skeleton.js.map +1 -1
  308. package/dist/cssm/components/Slider/SliderThumb/SliderThumb.module.css +2 -1
  309. package/dist/cssm/components/Tabs/Tabs.js +19 -9
  310. package/dist/cssm/components/Tabs/Tabs.js.map +1 -1
  311. package/dist/cssm/components/Tabs/TabsController.js.map +1 -1
  312. package/dist/cssm/components/Tabs/TabsControllerContext.js +4 -0
  313. package/dist/cssm/components/Tabs/TabsControllerContext.js.map +1 -0
  314. package/dist/cssm/components/Tabs/TabsModeContext.js +1 -2
  315. package/dist/cssm/components/Tabs/TabsModeContext.js.map +1 -1
  316. package/dist/cssm/components/TabsItem/TabsItem.js +3 -1
  317. package/dist/cssm/components/TabsItem/TabsItem.js.map +1 -1
  318. package/dist/cssm/components/Tooltip/Tooltip.js.map +1 -1
  319. package/dist/cssm/components/Tooltip/useTooltip.js +2 -1
  320. package/dist/cssm/components/Tooltip/useTooltip.js.map +1 -1
  321. package/dist/cssm/components/Typography/Caption/Caption.js +4 -1
  322. package/dist/cssm/components/Typography/Caption/Caption.js.map +1 -1
  323. package/dist/cssm/components/Typography/Footnote/Footnote.js +4 -1
  324. package/dist/cssm/components/Typography/Footnote/Footnote.js.map +1 -1
  325. package/dist/cssm/components/Typography/Typography.js +7 -1
  326. package/dist/cssm/components/Typography/Typography.js.map +1 -1
  327. package/dist/cssm/components/View/View.js +2 -1
  328. package/dist/cssm/components/View/View.js.map +1 -1
  329. package/dist/cssm/components/View/View.module.css +1 -1
  330. package/dist/cssm/components/View/ViewInfinite.js +2 -1
  331. package/dist/cssm/components/View/ViewInfinite.js.map +1 -1
  332. package/dist/cssm/components/VisuallyHidden/VisuallyHidden.module.css +0 -2
  333. package/dist/cssm/hooks/useCalendar.js +6 -4
  334. package/dist/cssm/hooks/useCalendar.js.map +1 -1
  335. package/dist/cssm/hooks/useFloatingElement.js +3 -2
  336. package/dist/cssm/hooks/useFloatingElement.js.map +1 -1
  337. package/dist/cssm/hooks/useTodayDate.js +3 -2
  338. package/dist/cssm/hooks/useTodayDate.js.map +1 -1
  339. package/dist/cssm/index.js.map +1 -1
  340. package/dist/cssm/lib/accessibility.js +8 -0
  341. package/dist/cssm/lib/accessibility.js.map +1 -1
  342. package/dist/cssm/lib/calendar.js +9 -7
  343. package/dist/cssm/lib/calendar.js.map +1 -1
  344. package/dist/cssm/lib/date.js +66 -3
  345. package/dist/cssm/lib/date.js.map +1 -1
  346. package/dist/cssm/lib/floating/useFloatingMiddlewaresBootstrap/index.js +18 -8
  347. package/dist/cssm/lib/floating/useFloatingMiddlewaresBootstrap/index.js.map +1 -1
  348. package/dist/cssm/lib/floating/useFloatingWithInteractions/types.js.map +1 -1
  349. package/dist/cssm/lib/touch/UIPanGestureRecognizer.js +2 -2
  350. package/dist/cssm/lib/touch/UIPanGestureRecognizer.js.map +1 -1
  351. package/dist/cssm/lib/utils.js +1 -0
  352. package/dist/cssm/lib/utils.js.map +1 -1
  353. package/dist/cssm/styles/dynamicTokens.css +14 -2
  354. package/dist/cssm/styles/themes.css +1 -1
  355. package/dist/hooks/useCalendar.d.ts.map +1 -1
  356. package/dist/hooks/useCalendar.js +6 -4
  357. package/dist/hooks/useCalendar.js.map +1 -1
  358. package/dist/hooks/useFloatingElement.d.ts +1 -1
  359. package/dist/hooks/useFloatingElement.d.ts.map +1 -1
  360. package/dist/hooks/useFloatingElement.js +3 -2
  361. package/dist/hooks/useFloatingElement.js.map +1 -1
  362. package/dist/hooks/useTodayDate.d.ts.map +1 -1
  363. package/dist/hooks/useTodayDate.js +3 -2
  364. package/dist/hooks/useTodayDate.js.map +1 -1
  365. package/dist/index.d.ts +4 -2
  366. package/dist/index.d.ts.map +1 -1
  367. package/dist/index.js.map +1 -1
  368. package/dist/lib/accessibility.d.ts +1 -1
  369. package/dist/lib/accessibility.d.ts.map +1 -1
  370. package/dist/lib/accessibility.js +8 -0
  371. package/dist/lib/accessibility.js.map +1 -1
  372. package/dist/lib/calendar.d.ts.map +1 -1
  373. package/dist/lib/calendar.js +9 -7
  374. package/dist/lib/calendar.js.map +1 -1
  375. package/dist/lib/date.d.ts +31 -1
  376. package/dist/lib/date.d.ts.map +1 -1
  377. package/dist/lib/date.js +67 -3
  378. package/dist/lib/date.js.map +1 -1
  379. package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.d.ts +6 -1
  380. package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.d.ts.map +1 -1
  381. package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.js +18 -8
  382. package/dist/lib/floating/useFloatingMiddlewaresBootstrap/index.js.map +1 -1
  383. package/dist/lib/floating/useFloatingWithInteractions/types.d.ts +2 -0
  384. package/dist/lib/floating/useFloatingWithInteractions/types.d.ts.map +1 -1
  385. package/dist/lib/floating/useFloatingWithInteractions/types.js.map +1 -1
  386. package/dist/lib/touch/UIPanGestureRecognizer.d.ts.map +1 -1
  387. package/dist/lib/touch/UIPanGestureRecognizer.js +2 -2
  388. package/dist/lib/touch/UIPanGestureRecognizer.js.map +1 -1
  389. package/dist/lib/utils.d.ts +1 -0
  390. package/dist/lib/utils.d.ts.map +1 -1
  391. package/dist/lib/utils.js +1 -0
  392. package/dist/lib/utils.js.map +1 -1
  393. package/dist/vkui.css +1 -1
  394. package/dist/vkui.css.map +1 -1
  395. package/package.json +6 -7
  396. package/src/components/Banner/Banner.module.css +1 -6
  397. package/src/components/Banner/Banner.module.css.d.ts.map +1 -1
  398. package/src/components/Calendar/Calendar.tsx +6 -6
  399. package/src/components/CalendarDays/CalendarDays.tsx +3 -3
  400. package/src/components/CalendarRange/CalendarRange.tsx +15 -20
  401. package/src/components/CalendarRange/utils.ts +7 -6
  402. package/src/components/Cell/Cell.tsx +3 -0
  403. package/src/components/Checkbox/Checkbox.tsx +6 -0
  404. package/src/components/Checkbox/CheckboxSimple/CheckboxSimple.module.css +7 -2
  405. package/src/components/Checkbox/CheckboxSimple/CheckboxSimple.module.css.d.ts.map +1 -1
  406. package/src/components/Checkbox/CheckboxSimple/CheckboxSimple.tsx +12 -3
  407. package/src/components/ChipsInputBase/Chip/Chip.module.css +8 -1
  408. package/src/components/ChipsInputBase/Chip/Chip.module.css.d.ts.map +1 -1
  409. package/src/components/ChipsInputBase/Chip/Chip.tsx +55 -1
  410. package/src/components/ChipsInputBase/types.ts +2 -45
  411. package/src/components/ContentBadge/ContentBadge.tsx +18 -12
  412. package/src/components/ContentCard/ContentCard.tsx +1 -1
  413. package/src/components/CustomSelect/CustomSelect.tsx +216 -562
  414. package/src/components/CustomSelect/CustomSelectInput/CustomSelectInput.module.css +12 -0
  415. package/src/components/CustomSelect/CustomSelectInput/CustomSelectInput.module.css.d.ts.map +1 -1
  416. package/src/components/CustomSelect/CustomSelectInput/CustomSelectInput.tsx +25 -2
  417. package/src/components/CustomSelect/helpers.ts +103 -0
  418. package/src/components/CustomSelect/hooks/useAfterItems.tsx +89 -0
  419. package/src/components/CustomSelect/hooks/useDropdownOpenedController.ts +61 -0
  420. package/src/components/CustomSelect/hooks/useFocusedOptionController.ts +86 -0
  421. package/src/components/CustomSelect/hooks/useInputKeyboardController.ts +96 -0
  422. package/src/components/CustomSelect/hooks/useInputValueController.ts +58 -0
  423. package/src/components/CustomSelect/hooks/useScrollListController.ts +46 -0
  424. package/src/components/CustomSelect/hooks/useSelectedOptionController.ts +132 -0
  425. package/src/components/CustomSelect/types.ts +38 -0
  426. package/src/components/CustomSelectDropdown/CustomSelectDropdown.tsx +1 -0
  427. package/src/components/DateInput/DateInput.tsx +9 -3
  428. package/src/components/DateRangeInput/DateRangeInput.tsx +9 -6
  429. package/src/components/ImageBase/ImageBaseBadge/ImageBaseBadge.tsx +1 -1
  430. package/src/components/MiniInfoCell/MiniInfoCell.tsx +8 -3
  431. package/src/components/ModalCard/ModalCard.tsx +2 -0
  432. package/src/components/ModalCard/ModalCardInternal.tsx +8 -2
  433. package/src/components/ModalCard/types.ts +8 -0
  434. package/src/components/ModalOutlet/ModalOutlet.module.css +4 -0
  435. package/src/components/ModalOutlet/ModalOutlet.module.css.d.ts.map +1 -1
  436. package/src/components/ModalOutlet/ModalOutlet.tsx +8 -1
  437. package/src/components/ModalOverlay/ModalOverlay.module.css +1 -1
  438. package/src/components/ModalPage/ModalPage.module.css +1 -0
  439. package/src/components/ModalPage/ModalPage.module.css.d.ts.map +1 -1
  440. package/src/components/ModalPage/ModalPage.tsx +2 -0
  441. package/src/components/ModalPage/ModalPageInternal.tsx +8 -2
  442. package/src/components/ModalPage/types.ts +8 -0
  443. package/src/components/ModalRoot/ModalRoot.tsx +19 -6
  444. package/src/components/ModalRoot/types.ts +7 -0
  445. package/src/components/ModalRoot/useModalManager.tsx +4 -0
  446. package/src/components/OnboardingTooltip/OnboardingTooltip.tsx +3 -0
  447. package/src/components/Popover/Popover.tsx +1 -0
  448. package/src/components/Popover/usePopover.tsx +2 -0
  449. package/src/components/Popper/Popper.tsx +3 -0
  450. package/src/components/RichCell/RichCell.module.css +4 -2
  451. package/src/components/RichCell/RichCell.module.css.d.ts.map +1 -1
  452. package/src/components/Select/Select.tsx +5 -5
  453. package/src/components/SelectionControl/SelectionControl.module.css +6 -3
  454. package/src/components/SelectionControl/SelectionControl.module.css.d.ts.map +1 -1
  455. package/src/components/SelectionControl/SelectionControl.tsx +30 -8
  456. package/src/components/SelectionControl/SelectionControlContext.ts +7 -0
  457. package/src/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.module.css +6 -3
  458. package/src/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.module.css.d.ts.map +1 -1
  459. package/src/components/SelectionControl/SelectionControlLabel/SelectionControlLabel.tsx +7 -1
  460. package/src/components/SimpleCell/SimpleCell.tsx +5 -0
  461. package/src/components/Skeleton/Skeleton.tsx +1 -1
  462. package/src/components/Slider/SliderThumb/SliderThumb.module.css +1 -1
  463. package/src/components/Tabs/Tabs.tsx +16 -12
  464. package/src/components/Tabs/TabsController.ts +2 -2
  465. package/src/components/Tabs/TabsControllerContext.ts +7 -0
  466. package/src/components/Tabs/TabsModeContext.ts +0 -3
  467. package/src/components/TabsItem/TabsItem.tsx +5 -9
  468. package/src/components/Tooltip/Tooltip.tsx +1 -0
  469. package/src/components/Tooltip/useTooltip.tsx +2 -0
  470. package/src/components/Typography/Caption/Caption.tsx +14 -6
  471. package/src/components/Typography/Footnote/Footnote.tsx +10 -6
  472. package/src/components/Typography/Typography.tsx +9 -2
  473. package/src/components/View/View.module.css +1 -1
  474. package/src/components/View/View.tsx +2 -1
  475. package/src/components/View/ViewInfinite.tsx +2 -1
  476. package/src/components/VisuallyHidden/VisuallyHidden.module.css +0 -2
  477. package/src/components/VisuallyHidden/VisuallyHidden.module.css.d.ts.map +1 -1
  478. package/src/hooks/useCalendar.ts +6 -4
  479. package/src/hooks/useFloatingElement.tsx +2 -0
  480. package/src/hooks/useTodayDate.ts +3 -2
  481. package/src/index.ts +5 -3
  482. package/src/lib/accessibility.ts +4 -0
  483. package/src/lib/calendar.ts +8 -12
  484. package/src/lib/date.ts +82 -3
  485. package/src/lib/floating/useFloatingMiddlewaresBootstrap/index.ts +23 -10
  486. package/src/lib/floating/useFloatingWithInteractions/types.ts +2 -0
  487. package/src/lib/touch/UIPanGestureRecognizer.ts +2 -2
  488. package/src/lib/utils.ts +3 -0
  489. package/src/styles/dynamicTokens.css +13 -2
@@ -1,48 +1,52 @@
1
1
  'use client';
2
2
 
3
3
  import * as React from 'react';
4
- import { classNames, debounce } from '@vkontakte/vkjs';
4
+ import { classNames } from '@vkontakte/vkjs';
5
+ import { getRequiredValueByKey } from '../../helpers/getValueByKey';
5
6
  import { useAdaptivity } from '../../hooks/useAdaptivity';
6
7
  import { useExternRef } from '../../hooks/useExternRef';
7
- import { useFocusWithin } from '../../hooks/useFocusWithin';
8
- import { useStateWithPrev } from '../../hooks/useStateWithPrev';
9
8
  import { callMultiple } from '../../lib/callMultiple';
10
9
  import { useDOM } from '../../lib/dom';
11
- import type { Alignment, Placement, Side } from '../../lib/floating';
10
+ import type { Placement } from '../../lib/floating';
12
11
  import { defaultFilterFn, type FilterFn } from '../../lib/select';
13
12
  import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';
14
- import { warnOnce } from '../../lib/warnOnce';
13
+ import { preventDefault } from '../../lib/utils';
15
14
  import {
16
15
  CustomSelectDropdown,
17
16
  type CustomSelectDropdownProps,
18
17
  } from '../CustomSelectDropdown/CustomSelectDropdown';
19
- import {
20
- CustomSelectOption,
21
- type CustomSelectOptionProps,
22
- } from '../CustomSelectOption/CustomSelectOption';
23
- import { DropdownIcon } from '../DropdownIcon/DropdownIcon';
18
+ import { CustomSelectOption } from '../CustomSelectOption/CustomSelectOption';
24
19
  import type { FormFieldProps } from '../FormField/FormField';
25
- import type {
26
- NativeSelectProps,
27
- NativeSelectValue,
28
- SelectValue,
29
- } from '../NativeSelect/NativeSelect';
30
- import {
31
- NOT_SELECTED,
32
- remapFromNativeValueToSelectValue,
33
- remapFromSelectValueToNativeValue,
34
- } from '../NativeSelect/NativeSelect';
20
+ import type { NativeSelectProps, SelectValue } from '../NativeSelect/NativeSelect';
21
+ import { NOT_SELECTED, remapFromNativeValueToSelectValue } from '../NativeSelect/NativeSelect';
35
22
  import type { SelectType } from '../Select/Select';
36
23
  import { Footnote } from '../Typography/Footnote/Footnote';
37
24
  import { VisuallyHidden } from '../VisuallyHidden/VisuallyHidden';
38
- import {
39
- CustomSelectClearButton,
40
- type CustomSelectClearButtonProps,
41
- } from './CustomSelectClearButton';
25
+ import { type CustomSelectClearButtonProps } from './CustomSelectClearButton';
42
26
  import {
43
27
  CustomSelectInput,
44
28
  type CustomSelectInputProps,
45
29
  } from './CustomSelectInput/CustomSelectInput';
30
+ import {
31
+ checkMixControlledAndUncontrolledState,
32
+ checkOptionsValueType,
33
+ filter,
34
+ findSelectedIndex,
35
+ getOptionByValue,
36
+ } from './helpers';
37
+ import { useAfterItems } from './hooks/useAfterItems';
38
+ import { useDropdownOpenedController } from './hooks/useDropdownOpenedController';
39
+ import { useFocusedOptionController } from './hooks/useFocusedOptionController';
40
+ import { useInputKeyboardController } from './hooks/useInputKeyboardController';
41
+ import { useInputValueController } from './hooks/useInputValueController';
42
+ import { useScrollListController } from './hooks/useScrollListController';
43
+ import { useSelectedOptionController } from './hooks/useSelectedOptionController';
44
+ import type {
45
+ CustomSelectOptionInterface,
46
+ CustomSelectRenderOption,
47
+ MousePosition,
48
+ PopupDirection,
49
+ } from './types';
46
50
  import styles from './CustomSelect.module.css';
47
51
 
48
52
  const sizeYClassNames = {
@@ -50,61 +54,6 @@ const sizeYClassNames = {
50
54
  compact: styles.sizeYCompact,
51
55
  };
52
56
 
53
- const findIndexAfter = (options: CustomSelectOptionInterface[] = [], startIndex = -1) => {
54
- if (startIndex >= options.length - 1) {
55
- return -1;
56
- }
57
- return options.findIndex((option, i) => i > startIndex && !option.disabled);
58
- };
59
-
60
- const findIndexBefore = (
61
- options: CustomSelectOptionInterface[] = [],
62
- endIndex: number = options.length,
63
- ) => {
64
- let result = -1;
65
- if (endIndex <= 0) {
66
- return result;
67
- }
68
- for (let i = endIndex - 1; i >= 0; i--) {
69
- let option = options[i];
70
-
71
- if (!option.disabled) {
72
- result = i;
73
- break;
74
- }
75
- }
76
- return result;
77
- };
78
-
79
- const warn = warnOnce('CustomSelect');
80
-
81
- const checkOptionsValueType = <T extends CustomSelectOptionInterface>(options: T[]) => {
82
- if (new Set(options.map((item) => typeof item.value)).size > 1) {
83
- warn(
84
- 'Некоторые значения ваших опций имеют разные типы. onChange всегда возвращает строковый тип.',
85
- 'error',
86
- );
87
- }
88
- };
89
-
90
- const checkMixControlledAndUncontrolledState = (
91
- oldIsControlled: boolean,
92
- newIsControlled: boolean,
93
- ) => {
94
- if (!oldIsControlled && newIsControlled) {
95
- warn(
96
- `Похоже, что компонент был переведен из состояния Uncontrolled в Controlled. Пожалуйста, не делайте так. Если вам нужно отобразить невыбранное состояние компонента, используйте value=null вместо undefined`,
97
- 'error',
98
- );
99
- }
100
- if (oldIsControlled && !newIsControlled) {
101
- warn(
102
- `Похоже, что компонент был переведен из состояния Controlled в Uncontrolled. Пожалуйста, не делайте так. Если вам нужно отобразить невыбранное состояние компонента, используйте value=null вместо undefined`,
103
- 'error',
104
- );
105
- }
106
- };
107
-
108
57
  function defaultRenderOptionFn<T extends CustomSelectOptionInterface>({
109
58
  option,
110
59
  ...props
@@ -112,75 +61,48 @@ function defaultRenderOptionFn<T extends CustomSelectOptionInterface>({
112
61
  return <CustomSelectOption {...props} />;
113
62
  }
114
63
 
115
- const handleOptionDown: MouseEventHandler = (e: React.MouseEvent<HTMLElement>) => {
116
- e.preventDefault();
117
- };
118
-
119
- function findSelectedIndex<T extends CustomSelectOptionInterface>(
120
- options: T[] = [],
121
- value: SelectValue,
122
- ) {
123
- if (value === NOT_SELECTED.CUSTOM) {
124
- return -1;
125
- }
126
- return (
127
- options.findIndex((item) => {
128
- value = typeof item.value === 'number' ? Number(value) : value;
129
- return item.value === value;
130
- }) ?? -1
131
- );
132
- }
133
-
134
- const filter = <T extends CustomSelectOptionInterface>(
135
- options: SelectProps<T>['options'],
136
- inputValue: string,
137
- filterFn: SelectProps<T>['filterFn'],
138
- ) => {
139
- return typeof filterFn === 'function'
140
- ? options.filter((option) => filterFn(inputValue, option))
141
- : options;
142
- };
143
-
144
- /* eslint-disable jsdoc/require-jsdoc */
145
- type MousePosition = {
146
- x: React.MouseEvent['clientX'];
147
- y: React.MouseEvent['clientY'];
148
- };
149
- /* eslint-enable jsdoc/require-jsdoc */
150
-
151
64
  function isMousePositionChanged(event: React.MouseEvent, prevPosition: MousePosition) {
152
65
  return (
153
66
  Math.abs(prevPosition.x - event.clientX) >= 1 || Math.abs(prevPosition.y - event.clientY) >= 1
154
67
  );
155
68
  }
156
69
 
157
- export interface CustomSelectOptionInterface {
158
- /**
159
- * Значение.
160
- */
161
- value: Exclude<SelectValue, null>;
162
- /**
163
- * Отображаемый текст.
164
- */
165
- label: React.ReactElement | string;
166
- /**
167
- * Блокировка взаимодействия с компонентом.
168
- */
169
- disabled?: boolean;
170
- [index: string]: any;
171
- }
172
-
173
- export interface CustomSelectRenderOption<T extends CustomSelectOptionInterface>
174
- extends CustomSelectOptionProps {
175
- /**
176
- * Данные об опции.
177
- */
178
- option: T;
179
- }
180
-
181
- type PopupDirectionSide = Extract<Side, 'top' | 'bottom'>;
70
+ const FETCH_STATUS_RESET_DELAY = 2000;
71
+
72
+ const FetchingStatus = ({
73
+ fetching = false,
74
+ options,
75
+ fetchingInProgressLabel = 'Список опций загружается...',
76
+ fetchingCompletedLabel = `Загружено опций: ${options.length}`,
77
+ }: Pick<
78
+ SelectProps,
79
+ 'fetching' | 'fetchingInProgressLabel' | 'fetchingCompletedLabel' | 'options'
80
+ >) => {
81
+ const [status, setStatus] = React.useState<'fetching' | 'loaded' | 'none'>('none');
82
+
83
+ const content = getRequiredValueByKey(status, {
84
+ fetching: fetchingInProgressLabel,
85
+ loaded:
86
+ typeof fetchingCompletedLabel === 'function'
87
+ ? fetchingCompletedLabel(options.length)
88
+ : fetchingCompletedLabel,
89
+ none: '',
90
+ });
91
+
92
+ useIsomorphicLayoutEffect(
93
+ function updateStatus() {
94
+ if (fetching) {
95
+ setStatus('fetching');
96
+ } else {
97
+ setStatus('loaded');
98
+ setTimeout(() => setStatus('none'), FETCH_STATUS_RESET_DELAY);
99
+ }
100
+ },
101
+ [fetching],
102
+ );
182
103
 
183
- type PopupDirection = PopupDirectionSide | `${PopupDirectionSide}-${Alignment}`;
104
+ return <VisuallyHidden aria-live="polite">{content}</VisuallyHidden>;
105
+ };
184
106
 
185
107
  export type { CustomSelectClearButtonProps };
186
108
 
@@ -223,7 +145,7 @@ export interface SelectProps<
223
145
  * Рендер-проп для кастомного рендера опции.
224
146
  * В объекте аргумента приходят [свойства опции](https://vkui.io/components/custom-select#custom-select-option-api).
225
147
  *
226
- * > ⚠️ Важно: cвойство опции `disabled` должно выставляться только через проп `options`.
148
+ * > ⚠️ Важно: свойство опции `disabled` должно выставляться только через проп `options`.
227
149
  * > Запрещается выставлять `disabled` проп опциям в обход `options`, иначе `CustomSelect` не будет знать об актуальном состоянии
228
150
  * опции.
229
151
  */
@@ -299,17 +221,27 @@ export interface SelectProps<
299
221
  * Обработчик события `keyDown` в поле ввода.
300
222
  */
301
223
  onInputKeyDown?: (e: React.KeyboardEvent, isOpen: boolean) => void;
224
+ /**
225
+ * Включает режим в котором выбранное значение `CustomSelect` читается скринридерами корректно.
226
+ * В данном режиме введенное в поле ввода значение не сбрасывается при потере фокуса.
227
+ */
228
+ accessible?: boolean /* TODO [>=v8] включить по умолчанию */;
229
+ /**
230
+ * Текстовая метка для индикации процесса загрузки данных для пользователей скринридерами. По умолчанию: `"Список опций загружается..."`.
231
+ */
232
+ fetchingInProgressLabel?: string;
233
+ /**
234
+ * Текстовая метка для индикации завершения процесса загрузки данных для пользователей скринридерами. По умолчанию: `"Загружено опций: ${options.length}"`.
235
+ */
236
+ fetchingCompletedLabel?: string | ((optionsCount: number) => string);
302
237
  }
303
238
 
304
- type MouseEventHandler = (event: React.MouseEvent<HTMLElement>) => void;
305
-
306
239
  /**
307
240
  * @see https://vkui.io/components/custom-select
308
241
  */
309
242
  export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterface>(
310
243
  props: SelectProps<OptionInterfaceT>,
311
244
  ): React.ReactNode {
312
- const [opened, setOpened] = React.useState(false);
313
245
  const {
314
246
  before,
315
247
  name,
@@ -329,11 +261,11 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
329
261
  selectType = 'default',
330
262
  searchable = false,
331
263
  'renderOption': renderOptionProp = defaultRenderOptionFn,
332
- 'options': optionsProp,
264
+ 'options': options,
333
265
  emptyText = 'Ничего не найдено',
334
266
  filterFn = defaultFilterFn,
335
267
  'icon': iconProp,
336
- ClearButton = CustomSelectClearButton,
268
+ ClearButton,
337
269
  allowClearButton = false,
338
270
  dropdownOffsetDistance = 0,
339
271
  dropdownAutoWidth = false,
@@ -345,85 +277,119 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
345
277
  required,
346
278
  getSelectInputRef,
347
279
  overscrollBehavior,
348
- onInputKeyDown,
280
+ 'onInputKeyDown': onInputKeyDownProp,
349
281
  readOnly,
282
+ accessible = false,
283
+ fetchingInProgressLabel,
284
+ fetchingCompletedLabel,
350
285
  ...restProps
351
286
  } = props;
352
287
 
353
288
  if (process.env.NODE_ENV === 'development') {
354
- checkOptionsValueType(optionsProp);
289
+ checkOptionsValueType(options);
355
290
  }
356
291
 
357
292
  const { sizeY = 'none' } = useAdaptivity();
358
293
 
359
294
  const containerRef = React.useRef<HTMLDivElement>(null);
360
295
  const handleRootRef = useExternRef(containerRef, getRootRef);
361
- const scrollBoxRef = React.useRef<HTMLDivElement | null>(null);
362
296
  const selectElRef = useExternRef(getRef);
363
- const optionsWrapperRef = React.useRef<HTMLDivElement>(null);
364
- const scrollPerformedRef = React.useRef(false);
297
+ const selectInputRef = useExternRef(getSelectInputRef);
365
298
 
366
- const [focusedOptionIndex, setFocusedOptionIndex] = React.useState<number | undefined>(-1);
367
- const [isControlledOutside, setIsControlledOutside] = React.useState(props.value !== undefined);
368
- const [inputValue, setInputValue] = React.useState('');
369
- const [[nativeSelectValue, prevNativeSelectValue], setNativeSelectValue] =
370
- useStateWithPrev<NativeSelectValue>(() => {
371
- if (props.value !== undefined) {
372
- return remapFromSelectValueToNativeValue(props.value);
373
- }
374
- if (defaultValue !== undefined) {
375
- return remapFromSelectValueToNativeValue(defaultValue);
376
- }
377
- return NOT_SELECTED.NATIVE;
378
- });
299
+ const propsValue = React.useMemo<SelectValue | undefined>(() => {
300
+ if (props.value === undefined) {
301
+ return undefined;
302
+ }
303
+ return getOptionByValue(options, props.value)?.value ?? null;
304
+ }, [options, props.value]);
379
305
 
306
+ const [isControlledOutside, setIsControlledOutside] = React.useState(props.value !== undefined);
380
307
  const [popperPlacement, setPopperPlacement] = React.useState<Placement>(popupDirection);
381
308
 
382
- const options = React.useMemo(() => {
383
- return filter(optionsProp, inputValue, filterFn);
384
- }, [filterFn, inputValue, optionsProp]);
309
+ const {
310
+ nativeSelectValue,
311
+ setNativeSelectValue,
312
+ selectedOptionValue,
313
+ setSelectedOptionValue,
314
+ onNativeSelectChange,
315
+ } = useSelectedOptionController({
316
+ value: propsValue,
317
+ defaultValue,
318
+ isControlledOutside,
319
+ allowClearButton,
320
+ onChange,
321
+ });
385
322
 
386
- const [selectedOptionIndex, setSelectedOptionIndex] = React.useState<number | undefined>(
387
- findSelectedIndex(options, props.value ?? defaultValue ?? null),
323
+ const selected = React.useMemo(
324
+ () => options.find((option) => option.value === selectedOptionValue),
325
+ [options, selectedOptionValue],
388
326
  );
389
327
 
328
+ const { inputValue, onInputChange, resetInputValue, resetInputValueBySelectedOption } =
329
+ useInputValueController({
330
+ options,
331
+ accessible,
332
+ selectedValue: selectedOptionValue,
333
+ onInputChange: onInputChangeProp,
334
+ });
335
+
336
+ const filteredOptions = React.useMemo(
337
+ () => filter(options, searchable ? inputValue : '', filterFn),
338
+ [filterFn, inputValue, options, searchable],
339
+ );
340
+
341
+ const { scrollToElement, optionsWrapperRef, scrollBoxRef } = useScrollListController();
342
+
343
+ const {
344
+ focusedOptionValue,
345
+ setFocusedOptionValue,
346
+ resetFocusedOption,
347
+ focusOptionByIndex,
348
+ focusOption,
349
+ selectFocusedValue,
350
+ } = useFocusedOptionController({
351
+ selectedOptionValue,
352
+ filteredOptions,
353
+ scrollToElement,
354
+ });
355
+
356
+ const scrollToSelectedOption = () => {
357
+ scrollToElement(findSelectedIndex(filteredOptions, selectedOptionValue), true);
358
+ };
359
+
360
+ const { opened, open, close, toggleOpened } = useDropdownOpenedController({
361
+ onOpen: callMultiple(selectFocusedValue, onOpen),
362
+ onOpened: scrollToSelectedOption,
363
+ onClose,
364
+ onClosed: accessible ? resetInputValueBySelectedOption : resetInputValue,
365
+ });
366
+
390
367
  React.useEffect(
391
- function updateOptionsIndexes() {
368
+ function updateOptionsValue() {
392
369
  const value =
393
- props.value !== undefined
394
- ? props.value
370
+ propsValue !== undefined
371
+ ? propsValue
395
372
  : remapFromNativeValueToSelectValue(nativeSelectValue);
396
-
397
- const selectedIndex = findSelectedIndex(options, value);
398
- setSelectedOptionIndex(selectedIndex);
399
- setFocusedOptionIndex(selectedIndex);
373
+ setSelectedOptionValue(value);
374
+ setFocusedOptionValue(value);
400
375
  },
401
- [props.value, nativeSelectValue, options, filterFn],
376
+ [propsValue, nativeSelectValue, setFocusedOptionValue, setSelectedOptionValue],
402
377
  );
403
378
 
404
379
  React.useEffect(
405
380
  function syncIsControlledState() {
406
381
  setIsControlledOutside((oldIsControlled) => {
407
- const newIsControlled = props.value !== undefined;
382
+ const newIsControlled = propsValue !== undefined;
408
383
  checkMixControlledAndUncontrolledState(oldIsControlled, newIsControlled);
409
384
  return newIsControlled;
410
385
  });
411
386
  },
412
- [props.value],
413
- );
414
-
415
- React.useEffect(
416
- function syncNativeSelectValueWithPropValue() {
417
- if (props.value !== undefined) {
418
- setNativeSelectValue(remapFromSelectValueToNativeValue(props.value));
419
- }
420
- },
421
- [props.value, setNativeSelectValue],
387
+ [propsValue],
422
388
  );
423
389
 
424
390
  useIsomorphicLayoutEffect(() => {
425
391
  if (
426
- options.some(({ value }) => nativeSelectValue === value) ||
392
+ filteredOptions.some(({ value }) => nativeSelectValue === value) ||
427
393
  (allowClearButton && nativeSelectValue === NOT_SELECTED.NATIVE)
428
394
  ) {
429
395
  const event = new Event('change', { bubbles: true });
@@ -432,14 +398,6 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
432
398
  }
433
399
  }, [nativeSelectValue]);
434
400
 
435
- const selected = React.useMemo(() => {
436
- if (!options.length) {
437
- return null;
438
- }
439
-
440
- return selectedOptionIndex !== undefined ? options[selectedOptionIndex] : undefined;
441
- }, [options, selectedOptionIndex]);
442
-
443
401
  const openedClassNames = React.useMemo(
444
402
  () =>
445
403
  (opened &&
@@ -449,150 +407,40 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
449
407
  [dropdownOffsetDistance, opened, popperPlacement],
450
408
  );
451
409
 
452
- const scrollToElement = React.useCallback((index: number, center = false) => {
453
- const dropdown = scrollBoxRef.current;
454
- const optionsWrapper = optionsWrapperRef.current;
455
- const item =
456
- dropdown && optionsWrapper ? (optionsWrapper.children[index] as HTMLElement) : null;
457
-
458
- if (!item || !dropdown) {
459
- return;
460
- }
461
-
462
- const dropdownHeight = dropdown.offsetHeight;
463
- const scrollTop = dropdown.scrollTop;
464
- const itemTop = item.offsetTop;
465
- const itemHeight = item.offsetHeight;
466
-
467
- if (center) {
468
- dropdown.scrollTop = itemTop - dropdownHeight / 2 + itemHeight / 2;
469
- } else if (itemTop + itemHeight > dropdownHeight + scrollTop) {
470
- dropdown.scrollTop = itemTop - dropdownHeight + itemHeight;
471
- } else if (itemTop < scrollTop) {
472
- dropdown.scrollTop = itemTop;
473
- }
474
- }, []);
475
-
476
- const focusOptionByIndex = React.useCallback(
477
- (index: number | undefined, scrollTo = true) => {
478
- if (index === undefined || index < 0 || index > (options.length ?? 0) - 1) {
479
- return;
480
- }
481
-
482
- const option = options[index];
483
-
484
- if (option?.disabled) {
485
- return;
486
- }
487
-
488
- if (scrollTo) {
489
- scrollToElement(index);
490
- }
491
-
492
- setFocusedOptionIndex(index);
493
- },
494
- [options, scrollToElement],
495
- );
496
-
497
- const isValidIndex = React.useCallback(
498
- (index: number) => {
499
- return index >= 0 && index < (options.length ?? 0);
500
- },
501
- [options.length],
502
- );
503
-
504
- useIsomorphicLayoutEffect(() => {
505
- if (!opened) {
506
- scrollPerformedRef.current = false;
507
- return;
508
- }
509
-
510
- if (scrollPerformedRef.current) {
511
- return;
512
- }
513
-
514
- const isIndexValid = selectedOptionIndex !== undefined && isValidIndex(selectedOptionIndex);
515
-
516
- if (scrollBoxRef.current && isIndexValid) {
517
- scrollPerformedRef.current = true;
518
- scrollToElement(selectedOptionIndex, true);
519
- }
520
- }, [opened, selectedOptionIndex, scrollToElement, isValidIndex]);
521
-
522
- const [keyboardInput, setKeyboardInput] = React.useState('');
523
- const resetKeyboardInput = React.useCallback(() => {
524
- setKeyboardInput('');
525
- }, []);
526
-
527
- const resetFocusedOption = React.useCallback(() => {
528
- setFocusedOptionIndex(-1);
529
- }, []);
530
-
531
- const onKeyboardInput = React.useCallback(
532
- (key: string) => {
533
- if (!opened) {
534
- setOpened(true);
535
- }
536
- resetFocusedOption();
537
- const fullInput = keyboardInput + key;
538
-
539
- setKeyboardInput(fullInput);
540
- },
541
- [keyboardInput, opened, resetFocusedOption],
542
- );
543
-
544
- const close = React.useCallback(() => {
545
- resetKeyboardInput();
546
-
547
- setInputValue('');
548
- setOpened(false);
549
- resetFocusedOption();
550
- onClose?.();
551
- }, [onClose, resetKeyboardInput, resetFocusedOption]);
552
-
553
410
  const selectOption = React.useCallback(
554
- (index: number) => {
555
- const item = options[index];
556
- setNativeSelectValue(item?.value ?? NOT_SELECTED.NATIVE);
411
+ (value: Exclude<SelectValue, null>) => {
412
+ setNativeSelectValue(value ?? NOT_SELECTED.NATIVE);
557
413
  close();
558
414
 
559
415
  const shouldTriggerOnChangeWhenControlledAndInnerValueIsOutOfSync =
560
- isControlledOutside &&
561
- props.value !== nativeSelectValue &&
562
- nativeSelectValue === item?.value;
416
+ isControlledOutside && propsValue !== nativeSelectValue && nativeSelectValue === value;
563
417
 
564
418
  if (shouldTriggerOnChangeWhenControlledAndInnerValueIsOutOfSync) {
565
419
  const event = new Event('change', { bubbles: true });
566
420
  selectElRef.current?.dispatchEvent(event);
567
421
  }
568
422
  },
569
- [
570
- close,
571
- options,
572
- selectElRef,
573
- isControlledOutside,
574
- props.value,
575
- nativeSelectValue,
576
- setNativeSelectValue,
577
- ],
423
+ [close, setNativeSelectValue, isControlledOutside, propsValue, nativeSelectValue, selectElRef],
578
424
  );
579
425
 
580
426
  const selectFocused = React.useCallback(() => {
581
- if (focusedOptionIndex === undefined || !isValidIndex(focusedOptionIndex)) {
427
+ if (focusedOptionValue === null) {
582
428
  return;
583
429
  }
584
430
 
585
- selectOption(focusedOptionIndex);
586
- }, [focusedOptionIndex, isValidIndex, selectOption]);
587
-
588
- const open = React.useCallback(() => {
589
- setOpened(true);
590
- setFocusedOptionIndex(selectedOptionIndex);
431
+ selectOption(focusedOptionValue);
432
+ }, [focusedOptionValue, selectOption]);
591
433
 
592
- if (typeof onOpen === 'function') {
593
- onOpen();
594
- }
595
- }, [onOpen, selectedOptionIndex]);
434
+ const onInputKeyDown = useInputKeyboardController({
435
+ opened,
436
+ open,
437
+ close,
438
+ resetFocusedOption,
439
+ selectFocused,
440
+ focusOption,
441
+ scrollBoxRef,
442
+ onInputKeyDown: onInputKeyDownProp,
443
+ });
596
444
 
597
445
  const onBlur = React.useCallback(() => {
598
446
  close();
@@ -605,174 +453,19 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
605
453
  selectElRef.current?.dispatchEvent(event);
606
454
  }, [selectElRef]);
607
455
 
608
- const onClick = React.useCallback(() => {
609
- if (opened) {
610
- close();
611
- } else {
612
- open();
613
- }
614
- }, [close, open, opened]);
615
-
616
- const handleKeyUp = React.useMemo(() => debounce(resetKeyboardInput, 1000), [resetKeyboardInput]);
617
-
618
- const focusOption = React.useCallback(
619
- (type: 'next' | 'prev') => {
620
- let index = focusedOptionIndex;
621
-
622
- if (type === 'next') {
623
- const nextIndex = findIndexAfter(options, index);
624
- index = nextIndex === -1 ? findIndexAfter(options) : nextIndex; // Следующий за index или первый валидный до index
625
- } else if (type === 'prev') {
626
- const beforeIndex = findIndexBefore(options, index);
627
- index = beforeIndex === -1 ? findIndexBefore(options) : beforeIndex; // Предшествующий index или последний валидный после index
628
- }
629
-
630
- focusOptionByIndex(index);
631
- },
632
- [focusOptionByIndex, focusedOptionIndex, options],
633
- );
634
-
635
- const onNativeSelectChange: React.ChangeEventHandler<HTMLSelectElement> = (e) => {
636
- // для ситуаций, когда в опциях value это string а value/defaultValue это number
637
- // и наоборот, приводим значение nativeSelectValue из стейта к строке.
638
- // ведь nativeSelect всегда возвращает string в onChange, а пользователь
639
- // может использовать number для опций
640
- //
641
- // native select всегда возвращает string в качестве value в onChange
642
- // Когда селект контролируемый, то пользователь, в onChange может сохранить в свой стейт строку (например '3'), хотя
643
- // в качестве value опции может использовать число (3),
644
- // тогда строчное значение value ('3') из стейта пользователя
645
- // будет передано в CustomSelect, и после синхронизации nativeSelectValue (3) и props.value ('3') и после клика на уже выбранную опцию (3),
646
- // когда nativeSelectValue обновится на значение опции (число 3),
647
- // сравнение nativeSelectValue (3) и prevNativeSelectValue ('3') может не сработать лишь из-за того, что они в разных типах.
648
- const convertedNativeSelectValue =
649
- typeof nativeSelectValue === 'number' &&
650
- (typeof props.value === 'string' || typeof prevNativeSelectValue === 'string')
651
- ? String(nativeSelectValue)
652
- : nativeSelectValue;
653
-
654
- const isCalledWithSameControlledOptionValue =
655
- isControlledOutside &&
656
- props.value === remapFromNativeValueToSelectValue(convertedNativeSelectValue);
657
-
658
- const isNativeValueChanged =
659
- convertedNativeSelectValue !== prevNativeSelectValue && prevNativeSelectValue !== undefined;
660
-
661
- const isTriggeredByClearButton = allowClearButton && nativeSelectValue === NOT_SELECTED.NATIVE;
662
-
663
- const shouldCallOnChange =
664
- !isCalledWithSameControlledOptionValue && (isNativeValueChanged || isTriggeredByClearButton);
665
-
666
- if (!shouldCallOnChange) {
667
- return;
668
- }
669
-
670
- const remappedNativeValue = remapFromNativeValueToSelectValue(e.currentTarget.value);
671
-
672
- if (e.target.value === NOT_SELECTED.NATIVE) {
673
- e.target.value = '';
674
- }
675
- if (e.currentTarget.value === NOT_SELECTED.NATIVE) {
676
- e.currentTarget.value = '';
677
- }
678
-
679
- onChange?.(e, remappedNativeValue);
680
- };
681
-
682
- const onInputChange: React.ChangeEventHandler<HTMLInputElement> = React.useCallback(
683
- (e) => {
684
- onInputChangeProp && onInputChangeProp(e);
685
- setInputValue(e.target.value);
686
- },
687
- [onInputChangeProp],
688
- );
689
-
690
- const areOptionsShown = React.useCallback(() => {
691
- return scrollBoxRef.current !== null;
692
- }, []);
693
-
694
- const handleKeyDownSelect = React.useCallback(
695
- (event: React.KeyboardEvent) => {
696
- if (event.key.length === 1 && event.key !== ' ') {
697
- onKeyboardInput(event.key);
698
- return;
699
- }
700
-
701
- ['ArrowUp', 'ArrowDown', 'Escape', 'Enter'].includes(event.key) &&
702
- areOptionsShown() &&
703
- event.preventDefault();
704
-
705
- switch (event.key) {
706
- case 'ArrowUp':
707
- if (opened) {
708
- areOptionsShown() && focusOption('prev');
709
- } else {
710
- open();
711
- }
712
- break;
713
- case 'ArrowDown':
714
- if (opened) {
715
- areOptionsShown() && focusOption('next');
716
- } else {
717
- open();
718
- }
719
- break;
720
- case 'Escape':
721
- close();
722
- break;
723
- case 'Backspace':
724
- case 'Delete': {
725
- if (!opened) {
726
- setOpened(true);
727
- }
728
- resetFocusedOption();
729
-
730
- break;
731
- }
732
- case 'Enter':
733
- case 'Spacebar':
734
- case ' ':
735
- if (opened) {
736
- areOptionsShown() && selectFocused();
737
- } else {
738
- open();
739
- }
740
- break;
741
- }
742
- },
743
- [
744
- areOptionsShown,
745
- close,
746
- focusOption,
747
- onKeyboardInput,
748
- open,
749
- opened,
750
- selectFocused,
751
- resetFocusedOption,
752
- ],
753
- );
754
-
755
- const handleInputKeydown = React.useCallback(
756
- (event: React.KeyboardEvent) => {
757
- onInputKeyDown?.(event, opened);
758
- },
759
- [opened, onInputKeyDown],
760
- );
761
- const _onInputKeyDown = callMultiple(handleKeyDownSelect, handleInputKeydown);
762
-
763
456
  const handleOptionClick = React.useCallback(
764
457
  (e: React.MouseEvent<HTMLElement>) => {
765
458
  const index = Array.prototype.indexOf.call(
766
459
  e.currentTarget.parentNode?.children,
767
460
  e.currentTarget,
768
461
  );
769
- const option = options[index];
462
+ const option = filteredOptions[index];
770
463
 
771
464
  if (option && !option.disabled) {
772
- selectOption(index);
465
+ selectOption(option.value);
773
466
  }
774
467
  },
775
- [options, selectOption],
468
+ [filteredOptions, selectOption],
776
469
  );
777
470
 
778
471
  const lastMousePositionRef = React.useRef<MousePosition>({ x: 0, y: 0 });
@@ -788,8 +481,8 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
788
481
  const popupAriaId = React.useId();
789
482
  const renderOption = React.useCallback(
790
483
  (option: OptionInterfaceT, index: number) => {
791
- const hovered = index === focusedOptionIndex;
792
- const selected = index === selectedOptionIndex;
484
+ const hovered = option.value === focusedOptionValue;
485
+ const selected = option.value === selectedOptionValue;
793
486
 
794
487
  return (
795
488
  <React.Fragment key={`${typeof option.value}-${option.value}`}>
@@ -800,7 +493,7 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
800
493
  selected,
801
494
  disabled: option.disabled,
802
495
  onClick: handleOptionClick,
803
- onMouseDown: handleOptionDown,
496
+ onMouseDown: preventDefault,
804
497
  // Используем `onMouseMove` вместо `onMouseEnter/onMouseOver`.
805
498
  // Потому что если при навигации с клавиатуры курсор наведён на
806
499
  // список, то при первом автоматическом скролле списка вызывается событие MouseOver/MouseEnter
@@ -816,19 +509,19 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
816
509
  );
817
510
  },
818
511
  [
819
- focusedOptionIndex,
820
- handleOptionClick,
821
- focusOptionOnMouseMove,
512
+ focusedOptionValue,
513
+ selectedOptionValue,
822
514
  renderOptionProp,
823
- selectedOptionIndex,
515
+ handleOptionClick,
824
516
  popupAriaId,
517
+ focusOptionOnMouseMove,
825
518
  ],
826
519
  );
827
520
 
828
521
  const resolvedContent = React.useMemo(() => {
829
522
  const defaultDropdownContent =
830
- options.length > 0 ? (
831
- <div ref={optionsWrapperRef}>{options.map(renderOption)}</div>
523
+ filteredOptions.length > 0 ? (
524
+ <div ref={optionsWrapperRef}>{filteredOptions.map(renderOption)}</div>
832
525
  ) : (
833
526
  <Footnote className={styles.empty}>{emptyText}</Footnote>
834
527
  );
@@ -838,61 +531,25 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
838
531
  } else {
839
532
  return defaultDropdownContent;
840
533
  }
841
- }, [emptyText, options, renderDropdown, renderOption]);
842
-
843
- const selectInputRef = useExternRef(getSelectInputRef);
844
-
845
- const controlledValueSet = isControlledOutside && props.value !== NOT_SELECTED.CUSTOM;
846
- const uncontrolledValueSet = !isControlledOutside && nativeSelectValue !== NOT_SELECTED.NATIVE;
847
- const clearButtonShown =
848
- allowClearButton && !opened && (controlledValueSet || uncontrolledValueSet);
849
-
850
- const clearButton = React.useMemo(() => {
851
- if (!clearButtonShown) {
852
- return null;
853
- }
854
-
855
- return (
856
- <ClearButton
857
- className={iconProp === undefined ? styles.clearIcon : undefined}
858
- onClick={function clearSelectState() {
859
- setNativeSelectValue(NOT_SELECTED.NATIVE);
860
- setInputValue('');
861
- selectInputRef.current && selectInputRef.current.focus();
862
- }}
863
- disabled={restProps.disabled}
864
- data-testid={clearButtonTestId}
865
- />
866
- );
867
- }, [
868
- clearButtonShown,
534
+ }, [emptyText, filteredOptions, optionsWrapperRef, renderDropdown, renderOption]);
535
+
536
+ const afterItems = useAfterItems({
537
+ value: propsValue,
538
+ nativeSelectValue,
539
+ isControlledOutside,
540
+ opened,
541
+ allowClearButton,
869
542
  ClearButton,
870
- iconProp,
871
- restProps.disabled,
543
+ onClearButtonClick: () => {
544
+ setNativeSelectValue(NOT_SELECTED.NATIVE);
545
+ resetInputValue();
546
+ selectInputRef.current && selectInputRef.current.focus();
547
+ },
872
548
  clearButtonTestId,
873
- setNativeSelectValue,
874
- selectInputRef,
875
- ]);
876
-
877
- const icon = React.useMemo(() => {
878
- if (iconProp !== undefined) {
879
- return iconProp;
880
- }
881
-
882
- return (
883
- <DropdownIcon
884
- className={clearButtonShown ? styles.dropdownIcon : undefined}
885
- opened={opened}
886
- />
887
- );
888
- }, [clearButtonShown, iconProp, opened]);
889
-
890
- const afterIcons = !readOnly && (icon || clearButtonShown) && (
891
- <React.Fragment>
892
- {clearButton}
893
- {icon}
894
- </React.Fragment>
895
- );
549
+ disabled: restProps.disabled,
550
+ readOnly,
551
+ icon: iconProp,
552
+ });
896
553
 
897
554
  const { document } = useDOM();
898
555
  const passClickAndFocusToInputOnClick = React.useCallback(
@@ -935,17 +592,11 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
935
592
  }
936
593
  };
937
594
 
938
- const ariaActiveDescendantOptionIndex: undefined | number =
939
- focusedOptionIndex !== -1 ? focusedOptionIndex : undefined;
940
- const ariaActiveDescendantId =
941
- ariaActiveDescendantOptionIndex !== undefined
942
- ? options[ariaActiveDescendantOptionIndex] && options[ariaActiveDescendantOptionIndex].value
943
- : null;
595
+ const ariaActiveDescendantId = focusedOptionValue !== null ? focusedOptionValue : undefined;
944
596
 
945
597
  const selectInputAriaProps: React.HTMLAttributes<HTMLElement> = {
946
598
  'role': 'combobox',
947
599
  'aria-controls': popupAriaId,
948
- 'aria-owns': popupAriaId,
949
600
  'aria-expanded': opened,
950
601
  'aria-activedescendant':
951
602
  ariaActiveDescendantId && opened ? `${popupAriaId}-${ariaActiveDescendantId}` : undefined,
@@ -954,8 +605,6 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
954
605
  'aria-autocomplete': 'none',
955
606
  };
956
607
 
957
- const focusWithin = useFocusWithin(handleRootRef);
958
-
959
608
  const resetOptionFocusOnMouseLeave = React.useCallback(
960
609
  (event: React.MouseEvent) => {
961
610
  // В Хроме eсли мышка пользователя находится над инпутом селекта,
@@ -983,9 +632,6 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
983
632
  lastMousePositionRef.current = { x: e.clientX, y: e.clientY };
984
633
  }}
985
634
  >
986
- {focusWithin && selected && !opened && (
987
- <VisuallyHidden aria-live="polite">{selected.label}</VisuallyHidden>
988
- )}
989
635
  <CustomSelectInput
990
636
  autoComplete="off"
991
637
  autoCapitalize="none"
@@ -999,17 +645,25 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
999
645
  className={openedClassNames}
1000
646
  readOnly={readOnly || !searchable}
1001
647
  fetching={fetching}
648
+ searchable={searchable}
649
+ accessible={accessible}
1002
650
  value={inputValue}
1003
- onKeyUp={handleKeyUp}
1004
- onKeyDown={!readOnly ? _onInputKeyDown : undefined}
651
+ onKeyDown={!readOnly ? onInputKeyDown : undefined}
1005
652
  onChange={onInputChange}
1006
- onClick={!readOnly ? onClick : undefined}
653
+ onClick={!readOnly ? toggleOpened : undefined}
1007
654
  before={before}
1008
- after={afterIcons}
655
+ after={afterItems}
1009
656
  selectType={selectType}
1010
657
  >
1011
658
  {selected?.label}
1012
659
  </CustomSelectInput>
660
+
661
+ <FetchingStatus
662
+ fetching={fetching}
663
+ options={filteredOptions}
664
+ fetchingInProgressLabel={fetchingInProgressLabel}
665
+ fetchingCompletedLabel={fetchingCompletedLabel}
666
+ />
1013
667
  <select
1014
668
  tabIndex={-1}
1015
669
  ref={selectElRef}
@@ -1027,7 +681,7 @@ export function CustomSelect<OptionInterfaceT extends CustomSelectOptionInterfac
1027
681
  {(allowClearButton || nativeSelectValue === NOT_SELECTED.NATIVE) && (
1028
682
  <option key={NOT_SELECTED.NATIVE} value={NOT_SELECTED.NATIVE} />
1029
683
  )}
1030
- {optionsProp.map((item) => (
684
+ {options.map((item) => (
1031
685
  <option key={`${item.value}`} value={item.value} />
1032
686
  ))}
1033
687
  </select>