react-scroll-box
Advanced tools
| {"version":3,"sources":[],"names":[],"mappings":"","file":"index.css","sourceRoot":""} |
Sorry, the diff of this file is too big to display
| { | ||
| "name": "react-scroll-box", | ||
| "version": "3.0.0", | ||
| "author": "Savva Mikhalevski", | ||
| "description": "Charged cross-browser and cross-platform scrollable container implementation with no external dependencies but React 15+", | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/smikhalevski/react-scroll-box.git" | ||
| }, | ||
| "main": "index.js", | ||
| "homepage": "https://github.com/smikhalevski/react-scroll-box", | ||
| "keywords": [ | ||
| "react", | ||
| "component", | ||
| "scroll", | ||
| "scrollbox", | ||
| "scrollbar" | ||
| ], | ||
| "scripts": { | ||
| "start": "webpack-dev-server -d --progress --config webpack.gh-pages.config.js", | ||
| "build": "rm -rf target/out; webpack -p --devtool source-map", | ||
| "build:gh-pages": "rm -rf target/gh-pages; webpack -p --config webpack.gh-pages.config.js" | ||
| }, | ||
| "devDependencies": { | ||
| "webpack": "2.6.1", | ||
| "webpack-dev-server": "2.4.5", | ||
| "babel-loader": "^6.2.10", | ||
| "hson-loader": "^2.0.0", | ||
| "less-loader": "^4.0.3", | ||
| "style-loader": "^0.18.0", | ||
| "css-loader": "^0.28.3", | ||
| "file-loader": "^0.11.1", | ||
| "extract-text-webpack-plugin": "2.1.0", | ||
| "babel-core": "^6.24.1", | ||
| "babel-preset-es2015": "^6.24.1", | ||
| "babel-preset-react": "^6.24.1", | ||
| "babel-preset-stage-0": "^6.24.1", | ||
| "babel-plugin-transform-runtime": "^6.23.0", | ||
| "babel-plugin-transform-regenerator": "^6.24.1", | ||
| "less": "^2.7.2", | ||
| "classnames": "^2.2.5", | ||
| "lodash": "^4.17.4", | ||
| "classlist-polyfill": "^1.2.0" | ||
| }, | ||
| "dependencies": { | ||
| "react": "^15.0.0", | ||
| "prop-types": "^15.5.10", | ||
| "react-dom": "^15.0.0" | ||
| } | ||
| } |
| import React from 'react'; | ||
| import {findDOMNode} from 'react-dom'; | ||
| import {bool, element, func, node, number, object, oneOf, string} from 'prop-types'; | ||
| export const FastTrackMode = { | ||
| PAGING: 'paging', | ||
| GOTO: 'goto' | ||
| }; | ||
| export const ScrollCause = { | ||
| HANDLE_DRAG: 0, | ||
| MOUSE_WHEEL: 1, | ||
| FAST_TRACK: 2, | ||
| KEYBOARD: 3, | ||
| TOUCH: 4 | ||
| }; | ||
| export const ScrollEasing = { | ||
| easeQuadOut(percent, elapsed, min, max, duration) { | ||
| percent -= 1; | ||
| return min + max * Math.sqrt(1 - Math.pow(percent, 2)); | ||
| } | ||
| }; | ||
| export class AbstractScrollBox extends React.Component { | ||
| static propTypes = { | ||
| // Viewport element. | ||
| children: element.isRequired, | ||
| // Use native client scroll bars. | ||
| nativeScrollBars: bool, | ||
| className: string, | ||
| style: object, | ||
| disabled: bool, | ||
| // Events | ||
| onScroll: func, | ||
| onScrollX: func, | ||
| onScrollY: func, | ||
| onScrollStart: func, | ||
| onScrollStartX: func, | ||
| onScrollStartY: func, | ||
| onScrollEnd: func, | ||
| onScrollEndX: func, | ||
| onScrollEndY: func, | ||
| // Disable scrolling in corresponding direction. | ||
| disableScrollX: bool, | ||
| disableScrollY: bool, | ||
| // Toggle scroll bar visibility for corresponding direction. | ||
| hideScrollBarX: bool, | ||
| hideScrollBarY: bool, | ||
| // Toggle show scroll bars outside of scroll box rectangle. | ||
| // This has no effect when native scroll bars are enabled on mobile device. | ||
| outsetScrollBarX: bool, | ||
| outsetScrollBarY: bool, | ||
| // Minimum number of pixels when scroll bars are required. | ||
| scrollMinX: number, | ||
| scrollMinY: number, | ||
| // Distance from cursor to edge of the scroll track when scroll bar is considered to be hovered. | ||
| trackHoverProximityX: number, | ||
| trackHoverProximityY: number, | ||
| // Default easing functions applied when scroll with non-zero duration is requested. | ||
| easingX: func, | ||
| easingY: func, | ||
| // Handle drag | ||
| captureHandleDragX: bool, | ||
| captureHandleDragY: bool, | ||
| // Interrupt handle drag when programmatic scrolling requested. | ||
| interruptibleHandleDrag: bool, | ||
| // Fast tracking occurs when user clicks on scroll track. | ||
| captureFastTrackX: bool, | ||
| captureFastTrackY: bool, | ||
| fastTrackModeX: oneOf(Object.values(FastTrackMode)), | ||
| fastTrackModeY: oneOf(Object.values(FastTrackMode)), | ||
| fastTrackScrollDurationX: number, | ||
| fastTrackScrollDurationY: number, | ||
| // Keyboard | ||
| captureKeyboard: bool, | ||
| keyboardStepX: number, | ||
| keyboardStepY: number, | ||
| keyboardScrollDurationX: number, | ||
| keyboardScrollDurationY: number, | ||
| // Wheel | ||
| captureWheel: bool, | ||
| wheelLineHeight: number, | ||
| wheelStepX: number, | ||
| wheelStepY: number, | ||
| propagateWheelScrollX: bool, | ||
| propagateWheelScrollY: bool, | ||
| swapWheelAxes: bool, | ||
| wheelScrollDurationX: number, | ||
| wheelScrollDurationY: number, | ||
| // Touch | ||
| captureTouch: bool, | ||
| propagateTouchScrollX: bool, | ||
| propagateTouchScrollY: bool, | ||
| touchSingleAxis: bool, | ||
| touchStartDistance: number, | ||
| continuousTouchScrollX: bool, | ||
| continuousTouchScrollY: bool, | ||
| inertiaEasingX: func, | ||
| inertiaEasingY: func, | ||
| inertiaDistanceX: func, | ||
| inertiaDistanceY: func, | ||
| inertiaDurationX: func, | ||
| inertiaDurationY: func, | ||
| // Layout | ||
| trackChildrenX: node, | ||
| trackChildrenY: node, | ||
| handleChildrenX: node, | ||
| handleChildrenY: node | ||
| }; | ||
| static defaultProps = { | ||
| nativeScrollBars: false, | ||
| className: 'scroll-box--wrapped', | ||
| style: null, | ||
| disabled: false, | ||
| onScroll(target, dx, dy, causeX, causeY) {}, | ||
| onScrollX(target, dx, causeX) {}, | ||
| onScrollY(target, dy, causeY) {}, | ||
| onScrollStart(target, causeX, causeY) {}, | ||
| onScrollStartX(target, causeX) {}, | ||
| onScrollStartY(target, causeY) {}, | ||
| onScrollEnd(target, causeX, causeY) {}, | ||
| onScrollEndX(target, causeX) {}, | ||
| onScrollEndY(target, causeY) {}, | ||
| disableScrollX: false, | ||
| disableScrollY: false, | ||
| hideScrollBarX: false, | ||
| hideScrollBarY: false, | ||
| outsetScrollBarX: false, | ||
| outsetScrollBarY: false, | ||
| scrollMinX: 2, | ||
| scrollMinY: 2, | ||
| trackHoverProximityX: 50, | ||
| trackHoverProximityY: 50, | ||
| easingX: ScrollEasing.easeQuadOut, | ||
| easingY: ScrollEasing.easeQuadOut, | ||
| // Handle drag | ||
| captureHandleDragX: true, | ||
| captureHandleDragY: true, | ||
| interruptibleHandleDrag: true, | ||
| // Fast track | ||
| captureFastTrackX: true, | ||
| captureFastTrackY: true, | ||
| fastTrackModeX: FastTrackMode.GOTO, | ||
| fastTrackModeY: FastTrackMode.GOTO, | ||
| fastTrackScrollDurationX: 500, | ||
| fastTrackScrollDurationY: 500, | ||
| // Keyboard | ||
| captureKeyboard: true, | ||
| keyboardStepX: 30, | ||
| keyboardStepY: 30, | ||
| keyboardScrollDurationX: 200, | ||
| keyboardScrollDurationY: 200, | ||
| // Wheel | ||
| captureWheel: true, | ||
| // Used when scroll by line-height is requested. | ||
| wheelLineHeight: 24, | ||
| wheelStepX: 100, | ||
| wheelStepY: 100, | ||
| propagateWheelScrollX: false, | ||
| propagateWheelScrollY: true, | ||
| swapWheelAxes: false, | ||
| wheelScrollDurationX: 100, | ||
| wheelScrollDurationY: 100, | ||
| // Touch | ||
| captureTouch: true, | ||
| propagateTouchScrollX: true, | ||
| propagateTouchScrollY: true, | ||
| touchSingleAxis: true, | ||
| touchStartDistance: 10, | ||
| continuousTouchScrollX: false, | ||
| continuousTouchScrollY: false, | ||
| inertiaEasingX: ScrollEasing.easeQuadOut, | ||
| inertiaEasingY: ScrollEasing.easeQuadOut, | ||
| inertiaDistanceX: (dx, dt) => dx / dt * 100, | ||
| inertiaDistanceY: (dy, dt) => dy / dt * 100, | ||
| inertiaDurationX: (dx, dt) => dx / dt * 100, | ||
| inertiaDurationY: (dy, dt) => dy / dt * 100, | ||
| // Layout | ||
| trackChildrenX: null, | ||
| trackChildrenY: null, | ||
| handleChildrenX: null, | ||
| handleChildrenY: null | ||
| }; | ||
| constructor(props) { | ||
| super(props); | ||
| let _scrollX = 0, | ||
| _scrollY = 0, | ||
| _prevX = 0, | ||
| _prevY = 0, | ||
| _targetX = 0, | ||
| _targetY = 0, | ||
| _durationX = 0, | ||
| _durationY = 0, | ||
| _easingX, | ||
| _easingY, | ||
| _timestampX = 0, | ||
| _timestampY = 0, | ||
| _dispatchPrevented = false, | ||
| _scrollMaxX = 0, | ||
| _scrollMaxY = 0, | ||
| _trackMaxX = 0, | ||
| _trackMaxY = 0, | ||
| _requiresScrollBarX = false, | ||
| _requiresScrollBarY = false, | ||
| _requestId, | ||
| _scrollingX = false, | ||
| _scrollingY = false, | ||
| _causeX = null, | ||
| _causeY = null, | ||
| _tickX = 0, | ||
| _tickY = 0, | ||
| // Refs | ||
| _root, | ||
| _viewport, | ||
| _handleX, | ||
| _handleY, | ||
| _trackX, | ||
| _trackY; | ||
| const setHandleX = ref => _handleX = ref; | ||
| const setHandleY = ref => _handleY = ref; | ||
| const setTrackX = ref => _trackX = ref; | ||
| const setTrackY = ref => _trackY = ref; | ||
| this.componentDidMount = () => { | ||
| _root = findDOMNode(this); | ||
| _viewport = _root.firstChild; | ||
| const requestPropagateChanges = () => { | ||
| if (window.cancelAnimationFrame) { | ||
| _requestId = requestAnimationFrame(requestPropagateChanges); | ||
| } else { | ||
| _requestId = setTimeout(requestPropagateChanges, 1000 / 30); | ||
| } | ||
| propagateChanges(); | ||
| }; | ||
| requestPropagateChanges(); | ||
| addEventListener('mousemove', handleTrackHover); | ||
| // Fix https://github.com/facebook/react/issues/8968 | ||
| _root.addEventListener('touchstart', handleTouchStart); | ||
| }; | ||
| this.componentWillUnmount = () => { | ||
| _root = null; | ||
| if (window.cancelAnimationFrame) { | ||
| cancelAnimationFrame(_requestId); | ||
| } else { | ||
| clearTimeout(_requestId); | ||
| } | ||
| removeEventListener('mousemove', handleTrackHover); | ||
| }; | ||
| this.componentDidUpdate = () => { | ||
| _viewport = _root.firstChild; | ||
| propagateChanges(); | ||
| }; | ||
| this.render = () => { | ||
| const { | ||
| className, | ||
| style, | ||
| disabled, | ||
| outsetScrollBarX, | ||
| outsetScrollBarY, | ||
| nativeScrollBars, | ||
| disableScrollX, | ||
| disableScrollY, | ||
| hideScrollBarX, | ||
| hideScrollBarY, | ||
| children, | ||
| trackChildrenX, | ||
| trackChildrenY, | ||
| handleChildrenX, | ||
| handleChildrenY | ||
| } = this.props; | ||
| let classNames = ['scroll-box']; | ||
| if (className) { | ||
| classNames.push(className); | ||
| } | ||
| if (disabled) { | ||
| classNames.push('scroll-box--disabled'); | ||
| } | ||
| if (outsetScrollBarX) { | ||
| classNames.push('scroll-box--outset-x'); | ||
| } | ||
| if (outsetScrollBarY) { | ||
| classNames.push('scroll-box--outset-y'); | ||
| } | ||
| if (!disableScrollX && !hideScrollBarX) { | ||
| classNames.push('scroll-box--enable-x'); | ||
| } | ||
| if (!disableScrollY && !hideScrollBarY) { | ||
| classNames.push('scroll-box--enable-y'); | ||
| } | ||
| if (nativeScrollBars) { | ||
| classNames.push('scroll-box--native-scroll-bars'); | ||
| } | ||
| return ( | ||
| <div style={style} | ||
| className={classNames.join(' ')} | ||
| onWheel={handleWheel} | ||
| onKeyDown={handleKeyDown} | ||
| tabIndex="-1"> | ||
| {children} | ||
| <div className="scroll-box__track scroll-box__track--x" | ||
| onMouseDown={handleFastTrackX} | ||
| ref={setTrackX}> | ||
| <div className="scroll-box__handle scroll-box__handle--x" | ||
| onMouseDown={handleDragStartX} | ||
| ref={setHandleX}> | ||
| {handleChildrenX} | ||
| </div> | ||
| {trackChildrenX} | ||
| </div> | ||
| <div className="scroll-box__track scroll-box__track--y" | ||
| onMouseDown={handleFastTrackY} | ||
| ref={setTrackY}> | ||
| <div className="scroll-box__handle scroll-box__handle--y" | ||
| onMouseDown={handleDragStartY} | ||
| ref={setHandleY}> | ||
| {handleChildrenY} | ||
| </div> | ||
| {trackChildrenY} | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
| this.scrollTo = ({ | ||
| x, y, | ||
| easing, | ||
| easingX = easing || this.props.easingX, | ||
| easingY = easing || this.props.easingY, | ||
| duration = 0, | ||
| durationX = duration, | ||
| durationY = duration, | ||
| dispatchPrevented = false | ||
| } = {}) => { | ||
| if (!isNaN(x) && x !== null) { | ||
| _prevX = _scrollX; | ||
| _targetX = x | 0; | ||
| _easingX = easingX; | ||
| _durationX = durationX; | ||
| _timestampX = Date.now(); | ||
| _dispatchPrevented = dispatchPrevented; | ||
| _tickX++; | ||
| } | ||
| if (!isNaN(y) && y !== null) { | ||
| _prevY = _scrollY; | ||
| _targetY = y | 0; | ||
| _easingY = easingY; | ||
| _durationY = durationY; | ||
| _timestampY = Date.now(); | ||
| _dispatchPrevented = dispatchPrevented; | ||
| _tickY++; | ||
| } | ||
| propagateChanges(); | ||
| }; | ||
| this.scrollToX = (x, options = {}) => this.scrollTo({...options, x}); | ||
| this.scrollToY = (y, options = {}) => this.scrollTo({...options, y}); | ||
| this.scrollBy = ({dx, dy, ...options} = {}) => { | ||
| this.scrollTo({ | ||
| ...options, | ||
| x: _targetX + dx, | ||
| y: _targetY + dy | ||
| }); | ||
| }; | ||
| this.scrollByX = (dx, options = {}) => this.scrollBy({...options, dx}); | ||
| this.scrollByY = (dy, options = {}) => this.scrollBy({...options, dy}); | ||
| this.scrollToPage = ({ | ||
| x, y, | ||
| ...options | ||
| } = {}) => { | ||
| x *= this.getPageWidth(); | ||
| y *= this.getPageHeight(); | ||
| this.scrollTo({...options, x, y}); | ||
| }; | ||
| this.scrollToPageX = (x, options = {}) => this.scrollToPage({...options, x}); | ||
| this.scrollToPageY = (y, options = {}) => this.scrollToPage({...options, y}); | ||
| this.scrollByPage = ({ | ||
| dx, dy, | ||
| ...options | ||
| } = {}) => { | ||
| dx *= this.getPageWidth(); | ||
| dy *= this.getPageHeight(); | ||
| this.scrollBy({...options, dx, dy}); | ||
| }; | ||
| this.scrollByPageX = (dx, options = {}) => this.scrollByPage({...options, dx}); | ||
| this.scrollByPageY = (dy, options = {}) => this.scrollByPage({...options, dy}); | ||
| this.getPageWidth = () => _viewport.clientWidth; | ||
| this.getPageHeight = () => _viewport.clientHeight; | ||
| Object.defineProperties(this, { | ||
| targetX: { | ||
| get: () => _targetX, | ||
| set: x => this.scrollToX(x) | ||
| }, | ||
| targetY: { | ||
| get: () => _targetY, | ||
| set: y => this.scrollToY(y) | ||
| }, | ||
| scrollX: { | ||
| get: () => _scrollX, | ||
| set: x => this.scrollToX(x) | ||
| }, | ||
| scrollY: { | ||
| get: () => _scrollY, | ||
| set: y => this.scrollToY(y) | ||
| }, | ||
| scrollMaxX: { | ||
| get: () => _scrollMaxX | ||
| }, | ||
| scrollMaxY: { | ||
| get: () => _scrollMaxY | ||
| } | ||
| }); | ||
| const isTargetIgnored = target => /textarea|input/i.test(target.tagName); | ||
| const propagateChanges = () => { | ||
| const { | ||
| disableScrollX, | ||
| disableScrollY, | ||
| scrollMinX, | ||
| scrollMinY, | ||
| nativeScrollBars, | ||
| outsetScrollBarX, | ||
| outsetScrollBarY, | ||
| onScroll, | ||
| onScrollX, | ||
| onScrollY, | ||
| onScrollStart, | ||
| onScrollStartX, | ||
| onScrollStartY, | ||
| onScrollEnd, | ||
| onScrollEndX, | ||
| onScrollEndY | ||
| } = this.props; | ||
| const { | ||
| clientWidth, | ||
| clientHeight, | ||
| offsetWidth, | ||
| offsetHeight, | ||
| scrollWidth, | ||
| scrollHeight, | ||
| scrollTop, | ||
| scrollLeft | ||
| } = _viewport; | ||
| _scrollMaxX = scrollWidth - clientWidth; | ||
| _scrollMaxY = scrollHeight - clientHeight; | ||
| _requiresScrollBarX = !disableScrollX && _scrollMaxX >= scrollMinX; | ||
| _requiresScrollBarY = !disableScrollY && _scrollMaxY >= scrollMinY; | ||
| _root.classList.toggle('scroll-box--requires-x', _requiresScrollBarX); | ||
| _root.classList.toggle('scroll-box--requires-y', _requiresScrollBarY); | ||
| _viewport.style.height = do { | ||
| if (nativeScrollBars && outsetScrollBarX) { | ||
| `calc(100% + ${offsetHeight - clientHeight}px)`; | ||
| } else { | ||
| '100%'; | ||
| } | ||
| }; | ||
| _viewport.style.width = do { | ||
| if (nativeScrollBars && outsetScrollBarY) { | ||
| `calc(100% + ${offsetWidth - clientWidth}px)`; | ||
| } else { | ||
| '100%'; | ||
| } | ||
| }; | ||
| _targetX = Math.max(0, Math.min(_targetX, _scrollMaxX)); | ||
| _targetY = Math.max(0, Math.min(_targetY, _scrollMaxY)); | ||
| let nextScrollX = _scrollX, | ||
| nextScrollY = _scrollY; | ||
| if (_scrollX === scrollLeft && _scrollY === scrollTop) { | ||
| // Controlled scroll position coincides with viewport position. | ||
| if (nextScrollX !== _targetX) { | ||
| const elapsedX = Date.now() - _timestampX; | ||
| if (elapsedX < _durationX) { | ||
| nextScrollX = _prevX + _easingX(elapsedX / _durationX, elapsedX, 0, 1, _durationX) * (_targetX - _prevX) | 0; | ||
| } else { | ||
| nextScrollX = _targetX; | ||
| } | ||
| } | ||
| if (nextScrollY !== _targetY) { | ||
| const elapsedY = Date.now() - _timestampY; | ||
| if (elapsedY < _durationY) { | ||
| nextScrollY = _prevY + _easingY(elapsedY / _durationY, elapsedY, 0, 1, _durationY) * (_targetY - _prevY) | 0; | ||
| } else { | ||
| nextScrollY = _targetY; | ||
| } | ||
| } | ||
| } | ||
| const clientScrollingX = _scrollX !== scrollLeft, | ||
| clientScrollingY = _scrollY !== scrollTop; | ||
| if (clientScrollingX) { | ||
| _targetX = nextScrollX = scrollLeft; | ||
| } | ||
| if (clientScrollingY) { | ||
| _targetY = nextScrollY = scrollTop; | ||
| } | ||
| const nextScrollingX = nextScrollX !== _targetX, | ||
| nextScrollingY = nextScrollY !== _targetY; | ||
| const dx = _scrollX - nextScrollX, | ||
| dy = _scrollY - nextScrollY; | ||
| const tickX = _tickX, | ||
| tickY = _tickY; | ||
| if (!_dispatchPrevented) { | ||
| // Events can be triggered. | ||
| // Checking ticks after each event callback invocation to ensure that any scroll | ||
| // methods were not called inside those callbacks. | ||
| if ( | ||
| (nextScrollingX || nextScrollingY || clientScrollingX || clientScrollingY) && | ||
| !_scrollingX && !_scrollingY | ||
| ) { | ||
| onScrollStart(this, _causeX, _causeY); | ||
| } | ||
| if (tickX === _tickX && nextScrollingX && !_scrollingX) { | ||
| onScrollStartX(this, _causeX); | ||
| } | ||
| if (tickY === _tickY && nextScrollingY && !_scrollingY) { | ||
| onScrollStartY(this, _causeY); | ||
| } | ||
| if ( | ||
| tickX === _tickX && tickY === _tickY && | ||
| (dx || dy) | ||
| ) { | ||
| onScroll(this, dx, dy, _causeX, _causeY); | ||
| } | ||
| if (tickX === _tickX && dx) { | ||
| onScrollX(this, dx, _causeX); | ||
| } | ||
| if (tickY === _tickY && dy) { | ||
| onScrollY(this, dy, _causeY); | ||
| } | ||
| if ( | ||
| tickX === _tickX && tickY === _tickY && | ||
| !nextScrollingX && !nextScrollingY && | ||
| (_scrollingX || _scrollingY || clientScrollingX || clientScrollingY) | ||
| ) { | ||
| onScrollEnd(this, _causeX, _causeY); | ||
| } | ||
| if (tickX === _tickX && !nextScrollingX && _scrollingX) { | ||
| onScrollEndX(this, _causeX); | ||
| } | ||
| if (tickY === _tickY && !nextScrollingY && _scrollingY) { | ||
| onScrollEndY(this, _causeY); | ||
| } | ||
| if (tickX === _tickX && (_causeX !== ScrollCause.TOUCH || _causeX !== ScrollCause.HANDLE_DRAG)) { | ||
| _causeX = null; | ||
| } | ||
| if (tickY === _tickY && (_causeY !== ScrollCause.TOUCH || _causeY !== ScrollCause.HANDLE_DRAG)) { | ||
| _causeY = null; | ||
| } | ||
| } | ||
| if (dx && tickX === _tickX) { | ||
| _viewport.scrollLeft = _scrollX = nextScrollX; | ||
| } | ||
| if (dy && tickY === _tickY) { | ||
| _viewport.scrollTop = _scrollY = nextScrollY; | ||
| } | ||
| if (!nativeScrollBars) { | ||
| _trackMaxX = _trackX.clientWidth - _handleX.offsetWidth; | ||
| _handleX.style.width = clientWidth / scrollWidth * 100 + '%'; | ||
| _handleX.style.left = _trackMaxX * nextScrollX / _scrollMaxX + 'px'; | ||
| _trackMaxY = _trackY.clientHeight - _handleY.offsetHeight; | ||
| _handleY.style.height = clientHeight / scrollHeight * 100 + '%'; | ||
| _handleY.style.top = _trackMaxY * nextScrollY / _scrollMaxY + 'px'; | ||
| } | ||
| }; | ||
| const handleKeyDown = event => { | ||
| const {target, keyCode, shiftKey} = event; | ||
| const { | ||
| disabled, | ||
| captureKeyboard, | ||
| keyboardStepX, | ||
| keyboardStepY, | ||
| keyboardScrollDurationX, | ||
| keyboardScrollDurationY | ||
| } = this.props; | ||
| if (disabled || !captureKeyboard || isTargetIgnored(target)) { | ||
| // Do not handle any keyboard events when text-related controls are focused. | ||
| return; | ||
| } | ||
| const optionsX = {duration: keyboardScrollDurationX}, | ||
| optionsY = {duration: keyboardScrollDurationY}; | ||
| switch (keyCode) { | ||
| case 36: // Home | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollToY(0, optionsY); | ||
| break; | ||
| case 35: // End | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollToY(_scrollMaxY, optionsY); | ||
| break; | ||
| case 33: // Page Up | ||
| case 34: // Page Down | ||
| event.preventDefault(); | ||
| let dy = this.getPageHeight(), | ||
| dx = this.getPageWidth(); | ||
| if (keyCode === 33) { // Page Up | ||
| dy *= -1; | ||
| dx *= -1; | ||
| } | ||
| if (shiftKey) { | ||
| _causeX = ScrollCause.KEYBOARD; | ||
| this.scrollByX(dx, optionsX); | ||
| } else { | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollByY(dy, optionsY); | ||
| } | ||
| break; | ||
| case 38: // Up | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollByY(-keyboardStepY, optionsY); | ||
| break; | ||
| case 40: // Down | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollByY(keyboardStepY, optionsY); | ||
| break; | ||
| case 37: // Left | ||
| event.preventDefault(); | ||
| _causeX = ScrollCause.KEYBOARD; | ||
| this.scrollByX(-keyboardStepX, optionsX); | ||
| break; | ||
| case 39: // Right | ||
| event.preventDefault(); | ||
| _causeX = ScrollCause.KEYBOARD; | ||
| this.scrollByX(keyboardStepX, optionsX); | ||
| break; | ||
| } | ||
| }; | ||
| const handleFastTrack = (event, horizontal) => { | ||
| const { | ||
| disabled, | ||
| captureFastTrackX, | ||
| captureFastTrackY, | ||
| fastTrackModeX, | ||
| fastTrackModeY, | ||
| fastTrackScrollDurationX, | ||
| fastTrackScrollDurationY | ||
| } = this.props; | ||
| if (disabled || !(captureFastTrackX || captureFastTrackY) || event.button) { | ||
| // Component is disabled or secondary mouse button is being pressed. | ||
| return; | ||
| } | ||
| const { | ||
| clientWidth, | ||
| clientHeight, | ||
| scrollWidth, | ||
| scrollHeight | ||
| } = _viewport; | ||
| if (horizontal) { | ||
| if (!captureFastTrackX) { | ||
| return; | ||
| } | ||
| _causeX = ScrollCause.FAST_TRACK; | ||
| const pointerX = event.clientX - _trackX.getBoundingClientRect().left, | ||
| optionsX = {duration: fastTrackScrollDurationX}; | ||
| switch (fastTrackModeX) { | ||
| case FastTrackMode.PAGING: | ||
| this.scrollToX(_targetX + (1 - 2 * (pointerX < _handleX.offsetLeft)) * this.getPageWidth(), optionsX); | ||
| break; | ||
| case FastTrackMode.GOTO: | ||
| this.scrollToX(pointerX / _trackX.clientWidth * scrollWidth - clientWidth / 2, optionsX); | ||
| break; | ||
| } | ||
| } else { | ||
| if (!captureFastTrackY) { | ||
| return; | ||
| } | ||
| _causeY = ScrollCause.FAST_TRACK; | ||
| const pointerY = event.clientY - _trackY.getBoundingClientRect().top, | ||
| optionsY = {duration: fastTrackScrollDurationY}; | ||
| switch (fastTrackModeY) { | ||
| case FastTrackMode.PAGING: | ||
| this.scrollToY(_targetY + (1 - 2 * (pointerY < _handleY.offsetTop)) * this.getPageHeight(), optionsY); | ||
| break; | ||
| case FastTrackMode.GOTO: | ||
| this.scrollToY(pointerY / _trackY.clientHeight * scrollHeight - clientHeight / 2, optionsY); | ||
| break; | ||
| } | ||
| } | ||
| }; | ||
| const handleFastTrackX = event => handleFastTrack(event, true); | ||
| const handleFastTrackY = event => handleFastTrack(event, false); | ||
| const handleDragStart = (event, horizontal) => { | ||
| const { | ||
| disabled, | ||
| captureHandleDragX, | ||
| captureHandleDragY, | ||
| interruptibleHandleDrag | ||
| } = this.props; | ||
| // Handle can be dragged with left mouse button only. | ||
| if (disabled || !(captureHandleDragX || captureHandleDragY) || event.button) { | ||
| return; | ||
| } | ||
| event.preventDefault(); | ||
| event.stopPropagation(); | ||
| let track; | ||
| if (horizontal) { | ||
| _causeX = ScrollCause.HANDLE_DRAG; | ||
| track = _trackX; | ||
| } else { | ||
| _causeY = ScrollCause.HANDLE_DRAG; | ||
| track = _trackY; | ||
| } | ||
| const offsetX = event.clientX - _handleX.offsetLeft, | ||
| offsetY = event.clientY - _handleY.offsetTop; | ||
| const handleDrag = event => { | ||
| const cause = horizontal ? _causeX : _causeY; | ||
| if (!_root || event.button || (interruptibleHandleDrag && cause !== ScrollCause.HANDLE_DRAG)) { | ||
| stopDrag(); | ||
| return; | ||
| } | ||
| if (horizontal) { | ||
| _causeX = ScrollCause.HANDLE_DRAG; | ||
| this.scrollToX(_scrollMaxX * (event.clientX - offsetX) / _trackMaxX); | ||
| } else { | ||
| _causeY = ScrollCause.HANDLE_DRAG; | ||
| this.scrollToY(_scrollMaxY * (event.clientY - offsetY) / _trackMaxY); | ||
| } | ||
| }; | ||
| const handleDragEnd = () => { | ||
| if (horizontal) { | ||
| _causeX = null; | ||
| } else { | ||
| _causeY = null; | ||
| } | ||
| stopDrag(); | ||
| }; | ||
| const stopDrag = () => { | ||
| removeEventListener('mousemove', handleDrag); | ||
| removeEventListener('mouseup', handleDragEnd); | ||
| track.classList.remove('scroll-box__track--dragged'); | ||
| }; | ||
| addEventListener('mousemove', handleDrag); | ||
| addEventListener('mouseup', handleDragEnd); | ||
| track.classList.add('scroll-box__track--dragged'); | ||
| }; | ||
| const handleDragStartX = event => handleDragStart(event, true); | ||
| const handleDragStartY = event => handleDragStart(event, false); | ||
| const handleWheel = event => { | ||
| let {target, deltaMode, deltaX, deltaY, shiftKey, nativeEvent} = event; | ||
| const { | ||
| wheelStepX, | ||
| wheelStepY, | ||
| disabled, | ||
| nativeScrollBars, | ||
| captureWheel, | ||
| wheelLineHeight, | ||
| propagateWheelScrollX, | ||
| propagateWheelScrollY, | ||
| swapWheelAxes, | ||
| wheelScrollDurationX, | ||
| wheelScrollDurationY | ||
| } = this.props; | ||
| if (nativeScrollBars && !captureWheel) { | ||
| event.preventDefault(); | ||
| } | ||
| if (disabled || nativeScrollBars || (target !== _viewport && isTargetIgnored(target))) { | ||
| return; | ||
| } | ||
| // By default, Google Chrome changes scrolling orientation if shift key is pressed, | ||
| // so propagate this behavior to other browsers as well. | ||
| if (shiftKey && !deltaX) { | ||
| deltaX = deltaY; | ||
| deltaY = 0; | ||
| } | ||
| if (swapWheelAxes) { | ||
| const buffer = deltaX; | ||
| deltaX = deltaY; | ||
| deltaY = buffer; | ||
| } | ||
| const stopPropagationX = !deltaX || (_requiresScrollBarX && ((deltaX < 0 && _targetX > 0) || (deltaX > 0 && _targetX !== _scrollMaxX))), | ||
| stopPropagationY = !deltaY || (_requiresScrollBarY && ((deltaY < 0 && _targetY > 0) || (deltaY > 0 && _targetY !== _scrollMaxY))); | ||
| const propagateX = deltaX * !stopPropagationX * propagateWheelScrollX, | ||
| propagateY = deltaY * !stopPropagationY * propagateWheelScrollY; | ||
| if (propagateX || propagateY) { | ||
| if (propagateX === deltaX && propagateY === deltaY) { | ||
| return; | ||
| } else { | ||
| event.stopPropagation(); | ||
| event.preventDefault(); | ||
| target.dispatchEvent(new WheelEvent(nativeEvent.type, {deltaX: propagateX, deltaY: propagateY})); | ||
| } | ||
| } | ||
| let dx = deltaX * _requiresScrollBarX, | ||
| dy = deltaY * _requiresScrollBarY; | ||
| if (!dx && !dy) { | ||
| return; | ||
| } | ||
| event.stopPropagation(); | ||
| event.preventDefault(); | ||
| // Converts received delta values into pixels. | ||
| switch (deltaMode) { | ||
| case 0x01: // Delta values are specified in lines. | ||
| dx *= wheelLineHeight; | ||
| dy *= wheelLineHeight; | ||
| break; | ||
| case 0x02: // Delta values are specified in pages. | ||
| dx *= this.getPageWidth(); | ||
| dy *= this.getPageHeight(); | ||
| break; | ||
| default: | ||
| // Delta values are specified in pixels. | ||
| break; | ||
| } | ||
| dx *= wheelStepX / 100; | ||
| dy *= wheelStepY / 100; | ||
| let nextTargetX = _targetX + dx, | ||
| nextTargetY = _targetY + dy; | ||
| // Prevent jumping to target position when animated scrolling is in progress, | ||
| // but preserve scroll speed when mouse wheel events arrive frequently. | ||
| if (Date.now() - _timestampX > wheelScrollDurationX) { | ||
| nextTargetX = _scrollX + dx; | ||
| } | ||
| if (Date.now() - _timestampX > wheelScrollDurationY) { | ||
| nextTargetY = _scrollY + dy; | ||
| } | ||
| if (dx) { | ||
| _causeX = ScrollCause.MOUSE_WHEEL; | ||
| this.scrollToX(nextTargetX, {duration: wheelScrollDurationX}); | ||
| } | ||
| if (dy) { | ||
| _causeY = ScrollCause.MOUSE_WHEEL; | ||
| this.scrollToY(nextTargetY, {duration: wheelScrollDurationY}); | ||
| } | ||
| }; | ||
| const toggleTrackHover = (track, status) => track.classList.toggle('scroll-box__track--hover', status); | ||
| const isTrackHovered = (event, track, proximity) => { | ||
| const {clientX, clientY} = event, | ||
| {width, left, top, height} = track.getBoundingClientRect(); | ||
| return proximity > clientY - height - top && | ||
| proximity > clientX - width - left && | ||
| proximity > left - clientX && | ||
| proximity > top - clientY; | ||
| }; | ||
| const handleTrackHover = event => { | ||
| const { | ||
| disabled, | ||
| nativeScrollBars, | ||
| captureHandleDragX, | ||
| captureHandleDragY, | ||
| captureFastTrackX, | ||
| captureFastTrackY, | ||
| trackHoverProximityX, | ||
| trackHoverProximityY | ||
| } = this.props; | ||
| if ('orientation' in window || nativeScrollBars || disabled) { | ||
| return; | ||
| } | ||
| if (_requiresScrollBarX && (captureHandleDragX || captureFastTrackX)) { | ||
| const statusX = (!event.buttons || _causeX === ScrollCause.HANDLE_DRAG) && isTrackHovered(event, _trackX, trackHoverProximityX); | ||
| toggleTrackHover(_trackX, statusX); | ||
| } | ||
| if (_requiresScrollBarY && (captureHandleDragY || captureFastTrackY)) { | ||
| const statusY = (!event.buttons || _causeY === ScrollCause.HANDLE_DRAG) && isTrackHovered(event, _trackY, trackHoverProximityY); | ||
| toggleTrackHover(_trackY, statusY); | ||
| } | ||
| }; | ||
| const isIgnoredChangeX = dx => (dx < 0 && !_targetX) || (dx > 0 && _targetX === _scrollMaxX); | ||
| const isIgnoredChangeY = dy => (dy < 0 && !_targetY) || (dy > 0 && _targetY === _scrollMaxY); | ||
| const preventDefault = event => { | ||
| if (event.cancelable) { | ||
| event.preventDefault(); | ||
| } | ||
| }; | ||
| const handleTouchStart = event => { | ||
| const {target, touches} = event; | ||
| const { | ||
| disabled, | ||
| nativeScrollBars, | ||
| captureTouch, | ||
| propagateTouchScrollX, | ||
| propagateTouchScrollY, | ||
| touchSingleAxis, | ||
| touchStartDistance, | ||
| continuousTouchScrollX, | ||
| continuousTouchScrollY, | ||
| inertiaEasingX, | ||
| inertiaEasingY, | ||
| inertiaDistanceX, | ||
| inertiaDistanceY, | ||
| inertiaDurationX, | ||
| inertiaDurationY | ||
| } = this.props; | ||
| if (nativeScrollBars && !captureTouch) { | ||
| preventDefault(event); | ||
| } | ||
| if (disabled || nativeScrollBars || touches.length > 1 || (target !== _viewport && isTargetIgnored(target))) { | ||
| return; | ||
| } | ||
| const { | ||
| clientX: initialClientX, | ||
| clientY: initialClientY | ||
| } = touches[0]; | ||
| const initialScrollX = _scrollX, | ||
| initialScrollY = _scrollY; | ||
| let prevClientX, | ||
| prevClientY, | ||
| lastClientX, | ||
| lastClientY, | ||
| prevTimestamp, | ||
| lastTimestamp, | ||
| horizontal, | ||
| stopPropagationX, | ||
| stopPropagationY; | ||
| const handleTouchMove = event => { | ||
| const {clientX, clientY} = event.touches[0]; | ||
| const dx = initialClientX - clientX, | ||
| dy = initialClientY - clientY, | ||
| pending = isNaN(lastClientX); | ||
| if (pending && Math.sqrt(dx * dx + dy * dy) < touchStartDistance) { | ||
| preventDefault(event); | ||
| return; | ||
| } | ||
| if (pending && touchSingleAxis) { | ||
| horizontal = Math.abs(dx) > Math.abs(dy); | ||
| } | ||
| if (pending || continuousTouchScrollX) { | ||
| stopPropagationX = _requiresScrollBarX && !isIgnoredChangeX(dx); | ||
| } | ||
| if (pending || continuousTouchScrollY) { | ||
| stopPropagationY = _requiresScrollBarY && !isIgnoredChangeY(dy); | ||
| } | ||
| prevClientX = lastClientX; | ||
| prevClientY = lastClientY; | ||
| lastClientX = clientX; | ||
| lastClientY = clientY; | ||
| prevTimestamp = lastTimestamp; | ||
| lastTimestamp = Date.now(); | ||
| const targetX = initialScrollX + dx, | ||
| targetY = initialScrollY + dy; | ||
| if (touchSingleAxis) { | ||
| if (horizontal) { | ||
| if (stopPropagationX || !propagateTouchScrollX) { | ||
| preventDefault(event); | ||
| this.scrollToX(targetX); | ||
| } | ||
| } else { | ||
| if (stopPropagationY || !propagateTouchScrollY) { | ||
| preventDefault(event); | ||
| this.scrollToY(targetY); | ||
| } | ||
| } | ||
| } else { | ||
| if (stopPropagationX || stopPropagationY || (!propagateTouchScrollX && !propagateTouchScrollY)) { | ||
| preventDefault(event); | ||
| this.scrollTo({x: targetX, y: targetY}); | ||
| } | ||
| } | ||
| }; | ||
| const handleTouchEnd = () => { | ||
| if (!isNaN(prevClientX)) { | ||
| const dt = lastTimestamp - prevTimestamp, | ||
| dx = prevClientX - lastClientX, | ||
| dy = prevClientY - lastClientY, | ||
| distanceX = inertiaDistanceX(dx, dt), | ||
| distanceY = inertiaDistanceY(dy, dt), | ||
| durationX = Math.abs(inertiaDurationX(dx, dt)), | ||
| durationY = Math.abs(inertiaDurationY(dy, dt)); | ||
| const targetX = _targetX + distanceX, | ||
| targetY = _targetY + distanceY; | ||
| if (touchSingleAxis) { | ||
| if (horizontal) { | ||
| this.scrollToX(targetX, {easingX: inertiaEasingX, durationX}); | ||
| } else { | ||
| this.scrollToY(targetY, {easingY: inertiaEasingY, durationY: 100}); | ||
| } | ||
| } else { | ||
| this.scrollTo({ | ||
| x: targetX, | ||
| y: targetY, | ||
| easingX: inertiaEasingX, | ||
| easingY: inertiaEasingY, | ||
| durationX, | ||
| durationY | ||
| }); | ||
| } | ||
| } | ||
| removeEventListener('touchmove', handleTouchMove); | ||
| removeEventListener('touchend', handleTouchEnd); | ||
| removeEventListener('touchcancel', handleTouchEnd); | ||
| }; | ||
| addEventListener('touchmove', handleTouchMove, {passive: false}); | ||
| addEventListener('touchend', handleTouchEnd); | ||
| addEventListener('touchcancel', handleTouchEnd); | ||
| }; | ||
| } | ||
| } |
| export {ScrollBox} from './ScrollBox'; | ||
| export {AbstractScrollBox, FastTrackMode, ScrollCause} from './AbstractScrollBox'; |
| @scroll-box: scroll-box; // Namespace class | ||
| @scroll-bar-border-radius: @scroll-bar-hover-weight; // Rounded caps. | ||
| @scroll-bar-weight: 6px; // Height of width for horizontal or vertical scroll bar respectively. | ||
| @scroll-bar-hover-weight: (@scroll-bar-weight * 1.7); | ||
| @scroll-bar-offset: 4px; // Distance from scroll box container border to scroll bar. | ||
| @scroll-bar-min-size: 30px; | ||
| @scroll-bar-max-size: 100%; | ||
| @scroll-bar-y-width: @scroll-bar-weight; | ||
| @scroll-bar-y-hover-width: @scroll-bar-hover-weight; | ||
| @scroll-bar-y-top: @scroll-bar-offset; | ||
| @scroll-bar-y-bottom: @scroll-bar-offset; | ||
| @scroll-bar-y-right: @scroll-bar-offset; | ||
| @scroll-bar-y-min-height: @scroll-bar-min-size; | ||
| @scroll-bar-y-max-height: @scroll-bar-max-size; | ||
| @scroll-bar-x-height: @scroll-bar-weight; | ||
| @scroll-bar-x-hover-height: @scroll-bar-hover-weight; | ||
| @scroll-bar-x-left: @scroll-bar-offset; | ||
| @scroll-bar-x-right: @scroll-bar-offset; | ||
| @scroll-bar-x-bottom: @scroll-bar-offset; | ||
| @scroll-bar-x-min-width: @scroll-bar-min-size; | ||
| @scroll-bar-x-max-width: @scroll-bar-max-size; | ||
| @scroll-cursor-handle: default; | ||
| @scroll-cursor-track: default; | ||
| .@{scroll-box} { | ||
| position: relative; | ||
| &:focus { | ||
| outline: none; | ||
| } | ||
| &--disabled { | ||
| > .@{scroll-box}__viewport { | ||
| // Hide client scrollbars. | ||
| overflow: hidden !important; | ||
| } | ||
| > .@{scroll-box}__track { | ||
| // Hide custom scrollbars. | ||
| visibility: hidden !important; | ||
| } | ||
| } | ||
| // By default scroll box looks like an unwrapped container. | ||
| &--wrapped { | ||
| > .@{scroll-box}__viewport { | ||
| position: absolute; | ||
| top: 0; | ||
| left: 0; | ||
| width: 100%; | ||
| height: 100%; | ||
| overflow: hidden; | ||
| padding: inherit; | ||
| border-radius: inherit; | ||
| } | ||
| > .@{scroll-box}__track { | ||
| display: block; | ||
| } | ||
| } | ||
| // Used if fallback to client system scrolling should occur. | ||
| &--native-scroll-bars { | ||
| &.@{scroll-box}--enable-y.@{scroll-box}--requires-y > .@{scroll-box}__viewport { | ||
| overflow-y: auto; | ||
| } | ||
| &.@{scroll-box}--enable-x.@{scroll-box}--requires-x > .@{scroll-box}__viewport { | ||
| overflow-x: auto; | ||
| } | ||
| > .@{scroll-box}__viewport { | ||
| -webkit-overflow-scrolling: touch; | ||
| } | ||
| } | ||
| &:not(.@{scroll-box}--native-scroll-bars) { | ||
| &.@{scroll-box}--enable-y.@{scroll-box}--requires-y > .@{scroll-box}__track--y { | ||
| visibility: visible; | ||
| } | ||
| &.@{scroll-box}--enable-x.@{scroll-box}--requires-x > .@{scroll-box}__track--x { | ||
| visibility: visible; | ||
| } | ||
| // Both non-client scrollbars are visible and they are inside | ||
| // scrollable are, we should prevent their intersection in the | ||
| // shared corner. | ||
| &.@{scroll-box}--enable-x.@{scroll-box}--requires-x.@{scroll-box}--enable-y.@{scroll-box}--requires-y:not(.@{scroll-box}--outset) { | ||
| > .@{scroll-box}__track { | ||
| &--y { | ||
| margin-bottom: (2 * @scroll-bar-y-bottom + @scroll-bar-x-height); | ||
| } | ||
| &--x { | ||
| margin-right: (2 * @scroll-bar-x-right + @scroll-bar-y-width); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| &__handle, | ||
| &__track { | ||
| position: absolute; | ||
| border-radius: @scroll-bar-border-radius; | ||
| transition: .2s ease-in-out; | ||
| } | ||
| &__handle { | ||
| transition-property: background; | ||
| cursor: @scroll-cursor-handle; | ||
| &--y { | ||
| width: 100%; | ||
| min-height: @scroll-bar-y-min-height; | ||
| max-height: @scroll-bar-y-max-height; | ||
| top: 0; | ||
| } | ||
| &--x { | ||
| height: 100%; | ||
| min-width: @scroll-bar-x-min-width; | ||
| max-width: @scroll-bar-x-max-width; | ||
| left: 0; | ||
| } | ||
| } | ||
| &__track { | ||
| display: none; // Scroll not used by default. | ||
| visibility: hidden; | ||
| transition-property: background, width, height; | ||
| cursor: @scroll-cursor-track; | ||
| &--y { | ||
| top: 0; | ||
| bottom: 0; | ||
| right: 0; | ||
| width: @scroll-bar-y-width; | ||
| margin: @scroll-bar-y-top @scroll-bar-y-right @scroll-bar-y-bottom 0; | ||
| &.@{scroll-box}__track { | ||
| &--hover, | ||
| &--dragged { | ||
| width: @scroll-bar-y-hover-width; | ||
| } | ||
| } | ||
| .@{scroll-box}--outset > & { | ||
| left: 100%; | ||
| margin-left: @scroll-bar-y-right; | ||
| } | ||
| } | ||
| &--x { | ||
| left: 0; | ||
| right: 0; | ||
| bottom: 0; | ||
| height: @scroll-bar-x-height; | ||
| margin: 0 @scroll-bar-x-right @scroll-bar-x-bottom @scroll-bar-x-left; | ||
| &.@{scroll-box}__track { | ||
| &--hover, | ||
| &--dragged { | ||
| height: @scroll-bar-x-hover-height; | ||
| } | ||
| } | ||
| .@{scroll-box}--outset > & { | ||
| top: 100%; | ||
| margin-top: @scroll-bar-x-bottom; | ||
| } | ||
| } | ||
| } | ||
| // Apply default coloring. | ||
| .scroll-box-color(); | ||
| } | ||
| .scroll-box-color( | ||
| @handle-bg: rgba(0,0,0,.4); | ||
| @track-bg: transparent; | ||
| @hover-handle-bg: rgba(0,0,0,.6); | ||
| @hover-track-bg: rgba(0,0,0,.2); | ||
| ) { | ||
| > .@{scroll-box}__track { | ||
| background: @track-bg; | ||
| > .@{scroll-box}__handle { | ||
| background: @handle-bg; | ||
| } | ||
| &--hover, | ||
| &--dragged { | ||
| background: @hover-track-bg; | ||
| > .@{scroll-box}__handle { | ||
| background: @hover-handle-bg; | ||
| } | ||
| } | ||
| } | ||
| } |
| import React from 'react'; | ||
| import {AbstractScrollBox} from './AbstractScrollBox'; | ||
| export class ScrollBox extends React.Component { | ||
| render() { | ||
| return ( | ||
| <AbstractScrollBox {...this.props}> | ||
| <div className="scroll-box__viewport"> | ||
| {this.props.children} | ||
| </div> | ||
| </AbstractScrollBox> | ||
| ); | ||
| } | ||
| } |
+3
-2
| { | ||
| "name": "react-scroll-box", | ||
| "version": "0.2.9", | ||
| "version": "0.3.4", | ||
| "author": "Savva Mikhalevski", | ||
@@ -55,4 +55,5 @@ "description": "Charged cross-browser and cross-platform scrollable container implementation with no external dependencies but React 0.13+", | ||
| "react": ">=0.13.0", | ||
| "react-dom": ">=0.13.0" | ||
| "react-dom": ">=0.13.0", | ||
| "prop-types": ">=15.5.10" | ||
| } | ||
| } |
+3
-1
@@ -5,2 +5,4 @@ # React Scroll Box | ||
| _Note_ I'm currently working on `resct-scroll-box@0.3`. It would contain [50+ configurable paramters](https://github.com/smikhalevski/react-scroll-box/blob/master/src/main/GenericScrollBox.js#L32) and would provide fine grained tracking of scrolling events and [their causes](https://github.com/smikhalevski/react-scroll-box/blob/master/src/main/GenericScrollBox.js#L15). | ||
| Charged cross-browser and cross-platform scrollable container implementation with no external dependencies but React 0.13+. | ||
@@ -47,3 +49,3 @@ | ||
| In most cases you should use `ScrollBox` to create a scrollable area, but in cause you need more control over viewport use [`GenericScrollBox`](#genericscrollbox). | ||
| In most cases you should use `ScrollBox` to create a scrollable area, but in case you need more control over viewport use [`GenericScrollBox`](#genericscrollbox). | ||
@@ -50,0 +52,0 @@ By default, `ScrollBox` has no decoration and behaves as a regular `div` container. Specify height for scroll box in your styles, otherwise container would contract to zero height. |
+955
-542
| import React from 'react'; | ||
| import {findDOMNode} from 'react-dom'; | ||
| import {any, bool, element, func, node, number, object, oneOf, string} from 'prop-types'; | ||
| const {number, bool, func, oneOf, any} = React.PropTypes; | ||
| function isCoordinate(value) { | ||
| return value != null && !isNaN(value); | ||
| } | ||
| export const ScrollAxes = { | ||
| X: 'x', | ||
| Y: 'y', | ||
| XY: 'xy' | ||
| export const FastTrackMode = { | ||
| PAGING: 'paging', | ||
| GOTO: 'goto' | ||
| }; | ||
| export const FastTrack = { | ||
| PAGING: 'paging', | ||
| GOTO: 'goto', | ||
| OFF: null | ||
| export const ScrollCause = { | ||
| HANDLE_DRAG: 0, | ||
| MOUSE_WHEEL: 1, | ||
| FAST_TRACK: 2, | ||
| KEYBOARD: 3, | ||
| TOUCH: 4 | ||
| }; | ||
| export const FastTrackModeShape = oneOf([FastTrackMode.GOTO, FastTrackMode.PAGING]); | ||
| export function easeQuadOut(percent, elapsed, min, max, duration) { | ||
| percent -= 1; | ||
| return min + max * Math.sqrt(1 - Math.pow(percent, 2)); | ||
| } | ||
| export class GenericScrollBox extends React.Component { | ||
| static defaultProps = { | ||
| className: 'scroll-box--wrapped', | ||
| axes: ScrollAxes.XY, | ||
| hoverProximity: 50, | ||
| disabled: false, | ||
| outset: false, | ||
| scrollMinX: 2, | ||
| scrollMinY: 2, | ||
| defaultEasing: (percent, elapsed, min, max, duration) => max * Math.sqrt(1 - --percent * percent) + min, | ||
| static propTypes = { | ||
| // Viewport element. | ||
| children: element.isRequired, | ||
| // Drag | ||
| captureHandleDrag: true, | ||
| // Use client scroll bars. | ||
| clientScrollBars: bool, | ||
| className: any, | ||
| style: object, | ||
| disabled: bool, | ||
| // Events | ||
| onViewportScroll: target => {}, | ||
| onScroll: func, | ||
| onScrollX: func, | ||
| onScrollY: func, | ||
| // Fast tracking | ||
| fastTrack: FastTrack.GOTO, | ||
| fastTrackDuration: 500, | ||
| onScrollStart: func, | ||
| onScrollStartX: func, | ||
| onScrollStartY: func, | ||
| // Keyboard | ||
| captureKeyboard: true, | ||
| keyboardStepX: 30, | ||
| keyboardStepY: 30, | ||
| keyboardScrollDuration: 200, | ||
| onScrollEnd: func, | ||
| onScrollEndX: func, | ||
| onScrollEndY: func, | ||
| // Wheel | ||
| captureWheel: true, | ||
| wheelStepX: 30, | ||
| wheelStepY: 30, | ||
| propagateWheelScroll: false, | ||
| swapWheelAxes: false, | ||
| wheelScrollDuration: 100, | ||
| // Allow scrolling in corresponding direction. | ||
| disableScrollX: bool, | ||
| disableScrollY: bool, | ||
| // Touch | ||
| propagateTouchScroll: false | ||
| }; | ||
| // Toggle scroll bar visibility for corresponding direction. | ||
| hideScrollBarX: bool, | ||
| hideScrollBarY: bool, | ||
| static propTypes = { | ||
| nativeScroll: bool, | ||
| className: any, | ||
| axes: oneOf([ScrollAxes.X, ScrollAxes.Y, ScrollAxes.XY]), | ||
| hoverProximity: number, | ||
| disabled: bool, | ||
| outset: bool, | ||
| // Toggle show scroll bars outside of scroll box rectangle. | ||
| // This has no effect when client scroll bars are enabled and they are shown above content. | ||
| outsetScrollBarX: bool, | ||
| outsetScrollBarY: bool, | ||
| // Minimum number of pixels when scroll bars are required. | ||
| scrollMinX: number, | ||
| scrollMinY: number, | ||
| defaultEasing: func, | ||
| // Drag | ||
| captureHandleDrag: bool, | ||
| // Distance from cursor to edge of the scroll track when scroll bar is considered to be hovered. | ||
| trackHoverProximityX: number, | ||
| trackHoverProximityY: number, | ||
| // Events | ||
| onViewportScroll: func, | ||
| // Default easing functions applied when scroll with non-zero duration is requested. | ||
| easingX: func, | ||
| easingY: func, | ||
| // Fast tracking | ||
| fastTrack: oneOf([FastTrack.GOTO, FastTrack.PAGING, FastTrack.OFF]), | ||
| fastTrackDuration: number, | ||
| // Handle drag | ||
| captureHandleDragX: bool, | ||
| captureHandleDragY: bool, | ||
| permitHandleDragInterruption: bool, | ||
| // Fast tracking occurs when user clicks on scroll track. | ||
| captureFastTrackX: bool, | ||
| captureFastTrackY: bool, | ||
| fastTrackModeX: FastTrackModeShape, | ||
| fastTrackModeY: FastTrackModeShape, | ||
| fastTrackScrollDurationX: number, | ||
| fastTrackScrollDurationY: number, | ||
| // Keyboard | ||
@@ -83,587 +100,983 @@ captureKeyboard: bool, | ||
| keyboardStepY: number, | ||
| keyboardScrollDuration: number, | ||
| keyboardScrollDurationX: number, | ||
| keyboardScrollDurationY: number, | ||
| // Wheel | ||
| captureWheel: bool, | ||
| lineHeight: number, | ||
| wheelStepX: number, | ||
| wheelStepY: number, | ||
| propagateWheelScroll: bool, | ||
| propagateWheelScrollX: bool, | ||
| propagateWheelScrollY: bool, | ||
| swapWheelAxes: bool, | ||
| wheelScrollDuration: number, | ||
| wheelScrollDurationX: number, | ||
| wheelScrollDurationY: number, | ||
| // Touch | ||
| propagateTouchScroll: bool, | ||
| captureTouch: bool, | ||
| propagateTouchScrollX: bool, | ||
| propagateTouchScrollY: bool, | ||
| // Layout | ||
| trackXChildren: any, | ||
| trackYChildren: any, | ||
| handleXChildren: any, | ||
| handleYChildren: any | ||
| trackChildrenX: node, | ||
| trackChildrenY: node, | ||
| handleChildrenX: node, | ||
| handleChildrenY: node | ||
| }; | ||
| // Handle elements. | ||
| // Set to `null` when component is unmounted. | ||
| handleX = null; | ||
| handleY = null; | ||
| static defaultProps = { | ||
| clientScrollBars: false, | ||
| className: 'scroll-box--wrapped', | ||
| // Track elements. | ||
| // Set to `null` when component is unmounted. | ||
| trackX = null; | ||
| trackY = null; | ||
| disabled: false, | ||
| // Viewport element. | ||
| // Set to `null` when component is unmounted. | ||
| viewport = null; | ||
| onScroll: (target, dx, dy, causeX, causeY) => {}, | ||
| onScrollX: (target, dx, causeX) => {}, | ||
| onScrollY: (target, dy, causeY) => {}, | ||
| // Scroll position in pixels that was last requested. | ||
| targetX = 0; | ||
| targetY = 0; | ||
| onScrollStart: (target, causeX, causeY) => {}, | ||
| onScrollStartX: (target, causeX) => {}, | ||
| onScrollStartY: (target, causeY) => {}, | ||
| // Previously requested scroll position. | ||
| previousX = 0; | ||
| previousY = 0; | ||
| onScrollEnd: (target, causeX, causeY) => {}, | ||
| onScrollEndX: (target, causeX) => {}, | ||
| onScrollEndY: (target, causeY) => {}, | ||
| // Actual scroll position that user observes. | ||
| // This changes repeatedly during animation, while is static these | ||
| // values are equal to `x` and `y`. | ||
| scrollX = 0; | ||
| scrollY = 0; | ||
| disableScrollX: false, | ||
| disableScrollY: false, | ||
| // Maximum values for horizontal and vertical scroll positions. | ||
| scrollMaxX = 0; | ||
| scrollMaxY = 0; | ||
| hideScrollBarX: false, | ||
| hideScrollBarY: false, | ||
| // Maximum values for horizontal and vertical handle positions. If native scroll is used then equals to 0. | ||
| trackMaxX = 0; | ||
| trackMaxY = 0; | ||
| outsetScrollBarX: false, | ||
| outsetScrollBarY: false, | ||
| // Does scroll box require actual presence of horizontal or vertical scroll bars. | ||
| // If set to `true`, then axis is permitted via `props.axes` and corresponding `scrollMax >= scrollMin`. | ||
| exposesX = false; | ||
| exposesY = false; | ||
| scrollMinX: 2, | ||
| scrollMinY: 2, | ||
| // Id of request animation frame that keeps scroll box in sync. | ||
| _forceSyncId = 0; | ||
| trackHoverProximityX: 50, | ||
| trackHoverProximityY: 50, | ||
| // Timestamp when scroll position started to change last time. | ||
| _easingBeginTimestamp = 0; | ||
| easingX: easeQuadOut, | ||
| easingY: easeQuadOut, | ||
| // Duration of currently running animation. In case no animation is in progress `_easingDuration` equals to 0. | ||
| _easingDuration = 0; | ||
| // Handle drag | ||
| captureHandleDragX: true, | ||
| captureHandleDragY: true, | ||
| permitHandleDragInterruption: true, | ||
| _easing = null; | ||
| // Fast track | ||
| captureFastTrackX: true, | ||
| captureFastTrackY: true, | ||
| // If set to `true` prevents triggering `onViewportScroll` if any scrolling occurs. | ||
| // Automatically reset to `false` then scroll animation finishes. | ||
| _silent = false; | ||
| fastTrackModeX: FastTrackMode.GOTO, | ||
| fastTrackModeY: FastTrackMode.GOTO, | ||
| _touchOffsetX = 0; | ||
| _touchOffsetY = 0; | ||
| _touchStart = null; | ||
| _touchEnd = null; | ||
| fastTrackScrollDurationX: 500, | ||
| fastTrackScrollDurationY: 500, | ||
| scrollBy(dx, dy, duration, easing, silent) { | ||
| this.scrollTo(this.targetX + dx, this.targetY + dy, duration, easing, silent); | ||
| } | ||
| // Keyboard | ||
| captureKeyboard: true, | ||
| keyboardStepX: 30, | ||
| keyboardStepY: 30, | ||
| keyboardScrollDuration: 200, | ||
| scrollTo(x, y, duration = 0, easing = this.props.defaultEasing, silent = false) { | ||
| // Consider actual scroll position to be a starting point. | ||
| this._easingDuration = duration; | ||
| this._easingBeginTimestamp = Date.now(); | ||
| this.previousX = this.scrollX; | ||
| this.previousY = this.scrollY; | ||
| if (!isNaN(x)) { | ||
| this.targetX = x; | ||
| } | ||
| if (!isNaN(y)) { | ||
| this.targetY = y; | ||
| } | ||
| this._easing = easing; | ||
| this._silent = Boolean(silent); | ||
| this._forceSync(); | ||
| } | ||
| // Wheel | ||
| captureWheel: true, | ||
| lineHeight: 24, | ||
| wheelStepX: 100, | ||
| wheelStepY: 100, | ||
| propagateWheelScrollX: true, | ||
| propagateWheelScrollY: true, | ||
| swapWheelAxes: false, | ||
| wheelScrollDurationX: 100, | ||
| wheelScrollDurationY: 100, | ||
| // Synchronize scrollbar positions immediately without waiting for animation frame. | ||
| _forceSync() { | ||
| const {handleX, handleY, viewport, scrollY, scrollX, previousX, previousY, _silent, _easingBeginTimestamp, _easing, _easingDuration} = this, | ||
| {axes, nativeScroll, outset, onViewportScroll, scrollMinX, scrollMinY} = this.props, | ||
| {clientWidth, clientHeight, offsetWidth, offsetHeight, scrollWidth, scrollHeight, scrollTop, scrollLeft} = viewport; | ||
| // Touch | ||
| captureTouch: true, | ||
| propagateTouchScrollX: true, | ||
| propagateTouchScrollY: true, | ||
| }; | ||
| const SCROLL_MAX_X = Math.max(0, scrollWidth - clientWidth), | ||
| SCROLL_MAX_Y = Math.max(0, scrollHeight - clientHeight); | ||
| constructor(props) { | ||
| super(props); | ||
| this.exposesX = axes.indexOf(ScrollAxes.X) > -1 && SCROLL_MAX_X >= scrollMinX; | ||
| this.exposesY = axes.indexOf(ScrollAxes.Y) > -1 && SCROLL_MAX_Y >= scrollMinY; | ||
| let _scrollX = 0, | ||
| _scrollY = 0, | ||
| _previousX = 0, | ||
| _previousY = 0, | ||
| _targetX = 0, | ||
| _targetY = 0, | ||
| _durationX = 0, | ||
| _durationY = 0, | ||
| _easingX, | ||
| _easingY, | ||
| _timestampX = 0, | ||
| _timestampY = 0, | ||
| _dispatchPrevented = false, | ||
| this.el.classList.toggle('scroll-box--show-axis-x', this.exposesX); | ||
| this.el.classList.toggle('scroll-box--show-axis-y', this.exposesY); | ||
| _scrollMaxX = 0, | ||
| _scrollMaxY = 0, | ||
| // Scrollbars may have non-zero thickness so in case of outset positioning | ||
| // pixes cropped by scrollbar must be compensated. | ||
| let width = '100%', | ||
| height = '100%'; | ||
| if (nativeScroll && outset) { | ||
| let trackYWidth = offsetWidth - clientWidth, | ||
| trackXHeight = offsetHeight - clientHeight; | ||
| if (trackYWidth) { | ||
| width = `calc(100% + ${trackYWidth}px)`; | ||
| _trackMaxX = 0, | ||
| _trackMaxY = 0, | ||
| _requiresScrollBarX = false, | ||
| _requiresScrollBarY = false, | ||
| _requestId, | ||
| _scrollingX = false, | ||
| _scrollingY = false, | ||
| _causeX = null, | ||
| _causeY = null, | ||
| _tickX = 0, | ||
| _tickY = 0, | ||
| _root, | ||
| _viewport, | ||
| _handleX, | ||
| _handleY, | ||
| _trackX, | ||
| _trackY; | ||
| this.render = () => { | ||
| const { | ||
| className, | ||
| style, | ||
| disabled, | ||
| outsetScrollBarX, | ||
| outsetScrollBarY, | ||
| clientScrollBars, | ||
| disableScrollX, | ||
| disableScrollY, | ||
| hideScrollBarX, | ||
| hideScrollBarY, | ||
| children, | ||
| trackChildrenX, | ||
| trackChildrenY, | ||
| handleChildrenX, | ||
| handleChildrenY | ||
| } = this.props; | ||
| let classNames = ['scroll-box']; | ||
| if (className) { | ||
| classNames = classNames.concat(className); | ||
| } | ||
| if (trackXHeight) { | ||
| height = `calc(100% + ${trackXHeight}px)`; | ||
| if (disabled) { | ||
| classNames.push('scroll-box--disabled'); | ||
| } | ||
| } | ||
| viewport.style.width = width; | ||
| viewport.style.height = height; | ||
| if (outsetScrollBarX) { | ||
| classNames.push('scroll-box--outset-x'); | ||
| } | ||
| if (outsetScrollBarY) { | ||
| classNames.push('scroll-box--outset-y'); | ||
| } | ||
| if (!disableScrollX && !hideScrollBarX) { | ||
| classNames.push('scroll-box--enable-x'); | ||
| } | ||
| if (!disableScrollY && !hideScrollBarY) { | ||
| classNames.push('scroll-box--enable-y'); | ||
| } | ||
| if (clientScrollBars) { | ||
| classNames.push('scroll-box--client-scroll-bars'); | ||
| } | ||
| let targetX = Math.max(0, Math.min(Math.round(this.targetX), SCROLL_MAX_X)) * this.exposesX, | ||
| targetY = Math.max(0, Math.min(Math.round(this.targetY), SCROLL_MAX_Y)) * this.exposesY, | ||
| x = targetX, | ||
| y = targetY; | ||
| return ( | ||
| <div style={style} | ||
| className={classNames.join(' ')} | ||
| onWheel={handleWheel} | ||
| onKeyDown={handleKeyDown} | ||
| onTouchStart={handleTouchStart} | ||
| tabIndex="-1"> | ||
| {children} | ||
| <div className="scroll-box__track scroll-box__track--x" | ||
| onMouseDown={handleFastTrackX} | ||
| ref="trackX"> | ||
| <div className="scroll-box__handle scroll-box__handle--x" | ||
| onMouseDown={handleDragStartX} | ||
| ref="handleX"> | ||
| {handleChildrenX} | ||
| </div> | ||
| {trackChildrenX} | ||
| </div> | ||
| <div className="scroll-box__track scroll-box__track--y" | ||
| onMouseDown={handleFastTrackY} | ||
| ref="trackY"> | ||
| <div className="scroll-box__handle scroll-box__handle--y" | ||
| onMouseDown={handleDragStartY} | ||
| ref="handleY"> | ||
| {handleChildrenY} | ||
| </div> | ||
| {trackChildrenY} | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
| if (scrollY == scrollTop && scrollX == scrollLeft) { | ||
| let elapsed = Date.now() - _easingBeginTimestamp; | ||
| if (elapsed < _easingDuration && typeof _easing == 'function') { | ||
| let ratio = _easing(elapsed / _easingDuration, elapsed, 0, 1, _easingDuration); | ||
| this.componentDidMount = () => { | ||
| _root = findDOMNode(this); | ||
| // Compute eased scroll positions. | ||
| x = Math.round(previousX + ratio * (targetX - previousX)); | ||
| y = Math.round(previousY + ratio * (targetY - previousY)); | ||
| const {handleX, handleY, trackX, trackY} = this.refs; | ||
| _handleX = findDOMNode(handleX); | ||
| _handleY = findDOMNode(handleY); | ||
| _trackX = findDOMNode(trackX); | ||
| _trackY = findDOMNode(trackY); | ||
| _viewport = _root.firstElementChild; | ||
| const requestPropagateChanges = () => { | ||
| if (window.cancelAnimationFrame) { | ||
| _requestId = requestAnimationFrame(requestPropagateChanges); | ||
| } else { | ||
| _requestId = setTimeout(requestPropagateChanges, 1000 / 30); | ||
| } | ||
| propagateChanges(); | ||
| }; | ||
| requestPropagateChanges(); | ||
| addEventListener('mousemove', handleBarHover); | ||
| }; | ||
| this.componentWillUnmount = () => { | ||
| _root = null; | ||
| if (window.cancelAnimationFrame) { | ||
| cancelAnimationFrame(_requestId); | ||
| } else { | ||
| // Scroll animation completed. | ||
| this._easingDuration = 0; | ||
| clearTimeout(_requestId); | ||
| } | ||
| // Prevent native scrolling glitches, especially if native scroll is inertial or smooth. | ||
| viewport.scrollLeft = x; | ||
| viewport.scrollTop = y; | ||
| } else { | ||
| // Viewport scroll position is not synced with component state. | ||
| // This is usually caused by system scrolling, resize of element etc. | ||
| // So stop running animation and update component state with current | ||
| // viewport scroll offsets. | ||
| this._easingDuration = 0; | ||
| x = targetX = scrollLeft; | ||
| y = targetY = scrollTop; | ||
| } | ||
| this.targetX = targetX; | ||
| this.targetY = targetY; | ||
| removeEventListener('mousemove', handleBarHover); | ||
| }; | ||
| if (scrollX == x && scrollY == y && this.scrollMaxX == SCROLL_MAX_X && this.scrollMaxY == SCROLL_MAX_Y) { | ||
| if (!this._easingDuration) { | ||
| // Animation has completed and geometry did not change. | ||
| this._easing = null; | ||
| this._silent = false; | ||
| this.componentDidUpdate = () => { | ||
| _viewport = _root.firstElementChild; | ||
| propagateChanges(); | ||
| }; | ||
| this.scrollTo = ({ | ||
| x, y, | ||
| easing, | ||
| easingX = easing || this.props.easingX, | ||
| easingY = easing || this.props.easingY, | ||
| duration = 0, | ||
| durationX = duration, | ||
| durationY = duration, | ||
| dispatchPrevented = false | ||
| } = {}) => { | ||
| if (isCoordinate(x)) { | ||
| _previousX = _scrollX; | ||
| _targetX = x | 0; | ||
| _easingX = easingX; | ||
| _durationX = durationX; | ||
| _timestampX = Date.now(); | ||
| _dispatchPrevented = dispatchPrevented; | ||
| _tickX++; | ||
| } | ||
| // TODO Viewport did not change its scroll parameters, so invocation of `onViewportScroll` and further altering geometry of handles and tracks may not be required. | ||
| } | ||
| this.scrollX = x; | ||
| this.scrollY = y; | ||
| this.scrollMaxX = SCROLL_MAX_X; | ||
| this.scrollMaxY = SCROLL_MAX_Y; | ||
| this.trackMaxX = 0; | ||
| this.trackMaxY = 0; | ||
| // Update custom handle positions and sizes. | ||
| // Scrollbar size represents ratio of content and viewport sizes. | ||
| if (!nativeScroll) { | ||
| this.trackMaxX = this.trackX.clientWidth - handleX.offsetWidth; | ||
| this.trackMaxY = this.trackY.clientHeight - handleY.offsetHeight; | ||
| if (isCoordinate(y)) { | ||
| _previousY = _scrollY; | ||
| _targetY = y | 0; | ||
| _easingY = easingY; | ||
| _durationY = durationY; | ||
| _timestampY = Date.now(); | ||
| _dispatchPrevented = dispatchPrevented; | ||
| _tickY++; | ||
| } | ||
| handleX.style.width = clientWidth / scrollWidth * 100 + '%'; | ||
| handleX.style.left = this.trackMaxX * x / SCROLL_MAX_X + 'px'; | ||
| propagateChanges(); | ||
| }; | ||
| handleY.style.height = clientHeight / scrollHeight * 100 + '%'; | ||
| handleY.style.top = this.trackMaxY * y / SCROLL_MAX_Y + 'px'; | ||
| } | ||
| if (!_silent && !(scrollX == x && scrollY == y)) { | ||
| onViewportScroll(this); | ||
| } | ||
| } | ||
| this.scrollToX = (x, options = {}) => this.scrollTo({...options, x}); | ||
| onTouchStart = e => { | ||
| if (this.props.nativeScroll || this.props.disabled || e.touches.length > 1 || e.isDefaultPrevented()) { | ||
| return; | ||
| } | ||
| if (!this.exposesX && !this.exposesY) { | ||
| return; // No scrolling is available. | ||
| } | ||
| e.stopPropagation(); | ||
| let touch = e.touches[0], | ||
| x = this.viewport.scrollLeft, | ||
| y = this.viewport.scrollTop; | ||
| this._touchOffsetX = x + touch.screenX; | ||
| this._touchOffsetY = y + touch.screenY; | ||
| this._touchStart = {x, y}; | ||
| }; | ||
| this.scrollToY = (y, options = {}) => this.scrollTo({...options, y}); | ||
| onTouchMove = e => { | ||
| const {propagateTouchScroll} = this.props, | ||
| {targetX, targetY, scrollMaxX, scrollMaxY, exposesX, exposesY} = this; | ||
| this.scrollBy = ({dx, dy, ...options} = {}) => { | ||
| this.scrollTo({ | ||
| ...options, | ||
| x: _targetX + dx, | ||
| y: _targetY + dy | ||
| }); | ||
| }; | ||
| this.scrollByX = (dx, options = {}) => this.scrollBy({...options, dx}); | ||
| this.scrollByY = (dy, options = {}) => this.scrollBy({...options, dy}); | ||
| if (!this._touchStart) { | ||
| return; | ||
| } | ||
| let touch = e.touches[0], | ||
| x = this._touchOffsetX - touch.screenX, | ||
| y = this._touchOffsetY - touch.screenY; | ||
| this.scrollToPage = ({ | ||
| x, y, | ||
| ...options | ||
| } = {}) => { | ||
| x *= this.getPageWidth(); | ||
| y *= this.getPageHeight(); | ||
| this.scrollTo({...options, x, y}); | ||
| }; | ||
| let prevTouch = this._touchEnd || this._touchStart, | ||
| deltaX = prevTouch.x - x, | ||
| deltaY = prevTouch.y - y; | ||
| this.scrollToPageX = (x, options = {}) => this.scrollToPage({...options, x}); | ||
| let dx = deltaX * exposesX, | ||
| dy = deltaY * exposesY; | ||
| if ( | ||
| (deltaX && !exposesX) || (dx < 0 && !targetX) || (dx > 0 && targetX == scrollMaxX) || | ||
| (deltaY && !exposesY) || (dy < 0 && !targetY) || (dy > 0 && targetY == scrollMaxY) | ||
| ) { | ||
| // Content is scrolled to its possible limit. | ||
| if (!propagateTouchScroll) { | ||
| e.preventDefault(); | ||
| this.scrollToPageY = (y, options = {}) => this.scrollToPage({...options, y}); | ||
| this.scrollByPage = ({ | ||
| dx, dy, | ||
| ...options | ||
| } = {}) => { | ||
| dx *= this.getPageWidth(); | ||
| dy *= this.getPageHeight(); | ||
| this.scrollBy({...options, dx, dy}); | ||
| }; | ||
| this.scrollByPageX = (dx, options = {}) => this.scrollByPage({...options, dx}); | ||
| this.scrollByPageY = (dy, options = {}) => this.scrollByPage({...options, dy}); | ||
| this.getPageWidth = () => _viewport.clientWidth; | ||
| this.getPageHeight = () => _viewport.clientHeight; | ||
| Object.defineProperties(this, { | ||
| targetX: { | ||
| get: () => _targetX, | ||
| set: x => this.scrollToX(x) | ||
| }, | ||
| targetY: { | ||
| get: () => _targetY, | ||
| set: y => this.scrollToY(y) | ||
| }, | ||
| scrollX: { | ||
| get: () => _scrollX, | ||
| set: x => this.scrollToX(x) | ||
| }, | ||
| scrollY: { | ||
| get: () => _scrollY, | ||
| set: y => this.scrollToY(y) | ||
| }, | ||
| scrollMaxX: { | ||
| get: () => _scrollMaxX | ||
| }, | ||
| scrollMaxY: { | ||
| get: () => _scrollMaxY | ||
| } | ||
| return; | ||
| } | ||
| }); | ||
| if (this._touchEnd) { | ||
| let coords = this._touchStart; | ||
| this._touchStart = this._touchEnd; | ||
| this._touchEnd = coords; | ||
| coords.x = x; | ||
| coords.y = y; | ||
| } else { | ||
| this._touchEnd = {x, y}; | ||
| } | ||
| this.scrollTo(x, y, 0); | ||
| }; | ||
| const propagateChanges = () => { | ||
| const { | ||
| disableScrollX, | ||
| disableScrollY, | ||
| onTouchEnd = e => { | ||
| if (!this._touchEnd) { | ||
| return; | ||
| } | ||
| const {_touchStart, _touchEnd} = this; | ||
| let dt = Date.now() - this._easingBeginTimestamp, | ||
| dx = _touchStart.x - _touchEnd.x, | ||
| dy = _touchStart.y - _touchEnd.y, | ||
| distance = Math.sqrt(dx * dx + dy * dy), | ||
| velocity = distance / dt * 100; | ||
| scrollMinX, | ||
| scrollMinY, | ||
| this._touchStart = null; | ||
| this._touchEnd = null; | ||
| this.scrollTo(_touchEnd.x - velocity * dx / distance, _touchEnd.y - velocity * dy / distance, velocity); | ||
| }; | ||
| clientScrollBars, | ||
| onWheel = e => { | ||
| const {wheelStepX, wheelStepY, disabled, nativeScroll, captureWheel, propagateWheelScroll, swapWheelAxes, wheelScrollDuration} = this.props, | ||
| {targetX, targetY, scrollMaxX, scrollMaxY, exposesX, exposesY} = this, | ||
| el = e.target; | ||
| if (nativeScroll && !captureWheel) { | ||
| e.preventDefault(); | ||
| } | ||
| if ( | ||
| disabled || e.isDefaultPrevented() || // Event prevented. | ||
| !captureWheel || // Wheel events prevented. | ||
| (el != this.viewport && el.tagName.toLowerCase() == 'textarea') // Nested textarea is focused and its is not a viewport. | ||
| ) { | ||
| return; | ||
| } | ||
| let dx = e.deltaX * exposesX, | ||
| dy = e.deltaY * exposesY; | ||
| if ( | ||
| (e.deltaX && !exposesX) || (dx < 0 && !targetX) || (dx > 0 && targetX == scrollMaxX) || | ||
| (e.deltaY && !exposesY) || (dy < 0 && !targetY) || (dy > 0 && targetY == scrollMaxY) | ||
| ) { | ||
| // Content is scrolled to its possible limit. | ||
| if (!propagateWheelScroll) { | ||
| e.preventDefault(); | ||
| outsetScrollBarX, | ||
| outsetScrollBarY, | ||
| onScroll, | ||
| onScrollX, | ||
| onScrollY, | ||
| onScrollStart, | ||
| onScrollStartX, | ||
| onScrollStartY, | ||
| onScrollEnd, | ||
| onScrollEndX, | ||
| onScrollEndY | ||
| } = this.props; | ||
| const { | ||
| clientWidth, | ||
| clientHeight, | ||
| offsetWidth, | ||
| offsetHeight, | ||
| scrollWidth, | ||
| scrollHeight, | ||
| scrollTop, | ||
| scrollLeft | ||
| } = _viewport; | ||
| _scrollMaxX = scrollWidth - clientWidth; | ||
| _scrollMaxY = scrollHeight - clientHeight; | ||
| _requiresScrollBarX = !disableScrollX && _scrollMaxX >= scrollMinX; | ||
| _requiresScrollBarY = !disableScrollY && _scrollMaxY >= scrollMinY; | ||
| _root.classList.toggle('scroll-box--requires-x', _requiresScrollBarX); | ||
| _root.classList.toggle('scroll-box--requires-y', _requiresScrollBarY); | ||
| if (clientScrollBars && outsetScrollBarX) { | ||
| _viewport.style.height = `calc(100% + ${offsetHeight - clientHeight}px)`; | ||
| } else { | ||
| _viewport.style.height = '100%'; | ||
| } | ||
| return; | ||
| } | ||
| // By default, Google Chrome changes scrolling orientation if shift key is pressed, | ||
| // so propagate this behavior to other browsers as well. | ||
| if (e.shiftKey && !dx) { | ||
| dx = dy; | ||
| dy = 0; | ||
| } | ||
| if (swapWheelAxes) { | ||
| [dx, dy] = [dy, dx]; | ||
| } | ||
| e.preventDefault(); | ||
| if (typeof InstallTrigger != 'undefined') { | ||
| const FIREFOX_SPEED_FACTOR = 30; | ||
| dx *= FIREFOX_SPEED_FACTOR; | ||
| dy *= FIREFOX_SPEED_FACTOR; | ||
| } | ||
| dx *= wheelStepX / 100; | ||
| dy *= wheelStepY / 100; | ||
| if (clientScrollBars && outsetScrollBarY) { | ||
| _viewport.style.width = `calc(100% + ${offsetWidth - clientWidth}px)`; | ||
| } else { | ||
| _viewport.style.width = '100%'; | ||
| } | ||
| // Prevent jumping to target position when slow animated scrolling is in progress, | ||
| // but preserve scroll speed when mouse wheel arrive frequently. | ||
| if (Date.now() - this._easingBeginTimestamp > wheelScrollDuration) { | ||
| this.scrollTo(this.scrollX + dx, this.scrollY + dy, wheelScrollDuration); | ||
| } else { | ||
| this.scrollTo(this.targetX + dx, this.targetY + dy, wheelScrollDuration); | ||
| } | ||
| }; | ||
| _targetX = Math.max(0, Math.min(_targetX, _scrollMaxX)); | ||
| _targetY = Math.max(0, Math.min(_targetY, _scrollMaxY)); | ||
| onKeyDown = e => { | ||
| const {keyboardStepX, keyboardStepY, disabled, captureKeyboard, keyboardScrollDuration} = this.props; | ||
| let el = e.target, | ||
| tagName = el.tagName.toLowerCase(); | ||
| if ( | ||
| disabled || e.isDefaultPrevented() || // Event prevented. | ||
| !captureKeyboard || !/3[3456789]|40/.test(String(e.keyCode)) || // Keyboard events prevented. | ||
| tagName == 'textarea' || (tagName == 'input' && el.type == 'text') // Nested textarea or input is focused. | ||
| ) { | ||
| return; | ||
| } | ||
| // Prevent page scrolling. | ||
| e.preventDefault(); | ||
| switch (e.keyCode) { | ||
| case 36: // Home | ||
| this.scrollTo(0, 0, keyboardScrollDuration); | ||
| break; | ||
| case 35: // End | ||
| this.scrollTo(this.scrollMaxX, this.scrollMaxY, keyboardScrollDuration); | ||
| break; | ||
| case 33: // PgUp | ||
| case 34: // PgDn | ||
| let dy = this.viewport.clientHeight, | ||
| dx = this.viewport.clientWidth; | ||
| if (e.keyCode == 33) { | ||
| // For PageUp invert direction. | ||
| dy *= -1; | ||
| dx *= -1; | ||
| let nextScrollX = _scrollX, | ||
| nextScrollY = _scrollY; | ||
| if (_scrollX == scrollLeft && _scrollY == scrollTop) { | ||
| // Controlled scroll position coincides with viewport position. | ||
| if (nextScrollX != _targetX) { | ||
| const elapsedX = Date.now() - _timestampX; | ||
| if (elapsedX < _durationX) { | ||
| nextScrollX = _previousX + _easingX(elapsedX / _durationX, elapsedX, 0, 1, _durationX) * (_targetX - _previousX) | 0; | ||
| } else { | ||
| nextScrollX = _targetX; | ||
| } | ||
| } | ||
| if (e.shiftKey) { | ||
| this.scrollBy(dx, 0, keyboardScrollDuration); | ||
| } else { | ||
| this.scrollBy(0, dy, keyboardScrollDuration); | ||
| if (nextScrollY != _targetY) { | ||
| const elapsedY = Date.now() - _timestampY; | ||
| if (elapsedY < _durationY) { | ||
| nextScrollY = _previousY + _easingY(elapsedY / _durationY, elapsedY, 0, 1, _durationY) * (_targetY - _previousY) | 0; | ||
| } else { | ||
| nextScrollY = _targetY; | ||
| } | ||
| } | ||
| break; | ||
| case 38: // Up | ||
| this.scrollBy(0, -keyboardStepY, keyboardScrollDuration); | ||
| break; | ||
| case 40: // Down | ||
| this.scrollBy(0, keyboardStepY, keyboardScrollDuration); | ||
| break; | ||
| case 37: // Left | ||
| this.scrollBy(-keyboardStepX, 0, keyboardScrollDuration); | ||
| break; | ||
| case 39: // Right | ||
| this.scrollBy(keyboardStepX, 0, keyboardScrollDuration); | ||
| break; | ||
| } | ||
| }; | ||
| } | ||
| onDragStart(e, axis) { | ||
| const {disabled, captureHandleDrag} = this.props; | ||
| if (disabled || !captureHandleDrag || e.button != 0) { | ||
| return; | ||
| } | ||
| e.preventDefault(); | ||
| e.stopPropagation(); | ||
| const clientScrollingX = _scrollX != scrollLeft, | ||
| clientScrollingY = _scrollY != scrollTop; | ||
| let track; | ||
| if (axis == ScrollAxes.X) { | ||
| track = this.trackX; | ||
| } else { | ||
| track = this.trackY; | ||
| } | ||
| const OFFSET_X = e.clientX - this.handleX.offsetLeft, | ||
| OFFSET_Y = e.clientY - this.handleY.offsetTop; | ||
| if (clientScrollingX) { | ||
| _targetX = nextScrollX = scrollLeft; | ||
| } | ||
| if (clientScrollingY) { | ||
| _targetY = nextScrollY = scrollTop; | ||
| } | ||
| let onDrag = e => { | ||
| if (!this._forceSyncId || e.button != 0) { | ||
| onDragEnd(); // Component was unmounted or button was released. | ||
| const nextScrollingX = nextScrollX != _targetX, | ||
| nextScrollingY = nextScrollY != _targetY; | ||
| const dx = _scrollX - nextScrollX, | ||
| dy = _scrollY - nextScrollY; | ||
| const tickX = _tickX, | ||
| tickY = _tickY; | ||
| if (!_dispatchPrevented) { | ||
| // Events can be triggered. | ||
| // Checking ticks after each event callback invocation to ensure that any scroll | ||
| // methods were not called inside those callbacks. | ||
| if ( | ||
| (nextScrollingX | nextScrollingY | clientScrollingX | clientScrollingY) && | ||
| !_scrollingX && !_scrollingY | ||
| ) { | ||
| onScrollStart(this, _causeX, _causeY); | ||
| } | ||
| if (tickX == _tickX && nextScrollingX && !_scrollingX) { | ||
| onScrollStartX(this, _causeX); | ||
| } | ||
| if (tickY == _tickY && nextScrollingY && !_scrollingY) { | ||
| onScrollStartY(this, _causeY); | ||
| } | ||
| if ( | ||
| tickX == _tickX && tickY == _tickY && | ||
| (dx | dy) | ||
| ) { | ||
| onScroll(this, dx, dy, _causeX, _causeY); | ||
| } | ||
| if (tickX == _tickX && dx) { | ||
| onScrollX(this, dx, _causeX); | ||
| } | ||
| if (tickY == _tickY && dy) { | ||
| onScrollY(this, dy, _causeY); | ||
| } | ||
| if ( | ||
| tickX == _tickX && tickY == _tickY && | ||
| !nextScrollingX && !nextScrollingY && | ||
| (_scrollingX | _scrollingY | clientScrollingX | clientScrollingY) | ||
| ) { | ||
| onScrollEnd(this, _causeX, _causeY); | ||
| } | ||
| if (tickX == _tickX && !nextScrollingX && _scrollingX) { | ||
| onScrollEndX(this, _causeX); | ||
| } | ||
| if (tickY == _tickY && !nextScrollingY && _scrollingY) { | ||
| onScrollEndY(this, _causeY); | ||
| } | ||
| if (tickX == _tickX && _causeX != ScrollCause.TOUCH | _causeX != ScrollCause.HANDLE_DRAG) { | ||
| _causeX = null; | ||
| } | ||
| if (tickY == _tickY && _causeY != ScrollCause.TOUCH | _causeY != ScrollCause.HANDLE_DRAG) { | ||
| _causeY = null; | ||
| } | ||
| } | ||
| if (axis == ScrollAxes.X) { | ||
| var x = this.scrollMaxX * (e.clientX - OFFSET_X) / this.trackMaxX; | ||
| } else { | ||
| var y = this.scrollMaxY * (e.clientY - OFFSET_Y) / this.trackMaxY; | ||
| if (dx && tickX == _tickX) { | ||
| _viewport.scrollLeft = _scrollX = nextScrollX; | ||
| } | ||
| this.scrollTo(x, y, 0); | ||
| if (dy && tickY == _tickY) { | ||
| _viewport.scrollTop = _scrollY = nextScrollY; | ||
| } | ||
| if (!clientScrollBars) { | ||
| _trackMaxX = _trackX.clientWidth - _handleX.offsetWidth; | ||
| _handleX.style.width = clientWidth / scrollWidth * 100 + '%'; | ||
| _handleX.style.left = _trackMaxX * nextScrollX / _scrollMaxX + 'px'; | ||
| _trackMaxY = _trackY.clientHeight - _handleY.offsetHeight; | ||
| _handleY.style.height = clientHeight / scrollHeight * 100 + '%'; | ||
| _handleY.style.top = _trackMaxY * nextScrollY / _scrollMaxY + 'px'; | ||
| } | ||
| }; | ||
| let onDragEnd = e => { | ||
| removeEventListener('mousemove', onDrag); | ||
| removeEventListener('mouseup', onDragEnd); | ||
| if (this._forceSyncId) { | ||
| // Ensure component is mounted. | ||
| track.classList.remove('scroll-box__track--dragged'); | ||
| const handleKeyDown = event => { | ||
| const {target: {tagName}, keyCode, shiftKey} = event; | ||
| const { | ||
| disabled, | ||
| captureKeyboard, | ||
| keyboardStepX, | ||
| keyboardStepY, | ||
| keyboardScrollDuration | ||
| } = this.props; | ||
| if (disabled | !captureKeyboard | tagName == 'TEXTAREA' | tagName == 'INPUT') { | ||
| // Do not handle any keyboard events when text-related controls are focused. | ||
| return; | ||
| } | ||
| const options = {duration: keyboardScrollDuration}; | ||
| switch (keyCode) { | ||
| case 36: // Home | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollToY(0, options); | ||
| break; | ||
| case 35: // End | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollToY(_scrollMaxY, options); | ||
| break; | ||
| case 33: // Page Up | ||
| case 34: // Page Down | ||
| event.preventDefault(); | ||
| let dy = this.getPageHeight(), | ||
| dx = this.getPageWidth(); | ||
| if (keyCode == 33) { // Page Up | ||
| dy *= -1; | ||
| dx *= -1; | ||
| } | ||
| if (shiftKey) { | ||
| _causeX = ScrollCause.KEYBOARD; | ||
| this.scrollByX(dx, options); | ||
| } else { | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollByY(dy, options); | ||
| } | ||
| break; | ||
| case 38: // Up | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollByY(-keyboardStepY, options); | ||
| break; | ||
| case 40: // Down | ||
| event.preventDefault(); | ||
| _causeY = ScrollCause.KEYBOARD; | ||
| this.scrollByY(keyboardStepY, options); | ||
| break; | ||
| case 37: // Left | ||
| event.preventDefault(); | ||
| _causeX = ScrollCause.KEYBOARD; | ||
| this.scrollByX(-keyboardStepX, options); | ||
| break; | ||
| case 39: // Right | ||
| event.preventDefault(); | ||
| _causeX = ScrollCause.KEYBOARD; | ||
| this.scrollByX(keyboardStepX, options); | ||
| break; | ||
| } | ||
| }; | ||
| addEventListener('mousemove', onDrag); | ||
| addEventListener('mouseup', onDragEnd); | ||
| track.classList.add('scroll-box__track--dragged'); | ||
| }; | ||
| const handleFastTrack = (event, isHorizontal) => { | ||
| const { | ||
| disabled, | ||
| onDragStartX = e => this.onDragStart(e, ScrollAxes.X); | ||
| captureFastTrackX, | ||
| captureFastTrackY, | ||
| onDragStartY = e => this.onDragStart(e, ScrollAxes.Y); | ||
| fastTrackModeX, | ||
| fastTrackModeY, | ||
| onFastTrack(e, axis) { | ||
| const {disabled, fastTrack, fastTrackDuration} = this.props; | ||
| if (disabled || e.button != 0) { | ||
| return; // Component is disabled or secondary mouse button is being pressed. | ||
| } | ||
| let x, y; | ||
| const {clientWidth, clientHeight, scrollWidth, scrollHeight} = this.viewport, | ||
| POINTER_X = e.clientX - this.trackX.getBoundingClientRect().left, | ||
| POINTER_Y = e.clientY - this.trackY.getBoundingClientRect().top; | ||
| fastTrackScrollDurationX, | ||
| fastTrackScrollDurationY | ||
| } = this.props; | ||
| switch (fastTrack) { | ||
| if (disabled | !captureFastTrackX && !captureFastTrackY | event.button) { | ||
| // Component is disabled or secondary mouse button is being pressed. | ||
| return; | ||
| } | ||
| case FastTrack.PAGING: | ||
| if (axis == ScrollAxes.X) { | ||
| x = this.targetX + (1 - 2 * (POINTER_X < this.handleX.offsetLeft)) * clientWidth; | ||
| const { | ||
| clientWidth, | ||
| clientHeight, | ||
| scrollWidth, | ||
| scrollHeight | ||
| } = _viewport; | ||
| if (isHorizontal) { | ||
| if (!captureFastTrackX) { | ||
| return; | ||
| } | ||
| _causeX = ScrollCause.FAST_TRACK; | ||
| const pointerX = event.clientX - _trackX.getBoundingClientRect().left, | ||
| optionsX = {duration: fastTrackScrollDurationX}; | ||
| switch (fastTrackModeX) { | ||
| case FastTrackMode.PAGING: | ||
| this.scrollToX(_targetX + (1 - 2 * (pointerX < _handleX.offsetLeft)) * this.getPageWidth(), optionsX); | ||
| break; | ||
| case FastTrackMode.GOTO: | ||
| this.scrollToX(pointerX / _trackX.clientWidth * scrollWidth - clientWidth / 2, optionsX); | ||
| break; | ||
| } | ||
| } else { | ||
| if (!captureFastTrackY) { | ||
| return; | ||
| } | ||
| _causeY = ScrollCause.FAST_TRACK; | ||
| const pointerY = event.clientY - _trackY.getBoundingClientRect().top, | ||
| optionsY = {duration: fastTrackScrollDurationY}; | ||
| switch (fastTrackModeY) { | ||
| case FastTrackMode.PAGING: | ||
| this.scrollToY(_targetY + (1 - 2 * (pointerY < _handleY.offsetTop)) * this.getPageHeight(), optionsY); | ||
| break; | ||
| case FastTrackMode.GOTO: | ||
| this.scrollToY(pointerY / _trackY.clientHeight * scrollHeight - clientHeight / 2, optionsY); | ||
| break; | ||
| } | ||
| } | ||
| }; | ||
| const handleFastTrackX = event => handleFastTrack(event, true); | ||
| const handleFastTrackY = event => handleFastTrack(event, false); | ||
| const handleDragStart = (event, isHorizontal) => { | ||
| const { | ||
| disabled, | ||
| captureHandleDragX, | ||
| captureHandleDragY, | ||
| permitHandleDragInterruption | ||
| } = this.props; | ||
| // Handle can be dragged with left mouse button only. | ||
| if (disabled | !captureHandleDragX && !captureHandleDragY | event.button) { | ||
| return; | ||
| } | ||
| event.preventDefault(); | ||
| event.stopPropagation(); | ||
| let track; | ||
| if (isHorizontal) { | ||
| _causeX = ScrollCause.HANDLE_DRAG; | ||
| track = _trackX; | ||
| } else { | ||
| _causeY = ScrollCause.HANDLE_DRAG; | ||
| track = _trackY; | ||
| } | ||
| const offsetX = event.clientX - _handleX.offsetLeft, | ||
| offsetY = event.clientY - _handleY.offsetTop; | ||
| const handleDrag = event => { | ||
| if (!_root | event.button | permitHandleDragInterruption && (isHorizontal ? _causeX : _causeY) != ScrollCause.HANDLE_DRAG) { | ||
| stopDrag(); | ||
| return; | ||
| } | ||
| if (isHorizontal) { | ||
| _causeX = ScrollCause.HANDLE_DRAG; | ||
| this.scrollToX(_scrollMaxX * (event.clientX - offsetX) / _trackMaxX); | ||
| } else { | ||
| y = this.targetY + (1 - 2 * (POINTER_Y < this.handleY.offsetTop)) * clientHeight; | ||
| _causeY = ScrollCause.HANDLE_DRAG; | ||
| this.scrollToY(_scrollMaxY * (event.clientY - offsetY) / _trackMaxY); | ||
| } | ||
| break; | ||
| }; | ||
| case FastTrack.GOTO: | ||
| if (axis == ScrollAxes.X) { | ||
| x = POINTER_X / this.trackX.clientWidth * scrollWidth - clientWidth / 2; | ||
| const handleDragEnd = () => { | ||
| if (isHorizontal) { | ||
| _causeX = null; | ||
| } else { | ||
| y = POINTER_Y / this.trackY.clientHeight * scrollHeight - clientHeight / 2; | ||
| _causeY = null; | ||
| } | ||
| break; | ||
| stopDrag(); | ||
| }; | ||
| default: return; | ||
| } | ||
| this.scrollTo(x, y, fastTrackDuration); | ||
| }; | ||
| const stopDrag = () => { | ||
| removeEventListener('mousemove', handleDrag); | ||
| removeEventListener('mouseup', handleDragEnd); | ||
| onFastTrackX = e => this.onFastTrack(e, ScrollAxes.X); | ||
| track.classList.remove('scroll-box__track--dragged'); | ||
| }; | ||
| onFastTrackY = e => this.onFastTrack(e, ScrollAxes.Y); | ||
| addEventListener('mousemove', handleDrag); | ||
| addEventListener('mouseup', handleDragEnd); | ||
| _updateTrackHoverStatus(e, track) { | ||
| const {clientX, clientY} = e, | ||
| {hoverProximity} = this.props, | ||
| {width, left, top, height} = track.getBoundingClientRect(); | ||
| track.classList.add('scroll-box__track--dragged'); | ||
| }; | ||
| track.classList.toggle('scroll-box__track--hover', | ||
| clientY - height - top < hoverProximity && top - clientY < hoverProximity && | ||
| clientX - width - left < hoverProximity && left - clientX < hoverProximity); | ||
| } | ||
| const handleDragStartX = event => handleDragStart(event, true); | ||
| onCursorApproachingTrack = e => { | ||
| let {nativeScroll, disabled, captureHandleDrag, fastTrack} = this.props; | ||
| // Do not track cursor proximity for native scroll bar, when handle is being dragged, | ||
| // when selection is in progress or when another handle is being dragged (even on another | ||
| // scroll box instance). | ||
| if (nativeScroll || disabled || (!captureHandleDrag && fastTrack == FastTrack.OFF) || e.buttons > 0) { | ||
| return; | ||
| } | ||
| // Update track hover status only if it is actually in use. | ||
| if (this.exposesX) { | ||
| this._updateTrackHoverStatus(e, this.trackX); | ||
| } | ||
| if (this.exposesY) { | ||
| this._updateTrackHoverStatus(e, this.trackY); | ||
| } | ||
| }; | ||
| const handleDragStartY = event => handleDragStart(event, false); | ||
| _updateReferences() { | ||
| let {refs} = this; | ||
| for (let ref in refs) { | ||
| if (refs.hasOwnProperty(ref)) { | ||
| this[ref] = findDOMNode(refs[ref]); | ||
| const handleWheel = event => { | ||
| let {target, deltaMode, deltaX, deltaY, shiftKey} = event; | ||
| const { | ||
| wheelStepX, | ||
| wheelStepY, | ||
| disabled, | ||
| clientScrollBars, | ||
| captureWheel, | ||
| lineHeight, | ||
| propagateWheelScrollX, | ||
| propagateWheelScrollY, | ||
| swapWheelAxes, | ||
| wheelScrollDurationX, | ||
| wheelScrollDurationY | ||
| } = this.props; | ||
| if (clientScrollBars && !captureWheel) { | ||
| event.preventDefault(); | ||
| } | ||
| } | ||
| this.el = findDOMNode(this); | ||
| this.viewport = this.el.firstChild; | ||
| if (disabled | event.isDefaultPrevented()) { | ||
| return; | ||
| } | ||
| if (target != _viewport && target.tagName == 'TEXTAREA') { | ||
| // Nested textarea is focused and its is not a viewport. | ||
| return; | ||
| } | ||
| const {nativeScroll} = this.props; | ||
| if (nativeScroll == null) { | ||
| if (typeof window != 'undefined' && 'orientation' in window) { | ||
| this.el.classList.add('scroll-box--native'); | ||
| // By default, Google Chrome changes scrolling orientation if shift key is pressed, | ||
| // so propagate this behavior to other browsers as well. | ||
| if (shiftKey && deltaX == 0) { | ||
| deltaX = deltaY; | ||
| deltaY = 0; | ||
| } | ||
| } else { | ||
| this.el.classList.toggle('scroll-box--native', nativeScroll); | ||
| } | ||
| } | ||
| componentDidMount() { | ||
| let requestForceSync = () => { | ||
| if (window.cancelAnimationFrame) { | ||
| this._forceSyncId = requestAnimationFrame(requestForceSync); | ||
| } else { | ||
| this._forceSyncId = setTimeout(requestForceSync, 1000 / 30); | ||
| if (swapWheelAxes) { | ||
| const buffer = deltaX; | ||
| deltaX = deltaY; | ||
| deltaY = buffer; | ||
| } | ||
| this._forceSync(); | ||
| let dx = deltaX * _requiresScrollBarX, | ||
| dy = deltaY * _requiresScrollBarY; | ||
| if (deltaX && !_requiresScrollBarX | dx < 0 && !_targetX | dx > 0 && _targetX == _scrollMaxX) { | ||
| // Content is scrolled to its possible limit. | ||
| if (!propagateWheelScrollX) { | ||
| event.preventDefault(); | ||
| } | ||
| return; | ||
| } | ||
| if (deltaY && !_requiresScrollBarY | dy < 0 && !_targetY | dy > 0 && _targetY == _scrollMaxY) { | ||
| if (!propagateWheelScrollY) { | ||
| event.preventDefault(); | ||
| } | ||
| return; | ||
| } | ||
| event.preventDefault(); | ||
| // Converts received delta values into pixels. | ||
| switch (deltaMode) { | ||
| case 0x01: // Delta values are specified in lines. | ||
| dx *= lineHeight; | ||
| dy *= lineHeight; | ||
| break; | ||
| case 0x02: | ||
| dx *= this.getPageWidth(); | ||
| dy *= this.getPageHeight(); | ||
| break; | ||
| default: | ||
| // Delta values are specified in pixels. | ||
| break; | ||
| } | ||
| dx *= wheelStepX / 100; | ||
| dy *= wheelStepY / 100; | ||
| let nextTargetX = _targetX + dx, | ||
| nextTargetY = _targetY + dy; | ||
| // Prevent jumping to target position when animated scrolling is in progress, | ||
| // but preserve scroll speed when mouse wheel events arrive frequently. | ||
| if (Date.now() - _timestampX > wheelScrollDurationX) { | ||
| nextTargetX = _scrollX + dx; | ||
| } | ||
| if (Date.now() - _timestampX > wheelScrollDurationY) { | ||
| nextTargetY = _scrollY + dy; | ||
| } | ||
| if (dx) { | ||
| _causeX = ScrollCause.MOUSE_WHEEL; | ||
| this.scrollToX(nextTargetX, {duration: wheelScrollDurationX}); | ||
| } | ||
| if (dy) { | ||
| _causeY = ScrollCause.MOUSE_WHEEL; | ||
| this.scrollToY(nextTargetY, {duration: wheelScrollDurationY}); | ||
| } | ||
| }; | ||
| this._updateReferences(); | ||
| requestForceSync(); | ||
| addEventListener('mousemove', this.onCursorApproachingTrack); | ||
| } | ||
| componentDidUpdate() { | ||
| this._updateReferences(); | ||
| this._forceSync(); | ||
| } | ||
| const updateTrackHoverStatus = (event, track, proximity, status) => { | ||
| if (status == null) { | ||
| const {clientX, clientY} = event, | ||
| {width, left, top, height} = track.getBoundingClientRect(); | ||
| status = | ||
| proximity > clientY - height - top && | ||
| proximity > clientX - width - left && | ||
| proximity > left - clientX && | ||
| proximity > top - clientY; | ||
| } | ||
| track.classList.toggle('scroll-box__track--hover', status); | ||
| }; | ||
| componentWillUnmount() { | ||
| if (window.cancelAnimationFrame) { | ||
| cancelAnimationFrame(this._forceSyncId); | ||
| } else { | ||
| clearTimeout(this._forceSyncId); | ||
| } | ||
| this._forceSyncId = 0; | ||
| removeEventListener('mousemove', this.onCursorApproachingTrack); | ||
| } | ||
| const handleBarHover = event => { | ||
| const { | ||
| disabled, | ||
| clientScrollBars, | ||
| captureHandleDragX, | ||
| captureHandleDragY, | ||
| captureFastTrackX, | ||
| captureFastTrackY, | ||
| trackHoverProximityX, | ||
| trackHoverProximityY | ||
| } = this.props; | ||
| render() { | ||
| const {axes, trackXChildren, trackYChildren, handleXChildren, handleYChildren, disabled, outset, className, children, style} = this.props; | ||
| let classNames = ['scroll-box']; | ||
| if (className) { | ||
| classNames = classNames.concat(className); | ||
| } | ||
| if (disabled) { | ||
| classNames.push('scroll-box--disabled'); | ||
| } | ||
| if (outset) { | ||
| classNames.push('scroll-box--outset'); | ||
| } | ||
| if (axes.indexOf(ScrollAxes.X) > -1) { | ||
| classNames.push('scroll-box--has-axis-x'); | ||
| } | ||
| if (axes.indexOf(ScrollAxes.Y) > -1) { | ||
| classNames.push('scroll-box--has-axis-y'); | ||
| } | ||
| return ( | ||
| <div style={style} | ||
| className={classNames.join(' ')} | ||
| onWheel={this.onWheel} | ||
| onKeyDown={this.onKeyDown} | ||
| onTouchStart={this.onTouchStart} | ||
| onTouchMove={this.onTouchMove} | ||
| onTouchEnd={this.onTouchEnd} | ||
| onTouchCancel={this.onTouchEnd} | ||
| tabIndex="-1"> | ||
| {React.Children.only(children)} | ||
| <div className="scroll-box__track scroll-box__track--x" | ||
| onMouseDown={this.onFastTrackX} | ||
| ref="trackX"> | ||
| <div className="scroll-box__handle scroll-box__handle--x" | ||
| onMouseDown={this.onDragStartX} | ||
| ref="handleX"> | ||
| {handleXChildren} | ||
| </div> | ||
| {trackXChildren} | ||
| </div> | ||
| <div className="scroll-box__track scroll-box__track--y" | ||
| onMouseDown={this.onFastTrackY} | ||
| ref="trackY"> | ||
| <div className="scroll-box__handle scroll-box__handle--y" | ||
| onMouseDown={this.onDragStartY} | ||
| ref="handleY"> | ||
| {handleYChildren} | ||
| </div> | ||
| {trackYChildren} | ||
| </div> | ||
| </div> | ||
| ); | ||
| if ('orientation' in window | clientScrollBars | disabled) { | ||
| return; | ||
| } | ||
| if (event.buttons) { | ||
| if (_causeX != ScrollCause.HANDLE_DRAG) { | ||
| var statusX = false; | ||
| } | ||
| if (_causeY != ScrollCause.HANDLE_DRAG) { | ||
| var statusY = false; | ||
| } | ||
| } | ||
| if (_requiresScrollBarX && (captureHandleDragX | captureFastTrackX)) { | ||
| updateTrackHoverStatus(event, _trackX, trackHoverProximityX, statusX); | ||
| } | ||
| if (_requiresScrollBarY && (captureHandleDragY | captureFastTrackY)) { | ||
| updateTrackHoverStatus(event, _trackY, trackHoverProximityY, statusY); | ||
| } | ||
| }; | ||
| const handleTouchStart = event => { | ||
| const {target, touches} = event; | ||
| const { | ||
| disabled, | ||
| clientScrollBars, | ||
| captureTouch, | ||
| propagateTouchScrollX, | ||
| propagateTouchScrollY, | ||
| } = this.props; | ||
| if (clientScrollBars && !captureTouch) { | ||
| event.preventDefault(); | ||
| } | ||
| if (clientScrollBars | disabled | touches.length > 1 | event.isDefaultPrevented()) { | ||
| return; | ||
| } | ||
| if (target != _viewport && target.tagName == 'TEXTAREA') { | ||
| // Nested textarea is focused and its is not a viewport. | ||
| return; | ||
| } | ||
| const { | ||
| clientX: initialClientX, | ||
| clientY: initialClientY | ||
| } = touches[0]; | ||
| let scrolled = false; | ||
| const handleTouchMove = event => { | ||
| const {targetX, targetY, scrollMaxX, scrollMaxY} = this; | ||
| const {clientX, clientY} = event.touches[0]; | ||
| const dx = initialClientX - clientX, | ||
| dy = initialClientY - clientY; | ||
| if ( | ||
| (dx < 0 && !targetX) || (dx > 0 && targetX == scrollMaxX) || | ||
| (dy < 0 && !targetY) || (dy > 0 && targetY == scrollMaxY) | ||
| ) { | ||
| if (!scrolled) { | ||
| disposeTouch(); | ||
| } | ||
| return; | ||
| } | ||
| scrolled = true; | ||
| event.preventDefault(); | ||
| this.scrollTo({x: _scrollX + dx, y: _scrollY + dy}); | ||
| }; | ||
| const handleTouchEnd = event => { | ||
| disposeTouch(); | ||
| }; | ||
| const disposeTouch = () => { | ||
| removeEventListener('touchmove', handleTouchMove); | ||
| removeEventListener('touchend', handleTouchEnd); | ||
| removeEventListener('touchcancel', handleTouchEnd); | ||
| }; | ||
| addEventListener('touchmove', handleTouchMove); | ||
| addEventListener('touchend', handleTouchEnd); | ||
| addEventListener('touchcancel', handleTouchEnd); | ||
| }; | ||
| } | ||
| } |
| export {ScrollBox} from './ScrollBox'; | ||
| export {GenericScrollBox, FastTrack, ScrollAxes} from './GenericScrollBox'; | ||
| export {GenericScrollBox, FastTrackMode, ScrollCause} from './GenericScrollBox'; |
+10
-10
@@ -38,3 +38,3 @@ @scroll-box: scroll-box; // Namespace class | ||
| > .@{scroll-box}__viewport { | ||
| // Hide native scrollbars. | ||
| // Hide client scrollbars. | ||
| overflow: hidden !important; | ||
@@ -53,9 +53,9 @@ } | ||
| // Used if fallback to native system scrolling should occur. | ||
| &--native { | ||
| // Used if fallback to client system scrolling should occur. | ||
| &--client-scroll-bars { | ||
| &.@{scroll-box}--has-axis-y.@{scroll-box}--show-axis-y > .@{scroll-box}__viewport { | ||
| &.@{scroll-box}--enable-y.@{scroll-box}--requires-y > .@{scroll-box}__viewport { | ||
| overflow-y: auto; | ||
| } | ||
| &.@{scroll-box}--has-axis-x.@{scroll-box}--show-axis-x > .@{scroll-box}__viewport { | ||
| &.@{scroll-box}--enable-x.@{scroll-box}--requires-x > .@{scroll-box}__viewport { | ||
| overflow-x: auto; | ||
@@ -68,14 +68,14 @@ } | ||
| &:not(.@{scroll-box}--native) { | ||
| &.@{scroll-box}--has-axis-y.@{scroll-box}--show-axis-y > .@{scroll-box}__track--y { | ||
| &:not(.@{scroll-box}--client-scroll-bars) { | ||
| &.@{scroll-box}--enable-y.@{scroll-box}--requires-y > .@{scroll-box}__track--y { | ||
| visibility: visible; | ||
| } | ||
| &.@{scroll-box}--has-axis-x.@{scroll-box}--show-axis-x > .@{scroll-box}__track--x { | ||
| &.@{scroll-box}--enable-x.@{scroll-box}--requires-x > .@{scroll-box}__track--x { | ||
| visibility: visible; | ||
| } | ||
| // Both non-native scrollbars are visible and they are inside | ||
| // Both non-client scrollbars are visible and they are inside | ||
| // scrollable are, we should prevent their intersection in the | ||
| // shared corner. | ||
| &.@{scroll-box}--has-axis-x.@{scroll-box}--show-axis-x.@{scroll-box}--has-axis-y.@{scroll-box}--show-axis-y:not(.@{scroll-box}--outset) { | ||
| &.@{scroll-box}--enable-x.@{scroll-box}--requires-x.@{scroll-box}--enable-y.@{scroll-box}--requires-y:not(.@{scroll-box}--outset) { | ||
| > .@{scroll-box}__track { | ||
@@ -82,0 +82,0 @@ &--y { |
@@ -1,1 +0,1 @@ | ||
| .scroll-box{position:relative}.scroll-box:focus{outline:none}.scroll-box--disabled>.scroll-box__viewport{overflow:hidden!important}.scroll-box--disabled>.scroll-box__track{visibility:hidden!important}.scroll-box--wrapped>.scroll-box__viewport{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;padding:inherit;border-radius:inherit}.scroll-box--wrapped>.scroll-box__track{display:block}.scroll-box--native.scroll-box--has-axis-y.scroll-box--show-axis-y>.scroll-box__viewport{overflow-y:auto}.scroll-box--native.scroll-box--has-axis-x.scroll-box--show-axis-x>.scroll-box__viewport{overflow-x:auto}.scroll-box--native>.scroll-box__viewport{-webkit-overflow-scrolling:touch}.scroll-box:not(.scroll-box--native).scroll-box--has-axis-x.scroll-box--show-axis-x>.scroll-box__track--x,.scroll-box:not(.scroll-box--native).scroll-box--has-axis-y.scroll-box--show-axis-y>.scroll-box__track--y{visibility:visible}.scroll-box:not(.scroll-box--native).scroll-box--has-axis-x.scroll-box--show-axis-x.scroll-box--has-axis-y.scroll-box--show-axis-y:not(.scroll-box--outset)>.scroll-box__track--y{margin-bottom:14px}.scroll-box:not(.scroll-box--native).scroll-box--has-axis-x.scroll-box--show-axis-x.scroll-box--has-axis-y.scroll-box--show-axis-y:not(.scroll-box--outset)>.scroll-box__track--x{margin-right:14px}.scroll-box__handle,.scroll-box__track{position:absolute;border-radius:10.2px;transition:.2s ease-in-out}.scroll-box__handle{transition-property:background;cursor:default}.scroll-box__handle--y{width:100%;min-height:30px;max-height:100%;top:0}.scroll-box__handle--x{height:100%;min-width:30px;max-width:100%;left:0}.scroll-box__track{display:none;visibility:hidden;transition-property:background,width,height;cursor:default}.scroll-box__track--y{top:0;bottom:0;right:0;width:6px;margin:4px 4px 4px 0}.scroll-box__track--y.scroll-box__track--dragged,.scroll-box__track--y.scroll-box__track--hover{width:10.2px}.scroll-box--outset>.scroll-box__track--y{left:100%;margin-left:4px}.scroll-box__track--x{left:0;right:0;bottom:0;height:6px;margin:0 4px 4px}.scroll-box__track--x.scroll-box__track--dragged,.scroll-box__track--x.scroll-box__track--hover{height:10.2px}.scroll-box--outset>.scroll-box__track--x{top:100%;margin-top:4px}.scroll-box>.scroll-box__track{background:transparent}.scroll-box>.scroll-box__track>.scroll-box__handle{background:rgba(0,0,0,.4)}.scroll-box>.scroll-box__track--dragged,.scroll-box>.scroll-box__track--hover{background:rgba(0,0,0,.2)}.scroll-box>.scroll-box__track--dragged>.scroll-box__handle,.scroll-box>.scroll-box__track--hover>.scroll-box__handle{background:rgba(0,0,0,.6)} | ||
| .scroll-box{position:relative}.scroll-box:focus{outline:none}.scroll-box--disabled>.scroll-box__viewport{overflow:hidden!important}.scroll-box--disabled>.scroll-box__track{visibility:hidden!important}.scroll-box--wrapped>.scroll-box__viewport{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;padding:inherit;border-radius:inherit}.scroll-box--wrapped>.scroll-box__track{display:block}.scroll-box--client-scroll-bars.scroll-box--enable-y.scroll-box--requires-y>.scroll-box__viewport{overflow-y:auto}.scroll-box--client-scroll-bars.scroll-box--enable-x.scroll-box--requires-x>.scroll-box__viewport{overflow-x:auto}.scroll-box--client-scroll-bars>.scroll-box__viewport{-webkit-overflow-scrolling:touch}.scroll-box:not(.scroll-box--client-scroll-bars).scroll-box--enable-x.scroll-box--requires-x>.scroll-box__track--x,.scroll-box:not(.scroll-box--client-scroll-bars).scroll-box--enable-y.scroll-box--requires-y>.scroll-box__track--y{visibility:visible}.scroll-box:not(.scroll-box--client-scroll-bars).scroll-box--enable-x.scroll-box--requires-x.scroll-box--enable-y.scroll-box--requires-y:not(.scroll-box--outset)>.scroll-box__track--y{margin-bottom:14px}.scroll-box:not(.scroll-box--client-scroll-bars).scroll-box--enable-x.scroll-box--requires-x.scroll-box--enable-y.scroll-box--requires-y:not(.scroll-box--outset)>.scroll-box__track--x{margin-right:14px}.scroll-box__handle,.scroll-box__track{position:absolute;border-radius:10.2px;transition:.2s ease-in-out}.scroll-box__handle{transition-property:background;cursor:default}.scroll-box__handle--y{width:100%;min-height:30px;max-height:100%;top:0}.scroll-box__handle--x{height:100%;min-width:30px;max-width:100%;left:0}.scroll-box__track{display:none;visibility:hidden;transition-property:background,width,height;cursor:default}.scroll-box__track--y{top:0;bottom:0;right:0;width:6px;margin:4px 4px 4px 0}.scroll-box__track--y.scroll-box__track--dragged,.scroll-box__track--y.scroll-box__track--hover{width:10.2px}.scroll-box--outset>.scroll-box__track--y{left:100%;margin-left:4px}.scroll-box__track--x{left:0;right:0;bottom:0;height:6px;margin:0 4px 4px}.scroll-box__track--x.scroll-box__track--dragged,.scroll-box__track--x.scroll-box__track--hover{height:10.2px}.scroll-box--outset>.scroll-box__track--x{top:100%;margin-top:4px}.scroll-box>.scroll-box__track{background:transparent}.scroll-box>.scroll-box__track>.scroll-box__handle{background:rgba(0,0,0,.4)}.scroll-box>.scroll-box__track--dragged,.scroll-box>.scroll-box__track--hover{background:rgba(0,0,0,.2)}.scroll-box>.scroll-box__track--dragged>.scroll-box__handle,.scroll-box>.scroll-box__track--hover>.scroll-box__handle{background:rgba(0,0,0,.6)} |
@@ -1,1 +0,6 @@ | ||
| module.exports=function(e){function t(r){if(o[r])return o[r].exports;var a=o[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var o={};return t.m=e,t.c=o,t.p="",t(0)}([function(e,t,o){o(5),e.exports=o(4)},function(e,t,o){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.GenericScrollBox=t.FastTrack=t.ScrollAxes=void 0;var l=function(){function e(e,t){for(var o=0;o<t.length;o++){var r=t[o];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,o,r){return o&&e(t.prototype,o),r&&e(t,r),t}}(),i=o(2),c=r(i),u=o(6),h=c["default"].PropTypes,f=h.number,p=h.bool,d=h.func,v=h.oneOf,x=h.any,y=t.ScrollAxes={X:"x",Y:"y",XY:"xy"},g=t.FastTrack={PAGING:"paging",GOTO:"goto",OFF:null},b=t.GenericScrollBox=function(e){function t(){var e,o,r,s;a(this,t);for(var l=arguments.length,i=Array(l),c=0;l>c;c++)i[c]=arguments[c];return o=r=n(this,(e=Object.getPrototypeOf(t)).call.apply(e,[this].concat(i))),r.handleX=null,r.handleY=null,r.trackX=null,r.trackY=null,r.viewport=null,r.targetX=0,r.targetY=0,r.previousX=0,r.previousY=0,r.scrollX=0,r.scrollY=0,r.scrollMaxX=0,r.scrollMaxY=0,r.trackMaxX=0,r.trackMaxY=0,r.exposesX=!1,r.exposesY=!1,r._forceSyncId=0,r._easingBeginTimestamp=0,r._easingDuration=0,r._easing=null,r._silent=!1,r._touchOffsetX=0,r._touchOffsetY=0,r._touchStart=null,r._touchEnd=null,r.onTouchStart=function(e){if(!(r.props.nativeScroll||r.props.disabled||e.touches.length>1||e.isDefaultPrevented())&&(r.exposesX||r.exposesY)){e.stopPropagation();var t=e.touches[0],o=r.viewport.scrollLeft,a=r.viewport.scrollTop;r._touchOffsetX=o+t.screenX,r._touchOffsetY=a+t.screenY,r._touchStart={x:o,y:a}}},r.onTouchMove=function(e){var t=r.props.propagateTouchScroll,o=r,a=o.targetX,n=o.targetY,s=o.scrollMaxX,l=o.scrollMaxY,i=o.exposesX,c=o.exposesY;if(r._touchStart){var u=e.touches[0],h=r._touchOffsetX-u.screenX,f=r._touchOffsetY-u.screenY,p=r._touchEnd||r._touchStart,d=p.x-h,v=p.y-f,x=d*i,y=v*c;if(d&&!i||0>x&&!a||x>0&&a==s||v&&!c||0>y&&!n||y>0&&n==l)return void(t||e.preventDefault());if(r._touchEnd){var g=r._touchStart;r._touchStart=r._touchEnd,r._touchEnd=g,g.x=h,g.y=f}else r._touchEnd={x:h,y:f};r.scrollTo(h,f,0)}},r.onTouchEnd=function(e){if(r._touchEnd){var t=r,o=t._touchStart,a=t._touchEnd,n=Date.now()-r._easingBeginTimestamp,s=o.x-a.x,l=o.y-a.y,i=Math.sqrt(s*s+l*l),c=i/n*100;r._touchStart=null,r._touchEnd=null,r.scrollTo(a.x-c*s/i,a.y-c*l/i,c)}},r.onWheel=function(e){var t=r.props,o=t.wheelStepX,a=t.wheelStepY,n=t.disabled,s=t.nativeScroll,l=t.captureWheel,i=t.propagateWheelScroll,c=t.swapWheelAxes,u=t.wheelScrollDuration,h=r,f=h.targetX,p=h.targetY,d=h.scrollMaxX,v=h.scrollMaxY,x=h.exposesX,y=h.exposesY,g=e.target;if(s&&!l&&e.preventDefault(),!(n||e.isDefaultPrevented()||!l||g!=r.viewport&&"textarea"==g.tagName.toLowerCase())){var b=e.deltaX*x,_=e.deltaY*y;if(e.deltaX&&!x||0>b&&!f||b>0&&f==d||e.deltaY&&!y||0>_&&!p||_>0&&p==v)return void(i||e.preventDefault());if(e.shiftKey&&!b&&(b=_,_=0),c){var k=[_,b];b=k[0],_=k[1]}if(e.preventDefault(),"undefined"!=typeof InstallTrigger){var X=30;b*=X,_*=X}b*=o/100,_*=a/100,Date.now()-r._easingBeginTimestamp>u?r.scrollTo(r.scrollX+b,r.scrollY+_,u):r.scrollTo(r.targetX+b,r.targetY+_,u)}},r.onKeyDown=function(e){var t=r.props,o=t.keyboardStepX,a=t.keyboardStepY,n=t.disabled,s=t.captureKeyboard,l=t.keyboardScrollDuration,i=e.target,c=i.tagName.toLowerCase();if(!n&&!e.isDefaultPrevented()&&s&&/3[3456789]|40/.test(String(e.keyCode))&&"textarea"!=c&&("input"!=c||"text"!=i.type))switch(e.preventDefault(),e.keyCode){case 36:r.scrollTo(0,0,l);break;case 35:r.scrollTo(r.scrollMaxX,r.scrollMaxY,l);break;case 33:case 34:var u=r.viewport.clientHeight,h=r.viewport.clientWidth;33==e.keyCode&&(u*=-1,h*=-1),e.shiftKey?r.scrollBy(h,0,l):r.scrollBy(0,u,l);break;case 38:r.scrollBy(0,-a,l);break;case 40:r.scrollBy(0,a,l);break;case 37:r.scrollBy(-o,0,l);break;case 39:r.scrollBy(o,0,l)}},r.onDragStartX=function(e){return r.onDragStart(e,y.X)},r.onDragStartY=function(e){return r.onDragStart(e,y.Y)},r.onFastTrackX=function(e){return r.onFastTrack(e,y.X)},r.onFastTrackY=function(e){return r.onFastTrack(e,y.Y)},r.onCursorApproachingTrack=function(e){var t=r.props,o=t.nativeScroll,a=t.disabled,n=t.captureHandleDrag,s=t.fastTrack;o||a||!n&&s==g.OFF||e.buttons>0||(r.exposesX&&r._updateTrackHoverStatus(e,r.trackX),r.exposesY&&r._updateTrackHoverStatus(e,r.trackY))},s=o,n(r,s)}return s(t,e),l(t,[{key:"scrollBy",value:function(e,t,o,r,a){this.scrollTo(this.targetX+e,this.targetY+t,o,r,a)}},{key:"scrollTo",value:function(e,t){var o=arguments.length<=2||void 0===arguments[2]?0:arguments[2],r=arguments.length<=3||void 0===arguments[3]?this.props.defaultEasing:arguments[3],a=arguments.length<=4||void 0===arguments[4]?!1:arguments[4];this._easingDuration=o,this._easingBeginTimestamp=Date.now(),this.previousX=this.scrollX,this.previousY=this.scrollY,isNaN(e)||(this.targetX=e),isNaN(t)||(this.targetY=t),this._easing=r,this._silent=Boolean(a),this._forceSync()}},{key:"_forceSync",value:function(){var e=this.handleX,t=this.handleY,o=this.viewport,r=this.scrollY,a=this.scrollX,n=this.previousX,s=this.previousY,l=this._silent,i=this._easingBeginTimestamp,c=this._easing,u=this._easingDuration,h=this.props,f=h.axes,p=h.nativeScroll,d=h.outset,v=h.onViewportScroll,x=h.scrollMinX,g=h.scrollMinY,b=o.clientWidth,_=o.clientHeight,k=o.offsetWidth,X=o.offsetHeight,Y=o.scrollWidth,m=o.scrollHeight,S=o.scrollTop,w=o.scrollLeft,T=Math.max(0,Y-b),M=Math.max(0,m-_);this.exposesX=f.indexOf(y.X)>-1&&T>=x,this.exposesY=f.indexOf(y.Y)>-1&&M>=g,this.el.classList.toggle("scroll-box--show-axis-x",this.exposesX),this.el.classList.toggle("scroll-box--show-axis-y",this.exposesY);var D="100%",O="100%";if(p&&d){var E=k-b,P=X-_;E&&(D="calc(100% + "+E+"px)"),P&&(O="calc(100% + "+P+"px)")}o.style.width=D,o.style.height=O;var C=Math.max(0,Math.min(Math.round(this.targetX),T))*this.exposesX,B=Math.max(0,Math.min(Math.round(this.targetY),M))*this.exposesY,W=C,F=B;if(r==S&&a==w){var j=Date.now()-i;if(u>j&&"function"==typeof c){var L=c(j/u,j,0,1,u);W=Math.round(n+L*(C-n)),F=Math.round(s+L*(B-s))}else this._easingDuration=0;o.scrollLeft=W,o.scrollTop=F}else this._easingDuration=0,W=C=w,F=B=S;this.targetX=C,this.targetY=B,a==W&&r==F&&this.scrollMaxX==T&&this.scrollMaxY==M&&(this._easingDuration||(this._easing=null,this._silent=!1)),this.scrollX=W,this.scrollY=F,this.scrollMaxX=T,this.scrollMaxY=M,this.trackMaxX=0,this.trackMaxY=0,p||(this.trackMaxX=this.trackX.clientWidth-e.offsetWidth,this.trackMaxY=this.trackY.clientHeight-t.offsetHeight,e.style.width=b/Y*100+"%",e.style.left=this.trackMaxX*W/T+"px",t.style.height=_/m*100+"%",t.style.top=this.trackMaxY*F/M+"px"),l||a==W&&r==F||v(this)}},{key:"onDragStart",value:function(e,t){var o=this,r=this.props,a=r.disabled,n=r.captureHandleDrag;if(!a&&n&&0==e.button){e.preventDefault(),e.stopPropagation();var s=void 0;s=t==y.X?this.trackX:this.trackY;var l=e.clientX-this.handleX.offsetLeft,i=e.clientY-this.handleY.offsetTop,c=function(e){if(o._forceSyncId&&0==e.button||u(),t==y.X)var r=o.scrollMaxX*(e.clientX-l)/o.trackMaxX;else var a=o.scrollMaxY*(e.clientY-i)/o.trackMaxY;o.scrollTo(r,a,0)},u=function h(e){removeEventListener("mousemove",c),removeEventListener("mouseup",h),o._forceSyncId&&s.classList.remove("scroll-box__track--dragged")};addEventListener("mousemove",c),addEventListener("mouseup",u),s.classList.add("scroll-box__track--dragged")}}},{key:"onFastTrack",value:function(e,t){var o=this.props,r=o.disabled,a=o.fastTrack,n=o.fastTrackDuration;if(!r&&0==e.button){var s=void 0,l=void 0,i=this.viewport,c=i.clientWidth,u=i.clientHeight,h=i.scrollWidth,f=i.scrollHeight,p=e.clientX-this.trackX.getBoundingClientRect().left,d=e.clientY-this.trackY.getBoundingClientRect().top;switch(a){case g.PAGING:t==y.X?s=this.targetX+(1-2*(p<this.handleX.offsetLeft))*c:l=this.targetY+(1-2*(d<this.handleY.offsetTop))*u;break;case g.GOTO:t==y.X?s=p/this.trackX.clientWidth*h-c/2:l=d/this.trackY.clientHeight*f-u/2;break;default:return}this.scrollTo(s,l,n)}}},{key:"_updateTrackHoverStatus",value:function(e,t){var o=e.clientX,r=e.clientY,a=this.props.hoverProximity,n=t.getBoundingClientRect(),s=n.width,l=n.left,i=n.top,c=n.height;t.classList.toggle("scroll-box__track--hover",a>r-c-i&&a>i-r&&a>o-s-l&&a>l-o)}},{key:"_updateReferences",value:function(){var e=this.refs;for(var t in e)e.hasOwnProperty(t)&&(this[t]=(0,u.findDOMNode)(e[t]));this.el=(0,u.findDOMNode)(this),this.viewport=this.el.firstChild;var o=this.props.nativeScroll;null==o?"undefined"!=typeof window&&"orientation"in window&&this.el.classList.add("scroll-box--native"):this.el.classList.toggle("scroll-box--native",o)}},{key:"componentDidMount",value:function(){var e=this,t=function o(){window.cancelAnimationFrame?e._forceSyncId=requestAnimationFrame(o):e._forceSyncId=setTimeout(o,1e3/30),e._forceSync()};this._updateReferences(),t(),addEventListener("mousemove",this.onCursorApproachingTrack)}},{key:"componentDidUpdate",value:function(){this._updateReferences(),this._forceSync()}},{key:"componentWillUnmount",value:function(){window.cancelAnimationFrame?cancelAnimationFrame(this._forceSyncId):clearTimeout(this._forceSyncId),this._forceSyncId=0,removeEventListener("mousemove",this.onCursorApproachingTrack)}},{key:"render",value:function(){var e=this.props,t=e.axes,o=e.trackXChildren,r=e.trackYChildren,a=e.handleXChildren,n=e.handleYChildren,s=e.disabled,l=e.outset,i=e.className,u=e.children,h=e.style,f=["scroll-box"];return i&&(f=f.concat(i)),s&&f.push("scroll-box--disabled"),l&&f.push("scroll-box--outset"),t.indexOf(y.X)>-1&&f.push("scroll-box--has-axis-x"),t.indexOf(y.Y)>-1&&f.push("scroll-box--has-axis-y"),c["default"].createElement("div",{style:h,className:f.join(" "),onWheel:this.onWheel,onKeyDown:this.onKeyDown,onTouchStart:this.onTouchStart,onTouchMove:this.onTouchMove,onTouchEnd:this.onTouchEnd,onTouchCancel:this.onTouchEnd,tabIndex:"-1"},c["default"].Children.only(u),c["default"].createElement("div",{className:"scroll-box__track scroll-box__track--x",onMouseDown:this.onFastTrackX,ref:"trackX"},c["default"].createElement("div",{className:"scroll-box__handle scroll-box__handle--x",onMouseDown:this.onDragStartX,ref:"handleX"},a),o),c["default"].createElement("div",{className:"scroll-box__track scroll-box__track--y",onMouseDown:this.onFastTrackY,ref:"trackY"},c["default"].createElement("div",{className:"scroll-box__handle scroll-box__handle--y",onMouseDown:this.onDragStartY,ref:"handleY"},n),r))}}]),t}(c["default"].Component);b.defaultProps={className:"scroll-box--wrapped",axes:y.XY,hoverProximity:50,disabled:!1,outset:!1,scrollMinX:2,scrollMinY:2,defaultEasing:function(e,t,o,r,a){return r*Math.sqrt(1- --e*e)+o},captureHandleDrag:!0,onViewportScroll:function(e){},fastTrack:g.GOTO,fastTrackDuration:500,captureKeyboard:!0,keyboardStepX:30,keyboardStepY:30,keyboardScrollDuration:200,captureWheel:!0,wheelStepX:30,wheelStepY:30,propagateWheelScroll:!1,swapWheelAxes:!1,wheelScrollDuration:100,propagateTouchScroll:!1},b.propTypes={nativeScroll:p,className:x,axes:v([y.X,y.Y,y.XY]),hoverProximity:f,disabled:p,outset:p,scrollMinX:f,scrollMinY:f,defaultEasing:d,captureHandleDrag:p,onViewportScroll:d,fastTrack:v([g.GOTO,g.PAGING,g.OFF]),fastTrackDuration:f,captureKeyboard:p,keyboardStepX:f,keyboardStepY:f,keyboardScrollDuration:f,captureWheel:p,wheelStepX:f,wheelStepY:f,propagateWheelScroll:p,swapWheelAxes:p,wheelScrollDuration:f,propagateTouchScroll:p,trackXChildren:x,trackYChildren:x,handleXChildren:x,handleYChildren:x}},function(e,t){e.exports=require("react")},function(e,t,o){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function a(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.ScrollBox=void 0;var l=function(){function e(e,t){for(var o=0;o<t.length;o++){var r=t[o];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,o,r){return o&&e(t.prototype,o),r&&e(t,r),t}}(),i=o(2),c=r(i),u=o(1);t.ScrollBox=function(e){function t(){return a(this,t),n(this,Object.getPrototypeOf(t).apply(this,arguments))}return s(t,e),l(t,[{key:"render",value:function(){return c["default"].createElement(u.GenericScrollBox,this.props,c["default"].createElement("div",{className:"scroll-box__viewport"},this.props.children))}}]),t}(c["default"].Component)},function(e,t,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=o(3);Object.defineProperty(t,"ScrollBox",{enumerable:!0,get:function(){return r.ScrollBox}});var a=o(1);Object.defineProperty(t,"GenericScrollBox",{enumerable:!0,get:function(){return a.GenericScrollBox}}),Object.defineProperty(t,"FastTrack",{enumerable:!0,get:function(){return a.FastTrack}}),Object.defineProperty(t,"ScrollAxes",{enumerable:!0,get:function(){return a.ScrollAxes}})},function(e,t){},function(e,t){e.exports=require("react-dom")}]); | ||
| module.exports=function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={exports:{},id:n,loaded:!1};return e[n].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){r(15),e.exports=r(14)},function(e,t){"use strict";function r(){throw new Error("setTimeout has not been defined")}function n(){throw new Error("clearTimeout has not been defined")}function o(e){if(s===setTimeout)return setTimeout(e,0);if((s===r||!s)&&setTimeout)return s=setTimeout,setTimeout(e,0);try{return s(e,0)}catch(t){try{return s.call(null,e,0)}catch(t){return s.call(this,e,0)}}}function l(e){if(f===clearTimeout)return clearTimeout(e);if((f===n||!f)&&clearTimeout)return f=clearTimeout,clearTimeout(e);try{return f(e)}catch(t){try{return f.call(null,e)}catch(t){return f.call(this,e)}}}function a(){h&&d&&(h=!1,d.length?y=d.concat(y):v=-1,y.length&&i())}function i(){if(!h){var e=o(a);h=!0;for(var t=y.length;t;){for(d=y,y=[];++v<t;)d&&d[v].run();v=-1,t=y.length}d=null,h=!1,l(e)}}function c(e,t){this.fun=e,this.array=t}function u(){}var s,f,p=e.exports={};!function(){try{s="function"==typeof setTimeout?setTimeout:r}catch(e){s=r}try{f="function"==typeof clearTimeout?clearTimeout:n}catch(e){f=n}}();var d,y=[],h=!1,v=-1;p.nextTick=function(e){var t=new Array(arguments.length-1);if(arguments.length>1)for(var r=1;r<arguments.length;r++)t[r-1]=arguments[r];y.push(new c(e,t)),1!==y.length||h||o(i)},c.prototype.run=function(){this.fun.apply(null,this.array)},p.title="browser",p.browser=!0,p.env={},p.argv=[],p.version="",p.versions={},p.on=u,p.addListener=u,p.once=u,p.off=u,p.removeListener=u,p.removeAllListeners=u,p.emit=u,p.prependListener=u,p.prependOnceListener=u,p.listeners=function(e){return[]},p.binding=function(e){throw new Error("process.binding is not supported")},p.cwd=function(){return"/"},p.chdir=function(e){throw new Error("process.chdir is not supported")},p.umask=function(){return 0}},function(e,t){"use strict";function r(e){return function(){return e}}var n=function(){};n.thatReturns=r,n.thatReturnsFalse=r(!1),n.thatReturnsTrue=r(!0),n.thatReturnsNull=r(null),n.thatReturnsThis=function(){return this},n.thatReturnsArgument=function(e){return e},e.exports=n},function(e,t,r){(function(t){"use strict";function r(e,t,r,o,l,a,i,c){if(n(t),!e){var u;if(void 0===t)u=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var s=[r,o,l,a,i,c],f=0;u=new Error(t.replace(/%s/g,function(){return s[f++]})),u.name="Invariant Violation"}throw u.framesToPop=1,u}}var n=function(e){};"production"!==t.env.NODE_ENV&&(n=function(e){if(void 0===e)throw new Error("invariant requires an error message argument")}),e.exports=r}).call(t,r(1))},function(e,t){"use strict";var r="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED";e.exports=r},function(e,t,r){(function(t){"use strict";var n=r(2),o=n;if("production"!==t.env.NODE_ENV){var l=function(e){for(var t=arguments.length,r=Array(t>1?t-1:0),n=1;n<t;n++)r[n-1]=arguments[n];var o=0,l="Warning: "+e.replace(/%s/g,function(){return r[o++]});"undefined"!=typeof console&&console.error(l);try{throw new Error(l)}catch(a){}};o=function(e,t){if(void 0===t)throw new Error("`warning(condition, format, ...args)` requires a warning message argument");if(0!==t.indexOf("Failed Composite propType: ")&&!e){for(var r=arguments.length,n=Array(r>2?r-2:0),o=2;o<r;o++)n[o-2]=arguments[o];l.apply(void 0,[t].concat(n))}}}e.exports=o}).call(t,r(1))},function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){var r={};for(var n in e)t.indexOf(n)>=0||Object.prototype.hasOwnProperty.call(e,n)&&(r[n]=e[n]);return r}function l(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function c(e){return null!=e&&!isNaN(e)}function u(e,t,r,n,o){return e-=1,r+n*Math.sqrt(1-Math.pow(e,2))}Object.defineProperty(t,"__esModule",{value:!0}),t.GenericScrollBox=t.FastTrackModeShape=t.ScrollCause=t.FastTrackMode=void 0;var s=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e};t.easeQuadOut=u;var f=r(7),p=n(f),d=r(16),y=r(12),h=t.FastTrackMode={PAGING:"paging",GOTO:"goto"},v=t.ScrollCause={HANDLE_DRAG:0,MOUSE_WHEEL:1,FAST_TRACK:2,KEYBOARD:3,TOUCH:4},b=t.FastTrackModeShape=(0,y.oneOf)([h.GOTO,h.PAGING]),g=t.GenericScrollBox=function(e){function t(e){l(this,t);var r=a(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e)),n=0,i=0,u=0,f=0,y=0,b=0,g=0,m=0,S=void 0,T=void 0,O=0,x=0,w=!1,E=0,Y=0,D=0,X=0,k=!1,_=!1,P=void 0,A=!1,N=!1,B=null,j=null,R=0,H=0,M=void 0,L=void 0,C=void 0,W=void 0,G=void 0,I=void 0;r.render=function(){var e=r.props,t=e.className,n=e.style,o=e.disabled,l=e.outsetScrollBarX,a=e.outsetScrollBarY,i=e.clientScrollBars,c=e.disableScrollX,u=e.disableScrollY,s=e.hideScrollBarX,f=e.hideScrollBarY,d=e.children,y=e.trackChildrenX,h=e.trackChildrenY,v=e.handleChildrenX,b=e.handleChildrenY,g=["scroll-box"];return t&&(g=g.concat(t)),o&&g.push("scroll-box--disabled"),l&&g.push("scroll-box--outset-x"),a&&g.push("scroll-box--outset-y"),c||s||g.push("scroll-box--enable-x"),u||f||g.push("scroll-box--enable-y"),i&&g.push("scroll-box--client-scroll-bars"),p["default"].createElement("div",{style:n,className:g.join(" "),onWheel:z,onKeyDown:K,onTouchStart:te,tabIndex:"-1"},d,p["default"].createElement("div",{className:"scroll-box__track scroll-box__track--x",onMouseDown:U,ref:"trackX"},p["default"].createElement("div",{className:"scroll-box__handle scroll-box__handle--x",onMouseDown:$,ref:"handleX"},v),y),p["default"].createElement("div",{className:"scroll-box__track scroll-box__track--y",onMouseDown:V,ref:"trackY"},p["default"].createElement("div",{className:"scroll-box__handle scroll-box__handle--y",onMouseDown:Q,ref:"handleY"},b),h))},r.componentDidMount=function(){M=(0,d.findDOMNode)(r);var e=r.refs,t=e.handleX,n=e.handleY,o=e.trackX,l=e.trackY;C=(0,d.findDOMNode)(t),W=(0,d.findDOMNode)(n),G=(0,d.findDOMNode)(o),I=(0,d.findDOMNode)(l),L=M.firstElementChild;var a=function i(){P=window.cancelAnimationFrame?requestAnimationFrame(i):setTimeout(i,1e3/30),F()};a(),addEventListener("mousemove",ee)},r.componentWillUnmount=function(){M=null,window.cancelAnimationFrame?cancelAnimationFrame(P):clearTimeout(P),removeEventListener("mousemove",ee)},r.componentDidUpdate=function(){L=M.firstElementChild,F()},r.scrollTo=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.x,o=e.y,l=e.easing,a=e.easingX,s=void 0===a?l||r.props.easingX:a,p=e.easingY,d=void 0===p?l||r.props.easingY:p,h=e.duration,v=void 0===h?0:h,E=e.durationX,Y=void 0===E?v:E,D=e.durationY,X=void 0===D?v:D,k=e.dispatchPrevented,_=void 0!==k&&k;c(t)&&(u=n,y=0|t,S=s,g=Y,O=Date.now(),w=_,R++),c(o)&&(f=i,b=0|o,T=d,m=X,x=Date.now(),w=_,H++),F()},r.scrollToX=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollTo(s({},t,{x:e}))},r.scrollToY=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollTo(s({},t,{y:e}))},r.scrollBy=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.dx,n=e.dy,l=o(e,["dx","dy"]);r.scrollTo(s({},l,{x:y+t,y:b+n}))},r.scrollByX=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollBy(s({},t,{dx:e}))},r.scrollByY=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollBy(s({},t,{dy:e}))},r.scrollToPage=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.x,n=e.y,l=o(e,["x","y"]);t*=r.getPageWidth(),n*=r.getPageHeight(),r.scrollTo(s({},l,{x:t,y:n}))},r.scrollToPageX=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollToPage(s({},t,{x:e}))},r.scrollToPageY=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollToPage(s({},t,{y:e}))},r.scrollByPage=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.dx,n=e.dy,l=o(e,["dx","dy"]);t*=r.getPageWidth(),n*=r.getPageHeight(),r.scrollBy(s({},l,{dx:t,dy:n}))},r.scrollByPageX=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollByPage(s({},t,{dx:e}))},r.scrollByPageY=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return r.scrollByPage(s({},t,{dy:e}))},r.getPageWidth=function(){return L.clientWidth},r.getPageHeight=function(){return L.clientHeight},Object.defineProperties(r,{targetX:{get:function(){return y},set:function(e){return r.scrollToX(e)}},targetY:{get:function(){return b},set:function(e){return r.scrollToY(e)}},scrollX:{get:function(){return n},set:function(e){return r.scrollToX(e)}},scrollY:{get:function(){return i},set:function(e){return r.scrollToY(e)}},scrollMaxX:{get:function(){return E}},scrollMaxY:{get:function(){return Y}}});var F=function(){var e=r.props,t=e.disableScrollX,o=e.disableScrollY,l=e.scrollMinX,a=e.scrollMinY,c=e.clientScrollBars,s=e.outsetScrollBarX,p=e.outsetScrollBarY,d=e.onScroll,h=e.onScrollX,P=e.onScrollY,F=e.onScrollStart,K=e.onScrollStartX,q=e.onScrollStartY,U=e.onScrollEnd,V=e.onScrollEndX,J=e.onScrollEndY,$=L,Q=$.clientWidth,z=$.clientHeight,Z=$.offsetWidth,ee=$.offsetHeight,te=$.scrollWidth,re=$.scrollHeight,ne=$.scrollTop,oe=$.scrollLeft;E=te-Q,Y=re-z,k=!t&&E>=l,_=!o&&Y>=a,M.classList.toggle("scroll-box--requires-x",k),M.classList.toggle("scroll-box--requires-y",_),c&&s?L.style.height="calc(100% + "+(ee-z)+"px)":L.style.height="100%",c&&p?L.style.width="calc(100% + "+(Z-Q)+"px)":L.style.width="100%",y=Math.max(0,Math.min(y,E)),b=Math.max(0,Math.min(b,Y));var le=n,ae=i;if(n==oe&&i==ne){if(le!=y){var ie=Date.now()-O;le=ie<g?u+S(ie/g,ie,0,1,g)*(y-u)|0:y}if(ae!=b){var ce=Date.now()-x;ae=ce<m?f+T(ce/m,ce,0,1,m)*(b-f)|0:b}}var ue=n!=oe,se=i!=ne;ue&&(y=le=oe),se&&(b=ae=ne);var fe=le!=y,pe=ae!=b,de=n-le,ye=i-ae,he=R,ve=H;w||(fe|pe|ue|se&&!A&&!N&&F(r,B,j),he==R&&fe&&!A&&K(r,B),ve==H&&pe&&!N&&q(r,j),he==R&&ve==H&&de|ye&&d(r,de,ye,B,j),he==R&&de&&h(r,de,B),ve==H&&ye&&P(r,ye,j),he==R&&ve==H&&!fe&&!pe&&A|N|ue|se&&U(r,B,j),he==R&&!fe&&A&&V(r,B),ve==H&&!pe&&N&&J(r,j),he==R&&B!=v.TOUCH|B!=v.HANDLE_DRAG&&(B=null),ve==H&&j!=v.TOUCH|j!=v.HANDLE_DRAG&&(j=null)),de&&he==R&&(L.scrollLeft=n=le),ye&&ve==H&&(L.scrollTop=i=ae),c||(D=G.clientWidth-C.offsetWidth,C.style.width=Q/te*100+"%",C.style.left=D*le/E+"px",X=I.clientHeight-W.offsetHeight,W.style.height=z/re*100+"%",W.style.top=X*ae/Y+"px")},K=function(e){var t=e.target.tagName,n=e.keyCode,o=e.shiftKey,l=r.props,a=l.disabled,i=l.captureKeyboard,c=l.keyboardStepX,u=l.keyboardStepY,s=l.keyboardScrollDuration;if(!(a|!i|"TEXTAREA"==t|"INPUT"==t)){var f={duration:s};switch(n){case 36:e.preventDefault(),j=v.KEYBOARD,r.scrollToY(0,f);break;case 35:e.preventDefault(),j=v.KEYBOARD,r.scrollToY(Y,f);break;case 33:case 34:e.preventDefault();var p=r.getPageHeight(),d=r.getPageWidth();33==n&&(p*=-1,d*=-1),o?(B=v.KEYBOARD,r.scrollByX(d,f)):(j=v.KEYBOARD,r.scrollByY(p,f));break;case 38:e.preventDefault(),j=v.KEYBOARD,r.scrollByY(-u,f);break;case 40:e.preventDefault(),j=v.KEYBOARD,r.scrollByY(u,f);break;case 37:e.preventDefault(),B=v.KEYBOARD,r.scrollByX(-c,f);break;case 39:e.preventDefault(),B=v.KEYBOARD,r.scrollByX(c,f)}}},q=function(e,t){var n=r.props,o=n.disabled,l=n.captureFastTrackX,a=n.captureFastTrackY,i=n.fastTrackModeX,c=n.fastTrackModeY,u=n.fastTrackScrollDurationX,s=n.fastTrackScrollDurationY;if(!(o|!l&&!a|e.button)){var f=L,p=f.clientWidth,d=f.clientHeight,g=f.scrollWidth,m=f.scrollHeight;if(t){if(!l)return;B=v.FAST_TRACK;var S=e.clientX-G.getBoundingClientRect().left,T={duration:u};switch(i){case h.PAGING:r.scrollToX(y+(1-2*(S<C.offsetLeft))*r.getPageWidth(),T);break;case h.GOTO:r.scrollToX(S/G.clientWidth*g-p/2,T)}}else{if(!a)return;j=v.FAST_TRACK;var O=e.clientY-I.getBoundingClientRect().top,x={duration:s};switch(c){case h.PAGING:r.scrollToY(b+(1-2*(O<W.offsetTop))*r.getPageHeight(),x);break;case h.GOTO:r.scrollToY(O/I.clientHeight*m-d/2,x)}}}},U=function(e){return q(e,!0)},V=function(e){return q(e,!1)},J=function(e,t){var n=r.props,o=n.disabled,l=n.captureHandleDragX,a=n.captureHandleDragY,i=n.permitHandleDragInterruption;if(!(o|!l&&!a|e.button)){e.preventDefault(),e.stopPropagation();var c=void 0;t?(B=v.HANDLE_DRAG,c=G):(j=v.HANDLE_DRAG,c=I);var u=e.clientX-C.offsetLeft,s=e.clientY-W.offsetTop,f=function(e){return!M|e.button|i&&(t?B:j)!=v.HANDLE_DRAG?void d():void(t?(B=v.HANDLE_DRAG,r.scrollToX(E*(e.clientX-u)/D)):(j=v.HANDLE_DRAG,r.scrollToY(Y*(e.clientY-s)/X)))},p=function(){t?B=null:j=null,d()},d=function(){removeEventListener("mousemove",f),removeEventListener("mouseup",p),c.classList.remove("scroll-box__track--dragged")};addEventListener("mousemove",f),addEventListener("mouseup",p),c.classList.add("scroll-box__track--dragged")}},$=function(e){return J(e,!0)},Q=function(e){return J(e,!1)},z=function(e){var t=e.target,o=e.deltaMode,l=e.deltaX,a=e.deltaY,c=e.shiftKey,u=r.props,s=u.wheelStepX,f=u.wheelStepY,p=u.disabled,d=u.clientScrollBars,h=u.captureWheel,g=u.lineHeight,m=u.propagateWheelScrollX,S=u.propagateWheelScrollY,T=u.swapWheelAxes,x=u.wheelScrollDurationX,w=u.wheelScrollDurationY;if(d&&!h&&e.preventDefault(),!(p|e.isDefaultPrevented()||t!=L&&"TEXTAREA"==t.tagName)){if(c&&0==l&&(l=a,a=0),T){var D=l;l=a,a=D}var X=l*k,P=a*_;if(l&&!k|X<0&&!y|X>0&&y==E)return void(m||e.preventDefault());if(a&&!_|P<0&&!b|P>0&&b==Y)return void(S||e.preventDefault());switch(e.preventDefault(),o){case 1:X*=g,P*=g;break;case 2:X*=r.getPageWidth(),P*=r.getPageHeight()}X*=s/100,P*=f/100;var A=y+X,N=b+P;Date.now()-O>x&&(A=n+X),Date.now()-O>w&&(N=i+P),X&&(B=v.MOUSE_WHEEL,r.scrollToX(A,{duration:x})),P&&(j=v.MOUSE_WHEEL,r.scrollToY(N,{duration:w}))}},Z=function(e,t,r,n){if(null==n){var o=e.clientX,l=e.clientY,a=t.getBoundingClientRect(),i=a.width,c=a.left,u=a.top,s=a.height;n=r>l-s-u&&r>o-i-c&&r>c-o&&r>u-l}t.classList.toggle("scroll-box__track--hover",n)},ee=function(e){var t=r.props,n=t.disabled,o=t.clientScrollBars,l=t.captureHandleDragX,a=t.captureHandleDragY,i=t.captureFastTrackX,c=t.captureFastTrackY,u=t.trackHoverProximityX,s=t.trackHoverProximityY;if(!("orientation"in window|o|n)){if(e.buttons){if(B!=v.HANDLE_DRAG)var f=!1;if(j!=v.HANDLE_DRAG)var p=!1}k&&l|i&&Z(e,G,u,f),_&&a|c&&Z(e,I,s,p)}},te=function(e){var t=e.target,o=e.touches,l=r.props,a=l.disabled,c=l.clientScrollBars,u=l.captureTouch;l.propagateTouchScrollX,l.propagateTouchScrollY;if(c&&!u&&e.preventDefault(),!(c|a|o.length>1|e.isDefaultPrevented()||t!=L&&"TEXTAREA"==t.tagName)){var s=o[0],f=s.clientX,p=s.clientY,d=!1,y=function(e){var t=r.targetX,o=r.targetY,l=r.scrollMaxX,a=r.scrollMaxY,c=e.touches[0],u=c.clientX,s=c.clientY,y=f-u,h=p-s;return y<0&&!t||y>0&&t==l||h<0&&!o||h>0&&o==a?void(d||v()):(d=!0,e.preventDefault(),void r.scrollTo({x:n+y,y:i+h}))},h=function(e){v()},v=function(){removeEventListener("touchmove",y),removeEventListener("touchend",h),removeEventListener("touchcancel",h)};addEventListener("touchmove",y),addEventListener("touchend",h),addEventListener("touchcancel",h)}};return r}return i(t,e),t}(p["default"].Component);g.propTypes={children:y.element.isRequired,clientScrollBars:y.bool,className:y.any,style:y.object,disabled:y.bool,onScroll:y.func,onScrollX:y.func,onScrollY:y.func,onScrollStart:y.func,onScrollStartX:y.func,onScrollStartY:y.func,onScrollEnd:y.func,onScrollEndX:y.func,onScrollEndY:y.func,disableScrollX:y.bool,disableScrollY:y.bool,hideScrollBarX:y.bool,hideScrollBarY:y.bool,outsetScrollBarX:y.bool,outsetScrollBarY:y.bool,scrollMinX:y.number,scrollMinY:y.number,trackHoverProximityX:y.number,trackHoverProximityY:y.number,easingX:y.func,easingY:y.func,captureHandleDragX:y.bool,captureHandleDragY:y.bool,permitHandleDragInterruption:y.bool,captureFastTrackX:y.bool,captureFastTrackY:y.bool,fastTrackModeX:b,fastTrackModeY:b,fastTrackScrollDurationX:y.number,fastTrackScrollDurationY:y.number,captureKeyboard:y.bool,keyboardStepX:y.number,keyboardStepY:y.number,keyboardScrollDurationX:y.number,keyboardScrollDurationY:y.number,captureWheel:y.bool,lineHeight:y.number,wheelStepX:y.number,wheelStepY:y.number,propagateWheelScrollX:y.bool,propagateWheelScrollY:y.bool,swapWheelAxes:y.bool,wheelScrollDurationX:y.number,wheelScrollDurationY:y.number,captureTouch:y.bool,propagateTouchScrollX:y.bool,propagateTouchScrollY:y.bool,trackChildrenX:y.node,trackChildrenY:y.node,handleChildrenX:y.node,handleChildrenY:y.node},g.defaultProps={clientScrollBars:!1,className:"scroll-box--wrapped",disabled:!1,onScroll:function(e,t,r,n,o){},onScrollX:function(e,t,r){},onScrollY:function(e,t,r){},onScrollStart:function(e,t,r){},onScrollStartX:function(e,t){},onScrollStartY:function(e,t){},onScrollEnd:function(e,t,r){},onScrollEndX:function(e,t){},onScrollEndY:function(e,t){},disableScrollX:!1,disableScrollY:!1,hideScrollBarX:!1,hideScrollBarY:!1,outsetScrollBarX:!1,outsetScrollBarY:!1,scrollMinX:2,scrollMinY:2,trackHoverProximityX:50,trackHoverProximityY:50,easingX:u,easingY:u,captureHandleDragX:!0,captureHandleDragY:!0,permitHandleDragInterruption:!0,captureFastTrackX:!0,captureFastTrackY:!0,fastTrackModeX:h.GOTO,fastTrackModeY:h.GOTO,fastTrackScrollDurationX:500,fastTrackScrollDurationY:500,captureKeyboard:!0,keyboardStepX:30,keyboardStepY:30,keyboardScrollDuration:200,captureWheel:!0,lineHeight:24,wheelStepX:100,wheelStepY:100,propagateWheelScrollX:!0,propagateWheelScrollY:!0,swapWheelAxes:!1,wheelScrollDurationX:100,wheelScrollDurationY:100,captureTouch:!0,propagateTouchScrollX:!0,propagateTouchScrollY:!0}},function(e,t){e.exports=require("react")},function(e,t){/* | ||
| object-assign | ||
| (c) Sindre Sorhus | ||
| @license MIT | ||
| */ | ||
| "use strict";function r(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}function n(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},r=0;r<10;r++)t["_"+String.fromCharCode(r)]=r;var n=Object.getOwnPropertyNames(t).map(function(e){return t[e]});if("0123456789"!==n.join(""))return!1;var o={};return"abcdefghijklmnopqrst".split("").forEach(function(e){o[e]=e}),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},o)).join("")}catch(l){return!1}}var o=Object.getOwnPropertySymbols,l=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;e.exports=n()?Object.assign:function(e,t){for(var n,i,c=r(e),u=1;u<arguments.length;u++){n=Object(arguments[u]);for(var s in n)l.call(n,s)&&(c[s]=n[s]);if(o){i=o(n);for(var f=0;f<i.length;f++)a.call(n,i[f])&&(c[i[f]]=n[i[f]])}}return c}},function(e,t,r){(function(t){"use strict";function n(e,r,n,u,s){if("production"!==t.env.NODE_ENV)for(var f in e)if(e.hasOwnProperty(f)){var p;try{l("function"==typeof e[f],"%s: %s type `%s` is invalid; it must be a function, usually from the `prop-types` package, but received `%s`.",u||"React class",n,f,o(e[f])),p=e[f](r,f,u,n,null,i)}catch(d){p=d}if(a(!p||p instanceof Error,"%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).",u||"React class",n,f,"undefined"==typeof p?"undefined":o(p)),p instanceof Error&&!(p.message in c)){c[p.message]=!0;var y=s?s():"";a(!1,"Failed %s type: %s%s",n,p.message,null!=y?y:"")}}}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};if("production"!==t.env.NODE_ENV)var l=r(3),a=r(5),i=r(4),c={};e.exports=n}).call(t,r(1))},function(e,t,r){"use strict";var n=r(2),o=r(3),l=r(4);e.exports=function(){function e(e,t,r,n,a,i){i!==l&&o(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types")}function t(){return e}e.isRequired=e;var r={array:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t};return r.checkPropTypes=n,r.PropTypes=r,r}},function(e,t,r){(function(t){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o=r(2),l=r(3),a=r(5),i=r(8),c=r(4),u=r(9);e.exports=function(e,r){function s(e){var t=e&&(P&&e[P]||e[A]);if("function"==typeof t)return t}function f(e,t){return e===t?0!==e||1/e===1/t:e!==e&&t!==t}function p(e){this.message=e,this.stack=""}function d(e){function n(n,u,s,f,d,y,h){if(f=f||N,y=y||s,h!==c)if(r)l(!1,"Calling PropTypes validators directly is not supported by the `prop-types` package. Use `PropTypes.checkPropTypes()` to call them. Read more at http://fb.me/use-check-prop-types");else if("production"!==t.env.NODE_ENV&&"undefined"!=typeof console){var v=f+":"+s;!o[v]&&i<3&&(a(!1,"You are manually calling a React.PropTypes validation function for the `%s` prop on `%s`. This is deprecated and will throw in the standalone `prop-types` package. You may be seeing this warning due to a third-party PropTypes library. See https://fb.me/react-warning-dont-call-proptypes for details.",y,f),o[v]=!0,i++)}return null==u[s]?n?new p(null===u[s]?"The "+d+" `"+y+"` is marked as required "+("in `"+f+"`, but its value is `null`."):"The "+d+" `"+y+"` is marked as required in "+("`"+f+"`, but its value is `undefined`.")):null:e(u,s,f,d,y)}if("production"!==t.env.NODE_ENV)var o={},i=0;var u=n.bind(null,!1);return u.isRequired=n.bind(null,!0),u}function y(e){function t(t,r,n,o,l,a){var i=t[r],c=D(i);if(c!==e){var u=X(i);return new p("Invalid "+o+" `"+l+"` of type "+("`"+u+"` supplied to `"+n+"`, expected ")+("`"+e+"`."))}return null}return d(t)}function h(){return d(o.thatReturnsNull)}function v(e){function t(t,r,n,o,l){if("function"!=typeof e)return new p("Property `"+l+"` of component `"+n+"` has invalid PropType notation inside arrayOf.");var a=t[r];if(!Array.isArray(a)){var i=D(a);return new p("Invalid "+o+" `"+l+"` of type "+("`"+i+"` supplied to `"+n+"`, expected an array."))}for(var u=0;u<a.length;u++){var s=e(a,u,n,o,l+"["+u+"]",c);if(s instanceof Error)return s}return null}return d(t)}function b(){function t(t,r,n,o,l){var a=t[r];if(!e(a)){var i=D(a);return new p("Invalid "+o+" `"+l+"` of type "+("`"+i+"` supplied to `"+n+"`, expected a single ReactElement."))}return null}return d(t)}function g(e){function t(t,r,n,o,l){if(!(t[r]instanceof e)){var a=e.name||N,i=_(t[r]);return new p("Invalid "+o+" `"+l+"` of type "+("`"+i+"` supplied to `"+n+"`, expected ")+("instance of `"+a+"`."))}return null}return d(t)}function m(e){function r(t,r,n,o,l){for(var a=t[r],i=0;i<e.length;i++)if(f(a,e[i]))return null;var c=JSON.stringify(e);return new p("Invalid "+o+" `"+l+"` of value `"+a+"` "+("supplied to `"+n+"`, expected one of "+c+"."))}return Array.isArray(e)?d(r):("production"!==t.env.NODE_ENV?a(!1,"Invalid argument supplied to oneOf, expected an instance of array."):void 0,o.thatReturnsNull)}function S(e){function t(t,r,n,o,l){if("function"!=typeof e)return new p("Property `"+l+"` of component `"+n+"` has invalid PropType notation inside objectOf.");var a=t[r],i=D(a);if("object"!==i)return new p("Invalid "+o+" `"+l+"` of type "+("`"+i+"` supplied to `"+n+"`, expected an object."));for(var u in a)if(a.hasOwnProperty(u)){var s=e(a,u,n,o,l+"."+u,c);if(s instanceof Error)return s}return null}return d(t)}function T(e){function r(t,r,n,o,l){for(var a=0;a<e.length;a++){var i=e[a];if(null==i(t,r,n,o,l,c))return null}return new p("Invalid "+o+" `"+l+"` supplied to "+("`"+n+"`."))}if(!Array.isArray(e))return"production"!==t.env.NODE_ENV?a(!1,"Invalid argument supplied to oneOfType, expected an instance of array."):void 0,o.thatReturnsNull;for(var n=0;n<e.length;n++){var l=e[n];if("function"!=typeof l)return a(!1,"Invalid argument supplied to oneOfType. Expected an array of check functions, but received %s at index %s.",k(l),n),o.thatReturnsNull}return d(r)}function O(){function e(e,t,r,n,o){return E(e[t])?null:new p("Invalid "+n+" `"+o+"` supplied to "+("`"+r+"`, expected a ReactNode."))}return d(e)}function x(e){function t(t,r,n,o,l){var a=t[r],i=D(a);if("object"!==i)return new p("Invalid "+o+" `"+l+"` of type `"+i+"` "+("supplied to `"+n+"`, expected `object`."));for(var u in e){var s=e[u];if(s){var f=s(a,u,n,o,l+"."+u,c);if(f)return f}}return null}return d(t)}function w(e){function t(t,r,n,o,l){var a=t[r],u=D(a);if("object"!==u)return new p("Invalid "+o+" `"+l+"` of type `"+u+"` "+("supplied to `"+n+"`, expected `object`."));var s=i({},t[r],e);for(var f in s){var d=e[f];if(!d)return new p("Invalid "+o+" `"+l+"` key `"+f+"` supplied to `"+n+"`.\nBad object: "+JSON.stringify(t[r],null," ")+"\nValid keys: "+JSON.stringify(Object.keys(e),null," "));var y=d(a,f,n,o,l+"."+f,c);if(y)return y}return null}return d(t)}function E(t){switch("undefined"==typeof t?"undefined":n(t)){case"number":case"string":case"undefined":return!0;case"boolean":return!t;case"object":if(Array.isArray(t))return t.every(E);if(null===t||e(t))return!0;var r=s(t);if(!r)return!1;var o,l=r.call(t);if(r!==t.entries){for(;!(o=l.next()).done;)if(!E(o.value))return!1}else for(;!(o=l.next()).done;){var a=o.value;if(a&&!E(a[1]))return!1}return!0;default:return!1}}function Y(e,t){return"symbol"===e||("Symbol"===t["@@toStringTag"]||"function"==typeof Symbol&&t instanceof Symbol)}function D(e){var t="undefined"==typeof e?"undefined":n(e);return Array.isArray(e)?"array":e instanceof RegExp?"object":Y(t,e)?"symbol":t}function X(e){if("undefined"==typeof e||null===e)return""+e;var t=D(e);if("object"===t){if(e instanceof Date)return"date";if(e instanceof RegExp)return"regexp"}return t}function k(e){var t=X(e);switch(t){case"array":case"object":return"an "+t;case"boolean":case"date":case"regexp":return"a "+t;default:return t}}function _(e){return e.constructor&&e.constructor.name?e.constructor.name:N}var P="function"==typeof Symbol&&Symbol.iterator,A="@@iterator",N="<<anonymous>>",B={array:y("array"),bool:y("boolean"),func:y("function"),number:y("number"),object:y("object"),string:y("string"),symbol:y("symbol"),any:h(),arrayOf:v,element:b(),instanceOf:g,node:O(),objectOf:S,oneOf:m,oneOfType:T,shape:x,exact:w};return p.prototype=Error.prototype,B.checkPropTypes=u,B.PropTypes=B,B}}).call(t,r(1))},function(e,t,r){(function(t){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};if("production"!==t.env.NODE_ENV){var o="function"==typeof Symbol&&Symbol["for"]&&Symbol["for"]("react.element")||60103,l=function(e){return"object"===("undefined"==typeof e?"undefined":n(e))&&null!==e&&e.$$typeof===o},a=!0;e.exports=r(11)(l,a)}else e.exports=r(10)()}).call(t,r(1))},function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function l(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.ScrollBox=void 0;var i=function(){function e(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,r,n){return r&&e(t.prototype,r),n&&e(t,n),t}}(),c=r(7),u=n(c),s=r(6);t.ScrollBox=function(e){function t(){return o(this,t),l(this,(t.__proto__||Object.getPrototypeOf(t)).apply(this,arguments))}return a(t,e),i(t,[{key:"render",value:function(){return u["default"].createElement(s.GenericScrollBox,this.props,u["default"].createElement("div",{className:"scroll-box__viewport"},this.props.children))}}]),t}(u["default"].Component)},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(13);Object.defineProperty(t,"ScrollBox",{enumerable:!0,get:function(){return n.ScrollBox}});var o=r(6);Object.defineProperty(t,"GenericScrollBox",{enumerable:!0,get:function(){return o.GenericScrollBox}}),Object.defineProperty(t,"FastTrackMode",{enumerable:!0,get:function(){return o.FastTrackMode}}),Object.defineProperty(t,"ScrollCause",{enumerable:!0,get:function(){return o.ScrollCause}})},function(e,t){},function(e,t){e.exports=require("react-dom")}]); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
386792
560.28%17
70%1963
226.62%241
0.84%3
50%1
Infinity%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added