UNPKG

@evg-b/evg-ui

Version:

EVG-UI library inspired by Material Design.

426 lines (384 loc) 14.1 kB
import _extends from '@babel/runtime/helpers/extends'; import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties'; import _defineProperty from '@babel/runtime/helpers/defineProperty'; import React, { useRef, useState, useCallback, 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/classCallCheck'; import '@babel/runtime/helpers/createClass'; import TouchDriver from '../TouchDriver/TouchDriver.js'; import Modal from '../Modal/Modal.js'; import Carousel from '../Carousel/Carousel.js'; import calcMaxSizeRatio from '../utils/calcMaxSizeRatio.js'; import Image from '../Image/Image.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 styles = { // Lightbox base: { width: '100%', height: '100%', display: 'grid', gridTemplateColumns: 'repeat(3, 150px)', gridTemplateRows: 'repeat(3, 150px)', gridAutoColumns: '150px', gridAutoRows: '150px', gridGap: '2%', padding: '2%', boxSizing: 'border-box' }, modal: { padding: 0, margin: 0 }, img: { tapHighlightColor: 'transparent', cursor: 'pointer', width: '100%', height: '100%', objectFit: 'cover' }, // Lightbox testBlock: _objectSpread(_objectSpread({}, absolutePosition), {}, { display: 'flex', justifyContent: 'center', alignItems: 'center' }), Lightbox: { width: '100vw', height: '100vh' }, blockTouchCarousel: { pointerEvents: 'none' }, hidden: { display: 'none' // visible }, imgFlip: { width: 'var(--evg-img-center-width-end,0)', height: 'var(--evg-img-center-height-end,0)', transform: 'translateY(var(--evg-img-coord-y-now,0))', objectFit: 'cover', willChange: 'transform' }, imgFlip_normal: { animation: function animation(props) { return "$move ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1) both normal"); } }, imgFlip_reverse: { animation: function animation(props) { return "$move ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1) both reverse"); } }, '@keyframes move': { from: { width: 'var(--evg-img-width-start,0)', height: 'var(--evg-img-height-start,0)', transform: 'translate(var(--evg-img-coord-start,0))' // x,y }, to: { width: 'var(--evg-img-center-width-end,0)', height: 'var(--evg-img-center-height-end,0)', transform: 'translateY(var(--evg-img-coord-y-now,0))' // y } }, imgFlip_comeback: { animation: function animation(props) { return "$comeback ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1)"); } }, '@keyframes comeback': { to: { transform: 'translateY(0)' } }, blackout: { backgroundColor: 'rgba(0,0,0,var(--evg-img-blackout,0))', willChange: 'background-color' }, blackout_normal: { animation: function animation(props) { return "$blackout ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1) normal"); } }, blackout_reverse: { animation: function animation(props) { return "$blackout ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1) reverse"); } }, blackout_back: { animation: function animation(props) { return "$blackout_back ".concat(props.duration, "ms cubic-bezier(0.4, 0, 0.2, 1)"); } }, '@keyframes blackout': { from: { backgroundColor: 'rgba(0,0,0,0)' }, to: { backgroundColor: 'rgba(0,0,0,var(--evg-img-blackout,1))' } }, '@keyframes blackout_back': { to: { backgroundColor: 'rgba(0,0,0,1)' } }, ImgLeft: { width: 'var(--evg-img-left-width-end,0)', height: 'var(--evg-img-left-height-end,0)', objectFit: 'cover' }, ImgCenter: { width: 'var(--evg-img-center-width-end,0)', height: 'var(--evg-img-center-height-end,0)', objectFit: 'cover' }, ImgRight: { width: 'var(--evg-img-right-width-end,0)', height: 'var(--evg-img-right-height-end,0)', objectFit: 'cover' } }; /** * Lightbox - компонент для подробного ознакомления пользователя изображением из галереи. Поддержка жестов и интуитивное управление. */ var Lightbox = /*#__PURE__*/React.forwardRef(function Lightbox(props, ref) { var _classNames, _classNames3; var classes = props.classes; props.className; props.children; var imgs = props.imgs; props.duration; var otherProps = _objectWithoutProperties(props, ["classes", "className", "children", "imgs", "duration"]); var LightboxEVG_ref = useRef(); LightboxEVG_ref = ref || LightboxEVG_ref; var Modal_ref = useRef(); // для --css-var var _useState = useState(-1), _useState2 = _slicedToArray(_useState, 2), indexOpen = _useState2[0], setIndexOpen = _useState2[1]; var _useState3 = useState(false), _useState4 = _slicedToArray(_useState3, 2), isModal = _useState4[0], setIsModal = _useState4[1]; var _useState5 = useState(false), _useState6 = _slicedToArray(_useState5, 2), comeback = _useState6[0], setComeback = _useState6[1]; var _useState7 = useState(false), _useState8 = _slicedToArray(_useState7, 2), flip = _useState8[0], setFlip = _useState8[1]; var _useState9 = useState(false), _useState10 = _slicedToArray(_useState9, 2), normalAnimation = _useState10[0], setNormalAnimation = _useState10[1]; var _useState11 = useState(false), _useState12 = _slicedToArray(_useState11, 2), reverseAnimation = _useState12[0], setReverseAnimation = _useState12[1]; var ratioSizeImgByIndex = useCallback(function () { var imgIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var ims = _toConsumableArray(LightboxEVG_ref.current.getElementsByTagName('img')); var leftImg = imgs[imgIndex - 1] ? ims.find(function (e) { return Number(e.dataset.index) === imgIndex - 1; }) : ''; var centerImg = ims.find(function (e) { return Number(e.dataset.index) === imgIndex; }); var rightImg = imgs[imgIndex + 1] ? ims.find(function (e) { return Number(e.dataset.index) === imgIndex + 1; }) : ''; leftImg && calcPosition(leftImg, 'left'); calcPosition(centerImg, 'center'); rightImg && calcPosition(rightImg, 'right'); }, [imgs, calcPosition]); var setEvgVar = function setEvgVar(key, val) { // установка css var var Modal_S = Modal_ref.current; Modal_S.style.setProperty(key, val); }; var calcPosition = useCallback(function (img) { var prefix = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'center'; var _document$documentEle = document.documentElement, clientWidth = _document$documentEle.clientWidth, clientHeight = _document$documentEle.clientHeight; if (prefix === 'center') { var _img$getBoundingClien = img.getBoundingClientRect(), top = _img$getBoundingClien.top, left = _img$getBoundingClien.left, width = _img$getBoundingClien.width, height = _img$getBoundingClien.height; var centerX = clientWidth / 2, centerY = clientHeight / 2; var newX = -(centerX - width / 2) + left; var newY = -(centerY - height / 2) + top; setEvgVar('--evg-img-coord-start', "".concat(newX, "px,").concat(newY, "px")); setEvgVar('--evg-img-width-start', "".concat(width, "px")); setEvgVar('--evg-img-height-start', "".concat(height, "px")); } var imgSizeEnd = calcMaxSizeRatio(img.naturalWidth, img.naturalHeight, clientWidth, clientHeight); setEvgVar("--evg-img-".concat(prefix, "-width-end"), "".concat(imgSizeEnd.newWidth, "px")); setEvgVar("--evg-img-".concat(prefix, "-height-end"), "".concat(imgSizeEnd.newHeight, "px")); }, []); var calcBlackout = function calcBlackout(shiftY) { var HeightCenter = document.documentElement.clientHeight / 2; var blackoutPerc = Number((1 - Math.abs(shiftY) / HeightCenter).toFixed(2)); return blackoutPerc; }; var onHandlerClick = function onHandlerClick(e) { setIsModal(true); setIndexOpen(Number(e.currentTarget.dataset.index)); }; var onClose = function onClose() { if (isModal && !normalAnimation) { setFlip(false); setNormalAnimation(false); setReverseAnimation(true); } }; // --- touchDriver var onMoveXY = function onMoveXY(_ref) { var shiftY = _ref.shiftY, itXorY = _ref.itXorY, startItXorY = _ref.startItXorY; if (itXorY === 'y' && startItXorY === 'y') { flip && setFlip(false); setEvgVar('--evg-img-coord-y-now', "".concat(shiftY, "px")); setEvgVar('--evg-img-blackout', calcBlackout(shiftY)); } }; var onMoveEnd = function onMoveEnd(_ref2) { var shiftY = _ref2.shiftY, inertia = _ref2.inertia, startItXorY = _ref2.startItXorY; // todo: подключить инерцию if (startItXorY === 'y' && shiftY !== 0) { if (inertia || Math.abs(shiftY) > 200) { onClose(); } else { setComeback(true); } } }; // --- touchDriver var onAnimationEnd = function onAnimationEnd(e) { if (e.animationName.includes('move')) { if (normalAnimation) { setNormalAnimation(false); setFlip(true); } if (reverseAnimation) { setIsModal(false); } } if (e.animationName.includes('back')) { setEvgVar('--evg-img-coord-y-now', 0); setFlip(true); setComeback(false); } }; var handlerChangeImg = function handlerChangeImg(index) { setIndexOpen(index); }; useEffect(function () { if (isModal) { // modal смонтирован setNormalAnimation(true); } else { setIndexOpen(-1); setReverseAnimation(false); } }, [isModal]); useEffect(function () { indexOpen !== -1 && ratioSizeImgByIndex(indexOpen); }, [indexOpen, ratioSizeImgByIndex]); var flipImg = /*#__PURE__*/React.createElement("img", { className: classNames(classes.imgFlip, (_classNames = {}, _defineProperty(_classNames, classes.imgFlip_normal, normalAnimation), _defineProperty(_classNames, classes.imgFlip_reverse, reverseAnimation), _defineProperty(_classNames, classes.imgFlip_comeback, comeback), _defineProperty(_classNames, classes.hidden, flip), _classNames)), onAnimationEnd: onAnimationEnd, src: imgs[indexOpen], alt: "" }); var flipViewer = /*#__PURE__*/React.createElement(Carousel, { backgroundColor: "#000000", className: classNames(classes.Lightbox, _defineProperty({}, classes.hidden, !flip)), classes: { ImgLeft: classes.ImgLeft, ImgCenter: classes.ImgCenter, ImgRight: classes.ImgRight }, imgs: imgs, imgStart: indexOpen, onChangeImg: handlerChangeImg }); return /*#__PURE__*/React.createElement("div", _extends({ ref: LightboxEVG_ref, className: classes.base }, otherProps), imgs.map(function (elem, index) { return /*#__PURE__*/React.createElement(Image, { key: index, className: classes.img, style: index === indexOpen && isModal ? { opacity: 0, transition: 'opacity 0ms 30ms' } : { opacity: 1 }, "data-index": index, src: elem, alt: "", onClick: onHandlerClick }); }), /*#__PURE__*/React.createElement(Modal, { innerRef: Modal_ref, className: classNames(classes.modal, classes.blackout, (_classNames3 = {}, _defineProperty(_classNames3, classes.blackout_normal, normalAnimation), _defineProperty(_classNames3, classes.blackout_reverse, reverseAnimation), _defineProperty(_classNames3, classes.blackout_back, comeback), _classNames3)), component: TouchDriver, open: isModal, onClose: onClose, moveXY: onMoveXY, moveEnd: onMoveEnd, isEsc: true }, /*#__PURE__*/React.createElement("div", { className: classNames(classes.testBlock) }, flipImg, flipViewer))); }); Lightbox.propTypes = { /** * Объект содержит jss стили компонента. */ classes: PropTypes.object, /** * Чтобы указать CSS классы, используйте этот атрибут. */ className: PropTypes.string, /** * Это свойство не реализуется. */ children: PropTypes.any, /** * Массив изображений. */ imgs: PropTypes.arrayOf(PropTypes.string), /** * Время выполнения анимации полета изображения. */ duration: PropTypes.number }; Lightbox.defaultProps = { imgs: [], duration: 300 }; Lightbox.displayName = 'LightboxEVG'; var Lightbox$1 = withStyles(styles)(Lightbox); export default Lightbox$1;