diff --git a/src/components/Palette.jsx b/src/components/Palette.jsx index ddf5f9d..1e9f2e0 100644 --- a/src/components/Palette.jsx +++ b/src/components/Palette.jsx @@ -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'; /* diff --git a/src/components/Window.jsx b/src/components/Window.jsx index ac35212..552e677 100644 --- a/src/components/Window.jsx +++ b/src/components/Window.jsx @@ -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 (
dispatch(focusWindow(id))} + onClick={focus} style={{ left: xPos, top: yPos, @@ -156,37 +84,35 @@ const Window = ({ id }) => { >
+ {title} X
diff --git a/src/components/hooks/drag.js b/src/components/hooks/drag.js new file mode 100644 index 0000000..80bad60 --- /dev/null +++ b/src/components/hooks/drag.js @@ -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; diff --git a/src/utils/reactHookResize.js b/src/components/hooks/resize.js similarity index 100% rename from src/utils/reactHookResize.js rename to src/components/hooks/resize.js diff --git a/src/reducers/windows.js b/src/reducers/windows.js index 522ac49..3bd2dc0 100644 --- a/src/reducers/windows.js +++ b/src/reducers/windows.js @@ -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);