move drag detection into hook
This commit is contained in:
parent
f593d8c7e2
commit
1c486f3105
|
@ -8,7 +8,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { selectColor } from '../actions';
|
import { selectColor } from '../actions';
|
||||||
import type { State } from '../reducers';
|
import type { State } from '../reducers';
|
||||||
import useWindowSize from '../utils/reactHookResize';
|
import useWindowSize from './hooks/resize';
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* @flow
|
* @flow
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useCallback, useRef, useEffect } from 'react';
|
import React, { useCallback, useRef } from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -14,117 +14,45 @@ import {
|
||||||
cloneWindow,
|
cloneWindow,
|
||||||
focusWindow,
|
focusWindow,
|
||||||
} from '../actions';
|
} from '../actions';
|
||||||
|
import useDrag from './hooks/drag';
|
||||||
import COMPONENTS from './windows';
|
import COMPONENTS from './windows';
|
||||||
|
|
||||||
const selectWindowById = (state, windowId) => state.windows.windows.find((win) => win.windowId === windowId);
|
const selectWindowById = (state, windowId) => state.windows.windows.find((win) => win.windowId === windowId);
|
||||||
|
|
||||||
const Window = ({ id }) => {
|
const Window = ({ id }) => {
|
||||||
const titleBarRef = useRef(null);
|
const titleBarRef = useRef(null);
|
||||||
|
const resizeRef = useRef(null);
|
||||||
|
|
||||||
const win = useSelector((state) => selectWindowById(state, id));
|
const win = useSelector((state) => selectWindowById(state, id));
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const startMove = useCallback((event) => {
|
const focus = useCallback(() => dispatch(focusWindow(id)), []);
|
||||||
try {
|
|
||||||
event.stopPropagation();
|
|
||||||
dispatch(focusWindow(id));
|
|
||||||
console.log('startMove');
|
|
||||||
|
|
||||||
let {
|
useDrag(
|
||||||
clientX: startX,
|
titleBarRef,
|
||||||
clientY: startY,
|
focus,
|
||||||
} = event.touches ? event.touches[0] : evt;
|
useCallback((xDiff, yDiff) => dispatch(moveWindow(id, xDiff, yDiff)), []),
|
||||||
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);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const startResize = useCallback((event) => {
|
useDrag(
|
||||||
dispatch(focusWindow(id));
|
resizeRef,
|
||||||
|
focus,
|
||||||
let {
|
useCallback((xDiff, yDiff) => dispatch(resizeWindow(id, xDiff, yDiff)), []),
|
||||||
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]);
|
|
||||||
|
|
||||||
const clone = (evt) => {
|
const clone = (evt) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
evt.preventDefault();
|
|
||||||
dispatch(cloneWindow(id));
|
dispatch(cloneWindow(id));
|
||||||
};
|
};
|
||||||
|
|
||||||
const maximize = (evt) => {
|
const maximize = (evt) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
evt.preventDefault();
|
|
||||||
dispatch(maximizeWindow(id));
|
dispatch(maximizeWindow(id));
|
||||||
};
|
};
|
||||||
|
|
||||||
const close = (evt) => {
|
const close = (evt) => {
|
||||||
evt.stopPropagation();
|
evt.stopPropagation();
|
||||||
evt.preventDefault();
|
|
||||||
dispatch(closeWindow(id));
|
dispatch(closeWindow(id));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -146,7 +74,7 @@ const Window = ({ id }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`window ${windowType}`}
|
className={`window ${windowType}`}
|
||||||
onClick={() => dispatch(focusWindow(id))}
|
onClick={focus}
|
||||||
style={{
|
style={{
|
||||||
left: xPos,
|
left: xPos,
|
||||||
top: yPos,
|
top: yPos,
|
||||||
|
@ -156,37 +84,35 @@ const Window = ({ id }) => {
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="win-topbar"
|
className="win-topbar"
|
||||||
ref={titleBarRef}
|
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="win-topbtn"
|
className="win-topbtn"
|
||||||
onMouseDown={clone}
|
onClick={clone}
|
||||||
>
|
>
|
||||||
+
|
+
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className="win-title"
|
className="win-title"
|
||||||
|
ref={titleBarRef}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className="win-topbtn"
|
className="win-topbtn"
|
||||||
onMouseDown={maximize}
|
onClick={maximize}
|
||||||
>
|
>
|
||||||
↑
|
↑
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className="win-topbtn"
|
className="win-topbtn"
|
||||||
onMouseDown={close}
|
onClick={close}
|
||||||
>
|
>
|
||||||
X
|
X
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
onMouseDown={startResize}
|
|
||||||
onTouchStart={startResize}
|
|
||||||
className="win-resize"
|
className="win-resize"
|
||||||
touchAction="none"
|
ref={resizeRef}
|
||||||
>
|
>
|
||||||
▨
|
▨
|
||||||
</div>
|
</div>
|
||||||
|
|
66
src/components/hooks/drag.js
Normal file
66
src/components/hooks/drag.js
Normal 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;
|
|
@ -8,8 +8,8 @@ import type { Action } from '../actions/types';
|
||||||
|
|
||||||
import { clamp } from '../core/utils';
|
import { clamp } from '../core/utils';
|
||||||
|
|
||||||
const SCREEN_MARGIN_SE = 30;
|
const SCREEN_MARGIN_S = 30;
|
||||||
const SCREEN_MARGIN_W = 70;
|
const SCREEN_MARGIN_EW = 70;
|
||||||
const MIN_WIDTH = 70;
|
const MIN_WIDTH = 70;
|
||||||
const MIN_HEIGHT = 50;
|
const MIN_HEIGHT = 50;
|
||||||
|
|
||||||
|
@ -191,8 +191,8 @@ export default function windows(
|
||||||
{
|
{
|
||||||
...win,
|
...win,
|
||||||
windowId: newWindowId,
|
windowId: newWindowId,
|
||||||
xPos: Math.min(win.xPos + 15, width - SCREEN_MARGIN_SE),
|
xPos: Math.min(win.xPos + 15, width - SCREEN_MARGIN_EW),
|
||||||
yPos: Math.min(win.yPos + 15, height - SCREEN_MARGIN_SE),
|
yPos: Math.min(win.yPos + 15, height - SCREEN_MARGIN_S),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
args: {
|
args: {
|
||||||
|
@ -300,10 +300,10 @@ export default function windows(
|
||||||
...win,
|
...win,
|
||||||
xPos: clamp(
|
xPos: clamp(
|
||||||
win.xPos + xDiff,
|
win.xPos + xDiff,
|
||||||
-win.width + SCREEN_MARGIN_W,
|
-win.width + SCREEN_MARGIN_EW,
|
||||||
width - SCREEN_MARGIN_SE,
|
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 {
|
return {
|
||||||
|
@ -322,14 +322,15 @@ export default function windows(
|
||||||
if (win.windowId !== windowId) return win;
|
if (win.windowId !== windowId) return win;
|
||||||
return {
|
return {
|
||||||
...win,
|
...win,
|
||||||
width: Math.max(
|
width: clamp(
|
||||||
win.width + xDiff,
|
win.width + xDiff,
|
||||||
MIN_WIDTH,
|
Math.max(MIN_WIDTH, SCREEN_MARGIN_EW - win.xPos),
|
||||||
SCREEN_MARGIN_W - win.xPos,
|
window.innerWidth,
|
||||||
),
|
),
|
||||||
height: Math.max(
|
height: clamp(
|
||||||
win.height + yDiff,
|
win.height + yDiff,
|
||||||
MIN_HEIGHT,
|
MIN_HEIGHT,
|
||||||
|
window.innerHeight,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -344,20 +345,28 @@ export default function windows(
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
} = action;
|
} = action;
|
||||||
const xMax = width - SCREEN_MARGIN_SE;
|
const xMax = width - SCREEN_MARGIN_EW;
|
||||||
const yMax = height - SCREEN_MARGIN_SE;
|
const yMax = height - SCREEN_MARGIN_S;
|
||||||
let modified = false;
|
let modified = false;
|
||||||
|
|
||||||
const newWindows = [];
|
const newWindows = [];
|
||||||
for (let i = 0; i < state.windows.length; i += 1) {
|
for (let i = 0; i < state.windows.length; i += 1) {
|
||||||
const win = state.windows[i];
|
const win = state.windows[i];
|
||||||
const { xPos, yPos } = win;
|
const {
|
||||||
if (xPos > xMax || yPos > yMax) {
|
xPos,
|
||||||
|
yPos,
|
||||||
|
width: winWidth,
|
||||||
|
height: winHeight,
|
||||||
|
} = win;
|
||||||
|
if (xPos > xMax || yPos > yMax
|
||||||
|
|| width > winWidth || height > winHeight) {
|
||||||
modified = true;
|
modified = true;
|
||||||
newWindows.push({
|
newWindows.push({
|
||||||
...win,
|
...win,
|
||||||
xPos: Math.min(xMax, xPos),
|
xPos: Math.min(xMax, xPos),
|
||||||
yPos: Math.min(yMax, yPos),
|
yPos: Math.min(yMax, yPos),
|
||||||
|
width: Math.min(winWidth, width - SCREEN_MARGIN_S),
|
||||||
|
height: Math.min(winHeight, height - SCREEN_MARGIN_S),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
newWindows.push(win);
|
newWindows.push(win);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user