Skip to content

Commit 0c838eb

Browse files
authored
breaking(responsive, xychart): require ResizeObserver or polyfill (#1622)
* breaking(responsive): remove legacy ParentSize, withParentSize and add polyfill option * fix(xychart, responsive): fix ResizeObserver polyfill * fix(xychart): clean up ResizeObserverPolyfill types * fix(visx): fix test * test(visx): remove tsconfig, fix jest tests * docs(responsive): fix typo
1 parent 09b74c5 commit 0c838eb

File tree

24 files changed

+198
-301
lines changed

24 files changed

+198
-301
lines changed

config-jest/setup/console.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
console.warn = console.error = function mockedConsole(message) {
2-
throw new Error(message);
3-
};
1+
function mockedConsole(...args) {
2+
throw new Error(args);
3+
}
4+
5+
console.warn = mockedConsole;
6+
console.error = mockedConsole;

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,5 @@ module.exports = {
4242
testURL: 'http://localhost',
4343
timers: 'fake',
4444
verbose: false,
45-
testPathIgnorePatterns: ['<rootDir>/packages/visx-demo', '<rootDir>/packages/visx-visx'],
45+
testPathIgnorePatterns: ['<rootDir>/packages/visx-demo'],
4646
};

packages/visx-responsive/Readme.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@
66

77
The `@visx/responsive` package is here to help you make responsive graphs.
88

9-
**With Enhancers**
9+
**Enhancers**
1010

1111
`withScreenSize`
1212

1313
`withParentSize`
1414

15-
**With Components**
15+
**Components**
1616

1717
`ParentSize`
1818

1919
`ScaleSVG`
2020

21-
## `withScreenSize`
21+
### `withScreenSize`
2222

2323
If you would like your graph to adapt to the screen size, you can use `withScreenSize()`. The
2424
resulting component will pass `screenWidth` and `screenHeight` props to the wrapped component
@@ -76,9 +76,9 @@ let chartToRender = (
7676
parentHeight={parent.height}
7777
parentTop={parent.top}
7878
parentLeft={parent.left}
79-
// this is the referer to the wrapper component
79+
// this is the referrer to the wrapper component
8080
parentRef={parent.ref}
81-
// this function can be called inside MySuperCoolVisxChart to cause a resize of the wrapper component
81+
// this function can be called inside MyVisxChart to cause a resize of the wrapper component
8282
resizeParent={parent.resize}
8383
/>
8484
)}
@@ -109,10 +109,22 @@ let chartToRender = (
109109
// ... Render the chartToRender somewhere
110110
```
111111

112-
##### ⚠️ `ResizeObserver` dependency
112+
### ⚠️ `ResizeObserver` dependency
113113

114-
If you don't need a polyfill for `ResizeObserver` or are already including it in your bundle, you
115-
should use `ParentSizeModern` and `withParentSizeModern` which doesn't include the polyfill.
114+
The `ParentSize` component and `withParentSize` enhancer rely on `ResizeObserver`s for auto-sizing.
115+
If you need a polyfill, you can either polute the `window` object or inject it cleanly through
116+
props:
117+
118+
```tsx
119+
import { ResizeObserver } from 'your-favorite-polyfill';
120+
121+
function App() {
122+
return (
123+
<ParentSize resizeObserverPolyfill={ResizeObserver} {...}>
124+
{() => {...}}
125+
</ParentSize>
126+
);
127+
```
116128
117129
## Installation
118130

packages/visx-responsive/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
},
2929
"homepage": "https://github.com/airbnb/visx#readme",
3030
"dependencies": {
31-
"@juggle/resize-observer": "^3.3.1",
3231
"@types/lodash": "^4.14.172",
3332
"@types/react": "*",
3433
"lodash": "^4.17.21",
@@ -37,6 +36,9 @@
3736
"peerDependencies": {
3837
"react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0"
3938
},
39+
"devDependencies": {
40+
"@juggle/resize-observer": "^3.3.1"
41+
},
4042
"publishConfig": {
4143
"access": "public"
4244
}

packages/visx-responsive/src/components/ParentSize.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import debounce from 'lodash/debounce';
22
import React, { useEffect, useMemo, useRef, useState } from 'react';
3-
import { ResizeObserver } from '@juggle/resize-observer';
3+
import { ResizeObserverPolyfill } from '../types';
4+
5+
// @TODO remove when upgraded to TS 4 which has its own declaration
6+
interface PrivateWindow {
7+
ResizeObserver: ResizeObserverPolyfill;
8+
}
49

510
export type ParentSizeProps = {
611
/** Optional `className` to add to the parent `div` wrapper used for size measurement. */
@@ -13,6 +18,8 @@ export type ParentSizeProps = {
1318
ignoreDimensions?: keyof ParentSizeState | (keyof ParentSizeState)[];
1419
/** Optional `style` object to apply to the parent `div` wrapper used for size measurement. */
1520
parentSizeStyles?: React.CSSProperties;
21+
/** Optionally inject a ResizeObserver polyfill, else this *must* be globally available. */
22+
resizeObserverPolyfill?: ResizeObserverPolyfill;
1623
/** Child render function `({ width, height, top, left, ref, resize }) => ReactNode`. */
1724
children: (
1825
args: {
@@ -32,14 +39,16 @@ type ParentSizeState = {
3239
export type ParentSizeProvidedProps = ParentSizeState;
3340

3441
const defaultIgnoreDimensions: ParentSizeProps['ignoreDimensions'] = [];
42+
const defaultParentSizeStyles = { width: '100%', height: '100%' };
3543

3644
export default function ParentSize({
3745
className,
3846
children,
3947
debounceTime = 300,
4048
ignoreDimensions = defaultIgnoreDimensions,
41-
parentSizeStyles = { width: '100%', height: '100%' },
49+
parentSizeStyles = defaultParentSizeStyles,
4250
enableDebounceLeadingCall = true,
51+
resizeObserverPolyfill,
4352
...restProps
4453
}: ParentSizeProps & Omit<React.HTMLAttributes<HTMLDivElement>, keyof ParentSizeProps>) {
4554
const target = useRef<HTMLDivElement | null>(null);
@@ -71,9 +80,12 @@ export default function ParentSize({
7180
}, [debounceTime, enableDebounceLeadingCall, ignoreDimensions]);
7281

7382
useEffect(() => {
74-
const observer = new ResizeObserver((entries = [] /** , observer */) => {
83+
const LocalResizeObserver =
84+
resizeObserverPolyfill || (window as unknown as PrivateWindow).ResizeObserver;
85+
86+
const observer = new LocalResizeObserver((entries) => {
7587
entries.forEach((entry) => {
76-
const { left, top, width, height } = entry.contentRect;
88+
const { left, top, width, height } = entry?.contentRect ?? {};
7789
animationFrameID.current = window.requestAnimationFrame(() => {
7890
resize({ width, height, top, left });
7991
});
@@ -84,9 +96,9 @@ export default function ParentSize({
8496
return () => {
8597
window.cancelAnimationFrame(animationFrameID.current);
8698
observer.disconnect();
87-
if (resize?.cancel) resize.cancel();
99+
resize.cancel();
88100
};
89-
}, [resize]);
101+
}, [resize, resizeObserverPolyfill]);
90102

91103
return (
92104
<div style={parentSizeStyles} ref={target} className={className} {...restProps}>

packages/visx-responsive/src/components/ParentSizeModern.tsx

Lines changed: 0 additions & 105 deletions
This file was deleted.

packages/visx-responsive/src/enhancers/withParentSize.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import React from 'react';
22
import debounce from 'lodash/debounce';
3-
import { ResizeObserver } from '@juggle/resize-observer';
3+
import { ResizeObserver, ResizeObserverPolyfill } from '../types';
44

55
const CONTAINER_STYLES = { width: '100%', height: '100%' };
66

7+
// @TODO remove when upgraded to TS 4 which has its own declaration
8+
interface PrivateWindow {
9+
ResizeObserver: ResizeObserverPolyfill;
10+
}
11+
712
export type WithParentSizeProps = {
813
debounceTime?: number;
914
enableDebounceLeadingCall?: boolean;
@@ -20,6 +25,8 @@ export type WithParentSizeProvidedProps = WithParentSizeState;
2025

2126
export default function withParentSize<BaseComponentProps extends WithParentSizeProps = {}>(
2227
BaseComponent: React.ComponentType<BaseComponentProps & WithParentSizeProvidedProps>,
28+
/** Optionally inject a ResizeObserver polyfill, else this *must* be globally available. */
29+
resizeObserverPolyfill?: ResizeObserverPolyfill,
2330
) {
2431
return class WrappedComponent extends React.Component<
2532
BaseComponentProps & WithParentSizeProvidedProps,
@@ -38,7 +45,10 @@ export default function withParentSize<BaseComponentProps extends WithParentSize
3845
container: HTMLDivElement | null = null;
3946

4047
componentDidMount() {
41-
this.resizeObserver = new ResizeObserver((entries /** , observer */) => {
48+
const ResizeObserverLocal =
49+
resizeObserverPolyfill || (window as unknown as PrivateWindow).ResizeObserver;
50+
51+
this.resizeObserver = new ResizeObserverLocal((entries) => {
4252
entries.forEach((entry) => {
4353
const { width, height } = entry.contentRect;
4454
this.animationFrameID = window.requestAnimationFrame(() => {

0 commit comments

Comments
 (0)