virtual-scroller 1.13.1 → 1.15.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 (231) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +825 -578
  3. package/bundle/index-dom-bypass.html +198 -0
  4. package/bundle/index-dom-grid.html +204 -0
  5. package/bundle/index-dom-scrollableContainer.html +215 -0
  6. package/bundle/index-dom-tbody-scrollableContainer.html +81 -0
  7. package/bundle/index-dom-tbody.html +65 -0
  8. package/bundle/index-dom.html +116 -83
  9. package/bundle/{index-bypass.html → index-react-bypass.html} +83 -78
  10. package/bundle/{index-grid.html → index-react-grid.html} +78 -91
  11. package/bundle/{index-scrollableContainer.html → index-react-scrollableContainer.html} +96 -91
  12. package/bundle/index-react-strictMode.html +199 -0
  13. package/bundle/index-react-tbody-scrollableContainer.html +96 -0
  14. package/bundle/index-react-tbody.html +80 -0
  15. package/bundle/{messages.js → items.js} +1 -1
  16. package/bundle/lib/babel.min.js +25 -0
  17. package/bundle/lib/prop-types.min.js +1 -0
  18. package/bundle/lib/react-dom.development.js +29924 -0
  19. package/bundle/lib/react-dom.production.min.js +267 -0
  20. package/bundle/lib/react.development.js +3343 -0
  21. package/bundle/lib/react.production.min.js +31 -0
  22. package/bundle/style.base.css +33 -0
  23. package/{website/style.css → bundle/style.list.css} +10 -43
  24. package/bundle/style.list.grid.css +23 -0
  25. package/bundle/virtual-scroller-dom.js +1 -1
  26. package/bundle/virtual-scroller-dom.js.map +1 -1
  27. package/bundle/virtual-scroller-react.js +1 -1
  28. package/bundle/virtual-scroller-react.js.map +1 -1
  29. package/bundle/virtual-scroller.js +1 -1
  30. package/bundle/virtual-scroller.js.map +1 -1
  31. package/commonjs/BeforeResize.js +1 -2
  32. package/commonjs/BeforeResize.js.map +1 -1
  33. package/commonjs/DOM/VirtualScroller.js +67 -44
  34. package/commonjs/DOM/VirtualScroller.js.map +1 -1
  35. package/commonjs/DOM/tbody.js +15 -15
  36. package/commonjs/DOM/tbody.js.map +1 -1
  37. package/commonjs/ItemHeights.js +10 -13
  38. package/commonjs/ItemHeights.js.map +1 -1
  39. package/commonjs/Layout.defaults.js +21 -0
  40. package/commonjs/Layout.defaults.js.map +1 -0
  41. package/commonjs/Layout.js +78 -67
  42. package/commonjs/Layout.js.map +1 -1
  43. package/commonjs/Layout.test.js +8 -4
  44. package/commonjs/Layout.test.js.map +1 -1
  45. package/commonjs/Scroll.js +3 -3
  46. package/commonjs/Scroll.js.map +1 -1
  47. package/commonjs/ScrollableContainerResizeHandler.js +4 -5
  48. package/commonjs/ScrollableContainerResizeHandler.js.map +1 -1
  49. package/commonjs/VirtualScroller.constructor.js +53 -31
  50. package/commonjs/VirtualScroller.constructor.js.map +1 -1
  51. package/commonjs/VirtualScroller.items.js +50 -4
  52. package/commonjs/VirtualScroller.items.js.map +1 -1
  53. package/commonjs/VirtualScroller.js +44 -28
  54. package/commonjs/VirtualScroller.js.map +1 -1
  55. package/commonjs/VirtualScroller.layout.js +42 -31
  56. package/commonjs/VirtualScroller.layout.js.map +1 -1
  57. package/commonjs/VirtualScroller.onContainerResize.js +1 -2
  58. package/commonjs/VirtualScroller.onContainerResize.js.map +1 -1
  59. package/commonjs/VirtualScroller.onRender.js +1 -1
  60. package/commonjs/VirtualScroller.onRender.js.map +1 -1
  61. package/commonjs/VirtualScroller.state.js +18 -9
  62. package/commonjs/VirtualScroller.state.js.map +1 -1
  63. package/commonjs/VirtualScroller.verticalSpacing.js +39 -6
  64. package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -1
  65. package/commonjs/react/VirtualScroller.js +98 -37
  66. package/commonjs/react/VirtualScroller.js.map +1 -1
  67. package/commonjs/react/useClassName.js +2 -2
  68. package/commonjs/react/useClassName.js.map +1 -1
  69. package/commonjs/react/useForwardedRef.js +50 -0
  70. package/commonjs/react/useForwardedRef.js.map +1 -0
  71. package/commonjs/react/useInstanceMethods.js +4 -4
  72. package/commonjs/react/useInstanceMethods.js.map +1 -1
  73. package/commonjs/react/useItemKeys.js +28 -5
  74. package/commonjs/react/useItemKeys.js.map +1 -1
  75. package/commonjs/react/useOnItemHeightDidChange.js +28 -12
  76. package/commonjs/react/useOnItemHeightDidChange.js.map +1 -1
  77. package/commonjs/react/useSetItemState.js +31 -12
  78. package/commonjs/react/useSetItemState.js.map +1 -1
  79. package/commonjs/react/useState.js +10 -11
  80. package/commonjs/react/useState.js.map +1 -1
  81. package/commonjs/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +3 -3
  82. package/commonjs/react/useStateWithRepeatableRead.js.map +1 -0
  83. package/commonjs/react/useStyle.js +10 -4
  84. package/commonjs/react/useStyle.js.map +1 -1
  85. package/commonjs/react/useValidateTableBodyItemsContainer.js +24 -0
  86. package/commonjs/react/useValidateTableBodyItemsContainer.js.map +1 -0
  87. package/commonjs/react/useVirtualScroller.js +12 -14
  88. package/commonjs/react/useVirtualScroller.js.map +1 -1
  89. package/commonjs/test/ItemsContainer.js +10 -10
  90. package/commonjs/test/ItemsContainer.js.map +1 -1
  91. package/commonjs/test/VirtualScroller.js +25 -10
  92. package/commonjs/test/VirtualScroller.js.map +1 -1
  93. package/dom/index.d.ts +11 -9
  94. package/index.d.ts +19 -9
  95. package/modules/BeforeResize.js +1 -2
  96. package/modules/BeforeResize.js.map +1 -1
  97. package/modules/DOM/VirtualScroller.js +67 -44
  98. package/modules/DOM/VirtualScroller.js.map +1 -1
  99. package/modules/DOM/tbody.js +14 -13
  100. package/modules/DOM/tbody.js.map +1 -1
  101. package/modules/ItemHeights.js +11 -14
  102. package/modules/ItemHeights.js.map +1 -1
  103. package/modules/Layout.defaults.js +11 -0
  104. package/modules/Layout.defaults.js.map +1 -0
  105. package/modules/Layout.js +77 -67
  106. package/modules/Layout.js.map +1 -1
  107. package/modules/Layout.test.js +8 -4
  108. package/modules/Layout.test.js.map +1 -1
  109. package/modules/Scroll.js +3 -3
  110. package/modules/Scroll.js.map +1 -1
  111. package/modules/ScrollableContainerResizeHandler.js +4 -5
  112. package/modules/ScrollableContainerResizeHandler.js.map +1 -1
  113. package/modules/VirtualScroller.constructor.js +53 -31
  114. package/modules/VirtualScroller.constructor.js.map +1 -1
  115. package/modules/VirtualScroller.items.js +51 -5
  116. package/modules/VirtualScroller.items.js.map +1 -1
  117. package/modules/VirtualScroller.js +44 -28
  118. package/modules/VirtualScroller.js.map +1 -1
  119. package/modules/VirtualScroller.layout.js +42 -31
  120. package/modules/VirtualScroller.layout.js.map +1 -1
  121. package/modules/VirtualScroller.onContainerResize.js +1 -2
  122. package/modules/VirtualScroller.onContainerResize.js.map +1 -1
  123. package/modules/VirtualScroller.onRender.js +1 -1
  124. package/modules/VirtualScroller.onRender.js.map +1 -1
  125. package/modules/VirtualScroller.state.js +18 -9
  126. package/modules/VirtualScroller.state.js.map +1 -1
  127. package/modules/VirtualScroller.verticalSpacing.js +38 -6
  128. package/modules/VirtualScroller.verticalSpacing.js.map +1 -1
  129. package/modules/react/VirtualScroller.js +97 -38
  130. package/modules/react/VirtualScroller.js.map +1 -1
  131. package/modules/react/useClassName.js +3 -3
  132. package/modules/react/useClassName.js.map +1 -1
  133. package/modules/react/useForwardedRef.js +42 -0
  134. package/modules/react/useForwardedRef.js.map +1 -0
  135. package/modules/react/useInstanceMethods.js +4 -4
  136. package/modules/react/useInstanceMethods.js.map +1 -1
  137. package/modules/react/useItemKeys.js +28 -5
  138. package/modules/react/useItemKeys.js.map +1 -1
  139. package/modules/react/useOnItemHeightDidChange.js +28 -12
  140. package/modules/react/useOnItemHeightDidChange.js.map +1 -1
  141. package/modules/react/useSetItemState.js +31 -12
  142. package/modules/react/useSetItemState.js.map +1 -1
  143. package/modules/react/useState.js +10 -11
  144. package/modules/react/useState.js.map +1 -1
  145. package/modules/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +2 -2
  146. package/modules/react/useStateWithRepeatableRead.js.map +1 -0
  147. package/modules/react/useStyle.js +10 -4
  148. package/modules/react/useStyle.js.map +1 -1
  149. package/modules/react/useValidateTableBodyItemsContainer.js +16 -0
  150. package/modules/react/useValidateTableBodyItemsContainer.js.map +1 -0
  151. package/modules/react/useVirtualScroller.js +10 -12
  152. package/modules/react/useVirtualScroller.js.map +1 -1
  153. package/modules/test/ItemsContainer.js +10 -10
  154. package/modules/test/ItemsContainer.js.map +1 -1
  155. package/modules/test/VirtualScroller.js +25 -10
  156. package/modules/test/VirtualScroller.js.map +1 -1
  157. package/package.json +1 -1
  158. package/react/as.d.ts +42 -0
  159. package/react/index.d.ts +204 -63
  160. package/source/BeforeResize.js +1 -2
  161. package/source/DOM/VirtualScroller.js +65 -40
  162. package/source/DOM/tbody.js +15 -14
  163. package/source/ItemHeights.js +11 -12
  164. package/source/Layout.defaults.js +8 -0
  165. package/source/Layout.js +69 -56
  166. package/source/Layout.test.js +7 -2
  167. package/source/Scroll.js +3 -3
  168. package/source/ScrollableContainerResizeHandler.js +4 -4
  169. package/source/VirtualScroller.constructor.js +40 -31
  170. package/source/VirtualScroller.items.js +47 -2
  171. package/source/VirtualScroller.js +49 -27
  172. package/source/VirtualScroller.layout.js +43 -30
  173. package/source/VirtualScroller.onContainerResize.js +1 -2
  174. package/source/VirtualScroller.onRender.js +1 -1
  175. package/source/VirtualScroller.state.js +18 -11
  176. package/source/VirtualScroller.verticalSpacing.js +32 -6
  177. package/source/react/VirtualScroller.js +111 -36
  178. package/source/react/useClassName.js +3 -3
  179. package/source/react/useForwardedRef.js +39 -0
  180. package/source/react/useInstanceMethods.js +12 -4
  181. package/source/react/useItemKeys.js +22 -4
  182. package/source/react/useOnItemHeightDidChange.js +29 -10
  183. package/source/react/useSetItemState.js +32 -10
  184. package/source/react/useState.js +7 -8
  185. package/source/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +1 -1
  186. package/source/react/useStyle.js +3 -2
  187. package/source/react/useValidateTableBodyItemsContainer.js +16 -0
  188. package/source/react/useVirtualScroller.js +4 -6
  189. package/source/test/ItemsContainer.js +10 -10
  190. package/source/test/VirtualScroller.js +16 -10
  191. package/website/index-dom-bypass.html +198 -0
  192. package/website/index-dom-grid.html +204 -0
  193. package/website/index-dom-scrollableContainer.html +215 -0
  194. package/website/index-dom-tbody-scrollableContainer.html +81 -0
  195. package/website/index-dom-tbody.html +65 -0
  196. package/website/index-dom.html +117 -84
  197. package/website/index-react-bypass.html +200 -0
  198. package/website/{index-grid.html → index-react-grid.html} +79 -92
  199. package/website/index-react-scrollableContainer.html +213 -0
  200. package/website/index-react-strictMode.html +199 -0
  201. package/website/index-react-tbody-scrollableContainer.html +96 -0
  202. package/website/index-react-tbody.html +80 -0
  203. package/website/{index-bypass.html → index-react.html} +84 -70
  204. package/website/index.html +84 -69
  205. package/website/{messages.js → items.js} +1 -1
  206. package/website/lib/babel.min.js +25 -0
  207. package/website/lib/prop-types.min.js +1 -0
  208. package/website/lib/react-dom.development.js +29924 -0
  209. package/website/lib/react-dom.production.min.js +267 -0
  210. package/website/lib/react.development.js +3343 -0
  211. package/website/lib/react.production.min.js +31 -0
  212. package/website/style.base.css +33 -0
  213. package/website/style.list.css +92 -0
  214. package/website/style.list.grid.css +23 -0
  215. package/bundle/index-tbody-scrollableContainer.html +0 -70
  216. package/bundle/index-tbody.html +0 -57
  217. package/bundle/on-scroll-to-dom.js +0 -2
  218. package/bundle/on-scroll-to-dom.js.map +0 -1
  219. package/bundle/on-scroll-to-react.js +0 -2
  220. package/bundle/on-scroll-to-react.js.map +0 -1
  221. package/bundle/on-scroll-to.js +0 -2
  222. package/bundle/on-scroll-to.js.map +0 -1
  223. package/commonjs/react/useStateNoStaleBug.js.map +0 -1
  224. package/modules/react/useStateNoStaleBug.js.map +0 -1
  225. package/website/index-scrollableContainer.html +0 -208
  226. package/website/index-tbody-scrollableContainer.html +0 -70
  227. package/website/index-tbody.html +0 -57
  228. package/website/lib/on-scroll-to-dom.js +0 -2
  229. package/website/lib/on-scroll-to-dom.js.map +0 -1
  230. package/website/lib/on-scroll-to-react.js +0 -2
  231. package/website/lib/on-scroll-to-react.js.map +0 -1
@@ -6,58 +6,36 @@
6
6
  <!-- Fix document width for mobile devices. -->
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
8
 
9
- <title>React VirtualScroller Demo (Grid Layout)</title>
9
+ <title>VirtualScroller (React) (Grid)</title>
10
10
 
11
- <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
12
- <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
13
- <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js"></script>
14
- <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
11
+ <script src="./lib/react.development.js"></script>
12
+ <script src="./lib/react-dom.development.js"></script>
13
+ <script src="./lib/prop-types.min.js"></script>
14
+ <script src="./lib/babel.min.js"></script>
15
15
 
16
16
  <script src="./virtual-scroller-react.js"></script>
17
- <script src="./lib/on-scroll-to-react.js"></script>
18
- <script src="./messages.js"></script>
17
+ <script src="./items.js"></script>
19
18
 
20
- <link rel="stylesheet" href="./style.css"/>
21
-
22
- <style>
23
- #messages {
24
- display: flex;
25
- flex-wrap: wrap;
26
- }
27
- .feed-message {
28
- flex-basis: 33.333333%;
29
- box-sizing: border-box;
30
- border: 2px solid rgb(230, 236, 240);
31
- }
32
- .container {
33
- max-width: 1280px;
34
- }
35
- @media screen and (max-width: 1280px) {
36
- .container {
37
- max-width: 720px;
38
- }
39
- .feed-message {
40
- flex-basis: 100%;
41
- }
42
- }
43
- </style>
19
+ <link rel="stylesheet" href="./style.base.css"/>
20
+ <link rel="stylesheet" href="./style.list.css"/>
21
+ <link rel="stylesheet" href="./style.list.grid.css"/>
44
22
  </head>
45
23
 
46
24
  <body>
47
25
  <!-- http://tholman.com/github-corners/ -->
48
- <a title="Go to GitLab repo" href="https://gitlab.com/catamphetamine/virtual-scroller" class="github-corner" aria-label="View source on GitLab"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
26
+ <a title="Go to GitHub repo" href="https://gitlab.com/catamphetamine/virtual-scroller" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
49
27
 
50
28
  <div id="root"></div>
51
29
 
52
30
  <script>
53
31
  // Enable debug output to console.
54
32
  window.VirtualScrollerDebug = true
55
- // Whether "dynamically loaded list" mode is enabled.
56
- window.dynamic = new URL(window.location).searchParams.get('dynamic')
33
+ // Pass `?pagination=✓` URL query parameter to enable pagination.
34
+ window.PAGINATION = Boolean(new URL(window.location).searchParams.get('pagination'))
57
35
  </script>
58
36
 
59
37
  <script type="text/babel">
60
- const BATCH_SIZE = 6
38
+ const BATCH_SIZE = 6
61
39
  const COLUMNS_COUNT = 3
62
40
 
63
41
  function getColumnsCount(container) {
@@ -67,58 +45,71 @@
67
45
  return 1
68
46
  }
69
47
 
70
- class FeedMessages extends React.Component {
48
+ function getInitialState(items) {
49
+ if (window.PAGINATION) {
50
+ const fromIndex = Math.floor((items.length - BATCH_SIZE) / 2 / COLUMNS_COUNT) * COLUMNS_COUNT
51
+ const toIndex = fromIndex + BATCH_SIZE - 1
52
+ return {
53
+ fromIndex,
54
+ toIndex,
55
+ items: items.slice(fromIndex, toIndex + 1)
56
+ }
57
+ } else {
58
+ return {
59
+ fromIndex: 0,
60
+ toIndex: items.length,
61
+ items: items
62
+ }
63
+ }
64
+ }
65
+
66
+ function onShowPrevious(items, getState, setState) {
67
+ let { fromIndex } = getState()
68
+ const { toIndex } = getState()
69
+ fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
70
+ setState({
71
+ fromIndex,
72
+ items: items.slice(fromIndex, toIndex + 1)
73
+ })
74
+ }
75
+
76
+ function onShowNext(items, getState, setState) {
77
+ const { fromIndex } = getState()
78
+ let { toIndex } = getState()
79
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
80
+ setState({
81
+ toIndex,
82
+ items: items.slice(fromIndex, toIndex + 1)
83
+ })
84
+ }
85
+
86
+ class VirtualScrollerDemo extends React.Component {
71
87
  constructor(props) {
72
88
  super(props)
73
- const { messages } = this.props
74
- if (window.dynamic) {
75
- const fromIndex = Math.floor((messages.length - BATCH_SIZE) / 2 / COLUMNS_COUNT) * COLUMNS_COUNT
76
- const toIndex = fromIndex + BATCH_SIZE - 1
77
- this.state = {
78
- fromIndex,
79
- toIndex,
80
- messages: messages.slice(fromIndex, toIndex + 1)
81
- }
82
- } else {
83
- this.state = {
84
- fromIndex: 0,
85
- toIndex: messages.length,
86
- messages
87
- }
88
- }
89
+
90
+ this.state = getInitialState(ITEMS)
89
91
  }
90
92
 
93
+ getState = () => this.state
94
+
91
95
  onShowPrevious = () => {
92
- const { messages } = this.props
93
- let { fromIndex } = this.state
94
- const { toIndex } = this.state
95
- fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
96
- this.setState({
97
- fromIndex,
98
- messages: messages.slice(fromIndex, toIndex + 1)
99
- })
96
+ onShowPrevious(ITEMS, this.getState, this.setState.bind(this))
100
97
  }
101
98
 
102
99
  onShowNext = () => {
103
- const { messages } = this.props
104
- const { fromIndex } = this.state
105
- let { toIndex } = this.state
106
- toIndex = Math.min(toIndex + BATCH_SIZE, messages.length - 1)
107
- this.setState({
108
- toIndex,
109
- messages: messages.slice(fromIndex, toIndex + 1)
110
- })
100
+ onShowNext(ITEMS, this.getState, this.setState.bind(this))
111
101
  }
112
102
 
113
103
  render() {
114
104
  const {
115
105
  fromIndex,
116
106
  toIndex,
117
- messages
107
+ items
118
108
  } = this.state
109
+
119
110
  return (
120
111
  <React.Fragment>
121
- {window.dynamic && fromIndex > 0 &&
112
+ {window.PAGINATION && fromIndex > 0 &&
122
113
  <button
123
114
  type="button"
124
115
  onClick={this.onShowPrevious}
@@ -127,12 +118,13 @@
127
118
  </button>
128
119
  }
129
120
  <VirtualScroller
130
- id="messages"
131
- items={messages}
132
- itemComponent={Message}
121
+ id="list"
122
+ items={items}
123
+ itemComponent={Item}
133
124
  preserveScrollPositionOnPrependItems
134
- getColumnsCount={getColumnsCount}/>
135
- {window.dynamic && toIndex < this.props.messages.length - 1 &&
125
+ getColumnsCount={getColumnsCount}
126
+ />
127
+ {window.PAGINATION && toIndex < ITEMS.length - 1 &&
136
128
  <button
137
129
  type="button"
138
130
  onClick={this.onShowNext}
@@ -145,25 +137,23 @@
145
137
  }
146
138
  }
147
139
 
148
- const message = PropTypes.shape({
140
+ const item = PropTypes.shape({
149
141
  username: PropTypes.string.isRequired,
150
142
  date: PropTypes.instanceOf(Date).isRequired,
151
143
  text: PropTypes.string.isRequired
152
144
  })
153
145
 
154
- FeedMessages.propTypes = {
155
- messages: PropTypes.arrayOf(message).isRequired
156
- }
146
+ function Item(props) {
147
+ const { children: item } = props
157
148
 
158
- function Message(props) {
159
- const { item: message } = props
160
149
  const {
161
150
  username,
162
151
  date,
163
152
  text
164
- } = message
153
+ } = item
154
+
165
155
  return (
166
- <article className="feed-message">
156
+ <article className="list-item">
167
157
  <a target="_blank" href={`https://twitter.com/${username}`}>
168
158
  @{username}
169
159
  </a>
@@ -177,11 +167,11 @@
177
167
  )
178
168
  }
179
169
 
180
- Message.propTypes = {
181
- item: message.isRequired
170
+ Item.propTypes = {
171
+ children: item.isRequired
182
172
  }
183
173
 
184
- class Feed extends React.Component {
174
+ class Demo extends React.Component {
185
175
  render() {
186
176
  return (
187
177
  <section className="container">
@@ -189,8 +179,7 @@
189
179
  <TwitterLogo/>
190
180
  Latest Tweets on #politics
191
181
  </h1>
192
- <FeedMessages
193
- messages={messages}/>
182
+ <VirtualScrollerDemo/>
194
183
  <footer>
195
184
  © Twitter Inc., 2019
196
185
  </footer>
@@ -207,10 +196,8 @@
207
196
  )
208
197
  }
209
198
 
210
- ReactDOM.render(
211
- <Feed/>,
212
- document.getElementById('root')
213
- )
199
+ const root = ReactDOM.createRoot(document.getElementById('root'))
200
+ root.render(<Demo/>)
214
201
  </script>
215
202
  </body>
216
203
  </html>
@@ -0,0 +1,213 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <!-- Fix encoding. -->
5
+ <meta charset="utf-8">
6
+ <!-- Fix document width for mobile devices. -->
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+
9
+ <title>VirtualScroller (React) (Scrollable Container)</title>
10
+
11
+ <script src="./lib/react.development.js"></script>
12
+ <script src="./lib/react-dom.development.js"></script>
13
+ <script src="./lib/prop-types.min.js"></script>
14
+ <script src="./lib/babel.min.js"></script>
15
+
16
+ <script src="./virtual-scroller-react.js"></script>
17
+ <script src="./items.js"></script>
18
+
19
+ <link rel="stylesheet" href="./style.base.css"/>
20
+ <link rel="stylesheet" href="./style.list.css"/>
21
+
22
+ <style>
23
+ #scrollable-container {
24
+ margin-top: 20vh;
25
+ margin-bottom: 20vh;
26
+ max-height: 60vh;
27
+ overflow: auto;
28
+ }
29
+ </style>
30
+ </head>
31
+
32
+ <body>
33
+ <!-- http://tholman.com/github-corners/ -->
34
+ <a title="Go to GitHub repo" href="https://gitlab.com/catamphetamine/virtual-scroller" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
35
+
36
+ <div id="root"></div>
37
+
38
+ <script>
39
+ // Enable debug output to console.
40
+ window.VirtualScrollerDebug = true
41
+ // Pass `?pagination=✓` URL query parameter to enable pagination.
42
+ window.PAGINATION = Boolean(new URL(window.location).searchParams.get('pagination'))
43
+ </script>
44
+
45
+ <script type="text/babel">
46
+ const BATCH_SIZE = 6
47
+ const COLUMNS_COUNT = 1
48
+
49
+ function getColumnsCount(container) {
50
+ return 1
51
+ }
52
+
53
+ function getInitialState(items) {
54
+ if (window.PAGINATION) {
55
+ const fromIndex = Math.floor((items.length - BATCH_SIZE) / 2 / COLUMNS_COUNT) * COLUMNS_COUNT
56
+ const toIndex = fromIndex + BATCH_SIZE - 1
57
+ return {
58
+ fromIndex,
59
+ toIndex,
60
+ items: items.slice(fromIndex, toIndex + 1)
61
+ }
62
+ } else {
63
+ return {
64
+ fromIndex: 0,
65
+ toIndex: items.length,
66
+ items: items
67
+ }
68
+ }
69
+ }
70
+
71
+ function onShowPrevious(items, getState, setState) {
72
+ let { fromIndex } = getState()
73
+ const { toIndex } = getState()
74
+ fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
75
+ setState({
76
+ fromIndex,
77
+ items: items.slice(fromIndex, toIndex + 1)
78
+ })
79
+ }
80
+
81
+ function onShowNext(items, getState, setState) {
82
+ const { fromIndex } = getState()
83
+ let { toIndex } = getState()
84
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
85
+ setState({
86
+ toIndex,
87
+ items: items.slice(fromIndex, toIndex + 1)
88
+ })
89
+ }
90
+
91
+ function getScrollableContainer() {
92
+ return document.getElementById('scrollable-container')
93
+ }
94
+
95
+ class VirtualScrollerDemo extends React.Component {
96
+ constructor(props) {
97
+ super(props)
98
+
99
+ this.state = getInitialState(ITEMS)
100
+ }
101
+
102
+ getState = () => this.state
103
+
104
+ onShowPrevious = () => {
105
+ onShowPrevious(ITEMS, this.getState, this.setState.bind(this))
106
+ }
107
+
108
+ onShowNext = () => {
109
+ onShowNext(ITEMS, this.getState, this.setState.bind(this))
110
+ }
111
+
112
+ render() {
113
+ const {
114
+ fromIndex,
115
+ toIndex,
116
+ items
117
+ } = this.state
118
+
119
+ return (
120
+ <div id="scrollable-container">
121
+ {window.PAGINATION && fromIndex > 0 &&
122
+ <button
123
+ type="button"
124
+ onClick={this.onShowPrevious}
125
+ className="load-items-button">
126
+ Show previous
127
+ </button>
128
+ }
129
+ <VirtualScroller
130
+ id="list"
131
+ items={items}
132
+ itemComponent={Item}
133
+ preserveScrollPositionOnPrependItems
134
+ getColumnsCount={getColumnsCount}
135
+ getScrollableContainer={getScrollableContainer}
136
+ />
137
+ {window.PAGINATION && toIndex < ITEMS.length - 1 &&
138
+ <button
139
+ type="button"
140
+ onClick={this.onShowNext}
141
+ className="load-items-button">
142
+ Show next
143
+ </button>
144
+ }
145
+ </div>
146
+ )
147
+ }
148
+ }
149
+
150
+ const item = PropTypes.shape({
151
+ username: PropTypes.string.isRequired,
152
+ date: PropTypes.instanceOf(Date).isRequired,
153
+ text: PropTypes.string.isRequired
154
+ })
155
+
156
+ function Item(props) {
157
+ const { children: item } = props
158
+
159
+ const {
160
+ username,
161
+ date,
162
+ text
163
+ } = item
164
+
165
+ return (
166
+ <article className="list-item">
167
+ <a target="_blank" href={`https://twitter.com/${username}`}>
168
+ @{username}
169
+ </a>
170
+ <time dateTime={date.toISOString()}>
171
+ {date.getMonth() + 1}/{date.getDate()}/{date.getFullYear()}
172
+ </time>
173
+ <p>
174
+ {text}
175
+ </p>
176
+ </article>
177
+ )
178
+ }
179
+
180
+ Item.propTypes = {
181
+ children: item.isRequired
182
+ }
183
+
184
+ class Demo extends React.Component {
185
+ render() {
186
+ return (
187
+ <section className="container">
188
+ <h1>
189
+ <TwitterLogo/>
190
+ Latest Tweets on #politics
191
+ </h1>
192
+ <VirtualScrollerDemo/>
193
+ <footer>
194
+ © Twitter Inc., 2019
195
+ </footer>
196
+ </section>
197
+ )
198
+ }
199
+ }
200
+
201
+ function TwitterLogo() {
202
+ return (
203
+ <svg className="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
204
+ <path fill="#00AAEC" fillRule="evenodd" d="M128 23.294a51.28 51.28 0 0 1-15.079 4.237c5.424-3.328 9.587-8.606 11.548-14.892a51.718 51.718 0 0 1-16.687 6.526c-4.778-5.231-11.608-8.498-19.166-8.498-14.493 0-26.251 12.057-26.251 26.927 0 2.111.225 4.16.676 6.133-21.824-1.126-41.17-11.835-54.131-28.145a27.422 27.422 0 0 0-3.554 13.552c0 9.338 4.636 17.581 11.683 22.412-4.297-.131-8.355-1.356-11.901-3.359v.331c0 13.051 9.053 23.937 21.074 26.403-2.201.632-4.523.948-6.92.948-1.69 0-3.343-.162-4.944-.478 3.343 10.694 13.035 18.483 24.53 18.691-8.986 7.227-20.315 11.533-32.614 11.533-2.119 0-4.215-.123-6.266-.37 11.623 7.627 25.432 12.088 40.255 12.088 48.309 0 74.717-41.026 74.717-76.612a89.39 89.39 0 0 0-.068-3.49A53.862 53.862 0 0 0 128 23.294" clipRule="evenodd"/>
205
+ </svg>
206
+ )
207
+ }
208
+
209
+ const root = ReactDOM.createRoot(document.getElementById('root'))
210
+ root.render(<Demo/>)
211
+ </script>
212
+ </body>
213
+ </html>
@@ -0,0 +1,199 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <!-- Fix encoding. -->
5
+ <meta charset="utf-8">
6
+ <!-- Fix document width for mobile devices. -->
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
+
9
+ <title>VirtualScroller (React) (<StrictMode/>)</title>
10
+
11
+ <script src="./lib/react.development.js"></script>
12
+ <script src="./lib/react-dom.development.js"></script>
13
+ <script src="./lib/prop-types.min.js"></script>
14
+ <script src="./lib/babel.min.js"></script>
15
+
16
+ <script src="./virtual-scroller-react.js"></script>
17
+ <script src="./items.js"></script>
18
+
19
+ <link rel="stylesheet" href="./style.base.css"/>
20
+ <link rel="stylesheet" href="./style.list.css"/>
21
+ </head>
22
+
23
+ <body>
24
+ <!-- http://tholman.com/github-corners/ -->
25
+ <a title="Go to GitHub repo" href="https://gitlab.com/catamphetamine/virtual-scroller" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
26
+
27
+ <div id="root"></div>
28
+
29
+ <script>
30
+ // Enable debug output to console.
31
+ window.VirtualScrollerDebug = true
32
+ // Pass `?pagination=✓` URL query parameter to enable pagination.
33
+ window.PAGINATION = Boolean(new URL(window.location).searchParams.get('pagination'))
34
+ </script>
35
+
36
+ <script type="text/babel">
37
+ const BATCH_SIZE = 6
38
+ const COLUMNS_COUNT = 1
39
+
40
+ function getColumnsCount(container) {
41
+ return 1
42
+ }
43
+
44
+ function getInitialState(items) {
45
+ if (window.PAGINATION) {
46
+ const fromIndex = Math.floor((items.length - BATCH_SIZE) / 2 / COLUMNS_COUNT) * COLUMNS_COUNT
47
+ const toIndex = fromIndex + BATCH_SIZE - 1
48
+ return {
49
+ fromIndex,
50
+ toIndex,
51
+ items: items.slice(fromIndex, toIndex + 1)
52
+ }
53
+ } else {
54
+ return {
55
+ fromIndex: 0,
56
+ toIndex: items.length,
57
+ items: items
58
+ }
59
+ }
60
+ }
61
+
62
+ function onShowPrevious(items, getState, setState) {
63
+ let { fromIndex } = getState()
64
+ const { toIndex } = getState()
65
+ fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
66
+ setState({
67
+ fromIndex,
68
+ items: items.slice(fromIndex, toIndex + 1)
69
+ })
70
+ }
71
+
72
+ function onShowNext(items, getState, setState) {
73
+ const { fromIndex } = getState()
74
+ let { toIndex } = getState()
75
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
76
+ setState({
77
+ toIndex,
78
+ items: items.slice(fromIndex, toIndex + 1)
79
+ })
80
+ }
81
+
82
+ class VirtualScrollerDemo extends React.Component {
83
+ constructor(props) {
84
+ super(props)
85
+
86
+ this.state = getInitialState(ITEMS)
87
+ }
88
+
89
+ getState = () => this.state
90
+
91
+ onShowPrevious = () => {
92
+ onShowPrevious(ITEMS, this.getState, this.setState.bind(this))
93
+ }
94
+
95
+ onShowNext = () => {
96
+ onShowNext(ITEMS, this.getState, this.setState.bind(this))
97
+ }
98
+
99
+ render() {
100
+ const {
101
+ fromIndex,
102
+ toIndex,
103
+ items
104
+ } = this.state
105
+
106
+ return (
107
+ <React.Fragment>
108
+ {window.PAGINATION && fromIndex > 0 &&
109
+ <button
110
+ type="button"
111
+ onClick={this.onShowPrevious}
112
+ className="load-items-button">
113
+ Show previous
114
+ </button>
115
+ }
116
+ <VirtualScroller
117
+ id="list"
118
+ items={items}
119
+ itemComponent={Item}
120
+ preserveScrollPositionOnPrependItems
121
+ getColumnsCount={getColumnsCount}
122
+ />
123
+ {window.PAGINATION && toIndex < ITEMS.length - 1 &&
124
+ <button
125
+ type="button"
126
+ onClick={this.onShowNext}
127
+ className="load-items-button">
128
+ Show next
129
+ </button>
130
+ }
131
+ </React.Fragment>
132
+ )
133
+ }
134
+ }
135
+
136
+ const item = PropTypes.shape({
137
+ username: PropTypes.string.isRequired,
138
+ date: PropTypes.instanceOf(Date).isRequired,
139
+ text: PropTypes.string.isRequired
140
+ })
141
+
142
+ function Item(props) {
143
+ const { children: item } = props
144
+
145
+ const {
146
+ username,
147
+ date,
148
+ text
149
+ } = item
150
+
151
+ return (
152
+ <article className="list-item">
153
+ <a target="_blank" href={`https://twitter.com/${username}`}>
154
+ @{username}
155
+ </a>
156
+ <time dateTime={date.toISOString()}>
157
+ {date.getMonth() + 1}/{date.getDate()}/{date.getFullYear()}
158
+ </time>
159
+ <p>
160
+ {text}
161
+ </p>
162
+ </article>
163
+ )
164
+ }
165
+
166
+ Item.propTypes = {
167
+ children: item.isRequired
168
+ }
169
+
170
+ class Demo extends React.Component {
171
+ render() {
172
+ return (
173
+ <section className="container">
174
+ <h1>
175
+ <TwitterLogo/>
176
+ Latest Tweets on #politics
177
+ </h1>
178
+ <VirtualScrollerDemo/>
179
+ <footer>
180
+ © Twitter Inc., 2019
181
+ </footer>
182
+ </section>
183
+ )
184
+ }
185
+ }
186
+
187
+ function TwitterLogo() {
188
+ return (
189
+ <svg className="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
190
+ <path fill="#00AAEC" fillRule="evenodd" d="M128 23.294a51.28 51.28 0 0 1-15.079 4.237c5.424-3.328 9.587-8.606 11.548-14.892a51.718 51.718 0 0 1-16.687 6.526c-4.778-5.231-11.608-8.498-19.166-8.498-14.493 0-26.251 12.057-26.251 26.927 0 2.111.225 4.16.676 6.133-21.824-1.126-41.17-11.835-54.131-28.145a27.422 27.422 0 0 0-3.554 13.552c0 9.338 4.636 17.581 11.683 22.412-4.297-.131-8.355-1.356-11.901-3.359v.331c0 13.051 9.053 23.937 21.074 26.403-2.201.632-4.523.948-6.92.948-1.69 0-3.343-.162-4.944-.478 3.343 10.694 13.035 18.483 24.53 18.691-8.986 7.227-20.315 11.533-32.614 11.533-2.119 0-4.215-.123-6.266-.37 11.623 7.627 25.432 12.088 40.255 12.088 48.309 0 74.717-41.026 74.717-76.612a89.39 89.39 0 0 0-.068-3.49A53.862 53.862 0 0 0 128 23.294" clipRule="evenodd"/>
191
+ </svg>
192
+ )
193
+ }
194
+
195
+ const root = ReactDOM.createRoot(document.getElementById('root'))
196
+ root.render(<React.StrictMode><Demo/></React.StrictMode>)
197
+ </script>
198
+ </body>
199
+ </html>