virtual-scroller 1.7.9 → 1.9.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 (283) hide show
  1. package/.gitlab-ci.yml +1 -1
  2. package/CHANGELOG.md +71 -1
  3. package/README.md +434 -151
  4. package/bundle/index-bypass.html +1 -1
  5. package/bundle/index-dom.html +1 -1
  6. package/bundle/index-grid.html +1 -2
  7. package/bundle/index-scrollableContainer.html +1 -1
  8. package/bundle/index-tbody-scrollableContainer.html +2 -0
  9. package/bundle/index-tbody.html +2 -0
  10. package/bundle/virtual-scroller-dom.js +1 -1
  11. package/bundle/virtual-scroller-dom.js.map +1 -1
  12. package/bundle/virtual-scroller-react.js +1 -1
  13. package/bundle/virtual-scroller-react.js.map +1 -1
  14. package/bundle/virtual-scroller.js +1 -1
  15. package/bundle/virtual-scroller.js.map +1 -1
  16. package/commonjs/BeforeResize.js +315 -0
  17. package/commonjs/BeforeResize.js.map +1 -0
  18. package/commonjs/DOM/Engine.js +46 -0
  19. package/commonjs/DOM/Engine.js.map +1 -0
  20. package/commonjs/DOM/ItemsContainer.js +78 -0
  21. package/commonjs/DOM/ItemsContainer.js.map +1 -0
  22. package/commonjs/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +71 -44
  23. package/commonjs/DOM/ListTopOffsetWatcher.js.map +1 -0
  24. package/commonjs/DOM/ScrollableContainer.js +69 -101
  25. package/commonjs/DOM/ScrollableContainer.js.map +1 -1
  26. package/commonjs/DOM/VirtualScroller.js +37 -29
  27. package/commonjs/DOM/VirtualScroller.js.map +1 -1
  28. package/commonjs/DOM/tbody.js +17 -11
  29. package/commonjs/DOM/tbody.js.map +1 -1
  30. package/commonjs/ItemHeights.js +33 -34
  31. package/commonjs/ItemHeights.js.map +1 -1
  32. package/commonjs/Layout.js +591 -216
  33. package/commonjs/Layout.js.map +1 -1
  34. package/commonjs/Layout.test.js +196 -0
  35. package/commonjs/Layout.test.js.map +1 -0
  36. package/commonjs/ListHeightMeasurement.js +124 -0
  37. package/commonjs/ListHeightMeasurement.js.map +1 -0
  38. package/commonjs/Resize.js +50 -39
  39. package/commonjs/Resize.js.map +1 -1
  40. package/commonjs/Scroll.js +139 -95
  41. package/commonjs/Scroll.js.map +1 -1
  42. package/commonjs/VirtualScroller.columns.js +43 -0
  43. package/commonjs/VirtualScroller.columns.js.map +1 -0
  44. package/commonjs/VirtualScroller.constructor.js +408 -0
  45. package/commonjs/VirtualScroller.constructor.js.map +1 -0
  46. package/commonjs/VirtualScroller.items.js +305 -0
  47. package/commonjs/VirtualScroller.items.js.map +1 -0
  48. package/commonjs/VirtualScroller.js +160 -1021
  49. package/commonjs/VirtualScroller.js.map +1 -1
  50. package/commonjs/VirtualScroller.layout.js +562 -0
  51. package/commonjs/VirtualScroller.layout.js.map +1 -0
  52. package/commonjs/VirtualScroller.onRender.js +357 -0
  53. package/commonjs/VirtualScroller.onRender.js.map +1 -0
  54. package/commonjs/VirtualScroller.resize.js +186 -0
  55. package/commonjs/VirtualScroller.resize.js.map +1 -0
  56. package/commonjs/VirtualScroller.state.js +301 -0
  57. package/commonjs/VirtualScroller.state.js.map +1 -0
  58. package/commonjs/VirtualScroller.verticalSpacing.js +65 -0
  59. package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -0
  60. package/commonjs/getItemCoordinates.js.map +1 -1
  61. package/commonjs/getItemsDiff.js.map +1 -1
  62. package/commonjs/getVerticalSpacing.js +8 -8
  63. package/commonjs/getVerticalSpacing.js.map +1 -1
  64. package/commonjs/package.json +5 -0
  65. package/commonjs/react/VirtualScroller.js +182 -628
  66. package/commonjs/react/VirtualScroller.js.map +1 -1
  67. package/commonjs/react/useClassName.js +26 -0
  68. package/commonjs/react/useClassName.js.map +1 -0
  69. package/commonjs/react/useHandleItemsChange.js +116 -0
  70. package/commonjs/react/useHandleItemsChange.js.map +1 -0
  71. package/commonjs/react/useInstanceMethods.js +37 -0
  72. package/commonjs/react/useInstanceMethods.js.map +1 -0
  73. package/commonjs/react/useItemKeys.js +60 -0
  74. package/commonjs/react/useItemKeys.js.map +1 -0
  75. package/commonjs/react/useOnItemHeightChange.js +32 -0
  76. package/commonjs/react/useOnItemHeightChange.js.map +1 -0
  77. package/commonjs/react/useOnItemStateChange.js +32 -0
  78. package/commonjs/react/useOnItemStateChange.js.map +1 -0
  79. package/commonjs/react/useState.js +140 -0
  80. package/commonjs/react/useState.js.map +1 -0
  81. package/commonjs/react/useStyle.js +29 -0
  82. package/commonjs/react/useStyle.js.map +1 -0
  83. package/commonjs/react/useVirtualScroller.js +62 -0
  84. package/commonjs/react/useVirtualScroller.js.map +1 -0
  85. package/commonjs/react/useVirtualScrollerStartStop.js +20 -0
  86. package/commonjs/react/useVirtualScrollerStartStop.js.map +1 -0
  87. package/commonjs/test/Engine.js +23 -0
  88. package/commonjs/test/Engine.js.map +1 -0
  89. package/commonjs/test/ItemsContainer.js +127 -0
  90. package/commonjs/test/ItemsContainer.js.map +1 -0
  91. package/commonjs/test/ScrollableContainer.js +130 -0
  92. package/commonjs/test/ScrollableContainer.js.map +1 -0
  93. package/commonjs/test/VirtualScroller.js +281 -0
  94. package/commonjs/test/VirtualScroller.js.map +1 -0
  95. package/commonjs/utility/debounce.js +28 -6
  96. package/commonjs/utility/debounce.js.map +1 -1
  97. package/commonjs/utility/debug.js +51 -12
  98. package/commonjs/utility/debug.js.map +1 -1
  99. package/commonjs/utility/getStateSnapshot.js +50 -0
  100. package/commonjs/utility/getStateSnapshot.js.map +1 -0
  101. package/commonjs/utility/px.js +1 -1
  102. package/commonjs/utility/px.js.map +1 -1
  103. package/commonjs/utility/px.test.js +14 -0
  104. package/commonjs/utility/px.test.js.map +1 -0
  105. package/commonjs/utility/shallowEqual.js +1 -1
  106. package/commonjs/utility/shallowEqual.js.map +1 -1
  107. package/commonjs/utility/throttle.js.map +1 -1
  108. package/dom/index.cjs +4 -0
  109. package/dom/index.cjs.js +9 -0
  110. package/dom/index.d.ts +25 -0
  111. package/dom/index.js +1 -1
  112. package/dom/package.json +10 -4
  113. package/index.cjs +4 -0
  114. package/index.cjs.js +9 -0
  115. package/index.d.ts +99 -0
  116. package/index.js +1 -1
  117. package/modules/BeforeResize.js +305 -0
  118. package/modules/BeforeResize.js.map +1 -0
  119. package/modules/DOM/Engine.js +27 -0
  120. package/modules/DOM/Engine.js.map +1 -0
  121. package/modules/DOM/ItemsContainer.js +71 -0
  122. package/modules/DOM/ItemsContainer.js.map +1 -0
  123. package/modules/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +72 -44
  124. package/modules/DOM/ListTopOffsetWatcher.js.map +1 -0
  125. package/modules/DOM/ScrollableContainer.js +68 -100
  126. package/modules/DOM/ScrollableContainer.js.map +1 -1
  127. package/modules/DOM/VirtualScroller.js +32 -28
  128. package/modules/DOM/VirtualScroller.js.map +1 -1
  129. package/modules/DOM/tbody.js +11 -9
  130. package/modules/DOM/tbody.js.map +1 -1
  131. package/modules/ItemHeights.js +28 -33
  132. package/modules/ItemHeights.js.map +1 -1
  133. package/modules/Layout.js +585 -214
  134. package/modules/Layout.js.map +1 -1
  135. package/modules/Layout.test.js +190 -0
  136. package/modules/Layout.test.js.map +1 -0
  137. package/modules/ListHeightMeasurement.js +117 -0
  138. package/modules/ListHeightMeasurement.js.map +1 -0
  139. package/modules/Resize.js +50 -39
  140. package/modules/Resize.js.map +1 -1
  141. package/modules/Scroll.js +139 -94
  142. package/modules/Scroll.js.map +1 -1
  143. package/modules/VirtualScroller.columns.js +36 -0
  144. package/modules/VirtualScroller.columns.js.map +1 -0
  145. package/modules/VirtualScroller.constructor.js +371 -0
  146. package/modules/VirtualScroller.constructor.js.map +1 -0
  147. package/modules/VirtualScroller.items.js +288 -0
  148. package/modules/VirtualScroller.items.js.map +1 -0
  149. package/modules/VirtualScroller.js +159 -1014
  150. package/modules/VirtualScroller.js.map +1 -1
  151. package/modules/VirtualScroller.layout.js +549 -0
  152. package/modules/VirtualScroller.layout.js.map +1 -0
  153. package/modules/VirtualScroller.onRender.js +337 -0
  154. package/modules/VirtualScroller.onRender.js.map +1 -0
  155. package/modules/VirtualScroller.resize.js +176 -0
  156. package/modules/VirtualScroller.resize.js.map +1 -0
  157. package/modules/VirtualScroller.state.js +283 -0
  158. package/modules/VirtualScroller.state.js.map +1 -0
  159. package/modules/VirtualScroller.verticalSpacing.js +54 -0
  160. package/modules/VirtualScroller.verticalSpacing.js.map +1 -0
  161. package/modules/getItemCoordinates.js.map +1 -1
  162. package/modules/getItemsDiff.js.map +1 -1
  163. package/modules/getVerticalSpacing.js +8 -8
  164. package/modules/getVerticalSpacing.js.map +1 -1
  165. package/modules/react/VirtualScroller.js +179 -634
  166. package/modules/react/VirtualScroller.js.map +1 -1
  167. package/modules/react/useClassName.js +18 -0
  168. package/modules/react/useClassName.js.map +1 -0
  169. package/modules/react/useHandleItemsChange.js +108 -0
  170. package/modules/react/useHandleItemsChange.js.map +1 -0
  171. package/modules/react/useInstanceMethods.js +28 -0
  172. package/modules/react/useInstanceMethods.js.map +1 -0
  173. package/modules/react/useItemKeys.js +52 -0
  174. package/modules/react/useItemKeys.js.map +1 -0
  175. package/modules/react/useOnItemHeightChange.js +24 -0
  176. package/modules/react/useOnItemHeightChange.js.map +1 -0
  177. package/modules/react/useOnItemStateChange.js +24 -0
  178. package/modules/react/useOnItemStateChange.js.map +1 -0
  179. package/modules/react/useState.js +132 -0
  180. package/modules/react/useState.js.map +1 -0
  181. package/modules/react/useStyle.js +19 -0
  182. package/modules/react/useStyle.js.map +1 -0
  183. package/modules/react/useVirtualScroller.js +51 -0
  184. package/modules/react/useVirtualScroller.js.map +1 -0
  185. package/modules/react/useVirtualScrollerStartStop.js +12 -0
  186. package/modules/react/useVirtualScrollerStartStop.js.map +1 -0
  187. package/modules/test/Engine.js +11 -0
  188. package/modules/test/Engine.js.map +1 -0
  189. package/modules/test/ItemsContainer.js +120 -0
  190. package/modules/test/ItemsContainer.js.map +1 -0
  191. package/modules/test/ScrollableContainer.js +123 -0
  192. package/modules/test/ScrollableContainer.js.map +1 -0
  193. package/modules/test/VirtualScroller.js +270 -0
  194. package/modules/test/VirtualScroller.js.map +1 -0
  195. package/modules/utility/debounce.js +28 -6
  196. package/modules/utility/debounce.js.map +1 -1
  197. package/modules/utility/debug.js +47 -10
  198. package/modules/utility/debug.js.map +1 -1
  199. package/modules/utility/getStateSnapshot.js +43 -0
  200. package/modules/utility/getStateSnapshot.js.map +1 -0
  201. package/modules/utility/px.js +1 -1
  202. package/modules/utility/px.js.map +1 -1
  203. package/modules/utility/px.test.js +9 -0
  204. package/modules/utility/px.test.js.map +1 -0
  205. package/modules/utility/shallowEqual.js +1 -1
  206. package/modules/utility/shallowEqual.js.map +1 -1
  207. package/modules/utility/throttle.js.map +1 -1
  208. package/package.json +54 -29
  209. package/react/index.cjs +4 -0
  210. package/react/index.cjs.js +9 -0
  211. package/react/index.d.ts +28 -0
  212. package/react/index.js +1 -1
  213. package/react/package.json +10 -4
  214. package/rollup.config.mjs +62 -0
  215. package/runnable/create-commonjs-package-json.js +11 -0
  216. package/source/BeforeResize.js +312 -0
  217. package/source/DOM/Engine.js +30 -0
  218. package/source/DOM/ItemsContainer.js +48 -0
  219. package/source/DOM/{WaitForStylesToLoad.js → ListTopOffsetWatcher.js} +61 -30
  220. package/source/DOM/ScrollableContainer.js +51 -73
  221. package/source/DOM/VirtualScroller.js +33 -18
  222. package/source/DOM/tbody.js +30 -21
  223. package/source/ItemHeights.js +27 -27
  224. package/source/Layout.js +629 -252
  225. package/source/Layout.test.js +176 -0
  226. package/source/ListHeightMeasurement.js +95 -0
  227. package/source/Resize.js +56 -32
  228. package/source/Scroll.js +135 -82
  229. package/source/VirtualScroller.columns.js +26 -0
  230. package/source/VirtualScroller.constructor.js +336 -0
  231. package/source/VirtualScroller.items.js +302 -0
  232. package/source/VirtualScroller.js +162 -936
  233. package/source/VirtualScroller.layout.js +539 -0
  234. package/source/VirtualScroller.onRender.js +345 -0
  235. package/source/VirtualScroller.resize.js +189 -0
  236. package/source/VirtualScroller.state.js +284 -0
  237. package/source/VirtualScroller.verticalSpacing.js +51 -0
  238. package/source/getVerticalSpacing.js +7 -7
  239. package/source/react/VirtualScroller.js +243 -603
  240. package/source/react/useClassName.js +14 -0
  241. package/source/react/useHandleItemsChange.js +115 -0
  242. package/source/react/useInstanceMethods.js +25 -0
  243. package/source/react/useItemKeys.js +59 -0
  244. package/source/react/useOnItemHeightChange.js +28 -0
  245. package/source/react/useOnItemStateChange.js +28 -0
  246. package/source/react/useState.js +114 -0
  247. package/source/react/useStyle.js +20 -0
  248. package/source/react/useVirtualScroller.js +59 -0
  249. package/source/react/useVirtualScrollerStartStop.js +12 -0
  250. package/source/test/Engine.js +11 -0
  251. package/source/test/ItemsContainer.js +87 -0
  252. package/source/test/ScrollableContainer.js +88 -0
  253. package/source/test/VirtualScroller.js +232 -0
  254. package/source/utility/debounce.js +22 -5
  255. package/source/utility/debug.js +34 -3
  256. package/source/utility/getStateSnapshot.js +36 -0
  257. package/source/utility/px.js +1 -1
  258. package/source/utility/px.test.js +9 -0
  259. package/website/index-bypass.html +195 -0
  260. package/website/index-grid.html +0 -1
  261. package/website/index-scrollableContainer.html +208 -0
  262. package/website/index-tbody-scrollableContainer.html +68 -0
  263. package/website/index-tbody.html +55 -0
  264. package/commonjs/DOM/RenderingEngine.js +0 -33
  265. package/commonjs/DOM/RenderingEngine.js.map +0 -1
  266. package/commonjs/DOM/Screen.js +0 -87
  267. package/commonjs/DOM/Screen.js.map +0 -1
  268. package/commonjs/DOM/WaitForStylesToLoad.js.map +0 -1
  269. package/commonjs/RestoreScroll.js +0 -118
  270. package/commonjs/RestoreScroll.js.map +0 -1
  271. package/dom/index.commonjs.js +0 -4
  272. package/index.commonjs.js +0 -4
  273. package/modules/DOM/RenderingEngine.js +0 -19
  274. package/modules/DOM/RenderingEngine.js.map +0 -1
  275. package/modules/DOM/Screen.js +0 -80
  276. package/modules/DOM/Screen.js.map +0 -1
  277. package/modules/DOM/WaitForStylesToLoad.js.map +0 -1
  278. package/modules/RestoreScroll.js +0 -111
  279. package/modules/RestoreScroll.js.map +0 -1
  280. package/react/index.commonjs.js +0 -4
  281. package/source/DOM/RenderingEngine.js +0 -22
  282. package/source/DOM/Screen.js +0 -51
  283. package/source/RestoreScroll.js +0 -86
@@ -7,59 +7,81 @@ exports["default"] = void 0;
7
7
 
8
8
  var _requestAnimationFrameTimeout = require("request-animation-frame-timeout");
9
9
 
10
- var _Layout = require("../Layout");
11
-
12
10
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
13
11
 
14
12
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
15
13
 
16
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
14
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
15
+
16
+ // Refreshing two times every seconds seems reasonable.
17
+ var WATCH_LIST_TOP_OFFSET_INTERVAL = 500; // Refreshing for 3 seconds after the initial page load seems reasonable.
17
18
 
18
- // `VirtualScroller` calls `this.layout.layOut()` on mount,
19
+ var WATCH_LIST_TOP_OFFSET_MAX_DURATION = 3000; // `VirtualScroller` calls `this.layout.layOut()` on mount,
19
20
  // but if the page styles are applied after `VirtualScroller` mounts
20
21
  // (for example, if styles are applied via javascript, like Webpack does)
21
- // then the list might not render correctly and will only show the first item.
22
- // The reason for that would be that calling `.getListTopOffsetInsideScrollableContainer()`
23
- // on mount returns "incorrect" `top` position because the styles haven't been applied yet.
22
+ // then the list might not render correctly and it will only show the first item.
23
+ // The reason is that in that case calling `.getListTopOffset()` on mount
24
+ // returns "incorrect" `top` position because the styles haven't been applied yet.
25
+ //
24
26
  // For example, consider a page:
27
+ //
25
28
  // <div class="page">
26
29
  // <nav class="sidebar">...</nav>
27
30
  // <main>...</main>
28
31
  // </div>
29
- // The sidebar is styled as `position: fixed`, but until
30
- // the page styles have been applied it's gonna be a regular `<div/>`
32
+ //
33
+ // The sidebar is styled as `position: fixed`, but, until
34
+ // the page styles have been applied, it's gonna be a regular `<div/>`
31
35
  // meaning that `<main/>` will be rendered below the sidebar
32
- // and will appear offscreen and so it will only render the first item.
33
- // Then, the page styles are loaded and applied and the sidebar
34
- // is now `position: fixed` so `<main/>` is now rendered at the top of the page
36
+ // and will appear offscreen, and so it will only render the first item.
37
+ //
38
+ // Then, the page styles are loaded and applied, and the sidebar
39
+ // is now `position: fixed`, so `<main/>` is now rendered at the top of the page,
35
40
  // but `VirtualScroller`'s `.render()` has already been called
36
41
  // and it won't re-render until the user scrolls or the window is resized.
37
- // This type of a bug doesn't occur in production, but it can appear
42
+ //
43
+ // This type of a bug doesn't seem to occur in production, but it can appear
38
44
  // in development mode when using Webpack. The workaround `VirtualScroller`
39
- // implements for such cases is calling `.getListTopOffsetInsideScrollableContainer()`
45
+ // implements for such cases is calling `.getListTopOffset()`
40
46
  // on the list container DOM element periodically (every second) to check
41
47
  // if the `top` coordinate has changed as a result of CSS being applied:
42
48
  // if it has then it recalculates the shown item indexes.
43
- var WaitForStylesToLoad =
44
- /*#__PURE__*/
45
- function () {
46
- function WaitForStylesToLoad(_ref) {
47
- var updateLayout = _ref.updateLayout,
48
- getListTopOffsetInsideScrollableContainer = _ref.getListTopOffsetInsideScrollableContainer;
49
-
50
- _classCallCheck(this, WaitForStylesToLoad);
51
-
52
- this.updateLayout = updateLayout;
53
- this.getListTopOffsetInsideScrollableContainer = getListTopOffsetInsideScrollableContainer;
49
+ //
50
+ // Maybe this bug could occur in production when using Webpack chunks.
51
+ // That depends on how a style of a chunk is added to the page:
52
+ // if it's added via `javascript` after the page has been rendered
53
+ // then this workaround will also work for that case.
54
+ //
55
+ // Another example would be a page having a really tall expanded "accordion"
56
+ // section, below which a `VirtualScroller` list resides. If the user un-expands
57
+ // such expanded "accordion" section, the list would become visible but
58
+ // it wouldn't get re-rendered because no `scroll` event has occured,
59
+ // and the list only re-renders automatically on `scroll` events.
60
+ // To work around such cases, call `virtualScroller.updateLayout()` method manually.
61
+ // The workaround below could be extended to refresh the list's top coordinate
62
+ // indefinitely and at higher intervals, but why waste CPU time on that.
63
+ // There doesn't seem to be any DOM API for tracking an element's top position.
64
+ // There is `IntersectionObserver` API but it doesn't exactly do that.
65
+ //
66
+
67
+ var ListTopOffsetWatcher = /*#__PURE__*/function () {
68
+ function ListTopOffsetWatcher(_ref) {
69
+ var getListTopOffset = _ref.getListTopOffset,
70
+ onListTopOffsetChange = _ref.onListTopOffsetChange;
71
+
72
+ _classCallCheck(this, ListTopOffsetWatcher);
73
+
74
+ this.getListTopOffset = getListTopOffset;
75
+ this.onListTopOffsetChange = onListTopOffsetChange;
54
76
  }
55
77
 
56
- _createClass(WaitForStylesToLoad, [{
57
- key: "onGotListTopOffset",
58
- value: function onGotListTopOffset(listTopOffset) {
78
+ _createClass(ListTopOffsetWatcher, [{
79
+ key: "onListTopOffset",
80
+ value: function onListTopOffset(listTopOffset) {
59
81
  if (this.listTopOffsetInsideScrollableContainer === undefined) {
60
82
  // Start periodical checks of the list's top offset
61
83
  // in order to perform a re-layout in case it changes.
62
- // See the comments in `WaitForStylesToLoad.js` file
84
+ // See the comments in `ListTopOffsetWatcher.js` file
63
85
  // on why can the list's top offset change, and in which circumstances.
64
86
  this.start();
65
87
  }
@@ -69,14 +91,23 @@ function () {
69
91
  }, {
70
92
  key: "start",
71
93
  value: function start() {
72
- this.isRendered = true;
94
+ this._isActive = true;
73
95
  this.watchListTopOffset();
74
96
  }
97
+ }, {
98
+ key: "isStarted",
99
+ value: function isStarted() {
100
+ return this._isActive;
101
+ }
75
102
  }, {
76
103
  key: "stop",
77
104
  value: function stop() {
78
- this.isRendered = false;
79
- (0, _requestAnimationFrameTimeout.clearTimeout)(this.watchListTopOffsetTimer);
105
+ this._isActive = false;
106
+
107
+ if (this.watchListTopOffsetTimer) {
108
+ (0, _requestAnimationFrameTimeout.clearTimeout)(this.watchListTopOffsetTimer);
109
+ this.watchListTopOffsetTimer = undefined;
110
+ }
80
111
  }
81
112
  }, {
82
113
  key: "watchListTopOffset",
@@ -88,20 +119,18 @@ function () {
88
119
  var check = function check() {
89
120
  // If `VirtualScroller` has been unmounted
90
121
  // while `setTimeout()` was waiting, then exit.
91
- if (!_this.isRendered) {
122
+ if (!_this._isActive) {
92
123
  return;
93
124
  } // Skip comparing `top` coordinate of the list
94
125
  // when this function is called for the first time.
95
126
 
96
127
 
97
128
  if (_this.listTopOffsetInsideScrollableContainer !== undefined) {
98
- // Calling `this.getListTopOffsetInsideScrollableContainer()`
99
- // on an element is about 0.003 milliseconds on a modern desktop CPU,
129
+ // Calling `this.getListTopOffset()` on an element
130
+ // runs about 0.003 milliseconds on a modern desktop CPU,
100
131
  // so I guess it's fine calling it twice a second.
101
- if (_this.getListTopOffsetInsideScrollableContainer() !== _this.listTopOffsetInsideScrollableContainer) {
102
- _this.updateLayout({
103
- reason: _Layout.LAYOUT_REASON.TOP_OFFSET_CHANGED
104
- });
132
+ if (_this.getListTopOffset() !== _this.listTopOffsetInsideScrollableContainer) {
133
+ _this.onListTopOffsetChange();
105
134
  }
106
135
  } // Compare `top` coordinate of the list twice a second
107
136
  // to find out if it has changed as a result of loading CSS styles.
@@ -122,10 +151,8 @@ function () {
122
151
  }
123
152
  }]);
124
153
 
125
- return WaitForStylesToLoad;
154
+ return ListTopOffsetWatcher;
126
155
  }();
127
156
 
128
- exports["default"] = WaitForStylesToLoad;
129
- var WATCH_LIST_TOP_OFFSET_INTERVAL = 500;
130
- var WATCH_LIST_TOP_OFFSET_MAX_DURATION = 3000;
131
- //# sourceMappingURL=WaitForStylesToLoad.js.map
157
+ exports["default"] = ListTopOffsetWatcher;
158
+ //# sourceMappingURL=ListTopOffsetWatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListTopOffsetWatcher.js","names":["WATCH_LIST_TOP_OFFSET_INTERVAL","WATCH_LIST_TOP_OFFSET_MAX_DURATION","ListTopOffsetWatcher","getListTopOffset","onListTopOffsetChange","listTopOffset","listTopOffsetInsideScrollableContainer","undefined","start","_isActive","watchListTopOffset","watchListTopOffsetTimer","clearTimeout","startedAt","Date","now","check","setTimeout"],"sources":["../../source/DOM/ListTopOffsetWatcher.js"],"sourcesContent":["// For some weird reason, in Chrome, `setTimeout()` would lag up to a second (or more) behind.\r\n// Turns out, Chrome developers have deprecated `setTimeout()` API entirely without asking anyone.\r\n// Replacing `setTimeout()` with `requestAnimationFrame()` can work around that Chrome bug.\r\n// https://github.com/bvaughn/react-virtualized/issues/722\r\nimport { setTimeout, clearTimeout } from 'request-animation-frame-timeout'\r\n\r\n// Refreshing two times every seconds seems reasonable.\r\nconst WATCH_LIST_TOP_OFFSET_INTERVAL = 500\r\n\r\n// Refreshing for 3 seconds after the initial page load seems reasonable.\r\nconst WATCH_LIST_TOP_OFFSET_MAX_DURATION = 3000\r\n\r\n// `VirtualScroller` calls `this.layout.layOut()` on mount,\r\n// but if the page styles are applied after `VirtualScroller` mounts\r\n// (for example, if styles are applied via javascript, like Webpack does)\r\n// then the list might not render correctly and it will only show the first item.\r\n// The reason is that in that case calling `.getListTopOffset()` on mount\r\n// returns \"incorrect\" `top` position because the styles haven't been applied yet.\r\n//\r\n// For example, consider a page:\r\n//\r\n// <div class=\"page\">\r\n// <nav class=\"sidebar\">...</nav>\r\n// <main>...</main>\r\n// </div>\r\n//\r\n// The sidebar is styled as `position: fixed`, but, until\r\n// the page styles have been applied, it's gonna be a regular `<div/>`\r\n// meaning that `<main/>` will be rendered below the sidebar\r\n// and will appear offscreen, and so it will only render the first item.\r\n//\r\n// Then, the page styles are loaded and applied, and the sidebar\r\n// is now `position: fixed`, so `<main/>` is now rendered at the top of the page,\r\n// but `VirtualScroller`'s `.render()` has already been called\r\n// and it won't re-render until the user scrolls or the window is resized.\r\n//\r\n// This type of a bug doesn't seem to occur in production, but it can appear\r\n// in development mode when using Webpack. The workaround `VirtualScroller`\r\n// implements for such cases is calling `.getListTopOffset()`\r\n// on the list container DOM element periodically (every second) to check\r\n// if the `top` coordinate has changed as a result of CSS being applied:\r\n// if it has then it recalculates the shown item indexes.\r\n//\r\n// Maybe this bug could occur in production when using Webpack chunks.\r\n// That depends on how a style of a chunk is added to the page:\r\n// if it's added via `javascript` after the page has been rendered\r\n// then this workaround will also work for that case.\r\n//\r\n// Another example would be a page having a really tall expanded \"accordion\"\r\n// section, below which a `VirtualScroller` list resides. If the user un-expands\r\n// such expanded \"accordion\" section, the list would become visible but\r\n// it wouldn't get re-rendered because no `scroll` event has occured,\r\n// and the list only re-renders automatically on `scroll` events.\r\n// To work around such cases, call `virtualScroller.updateLayout()` method manually.\r\n// The workaround below could be extended to refresh the list's top coordinate\r\n// indefinitely and at higher intervals, but why waste CPU time on that.\r\n// There doesn't seem to be any DOM API for tracking an element's top position.\r\n// There is `IntersectionObserver` API but it doesn't exactly do that.\r\n//\r\nexport default class ListTopOffsetWatcher {\r\n\tconstructor({\r\n\t\tgetListTopOffset,\r\n\t\tonListTopOffsetChange\r\n\t}) {\r\n\t\tthis.getListTopOffset = getListTopOffset\r\n\t\tthis.onListTopOffsetChange = onListTopOffsetChange\r\n\t}\r\n\r\n\tonListTopOffset(listTopOffset) {\r\n\t\tif (this.listTopOffsetInsideScrollableContainer === undefined) {\r\n\t\t\t// Start periodical checks of the list's top offset\r\n\t\t\t// in order to perform a re-layout in case it changes.\r\n\t\t\t// See the comments in `ListTopOffsetWatcher.js` file\r\n\t\t\t// on why can the list's top offset change, and in which circumstances.\r\n\t\t\tthis.start()\r\n\t\t}\r\n\t\tthis.listTopOffsetInsideScrollableContainer = listTopOffset\r\n\t}\r\n\r\n\tstart() {\r\n\t\tthis._isActive = true\r\n\t\tthis.watchListTopOffset()\r\n\t}\r\n\r\n\tisStarted() {\r\n\t\treturn this._isActive\r\n\t}\r\n\r\n\tstop() {\r\n\t\tthis._isActive = false\r\n\r\n\t\tif (this.watchListTopOffsetTimer) {\r\n\t\t\tclearTimeout(this.watchListTopOffsetTimer)\r\n\t\t\tthis.watchListTopOffsetTimer = undefined\r\n\t\t}\r\n\t}\r\n\r\n\twatchListTopOffset() {\r\n\t\tconst startedAt = Date.now()\r\n\t\tconst check = () => {\r\n\t\t\t// If `VirtualScroller` has been unmounted\r\n\t\t\t// while `setTimeout()` was waiting, then exit.\r\n\t\t\tif (!this._isActive) {\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\t\t\t// Skip comparing `top` coordinate of the list\r\n\t\t\t// when this function is called for the first time.\r\n\t\t\tif (this.listTopOffsetInsideScrollableContainer !== undefined) {\r\n\t\t\t\t// Calling `this.getListTopOffset()` on an element\r\n\t\t\t\t// runs about 0.003 milliseconds on a modern desktop CPU,\r\n\t\t\t\t// so I guess it's fine calling it twice a second.\r\n\t\t\t\tif (this.getListTopOffset() !== this.listTopOffsetInsideScrollableContainer) {\r\n\t\t\t\t\tthis.onListTopOffsetChange()\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\t// Compare `top` coordinate of the list twice a second\r\n\t\t\t// to find out if it has changed as a result of loading CSS styles.\r\n\t\t\t// The total duration of 3 seconds would be enough for any styles to load, I guess.\r\n\t\t\t// There could be other cases changing the `top` coordinate\r\n\t\t\t// of the list (like collapsing an \"accordeon\" panel above the list\r\n\t\t\t// without scrolling the page), but those cases should be handled\r\n\t\t\t// by manually calling `.updateLayout()` instance method on `VirtualScroller` instance.\r\n\t\t\tif (Date.now() - startedAt < WATCH_LIST_TOP_OFFSET_MAX_DURATION) {\r\n\t\t\t\tthis.watchListTopOffsetTimer = setTimeout(check, WATCH_LIST_TOP_OFFSET_INTERVAL)\r\n\t\t\t}\r\n\t\t}\r\n\t\t// Run the cycle.\r\n\t\tcheck()\r\n\t}\r\n}"],"mappings":";;;;;;;AAIA;;;;;;;;AAEA;AACA,IAAMA,8BAA8B,GAAG,GAAvC,C,CAEA;;AACA,IAAMC,kCAAkC,GAAG,IAA3C,C,CAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;IACqBC,oB;EACpB,oCAGG;IAAA,IAFFC,gBAEE,QAFFA,gBAEE;IAAA,IADFC,qBACE,QADFA,qBACE;;IAAA;;IACF,KAAKD,gBAAL,GAAwBA,gBAAxB;IACA,KAAKC,qBAAL,GAA6BA,qBAA7B;EACA;;;;WAED,yBAAgBC,aAAhB,EAA+B;MAC9B,IAAI,KAAKC,sCAAL,KAAgDC,SAApD,EAA+D;QAC9D;QACA;QACA;QACA;QACA,KAAKC,KAAL;MACA;;MACD,KAAKF,sCAAL,GAA8CD,aAA9C;IACA;;;WAED,iBAAQ;MACP,KAAKI,SAAL,GAAiB,IAAjB;MACA,KAAKC,kBAAL;IACA;;;WAED,qBAAY;MACX,OAAO,KAAKD,SAAZ;IACA;;;WAED,gBAAO;MACN,KAAKA,SAAL,GAAiB,KAAjB;;MAEA,IAAI,KAAKE,uBAAT,EAAkC;QACjC,IAAAC,0CAAA,EAAa,KAAKD,uBAAlB;QACA,KAAKA,uBAAL,GAA+BJ,SAA/B;MACA;IACD;;;WAED,8BAAqB;MAAA;;MACpB,IAAMM,SAAS,GAAGC,IAAI,CAACC,GAAL,EAAlB;;MACA,IAAMC,KAAK,GAAG,SAARA,KAAQ,GAAM;QACnB;QACA;QACA,IAAI,CAAC,KAAI,CAACP,SAAV,EAAqB;UACpB;QACA,CALkB,CAMnB;QACA;;;QACA,IAAI,KAAI,CAACH,sCAAL,KAAgDC,SAApD,EAA+D;UAC9D;UACA;UACA;UACA,IAAI,KAAI,CAACJ,gBAAL,OAA4B,KAAI,CAACG,sCAArC,EAA6E;YAC5E,KAAI,CAACF,qBAAL;UACA;QACD,CAfkB,CAgBnB;QACA;QACA;QACA;QACA;QACA;QACA;;;QACA,IAAIU,IAAI,CAACC,GAAL,KAAaF,SAAb,GAAyBZ,kCAA7B,EAAiE;UAChE,KAAI,CAACU,uBAAL,GAA+B,IAAAM,wCAAA,EAAWD,KAAX,EAAkBhB,8BAAlB,CAA/B;QACA;MACD,CA1BD,CAFoB,CA6BpB;;;MACAgB,KAAK;IACL"}
@@ -1,39 +1,43 @@
1
1
  "use strict";
2
2
 
3
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
4
+
3
5
  Object.defineProperty(exports, "__esModule", {
4
6
  value: true
5
7
  });
6
- exports.ScrollableWindowContainer = exports["default"] = void 0;
8
+ exports["default"] = exports.ScrollableWindowContainer = void 0;
7
9
 
8
- function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
10
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
9
11
 
10
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
12
+ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
11
13
 
12
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
14
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
13
15
 
14
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
16
+ function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
15
17
 
16
- function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
18
+ function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
17
19
 
18
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
20
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
21
+
22
+ function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
19
23
 
20
24
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
21
25
 
22
26
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
23
27
 
24
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
28
+ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
25
29
 
26
- var ScrollableContainer =
27
- /*#__PURE__*/
28
- function () {
30
+ var ScrollableContainer = /*#__PURE__*/function () {
29
31
  /**
30
32
  * Constructs a new "scrollable container" from an element.
31
- * @param {Element} scrollableContainer
33
+ * @param {func} getElement — Returns the scrollable container element.
34
+ * @param {func} getItemsContainerElement — Returns items "container" element.
32
35
  */
33
- function ScrollableContainer(element) {
36
+ function ScrollableContainer(getElement, getItemsContainerElement) {
34
37
  _classCallCheck(this, ScrollableContainer);
35
38
 
36
- this.element = element;
39
+ this.getElement = getElement;
40
+ this.getItemsContainerElement = getItemsContainerElement;
37
41
  }
38
42
  /**
39
43
  * Returns the current scroll position.
@@ -44,7 +48,7 @@ function () {
44
48
  _createClass(ScrollableContainer, [{
45
49
  key: "getScrollY",
46
50
  value: function getScrollY() {
47
- return this.element.scrollTop;
51
+ return this.getElement().scrollTop;
48
52
  }
49
53
  /**
50
54
  * Scrolls to a specific position.
@@ -57,10 +61,10 @@ function () {
57
61
  // IE 11 doesn't seem to have a `.scrollTo()` method.
58
62
  // https://gitlab.com/catamphetamine/virtual-scroller/-/issues/10
59
63
  // https://stackoverflow.com/questions/39908825/window-scrollto-is-not-working-in-internet-explorer-11
60
- if (this.element.scrollTo) {
61
- this.element.scrollTo(0, scrollY);
64
+ if (this.getElement().scrollTo) {
65
+ this.getElement().scrollTo(0, scrollY);
62
66
  } else {
63
- this.element.scrollTop = scrollY;
67
+ this.getElement().scrollTop = scrollY;
64
68
  }
65
69
  }
66
70
  /**
@@ -72,7 +76,7 @@ function () {
72
76
  }, {
73
77
  key: "getWidth",
74
78
  value: function getWidth() {
75
- return this.element.offsetWidth;
79
+ return this.getElement().offsetWidth;
76
80
  }
77
81
  /**
78
82
  * Returns the height of the "scrollable container" itself.
@@ -83,78 +87,54 @@ function () {
83
87
  }, {
84
88
  key: "getHeight",
85
89
  value: function getHeight() {
86
- // if (!this.element && !precise) {
90
+ // if (!this.getElement() && !precise) {
87
91
  // return getScreenHeight()
88
92
  // }
89
- return this.element.offsetHeight;
90
- }
91
- /**
92
- * Returns the height of the content in a scrollable container.
93
- * For example, a scrollable container can have a height of 500px,
94
- * but the content in it could have a height of 5000px,
95
- * in which case a vertical scrollbar is rendered, and only
96
- * one-tenth of all the items are shown at any given moment.
97
- * This function is currently only used when using the
98
- * `preserveScrollPositionOfTheBottomOfTheListOnMount` feature.
99
- * @return {number}
100
- */
101
-
102
- }, {
103
- key: "getContentHeight",
104
- value: function getContentHeight() {
105
- return this.element.scrollHeight;
93
+ return this.getElement().offsetHeight;
106
94
  }
107
95
  /**
108
- * Returns a "top offset" of an element
96
+ * Returns a "top offset" of an items container element
109
97
  * relative to the "scrollable container"'s top edge.
110
- * @param {Element} element
111
98
  * @return {number}
112
99
  */
113
100
 
114
101
  }, {
115
- key: "getTopOffset",
116
- value: function getTopOffset(element) {
117
- var scrollableContainerTop = this.element.getBoundingClientRect().top;
118
- var scrollableContainerBorderTopWidth = this.element.clientTop;
119
- var top = element.getBoundingClientRect().top;
120
- return top - scrollableContainerTop + this.getScrollY() - scrollableContainerBorderTopWidth;
102
+ key: "getItemsContainerTopOffset",
103
+ value: function getItemsContainerTopOffset() {
104
+ var scrollableContainerTop = this.getElement().getBoundingClientRect().top;
105
+ var scrollableContainerBorderTopWidth = this.getElement().clientTop;
106
+ var itemsContainerTop = this.getItemsContainerElement().getBoundingClientRect().top;
107
+ return itemsContainerTop - scrollableContainerTop + this.getScrollY() - scrollableContainerBorderTopWidth;
121
108
  } // isVisible() {
122
- // const { top, bottom } = this.element.getBoundingClientRect()
109
+ // const { top, bottom } = this.getElement().getBoundingClientRect()
123
110
  // return bottom > 0 && top < getScreenHeight()
124
111
  // }
125
112
 
126
113
  /**
127
114
  * Adds a "scroll" event listener to the "scrollable container".
128
- * @param {onScroll} Should be called whenever the scroll position inside the "scrollable container" (potentially) changes.
115
+ * @param {onScrollListener} Should be called whenever the scroll position inside the "scrollable container" (potentially) changes.
129
116
  * @return {function} Returns a function that stops listening.
130
117
  */
131
118
 
132
119
  }, {
133
- key: "addScrollListener",
134
- value: function addScrollListener(onScroll) {
135
- var _this = this;
136
-
137
- this.element.addEventListener('scroll', onScroll);
120
+ key: "onScroll",
121
+ value: function onScroll(onScrollListener) {
122
+ var element = this.getElement();
123
+ element.addEventListener('scroll', onScrollListener);
138
124
  return function () {
139
- return _this.element.removeEventListener('scroll', onScroll);
125
+ return element.removeEventListener('scroll', onScrollListener);
140
126
  };
141
127
  }
142
128
  /**
143
129
  * Adds a "resize" event listener to the "scrollable container".
144
130
  * @param {onResize} Should be called whenever the "scrollable container"'s width or height (potentially) changes.
145
- * @param {Element} options.container The result of the `getContainerElement()` function that was passed in `VirtualScroller` constructor. For example, DOM renderer uses it to filter-out unrelated "resize" events.
146
- * @return {function} Returns a function that stops listening.
131
+ * @return {function} Returns a function that stops listening.
147
132
  */
148
133
 
149
134
  }, {
150
135
  key: "onResize",
151
- value: function onResize(_onResize, _ref) {
152
- var _this2 = this;
153
-
154
- var container = _ref.container;
155
- // Could somehow track DOM Element size.
156
- // For now, `scrollableContainer` is supposed to have constant width and height.
157
- // (unless window is resized).
136
+ value: function onResize(_onResize) {
137
+ // Watches "scrollable container"'s dimensions via a `ResizeObserver`.
158
138
  // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver
159
139
  // https://web.dev/resize-observer/
160
140
  var unobserve;
@@ -163,7 +143,7 @@ function () {
163
143
  var resizeObserver = new ResizeObserver(function (entries) {
164
144
  // "one entry per observed element".
165
145
  // https://web.dev/resize-observer/
166
- // `entry.target === this.element`.
146
+ // `entry.target === this.getElement()`.
167
147
  var entry = entries[0]; // // If `entry.contentBoxSize` property is supported by the web browser.
168
148
  // if (entry.contentBoxSize) {
169
149
  // // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize
@@ -173,10 +153,11 @@ function () {
173
153
 
174
154
  _onResize();
175
155
  });
176
- resizeObserver.observe(this.element);
156
+ var element = this.getElement();
157
+ resizeObserver.observe(element);
177
158
 
178
159
  unobserve = function unobserve() {
179
- return resizeObserver.unobserve(_this2.element);
160
+ return resizeObserver.unobserve(element);
180
161
  };
181
162
  } // I guess, if window is resized, `onResize()` will be triggered twice:
182
163
  // once for window resize, and once for the scrollable container resize.
@@ -187,7 +168,7 @@ function () {
187
168
 
188
169
 
189
170
  var unlistenGlobalResize = addGlobalResizeListener(_onResize, {
190
- container: container
171
+ itemsContainerElement: this.getItemsContainerElement()
191
172
  });
192
173
  return function () {
193
174
  if (unobserve) {
@@ -204,15 +185,21 @@ function () {
204
185
 
205
186
  exports["default"] = ScrollableContainer;
206
187
 
207
- var ScrollableWindowContainer =
208
- /*#__PURE__*/
209
- function (_ScrollableContainer) {
188
+ var ScrollableWindowContainer = /*#__PURE__*/function (_ScrollableContainer) {
210
189
  _inherits(ScrollableWindowContainer, _ScrollableContainer);
211
190
 
212
- function ScrollableWindowContainer() {
191
+ var _super = _createSuper(ScrollableWindowContainer);
192
+
193
+ /**
194
+ * Constructs a new window "scrollable container".
195
+ * @param {func} getItemsContainerElement — Returns items "container" element.
196
+ */
197
+ function ScrollableWindowContainer(getItemsContainerElement) {
213
198
  _classCallCheck(this, ScrollableWindowContainer);
214
199
 
215
- return _possibleConstructorReturn(this, _getPrototypeOf(ScrollableWindowContainer).call(this, window));
200
+ return _super.call(this, function () {
201
+ return window;
202
+ }, getItemsContainerElement);
216
203
  }
217
204
  /**
218
205
  * Returns the current scroll position.
@@ -266,47 +253,28 @@ function (_ScrollableContainer) {
266
253
  return window.innerHeight;
267
254
  }
268
255
  /**
269
- * Returns the height of the content in a scrollable container.
270
- * For example, a scrollable container can have a height of 500px,
271
- * but the content in it could have a height of 5000px,
272
- * in which case a vertical scrollbar is rendered, and only
273
- * one-tenth of all the items are shown at any given moment.
274
- * This function is currently only used when using the
275
- * `preserveScrollPositionOfTheBottomOfTheListOnMount` feature.
276
- * @return {number}
277
- */
278
-
279
- }, {
280
- key: "getContentHeight",
281
- value: function getContentHeight() {
282
- return document.documentElement.scrollHeight;
283
- }
284
- /**
285
- * Returns a "top offset" of an element
256
+ * Returns a "top offset" of an items container element
286
257
  * relative to the "scrollable container"'s top edge.
287
- * @param {Element} element
288
258
  * @return {number}
289
259
  */
290
260
 
291
261
  }, {
292
- key: "getTopOffset",
293
- value: function getTopOffset(element) {
262
+ key: "getItemsContainerTopOffset",
263
+ value: function getItemsContainerTopOffset() {
294
264
  var borderTopWidth = document.clientTop || document.body.clientTop || 0;
295
- return element.getBoundingClientRect().top + this.getScrollY() - borderTopWidth;
265
+ return this.getItemsContainerElement().getBoundingClientRect().top + this.getScrollY() - borderTopWidth;
296
266
  }
297
267
  /**
298
268
  * Adds a "resize" event listener to the "scrollable container".
299
269
  * @param {onScroll} Should be called whenever the "scrollable container"'s width or height (potentially) changes.
300
- * @param {Element} options.container — The result of the `getContainerElement()` function that was passed in `VirtualScroller` constructor. For example, DOM renderer uses it to filter-out unrelated "resize" events.
301
270
  * @return {function} Returns a function that stops listening.
302
271
  */
303
272
 
304
273
  }, {
305
274
  key: "onResize",
306
- value: function onResize(_onResize2, _ref2) {
307
- var container = _ref2.container;
275
+ value: function onResize(_onResize2) {
308
276
  return addGlobalResizeListener(_onResize2, {
309
- container: container
277
+ itemsContainerElement: this.getItemsContainerElement()
310
278
  });
311
279
  } // isVisible() {
312
280
  // return true
@@ -318,16 +286,16 @@ function (_ScrollableContainer) {
318
286
  }(ScrollableContainer);
319
287
  /**
320
288
  * Adds a "resize" event listener to the `window`.
321
- * @param {onResize} Should be called whenever the "container"'s width or height (potentially) changes.
322
- * @param {Element} options.container — The "container".
289
+ * @param {onResize} Should be called whenever the "scrollable container"'s width or height (potentially) changes.
290
+ * @param {Element} options.itemsContainerElement — The items "container" element, which is not the same as the "scrollable container" element. For example, "scrollable container" could be resized while the list element retaining its size. One such example is a user entering fullscreen mode on an HTML5 `<video/>` element: in that case, a "resize" event is triggered on a window, and window dimensions change to the user's screen size, but such "resize" event can be ignored because the list isn't visible until the user exits fullscreen mode.
323
291
  * @return {function} Returns a function that stops listening.
324
292
  */
325
293
 
326
294
 
327
295
  exports.ScrollableWindowContainer = ScrollableWindowContainer;
328
296
 
329
- function addGlobalResizeListener(onResize, _ref3) {
330
- var container = _ref3.container;
297
+ function addGlobalResizeListener(onResize, _ref) {
298
+ var itemsContainerElement = _ref.itemsContainerElement;
331
299
 
332
300
  var onResizeListener = function onResizeListener() {
333
301
  // By default, `VirtualScroller` always performs a re-layout
@@ -359,7 +327,7 @@ function addGlobalResizeListener(onResize, _ref3) {
359
327
  // the layout wouldn't be affected too, so such `resize` event should also be
360
328
  // ignored: when `document.fullscreenElement` is inside the `container`.
361
329
  //
362
- if (document.fullscreenElement.contains(container)) {// The element is either the `container`'s ancestor,
330
+ if (document.fullscreenElement.contains(itemsContainerElement)) {// The element is either the `container`'s ancestor,
363
331
  // Or is the `container` itself.
364
332
  // (`a.contains(b)` includes the `a === b` case).
365
333
  // So the `resize` event will affect the `container`'s dimensions.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../source/DOM/ScrollableContainer.js"],"names":["ScrollableContainer","element","scrollTop","scrollY","scrollTo","offsetWidth","offsetHeight","scrollHeight","scrollableContainerTop","getBoundingClientRect","top","scrollableContainerBorderTopWidth","clientTop","getScrollY","onScroll","addEventListener","removeEventListener","onResize","container","unobserve","ResizeObserver","resizeObserver","entries","entry","observe","unlistenGlobalResize","addGlobalResizeListener","ScrollableWindowContainer","window","pageYOffset","innerWidth","innerHeight","document","documentElement","borderTopWidth","body","onResizeListener","fullscreenElement","contains"],"mappings":"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","sourcesContent":["export default class ScrollableContainer {\r\n\t/**\r\n\t * Constructs a new \"scrollable container\" from an element.\r\n\t * @param {Element} scrollableContainer\r\n\t */\r\n\tconstructor(element) {\r\n\t\tthis.element = element\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the current scroll position.\r\n\t * @return {number}\r\n\t */\r\n\tgetScrollY() {\r\n\t\treturn this.element.scrollTop\r\n\t}\r\n\r\n\t/**\r\n\t * Scrolls to a specific position.\r\n\t * @param {number} scrollY\r\n\t */\r\n\tscrollToY(scrollY) {\r\n\t\t// IE 11 doesn't seem to have a `.scrollTo()` method.\r\n\t\t// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/10\r\n\t\t// https://stackoverflow.com/questions/39908825/window-scrollto-is-not-working-in-internet-explorer-11\r\n\t\tif (this.element.scrollTo) {\r\n\t\t\tthis.element.scrollTo(0, scrollY)\r\n\t\t} else {\r\n\t\t\tthis.element.scrollTop = scrollY\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns \"scrollable container\" width,\r\n\t * i.e. the available width for its content.\r\n\t * @return {number}\r\n\t */\r\n\tgetWidth() {\r\n\t\treturn this.element.offsetWidth\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the height of the \"scrollable container\" itself.\r\n\t * Not to be confused with the height of \"scrollable container\"'s content.\r\n\t * @return {number}\r\n\t */\r\n\tgetHeight() {\r\n\t\t// if (!this.element && !precise) {\r\n\t\t// \treturn getScreenHeight()\r\n\t\t// }\r\n\t\treturn this.element.offsetHeight\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the height of the content in a scrollable container.\r\n\t * For example, a scrollable container can have a height of 500px,\r\n\t * but the content in it could have a height of 5000px,\r\n\t * in which case a vertical scrollbar is rendered, and only\r\n\t * one-tenth of all the items are shown at any given moment.\r\n\t * This function is currently only used when using the\r\n\t * `preserveScrollPositionOfTheBottomOfTheListOnMount` feature.\r\n\t * @return {number}\r\n\t */\r\n\tgetContentHeight() {\r\n\t\treturn this.element.scrollHeight\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a \"top offset\" of an element\r\n\t * relative to the \"scrollable container\"'s top edge.\r\n\t * @param {Element} element\r\n\t * @return {number}\r\n\t */\r\n\tgetTopOffset(element) {\r\n\t\tconst scrollableContainerTop = this.element.getBoundingClientRect().top\r\n\t\tconst scrollableContainerBorderTopWidth = this.element.clientTop\r\n\t\tconst top = element.getBoundingClientRect().top\r\n\t\treturn (top - scrollableContainerTop) + this.getScrollY() - scrollableContainerBorderTopWidth\r\n\t}\r\n\r\n\t// isVisible() {\r\n\t// \tconst { top, bottom } = this.element.getBoundingClientRect()\r\n\t// \treturn bottom > 0 && top < getScreenHeight()\r\n\t// }\r\n\r\n\t/**\r\n\t * Adds a \"scroll\" event listener to the \"scrollable container\".\r\n\t * @param {onScroll} Should be called whenever the scroll position inside the \"scrollable container\" (potentially) changes.\r\n\t * @return {function} Returns a function that stops listening.\r\n\t */\r\n\taddScrollListener(onScroll) {\r\n\t\tthis.element.addEventListener('scroll', onScroll)\r\n\t\treturn () => this.element.removeEventListener('scroll', onScroll)\r\n\t}\r\n\r\n\t/**\r\n\t * Adds a \"resize\" event listener to the \"scrollable container\".\r\n\t * @param {onResize} Should be called whenever the \"scrollable container\"'s width or height (potentially) changes.\r\n\t * @param {Element} options.container — The result of the `getContainerElement()` function that was passed in `VirtualScroller` constructor. For example, DOM renderer uses it to filter-out unrelated \"resize\" events.\r\n\t * @return {function} Returns a function that stops listening.\r\n\t */\r\n\tonResize(onResize, { container }) {\r\n\t\t// Could somehow track DOM Element size.\r\n\t\t// For now, `scrollableContainer` is supposed to have constant width and height.\r\n\t\t// (unless window is resized).\r\n\t\t// https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver\r\n\t\t// https://web.dev/resize-observer/\r\n\t\tlet unobserve\r\n\t\tif (typeof ResizeObserver !== 'undefined') {\r\n\t\t\tconst resizeObserver = new ResizeObserver((entries) => {\r\n\t\t\t\t// \"one entry per observed element\".\r\n\t\t\t\t// https://web.dev/resize-observer/\r\n\t\t\t\t// `entry.target === this.element`.\r\n\t\t\t\tconst entry = entries[0]\r\n\t\t\t\t// // If `entry.contentBoxSize` property is supported by the web browser.\r\n\t\t\t\t// if (entry.contentBoxSize) {\r\n\t\t\t\t// \t// https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize\r\n\t\t\t\t// \tconst width = entry.contentBoxSize.inlineSize\r\n\t\t\t\t// \tconst height = entry.contentBoxSize.blockSize\r\n\t\t\t\t// }\r\n\t\t\t\tonResize()\r\n\t\t\t})\r\n\t\t\tresizeObserver.observe(this.element)\r\n\t\t\tunobserve = () => resizeObserver.unobserve(this.element)\r\n\t\t}\r\n\t\t// I guess, if window is resized, `onResize()` will be triggered twice:\r\n\t\t// once for window resize, and once for the scrollable container resize.\r\n\t\t// But `onResize()` also has an internal check: if the container size\r\n\t\t// hasn't changed since the previous time `onResize()` has been called,\r\n\t\t// then `onResize()` doesn't do anything, so, I guess, there shouldn't be\r\n\t\t// any \"performance implications\" of running the listener twice in such case.\r\n\t\tconst unlistenGlobalResize = addGlobalResizeListener(onResize, { container })\r\n\t\treturn () => {\r\n\t\t\tif (unobserve) {\r\n\t\t\t\tunobserve()\r\n\t\t\t}\r\n\t\t\tunlistenGlobalResize()\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ScrollableWindowContainer extends ScrollableContainer {\r\n\tconstructor() {\r\n\t\tsuper(window)\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the current scroll position.\r\n\t * @return {number}\r\n\t */\r\n\tgetScrollY() {\r\n\t\t// `window.scrollY` is not supported by Internet Explorer.\r\n\t\treturn window.pageYOffset\r\n\t}\r\n\r\n\t/**\r\n\t * Returns \"scrollable container\" width,\r\n\t * i.e. the available width for its content.\r\n\t * @return {number}\r\n\t */\r\n\tgetWidth() {\r\n\t\t// https://javascript.info/size-and-scroll-window\r\n\t\t// `<!DOCTYPE html>` may be required in order for this to work correctly.\r\n\t\t// Includes scrollbar (if any).\r\n\t\t// Correctly reflects page zoom in iOS Safari.\r\n\t\t// (scales screen width accordingly).\r\n\t\t// But, includes scrollbar (if any).\r\n\t\treturn window.innerWidth\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the height of the \"scrollable container\" itself.\r\n\t * Not to be confused with the height of \"scrollable container\"'s content.\r\n\t * @return {number}\r\n\t */\r\n\tgetHeight() {\r\n\t\t// https://javascript.info/size-and-scroll-window\r\n\t\t// `<!DOCTYPE html>` is required in order for this to work correctly.\r\n\t\t// Without it, the returned height would be the height of the entire document.\r\n\t\t// Includes scrollbar (if any).\r\n\t\t// Supports iOS Safari's dynamically shown/hidden\r\n\t\t// top URL bar and bottom actions bar.\r\n\t\t// https://codesandbox.io/s/elegant-fog-iddrh\r\n\t\t// Tested in IE 11.\r\n\t\t// It also correctly reflects page zoom in iOS Safari.\r\n\t\t// (scales screen height accordingly).\r\n\t\t// But, includes scrollbar (if any).\r\n\t\treturn window.innerHeight\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the height of the content in a scrollable container.\r\n\t * For example, a scrollable container can have a height of 500px,\r\n\t * but the content in it could have a height of 5000px,\r\n\t * in which case a vertical scrollbar is rendered, and only\r\n\t * one-tenth of all the items are shown at any given moment.\r\n\t * This function is currently only used when using the\r\n\t * `preserveScrollPositionOfTheBottomOfTheListOnMount` feature.\r\n\t * @return {number}\r\n\t */\r\n\tgetContentHeight() {\r\n\t\treturn document.documentElement.scrollHeight\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a \"top offset\" of an element\r\n\t * relative to the \"scrollable container\"'s top edge.\r\n\t * @param {Element} element\r\n\t * @return {number}\r\n\t */\r\n\tgetTopOffset(element) {\r\n\t\tconst borderTopWidth = document.clientTop || document.body.clientTop || 0\r\n\t\treturn element.getBoundingClientRect().top + this.getScrollY() - borderTopWidth\r\n\t}\r\n\r\n\t/**\r\n\t * Adds a \"resize\" event listener to the \"scrollable container\".\r\n\t * @param {onScroll} Should be called whenever the \"scrollable container\"'s width or height (potentially) changes.\r\n\t * @param {Element} options.container — The result of the `getContainerElement()` function that was passed in `VirtualScroller` constructor. For example, DOM renderer uses it to filter-out unrelated \"resize\" events.\r\n\t * @return {function} Returns a function that stops listening.\r\n\t */\r\n\tonResize(onResize, { container }) {\r\n\t\treturn addGlobalResizeListener(onResize, { container })\r\n\t}\r\n\r\n\t// isVisible() {\r\n\t// \treturn true\r\n\t// }\r\n}\r\n\r\n/**\r\n * Adds a \"resize\" event listener to the `window`.\r\n * @param {onResize} Should be called whenever the \"container\"'s width or height (potentially) changes.\r\n * @param {Element} options.container — The \"container\".\r\n * @return {function} Returns a function that stops listening.\r\n */\r\nfunction addGlobalResizeListener(onResize, { container }) {\r\n\tconst onResizeListener = () => {\r\n\t\t// By default, `VirtualScroller` always performs a re-layout\r\n\t\t// on window `resize` event. But browsers (Chrome, Firefox)\r\n\t\t// [trigger](https://developer.mozilla.org/en-US/docs/Web/API/Window/fullScreen#Notes)\r\n\t\t// window `resize` event also when a user switches into fullscreen mode:\r\n\t\t// for example, when a user is watching a video and double-clicks on it\r\n\t\t// to maximize it. And also when the user goes out of the fullscreen mode.\r\n\t\t// Each such fullscreen mode entering/exiting will trigger window `resize`\r\n\t\t// event that will it turn trigger a re-layout of `VirtualScroller`,\r\n\t\t// resulting in bad user experience. To prevent that, such cases are filtered out.\r\n\t\t// Some other workaround:\r\n\t\t// https://stackoverflow.com/questions/23770449/embedded-youtube-video-fullscreen-or-causing-resize\r\n\t\tif (document.fullscreenElement) {\r\n\t\t\t// If the fullscreened element doesn't contain the list\r\n\t\t\t// (and is not the list itself), then the layout hasn't been affected,\r\n\t\t\t// so don't perform a re-layout.\r\n\t\t\t//\r\n\t\t\t// For example, suppose there's a list of items, and some item contains a video.\r\n\t\t\t// If, upon clicking such video, it plays inline, and the user enters\r\n\t\t\t// fullscreen mode while playing such inline video, then the layout won't be\r\n\t\t\t// affected, and so such `resize` event should be ignored: when\r\n\t\t\t// `document.fullscreenElement` is in a separate \"branch\" relative to the\r\n\t\t\t// `container`.\r\n\t\t\t//\r\n\t\t\t// Another scenario: suppose that upon click, the video doesn't play inline,\r\n\t\t\t// but instead a \"Slideshow\" component is open, with the video shown at the\r\n\t\t\t// center of the screen in an overlay. If then the user enters fullscreen mode,\r\n\t\t\t// the layout wouldn't be affected too, so such `resize` event should also be\r\n\t\t\t// ignored: when `document.fullscreenElement` is inside the `container`.\r\n\t\t\t//\r\n\t\t\tif (document.fullscreenElement.contains(container)) {\r\n\t\t\t\t// The element is either the `container`'s ancestor,\r\n\t\t\t\t// Or is the `container` itself.\r\n\t\t\t\t// (`a.contains(b)` includes the `a === b` case).\r\n\t\t\t\t// So the `resize` event will affect the `container`'s dimensions.\r\n\t\t\t} else {\r\n\t\t\t\t// The element is either inside the `container`,\r\n\t\t\t\t// Or is in a separate tree.\r\n\t\t\t\t// So the `resize` event won't affect the `container`'s dimensions.\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\t\t}\r\n\t\tonResize()\r\n\t}\r\n\twindow.addEventListener('resize', onResizeListener)\r\n\treturn () => window.removeEventListener('resize', onResizeListener)\r\n}"],"file":"ScrollableContainer.js"}
1
+ {"version":3,"file":"ScrollableContainer.js","names":["ScrollableContainer","getElement","getItemsContainerElement","scrollTop","scrollY","scrollTo","offsetWidth","offsetHeight","scrollableContainerTop","getBoundingClientRect","top","scrollableContainerBorderTopWidth","clientTop","itemsContainerTop","getScrollY","onScrollListener","element","addEventListener","removeEventListener","onResize","unobserve","ResizeObserver","resizeObserver","entries","entry","observe","unlistenGlobalResize","addGlobalResizeListener","itemsContainerElement","ScrollableWindowContainer","window","pageYOffset","innerWidth","innerHeight","borderTopWidth","document","body","onResizeListener","fullscreenElement","contains"],"sources":["../../source/DOM/ScrollableContainer.js"],"sourcesContent":["export default class ScrollableContainer {\r\n\t/**\r\n\t * Constructs a new \"scrollable container\" from an element.\r\n\t * @param {func} getElement — Returns the scrollable container element.\r\n\t * @param {func} getItemsContainerElement — Returns items \"container\" element.\r\n\t */\r\n\tconstructor(getElement, getItemsContainerElement) {\r\n\t\tthis.getElement = getElement\r\n\t\tthis.getItemsContainerElement = getItemsContainerElement\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the current scroll position.\r\n\t * @return {number}\r\n\t */\r\n\tgetScrollY() {\r\n\t\treturn this.getElement().scrollTop\r\n\t}\r\n\r\n\t/**\r\n\t * Scrolls to a specific position.\r\n\t * @param {number} scrollY\r\n\t */\r\n\tscrollToY(scrollY) {\r\n\t\t// IE 11 doesn't seem to have a `.scrollTo()` method.\r\n\t\t// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/10\r\n\t\t// https://stackoverflow.com/questions/39908825/window-scrollto-is-not-working-in-internet-explorer-11\r\n\t\tif (this.getElement().scrollTo) {\r\n\t\t\tthis.getElement().scrollTo(0, scrollY)\r\n\t\t} else {\r\n\t\t\tthis.getElement().scrollTop = scrollY\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Returns \"scrollable container\" width,\r\n\t * i.e. the available width for its content.\r\n\t * @return {number}\r\n\t */\r\n\tgetWidth() {\r\n\t\treturn this.getElement().offsetWidth\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the height of the \"scrollable container\" itself.\r\n\t * Not to be confused with the height of \"scrollable container\"'s content.\r\n\t * @return {number}\r\n\t */\r\n\tgetHeight() {\r\n\t\t// if (!this.getElement() && !precise) {\r\n\t\t// \treturn getScreenHeight()\r\n\t\t// }\r\n\t\treturn this.getElement().offsetHeight\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a \"top offset\" of an items container element\r\n\t * relative to the \"scrollable container\"'s top edge.\r\n\t * @return {number}\r\n\t */\r\n\tgetItemsContainerTopOffset() {\r\n\t\tconst scrollableContainerTop = this.getElement().getBoundingClientRect().top\r\n\t\tconst scrollableContainerBorderTopWidth = this.getElement().clientTop\r\n\t\tconst itemsContainerTop = this.getItemsContainerElement().getBoundingClientRect().top\r\n\t\treturn (itemsContainerTop - scrollableContainerTop) + this.getScrollY() - scrollableContainerBorderTopWidth\r\n\t}\r\n\r\n\t// isVisible() {\r\n\t// \tconst { top, bottom } = this.getElement().getBoundingClientRect()\r\n\t// \treturn bottom > 0 && top < getScreenHeight()\r\n\t// }\r\n\r\n\t/**\r\n\t * Adds a \"scroll\" event listener to the \"scrollable container\".\r\n\t * @param {onScrollListener} Should be called whenever the scroll position inside the \"scrollable container\" (potentially) changes.\r\n\t * @return {function} Returns a function that stops listening.\r\n\t */\r\n\tonScroll(onScrollListener) {\r\n\t\tconst element = this.getElement()\r\n\t\telement.addEventListener('scroll', onScrollListener)\r\n\t\treturn () => element.removeEventListener('scroll', onScrollListener)\r\n\t}\r\n\r\n\t/**\r\n\t * Adds a \"resize\" event listener to the \"scrollable container\".\r\n\t * @param {onResize} Should be called whenever the \"scrollable container\"'s width or height (potentially) changes.\r\n * @return {function} Returns a function that stops listening.\r\n\t */\r\n\tonResize(onResize) {\r\n\t\t// Watches \"scrollable container\"'s dimensions via a `ResizeObserver`.\r\n\t\t// https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver\r\n\t\t// https://web.dev/resize-observer/\r\n\t\tlet unobserve\r\n\t\tif (typeof ResizeObserver !== 'undefined') {\r\n\t\t\tconst resizeObserver = new ResizeObserver((entries) => {\r\n\t\t\t\t// \"one entry per observed element\".\r\n\t\t\t\t// https://web.dev/resize-observer/\r\n\t\t\t\t// `entry.target === this.getElement()`.\r\n\t\t\t\tconst entry = entries[0]\r\n\t\t\t\t// // If `entry.contentBoxSize` property is supported by the web browser.\r\n\t\t\t\t// if (entry.contentBoxSize) {\r\n\t\t\t\t// \t// https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize\r\n\t\t\t\t// \tconst width = entry.contentBoxSize.inlineSize\r\n\t\t\t\t// \tconst height = entry.contentBoxSize.blockSize\r\n\t\t\t\t// }\r\n\t\t\t\tonResize()\r\n\t\t\t})\r\n\t\t\tconst element = this.getElement()\r\n\t\t\tresizeObserver.observe(element)\r\n\t\t\tunobserve = () => resizeObserver.unobserve(element)\r\n\t\t}\r\n\t\t// I guess, if window is resized, `onResize()` will be triggered twice:\r\n\t\t// once for window resize, and once for the scrollable container resize.\r\n\t\t// But `onResize()` also has an internal check: if the container size\r\n\t\t// hasn't changed since the previous time `onResize()` has been called,\r\n\t\t// then `onResize()` doesn't do anything, so, I guess, there shouldn't be\r\n\t\t// any \"performance implications\" of running the listener twice in such case.\r\n\t\tconst unlistenGlobalResize = addGlobalResizeListener(onResize, {\r\n\t\t\titemsContainerElement: this.getItemsContainerElement()\r\n\t\t})\r\n\t\treturn () => {\r\n\t\t\tif (unobserve) {\r\n\t\t\t\tunobserve()\r\n\t\t\t}\r\n\t\t\tunlistenGlobalResize()\r\n\t\t}\r\n\t}\r\n}\r\n\r\nexport class ScrollableWindowContainer extends ScrollableContainer {\r\n\t/**\r\n\t * Constructs a new window \"scrollable container\".\r\n\t * @param {func} getItemsContainerElement — Returns items \"container\" element.\r\n\t */\r\n\tconstructor(getItemsContainerElement) {\r\n\t\tsuper(() => window, getItemsContainerElement)\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the current scroll position.\r\n\t * @return {number}\r\n\t */\r\n\tgetScrollY() {\r\n\t\t// `window.scrollY` is not supported by Internet Explorer.\r\n\t\treturn window.pageYOffset\r\n\t}\r\n\r\n\t/**\r\n\t * Returns \"scrollable container\" width,\r\n\t * i.e. the available width for its content.\r\n\t * @return {number}\r\n\t */\r\n\tgetWidth() {\r\n\t\t// https://javascript.info/size-and-scroll-window\r\n\t\t// `<!DOCTYPE html>` may be required in order for this to work correctly.\r\n\t\t// Includes scrollbar (if any).\r\n\t\t// Correctly reflects page zoom in iOS Safari.\r\n\t\t// (scales screen width accordingly).\r\n\t\t// But, includes scrollbar (if any).\r\n\t\treturn window.innerWidth\r\n\t}\r\n\r\n\t/**\r\n\t * Returns the height of the \"scrollable container\" itself.\r\n\t * Not to be confused with the height of \"scrollable container\"'s content.\r\n\t * @return {number}\r\n\t */\r\n\tgetHeight() {\r\n\t\t// https://javascript.info/size-and-scroll-window\r\n\t\t// `<!DOCTYPE html>` is required in order for this to work correctly.\r\n\t\t// Without it, the returned height would be the height of the entire document.\r\n\t\t// Includes scrollbar (if any).\r\n\t\t// Supports iOS Safari's dynamically shown/hidden\r\n\t\t// top URL bar and bottom actions bar.\r\n\t\t// https://codesandbox.io/s/elegant-fog-iddrh\r\n\t\t// Tested in IE 11.\r\n\t\t// It also correctly reflects page zoom in iOS Safari.\r\n\t\t// (scales screen height accordingly).\r\n\t\t// But, includes scrollbar (if any).\r\n\t\treturn window.innerHeight\r\n\t}\r\n\r\n\t/**\r\n\t * Returns a \"top offset\" of an items container element\r\n\t * relative to the \"scrollable container\"'s top edge.\r\n\t * @return {number}\r\n\t */\r\n\tgetItemsContainerTopOffset() {\r\n\t\tconst borderTopWidth = document.clientTop || document.body.clientTop || 0\r\n\t\treturn this.getItemsContainerElement().getBoundingClientRect().top + this.getScrollY() - borderTopWidth\r\n\t}\r\n\r\n\t/**\r\n\t * Adds a \"resize\" event listener to the \"scrollable container\".\r\n\t * @param {onScroll} Should be called whenever the \"scrollable container\"'s width or height (potentially) changes.\r\n\t * @return {function} Returns a function that stops listening.\r\n\t */\r\n\tonResize(onResize) {\r\n\t\treturn addGlobalResizeListener(onResize, {\r\n\t\t\titemsContainerElement: this.getItemsContainerElement()\r\n\t\t})\r\n\t}\r\n\r\n\t// isVisible() {\r\n\t// \treturn true\r\n\t// }\r\n}\r\n\r\n/**\r\n * Adds a \"resize\" event listener to the `window`.\r\n * @param {onResize} Should be called whenever the \"scrollable container\"'s width or height (potentially) changes.\r\n * @param {Element} options.itemsContainerElement — The items \"container\" element, which is not the same as the \"scrollable container\" element. For example, \"scrollable container\" could be resized while the list element retaining its size. One such example is a user entering fullscreen mode on an HTML5 `<video/>` element: in that case, a \"resize\" event is triggered on a window, and window dimensions change to the user's screen size, but such \"resize\" event can be ignored because the list isn't visible until the user exits fullscreen mode.\r\n * @return {function} Returns a function that stops listening.\r\n */\r\nfunction addGlobalResizeListener(onResize, { itemsContainerElement }) {\r\n\tconst onResizeListener = () => {\r\n\t\t// By default, `VirtualScroller` always performs a re-layout\r\n\t\t// on window `resize` event. But browsers (Chrome, Firefox)\r\n\t\t// [trigger](https://developer.mozilla.org/en-US/docs/Web/API/Window/fullScreen#Notes)\r\n\t\t// window `resize` event also when a user switches into fullscreen mode:\r\n\t\t// for example, when a user is watching a video and double-clicks on it\r\n\t\t// to maximize it. And also when the user goes out of the fullscreen mode.\r\n\t\t// Each such fullscreen mode entering/exiting will trigger window `resize`\r\n\t\t// event that will it turn trigger a re-layout of `VirtualScroller`,\r\n\t\t// resulting in bad user experience. To prevent that, such cases are filtered out.\r\n\t\t// Some other workaround:\r\n\t\t// https://stackoverflow.com/questions/23770449/embedded-youtube-video-fullscreen-or-causing-resize\r\n\t\tif (document.fullscreenElement) {\r\n\t\t\t// If the fullscreened element doesn't contain the list\r\n\t\t\t// (and is not the list itself), then the layout hasn't been affected,\r\n\t\t\t// so don't perform a re-layout.\r\n\t\t\t//\r\n\t\t\t// For example, suppose there's a list of items, and some item contains a video.\r\n\t\t\t// If, upon clicking such video, it plays inline, and the user enters\r\n\t\t\t// fullscreen mode while playing such inline video, then the layout won't be\r\n\t\t\t// affected, and so such `resize` event should be ignored: when\r\n\t\t\t// `document.fullscreenElement` is in a separate \"branch\" relative to the\r\n\t\t\t// `container`.\r\n\t\t\t//\r\n\t\t\t// Another scenario: suppose that upon click, the video doesn't play inline,\r\n\t\t\t// but instead a \"Slideshow\" component is open, with the video shown at the\r\n\t\t\t// center of the screen in an overlay. If then the user enters fullscreen mode,\r\n\t\t\t// the layout wouldn't be affected too, so such `resize` event should also be\r\n\t\t\t// ignored: when `document.fullscreenElement` is inside the `container`.\r\n\t\t\t//\r\n\t\t\tif (document.fullscreenElement.contains(itemsContainerElement)) {\r\n\t\t\t\t// The element is either the `container`'s ancestor,\r\n\t\t\t\t// Or is the `container` itself.\r\n\t\t\t\t// (`a.contains(b)` includes the `a === b` case).\r\n\t\t\t\t// So the `resize` event will affect the `container`'s dimensions.\r\n\t\t\t} else {\r\n\t\t\t\t// The element is either inside the `container`,\r\n\t\t\t\t// Or is in a separate tree.\r\n\t\t\t\t// So the `resize` event won't affect the `container`'s dimensions.\r\n\t\t\t\treturn\r\n\t\t\t}\r\n\t\t}\r\n\t\tonResize()\r\n\t}\r\n\twindow.addEventListener('resize', onResizeListener)\r\n\treturn () => window.removeEventListener('resize', onResizeListener)\r\n}"],"mappings":"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"}