@cloud-ru/ds-list 1.0.0

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 (439) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +201 -0
  3. package/README.md +1413 -0
  4. package/dist/cjs/components/Items/AccordionItem/AccordionItem.d.ts +4 -0
  5. package/dist/cjs/components/Items/AccordionItem/AccordionItem.js +37 -0
  6. package/dist/cjs/components/Items/AccordionItem/index.d.ts +1 -0
  7. package/dist/cjs/components/Items/AccordionItem/index.js +17 -0
  8. package/dist/cjs/components/Items/BaseItem/BaseItem.d.ts +24 -0
  9. package/dist/cjs/components/Items/BaseItem/BaseItem.js +118 -0
  10. package/dist/cjs/components/Items/BaseItem/constants.d.ts +3 -0
  11. package/dist/cjs/components/Items/BaseItem/constants.js +8 -0
  12. package/dist/cjs/components/Items/BaseItem/index.d.ts +1 -0
  13. package/dist/cjs/components/Items/BaseItem/index.js +17 -0
  14. package/dist/cjs/components/Items/BaseItem/styles.module.css +312 -0
  15. package/dist/cjs/components/Items/GroupSelectItem/GroupSelectItem.d.ts +4 -0
  16. package/dist/cjs/components/Items/GroupSelectItem/GroupSelectItem.js +22 -0
  17. package/dist/cjs/components/Items/GroupSelectItem/index.d.ts +1 -0
  18. package/dist/cjs/components/Items/GroupSelectItem/index.js +17 -0
  19. package/dist/cjs/components/Items/NextListItem/NextListItem.d.ts +2 -0
  20. package/dist/cjs/components/Items/NextListItem/NextListItem.js +71 -0
  21. package/dist/cjs/components/Items/NextListItem/constants.d.ts +2 -0
  22. package/dist/cjs/components/Items/NextListItem/constants.js +13 -0
  23. package/dist/cjs/components/Items/NextListItem/index.d.ts +1 -0
  24. package/dist/cjs/components/Items/NextListItem/index.js +17 -0
  25. package/dist/cjs/components/Items/NextListItem/types.d.ts +4 -0
  26. package/dist/cjs/components/Items/NextListItem/types.js +2 -0
  27. package/dist/cjs/components/Items/PinGroupItem/PinGroupItem.d.ts +7 -0
  28. package/dist/cjs/components/Items/PinGroupItem/PinGroupItem.js +27 -0
  29. package/dist/cjs/components/Items/PinGroupItem/index.d.ts +1 -0
  30. package/dist/cjs/components/Items/PinGroupItem/index.js +17 -0
  31. package/dist/cjs/components/Items/PinGroupItem/styles.module.css +12 -0
  32. package/dist/cjs/components/Items/SearchItem/SearchItem.d.ts +17 -0
  33. package/dist/cjs/components/Items/SearchItem/SearchItem.js +28 -0
  34. package/dist/cjs/components/Items/SearchItem/index.d.ts +1 -0
  35. package/dist/cjs/components/Items/SearchItem/index.js +17 -0
  36. package/dist/cjs/components/Items/SearchItem/styles.module.css +13 -0
  37. package/dist/cjs/components/Items/SimpleItem/components/DragHandle/DragHandle.d.ts +7 -0
  38. package/dist/cjs/components/Items/SimpleItem/components/DragHandle/DragHandle.js +20 -0
  39. package/dist/cjs/components/Items/SimpleItem/components/DragHandle/index.d.ts +1 -0
  40. package/dist/cjs/components/Items/SimpleItem/components/DragHandle/index.js +17 -0
  41. package/dist/cjs/components/Items/SimpleItem/components/OverlayDragHandle/OverlayDragHandle.d.ts +2 -0
  42. package/dist/cjs/components/Items/SimpleItem/components/OverlayDragHandle/OverlayDragHandle.js +9 -0
  43. package/dist/cjs/components/Items/SimpleItem/components/OverlayDragHandle/index.d.ts +1 -0
  44. package/dist/cjs/components/Items/SimpleItem/components/OverlayDragHandle/index.js +17 -0
  45. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.d.ts +19 -0
  46. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.js +52 -0
  47. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlock/index.d.ts +1 -0
  48. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlock/index.js +17 -0
  49. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.d.ts +15 -0
  50. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.js +19 -0
  51. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/index.d.ts +1 -0
  52. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/index.js +17 -0
  53. package/dist/cjs/components/Items/SimpleItem/components/SimpleItem/SimpleItem.d.ts +11 -0
  54. package/dist/cjs/components/Items/SimpleItem/components/SimpleItem/SimpleItem.js +48 -0
  55. package/dist/cjs/components/Items/SimpleItem/components/SimpleItem/index.d.ts +1 -0
  56. package/dist/cjs/components/Items/SimpleItem/components/SimpleItem/index.js +17 -0
  57. package/dist/cjs/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.d.ts +15 -0
  58. package/dist/cjs/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.js +19 -0
  59. package/dist/cjs/components/Items/SimpleItem/components/SimpleItemOverlay/index.d.ts +1 -0
  60. package/dist/cjs/components/Items/SimpleItem/components/SimpleItemOverlay/index.js +17 -0
  61. package/dist/cjs/components/Items/SimpleItem/components/index.d.ts +4 -0
  62. package/dist/cjs/components/Items/SimpleItem/components/index.js +20 -0
  63. package/dist/cjs/components/Items/SimpleItem/constants.d.ts +7 -0
  64. package/dist/cjs/components/Items/SimpleItem/constants.js +9 -0
  65. package/dist/cjs/components/Items/SimpleItem/index.d.ts +2 -0
  66. package/dist/cjs/components/Items/SimpleItem/index.js +18 -0
  67. package/dist/cjs/components/Items/SimpleItem/styles.module.css +96 -0
  68. package/dist/cjs/components/Items/SimpleItem/types.d.ts +3 -0
  69. package/dist/cjs/components/Items/SimpleItem/types.js +2 -0
  70. package/dist/cjs/components/Items/SimpleItem/utils.d.ts +6 -0
  71. package/dist/cjs/components/Items/SimpleItem/utils.js +11 -0
  72. package/dist/cjs/components/Items/hooks.d.ts +23 -0
  73. package/dist/cjs/components/Items/hooks.js +130 -0
  74. package/dist/cjs/components/Items/index.d.ts +5 -0
  75. package/dist/cjs/components/Items/index.js +21 -0
  76. package/dist/cjs/components/Items/styles.module.css +168 -0
  77. package/dist/cjs/components/Items/types.d.ts +168 -0
  78. package/dist/cjs/components/Items/types.js +2 -0
  79. package/dist/cjs/components/Items/utils.d.ts +52 -0
  80. package/dist/cjs/components/Items/utils.js +218 -0
  81. package/dist/cjs/components/Lists/Droplist/DropList.d.ts +21 -0
  82. package/dist/cjs/components/Lists/Droplist/DropList.js +36 -0
  83. package/dist/cjs/components/Lists/Droplist/constants.d.ts +8 -0
  84. package/dist/cjs/components/Lists/Droplist/constants.js +10 -0
  85. package/dist/cjs/components/Lists/Droplist/index.d.ts +1 -0
  86. package/dist/cjs/components/Lists/Droplist/index.js +17 -0
  87. package/dist/cjs/components/Lists/List/List.d.ts +61 -0
  88. package/dist/cjs/components/Lists/List/List.js +62 -0
  89. package/dist/cjs/components/Lists/List/index.d.ts +1 -0
  90. package/dist/cjs/components/Lists/List/index.js +17 -0
  91. package/dist/cjs/components/Lists/ListPrivate/ListPrivate.d.ts +18 -0
  92. package/dist/cjs/components/Lists/ListPrivate/ListPrivate.js +301 -0
  93. package/dist/cjs/components/Lists/ListPrivate/constants.d.ts +7 -0
  94. package/dist/cjs/components/Lists/ListPrivate/constants.js +19 -0
  95. package/dist/cjs/components/Lists/ListPrivate/index.d.ts +1 -0
  96. package/dist/cjs/components/Lists/ListPrivate/index.js +17 -0
  97. package/dist/cjs/components/Lists/ListPrivate/styles.module.css +80 -0
  98. package/dist/cjs/components/Lists/contexts/CollapseProvider.d.ts +17 -0
  99. package/dist/cjs/components/Lists/contexts/CollapseProvider.js +10 -0
  100. package/dist/cjs/components/Lists/contexts/FocusListProvider.d.ts +9 -0
  101. package/dist/cjs/components/Lists/contexts/FocusListProvider.js +9 -0
  102. package/dist/cjs/components/Lists/contexts/NewListProvider.d.ts +33 -0
  103. package/dist/cjs/components/Lists/contexts/NewListProvider.js +23 -0
  104. package/dist/cjs/components/Lists/contexts/OpenListProvider.d.ts +6 -0
  105. package/dist/cjs/components/Lists/contexts/OpenListProvider.js +10 -0
  106. package/dist/cjs/components/Lists/contexts/SelectionProvider.d.ts +74 -0
  107. package/dist/cjs/components/Lists/contexts/SelectionProvider.js +90 -0
  108. package/dist/cjs/components/Lists/contexts/index.d.ts +5 -0
  109. package/dist/cjs/components/Lists/contexts/index.js +21 -0
  110. package/dist/cjs/components/Lists/hooks.d.ts +83 -0
  111. package/dist/cjs/components/Lists/hooks.js +242 -0
  112. package/dist/cjs/components/Lists/index.d.ts +5 -0
  113. package/dist/cjs/components/Lists/index.js +21 -0
  114. package/dist/cjs/components/Lists/styles.module.css +65 -0
  115. package/dist/cjs/components/Lists/types.d.ts +200 -0
  116. package/dist/cjs/components/Lists/types.js +2 -0
  117. package/dist/cjs/components/Lists/utils.d.ts +8 -0
  118. package/dist/cjs/components/Lists/utils.js +31 -0
  119. package/dist/cjs/components/index.d.ts +2 -0
  120. package/dist/cjs/components/index.js +18 -0
  121. package/dist/cjs/constants.d.ts +48 -0
  122. package/dist/cjs/constants.js +51 -0
  123. package/dist/cjs/helperComponents/CollapseBlockPrivate/CollapseBlockPrivate.d.ts +9 -0
  124. package/dist/cjs/helperComponents/CollapseBlockPrivate/CollapseBlockPrivate.js +15 -0
  125. package/dist/cjs/helperComponents/CollapseBlockPrivate/index.d.ts +1 -0
  126. package/dist/cjs/helperComponents/CollapseBlockPrivate/index.js +17 -0
  127. package/dist/cjs/helperComponents/CollapseBlockPrivate/styles.module.css +27 -0
  128. package/dist/cjs/helperComponents/DesktopDroplist/DesktopDroplist.d.ts +7 -0
  129. package/dist/cjs/helperComponents/DesktopDroplist/DesktopDroplist.js +142 -0
  130. package/dist/cjs/helperComponents/DesktopDroplist/index.d.ts +1 -0
  131. package/dist/cjs/helperComponents/DesktopDroplist/index.js +17 -0
  132. package/dist/cjs/helperComponents/HiddenTabButton/HiddenTabButton.d.ts +7 -0
  133. package/dist/cjs/helperComponents/HiddenTabButton/HiddenTabButton.js +20 -0
  134. package/dist/cjs/helperComponents/HiddenTabButton/index.d.ts +1 -0
  135. package/dist/cjs/helperComponents/HiddenTabButton/index.js +17 -0
  136. package/dist/cjs/helperComponents/HiddenTabButton/styles.module.css +9 -0
  137. package/dist/cjs/helperComponents/ItemContent/ItemContent.d.ts +17 -0
  138. package/dist/cjs/helperComponents/ItemContent/ItemContent.js +27 -0
  139. package/dist/cjs/helperComponents/ItemContent/index.d.ts +1 -0
  140. package/dist/cjs/helperComponents/ItemContent/index.js +17 -0
  141. package/dist/cjs/helperComponents/ItemContent/styles.module.css +139 -0
  142. package/dist/cjs/helperComponents/ListEmptyState/ListEmptyState.d.ts +16 -0
  143. package/dist/cjs/helperComponents/ListEmptyState/ListEmptyState.js +25 -0
  144. package/dist/cjs/helperComponents/ListEmptyState/hooks.d.ts +10 -0
  145. package/dist/cjs/helperComponents/ListEmptyState/hooks.js +30 -0
  146. package/dist/cjs/helperComponents/ListEmptyState/index.d.ts +2 -0
  147. package/dist/cjs/helperComponents/ListEmptyState/index.js +20 -0
  148. package/dist/cjs/helperComponents/ListEmptyState/styles.module.css +8 -0
  149. package/dist/cjs/helperComponents/MobileDroplist/MobileDroplist.d.ts +9 -0
  150. package/dist/cjs/helperComponents/MobileDroplist/MobileDroplist.js +143 -0
  151. package/dist/cjs/helperComponents/MobileDroplist/MobileDroplist.module.css +16 -0
  152. package/dist/cjs/helperComponents/MobileDroplist/index.d.ts +1 -0
  153. package/dist/cjs/helperComponents/MobileDroplist/index.js +17 -0
  154. package/dist/cjs/helperComponents/MobileDroplist/utils.d.ts +11 -0
  155. package/dist/cjs/helperComponents/MobileDroplist/utils.js +65 -0
  156. package/dist/cjs/helperComponents/Separator/Separator.d.ts +20 -0
  157. package/dist/cjs/helperComponents/Separator/Separator.js +40 -0
  158. package/dist/cjs/helperComponents/Separator/constants.d.ts +3 -0
  159. package/dist/cjs/helperComponents/Separator/constants.js +10 -0
  160. package/dist/cjs/helperComponents/Separator/index.d.ts +1 -0
  161. package/dist/cjs/helperComponents/Separator/index.js +17 -0
  162. package/dist/cjs/helperComponents/Separator/styles.module.css +168 -0
  163. package/dist/cjs/helperComponents/index.d.ts +5 -0
  164. package/dist/cjs/helperComponents/index.js +21 -0
  165. package/dist/cjs/index.d.ts +9 -0
  166. package/dist/cjs/index.js +37 -0
  167. package/dist/cjs/locale/index.d.ts +79 -0
  168. package/dist/cjs/locale/index.js +44 -0
  169. package/dist/cjs/package.json +3 -0
  170. package/dist/cjs/style.css +1113 -0
  171. package/dist/cjs/types.d.ts +38 -0
  172. package/dist/cjs/types.js +2 -0
  173. package/dist/cjs/utils.d.ts +18 -0
  174. package/dist/cjs/utils.js +26 -0
  175. package/dist/esm/components/Items/AccordionItem/AccordionItem.d.ts +4 -0
  176. package/dist/esm/components/Items/AccordionItem/AccordionItem.js +34 -0
  177. package/dist/esm/components/Items/AccordionItem/index.d.ts +1 -0
  178. package/dist/esm/components/Items/AccordionItem/index.js +1 -0
  179. package/dist/esm/components/Items/BaseItem/BaseItem.d.ts +24 -0
  180. package/dist/esm/components/Items/BaseItem/BaseItem.js +112 -0
  181. package/dist/esm/components/Items/BaseItem/constants.d.ts +3 -0
  182. package/dist/esm/components/Items/BaseItem/constants.js +5 -0
  183. package/dist/esm/components/Items/BaseItem/index.d.ts +1 -0
  184. package/dist/esm/components/Items/BaseItem/index.js +1 -0
  185. package/dist/esm/components/Items/BaseItem/styles.module.css +312 -0
  186. package/dist/esm/components/Items/GroupSelectItem/GroupSelectItem.d.ts +4 -0
  187. package/dist/esm/components/Items/GroupSelectItem/GroupSelectItem.js +19 -0
  188. package/dist/esm/components/Items/GroupSelectItem/index.d.ts +1 -0
  189. package/dist/esm/components/Items/GroupSelectItem/index.js +1 -0
  190. package/dist/esm/components/Items/NextListItem/NextListItem.d.ts +2 -0
  191. package/dist/esm/components/Items/NextListItem/NextListItem.js +68 -0
  192. package/dist/esm/components/Items/NextListItem/constants.d.ts +2 -0
  193. package/dist/esm/components/Items/NextListItem/constants.js +10 -0
  194. package/dist/esm/components/Items/NextListItem/index.d.ts +1 -0
  195. package/dist/esm/components/Items/NextListItem/index.js +1 -0
  196. package/dist/esm/components/Items/NextListItem/types.d.ts +4 -0
  197. package/dist/esm/components/Items/NextListItem/types.js +1 -0
  198. package/dist/esm/components/Items/PinGroupItem/PinGroupItem.d.ts +7 -0
  199. package/dist/esm/components/Items/PinGroupItem/PinGroupItem.js +20 -0
  200. package/dist/esm/components/Items/PinGroupItem/index.d.ts +1 -0
  201. package/dist/esm/components/Items/PinGroupItem/index.js +1 -0
  202. package/dist/esm/components/Items/PinGroupItem/styles.module.css +12 -0
  203. package/dist/esm/components/Items/SearchItem/SearchItem.d.ts +17 -0
  204. package/dist/esm/components/Items/SearchItem/SearchItem.js +22 -0
  205. package/dist/esm/components/Items/SearchItem/index.d.ts +1 -0
  206. package/dist/esm/components/Items/SearchItem/index.js +1 -0
  207. package/dist/esm/components/Items/SearchItem/styles.module.css +13 -0
  208. package/dist/esm/components/Items/SimpleItem/components/DragHandle/DragHandle.d.ts +7 -0
  209. package/dist/esm/components/Items/SimpleItem/components/DragHandle/DragHandle.js +14 -0
  210. package/dist/esm/components/Items/SimpleItem/components/DragHandle/index.d.ts +1 -0
  211. package/dist/esm/components/Items/SimpleItem/components/DragHandle/index.js +1 -0
  212. package/dist/esm/components/Items/SimpleItem/components/OverlayDragHandle/OverlayDragHandle.d.ts +2 -0
  213. package/dist/esm/components/Items/SimpleItem/components/OverlayDragHandle/OverlayDragHandle.js +6 -0
  214. package/dist/esm/components/Items/SimpleItem/components/OverlayDragHandle/index.d.ts +1 -0
  215. package/dist/esm/components/Items/SimpleItem/components/OverlayDragHandle/index.js +1 -0
  216. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.d.ts +19 -0
  217. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.js +46 -0
  218. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlock/index.d.ts +1 -0
  219. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlock/index.js +1 -0
  220. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.d.ts +15 -0
  221. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.js +13 -0
  222. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/index.d.ts +1 -0
  223. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/index.js +1 -0
  224. package/dist/esm/components/Items/SimpleItem/components/SimpleItem/SimpleItem.d.ts +11 -0
  225. package/dist/esm/components/Items/SimpleItem/components/SimpleItem/SimpleItem.js +42 -0
  226. package/dist/esm/components/Items/SimpleItem/components/SimpleItem/index.d.ts +1 -0
  227. package/dist/esm/components/Items/SimpleItem/components/SimpleItem/index.js +1 -0
  228. package/dist/esm/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.d.ts +15 -0
  229. package/dist/esm/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.js +13 -0
  230. package/dist/esm/components/Items/SimpleItem/components/SimpleItemOverlay/index.d.ts +1 -0
  231. package/dist/esm/components/Items/SimpleItem/components/SimpleItemOverlay/index.js +1 -0
  232. package/dist/esm/components/Items/SimpleItem/components/index.d.ts +4 -0
  233. package/dist/esm/components/Items/SimpleItem/components/index.js +4 -0
  234. package/dist/esm/components/Items/SimpleItem/constants.d.ts +7 -0
  235. package/dist/esm/components/Items/SimpleItem/constants.js +6 -0
  236. package/dist/esm/components/Items/SimpleItem/index.d.ts +2 -0
  237. package/dist/esm/components/Items/SimpleItem/index.js +2 -0
  238. package/dist/esm/components/Items/SimpleItem/styles.module.css +96 -0
  239. package/dist/esm/components/Items/SimpleItem/types.d.ts +3 -0
  240. package/dist/esm/components/Items/SimpleItem/types.js +1 -0
  241. package/dist/esm/components/Items/SimpleItem/utils.d.ts +6 -0
  242. package/dist/esm/components/Items/SimpleItem/utils.js +8 -0
  243. package/dist/esm/components/Items/hooks.d.ts +23 -0
  244. package/dist/esm/components/Items/hooks.js +125 -0
  245. package/dist/esm/components/Items/index.d.ts +5 -0
  246. package/dist/esm/components/Items/index.js +5 -0
  247. package/dist/esm/components/Items/styles.module.css +168 -0
  248. package/dist/esm/components/Items/types.d.ts +168 -0
  249. package/dist/esm/components/Items/types.js +1 -0
  250. package/dist/esm/components/Items/utils.d.ts +52 -0
  251. package/dist/esm/components/Items/utils.js +203 -0
  252. package/dist/esm/components/Lists/Droplist/DropList.d.ts +21 -0
  253. package/dist/esm/components/Lists/Droplist/DropList.js +32 -0
  254. package/dist/esm/components/Lists/Droplist/constants.d.ts +8 -0
  255. package/dist/esm/components/Lists/Droplist/constants.js +7 -0
  256. package/dist/esm/components/Lists/Droplist/index.d.ts +1 -0
  257. package/dist/esm/components/Lists/Droplist/index.js +1 -0
  258. package/dist/esm/components/Lists/List/List.d.ts +61 -0
  259. package/dist/esm/components/Lists/List/List.js +56 -0
  260. package/dist/esm/components/Lists/List/index.d.ts +1 -0
  261. package/dist/esm/components/Lists/List/index.js +1 -0
  262. package/dist/esm/components/Lists/ListPrivate/ListPrivate.d.ts +18 -0
  263. package/dist/esm/components/Lists/ListPrivate/ListPrivate.js +295 -0
  264. package/dist/esm/components/Lists/ListPrivate/constants.d.ts +7 -0
  265. package/dist/esm/components/Lists/ListPrivate/constants.js +16 -0
  266. package/dist/esm/components/Lists/ListPrivate/index.d.ts +1 -0
  267. package/dist/esm/components/Lists/ListPrivate/index.js +1 -0
  268. package/dist/esm/components/Lists/ListPrivate/styles.module.css +80 -0
  269. package/dist/esm/components/Lists/contexts/CollapseProvider.d.ts +17 -0
  270. package/dist/esm/components/Lists/contexts/CollapseProvider.js +5 -0
  271. package/dist/esm/components/Lists/contexts/FocusListProvider.d.ts +9 -0
  272. package/dist/esm/components/Lists/contexts/FocusListProvider.js +5 -0
  273. package/dist/esm/components/Lists/contexts/NewListProvider.d.ts +33 -0
  274. package/dist/esm/components/Lists/contexts/NewListProvider.js +18 -0
  275. package/dist/esm/components/Lists/contexts/OpenListProvider.d.ts +6 -0
  276. package/dist/esm/components/Lists/contexts/OpenListProvider.js +6 -0
  277. package/dist/esm/components/Lists/contexts/SelectionProvider.d.ts +74 -0
  278. package/dist/esm/components/Lists/contexts/SelectionProvider.js +83 -0
  279. package/dist/esm/components/Lists/contexts/index.d.ts +5 -0
  280. package/dist/esm/components/Lists/contexts/index.js +5 -0
  281. package/dist/esm/components/Lists/hooks.d.ts +83 -0
  282. package/dist/esm/components/Lists/hooks.js +238 -0
  283. package/dist/esm/components/Lists/index.d.ts +5 -0
  284. package/dist/esm/components/Lists/index.js +5 -0
  285. package/dist/esm/components/Lists/styles.module.css +65 -0
  286. package/dist/esm/components/Lists/types.d.ts +200 -0
  287. package/dist/esm/components/Lists/types.js +1 -0
  288. package/dist/esm/components/Lists/utils.d.ts +8 -0
  289. package/dist/esm/components/Lists/utils.js +28 -0
  290. package/dist/esm/components/index.d.ts +2 -0
  291. package/dist/esm/components/index.js +2 -0
  292. package/dist/esm/constants.d.ts +48 -0
  293. package/dist/esm/constants.js +48 -0
  294. package/dist/esm/helperComponents/CollapseBlockPrivate/CollapseBlockPrivate.d.ts +9 -0
  295. package/dist/esm/helperComponents/CollapseBlockPrivate/CollapseBlockPrivate.js +9 -0
  296. package/dist/esm/helperComponents/CollapseBlockPrivate/index.d.ts +1 -0
  297. package/dist/esm/helperComponents/CollapseBlockPrivate/index.js +1 -0
  298. package/dist/esm/helperComponents/CollapseBlockPrivate/styles.module.css +27 -0
  299. package/dist/esm/helperComponents/DesktopDroplist/DesktopDroplist.d.ts +7 -0
  300. package/dist/esm/helperComponents/DesktopDroplist/DesktopDroplist.js +136 -0
  301. package/dist/esm/helperComponents/DesktopDroplist/index.d.ts +1 -0
  302. package/dist/esm/helperComponents/DesktopDroplist/index.js +1 -0
  303. package/dist/esm/helperComponents/HiddenTabButton/HiddenTabButton.d.ts +7 -0
  304. package/dist/esm/helperComponents/HiddenTabButton/HiddenTabButton.js +14 -0
  305. package/dist/esm/helperComponents/HiddenTabButton/index.d.ts +1 -0
  306. package/dist/esm/helperComponents/HiddenTabButton/index.js +1 -0
  307. package/dist/esm/helperComponents/HiddenTabButton/styles.module.css +9 -0
  308. package/dist/esm/helperComponents/ItemContent/ItemContent.d.ts +17 -0
  309. package/dist/esm/helperComponents/ItemContent/ItemContent.js +21 -0
  310. package/dist/esm/helperComponents/ItemContent/index.d.ts +1 -0
  311. package/dist/esm/helperComponents/ItemContent/index.js +1 -0
  312. package/dist/esm/helperComponents/ItemContent/styles.module.css +139 -0
  313. package/dist/esm/helperComponents/ListEmptyState/ListEmptyState.d.ts +16 -0
  314. package/dist/esm/helperComponents/ListEmptyState/ListEmptyState.js +19 -0
  315. package/dist/esm/helperComponents/ListEmptyState/hooks.d.ts +10 -0
  316. package/dist/esm/helperComponents/ListEmptyState/hooks.js +27 -0
  317. package/dist/esm/helperComponents/ListEmptyState/index.d.ts +2 -0
  318. package/dist/esm/helperComponents/ListEmptyState/index.js +2 -0
  319. package/dist/esm/helperComponents/ListEmptyState/styles.module.css +8 -0
  320. package/dist/esm/helperComponents/MobileDroplist/MobileDroplist.d.ts +9 -0
  321. package/dist/esm/helperComponents/MobileDroplist/MobileDroplist.js +137 -0
  322. package/dist/esm/helperComponents/MobileDroplist/MobileDroplist.module.css +16 -0
  323. package/dist/esm/helperComponents/MobileDroplist/index.d.ts +1 -0
  324. package/dist/esm/helperComponents/MobileDroplist/index.js +1 -0
  325. package/dist/esm/helperComponents/MobileDroplist/utils.d.ts +11 -0
  326. package/dist/esm/helperComponents/MobileDroplist/utils.js +61 -0
  327. package/dist/esm/helperComponents/Separator/Separator.d.ts +20 -0
  328. package/dist/esm/helperComponents/Separator/Separator.js +34 -0
  329. package/dist/esm/helperComponents/Separator/constants.d.ts +3 -0
  330. package/dist/esm/helperComponents/Separator/constants.js +7 -0
  331. package/dist/esm/helperComponents/Separator/index.d.ts +1 -0
  332. package/dist/esm/helperComponents/Separator/index.js +1 -0
  333. package/dist/esm/helperComponents/Separator/styles.module.css +168 -0
  334. package/dist/esm/helperComponents/index.d.ts +5 -0
  335. package/dist/esm/helperComponents/index.js +5 -0
  336. package/dist/esm/index.d.ts +9 -0
  337. package/dist/esm/index.js +14 -0
  338. package/dist/esm/locale/index.d.ts +79 -0
  339. package/dist/esm/locale/index.js +41 -0
  340. package/dist/esm/style.css +1113 -0
  341. package/dist/esm/types.d.ts +38 -0
  342. package/dist/esm/types.js +1 -0
  343. package/dist/esm/utils.d.ts +18 -0
  344. package/dist/esm/utils.js +19 -0
  345. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  346. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  347. package/package.json +70 -0
  348. package/src/_iconSizes.scss +7 -0
  349. package/src/components/Items/AccordionItem/AccordionItem.tsx +79 -0
  350. package/src/components/Items/AccordionItem/index.ts +1 -0
  351. package/src/components/Items/BaseItem/BaseItem.tsx +274 -0
  352. package/src/components/Items/BaseItem/constants.ts +9 -0
  353. package/src/components/Items/BaseItem/index.ts +1 -0
  354. package/src/components/Items/BaseItem/styles.module.scss +330 -0
  355. package/src/components/Items/GroupSelectItem/GroupSelectItem.tsx +48 -0
  356. package/src/components/Items/GroupSelectItem/index.ts +1 -0
  357. package/src/components/Items/NextListItem/NextListItem.tsx +157 -0
  358. package/src/components/Items/NextListItem/constants.ts +12 -0
  359. package/src/components/Items/NextListItem/index.ts +1 -0
  360. package/src/components/Items/NextListItem/types.ts +3 -0
  361. package/src/components/Items/PinGroupItem/PinGroupItem.tsx +38 -0
  362. package/src/components/Items/PinGroupItem/index.ts +1 -0
  363. package/src/components/Items/PinGroupItem/styles.module.scss +14 -0
  364. package/src/components/Items/SearchItem/SearchItem.tsx +55 -0
  365. package/src/components/Items/SearchItem/index.ts +1 -0
  366. package/src/components/Items/SearchItem/styles.module.scss +26 -0
  367. package/src/components/Items/SimpleItem/components/DragHandle/DragHandle.tsx +27 -0
  368. package/src/components/Items/SimpleItem/components/DragHandle/index.ts +1 -0
  369. package/src/components/Items/SimpleItem/components/OverlayDragHandle/OverlayDragHandle.tsx +6 -0
  370. package/src/components/Items/SimpleItem/components/OverlayDragHandle/index.ts +1 -0
  371. package/src/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.tsx +87 -0
  372. package/src/components/Items/SimpleItem/components/SimpleGroupBlock/index.ts +1 -0
  373. package/src/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.tsx +33 -0
  374. package/src/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/index.ts +1 -0
  375. package/src/components/Items/SimpleItem/components/SimpleItem/SimpleItem.tsx +70 -0
  376. package/src/components/Items/SimpleItem/components/SimpleItem/index.ts +1 -0
  377. package/src/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.tsx +26 -0
  378. package/src/components/Items/SimpleItem/components/SimpleItemOverlay/index.ts +1 -0
  379. package/src/components/Items/SimpleItem/components/index.ts +4 -0
  380. package/src/components/Items/SimpleItem/constants.ts +8 -0
  381. package/src/components/Items/SimpleItem/index.ts +2 -0
  382. package/src/components/Items/SimpleItem/styles.module.scss +149 -0
  383. package/src/components/Items/SimpleItem/types.ts +7 -0
  384. package/src/components/Items/SimpleItem/utils.ts +8 -0
  385. package/src/components/Items/hooks.tsx +233 -0
  386. package/src/components/Items/index.ts +5 -0
  387. package/src/components/Items/styles.module.scss +107 -0
  388. package/src/components/Items/types.ts +203 -0
  389. package/src/components/Items/utils.ts +302 -0
  390. package/src/components/Lists/Droplist/DropList.tsx +62 -0
  391. package/src/components/Lists/Droplist/constants.ts +11 -0
  392. package/src/components/Lists/Droplist/index.ts +1 -0
  393. package/src/components/Lists/List/List.tsx +155 -0
  394. package/src/components/Lists/List/index.ts +1 -0
  395. package/src/components/Lists/ListPrivate/ListPrivate.tsx +560 -0
  396. package/src/components/Lists/ListPrivate/constants.ts +22 -0
  397. package/src/components/Lists/ListPrivate/index.ts +1 -0
  398. package/src/components/Lists/ListPrivate/styles.module.scss +90 -0
  399. package/src/components/Lists/contexts/CollapseProvider.tsx +22 -0
  400. package/src/components/Lists/contexts/FocusListProvider.tsx +15 -0
  401. package/src/components/Lists/contexts/NewListProvider.tsx +76 -0
  402. package/src/components/Lists/contexts/OpenListProvider.tsx +13 -0
  403. package/src/components/Lists/contexts/SelectionProvider.tsx +214 -0
  404. package/src/components/Lists/contexts/index.ts +5 -0
  405. package/src/components/Lists/hooks.ts +351 -0
  406. package/src/components/Lists/index.ts +5 -0
  407. package/src/components/Lists/styles.module.scss +95 -0
  408. package/src/components/Lists/types.ts +231 -0
  409. package/src/components/Lists/utils.ts +32 -0
  410. package/src/components/index.ts +2 -0
  411. package/src/constants.ts +53 -0
  412. package/src/helperComponents/CollapseBlockPrivate/CollapseBlockPrivate.tsx +32 -0
  413. package/src/helperComponents/CollapseBlockPrivate/index.ts +1 -0
  414. package/src/helperComponents/CollapseBlockPrivate/styles.module.scss +32 -0
  415. package/src/helperComponents/DesktopDroplist/DesktopDroplist.tsx +313 -0
  416. package/src/helperComponents/DesktopDroplist/index.ts +1 -0
  417. package/src/helperComponents/HiddenTabButton/HiddenTabButton.tsx +35 -0
  418. package/src/helperComponents/HiddenTabButton/index.ts +1 -0
  419. package/src/helperComponents/HiddenTabButton/styles.module.scss +11 -0
  420. package/src/helperComponents/ItemContent/ItemContent.tsx +80 -0
  421. package/src/helperComponents/ItemContent/index.ts +1 -0
  422. package/src/helperComponents/ItemContent/styles.module.scss +100 -0
  423. package/src/helperComponents/ListEmptyState/ListEmptyState.tsx +52 -0
  424. package/src/helperComponents/ListEmptyState/hooks.ts +42 -0
  425. package/src/helperComponents/ListEmptyState/index.ts +2 -0
  426. package/src/helperComponents/ListEmptyState/styles.module.scss +11 -0
  427. package/src/helperComponents/MobileDroplist/MobileDroplist.module.scss +25 -0
  428. package/src/helperComponents/MobileDroplist/MobileDroplist.tsx +230 -0
  429. package/src/helperComponents/MobileDroplist/index.ts +1 -0
  430. package/src/helperComponents/MobileDroplist/utils.tsx +76 -0
  431. package/src/helperComponents/Separator/Separator.tsx +115 -0
  432. package/src/helperComponents/Separator/constants.ts +11 -0
  433. package/src/helperComponents/Separator/index.ts +1 -0
  434. package/src/helperComponents/Separator/styles.module.scss +255 -0
  435. package/src/helperComponents/index.ts +5 -0
  436. package/src/index.ts +19 -0
  437. package/src/locale/index.ts +45 -0
  438. package/src/types.ts +44 -0
  439. package/src/utils.ts +26 -0
@@ -0,0 +1,560 @@
1
+ import {
2
+ closestCenter,
3
+ CollisionDetection,
4
+ DndContext,
5
+ DragEndEvent,
6
+ DragOverlay,
7
+ DragStartEvent,
8
+ KeyboardSensor,
9
+ MeasuringStrategy,
10
+ MouseSensor,
11
+ pointerWithin,
12
+ TouchSensor,
13
+ useSensor,
14
+ useSensors,
15
+ } from '@dnd-kit/core';
16
+ import { SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable';
17
+ import { Spinner } from '@cloud-ru/ds-loader';
18
+ import { usePortalContext } from '@cloud-ru/ds-portal-context';
19
+ import { Scroll } from '@cloud-ru/ds-scroll';
20
+ import { extractSupportProps, isBrowser, useLayoutEffect } from '@cloud-ru/ds-utils';
21
+ import { useVirtualizer } from '@tanstack/react-virtual';
22
+ import cn from 'classnames';
23
+ import mergeRefs from 'merge-refs';
24
+ import { ForwardedRef, forwardRef, ReactNode, Ref, useCallback, useEffect, useMemo, useRef, useState } from 'react';
25
+ import { createPortal } from 'react-dom';
26
+
27
+ import { DEFAULT_SIZE, TEST_IDS } from '../../../constants';
28
+ import { ListEmptyState, useEmptyState } from '../../../helperComponents';
29
+ import { stopPropagation } from '../../../utils';
30
+ import {
31
+ FlattenSimpleItem,
32
+ isGroupItem,
33
+ isSimpleItem,
34
+ ItemId,
35
+ PinBottomGroupItem,
36
+ PinTopGroupItem,
37
+ SearchItem,
38
+ useRenderItems,
39
+ } from '../../Items';
40
+ import { SimpleGroupBlockOverlay, SimpleItemOverlay } from '../../Items/SimpleItem';
41
+ import { useNewListContext, useSelectionContext } from '../contexts';
42
+ import commonStyles from '../styles.module.scss';
43
+ import { ListPrivateProps } from '../types';
44
+ import { ALL_SIZES, SPINNER_SIZE_MAP } from './constants';
45
+ import styles from './styles.module.scss';
46
+
47
+ // Отделяет клик (activation через `onClick` айтема) от начала перетаскивания — тот же порог активации,
48
+ // что у `@cloud-ru/ds-table` (`useColumnOrderByDrag`), для единообразия поведения по репо.
49
+ const draggingOptions = { activationConstraint: { distance: 5 } };
50
+
51
+ // Пересчитывать rect'ы droppable-строк на каждом кадре перетаскивания. В `Droplist` (popover) список лежит
52
+ // в скролл-контейнере с трансформами: измеренные при монтировании rect'ы устаревают, коллизия
53
+ // указывает на последнюю строку и строка «улетает» в конец. `Always` держит измерения свежими.
54
+ const measuringConfig = { droppable: { strategy: MeasuringStrategy.Always } };
55
+
56
+ type ScrollState = {
57
+ virtualizer: ItemId | null;
58
+ browser: ItemId | null;
59
+ measured: boolean;
60
+ };
61
+
62
+ /**
63
+ * Центрирует элемент внутри своего scroll-контейнера правкой `scrollTop` контейнера.
64
+ * В отличие от `element.scrollIntoView({ block: 'center' })`, НЕ скроллит вышестоящие предки
65
+ * (включая window) — иначе при монтировании списка с `scrollToSelectedItem` страница доков
66
+ * «дёргалась» (окно прыгало, чтобы показать выбранный элемент). См. ревью MR!101.
67
+ */
68
+ function centerItemInScrollContainer(container: HTMLElement | null, item: HTMLElement | null) {
69
+ if (!container || !item) {
70
+ return;
71
+ }
72
+ const containerRect = container.getBoundingClientRect();
73
+ const itemRect = item.getBoundingClientRect();
74
+ const delta = itemRect.top - containerRect.top - (container.clientHeight - itemRect.height) / 2;
75
+ container.scrollTop += delta;
76
+ }
77
+
78
+ export const ListPrivate = forwardRef(
79
+ (
80
+ {
81
+ items,
82
+ pinTop,
83
+ pinBottom,
84
+ onKeyDown,
85
+ onBlur,
86
+ onFocus,
87
+ tabIndex,
88
+ active,
89
+ scroll,
90
+ nested,
91
+ search,
92
+ searchItem,
93
+ scrollRef,
94
+ scrollContainerRef,
95
+ onScroll,
96
+ footer,
97
+ header,
98
+ headerDivider,
99
+ footerDivider,
100
+ loading,
101
+ limitedScrollHeight,
102
+ untouchableScrollbars,
103
+ className,
104
+ noDataState,
105
+ noResultsState,
106
+ errorDataState,
107
+ dataError,
108
+ dataFiltered,
109
+ scrollToSelectedItem = false,
110
+ virtualized: virtualizedProp = false,
111
+ scrollContainerClassName,
112
+ barHideStrategy = 'never',
113
+ onDragEnd,
114
+ sortableIds,
115
+ ...props
116
+ }: ListPrivateProps,
117
+ ref: ForwardedRef<HTMLElement>,
118
+ ) => {
119
+ const { size = DEFAULT_SIZE, flattenItems, focusFlattenItems } = useNewListContext();
120
+ const { value, isSelectionSingle } = useSelectionContext();
121
+ // `onDragEnd`/`SortableContext` конфликтуют с виртуализатором: обе стороны применяют свой
122
+ // `transform` к строке (см. JSDoc `ListPrivateProps.onDragEnd`) — запрещено уже на уровне
123
+ // типов (`ListProps`), здесь рантайм-зеркало на случай прямого использования `ListPrivate`.
124
+ const virtualized = virtualizedProp && !onDragEnd;
125
+ const sensors = useSensors(
126
+ useSensor(MouseSensor, draggingOptions),
127
+ useSensor(TouchSensor, {}),
128
+ useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
129
+ );
130
+ // Id перетаскиваемой строки — для рендера её копии в `DragOverlay`. Копия живёт в портале
131
+ // над страницей и не режется `overflow: hidden` контейнера `List` (исходная строка остаётся
132
+ // на месте «призраком»). `null`, когда перетаскивание не идёт.
133
+ const [activeDragId, setActiveDragId] = useState<ItemId | null>(null);
134
+ const handleDragStart = useCallback((event: DragStartEvent) => setActiveDragId(event.active.id), []);
135
+ const handleDragEnd = useCallback(
136
+ (event: DragEndEvent) => {
137
+ setActiveDragId(null);
138
+ onDragEnd?.(event);
139
+ },
140
+ [onDragEnd],
141
+ );
142
+ const handleDragCancel = useCallback(() => setActiveDragId(null), []);
143
+ const activeOverlayItem = activeDragId != null ? flattenItems[activeDragId] : undefined;
144
+
145
+ // Переупорядочивание строго внутри одного sortable-контейнера: верхний уровень (строки без группы + сами
146
+ // группы — «братья») либо контейнер конкретной группы (её строки). Остаются только droppable
147
+ // того же контейнера, что и активный элемент (`container` в `data` ставят `SimpleItem`/
148
+ // `SimpleGroupBlock`).
149
+ const collisionDetection = useCallback<CollisionDetection>(args => {
150
+ const activeContainer = (args.active.data.current as { container?: ItemId } | undefined)?.container;
151
+ const droppableContainers = args.droppableContainers.filter(
152
+ container => (container.data.current as { container?: ItemId } | undefined)?.container === activeContainer,
153
+ );
154
+
155
+ // Сначала — droppable под курсором (`pointerWithin`). Группа сортируется целым блоком
156
+ // (`SimpleGroupBlock`: заголовок + строки), поэтому её droppable-rect высокий; `closestCenter`
157
+ // сравнивал бы расстояние до центра блока — курсор над заголовком группы был далеко от центра,
158
+ // и цель «перепрыгивала» через всю группу (строка вставала под неё). `pointerWithin` берёт тот
159
+ // блок, над которым реально курсор, — вставка идёт туда, где визуально находится указатель.
160
+ const pointerCollisions = pointerWithin({ ...args, droppableContainers });
161
+ if (pointerCollisions.length > 0) {
162
+ return pointerCollisions;
163
+ }
164
+
165
+ // Fallback для клавиатурного сенсора (у него нет координат указателя → `pointerWithin` пуст).
166
+ return closestCenter({ ...args, droppableContainers });
167
+ }, []);
168
+
169
+ // Портал `DragOverlay` — в themed-корень (`@cloud-ru/ds-portal-context`), а не в `document.body`. Все
170
+ // `--sn-*` токены объявлены на theme-scope (`RootThemeProvider`), а не на `:root`; в `body`
171
+ // копия строки теряла их и падала на дефолты (раздутые паддинги/цвета — «гигантский призрак»).
172
+ // Корень портал-контекста лежит внутри theme-scope и не трансформирован, поэтому `position:
173
+ // fixed` у `DragOverlay` остаётся относительно вьюпорта (в т.ч. внутри popover-Droplist).
174
+ const portalRoot = usePortalContext();
175
+
176
+ const innerScrollRef = useRef<HTMLElement | null>(null);
177
+ // `@cloud-ru/ds-scroll` (OverlayScrollbars) разрешает свой ref в viewport-элемент только после
178
+ // инициализации инстанса. До этого `innerScrollRef.current` === null, и виртуализатор
179
+ // не получает scroll-элемент → рендерит пустой контейнер. Флаг поднимается из
180
+ // `onInitialized` и форсит повторный `measure()` уже с готовым viewport'ом.
181
+ const [scrollElementReady, setScrollElementReady] = useState(false);
182
+
183
+ const itemsJSX = useRenderItems(items);
184
+ const itemsPinTopJSX = useRenderItems(pinTop);
185
+ const itemsPinBottomJSX = useRenderItems(pinBottom);
186
+
187
+ const pinTopItemsPresent = Number(pinTop?.length) > 0;
188
+ const pinBottomItemsPresent = Number(pinBottom?.length) > 0;
189
+
190
+ const [scrollState, setScrollState] = useState<ScrollState>({ virtualizer: null, browser: null, measured: false });
191
+
192
+ const emptyStates = useEmptyState({ noDataState, noResultsState, errorDataState });
193
+ const hasNoItems = items.length === 0;
194
+
195
+ const { selectedItemIndex, selectedItem } = useMemo(() => {
196
+ const result = {
197
+ selectedItemIndex: -1,
198
+ selectedItem: undefined,
199
+ };
200
+
201
+ if (!scrollToSelectedItem || !value) {
202
+ return result;
203
+ }
204
+
205
+ const selectedItem = isSelectionSingle ? flattenItems[value] : flattenItems[value[0]];
206
+ if (!selectedItem?.id) {
207
+ return result;
208
+ }
209
+
210
+ const allFocusFlattenItems = Object.values(focusFlattenItems);
211
+ const index = allFocusFlattenItems.findIndex(item => item.originalId === selectedItem.id);
212
+ if (index < 0) {
213
+ return result;
214
+ }
215
+
216
+ return {
217
+ selectedItemIndex: index,
218
+ selectedItem: allFocusFlattenItems[index],
219
+ };
220
+ }, [flattenItems, focusFlattenItems, isSelectionSingle, scrollToSelectedItem, value]);
221
+
222
+ // Реальная высота строки может превышать однострочный `ALL_SIZES[size]` (например, item с
223
+ // `description` — двухстрочный). Если estimateSize занижен, незамеренные строки оцениваются
224
+ // меньше реальных, и по мере прокрутки `measureElement` правит totalSize — контент «скачет».
225
+ // Меряем фактическую высоту первой отрисованной строки и используем как оценку для остальных:
226
+ // totalSize становится точным сразу, скачок пропадает. measureElement по-прежнему уточняет
227
+ // разнородные строки построчно.
228
+ const [measuredRowSize, setMeasuredRowSize] = useState<number | null>(null);
229
+
230
+ const virtualizer = useVirtualizer({
231
+ count: itemsJSX.length,
232
+ // Зависимость на `scrollElementReady` заставляет виртуализатор перечитать scroll-элемент
233
+ // после инициализации OverlayScrollbars (когда `innerScrollRef.current` уже не null).
234
+ getScrollElement: () => (scroll && scrollElementReady ? innerScrollRef.current : null),
235
+ estimateSize: () => measuredRowSize ?? ALL_SIZES[size],
236
+ enabled: virtualized,
237
+ overscan: 5, // Amount of elements in DOM before/after visible ones
238
+ });
239
+ const virtualItems = virtualizer.getVirtualItems();
240
+
241
+ // Сбрасываем измеренную оценку при смене size — однострочная база снова станет дефолтом
242
+ // до первого замера новой плотности.
243
+ useEffect(() => {
244
+ setMeasuredRowSize(null);
245
+ }, [size]);
246
+
247
+ // Замер реальной высоты первой строки после её отрисовки (до того, как пользователь начнёт
248
+ // скроллить). Один замер на size: как только оценка зафиксирована, эффект больше ничего не
249
+ // делает (measureElement продолжает уточнять разнородные строки построчно).
250
+ const hasRenderedRows = virtualItems.length > 0;
251
+ useLayoutEffect(() => {
252
+ if (!virtualized || !scrollElementReady || measuredRowSize !== null || !hasRenderedRows) {
253
+ return;
254
+ }
255
+ const firstRow = innerScrollRef.current?.querySelector<HTMLElement>('[data-index]');
256
+ const height = firstRow?.offsetHeight;
257
+ if (height && Math.abs(height - ALL_SIZES[size]) > 1) {
258
+ setMeasuredRowSize(height);
259
+ }
260
+ }, [virtualized, scrollElementReady, measuredRowSize, hasRenderedRows, size]);
261
+
262
+ useEffect(() => {
263
+ if (!scrollElementReady) {
264
+ return; // Scroll-элемент ещё не готов — измерять нечего, иначе фиксируем пустой кадр.
265
+ }
266
+ if (scrollState.measured) {
267
+ return;
268
+ }
269
+
270
+ virtualizer.measure();
271
+
272
+ setScrollState(prevState => ({
273
+ ...prevState,
274
+ measured: true,
275
+ }));
276
+ }, [scrollElementReady, scrollState.measured, virtualizer]);
277
+
278
+ const isScrollToItemEnabled = scroll && scrollToSelectedItem && virtualized;
279
+
280
+ useEffect(() => {
281
+ if (isScrollToItemEnabled) {
282
+ if (!scrollState.measured) {
283
+ return; // Not measured yet
284
+ }
285
+ if (selectedItemIndex < 0 || !selectedItem) {
286
+ return; // Cannot scroll to non-existing item
287
+ }
288
+ if (scrollState.virtualizer === selectedItem.originalId) {
289
+ return; // No need to re-scroll to the same item during re-renders
290
+ }
291
+ if (selectedItem?.itemRef && innerScrollRef.current?.contains(selectedItem?.itemRef.current)) {
292
+ return; // No need to scroll to manually clicked item currently present in DOM
293
+ }
294
+
295
+ virtualizer.scrollToIndex(selectedItemIndex, { align: 'center' });
296
+
297
+ setScrollState(prevState => ({
298
+ ...prevState,
299
+ virtualizer: selectedItem.originalId,
300
+ }));
301
+ }
302
+ }, [isScrollToItemEnabled, scrollState, selectedItem, selectedItemIndex, virtualizer]);
303
+
304
+ const isTargetPresentInDom = Boolean(selectedItem?.itemRef?.current);
305
+
306
+ useEffect(() => {
307
+ if (!selectedItem) {
308
+ return;
309
+ }
310
+ if (scrollState.virtualizer === null) {
311
+ return; // Not scrolled by virtualizer yet, no need for additional scroll
312
+ }
313
+ if (!isTargetPresentInDom) {
314
+ return; // Target element is not present in DOM yet, additional scroll does not work without it
315
+ }
316
+ if (scrollState.virtualizer === scrollState.browser) {
317
+ return; // Virtualizer scroll has not been executed => no need for additional scroll
318
+ }
319
+
320
+ centerItemInScrollContainer(innerScrollRef.current, selectedItem.itemRef?.current ?? null);
321
+
322
+ setScrollState(prevState => ({
323
+ ...prevState,
324
+ browser: selectedItem.originalId,
325
+ }));
326
+ }, [scrollState, selectedItem, isTargetPresentInDom, selectedItemIndex]);
327
+
328
+ // Non-virtualized: центрируем выбранный элемент в собственном scroll-контейнере при смене
329
+ // `selection` (на первом маунте это делает `onScrollInitialized`). Виртуализованный путь
330
+ // ведут эффекты выше через виртуализатор, поэтому здесь только `!virtualized`. Хелпер тот
331
+ // же `centerItemInScrollContainer` — обычному листу отдельный виртуализатор не нужен.
332
+ useEffect(() => {
333
+ if (virtualized || !scroll || !scrollToSelectedItem || !scrollElementReady) {
334
+ return;
335
+ }
336
+
337
+ const container = innerScrollRef.current;
338
+ const item = selectedItem?.itemRef?.current ?? null;
339
+ if (!container || !item) {
340
+ return;
341
+ }
342
+
343
+ centerItemInScrollContainer(container, item);
344
+ }, [virtualized, scroll, scrollToSelectedItem, scrollElementReady, selectedItem]);
345
+
346
+ const loadingJSX = useMemo(
347
+ () =>
348
+ loading && (
349
+ <div
350
+ role={'status'}
351
+ tabIndex={-1}
352
+ className={styles.loader}
353
+ data-size={size}
354
+ data-no-items={hasNoItems || undefined}
355
+ data-test-id={TEST_IDS.loader}
356
+ >
357
+ <Spinner size={SPINNER_SIZE_MAP[size]} />
358
+ </div>
359
+ ),
360
+ [hasNoItems, loading, size],
361
+ );
362
+
363
+ const content = useMemo(() => {
364
+ const itemsBody: ReactNode = virtualized ? (
365
+ <div className={styles.virtualizedContainer} style={{ height: virtualizer.getTotalSize() }} tabIndex={-1}>
366
+ {virtualItems.map(virtualRow => (
367
+ <div
368
+ key={virtualRow.key}
369
+ data-index={virtualRow.index}
370
+ ref={virtualizer.measureElement}
371
+ tabIndex={-1}
372
+ className={styles.virtualizedPositionBox}
373
+ style={{
374
+ transform: `translateY(${virtualRow.start}px)`,
375
+ }}
376
+ >
377
+ {itemsJSX[virtualRow.index]}
378
+ </div>
379
+ ))}
380
+ </div>
381
+ ) : (
382
+ itemsJSX
383
+ );
384
+
385
+ // Содержимое `DragOverlay`: копия строки (`SimpleItemOverlay`) либо заголовка группы
386
+ // (`SimpleGroupBlockOverlay`) — по типу активного элемента.
387
+ let dragOverlayContent: ReactNode = null;
388
+ if (activeOverlayItem && isSimpleItem(activeOverlayItem)) {
389
+ dragOverlayContent = <SimpleItemOverlay {...activeOverlayItem} />;
390
+ } else if (activeOverlayItem && isGroupItem(activeOverlayItem)) {
391
+ const rows = ((activeOverlayItem as { allChildIds?: ItemId[] }).allChildIds ?? [])
392
+ .map(rowId => flattenItems[rowId])
393
+ .filter((row): row is FlattenSimpleItem => isSimpleItem(row));
394
+ dragOverlayContent = (
395
+ <SimpleGroupBlockOverlay
396
+ size={size}
397
+ rows={rows}
398
+ label={activeOverlayItem.label}
399
+ beforeContent={activeOverlayItem.beforeContent}
400
+ truncate={activeOverlayItem.truncate}
401
+ divider={activeOverlayItem.divider}
402
+ groupVariant={activeOverlayItem.groupVariant}
403
+ />
404
+ );
405
+ }
406
+
407
+ // `SortableContext`/`DndContext` — чистые провайдеры контекста, не рендерят DOM-узлов,
408
+ // поэтому оборачивание всего блока (включая loader/empty-state) безопасно и не меняет
409
+ // разметку `<ul>`.
410
+ const body = onDragEnd ? (
411
+ <DndContext
412
+ sensors={sensors}
413
+ collisionDetection={collisionDetection}
414
+ measuring={measuringConfig}
415
+ onDragStart={handleDragStart}
416
+ onDragEnd={handleDragEnd}
417
+ onDragCancel={handleDragCancel}
418
+ >
419
+ <SortableContext items={sortableIds ?? []} strategy={verticalListSortingStrategy}>
420
+ {itemsBody}
421
+ </SortableContext>
422
+ {/* Портал в themed-корень портал-контекста (см. `portalRoot` выше): `DragOverlay`
423
+ позиционируется `position: fixed`, а корень не трансформирован — копия остаётся у
424
+ курсора и вне `overflow: hidden` контейнера `List` (в т.ч. в popover-Droplist), при
425
+ этом сохраняет `--sn-*` токены темы. `dropAnimation={null}`: порядок применяется
426
+ синхронно в `onItemsReorder`, копию не анимируем «в слот». */}
427
+ {isBrowser() &&
428
+ createPortal(
429
+ <DragOverlay dropAnimation={null}>{dragOverlayContent}</DragOverlay>,
430
+ portalRoot.current ?? document.body,
431
+ )}
432
+ </DndContext>
433
+ ) : (
434
+ itemsBody
435
+ );
436
+
437
+ return (
438
+ <>
439
+ {body}
440
+ {loadingJSX}
441
+
442
+ <ListEmptyState
443
+ loading={loading}
444
+ dataError={dataError}
445
+ emptyStates={emptyStates}
446
+ hasNoItems={hasNoItems}
447
+ dataFiltered={dataFiltered ?? Boolean(search?.value)}
448
+ size={size}
449
+ />
450
+ </>
451
+ );
452
+ }, [
453
+ activeOverlayItem,
454
+ collisionDetection,
455
+ dataError,
456
+ dataFiltered,
457
+ emptyStates,
458
+ flattenItems,
459
+ handleDragCancel,
460
+ handleDragEnd,
461
+ handleDragStart,
462
+ hasNoItems,
463
+ itemsJSX,
464
+ loading,
465
+ loadingJSX,
466
+ onDragEnd,
467
+ portalRoot,
468
+ search?.value,
469
+ sensors,
470
+ size,
471
+ sortableIds,
472
+ virtualItems,
473
+ virtualized,
474
+ virtualizer,
475
+ ]);
476
+
477
+ const onScrollInitialized = useCallback(() => {
478
+ // OverlayScrollbars инициализирован — ref указывает на viewport. Поднимаем флаг,
479
+ // чтобы виртуализатор перечитал scroll-элемент и сделал первый корректный замер.
480
+ setScrollElementReady(true);
481
+
482
+ if (!selectedItem) {
483
+ return;
484
+ }
485
+
486
+ centerItemInScrollContainer(innerScrollRef.current, selectedItem?.itemRef?.current ?? null);
487
+ }, [selectedItem]);
488
+
489
+ const listJSX = (
490
+ <ul
491
+ className={cn(commonStyles.listContainer, className)}
492
+ ref={ref as ForwardedRef<HTMLUListElement>}
493
+ onKeyDown={onKeyDown}
494
+ tabIndex={tabIndex}
495
+ onFocus={onFocus}
496
+ onBlur={onBlur}
497
+ data-active={active || undefined}
498
+ role='menu'
499
+ {...extractSupportProps(props)}
500
+ >
501
+ {header && (
502
+ <div className={styles.header} data-divider={headerDivider || undefined} onFocus={stopPropagation}>
503
+ {header}
504
+ </div>
505
+ )}
506
+
507
+ {(pinTopItemsPresent || search) && (
508
+ <PinTopGroupItem>
509
+ {search && <SearchItem search={search} {...searchItem} />}
510
+
511
+ {pinTopItemsPresent && itemsPinTopJSX}
512
+ </PinTopGroupItem>
513
+ )}
514
+
515
+ {scroll ? (
516
+ <Scroll
517
+ className={cn(
518
+ {
519
+ [commonStyles.scrollContainerS]: scroll && limitedScrollHeight && size === 's',
520
+ [commonStyles.scrollContainerM]: scroll && limitedScrollHeight && size === 'm',
521
+ [commonStyles.scrollContainerL]: scroll && limitedScrollHeight && size === 'l',
522
+ },
523
+ scrollContainerClassName,
524
+ )}
525
+ barHideStrategy={barHideStrategy}
526
+ size={'s'}
527
+ ref={mergeRefs(innerScrollRef, scrollContainerRef)}
528
+ untouchableScrollbars={untouchableScrollbars}
529
+ onScroll={onScroll}
530
+ onInitialized={onScrollInitialized}
531
+ >
532
+ {content}
533
+
534
+ <div className={styles.scrollStub} ref={scrollRef as Ref<HTMLDivElement>} />
535
+ </Scroll>
536
+ ) : (
537
+ <>{content}</>
538
+ )}
539
+
540
+ {pinBottomItemsPresent && <PinBottomGroupItem>{itemsPinBottomJSX}</PinBottomGroupItem>}
541
+
542
+ {footer && (
543
+ <div className={styles.footer} data-divider={footerDivider || undefined} onFocus={stopPropagation}>
544
+ {footer}
545
+ </div>
546
+ )}
547
+ </ul>
548
+ );
549
+
550
+ if (!nested) {
551
+ return listJSX;
552
+ }
553
+
554
+ return (
555
+ <li className={styles.nestedItem} role='menuitem'>
556
+ {listJSX}
557
+ </li>
558
+ );
559
+ },
560
+ );
@@ -0,0 +1,22 @@
1
+ import { SpinnerProps } from '@cloud-ru/ds-loader';
2
+
3
+ import { Size } from '../../../types';
4
+
5
+ // Фактические высоты однострочного item в compact-density (s=24 / m=32 / l=40). Оценка
6
+ // виртуализатора должна совпадать с рендером: завышенный estimate даёт «скачок» скролла —
7
+ // измеренные строки сжимают totalSize по мере прокрутки (MR!101).
8
+ export const LARGE_SIZE_HEIGHT = 40;
9
+ export const MEDIUM_SIZE_HEIGHT = 32;
10
+ export const SMALL_SIZE_HEIGHT = 24;
11
+
12
+ export const ALL_SIZES: Record<Size, number> = {
13
+ m: MEDIUM_SIZE_HEIGHT,
14
+ s: SMALL_SIZE_HEIGHT,
15
+ l: LARGE_SIZE_HEIGHT,
16
+ };
17
+
18
+ export const SPINNER_SIZE_MAP: Record<Size, SpinnerProps['size']> = {
19
+ s: 'xs',
20
+ m: 'xs',
21
+ l: 's',
22
+ };
@@ -0,0 +1 @@
1
+ export * from './ListPrivate';
@@ -0,0 +1,90 @@
1
+ @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
+ @use '@cloud-ru/ds-figma-variables/build/scss/components/popupPrivate.module' as popupPrivate;
3
+
4
+ $sizes: 's', 'm', 'l';
5
+
6
+ $loader-height: (
7
+ 's': base.$sn-primitive-dimension-24,
8
+ 'm': base.$sn-primitive-dimension-32,
9
+ 'l': base.$sn-primitive-dimension-40,
10
+ );
11
+
12
+ .loader {
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+
17
+ @each $size in $sizes {
18
+ &[data-size='#{$size}'] {
19
+ height: base.simple-var($loader-height, $size);
20
+
21
+ &[data-no-items] {
22
+ $no-items-loading-height: calc(3 * base.simple-var($loader-height, $size));
23
+
24
+ min-width: calc(2 * $no-items-loading-height);
25
+ height: $no-items-loading-height;
26
+ }
27
+ }
28
+ }
29
+
30
+ &:focus-visible {
31
+ outline: base.$sn-theme-color-available-complementary solid base.$sn-primitive-strokeWeight-strokeSemiBold;
32
+ outline-offset: calc(0px - base.$sn-primitive-strokeWeight-strokeSemiBold);
33
+ }
34
+ }
35
+
36
+ .scrollStub {
37
+ height: base.$sn-primitive-dimension-1;
38
+ margin-top: calc(0px - base.$sn-primitive-dimension-1);
39
+ background: transparent;
40
+ }
41
+
42
+ // Обёртка вложенного списка рендерится как <li role='menuitem'> — снимаем нативный маркер списка.
43
+ .nestedItem {
44
+ list-style-type: none;
45
+ }
46
+
47
+ .footer {
48
+ display: flex;
49
+ flex-direction: column;
50
+ box-sizing: border-box;
51
+ padding: popupPrivate.$sn-popupPrivate-anatomy-dropdown-footer-paddingTop popupPrivate.$sn-popupPrivate-anatomy-dropdown-footer-paddingHorizontal
52
+ popupPrivate.$sn-popupPrivate-anatomy-dropdown-footer-paddingBottom;
53
+
54
+ &[data-divider] {
55
+ border-top: base.$sn-primitive-strokeWeight-strokeRegular solid base.$sn-theme-color-available-borderColor;
56
+ }
57
+ }
58
+
59
+ .header {
60
+ display: flex;
61
+ flex-direction: column;
62
+ gap: popupPrivate.$sn-popupPrivate-anatomy-dropdown-header-headlineWrapper-gap;
63
+
64
+ box-sizing: border-box;
65
+ padding: 0 popupPrivate.$sn-popupPrivate-anatomy-dropdown-header-headlineWrapper-paddingHorizontal
66
+ popupPrivate.$sn-popupPrivate-anatomy-dropdown-header-gap;
67
+
68
+ &[data-divider] {
69
+ margin-bottom: popupPrivate.$sn-popupPrivate-anatomy-dropdown-header-gap;
70
+ padding-bottom: popupPrivate.$sn-popupPrivate-anatomy-dropdown-header-headlineWrapper-paddingHorizontal;
71
+ border-bottom: base.$sn-primitive-strokeWeight-strokeRegular solid base.$sn-theme-color-available-borderColor;
72
+ }
73
+ }
74
+
75
+ .content {
76
+ overflow: hidden;
77
+ flex-grow: 1;
78
+ }
79
+
80
+ .virtualizedContainer {
81
+ position: relative;
82
+ width: 100%;
83
+ }
84
+
85
+ .virtualizedPositionBox {
86
+ position: absolute;
87
+ top: 0;
88
+ left: 0;
89
+ width: 100%;
90
+ }