UNPKG

@evg-b/evg-ui

Version:

EVG-UI library inspired by Material Design.

464 lines (411 loc) 13.8 kB
import _defineProperty from '@babel/runtime/helpers/defineProperty'; import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties'; import React, { useRef, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import withStyles from '../styles/withStyles.js'; import '@babel/runtime/helpers/construct'; import '@babel/runtime/helpers/toConsumableArray'; import '@babel/runtime/helpers/classCallCheck'; import '@babel/runtime/helpers/createClass'; import TouchDriver from '../TouchDriver/TouchDriver.js'; var styles = { base: { '--evg-scroller-size-y': 0, '--evg-scroller-size-x': 0, '--evg-scroller-y': 0, '--evg-scroller-x': 0, position: 'relative' }, wrapper: { overflow: 'scroll', maxHeight: 'inherit', height: 'inherit', minHeight: 'inherit', maxWidth: 'inherit', width: 'inherit', minWidth: 'inherit', '-ms-overflow-style': 'none', /* IE and Edge */ scrollbarWidth: 'none', /* Firefox */ '&::-webkit-scrollbar': { /* chrome */ display: 'none' } }, scrollVisible: { opacity: '1!important' }, autoHide: { opacity: 0, transition: function transition(props) { return "opacity ".concat(props.autoHideDuration, "ms linear"); } }, track: { zIndex: 1, cursor: 'pointer', position: 'absolute', backgroundColor: function backgroundColor(props) { return props.Color.Base('rgba', 0.1); }, borderRadius: '5px 5px', '&:after': { content: '""', position: 'absolute', backgroundColor: function backgroundColor(props) { return props.Color.Base('rgba', 0.6); }, borderRadius: '5px 5px' }, '&:hover': { opacity: 1 } }, trackY: { top: 0, right: 0, width: function width(props) { return "".concat(props.trackSize, "px"); }, height: '100%', '&:after': { transform: 'translateY(var(--evg-scroller-y))', right: '0px', width: function width(props) { return "".concat(props.trackSize, "px"); }, height: 'var(--evg-scroller-size-y)', willChange: 'transform' } }, trackX: { left: 0, bottom: 0, width: '100%', height: function height(props) { return "".concat(props.trackSize, "px"); }, '&:after': { transform: 'translateX(var(--evg-scroller-x))', bottom: '0px', height: function height(props) { return "".concat(props.trackSize, "px"); }, width: 'var(--evg-scroller-size-x)', willChange: 'transform' } } }; /** * Кроссбраузерный скроллбар. */ var Scroll = /*#__PURE__*/React.forwardRef(function Scroll(props, ref) { var _classNames, _classNames2; var classes = props.classes, className = props.className, children = props.children, _props$component = props.component, Component = _props$component === void 0 ? 'div' : _props$component; props.color; var vertical = props.vertical, horizontal = props.horizontal, autoHide = props.autoHide; props.autoHideDuration; var autoHideTimeout = props.autoHideTimeout; props.trackSize; var onScroll = props.onScroll, onScrollStart = props.onScrollStart, onScrollStop = props.onScrollStop, style = props.style; _objectWithoutProperties(props, ["classes", "className", "children", "component", "color", "vertical", "horizontal", "autoHide", "autoHideDuration", "autoHideTimeout", "trackSize", "onScroll", "onScrollStart", "onScrollStop", "style"]); var ScrollBase_ref = useRef(); ScrollBase_ref = ref || ScrollBase_ref; var ScrollSpace_ref = useRef(); var ScrollWrapper_ref = useRef(); var observer_ref = useRef(); var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), satisfactoryHeight = _useState2[0], setSatisfactoryHeight = _useState2[1]; var _useState3 = useState(false), _useState4 = _slicedToArray(_useState3, 2), satisfactoryWidth = _useState4[0], setSatisfactoryWidth = _useState4[1]; var _useState5 = useState(false), _useState6 = _slicedToArray(_useState5, 2), scrollVisible = _useState6[0], setScrollVisible = _useState6[1]; var touchTrack = useRef(false); var prevNow = useRef({ x: 0, y: 0 }); var lastMove = useRef(false); var setEvgVar = function setEvgVar(key, val) { // установка css var var S_B_S = ScrollBase_ref.current; S_B_S.style.setProperty(key, val); }; var getSpace = function getSpace() { // const { offsetWidth, offsetHeight } = ScrollBase_ref.current var _ScrollWrapper_ref$cu = ScrollWrapper_ref.current, offsetWidth = _ScrollWrapper_ref$cu.offsetWidth, offsetHeight = _ScrollWrapper_ref$cu.offsetHeight; var _ScrollSpace_ref$curr = ScrollSpace_ref.current, scrollWidth = _ScrollSpace_ref$curr.scrollWidth, scrollHeight = _ScrollSpace_ref$curr.scrollHeight; return { offset: { x: offsetWidth, y: offsetHeight }, scroll: { x: scrollWidth, y: scrollHeight } }; }; var calcScrollerSize = function calcScrollerSize() { var _getSpace = getSpace(), offset = _getSpace.offset, scroll = _getSpace.scroll; return { x: offset.x / scroll.x * offset.x | 0, y: offset.y / scroll.y * offset.y | 0 }; }; function satisfactorySize(e) { var _getSpace2 = getSpace(), offset = _getSpace2.offset, scroll = _getSpace2.scroll; if (offset.y < scroll.y) { setSatisfactoryHeight(true); } else { setSatisfactoryHeight(false); } if (offset.x < scroll.x) { setSatisfactoryWidth(true); } else { setSatisfactoryWidth(false); } setEvgVar('--evg-scroller-size-y', "".concat(calcScrollerSize().y, "px")); setEvgVar('--evg-scroller-size-x', "".concat(calcScrollerSize().x, "px")); } var calcPosition = function calcPosition() { var newPositionScroller = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var mod = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'y'; var _getSpace3 = getSpace(), offset = _getSpace3.offset, scroll = _getSpace3.scroll; var barSize = mod === 'y' ? calcScrollerSize().y : calcScrollerSize().x; var workSpace = mod === 'y' ? offset.y : offset.x; var allSpace = mod === 'y' ? scroll.y : scroll.x; var ratioShift = allSpace / workSpace; var startScroll = 0; var endScroll = workSpace - barSize; var scrollToY = ScrollWrapper_ref.current.scrollTop; var scrollToX = ScrollWrapper_ref.current.scrollLeft; if (newPositionScroller >= 0 && newPositionScroller < endScroll) { mod === 'y' ? scrollToY = ratioShift * newPositionScroller : scrollToX = ratioShift * newPositionScroller; setEvgVar("--evg-scroller-".concat(mod), "".concat(newPositionScroller, "px")); } else { if (Math.sign(newPositionScroller) === -1) { mod === 'y' ? scrollToY = startScroll : scrollToX = startScroll; setEvgVar("--evg-scroller-".concat(mod), "".concat(startScroll, "px")); } else { mod === 'y' ? scrollToY = ratioShift * endScroll : scrollToX = ratioShift * endScroll; setEvgVar("--evg-scroller-".concat(mod), "".concat(endScroll, "px")); } } ScrollWrapper_ref.current.scrollTo(scrollToX, scrollToY); }; var createAutoHideTimer = function createAutoHideTimer() { lastMove.current = setTimeout(function () { onScrollStop && onScrollStop(true); setScrollVisible(false); lastMove.current = false; }, autoHideTimeout); }; var moveScroll = function moveScroll(e) { if (!touchTrack.current) { var _getSpace4 = getSpace(), offset = _getSpace4.offset, scroll = _getSpace4.scroll; var scrollPercentageY = Number((e.target.scrollTop / scroll.y).toFixed(2)); var scrollPercentageX = Number((e.target.scrollLeft / scroll.x).toFixed(2)); var positionY = scrollPercentageY * offset.y; var positionX = scrollPercentageX * offset.x; prevNow.current.y = positionY; prevNow.current.x = positionX; setEvgVar('--evg-scroller-y', "".concat(positionY, "px")); setEvgVar('--evg-scroller-x', "".concat(positionX, "px")); } if (lastMove.current) { clearTimeout(lastMove.current); } else { onScrollStart && onScrollStart(true); setScrollVisible(true); } if (touchTrack.current) { if (!lastMove.current) { lastMove.current = true; } } onScroll && onScroll(e); if (!touchTrack.current && autoHide) { createAutoHideTimer(); } }; var onMoveStart = function onMoveStart(e, mod) { var nowY = e.nowY, nowX = e.nowX; touchTrack.current = true; var barSize = mod === 'y' ? calcScrollerSize().y : calcScrollerSize().x; var Now = mod === 'y' ? nowY : nowX; if (Now < prevNow.current[mod] || Now > prevNow.current[mod] + barSize) { var correction = barSize / 2; /* correction - корректируем позицию трекера, чтобы курсор оказался хотя бы в центре, а не с краю */ prevNow.current[mod] = Now - correction; calcPosition(prevNow.current[mod], mod); } }; var onMoveY = function onMoveY(_ref) { var deltaY = _ref.deltaY; prevNow.current.y += deltaY; calcPosition(prevNow.current.y, 'y'); }; var onMoveX = function onMoveX(_ref2) { var deltaX = _ref2.deltaX; prevNow.current.x += deltaX; calcPosition(prevNow.current.x, 'x'); }; var onMoveEnd = function onMoveEnd() { touchTrack.current = false; createAutoHideTimer(); }; useEffect(function () { if (observer_ref.current === undefined) { satisfactorySize(); observer_ref.current = new ResizeObserver(satisfactorySize); observer_ref.current.observe(ScrollSpace_ref.current); } }); useEffect(function () { return function () { observer_ref.current.disconnect(); }; }, []); var trackY = /*#__PURE__*/React.createElement(TouchDriver, { moveStart: function moveStart(e) { return onMoveStart(e, 'y'); }, moveXY: onMoveY, moveEnd: onMoveEnd, className: classNames(classes.track, classes.trackY, (_classNames = {}, _defineProperty(_classNames, classes.autoHide, autoHide), _defineProperty(_classNames, classes.scrollVisible, scrollVisible && autoHide), _classNames)) }); var trackX = /*#__PURE__*/React.createElement(TouchDriver, { moveStart: function moveStart(e) { return onMoveStart(e, 'x'); }, moveXY: onMoveX, moveEnd: onMoveEnd, className: classNames(classes.track, classes.trackX, (_classNames2 = {}, _defineProperty(_classNames2, classes.autoHide, autoHide), _defineProperty(_classNames2, classes.scrollVisible, scrollVisible && autoHide), _classNames2)) }); return /*#__PURE__*/React.createElement(Component, { ref: ScrollBase_ref, className: classNames(classes.base, className), style: style }, satisfactoryHeight && vertical ? trackY : null, satisfactoryWidth && horizontal ? trackX : null, /*#__PURE__*/React.createElement("div", { className: classes.wrapper, ref: ScrollWrapper_ref, onScroll: moveScroll }, /*#__PURE__*/React.createElement("div", { ref: ScrollSpace_ref, style: { display: 'inline-block', width: '100%', height: '100%' } }, children))); }); Scroll.propTypes = { /** * Это контент между открывающим и закрывающим тегом компонента. */ children: PropTypes.node, /** * Объект содержит jss стили компонента. */ classes: PropTypes.object, /** * Чтобы указать CSS классы, используйте этот атрибут. */ className: PropTypes.string, /** * Корневой узел. Это HTML элемент или компонент. */ component: PropTypes.elementType, /** * Название цвета в разных форматах. */ color: PropTypes.string, /** * Если true, вертикальный Scrollbar включен. */ vertical: PropTypes.bool, /** * Если true, горизонтальный Scrollbar включен. */ horizontal: PropTypes.bool, /** * Если true, Scrollbar будет скрываться через время. */ autoHide: PropTypes.bool, /** * Время выполнения анимации в ms */ autoHideDuration: PropTypes.number, /** * Время через которое скроется Scrollbar из-за бездействия. */ autoHideTimeout: PropTypes.number, /** * Размер track. */ trackSize: PropTypes.number, /** * Вызывается по время скрола. */ onScroll: PropTypes.func, /** * Вызывается при старте скрола. */ onScrollStart: PropTypes.func, /** * Вызывается в конце скрола. */ onScrollStop: PropTypes.func, /** * Style css. */ style: PropTypes.object }; Scroll.defaultProps = { component: 'div', color: '#000000', vertical: true, horizontal: true, autoHide: true, autoHideDuration: 500, autoHideTimeout: 800, trackSize: 6, style: {} }; Scroll.displayName = 'ScrollEVG'; var Scroll$1 = withStyles(styles)(Scroll); export default Scroll$1;