@evg-b/evg-ui
Version:
EVG-UI library inspired by Material Design.
347 lines (308 loc) • 11.3 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, { useRef, useState, useEffect } 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 TouchDriver from '../TouchDriver/TouchDriver.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 ArrayStates = {
'white': {
'hover': 0.04,
'focus': 0.12,
'selected': 0.08,
'activated': 0.12,
'pressed': 0.12,
'dragged': 0.08
},
'gray': {
'hover': 0.12,
'focus': 0.36,
'selected': 0.24,
'activated': 0.36,
'pressed': 0.48,
'dragged': 0.32
},
'color': {
'hover': 0.08,
'focus': 0.24,
'selected': 0.16,
'activated': 0.24,
'pressed': 0.32,
'dragged': 0.16
}
};
var OverlayColor = function OverlayColor(color) {
var contrast = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
return contrast ? Color(color).Contrast() : Color(color).Base();
};
var OpacityFromColor = function OpacityFromColor(color, effect) {
var opacity;
switch (color) {
case '#000000':
opacity = ArrayStates['white'][effect];
break;
case '#FFFFFF':
opacity = ArrayStates['gray'][effect];
break;
default:
opacity = ArrayStates['color'][effect];
break;
}
return opacity;
};
var absolutePosition = {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0
};
var styles = {
base: _objectSpread(_objectSpread({}, absolutePosition), {}, {
overflow: 'hidden',
outline: 'none',
'&:before': {
content: '""',
pointerEvents: 'none',
position: 'absolute',
top: 0,
left: 0,
opacity: 0,
width: 'var(--evg-ripple-size,100%)',
height: 'var(--evg-ripple-size,100%)',
borderRadius: '50%',
backgroundColor: function backgroundColor(props) {
return OverlayColor(props.color, props.contrast);
},
transformOrigin: 'center center',
transform: 'scale(1)',
willChange: 'transform,opacity'
},
'&:after': _objectSpread({
content: '""',
pointerEvents: 'none',
position: 'absolute',
opacity: 0,
width: '100%',
height: '100%',
backgroundColor: function backgroundColor(props) {
return OverlayColor(props.color, props.contrast);
}
}, absolutePosition),
'&:hover:after': {
opacity: function opacity(props) {
return OpacityFromColor(OverlayColor(props.color, props.contrast), 'hover');
}
}
}),
rippleFocus: {
'&:after,&:hover:after': {
opacity: function opacity(props) {
return OpacityFromColor(OverlayColor(props.color, props.contrast), 'focus');
}
}
},
rippleActive: {
'&:after,&:hover:after': {
opacity: function opacity(props) {
return OpacityFromColor(OverlayColor(props.color, props.contrast), 'activated');
}
}
},
rippleStart: {
'&:before': {
animation: "$startRipple 225ms both"
}
},
rippleEnd: {
'&:before': {
animation: "$startRipple 225ms both,$endRipple 225ms linear both 50ms"
}
},
'@keyframes startRipple': {
'0%': {
animationTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
opacity: 0,
transform: 'translate(var(--evg-ripple-coord-start)) scale(.2,.2)'
},
'50%': {
opacity: 'var(--evg-ripple-opacity)'
},
'100%': {
opacity: 'var(--evg-ripple-opacity)',
transform: 'translate(var(--evg-ripple-coord-end)) scale(1,1)'
}
},
'@keyframes endRipple': {
'0%': {
opacity: 'var(--evg-ripple-opacity)'
},
'100%': {
opacity: 0
}
}
};
/**
* Ripple сигнализирует пользователю что его взаимодействие с компонентом было получено, используя эффект ряби в точке касания.
* Так же помогает понять с каким именно компонентом произошло взаимодействие если они расположены слишком близко друг к другу.
*/
var Ripple = /*#__PURE__*/React.forwardRef(function Ripple(props, ref) {
var _classNames;
var classes = props.classes;
props.className;
props.children;
var _props$component = props.component,
Component = _props$component === void 0 ? 'span' : _props$component,
_props$rippleCenter = props.rippleCenter,
rippleCenter = _props$rippleCenter === void 0 ? false : _props$rippleCenter,
_props$isFocus = props.isFocus,
isFocus = _props$isFocus === void 0 ? false : _props$isFocus,
_props$isPressed = props.isPressed,
isPressed = _props$isPressed === void 0 ? false : _props$isPressed,
_props$isActive = props.isActive,
isActive = _props$isActive === void 0 ? false : _props$isActive,
color = props.color,
_props$contrast = props.contrast,
contrast = _props$contrast === void 0 ? true : _props$contrast,
otherProps = _objectWithoutProperties(props, ["classes", "className", "children", "component", "rippleCenter", "isFocus", "isPressed", "isActive", "color", "contrast"]);
var RippleRef = useRef();
RippleRef = ref || RippleRef;
var _useState = useState(false),
_useState2 = _slicedToArray(_useState, 2),
startRipple = _useState2[0],
setStartRipple = _useState2[1];
var _useState3 = useState(false),
_useState4 = _slicedToArray(_useState3, 2),
endRipple = _useState4[0],
setEndRipple = _useState4[1];
var isEndTouch = useRef(false);
var startRippleDone = useRef(false);
var startTouch = function startTouch(_ref) {
var startX = _ref.startX,
startY = _ref.startY;
RippleStartAnimation(startX, startY, rippleCenter);
};
var RippleStartAnimation = function RippleStartAnimation(startX, startY, center) {
isEndTouch.current = false;
var RippleRef_S = RippleRef.current;
var _RippleRef_S$getBound = RippleRef_S.getBoundingClientRect(),
width = _RippleRef_S$getBound.width,
height = _RippleRef_S$getBound.height;
var rippleSize = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
var coordY, coordX, coordEndY, coordEndX;
if (center) {
coordX = width / 2 - rippleSize / 2;
coordY = height / 2 - rippleSize / 2;
} else {
coordX = startX - rippleSize / 2;
coordY = startY - rippleSize / 2;
}
coordEndX = width / 2 - rippleSize / 2;
coordEndY = height / 2 - rippleSize / 2;
RippleRef_S.style.setProperty('--evg-ripple-size', "".concat(rippleSize, "px"));
RippleRef_S.style.setProperty('--evg-ripple-coord-start', "".concat(coordX, "px,").concat(coordY, "px"));
RippleRef_S.style.setProperty('--evg-ripple-coord-end', "".concat(coordEndX, "px,").concat(coordEndY, "px"));
RippleRef_S.style.setProperty('--evg-ripple-opacity', OpacityFromColor(OverlayColor(color, contrast), 'pressed'));
setStartRipple(true);
};
var endTouch = function endTouch() {
isEndTouch.current = true;
animationStartRippleDone();
};
var animationStartRippleDone = function animationStartRippleDone() {
if (isEndTouch.current && startRippleDone.current) {
setEndRipple(true);
}
};
var onAnimationEnd = function onAnimationEnd(e) {
if (e.animationName.includes('startRipple')) {
startRippleDone.current = true;
animationStartRippleDone();
}
if (e.animationName.includes('endRipple')) {
// end
DefaultSetState();
}
};
var DefaultSetState = function DefaultSetState() {
setStartRipple(false);
setEndRipple(false);
isEndTouch.current = false;
startRippleDone.current = false;
};
useEffect(function () {
if (isPressed) {
RippleStartAnimation(0, 0, true);
} else {
isEndTouch.current = true;
animationStartRippleDone();
} // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isPressed]);
return /*#__PURE__*/React.createElement(TouchDriver, _extends({
className: classNames(classes.base, (_classNames = {}, _defineProperty(_classNames, classes.rippleStart, startRipple), _defineProperty(_classNames, classes.rippleEnd, endRipple), _defineProperty(_classNames, classes.rippleFocus, isFocus), _defineProperty(_classNames, classes.rippleActive, isActive), _classNames)),
onAnimationEnd: onAnimationEnd,
innerRef: RippleRef,
component: Component,
moveStart: startTouch,
moveEnd: endTouch
}, otherProps));
});
Ripple.propTypes = {
/**
* Объект содержит jss стили компонента.
*/
classes: PropTypes.object,
/**
* Чтобы указать CSS классы, используйте этот атрибут.
*/
className: PropTypes.string,
/**
* Это свойство не реализуется.
*/
children: PropTypes.any,
/**
* Корневой узел. Это HTML элемент или компонент.
*/
component: PropTypes.elementType,
/**
* Если true, Ripple эффект стартует в центре.
*/
rippleCenter: PropTypes.bool,
/**
* Если true, примет состояние для focus.
*/
isFocus: PropTypes.bool,
/**
* Если true, примет состояние для pressed.
*/
isPressed: PropTypes.bool,
/**
* Если true, примет состояние для active.
*/
isActive: PropTypes.bool,
/**
* Название цвета в разных форматах.
*/
color: PropTypes.string,
/**
* Если true, цвет волны будет белым или серым автоматически.
* Для лучшего восприятия в зависимости от основного цвета.
*/
contrast: PropTypes.bool
};
Ripple.defaultProps = {
rippleCenter: false,
isFocus: false,
isPressed: false,
isActive: false,
color: 'default',
contrast: true
};
Ripple.displayName = 'RippleEVG';
var Ripple$1 = withStyles(styles)(Ripple);
export default Ripple$1;