@evg-b/evg-ui
Version:
EVG-UI library inspired by Material Design.
464 lines (411 loc) • 13.8 kB
JavaScript
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;