-
Notifications
You must be signed in to change notification settings - Fork 136
Expand file tree
/
Copy pathbutton.js
More file actions
75 lines (64 loc) · 2.42 KB
/
Copy pathbutton.js
File metadata and controls
75 lines (64 loc) · 2.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
const btn = document.getElementById('uniqueBtn');
const onMove = (e) => {
const rect = btn.getBoundingClientRect();
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
const dx = e.clientX - cx;
const dy = e.clientY - cy;
const tiltX = Math.max(Math.min((-dy / rect.height) * 6, 6), -6);
const tiltY = Math.max(Math.min((dx / rect.width) * 12, 12), -12);
btn.style.setProperty('--tiltX', tiltX + 'deg');
btn.style.setProperty('--tiltY', tiltY + 'deg');
};
const onLeave = () => {
btn.style.setProperty('--tiltX', '0deg');
btn.style.setProperty('--tiltY', '0deg');
};
btn.addEventListener('pointerenter', () => {
document.addEventListener('pointermove', onMove);
});
btn.addEventListener('pointerleave', () => {
document.removeEventListener('pointermove', onMove);
onLeave();
});
const createRipple = (x, y) => {
const circle = document.createElement('span');
circle.className = 'ripple';
const rect = btn.getBoundingClientRect();
circle.style.left = (x - rect.left) + 'px';
circle.style.top = (y - rect.top) + 'px';
const maxDim = Math.max(rect.width, rect.height) * 1.2;
circle.style.width = circle.style.height = maxDim + 'px';
btn.appendChild(circle);
circle.addEventListener('animationend', () => circle.remove(), { once: true });
};
btn.addEventListener('pointerdown', (ev) => {
if (ev.button !== 0 && ev.pointerType === 'mouse') return;
createRipple(ev.clientX, ev.clientY);
});
const performAction = async () => {
if (btn.classList.contains('success')) return;
btn.setAttribute('aria-busy', 'true');
btn.style.pointerEvents = 'none';
await new Promise(r => setTimeout(r, 650));
btn.classList.add('success');
btn.removeAttribute('aria-busy');
setTimeout(() => {
btn.classList.remove('success');
btn.style.pointerEvents = '';
}, 1400);
};
btn.addEventListener('click', () => performAction());
btn.addEventListener('keydown', (e) => {
if (e.key === ' ' || e.key === 'Spacebar' || e.key === 'Enter') {
if (e.key === ' ') e.preventDefault();
const rect = btn.getBoundingClientRect();
createRipple(rect.left + rect.width / 2, rect.top + rect.height / 2);
performAction();
}
});
btn.setAttribute('role', 'button');
btn.setAttribute('tabindex', '0');
window.addEventListener('pagehide', () => {
document.removeEventListener('pointermove', onMove);
});