Skip to content

Commit f11fd2c

Browse files
authored
Merge pull request #21 from bvaughn/master
rebase to future changes in main repo
2 parents b00b18f + 005be24 commit f11fd2c

File tree

12 files changed

+368
-65
lines changed

12 files changed

+368
-65
lines changed

.babelrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ if (env === 'commonjs' || env === 'es') {
1414
plugins: [
1515
'@babel/plugin-transform-runtime',
1616
'@babel/plugin-proposal-class-properties',
17+
'@babel/plugin-transform-flow-comments',
1718
['flow-react-proptypes', {deadCode: true, useESModules: true}],
1819
['transform-react-remove-prop-types', {mode: 'wrap'}],
1920
],

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
## Changelog
22

3+
##### NEXT
4+
5+
- Update peer dependencies to allow React 17 ([levenleven](https://github.com/levenleven) - [#1625](https://github.com/bvaughn/react-virtualized/pull/1625))
6+
- Use DOM API instead of creating Trusted Types policy to append a markup ([shhnjk](https://github.com/shhnjk) - [#1627](https://github.com/bvaughn/react-virtualized/pull/1627))
7+
- Fix bug in WindowScroller::updatePosition ([yamadapc](https://github.com/yamadapc) - [#1642](https://github.com/bvaughn/react-virtualized/pull/1642), [#1648](https://github.com/bvaughn/react-virtualized/pull/1648))
8+
- Fix babel tranform es error ([fupengl](https://github.com/fupengl) - [#1651](https://github.com/bvaughn/react-virtualized/pull/1651))
9+
- Fix issue with unused import being emitted ([mewhhaha](https://github.com/mewhhaha) - [#1635](https://github.com/bvaughn/react-virtualized/pull/1635))
10+
- Fix grid roles for accessbility ([asnewman](https://github.com/asnewman) - [#1624](https://github.com/bvaughn/react-virtualized/pull/1624))
11+
312
##### 9.22.3
413

514
- Add Trusted Types support ([shhnjk](https://github.com/shhnjk) - [#1614](https://github.com/bvaughn/react-virtualized/pull/1614))

docs/Grid.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,19 @@ function cellRangeRenderer({
182182
This is an advanced property.
183183
This function is responsible for calculating the number of cells to overscan before and after a specified range. By default, React Virtualized optimizes the number of cells to overscan based on scroll direction. If you'd like to customize this behavior, you may want to fork the [`defaultOverscanIndicesGetter`](https://github.com/bvaughn/react-virtualized/blob/master/source/Grid/defaultOverscanIndicesGetter.js) function.
184184

185-
```
186-
function overscanIndicesGetter ({
187-
direction, // One of "horizontal" or "vertical"
188-
cellCount, // Number of rows or columns in the current axis
189-
scrollDirection, // 1 (forwards) or -1 (backwards)
185+
```js
186+
function overscanIndicesGetter({
187+
direction, // One of "horizontal" or "vertical"
188+
cellCount, // Number of rows or columns in the current axis
189+
scrollDirection, // 1 (forwards) or -1 (backwards)
190190
overscanCellsCount, // Maximum number of cells to over-render in either direction
191-
startIndex, // Begin of range of visible cells
192-
stopIndex // End of range of visible cells
191+
startIndex, // Begin of range of visible cells
192+
stopIndex, // End of range of visible cells
193193
}) {
194194
return {
195195
overscanStartIndex: Math.max(0, startIndex - overscanCellsCount),
196-
overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount)
197-
}
196+
overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount),
197+
};
198198
}
199199
```
200200

jest-puppeteer.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
launch: {
3+
headless: process.env.HEADLESS !== 'false',
4+
devtools: process.env.DEVTOOLS === 'true',
5+
},
6+
};

package.json

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"@babel/plugin-proposal-class-properties": "^7.7.0",
7777
"@babel/plugin-transform-modules-commonjs": "^7.7.0",
7878
"@babel/plugin-transform-runtime": "^7.6.2",
79+
"@babel/plugin-transform-flow-comments": "^7.12.13",
7980
"@babel/polyfill": "^7.7.0",
8081
"@babel/preset-env": "^7.7.1",
8182
"@babel/preset-flow": "^7.0.0",
@@ -118,12 +119,12 @@
118119
"prettier": "1.19.1",
119120
"pretty-quick": "^2.0.1",
120121
"puppeteer": "^2.0.0",
121-
"react": "^16.11.0",
122+
"react": "^17.0.1",
122123
"react-codemirror": "^1.0.0",
123-
"react-dom": "^16.11.0",
124-
"react-router": "^5.1.2",
125-
"react-router-dom": "^5.1.2",
126-
"react-test-renderer": "^16.11.0",
124+
"react-dom": "^17.0.1",
125+
"react-router": "^5.2.0",
126+
"react-router-dom": "^5.2.0",
127+
"react-test-renderer": "^17.0.1",
127128
"rimraf": "^3.0.0",
128129
"rollup": "^1.26.5",
129130
"rollup-plugin-babel": "^4.3.3",
@@ -146,8 +147,8 @@
146147
"react-lifecycles-compat": "^3.0.4"
147148
},
148149
"peerDependencies": {
149-
"react": "^15.3.0 || ^16.0.0-alpha",
150-
"react-dom": "^15.3.0 || ^16.0.0-alpha"
150+
"react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0",
151+
"react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0"
151152
},
152153
"browserify": {
153154
"transform": [

source/Grid/Grid.jest.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1102,7 +1102,7 @@ describe('Grid', () => {
11021102
});
11031103
});
11041104

1105-
describe('styles, classNames, and ids', () => {
1105+
describe('styles, classNames, ids, and roles', () => {
11061106
it('should use the expected global CSS classNames', () => {
11071107
const rendered = findDOMNode(render(getMarkup()));
11081108
expect(rendered.className).toEqual('ReactVirtualized__Grid');
@@ -1132,6 +1132,12 @@ describe('Grid', () => {
11321132
.style.backgroundColor,
11331133
).toEqual('red');
11341134
});
1135+
1136+
it('should have the gridcell role', () => {
1137+
const containerStyle = {backgroundColor: 'red'};
1138+
const rendered = findDOMNode(render(getMarkup({containerStyle})));
1139+
expect(rendered.querySelectorAll('[role="gridcell"]').length).toEqual(20);
1140+
});
11351141
});
11361142

11371143
describe('onScroll', () => {

source/Grid/Grid.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class Grid extends React.PureComponent<Props, State> {
262262
autoHeight: false,
263263
autoWidth: false,
264264
cellRangeRenderer: defaultCellRangeRenderer,
265-
containerRole: 'rowgroup',
265+
containerRole: 'row',
266266
containerStyle: {},
267267
estimatedColumnSize: 100,
268268
estimatedRowSize: 30,

source/Grid/defaultCellRangeRenderer.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @flow */
22

33
import type {CellRangeRendererParams} from './types';
4+
import React from 'react';
45

56
/**
67
* Default implementation of cellRangeRenderer used by Grid.
@@ -138,6 +139,10 @@ export default function defaultCellRangeRenderer({
138139
warnAboutMissingStyle(parent, renderedCell);
139140
}
140141

142+
if (!renderedCell.props.role) {
143+
renderedCell = React.cloneElement(renderedCell, {role: 'gridcell'});
144+
}
145+
141146
renderedCells.push(renderedCell);
142147
}
143148
}
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/**
2+
* @jest-environment jest-environment-puppeteer
3+
*/
4+
5+
const bootstrap = async () => {
6+
const page = await global.browser.newPage();
7+
const scripts = [
8+
'./node_modules/react/umd/react.development.js',
9+
'./node_modules/react-dom/umd/react-dom.development.js',
10+
'./dist/umd/react-virtualized.js',
11+
];
12+
13+
for (const path of scripts) {
14+
await page.addScriptTag({path});
15+
}
16+
17+
return page;
18+
};
19+
20+
const renderWindowScroller = updateScrollTopOnUpdatePosition => {
21+
const {render} = window.ReactDOM;
22+
const {createElement, useState, useEffect} = window.React;
23+
const {WindowScroller} = window.ReactVirtualized;
24+
25+
const container = document.createElement('div');
26+
container.id = 'container';
27+
document.body.appendChild(container);
28+
document.body.style.margin = 0;
29+
30+
function Header({height}) {
31+
return createElement('div', {style: {height, backgroundColor: 'red'}});
32+
}
33+
34+
function App() {
35+
const [height, setHeight] = useState(100);
36+
window.setHeaderHeight = setHeight;
37+
useEffect(() => () => (window.setHeaderHeight = null));
38+
39+
return createElement(
40+
'div',
41+
{},
42+
createElement(Header, {height}),
43+
createElement(
44+
WindowScroller,
45+
{
46+
updateScrollTopOnUpdatePosition,
47+
ref: windowScroller => {
48+
window.windowScroller = windowScroller;
49+
},
50+
onScroll: window.scrollFn,
51+
onResize: window.resizeFn,
52+
},
53+
({width, scrollTop}) => {
54+
console.log({scrollTop});
55+
window.windowScrollerScrollTop = scrollTop;
56+
return createElement('div', {
57+
style: {
58+
width,
59+
height: 3000,
60+
backgroundColor: 'yellow',
61+
},
62+
});
63+
},
64+
),
65+
);
66+
}
67+
68+
render(
69+
createElement(
70+
'div',
71+
{'data-test-id': 'main-container'},
72+
createElement(App, {}),
73+
),
74+
container,
75+
);
76+
};
77+
78+
jest.setTimeout(1200000);
79+
80+
const delay = time => new Promise(resolve => setTimeout(resolve, time));
81+
82+
test('will react to header height updates if notified through updatePosition', async () => {
83+
const page = await bootstrap();
84+
const scrollFn = jest.fn();
85+
const resizeFn = jest.fn();
86+
await page.exposeFunction('scrollFn', scrollFn);
87+
await page.exposeFunction('resizeFn', resizeFn);
88+
89+
await page.setViewport({width: 400, height: 600});
90+
await page.evaluate(renderWindowScroller, true);
91+
92+
const el = await page.$('[data-test-id="main-container"]');
93+
expect(el).not.toBeNull();
94+
95+
await page.evaluate(() => window.scrollTo(0, 200));
96+
await delay(500);
97+
98+
{
99+
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
100+
expect(scrollTop).toEqual(100);
101+
}
102+
await delay(500);
103+
104+
// Update the header height
105+
await page.evaluate(() => {
106+
console.log('change header height');
107+
window.setHeaderHeight(200);
108+
});
109+
await delay(500);
110+
111+
await page.evaluate(() => {
112+
console.log('update position');
113+
window.windowScroller.updatePosition();
114+
});
115+
await delay(500);
116+
117+
// Despite header updates, we'd expect the scrollTop to be the same.
118+
{
119+
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
120+
expect(scrollTop).toEqual(100);
121+
}
122+
});
123+
124+
test('will NOT react to header height updates if notified through updatePosition if `updateScrollTopOnUpdatePosition` is false', async () => {
125+
const page = await bootstrap();
126+
const scrollFn = jest.fn();
127+
const resizeFn = jest.fn();
128+
await page.exposeFunction('scrollFn', scrollFn);
129+
await page.exposeFunction('resizeFn', resizeFn);
130+
131+
await page.setViewport({width: 400, height: 600});
132+
await page.evaluate(renderWindowScroller, false);
133+
134+
const el = await page.$('[data-test-id="main-container"]');
135+
expect(el).not.toBeNull();
136+
137+
await page.evaluate(() => window.scrollTo(0, 200));
138+
await delay(500);
139+
140+
{
141+
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
142+
expect(scrollTop).toEqual(100);
143+
}
144+
await delay(500);
145+
146+
// Update the header height
147+
await page.evaluate(() => {
148+
console.log('change header height');
149+
window.setHeaderHeight(200);
150+
});
151+
await delay(500);
152+
153+
await page.evaluate(() => {
154+
console.log('update position');
155+
window.windowScroller.updatePosition();
156+
});
157+
await delay(500);
158+
159+
// Despite header updates, we'd expect the scrollTop to be the same.
160+
// As the fix is off, this will fail.
161+
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
162+
expect(() => {
163+
expect(scrollTop).toEqual(100);
164+
}).toThrow();
165+
});
166+
167+
test('will properly process scroll events after header height updates', async () => {
168+
const page = await bootstrap();
169+
const scrollFn = jest.fn();
170+
const resizeFn = jest.fn();
171+
await page.exposeFunction('scrollFn', scrollFn);
172+
await page.exposeFunction('resizeFn', resizeFn);
173+
174+
await page.setViewport({width: 400, height: 600});
175+
await page.evaluate(renderWindowScroller, true);
176+
177+
const el = await page.$('[data-test-id="main-container"]');
178+
expect(el).not.toBeNull();
179+
180+
await page.evaluate(() => window.scrollTo(0, 200));
181+
await delay(500);
182+
183+
{
184+
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
185+
expect(scrollTop).toEqual(100);
186+
}
187+
await delay(500);
188+
189+
// Update the header height
190+
await page.evaluate(() => {
191+
window.setHeaderHeight(200);
192+
});
193+
await delay(500);
194+
195+
await page.evaluate(() => {
196+
window.windowScroller.updatePosition();
197+
});
198+
await delay(500);
199+
// This is only 50px under the first position
200+
await page.evaluate(() => window.scrollTo(0, 350));
201+
202+
{
203+
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
204+
expect(scrollTop).toEqual(150);
205+
}
206+
});

source/WindowScroller/WindowScroller.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ type Props = {
4747

4848
/** Width used for server-side rendering */
4949
serverWidth: number,
50+
51+
/** Force scrollTop updates when .updatePosition is called, fixing forced header height change updates */
52+
updateScrollTopOnUpdatePosition?: boolean,
5053
};
5154

5255
type State = {
@@ -118,6 +121,11 @@ export default class WindowScroller extends React.PureComponent<Props, State> {
118121
width: dimensions.width,
119122
});
120123
}
124+
125+
if (this.props.updateScrollTopOnUpdatePosition === true) {
126+
this.__handleWindowScrollEvent();
127+
this.__resetIsScrolling();
128+
}
121129
}
122130

123131
componentDidMount() {

source/WindowScroller/utils/onScroll.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// @flow
2+
'no babel-plugin-flow-react-proptypes';
23

34
import {
45
requestAnimationTimeout,

0 commit comments

Comments
 (0)