UNPKG

@fto-consult/expo-ui

Version:

Bibliothèque de composants UI Expo,react-native

103 lines (95 loc) • 4.17 kB
// Copyright 2023 @fto-consult/Boris Fouomene. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. import React, { useCallback, useRef, useState, useLayoutEffect } from "$react"; import { Platform, StyleSheet, View} from "react-native"; import { findDOMNode } from "react-dom"; import PropTypes from "prop-types"; import stableHash from "stable-hash"; import {defaultNumber,isNumber} from "$cutils"; const styles = StyleSheet.create({container: { flex: 1,pointerEvents:"box-none" }}); const AutoResizerComponent = React.forwardRef((props,ref) =>{ const { children, defaultHeight, defaultWidth, disableHeight, disableWidth, onResize: _onResize, compare, ...viewProps } = props; const innerRef = useRef(null); const layoutRef = React.useRef({ width : defaultNumber(disableWidth ? 0 : defaultWidth), height : defaultNumber(disableHeight ? 0 : defaultHeight), x : 0, y : 0, }) const [result, setResult] = useState(Object.clone(layoutRef.current)); const canRender = x=>!!(result.width || result.height) && isNumber(result.x) && isNumber(result.y); const onResize = useCallback(({ width, height,x,y}) => { layoutRef.current.width = disableWidth ? 0 : width || 0; layoutRef.current.height = disableHeight ? 0 : height || 0; layoutRef.current.x = disableWidth? 0 : x; layoutRef.current.y = disableHeight ? 0 : y; if (Math.abs(result.width - layoutRef.current.width) <= 50 && Math.abs(result.height-layoutRef.current.height)<=50) return; if(typeof compare ==='function' && compare({previous:result,current:layoutRef.current}) === false) return; setResult({...layoutRef.current}); },[stableHash({disableWidth, disableHeight, _onResize, result})]); const onLayout = useCallback(e => { const layout = e.nativeEvent.layout; const x = defaultNumber(layout.x,layout.left); const y = defaultNumber(layout.y,layout.top); onResize({width:layout.width,height:layout.height,x,y}); },[onResize]); // Avoid zero/flash on first render, at least on web // @see https://github.com/bvaughn/react-virtualized-auto-sizer/blob/ffcba2dd39b89111ed4b42d64431f35ce7c1c23a/src/index.js#L69-L94 // @see https://github.com/bvaughn/react-virtualized-auto-sizer/issues/10 useLayoutEffect(() => { if (Platform.OS !== "web") return; const autoSizer = findDOMNode(innerRef.current); if ( autoSizer && autoSizer.parentNode && autoSizer.parentNode.ownerDocument && autoSizer.parentNode.ownerDocument.defaultView && autoSizer.parentNode instanceof autoSizer.parentNode.ownerDocument.defaultView.HTMLElement ) { const parentNode = autoSizer.parentNode; const height = parentNode.offsetHeight || 0; const width = parentNode.offsetWidth || 0; const x = parentNode.offsetLeft || 0; const y = parentNode.offsetTop || 0; if ((width || height) && (x || y)) onResize({ width, height,x,y}); } }, []); // eslint-disable-line React.useEffect(()=>{ if(_onResize){ _onResize(result); } },[result]) return ( <View {...viewProps} ref={React.useMergeRefs(innerRef,ref)} onLayout={onLayout} style={[styles.container, viewProps.style]} > {canRender() && children({...result,left:result.x,top:result.y}) || null} </View> ); }); AutoResizerComponent.displayName = "AutoResizerComponent"; AutoResizerComponent.propTypes = { /*** func({width,height})=>PropTypes.node */ children : PropTypes.func.isRequired, defaultHeight : PropTypes.number, defaultWidth : PropTypes.number, disableHeight : PropTypes.bool, disableWidth : PropTypes.bool, /***({ width, height }) => void */ onResize : PropTypes.func, } export default AutoResizerComponent;