UNPKG

react-mosaic-component2

Version:
116 lines (115 loc) 4.31 kB
// src/Split.tsx import classNames from "classnames"; import { clamp } from "lodash-es"; import { throttle } from "lodash-es"; import React from "react"; import { BoundingBox } from "./util/BoundingBox.mjs"; var RESIZE_THROTTLE_MS = 1e3 / 30; var TOUCH_EVENT_OPTIONS = { capture: true, passive: false }; var Split = class extends React.PureComponent { rootElement = React.createRef(); listenersBound = false; static defaultProps = { onChange: () => void 0, onRelease: () => void 0, minimumPaneSizePercentage: 20 }; render() { const { direction } = this.props; return /* @__PURE__ */ React.createElement( "div", { className: classNames("mosaic-split", { "-row": direction === "row", "-column": direction === "column" }), ref: this.rootElement, onMouseDown: this.onMouseDown, style: this.computeStyle() }, /* @__PURE__ */ React.createElement("div", { className: "mosaic-split-line" }) ); } componentDidMount() { this.rootElement.current.addEventListener("touchstart", this.onMouseDown, TOUCH_EVENT_OPTIONS); } componentWillUnmount() { this.unbindListeners(); if (this.rootElement.current) { this.rootElement.current.ownerDocument.removeEventListener("touchstart", this.onMouseDown, TOUCH_EVENT_OPTIONS); } } bindListeners() { if (!this.listenersBound) { this.rootElement.current.ownerDocument.addEventListener("mousemove", this.onMouseMove, true); this.rootElement.current.ownerDocument.addEventListener("touchmove", this.onMouseMove, TOUCH_EVENT_OPTIONS); this.rootElement.current.ownerDocument.addEventListener("mouseup", this.onMouseUp, true); this.rootElement.current.ownerDocument.addEventListener("touchend", this.onMouseUp, true); this.listenersBound = true; } } unbindListeners() { if (this.rootElement.current) { this.rootElement.current.ownerDocument.removeEventListener("mousemove", this.onMouseMove, true); this.rootElement.current.ownerDocument.removeEventListener("touchmove", this.onMouseMove, TOUCH_EVENT_OPTIONS); this.rootElement.current.ownerDocument.removeEventListener("mouseup", this.onMouseUp, true); this.rootElement.current.ownerDocument.removeEventListener("touchend", this.onMouseUp, true); this.listenersBound = false; } } computeStyle() { const { boundingBox, direction, splitPercentage } = this.props; const positionStyle = direction === "column" ? "top" : "left"; const absolutePercentage = BoundingBox.getAbsoluteSplitPercentage(boundingBox, splitPercentage, direction); return { ...BoundingBox.asStyles(boundingBox), [positionStyle]: `${absolutePercentage}%` }; } onMouseDown = (event) => { if (!isTouchEvent(event)) { if (event.button !== 0) { return; } } event.preventDefault(); this.bindListeners(); }; onMouseUp = (event) => { this.unbindListeners(); const percentage = this.calculateRelativePercentage(event); this.props.onRelease(percentage); }; onMouseMove = (event) => { event.preventDefault(); this.throttledUpdatePercentage(event); }; throttledUpdatePercentage = throttle((event) => { const percentage = this.calculateRelativePercentage(event); if (percentage !== this.props.splitPercentage) { this.props.onChange(percentage); } }, RESIZE_THROTTLE_MS); calculateRelativePercentage(event) { const { minimumPaneSizePercentage, direction, boundingBox } = this.props; const parentBBox = this.rootElement.current.parentElement.getBoundingClientRect(); const location = isTouchEvent(event) ? event.changedTouches[0] : event; let absolutePercentage; if (direction === "column") { absolutePercentage = (location.clientY - parentBBox.top) / parentBBox.height * 100; } else { absolutePercentage = (location.clientX - parentBBox.left) / parentBBox.width * 100; } const relativePercentage = BoundingBox.getRelativeSplitPercentage(boundingBox, absolutePercentage, direction); return clamp(relativePercentage, minimumPaneSizePercentage, 100 - minimumPaneSizePercentage); } }; function isTouchEvent(event) { return event.changedTouches != null; } export { Split };