virtual-scroller 1.14.0 → 1.15.1

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 (235) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +403 -254
  3. package/bundle/index-dom-bypass.html +197 -0
  4. package/bundle/index-dom-grid.html +203 -0
  5. package/bundle/index-dom-scrollableContainer.html +214 -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 +114 -84
  9. package/bundle/index-react-bypass.html +194 -0
  10. package/bundle/{index-bypass.html → index-react-grid.html} +122 -120
  11. package/bundle/index-react-hook.html +209 -0
  12. package/bundle/index-react-scrollableContainer.html +207 -0
  13. package/bundle/index-react-strictMode.html +193 -0
  14. package/bundle/index-react-tbody-scrollableContainer.html +94 -0
  15. package/bundle/index-react-tbody.html +78 -0
  16. package/bundle/{messages.js → items.js} +1 -1
  17. package/bundle/lib/babel.min.js +25 -0
  18. package/bundle/lib/prop-types.min.js +1 -0
  19. package/bundle/lib/react-dom.development.js +29924 -0
  20. package/bundle/lib/react-dom.production.min.js +267 -0
  21. package/bundle/lib/react.development.js +3343 -0
  22. package/bundle/lib/react.production.min.js +31 -0
  23. package/bundle/style.base.css +33 -0
  24. package/{website/style.css → bundle/style.list.css} +10 -43
  25. package/bundle/style.list.grid.css +23 -0
  26. package/bundle/virtual-scroller-dom.js +1 -1
  27. package/bundle/virtual-scroller-dom.js.map +1 -1
  28. package/bundle/virtual-scroller-react.js +1 -1
  29. package/bundle/virtual-scroller-react.js.map +1 -1
  30. package/bundle/virtual-scroller.js +1 -1
  31. package/bundle/virtual-scroller.js.map +1 -1
  32. package/commonjs/BeforeResize.js +1 -2
  33. package/commonjs/BeforeResize.js.map +1 -1
  34. package/commonjs/DOM/VirtualScroller.js +7 -13
  35. package/commonjs/DOM/VirtualScroller.js.map +1 -1
  36. package/commonjs/DOM/tbody.js +6 -6
  37. package/commonjs/DOM/tbody.js.map +1 -1
  38. package/commonjs/ItemHeights.js +10 -13
  39. package/commonjs/ItemHeights.js.map +1 -1
  40. package/commonjs/Layout.defaults.js +21 -0
  41. package/commonjs/Layout.defaults.js.map +1 -0
  42. package/commonjs/Layout.js +75 -64
  43. package/commonjs/Layout.js.map +1 -1
  44. package/commonjs/Layout.test.js +8 -4
  45. package/commonjs/Layout.test.js.map +1 -1
  46. package/commonjs/VirtualScroller.constructor.js +38 -4
  47. package/commonjs/VirtualScroller.constructor.js.map +1 -1
  48. package/commonjs/VirtualScroller.items.js +50 -4
  49. package/commonjs/VirtualScroller.items.js.map +1 -1
  50. package/commonjs/VirtualScroller.js +23 -14
  51. package/commonjs/VirtualScroller.js.map +1 -1
  52. package/commonjs/VirtualScroller.layout.js +40 -29
  53. package/commonjs/VirtualScroller.layout.js.map +1 -1
  54. package/commonjs/VirtualScroller.onContainerResize.js +1 -2
  55. package/commonjs/VirtualScroller.onContainerResize.js.map +1 -1
  56. package/commonjs/VirtualScroller.state.js +10 -9
  57. package/commonjs/VirtualScroller.state.js.map +1 -1
  58. package/commonjs/VirtualScroller.verticalSpacing.js +39 -6
  59. package/commonjs/VirtualScroller.verticalSpacing.js.map +1 -1
  60. package/commonjs/react/VirtualScroller.js +124 -131
  61. package/commonjs/react/VirtualScroller.js.map +1 -1
  62. package/commonjs/react/useClassName.js +2 -2
  63. package/commonjs/react/useClassName.js.map +1 -1
  64. package/commonjs/react/useCreateVirtualScroller.js +64 -0
  65. package/commonjs/react/useCreateVirtualScroller.js.map +1 -0
  66. package/commonjs/react/useInstanceMethods.js +4 -4
  67. package/commonjs/react/useInstanceMethods.js.map +1 -1
  68. package/commonjs/react/useItemKeys.js +28 -5
  69. package/commonjs/react/useItemKeys.js.map +1 -1
  70. package/commonjs/react/useMergeRefs.js +52 -0
  71. package/commonjs/react/useMergeRefs.js.map +1 -0
  72. package/commonjs/react/useOnItemHeightDidChange.js +28 -12
  73. package/commonjs/react/useOnItemHeightDidChange.js.map +1 -1
  74. package/commonjs/react/useSetItemState.js +31 -12
  75. package/commonjs/react/useSetItemState.js.map +1 -1
  76. package/commonjs/react/{useVirtualScrollerStartStop.js → useStartStopVirtualScroller.js} +1 -1
  77. package/commonjs/react/{useVirtualScrollerStartStop.js.map → useStartStopVirtualScroller.js.map} +1 -1
  78. package/commonjs/react/useState.js +9 -9
  79. package/commonjs/react/useState.js.map +1 -1
  80. package/commonjs/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +3 -3
  81. package/commonjs/react/useStateWithRepeatableRead.js.map +1 -0
  82. package/commonjs/react/useStyle.js +28 -4
  83. package/commonjs/react/useStyle.js.map +1 -1
  84. package/commonjs/react/useValidateTableBodyItemsContainer.js +24 -0
  85. package/commonjs/react/useValidateTableBodyItemsContainer.js.map +1 -0
  86. package/commonjs/react/useVirtualScroller.js +142 -42
  87. package/commonjs/react/useVirtualScroller.js.map +1 -1
  88. package/commonjs/test/ItemsContainer.js +10 -10
  89. package/commonjs/test/ItemsContainer.js.map +1 -1
  90. package/commonjs/test/VirtualScroller.js +25 -10
  91. package/commonjs/test/VirtualScroller.js.map +1 -1
  92. package/dom/index.d.ts +6 -5
  93. package/index.d.ts +19 -8
  94. package/modules/BeforeResize.js +1 -2
  95. package/modules/BeforeResize.js.map +1 -1
  96. package/modules/DOM/VirtualScroller.js +7 -13
  97. package/modules/DOM/VirtualScroller.js.map +1 -1
  98. package/modules/DOM/tbody.js +4 -4
  99. package/modules/DOM/tbody.js.map +1 -1
  100. package/modules/ItemHeights.js +11 -14
  101. package/modules/ItemHeights.js.map +1 -1
  102. package/modules/Layout.defaults.js +11 -0
  103. package/modules/Layout.defaults.js.map +1 -0
  104. package/modules/Layout.js +74 -64
  105. package/modules/Layout.js.map +1 -1
  106. package/modules/Layout.test.js +8 -4
  107. package/modules/Layout.test.js.map +1 -1
  108. package/modules/VirtualScroller.constructor.js +37 -4
  109. package/modules/VirtualScroller.constructor.js.map +1 -1
  110. package/modules/VirtualScroller.items.js +51 -5
  111. package/modules/VirtualScroller.items.js.map +1 -1
  112. package/modules/VirtualScroller.js +23 -14
  113. package/modules/VirtualScroller.js.map +1 -1
  114. package/modules/VirtualScroller.layout.js +40 -29
  115. package/modules/VirtualScroller.layout.js.map +1 -1
  116. package/modules/VirtualScroller.onContainerResize.js +1 -2
  117. package/modules/VirtualScroller.onContainerResize.js.map +1 -1
  118. package/modules/VirtualScroller.state.js +10 -9
  119. package/modules/VirtualScroller.state.js.map +1 -1
  120. package/modules/VirtualScroller.verticalSpacing.js +38 -6
  121. package/modules/VirtualScroller.verticalSpacing.js.map +1 -1
  122. package/modules/react/VirtualScroller.js +122 -124
  123. package/modules/react/VirtualScroller.js.map +1 -1
  124. package/modules/react/useClassName.js +3 -3
  125. package/modules/react/useClassName.js.map +1 -1
  126. package/modules/react/useCreateVirtualScroller.js +53 -0
  127. package/modules/react/useCreateVirtualScroller.js.map +1 -0
  128. package/modules/react/useInstanceMethods.js +4 -4
  129. package/modules/react/useInstanceMethods.js.map +1 -1
  130. package/modules/react/useItemKeys.js +28 -5
  131. package/modules/react/useItemKeys.js.map +1 -1
  132. package/modules/react/useMergeRefs.js +44 -0
  133. package/modules/react/useMergeRefs.js.map +1 -0
  134. package/modules/react/useOnItemHeightDidChange.js +28 -12
  135. package/modules/react/useOnItemHeightDidChange.js.map +1 -1
  136. package/modules/react/useSetItemState.js +31 -12
  137. package/modules/react/useSetItemState.js.map +1 -1
  138. package/modules/react/{useVirtualScrollerStartStop.js → useStartStopVirtualScroller.js} +1 -1
  139. package/modules/react/{useVirtualScrollerStartStop.js.map → useStartStopVirtualScroller.js.map} +1 -1
  140. package/modules/react/useState.js +9 -9
  141. package/modules/react/useState.js.map +1 -1
  142. package/modules/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +2 -2
  143. package/modules/react/useStateWithRepeatableRead.js.map +1 -0
  144. package/modules/react/useStyle.js +27 -4
  145. package/modules/react/useStyle.js.map +1 -1
  146. package/modules/react/useValidateTableBodyItemsContainer.js +16 -0
  147. package/modules/react/useValidateTableBodyItemsContainer.js.map +1 -0
  148. package/modules/react/useVirtualScroller.js +136 -42
  149. package/modules/react/useVirtualScroller.js.map +1 -1
  150. package/modules/test/ItemsContainer.js +10 -10
  151. package/modules/test/ItemsContainer.js.map +1 -1
  152. package/modules/test/VirtualScroller.js +25 -10
  153. package/modules/test/VirtualScroller.js.map +1 -1
  154. package/package.json +4 -1
  155. package/react/as.d.ts +42 -0
  156. package/react/index.cjs +2 -1
  157. package/react/index.d.ts +248 -63
  158. package/react/index.js +1 -0
  159. package/rollup.config.mjs +15 -1
  160. package/source/BeforeResize.js +1 -2
  161. package/source/DOM/VirtualScroller.js +7 -13
  162. package/source/DOM/tbody.js +5 -5
  163. package/source/ItemHeights.js +11 -12
  164. package/source/Layout.defaults.js +8 -0
  165. package/source/Layout.js +66 -53
  166. package/source/Layout.test.js +7 -2
  167. package/source/VirtualScroller.constructor.js +27 -4
  168. package/source/VirtualScroller.items.js +47 -2
  169. package/source/VirtualScroller.js +23 -14
  170. package/source/VirtualScroller.layout.js +41 -28
  171. package/source/VirtualScroller.onContainerResize.js +1 -2
  172. package/source/VirtualScroller.state.js +10 -11
  173. package/source/VirtualScroller.verticalSpacing.js +32 -6
  174. package/source/react/VirtualScroller.js +135 -133
  175. package/source/react/useClassName.js +3 -3
  176. package/source/react/useCreateVirtualScroller.js +65 -0
  177. package/source/react/useInstanceMethods.js +12 -4
  178. package/source/react/useItemKeys.js +22 -4
  179. package/source/react/useMergeRefs.js +45 -0
  180. package/source/react/useOnItemHeightDidChange.js +29 -10
  181. package/source/react/useSetItemState.js +32 -10
  182. package/source/react/useState.js +6 -6
  183. package/source/react/{useStateNoStaleBug.js → useStateWithRepeatableRead.js} +1 -1
  184. package/source/react/useStyle.js +18 -2
  185. package/source/react/useValidateTableBodyItemsContainer.js +16 -0
  186. package/source/react/useVirtualScroller.js +155 -47
  187. package/source/test/ItemsContainer.js +10 -10
  188. package/source/test/VirtualScroller.js +16 -10
  189. package/website/index-dom-bypass.html +197 -0
  190. package/website/index-dom-grid.html +203 -0
  191. package/website/index-dom-scrollableContainer.html +214 -0
  192. package/website/index-dom-tbody-scrollableContainer.html +81 -0
  193. package/website/index-dom-tbody.html +65 -0
  194. package/website/index-dom.html +116 -84
  195. package/website/index-react-bypass.html +194 -0
  196. package/website/index-react-grid.html +197 -0
  197. package/website/index-react-hook.html +209 -0
  198. package/website/index-react-scrollableContainer.html +207 -0
  199. package/website/index-react-strictMode.html +193 -0
  200. package/website/index-react-tbody-scrollableContainer.html +94 -0
  201. package/website/index-react-tbody.html +78 -0
  202. package/website/index-react.html +193 -0
  203. package/website/index.html +120 -111
  204. package/website/{messages.js → items.js} +1 -1
  205. package/website/lib/babel.min.js +25 -0
  206. package/website/lib/prop-types.min.js +1 -0
  207. package/website/lib/react-dom.development.js +29924 -0
  208. package/website/lib/react-dom.production.min.js +267 -0
  209. package/website/lib/react.development.js +3343 -0
  210. package/website/lib/react.production.min.js +31 -0
  211. package/website/style.base.css +33 -0
  212. package/website/style.list.css +92 -0
  213. package/website/style.list.grid.css +23 -0
  214. package/bundle/index-grid.html +0 -216
  215. package/bundle/index-scrollableContainer.html +0 -208
  216. package/bundle/index-tbody-scrollableContainer.html +0 -70
  217. package/bundle/index-tbody.html +0 -57
  218. package/bundle/on-scroll-to-dom.js +0 -2
  219. package/bundle/on-scroll-to-dom.js.map +0 -1
  220. package/bundle/on-scroll-to-react.js +0 -2
  221. package/bundle/on-scroll-to-react.js.map +0 -1
  222. package/bundle/on-scroll-to.js +0 -2
  223. package/bundle/on-scroll-to.js.map +0 -1
  224. package/commonjs/react/useStateNoStaleBug.js.map +0 -1
  225. package/modules/react/useStateNoStaleBug.js.map +0 -1
  226. package/website/index-bypass.html +0 -185
  227. package/website/index-grid.html +0 -216
  228. package/website/index-scrollableContainer.html +0 -208
  229. package/website/index-tbody-scrollableContainer.html +0 -70
  230. package/website/index-tbody.html +0 -57
  231. package/website/lib/on-scroll-to-dom.js +0 -2
  232. package/website/lib/on-scroll-to-dom.js.map +0 -1
  233. package/website/lib/on-scroll-to-react.js +0 -2
  234. package/website/lib/on-scroll-to-react.js.map +0 -1
  235. /package/source/react/{useVirtualScrollerStartStop.js → useStartStopVirtualScroller.js} +0 -0
@@ -0,0 +1,197 @@
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) (Grid)</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
+ <link rel="stylesheet" href="./style.list.grid.css"/>
22
+ </head>
23
+
24
+ <body>
25
+ <!-- http://tholman.com/github-corners/ -->
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>
27
+
28
+ <div id="root"></div>
29
+
30
+ <script>
31
+ // Enable debug output to console.
32
+ window.VirtualScrollerDebug = true
33
+ // Pass `?pagination=✓` URL query parameter to enable pagination.
34
+ window.PAGINATION = Boolean(new URL(window.location).searchParams.get('pagination'))
35
+ </script>
36
+
37
+ <script type="text/babel">
38
+ const BATCH_SIZE = 6
39
+ const COLUMNS_COUNT = 3
40
+
41
+ function getColumnsCount(container) {
42
+ if (container.getWidth() > 1280) {
43
+ return COLUMNS_COUNT
44
+ }
45
+ return 1
46
+ }
47
+
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
+ ...getState(),
72
+ fromIndex,
73
+ items: items.slice(fromIndex, toIndex + 1)
74
+ })
75
+ }
76
+
77
+ function onShowNext(items, getState, setState) {
78
+ const { fromIndex } = getState()
79
+ let { toIndex } = getState()
80
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
81
+ setState({
82
+ ...getState(),
83
+ toIndex,
84
+ items: items.slice(fromIndex, toIndex + 1)
85
+ })
86
+ }
87
+
88
+ function VirtualScrollerDemo() {
89
+ const [state, setState] = React.useState(getInitialState(ITEMS))
90
+
91
+ const getState = () => state
92
+
93
+ const onShowPrevious_ = () => {
94
+ onShowPrevious(ITEMS, getState, setState)
95
+ }
96
+
97
+ const onShowNext_ = () => {
98
+ onShowNext(ITEMS, getState, setState)
99
+ }
100
+
101
+ const {
102
+ fromIndex,
103
+ toIndex,
104
+ items
105
+ } = state
106
+
107
+ return (
108
+ <React.Fragment>
109
+ {window.PAGINATION && fromIndex > 0 &&
110
+ <button
111
+ type="button"
112
+ onClick={onShowPrevious_}
113
+ className="load-items-button">
114
+ Show previous
115
+ </button>
116
+ }
117
+ <VirtualScroller
118
+ id="list"
119
+ items={items}
120
+ itemComponent={Item}
121
+ preserveScrollPositionOnPrependItems
122
+ getColumnsCount={getColumnsCount}
123
+ />
124
+ {window.PAGINATION && toIndex < ITEMS.length - 1 &&
125
+ <button
126
+ type="button"
127
+ onClick={onShowNext_}
128
+ className="load-items-button">
129
+ Show next
130
+ </button>
131
+ }
132
+ </React.Fragment>
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
+ function Demo() {
171
+ return (
172
+ <section className="container">
173
+ <h1>
174
+ <TwitterLogo/>
175
+ Latest Tweets on #politics
176
+ </h1>
177
+ <VirtualScrollerDemo/>
178
+ <footer>
179
+ © Twitter Inc., 2019
180
+ </footer>
181
+ </section>
182
+ )
183
+ }
184
+
185
+ function TwitterLogo() {
186
+ return (
187
+ <svg className="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
188
+ <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"/>
189
+ </svg>
190
+ )
191
+ }
192
+
193
+ const root = ReactDOM.createRoot(document.getElementById('root'))
194
+ root.render(<Demo/>)
195
+ </script>
196
+ </body>
197
+ </html>
@@ -0,0 +1,209 @@
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) (hook)</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
+ ...getState(),
68
+ fromIndex,
69
+ items: items.slice(fromIndex, toIndex + 1)
70
+ })
71
+ }
72
+
73
+ function onShowNext(items, getState, setState) {
74
+ const { fromIndex } = getState()
75
+ let { toIndex } = getState()
76
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
77
+ setState({
78
+ ...getState(),
79
+ toIndex,
80
+ items: items.slice(fromIndex, toIndex + 1)
81
+ })
82
+ }
83
+
84
+ function VirtualScrollerDemo() {
85
+ const [state, setState] = React.useState(getInitialState(ITEMS))
86
+
87
+ const getState = () => state
88
+
89
+ const onShowPrevious_ = () => {
90
+ onShowPrevious(ITEMS, getState, setState)
91
+ }
92
+
93
+ const onShowNext_ = () => {
94
+ onShowNext(ITEMS, getState, setState)
95
+ }
96
+
97
+ const {
98
+ fromIndex,
99
+ toIndex,
100
+ items
101
+ } = state
102
+
103
+ const {
104
+ state: {
105
+ items: itemsToRender,
106
+ firstShownItemIndex,
107
+ lastShownItemIndex
108
+ },
109
+ style,
110
+ className,
111
+ itemsContainerRef
112
+ } = VirtualScroller.useVirtualScroller({
113
+ items,
114
+ preserveScrollPositionOnPrependItems: true,
115
+ getColumnsCount
116
+ })
117
+
118
+ return (
119
+ <React.Fragment>
120
+ {window.PAGINATION && fromIndex > 0 &&
121
+ <button
122
+ type="button"
123
+ onClick={onShowPrevious_}
124
+ className="load-items-button">
125
+ Show previous
126
+ </button>
127
+ }
128
+ <div id="list" ref={itemsContainerRef} style={style} className={className}>
129
+ {itemsToRender.map((item, i) => {
130
+ if (i >= firstShownItemIndex && i <= lastShownItemIndex) {
131
+ return (
132
+ <Item key={i} item={item}/>
133
+ )
134
+ }
135
+ return null
136
+ })}
137
+ </div>
138
+ {window.PAGINATION && toIndex < ITEMS.length - 1 &&
139
+ <button
140
+ type="button"
141
+ onClick={onShowNext_}
142
+ className="load-items-button">
143
+ Show next
144
+ </button>
145
+ }
146
+ </React.Fragment>
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({ item }) {
157
+ const {
158
+ username,
159
+ date,
160
+ text
161
+ } = item
162
+
163
+ return (
164
+ <article className="list-item">
165
+ <a target="_blank" href={`https://twitter.com/${username}`}>
166
+ @{username}
167
+ </a>
168
+ <time dateTime={date.toISOString()}>
169
+ {date.getMonth() + 1}/{date.getDate()}/{date.getFullYear()}
170
+ </time>
171
+ <p>
172
+ {text}
173
+ </p>
174
+ </article>
175
+ )
176
+ }
177
+
178
+ Item.propTypes = {
179
+ children: item.isRequired
180
+ }
181
+
182
+ function Demo() {
183
+ return (
184
+ <section className="container">
185
+ <h1>
186
+ <TwitterLogo/>
187
+ Latest Tweets on #politics
188
+ </h1>
189
+ <VirtualScrollerDemo/>
190
+ <footer>
191
+ © Twitter Inc., 2019
192
+ </footer>
193
+ </section>
194
+ )
195
+ }
196
+
197
+ function TwitterLogo() {
198
+ return (
199
+ <svg className="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
200
+ <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"/>
201
+ </svg>
202
+ )
203
+ }
204
+
205
+ const root = ReactDOM.createRoot(document.getElementById('root'))
206
+ root.render(<Demo/>)
207
+ </script>
208
+ </body>
209
+ </html>
@@ -0,0 +1,207 @@
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
+ ...getState(),
77
+ fromIndex,
78
+ items: items.slice(fromIndex, toIndex + 1)
79
+ })
80
+ }
81
+
82
+ function onShowNext(items, getState, setState) {
83
+ const { fromIndex } = getState()
84
+ let { toIndex } = getState()
85
+ toIndex = Math.min(toIndex + BATCH_SIZE, items.length - 1)
86
+ setState({
87
+ ...getState(),
88
+ toIndex,
89
+ items: items.slice(fromIndex, toIndex + 1)
90
+ })
91
+ }
92
+
93
+ function getScrollableContainer() {
94
+ return document.getElementById('scrollable-container')
95
+ }
96
+
97
+ function VirtualScrollerDemo() {
98
+ const [state, setState] = React.useState(getInitialState(ITEMS))
99
+
100
+ const getState = () => state
101
+
102
+ const onShowPrevious_ = () => {
103
+ onShowPrevious(ITEMS, getState, setState)
104
+ }
105
+
106
+ const onShowNext_ = () => {
107
+ onShowNext(ITEMS, getState, setState)
108
+ }
109
+
110
+ const {
111
+ fromIndex,
112
+ toIndex,
113
+ items
114
+ } = state
115
+
116
+ return (
117
+ <div id="scrollable-container">
118
+ {window.PAGINATION && fromIndex > 0 &&
119
+ <button
120
+ type="button"
121
+ onClick={onShowPrevious_}
122
+ className="load-items-button">
123
+ Show previous
124
+ </button>
125
+ }
126
+ <VirtualScroller
127
+ id="list"
128
+ items={items}
129
+ itemComponent={Item}
130
+ preserveScrollPositionOnPrependItems
131
+ getColumnsCount={getColumnsCount}
132
+ getScrollableContainer={getScrollableContainer}
133
+ />
134
+ {window.PAGINATION && toIndex < ITEMS.length - 1 &&
135
+ <button
136
+ type="button"
137
+ onClick={onShowNext_}
138
+ className="load-items-button">
139
+ Show next
140
+ </button>
141
+ }
142
+ </div>
143
+ )
144
+ }
145
+
146
+ const item = PropTypes.shape({
147
+ username: PropTypes.string.isRequired,
148
+ date: PropTypes.instanceOf(Date).isRequired,
149
+ text: PropTypes.string.isRequired
150
+ })
151
+
152
+ function Item(props) {
153
+ const { children: item } = props
154
+
155
+ const {
156
+ username,
157
+ date,
158
+ text
159
+ } = item
160
+
161
+ return (
162
+ <article className="list-item">
163
+ <a target="_blank" href={`https://twitter.com/${username}`}>
164
+ @{username}
165
+ </a>
166
+ <time dateTime={date.toISOString()}>
167
+ {date.getMonth() + 1}/{date.getDate()}/{date.getFullYear()}
168
+ </time>
169
+ <p>
170
+ {text}
171
+ </p>
172
+ </article>
173
+ )
174
+ }
175
+
176
+ Item.propTypes = {
177
+ children: item.isRequired
178
+ }
179
+
180
+ function Demo() {
181
+ return (
182
+ <section className="container">
183
+ <h1>
184
+ <TwitterLogo/>
185
+ Latest Tweets on #politics
186
+ </h1>
187
+ <VirtualScrollerDemo/>
188
+ <footer>
189
+ © Twitter Inc., 2019
190
+ </footer>
191
+ </section>
192
+ )
193
+ }
194
+
195
+ function TwitterLogo() {
196
+ return (
197
+ <svg className="twitter-logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128">
198
+ <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"/>
199
+ </svg>
200
+ )
201
+ }
202
+
203
+ const root = ReactDOM.createRoot(document.getElementById('root'))
204
+ root.render(<Demo/>)
205
+ </script>
206
+ </body>
207
+ </html>