Skip to content

Commit

Permalink
Detect non-window element resize (#918)
Browse files Browse the repository at this point in the history
Detect non-window element resize
  • Loading branch information
TrySound authored Dec 29, 2017
1 parent 1936f5b commit 8849d0b
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 8 deletions.
16 changes: 16 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
{
"env": {
"commonjs": {
"ignore": [
"*.jest.js",
"*.e2e.js",
"*.example.js",
"source/demo",
"source/jest-*.js",
"source/TestUtils.js"
],
"plugins": [
"transform-runtime",
"flow-react-proptypes",
Expand Down Expand Up @@ -51,6 +59,14 @@
]
},
"es": {
"ignore": [
"*.jest.js",
"*.e2e.js",
"*.example.js",
"source/demo",
"source/jest-*.js",
"source/TestUtils.js"
],
"plugins": [
"transform-runtime",
"flow-react-proptypes",
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
"jsnext:main": "dist/es/index.js",
"license": "MIT",
"scripts": {
"build:types": "flow-copy-source --ignore \"**/*.{jest,example}.js\" source/WindowScroller dist/es/WindowScroller",
"build:types": "flow-copy-source --ignore \"**/*.{jest,e2e,example}.js\" source/WindowScroller dist/es/WindowScroller",
"build": "npm run build:commonjs && npm run build:css && npm run build:es && npm run build:demo && npm run build:umd",
"build:commonjs": "npm run clean:commonjs && cross-env NODE_ENV=production cross-env BABEL_ENV=commonjs babel source --out-dir dist/commonjs --ignore *.example.js,*.jest.js,source/demo/",
"build:commonjs": "npm run clean:commonjs && cross-env NODE_ENV=production cross-env BABEL_ENV=commonjs babel source --out-dir dist/commonjs",
"build:css": "postcss source/styles.css -o styles.css --use autoprefixer",
"build:demo": "npm run clean:demo && cross-env NODE_ENV=production webpack --config webpack.config.demo.js -p --bail",
"build:es": "npm run clean:es && npm run build:types && cross-env NODE_ENV=production cross-env BABEL_ENV=es babel source --out-dir dist/es --ignore *.example.js,*.jest.js,source/demo/",
"build:es": "npm run clean:es && npm run build:types && cross-env NODE_ENV=production cross-env BABEL_ENV=es babel source --out-dir dist/es",
"build:umd": "npm run clean:umd && cross-env NODE_ENV=production webpack --config webpack.config.umd.js --bail",
"check-all": "yarn prettier && yarn lint && yarn flow",
"ci-check": "yarn prettier:diff && yarn lint && yarn flow",
Expand Down
52 changes: 52 additions & 0 deletions source/WindowScroller/WindowScroller.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,55 @@ test('save position after resize and then scroll in container', async () => {
[{width: 400, height: 600}],
]);
});

test('react on container resize without window changing', async () => {
const page = await bootstrap();
const resizeFn = jest.fn();
await page.exposeFunction('resizeFn', resizeFn);

await page.evaluate(() => {
const {render} = window.ReactDOM;
const {createElement} = window.React;
const {WindowScroller} = window.ReactVirtualized;

const wrapper = document.createElement('div');
wrapper.id = 'wrapper';
Object.assign(wrapper.style, {
width: '1000px',
height: '800px',
display: 'flex',
});
const container = document.createElement('div');
Object.assign(container.style, {
flex: '1',
});
wrapper.appendChild(container);
document.body.style.margin = 0;
document.body.appendChild(wrapper);

render(
createElement(
WindowScroller,
{scrollElement: container, onResize: window.resizeFn},
() => null,
),
container,
);
});

await delay(100);

await page.$eval('#wrapper', el => {
el.style.width = '500px';
el.style.height = '700px';
});

await delay(100);

await page.close();

expect(resizeFn.mock.calls).toEqual([
[{width: 1000, height: 800}],
[{width: 500, height: 700}],
]);
});
38 changes: 33 additions & 5 deletions source/WindowScroller/WindowScroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
getPositionOffset,
getScrollOffset,
} from './utils/dimensions';
import createDetectElementResize from '../vendor/detectElementResize';

type Props = {
/**
Expand Down Expand Up @@ -57,6 +58,13 @@ type State = {
scrollTop: number,
};

type ResizeHandler = (element: Element, onResize: () => void) => void;

type DetectElementResize = {
addResizeListener: ResizeHandler,
removeResizeListener: ResizeHandler,
};

/**
* Specifies the number of miliseconds during which to disable pointer events while a scroll is in progress.
* This improves performance and makes scrolling smoother.
Expand All @@ -79,6 +87,7 @@ export default class WindowScroller extends React.PureComponent<Props, State> {
_isMounted = false;
_positionFromTop = 0;
_positionFromLeft = 0;
_detectElementResize: DetectElementResize = createDetectElementResize();

state = {
...getDimensions(this.props.scrollElement, this.props),
Expand Down Expand Up @@ -121,10 +130,9 @@ export default class WindowScroller extends React.PureComponent<Props, State> {

if (scrollElement) {
registerScrollListener(this, scrollElement);
this._registerResizeListener(scrollElement);
}

window.addEventListener('resize', this._onResize, false);

this._isMounted = true;
}

Expand All @@ -141,14 +149,18 @@ export default class WindowScroller extends React.PureComponent<Props, State> {

unregisterScrollListener(this, scrollElement);
registerScrollListener(this, nextScrollElement);

this._unregisterResizeListener(scrollElement);
this._registerResizeListener(nextScrollElement);
}
}

componentWillUnmount() {
if (this.props.scrollElement) {
unregisterScrollListener(this, this.props.scrollElement);
const scrollElement = this.props.scrollElement;
if (scrollElement) {
unregisterScrollListener(this, scrollElement);
this._unregisterResizeListener(scrollElement);
}
window.removeEventListener('resize', this._onResize, false);

this._isMounted = false;
}
Expand Down Expand Up @@ -182,6 +194,22 @@ export default class WindowScroller extends React.PureComponent<Props, State> {
}
};

_registerResizeListener = element => {
if (element === window) {
window.addEventListener('resize', this._onResize, false);
} else {
this._detectElementResize.addResizeListener(element, this._onResize);
}
};

_unregisterResizeListener = element => {
if (element === window) {
window.removeEventListener('resize', this._onResize, false);
} else if (element) {
this._detectElementResize.removeResizeListener(element, this._onResize);
}
};

_onResize = () => {
this.updatePosition();
};
Expand Down

0 comments on commit 8849d0b

Please sign in to comment.