@lonli-lokli/react-mosaic-component
Version:
A React Tiling Window Manager
248 lines (246 loc) • 9.3 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// libs/react-mosaic-component/src/lib/Mosaic.tsx
var Mosaic_exports = {};
__export(Mosaic_exports, {
Mosaic: () => Mosaic,
MosaicWithoutDragDropContext: () => MosaicWithoutDragDropContext
});
module.exports = __toCommonJS(Mosaic_exports);
var import_classnames = __toESM(require("classnames"), 1);
var import_lodash_es = require("lodash-es");
var import_rdndmb_html5_to_touch = require("rdndmb-html5-to-touch");
var import_react = __toESM(require("react"), 1);
var import_react_dnd = require("react-dnd");
var import_react_dnd_multi_backend = require("react-dnd-multi-backend");
var import_uuid = require("uuid");
var import_react_dnd2 = require("react-dnd");
var import_contextTypes = require("./contextTypes.cjs");
var import_MosaicRoot = require("./MosaicRoot.cjs");
var import_MosaicZeroState = require("./MosaicZeroState.cjs");
var import_RootDropTargets = require("./RootDropTargets.cjs");
var import_types = require("./types.cjs");
var import_mosaicUpdates = require("./util/mosaicUpdates.cjs");
var import_mosaicUtilities = require("./util/mosaicUtilities.cjs");
var DEFAULT_EXPAND_PERCENTAGE = 70;
function isUncontrolled(props) {
return props.initialValue != null;
}
var MosaicWithoutDragDropContext = class extends import_react.default.PureComponent {
static defaultProps = {
onChange: () => void 0,
zeroStateView: /* @__PURE__ */ import_react.default.createElement(import_MosaicZeroState.MosaicZeroState, null),
className: "mosaic-blueprint-theme",
blueprintNamespace: "bp5"
};
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.mosaicId && prevState.mosaicId !== nextProps.mosaicId && process.env.NODE_ENV !== "production") {
throw new Error(
"Mosaic does not support updating the mosaicId after instantiation"
);
}
if (isUncontrolled(nextProps) && nextProps.initialValue !== prevState.lastInitialValue) {
return {
lastInitialValue: (0, import_mosaicUtilities.convertLegacyToNary)(nextProps.initialValue),
currentNode: (0, import_mosaicUtilities.convertLegacyToNary)(nextProps.initialValue)
};
}
return null;
}
state = {
currentNode: null,
lastInitialValue: null,
mosaicId: this.props.mosaicId ?? (0, import_uuid.v4)()
};
render() {
const { className } = this.props;
return /* @__PURE__ */ import_react.default.createElement(import_contextTypes.MosaicContext.Provider, { value: this.childContext }, /* @__PURE__ */ import_react.default.createElement(MosaicRootWithDragDetection, { className }, this.renderTree(), /* @__PURE__ */ import_react.default.createElement(import_RootDropTargets.RootDropTargets, null)));
}
getRoot() {
if (isUncontrolled(this.props)) {
return this.state.currentNode;
} else {
return (0, import_mosaicUtilities.convertLegacyToNary)(this.props.value);
}
}
updateRoot = (updates, modifiers) => {
modifiers = {
shouldNormalize: modifiers?.shouldNormalize ?? false,
suppressOnRelease: modifiers?.suppressOnRelease ?? false,
suppressOnChange: modifiers?.suppressOnChange ?? false
};
const currentNode = this.getRoot() || {};
const updatedNode = modifiers.shouldNormalize ? (0, import_mosaicUtilities.normalizeMosaicTree)((0, import_mosaicUpdates.updateTree)(currentNode, updates)) : (0, import_mosaicUpdates.updateTree)(currentNode, updates);
this.replaceRoot(
updatedNode,
modifiers.suppressOnRelease,
modifiers.suppressOnChange
);
};
replaceRoot = (currentNode, suppressOnRelease = false, suppressOnChange = false) => {
if (!suppressOnChange) {
this.props.onChange(currentNode);
}
if (!suppressOnRelease && this.props.onRelease) {
this.props.onRelease(currentNode);
}
if (isUncontrolled(this.props)) {
this.setState({ currentNode });
}
};
actions = {
updateTree: this.updateRoot,
remove: (path) => {
if (path.length === 0) {
this.replaceRoot(null);
} else {
this.updateRoot([(0, import_mosaicUpdates.createRemoveUpdate)(this.getRoot(), path)], {
shouldNormalize: true
});
}
},
expand: (path, percentage = DEFAULT_EXPAND_PERCENTAGE) => this.updateRoot([(0, import_mosaicUpdates.createExpandUpdate)(path, percentage)]),
getRoot: () => this.getRoot(),
hide: (path, suppressOnChange = false) => {
this.updateRoot([(0, import_mosaicUpdates.createHideUpdate)(this.getRoot(), path)], {
suppressOnChange
});
},
show: (path, suppressOnChange = false) => {
const root = this.getRoot();
if (!root || path.length === 0) {
return;
}
const parentInfo = (0, import_mosaicUtilities.getParentAndChildIndex)(root, path);
if (!parentInfo) {
return;
}
const { parent } = parentInfo;
if ((0, import_mosaicUtilities.isSplitNode)(parent)) {
const equalPercentage = 100 / parent.children.length;
const newPercentages = Array(parent.children.length).fill(
equalPercentage
);
this.updateRoot(
[
{
path: path.slice(0, -1),
// Parent path
spec: {
splitPercentages: { $set: newPercentages }
}
}
],
{ suppressOnChange }
);
}
},
createNode: this.props.createNode,
replaceWith: (path, newNode) => this.updateRoot([
{
path,
spec: {
$set: newNode
}
}
])
};
childContext = {
mosaicActions: this.actions,
mosaicId: this.state.mosaicId,
blueprintNamespace: this.props.blueprintNamespace
};
renderTree() {
const root = this.getRoot();
this.validateTree(root);
if (root === null || root === void 0) {
return this.props.zeroStateView;
} else {
const { renderTile, resize } = this.props;
return /* @__PURE__ */ import_react.default.createElement(
import_MosaicRoot.MosaicRoot,
{
root,
renderTile,
renderTabToolbar: this.props.renderTabToolbar,
resize,
renderTabTitle: this.props.renderTabTitle,
renderTabButton: this.props.renderTabButton,
canClose: this.props.canClose
}
);
}
}
validateTree(node) {
if (process.env.NODE_ENV !== "production") {
const duplicates = (0, import_lodash_es.keys)((0, import_lodash_es.pickBy)((0, import_lodash_es.countBy)((0, import_mosaicUtilities.getLeaves)(node)), (n) => n > 1));
if (duplicates.length > 0) {
throw new Error(
`Duplicate IDs [${duplicates.join(", ")}] detected. Mosaic does not support leaves with the same ID`
);
}
}
}
};
function MosaicRootWithDragDetection({
className,
children
}) {
const [{ isDragging }] = (0, import_react_dnd2.useDrop)({
accept: import_types.MosaicDragType.WINDOW,
collect: (monitor) => ({
isDragging: monitor.getItem() !== null && monitor.getItemType() === import_types.MosaicDragType.WINDOW
})
});
return /* @__PURE__ */ import_react.default.createElement(
"div",
{
className: (0, import_classnames.default)(className, "mosaic mosaic-drop-target", {
"-dragging": isDragging
})
},
children
);
}
var Mosaic = class extends import_react.default.PureComponent {
render() {
return /* @__PURE__ */ import_react.default.createElement(
import_react_dnd.DndProvider,
{
backend: import_react_dnd_multi_backend.MultiBackend,
options: import_rdndmb_html5_to_touch.HTML5toTouch,
context: window,
...this.props.dragAndDropManager && {
manager: this.props.dragAndDropManager
}
},
/* @__PURE__ */ import_react.default.createElement(MosaicWithoutDragDropContext, { ...this.props })
);
}
};