97 lines
2.8 KiB
JavaScript
97 lines
2.8 KiB
JavaScript
import { getCustomColorFromModifiers, getCustomRadiusFromModifiers, willHaveAMouseUpEvent, toStyles } from './utils';
|
|
|
|
let rippleClass = 'ripple';
|
|
let removeTimeout = 1000;
|
|
|
|
/**
|
|
* Add a ripple effect to the element.
|
|
*
|
|
* @param {MouseEvent} event
|
|
* @param {HTMLElement} el
|
|
* @param {Array} modifiers
|
|
*/
|
|
export const addRipple = (event, el, modifiers) => {
|
|
if (! willHaveAMouseUpEvent(event)) {
|
|
return;
|
|
}
|
|
|
|
const ripple = document.createElement('span');
|
|
rippleClass.split(' ').forEach(className => ripple.classList.add(className));
|
|
|
|
el.appendChild(ripple);
|
|
|
|
const size = ripple.offsetWidth,
|
|
position = ripple.getBoundingClientRect(),
|
|
innerRipple = document.createElement('span');
|
|
|
|
const x = event.pageX - position.left - (size / 2),
|
|
y = event.pageY - position.top - (size / 2);
|
|
|
|
const style = {
|
|
top: `${y}px`,
|
|
left: `${x}px`,
|
|
width: `${size}px`,
|
|
height: `${size}px`,
|
|
};
|
|
|
|
const color = getCustomColorFromModifiers(modifiers);
|
|
if (color.indexOf('bg-') === 0) {
|
|
// Prefix with '!' for !important (requires Tailwind).
|
|
innerRipple.classList.add(`!${color}`);
|
|
} else if (color.indexOf('#') === 0 || color.indexOf('rgb') === 0) {
|
|
style['--ripple-color'] = color;
|
|
}
|
|
|
|
const radius = getCustomRadiusFromModifiers(modifiers);
|
|
if (radius) {
|
|
style['--ripple-radius'] = radius;
|
|
}
|
|
|
|
ripple.appendChild(innerRipple);
|
|
innerRipple.setAttribute('style', toStyles(style));
|
|
};
|
|
|
|
/**
|
|
* Remove the ripple from the element.
|
|
*
|
|
* @param {HTMLElement} el
|
|
*/
|
|
export const removeRipple = el => {
|
|
setTimeout(() => {
|
|
// We are only removing the first instance to prevent ripples from subsequent clicks
|
|
// being removed too quickly before the ripple effect can properly be seen.
|
|
const ripple = el.querySelector(`.${rippleClass.replace(' ', '.')}`);
|
|
|
|
ripple && ripple.remove();
|
|
}, removeTimeout);
|
|
};
|
|
|
|
function Ripple(Alpine) {
|
|
Alpine.directive('ripple', (el, { modifiers, expression }, { cleanup }) => {
|
|
const clickHandler = event => addRipple(event, el, modifiers);
|
|
const mouseUpHandler = () => removeRipple(el);
|
|
|
|
el.addEventListener('mousedown', clickHandler);
|
|
el.addEventListener('mouseup', mouseUpHandler);
|
|
|
|
cleanup(() => {
|
|
el.removeEventListener('mousedown', clickHandler);
|
|
el.removeEventListener('mouseup', mouseUpHandler);
|
|
});
|
|
});
|
|
}
|
|
|
|
Ripple.configure = config => {
|
|
if (config.hasOwnProperty('class') && typeof config.class === 'string') {
|
|
rippleClass = config.class;
|
|
}
|
|
|
|
if (config.hasOwnProperty('removeTimeout') && typeof config.removeTimeout === 'number') {
|
|
removeTimeout = config.removeTimeout;
|
|
}
|
|
|
|
return Ripple;
|
|
};
|
|
|
|
export default Ripple;
|