UNPKG

@evg-b/evg-ui

Version:

EVG-UI library inspired by Material Design.

399 lines (356 loc) 13 kB
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;