UNPKG

react-flexigrid

Version:

A React table component designed to allow presenting millions of rows of data.

186 lines (164 loc) 4.42 kB
/* eslint-disable react/require-default-props */ import React from 'react' import classNames from 'classnames' import PropTypes from 'prop-types' import propTypes from './struct/propTypes' import MouseMoveTracker from './dom/MouseMoveTracker' import { clamp, shallowEqual, cancelAnimationFrame, requestAnimationFrame, } from './utils' const miniColumnWidth = 4 export default class FlexiGridColumnResizeHandler extends React.Component { static propTypes = { prefixCls: PropTypes.string, rtl: PropTypes.bool, visible: PropTypes.bool, height: PropTypes.number, offsetLeft: PropTypes.number, offsetTop: PropTypes.number, initialWidth: PropTypes.number, minWidth: PropTypes.number, maxWidth: PropTypes.number, knobSize: PropTypes.number, adjustKnob: PropTypes.bool, initialEvent: propTypes.domEvent, columnKey: propTypes.columnKey, onColumnResizing: PropTypes.func, onColumnResized: PropTypes.func, } static defaultProps = { rtl: false, visible: false, adjustKnob: false, height: 0, offsetLeft: 0, offsetTop: 0, initialWidth: 0, minWidth: miniColumnWidth, maxWidth: Number.MAX_SAFE_INTEGER, knobSize: 0, initialEvent: null, } constructor(props) { super(props) this.state = { width: 0, cursorDelta: 0, } this.cache = null this.animating = false } componentDidMount() { this.mouseMoveTracker = new MouseMoveTracker( document.body, this.onColumnResizing, this.onColumnResized, ) } componentWillReceiveProps(props) { if (props.initialEvent && !this.mouseMoveTracker.isDragging()) { this.mouseMoveTracker.capture(props.initialEvent) this.setState({ left: props.offsetLeft - (props.rtl ? 1 : 0), width: props.initialWidth, cursorDelta: props.initialWidth, }) this.cache = null this.animating = true this.frameId = requestAnimationFrame(this.updateState) } } shouldComponentUpdate(nextProps, nextState) { return ( !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState) ) } componentWillUnmount() { this.mouseMoveTracker.release() this.mouseMoveTracker = null } onColumnResizing = (deltaX) => { const { rtl } = this.props const state = this.cache || this.state const newWidth = state.cursorDelta + (rtl ? -deltaX : deltaX) const newFixedWidth = clamp( newWidth, this.props.minWidth || miniColumnWidth, this.props.maxWidth, ) const left = state.left - (this.props.rtl ? newFixedWidth - state.width : 0) this.cache = { left, width: newFixedWidth, cursorDelta: newWidth, } } onColumnResized = () => { cancelAnimationFrame(this.frameId) this.cache = null this.frameId = null this.animating = false this.mouseMoveTracker.release() if (this.props.onColumnResized) { this.props.onColumnResized(this.state.width, this.props.columnKey) } } updateState = () => { if (this.animating) { this.frameId = requestAnimationFrame(this.updateState) } if (this.cache) { this.setState(this.cache) if (this.props.onColumnResizing) { this.props.onColumnResizing(this.cache.width, this.props.columnKey) } } } render() { const { prefixCls, rtl, visible, height, offsetTop, knobSize, adjustKnob } = this.props const { width, left } = this.state const className = classNames( `${prefixCls}-resize-handler`, { visible, }, ) const wrapStyle = { width, left, height: height - offsetTop, top: offsetTop, } const lineStyle = { height: wrapStyle.height, top: 0, } const innerStyle = { ...lineStyle, width: knobSize, right: -Math.ceil(knobSize / 2), } if (rtl) { lineStyle.left = 0 innerStyle.left = -Math.ceil(knobSize / 2) } else { lineStyle.right = adjustKnob ? knobSize : 0 innerStyle.right = (adjustKnob ? knobSize : 0) - Math.ceil(knobSize / 2) } return ( <div className={className} style={wrapStyle} > <div className={'knob-marker'} style={lineStyle} /> <div className={'mouse-area'} style={innerStyle} /> </div> ) } }