@evg-b/evg-ui
Version:
EVG-UI library inspired by Material Design.
399 lines (356 loc) • 13 kB
JavaScript
import _extends from '@babel/runtime/helpers/extends';
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import React, { useState, useRef, useCallback, useEffect, useLayoutEffect } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import withStyles from '../styles/withStyles.js';
import Color from '../styles/Color/Color.js';
import Image from '../Image/Image.js';
import TouchDriver from '../TouchDriver/TouchDriver.js';
import ChevronLeft from '../internal/icons/Carousel/ChevronLeft.js';
import ChevronRight from '../internal/icons/Carousel/ChevronRight.js';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var absolutePosition = {
position: 'absolute',
top: 0,
right: 0,
left: 0,
bottom: 0
};
var wrapperImg = {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '100%'
};
var styles = {
base: {
position: 'relative',
overflow: 'hidden',
width: '100%',
height: '100%',
backgroundColor: function backgroundColor(props) {
return Color(props.backgroundColor).Base();
},
'-webkit-touch-callout': 'none',
/* iOS Safari */
'-webkit-user-select': 'none',
/* Chrome/Safari/Opera */
'-moz-user-select': 'none',
/* Firefox */
'-ms-user-select': 'none',
/* Internet Explorer/Edge */
userSelect: 'none'
},
v_zone: _objectSpread(_objectSpread({}, absolutePosition), {}, {
willChange: 'transform'
}),
v_center: _objectSpread(_objectSpread({}, absolutePosition), wrapperImg),
v_zone_right: {
animation: function animation(props) {
return "$right ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1) both");
}
},
v_zone_left: {
animation: function animation(props) {
return "$left ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1) both");
}
},
v_zone_comeback: {
animation: function animation(props) {
return "$comeback ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1) both");
}
},
'@keyframes right': {
to: {
transform: 'translateX(-105%)'
}
},
'@keyframes left': {
to: {
transform: 'translateX(105%)'
}
},
'@keyframes comeback': {
to: {
transform: 'translateX(0)'
}
},
v_left: _objectSpread(_objectSpread(_objectSpread({}, absolutePosition), wrapperImg), {}, {
transform: 'translateX(-105%)'
}),
v_right: _objectSpread(_objectSpread(_objectSpread({}, absolutePosition), wrapperImg), {}, {
transform: 'translateX(105%)'
}),
v_btn: {
zIndex: 1,
position: 'absolute',
color: function color(props) {
return Color(props.backgroundColor).Contrast();
},
cursor: 'pointer',
height: '100%',
width: '5%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'background-color 500ms cubic-bezier(0.4, 0, 0.2, 1)',
'&:hover': {
backgroundColor: function backgroundColor(props) {
return Color(props.backgroundColor).Contrast('RGBA', 0.2);
}
}
},
v_btn_left: {
left: 0
},
v_btn_right: {
right: 0
},
'@media (max-width: 1024px)': {
v_btn: {
display: 'none'
}
},
сarouselImg: {
maxWidth: '100%',
maxHeight: '90%'
},
ImgLeft: {},
ImgCenter: {},
ImgRight: {}
};
/**
* Это карусель инструмент для отображения изображений.
* Поддерживает жесты и оптимизирован для N-количества элементов.
*/
var Carousel = /*#__PURE__*/React.forwardRef(function Carousel(props, ref) {
var _classNames;
var classes = props.classes,
className = props.className;
props.children;
var _props$imgs = props.imgs,
imgs = _props$imgs === void 0 ? [] : _props$imgs,
imgStart = props.imgStart,
onChangeImg = props.onChangeImg;
props.backgroundColor;
var sensitivity = props.sensitivity;
props.duration;
var otherProps = _objectWithoutProperties(props, ["classes", "className", "children", "imgs", "imgStart", "onChangeImg", "backgroundColor", "sensitivity", "duration"]);
var _useState = useState(imgStart < imgs.length ? imgStart : 0),
_useState2 = _slicedToArray(_useState, 2),
imgIndex = _useState2[0],
setImgIndex = _useState2[1];
var _useState3 = useState(0),
_useState4 = _slicedToArray(_useState3, 2),
indexDirection = _useState4[0],
setIndexDirection = _useState4[1]; // -1 | 0 | 1
var _useState5 = useState(false),
_useState6 = _slicedToArray(_useState5, 2),
comeback = _useState6[0],
setComeback = _useState6[1];
var _useState7 = useState({
left: '',
center: '',
right: ''
}),
_useState8 = _slicedToArray(_useState7, 2),
stateImg = _useState8[0],
setStateImg = _useState8[1];
var ViewerEVG_ref = useRef(); // для --var-css
ViewerEVG_ref = ref || ViewerEVG_ref;
var ViewerEVGZone_ref = useRef();
var imgIndex_ref = useRef(imgStart);
var comeBack = useCallback(function () {
moveZone(0);
}, [moveZone]);
var moveZone = useCallback(function (shift) {
var ViewerEVGZone_s = ViewerEVGZone_ref.current;
ViewerEVGZone_s.style.transform = "translateX(".concat(shift, "px)");
}, []); // --- touchDriver
var onMoveXY = function onMoveXY(_ref) {
var shiftX = _ref.shiftX,
itXorY = _ref.itXorY,
startItXorY = _ref.startItXorY;
if (itXorY === 'x' && startItXorY === 'x') {
moveZone(shiftX);
}
};
var onMoveEnd = function onMoveEnd(_ref2) {
var shiftX = _ref2.shiftX,
inertia = _ref2.inertia,
startItXorY = _ref2.startItXorY;
if (shiftX !== 0 && startItXorY === 'x') {
if (inertia || Math.abs(shiftX) > sensitivity) {
if (Math.sign(shiftX) === 1) {
moveSlide('ArrowLeft');
} else {
moveSlide('ArrowRight');
}
} else {
setComeback(true);
}
}
}; // --- touchDriver
// --- replace
var pseudoReplace = function pseudoReplace(direction) {
var pseudo = _objectSpread({}, stateImg);
if (direction === 'right') {
pseudo.center = pseudo.right;
} else {
pseudo.center = pseudo.left;
}
setStateImg(pseudo);
};
var realReplace = useCallback(function (imgIndex) {
// TODO: можно в center передавать уже созданные компоненты Image из left или right.
// это может защитить от потери кэша.
setStateImg({
left: imgs[imgIndex - 1] ? /*#__PURE__*/React.createElement(Image, {
className: classNames(classes.сarouselImg, classes.ImgLeft),
src: imgs[imgIndex - 1]
}) : '',
center: /*#__PURE__*/React.createElement(Image, {
className: classNames(classes.сarouselImg, classes.ImgCenter),
src: imgs[imgIndex]
}),
right: imgs[imgIndex + 1] ? /*#__PURE__*/React.createElement(Image, {
className: classNames(classes.сarouselImg, classes.ImgRight),
src: imgs[imgIndex + 1]
}) : ''
});
}, [imgs, classes]); // --- replace
var moveSlide = function moveSlide(direction) {
switch (direction) {
case 'ArrowRight':
imgs[imgIndex_ref.current + 1] ? setIndexDirection(function (prev) {
return prev === 0 ? 1 : prev;
}) : setComeback(true);
break;
case 'ArrowLeft':
imgs[imgIndex_ref.current - 1] ? setIndexDirection(function (prev) {
return prev === 0 ? -1 : prev;
}) : setComeback(true);
break;
}
};
var onKeyUp = function onKeyUp(e) {
e.preventDefault();
if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
moveSlide(e.key);
}
};
var onAnimationEnd = function onAnimationEnd(e) {
if (e.animationName.includes('right')) {
imgIndex_ref.current = imgIndex_ref.current + 1;
pseudoReplace('right');
}
if (e.animationName.includes('left')) {
imgIndex_ref.current = imgIndex_ref.current - 1;
pseudoReplace('left');
}
if (e.animationName.includes('comeback')) {
comeBack();
setComeback(false);
}
};
useEffect(function () {
setImgIndex(imgStart);
}, [imgStart]);
useEffect(function () {
realReplace(imgIndex); // через changeImg внешнии модули такие как mediaViewer может следить за изменениями
onChangeImg && onChangeImg(imgIndex);
}, [imgIndex, onChangeImg, realReplace]);
useLayoutEffect(function () {
comeBack();
setImgIndex(imgIndex_ref.current);
setIndexDirection(0);
}, [stateImg, comeBack]);
useEffect(function () {
window.addEventListener('keyup', onKeyUp);
return function () {
window.removeEventListener('keyup', onKeyUp);
}; // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
var leftArrow = stateImg.left ? /*#__PURE__*/React.createElement("div", {
className: classNames(classes.v_btn, classes.v_btn_left),
onClick: function onClick() {
return moveSlide('ArrowLeft');
}
}, /*#__PURE__*/React.createElement(ChevronLeft, null)) : null;
var rightArrow = stateImg.right ? /*#__PURE__*/React.createElement("div", {
className: classNames(classes.v_btn, classes.v_btn_right),
onClick: function onClick() {
return moveSlide('ArrowRight');
}
}, /*#__PURE__*/React.createElement(ChevronRight, null)) : null;
var vLeft = stateImg.left ? /*#__PURE__*/React.createElement("div", {
className: classNames(classes.v_left)
}, stateImg.left) : null;
var vRight = stateImg.right ? /*#__PURE__*/React.createElement("div", {
className: classNames(classes.v_right)
}, stateImg.right) : null;
return /*#__PURE__*/React.createElement(TouchDriver, _extends({
innerRef: ViewerEVG_ref,
className: classNames(classes.base, className),
moveXY: onMoveXY,
moveEnd: onMoveEnd
}, otherProps), /*#__PURE__*/React.createElement("div", {
ref: ViewerEVGZone_ref,
className: classNames(classes.v_zone, (_classNames = {}, _defineProperty(_classNames, classes.v_zone_right, indexDirection === 1), _defineProperty(_classNames, classes.v_zone_left, indexDirection === -1), _defineProperty(_classNames, classes.v_zone_comeback, comeback), _classNames)),
onAnimationEnd: onAnimationEnd
}, vLeft, /*#__PURE__*/React.createElement("div", {
className: classNames(classes.v_center)
}, stateImg.center), vRight), leftArrow, rightArrow);
});
Carousel.propTypes = {
/**
* Объект содержит jss стили компонента.
*/
classes: PropTypes.object,
/**
* Чтобы указать CSS классы, используйте этот атрибут.
*/
className: PropTypes.string,
/**
* Это свойство не реализуется.
*/
children: PropTypes.any,
/**
* Массив изображений.
*/
imgs: PropTypes.arrayOf(PropTypes.string),
/**
* Index стартового изображения в массиве.
*/
imgStart: PropTypes.number,
/**
* Цвет фона.
*/
backgroundColor: PropTypes.string,
/**
* Вызывается при изменении img. Возвращает index активного изображения.
*/
onChangeImg: PropTypes.func,
/**
* Количество пикселей в сдвиге после которого запускается смена изображения.
*/
sensitivity: PropTypes.number,
/**
* Время выполнения анимации смены изображения.
*/
duration: PropTypes.number
};
Carousel.defaultProps = {
imgStart: 0,
backgroundColor: 'gray900',
sensitivity: 200,
duration: 200
};
Carousel.displayName = 'CarouselEVG';
var Carousel$1 = withStyles(styles)(Carousel);
export default Carousel$1;