react-resize-detector
Advanced tools
Comparing version
@@ -1,3 +0,3 @@ | ||
import useResizeDetector from './useResizeDetector'; | ||
import useResizeDetector from './useResizeDetector.js'; | ||
export { useResizeDetector }; | ||
export type { UseResizeDetectorReturn, useResizeDetectorProps, OnResizeCallback, ResizePayload, ResfreshModeType, ResfreshOptionsType, Dimensions, } from './types'; | ||
export type { UseResizeDetectorReturn, useResizeDetectorProps, OnResizeCallback, ResizePayload, RefreshModeType, RefreshOptionsType, Dimensions, } from './types.js'; |
@@ -17,4 +17,4 @@ import type { MutableRefObject } from 'react'; | ||
}; | ||
export type ResfreshModeType = 'throttle' | 'debounce'; | ||
export type ResfreshOptionsType = { | ||
export type RefreshModeType = 'throttle' | 'debounce'; | ||
export type RefreshOptionsType = { | ||
leading?: boolean; | ||
@@ -52,3 +52,3 @@ trailing?: boolean; | ||
*/ | ||
refreshMode?: ResfreshModeType; | ||
refreshMode?: RefreshModeType; | ||
/** | ||
@@ -63,3 +63,3 @@ * Set the timeout/interval for `refreshMode` strategy | ||
*/ | ||
refreshOptions?: ResfreshOptionsType; | ||
refreshOptions?: RefreshOptionsType; | ||
/** | ||
@@ -66,0 +66,0 @@ * These options will be used as a second parameter of `resizeObserver.observe` method |
@@ -1,3 +0,3 @@ | ||
import type { UseResizeDetectorReturn, useResizeDetectorProps } from './types'; | ||
import type { UseResizeDetectorReturn, useResizeDetectorProps } from './types.js'; | ||
declare function useResizeDetector<T extends HTMLElement = any>({ skipOnMount, refreshMode, refreshRate, refreshOptions, handleWidth, handleHeight, targetRef, observerOptions, onResize, }?: useResizeDetectorProps<T>): UseResizeDetectorReturn<T>; | ||
export default useResizeDetector; |
@@ -51,4 +51,9 @@ import { useRef, useState, useCallback, useEffect } from 'react'; | ||
if (refElement) { | ||
resizeObserver = new window.ResizeObserver(resizeHandler); | ||
resizeObserver.observe(refElement, observerOptions); | ||
try { | ||
resizeObserver = new window.ResizeObserver(resizeHandler); | ||
resizeObserver.observe(refElement, observerOptions); | ||
} | ||
catch (error) { | ||
console.warn('ResizeObserver not supported or failed to initialize:', error); | ||
} | ||
} | ||
@@ -55,0 +60,0 @@ // If refElement is not available, reset the size |
import * as React from 'react'; | ||
import type { DebouncedFunc } from 'lodash'; | ||
import { OnRefChangeType, Props } from './types'; | ||
import { OnRefChangeType, Props } from './types.js'; | ||
export type PatchedResizeObserverCallback = DebouncedFunc<ResizeObserverCallback> | ResizeObserverCallback; | ||
@@ -5,0 +5,0 @@ /** |
@@ -83,12 +83,15 @@ import * as React from 'react'; | ||
// undefined No No? Yes | ||
if (box === 'border-box') { | ||
var _a, _b; | ||
const borderBox = (_a = entry.borderBoxSize) === null || _a === void 0 ? void 0 : _a[0]; | ||
const contentBox = (_b = entry.contentBoxSize) === null || _b === void 0 ? void 0 : _b[0]; | ||
if (box === 'border-box' && borderBox) { | ||
return { | ||
width: entry.borderBoxSize[0].inlineSize, | ||
height: entry.borderBoxSize[0].blockSize, | ||
width: borderBox.inlineSize, | ||
height: borderBox.blockSize, | ||
}; | ||
} | ||
if (box === 'content-box') { | ||
if (box === 'content-box' && contentBox) { | ||
return { | ||
width: entry.contentBoxSize[0].inlineSize, | ||
height: entry.contentBoxSize[0].blockSize, | ||
width: contentBox.inlineSize, | ||
height: contentBox.blockSize, | ||
}; | ||
@@ -95,0 +98,0 @@ } |
{ | ||
"name": "react-resize-detector", | ||
"version": "12.0.2", | ||
"version": "12.1.0-beta.0", | ||
"description": "React resize detector", | ||
@@ -16,2 +16,3 @@ "type": "module", | ||
"scripts": { | ||
"prebuild": "tsc", | ||
"build": "rollup -c", | ||
@@ -28,17 +29,18 @@ "prettier": "prettier --write .", | ||
"devDependencies": { | ||
"@rollup/plugin-commonjs": "^28.0.2", | ||
"@rollup/plugin-node-resolve": "^16.0.0", | ||
"@eslint/js": "^9.28.0", | ||
"@rollup/plugin-commonjs": "^28.0.3", | ||
"@rollup/plugin-node-resolve": "^16.0.1", | ||
"@rollup/plugin-typescript": "^12.1.2", | ||
"@types/lodash": "^4.17.13", | ||
"@types/react": "^19.0.2", | ||
"@types/react-dom": "^19.0.2", | ||
"eslint": "^9.17.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"eslint-plugin-react": "^7.37.3", | ||
"prettier": "^3.4.2", | ||
"rollup": "^4.29.1", | ||
"@types/lodash": "^4.17.17", | ||
"@types/react": "^19.1.7", | ||
"@types/react-dom": "^19.1.6", | ||
"eslint": "^9.28.0", | ||
"eslint-config-prettier": "^10.1.5", | ||
"eslint-plugin-react": "^7.37.5", | ||
"prettier": "^3.5.3", | ||
"rollup": "^4.42.0", | ||
"rollup-plugin-node-externals": "^8.0.0", | ||
"tslib": "^2.8.1", | ||
"typescript": "^5.7.2", | ||
"typescript-eslint": "^8.19.0" | ||
"typescript": "^5.8.3", | ||
"typescript-eslint": "^8.34.0" | ||
}, | ||
@@ -45,0 +47,0 @@ "peerDependencies": { |
188
README.md
@@ -19,7 +19,7 @@ # Handle element resizes like it's 2025! | ||
## Is it necessary for you to use this library? | ||
## Should you use this library? | ||
Container queries now work in [all major browsers](https://caniuse.com/css-container-queries). It's very likely you can solve your task using [pure CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries). | ||
**Consider CSS Container Queries first!** They now work in [all major browsers](https://caniuse.com/css-container-queries) and might solve your use case with pure CSS. | ||
<details><summary>Example</summary> | ||
<details><summary>CSS Container Queries Example</summary> | ||
@@ -55,17 +55,28 @@ ```html | ||
**Use this library when you need:** | ||
- JavaScript-based resize logic with full TypeScript support | ||
- Complex calculations based on dimensions | ||
- Integration with React state/effects | ||
- Programmatic control over resize behavior | ||
## Installation | ||
```ssh | ||
npm i react-resize-detector | ||
// OR | ||
```bash | ||
npm install react-resize-detector | ||
# OR | ||
yarn add react-resize-detector | ||
# OR | ||
pnpm add react-resize-detector | ||
``` | ||
## Example | ||
## Quick Start | ||
```jsx | ||
### Basic Usage | ||
```tsx | ||
import { useResizeDetector } from 'react-resize-detector'; | ||
const CustomComponent = () => { | ||
const { width, height, ref } = useResizeDetector(); | ||
const { width, height, ref } = useResizeDetector<HTMLDivElement>(); | ||
return <div ref={ref}>{`${width}x${height}`}</div>; | ||
@@ -75,16 +86,18 @@ }; | ||
#### With props | ||
### With Resize Callback | ||
```js | ||
import { useResizeDetector } from 'react-resize-detector'; | ||
```tsx | ||
import { useCallback } from 'react'; | ||
import { useResizeDetector, OnResizeCallback } from 'react-resize-detector'; | ||
const CustomComponent = () => { | ||
const onResize = useCallback(() => { | ||
// on resize logic | ||
const onResize: OnResizeCallback = useCallback((payload) => { | ||
if (payload.width !== null && payload.height !== null) { | ||
console.log('Dimensions:', payload.width, payload.height); | ||
} else { | ||
console.log('Element unmounted'); | ||
} | ||
}, []); | ||
const { width, height, ref } = useResizeDetector({ | ||
handleHeight: false, | ||
refreshMode: 'debounce', | ||
refreshRate: 1000, | ||
const { width, height, ref } = useResizeDetector<HTMLDivElement>({ | ||
onResize, | ||
@@ -97,11 +110,12 @@ }); | ||
#### With custom ref | ||
### With External Ref (Advanced) | ||
_It's not advised to use this approach, as dynamically mounting and unmounting the observed element could lead to unexpected behavior._ | ||
```js | ||
```tsx | ||
import { useRef } from 'react'; | ||
import { useResizeDetector } from 'react-resize-detector'; | ||
const CustomComponent = () => { | ||
const targetRef = useRef(); | ||
const targetRef = useRef<HTMLDivElement>(null); | ||
const { width, height } = useResizeDetector({ targetRef }); | ||
@@ -112,21 +126,109 @@ return <div ref={targetRef}>{`${width}x${height}`}</div>; | ||
## API | ||
## API Reference | ||
| Prop | Type | Description | Default | | ||
| --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | ||
| onResize | Func | Function that will be invoked with `width`, `height` and ResizeObserver `entry` arguments | `undefined` | | ||
| handleWidth | Bool | Trigger `onResize` on width change | `true` | | ||
| handleHeight | Bool | Trigger `onResize` on height change | `true` | | ||
| skipOnMount | Bool | Do not trigger onResize when a component mounts | `false` | | ||
| refreshMode | String | Possible values: `throttle` and `debounce` See [lodash docs](https://lodash.com/docs#debounce) for more information. `undefined` - callback will be fired for every frame | `undefined` | | ||
| refreshRate | Number | Use this in conjunction with `refreshMode`. Important! It's a numeric prop so set it accordingly, e.g. `refreshRate={500}` | `1000` | | ||
| refreshOptions | Object | Use this in conjunction with `refreshMode`. An object in shape of `{ leading: bool, trailing: bool }`. Please refer to [lodash's docs](https://lodash.com/docs/4.17.11#throttle) for more info | `undefined` | | ||
| observerOptions | Object | These options will be used as a second parameter of [`resizeObserver.observe`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe) method. | `undefined` | | ||
| targetRef | Ref | Use this prop to pass a reference to the element you want to attach resize handlers to. It must be an instance of `React.useRef` or `React.createRef` functions | `undefined` | | ||
### Hook Signature | ||
## Testing with Enzyme and Jest | ||
```typescript | ||
useResizeDetector<T extends HTMLElement = HTMLElement>( | ||
props?: useResizeDetectorProps<T> | ||
): UseResizeDetectorReturn<T> | ||
``` | ||
Thanks to [@Primajin](https://github.com/Primajin) for posting this [snippet](https://github.com/maslianok/react-resize-detector/issues/145) | ||
### Props | ||
| Prop | Type | Description | Default | | ||
| ----------------- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ----------- | | ||
| `onResize` | `(payload: ResizePayload) => void` | Callback invoked with resize information | `undefined` | | ||
| `handleWidth` | `boolean` | Trigger updates on width changes | `true` | | ||
| `handleHeight` | `boolean` | Trigger updates on height changes | `true` | | ||
| `skipOnMount` | `boolean` | Skip the first resize event when component mounts | `false` | | ||
| `refreshMode` | `'throttle' \| 'debounce'` | Rate limiting strategy. See [lodash docs](https://lodash.com/docs) | `undefined` | | ||
| `refreshRate` | `number` | Delay in milliseconds for rate limiting | `1000` | | ||
| `refreshOptions` | `{ leading?: boolean; trailing?: boolean }` | Additional options for throttle/debounce | `undefined` | | ||
| `observerOptions` | `ResizeObserverOptions` | Options passed to [`resizeObserver.observe`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe) | `undefined` | | ||
| `targetRef` | `MutableRefObject<T \| null>` | External ref to observe (use with caution) | `undefined` | | ||
## Advanced Examples | ||
### Responsive Component | ||
```jsx | ||
import { useResizeDetector } from 'react-resize-detector'; | ||
const ResponsiveCard = () => { | ||
const { width, ref } = useResizeDetector(); | ||
const cardStyle = { | ||
padding: width > 600 ? '2rem' : '1rem', | ||
fontSize: width > 400 ? '1.2em' : '1em', | ||
flexDirection: width > 500 ? 'row' : 'column', | ||
}; | ||
return ( | ||
<div ref={ref} style={cardStyle}> | ||
<h2>Responsive Card</h2> | ||
<p>Width: {width}px</p> | ||
</div> | ||
); | ||
}; | ||
``` | ||
### Chart Resizing | ||
```jsx | ||
import { useResizeDetector } from 'react-resize-detector'; | ||
import { useEffect, useRef } from 'react'; | ||
const Chart = () => { | ||
const chartRef = useRef(null); | ||
const { width, height, ref } = useResizeDetector({ | ||
refreshMode: 'debounce', | ||
refreshRate: 100, | ||
}); | ||
useEffect(() => { | ||
if (width && height && chartRef.current) { | ||
// Redraw chart with new dimensions | ||
redrawChart(chartRef.current, width, height); | ||
} | ||
}, [width, height]); | ||
return <canvas ref={ref} />; | ||
}; | ||
``` | ||
### Performance Optimization | ||
```jsx | ||
import { useResizeDetector } from 'react-resize-detector'; | ||
const OptimizedComponent = () => { | ||
const { width, height, ref } = useResizeDetector({ | ||
// Only track width changes | ||
handleHeight: false, | ||
// Debounce rapid changes | ||
refreshMode: 'debounce', | ||
refreshRate: 150, | ||
// Skip initial mount calculation | ||
skipOnMount: true, | ||
// Use border-box for more accurate measurements | ||
observerOptions: { box: 'border-box' }, | ||
}); | ||
return <div ref={ref}>Optimized: {width}px wide</div>; | ||
}; | ||
``` | ||
## Browser Support | ||
- ✅ Chrome 64+ | ||
- ✅ Firefox 69+ | ||
- ✅ Safari 13.1+ | ||
- ✅ Edge 79+ | ||
For older browsers, consider using a [ResizeObserver polyfill](https://github.com/que-etc/resize-observer-polyfill). | ||
## Testing | ||
```jsx | ||
const { ResizeObserver } = window; | ||
@@ -136,2 +238,3 @@ | ||
delete window.ResizeObserver; | ||
// Mock ResizeObserver for tests | ||
window.ResizeObserver = jest.fn().mockImplementation(() => ({ | ||
@@ -142,4 +245,2 @@ observe: jest.fn(), | ||
})); | ||
wrapper = mount(<MyComponent />); | ||
}); | ||
@@ -151,8 +252,11 @@ | ||
}); | ||
it('should do my test', () => { | ||
// [...] | ||
}); | ||
``` | ||
## Performance Tips | ||
1. **Use `handleWidth`/`handleHeight: false`** if you only need one dimension | ||
2. **Enable `skipOnMount: true`** if you don't need initial measurements | ||
3. **Use `debounce` or `throttle`** for expensive resize handlers | ||
4. **Specify `observerOptions.box`** for consistent measurements | ||
## License | ||
@@ -162,4 +266,4 @@ | ||
## ❤️ | ||
## ❤️ Support | ||
Show us some love and STAR ⭐ the project if you find it useful |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
261
66.24%37250
-41.2%16
6.67%13
-38.1%293
-57.04%1
Infinity%