import React from "react"; import { findDOMNode } from "react-dom"; import { snapToMany, snapWithin, applySnap } from "../snapUtils"; const WINDOW_HEIGHT = 116; const WINDOW_WIDTH = 275; class WindowManager extends React.Component { constructor(props) { super(props); this.windowNodes = []; this.state = {}; this.getRef = this.getRef.bind(this); this.handleMouseDown = this.handleMouseDown.bind(this); } componentDidMount() { window.addEventListener("resize", this.centerWindows.bind(this)); const { innerHeight, innerWidth } = window; if (innerHeight || innerWidth) { this.centerWindows(); } } centerWindows() { const { innerHeight, innerWidth } = window; const state = {}; const children = this.validChildren(); const totalHeight = children.length * WINDOW_HEIGHT; children.forEach((child, i) => { const offset = WINDOW_HEIGHT * i; state[i] = { left: innerWidth / 2 - WINDOW_WIDTH / 2, top: innerHeight / 2 - totalHeight / 2 + offset }; }); this.setState(state); } getRef(node) { this.windowNodes.push(node); } otherWindows(element) { const domNodes = this.windowNodes.map(findDOMNode); return domNodes.filter(node => node !== element); } nodeInfo(node) { const child = node.childNodes[0]; const { height, width } = child.getBoundingClientRect(); const { offsetLeft, offsetTop } = node; return { x: offsetLeft, y: offsetTop, height, width }; } handleMouseDown(i, e) { if (!e.target.classList.contains("draggable")) { return; } const mouseStart = { x: e.clientX, y: e.clientY }; const windowStart = this.nodeInfo(e.currentTarget); const otherWindowNodes = this.otherWindows(e.currentTarget).map( this.nodeInfo ); const browserSize = { width: window.innerWidth, height: window.innerHeight }; const handleMouseMove = ee => { const diff = { x: ee.clientX - mouseStart.x, y: ee.clientY - mouseStart.y }; const proposedWindow = { ...windowStart, x: windowStart.x + diff.x, y: windowStart.y + diff.y }; const snappedToOthers = snapToMany(proposedWindow, otherWindowNodes); const snappedToBrowser = snapWithin(proposedWindow, browserSize); const newPosition = applySnap( proposedWindow, snappedToBrowser, snappedToOthers ); this.setState({ [i]: { top: newPosition.y, left: newPosition.x } }); }; window.addEventListener("mouseup", () => { window.removeEventListener("mousemove", handleMouseMove); }); window.addEventListener("mousemove", handleMouseMove); } validChildren() { return React.Children.toArray(this.props.children).filter(child => child); } render() { const style = { position: "absolute" }; const parentStyle = { position: "absolute", width: 0, height: 0, top: 0, left: 0 }; return (