virtual-scroller 1.13.0 → 1.14.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.
- package/CHANGELOG.md +13 -0
- package/README.md +712 -524
- package/bundle/index-dom.html +2 -0
- package/bundle/virtual-scroller-dom.js +1 -1
- package/bundle/virtual-scroller-dom.js.map +1 -1
- package/bundle/virtual-scroller-react.js +1 -1
- package/bundle/virtual-scroller-react.js.map +1 -1
- package/bundle/virtual-scroller.js +1 -1
- package/bundle/virtual-scroller.js.map +1 -1
- package/commonjs/DOM/VirtualScroller.js +60 -31
- package/commonjs/DOM/VirtualScroller.js.map +1 -1
- package/commonjs/DOM/tbody.js +9 -9
- package/commonjs/DOM/tbody.js.map +1 -1
- package/commonjs/Layout.js +3 -3
- package/commonjs/Layout.js.map +1 -1
- package/commonjs/Scroll.js +3 -3
- package/commonjs/Scroll.js.map +1 -1
- package/commonjs/ScrollableContainerResizeHandler.js +4 -5
- package/commonjs/ScrollableContainerResizeHandler.js.map +1 -1
- package/commonjs/VirtualScroller.constructor.js +15 -27
- package/commonjs/VirtualScroller.constructor.js.map +1 -1
- package/commonjs/VirtualScroller.js +21 -14
- package/commonjs/VirtualScroller.js.map +1 -1
- package/commonjs/VirtualScroller.layout.js +2 -2
- package/commonjs/VirtualScroller.layout.js.map +1 -1
- package/commonjs/VirtualScroller.onRender.js +1 -1
- package/commonjs/VirtualScroller.onRender.js.map +1 -1
- package/commonjs/VirtualScroller.state.js +8 -0
- package/commonjs/VirtualScroller.state.js.map +1 -1
- package/commonjs/react/VirtualScroller.js +15 -5
- package/commonjs/react/VirtualScroller.js.map +1 -1
- package/commonjs/react/useState.js +1 -2
- package/commonjs/react/useState.js.map +1 -1
- package/commonjs/react/useVirtualScroller.js +8 -11
- package/commonjs/react/useVirtualScroller.js.map +1 -1
- package/dom/index.d.ts +5 -4
- package/index.d.ts +0 -1
- package/modules/DOM/VirtualScroller.js +60 -31
- package/modules/DOM/VirtualScroller.js.map +1 -1
- package/modules/DOM/tbody.js +10 -9
- package/modules/DOM/tbody.js.map +1 -1
- package/modules/Layout.js +3 -3
- package/modules/Layout.js.map +1 -1
- package/modules/Scroll.js +3 -3
- package/modules/Scroll.js.map +1 -1
- package/modules/ScrollableContainerResizeHandler.js +4 -5
- package/modules/ScrollableContainerResizeHandler.js.map +1 -1
- package/modules/VirtualScroller.constructor.js +16 -27
- package/modules/VirtualScroller.constructor.js.map +1 -1
- package/modules/VirtualScroller.js +21 -14
- package/modules/VirtualScroller.js.map +1 -1
- package/modules/VirtualScroller.layout.js +2 -2
- package/modules/VirtualScroller.layout.js.map +1 -1
- package/modules/VirtualScroller.onRender.js +1 -1
- package/modules/VirtualScroller.onRender.js.map +1 -1
- package/modules/VirtualScroller.state.js +8 -0
- package/modules/VirtualScroller.state.js.map +1 -1
- package/modules/react/VirtualScroller.js +15 -5
- package/modules/react/VirtualScroller.js.map +1 -1
- package/modules/react/useState.js +1 -2
- package/modules/react/useState.js.map +1 -1
- package/modules/react/useVirtualScroller.js +6 -9
- package/modules/react/useVirtualScroller.js.map +1 -1
- package/package.json +2 -2
- package/source/DOM/VirtualScroller.js +58 -27
- package/source/DOM/tbody.js +10 -9
- package/source/Layout.js +3 -3
- package/source/Scroll.js +3 -3
- package/source/ScrollableContainerResizeHandler.js +4 -4
- package/source/VirtualScroller.constructor.js +13 -27
- package/source/VirtualScroller.js +26 -13
- package/source/VirtualScroller.layout.js +2 -2
- package/source/VirtualScroller.onRender.js +1 -1
- package/source/VirtualScroller.state.js +8 -0
- package/source/react/VirtualScroller.js +16 -4
- package/source/react/useState.js +1 -2
- package/source/react/useVirtualScroller.js +0 -3
|
@@ -5,34 +5,46 @@ import px from '../utility/px.js'
|
|
|
5
5
|
|
|
6
6
|
export default class VirtualScroller {
|
|
7
7
|
constructor(itemsContainerElement, items, renderItem, options = {}) {
|
|
8
|
-
this.
|
|
8
|
+
this.getItemsContainerElement = typeof itemsContainerElement === 'function'
|
|
9
|
+
? itemsContainerElement
|
|
10
|
+
: () => itemsContainerElement
|
|
11
|
+
|
|
9
12
|
this.renderItem = renderItem
|
|
10
13
|
|
|
11
14
|
const {
|
|
12
15
|
onMount,
|
|
13
16
|
onItemUnmount,
|
|
17
|
+
readyToStart,
|
|
18
|
+
readyToRender,
|
|
14
19
|
...restOptions
|
|
15
20
|
} = options
|
|
16
21
|
|
|
22
|
+
// `onMount()` option is deprecated due to no longer being used.
|
|
23
|
+
// If someone thinks there's a valid use case for it, create an issue.
|
|
24
|
+
this._onMount = onMount
|
|
25
|
+
|
|
17
26
|
this.onItemUnmount = onItemUnmount
|
|
18
|
-
this.tbody = this.container.tagName === 'TBODY'
|
|
19
27
|
|
|
20
28
|
this.virtualScroller = new VirtualScrollerCore(
|
|
21
|
-
|
|
29
|
+
this.getItemsContainerElement,
|
|
22
30
|
items,
|
|
23
31
|
{
|
|
24
32
|
...restOptions,
|
|
25
|
-
render: this.render
|
|
26
|
-
tbody: this.tbody
|
|
33
|
+
render: this.render
|
|
27
34
|
}
|
|
28
35
|
)
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
if (readyToRender === false) {
|
|
38
|
+
// Don't automatically perform the initial render of the list.
|
|
39
|
+
// This means that neither `this.render()` nor `this.start()` methods should be called.
|
|
40
|
+
} else if (readyToStart === false) {
|
|
41
|
+
// Don't automatically call the `.start()` method of the "core" component.
|
|
42
|
+
// Still, perform the initial render of the list.
|
|
43
|
+
this.render(this.virtualScroller.getInitialState())
|
|
44
|
+
} else {
|
|
45
|
+
// Calls the `.start()` method of the "core" component.
|
|
46
|
+
// It performs the initial render of the list and starts listening to scroll events.
|
|
47
|
+
this.start()
|
|
36
48
|
}
|
|
37
49
|
}
|
|
38
50
|
|
|
@@ -45,18 +57,24 @@ export default class VirtualScroller {
|
|
|
45
57
|
afterItemsHeight
|
|
46
58
|
} = state
|
|
47
59
|
|
|
60
|
+
const itemsContainerElement = this.getItemsContainerElement()
|
|
61
|
+
|
|
48
62
|
// log('~ On state change ~')
|
|
49
63
|
// log('Previous state', prevState)
|
|
50
64
|
// log('New state', state)
|
|
51
65
|
|
|
52
|
-
// Set container padding
|
|
53
|
-
//
|
|
66
|
+
// Set items container's padding-top and padding-bottom.
|
|
67
|
+
// But only do that for a non-`<tbody/>` item container
|
|
68
|
+
// because, strangely, CSS `padding` doesn't work on a `<tbody/>` element.
|
|
54
69
|
// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
|
|
70
|
+
//
|
|
55
71
|
// `this.virtualScroller` hasn't been initialized yet at this stage,
|
|
56
|
-
// so
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
72
|
+
// so this code can't use `this.virtualScroller.isItemsContainerElementTableBody()` function yet.
|
|
73
|
+
// Instead, it uses its own method of detecting the use of a `<tbody/>` container.
|
|
74
|
+
//
|
|
75
|
+
if (!this.virtualScroller.isItemsContainerElementTableBody()) {
|
|
76
|
+
itemsContainerElement.style.paddingTop = px(beforeItemsHeight)
|
|
77
|
+
itemsContainerElement.style.paddingBottom = px(afterItemsHeight)
|
|
60
78
|
}
|
|
61
79
|
|
|
62
80
|
// Perform an intelligent "diff" re-render if the `items` are the same.
|
|
@@ -64,7 +82,7 @@ export default class VirtualScroller {
|
|
|
64
82
|
// Remove no longer visible items from the DOM.
|
|
65
83
|
if (diffRender) {
|
|
66
84
|
// Decrement instead of increment here because
|
|
67
|
-
// `
|
|
85
|
+
// `itemsContainerElement.removeChild()` changes indexes.
|
|
68
86
|
let i = prevState.lastShownItemIndex
|
|
69
87
|
while (i >= prevState.firstShownItemIndex) {
|
|
70
88
|
if (i >= firstShownItemIndex && i <= lastShownItemIndex) {
|
|
@@ -72,20 +90,20 @@ export default class VirtualScroller {
|
|
|
72
90
|
} else {
|
|
73
91
|
log('DOM: Remove element for item index', i)
|
|
74
92
|
// The item is no longer visible. Remove it.
|
|
75
|
-
this.unmountItem(
|
|
93
|
+
this.unmountItem(itemsContainerElement.childNodes[i - prevState.firstShownItemIndex])
|
|
76
94
|
}
|
|
77
95
|
i--
|
|
78
96
|
}
|
|
79
97
|
} else {
|
|
80
98
|
log('DOM: Rerender the list from scratch')
|
|
81
|
-
while (
|
|
82
|
-
this.unmountItem(
|
|
99
|
+
while (itemsContainerElement.firstChild) {
|
|
100
|
+
this.unmountItem(itemsContainerElement.firstChild)
|
|
83
101
|
}
|
|
84
102
|
}
|
|
85
103
|
|
|
86
104
|
// Add newly visible items to the DOM.
|
|
87
105
|
let shouldPrependItems = diffRender
|
|
88
|
-
const prependBeforeItemElement = shouldPrependItems &&
|
|
106
|
+
const prependBeforeItemElement = shouldPrependItems && itemsContainerElement.firstChild
|
|
89
107
|
let i = firstShownItemIndex
|
|
90
108
|
while (i <= lastShownItemIndex) {
|
|
91
109
|
if (diffRender && i >= prevState.firstShownItemIndex && i <= prevState.lastShownItemIndex) {
|
|
@@ -98,16 +116,28 @@ export default class VirtualScroller {
|
|
|
98
116
|
const item = this.renderItem(items[i])
|
|
99
117
|
if (shouldPrependItems) {
|
|
100
118
|
log('DOM: Prepend element for item index', i)
|
|
101
|
-
// Append `item` to `
|
|
102
|
-
|
|
119
|
+
// Append `item` to `itemsContainerElement` before the retained items.
|
|
120
|
+
itemsContainerElement.insertBefore(item, prependBeforeItemElement)
|
|
103
121
|
} else {
|
|
104
122
|
log('DOM: Append element for item index', i)
|
|
105
|
-
// Append `item` to `
|
|
106
|
-
|
|
123
|
+
// Append `item` to `itemsContainerElement`.
|
|
124
|
+
itemsContainerElement.appendChild(item)
|
|
107
125
|
}
|
|
108
126
|
}
|
|
109
127
|
i++
|
|
110
128
|
}
|
|
129
|
+
|
|
130
|
+
// Call `onMount()` function when the list has rendered for the first time.
|
|
131
|
+
//
|
|
132
|
+
// `onMount()` option is deprecated due to no longer being used.
|
|
133
|
+
// If someone thinks there's a valid use case for it, create an issue.
|
|
134
|
+
//
|
|
135
|
+
if (!this._isMounted) {
|
|
136
|
+
this._isMounted = true
|
|
137
|
+
if (this._onMount) {
|
|
138
|
+
this._onMount()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
111
141
|
}
|
|
112
142
|
|
|
113
143
|
// Public API. Should be "bound" to `this`.
|
|
@@ -135,7 +165,8 @@ export default class VirtualScroller {
|
|
|
135
165
|
}
|
|
136
166
|
|
|
137
167
|
unmountItem(itemElement) {
|
|
138
|
-
this.
|
|
168
|
+
this.getItemsContainerElement().removeChild(itemElement)
|
|
169
|
+
|
|
139
170
|
if (this.onItemUnmount) {
|
|
140
171
|
this.onItemUnmount(itemElement)
|
|
141
172
|
}
|
package/source/DOM/tbody.js
CHANGED
|
@@ -5,17 +5,18 @@ import px from '../utility/px.js'
|
|
|
5
5
|
|
|
6
6
|
export const BROWSER_NOT_SUPPORTED_ERROR = 'It looks like you\'re using Internet Explorer which doesn\'t support CSS variables required for a <tbody/> container. VirtualScroller has been switched into "bypass" mode (render all items). See: https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
//
|
|
8
|
+
function isInternetExplorer() {
|
|
9
|
+
// This function detects Internet Explorer using `documentMode` IE-only property.
|
|
10
10
|
// https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie
|
|
11
|
-
// `documentMode`
|
|
12
|
-
// Supports IE 9-11. Maybe even IE 8.
|
|
11
|
+
// The `documentMode` property exists in IE 9-11. Maybe even IE 8.
|
|
13
12
|
// http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
return typeof window !== 'undefined' && Boolean(window.document.documentMode)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function supportsTbody() {
|
|
17
|
+
// Internet Explorer doesn't support CSS Variables
|
|
18
|
+
// and therefore it will not be able to apply the `<tbody/>` workaround.
|
|
19
|
+
return !isInternetExplorer()
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export const TBODY_CLASS_NAME = 'VirtualScroller'
|
package/source/Layout.js
CHANGED
|
@@ -3,7 +3,7 @@ import ScrollableContainerNotReadyError from './ScrollableContainerNotReadyError
|
|
|
3
3
|
|
|
4
4
|
export default class Layout {
|
|
5
5
|
constructor({
|
|
6
|
-
|
|
6
|
+
isInBypassMode,
|
|
7
7
|
getInitialEstimatedItemHeight,
|
|
8
8
|
getInitialEstimatedVisibleItemRowsCount,
|
|
9
9
|
measureItemsBatchSize,
|
|
@@ -19,7 +19,7 @@ export default class Layout {
|
|
|
19
19
|
getMaxVisibleAreaHeight,
|
|
20
20
|
getPreviouslyCalculatedLayout
|
|
21
21
|
}) {
|
|
22
|
-
this.
|
|
22
|
+
this.isInBypassMode = isInBypassMode
|
|
23
23
|
this.getInitialEstimatedItemHeight = getInitialEstimatedItemHeight
|
|
24
24
|
this.getInitialEstimatedVisibleItemRowsCount = getInitialEstimatedVisibleItemRowsCount
|
|
25
25
|
this.measureItemsBatchSize = measureItemsBatchSize
|
|
@@ -100,7 +100,7 @@ export default class Layout {
|
|
|
100
100
|
columnsCount,
|
|
101
101
|
firstShownItemIndex
|
|
102
102
|
}) {
|
|
103
|
-
if (this.
|
|
103
|
+
if (this.isInBypassMode()) {
|
|
104
104
|
return itemsCount - 1
|
|
105
105
|
}
|
|
106
106
|
// On server side, at initialization time,
|
package/source/Scroll.js
CHANGED
|
@@ -8,7 +8,7 @@ import log from './utility/debug.js'
|
|
|
8
8
|
|
|
9
9
|
export default class Scroll {
|
|
10
10
|
constructor({
|
|
11
|
-
|
|
11
|
+
isInBypassMode,
|
|
12
12
|
scrollableContainer,
|
|
13
13
|
itemsContainer,
|
|
14
14
|
onScroll,
|
|
@@ -23,7 +23,7 @@ export default class Scroll {
|
|
|
23
23
|
onScrolledToTop,
|
|
24
24
|
waitForScrollingToStop
|
|
25
25
|
}) {
|
|
26
|
-
this.
|
|
26
|
+
this.isInBypassMode = isInBypassMode
|
|
27
27
|
this.scrollableContainer = scrollableContainer
|
|
28
28
|
this.itemsContainer = itemsContainer
|
|
29
29
|
this.onScroll = onScroll
|
|
@@ -98,7 +98,7 @@ export default class Scroll {
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
if (this.
|
|
101
|
+
if (this.isInBypassMode()) {
|
|
102
102
|
return
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import debounce from './utility/debounce.js'
|
|
2
|
-
import log from './utility/debug.js'
|
|
2
|
+
// import log from './utility/debug.js'
|
|
3
3
|
|
|
4
4
|
export default class ScrollableContainerResizeHandler {
|
|
5
5
|
constructor({
|
|
6
|
-
|
|
6
|
+
isInBypassMode,
|
|
7
7
|
getWidth,
|
|
8
8
|
getHeight,
|
|
9
9
|
listenForResize,
|
|
@@ -13,7 +13,7 @@ export default class ScrollableContainerResizeHandler {
|
|
|
13
13
|
onWidthChange,
|
|
14
14
|
onNoChange
|
|
15
15
|
}) {
|
|
16
|
-
this.
|
|
16
|
+
this.isInBypassMode = isInBypassMode
|
|
17
17
|
|
|
18
18
|
this.onHeightChange = onHeightChange
|
|
19
19
|
this.onWidthChange = onWidthChange
|
|
@@ -35,7 +35,7 @@ export default class ScrollableContainerResizeHandler {
|
|
|
35
35
|
|
|
36
36
|
start() {
|
|
37
37
|
this.isActive = true
|
|
38
|
-
if (this.
|
|
38
|
+
if (this.isInBypassMode()) {
|
|
39
39
|
return
|
|
40
40
|
}
|
|
41
41
|
this.width = this.getWidth()
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
supportsTbody,
|
|
3
|
-
BROWSER_NOT_SUPPORTED_ERROR
|
|
4
|
-
} from './DOM/tbody.js'
|
|
5
|
-
|
|
6
1
|
import DOMEngine from './DOM/Engine.js'
|
|
7
2
|
|
|
8
3
|
import Layout, { LAYOUT_REASON } from './Layout.js'
|
|
@@ -12,7 +7,7 @@ import Scroll from './Scroll.js'
|
|
|
12
7
|
import ListHeightMeasurement from './ListHeightMeasurement.js'
|
|
13
8
|
import ItemHeights from './ItemHeights.js'
|
|
14
9
|
|
|
15
|
-
import log, { warn
|
|
10
|
+
import log, { warn } from './utility/debug.js'
|
|
16
11
|
|
|
17
12
|
import createStateHelpers from './VirtualScroller.state.js'
|
|
18
13
|
import createVerticalSpacingHelpers from './VirtualScroller.verticalSpacing.js'
|
|
@@ -34,6 +29,7 @@ export default function VirtualScrollerConstructor(
|
|
|
34
29
|
options = {}
|
|
35
30
|
) {
|
|
36
31
|
const {
|
|
32
|
+
bypass,
|
|
37
33
|
render,
|
|
38
34
|
state,
|
|
39
35
|
getInitialItemState = () => {},
|
|
@@ -46,7 +42,6 @@ export default function VirtualScrollerConstructor(
|
|
|
46
42
|
measureItemsBatchSize = 50,
|
|
47
43
|
getColumnsCount,
|
|
48
44
|
getItemId,
|
|
49
|
-
tbody,
|
|
50
45
|
// `estimatedItemHeight` is deprecated, use `getEstimatedItemHeight()` instead.
|
|
51
46
|
estimatedItemHeight,
|
|
52
47
|
getEstimatedVisibleItemRowsCount,
|
|
@@ -59,7 +54,6 @@ export default function VirtualScrollerConstructor(
|
|
|
59
54
|
} = options
|
|
60
55
|
|
|
61
56
|
let {
|
|
62
|
-
bypass,
|
|
63
57
|
getEstimatedItemHeight,
|
|
64
58
|
getScrollableContainer
|
|
65
59
|
} = options
|
|
@@ -104,21 +98,6 @@ export default function VirtualScrollerConstructor(
|
|
|
104
98
|
throw new Error('[virtual-scroller] `getState`/`setState` options usage has changed in the new version. See the readme for more details.')
|
|
105
99
|
}
|
|
106
100
|
|
|
107
|
-
// Work around `<tbody/>` not being able to have `padding`.
|
|
108
|
-
// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
|
|
109
|
-
if (tbody) {
|
|
110
|
-
if (this.engine !== DOMEngine) {
|
|
111
|
-
throw new Error('[virtual-scroller] `tbody` option is only supported for DOM rendering engine')
|
|
112
|
-
}
|
|
113
|
-
log('~ <tbody/> detected ~')
|
|
114
|
-
this.tbody = true
|
|
115
|
-
if (!supportsTbody()) {
|
|
116
|
-
log('~ <tbody/> not supported ~')
|
|
117
|
-
reportError(BROWSER_NOT_SUPPORTED_ERROR)
|
|
118
|
-
bypass = true
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
101
|
if (bypass) {
|
|
123
102
|
log('~ "bypass" mode ~')
|
|
124
103
|
}
|
|
@@ -133,7 +112,7 @@ export default function VirtualScrollerConstructor(
|
|
|
133
112
|
// It turned out that unmounting large React component trees
|
|
134
113
|
// is a very long process, so `VirtualScroller` does seem to
|
|
135
114
|
// make sense when used in a React application.
|
|
136
|
-
this.
|
|
115
|
+
this._bypass = bypass
|
|
137
116
|
// this.bypassBatchSize = bypassBatchSize || 10
|
|
138
117
|
|
|
139
118
|
// Using `setTimeout()` in render loop is a workaround
|
|
@@ -238,6 +217,13 @@ function createHelpers({
|
|
|
238
217
|
this.itemsContainer.clear()
|
|
239
218
|
}
|
|
240
219
|
|
|
220
|
+
this.isItemsContainerElementTableBody = () => {
|
|
221
|
+
return this.engine === DOMEngine &&
|
|
222
|
+
this.getItemsContainerElement().tagName === 'TBODY'
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
this.isInBypassMode = () => this._bypass
|
|
226
|
+
|
|
241
227
|
this.scrollableContainer = this.engine.createScrollableContainer(
|
|
242
228
|
getScrollableContainer,
|
|
243
229
|
this.getItemsContainerElement
|
|
@@ -251,7 +237,7 @@ function createHelpers({
|
|
|
251
237
|
})
|
|
252
238
|
|
|
253
239
|
this.layout = new Layout({
|
|
254
|
-
|
|
240
|
+
isInBypassMode: this.isInBypassMode,
|
|
255
241
|
getInitialEstimatedItemHeight: getEstimatedItemHeight,
|
|
256
242
|
getInitialEstimatedVisibleItemRowsCount: getEstimatedVisibleItemRowsCount,
|
|
257
243
|
measureItemsBatchSize,
|
|
@@ -278,7 +264,7 @@ function createHelpers({
|
|
|
278
264
|
})
|
|
279
265
|
|
|
280
266
|
this.scrollableContainerResizeHandler = new ScrollableContainerResizeHandler({
|
|
281
|
-
|
|
267
|
+
isInBypassMode: this.isInBypassMode,
|
|
282
268
|
getWidth: () => this.scrollableContainer.getWidth(),
|
|
283
269
|
getHeight: () => this.scrollableContainer.getHeight(),
|
|
284
270
|
listenForResize: (listener) => this.scrollableContainer.onResize(listener),
|
|
@@ -308,7 +294,7 @@ function createHelpers({
|
|
|
308
294
|
})
|
|
309
295
|
|
|
310
296
|
this.scroll = new Scroll({
|
|
311
|
-
|
|
297
|
+
isInBypassMode: this.isInBypassMode,
|
|
312
298
|
scrollableContainer: this.scrollableContainer,
|
|
313
299
|
itemsContainer: this.itemsContainer,
|
|
314
300
|
waitForScrollingToStop,
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import VirtualScrollerConstructor from './VirtualScroller.constructor.js'
|
|
2
|
-
import { hasTbodyStyles, addTbodyStyles } from './DOM/tbody.js'
|
|
3
2
|
import { LAYOUT_REASON } from './Layout.js'
|
|
4
|
-
import log, { warn } from './utility/debug.js'
|
|
3
|
+
import log, { warn, reportError } from './utility/debug.js'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
supportsTbody,
|
|
7
|
+
hasTbodyStyles,
|
|
8
|
+
addTbodyStyles,
|
|
9
|
+
BROWSER_NOT_SUPPORTED_ERROR
|
|
10
|
+
} from './DOM/tbody.js'
|
|
5
11
|
|
|
6
12
|
export default class VirtualScroller {
|
|
7
13
|
/**
|
|
8
|
-
* @param {function} getItemsContainerElement — Returns the container DOM `Element`.
|
|
14
|
+
* @param {function} getItemsContainerElement — Returns the items container DOM `Element`.
|
|
9
15
|
* @param {any[]} items — The list of items.
|
|
10
16
|
* @param {Object} [options] — See README.md.
|
|
11
17
|
* @return {VirtualScroller}
|
|
@@ -35,13 +41,8 @@ export default class VirtualScroller {
|
|
|
35
41
|
const isRestart = this._isActive === false
|
|
36
42
|
|
|
37
43
|
if (!isRestart) {
|
|
44
|
+
this.setUpState()
|
|
38
45
|
this.waitingForRender = true
|
|
39
|
-
|
|
40
|
-
// If no custom state storage has been configured, use the default one.
|
|
41
|
-
// Also sets the initial state.
|
|
42
|
-
if (!this._usesCustomStateStorage) {
|
|
43
|
-
this.useDefaultStateStorage()
|
|
44
|
-
}
|
|
45
46
|
// If `render()` function parameter was passed,
|
|
46
47
|
// perform an initial render.
|
|
47
48
|
if (this._render) {
|
|
@@ -67,11 +68,23 @@ export default class VirtualScroller {
|
|
|
67
68
|
// Reset `_isSettingNewItems` flag just in case it has some "leftover" value.
|
|
68
69
|
this._isSettingNewItems = undefined
|
|
69
70
|
|
|
70
|
-
//
|
|
71
|
+
// When `<tbody/>` is used as an items container element,
|
|
72
|
+
// `virtual-scroller` has to work around the HTML bug of
|
|
73
|
+
// `padding` not working on a `<tbody/>` element.
|
|
71
74
|
// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
|
|
72
|
-
if (this.
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
+
if (!this.isInBypassMode()) {
|
|
76
|
+
if (this.isItemsContainerElementTableBody()) {
|
|
77
|
+
if (supportsTbody()) {
|
|
78
|
+
if (!hasTbodyStyles(this.getItemsContainerElement())) {
|
|
79
|
+
log('~ <tbody/> container ~')
|
|
80
|
+
addTbodyStyles(this.getItemsContainerElement())
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
log('~ <tbody/> container not supported ~')
|
|
84
|
+
reportError(BROWSER_NOT_SUPPORTED_ERROR)
|
|
85
|
+
log('~ enter "bypass" mode ~')
|
|
86
|
+
this._bypass = true
|
|
87
|
+
}
|
|
75
88
|
}
|
|
76
89
|
}
|
|
77
90
|
|
|
@@ -122,7 +122,7 @@ export default function() {
|
|
|
122
122
|
const layoutDuration = Date.now() - startedAt
|
|
123
123
|
|
|
124
124
|
// Debugging.
|
|
125
|
-
log('~ Calculated Layout' + (this.
|
|
125
|
+
log('~ Calculated Layout' + (this.isInBypassMode() ? ' (bypass)' : '') + ' ~')
|
|
126
126
|
if (layoutDuration < SLOW_LAYOUT_DURATION) {
|
|
127
127
|
// log('Calculated in', layoutDuration, 'ms')
|
|
128
128
|
} else {
|
|
@@ -234,7 +234,7 @@ export default function() {
|
|
|
234
234
|
|
|
235
235
|
const visibleAreaInsideTheList = getCoordinatesOfVisibleAreaInsideTheList.call(this)
|
|
236
236
|
|
|
237
|
-
if (this.
|
|
237
|
+
if (this.isInBypassMode()) {
|
|
238
238
|
return {
|
|
239
239
|
firstShownItemIndex: 0,
|
|
240
240
|
lastShownItemIndex: itemsCount - 1,
|
|
@@ -27,7 +27,7 @@ export default function() {
|
|
|
27
27
|
// Update `<tbody/>` `padding`.
|
|
28
28
|
// (`<tbody/>` is different in a way that it can't have `margin`, only `padding`).
|
|
29
29
|
// https://gitlab.com/catamphetamine/virtual-scroller/-/issues/1
|
|
30
|
-
if (this.
|
|
30
|
+
if (this.isItemsContainerElementTableBody()) {
|
|
31
31
|
setTbodyPadding(
|
|
32
32
|
this.getItemsContainerElement(),
|
|
33
33
|
newState.beforeItemsHeight,
|
|
@@ -166,6 +166,14 @@ export default function createStateHelpers({
|
|
|
166
166
|
setInitialState(this.getInitialState())
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
this.setUpState = () => {
|
|
170
|
+
// If no custom state storage has been configured, use the default one.
|
|
171
|
+
// Also sets the initial state.
|
|
172
|
+
if (!this._usesCustomStateStorage) {
|
|
173
|
+
this.useDefaultStateStorage()
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
169
177
|
function defaultGetState() {
|
|
170
178
|
return this.state
|
|
171
179
|
}
|
|
@@ -37,6 +37,8 @@ function VirtualScroller({
|
|
|
37
37
|
getEstimatedItemHeight,
|
|
38
38
|
getEstimatedVisibleItemRowsCount,
|
|
39
39
|
bypass,
|
|
40
|
+
// `tbody` property is deprecated.
|
|
41
|
+
// Pass `as: "tbody"` property instead.
|
|
40
42
|
tbody,
|
|
41
43
|
// `preserveScrollPosition` property name is deprecated,
|
|
42
44
|
// use `preserveScrollPositionOnPrependItems` property instead.
|
|
@@ -62,6 +64,16 @@ function VirtualScroller({
|
|
|
62
64
|
getInitialItemState,
|
|
63
65
|
...rest
|
|
64
66
|
}, ref) {
|
|
67
|
+
// It turns out that since May 2022, `useVirtualScroller()` hook completely ignored the `tbody` property.
|
|
68
|
+
// Instead, it always derived `tbody` property value from `as` property value by comparing it to `"tbody"` string.
|
|
69
|
+
// As a result, it seemed like the explicit passing of `tbody` property didn't really work as intended.
|
|
70
|
+
// In the end, it was decided that perhaps `tbody` property value should always be derived from `as` property
|
|
71
|
+
// without a developer having to manually specify it. So the `tbody` property was deprecated.
|
|
72
|
+
// It still exists though for backwards compatibility with the older versions of the package.
|
|
73
|
+
if (tbody === undefined) {
|
|
74
|
+
tbody = AsComponent === 'tbody'
|
|
75
|
+
}
|
|
76
|
+
|
|
65
77
|
// List items "container" DOM Element reference.
|
|
66
78
|
const container = useRef()
|
|
67
79
|
|
|
@@ -75,7 +87,6 @@ function VirtualScroller({
|
|
|
75
87
|
getEstimatedVisibleItemRowsCount,
|
|
76
88
|
bypass,
|
|
77
89
|
// bypassBatchSize,
|
|
78
|
-
tbody,
|
|
79
90
|
onItemInitialRender,
|
|
80
91
|
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
81
92
|
onItemFirstRender,
|
|
@@ -109,8 +120,7 @@ function VirtualScroller({
|
|
|
109
120
|
stateToRender
|
|
110
121
|
} = useState({
|
|
111
122
|
initialState: _initialState,
|
|
112
|
-
onRender: virtualScroller.onRender
|
|
113
|
-
itemsProperty
|
|
123
|
+
onRender: virtualScroller.onRender
|
|
114
124
|
})
|
|
115
125
|
|
|
116
126
|
// Use custom (external) state storage in the `VirtualScroller`.
|
|
@@ -283,7 +293,9 @@ VirtualScroller.propTypes = {
|
|
|
283
293
|
getEstimatedVisibleItemRowsCount: PropTypes.func,
|
|
284
294
|
bypass: PropTypes.bool,
|
|
285
295
|
// bypassBatchSize: PropTypes.number,
|
|
286
|
-
tbody
|
|
296
|
+
// `tbody` property is deprecated.
|
|
297
|
+
// Pass `as: "tbody"` property instead.
|
|
298
|
+
// tbody: PropTypes.bool,
|
|
287
299
|
preserveScrollPositionOnPrependItems: PropTypes.bool,
|
|
288
300
|
// `preserveScrollPosition` property name is deprecated,
|
|
289
301
|
// use `preserveScrollPositionOnPrependItems` instead.
|
package/source/react/useState.js
CHANGED
|
@@ -9,8 +9,7 @@ import useLayoutEffectDontMountTwiceInStrictMode from './useLayoutEffectDontMoun
|
|
|
9
9
|
// Creates state management functions.
|
|
10
10
|
export default function _useState({
|
|
11
11
|
initialState,
|
|
12
|
-
onRender
|
|
13
|
-
itemsProperty
|
|
12
|
+
onRender
|
|
14
13
|
}) {
|
|
15
14
|
// This is a state variable that is used to re-render the component.
|
|
16
15
|
// Right after the component has finished re-rendering,
|
|
@@ -11,7 +11,6 @@ export default function useVirtualScroller({
|
|
|
11
11
|
getEstimatedVisibleItemRowsCount,
|
|
12
12
|
bypass,
|
|
13
13
|
// bypassBatchSize,
|
|
14
|
-
tbody,
|
|
15
14
|
onItemInitialRender,
|
|
16
15
|
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
17
16
|
onItemFirstRender,
|
|
@@ -44,7 +43,6 @@ export default function useVirtualScroller({
|
|
|
44
43
|
getEstimatedVisibleItemRowsCount,
|
|
45
44
|
bypass,
|
|
46
45
|
// bypassBatchSize,
|
|
47
|
-
tbody,
|
|
48
46
|
onItemInitialRender,
|
|
49
47
|
// `onItemFirstRender(i)` is deprecated, use `onItemInitialRender(item)` instead.
|
|
50
48
|
onItemFirstRender,
|
|
@@ -57,7 +55,6 @@ export default function useVirtualScroller({
|
|
|
57
55
|
getScrollableContainer,
|
|
58
56
|
getColumnsCount,
|
|
59
57
|
getItemId,
|
|
60
|
-
tbody: AsComponent === 'tbody',
|
|
61
58
|
state: initialState,
|
|
62
59
|
getInitialItemState,
|
|
63
60
|
onStateChange
|