igniteui-webcomponents 7.3.0-beta.0 → 7.3.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 (375) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/animations/player.d.ts +7 -2
  3. package/animations/player.js +1 -2
  4. package/animations/player.js.map +1 -1
  5. package/components/accordion/accordion.js +4 -16
  6. package/components/accordion/accordion.js.map +1 -1
  7. package/components/avatar/avatar.d.ts +0 -1
  8. package/components/avatar/avatar.js +5 -9
  9. package/components/avatar/avatar.js.map +1 -1
  10. package/components/badge/badge.d.ts +1 -3
  11. package/components/badge/badge.js +4 -8
  12. package/components/badge/badge.js.map +1 -1
  13. package/components/banner/banner.d.ts +6 -5
  14. package/components/banner/banner.js +19 -17
  15. package/components/banner/banner.js.map +1 -1
  16. package/components/button/button-base.d.ts +1 -1
  17. package/components/button/button-base.js.map +1 -1
  18. package/components/button-group/button-group.d.ts +0 -1
  19. package/components/button-group/button-group.js +12 -17
  20. package/components/button-group/button-group.js.map +1 -1
  21. package/components/calendar/base.d.ts +3 -13
  22. package/components/calendar/base.js +10 -31
  23. package/components/calendar/base.js.map +1 -1
  24. package/components/calendar/calendar.d.ts +2 -2
  25. package/components/calendar/months-view/months-view.d.ts +1 -1
  26. package/components/calendar/months-view/months-view.js.map +1 -1
  27. package/components/carousel/carousel-indicator.d.ts +1 -1
  28. package/components/carousel/carousel-indicator.js +13 -13
  29. package/components/carousel/carousel-indicator.js.map +1 -1
  30. package/components/carousel/carousel-slide.d.ts +0 -2
  31. package/components/carousel/carousel-slide.js +7 -9
  32. package/components/carousel/carousel-slide.js.map +1 -1
  33. package/components/carousel/carousel.d.ts +52 -35
  34. package/components/carousel/carousel.js +136 -122
  35. package/components/carousel/carousel.js.map +1 -1
  36. package/components/carousel/themes/carousel.base.css.js +1 -1
  37. package/components/carousel/themes/carousel.base.css.js.map +1 -1
  38. package/components/chat/chat-input.d.ts +1 -1
  39. package/components/chat/chat-input.js +21 -21
  40. package/components/chat/chat-input.js.map +1 -1
  41. package/components/chat/chat.d.ts +0 -2
  42. package/components/chat/chat.js +6 -12
  43. package/components/chat/chat.js.map +1 -1
  44. package/components/checkbox/checkbox-base.d.ts +1 -1
  45. package/components/checkbox/checkbox.d.ts +3 -5
  46. package/components/checkbox/checkbox.js +33 -44
  47. package/components/checkbox/checkbox.js.map +1 -1
  48. package/components/checkbox/switch.d.ts +1 -1
  49. package/components/checkbox/switch.js +23 -34
  50. package/components/checkbox/switch.js.map +1 -1
  51. package/components/chip/chip.d.ts +1 -14
  52. package/components/chip/chip.js +12 -33
  53. package/components/chip/chip.js.map +1 -1
  54. package/components/color-picker/color-picker.d.ts +261 -0
  55. package/components/color-picker/color-picker.js +620 -0
  56. package/components/color-picker/color-picker.js.map +1 -0
  57. package/components/color-picker/common.d.ts +37 -0
  58. package/components/color-picker/common.js +55 -0
  59. package/components/color-picker/common.js.map +1 -0
  60. package/components/color-picker/converters.d.ts +18 -0
  61. package/components/color-picker/converters.js +173 -0
  62. package/components/color-picker/converters.js.map +1 -0
  63. package/components/color-picker/model.d.ts +120 -0
  64. package/components/color-picker/model.js +174 -0
  65. package/components/color-picker/model.js.map +1 -0
  66. package/components/color-picker/picker-canvas.d.ts +95 -0
  67. package/components/color-picker/picker-canvas.js +154 -0
  68. package/components/color-picker/picker-canvas.js.map +1 -0
  69. package/components/color-picker/themes/color-picker.base.css.d.ts +1 -0
  70. package/components/color-picker/themes/color-picker.base.css.js +3 -0
  71. package/components/color-picker/themes/color-picker.base.css.js.map +1 -0
  72. package/components/color-picker/themes/dark/color-picker.bootstrap.css.d.ts +1 -0
  73. package/components/color-picker/themes/dark/color-picker.bootstrap.css.js +3 -0
  74. package/components/color-picker/themes/dark/color-picker.bootstrap.css.js.map +1 -0
  75. package/components/color-picker/themes/dark/color-picker.fluent.css.d.ts +1 -0
  76. package/components/color-picker/themes/dark/color-picker.fluent.css.js +3 -0
  77. package/components/color-picker/themes/dark/color-picker.fluent.css.js.map +1 -0
  78. package/components/color-picker/themes/dark/color-picker.indigo.css.d.ts +1 -0
  79. package/components/color-picker/themes/dark/color-picker.indigo.css.js +3 -0
  80. package/components/color-picker/themes/dark/color-picker.indigo.css.js.map +1 -0
  81. package/components/color-picker/themes/dark/color-picker.material.css.d.ts +1 -0
  82. package/components/color-picker/themes/dark/color-picker.material.css.js +3 -0
  83. package/components/color-picker/themes/dark/color-picker.material.css.js.map +1 -0
  84. package/components/color-picker/themes/light/color-picker.bootstrap.css.d.ts +1 -0
  85. package/components/color-picker/themes/light/color-picker.bootstrap.css.js +3 -0
  86. package/components/color-picker/themes/light/color-picker.bootstrap.css.js.map +1 -0
  87. package/components/color-picker/themes/light/color-picker.fluent.css.d.ts +1 -0
  88. package/components/color-picker/themes/light/color-picker.fluent.css.js +3 -0
  89. package/components/color-picker/themes/light/color-picker.fluent.css.js.map +1 -0
  90. package/components/color-picker/themes/light/color-picker.indigo.css.d.ts +1 -0
  91. package/components/color-picker/themes/light/color-picker.indigo.css.js +3 -0
  92. package/components/color-picker/themes/light/color-picker.indigo.css.js.map +1 -0
  93. package/components/color-picker/themes/light/color-picker.material.css.d.ts +1 -0
  94. package/components/color-picker/themes/light/color-picker.material.css.js +3 -0
  95. package/components/color-picker/themes/light/color-picker.material.css.js.map +1 -0
  96. package/components/color-picker/themes/light/color-picker.shared.css.d.ts +1 -0
  97. package/components/color-picker/themes/light/color-picker.shared.css.js +3 -0
  98. package/components/color-picker/themes/light/color-picker.shared.css.js.map +1 -0
  99. package/components/color-picker/themes/picker-canvas.base.css.d.ts +1 -0
  100. package/components/color-picker/themes/picker-canvas.base.css.js +3 -0
  101. package/components/color-picker/themes/picker-canvas.base.css.js.map +1 -0
  102. package/components/color-picker/themes/shared/color-picker.bootstrap.css.d.ts +1 -0
  103. package/components/color-picker/themes/shared/color-picker.bootstrap.css.js +3 -0
  104. package/components/color-picker/themes/shared/color-picker.bootstrap.css.js.map +1 -0
  105. package/components/color-picker/themes/shared/color-picker.common.css.d.ts +1 -0
  106. package/components/color-picker/themes/shared/color-picker.common.css.js +3 -0
  107. package/components/color-picker/themes/shared/color-picker.common.css.js.map +1 -0
  108. package/components/color-picker/themes/shared/color-picker.fluent.css.d.ts +1 -0
  109. package/components/color-picker/themes/shared/color-picker.fluent.css.js +3 -0
  110. package/components/color-picker/themes/shared/color-picker.fluent.css.js.map +1 -0
  111. package/components/color-picker/themes/shared/color-picker.indigo.css.d.ts +1 -0
  112. package/components/color-picker/themes/shared/color-picker.indigo.css.js +3 -0
  113. package/components/color-picker/themes/shared/color-picker.indigo.css.js.map +1 -0
  114. package/components/color-picker/themes/shared/color-picker.material.css.d.ts +1 -0
  115. package/components/color-picker/themes/shared/color-picker.material.css.js +3 -0
  116. package/components/color-picker/themes/shared/color-picker.material.css.js.map +1 -0
  117. package/components/color-picker/themes/themes.d.ts +2 -0
  118. package/components/color-picker/themes/themes.js +50 -0
  119. package/components/color-picker/themes/themes.js.map +1 -0
  120. package/components/color-picker/validators.d.ts +3 -0
  121. package/components/color-picker/validators.js +5 -0
  122. package/components/color-picker/validators.js.map +1 -0
  123. package/components/combo/combo-item.d.ts +1 -3
  124. package/components/combo/combo-item.js +5 -12
  125. package/components/combo/combo-item.js.map +1 -1
  126. package/components/combo/combo.d.ts +7 -20
  127. package/components/combo/combo.js +59 -81
  128. package/components/combo/combo.js.map +1 -1
  129. package/components/date-picker/date-picker.base.d.ts +12 -9
  130. package/components/date-picker/date-picker.base.js +24 -31
  131. package/components/date-picker/date-picker.base.js.map +1 -1
  132. package/components/date-picker/date-picker.d.ts +1 -1
  133. package/components/date-picker/date-picker.js +3 -5
  134. package/components/date-picker/date-picker.js.map +1 -1
  135. package/components/date-range-picker/date-range-input.d.ts +2 -4
  136. package/components/date-range-picker/date-range-input.js +6 -37
  137. package/components/date-range-picker/date-range-input.js.map +1 -1
  138. package/components/date-range-picker/date-range-picker.d.ts +2 -5
  139. package/components/date-range-picker/date-range-picker.js +15 -28
  140. package/components/date-range-picker/date-range-picker.js.map +1 -1
  141. package/components/date-range-picker/predefined-ranges-area.d.ts +2 -2
  142. package/components/date-range-picker/predefined-ranges-area.js +4 -6
  143. package/components/date-range-picker/predefined-ranges-area.js.map +1 -1
  144. package/components/date-range-picker/validators.d.ts +1 -1
  145. package/components/date-range-picker/validators.js +5 -18
  146. package/components/date-range-picker/validators.js.map +1 -1
  147. package/components/date-time-input/date-part.d.ts +2 -1
  148. package/components/date-time-input/date-part.js +38 -75
  149. package/components/date-time-input/date-part.js.map +1 -1
  150. package/components/date-time-input/date-time-input.base.d.ts +31 -12
  151. package/components/date-time-input/date-time-input.base.js +43 -11
  152. package/components/date-time-input/date-time-input.base.js.map +1 -1
  153. package/components/date-time-input/date-time-input.d.ts +1 -3
  154. package/components/date-time-input/date-time-input.js +7 -40
  155. package/components/date-time-input/date-time-input.js.map +1 -1
  156. package/components/date-time-input/datetime-mask-parser.d.ts +8 -0
  157. package/components/date-time-input/datetime-mask-parser.js +8 -8
  158. package/components/date-time-input/datetime-mask-parser.js.map +1 -1
  159. package/components/date-time-input/validators.js +3 -14
  160. package/components/date-time-input/validators.js.map +1 -1
  161. package/components/dialog/dialog.d.ts +6 -7
  162. package/components/dialog/dialog.js +21 -26
  163. package/components/dialog/dialog.js.map +1 -1
  164. package/components/divider/divider.d.ts +1 -4
  165. package/components/divider/divider.js +8 -17
  166. package/components/divider/divider.js.map +1 -1
  167. package/components/dropdown/dropdown-group.js +1 -6
  168. package/components/dropdown/dropdown-group.js.map +1 -1
  169. package/components/expansion-panel/expansion-panel.d.ts +15 -5
  170. package/components/expansion-panel/expansion-panel.js +23 -34
  171. package/components/expansion-panel/expansion-panel.js.map +1 -1
  172. package/components/file-input/file-input.d.ts +2 -14
  173. package/components/file-input/file-input.js +5 -23
  174. package/components/file-input/file-input.js.map +1 -1
  175. package/components/highlight/highlight.d.ts +6 -8
  176. package/components/highlight/highlight.js +12 -20
  177. package/components/highlight/highlight.js.map +1 -1
  178. package/components/icon/icon-references.js +1 -0
  179. package/components/icon/icon-references.js.map +1 -1
  180. package/components/icon/icon.d.ts +1 -1
  181. package/components/icon/internal-icons-lib.js +3 -0
  182. package/components/icon/internal-icons-lib.js.map +1 -1
  183. package/components/icon/registry/types.d.ts +1 -1
  184. package/components/icon/registry/types.js.map +1 -1
  185. package/components/input/input.d.ts +9 -19
  186. package/components/input/input.js +30 -60
  187. package/components/input/input.js.map +1 -1
  188. package/components/input/themes/shared/input.material.css.js +1 -1
  189. package/components/input/themes/shared/input.material.css.js.map +1 -1
  190. package/components/mask-input/mask-input.d.ts +1 -1
  191. package/components/mask-input/mask-input.js +2 -4
  192. package/components/mask-input/mask-input.js.map +1 -1
  193. package/components/nav-drawer/nav-drawer.d.ts +7 -7
  194. package/components/nav-drawer/nav-drawer.js +12 -23
  195. package/components/nav-drawer/nav-drawer.js.map +1 -1
  196. package/components/progress/base.d.ts +4 -7
  197. package/components/progress/base.js +21 -45
  198. package/components/progress/base.js.map +1 -1
  199. package/components/qr-code/qr-code.d.ts +1 -1
  200. package/components/qr-code/qr-code.js +3 -2
  201. package/components/qr-code/qr-code.js.map +1 -1
  202. package/components/qr-code/types.d.ts +1 -1
  203. package/components/qr-code/types.js.map +1 -1
  204. package/components/radio/controller.d.ts +2 -30
  205. package/components/radio/controller.js +8 -94
  206. package/components/radio/controller.js.map +1 -1
  207. package/components/radio/radio.d.ts +5 -5
  208. package/components/radio/radio.js +48 -58
  209. package/components/radio/radio.js.map +1 -1
  210. package/components/radio-group/radio-group.d.ts +1 -2
  211. package/components/radio-group/radio-group.js +2 -9
  212. package/components/radio-group/radio-group.js.map +1 -1
  213. package/components/rating/rating.d.ts +24 -12
  214. package/components/rating/rating.js +79 -73
  215. package/components/rating/rating.js.map +1 -1
  216. package/components/resize-container/default-ghost.js +4 -3
  217. package/components/resize-container/default-ghost.js.map +1 -1
  218. package/components/resize-container/resize-container.d.ts +1 -1
  219. package/components/resize-container/resize-container.js +5 -3
  220. package/components/resize-container/resize-container.js.map +1 -1
  221. package/components/resize-container/resize-controller.js +4 -3
  222. package/components/resize-container/resize-controller.js.map +1 -1
  223. package/components/select/select-group.d.ts +2 -1
  224. package/components/select/select-group.js +7 -11
  225. package/components/select/select-group.js.map +1 -1
  226. package/components/select/select.d.ts +3 -4
  227. package/components/select/select.js +23 -28
  228. package/components/select/select.js.map +1 -1
  229. package/components/slider/range-slider.d.ts +3 -2
  230. package/components/slider/range-slider.js +22 -70
  231. package/components/slider/range-slider.js.map +1 -1
  232. package/components/slider/slider-base.d.ts +9 -6
  233. package/components/slider/slider-base.js +27 -28
  234. package/components/slider/slider-base.js.map +1 -1
  235. package/components/slider/slider.js +9 -5
  236. package/components/slider/slider.js.map +1 -1
  237. package/components/splitter/splitter.d.ts +1 -1
  238. package/components/splitter/splitter.js.map +1 -1
  239. package/components/stepper/step.d.ts +3 -0
  240. package/components/stepper/step.js +9 -5
  241. package/components/stepper/step.js.map +1 -1
  242. package/components/stepper/stepper.d.ts +0 -11
  243. package/components/stepper/stepper.js +21 -86
  244. package/components/stepper/stepper.js.map +1 -1
  245. package/components/tabs/tab.d.ts +1 -1
  246. package/components/tabs/tab.js +6 -5
  247. package/components/tabs/tab.js.map +1 -1
  248. package/components/tabs/tabs.d.ts +1 -5
  249. package/components/tabs/tabs.js +12 -34
  250. package/components/tabs/tabs.js.map +1 -1
  251. package/components/textarea/textarea.d.ts +6 -7
  252. package/components/textarea/textarea.js +3 -10
  253. package/components/textarea/textarea.js.map +1 -1
  254. package/components/theme-provider/theme-provider.d.ts +2 -4
  255. package/components/theme-provider/theme-provider.js +11 -21
  256. package/components/theme-provider/theme-provider.js.map +1 -1
  257. package/components/tile-manager/tile-manager.d.ts +10 -21
  258. package/components/tile-manager/tile-manager.js +43 -74
  259. package/components/tile-manager/tile-manager.js.map +1 -1
  260. package/components/tile-manager/tile.d.ts +10 -18
  261. package/components/tile-manager/tile.js +50 -67
  262. package/components/tile-manager/tile.js.map +1 -1
  263. package/components/tooltip/tooltip.d.ts +4 -7
  264. package/components/tooltip/tooltip.js +20 -28
  265. package/components/tooltip/tooltip.js.map +1 -1
  266. package/components/tree/tree.d.ts +1 -14
  267. package/components/tree/tree.js +5 -23
  268. package/components/tree/tree.js.map +1 -1
  269. package/components/tree/tree.navigation.d.ts +1 -1
  270. package/components/tree/tree.navigation.js.map +1 -1
  271. package/components/types.d.ts +2 -0
  272. package/components/types.js.map +1 -1
  273. package/components/validation-container/validation-container.d.ts +1 -2
  274. package/components/validation-container/validation-container.js.map +1 -1
  275. package/components/virtualization/engine.d.ts +40 -38
  276. package/components/virtualization/engine.js.map +1 -1
  277. package/components/virtualization/types.d.ts +6 -5
  278. package/components/virtualization/types.js.map +1 -1
  279. package/components/virtualization/virtualization.d.ts +94 -80
  280. package/components/virtualization/virtualization.js +10 -2
  281. package/components/virtualization/virtualization.js.map +1 -1
  282. package/custom-elements.json +31948 -26708
  283. package/igniteui-webcomponents.css-data.json +1 -1
  284. package/igniteui-webcomponents.html-data.json +1 -1
  285. package/index.d.ts +1 -0
  286. package/index.js +1 -0
  287. package/index.js.map +1 -1
  288. package/internals/controllers/aria-projection.d.ts +6 -6
  289. package/internals/controllers/aria-projection.js.map +1 -1
  290. package/internals/controllers/context-provider.d.ts +48 -0
  291. package/internals/controllers/context-provider.js +29 -0
  292. package/internals/controllers/context-provider.js.map +1 -0
  293. package/internals/controllers/drag.js +6 -6
  294. package/internals/controllers/drag.js.map +1 -1
  295. package/internals/controllers/gestures.js +3 -0
  296. package/internals/controllers/gestures.js.map +1 -1
  297. package/internals/controllers/group.d.ts +64 -0
  298. package/internals/controllers/group.js +104 -0
  299. package/internals/controllers/group.js.map +1 -0
  300. package/internals/controllers/internals.d.ts +16 -3
  301. package/internals/controllers/internals.js +10 -3
  302. package/internals/controllers/internals.js.map +1 -1
  303. package/internals/controllers/key-bindings.d.ts +6 -0
  304. package/internals/controllers/key-bindings.js +3 -0
  305. package/internals/controllers/key-bindings.js.map +1 -1
  306. package/internals/controllers/roving-focus.d.ts +72 -0
  307. package/internals/controllers/roving-focus.js +61 -0
  308. package/internals/controllers/roving-focus.js.map +1 -0
  309. package/internals/controllers/slot.d.ts +8 -0
  310. package/internals/controllers/slot.js +4 -0
  311. package/internals/controllers/slot.js.map +1 -1
  312. package/internals/controllers/toggle.d.ts +96 -0
  313. package/internals/controllers/toggle.js +65 -0
  314. package/internals/controllers/toggle.js.map +1 -0
  315. package/internals/date/converters.js +2 -5
  316. package/internals/date/converters.js.map +1 -1
  317. package/internals/date/model.d.ts +4 -0
  318. package/internals/date/model.js +6 -0
  319. package/internals/date/model.js.map +1 -1
  320. package/internals/decorators/coerced-property.d.ts +47 -0
  321. package/internals/decorators/coerced-property.js +36 -0
  322. package/internals/decorators/coerced-property.js.map +1 -0
  323. package/internals/definitions/defineAllComponents.js +2 -0
  324. package/internals/definitions/defineAllComponents.js.map +1 -1
  325. package/internals/i18n/i18n-controller.d.ts +22 -3
  326. package/internals/i18n/i18n-controller.js +28 -6
  327. package/internals/i18n/i18n-controller.js.map +1 -1
  328. package/internals/mixins/alert.d.ts +1 -1
  329. package/internals/mixins/alert.js +5 -3
  330. package/internals/mixins/alert.js.map +1 -1
  331. package/internals/mixins/combo-box.d.ts +3 -12
  332. package/internals/mixins/combo-box.js +6 -32
  333. package/internals/mixins/combo-box.js.map +1 -1
  334. package/internals/mixins/forms/associated.js +18 -0
  335. package/internals/mixins/forms/associated.js.map +1 -1
  336. package/internals/mixins/forms/types.d.ts +20 -1
  337. package/internals/mixins/forms/types.js.map +1 -1
  338. package/internals/mixins/i18n.d.ts +31 -0
  339. package/internals/mixins/i18n.js +36 -0
  340. package/internals/mixins/i18n.js.map +1 -0
  341. package/internals/mixins/mask-behavior.d.ts +6 -5
  342. package/internals/mixins/mask-behavior.js +1 -2
  343. package/internals/mixins/mask-behavior.js.map +1 -1
  344. package/internals/mixins/option.js +4 -2
  345. package/internals/mixins/option.js.map +1 -1
  346. package/internals/templates/masked-input.d.ts +1 -1
  347. package/internals/templates/masked-input.js.map +1 -1
  348. package/internals/templates/slotted-icon.d.ts +32 -0
  349. package/internals/templates/slotted-icon.js +19 -0
  350. package/internals/templates/slotted-icon.js.map +1 -0
  351. package/internals/templates/toggle-shell.d.ts +46 -0
  352. package/internals/templates/toggle-shell.js +38 -0
  353. package/internals/templates/toggle-shell.js.map +1 -0
  354. package/internals/timing.d.ts +32 -0
  355. package/internals/timing.js +20 -0
  356. package/internals/timing.js.map +1 -0
  357. package/internals/utils/arrays.d.ts +2 -2
  358. package/internals/utils/arrays.js.map +1 -1
  359. package/internals/utils/dom.d.ts +22 -0
  360. package/internals/utils/dom.js +15 -1
  361. package/internals/utils/dom.js.map +1 -1
  362. package/internals/utils/math.d.ts +1 -1
  363. package/internals/utils/math.js.map +1 -1
  364. package/internals/utils/types.d.ts +1 -1
  365. package/internals/utils/types.js.map +1 -1
  366. package/internals/validators.d.ts +23 -0
  367. package/internals/validators.js +21 -0
  368. package/internals/validators.js.map +1 -1
  369. package/package.json +3 -1
  370. package/theming/theming-controller.d.ts +3 -3
  371. package/theming/theming-controller.js.map +1 -1
  372. package/web-types.json +2 -2
  373. package/internals/decorators/watch.d.ts +0 -5
  374. package/internals/decorators/watch.js +0 -19
  375. package/internals/decorators/watch.js.map +0 -1
@@ -1,52 +1,53 @@
1
1
  import type { ScrollAlignment, VisibleRange } from './types.js';
2
2
  /**
3
- * Pure scroll-math engine for a single axis of virtual scrolling. All size
4
- * state is held in a Fenwick tree.
3
+ * Pure scroll-math engine for one axis of virtual scrolling. A Fenwick tree
4
+ * holds all size state.
5
5
  *
6
- * ### Virtual vs DOM coordinates
6
+ * ### Virtual and DOM coordinates
7
7
  *
8
- * Browsers cap how far an element can be scrolled. When the summed item size
9
- * exceeds that cap, the engine compresses the *virtual* space (`0…totalSize`)
10
- * into the *DOM* space the browser can represent (`0…domSize`) by the factor
11
- * `_virtualRatio`. Every offset crossing that boundary is scaled: incoming
12
- * scroll positions are multiplied by the ratio, outgoing offsets divided by
13
- * it. Item sizes render at their real px size and so are always virtual.
8
+ * Browsers limit how far an element can scroll. When the total item size is
9
+ * larger than that limit, the engine compresses the *virtual* space
10
+ * (`0…totalSize`) into the *DOM* space the browser can represent
11
+ * (`0…domSize`) by the factor `_virtualRatio`. Each offset that crosses that
12
+ * boundary is scaled: incoming scroll positions are multiplied by the ratio,
13
+ * and outgoing offsets are divided by it. Items render at their real pixel
14
+ * size, so item sizes are always virtual.
14
15
  */
15
16
  export declare class VirtualScrollEngine {
16
17
  private _maxBrowserSize;
17
18
  /**
18
- * The ratio `totalSize / maxBrowserSize` when `totalSize` exceeds the
19
- * maximum DOM coordinate the browser supports; `1` otherwise.
20
- * Used to map virtual scroll positions to DOM scroll positions.
19
+ * The ratio `totalSize / maxBrowserSize` when `totalSize` is larger than
20
+ * the maximum DOM coordinate the browser supports; `1` otherwise.
21
+ * Maps virtual scroll positions to DOM scroll positions.
21
22
  */
22
23
  private _virtualRatio;
23
24
  /** Binary Indexed Tree for O(log N) size queries and updates. */
24
25
  private _tree;
25
26
  /**
26
- * Called whenever item sizes or the item count change, e.g.
27
- * `() => this.requestUpdate()`.
27
+ * Called when item sizes or the item count change.
28
+ * Example: `() => this.requestUpdate()`.
28
29
  */
29
30
  onSizeChange: (() => void) | null;
30
31
  /** Total virtual size of all items in px. */
31
32
  get totalSize(): number;
32
33
  /** Total size in DOM space, clamped to the maximum browser size. */
33
34
  get domSize(): number;
34
- /** Probes the document for the maximum browser size and rescales. */
35
+ /** Measures the maximum browser size for the document and rescales. */
35
36
  initMaxBrowserSize(doc: Document): void;
36
37
  /**
37
- * Grows or shrinks the internal sizes array to `length`. Measured sizes
38
- * below `retainCount` are preserved; the rest is refilled with
39
- * `estimatedSize` and marked unmeasured. Callers that only append can leave
40
- * `retainCount` at its default; callers whose data changed identity at some
41
- * index must pass it, so the stale measurements behind it are discarded.
38
+ * Resizes the internal sizes array to `length`. Measured sizes below
39
+ * `retainCount` are kept. The remainder is filled with `estimatedSize` and
40
+ * marked unmeasured. Callers that only append can keep the default
41
+ * `retainCount`. Callers whose data changed identity at some index must
42
+ * pass that index, so the stale measurements after it are discarded.
42
43
  */
43
44
  resize(length: number, estimatedSize: number, retainCount?: number): void;
44
45
  /** Records the measured DOM size for a single item. */
45
46
  measureItem(index: number, size: number): void;
46
47
  /**
47
- * Applies a new estimated size to every item not yet measured in the DOM.
48
- * Use this when `estimatedItemSize` changes but the item count doesn't, so
49
- * `resize` would be a no-op.
48
+ * Applies a new estimated size to each item that is not measured in the
49
+ * DOM. Use this when `estimatedItemSize` changes but the item count does
50
+ * not, because `resize` is then a no-op.
50
51
  */
51
52
  updateEstimatedSize(estimatedSize: number): void;
52
53
  /**
@@ -56,36 +57,37 @@ export declare class VirtualScrollEngine {
56
57
  getScrollOffsetForIndex(index: number): number;
57
58
  /**
58
59
  * The largest DOM scroll offset the host can reach for the given viewport
59
- * size. Requesting anything beyond it silently does nothing, so offsets
60
- * handed out to a caller that waits for the scroll to settle are clamped
61
- * to it.
60
+ * size. A request beyond it does nothing, so offsets given to a caller
61
+ * that waits for the scroll to settle are clamped to it.
62
62
  */
63
63
  private _getMaxScrollOffset;
64
64
  /**
65
- * Returns the DOM scroll offset that positions the item at `index`
66
- * according to `align` within a `viewportSize` px viewport, clamped to the
65
+ * Returns the DOM scroll offset that positions the item at `index` in a
66
+ * `viewportSize` px viewport, aligned by `align` and clamped to the
67
67
  * reachable scroll range.
68
68
  *
69
69
  * The slack is computed in virtual space against the item's real size and
70
- * converted to DOM space once, at the end: a DOM pixel is worth
71
- * `_virtualRatio` virtual pixels, so mixing the two would scale the slack.
70
+ * converted to DOM space once, at the end. One DOM pixel equals
71
+ * `_virtualRatio` virtual pixels, so mixed coordinates would scale the
72
+ * slack.
72
73
  */
73
74
  getAlignedScrollOffset(index: number, viewportSize: number, align: ScrollAlignment): number;
74
75
  /**
75
- * Whether the item at `index` needs no scrolling to be seen at the given DOM
76
- * scroll position: either it sits entirely inside the viewport, or it is
77
- * larger than the viewport and already covers it end to end. The latter
78
- * mirrors native `scrollIntoView({ block: 'nearest' })`.
76
+ * Whether the item at `index` is visible without more scrolling at the
77
+ * given DOM scroll position. True when the item is fully inside the
78
+ * viewport, or when it is larger than the viewport and covers it fully.
79
+ * The second case matches native `scrollIntoView({ block: 'nearest' })`.
79
80
  */
80
81
  isIndexInView(index: number, scrollPosition: number, viewportSize: number): boolean;
81
82
  /**
82
- * Returns the visible + over-scanned item range for the given scroll state.
83
+ * Returns the visible and over-scanned item range for the given scroll
84
+ * state.
83
85
  */
84
86
  getVisibleRange(scrollPosition: number, viewportSize: number, overScan: number): VisibleRange;
85
87
  /**
86
- * Sum of the actual sizes of the items in [startIndex, endIndex]. Clamps the
87
- * content translate offset so rendered items never overflow past `domSize`
88
- * under coordinate compression.
88
+ * Sum of the actual sizes of the items in [startIndex, endIndex]. The
89
+ * render pass uses it to clamp the content translate offset, so rendered
90
+ * items do not overflow past `domSize` under coordinate compression.
89
91
  */
90
92
  getPhysicalRangeSize(startIndex: number, endIndex: number): number;
91
93
  private _updateVirtualRatio;
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/components/virtualization/engine.ts"],"names":[],"mappings":"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","sourcesContent":["import { clamp } from '#internals/utils/math.js';\nimport type { ScrollAlignment, VisibleRange } from './types.js';\n\n/**\n * The maximum scrollable coordinate doesn't change over a document's lifetime,\n * so instances sharing one document share a single probe.\n */\nconst _maxBrowserSizeCache = new WeakMap<Document, number>();\n\n/**\n * Probes the browser for the maximum scrollable coordinate it supports.\n */\nfunction getMaxBrowserSizeProbePx(doc: Document): number {\n const cached = _maxBrowserSizeCache.get(doc);\n if (cached !== undefined) {\n return cached;\n }\n\n const container = doc.body ?? doc.documentElement;\n if (!container) {\n return Number.POSITIVE_INFINITY;\n }\n\n const div = doc.createElement('div');\n div.style.position = 'absolute';\n div.style.top = `${Number.MAX_SAFE_INTEGER}px`;\n div.style.width = '0';\n div.style.height = '0';\n div.style.visibility = 'hidden';\n container.appendChild(div);\n const scrollOffset = doc.documentElement?.scrollTop ?? 0;\n const size = Math.abs(div.getBoundingClientRect().top) + scrollOffset;\n container.removeChild(div);\n\n _maxBrowserSizeCache.set(doc, size);\n return size;\n}\n\n/**\n * Clamps `index` into `[0, length - 1]`, keeping both `prefixSum(index)` and\n * `prefixSum(index + 1)` addressable. Callers guard for `length > 0`.\n */\nfunction clampIndex(index: number, length: number): number {\n return clamp(index, 0, length - 1);\n}\n\n/**\n * Fills `tree` - a 1-indexed Fenwick array of `sizes.length + 1` entries,\n * expected to be zeroed - with the partial range sums of `sizes` in a single\n * O(N) pass. Returns the grand total.\n */\nfunction buildTree(tree: Float64Array, sizes: Float64Array): number {\n const length = sizes.length;\n let total = 0;\n\n for (let i = 1; i <= length; i++) {\n tree[i] += sizes[i - 1];\n total += sizes[i - 1];\n const j = i + (i & -i);\n if (j <= length) {\n tree[j] += tree[i];\n }\n }\n return total;\n}\n\n/**\n * Binary Indexed Tree (Fenwick tree) over item sizes. Every hot-path\n * operation is O(log N): point update (item measured), prefix sum (scroll\n * offset) and index at offset (scroll -> item, via binary lifting).\n */\nclass SizeTree {\n public readonly length: number;\n\n /** 1-indexed BIT; each cell holds a partial range sum. */\n private readonly _tree: Float64Array;\n\n /** Raw per-item sizes (0-indexed), kept for O(1) reads and delta calc. */\n private readonly _sizes: Float64Array;\n\n /**\n * Which indices hold a real, DOM-measured size (`1`) rather than an\n * estimate (`0`). Only the latter are touched by `applyEstimate`.\n */\n private readonly _measured: Uint8Array;\n\n /** Running total maintained alongside tree updates in O(1). */\n private _total: number;\n\n /**\n * Highest power-of-two <= `length`, for the binary lifting in\n * `findIndexAtOffset`. Precomputed since that runs on every scroll event.\n */\n private readonly _topBit: number;\n\n private constructor(\n length: number,\n sizes: Float64Array,\n tree: Float64Array,\n total: number,\n measured: Uint8Array\n ) {\n this.length = length;\n this._sizes = sizes;\n this._tree = tree;\n this._total = total;\n this._measured = measured;\n this._topBit = length > 0 ? 1 << (31 - Math.clz32(length)) : 0;\n }\n\n /**\n * Creates a tree of `length` items all initialized to `fillSize`, none of\n * which are considered measured yet. O(N).\n */\n public static filled(length: number, fillSize: number): SizeTree {\n return SizeTree._build(\n new Float64Array(length).fill(fillSize),\n new Uint8Array(length)\n );\n }\n\n /**\n * Builds a tree from a sizes array and its matching measured-flags array. O(N).\n */\n private static _build(sizes: Float64Array, measured: Uint8Array): SizeTree {\n const tree = new Float64Array(sizes.length + 1);\n const total = buildTree(tree, sizes);\n return new SizeTree(sizes.length, sizes, tree, total, measured);\n }\n\n /** Total size of all items. O(1). */\n public get totalSize(): number {\n return this._total;\n }\n\n /**\n * Prefix sum of items [0, i) — the virtual scroll offset at the leading\n * edge of item i. O(log N).\n */\n public prefixSum(i: number): number {\n let sum = 0;\n for (let j = i; j > 0; j -= j & -j) {\n sum += this._tree[j];\n }\n return sum;\n }\n\n /**\n * Update the size of the item at 0-based index. Marks the item as\n * explicitly measured, exempting it from future `applyEstimate()` calls.\n * Returns true when the size actually changed. O(log N).\n */\n public update(index: number, newSize: number): boolean {\n if (index < 0 || index >= this.length) return false;\n\n const old = this._sizes[index];\n this._measured[index] = 1;\n if (old === newSize) return false;\n\n const delta = newSize - old;\n this._sizes[index] = newSize;\n this._total += delta;\n for (let i = index + 1; i <= this.length; i += i & -i) {\n this._tree[i] += delta;\n }\n return true;\n }\n\n /**\n * Returns a new tree of `newLength` items in a single O(N) pass. Sizes and\n * their measured flags are preserved up to\n * `min(this.length, newLength, retainCount)`; the rest is filled with\n * `fillSize` and marked unmeasured. Pass a `retainCount` below the item\n * count when the data behind those indices changed identity.\n */\n public cloneResized(\n newLength: number,\n fillSize: number,\n retainCount = newLength\n ): SizeTree {\n const sizes = new Float64Array(newLength).fill(fillSize);\n const measured = new Uint8Array(newLength);\n const retained = Math.max(0, Math.min(this.length, newLength, retainCount));\n sizes.set(this._sizes.subarray(0, retained));\n measured.set(this._measured.subarray(0, retained));\n return SizeTree._build(sizes, measured);\n }\n\n /**\n * Applies `estimatedSize` to every unmeasured item, leaving measured ones\n * untouched. Returns true when at least one size changed.\n *\n * One estimate change can affect most of the list at once, so this rebuilds\n * in a single O(N) pass instead of one O(log N) `update` per item.\n */\n public applyEstimate(estimatedSize: number): boolean {\n let changed = false;\n for (let i = 0; i < this.length; i++) {\n if (!this._measured[i] && this._sizes[i] !== estimatedSize) {\n this._sizes[i] = estimatedSize;\n changed = true;\n }\n }\n if (!changed) return false;\n\n this._tree.fill(0);\n this._total = buildTree(this._tree, this._sizes);\n return true;\n }\n\n /**\n * Returns the 0-based index of the item containing the scroll `offset`, i.e.\n * the largest i where `prefixSum(i) <= offset < prefixSum(i + 1)`. O(log N).\n */\n public findIndexAtOffset(offset: number): number {\n if (offset <= 0 || this.length === 0) return 0;\n\n let idx = 0;\n let remaining = offset;\n\n for (let bit = this._topBit; bit > 0; bit >>= 1) {\n const next = idx + bit;\n if (next <= this.length && this._tree[next] <= remaining) {\n idx = next;\n remaining -= this._tree[idx];\n }\n }\n return Math.min(this.length - 1, idx);\n }\n}\n\n/**\n * Pure scroll-math engine for a single axis of virtual scrolling. All size\n * state is held in a Fenwick tree.\n *\n * ### Virtual vs DOM coordinates\n *\n * Browsers cap how far an element can be scrolled. When the summed item size\n * exceeds that cap, the engine compresses the *virtual* space (`0…totalSize`)\n * into the *DOM* space the browser can represent (`0…domSize`) by the factor\n * `_virtualRatio`. Every offset crossing that boundary is scaled: incoming\n * scroll positions are multiplied by the ratio, outgoing offsets divided by\n * it. Item sizes render at their real px size and so are always virtual.\n */\nexport class VirtualScrollEngine {\n private _maxBrowserSize = Number.POSITIVE_INFINITY;\n\n /**\n * The ratio `totalSize / maxBrowserSize` when `totalSize` exceeds the\n * maximum DOM coordinate the browser supports; `1` otherwise.\n * Used to map virtual scroll positions to DOM scroll positions.\n */\n private _virtualRatio = 1;\n\n /** Binary Indexed Tree for O(log N) size queries and updates. */\n private _tree: SizeTree | null = null;\n\n /**\n * Called whenever item sizes or the item count change, e.g.\n * `() => this.requestUpdate()`.\n */\n public onSizeChange: (() => void) | null = null;\n\n /** Total virtual size of all items in px. */\n public get totalSize(): number {\n return this._tree?.totalSize ?? 0;\n }\n\n /** Total size in DOM space, clamped to the maximum browser size. */\n public get domSize(): number {\n return this._virtualRatio !== 1 ? this._maxBrowserSize : this.totalSize;\n }\n\n /** Probes the document for the maximum browser size and rescales. */\n public initMaxBrowserSize(doc: Document): void {\n this._maxBrowserSize = getMaxBrowserSizeProbePx(doc);\n this._updateVirtualRatio();\n }\n\n /**\n * Grows or shrinks the internal sizes array to `length`. Measured sizes\n * below `retainCount` are preserved; the rest is refilled with\n * `estimatedSize` and marked unmeasured. Callers that only append can leave\n * `retainCount` at its default; callers whose data changed identity at some\n * index must pass it, so the stale measurements behind it are discarded.\n */\n public resize(\n length: number,\n estimatedSize: number,\n retainCount = length\n ): void {\n if (this._tree?.length === length && retainCount >= length) return;\n\n this._tree = this._tree\n ? this._tree.cloneResized(length, estimatedSize, retainCount)\n : SizeTree.filled(length, estimatedSize);\n this._updateVirtualRatio();\n this.onSizeChange?.();\n }\n\n /** Records the measured DOM size for a single item. */\n public measureItem(index: number, size: number): void {\n if (!this._tree?.update(index, size)) return;\n\n this._updateVirtualRatio();\n this.onSizeChange?.();\n }\n\n /**\n * Applies a new estimated size to every item not yet measured in the DOM.\n * Use this when `estimatedItemSize` changes but the item count doesn't, so\n * `resize` would be a no-op.\n */\n public updateEstimatedSize(estimatedSize: number): void {\n if (!this._tree?.applyEstimate(estimatedSize)) return;\n\n this._updateVirtualRatio();\n this.onSizeChange?.();\n }\n\n /**\n * Returns the DOM scroll offset in px that puts the item at `index` at the\n * leading edge of the viewport.\n */\n public getScrollOffsetForIndex(index: number): number {\n if (!this._tree || index <= 0) return 0;\n\n const clamped = Math.min(index, this._tree.length);\n return this._tree.prefixSum(clamped) / this._virtualRatio;\n }\n\n /**\n * The largest DOM scroll offset the host can reach for the given viewport\n * size. Requesting anything beyond it silently does nothing, so offsets\n * handed out to a caller that waits for the scroll to settle are clamped\n * to it.\n */\n private _getMaxScrollOffset(viewportSize: number): number {\n return Math.max(0, this.domSize - viewportSize);\n }\n\n /**\n * Returns the DOM scroll offset that positions the item at `index`\n * according to `align` within a `viewportSize` px viewport, clamped to the\n * reachable scroll range.\n *\n * The slack is computed in virtual space against the item's real size and\n * converted to DOM space once, at the end: a DOM pixel is worth\n * `_virtualRatio` virtual pixels, so mixing the two would scale the slack.\n */\n public getAlignedScrollOffset(\n index: number,\n viewportSize: number,\n align: ScrollAlignment\n ): number {\n if (!this._tree || this._tree.length === 0) return 0;\n\n const clamped = clampIndex(index, this._tree.length);\n const itemStart = this._tree.prefixSum(clamped);\n let offset = itemStart;\n\n if (align !== 'start') {\n const itemEnd = this._tree.prefixSum(clamped + 1);\n const slack = viewportSize - Math.max(0, itemEnd - itemStart);\n offset -= align === 'center' ? slack / 2 : slack;\n }\n\n return clamp(\n offset / this._virtualRatio,\n 0,\n this._getMaxScrollOffset(viewportSize)\n );\n }\n\n /**\n * Whether the item at `index` needs no scrolling to be seen at the given DOM\n * scroll position: either it sits entirely inside the viewport, or it is\n * larger than the viewport and already covers it end to end. The latter\n * mirrors native `scrollIntoView({ block: 'nearest' })`.\n */\n public isIndexInView(\n index: number,\n scrollPosition: number,\n viewportSize: number\n ): boolean {\n if (!this._tree || this._tree.length === 0) return false;\n\n const clamped = clampIndex(index, this._tree.length);\n const itemStart = this._tree.prefixSum(clamped);\n const itemEnd = this._tree.prefixSum(clamped + 1);\n const viewStart = Math.max(0, scrollPosition) * this._virtualRatio;\n const viewEnd = viewStart + viewportSize;\n\n const contained = itemStart >= viewStart && itemEnd <= viewEnd;\n const spanning = itemStart <= viewStart && itemEnd >= viewEnd;\n\n return contained || spanning;\n }\n\n /**\n * Returns the visible + over-scanned item range for the given scroll state.\n */\n public getVisibleRange(\n scrollPosition: number,\n viewportSize: number,\n overScan: number\n ): VisibleRange {\n if (!this._tree || this._tree.length === 0 || viewportSize <= 0) {\n return { startIndex: 0, endIndex: -1 };\n }\n\n // The viewport is *not* scaled by the virtual ratio: items render at their\n // real px size, so a `viewportSize` px viewport always shows that many\n // virtual px worth of items, however compressed the scroll range is.\n const startOffset = Math.max(0, scrollPosition) * this._virtualRatio;\n const first = this._tree.findIndexAtOffset(startOffset);\n const last = this._tree.findIndexAtOffset(startOffset + viewportSize);\n\n return {\n startIndex: Math.max(0, first - overScan),\n endIndex: Math.min(this._tree.length - 1, last + overScan),\n };\n }\n\n /**\n * Sum of the actual sizes of the items in [startIndex, endIndex]. Clamps the\n * content translate offset so rendered items never overflow past `domSize`\n * under coordinate compression.\n */\n public getPhysicalRangeSize(startIndex: number, endIndex: number): number {\n if (!this._tree) return 0;\n\n const start = Math.max(0, startIndex);\n const end = Math.min(Math.max(endIndex + 1, start), this._tree.length);\n return this._tree.prefixSum(end) - this._tree.prefixSum(start);\n }\n\n private _updateVirtualRatio(): void {\n const totalSize = this._tree?.totalSize ?? 0;\n this._virtualRatio =\n totalSize <= this._maxBrowserSize ? 1 : totalSize / this._maxBrowserSize;\n }\n}\n"]}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/components/virtualization/engine.ts"],"names":[],"mappings":"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","sourcesContent":["import { clamp } from '#internals/utils/math.js';\nimport type { ScrollAlignment, VisibleRange } from './types.js';\n\n/**\n * The maximum scrollable coordinate of a document does not change.\n * All instances in one document share one probe result.\n */\nconst _maxBrowserSizeCache = new WeakMap<Document, number>();\n\n/**\n * Measures the maximum scrollable coordinate that the browser supports.\n */\nfunction getMaxBrowserSizeProbePx(doc: Document): number {\n const cached = _maxBrowserSizeCache.get(doc);\n if (cached !== undefined) {\n return cached;\n }\n\n const container = doc.body ?? doc.documentElement;\n if (!container) {\n return Number.POSITIVE_INFINITY;\n }\n\n const div = doc.createElement('div');\n div.style.position = 'absolute';\n div.style.top = `${Number.MAX_SAFE_INTEGER}px`;\n div.style.width = '0';\n div.style.height = '0';\n div.style.visibility = 'hidden';\n container.appendChild(div);\n const scrollOffset = doc.documentElement?.scrollTop ?? 0;\n const size = Math.abs(div.getBoundingClientRect().top) + scrollOffset;\n container.removeChild(div);\n\n _maxBrowserSizeCache.set(doc, size);\n return size;\n}\n\n/**\n * Clamps `index` into `[0, length - 1]`. This keeps `prefixSum(index)` and\n * `prefixSum(index + 1)` valid. Callers make sure that `length > 0`.\n */\nfunction clampIndex(index: number, length: number): number {\n return clamp(index, 0, length - 1);\n}\n\n/**\n * Fills `tree` with the partial range sums of `sizes` in one O(N) pass.\n * `tree` is a 1-indexed Fenwick array of `sizes.length + 1` zeroed entries.\n * Returns the total sum.\n */\nfunction buildTree(tree: Float64Array, sizes: Float64Array): number {\n const length = sizes.length;\n let total = 0;\n\n for (let i = 1; i <= length; i++) {\n tree[i] += sizes[i - 1];\n total += sizes[i - 1];\n const j = i + (i & -i);\n if (j <= length) {\n tree[j] += tree[i];\n }\n }\n return total;\n}\n\n/**\n * Binary Indexed Tree (Fenwick tree) over item sizes. Each hot-path operation\n * is O(log N): point update (item measured), prefix sum (scroll offset), and\n * index at offset (scroll to item, through binary lifting).\n */\nclass SizeTree {\n public readonly length: number;\n\n /** A 1-indexed BIT. Each cell holds a partial range sum. */\n private readonly _tree: Float64Array;\n\n /** Raw per-item sizes, 0-indexed. Kept for O(1) reads and delta calculation. */\n private readonly _sizes: Float64Array;\n\n /**\n * Flags the indices that hold a DOM-measured size (`1`) instead of an\n * estimate (`0`). `applyEstimate` changes only the estimated entries.\n */\n private readonly _measured: Uint8Array;\n\n /** Running total. Updated together with the tree in O(1). */\n private _total: number;\n\n /**\n * The highest power of two <= `length`, for the binary lifting in\n * `findIndexAtOffset`. Precomputed because that runs on each scroll event.\n */\n private readonly _topBit: number;\n\n private constructor(\n length: number,\n sizes: Float64Array,\n tree: Float64Array,\n total: number,\n measured: Uint8Array\n ) {\n this.length = length;\n this._sizes = sizes;\n this._tree = tree;\n this._total = total;\n this._measured = measured;\n this._topBit = length > 0 ? 1 << (31 - Math.clz32(length)) : 0;\n }\n\n /**\n * Creates a tree of `length` items, each set to `fillSize` and marked\n * unmeasured. O(N).\n */\n public static filled(length: number, fillSize: number): SizeTree {\n return SizeTree._build(\n new Float64Array(length).fill(fillSize),\n new Uint8Array(length)\n );\n }\n\n /**\n * Builds a tree from a sizes array and its matching measured-flags array. O(N).\n */\n private static _build(sizes: Float64Array, measured: Uint8Array): SizeTree {\n const tree = new Float64Array(sizes.length + 1);\n const total = buildTree(tree, sizes);\n return new SizeTree(sizes.length, sizes, tree, total, measured);\n }\n\n /** Total size of all items. O(1). */\n public get totalSize(): number {\n return this._total;\n }\n\n /**\n * Prefix sum of items [0, i): the virtual scroll offset at the leading\n * edge of item i. O(log N).\n */\n public prefixSum(i: number): number {\n let sum = 0;\n for (let j = i; j > 0; j -= j & -j) {\n sum += this._tree[j];\n }\n return sum;\n }\n\n /**\n * Sets the size of the item at a 0-based index and marks the item as\n * measured. Later `applyEstimate()` calls do not change measured items.\n * Returns true when the size changed. O(log N).\n */\n public update(index: number, newSize: number): boolean {\n if (index < 0 || index >= this.length) return false;\n\n const old = this._sizes[index];\n this._measured[index] = 1;\n if (old === newSize) return false;\n\n const delta = newSize - old;\n this._sizes[index] = newSize;\n this._total += delta;\n for (let i = index + 1; i <= this.length; i += i & -i) {\n this._tree[i] += delta;\n }\n return true;\n }\n\n /**\n * Returns a new tree of `newLength` items in one O(N) pass. Sizes and\n * measured flags are kept up to `min(this.length, newLength, retainCount)`.\n * The remainder is filled with `fillSize` and marked unmeasured. Pass a\n * `retainCount` below the item count when the data behind those indices\n * changed identity.\n */\n public cloneResized(\n newLength: number,\n fillSize: number,\n retainCount = newLength\n ): SizeTree {\n const sizes = new Float64Array(newLength).fill(fillSize);\n const measured = new Uint8Array(newLength);\n const retained = Math.max(0, Math.min(this.length, newLength, retainCount));\n sizes.set(this._sizes.subarray(0, retained));\n measured.set(this._measured.subarray(0, retained));\n return SizeTree._build(sizes, measured);\n }\n\n /**\n * Sets `estimatedSize` on each unmeasured item. Measured items do not\n * change. Returns true when at least one size changed.\n *\n * One estimate change can touch most of the list, so this rebuilds in one\n * O(N) pass instead of one O(log N) `update` per item.\n */\n public applyEstimate(estimatedSize: number): boolean {\n let changed = false;\n for (let i = 0; i < this.length; i++) {\n if (!this._measured[i] && this._sizes[i] !== estimatedSize) {\n this._sizes[i] = estimatedSize;\n changed = true;\n }\n }\n if (!changed) return false;\n\n this._tree.fill(0);\n this._total = buildTree(this._tree, this._sizes);\n return true;\n }\n\n /**\n * Returns the 0-based index of the item that contains the scroll `offset`:\n * the largest i where `prefixSum(i) <= offset < prefixSum(i + 1)`. O(log N).\n */\n public findIndexAtOffset(offset: number): number {\n if (offset <= 0 || this.length === 0) return 0;\n\n let idx = 0;\n let remaining = offset;\n\n for (let bit = this._topBit; bit > 0; bit >>= 1) {\n const next = idx + bit;\n if (next <= this.length && this._tree[next] <= remaining) {\n idx = next;\n remaining -= this._tree[idx];\n }\n }\n return Math.min(this.length - 1, idx);\n }\n}\n\n/**\n * Pure scroll-math engine for one axis of virtual scrolling. A Fenwick tree\n * holds all size state.\n *\n * ### Virtual and DOM coordinates\n *\n * Browsers limit how far an element can scroll. When the total item size is\n * larger than that limit, the engine compresses the *virtual* space\n * (`0…totalSize`) into the *DOM* space the browser can represent\n * (`0…domSize`) by the factor `_virtualRatio`. Each offset that crosses that\n * boundary is scaled: incoming scroll positions are multiplied by the ratio,\n * and outgoing offsets are divided by it. Items render at their real pixel\n * size, so item sizes are always virtual.\n */\nexport class VirtualScrollEngine {\n private _maxBrowserSize = Number.POSITIVE_INFINITY;\n\n /**\n * The ratio `totalSize / maxBrowserSize` when `totalSize` is larger than\n * the maximum DOM coordinate the browser supports; `1` otherwise.\n * Maps virtual scroll positions to DOM scroll positions.\n */\n private _virtualRatio = 1;\n\n /** Binary Indexed Tree for O(log N) size queries and updates. */\n private _tree: SizeTree | null = null;\n\n /**\n * Called when item sizes or the item count change.\n * Example: `() => this.requestUpdate()`.\n */\n public onSizeChange: (() => void) | null = null;\n\n /** Total virtual size of all items in px. */\n public get totalSize(): number {\n return this._tree?.totalSize ?? 0;\n }\n\n /** Total size in DOM space, clamped to the maximum browser size. */\n public get domSize(): number {\n return this._virtualRatio !== 1 ? this._maxBrowserSize : this.totalSize;\n }\n\n /** Measures the maximum browser size for the document and rescales. */\n public initMaxBrowserSize(doc: Document): void {\n this._maxBrowserSize = getMaxBrowserSizeProbePx(doc);\n this._updateVirtualRatio();\n }\n\n /**\n * Resizes the internal sizes array to `length`. Measured sizes below\n * `retainCount` are kept. The remainder is filled with `estimatedSize` and\n * marked unmeasured. Callers that only append can keep the default\n * `retainCount`. Callers whose data changed identity at some index must\n * pass that index, so the stale measurements after it are discarded.\n */\n public resize(\n length: number,\n estimatedSize: number,\n retainCount = length\n ): void {\n if (this._tree?.length === length && retainCount >= length) return;\n\n this._tree = this._tree\n ? this._tree.cloneResized(length, estimatedSize, retainCount)\n : SizeTree.filled(length, estimatedSize);\n this._updateVirtualRatio();\n this.onSizeChange?.();\n }\n\n /** Records the measured DOM size for a single item. */\n public measureItem(index: number, size: number): void {\n if (!this._tree?.update(index, size)) return;\n\n this._updateVirtualRatio();\n this.onSizeChange?.();\n }\n\n /**\n * Applies a new estimated size to each item that is not measured in the\n * DOM. Use this when `estimatedItemSize` changes but the item count does\n * not, because `resize` is then a no-op.\n */\n public updateEstimatedSize(estimatedSize: number): void {\n if (!this._tree?.applyEstimate(estimatedSize)) return;\n\n this._updateVirtualRatio();\n this.onSizeChange?.();\n }\n\n /**\n * Returns the DOM scroll offset in px that puts the item at `index` at the\n * leading edge of the viewport.\n */\n public getScrollOffsetForIndex(index: number): number {\n if (!this._tree || index <= 0) return 0;\n\n const clamped = Math.min(index, this._tree.length);\n return this._tree.prefixSum(clamped) / this._virtualRatio;\n }\n\n /**\n * The largest DOM scroll offset the host can reach for the given viewport\n * size. A request beyond it does nothing, so offsets given to a caller\n * that waits for the scroll to settle are clamped to it.\n */\n private _getMaxScrollOffset(viewportSize: number): number {\n return Math.max(0, this.domSize - viewportSize);\n }\n\n /**\n * Returns the DOM scroll offset that positions the item at `index` in a\n * `viewportSize` px viewport, aligned by `align` and clamped to the\n * reachable scroll range.\n *\n * The slack is computed in virtual space against the item's real size and\n * converted to DOM space once, at the end. One DOM pixel equals\n * `_virtualRatio` virtual pixels, so mixed coordinates would scale the\n * slack.\n */\n public getAlignedScrollOffset(\n index: number,\n viewportSize: number,\n align: ScrollAlignment\n ): number {\n if (!this._tree || this._tree.length === 0) return 0;\n\n const clamped = clampIndex(index, this._tree.length);\n const itemStart = this._tree.prefixSum(clamped);\n let offset = itemStart;\n\n if (align !== 'start') {\n const itemEnd = this._tree.prefixSum(clamped + 1);\n const slack = viewportSize - Math.max(0, itemEnd - itemStart);\n offset -= align === 'center' ? slack / 2 : slack;\n }\n\n return clamp(\n offset / this._virtualRatio,\n 0,\n this._getMaxScrollOffset(viewportSize)\n );\n }\n\n /**\n * Whether the item at `index` is visible without more scrolling at the\n * given DOM scroll position. True when the item is fully inside the\n * viewport, or when it is larger than the viewport and covers it fully.\n * The second case matches native `scrollIntoView({ block: 'nearest' })`.\n */\n public isIndexInView(\n index: number,\n scrollPosition: number,\n viewportSize: number\n ): boolean {\n if (!this._tree || this._tree.length === 0) return false;\n\n const clamped = clampIndex(index, this._tree.length);\n const itemStart = this._tree.prefixSum(clamped);\n const itemEnd = this._tree.prefixSum(clamped + 1);\n const viewStart = Math.max(0, scrollPosition) * this._virtualRatio;\n const viewEnd = viewStart + viewportSize;\n\n const contained = itemStart >= viewStart && itemEnd <= viewEnd;\n const spanning = itemStart <= viewStart && itemEnd >= viewEnd;\n\n return contained || spanning;\n }\n\n /**\n * Returns the visible and over-scanned item range for the given scroll\n * state.\n */\n public getVisibleRange(\n scrollPosition: number,\n viewportSize: number,\n overScan: number\n ): VisibleRange {\n if (!this._tree || this._tree.length === 0 || viewportSize <= 0) {\n return { startIndex: 0, endIndex: -1 };\n }\n\n // The viewport is not scaled by the virtual ratio. Items render at their\n // real pixel size, so a `viewportSize` px viewport always shows that many\n // virtual pixels of items, at any compression of the scroll range.\n const startOffset = Math.max(0, scrollPosition) * this._virtualRatio;\n const first = this._tree.findIndexAtOffset(startOffset);\n const last = this._tree.findIndexAtOffset(startOffset + viewportSize);\n\n return {\n startIndex: Math.max(0, first - overScan),\n endIndex: Math.min(this._tree.length - 1, last + overScan),\n };\n }\n\n /**\n * Sum of the actual sizes of the items in [startIndex, endIndex]. The\n * render pass uses it to clamp the content translate offset, so rendered\n * items do not overflow past `domSize` under coordinate compression.\n */\n public getPhysicalRangeSize(startIndex: number, endIndex: number): number {\n if (!this._tree) return 0;\n\n const start = Math.max(0, startIndex);\n const end = Math.min(Math.max(endIndex + 1, start), this._tree.length);\n return this._tree.prefixSum(end) - this._tree.prefixSum(start);\n }\n\n private _updateVirtualRatio(): void {\n const totalSize = this._tree?.totalSize ?? 0;\n this._virtualRatio =\n totalSize <= this._maxBrowserSize ? 1 : totalSize / this._maxBrowserSize;\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Context passed to the item template: the item data, its index and utility
2
+ * Context passed to the item template: the item data, its index, and utility
3
3
  * properties for rendering.
4
4
  */
5
5
  export declare class VirtualScrollItemContext<T> {
@@ -16,8 +16,8 @@ export declare class VirtualScrollItemContext<T> {
16
16
  get isLast(): boolean;
17
17
  }
18
18
  /**
19
- * How `scrollToIndex` positions the requested item within the viewport.
20
- * Mirrors the subset of `ScrollLogicalPosition` the engine can act on.
19
+ * How `scrollToIndex` positions the requested item in the viewport.
20
+ * The subset of `ScrollLogicalPosition` that the engine supports.
21
21
  */
22
22
  export type ScrollAlignment = 'start' | 'center' | 'end';
23
23
  /** The currently visible (and over-scanned) range of items. */
@@ -39,8 +39,9 @@ export interface VirtualScrollState {
39
39
  totalSize: number;
40
40
  }
41
41
  /**
42
- * A request for more data, emitted when the rendered window comes near the end
43
- * of the loaded items. Consumers listen for it and append what it asks for.
42
+ * A request for more data, emitted when the rendered window comes near the
43
+ * end of the loaded items. Consumers listen for it and append the requested
44
+ * items.
44
45
  */
45
46
  export interface VirtualScrollDataRequest {
46
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/virtualization/types.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,wBAAwB;IAQnC,YAAY,KAAQ,EAAE,KAAa,EAAE,KAAa;QAChD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAGD,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;IAC1B,CAAC;IAGD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACvC,CAAC;CACF","sourcesContent":["/**\n * Context passed to the item template: the item data, its index and utility\n * properties for rendering.\n */\nexport class VirtualScrollItemContext<T> {\n /** The current item in the virtual scroll */\n public readonly value: T;\n /** The index of the current item */\n public readonly index: number;\n /** The total number of items */\n public readonly count: number;\n\n constructor(value: T, index: number, count: number) {\n this.value = value;\n this.index = index;\n this.count = count;\n }\n\n /** Whether the current item is the first item */\n public get isFirst(): boolean {\n return this.index === 0;\n }\n\n /** Whether the current item is the last item */\n public get isLast(): boolean {\n return this.index === this.count - 1;\n }\n}\n\n/**\n * How `scrollToIndex` positions the requested item within the viewport.\n * Mirrors the subset of `ScrollLogicalPosition` the engine can act on.\n */\nexport type ScrollAlignment = 'start' | 'center' | 'end';\n\n/** The currently visible (and over-scanned) range of items. */\nexport interface VisibleRange {\n /** Index of the first rendered item (inclusive) */\n startIndex: number;\n /** Index of the last rendered item (inclusive) */\n endIndex: number;\n}\n\n/** Snapshot of the currently rendered virtual window */\nexport interface VirtualScrollState {\n /** The index of the first item currently rendered in the viewport. */\n startIndex: number;\n /** The index of the last item currently rendered in the viewport (inclusive). */\n endIndex: number;\n /** The size of the viewport in pixels. */\n viewportSize: number;\n /** The total size of the virtual scroll content in pixels. */\n totalSize: number;\n}\n\n/**\n * A request for more data, emitted when the rendered window comes near the end\n * of the loaded items. Consumers listen for it and append what it asks for.\n */\nexport interface VirtualScrollDataRequest {\n /**\n * The first index that does not yet have data.\n * Append at least `count` more items starting here.\n */\n startIndex: number;\n /** Number of items being requested. */\n count: number;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/virtualization/types.ts"],"names":[],"mappings":"AAIA,MAAM,OAAO,wBAAwB;IAQnC,YAAY,KAAQ,EAAE,KAAa,EAAE,KAAa;QAChD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAGD,IAAW,OAAO;QAChB,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC;IAC1B,CAAC;IAGD,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACvC,CAAC;CACF","sourcesContent":["/**\n * Context passed to the item template: the item data, its index, and utility\n * properties for rendering.\n */\nexport class VirtualScrollItemContext<T> {\n /** The current item in the virtual scroll */\n public readonly value: T;\n /** The index of the current item */\n public readonly index: number;\n /** The total number of items */\n public readonly count: number;\n\n constructor(value: T, index: number, count: number) {\n this.value = value;\n this.index = index;\n this.count = count;\n }\n\n /** Whether the current item is the first item */\n public get isFirst(): boolean {\n return this.index === 0;\n }\n\n /** Whether the current item is the last item */\n public get isLast(): boolean {\n return this.index === this.count - 1;\n }\n}\n\n/**\n * How `scrollToIndex` positions the requested item in the viewport.\n * The subset of `ScrollLogicalPosition` that the engine supports.\n */\nexport type ScrollAlignment = 'start' | 'center' | 'end';\n\n/** The currently visible (and over-scanned) range of items. */\nexport interface VisibleRange {\n /** Index of the first rendered item (inclusive) */\n startIndex: number;\n /** Index of the last rendered item (inclusive) */\n endIndex: number;\n}\n\n/** Snapshot of the currently rendered virtual window */\nexport interface VirtualScrollState {\n /** The index of the first item currently rendered in the viewport. */\n startIndex: number;\n /** The index of the last item currently rendered in the viewport (inclusive). */\n endIndex: number;\n /** The size of the viewport in pixels. */\n viewportSize: number;\n /** The total size of the virtual scroll content in pixels. */\n totalSize: number;\n}\n\n/**\n * A request for more data, emitted when the rendered window comes near the\n * end of the loaded items. Consumers listen for it and append the requested\n * items.\n */\nexport interface VirtualScrollDataRequest {\n /**\n * The first index that does not yet have data.\n * Append at least `count` more items starting here.\n */\n startIndex: number;\n /** Number of items being requested. */\n count: number;\n}\n"]}
@@ -9,18 +9,18 @@ export interface IgcVirtualScrollComponentEventMap {
9
9
  }
10
10
  declare const IgcVirtualScrollComponent_base: Constructor<import("#internals/mixins/event-emitter.js").EventEmitterInterface<IgcVirtualScrollComponentEventMap>> & Constructor<LitElement>;
11
11
  /**
12
- * A virtual scroll component that efficiently renders large lists by only
13
- * rendering the items currently visible in the viewport.
12
+ * A virtual scroll component for large lists. Only the items visible in the
13
+ * viewport are rendered.
14
14
  *
15
15
  * @element igc-virtual-scroll
16
16
  *
17
17
  * @fires igcStateChange - Emitted when the rendered virtual window changes.
18
- * @fires igcDataRequest - Emitted whenever the rendered window comes within a few items of the
19
- * end of `data` - including on the very first render, when the loaded items don't fill the viewport.
18
+ * @fires igcDataRequest - Emitted when the rendered window comes within a few items of the end
19
+ * of `data`. Also emitted on the first render, when the loaded items do not fill the viewport.
20
20
  *
21
21
  * @csspart virtualization-track - The full-size element that gives the host its scrollable extent.
22
- * @csspart virtualization-content - The wrapper holding the currently rendered items, translated
23
- * into position within the track.
22
+ * @csspart virtualization-content - The wrapper that holds the rendered items, translated into
23
+ * position within the track.
24
24
  */
25
25
  export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScrollComponent_base {
26
26
  static readonly tagName = "igc-virtual-scroll";
@@ -31,32 +31,39 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
31
31
  private readonly _contentRef;
32
32
  private readonly _itemResizeController;
33
33
  private _currentRange;
34
+ /**
35
+ * The item index each wrapper element was last observed under. Lit reuses
36
+ * the wrapper elements across renders. After a scroll, the same element
37
+ * can host a different item at an identical size, and a ResizeObserver
38
+ * does not report that. See `_scheduleItemMeasurement`.
39
+ */
40
+ private readonly _observedItemIndexes;
34
41
  private _lastEmittedState;
35
42
  private _hasPendingDataRequest;
36
43
  private _layoutCompletePromise;
37
44
  private _scrollRequestId;
38
45
  /**
39
46
  * The `startIndex` of the last emitted `igcDataRequest`, which is also the
40
- * item count it was emitted at. See `_checkDataRequest`.
47
+ * item count at that emit. See `_checkDataRequest`.
41
48
  *
42
- * Outlives a disconnect, like `_hasPendingDataRequest`: what the consumer has
43
- * already been asked for does not become untrue by moving the element, and
44
- * clearing only one of the two would re-open the request loop on reconnect.
49
+ * Kept across a disconnect, like `_hasPendingDataRequest`: a move in the
50
+ * DOM does not undo what the consumer was already asked for. If only one
51
+ * of the two were cleared, the request loop would reopen on reconnect.
45
52
  */
46
53
  private _lastDataRequestIndex;
47
54
  /**
48
- * The live scroll offset on the active axis. Deliberately *not* reactive:
49
- * nothing in `render` reads it except through `_currentRange`, so
50
- * `_handleScroll` schedules an update only when the window actually moves.
55
+ * The live scroll offset on the active axis. Not reactive by design:
56
+ * `render` reads it only through `_currentRange`, so `_handleScroll`
57
+ * schedules an update only when the window moves.
51
58
  */
52
59
  private _scrollPosition;
53
60
  private _viewportSize;
54
61
  /**
55
62
  * The array of items to virtualize.
56
63
  *
57
- * Compared by reference: mutating the array
58
- * in place (`data.push(...)`) produces no update. Assign a new array
59
- * instead, which is also what the `igcDataRequest` flow expects.
64
+ * Compared by reference: a mutation in place (`data.push(...)`) causes no
65
+ * update. Assign a new array instead. The `igcDataRequest` flow also
66
+ * expects a new array.
60
67
  */
61
68
  data: T[];
62
69
  /**
@@ -67,14 +74,14 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
67
74
  orientation: 'vertical' | 'horizontal';
68
75
  /**
69
76
  * Number of extra items to render beyond the visible area of the viewport.
70
- * Higher values reduce blank flashes during fast scrolling but may impact performance.
77
+ * Higher values reduce blank flashes during fast scrolling but can lower performance.
71
78
  * @attr over-scan
72
79
  * @default 2
73
80
  */
74
81
  overScan: number;
75
82
  /**
76
- * Estimated item size in pixels used before an item is measured in the DOM.
77
- * The engine replaces this with the actual measured size after the first render of each item.
83
+ * Estimated item size in pixels, used before an item is measured in the DOM.
84
+ * After the first render of an item, the engine replaces the estimate with the measured size.
78
85
  * @attr estimated-item-size
79
86
  * @default 50
80
87
  */
@@ -82,14 +89,14 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
82
89
  /**
83
90
  * A function that renders each item in the virtual scroll list.
84
91
  * Receives a VirtualScrollItemContext<T> with the item data, its index, and the total count.
85
- * If not provided, nothing is rendered.
92
+ * Without it, nothing is rendered.
86
93
  *
87
94
  * Items are measured by their border box, so margins accumulate as drift
88
95
  * down the list. Use padding on the item, or a gap on a wrapper, instead.
89
96
  *
90
- * Only the current window is ever in the DOM, so assistive technology
91
- * cannot infer an item's position from the markup. Templates rendering a
92
- * role with set semantics (`option`, `listitem`, `row`, ...) should map the
97
+ * Only the current window is in the DOM, so assistive technology cannot
98
+ * infer an item's position from the markup. Templates that render a role
99
+ * with set semantics (`option`, `listitem`, `row`, ...) should map the
93
100
  * context's `index` and `count` onto `aria-posinset` and `aria-setsize`.
94
101
  */
95
102
  itemTemplate: VirtualScrollItemTemplate<T> | null;
@@ -109,21 +116,20 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
109
116
  private get _normalizedOverScan();
110
117
  /** The configured `estimatedItemSize`, normalized to a positive number. */
111
118
  private get _normalizedItemSize();
112
- /** `data`, guarded against a consumer clearing it with a nullish value. */
119
+ /** `data`, guarded against a nullish value set by the consumer. */
113
120
  private get _items();
114
121
  /**
115
122
  * The window to render for the current scroll position and viewport. Empty
116
- * until an `itemTemplate` is set, since nothing renders without one.
123
+ * until an `itemTemplate` is set, because nothing renders without one.
117
124
  */
118
125
  private _computeRange;
119
126
  /**
120
- * The scroll offset that aligns `index` within the viewport according to
121
- * `options`, from the engine's *current* size data. As more items get
122
- * measured, the same index/options can yield a different, more accurate
123
- * result.
127
+ * The scroll offset that aligns `index` in the viewport according to
128
+ * `options`, from the engine's current size data. As more items are
129
+ * measured, the same input can give a different, more accurate result.
124
130
  *
125
131
  * For `block: 'nearest'` on an item already in view, returns the current
126
- * offset, so that no scrolling takes place.
132
+ * offset, so no scroll occurs.
127
133
  */
128
134
  private _getAlignedScrollOffset;
129
135
  /** Applies a scroll offset to the correct axis, accounting for RTL. */
@@ -131,99 +137,107 @@ export default class IgcVirtualScrollComponent<T = any> extends IgcVirtualScroll
131
137
  /** The current real scroll position on the active axis, normalized for RTL. */
132
138
  private _currentAxisScroll;
133
139
  /**
134
- * Applies a scroll offset to the active axis and waits for the resulting
135
- * scroll - instant or smooth - to settle.
140
+ * Applies a scroll offset to the active axis and waits for the scroll,
141
+ * instant or smooth, to settle.
136
142
  *
137
- * `scrollend` never fires when the requested offset doesn't actually move
138
- * the scroll position, so that case is short-circuited rather than waiting
139
- * for it. The timeout covers the rare case of the event never arriving at
140
- * all, e.g. the element being disconnected mid-scroll.
143
+ * `scrollend` does not fire when the requested offset does not move the
144
+ * scroll position, so that case resolves immediately. The timeout covers
145
+ * an event that never arrives, for example when the element disconnects
146
+ * mid-scroll.
141
147
  */
142
148
  private _scrollAndWaitForEnd;
143
149
  /**
144
- * Resolves with whichever comes first, `task` or a deadline of `ms`.
145
- * Whichever wins, the loser is torn down through the signal instead of
146
- * being left behind as a live timer or a dangling listener.
150
+ * Resolves with `task` or with a deadline of `ms`, whichever comes first.
151
+ * The signal then tears down the other, so no live timer or dangling
152
+ * listener remains.
147
153
  */
148
154
  private _withDeadline;
149
155
  private _waitForScrollEnd;
150
156
  /**
151
- * Resolves once no `scroll` event has arrived for `SCROLL_IDLE_MS`, the
152
- * closest approximation of `scrollend` without it. The first timer is armed
153
- * immediately, so a scroll that never moves still settles.
157
+ * Resolves when no `scroll` event arrives for `SCROLL_IDLE_MS`: the
158
+ * closest replacement for `scrollend`. The first timer starts immediately,
159
+ * so a scroll that does not move still settles.
154
160
  */
155
161
  private _waitForScrollIdle;
156
162
  private _timeout;
157
163
  private _measureViewport;
158
164
  /**
159
- * Records the new scroll offset and schedules a render only if it moves the
160
- * rendered window.
165
+ * Records the new scroll offset. Schedules a render only when the rendered
166
+ * window moves.
161
167
  *
162
- * `render` derives the track size, the content translate and the item slice
163
- * from `_currentRange`, and nothing from the scroll offset itself, so
164
- * scrolling within a single item would otherwise re-run every item template
165
- * for a pixel-identical result. `willUpdate` still recomputes
166
- * `_currentRange` for every other trigger, so this can only suppress a
167
- * redundant pass, never a needed one.
168
+ * `render` derives the track size, the content translate, and the item
169
+ * slice from `_currentRange`, not from the scroll offset. Without the
170
+ * guard, a scroll inside one item would re-run each item template for an
171
+ * identical result. `willUpdate` still recomputes `_currentRange` for each
172
+ * other trigger, so this suppresses only redundant passes, never a needed
173
+ * one.
168
174
  */
169
175
  private _handleScroll;
170
176
  /**
171
177
  * The number of leading items that kept their identity across a `data`
172
- * change, i.e. the index of the first item whose measured size no longer
173
- * describes what is rendered there. Appending (the `igcDataRequest` flow)
174
- * retains everything; filtering or replacing retains only the untouched
178
+ * change: the index of the first item whose measured size no longer
179
+ * matches its rendered content. An append (the `igcDataRequest` flow)
180
+ * retains all items. A filter or a replacement retains only the unchanged
175
181
  * prefix.
176
182
  */
177
183
  private _firstChangedIndex;
178
184
  private _handleItemResize;
179
185
  /**
180
- * Brings the item observer in sync with the rendered window, applying only
181
- * the difference: re-observing an already observed element makes the browser
182
- * deliver another initial measurement for it, so blanket re-registration
183
- * would fire a callback for every rendered item on every update pass.
186
+ * Synchronizes the item observer with the rendered window and applies only
187
+ * the difference. A newly observed element gets one initial measurement.
188
+ * An `observe` call on an already observed element is a no-op, so a
189
+ * re-measurement on demand requires re-registration: unobserve, then
190
+ * observe.
191
+ *
192
+ * Re-registration is applied to each element whose `data-vs-index`
193
+ * changed. Lit reuses the wrapper elements across renders, so after a
194
+ * scroll the same element can host a different item at an identical size.
195
+ * The observer does not report that, and the new index would keep its
196
+ * estimated size.
184
197
  */
185
198
  private _scheduleItemMeasurement;
186
199
  /**
187
- * Emits `igcStateChange`, unless the window is empty or identical to the one
188
- * last reported: measurement passes re-render without moving the window.
200
+ * Emits `igcStateChange`. Skipped when the window is empty or equal to the
201
+ * last reported one, because measurement passes re-render without a window
202
+ * change.
189
203
  */
190
204
  private _emitStateChange;
191
205
  private _checkDataRequest;
192
206
  /**
193
207
  * Resolves on the next animation frame, or after `LAYOUT_FRAME_TIMEOUT_MS`
194
- * if one never arrives. A hidden tab or a disconnected element is never
195
- * served frames, and `layoutComplete` must still settle there. There is no
196
- * layout to wait for in that state, so resolving early costs nothing.
208
+ * when no frame arrives. A hidden tab or a disconnected element gets no
209
+ * frames, and `layoutComplete` must still settle there. That state has no
210
+ * layout to wait for, so an early resolve is safe.
197
211
  */
198
212
  private _nextFrame;
199
213
  /**
200
- * Waits for the current update to finish and then gives any
201
- * ResizeObserver-driven item measurements a chance to run. If those schedule
202
- * a follow-up render - an estimated size being replaced with a measured one
203
- * - the wait repeats until nothing is pending, up to a safety cap.
214
+ * Waits for the current update, then lets ResizeObserver item measurements
215
+ * run. When those schedule a follow-up render, for example an estimate
216
+ * replaced by a measured size, the wait repeats until nothing is pending,
217
+ * up to a safety cap.
204
218
  */
205
219
  private _resolveLayoutComplete;
206
220
  /**
207
- * Resolves once the virtual scroll has fully settled: the current render
208
- * pass has completed *and* so have any item-size measurements it triggers,
209
- * along with the renders those in turn schedule.
221
+ * Resolves when the virtual scroll has settled: the current render pass is
222
+ * complete, the item-size measurements it triggers are complete, and so
223
+ * are the renders those measurements schedule.
210
224
  *
211
- * Unlike `updateComplete`, which reflects a single Lit render pass, this
212
- * covers changing `data`, scrolling or resizing the viewport, where the
213
- * stable DOM state is only reached after one or more follow-up renders.
225
+ * `updateComplete` covers one Lit render pass. This covers `data` changes,
226
+ * scrolls, and viewport resizes, where the stable DOM state comes after
227
+ * one or more follow-up renders.
214
228
  */
215
229
  get layoutComplete(): Promise<void>;
216
230
  /**
217
- * Programmatically scrolls to the specified item index.
231
+ * Scrolls to the specified item index.
218
232
  *
219
- * Items outside the rendered window only have an *estimated* size, so the
220
- * first jump may land off target. The items around where it lands are then
221
- * measured and the scroll position corrected, repeating - each pass landing
222
- * closer to the true target - until the offset stabilizes.
233
+ * Items outside the rendered window have only an estimated size, so the
234
+ * first jump can miss the target. The items at the landing point are then
235
+ * measured, and the scroll position is corrected. This repeats until the
236
+ * offset is stable.
223
237
  *
224
- * The returned promise resolves once the scroll has settled on that final,
225
- * corrected offset, and can be ignored by callers that only care about the
226
- * initial, approximate scroll.
238
+ * The returned promise resolves when the scroll settles on the final,
239
+ * corrected offset. Callers that need only the first, approximate scroll
240
+ * can ignore it.
227
241
  */
228
242
  scrollToIndex(index: number, options?: ScrollIntoViewOptions): Promise<void>;
229
243
  }