UNPKG

react-reflex

Version:

Flex layout component for advanced React web applications

203 lines (165 loc) 4.41 kB
/////////////////////////////////////////////////////////// // ReflexElement // By Philippe Leefsma // December 2016 // /////////////////////////////////////////////////////////// import ReflexHandle from './ReflexHandle' import {getDataProps} from './utilities' import throttle from 'lodash.throttle' import Measure from 'react-measure' import PropTypes from 'prop-types' import React from 'react' const toArray = (obj) => { return obj ? (Array.isArray(obj) ? obj : [obj]) : [] } class SizeAwareReflexElement extends React.Component { constructor (props) { super (props) this.setDimensions = throttle((dimensions) => { this.setState(dimensions) }, this.props.propagateDimensionsRate/1000) this.state = { height: "100%", width: "100%" } } onResize = (rect) => { const { resizeHeight, resizeWidth } = this.props const {height, width} = rect.bounds this.setDimensions({ ...(resizeHeight && {height}), ...(resizeWidth && {width}) }) } renderChildren () { const {propagateDimensions} = this.props const validChildren = toArray(this.props.children).filter(child => { return !!child }) return React.Children.map(validChildren, (child) => { if (this.props.withHandle || ReflexHandle.isA(child)) { return React.cloneElement(child, { dimensions: propagateDimensions && this.state, ...child.props, index: this.props.index - 1, events: this.props.events }) } if (propagateDimensions) { return React.cloneElement(child, { ...child.props, dimensions: this.state }) } return child }) } render () { return ( <Measure bounds onResize={this.onResize}> { ({measureRef}) => { return ( <div ref={measureRef} className="reflex-size-aware"> <div style={this.state}> { this.renderChildren() } </div> </div> ) } } </Measure> ) } } class ReflexElement extends React.Component { static propTypes = { propagateDimensions: PropTypes.bool, resizeHeight: PropTypes.bool, resizeWidth: PropTypes.bool, className: PropTypes.string, size: PropTypes.number } static defaultProps = { propagateDimensionsRate: 100, propagateDimensions: false, resizeHeight: true, resizeWidth: true, direction: [1], className: '' } constructor (props) { super (props) this.state = { size: props.size } } static getDerivedStateFromProps (nextProps, prevState) { if (nextProps.size !== prevState.size) { return { ...prevState, size: nextProps.size } } return null } async componentDidUpdate (prevProps, prevState, snapshot) { if (prevState.size !== this.state.size) { const directions = toArray(this.props.direction) for (let direction of directions) { await this.props.events.emit('element.size', { index: this.props.index, size: this.props.size, direction }) } } } renderChildren () { const validChildren = toArray(this.props.children).filter(child => { return !!child }) return React.Children.map(validChildren, (child) => { if (this.props.withHandle || ReflexHandle.isA(child)) { return React.cloneElement(child, { ...child.props, index: this.props.index - 1, events: this.props.events }) } return child }) } render () { const className = [ ...this.props.className.split(' '), this.props.orientation, 'reflex-element' ].join(' ').trim() const style = { ...this.props.style, flexGrow: this.props.flex, flexShrink: 1, flexBasis: '0%' } return ( <div {...getDataProps(this.props)} ref={this.props.innerRef} className={className} style={style}> { this.props.propagateDimensions ? <SizeAwareReflexElement {...this.props}/> : this.renderChildren() } </div> ) } } export default React.forwardRef((props, ref) => { return ( <ReflexElement innerRef={ref} {...props}/> ) })