UNPKG

@render-props/scrollable

Version:

A state container which provides an interface for listening to the scroll event of its child component and providing valuable data about direction, distance, and more. It also provides convenience functions for scrollTo with optional animation.

250 lines (220 loc) 5.66 kB
'use strict' var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault') exports.__esModule = true exports.default = Scrollable exports.Scrollable_ = void 0 var _extends2 = _interopRequireDefault( require('@babel/runtime/helpers/extends') ) var _react = _interopRequireDefault(require('react')) var _propTypes = _interopRequireDefault(require('prop-types')) var _events = _interopRequireDefault(require('@render-props/events')) var _throttle = _interopRequireDefault(require('@render-props/throttle')) var _utils = require('@render-props/utils') var _utils2 = require('./utils') /** import Scrollable from '@render-props/scrollable' const ScrollableBox = props => ( <Scrollable> { ({ scrollRef, scrollToX, scrollToY, scrollTo, scrollHeight, scrollWidth, scrollY, scrollX, clientHeight, clientWidth, max, direction, distance, }) => ( <div ref={scrollRef} style={{ width: 300, height: 300, overflow: 'auto', background: '#000' }} > <div style={{width: 600, height: 16000, position: 'relative'}}> <pre style={{ position: 'absolute', top: scrollY + 10, left: scrollX + 10 }}> {JSON.stringify({ scrollRef, scrollToX, scrollToY, scrollTo, scrollHeight, scrollWidth, scrollY, scrollX, clientHeight, clientWidth, max, direction, distance, }, null, 2)} </pre> </div> </div> ) } </Scrollable> ) */ const initialState = { scrollHeight: 0, scrollWidth: 0, scrollY: 0, scrollX: 0, clientHeight: 0, clientWidth: 0, max: { x: 0, y: 0, }, direction: { x: 0, y: 0, }, distance: { x: 0, y: 0, }, } class Scrollable_ extends _react.default.Component { constructor(props) { super(props) this.scrollable = null this.scrollRef = e => { if (e === null) { return } const scrollableChanged = this.scrollable !== e if (this.scrollable !== e) { if (this.scrollable !== null) { this.props.removeAllEvents(this.scrollable) } this.scrollable = e this.props.addEvent(e, 'scroll', this.onScroll) this.onScroll() } } this.onScroll = e => { this.props.throttleState(prevState => { const { scrollWidth, scrollHeight, scrollLeft, scrollTop, clientWidth, clientHeight, } = this.scrollable const nextScroll = { scrollX: scrollLeft, scrollY: scrollTop, } const direction = (0, _utils2.getDirection)(prevState, nextScroll) const distance = (0, _utils2.getDistance)(prevState, nextScroll) return { scrollWidth: scrollWidth, scrollHeight: scrollHeight, scrollX: scrollLeft, scrollY: scrollTop, clientWidth, clientHeight, max: { x: scrollWidth - clientWidth, y: scrollHeight - clientHeight, }, direction, distance, } }) } this.scrollTo = (posX, posY, opt) => { if (typeof opt !== 'object' && opt !== null) { if (posY !== void 0 && posX !== null) { this.scrollable.scrollTop = posY } if (posX !== void 0 && posY !== null) { this.scrollable.scrollLeft = posX } } else { ;(0, _utils2.scrollTo)( this.scrollable, { x: this.props.state.scrollX, y: this.props.state.scrollY, }, { x: posX, y: posY, }, opt ) } } this.scrollToX = (posX, opt) => this.scrollTo(posX, void 0, opt) this.scrollToY = (posY, opt) => this.scrollTo(void 0, posY, opt) this.scrollableContext = { scrollRef: this.scrollRef, scrollToX: this.scrollToX, scrollToY: this.scrollToY, scrollTo: this.scrollTo, } } componentDidMount() { const {initialX, initialY} = this.props if (initialX || initialY) { this.scrollTo(initialX, initialY) } } componentDidUpdate({state}) { if ( state.scrollX !== this.props.state.scrollX || state.scrollY !== this.props.state.scrollY ) { ;(0, _utils.callIfExists)(this.props.onScroll, this.props.state) } } render() { return this.props.children( (0, _extends2.default)(this.scrollableContext, this.props.state) ) } } exports.Scrollable_ = Scrollable_ Scrollable_.displayName = 'Scrollable' Scrollable_.propTypes = { children: _propTypes.default.func.isRequired, onScroll: _propTypes.default.func, initialX: _propTypes.default.number, initialY: _propTypes.default.number, } function Scrollable(props) { return _react.default.createElement(_events.default, null, function( eventContext ) { return _react.default.createElement( _throttle.default, { initialState: initialState, }, function(throttleContext) { return _react.default.createElement( Scrollable_, (0, _extends2.default)({}, eventContext, throttleContext, props) ) } ) }) }