react-mosaic-component2
Version:
A React Tiling Window Manager
258 lines (256 loc) • 11.9 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);
// src/MosaicWindow.tsx
var MosaicWindow_exports = {};
__export(MosaicWindow_exports, {
InternalMosaicWindow: () => InternalMosaicWindow,
MosaicWindow: () => MosaicWindow
});
module.exports = __toCommonJS(MosaicWindow_exports);
var import_classnames = __toESM(require("classnames"), 1);
var import_lodash_es = require("lodash-es");
var import_react = __toESM(require("react"), 1);
var import_react_dnd = require("react-dnd");
var import_defaultToolbarControls = require("./buttons/defaultToolbarControls.cjs");
var import_Separator = require("./buttons/Separator.cjs");
var import_contextTypes = require("./contextTypes.cjs");
var import_internalTypes = require("./internalTypes.cjs");
var import_MosaicDropTarget = require("./MosaicDropTarget.cjs");
var import_types = require("./types.cjs");
var import_mosaicUpdates = require("./util/mosaicUpdates.cjs");
var import_mosaicUtilities = require("./util/mosaicUtilities.cjs");
var import_OptionalBlueprint = require("./util/OptionalBlueprint.cjs");
var InternalMosaicWindow = class extends import_react.default.Component {
static defaultProps = {
additionalControlButtonText: "More",
draggable: true,
renderPreview: ({ title }) => /* @__PURE__ */ import_react.default.createElement("div", { className: "mosaic-preview" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "mosaic-window-toolbar" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "mosaic-window-title" }, title)), /* @__PURE__ */ import_react.default.createElement("div", { className: "mosaic-window-body" }, /* @__PURE__ */ import_react.default.createElement("h4", null, title), /* @__PURE__ */ import_react.default.createElement(import_OptionalBlueprint.OptionalBlueprint.Icon, { className: "default-preview-icon", size: "large", icon: "APPLICATION" }))),
renderToolbar: null
};
static contextType = import_contextTypes.MosaicContext;
state = {
additionalControlsOpen: false
};
rootElement = null;
render() {
const {
className,
isOver,
renderPreview,
additionalControls,
connectDropTarget,
connectDragPreview,
draggedMosaicId,
disableAdditionalControlsOverlay
} = this.props;
return /* @__PURE__ */ import_react.default.createElement(import_contextTypes.MosaicWindowContext.Provider, { value: this.childContext }, connectDropTarget(
/* @__PURE__ */ import_react.default.createElement(
"div",
{
className: (0, import_classnames.default)("mosaic-window mosaic-drop-target", className, {
"drop-target-hover": isOver && draggedMosaicId === this.context.mosaicId,
"additional-controls-open": this.state.additionalControlsOpen
}),
ref: (element) => {
this.rootElement = element;
}
},
this.renderToolbar(),
/* @__PURE__ */ import_react.default.createElement("div", { className: "mosaic-window-body" }, this.props.children),
!disableAdditionalControlsOverlay && /* @__PURE__ */ import_react.default.createElement(
"div",
{
className: "mosaic-window-body-overlay",
onClick: () => {
this.setAdditionalControlsOpen(false);
}
}
),
/* @__PURE__ */ import_react.default.createElement("div", { className: "mosaic-window-additional-actions-bar" }, additionalControls),
connectDragPreview(renderPreview(this.props)),
/* @__PURE__ */ import_react.default.createElement("div", { className: "drop-target-container" }, (0, import_lodash_es.values)(import_internalTypes.MosaicDropTargetPosition).map(this.renderDropTarget))
)
));
}
getToolbarControls() {
const { toolbarControls, createNode } = this.props;
if (toolbarControls) {
return toolbarControls;
} else if (createNode) {
return import_defaultToolbarControls.DEFAULT_CONTROLS_WITH_CREATION;
} else {
return import_defaultToolbarControls.DEFAULT_CONTROLS_WITHOUT_CREATION;
}
}
renderToolbar() {
const { title, draggable, additionalControls, additionalControlButtonText, path, renderToolbar } = this.props;
const { additionalControlsOpen } = this.state;
const toolbarControls = this.getToolbarControls();
const draggableAndNotRoot = draggable && path.length > 0;
const connectIfDraggable = draggableAndNotRoot ? this.props.connectDragSource : (el) => el;
if (renderToolbar) {
const connectedToolbar = connectIfDraggable(renderToolbar(this.props, draggable));
return /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_classnames.default)("mosaic-window-toolbar", { draggable: draggableAndNotRoot }) }, connectedToolbar);
}
const titleDiv = connectIfDraggable(
/* @__PURE__ */ import_react.default.createElement("div", { title, className: "mosaic-window-title" }, title)
);
const hasAdditionalControls = !(0, import_lodash_es.isEmpty)(additionalControls);
return /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_classnames.default)("mosaic-window-toolbar", { draggable: draggableAndNotRoot }) }, titleDiv, /* @__PURE__ */ import_react.default.createElement("div", { className: (0, import_classnames.default)("mosaic-window-controls", import_OptionalBlueprint.OptionalBlueprint.getClasses("BUTTON_GROUP")) }, hasAdditionalControls && /* @__PURE__ */ import_react.default.createElement(
"button",
{
onClick: () => this.setAdditionalControlsOpen(!additionalControlsOpen),
className: (0, import_classnames.default)(
import_OptionalBlueprint.OptionalBlueprint.getClasses(this.context.blueprintNamespace, "BUTTON", "MINIMAL"),
import_OptionalBlueprint.OptionalBlueprint.getIconClass(this.context.blueprintNamespace, "MORE"),
{
[import_OptionalBlueprint.OptionalBlueprint.getClasses(this.context.blueprintNamespace, "ACTIVE")]: additionalControlsOpen
}
)
},
/* @__PURE__ */ import_react.default.createElement("span", { className: "control-text" }, additionalControlButtonText)
), hasAdditionalControls && /* @__PURE__ */ import_react.default.createElement(import_Separator.Separator, null), toolbarControls));
}
renderDropTarget = (position) => {
const { path } = this.props;
return /* @__PURE__ */ import_react.default.createElement(import_MosaicDropTarget.MosaicDropTarget, { position, path, key: position });
};
checkCreateNode() {
if (this.props.createNode == null) {
throw new Error("Operation invalid unless `createNode` is defined");
}
}
split = (...args) => {
this.checkCreateNode();
const { createNode, path } = this.props;
const { mosaicActions } = this.context;
const root = mosaicActions.getRoot();
const direction = this.rootElement.offsetWidth > this.rootElement.offsetHeight ? "row" : "column";
return Promise.resolve(createNode(...args)).then(
(second) => mosaicActions.replaceWith(path, {
direction,
second,
first: (0, import_mosaicUtilities.getAndAssertNodeAtPathExists)(root, path)
})
);
};
swap = (...args) => {
this.checkCreateNode();
const { mosaicActions } = this.context;
const { createNode, path } = this.props;
return Promise.resolve(createNode(...args)).then((node) => mosaicActions.replaceWith(path, node));
};
setAdditionalControlsOpen = (additionalControlsOpenOption) => {
const additionalControlsOpen = additionalControlsOpenOption === "toggle" ? !this.state.additionalControlsOpen : additionalControlsOpenOption;
this.setState({ additionalControlsOpen });
this.props.onAdditionalControlsToggle?.(additionalControlsOpen);
};
getPath = () => this.props.path;
connectDragSource = (connectedElements) => {
const { connectDragSource } = this.props;
return connectDragSource(connectedElements);
};
childContext = {
// @ts-ignore
blueprintNamespace: this.context.blueprintNamespace,
mosaicWindowActions: {
split: this.split,
replaceWithNew: this.swap,
setAdditionalControlsOpen: this.setAdditionalControlsOpen,
getPath: this.getPath,
connectDragSource: this.connectDragSource
}
};
};
function ConnectedInternalMosaicWindow(props) {
const { mosaicActions, mosaicId } = (0, import_react.useContext)(import_contextTypes.MosaicContext);
const [, connectDragSource, connectDragPreview] = (0, import_react_dnd.useDrag)({
type: import_types.MosaicDragType.WINDOW,
item: (_monitor) => {
if (props.onDragStart) {
props.onDragStart();
}
const hideTimer = (0, import_lodash_es.defer)(() => mosaicActions.hide(props.path));
return {
mosaicId,
hideTimer
};
},
end: (item, monitor) => {
const { hideTimer } = item;
window.clearTimeout(hideTimer);
const ownPath = props.path;
const dropResult = monitor.getDropResult() || {};
const { position, path: destinationPath } = dropResult;
if (position != null && destinationPath != null && !(0, import_lodash_es.isEqual)(destinationPath, ownPath)) {
mosaicActions.updateTree((0, import_mosaicUpdates.createDragToUpdates)(mosaicActions.getRoot(), ownPath, destinationPath, position));
if (props.onDragEnd) {
props.onDragEnd("drop");
}
} else {
mosaicActions.updateTree([
{
path: (0, import_lodash_es.dropRight)(ownPath),
spec: {
splitPercentage: {
$set: void 0
}
}
}
]);
if (props.onDragEnd) {
props.onDragEnd("reset");
}
}
}
});
const [{ isOver, draggedMosaicId }, connectDropTarget] = (0, import_react_dnd.useDrop)({
accept: import_types.MosaicDragType.WINDOW,
collect: (monitor) => ({
isOver: monitor.isOver(),
draggedMosaicId: monitor.getItem()?.mosaicId
})
});
return /* @__PURE__ */ import_react.default.createElement(
InternalMosaicWindow,
{
...props,
connectDragPreview,
connectDragSource,
connectDropTarget,
isOver,
draggedMosaicId
}
);
}
var MosaicWindow = class extends import_react.default.PureComponent {
render() {
return /* @__PURE__ */ import_react.default.createElement(ConnectedInternalMosaicWindow, { ...this.props });
}
};