mirror of
https://github.com/streamich/react-use.git
synced 2026-01-18 14:06:52 +00:00
93 lines
2.2 KiB
TypeScript
93 lines
2.2 KiB
TypeScript
import * as React from 'react';
|
|
import {useState, useEffect, useRef} from './react';
|
|
|
|
const isClient = typeof window === 'object';
|
|
const DRAF = (callback: () => void) => setTimeout(callback, 35);
|
|
|
|
export type Element = ((state: State) => React.ReactElement<any>) | React.ReactElement<any>;
|
|
export interface State {
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
const useSize = (element: Element, {width = Infinity, height = Infinity}: Partial<State> = {}): [React.ReactElement<any>, State] => {
|
|
if (!isClient) {
|
|
return [
|
|
typeof element === 'function'
|
|
? element({width, height})
|
|
: element,
|
|
{width, height}
|
|
];
|
|
}
|
|
|
|
const [state, setState] = useState<State>({width, height});
|
|
|
|
if (typeof element === 'function') {
|
|
element = element(state);
|
|
}
|
|
|
|
const style = element.props.style || {};
|
|
const ref = useRef<HTMLIFrameElement | null>(null);
|
|
let window: Window | null = null;
|
|
const setSize = () => {
|
|
const iframe = ref.current;
|
|
const size = iframe
|
|
? {
|
|
width: iframe.offsetWidth,
|
|
height: iframe.offsetHeight,
|
|
}
|
|
: {width, height,};
|
|
|
|
setState(size);
|
|
}
|
|
const onWindow = (window: Window) => {
|
|
window.addEventListener('resize', setSize);
|
|
DRAF(setSize);
|
|
};
|
|
|
|
useEffect(() => {
|
|
const iframe: HTMLIFrameElement = ref.current!;
|
|
if (iframe.contentWindow) {
|
|
window = iframe.contentWindow!;
|
|
onWindow(window);
|
|
} else {
|
|
const onLoad = () => {
|
|
iframe.removeEventListener('load', onLoad);
|
|
window = iframe.contentWindow!;
|
|
onWindow(window);
|
|
};
|
|
|
|
iframe.addEventListener('load', onLoad);
|
|
}
|
|
|
|
return () => {
|
|
if (window) {
|
|
window.removeEventListener('resize', setSize);
|
|
}
|
|
};
|
|
}, [0]);
|
|
|
|
style.position = 'relative';
|
|
|
|
const sized = React.cloneElement(element, {style}, ...[
|
|
React.createElement('iframe', {
|
|
ref,
|
|
style: {
|
|
background: 'transparent',
|
|
border: 'none',
|
|
height: '100%',
|
|
left: 0,
|
|
position: 'absolute',
|
|
top: 0,
|
|
width: '100%',
|
|
zIndex: -1
|
|
}
|
|
}),
|
|
...React.Children.toArray(element.props.children)
|
|
]);
|
|
|
|
return [sized, state];
|
|
};
|
|
|
|
export default useSize;
|