Skip to content

Commit

Permalink
Merge pull request #21 from bvaughn/master
Browse files Browse the repository at this point in the history
rebase to future changes in main repo
  • Loading branch information
monadav authored Jul 11, 2022
2 parents b00b18f + 005be24 commit f11fd2c
Show file tree
Hide file tree
Showing 12 changed files with 368 additions and 65 deletions.
1 change: 1 addition & 0 deletions .babelrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ if (env === 'commonjs' || env === 'es') {
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-transform-flow-comments',
['flow-react-proptypes', {deadCode: true, useESModules: true}],
['transform-react-remove-prop-types', {mode: 'wrap'}],
],
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
## Changelog

##### NEXT

- Update peer dependencies to allow React 17 ([levenleven](https://github.com/levenleven) - [#1625](https://github.com/bvaughn/react-virtualized/pull/1625))
- 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))
- 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))
- Fix babel tranform es error ([fupengl](https://github.com/fupengl) - [#1651](https://github.com/bvaughn/react-virtualized/pull/1651))
- Fix issue with unused import being emitted ([mewhhaha](https://github.com/mewhhaha) - [#1635](https://github.com/bvaughn/react-virtualized/pull/1635))
- Fix grid roles for accessbility ([asnewman](https://github.com/asnewman) - [#1624](https://github.com/bvaughn/react-virtualized/pull/1624))

##### 9.22.3

- Add Trusted Types support ([shhnjk](https://github.com/shhnjk) - [#1614](https://github.com/bvaughn/react-virtualized/pull/1614))
Expand Down
18 changes: 9 additions & 9 deletions docs/Grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,19 @@ function cellRangeRenderer({
This is an advanced property.
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.

```
function overscanIndicesGetter ({
direction, // One of "horizontal" or "vertical"
cellCount, // Number of rows or columns in the current axis
scrollDirection, // 1 (forwards) or -1 (backwards)
```js
function overscanIndicesGetter({
direction, // One of "horizontal" or "vertical"
cellCount, // Number of rows or columns in the current axis
scrollDirection, // 1 (forwards) or -1 (backwards)
overscanCellsCount, // Maximum number of cells to over-render in either direction
startIndex, // Begin of range of visible cells
stopIndex // End of range of visible cells
startIndex, // Begin of range of visible cells
stopIndex, // End of range of visible cells
}) {
return {
overscanStartIndex: Math.max(0, startIndex - overscanCellsCount),
overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount)
}
overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount),
};
}
```

Expand Down
6 changes: 6 additions & 0 deletions jest-puppeteer.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
launch: {
headless: process.env.HEADLESS !== 'false',
devtools: process.env.DEVTOOLS === 'true',
},
};
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"@babel/plugin-proposal-class-properties": "^7.7.0",
"@babel/plugin-transform-modules-commonjs": "^7.7.0",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/plugin-transform-flow-comments": "^7.12.13",
"@babel/polyfill": "^7.7.0",
"@babel/preset-env": "^7.7.1",
"@babel/preset-flow": "^7.0.0",
Expand Down Expand Up @@ -118,12 +119,12 @@
"prettier": "1.19.1",
"pretty-quick": "^2.0.1",
"puppeteer": "^2.0.0",
"react": "^16.11.0",
"react": "^17.0.1",
"react-codemirror": "^1.0.0",
"react-dom": "^16.11.0",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-test-renderer": "^16.11.0",
"react-dom": "^17.0.1",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-test-renderer": "^17.0.1",
"rimraf": "^3.0.0",
"rollup": "^1.26.5",
"rollup-plugin-babel": "^4.3.3",
Expand All @@ -146,8 +147,8 @@
"react-lifecycles-compat": "^3.0.4"
},
"peerDependencies": {
"react": "^15.3.0 || ^16.0.0-alpha",
"react-dom": "^15.3.0 || ^16.0.0-alpha"
"react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0",
"react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0"
},
"browserify": {
"transform": [
Expand Down
8 changes: 7 additions & 1 deletion source/Grid/Grid.jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -1102,7 +1102,7 @@ describe('Grid', () => {
});
});

describe('styles, classNames, and ids', () => {
describe('styles, classNames, ids, and roles', () => {
it('should use the expected global CSS classNames', () => {
const rendered = findDOMNode(render(getMarkup()));
expect(rendered.className).toEqual('ReactVirtualized__Grid');
Expand Down Expand Up @@ -1132,6 +1132,12 @@ describe('Grid', () => {
.style.backgroundColor,
).toEqual('red');
});

it('should have the gridcell role', () => {
const containerStyle = {backgroundColor: 'red'};
const rendered = findDOMNode(render(getMarkup({containerStyle})));
expect(rendered.querySelectorAll('[role="gridcell"]').length).toEqual(20);
});
});

describe('onScroll', () => {
Expand Down
2 changes: 1 addition & 1 deletion source/Grid/Grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class Grid extends React.PureComponent<Props, State> {
autoHeight: false,
autoWidth: false,
cellRangeRenderer: defaultCellRangeRenderer,
containerRole: 'rowgroup',
containerRole: 'row',
containerStyle: {},
estimatedColumnSize: 100,
estimatedRowSize: 30,
Expand Down
5 changes: 5 additions & 0 deletions source/Grid/defaultCellRangeRenderer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @flow */

import type {CellRangeRendererParams} from './types';
import React from 'react';

/**
* Default implementation of cellRangeRenderer used by Grid.
Expand Down Expand Up @@ -138,6 +139,10 @@ export default function defaultCellRangeRenderer({
warnAboutMissingStyle(parent, renderedCell);
}

if (!renderedCell.props.role) {
renderedCell = React.cloneElement(renderedCell, {role: 'gridcell'});
}

renderedCells.push(renderedCell);
}
}
Expand Down
206 changes: 206 additions & 0 deletions source/WindowScroller/WindowScroller.header-resize.e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/**
* @jest-environment jest-environment-puppeteer
*/

const bootstrap = async () => {
const page = await global.browser.newPage();
const scripts = [
'./node_modules/react/umd/react.development.js',
'./node_modules/react-dom/umd/react-dom.development.js',
'./dist/umd/react-virtualized.js',
];

for (const path of scripts) {
await page.addScriptTag({path});
}

return page;
};

const renderWindowScroller = updateScrollTopOnUpdatePosition => {
const {render} = window.ReactDOM;
const {createElement, useState, useEffect} = window.React;
const {WindowScroller} = window.ReactVirtualized;

const container = document.createElement('div');
container.id = 'container';
document.body.appendChild(container);
document.body.style.margin = 0;

function Header({height}) {
return createElement('div', {style: {height, backgroundColor: 'red'}});
}

function App() {
const [height, setHeight] = useState(100);
window.setHeaderHeight = setHeight;
useEffect(() => () => (window.setHeaderHeight = null));

return createElement(
'div',
{},
createElement(Header, {height}),
createElement(
WindowScroller,
{
updateScrollTopOnUpdatePosition,
ref: windowScroller => {
window.windowScroller = windowScroller;
},
onScroll: window.scrollFn,
onResize: window.resizeFn,
},
({width, scrollTop}) => {
console.log({scrollTop});
window.windowScrollerScrollTop = scrollTop;
return createElement('div', {
style: {
width,
height: 3000,
backgroundColor: 'yellow',
},
});
},
),
);
}

render(
createElement(
'div',
{'data-test-id': 'main-container'},
createElement(App, {}),
),
container,
);
};

jest.setTimeout(1200000);

const delay = time => new Promise(resolve => setTimeout(resolve, time));

test('will react to header height updates if notified through updatePosition', async () => {
const page = await bootstrap();
const scrollFn = jest.fn();
const resizeFn = jest.fn();
await page.exposeFunction('scrollFn', scrollFn);
await page.exposeFunction('resizeFn', resizeFn);

await page.setViewport({width: 400, height: 600});
await page.evaluate(renderWindowScroller, true);

const el = await page.$('[data-test-id="main-container"]');
expect(el).not.toBeNull();

await page.evaluate(() => window.scrollTo(0, 200));
await delay(500);

{
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
expect(scrollTop).toEqual(100);
}
await delay(500);

// Update the header height
await page.evaluate(() => {
console.log('change header height');
window.setHeaderHeight(200);
});
await delay(500);

await page.evaluate(() => {
console.log('update position');
window.windowScroller.updatePosition();
});
await delay(500);

// Despite header updates, we'd expect the scrollTop to be the same.
{
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
expect(scrollTop).toEqual(100);
}
});

test('will NOT react to header height updates if notified through updatePosition if `updateScrollTopOnUpdatePosition` is false', async () => {
const page = await bootstrap();
const scrollFn = jest.fn();
const resizeFn = jest.fn();
await page.exposeFunction('scrollFn', scrollFn);
await page.exposeFunction('resizeFn', resizeFn);

await page.setViewport({width: 400, height: 600});
await page.evaluate(renderWindowScroller, false);

const el = await page.$('[data-test-id="main-container"]');
expect(el).not.toBeNull();

await page.evaluate(() => window.scrollTo(0, 200));
await delay(500);

{
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
expect(scrollTop).toEqual(100);
}
await delay(500);

// Update the header height
await page.evaluate(() => {
console.log('change header height');
window.setHeaderHeight(200);
});
await delay(500);

await page.evaluate(() => {
console.log('update position');
window.windowScroller.updatePosition();
});
await delay(500);

// Despite header updates, we'd expect the scrollTop to be the same.
// As the fix is off, this will fail.
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
expect(() => {
expect(scrollTop).toEqual(100);
}).toThrow();
});

test('will properly process scroll events after header height updates', async () => {
const page = await bootstrap();
const scrollFn = jest.fn();
const resizeFn = jest.fn();
await page.exposeFunction('scrollFn', scrollFn);
await page.exposeFunction('resizeFn', resizeFn);

await page.setViewport({width: 400, height: 600});
await page.evaluate(renderWindowScroller, true);

const el = await page.$('[data-test-id="main-container"]');
expect(el).not.toBeNull();

await page.evaluate(() => window.scrollTo(0, 200));
await delay(500);

{
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
expect(scrollTop).toEqual(100);
}
await delay(500);

// Update the header height
await page.evaluate(() => {
window.setHeaderHeight(200);
});
await delay(500);

await page.evaluate(() => {
window.windowScroller.updatePosition();
});
await delay(500);
// This is only 50px under the first position
await page.evaluate(() => window.scrollTo(0, 350));

{
const scrollTop = await page.evaluate(() => window.windowScrollerScrollTop);
expect(scrollTop).toEqual(150);
}
});
8 changes: 8 additions & 0 deletions source/WindowScroller/WindowScroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ type Props = {

/** Width used for server-side rendering */
serverWidth: number,

/** Force scrollTop updates when .updatePosition is called, fixing forced header height change updates */
updateScrollTopOnUpdatePosition?: boolean,
};

type State = {
Expand Down Expand Up @@ -118,6 +121,11 @@ export default class WindowScroller extends React.PureComponent<Props, State> {
width: dimensions.width,
});
}

if (this.props.updateScrollTopOnUpdatePosition === true) {
this.__handleWindowScrollEvent();
this.__resetIsScrolling();
}
}

componentDidMount() {
Expand Down
1 change: 1 addition & 0 deletions source/WindowScroller/utils/onScroll.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @flow
'no babel-plugin-flow-react-proptypes';

import {
requestAnimationTimeout,
Expand Down
Loading

0 comments on commit f11fd2c

Please sign in to comment.