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