PluginProbe
Extendify / 3.0.5
Extendify v3.0.5
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / hooks / useDraggable.js

useDraggable.js in Extendify 3.0.5, at src/Agent/hooks/useDraggable.js

118 lines 3.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { clamp } from '@agent/lib/util';
2 import { useLayoutEffect, useRef } from '@wordpress/element';
3
4 export const useDraggable = ({ el, open, initialPosition, onDragEnd }) => {
5 const offset = useRef({ x: 0, y: 0 });
6 const pointerIdRef = useRef(null);
7 const lastPosition = useRef({
8 x: initialPosition.x,
9 y: initialPosition.y,
10 });
11
12 useLayoutEffect(() => {
13 if (!el) return;
14 const id = requestAnimationFrame(() => {
15 el.style.setProperty('left', `${initialPosition.x}px`, 'important');
16 el.style.setProperty('top', `${initialPosition.y}px`, 'important');
17 });
18 return () => cancelAnimationFrame(id);
19 }, [el, initialPosition]);
20
21 useLayoutEffect(() => {
22 if (!el || !open) return;
23
24 // keep in bounds
25 const minX = 0;
26 const minY = 0;
27 const maxX = window.innerWidth - el.offsetWidth;
28 const maxY = window.innerHeight - el.offsetHeight;
29 const left = parseFloat(el.style.left) || 0;
30 const top = parseFloat(el.style.top) || 0;
31 const x = clamp(left, minX, maxX);
32 const y = clamp(top, minY, maxY);
33
34 if (left !== x || top !== y) {
35 el.style.setProperty('left', `${x}px`, 'important');
36 el.style.setProperty('top', `${y}px`, 'important');
37 }
38 }, [el, open]);
39
40 useLayoutEffect(() => {
41 const bg =
42 document.getElementById('wpwrap') ||
43 // TODO: is this on all block themes?
44 document.querySelector('.wp-site-blocks');
45 if (!el || !open || !bg) return;
46 const handle = el.querySelector('[data-extendify-agent-handle]');
47 if (!(handle instanceof HTMLElement)) return;
48
49 el.style.setProperty('left', `${initialPosition.x}px`, 'important');
50 el.style.setProperty('top', `${initialPosition.y}px`, 'important');
51
52 const onPointerDown = (e) => {
53 e.preventDefault();
54 e.stopPropagation();
55 bg.style.pointerEvents = 'none';
56 if (pointerIdRef.current !== null) {
57 return;
58 }
59 pointerIdRef.current = e.pointerId;
60 handle.setPointerCapture(e.pointerId);
61 offset.current = {
62 x: e.clientX - el.offsetLeft,
63 y: e.clientY - el.offsetTop,
64 };
65 document.addEventListener('pointermove', onPointerMove);
66 document.addEventListener('pointerup', onPointerUp);
67 };
68
69 const onPointerMove = (e) => {
70 const minX = 0;
71 const minY = 0;
72 const maxX = window.innerWidth - handle.offsetWidth;
73 const maxY = window.innerHeight - handle.offsetHeight;
74 const x = clamp(e.clientX - offset.current.x, minX, maxX);
75 const y = clamp(e.clientY - offset.current.y, minY, maxY);
76 el.style.setProperty('left', `${x}px`, 'important');
77 el.style.setProperty('top', `${y}px`, 'important');
78 lastPosition.current = { x, y };
79 };
80
81 const onPointerUp = (e) => {
82 bg.style.pointerEvents = 'auto';
83 if (pointerIdRef.current !== e.pointerId) {
84 return;
85 }
86 pointerIdRef.current = null;
87 handle.releasePointerCapture(e.pointerId);
88 document.removeEventListener('pointermove', onPointerMove);
89 document.removeEventListener('pointerup', onPointerUp);
90 onDragEnd(lastPosition.current.x, lastPosition.current.y);
91 };
92
93 const onBlur = () => onPointerUp(new PointerEvent('pointerup'));
94 const onContextMenu = (e) => {
95 e.preventDefault();
96 e.stopPropagation();
97 return false;
98 };
99
100 handle.addEventListener('pointerdown', onPointerDown);
101 handle.addEventListener('contextmenu', onContextMenu);
102 handle.addEventListener('blur', onBlur);
103
104 return () => {
105 handle.removeEventListener('pointerdown', onPointerDown);
106 handle.removeEventListener('blur', onBlur);
107 handle.removeEventListener('contextmenu', onContextMenu);
108 document.removeEventListener('pointermove', onPointerMove);
109 document.removeEventListener('pointerup', onPointerUp);
110 bg.style.pointerEvents = 'auto';
111 if (pointerIdRef.current !== null) {
112 handle.releasePointerCapture(pointerIdRef.current);
113 pointerIdRef.current = null;
114 }
115 };
116 }, [el, open, initialPosition.x, initialPosition.y, onDragEnd]);
117 };
118