move drag detection into hook

This commit is contained in:
HF 2021-04-29 16:07:11 +02:00
parent f593d8c7e2
commit 1c486f3105
5 changed files with 111 additions and 110 deletions

View File

@ -8,7 +8,7 @@ import { connect } from 'react-redux';
import { selectColor } from '../actions';
import type { State } from '../reducers';
import useWindowSize from '../utils/reactHookResize';
import useWindowSize from './hooks/resize';
/*

View File

@ -3,7 +3,7 @@
* @flow
*/
import React, { useCallback, useRef, useEffect } from 'react';
import React, { useCallback, useRef } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import {
@ -14,117 +14,45 @@ import {
cloneWindow,
focusWindow,
} from '../actions';
import useDrag from './hooks/drag';
import COMPONENTS from './windows';
const selectWindowById = (state, windowId) => state.windows.windows.find((win) => win.windowId === windowId);
const Window = ({ id }) => {
const titleBarRef = useRef(null);
const resizeRef = useRef(null);
const win = useSelector((state) => selectWindowById(state, id));
const dispatch = useDispatch();
const startMove = useCallback((event) => {
try {
event.stopPropagation();
dispatch(focusWindow(id));
console.log('startMove');
const focus = useCallback(() => dispatch(focusWindow(id)), []);
let {
clientX: startX,
clientY: startY,
} = event.touches ? event.touches[0] : evt;
const move = (evt) => {
evt.stopPropagation();
try {
const {
clientX: curX,
clientY: curY,
} = evt.touches ? evt.touches[0] : evt;
console.log(`move by ${curX-startX} - ${curY - startY}`);
dispatch(moveWindow(id, curX - startX, curY - startY));
startX = curX;
startY = curY;
} catch (e) {
console.log(e);
}
};
document.addEventListener('mousemove', move);
document.addEventListener('touchmove', move);
const stopMove = (evt) => {
evt.stopPropagation();
console.log('stopMove');
document.removeEventListener('mousemove', move);
document.removeEventListener('touchmove', move);
document.removeEventListener('mouseup', stopMove);
document.removeEventListener('touchcancel', stopMove);
document.removeEventListener('touchend', stopMove);
};
document.addEventListener('mouseup', stopMove);
document.addEventListener('touchcancel', stopMove);
document.addEventListener('touchend', stopMove);
} catch (e) {
console.log(e);
}
}, []);
useDrag(
titleBarRef,
focus,
useCallback((xDiff, yDiff) => dispatch(moveWindow(id, xDiff, yDiff)), []),
);
const startResize = useCallback((event) => {
dispatch(focusWindow(id));
let {
clientX: startX,
clientY: startY,
} = event;
const resize = (evt) => {
const {
clientX: curX,
clientY: curY,
} = evt;
dispatch(resizeWindow(id, curX - startX, curY - startY));
startX = curX;
startY = curY;
};
document.addEventListener('mousemove', resize);
const stopResize = () => {
document.removeEventListener('mousemove', resize);
document.removeEventListener('mouseup', stopResize);
document.removeEventListener('touchcancel', stopResize);
document.removeEventListener('touchend', stopResize);
};
document.addEventListener('mouseup', stopResize);
document.addEventListener('touchcancel', stopResize);
document.addEventListener('touchend', stopResize);
}, []);
useEffect(() => {
if (titleBarRef && titleBarRef.current) {
console.log('add listener')
console.log(titleBarRef.current);
titleBarRef.current.addEventListener('mousedown', startMove, {passive: false});
titleBarRef.current.addEventListener('touchstart', startMove, {passive: false});
}
return () => {
titleBarRef.current.removeEventListener('mousedown', startMove);
titleBarRef.current.removeEventListener('touchstart', startMove);
};
}, [titleBarRef, startMove]);
useDrag(
resizeRef,
focus,
useCallback((xDiff, yDiff) => dispatch(resizeWindow(id, xDiff, yDiff)), []),
);
const clone = (evt) => {
evt.stopPropagation();
evt.preventDefault();
dispatch(cloneWindow(id));
};
const maximize = (evt) => {
evt.stopPropagation();
evt.preventDefault();
dispatch(maximizeWindow(id));
};
const close = (evt) => {
evt.stopPropagation();
evt.preventDefault();
dispatch(closeWindow(id));
};
@ -146,7 +74,7 @@ const Window = ({ id }) => {
return (
<div
className={`window ${windowType}`}
onClick={() => dispatch(focusWindow(id))}
onClick={focus}
style={{
left: xPos,
top: yPos,
@ -156,37 +84,35 @@ const Window = ({ id }) => {
>
<div
className="win-topbar"
ref={titleBarRef}
>
<span
className="win-topbtn"
onMouseDown={clone}
onClick={clone}
>
+
</span>
<span
className="win-title"
ref={titleBarRef}
>
{title}
</span>
<span
className="win-topbtn"
onMouseDown={maximize}
onClick={maximize}
>
</span>
<span
className="win-topbtn"
onMouseDown={close}
onClick={close}
>
X
</span>
</div>
<div
onMouseDown={startResize}
onTouchStart={startResize}
className="win-resize"
touchAction="none"
ref={resizeRef}
>
</div>

View File

@ -0,0 +1,66 @@
/*
* @flex
*
* mouse draging
*/
import { useEffect, useCallback } from 'react';
/*
* @param elRef element reference from useRef
* @param startHandler function called on start of drag
* @param diffHandler functio that is called with dragged distance
*/
function useDrag(elRef, startHandler, diffHandler) {
const startDrag = useCallback((event) => {
event.preventDefault();
event.stopPropagation();
startHandler();
console.log('startDrag');
let {
clientX: startX,
clientY: startY,
} = event.touches ? event.touches[0] : event;
const drag = (evt) => {
evt.preventDefault();
evt.stopPropagation();
const {
clientX: curX,
clientY: curY,
} = evt.touches ? evt.touches[0] : evt;
console.log(`drag by ${curX - startX} - ${curY - startY}`);
diffHandler(curX - startX, curY - startY);
startX = curX;
startY = curY;
};
document.addEventListener('mousemove', drag);
document.addEventListener('touchmove', drag);
const stopDrag = (evt) => {
evt.preventDefault();
evt.stopPropagation();
console.log('stopDrag');
document.removeEventListener('mousemove', drag);
document.removeEventListener('touchmove', drag);
document.removeEventListener('mouseup', stopDrag);
document.removeEventListener('touchcancel', stopDrag);
document.removeEventListener('touchend', stopDrag);
};
document.addEventListener('mouseup', stopDrag);
document.addEventListener('touchcancel', stopDrag);
document.addEventListener('touchend', stopDrag);
}, [startHandler]);
useEffect(() => {
if (elRef && elRef.current) {
elRef.current.addEventListener('mousedown', startDrag, { passive: false });
elRef.current.addEventListener('touchstart', startDrag, { passive: false });
}
return () => {
elRef.current.removeEventListener('mousedown', startDrag);
elRef.current.removeEventListener('touchstart', startDrag);
};
}, [elRef, diffHandler]);
}
export default useDrag;

View File

@ -8,8 +8,8 @@ import type { Action } from '../actions/types';
import { clamp } from '../core/utils';
const SCREEN_MARGIN_SE = 30;
const SCREEN_MARGIN_W = 70;
const SCREEN_MARGIN_S = 30;
const SCREEN_MARGIN_EW = 70;
const MIN_WIDTH = 70;
const MIN_HEIGHT = 50;
@ -191,8 +191,8 @@ export default function windows(
{
...win,
windowId: newWindowId,
xPos: Math.min(win.xPos + 15, width - SCREEN_MARGIN_SE),
yPos: Math.min(win.yPos + 15, height - SCREEN_MARGIN_SE),
xPos: Math.min(win.xPos + 15, width - SCREEN_MARGIN_EW),
yPos: Math.min(win.yPos + 15, height - SCREEN_MARGIN_S),
},
],
args: {
@ -300,10 +300,10 @@ export default function windows(
...win,
xPos: clamp(
win.xPos + xDiff,
-win.width + SCREEN_MARGIN_W,
width - SCREEN_MARGIN_SE,
-win.width + SCREEN_MARGIN_EW,
width - SCREEN_MARGIN_S,
),
yPos: clamp(win.yPos + yDiff, 0, height - SCREEN_MARGIN_SE),
yPos: clamp(win.yPos + yDiff, 0, height - SCREEN_MARGIN_S),
};
});
return {
@ -322,14 +322,15 @@ export default function windows(
if (win.windowId !== windowId) return win;
return {
...win,
width: Math.max(
width: clamp(
win.width + xDiff,
MIN_WIDTH,
SCREEN_MARGIN_W - win.xPos,
Math.max(MIN_WIDTH, SCREEN_MARGIN_EW - win.xPos),
window.innerWidth,
),
height: Math.max(
height: clamp(
win.height + yDiff,
MIN_HEIGHT,
window.innerHeight,
),
};
});
@ -344,20 +345,28 @@ export default function windows(
width,
height,
} = action;
const xMax = width - SCREEN_MARGIN_SE;
const yMax = height - SCREEN_MARGIN_SE;
const xMax = width - SCREEN_MARGIN_EW;
const yMax = height - SCREEN_MARGIN_S;
let modified = false;
const newWindows = [];
for (let i = 0; i < state.windows.length; i += 1) {
const win = state.windows[i];
const { xPos, yPos } = win;
if (xPos > xMax || yPos > yMax) {
const {
xPos,
yPos,
width: winWidth,
height: winHeight,
} = win;
if (xPos > xMax || yPos > yMax
|| width > winWidth || height > winHeight) {
modified = true;
newWindows.push({
...win,
xPos: Math.min(xMax, xPos),
yPos: Math.min(yMax, yPos),
width: Math.min(winWidth, width - SCREEN_MARGIN_S),
height: Math.min(winHeight, height - SCREEN_MARGIN_S),
});
} else {
newWindows.push(win);