virtual-scroller 1.14.0 → 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 (216) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +309 -250
  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 +115 -84
  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 +7 -13
  34. package/commonjs/DOM/VirtualScroller.js.map +1 -1
  35. package/commonjs/DOM/tbody.js +6 -6
  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 +75 -64
  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/VirtualScroller.constructor.js +38 -4
  46. package/commonjs/VirtualScroller.constructor.js.map +1 -1
  47. package/commonjs/VirtualScroller.items.js +50 -4
  48. package/commonjs/VirtualScroller.items.js.map +1 -1
  49. package/commonjs/VirtualScroller.js +23 -14
  50. package/commonjs/VirtualScroller.js.map +1 -1
  51. package/commonjs/VirtualScroller.layout.js +40 -29
  52. package/commonjs/VirtualScroller.layout.js.map +1 -1
  53. package/commonjs/VirtualScroller.onContainerResize.js +1 -2
  54. package/commonjs/VirtualScroller.onContainerResize.js.map +1 -1
  55. package/commonjs/VirtualScroller.state.js +10 -9
  56. package/commonjs/VirtualScroller.state.js.map +1 -1
  57. package/commonjs/VirtualScroller.verticalSpacing.js +39 -6
  58. package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -1
  59. package/commonjs/react/VirtualScroller.js +85 -34
  60. package/commonjs/react/VirtualScroller.js.map +1 -1
  61. package/commonjs/react/useClassName.js +2 -2
  62. package/commonjs/react/useClassName.js.map +1 -1
  63. package/commonjs/react/useForwardedRef.js +50 -0
  64. package/commonjs/react/useForwardedRef.js.map +1 -0
  65. package/commonjs/react/useInstanceMethods.js +4 -4
  66. package/commonjs/react/useInstanceMethods.js.map +1 -1
  67. package/commonjs/react/useItemKeys.js +28 -5
  68. package/commonjs/react/useItemKeys.js.map +1 -1
  69. package/commonjs/react/useOnItemHeightDidChange.js +28 -12
  70. package/commonjs/react/useOnItemHeightDidChange.js.map +1 -1
  71. package/commonjs/react/useSetItemState.js +31 -12
  72. package/commonjs/react/useSetItemState.js.map +1 -1
  73. package/commonjs/react/useState.js +9 -9
  74. package/commonjs/react/useState.js.map +1 -1
  75. package/commonjs/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +3 -3
  76. package/commonjs/react/useStateWithRepeatableRead.js.map +1 -0
  77. package/commonjs/react/useStyle.js +10 -4
  78. package/commonjs/react/useStyle.js.map +1 -1
  79. package/commonjs/react/useValidateTableBodyItemsContainer.js +24 -0
  80. package/commonjs/react/useValidateTableBodyItemsContainer.js.map +1 -0
  81. package/commonjs/react/useVirtualScroller.js +4 -3
  82. package/commonjs/react/useVirtualScroller.js.map +1 -1
  83. package/commonjs/test/ItemsContainer.js +10 -10
  84. package/commonjs/test/ItemsContainer.js.map +1 -1
  85. package/commonjs/test/VirtualScroller.js +25 -10
  86. package/commonjs/test/VirtualScroller.js.map +1 -1
  87. package/dom/index.d.ts +6 -5
  88. package/index.d.ts +19 -8
  89. package/modules/BeforeResize.js +1 -2
  90. package/modules/BeforeResize.js.map +1 -1
  91. package/modules/DOM/VirtualScroller.js +7 -13
  92. package/modules/DOM/VirtualScroller.js.map +1 -1
  93. package/modules/DOM/tbody.js +4 -4
  94. package/modules/DOM/tbody.js.map +1 -1
  95. package/modules/ItemHeights.js +11 -14
  96. package/modules/ItemHeights.js.map +1 -1
  97. package/modules/Layout.defaults.js +11 -0
  98. package/modules/Layout.defaults.js.map +1 -0
  99. package/modules/Layout.js +74 -64
  100. package/modules/Layout.js.map +1 -1
  101. package/modules/Layout.test.js +8 -4
  102. package/modules/Layout.test.js.map +1 -1
  103. package/modules/VirtualScroller.constructor.js +37 -4
  104. package/modules/VirtualScroller.constructor.js.map +1 -1
  105. package/modules/VirtualScroller.items.js +51 -5
  106. package/modules/VirtualScroller.items.js.map +1 -1
  107. package/modules/VirtualScroller.js +23 -14
  108. package/modules/VirtualScroller.js.map +1 -1
  109. package/modules/VirtualScroller.layout.js +40 -29
  110. package/modules/VirtualScroller.layout.js.map +1 -1
  111. package/modules/VirtualScroller.onContainerResize.js +1 -2
  112. package/modules/VirtualScroller.onContainerResize.js.map +1 -1
  113. package/modules/VirtualScroller.state.js +10 -9
  114. package/modules/VirtualScroller.state.js.map +1 -1
  115. package/modules/VirtualScroller.verticalSpacing.js +38 -6
  116. package/modules/VirtualScroller.verticalSpacing.js.map +1 -1
  117. package/modules/react/VirtualScroller.js +84 -35
  118. package/modules/react/VirtualScroller.js.map +1 -1
  119. package/modules/react/useClassName.js +3 -3
  120. package/modules/react/useClassName.js.map +1 -1
  121. package/modules/react/useForwardedRef.js +42 -0
  122. package/modules/react/useForwardedRef.js.map +1 -0
  123. package/modules/react/useInstanceMethods.js +4 -4
  124. package/modules/react/useInstanceMethods.js.map +1 -1
  125. package/modules/react/useItemKeys.js +28 -5
  126. package/modules/react/useItemKeys.js.map +1 -1
  127. package/modules/react/useOnItemHeightDidChange.js +28 -12
  128. package/modules/react/useOnItemHeightDidChange.js.map +1 -1
  129. package/modules/react/useSetItemState.js +31 -12
  130. package/modules/react/useSetItemState.js.map +1 -1
  131. package/modules/react/useState.js +9 -9
  132. package/modules/react/useState.js.map +1 -1
  133. package/modules/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +2 -2
  134. package/modules/react/useStateWithRepeatableRead.js.map +1 -0
  135. package/modules/react/useStyle.js +10 -4
  136. package/modules/react/useStyle.js.map +1 -1
  137. package/modules/react/useValidateTableBodyItemsContainer.js +16 -0
  138. package/modules/react/useValidateTableBodyItemsContainer.js.map +1 -0
  139. package/modules/react/useVirtualScroller.js +4 -3
  140. package/modules/react/useVirtualScroller.js.map +1 -1
  141. package/modules/test/ItemsContainer.js +10 -10
  142. package/modules/test/ItemsContainer.js.map +1 -1
  143. package/modules/test/VirtualScroller.js +25 -10
  144. package/modules/test/VirtualScroller.js.map +1 -1
  145. package/package.json +1 -1
  146. package/react/as.d.ts +42 -0
  147. package/react/index.d.ts +204 -63
  148. package/source/BeforeResize.js +1 -2
  149. package/source/DOM/VirtualScroller.js +7 -13
  150. package/source/DOM/tbody.js +5 -5
  151. package/source/ItemHeights.js +11 -12
  152. package/source/Layout.defaults.js +8 -0
  153. package/source/Layout.js +66 -53
  154. package/source/Layout.test.js +7 -2
  155. package/source/VirtualScroller.constructor.js +27 -4
  156. package/source/VirtualScroller.items.js +47 -2
  157. package/source/VirtualScroller.js +23 -14
  158. package/source/VirtualScroller.layout.js +41 -28
  159. package/source/VirtualScroller.onContainerResize.js +1 -2
  160. package/source/VirtualScroller.state.js +10 -11
  161. package/source/VirtualScroller.verticalSpacing.js +32 -6
  162. package/source/react/VirtualScroller.js +96 -33
  163. package/source/react/useClassName.js +3 -3
  164. package/source/react/useForwardedRef.js +39 -0
  165. package/source/react/useInstanceMethods.js +12 -4
  166. package/source/react/useItemKeys.js +22 -4
  167. package/source/react/useOnItemHeightDidChange.js +29 -10
  168. package/source/react/useSetItemState.js +32 -10
  169. package/source/react/useState.js +6 -6
  170. package/source/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +1 -1
  171. package/source/react/useStyle.js +3 -2
  172. package/source/react/useValidateTableBodyItemsContainer.js +16 -0
  173. package/source/react/useVirtualScroller.js +4 -3
  174. package/source/test/ItemsContainer.js +10 -10
  175. package/source/test/VirtualScroller.js +16 -10
  176. package/website/index-dom-bypass.html +198 -0
  177. package/website/index-dom-grid.html +204 -0
  178. package/website/index-dom-scrollableContainer.html +215 -0
  179. package/website/index-dom-tbody-scrollableContainer.html +81 -0
  180. package/website/index-dom-tbody.html +65 -0
  181. package/website/index-dom.html +117 -84
  182. package/website/index-react-bypass.html +200 -0
  183. package/website/{index-grid.html → index-react-grid.html} +79 -92
  184. package/website/index-react-scrollableContainer.html +213 -0
  185. package/website/index-react-strictMode.html +199 -0
  186. package/website/index-react-tbody-scrollableContainer.html +96 -0
  187. package/website/index-react-tbody.html +80 -0
  188. package/website/{index-bypass.html → index-react.html} +84 -70
  189. package/website/index.html +84 -69
  190. package/website/{messages.js → items.js} +1 -1
  191. package/website/lib/babel.min.js +25 -0
  192. package/website/lib/prop-types.min.js +1 -0
  193. package/website/lib/react-dom.development.js +29924 -0
  194. package/website/lib/react-dom.production.min.js +267 -0
  195. package/website/lib/react.development.js +3343 -0
  196. package/website/lib/react.production.min.js +31 -0
  197. package/website/style.base.css +33 -0
  198. package/website/style.list.css +92 -0
  199. package/website/style.list.grid.css +23 -0
  200. package/bundle/index-tbody-scrollableContainer.html +0 -70
  201. package/bundle/index-tbody.html +0 -57
  202. package/bundle/on-scroll-to-dom.js +0 -2
  203. package/bundle/on-scroll-to-dom.js.map +0 -1
  204. package/bundle/on-scroll-to-react.js +0 -2
  205. package/bundle/on-scroll-to-react.js.map +0 -1
  206. package/bundle/on-scroll-to.js +0 -2
  207. package/bundle/on-scroll-to.js.map +0 -1
  208. package/commonjs/react/useStateNoStaleBug.js.map +0 -1
  209. package/modules/react/useStateNoStaleBug.js.map +0 -1
  210. package/website/index-scrollableContainer.html +0 -208
  211. package/website/index-tbody-scrollableContainer.html +0 -70
  212. package/website/index-tbody.html +0 -57
  213. package/website/lib/on-scroll-to-dom.js +0 -2
  214. package/website/lib/on-scroll-to-dom.js.map +0 -1
  215. package/website/lib/on-scroll-to-react.js +0 -2
  216. package/website/lib/on-scroll-to-react.js.map +0 -1
@@ -0,0 +1,198 @@
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 (DOM) (bypass)</title>
10
+
11
+ <script src="./virtual-scroller-dom.js"></script>
12
+ <script src="./items.js"></script>
13
+
14
+ <link rel="stylesheet" href="./style.base.css"/>
15
+ <link rel="stylesheet" href="./style.list.css"/>
16
+ </head>
17
+
18
+ <body>
19
+ <!-- http://tholman.com/github-corners/ -->
20
+ <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>
21
+
22
+ <section class="container">
23
+ <h1>
24
+ <svg class="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
25
+ <path fill="#00AAEC" fill-rule="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" clip-rule="evenodd"></path>
26
+ </svg>
27
+ Latest Tweets on #politics
28
+ </h1>
29
+ <div id="show-previous"></div>
30
+ <div id="list"></div>
31
+ <div id="show-next"></div>
32
+ <footer>
33
+ © Twitter Inc., 2019
34
+ </footer>
35
+ </section>
36
+
37
+ <script>
38
+ // Enable debug output to console.
39
+ window.VirtualScrollerDebug = true
40
+ // Pass `?pagination=✓` URL query parameter to enable pagination.
41
+ window.PAGINATION = Boolean(new URL(window.location).searchParams.get('pagination'))
42
+ </script>
43
+
44
+ <script>
45
+ const BATCH_SIZE = 6
46
+ const COLUMNS_COUNT = 1
47
+
48
+ function getColumnsCount(container) {
49
+ return 1
50
+ }
51
+
52
+ function getInitialState(items) {
53
+ if (window.PAGINATION) {
54
+ const fromIndex = Math.floor((items.length - BATCH_SIZE) / 2 / COLUMNS_COUNT) * COLUMNS_COUNT
55
+ const toIndex = fromIndex + BATCH_SIZE - 1
56
+ return {
57
+ fromIndex,
58
+ toIndex,
59
+ items: items.slice(fromIndex, toIndex + 1)
60
+ }
61
+ } else {
62
+ return {
63
+ fromIndex: 0,
64
+ toIndex: items.length,
65
+ items: items
66
+ }
67
+ }
68
+ }
69
+
70
+ function onShowPrevious(items, getState, setState) {
71
+ let { fromIndex } = getState()
72
+ const { toIndex } = getState()
73
+ fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
74
+ setState({
75
+ fromIndex,
76
+ items: items.slice(fromIndex, toIndex + 1)
77
+ })
78
+ }
79
+
80
+ function onShowNext(items, getState, setState) {
81
+ const { fromIndex } = getState()
82
+ let { toIndex } = getState()
83
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
84
+ setState({
85
+ toIndex,
86
+ items: items.slice(fromIndex, toIndex + 1)
87
+ })
88
+ }
89
+
90
+ function renderItem(item) {
91
+ const { username, date, text } = item
92
+
93
+ // Comment element.
94
+ const itemElement = document.createElement('article')
95
+ itemElement.classList.add('list-item')
96
+
97
+ // Comment author.
98
+ const authorElement = document.createElement('a')
99
+ authorElement.setAttribute('target', '_blank')
100
+ authorElement.setAttribute('href', `https://twitter.com/${username}`)
101
+ authorElement.textContent = `@${username}`
102
+ itemElement.appendChild(authorElement)
103
+
104
+ // Comment date.
105
+ const timeElement = document.createElement('time')
106
+ timeElement.setAttribute('datetime', date.toISOString())
107
+ timeElement.textContent = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`
108
+ itemElement.appendChild(timeElement)
109
+
110
+ // Comment text.
111
+ const textElement = document.createElement('p')
112
+ textElement.textContent = text
113
+ itemElement.appendChild(textElement)
114
+
115
+ // Return comment element.
116
+ return itemElement
117
+ }
118
+
119
+ function renderShowPrevious(items, getState, setState) {
120
+ const { fromIndex } = getState()
121
+ const container = document.getElementById('show-previous')
122
+ while (container.firstChild) {
123
+ container.removeChild(container.firstChild)
124
+ }
125
+ if (window.PAGINATION && fromIndex > 0) {
126
+ const button = document.createElement('button')
127
+ button.setAttribute('type', 'button')
128
+ button.classList.add('load-items-button')
129
+ button.addEventListener('click', () => onShowPrevious(items, getState, setState))
130
+ button.textContent = 'Show previous'
131
+ container.appendChild(button)
132
+ }
133
+ }
134
+
135
+ function renderShowNext(items, getState, setState) {
136
+ const { toIndex } = getState()
137
+ const container = document.getElementById('show-next')
138
+ while (container.firstChild) {
139
+ container.removeChild(container.firstChild)
140
+ }
141
+ if (window.PAGINATION && toIndex < items.length - 1) {
142
+ const button = document.createElement('button')
143
+ button.setAttribute('type', 'button')
144
+ button.classList.add('load-items-button')
145
+ button.addEventListener('click', () => onShowNext(items, getState, setState))
146
+ button.textContent = 'Show next'
147
+ container.appendChild(button)
148
+ }
149
+ }
150
+
151
+ class VirtualScrollerDemo {
152
+ constructor() {
153
+ this.state = getInitialState(ITEMS)
154
+ }
155
+
156
+ getState = () => {
157
+ return this.state
158
+ }
159
+
160
+ setState = (newState) => {
161
+ const prevState = this.state
162
+ this.state = {
163
+ ...this.state,
164
+ ...newState
165
+ }
166
+ this.onStateChange(this.state, prevState)
167
+ }
168
+
169
+ onStateChange(state, prevState) {
170
+ if (state.items !== prevState.items) {
171
+ this.virtualScroller.setItems(state.items, {
172
+ preserveScrollPositionOnPrependItems: true
173
+ })
174
+ this.renderPrevNextButtons()
175
+ }
176
+ }
177
+
178
+ renderPrevNextButtons() {
179
+ renderShowPrevious(ITEMS, this.getState, this.setState)
180
+ renderShowNext(ITEMS, this.getState, this.setState)
181
+ }
182
+
183
+ render() {
184
+ this.virtualScroller = new VirtualScroller(
185
+ document.getElementById('list'),
186
+ this.getState().items,
187
+ renderItem,
188
+ { getColumnsCount, bypass: true }
189
+ )
190
+ this.renderPrevNextButtons()
191
+ }
192
+ }
193
+
194
+ const virtualScrollerDemo = new VirtualScrollerDemo()
195
+ virtualScrollerDemo.render()
196
+ </script>
197
+ </body>
198
+ </html>
@@ -0,0 +1,204 @@
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 (DOM) (Grid)</title>
10
+
11
+ <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
12
+
13
+ <script src="./virtual-scroller-dom.js"></script>
14
+ <script src="./items.js"></script>
15
+
16
+ <link rel="stylesheet" href="./style.base.css"/>
17
+ <link rel="stylesheet" href="./style.list.css"/>
18
+ <link rel="stylesheet" href="./style.list.grid.css"/>
19
+ </head>
20
+
21
+ <body>
22
+ <!-- http://tholman.com/github-corners/ -->
23
+ <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>
24
+
25
+ <section class="container">
26
+ <h1>
27
+ <svg class="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
28
+ <path fill="#00AAEC" fill-rule="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" clip-rule="evenodd"></path>
29
+ </svg>
30
+ Latest Tweets on #politics
31
+ </h1>
32
+ <div id="show-previous"></div>
33
+ <div id="list"></div>
34
+ <div id="show-next"></div>
35
+ <footer>
36
+ © Twitter Inc., 2019
37
+ </footer>
38
+ </section>
39
+
40
+ <script>
41
+ // Enable debug output to console.
42
+ window.VirtualScrollerDebug = true
43
+ // Pass `?pagination=✓` URL query parameter to enable pagination.
44
+ window.PAGINATION = Boolean(new URL(window.location).searchParams.get('pagination'))
45
+ </script>
46
+
47
+ <script type="text/babel">
48
+ const BATCH_SIZE = 6
49
+ const COLUMNS_COUNT = 3
50
+
51
+ function getColumnsCount(container) {
52
+ if (container.getWidth() > 1280) {
53
+ return COLUMNS_COUNT
54
+ }
55
+ return 1
56
+ }
57
+
58
+ function getInitialState(items) {
59
+ if (window.PAGINATION) {
60
+ const fromIndex = Math.floor((items.length - BATCH_SIZE) / 2 / COLUMNS_COUNT) * COLUMNS_COUNT
61
+ const toIndex = fromIndex + BATCH_SIZE - 1
62
+ return {
63
+ fromIndex,
64
+ toIndex,
65
+ items: items.slice(fromIndex, toIndex + 1)
66
+ }
67
+ } else {
68
+ return {
69
+ fromIndex: 0,
70
+ toIndex: items.length,
71
+ items: items
72
+ }
73
+ }
74
+ }
75
+
76
+ function onShowPrevious(items, getState, setState) {
77
+ let { fromIndex } = getState()
78
+ const { toIndex } = getState()
79
+ fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
80
+ setState({
81
+ fromIndex,
82
+ items: items.slice(fromIndex, toIndex + 1)
83
+ })
84
+ }
85
+
86
+ function onShowNext(items, getState, setState) {
87
+ const { fromIndex } = getState()
88
+ let { toIndex } = getState()
89
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
90
+ setState({
91
+ toIndex,
92
+ items: items.slice(fromIndex, toIndex + 1)
93
+ })
94
+ }
95
+
96
+ function renderItem(item) {
97
+ const { username, date, text } = item
98
+
99
+ // Comment element.
100
+ const itemElement = document.createElement('article')
101
+ itemElement.classList.add('list-item')
102
+
103
+ // Comment author.
104
+ const authorElement = document.createElement('a')
105
+ authorElement.setAttribute('target', '_blank')
106
+ authorElement.setAttribute('href', `https://twitter.com/${username}`)
107
+ authorElement.textContent = `@${username}`
108
+ itemElement.appendChild(authorElement)
109
+
110
+ // Comment date.
111
+ const timeElement = document.createElement('time')
112
+ timeElement.setAttribute('datetime', date.toISOString())
113
+ timeElement.textContent = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`
114
+ itemElement.appendChild(timeElement)
115
+
116
+ // Comment text.
117
+ const textElement = document.createElement('p')
118
+ textElement.textContent = text
119
+ itemElement.appendChild(textElement)
120
+
121
+ // Return comment element.
122
+ return itemElement
123
+ }
124
+
125
+ function renderShowPrevious(items, getState, setState) {
126
+ const { fromIndex } = getState()
127
+ const container = document.getElementById('show-previous')
128
+ while (container.firstChild) {
129
+ container.removeChild(container.firstChild)
130
+ }
131
+ if (window.PAGINATION && fromIndex > 0) {
132
+ const button = document.createElement('button')
133
+ button.setAttribute('type', 'button')
134
+ button.classList.add('load-items-button')
135
+ button.addEventListener('click', () => onShowPrevious(items, getState, setState))
136
+ button.textContent = 'Show previous'
137
+ container.appendChild(button)
138
+ }
139
+ }
140
+
141
+ function renderShowNext(items, getState, setState) {
142
+ const { toIndex } = getState()
143
+ const container = document.getElementById('show-next')
144
+ while (container.firstChild) {
145
+ container.removeChild(container.firstChild)
146
+ }
147
+ if (window.PAGINATION && toIndex < items.length - 1) {
148
+ const button = document.createElement('button')
149
+ button.setAttribute('type', 'button')
150
+ button.classList.add('load-items-button')
151
+ button.addEventListener('click', () => onShowNext(items, getState, setState))
152
+ button.textContent = 'Show next'
153
+ container.appendChild(button)
154
+ }
155
+ }
156
+
157
+ class VirtualScrollerDemo {
158
+ constructor() {
159
+ this.state = getInitialState(ITEMS)
160
+ }
161
+
162
+ getState = () => {
163
+ return this.state
164
+ }
165
+
166
+ setState = (newState) => {
167
+ const prevState = this.state
168
+ this.state = {
169
+ ...this.state,
170
+ ...newState
171
+ }
172
+ this.onStateChange(this.state, prevState)
173
+ }
174
+
175
+ onStateChange(state, prevState) {
176
+ if (state.items !== prevState.items) {
177
+ this.virtualScroller.setItems(state.items, {
178
+ preserveScrollPositionOnPrependItems: true
179
+ })
180
+ this.renderPrevNextButtons()
181
+ }
182
+ }
183
+
184
+ renderPrevNextButtons() {
185
+ renderShowPrevious(ITEMS, this.getState, this.setState)
186
+ renderShowNext(ITEMS, this.getState, this.setState)
187
+ }
188
+
189
+ render() {
190
+ this.virtualScroller = new VirtualScroller(
191
+ document.getElementById('list'),
192
+ this.getState().items,
193
+ renderItem,
194
+ { getColumnsCount }
195
+ )
196
+ this.renderPrevNextButtons()
197
+ }
198
+ }
199
+
200
+ const virtualScrollerDemo = new VirtualScrollerDemo()
201
+ virtualScrollerDemo.render()
202
+ </script>
203
+ </body>
204
+ </html>
@@ -0,0 +1,215 @@
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 (DOM) (Scrollable Container)</title>
10
+
11
+ <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
12
+
13
+ <script src="./virtual-scroller-dom.js"></script>
14
+ <script src="./items.js"></script>
15
+
16
+ <link rel="stylesheet" href="./style.base.css"/>
17
+ <link rel="stylesheet" href="./style.list.css"/>
18
+
19
+ <style>
20
+ #scrollable-container {
21
+ margin-top: 20vh;
22
+ margin-bottom: 20vh;
23
+ max-height: 60vh;
24
+ overflow: auto;
25
+ }
26
+ </style>
27
+ </head>
28
+
29
+ <body>
30
+ <!-- http://tholman.com/github-corners/ -->
31
+ <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>
32
+
33
+ <section class="container">
34
+ <h1>
35
+ <svg class="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
36
+ <path fill="#00AAEC" fill-rule="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" clip-rule="evenodd"></path>
37
+ </svg>
38
+ Latest Tweets on #politics
39
+ </h1>
40
+ <div id="show-previous"></div>
41
+ <div id="scrollable-container">
42
+ <div id="list"></div>
43
+ </div>
44
+ <div id="show-next"></div>
45
+ <footer>
46
+ © Twitter Inc., 2019
47
+ </footer>
48
+ </section>
49
+
50
+ <script>
51
+ // Enable debug output to console.
52
+ window.VirtualScrollerDebug = true
53
+ // Pass `?pagination=✓` URL query parameter to enable pagination.
54
+ window.PAGINATION = Boolean(new URL(window.location).searchParams.get('pagination'))
55
+ </script>
56
+
57
+ <script type="text/babel">
58
+ const BATCH_SIZE = 6
59
+ const COLUMNS_COUNT = 1
60
+
61
+ function getColumnsCount(container) {
62
+ return 1
63
+ }
64
+
65
+ function getInitialState(items) {
66
+ if (window.PAGINATION) {
67
+ const fromIndex = Math.floor((items.length - BATCH_SIZE) / 2 / COLUMNS_COUNT) * COLUMNS_COUNT
68
+ const toIndex = fromIndex + BATCH_SIZE - 1
69
+ return {
70
+ fromIndex,
71
+ toIndex,
72
+ items: items.slice(fromIndex, toIndex + 1)
73
+ }
74
+ } else {
75
+ return {
76
+ fromIndex: 0,
77
+ toIndex: items.length,
78
+ items: items
79
+ }
80
+ }
81
+ }
82
+
83
+ function onShowPrevious(items, getState, setState) {
84
+ let { fromIndex } = getState()
85
+ const { toIndex } = getState()
86
+ fromIndex = Math.max(fromIndex - BATCH_SIZE, 0)
87
+ setState({
88
+ fromIndex,
89
+ items: items.slice(fromIndex, toIndex + 1)
90
+ })
91
+ }
92
+
93
+ function onShowNext(items, getState, setState) {
94
+ const { fromIndex } = getState()
95
+ let { toIndex } = getState()
96
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
97
+ setState({
98
+ toIndex,
99
+ items: items.slice(fromIndex, toIndex + 1)
100
+ })
101
+ }
102
+
103
+ function getScrollableContainer() {
104
+ return document.getElementById('scrollable-container')
105
+ }
106
+
107
+ function renderItem(item) {
108
+ const { username, date, text } = item
109
+
110
+ // Comment element.
111
+ const itemElement = document.createElement('article')
112
+ itemElement.classList.add('list-item')
113
+
114
+ // Comment author.
115
+ const authorElement = document.createElement('a')
116
+ authorElement.setAttribute('target', '_blank')
117
+ authorElement.setAttribute('href', `https://twitter.com/${username}`)
118
+ authorElement.textContent = `@${username}`
119
+ itemElement.appendChild(authorElement)
120
+
121
+ // Comment date.
122
+ const timeElement = document.createElement('time')
123
+ timeElement.setAttribute('datetime', date.toISOString())
124
+ timeElement.textContent = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`
125
+ itemElement.appendChild(timeElement)
126
+
127
+ // Comment text.
128
+ const textElement = document.createElement('p')
129
+ textElement.textContent = text
130
+ itemElement.appendChild(textElement)
131
+
132
+ // Return comment element.
133
+ return itemElement
134
+ }
135
+
136
+ function renderShowPrevious(items, getState, setState) {
137
+ const { fromIndex } = getState()
138
+ const container = document.getElementById('show-previous')
139
+ while (container.firstChild) {
140
+ container.removeChild(container.firstChild)
141
+ }
142
+ if (window.PAGINATION && fromIndex > 0) {
143
+ const button = document.createElement('button')
144
+ button.setAttribute('type', 'button')
145
+ button.classList.add('load-items-button')
146
+ button.addEventListener('click', () => onShowPrevious(items, getState, setState))
147
+ button.textContent = 'Show previous'
148
+ container.appendChild(button)
149
+ }
150
+ }
151
+
152
+ function renderShowNext(items, getState, setState) {
153
+ const { toIndex } = getState()
154
+ const container = document.getElementById('show-next')
155
+ while (container.firstChild) {
156
+ container.removeChild(container.firstChild)
157
+ }
158
+ if (window.PAGINATION && toIndex < items.length - 1) {
159
+ const button = document.createElement('button')
160
+ button.setAttribute('type', 'button')
161
+ button.classList.add('load-items-button')
162
+ button.addEventListener('click', () => onShowNext(items, getState, setState))
163
+ button.textContent = 'Show next'
164
+ container.appendChild(button)
165
+ }
166
+ }
167
+
168
+ class VirtualScrollerDemo {
169
+ constructor() {
170
+ this.state = getInitialState(ITEMS)
171
+ }
172
+
173
+ getState = () => {
174
+ return this.state
175
+ }
176
+
177
+ setState = (newState) => {
178
+ const prevState = this.state
179
+ this.state = {
180
+ ...this.state,
181
+ ...newState
182
+ }
183
+ this.onStateChange(this.state, prevState)
184
+ }
185
+
186
+ onStateChange(state, prevState) {
187
+ if (state.items !== prevState.items) {
188
+ this.virtualScroller.setItems(state.items, {
189
+ preserveScrollPositionOnPrependItems: true
190
+ })
191
+ this.renderPrevNextButtons()
192
+ }
193
+ }
194
+
195
+ renderPrevNextButtons() {
196
+ renderShowPrevious(ITEMS, this.getState, this.setState)
197
+ renderShowNext(ITEMS, this.getState, this.setState)
198
+ }
199
+
200
+ render() {
201
+ this.virtualScroller = new VirtualScroller(
202
+ document.getElementById('list'),
203
+ this.getState().items,
204
+ renderItem,
205
+ { getColumnsCount, getScrollableContainer }
206
+ )
207
+ this.renderPrevNextButtons()
208
+ }
209
+ }
210
+
211
+ const virtualScrollerDemo = new VirtualScrollerDemo()
212
+ virtualScrollerDemo.render()
213
+ </script>
214
+ </body>
215
+ </html>