@botiverse/raft-ui 0.51.0 → 0.52.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 (585) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/activity-inbox/activity-inbox-shell.d.mts +12 -0
  3. package/dist/components/activity-inbox/activity-inbox-shell.mjs +39 -0
  4. package/dist/components/activity-inbox/activity-inbox-shell.recipe.mjs +14 -0
  5. package/dist/components/activity-inbox/activity-inbox-sidebar.d.mts +6 -0
  6. package/dist/components/activity-inbox/activity-inbox-sidebar.mjs +22 -0
  7. package/dist/components/activity-inbox/activity-inbox-sidebar.recipe.mjs +22 -0
  8. package/dist/components/activity-inbox/activity-inbox-toolbar.d.mts +9 -0
  9. package/dist/components/activity-inbox/activity-inbox-toolbar.mjs +29 -0
  10. package/dist/components/activity-inbox/activity-inbox-toolbar.recipe.mjs +14 -0
  11. package/dist/components/activity-inbox/index.d.mts +4 -0
  12. package/dist/components/alert-dialog/alert-dialog.d.mts +41 -0
  13. package/dist/components/alert-dialog/alert-dialog.mjs +163 -0
  14. package/dist/components/alert-dialog/index.d.mts +2 -0
  15. package/dist/components/announcement-dialog/announcement-dialog.d.mts +18 -0
  16. package/dist/components/announcement-dialog/announcement-dialog.mjs +121 -0
  17. package/dist/components/announcement-dialog/index.d.mts +3 -0
  18. package/dist/components/app-rail/app-rail.d.mts +31 -0
  19. package/dist/components/app-rail/app-rail.mjs +126 -0
  20. package/dist/components/app-rail/app-rail.recipe.mjs +47 -0
  21. package/dist/components/app-rail/index.d.mts +2 -0
  22. package/dist/components/app-shell/app-shell.d.mts +27 -0
  23. package/dist/components/app-shell/app-shell.mjs +217 -0
  24. package/dist/components/app-shell/index.d.mts +2 -0
  25. package/dist/components/avatar/avatar.d.mts +169 -0
  26. package/dist/components/avatar/avatar.mjs +298 -0
  27. package/dist/components/avatar/index.d.mts +2 -0
  28. package/dist/components/badge/badge.d.mts +89 -0
  29. package/dist/components/badge/badge.mjs +203 -0
  30. package/dist/components/badge/index.d.mts +2 -0
  31. package/dist/components/banner/banner.d.mts +141 -0
  32. package/dist/components/banner/banner.mjs +228 -0
  33. package/dist/components/banner/index.d.mts +2 -0
  34. package/dist/components/button/button.d.mts +257 -0
  35. package/dist/components/button/button.mjs +177 -0
  36. package/dist/components/button/index.d.mts +2 -0
  37. package/dist/components/card/card.d.mts +21 -0
  38. package/dist/components/card/card.mjs +114 -0
  39. package/dist/components/card/card.recipe.d.mts +105 -0
  40. package/dist/components/card/card.recipe.mjs +67 -0
  41. package/dist/components/card/index.d.mts +2 -0
  42. package/dist/components/checkbox/checkbox-indicator.d.mts +92 -0
  43. package/dist/components/checkbox/checkbox-indicator.mjs +61 -0
  44. package/dist/components/checkbox/checkbox.d.mts +9 -0
  45. package/dist/components/checkbox/checkbox.mjs +40 -0
  46. package/dist/components/checkbox/index.d.mts +3 -0
  47. package/dist/components/choice-list/choice-list.d.mts +103 -0
  48. package/dist/components/choice-list/choice-list.mjs +301 -0
  49. package/dist/components/choice-list/choice-list.recipe.mjs +44 -0
  50. package/dist/components/choice-list/index.d.mts +2 -0
  51. package/dist/components/code-block/code-block.d.mts +30 -0
  52. package/dist/components/code-block/code-block.mjs +151 -0
  53. package/dist/components/code-block/code-block.recipe.mjs +47 -0
  54. package/dist/components/code-block/index.d.mts +2 -0
  55. package/dist/components/combobox/combobox.d.mts +69 -0
  56. package/dist/components/combobox/combobox.mjs +438 -0
  57. package/dist/components/combobox/index.d.mts +2 -0
  58. package/dist/components/combobox-select/combobox-select.d.mts +4 -0
  59. package/dist/components/combobox-select/combobox-select.list-side.mjs +16 -0
  60. package/dist/components/combobox-select/combobox-select.mjs +473 -0
  61. package/dist/components/combobox-select/combobox-select.options.mjs +21 -0
  62. package/dist/components/combobox-select/combobox-select.types.d.mts +83 -0
  63. package/dist/components/combobox-select/index.d.mts +3 -0
  64. package/dist/components/comment/comment-card.d.mts +40 -0
  65. package/dist/components/comment/comment-card.mjs +83 -0
  66. package/dist/components/comment/comment-entry.d.mts +24 -0
  67. package/dist/components/comment/comment-entry.mjs +75 -0
  68. package/dist/components/comment/comment-highlight.d.mts +18 -0
  69. package/dist/components/comment/comment-highlight.mjs +33 -0
  70. package/dist/components/comment/comment-margin-layout.d.mts +32 -0
  71. package/dist/components/comment/comment-margin-layout.mjs +44 -0
  72. package/dist/components/comment/comment-margin.d.mts +29 -0
  73. package/dist/components/comment/comment-margin.mjs +164 -0
  74. package/dist/components/comment/comment-marker.d.mts +16 -0
  75. package/dist/components/comment/comment-marker.mjs +24 -0
  76. package/dist/components/comment/comment.recipe.mjs +58 -0
  77. package/dist/components/comment/index.d.mts +8 -0
  78. package/dist/components/comment/use-comment-margin-fits.d.mts +16 -0
  79. package/dist/components/comment/use-comment-margin-fits.mjs +34 -0
  80. package/dist/components/composer/composer-attachment.recipe.mjs +85 -0
  81. package/dist/components/composer/composer-attachments-scroll-area.d.mts +5 -0
  82. package/dist/components/composer/composer-attachments-scroll-area.mjs +93 -0
  83. package/dist/components/composer/composer-attachments.d.mts +27 -0
  84. package/dist/components/composer/composer-attachments.mjs +147 -0
  85. package/dist/components/composer/composer-drop-overlay.d.mts +9 -0
  86. package/dist/components/composer/composer-drop-overlay.mjs +60 -0
  87. package/dist/components/composer/composer-drop-overlay.recipe.mjs +23 -0
  88. package/dist/components/composer/composer-root.d.mts +5 -0
  89. package/dist/components/composer/composer-root.mjs +18 -0
  90. package/dist/components/composer/composer-suggestion-list.d.mts +139 -0
  91. package/dist/components/composer/composer-suggestion-list.mjs +160 -0
  92. package/dist/components/composer/composer-toolbar-label.d.mts +5 -0
  93. package/dist/components/composer/composer-toolbar-label.mjs +24 -0
  94. package/dist/components/composer/composer.d.mts +20 -0
  95. package/dist/components/composer/composer.mjs +88 -0
  96. package/dist/components/composer/composer.recipe.mjs +29 -0
  97. package/dist/components/composer/index.d.mts +10 -0
  98. package/dist/components/composer/sortable-composer-attachments.d.mts +37 -0
  99. package/dist/components/composer/sortable-composer-attachments.mjs +247 -0
  100. package/dist/components/composer/use-composer-suggestions.d.mts +83 -0
  101. package/dist/components/composer/use-composer-suggestions.mjs +207 -0
  102. package/dist/components/context-menu/context-menu.d.mts +53 -0
  103. package/dist/components/context-menu/context-menu.mjs +275 -0
  104. package/dist/components/context-menu/index.d.mts +2 -0
  105. package/dist/components/conversation-panel/conversation-panel-empty-state.d.mts +9 -0
  106. package/dist/components/conversation-panel/conversation-panel-empty-state.mjs +57 -0
  107. package/dist/components/conversation-panel/conversation-panel.d.mts +20 -0
  108. package/dist/components/conversation-panel/conversation-panel.mjs +63 -0
  109. package/dist/components/conversation-panel/conversation-panel.recipe.mjs +15 -0
  110. package/dist/components/conversation-panel/index.d.mts +3 -0
  111. package/dist/components/copyable-code/copyable-code.d.mts +72 -0
  112. package/dist/components/copyable-code/copyable-code.mjs +153 -0
  113. package/dist/components/copyable-code/index.d.mts +2 -0
  114. package/dist/components/description-list/description-list.d.mts +59 -0
  115. package/dist/components/description-list/description-list.mjs +96 -0
  116. package/dist/components/description-list/index.d.mts +2 -0
  117. package/dist/components/dialog/dialog-sheet-context.mjs +58 -0
  118. package/dist/components/dialog/dialog-sheet.d.mts +31 -0
  119. package/dist/components/dialog/dialog-sheet.mjs +194 -0
  120. package/dist/components/dialog/dialog.d.mts +85 -0
  121. package/dist/components/dialog/dialog.mjs +371 -0
  122. package/dist/components/dialog/index.d.mts +3 -0
  123. package/dist/components/drag/drag-announcements.d.mts +72 -0
  124. package/dist/components/drag/drag-announcements.mjs +115 -0
  125. package/dist/components/drag/drag-lift.d.mts +100 -0
  126. package/dist/components/drag/drag-lift.mjs +276 -0
  127. package/dist/components/drag/drag-lists.d.mts +98 -0
  128. package/dist/components/drag/drag-lists.mjs +258 -0
  129. package/dist/components/drag/drag-sensors.d.mts +87 -0
  130. package/dist/components/drag/drag-sensors.mjs +169 -0
  131. package/dist/components/drag/drag.recipe.d.mts +7 -0
  132. package/dist/components/drag/drag.recipe.mjs +30 -0
  133. package/dist/components/drag/drop-placeholder.d.mts +41 -0
  134. package/dist/components/drag/drop-placeholder.mjs +161 -0
  135. package/dist/components/drag/index.d.mts +8 -0
  136. package/dist/components/drawer/drawer.d.mts +34 -0
  137. package/dist/components/drawer/drawer.mjs +202 -0
  138. package/dist/components/drawer/drawer.recipe.mjs +175 -0
  139. package/dist/components/drawer/index.d.mts +2 -0
  140. package/dist/components/dropdown-menu/dropdown-menu.d.mts +62 -0
  141. package/dist/components/dropdown-menu/dropdown-menu.mjs +319 -0
  142. package/dist/components/dropdown-menu/index.d.mts +2 -0
  143. package/dist/components/ellipsis/ellipsis.d.mts +55 -0
  144. package/dist/components/ellipsis/ellipsis.mjs +320 -0
  145. package/dist/components/ellipsis/index.d.mts +3 -0
  146. package/dist/components/empty-state/empty-state.d.mts +15 -0
  147. package/dist/components/empty-state/empty-state.mjs +102 -0
  148. package/dist/components/empty-state/index.d.mts +2 -0
  149. package/dist/components/field/field.d.mts +79 -0
  150. package/dist/components/field/field.mjs +100 -0
  151. package/dist/components/field/index.d.mts +2 -0
  152. package/dist/components/file-preview/file-preview.d.mts +17 -0
  153. package/dist/components/file-preview/file-preview.mjs +210 -0
  154. package/dist/components/file-preview/file-preview.recipe.d.mts +99 -0
  155. package/dist/components/file-preview/file-preview.recipe.mjs +39 -0
  156. package/dist/components/file-preview/index.d.mts +2 -0
  157. package/dist/components/files/files.d.mts +35 -0
  158. package/dist/components/files/files.mjs +69 -0
  159. package/dist/components/files/files.recipe.mjs +40 -0
  160. package/dist/components/files/index.d.mts +2 -0
  161. package/dist/components/filter-chip/filter-chip.d.mts +25 -0
  162. package/dist/components/filter-chip/filter-chip.mjs +59 -0
  163. package/dist/components/filter-chip/index.d.mts +2 -0
  164. package/dist/components/float-button/float-button.d.mts +36 -0
  165. package/dist/components/float-button/float-button.mjs +116 -0
  166. package/dist/components/float-button/float-button.position.d.mts +6 -0
  167. package/dist/components/float-button/float-button.position.mjs +41 -0
  168. package/dist/components/float-button/index.d.mts +3 -0
  169. package/dist/components/form-section/form-section.d.mts +16 -0
  170. package/dist/components/form-section/form-section.mjs +53 -0
  171. package/dist/components/form-section/index.d.mts +2 -0
  172. package/dist/components/icon-tile/icon-tile.d.mts +97 -0
  173. package/dist/components/icon-tile/icon-tile.mjs +49 -0
  174. package/dist/components/icon-tile/index.d.mts +2 -0
  175. package/dist/components/icons/action-icons.d.mts +34 -0
  176. package/dist/components/icons/action-icons.mjs +383 -0
  177. package/dist/components/icons/conversation-icons.d.mts +12 -0
  178. package/dist/components/icons/conversation-icons.mjs +147 -0
  179. package/dist/components/icons/index.d.mts +4 -0
  180. package/dist/components/icons/object-icons.d.mts +6 -0
  181. package/dist/components/icons/object-icons.mjs +27 -0
  182. package/dist/components/inbox-item/inbox-item-leading-badge.d.mts +13 -0
  183. package/dist/components/inbox-item/inbox-item-leading-badge.mjs +27 -0
  184. package/dist/components/inbox-item/inbox-item-skeleton.d.mts +46 -0
  185. package/dist/components/inbox-item/inbox-item-skeleton.mjs +89 -0
  186. package/dist/components/inbox-item/inbox-item-skeleton.recipe.mjs +20 -0
  187. package/dist/components/inbox-item/inbox-item.d.mts +71 -0
  188. package/dist/components/inbox-item/inbox-item.mjs +276 -0
  189. package/dist/components/inbox-item/inbox-item.recipe.mjs +137 -0
  190. package/dist/components/inbox-item/index.d.mts +2 -0
  191. package/dist/components/inline-code/index.d.mts +2 -0
  192. package/dist/components/inline-code/inline-code.d.mts +8 -0
  193. package/dist/components/inline-code/inline-code.mjs +30 -0
  194. package/dist/components/input/index.d.mts +2 -0
  195. package/dist/components/input/input.d.mts +16 -0
  196. package/dist/components/input/input.mjs +20 -0
  197. package/dist/components/input/input.recipe.mjs +12 -0
  198. package/dist/components/input-group/index.d.mts +2 -0
  199. package/dist/components/input-group/input-group.d.mts +93 -0
  200. package/dist/components/input-group/input-group.mjs +178 -0
  201. package/dist/components/kbd/index.d.mts +2 -0
  202. package/dist/components/kbd/kbd.d.mts +7 -0
  203. package/dist/components/kbd/kbd.mjs +34 -0
  204. package/dist/components/label/index.d.mts +2 -0
  205. package/dist/components/label/label.d.mts +60 -0
  206. package/dist/components/label/label.mjs +75 -0
  207. package/dist/components/legacy-task-panel/index.d.mts +2 -0
  208. package/dist/components/legacy-task-panel/legacy-task-panel.d.mts +57 -0
  209. package/dist/components/legacy-task-panel/legacy-task-panel.mjs +234 -0
  210. package/dist/components/legacy-task-panel/legacy-task-panel.recipe.mjs +30 -0
  211. package/dist/components/lightbox/index.d.mts +2 -0
  212. package/dist/components/lightbox/lightbox.d.mts +55 -0
  213. package/dist/components/lightbox/lightbox.mjs +336 -0
  214. package/dist/components/list-row/index.d.mts +2 -0
  215. package/dist/components/list-row/list-row-skeleton.d.mts +21 -0
  216. package/dist/components/list-row/list-row-skeleton.mjs +43 -0
  217. package/dist/components/list-row/list-row.d.mts +66 -0
  218. package/dist/components/list-row/list-row.mjs +167 -0
  219. package/dist/components/list-row/list-row.recipe.d.mts +126 -0
  220. package/dist/components/list-row/list-row.recipe.mjs +94 -0
  221. package/dist/components/live-agent-activity-bar/index.d.mts +2 -0
  222. package/dist/components/live-agent-activity-bar/live-agent-activity-bar.d.mts +25 -0
  223. package/dist/components/live-agent-activity-bar/live-agent-activity-bar.mjs +107 -0
  224. package/dist/components/logo/index.d.mts +2 -0
  225. package/dist/components/logo/raft-logo.d.mts +9 -0
  226. package/dist/components/logo/raft-logo.mjs +63 -0
  227. package/dist/components/markdown/index.d.mts +2 -0
  228. package/dist/components/markdown/markdown-parts.d.mts +54 -0
  229. package/dist/components/markdown/markdown-parts.mjs +153 -0
  230. package/dist/components/markdown/markdown.recipe.mjs +77 -0
  231. package/dist/components/message-action-card/index.d.mts +2 -0
  232. package/dist/components/message-action-card/message-action-card-content.recipe.mjs +50 -0
  233. package/dist/components/message-action-card/message-action-card.d.mts +95 -0
  234. package/dist/components/message-action-card/message-action-card.mjs +298 -0
  235. package/dist/components/message-action-card/message-action-card.recipe.mjs +47 -0
  236. package/dist/components/message-attachment/index.d.mts +5 -0
  237. package/dist/components/message-attachment/message-attachment.d.mts +27 -0
  238. package/dist/components/message-attachment/message-attachment.mjs +129 -0
  239. package/dist/components/message-attachment/message-attachment.recipe.mjs +36 -0
  240. package/dist/components/message-attachment/message-image-gallery-rows.d.mts +47 -0
  241. package/dist/components/message-attachment/message-image-gallery-rows.mjs +55 -0
  242. package/dist/components/message-attachment/message-image-gallery.d.mts +32 -0
  243. package/dist/components/message-attachment/message-image-gallery.mjs +105 -0
  244. package/dist/components/message-attachment/message-image-gallery.recipe.mjs +61 -0
  245. package/dist/components/message-attachment/message-video-preview.d.mts +19 -0
  246. package/dist/components/message-attachment/message-video-preview.mjs +92 -0
  247. package/dist/components/message-attachment/message-video-preview.recipe.mjs +33 -0
  248. package/dist/components/message-embed/index.d.mts +2 -0
  249. package/dist/components/message-embed/message-embed.d.mts +12 -0
  250. package/dist/components/message-embed/message-embed.mjs +42 -0
  251. package/dist/components/message-embed/message-embed.recipe.mjs +14 -0
  252. package/dist/components/message-forwarded-bundle/index.d.mts +2 -0
  253. package/dist/components/message-forwarded-bundle/message-forwarded-bundle.d.mts +92 -0
  254. package/dist/components/message-forwarded-bundle/message-forwarded-bundle.mjs +324 -0
  255. package/dist/components/message-forwarded-bundle/message-forwarded-bundle.recipe.mjs +81 -0
  256. package/dist/components/message-item/index.d.mts +13 -0
  257. package/dist/components/message-item/message-footer.d.mts +20 -0
  258. package/dist/components/message-item/message-footer.mjs +54 -0
  259. package/dist/components/message-item/message-footer.recipe.mjs +46 -0
  260. package/dist/components/message-item/message-item-content.d.mts +22 -0
  261. package/dist/components/message-item/message-item-content.mjs +81 -0
  262. package/dist/components/message-item/message-item-delegated.d.mts +38 -0
  263. package/dist/components/message-item/message-item-delegated.mjs +72 -0
  264. package/dist/components/message-item/message-item-gutter.d.mts +10 -0
  265. package/dist/components/message-item/message-item-gutter.mjs +41 -0
  266. package/dist/components/message-item/message-item-header.d.mts +29 -0
  267. package/dist/components/message-item/message-item-header.mjs +107 -0
  268. package/dist/components/message-item/message-item-label.mjs +113 -0
  269. package/dist/components/message-item/message-item-root.d.mts +25 -0
  270. package/dist/components/message-item/message-item-root.mjs +39 -0
  271. package/dist/components/message-item/message-item-toolbar.d.mts +9 -0
  272. package/dist/components/message-item/message-item-toolbar.mjs +131 -0
  273. package/dist/components/message-item/message-item.recipe.d.mts +101 -0
  274. package/dist/components/message-item/message-item.recipe.mjs +114 -0
  275. package/dist/components/message-item/message-multi-select.d.mts +15 -0
  276. package/dist/components/message-item/message-multi-select.mjs +49 -0
  277. package/dist/components/message-item/message-multi-select.recipe.mjs +23 -0
  278. package/dist/components/message-item/message-reaction.d.mts +39 -0
  279. package/dist/components/message-item/message-reaction.mjs +188 -0
  280. package/dist/components/message-item/message-reaction.recipe.mjs +76 -0
  281. package/dist/components/message-item/message-reference.d.mts +50 -0
  282. package/dist/components/message-item/message-reference.mjs +111 -0
  283. package/dist/components/message-item/message-reference.recipe.d.mts +6 -0
  284. package/dist/components/message-item/message-reference.recipe.mjs +63 -0
  285. package/dist/components/message-item/message-text-selection-toolbar.d.mts +24 -0
  286. package/dist/components/message-item/message-text-selection-toolbar.mjs +13 -0
  287. package/dist/components/message-list/index.d.mts +4 -0
  288. package/dist/components/message-list/message-list-jump.d.mts +21 -0
  289. package/dist/components/message-list/message-list-jump.mjs +73 -0
  290. package/dist/components/message-list/message-list-markers.d.mts +13 -0
  291. package/dist/components/message-list/message-list-markers.mjs +70 -0
  292. package/dist/components/message-list/message-list.d.mts +7 -0
  293. package/dist/components/message-list/message-list.mjs +52 -0
  294. package/dist/components/message-list/message-list.recipe.mjs +54 -0
  295. package/dist/components/message-quoted-preview/index.d.mts +2 -0
  296. package/dist/components/message-quoted-preview/message-quoted-preview.d.mts +40 -0
  297. package/dist/components/message-quoted-preview/message-quoted-preview.mjs +144 -0
  298. package/dist/components/message-quoted-preview/message-quoted-preview.recipe.mjs +38 -0
  299. package/dist/components/message-replies/index.d.mts +2 -0
  300. package/dist/components/message-replies/message-replies.d.mts +17 -0
  301. package/dist/components/message-replies/message-replies.mjs +79 -0
  302. package/dist/components/message-replies/message-replies.recipe.mjs +25 -0
  303. package/dist/components/message-translation/index.d.mts +2 -0
  304. package/dist/components/message-translation/message-translation.d.mts +20 -0
  305. package/dist/components/message-translation/message-translation.mjs +64 -0
  306. package/dist/components/message-translation/message-translation.recipe.mjs +27 -0
  307. package/dist/components/meter/index.d.mts +2 -0
  308. package/dist/components/meter/meter.d.mts +107 -0
  309. package/dist/components/meter/meter.mjs +118 -0
  310. package/dist/components/mobile-nav/index.d.mts +3 -0
  311. package/dist/components/mobile-nav/mobile-nav-server.d.mts +71 -0
  312. package/dist/components/mobile-nav/mobile-nav-server.mjs +287 -0
  313. package/dist/components/mobile-nav/mobile-nav.d.mts +12 -0
  314. package/dist/components/mobile-nav/mobile-nav.mjs +73 -0
  315. package/dist/components/mode-bar/index.d.mts +2 -0
  316. package/dist/components/mode-bar/mode-bar.d.mts +33 -0
  317. package/dist/components/mode-bar/mode-bar.mjs +115 -0
  318. package/dist/components/notification-center/index.d.mts +2 -0
  319. package/dist/components/notification-center/notification-center.d.mts +225 -0
  320. package/dist/components/notification-center/notification-center.mjs +340 -0
  321. package/dist/components/panel/index.d.mts +7 -0
  322. package/dist/components/panel/panel-action.d.mts +15 -0
  323. package/dist/components/panel/panel-action.mjs +23 -0
  324. package/dist/components/panel/panel-action.recipe.mjs +40 -0
  325. package/dist/components/panel/panel-header.d.mts +34 -0
  326. package/dist/components/panel/panel-header.mjs +135 -0
  327. package/dist/components/panel/panel-header.recipe.mjs +78 -0
  328. package/dist/components/panel/panel-notice.d.mts +16 -0
  329. package/dist/components/panel/panel-notice.mjs +77 -0
  330. package/dist/components/panel/panel-split-action.d.mts +34 -0
  331. package/dist/components/panel/panel-split-action.mjs +69 -0
  332. package/dist/components/panel/panel-split-action.recipe.mjs +53 -0
  333. package/dist/components/panel/panel-toggle-action.d.mts +6 -0
  334. package/dist/components/panel/panel-toggle-action.mjs +15 -0
  335. package/dist/components/panel/panel.d.mts +25 -0
  336. package/dist/components/panel/panel.mjs +96 -0
  337. package/dist/components/panel/panel.recipe.mjs +24 -0
  338. package/dist/components/picker-trigger-button/index.d.mts +2 -0
  339. package/dist/components/picker-trigger-button/picker-trigger-button.d.mts +7 -0
  340. package/dist/components/picker-trigger-button/picker-trigger-button.mjs +36 -0
  341. package/dist/components/popover/index.d.mts +2 -0
  342. package/dist/components/popover/popover.d.mts +41 -0
  343. package/dist/components/popover/popover.mjs +184 -0
  344. package/dist/components/preview-card/index.d.mts +2 -0
  345. package/dist/components/preview-card/preview-card.d.mts +43 -0
  346. package/dist/components/preview-card/preview-card.mjs +197 -0
  347. package/dist/components/profile-panel/index.d.mts +2 -0
  348. package/dist/components/profile-panel/profile-panel.d.mts +14 -0
  349. package/dist/components/profile-panel/profile-panel.mjs +46 -0
  350. package/dist/components/profile-panel/profile-panel.recipe.mjs +14 -0
  351. package/dist/components/progress/index.d.mts +2 -0
  352. package/dist/components/progress/progress.d.mts +119 -0
  353. package/dist/components/progress/progress.mjs +139 -0
  354. package/dist/components/pull-to-refresh/index.d.mts +4 -0
  355. package/dist/components/pull-to-refresh/pull-to-refresh-gesture.d.mts +30 -0
  356. package/dist/components/pull-to-refresh/pull-to-refresh-gesture.mjs +134 -0
  357. package/dist/components/pull-to-refresh/pull-to-refresh-indicator.d.mts +21 -0
  358. package/dist/components/pull-to-refresh/pull-to-refresh-indicator.mjs +153 -0
  359. package/dist/components/pull-to-refresh/pull-to-refresh-material-progress.mjs +150 -0
  360. package/dist/components/pull-to-refresh/use-pull-to-refresh.d.mts +55 -0
  361. package/dist/components/pull-to-refresh/use-pull-to-refresh.mjs +156 -0
  362. package/dist/components/radio-group/index.d.mts +2 -0
  363. package/dist/components/radio-group/radio-group.d.mts +14 -0
  364. package/dist/components/radio-group/radio-group.mjs +59 -0
  365. package/dist/components/resizable/index.d.mts +2 -0
  366. package/dist/components/resizable/resizable.d.mts +15 -0
  367. package/dist/components/resizable/resizable.mjs +39 -0
  368. package/dist/components/resizable/resizable.recipe.mjs +24 -0
  369. package/dist/components/scroll-area/index.d.mts +2 -0
  370. package/dist/components/scroll-area/scroll-area.d.mts +17 -0
  371. package/dist/components/scroll-area/scroll-area.mjs +55 -0
  372. package/dist/components/scroll-area/scroll-area.recipe.mjs +23 -0
  373. package/dist/components/search/index.d.mts +6 -0
  374. package/dist/components/search/search-entity.d.mts +24 -0
  375. package/dist/components/search/search-entity.mjs +106 -0
  376. package/dist/components/search/search-entity.recipe.mjs +41 -0
  377. package/dist/components/search/search-message.d.mts +25 -0
  378. package/dist/components/search/search-message.mjs +115 -0
  379. package/dist/components/search/search-message.recipe.mjs +32 -0
  380. package/dist/components/search/search-thread.d.mts +17 -0
  381. package/dist/components/search/search-thread.mjs +79 -0
  382. package/dist/components/search/search-thread.recipe.mjs +16 -0
  383. package/dist/components/search/search-trigger.d.mts +15 -0
  384. package/dist/components/search/search-trigger.mjs +59 -0
  385. package/dist/components/search/search.d.mts +23 -0
  386. package/dist/components/search/search.mjs +88 -0
  387. package/dist/components/search/search.recipe.mjs +22 -0
  388. package/dist/components/segmented-control/index.d.mts +2 -0
  389. package/dist/components/segmented-control/segmented-control.d.mts +38 -0
  390. package/dist/components/segmented-control/segmented-control.mjs +306 -0
  391. package/dist/components/select/index.d.mts +2 -0
  392. package/dist/components/select/select.d.mts +95 -0
  393. package/dist/components/select/select.mjs +483 -0
  394. package/dist/components/separator/index.d.mts +2 -0
  395. package/dist/components/separator/separator.d.mts +10 -0
  396. package/dist/components/separator/separator.mjs +49 -0
  397. package/dist/components/sidebar/index.d.mts +5 -0
  398. package/dist/components/sidebar/sidebar-item.d.mts +64 -0
  399. package/dist/components/sidebar/sidebar-item.mjs +201 -0
  400. package/dist/components/sidebar/sidebar-item.recipe.mjs +100 -0
  401. package/dist/components/sidebar/sidebar-menu.d.mts +13 -0
  402. package/dist/components/sidebar/sidebar-menu.mjs +67 -0
  403. package/dist/components/sidebar/sidebar-menu.recipe.mjs +22 -0
  404. package/dist/components/sidebar/sidebar-section.d.mts +41 -0
  405. package/dist/components/sidebar/sidebar-section.mjs +164 -0
  406. package/dist/components/sidebar/sidebar-section.recipe.mjs +45 -0
  407. package/dist/components/sidebar/sidebar.d.mts +17 -0
  408. package/dist/components/sidebar/sidebar.mjs +149 -0
  409. package/dist/components/sidebar/sidebar.recipe.mjs +37 -0
  410. package/dist/components/skeleton/index.d.mts +2 -0
  411. package/dist/components/skeleton/skeleton.d.mts +50 -0
  412. package/dist/components/skeleton/skeleton.mjs +29 -0
  413. package/dist/components/spinner/index.d.mts +2 -0
  414. package/dist/components/spinner/spinner.d.mts +77 -0
  415. package/dist/components/spinner/spinner.mjs +118 -0
  416. package/dist/components/status/index.d.mts +2 -0
  417. package/dist/components/status/status.d.mts +143 -0
  418. package/dist/components/status/status.mjs +56 -0
  419. package/dist/components/steps/index.d.mts +3 -0
  420. package/dist/components/steps/otter-indicator.d.mts +17 -0
  421. package/dist/components/steps/otter-indicator.mjs +331 -0
  422. package/dist/components/steps/steps.d.mts +50 -0
  423. package/dist/components/steps/steps.mjs +174 -0
  424. package/dist/components/switch/index.d.mts +2 -0
  425. package/dist/components/switch/switch.d.mts +9 -0
  426. package/dist/components/switch/switch.mjs +50 -0
  427. package/dist/components/system-message/index.d.mts +2 -0
  428. package/dist/components/system-message/system-message.d.mts +27 -0
  429. package/dist/components/system-message/system-message.mjs +113 -0
  430. package/dist/components/system-message/system-message.recipe.mjs +34 -0
  431. package/dist/components/table/index.d.mts +2 -0
  432. package/dist/components/table/table.d.mts +35 -0
  433. package/dist/components/table/table.mjs +102 -0
  434. package/dist/components/table/table.recipe.mjs +31 -0
  435. package/dist/components/tabs/index.d.mts +2 -0
  436. package/dist/components/tabs/tabs.d.mts +185 -0
  437. package/dist/components/tabs/tabs.mjs +528 -0
  438. package/dist/components/task-board/index.d.mts +2 -0
  439. package/dist/components/task-board/task-board-column.recipe.mjs +46 -0
  440. package/dist/components/task-board/task-board.d.mts +40 -0
  441. package/dist/components/task-board/task-board.mjs +155 -0
  442. package/dist/components/task-card/index.d.mts +2 -0
  443. package/dist/components/task-card/task-card-status.recipe.mjs +17 -0
  444. package/dist/components/task-card/task-card.d.mts +30 -0
  445. package/dist/components/task-card/task-card.mjs +141 -0
  446. package/dist/components/task-card/task-card.recipe.mjs +39 -0
  447. package/dist/components/task-dnd/index.d.mts +2 -0
  448. package/dist/components/task-dnd/task-dnd.d.mts +75 -0
  449. package/dist/components/task-dnd/task-dnd.mjs +341 -0
  450. package/dist/components/task-dnd/task-dnd.recipe.mjs +20 -0
  451. package/dist/components/task-list/index.d.mts +2 -0
  452. package/dist/components/task-list/task-list-section.recipe.mjs +37 -0
  453. package/dist/components/task-list/task-list.d.mts +34 -0
  454. package/dist/components/task-list/task-list.mjs +119 -0
  455. package/dist/components/tasks/index.d.mts +7 -0
  456. package/dist/components/tasks/task-chip.d.mts +14 -0
  457. package/dist/components/tasks/task-chip.mjs +81 -0
  458. package/dist/components/tasks/task-loading.d.mts +7 -0
  459. package/dist/components/tasks/task-loading.mjs +32 -0
  460. package/dist/components/tasks/task-loading.recipe.mjs +8 -0
  461. package/dist/components/tasks/task-status-badge.d.mts +24 -0
  462. package/dist/components/tasks/task-status-badge.mjs +24 -0
  463. package/dist/components/tasks/task-status-icon.d.mts +13 -0
  464. package/dist/components/tasks/task-status-icon.mjs +90 -0
  465. package/dist/components/tasks/task-status.recipe.d.mts +62 -0
  466. package/dist/components/tasks/task-status.recipe.mjs +33 -0
  467. package/dist/components/tasks/tasks-panel.d.mts +22 -0
  468. package/dist/components/tasks/tasks-panel.mjs +114 -0
  469. package/dist/components/tasks/tasks-panel.recipe.mjs +36 -0
  470. package/dist/components/text/index.d.mts +2 -0
  471. package/dist/components/text/text.d.mts +186 -0
  472. package/dist/components/text/text.mjs +114 -0
  473. package/dist/components/text-link/index.d.mts +2 -0
  474. package/dist/components/text-link/text-link.d.mts +36 -0
  475. package/dist/components/text-link/text-link.mjs +60 -0
  476. package/dist/components/text-selection-toolbar/index.d.mts +3 -0
  477. package/dist/components/text-selection-toolbar/text-selection-anchor.d.mts +22 -0
  478. package/dist/components/text-selection-toolbar/text-selection-anchor.mjs +106 -0
  479. package/dist/components/text-selection-toolbar/text-selection-toolbar.d.mts +20 -0
  480. package/dist/components/text-selection-toolbar/text-selection-toolbar.mjs +41 -0
  481. package/dist/components/text-selection-toolbar/text-selection-toolbar.recipe.mjs +19 -0
  482. package/dist/components/textarea/index.d.mts +2 -0
  483. package/dist/components/textarea/textarea.d.mts +16 -0
  484. package/dist/components/textarea/textarea.mjs +62 -0
  485. package/dist/components/thread-panel/index.d.mts +2 -0
  486. package/dist/components/thread-panel/thread-panel.d.mts +31 -0
  487. package/dist/components/thread-panel/thread-panel.mjs +162 -0
  488. package/dist/components/thread-panel/thread-panel.recipe.mjs +36 -0
  489. package/dist/components/timeline/index.d.mts +2 -0
  490. package/dist/components/timeline/timeline.d.mts +44 -0
  491. package/dist/components/timeline/timeline.mjs +81 -0
  492. package/dist/components/toast/index.d.mts +2 -0
  493. package/dist/components/toast/toast.d.mts +263 -0
  494. package/dist/components/toast/toast.mjs +556 -0
  495. package/dist/components/toggle-group/index.d.mts +2 -0
  496. package/dist/components/toggle-group/toggle-group.d.mts +15 -0
  497. package/dist/components/toggle-group/toggle-group.mjs +64 -0
  498. package/dist/components/tooltip/index.d.mts +2 -0
  499. package/dist/components/tooltip/tooltip.d.mts +18 -0
  500. package/dist/components/tooltip/tooltip.mjs +197 -0
  501. package/dist/components/virtual-list/ItemColumns.mjs +37 -0
  502. package/dist/components/virtual-list/VirtualList.d.mts +4 -0
  503. package/dist/components/virtual-list/VirtualList.mjs +1401 -0
  504. package/dist/components/virtual-list/VirtualListContext.mjs +5 -0
  505. package/dist/components/virtual-list/hooks/use-event-callback.mjs +10 -0
  506. package/dist/components/virtual-list/hooks/use-ios-momentum-compensation.mjs +148 -0
  507. package/dist/components/virtual-list/hooks/use-keyboard-scroll.mjs +42 -0
  508. package/dist/components/virtual-list/hooks/use-latest-ref.mjs +10 -0
  509. package/dist/components/virtual-list/hooks/use-layout-effect-with-previous.mjs +16 -0
  510. package/dist/components/virtual-list/hooks/use-memo-with-previous.mjs +22 -0
  511. package/dist/components/virtual-list/hooks/use-non-passive-wheel.mjs +23 -0
  512. package/dist/components/virtual-list/hooks/use-non-virtual-content-resize.mjs +28 -0
  513. package/dist/components/virtual-list/hooks/use-scroll-anchor.mjs +55 -0
  514. package/dist/components/virtual-list/index.d.mts +5 -0
  515. package/dist/components/virtual-list/public-types.d.mts +341 -0
  516. package/dist/components/virtual-list/resize-observer/ResizeObserverWrapper.d.mts +5 -0
  517. package/dist/components/virtual-list/resize-observer/ResizeObserverWrapper.mjs +70 -0
  518. package/dist/components/virtual-list/resize-observer/resize-observer-delegate.d.mts +6 -0
  519. package/dist/components/virtual-list/resize-observer/resize-observer-delegate.mjs +54 -0
  520. package/dist/components/virtual-list/utils/align.mjs +19 -0
  521. package/dist/components/virtual-list/utils/constants.mjs +30 -0
  522. package/dist/components/virtual-list/utils/fenwick-tree.mjs +66 -0
  523. package/dist/components/virtual-list/utils/items-anchor.mjs +49 -0
  524. package/dist/components/virtual-list/utils/measure.mjs +77 -0
  525. package/dist/components/virtual-list/utils/platform.mjs +39 -0
  526. package/dist/components/virtual-list/utils/range.mjs +103 -0
  527. package/dist/components/virtual-list/utils/size-cache.mjs +35 -0
  528. package/dist/components/workspace-button/index.d.mts +2 -0
  529. package/dist/components/workspace-button/workspace-button.d.mts +9 -0
  530. package/dist/components/workspace-button/workspace-button.mjs +28 -0
  531. package/dist/index.d.mts +239 -4864
  532. package/dist/index.mjs +142 -17054
  533. package/dist/lib/chip-remove.mjs +17 -0
  534. package/dist/lib/data-attributes.d.mts +5 -0
  535. package/dist/lib/decision-width.mjs +9 -0
  536. package/dist/lib/default-native-button.mjs +8 -0
  537. package/dist/lib/desktop-media.mjs +10 -0
  538. package/dist/lib/drag-escape.mjs +37 -0
  539. package/dist/lib/frame-insets.mjs +127 -0
  540. package/dist/lib/head-edges.mjs +44 -0
  541. package/dist/lib/hud-text-action.mjs +10 -0
  542. package/dist/lib/inline-chip.mjs +30 -0
  543. package/dist/lib/input-modality.d.mts +36 -0
  544. package/dist/lib/input-modality.mjs +186 -0
  545. package/dist/lib/list-cell.mjs +21 -0
  546. package/dist/lib/located.d.mts +25 -0
  547. package/dist/lib/located.mjs +28 -0
  548. package/dist/lib/overlay-depth.d.mts +42 -0
  549. package/dist/lib/overlay-depth.mjs +59 -0
  550. package/dist/lib/phone-media.mjs +24 -0
  551. package/dist/lib/presence.d.mts +16 -0
  552. package/dist/lib/presence.mjs +16 -0
  553. package/dist/lib/row-tone.d.mts +8 -0
  554. package/dist/lib/search-hit.mjs +18 -0
  555. package/dist/lib/stacked-actions.mjs +112 -0
  556. package/dist/lib/styled-props.d.mts +15 -0
  557. package/dist/lib/tap-activation.mjs +133 -0
  558. package/dist/lib/theme/theme-context.d.mts +10 -0
  559. package/dist/lib/theme/theme-context.mjs +9 -0
  560. package/dist/lib/theme/theme-provider.d.mts +23 -0
  561. package/dist/lib/theme/theme-provider.mjs +61 -0
  562. package/dist/lib/theme/theme-scope.mjs +19 -0
  563. package/dist/lib/theme/use-theme.d.mts +5 -0
  564. package/dist/lib/theme/use-theme.mjs +9 -0
  565. package/dist/lib/touch-drag.d.mts +55 -0
  566. package/dist/lib/touch-drag.mjs +151 -0
  567. package/dist/lib/truncation.d.mts +26 -0
  568. package/dist/lib/truncation.mjs +153 -0
  569. package/dist/lib/tv.d.mts +2 -0
  570. package/dist/lib/tv.mjs +14 -0
  571. package/dist/lib/use-copy-to-clipboard.mjs +58 -0
  572. package/dist/lib/use-merged-ref.mjs +60 -0
  573. package/dist/lib/use-mobile-viewport.mjs +17 -0
  574. package/dist/lib/use-overflow-title.mjs +49 -0
  575. package/dist/lib/use-scrollbar-size.d.mts +16 -0
  576. package/dist/lib/use-scrollbar-size.mjs +46 -0
  577. package/dist/lib/use-truncated.d.mts +20 -0
  578. package/dist/lib/use-truncated.mjs +34 -0
  579. package/dist/lib/without-children.d.mts +8 -0
  580. package/dist/wip.d.mts +61 -1190
  581. package/dist/wip.mjs +43 -2970
  582. package/package.json +8 -1
  583. package/dist/index-C3ymUW98.d.mts +0 -1816
  584. package/dist/mode-bar-tGnYByXp.mjs +0 -7564
  585. package/dist/style.css +0 -1395
@@ -0,0 +1,1401 @@
1
+ import { cn } from "../../cn.mjs";
2
+ import { useMergedRef } from "../../lib/use-merged-ref.mjs";
3
+ import { EMPTY_ARRAY, ITEM_KEY_ATTR, NON_VIRTUAL_VISIBLE_ITEMS_STYLE, RENDER_THRASHING_WINDOW_MS, VIRTUAL_VISIBLE_ITEMS_STYLE } from "./utils/constants.mjs";
4
+ import { FenwickTree } from "./utils/fenwick-tree.mjs";
5
+ import { findItemsAnchor, getAnchoredRange } from "./utils/items-anchor.mjs";
6
+ import { useEventCallback } from "./hooks/use-event-callback.mjs";
7
+ import { useLatestRef } from "./hooks/use-latest-ref.mjs";
8
+ import { useLayoutEffectWithPrevious } from "./hooks/use-layout-effect-with-previous.mjs";
9
+ import { useMemoWithPrevious } from "./hooks/use-memo-with-previous.mjs";
10
+ import { useNonPassiveWheel } from "./hooks/use-non-passive-wheel.mjs";
11
+ import { ColumnsContext, ItemColumns } from "./ItemColumns.mjs";
12
+ import { createLatestInNextFrame, getWheelDeltaScale, isCoarsePointer, isIOS } from "./utils/platform.mjs";
13
+ import { getAlignedScrollTop } from "./utils/align.mjs";
14
+ import { measureRowSpans, measureRowStart } from "./utils/measure.mjs";
15
+ import { createTypicalSizeCache, getTypicalSize, recordMeasuredSize } from "./utils/size-cache.mjs";
16
+ import { getHorizontalRange, getNeededEnd, getOverscannedRange, getVerticalRange, haveSameKeys, isHiddenByDisplayNone, px } from "./utils/range.mjs";
17
+ import { getResizeObserverDelegate } from "./resize-observer/resize-observer-delegate.mjs";
18
+ import { ResizeObserverWrapper } from "./resize-observer/ResizeObserverWrapper.mjs";
19
+ import { useIosMomentumCompensation } from "./hooks/use-ios-momentum-compensation.mjs";
20
+ import { useKeyboardScroll } from "./hooks/use-keyboard-scroll.mjs";
21
+ import { useNonVirtualContentResize } from "./hooks/use-non-virtual-content-resize.mjs";
22
+ import { useScrollAnchor } from "./hooks/use-scroll-anchor.mjs";
23
+ import { VirtualListContext } from "./VirtualListContext.mjs";
24
+ import { createElement, useCallback, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
25
+ import { jsx, jsxs } from "react/jsx-runtime";
26
+ import { flushSync } from "react-dom";
27
+ //#region src/components/virtual-list/VirtualList.tsx
28
+ /**
29
+ * The most range updates one aligned jump goes through before it stops (each one mounts and measures the
30
+ * rows the previous position brought into view; it is usually stable after 2-3).
31
+ */
32
+ const MAX_ALIGN_STEPS = 10;
33
+ function VirtualList(props) {
34
+ const { virtual = true, sessionId, showScrollbar = false, columns = EMPTY_ARRAY, renderCol, renderItemWithCols, items = EMPTY_ARRAY, itemMinSize, itemEstimatedSize, itemResizable = false, itemsStyle, visibleItemsTag = "div", visibleItemsProps, ignoreItemResize = false, onScroll, onWheel, onResize, defaultScrollKey, defaultScrollIndex, getKey, paddingTop = 0, paddingBottom = 0, children: renderItemChild, ItemComponent, empty, emptyAlign = "start", className, style, itemsClassName, footer, footerAfterBottomPadding, header, domRef, ref: _ref, onContentResize, onTransformChange, componentRef, printable, catchWheel = false, onRenderAnomaly, keyboardPageBottomOcclusion = 0, focusable = true, keepAnchorOnItemsChange = false, canAnchorItem, onKeyDown: onNativeKeyDown, ...nativeProps } = props;
35
+ const listElRef = useRef(null);
36
+ const [mergedListRefSetter] = useMergedRef(domRef, listElRef);
37
+ const itemsElRef = useRef(null);
38
+ const getVisibleItemsEl = useCallback(() => itemsElRef.current?.children[0] || null, []);
39
+ const [[renderReason, renderCallback, renderVersion], setRenderState] = useState([
40
+ null,
41
+ null,
42
+ 0
43
+ ]);
44
+ const viewportRef = useRef({
45
+ listHeight: void 0,
46
+ scrollTop: 0,
47
+ scrollLeft: 0,
48
+ listWidth: 0
49
+ });
50
+ const rangeRef = useRef({
51
+ prependIndexes: [],
52
+ verticalStartIndex: 0,
53
+ verticalEndIndex: -1,
54
+ horizontalStartIndex: 0,
55
+ horizontalEndIndex: -1
56
+ });
57
+ /**
58
+ * The rows kept mounted outside the range (absolutely positioned at their offsets): the rows holding
59
+ * the text selection and the row holding focus (`focusedKeyRef`).
60
+ */
61
+ const keptKeysRef = useRef([]);
62
+ /** The key of the row that holds focus (`document.activeElement` is in it), tracked by focusin / focusout. */
63
+ const focusedKeyRef = useRef(null);
64
+ /** The measured rows' sizes, by key (see `utils/size-cache.ts`). */
65
+ const keyToHeightOffsetRef = useRef(/* @__PURE__ */ new Map());
66
+ /** Bumped whenever `keyToHeightOffsetRef` changes (see `getTypicalSize`). */
67
+ const measuredVersionRef = useRef(0);
68
+ const typicalSizeRef = useRef(createTypicalSizeCache());
69
+ const leadingMarginRef = useRef(0);
70
+ /**
71
+ * Where the first mounted row in flow starts in the visible-items element (its top margin there,
72
+ * since nothing above it is mounted), as last written by `applyLayoutStyles`.
73
+ */
74
+ const firstRowStartRef = useRef(0);
75
+ const pendingScrollTaskRef = useRef(null);
76
+ const pendingScrollTaskTimeoutRef = useRef(null);
77
+ const pendingScrollTaskRafRef = useRef(null);
78
+ const wheelScrollingRef = useRef(false);
79
+ /** Whether the view last moved up (see `updateRange`). */
80
+ const scrollingUpRef = useRef(false);
81
+ /** Clears `wheelScrollingRef` in the next frame; this list's own, so other lists cannot replace it. */
82
+ const [runLatestInNextFrame] = useState(createLatestInNextFrame);
83
+ /** The wheel is only taken over (catchWheel) where the pointer is not coarse. */
84
+ const mayUseWheelRef = useRef(typeof document === "undefined" || !isCoarsePointer());
85
+ const reportRenderAnomaly = useEventCallback((anomaly) => {
86
+ onRenderAnomaly?.(anomaly);
87
+ });
88
+ const forcedRenderTimesRef = useRef([]);
89
+ /**
90
+ * The offset applied by the iOS compensation, created here (not in its hook) because
91
+ * `keepAnchorOnItemsChange` reads it while rendering, before the hook is called.
92
+ */
93
+ const compensationYRef = useRef(0);
94
+ /** The items, Fenwick tree and session of the last commit (the tree is updated in place by measurements). */
95
+ const committedLayoutRef = useRef(null);
96
+ const itemsAnchor = useMemo(() => {
97
+ const committed = committedLayoutRef.current;
98
+ const listEl = listElRef.current;
99
+ if (!keepAnchorOnItemsChange || !virtual || committed === null || listEl === null || committed.items === items || committed.sessionId !== sessionId) return null;
100
+ return findItemsAnchor({
101
+ prevItems: committed.items,
102
+ prevTree: committed.tree,
103
+ prevPrependIndexes: rangeRef.current.prependIndexes,
104
+ nextItems: items,
105
+ getKey,
106
+ canAnchor: canAnchorItem,
107
+ top: listEl.scrollTop + compensationYRef.current - paddingTop - leadingMarginRef.current
108
+ });
109
+ }, [items]);
110
+ /** The anchor whose range has been committed to `rangeRef` (so it is applied once). */
111
+ const appliedItemsAnchorRef = useRef(null);
112
+ const pendingItemsAnchor = itemsAnchor !== null && itemsAnchor !== appliedItemsAnchorRef.current ? itemsAnchor : null;
113
+ let renderedRange = rangeRef.current;
114
+ if (pendingItemsAnchor !== null) {
115
+ const [verticalStartIndex, verticalEndIndex] = getAnchoredRange(renderedRange.verticalStartIndex, renderedRange.verticalEndIndex, pendingItemsAnchor.index, items.length);
116
+ renderedRange = {
117
+ ...renderedRange,
118
+ prependIndexes: pendingItemsAnchor.prependIndexes,
119
+ verticalStartIndex,
120
+ verticalEndIndex
121
+ };
122
+ }
123
+ const { prependIndexes, verticalStartIndex: startIndex, verticalEndIndex: endIndex, horizontalStartIndex: colStartIndex, horizontalEndIndex: colEndIndex } = renderedRange;
124
+ const keyToIndexRef = useRef(void 0);
125
+ const prevSessionIdRef = useRef(sessionId);
126
+ const sessionChangedRef = useRef(false);
127
+ const lastTransformSignatureRef = useRef(null);
128
+ const clearPendingScrollTask = useCallback(() => {
129
+ if (pendingScrollTaskTimeoutRef.current !== null) {
130
+ window.clearTimeout(pendingScrollTaskTimeoutRef.current);
131
+ pendingScrollTaskTimeoutRef.current = null;
132
+ }
133
+ if (pendingScrollTaskRafRef.current != null) {
134
+ window.cancelAnimationFrame(pendingScrollTaskRafRef.current);
135
+ pendingScrollTaskRafRef.current = null;
136
+ }
137
+ pendingScrollTaskRef.current = null;
138
+ }, []);
139
+ useMemo(() => {
140
+ if (prevSessionIdRef.current === sessionId) return;
141
+ prevSessionIdRef.current = sessionId;
142
+ sessionChangedRef.current = true;
143
+ clearPendingScrollTask();
144
+ wheelScrollingRef.current = false;
145
+ keptKeysRef.current = [];
146
+ focusedKeyRef.current = null;
147
+ keyToHeightOffsetRef.current.clear();
148
+ measuredVersionRef.current += 1;
149
+ leadingMarginRef.current = 0;
150
+ keyToIndexRef.current = /* @__PURE__ */ new Map();
151
+ rangeRef.current = {
152
+ prependIndexes: [],
153
+ verticalStartIndex: 0,
154
+ verticalEndIndex: -1,
155
+ horizontalStartIndex: 0,
156
+ horizontalEndIndex: -1
157
+ };
158
+ const viewport = viewportRef.current;
159
+ viewport.scrollTop = 0;
160
+ viewport.scrollLeft = 0;
161
+ const listEl = listElRef.current;
162
+ if (listEl != null) {
163
+ listEl.scrollTop = 0;
164
+ listEl.scrollLeft = 0;
165
+ }
166
+ }, [sessionId, clearPendingScrollTask]);
167
+ useMemo(() => {
168
+ lastTransformSignatureRef.current = null;
169
+ }, [sessionId]);
170
+ useMemo(() => {
171
+ const keyToIndex = /* @__PURE__ */ new Map();
172
+ items.forEach((item, index) => {
173
+ keyToIndex.set(getKey(item), index);
174
+ });
175
+ keyToIndexRef.current = keyToIndex;
176
+ const keptKeys = [];
177
+ keptKeysRef.current.forEach((key) => {
178
+ if (keyToIndexRef.current.has(key)) keptKeys.push(key);
179
+ });
180
+ keptKeysRef.current = keptKeys;
181
+ }, [
182
+ sessionId,
183
+ items,
184
+ getKey
185
+ ]);
186
+ const totalColumnsWidth = useMemo(() => {
187
+ if (renderCol == null && renderItemWithCols == null || columns.length === 0) return;
188
+ let width = 0;
189
+ columns.forEach((column) => {
190
+ width += column.width;
191
+ });
192
+ return width;
193
+ }, [
194
+ sessionId,
195
+ renderCol,
196
+ renderItemWithCols,
197
+ columns
198
+ ]);
199
+ /**
200
+ * Rebuilt whenever the items or the session change: `itemEstimatedSize` for every item plus the
201
+ * measured offsets cached by key, so measurements survive re-renders and reordering.
202
+ */
203
+ const fenwickTree = useMemo(() => {
204
+ if (!virtual) return new FenwickTree(0, 0);
205
+ const tree = new FenwickTree(items.length, itemEstimatedSize);
206
+ const heightOffsets = keyToHeightOffsetRef.current;
207
+ items.forEach((item, index) => {
208
+ const key = getKey(item);
209
+ const offset = heightOffsets.get(key);
210
+ if (offset !== void 0) tree.add(index, offset);
211
+ });
212
+ return tree;
213
+ }, [
214
+ sessionId,
215
+ items,
216
+ itemEstimatedSize,
217
+ getKey,
218
+ virtual
219
+ ]);
220
+ const visibleItems = useMemo(() => {
221
+ if (!virtual) return items;
222
+ if (endIndex < startIndex) return [];
223
+ const visible = [];
224
+ const lastIndex = Math.min(endIndex, items.length - 1);
225
+ for (let i = startIndex; i <= lastIndex; ++i) visible.push(items[i]);
226
+ return visible;
227
+ }, [
228
+ sessionId,
229
+ startIndex,
230
+ endIndex,
231
+ items,
232
+ virtual
233
+ ]);
234
+ const xFenwickTree = useMemo(() => {
235
+ if (columns.length === 0) return null;
236
+ const tree = new FenwickTree(columns.length, 0);
237
+ columns.forEach((column, index) => {
238
+ tree.add(index, column.width);
239
+ });
240
+ return tree;
241
+ }, [sessionId, columns]);
242
+ const getColumnLeft = useEventCallback((index) => xFenwickTree !== null ? xFenwickTree.sum(index) : 0);
243
+ const columnsContextValue = useMemo(() => ({
244
+ startIndex: colStartIndex,
245
+ endIndex: colEndIndex,
246
+ columns,
247
+ renderCol,
248
+ renderItemWithCols,
249
+ getLeft: getColumnLeft
250
+ }), [
251
+ colStartIndex,
252
+ colEndIndex,
253
+ columns,
254
+ renderCol,
255
+ renderItemWithCols,
256
+ getColumnLeft
257
+ ]);
258
+ /** Where the rows start in the spacer's content: `paddingTop` plus the first row's top margin. */
259
+ const getRowsTop = useEventCallback(() => paddingTop + leadingMarginRef.current);
260
+ /**
261
+ * The mounted rows in flow, in order: the measured elements of the rendered range. Kept rows (outside
262
+ * the range, absolutely positioned) are left out: they take no space in the flow.
263
+ */
264
+ const getFlowRows = useEventCallback(() => {
265
+ const rows = [];
266
+ const visibleItemsEl = getVisibleItemsEl();
267
+ if (visibleItemsEl === null) return rows;
268
+ for (const el of Array.from(visibleItemsEl.children)) {
269
+ const key = el.getAttribute(ITEM_KEY_ATTR);
270
+ const index = key === null ? void 0 : keyToIndexRef.current.get(key);
271
+ if (key !== null && index !== void 0 && index >= startIndex && index <= endIndex && el instanceof HTMLElement) rows.push({
272
+ el,
273
+ key,
274
+ index
275
+ });
276
+ }
277
+ return rows;
278
+ });
279
+ /**
280
+ * Writes the layout without a render: the spacer height (the total size plus the first row's top
281
+ * margin; a min-height with itemResizable, so the real content may exceed it) and the visible items'
282
+ * translateY. It writes no CSS variable on the visible items: custom properties inherit, so one
283
+ * written there on every scroll restyles every row. Content that must follow the rows' offset uses
284
+ * `onTransformChange`.
285
+ *
286
+ * Unlike the reference implementation (DeepSeek web): the translateY puts the border box of the first
287
+ * mounted row at its offset (`firstIndex`, or the first row in the DOM), not the element's top. The visible-items element is a
288
+ * block formatting context, so the first mounted row's top margin is inside it, above the row, and
289
+ * does not collapse with the row before it (not mounted): the element starts that margin higher. The
290
+ * collapsed gap above that row is already in the size of the row before it (see `leadingMarginRef`),
291
+ * so the rows sit exactly where the tree has them whichever row is first, and moving the window's top
292
+ * edge moves no row. Read before anything is written, so it forces no extra layout.
293
+ */
294
+ const applyLayoutStyles = useEventCallback((firstIndex) => {
295
+ if (!virtual) return;
296
+ let index = Math.min(firstIndex, items.length);
297
+ let firstRowStart = 0;
298
+ const itemsEl = itemsElRef.current;
299
+ const visibleItemsEl = itemsEl?.children[0];
300
+ const firstRow = itemResizable ? getFlowRows()[0] : void 0;
301
+ if (firstRow !== void 0 && visibleItemsEl instanceof HTMLElement) {
302
+ index = firstRow.index;
303
+ firstRowStart = measureRowStart(visibleItemsEl, firstRow.el);
304
+ }
305
+ firstRowStartRef.current = firstRowStart;
306
+ const leadingMargin = leadingMarginRef.current;
307
+ if (itemsEl) {
308
+ const height = px(fenwickTree.sum() + leadingMargin) || "";
309
+ if (itemResizable) {
310
+ itemsEl.style.height = "";
311
+ itemsEl.style.minHeight = height;
312
+ } else {
313
+ const changed = itemsEl.style.height !== height || itemsEl.style.minHeight !== "";
314
+ itemsEl.style.height = height;
315
+ itemsEl.style.minHeight = "";
316
+ if (changed) onContentResize?.();
317
+ }
318
+ }
319
+ if (visibleItemsEl instanceof HTMLElement) {
320
+ const offset = px(leadingMargin + fenwickTree.sum(index) - firstRowStart);
321
+ visibleItemsEl.style.transform = `translateY(${offset})`;
322
+ const signature = `${index}|${offset}`;
323
+ if (lastTransformSignatureRef.current !== signature) {
324
+ lastTransformSignatureRef.current = signature;
325
+ onTransformChange?.();
326
+ }
327
+ }
328
+ });
329
+ useLayoutEffect(() => {
330
+ if (!virtual) {
331
+ const itemsEl = itemsElRef.current;
332
+ if (itemsEl) {
333
+ itemsEl.style.height = "";
334
+ itemsEl.style.minHeight = "";
335
+ }
336
+ }
337
+ }, [virtual]);
338
+ /** The size rows typically are: the mean of the measured rows (`getTypicalSize`). */
339
+ const getTypicalRowSize = useEventCallback(() => getTypicalSize(typicalSizeRef.current, keyToHeightOffsetRef.current, measuredVersionRef.current, itemEstimatedSize, itemMinSize));
340
+ /**
341
+ * The viewport sync. The range starts at the item at `scrollTop + compensation - paddingTop` and
342
+ * holds as many items as fit at `itemMinSize`, plus one, and is overscanned in batches
343
+ * (`getOverscannedRange`). Items holding the text selection, and the item
344
+ * holding focus, stay
345
+ * mounted ("kept"). When the new range is inside the old one, only the layout styles are written;
346
+ * otherwise the items entering above the old start are recorded (`prependIndexes`) and the range is
347
+ * rendered with flushSync, now or in a microtask (`deferRenderToMicrotask`). At 120 forced renders
348
+ * within a second a "renderThrashing" anomaly is reported. `afterRender` runs after the layout styles
349
+ * of the new range are applied.
350
+ */
351
+ const updateRange = useEventCallback((reason, deferRenderToMicrotask, afterRender) => {
352
+ if (!virtual) return;
353
+ const listEl = listElRef.current;
354
+ if (listEl == null) return;
355
+ const viewport = viewportRef.current;
356
+ if (viewport.listHeight === void 0) {
357
+ applyLayoutStyles(startIndex);
358
+ afterRender?.();
359
+ return;
360
+ }
361
+ const scrollTop = listEl.scrollTop;
362
+ const effectiveScrollTop = scrollTop + compensationYRef.current;
363
+ const scrollLeft = listEl.scrollLeft;
364
+ const range = rangeRef.current;
365
+ const prevRange = {
366
+ startIndex: range.verticalStartIndex,
367
+ endIndex: range.verticalEndIndex
368
+ };
369
+ const viewRange = getVerticalRange({
370
+ fenwickTree,
371
+ scrollTop: effectiveScrollTop,
372
+ listHeight: viewport.listHeight,
373
+ itemMinSize,
374
+ itemCount: items.length,
375
+ paddingTop: getRowsTop()
376
+ });
377
+ const overscanned = viewport.listHeight > 0;
378
+ if (scrollTop !== viewport.scrollTop) scrollingUpRef.current = scrollTop < viewport.scrollTop;
379
+ const nextRange = overscanned ? getOverscannedRange({
380
+ fenwickTree,
381
+ view: viewRange,
382
+ prev: prevRange,
383
+ neededEnd: getNeededEnd({
384
+ fenwickTree,
385
+ startIndex: viewRange.startIndex,
386
+ viewTop: effectiveScrollTop - getRowsTop(),
387
+ listHeight: viewport.listHeight,
388
+ itemMinSize,
389
+ itemCount: items.length,
390
+ isMeasured: (index) => {
391
+ const item = items[index];
392
+ return item !== void 0 && keyToHeightOffsetRef.current.has(getKey(item));
393
+ }
394
+ }),
395
+ viewTop: effectiveScrollTop - getRowsTop(),
396
+ moved: Math.abs(scrollTop - viewport.scrollTop),
397
+ movingUp: scrollingUpRef.current,
398
+ settling: pendingScrollTaskRef.current !== null,
399
+ plannedSize: (index) => {
400
+ const item = items[index];
401
+ return item !== void 0 && keyToHeightOffsetRef.current.has(getKey(item)) ? fenwickTree.get(index) : getTypicalRowSize();
402
+ },
403
+ listHeight: viewport.listHeight,
404
+ itemCount: items.length
405
+ }) : viewRange;
406
+ const rangeChanged = prevRange.startIndex !== nextRange.startIndex || prevRange.endIndex !== nextRange.endIndex;
407
+ const nextInsidePrev = !overscanned && nextRange.startIndex >= prevRange.startIndex && prevRange.endIndex >= nextRange.endIndex;
408
+ const prevColRange = {
409
+ startIndex: range.horizontalStartIndex,
410
+ endIndex: range.horizontalEndIndex
411
+ };
412
+ const nextColRange = getHorizontalRange({
413
+ xFenwickTree,
414
+ scrollLeft,
415
+ listWidth: viewport.listWidth,
416
+ columnCount: columns.length
417
+ });
418
+ const colRangeChanged = prevColRange.startIndex !== nextColRange.startIndex || prevColRange.endIndex !== nextColRange.endIndex;
419
+ viewport.scrollTop = scrollTop;
420
+ viewport.scrollLeft = scrollLeft;
421
+ let keptKeysChanged = false;
422
+ if (typeof window !== "undefined" && reason !== "sessionChanged") {
423
+ const { startIndex: nextStart, endIndex: nextEnd } = nextRange;
424
+ const keptKeys = [];
425
+ const keep = (key) => {
426
+ const index = keyToIndexRef.current.get(key);
427
+ if (index !== void 0 && (!(index >= nextStart) || !(index <= nextEnd)) && !keptKeys.includes(key)) keptKeys.push(key);
428
+ };
429
+ const focusedKey = focusedKeyRef.current;
430
+ if (focusedKey !== null) {
431
+ const active = document.activeElement;
432
+ if (active !== null && listEl.contains(active)) keep(focusedKey);
433
+ else focusedKeyRef.current = null;
434
+ }
435
+ const selection = window.getSelection();
436
+ if (selection != null && !selection.isCollapsed && selection.rangeCount > 0) listEl.querySelectorAll(`[${ITEM_KEY_ATTR}]`).forEach((itemEl) => {
437
+ if (!selection.containsNode(itemEl, true) && itemEl.getElementsByTagName("input").length !== 0) return;
438
+ const key = itemEl.getAttribute(ITEM_KEY_ATTR);
439
+ if (key !== null) keep(key);
440
+ });
441
+ if (!haveSameKeys(keptKeys, keptKeysRef.current)) {
442
+ keptKeysRef.current = keptKeys;
443
+ keptKeysChanged = true;
444
+ }
445
+ }
446
+ if (reason !== "sessionChanged" && !keptKeysChanged && (!rangeChanged || nextInsidePrev) && !colRangeChanged) {
447
+ if (nextInsidePrev) applyLayoutStyles(prevRange.startIndex);
448
+ else applyLayoutStyles(nextRange.startIndex);
449
+ afterRender?.();
450
+ return;
451
+ }
452
+ if (reason !== "sessionChanged") {
453
+ const entering = [];
454
+ if (pendingScrollTaskRef.current?.type === void 0 && nextRange.endIndex >= prevRange.startIndex) for (let i = nextRange.startIndex; i < prevRange.startIndex; ++i) entering.push(i);
455
+ range.prependIndexes = entering;
456
+ } else range.prependIndexes = [];
457
+ range.verticalStartIndex = nextRange.startIndex;
458
+ range.verticalEndIndex = nextRange.endIndex;
459
+ range.horizontalStartIndex = nextColRange.startIndex;
460
+ range.horizontalEndIndex = nextColRange.endIndex;
461
+ const now = Date.now();
462
+ const renderTimes = forcedRenderTimesRef.current;
463
+ renderTimes.push(now);
464
+ const windowStart = now - RENDER_THRASHING_WINDOW_MS;
465
+ while (renderTimes.length > 0 && renderTimes[0] < windowStart) renderTimes.shift();
466
+ if (renderTimes.length >= 120) {
467
+ reportRenderAnomaly({
468
+ type: "renderThrashing",
469
+ message: `${renderTimes.length} forced renders within ${RENDER_THRASHING_WINDOW_MS}ms`,
470
+ payload: {
471
+ renderCount: renderTimes.length,
472
+ windowMs: RENDER_THRASHING_WINDOW_MS,
473
+ triggerReason: reason,
474
+ itemCount: items.length
475
+ }
476
+ });
477
+ renderTimes.length = 0;
478
+ }
479
+ if (deferRenderToMicrotask) Promise.resolve().then(() => {
480
+ flushSync(() => {
481
+ setRenderState((state) => [
482
+ reason,
483
+ afterRender,
484
+ state[2] + 1
485
+ ]);
486
+ });
487
+ });
488
+ else flushSync(() => {
489
+ setRenderState((state) => [
490
+ reason,
491
+ afterRender,
492
+ state[2] + 1
493
+ ]);
494
+ });
495
+ });
496
+ /**
497
+ * A pending scroll task (to the top, the bottom, an index, or a custom task) stays armed for one
498
+ * animation frame plus one task, so that item sizes measured right after the jump replay it instead
499
+ * of being compensated.
500
+ */
501
+ const schedulePendingScrollTaskExpiry = useCallback(() => {
502
+ pendingScrollTaskRafRef.current = requestAnimationFrame(() => {
503
+ pendingScrollTaskRafRef.current = null;
504
+ pendingScrollTaskTimeoutRef.current = window.setTimeout(() => {
505
+ pendingScrollTaskRef.current = null;
506
+ pendingScrollTaskTimeoutRef.current = null;
507
+ });
508
+ });
509
+ }, []);
510
+ const scrollToPosition = useEventCallback((left, top, behavior) => {
511
+ listElRef.current?.scrollTo({
512
+ left,
513
+ top,
514
+ behavior
515
+ });
516
+ });
517
+ /**
518
+ * Scrolls to the offset of `index` in the Fenwick tree (an estimate for items not measured yet);
519
+ * an "instant" jump is armed as the pending task, to be replayed after measurements. `ensureVisibleOnly`
520
+ * (the `debounce` option) scrolls only as far as needed to show the item. With virtualization off the
521
+ * offset is read from the DOM (`getBoundingClientRect` of the index-th child).
522
+ */
523
+ const scrollToIndex = useEventCallback((index, behavior, ensureVisibleOnly, isReplay, scrollMarginTop = 0, scrollMarginBottom = 0) => {
524
+ if (!virtual) {
525
+ const listEl = listElRef.current;
526
+ const itemsEl = itemsElRef.current;
527
+ if (!itemsEl || !listEl) return;
528
+ const visibleItemsEl = itemsEl.firstElementChild;
529
+ if (!visibleItemsEl) return;
530
+ const itemEl = visibleItemsEl.children.item(index);
531
+ if (!(itemEl instanceof HTMLElement)) return;
532
+ const listRect = listEl.getBoundingClientRect();
533
+ const itemRect = itemEl.getBoundingClientRect();
534
+ const itemTop = itemRect.top - listRect.top + listEl.scrollTop;
535
+ if (ensureVisibleOnly) {
536
+ const { scrollTop, offsetHeight } = listEl;
537
+ const itemHeight = itemRect.height;
538
+ if (itemTop > scrollTop) {
539
+ if (!(itemTop + itemHeight <= scrollTop + offsetHeight)) listEl.scrollTo({
540
+ left: 0,
541
+ top: itemTop + itemHeight - offsetHeight + scrollMarginBottom,
542
+ behavior
543
+ });
544
+ } else listEl.scrollTo({
545
+ left: 0,
546
+ top: itemTop - scrollMarginTop,
547
+ behavior
548
+ });
549
+ } else listEl.scrollTo({
550
+ left: 0,
551
+ top: itemTop,
552
+ behavior
553
+ });
554
+ return;
555
+ }
556
+ const targetTop = fenwickTree.sum(index) + getRowsTop();
557
+ if (!isReplay) {
558
+ clearPendingScrollTask();
559
+ if (behavior === "instant") {
560
+ const item = items[index];
561
+ pendingScrollTaskRef.current = {
562
+ type: "index",
563
+ key: item === void 0 ? void 0 : getKey(item),
564
+ index,
565
+ debounce: ensureVisibleOnly
566
+ };
567
+ schedulePendingScrollTaskExpiry();
568
+ }
569
+ }
570
+ if (ensureVisibleOnly) {
571
+ const listEl = listElRef.current;
572
+ if (listEl) {
573
+ const { scrollTop, offsetHeight } = listEl;
574
+ if (targetTop > scrollTop) {
575
+ const itemSize = fenwickTree.get(index);
576
+ if (!(targetTop + itemSize <= scrollTop + offsetHeight)) {
577
+ listEl.scrollTo({
578
+ left: 0,
579
+ top: targetTop + itemSize - offsetHeight + scrollMarginBottom,
580
+ behavior
581
+ });
582
+ updateRange("listScroll", true, null);
583
+ }
584
+ } else {
585
+ listEl.scrollTo({
586
+ left: 0,
587
+ top: targetTop - scrollMarginTop,
588
+ behavior
589
+ });
590
+ updateRange("listScroll", true, null);
591
+ }
592
+ }
593
+ } else {
594
+ listElRef.current?.scrollTo({
595
+ left: 0,
596
+ top: targetTop,
597
+ behavior
598
+ });
599
+ updateRange("listScroll", true, null);
600
+ }
601
+ });
602
+ /**
603
+ * Measures the mounted rows in flow from layout, synchronously, and writes the sizes that changed into
604
+ * the Fenwick tree and the key -> offset cache, and the first row's top margin when the first row is
605
+ * mounted (`leadingMarginRef`). Reads everything first (`measureRowSpans`), then writes: no layout is
606
+ * forced in between. O(mounted rows).
607
+ *
608
+ * Unlike the reference implementation (DeepSeek web): it measured each row's own `offsetHeight`,
609
+ * which in block flow misses the margins between rows and a child's margins that collapse through a row, so the rows drifted from
610
+ * their offsets. A row's size here is the space it takes in the flow: from where its border box starts
611
+ * to where the next row's starts (the last mounted row: to the end of the rows), so collapsed margins
612
+ * are counted once, in the row above them, and the sizes add up to the laid-out height. A row's size
613
+ * depends on the next row's top margin, so every measurement measures the whole run, not the row that
614
+ * resized. The last mounted row's bottom margin does not collapse with the next row (not mounted): its
615
+ * size is provisional until the next row mounts, which corrects it without moving any mounted row
616
+ * (they are laid out by the browser, positioned by the first row's offset alone). Kept rows are not
617
+ * measured: absolutely positioned, they take no space in the flow, and keep the size they were
618
+ * measured at in it.
619
+ */
620
+ const measureFlowRun = useEventCallback(() => {
621
+ const resizes = [];
622
+ const visibleItemsEl = getVisibleItemsEl();
623
+ if (!virtual || ignoreItemResize || !itemResizable || !(visibleItemsEl instanceof HTMLElement)) return {
624
+ resizes,
625
+ leadingMarginDelta: 0
626
+ };
627
+ const rows = getFlowRows();
628
+ if (rows.length === 0) return {
629
+ resizes,
630
+ leadingMarginDelta: 0
631
+ };
632
+ const { spans, firstStart } = measureRowSpans(visibleItemsEl, rows.map((row) => row.el));
633
+ let leadingMarginDelta = 0;
634
+ if (rows[0].index === 0 && firstStart !== leadingMarginRef.current) {
635
+ leadingMarginDelta = firstStart - leadingMarginRef.current;
636
+ leadingMarginRef.current = firstStart;
637
+ }
638
+ rows.forEach(({ key, index }, i) => {
639
+ const size = spans[i];
640
+ const previousSize = fenwickTree.get(index);
641
+ if (recordMeasuredSize(keyToHeightOffsetRef.current, key, size, itemEstimatedSize)) measuredVersionRef.current += 1;
642
+ if (size === previousSize) return;
643
+ fenwickTree.add(index, size - previousSize);
644
+ resizes.push({
645
+ index,
646
+ key,
647
+ delta: size - previousSize
648
+ });
649
+ });
650
+ return {
651
+ resizes,
652
+ leadingMarginDelta
653
+ };
654
+ });
655
+ /**
656
+ * Measures the mounted rows now (`measureFlowRun`) and applies the layout; returns whether any size
657
+ * changed. Used by the aligned jump, which cannot wait for the batch (a microtask) or the
658
+ * ResizeObserver (after layout, possibly a frame later) to learn the sizes.
659
+ */
660
+ const measureMountedItems = useEventCallback(() => {
661
+ const { resizes, leadingMarginDelta } = measureFlowRun();
662
+ const changed = resizes.length !== 0 || leadingMarginDelta !== 0;
663
+ if (changed) {
664
+ applyLayoutStyles(startIndex);
665
+ onContentResize?.();
666
+ }
667
+ return changed;
668
+ });
669
+ /**
670
+ * Where item `index` is, in the list's scroll coordinates: read from the DOM when
671
+ * it is mounted (exact), else its offset in the Fenwick tree (estimates for unmeasured items).
672
+ */
673
+ const getItemExtent = useEventCallback((index) => {
674
+ const listEl = listElRef.current;
675
+ const item = items[index];
676
+ const visibleItemsEl = getVisibleItemsEl();
677
+ if (listEl && item !== void 0 && visibleItemsEl && itemResizable) {
678
+ const key = getKey(item);
679
+ for (const itemEl of Array.from(visibleItemsEl.children)) if (itemEl.getAttribute("data-virtual-list-item-key") === key) {
680
+ const rect = itemEl.getBoundingClientRect();
681
+ const listTop = listEl.getBoundingClientRect().top + listEl.clientTop;
682
+ return {
683
+ top: rect.top - listTop + listEl.scrollTop,
684
+ size: rect.height,
685
+ measured: true
686
+ };
687
+ }
688
+ }
689
+ return {
690
+ top: fenwickTree.sum(index) + getRowsTop(),
691
+ size: fenwickTree.get(index),
692
+ measured: !itemResizable
693
+ };
694
+ });
695
+ /** Bumped by every aligned jump: a chain of steps stops when a newer jump has started. */
696
+ const alignRunRef = useRef(0);
697
+ /**
698
+ * One step of an aligned jump: measure the mounted items, work out the exact
699
+ * `scrollTop` for the item from the DOM, set it, and update the range. If the range changes, the rows it
700
+ * brings into view are rendered (in a microtask, still before the browser paints) and the next step runs
701
+ * from the render callback (a layout effect) to measure them; the jump is done when a step finds the item
702
+ * mounted, no size changed and `scrollTop` already right. Bounded by `MAX_ALIGN_STEPS`. The item is
703
+ * found by its key at every step: rows inserted above it in between move its index.
704
+ */
705
+ const alignStep = useEventCallback((run, key, align, scrollMarginTop, scrollMarginBottom, remaining) => {
706
+ const listEl = listElRef.current;
707
+ const index = keyToIndexRef.current.get(key);
708
+ if (listEl == null || run !== alignRunRef.current || index === void 0) return;
709
+ const sizesChanged = measureMountedItems();
710
+ const { top: itemTop, size: itemSize, measured } = getItemExtent(index);
711
+ const viewportHeight = listEl.clientHeight;
712
+ const target = Math.round(getAlignedScrollTop({
713
+ itemTop,
714
+ itemSize,
715
+ viewportHeight,
716
+ align,
717
+ scrollMarginTop,
718
+ scrollMarginBottom,
719
+ maxScrollTop: listEl.scrollHeight - viewportHeight
720
+ }));
721
+ const moved = Math.abs(listEl.scrollTop - target) >= .5;
722
+ if (moved) listEl.scrollTo({
723
+ left: listEl.scrollLeft,
724
+ top: target,
725
+ behavior: "instant"
726
+ });
727
+ viewportRef.current.scrollTop = listEl.scrollTop;
728
+ if (!moved && !sizesChanged && measured || remaining <= 0) return;
729
+ updateRange("listScroll", true, () => {
730
+ alignStep(run, key, align, scrollMarginTop, scrollMarginBottom, remaining - 1);
731
+ });
732
+ });
733
+ /**
734
+ * `scrollTo({ index | key, align })`. Instant (or "auto"): the aligned steps above, armed as the pending
735
+ * task like the other instant jumps (item sizes reported after the jump replay it, for one frame plus one
736
+ * task). Smooth: one scroll to the position worked out from the current layout (estimates for rows not
737
+ * measured yet), like the smooth index jump. Virtualization off: read from the DOM.
738
+ */
739
+ const scrollToAligned = useEventCallback((index, align, behavior, isReplay, scrollMarginTop, scrollMarginBottom) => {
740
+ const listEl = listElRef.current;
741
+ if (listEl == null) return;
742
+ if (!virtual) {
743
+ const itemEl = getVisibleItemsEl()?.children.item(index);
744
+ if (!itemEl) return;
745
+ const rect = itemEl.getBoundingClientRect();
746
+ const listTop = listEl.getBoundingClientRect().top + listEl.clientTop;
747
+ const top = getAlignedScrollTop({
748
+ itemTop: rect.top - listTop + listEl.scrollTop,
749
+ itemSize: rect.height,
750
+ viewportHeight: listEl.clientHeight,
751
+ align,
752
+ scrollMarginTop,
753
+ scrollMarginBottom,
754
+ maxScrollTop: listEl.scrollHeight - listEl.clientHeight
755
+ });
756
+ listEl.scrollTo({
757
+ left: 0,
758
+ top: Math.round(top),
759
+ behavior
760
+ });
761
+ return;
762
+ }
763
+ const item = items[index];
764
+ if (item === void 0) return;
765
+ const key = getKey(item);
766
+ const smooth = behavior === "smooth";
767
+ if (!isReplay) {
768
+ clearPendingScrollTask();
769
+ if (!smooth) {
770
+ pendingScrollTaskRef.current = {
771
+ type: "align",
772
+ key,
773
+ align,
774
+ scrollMarginTop,
775
+ scrollMarginBottom
776
+ };
777
+ schedulePendingScrollTaskExpiry();
778
+ }
779
+ }
780
+ const run = ++alignRunRef.current;
781
+ if (smooth) {
782
+ const { top: itemTop, size: itemSize } = getItemExtent(index);
783
+ const top = getAlignedScrollTop({
784
+ itemTop,
785
+ itemSize,
786
+ viewportHeight: listEl.clientHeight,
787
+ align,
788
+ scrollMarginTop,
789
+ scrollMarginBottom,
790
+ maxScrollTop: listEl.scrollHeight - listEl.clientHeight
791
+ });
792
+ listEl.scrollTo({
793
+ left: 0,
794
+ top: Math.round(top),
795
+ behavior
796
+ });
797
+ updateRange("listScroll", true, null);
798
+ return;
799
+ }
800
+ alignStep(run, key, align, scrollMarginTop, scrollMarginBottom, MAX_ALIGN_STEPS);
801
+ });
802
+ const scrollTo = useEventCallback((options, topIfNumber) => {
803
+ if (typeof options == "number") {
804
+ scrollToPosition(options, topIfNumber, "instant");
805
+ return;
806
+ }
807
+ const { left, top, index, key, position, behavior = "instant", debounce = true, scrollMarginTop = 0, scrollMarginBottom = 0, align } = options;
808
+ if (left !== void 0 || top !== void 0) scrollToPosition(left, top, behavior);
809
+ else if (align !== void 0 && (index !== void 0 || key !== void 0)) {
810
+ const alignIndex = index ?? keyToIndexRef.current.get(key);
811
+ if (alignIndex !== void 0) scrollToAligned(alignIndex, align, behavior, false, scrollMarginTop, scrollMarginBottom);
812
+ } else if (index !== void 0) scrollToIndex(index, behavior, debounce, false, scrollMarginTop, scrollMarginBottom);
813
+ else if (key !== void 0) {
814
+ const keyIndex = keyToIndexRef.current.get(key);
815
+ if (keyIndex !== void 0) scrollToIndex(keyIndex, behavior, debounce, false, scrollMarginTop, scrollMarginBottom);
816
+ } else if (position) {
817
+ if (virtual) {
818
+ clearPendingScrollTask();
819
+ if (behavior === "instant") {
820
+ pendingScrollTaskRef.current = { type: position };
821
+ schedulePendingScrollTaskExpiry();
822
+ }
823
+ }
824
+ if (position === "bottom") {
825
+ scrollToPosition(0, listElRef.current?.scrollHeight || 2e9, behavior);
826
+ if (virtual) updateRange("listScroll", true, null);
827
+ } else if (position === "top") scrollToPosition(0, 0, behavior);
828
+ }
829
+ });
830
+ const replayPendingScrollTask = useEventCallback(() => {
831
+ const task = pendingScrollTaskRef.current;
832
+ if (task) {
833
+ if (task.type === "top") scrollToPosition(0, 0, "instant");
834
+ else if (task.type === "bottom") scrollToPosition(0, listElRef.current?.scrollHeight || 2e9, "instant");
835
+ else if (task.type === "index") {
836
+ const index = task.key === void 0 ? task.index : keyToIndexRef.current.get(task.key);
837
+ if (index !== void 0) scrollToIndex(index, "instant", task.debounce, true);
838
+ } else if (task.type === "align") {
839
+ const index = keyToIndexRef.current.get(task.key);
840
+ if (index === void 0) return;
841
+ scrollToAligned(index, task.align, "instant", true, task.scrollMarginTop, task.scrollMarginBottom);
842
+ } else if (task.type === "custom") task.task();
843
+ }
844
+ });
845
+ /**
846
+ * Runs `task` now (after a range update) and again after every batch of item resizes while it is
847
+ * armed (one frame plus one task).
848
+ */
849
+ const submitScrollAdjustingTask = useCallback((task) => {
850
+ clearPendingScrollTask();
851
+ pendingScrollTaskRef.current = {
852
+ type: "custom",
853
+ task
854
+ };
855
+ schedulePendingScrollTaskExpiry();
856
+ updateRange("listScroll", true, replayPendingScrollTask);
857
+ }, [
858
+ replayPendingScrollTask,
859
+ clearPendingScrollTask,
860
+ schedulePendingScrollTaskExpiry,
861
+ updateRange
862
+ ]);
863
+ const syncViewport = useCallback(() => {
864
+ updateRange("listScroll", false, null);
865
+ }, [updateRange]);
866
+ const restoreItemsAnchor = useEventCallback((anchor) => {
867
+ appliedItemsAnchorRef.current = anchor;
868
+ rangeRef.current = renderedRange;
869
+ const listEl = listElRef.current;
870
+ const index = keyToIndexRef.current.get(anchor.key);
871
+ const pendingType = pendingScrollTaskRef.current?.type;
872
+ if (listEl == null || index === void 0 || pendingType !== void 0 && pendingType !== "index" && pendingType !== "align") return;
873
+ applyLayoutStyles(startIndex);
874
+ const diff = fenwickTree.sum(index) + anchor.delta + getRowsTop() - (listEl.scrollTop + compensationYRef.current);
875
+ if (diff !== 0 && !addCompensation(diff)) listEl.scrollBy(0, diff);
876
+ viewportRef.current.scrollTop = listEl.scrollTop;
877
+ });
878
+ useLayoutEffect(() => {
879
+ if (pendingItemsAnchor !== null && !sessionChangedRef.current) restoreItemsAnchor(pendingItemsAnchor);
880
+ if (sessionChangedRef.current) {
881
+ updateRange("sessionChanged", true, replayPendingScrollTask);
882
+ sessionChangedRef.current = false;
883
+ } else if (itemResizable) {
884
+ const heightBefore = listElRef.current?.offsetHeight;
885
+ applyLayoutStyles(startIndex);
886
+ if (heightBefore === listElRef.current?.offsetHeight) updateRange("itemsChanged", true, replayPendingScrollTask);
887
+ } else updateRange("itemsChanged", true, replayPendingScrollTask);
888
+ }, [
889
+ sessionId,
890
+ items,
891
+ replayPendingScrollTask,
892
+ updateRange,
893
+ itemResizable,
894
+ applyLayoutStyles
895
+ ]);
896
+ useLayoutEffect(() => {
897
+ committedLayoutRef.current = {
898
+ items,
899
+ tree: fenwickTree,
900
+ sessionId
901
+ };
902
+ });
903
+ useLayoutEffect(() => {
904
+ applyLayoutStyles(startIndex);
905
+ renderCallback?.();
906
+ }, [
907
+ renderReason,
908
+ renderCallback,
909
+ renderVersion,
910
+ applyLayoutStyles
911
+ ]);
912
+ const getOffsetTopOfKey = useEventCallback((key) => {
913
+ const index = keyToIndexRef.current.get(key);
914
+ if (index !== void 0) return fenwickTree.sum(index) + getRowsTop();
915
+ });
916
+ const refreshListWidth = useCallback(() => {
917
+ const listEl = listElRef.current;
918
+ if (listEl) listEl.style.setProperty("--virtual-list-width", `${listEl.offsetWidth}px`);
919
+ }, [listElRef]);
920
+ const imperativeApi = useMemo(() => ({
921
+ listElRef,
922
+ itemsElRef,
923
+ scrollTo,
924
+ syncViewport,
925
+ getOffsetTopOfKey,
926
+ submitScrollAdjustingTask,
927
+ refreshListWidth
928
+ }), [
929
+ getOffsetTopOfKey,
930
+ scrollTo,
931
+ syncViewport,
932
+ submitScrollAdjustingTask,
933
+ refreshListWidth
934
+ ]);
935
+ useImperativeHandle(componentRef, () => imperativeApi, [imperativeApi]);
936
+ const itemResizeQueueRef = useRef([]);
937
+ const enqueueItemResize = useEventCallback((entry) => {
938
+ itemResizeQueueRef.current.push(entry);
939
+ });
940
+ const clearItemResizeQueue = useEventCallback(() => {
941
+ itemResizeQueueRef.current = [];
942
+ });
943
+ const batchResizeScheduledRef = useRef(false);
944
+ /**
945
+ * Applies the queued item measurements (in place of the browser's scroll anchoring): the mounted rows
946
+ * are measured (`measureFlowRun`: all of them, since a row's size depends on its neighbour) and each
947
+ * size change goes into the Fenwick tree and the key -> offset cache. With no pending scroll task,
948
+ * the size changes of items measured for the FIRST time among those that entered above the old start
949
+ * of the range (`prependIndexes`), and of rows above the view, are scrolled away (`scrollBy`, or
950
+ * through the iOS compensation during a touch scroll); with a pending task, the task is replayed.
951
+ */
952
+ const handleItemBatchResize = useEventCallback(() => {
953
+ if (!virtual) return;
954
+ const queue = itemResizeQueueRef.current;
955
+ if (ignoreItemResize) return;
956
+ const listElBefore = listElRef.current;
957
+ const viewTop = listElBefore == null ? 0 : listElBefore.scrollTop + compensationYRef.current - getRowsTop();
958
+ const viewTopIndex = listElBefore == null ? 0 : fenwickTree.getBound(viewTop);
959
+ const isFirstOfKey = /* @__PURE__ */ new Map();
960
+ for (const { key, isFirst } of queue) if (!isFirstOfKey.has(key)) isFirstOfKey.set(key, isFirst);
961
+ const { resizes, leadingMarginDelta } = measureFlowRun();
962
+ if (resizes.length === 0 && leadingMarginDelta === 0 && pendingScrollTaskRef.current === null) {
963
+ clearItemResizeQueue();
964
+ return;
965
+ }
966
+ const scrollTopBefore = listElBefore == null ? 0 : listElBefore.scrollTop;
967
+ const effectiveTopBefore = scrollTopBefore + compensationYRef.current;
968
+ applyLayoutStyles(startIndex);
969
+ const listEl = listElRef.current;
970
+ let contentMoved = true;
971
+ if (listEl != null) {
972
+ const pendingTask = pendingScrollTaskRef.current;
973
+ if (pendingTask?.type === void 0) {
974
+ const compensates = (index, key) => key !== void 0 && isFirstOfKey.get(key) === true && prependIndexes.includes(index) || index < viewTopIndex;
975
+ let compensation = 0;
976
+ let uncompensated = false;
977
+ for (const { index, key, delta } of resizes) if (compensates(index, key)) compensation += delta;
978
+ else if (delta !== 0) uncompensated = true;
979
+ const firstItem = items[0];
980
+ if (leadingMarginDelta !== 0 && (viewTop > 0 || compensates(0, firstItem === void 0 ? void 0 : getKey(firstItem)))) compensation += leadingMarginDelta;
981
+ else if (leadingMarginDelta !== 0) uncompensated = true;
982
+ if (compensation !== 0) {
983
+ const remaining = compensation - (listEl.scrollTop - scrollTopBefore);
984
+ if (remaining !== 0 && !addCompensation(remaining)) listEl.scrollBy(0, remaining);
985
+ }
986
+ const effectiveTop = listEl.scrollTop + compensationYRef.current;
987
+ contentMoved = uncompensated || Math.abs(effectiveTop - (effectiveTopBefore + compensation)) >= 1;
988
+ } else {
989
+ onContentResize?.();
990
+ replayPendingScrollTask();
991
+ }
992
+ const viewport = viewportRef.current;
993
+ viewport.scrollTop = listEl.scrollTop;
994
+ viewport.scrollLeft = listEl.scrollLeft;
995
+ if (pendingTask?.type === void 0 && contentMoved) onContentResize?.();
996
+ } else if (contentMoved) onContentResize?.();
997
+ clearItemResizeQueue();
998
+ updateRange("batchItemResize", false, null);
999
+ });
1000
+ /** Measurements of items that just mounted are applied together, in one microtask. */
1001
+ const scheduleItemBatchResize = useEventCallback(() => {
1002
+ if (!batchResizeScheduledRef.current) {
1003
+ Promise.resolve().then(() => {
1004
+ handleItemBatchResize();
1005
+ batchResizeScheduledRef.current = false;
1006
+ });
1007
+ batchResizeScheduledRef.current = true;
1008
+ }
1009
+ });
1010
+ /**
1011
+ * Ignores scroll events while a flush of the iOS compensation suppresses them; otherwise updates
1012
+ * the range (replaying a pending task) and calls `onScroll`.
1013
+ */
1014
+ const handleListScroll = useEventCallback((event) => {
1015
+ const scrollTop = event.target.scrollTop;
1016
+ if (!isScrollSuppressedWithForceRestore(scrollTop)) {
1017
+ if (!wheelScrollingRef.current) updateRange("listScroll", false, pendingScrollTaskRef.current ? replayPendingScrollTask : null);
1018
+ onScroll?.(event.nativeEvent);
1019
+ }
1020
+ });
1021
+ /**
1022
+ * With `catchWheel` (and a fine pointer): scrolls by the wheel itself (`preventDefault`, then
1023
+ * `scrollTop +=`) and updates the range at once, so the rows are rendered in the same frame.
1024
+ */
1025
+ const handleWheel = useEventCallback((wheelEvent) => {
1026
+ if (catchWheel) {
1027
+ if (mayUseWheelRef.current) {
1028
+ const listEl = listElRef.current;
1029
+ if (listEl != null) {
1030
+ const scale = getWheelDeltaScale();
1031
+ const deltaX = wheelEvent.deltaX / scale;
1032
+ const deltaY = wheelEvent.deltaY / scale;
1033
+ if (deltaX === 0 && (listEl.scrollTop === 0 && deltaY <= 0 || listEl.scrollTop + listEl.offsetHeight >= listEl.scrollHeight && deltaY >= 0)) return;
1034
+ wheelEvent.preventDefault();
1035
+ listEl.scrollTop += deltaY;
1036
+ listEl.scrollLeft += deltaX;
1037
+ syncViewport();
1038
+ wheelScrollingRef.current = true;
1039
+ runLatestInNextFrame(() => {
1040
+ wheelScrollingRef.current = false;
1041
+ });
1042
+ }
1043
+ }
1044
+ onWheel?.(wheelEvent);
1045
+ }
1046
+ });
1047
+ useNonPassiveWheel(useCallback(() => listElRef.current, []), handleWheel, catchWheel);
1048
+ const iosCompensationEnabled = isIOS && virtual;
1049
+ const { addCompensation, isScrollSuppressedWithForceRestore } = useIosMomentumCompensation({
1050
+ enabled: iosCompensationEnabled,
1051
+ listElRef,
1052
+ itemsElRef,
1053
+ syncViewport,
1054
+ compensationYRef
1055
+ });
1056
+ /**
1057
+ * The list's own resize: stores its height and width, sets `--virtual-list-width` and updates
1058
+ * the range. Skipped while the list is hidden with `display: none`.
1059
+ */
1060
+ const handleListResize = useEventCallback((listEl, deferRender) => {
1061
+ if (isHiddenByDisplayNone(listEl)) return;
1062
+ const height = listEl.offsetHeight;
1063
+ const width = listEl.offsetWidth;
1064
+ const viewport = viewportRef.current;
1065
+ if (listElRef.current) listElRef.current.style.setProperty("--virtual-list-width", `${width}px`);
1066
+ if (renderCol == null && renderItemWithCols == null) {
1067
+ if (height === viewport.listHeight) return;
1068
+ } else if (height === viewport.listHeight && width === viewport.listWidth) return;
1069
+ viewport.listHeight = height;
1070
+ viewport.listWidth = width;
1071
+ updateRange("listResize", deferRender, replayPendingScrollTask);
1072
+ });
1073
+ const onListResizeObserved = useEventCallback(({ entry }) => {
1074
+ handleListResize(entry.target, false);
1075
+ onResize?.(entry);
1076
+ });
1077
+ const onListRefUpdated = useEventCallback((el) => {
1078
+ if (el) handleListResize(el, true);
1079
+ });
1080
+ /**
1081
+ * Tracks the row holding focus: focusin finds the row the target is in (the visible-items element's
1082
+ * child it is inside); focusout to an element outside the list releases it, and the range is updated so
1083
+ * the row unmounts if it is out of the range. A focusout to nowhere (`relatedTarget` null) does not
1084
+ * release it: switching to another window or tab fires one while the element keeps focus, and the row
1085
+ * must still be there when the person comes back. When focus did go to the page instead (a click on
1086
+ * nothing focusable), the next range update finds `document.activeElement` outside the list and
1087
+ * releases the row then.
1088
+ */
1089
+ const handleFocusIn = useEventCallback((event) => {
1090
+ const visibleItemsEl = getVisibleItemsEl();
1091
+ let el = event.target instanceof Element ? event.target : null;
1092
+ while (el !== null && el.parentElement !== visibleItemsEl) el = el.parentElement;
1093
+ focusedKeyRef.current = el?.getAttribute("data-virtual-list-item-key") ?? null;
1094
+ });
1095
+ const handleFocusOut = useEventCallback((event) => {
1096
+ const listEl = listElRef.current;
1097
+ const next = event.relatedTarget;
1098
+ if (listEl === null || next === null || next instanceof Node && listEl.contains(next)) return;
1099
+ if (focusedKeyRef.current !== null) {
1100
+ focusedKeyRef.current = null;
1101
+ updateRange("listScroll", true, null);
1102
+ }
1103
+ });
1104
+ useLayoutEffect(() => {
1105
+ const listEl = listElRef.current;
1106
+ if (listEl === null) return;
1107
+ listEl.addEventListener("focusin", handleFocusIn);
1108
+ listEl.addEventListener("focusout", handleFocusOut);
1109
+ return () => {
1110
+ listEl.removeEventListener("focusin", handleFocusIn);
1111
+ listEl.removeEventListener("focusout", handleFocusOut);
1112
+ };
1113
+ }, [handleFocusIn, handleFocusOut]);
1114
+ useLayoutEffect(() => {
1115
+ if (defaultScrollIndex != null) scrollTo({ index: defaultScrollIndex });
1116
+ else if (defaultScrollKey != null) scrollTo({ key: defaultScrollKey });
1117
+ }, [sessionId]);
1118
+ const itemsContainerStyle = useMemo(() => ({
1119
+ boxSizing: "content-box",
1120
+ width: px(totalColumnsWidth) ?? void 0,
1121
+ paddingTop: px(paddingTop) ?? void 0,
1122
+ ...typeof itemsStyle == "object" ? itemsStyle : {}
1123
+ }), [
1124
+ totalColumnsWidth,
1125
+ paddingTop,
1126
+ itemsStyle
1127
+ ]);
1128
+ const [keptItemsBefore, keptItemsAfter] = useMemo(() => {
1129
+ if (!virtual) return [EMPTY_ARRAY, EMPTY_ARRAY];
1130
+ const before = [];
1131
+ const after = [];
1132
+ keptKeysRef.current.forEach((key) => {
1133
+ const index = keyToIndexRef.current.get(key);
1134
+ if (index === void 0) return;
1135
+ const item = items[index];
1136
+ if (item !== void 0) {
1137
+ if (index < startIndex) before.push(item);
1138
+ else if (index > endIndex) after.push(item);
1139
+ }
1140
+ });
1141
+ return [before, after];
1142
+ }, [
1143
+ virtual,
1144
+ keptKeysRef.current,
1145
+ items,
1146
+ startIndex,
1147
+ endIndex
1148
+ ]);
1149
+ /**
1150
+ * Renders one item. With `itemResizable` it is wrapped in a ResizeObserverWrapper: when the ref is
1151
+ * set the item gets `data-virtual-list-item-key` and is measured in the next microtask batch
1152
+ * (`isFirst`); later sizes come from the ResizeObserver. The React key is `sessionId:key`, so a new
1153
+ * session remounts every item.
1154
+ */
1155
+ const renderItem = useCallback((item, absolute) => {
1156
+ const key = getKey(item);
1157
+ const index = keyToIndexRef.current.get(key);
1158
+ const reactKey = sessionId !== void 0 ? `${sessionId}:${key}` : key;
1159
+ const absoluteStyle = absolute ? {
1160
+ position: "absolute",
1161
+ top: px(fenwickTree.sum(index) - fenwickTree.sum(startIndex) + firstRowStartRef.current),
1162
+ left: 0,
1163
+ right: 0
1164
+ } : void 0;
1165
+ const colsNode = renderCol != null ? /* @__PURE__ */ jsx(ItemColumns, {
1166
+ index,
1167
+ item
1168
+ }) : void 0;
1169
+ const itemWithColsNode = renderItemWithCols != null ? /* @__PURE__ */ jsx(ItemColumns, {
1170
+ index,
1171
+ item
1172
+ }) : void 0;
1173
+ if (itemResizable) return /* @__PURE__ */ jsx(ResizeObserverWrapper, {
1174
+ simulateRefUpdateTrigger: sessionId,
1175
+ disabled: !virtual,
1176
+ onRefUpdate: (el) => {
1177
+ if (el) {
1178
+ el.setAttribute(ITEM_KEY_ATTR, key);
1179
+ if (!ignoreItemResize && virtual) {
1180
+ enqueueItemResize({
1181
+ key,
1182
+ target: el,
1183
+ isFirst: true
1184
+ });
1185
+ scheduleItemBatchResize();
1186
+ }
1187
+ }
1188
+ },
1189
+ onResize: ({ entry, isFirst }) => {
1190
+ if (!ignoreItemResize) {
1191
+ enqueueItemResize({
1192
+ key,
1193
+ target: entry.target,
1194
+ isFirst
1195
+ });
1196
+ getResizeObserverDelegate().runAfterEntries(handleItemBatchResize);
1197
+ }
1198
+ },
1199
+ children: ({ ref }) => {
1200
+ if (ItemComponent) return /* @__PURE__ */ jsx(ItemComponent, {
1201
+ domRef: ref,
1202
+ item,
1203
+ index,
1204
+ renderedCols: colsNode,
1205
+ renderedItemWithCols: itemWithColsNode,
1206
+ style: absoluteStyle
1207
+ });
1208
+ else if (renderItemChild == null) return;
1209
+ else return renderItemChild({
1210
+ key: void 0,
1211
+ domRef: ref,
1212
+ item,
1213
+ index,
1214
+ renderedCols: colsNode,
1215
+ renderedItemWithCols: itemWithColsNode,
1216
+ style: absoluteStyle
1217
+ });
1218
+ }
1219
+ }, reactKey);
1220
+ else if (ItemComponent) return /* @__PURE__ */ jsx(ItemComponent, {
1221
+ domRef: null,
1222
+ item,
1223
+ index,
1224
+ renderedCols: colsNode,
1225
+ renderedItemWithCols: itemWithColsNode,
1226
+ style: absoluteStyle
1227
+ }, reactKey);
1228
+ else if (renderItemChild == null) return;
1229
+ else return renderItemChild({
1230
+ key: reactKey,
1231
+ domRef: null,
1232
+ item,
1233
+ index,
1234
+ renderedCols: colsNode,
1235
+ renderedItemWithCols: itemWithColsNode,
1236
+ style: absoluteStyle
1237
+ });
1238
+ }, [
1239
+ virtual,
1240
+ getKey,
1241
+ fenwickTree,
1242
+ startIndex,
1243
+ renderCol,
1244
+ renderItemWithCols,
1245
+ itemResizable,
1246
+ sessionId,
1247
+ ignoreItemResize,
1248
+ enqueueItemResize,
1249
+ scheduleItemBatchResize,
1250
+ handleItemBatchResize,
1251
+ ItemComponent,
1252
+ renderItemChild
1253
+ ]);
1254
+ const renderInputs = useMemo(() => ({}), [
1255
+ virtual,
1256
+ getKey,
1257
+ renderCol,
1258
+ renderItemWithCols,
1259
+ itemResizable,
1260
+ sessionId,
1261
+ ignoreItemResize,
1262
+ ItemComponent,
1263
+ renderItemChild
1264
+ ]);
1265
+ const [flowElements] = useState(() => /* @__PURE__ */ new Map());
1266
+ const renderedVisibleItems = useMemo(() => {
1267
+ const nodes = visibleItems.map((item) => {
1268
+ const key = getKey(item);
1269
+ const index = keyToIndexRef.current.get(key);
1270
+ const cached = flowElements.get(key);
1271
+ if (cached !== void 0 && cached.item === item && cached.index === index && cached.inputs === renderInputs) return cached.node;
1272
+ const node = renderItem(item, false);
1273
+ flowElements.set(key, {
1274
+ item,
1275
+ index,
1276
+ inputs: renderInputs,
1277
+ node
1278
+ });
1279
+ return node;
1280
+ });
1281
+ if (flowElements.size > visibleItems.length) {
1282
+ const inRange = new Set(visibleItems.map(getKey));
1283
+ for (const key of flowElements.keys()) if (!inRange.has(key)) flowElements.delete(key);
1284
+ }
1285
+ return nodes;
1286
+ }, [
1287
+ renderItem,
1288
+ visibleItems,
1289
+ getKey,
1290
+ flowElements,
1291
+ renderInputs
1292
+ ]);
1293
+ const renderedKeptBefore = useMemo(() => keptItemsBefore.map((item) => renderItem(item, true)), [renderItem, keptItemsBefore]);
1294
+ const renderedKeptAfter = useMemo(() => keptItemsAfter.map((item) => renderItem(item, true)), [renderItem, keptItemsAfter]);
1295
+ useNonVirtualContentResize(itemsElRef, onContentResize, !virtual);
1296
+ const onContentResizeRef = useLatestRef(onContentResize);
1297
+ const hasItems = items.length !== 0;
1298
+ const footerNode = useMemo(() => typeof footer != "function" ? footer : /* @__PURE__ */ jsx(ResizeObserverWrapper, {
1299
+ onResize: () => {
1300
+ onContentResizeRef.current?.();
1301
+ },
1302
+ onUnmounted: () => {
1303
+ onContentResizeRef.current?.();
1304
+ },
1305
+ children: ({ ref }) => footer({ domRef: ref })
1306
+ }), [footer, onContentResizeRef]);
1307
+ const emptyNode = useMemo(() => typeof empty != "function" ? empty : /* @__PURE__ */ jsx(ResizeObserverWrapper, {
1308
+ onResize: () => {
1309
+ onContentResizeRef.current?.();
1310
+ },
1311
+ onUnmounted: () => {
1312
+ onContentResizeRef.current?.();
1313
+ },
1314
+ children: ({ ref }) => empty({ domRef: ref })
1315
+ }), [empty, onContentResizeRef]);
1316
+ const { snapshotAnchorElementStateAndSaveToRef, restoreScrollStateFromAnchor, clearAnchor } = useScrollAnchor(listElRef, getVisibleItemsEl);
1317
+ useMemoWithPrevious((previous) => {
1318
+ if (!previous || !itemResizable) return;
1319
+ const [wasVirtual, previousSessionId] = previous;
1320
+ if (previousSessionId === sessionId) {
1321
+ if (wasVirtual && !virtual) snapshotAnchorElementStateAndSaveToRef();
1322
+ else {
1323
+ const visibleItemsEl = getVisibleItemsEl();
1324
+ if (!(visibleItemsEl instanceof HTMLElement)) return;
1325
+ const rows = [];
1326
+ for (const el of Array.from(visibleItemsEl.children)) {
1327
+ const key = el.getAttribute(ITEM_KEY_ATTR);
1328
+ if (key !== null && el instanceof HTMLElement) rows.push({
1329
+ el,
1330
+ key
1331
+ });
1332
+ }
1333
+ const { spans, firstStart } = measureRowSpans(visibleItemsEl, rows.map((row) => row.el));
1334
+ if (rows[0] !== void 0 && keyToIndexRef.current.get(rows[0].key) === 0) leadingMarginRef.current = firstStart;
1335
+ rows.forEach(({ key }, i) => {
1336
+ if (recordMeasuredSize(keyToHeightOffsetRef.current, key, spans[i], itemEstimatedSize)) measuredVersionRef.current += 1;
1337
+ });
1338
+ }
1339
+ }
1340
+ }, [virtual, sessionId]);
1341
+ useLayoutEffectWithPrevious((previous) => {
1342
+ if (!itemResizable || !previous) return;
1343
+ const [wasVirtual, previousSessionId] = previous;
1344
+ if (previousSessionId === sessionId && wasVirtual && !virtual) {
1345
+ restoreScrollStateFromAnchor();
1346
+ clearAnchor();
1347
+ }
1348
+ }, [virtual, sessionId]);
1349
+ const { onKeyDown: onKeyboardScroll } = useKeyboardScroll(scrollTo, { pageBottomOcclusion: keyboardPageBottomOcclusion });
1350
+ /** The consumer's `onKeyDown` first: a key it takes (`preventDefault`) does not scroll the list. */
1351
+ const onKeyDown = useCallback((event) => {
1352
+ onNativeKeyDown?.(event);
1353
+ onKeyboardScroll(event);
1354
+ }, [onNativeKeyDown, onKeyboardScroll]);
1355
+ const emptyCentered = items.length === 0 && emptyAlign === "center";
1356
+ const rootClassName = cn("r-virtual-list", columns.length !== 0 && "r-virtual-list--x-scrollable", showScrollbar && "r-virtual-list--show-scrollbar", printable === true && "r-virtual-list--printable", emptyCentered && "r-virtual-list--empty-centered", iosCompensationEnabled && "r-virtual-list--ios-compensation-enabled", className);
1357
+ return /* @__PURE__ */ jsx(ResizeObserverWrapper, {
1358
+ forwardedRef: mergedListRefSetter,
1359
+ onRefUpdate: onListRefUpdated,
1360
+ onResize: onListResizeObserved,
1361
+ children: ({ ref }) => /* @__PURE__ */ jsxs("div", {
1362
+ ...nativeProps,
1363
+ "data-slot": "virtual-list",
1364
+ className: rootClassName,
1365
+ style,
1366
+ onScroll: handleListScroll,
1367
+ ref,
1368
+ onKeyDown,
1369
+ tabIndex: focusable ? 0 : -1,
1370
+ children: [
1371
+ header,
1372
+ hasItems ? /* @__PURE__ */ jsx("div", {
1373
+ "data-slot": "virtual-list-items",
1374
+ ref: itemsElRef,
1375
+ className: itemsClassName,
1376
+ style: itemsContainerStyle,
1377
+ children: /* @__PURE__ */ jsx(VirtualListContext.Provider, {
1378
+ value: imperativeApi,
1379
+ children: /* @__PURE__ */ jsx(ColumnsContext.Provider, {
1380
+ value: columnsContextValue,
1381
+ children: createElement(visibleItemsTag, {
1382
+ "data-slot": "virtual-list-visible-items",
1383
+ style: virtual ? VIRTUAL_VISIBLE_ITEMS_STYLE : NON_VIRTUAL_VISIBLE_ITEMS_STYLE,
1384
+ ...visibleItemsProps
1385
+ }, ...renderedKeptBefore, ...renderedVisibleItems, ...renderedKeptAfter)
1386
+ })
1387
+ })
1388
+ }, "items") : /* @__PURE__ */ jsx("div", {
1389
+ "data-slot": "virtual-list-empty",
1390
+ className: cn("r-virtual-list__empty", emptyCentered && "r-virtual-list__empty--center"),
1391
+ children: emptyNode
1392
+ }, "empty"),
1393
+ footerNode,
1394
+ paddingBottom ? /* @__PURE__ */ jsx("div", { style: { paddingBottom } }) : null,
1395
+ footerAfterBottomPadding
1396
+ ]
1397
+ })
1398
+ });
1399
+ }
1400
+ //#endregion
1401
+ export { VirtualList };