react-mosaic-component2
Version:
A React Tiling Window Manager
116 lines (115 loc) • 4.31 kB
JavaScript
// 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
};