2313 lines
76 KiB
JavaScript
2313 lines
76 KiB
JavaScript
import {
|
|
require_react
|
|
} from "./chunk-7ZNOTH45.js";
|
|
import {
|
|
__toESM
|
|
} from "./chunk-V4OQ3NZ2.js";
|
|
|
|
// node_modules/react-resizable-panels/dist/react-resizable-panels.browser.development.js
|
|
var React = __toESM(require_react());
|
|
var import_react = __toESM(require_react());
|
|
var PanelGroupContext = (0, import_react.createContext)(null);
|
|
PanelGroupContext.displayName = "PanelGroupContext";
|
|
var DATA_ATTRIBUTES = {
|
|
group: "data-panel-group",
|
|
groupDirection: "data-panel-group-direction",
|
|
groupId: "data-panel-group-id",
|
|
panel: "data-panel",
|
|
panelCollapsible: "data-panel-collapsible",
|
|
panelId: "data-panel-id",
|
|
panelSize: "data-panel-size",
|
|
resizeHandle: "data-resize-handle",
|
|
resizeHandleActive: "data-resize-handle-active",
|
|
resizeHandleEnabled: "data-panel-resize-handle-enabled",
|
|
resizeHandleId: "data-panel-resize-handle-id",
|
|
resizeHandleState: "data-resize-handle-state"
|
|
};
|
|
var PRECISION = 10;
|
|
var useIsomorphicLayoutEffect = import_react.useLayoutEffect;
|
|
var useId = React["useId".toString()];
|
|
var wrappedUseId = typeof useId === "function" ? useId : () => null;
|
|
var counter = 0;
|
|
function useUniqueId(idFromParams = null) {
|
|
const idFromUseId = wrappedUseId();
|
|
const idRef = (0, import_react.useRef)(idFromParams || idFromUseId || null);
|
|
if (idRef.current === null) {
|
|
idRef.current = "" + counter++;
|
|
}
|
|
return idFromParams !== null && idFromParams !== void 0 ? idFromParams : idRef.current;
|
|
}
|
|
function PanelWithForwardedRef({
|
|
children,
|
|
className: classNameFromProps = "",
|
|
collapsedSize,
|
|
collapsible,
|
|
defaultSize,
|
|
forwardedRef,
|
|
id: idFromProps,
|
|
maxSize,
|
|
minSize,
|
|
onCollapse,
|
|
onExpand,
|
|
onResize,
|
|
order,
|
|
style: styleFromProps,
|
|
tagName: Type = "div",
|
|
...rest
|
|
}) {
|
|
const context = (0, import_react.useContext)(PanelGroupContext);
|
|
if (context === null) {
|
|
throw Error(`Panel components must be rendered within a PanelGroup container`);
|
|
}
|
|
const {
|
|
collapsePanel,
|
|
expandPanel,
|
|
getPanelSize,
|
|
getPanelStyle,
|
|
groupId,
|
|
isPanelCollapsed,
|
|
reevaluatePanelConstraints,
|
|
registerPanel,
|
|
resizePanel: resizePanel2,
|
|
unregisterPanel
|
|
} = context;
|
|
const panelId = useUniqueId(idFromProps);
|
|
const panelDataRef = (0, import_react.useRef)({
|
|
callbacks: {
|
|
onCollapse,
|
|
onExpand,
|
|
onResize
|
|
},
|
|
constraints: {
|
|
collapsedSize,
|
|
collapsible,
|
|
defaultSize,
|
|
maxSize,
|
|
minSize
|
|
},
|
|
id: panelId,
|
|
idIsFromProps: idFromProps !== void 0,
|
|
order
|
|
});
|
|
const devWarningsRef = (0, import_react.useRef)({
|
|
didLogMissingDefaultSizeWarning: false
|
|
});
|
|
{
|
|
if (!devWarningsRef.current.didLogMissingDefaultSizeWarning) ;
|
|
}
|
|
useIsomorphicLayoutEffect(() => {
|
|
const {
|
|
callbacks,
|
|
constraints
|
|
} = panelDataRef.current;
|
|
const prevConstraints = {
|
|
...constraints
|
|
};
|
|
panelDataRef.current.id = panelId;
|
|
panelDataRef.current.idIsFromProps = idFromProps !== void 0;
|
|
panelDataRef.current.order = order;
|
|
callbacks.onCollapse = onCollapse;
|
|
callbacks.onExpand = onExpand;
|
|
callbacks.onResize = onResize;
|
|
constraints.collapsedSize = collapsedSize;
|
|
constraints.collapsible = collapsible;
|
|
constraints.defaultSize = defaultSize;
|
|
constraints.maxSize = maxSize;
|
|
constraints.minSize = minSize;
|
|
if (prevConstraints.collapsedSize !== constraints.collapsedSize || prevConstraints.collapsible !== constraints.collapsible || prevConstraints.maxSize !== constraints.maxSize || prevConstraints.minSize !== constraints.minSize) {
|
|
reevaluatePanelConstraints(panelDataRef.current, prevConstraints);
|
|
}
|
|
});
|
|
useIsomorphicLayoutEffect(() => {
|
|
const panelData = panelDataRef.current;
|
|
registerPanel(panelData);
|
|
return () => {
|
|
unregisterPanel(panelData);
|
|
};
|
|
}, [order, panelId, registerPanel, unregisterPanel]);
|
|
(0, import_react.useImperativeHandle)(forwardedRef, () => ({
|
|
collapse: () => {
|
|
collapsePanel(panelDataRef.current);
|
|
},
|
|
expand: (minSize2) => {
|
|
expandPanel(panelDataRef.current, minSize2);
|
|
},
|
|
getId() {
|
|
return panelId;
|
|
},
|
|
getSize() {
|
|
return getPanelSize(panelDataRef.current);
|
|
},
|
|
isCollapsed() {
|
|
return isPanelCollapsed(panelDataRef.current);
|
|
},
|
|
isExpanded() {
|
|
return !isPanelCollapsed(panelDataRef.current);
|
|
},
|
|
resize: (size) => {
|
|
resizePanel2(panelDataRef.current, size);
|
|
}
|
|
}), [collapsePanel, expandPanel, getPanelSize, isPanelCollapsed, panelId, resizePanel2]);
|
|
const style = getPanelStyle(panelDataRef.current, defaultSize);
|
|
return (0, import_react.createElement)(Type, {
|
|
...rest,
|
|
children,
|
|
className: classNameFromProps,
|
|
id: panelId,
|
|
style: {
|
|
...style,
|
|
...styleFromProps
|
|
},
|
|
// CSS selectors
|
|
[DATA_ATTRIBUTES.groupId]: groupId,
|
|
[DATA_ATTRIBUTES.panel]: "",
|
|
[DATA_ATTRIBUTES.panelCollapsible]: collapsible || void 0,
|
|
[DATA_ATTRIBUTES.panelId]: panelId,
|
|
[DATA_ATTRIBUTES.panelSize]: parseFloat("" + style.flexGrow).toFixed(1)
|
|
});
|
|
}
|
|
var Panel = (0, import_react.forwardRef)((props2, ref) => (0, import_react.createElement)(PanelWithForwardedRef, {
|
|
...props2,
|
|
forwardedRef: ref
|
|
}));
|
|
PanelWithForwardedRef.displayName = "Panel";
|
|
Panel.displayName = "forwardRef(Panel)";
|
|
var nonce;
|
|
function getNonce() {
|
|
return nonce;
|
|
}
|
|
function setNonce(value) {
|
|
nonce = value;
|
|
}
|
|
var currentCursorStyle = null;
|
|
var enabled = true;
|
|
var getCustomCursorStyleFunction = null;
|
|
var prevRuleIndex = -1;
|
|
var styleElement = null;
|
|
function customizeGlobalCursorStyles(callback) {
|
|
getCustomCursorStyleFunction = callback;
|
|
}
|
|
function disableGlobalCursorStyles() {
|
|
enabled = false;
|
|
}
|
|
function enableGlobalCursorStyles() {
|
|
enabled = true;
|
|
}
|
|
function getCursorStyle(state, constraintFlags, isPointerDown2) {
|
|
const horizontalMin = (constraintFlags & EXCEEDED_HORIZONTAL_MIN) !== 0;
|
|
const horizontalMax = (constraintFlags & EXCEEDED_HORIZONTAL_MAX) !== 0;
|
|
const verticalMin = (constraintFlags & EXCEEDED_VERTICAL_MIN) !== 0;
|
|
const verticalMax = (constraintFlags & EXCEEDED_VERTICAL_MAX) !== 0;
|
|
if (getCustomCursorStyleFunction) {
|
|
return getCustomCursorStyleFunction({
|
|
exceedsHorizontalMaximum: horizontalMax,
|
|
exceedsHorizontalMinimum: horizontalMin,
|
|
exceedsVerticalMaximum: verticalMax,
|
|
exceedsVerticalMinimum: verticalMin,
|
|
intersectsHorizontalDragHandle: state === "horizontal" || state === "intersection",
|
|
intersectsVerticalDragHandle: state === "vertical" || state === "intersection",
|
|
isPointerDown: isPointerDown2
|
|
});
|
|
}
|
|
if (constraintFlags) {
|
|
if (horizontalMin) {
|
|
if (verticalMin) {
|
|
return "se-resize";
|
|
} else if (verticalMax) {
|
|
return "ne-resize";
|
|
} else {
|
|
return "e-resize";
|
|
}
|
|
} else if (horizontalMax) {
|
|
if (verticalMin) {
|
|
return "sw-resize";
|
|
} else if (verticalMax) {
|
|
return "nw-resize";
|
|
} else {
|
|
return "w-resize";
|
|
}
|
|
} else if (verticalMin) {
|
|
return "s-resize";
|
|
} else if (verticalMax) {
|
|
return "n-resize";
|
|
}
|
|
}
|
|
switch (state) {
|
|
case "horizontal":
|
|
return "ew-resize";
|
|
case "intersection":
|
|
return "move";
|
|
case "vertical":
|
|
return "ns-resize";
|
|
}
|
|
}
|
|
function resetGlobalCursorStyle() {
|
|
if (styleElement !== null) {
|
|
document.head.removeChild(styleElement);
|
|
currentCursorStyle = null;
|
|
styleElement = null;
|
|
prevRuleIndex = -1;
|
|
}
|
|
}
|
|
function setGlobalCursorStyle(state, constraintFlags, isPointerDown2) {
|
|
var _styleElement$sheet$i, _styleElement$sheet2;
|
|
if (!enabled) {
|
|
return;
|
|
}
|
|
const style = getCursorStyle(state, constraintFlags, isPointerDown2);
|
|
if (currentCursorStyle === style) {
|
|
return;
|
|
}
|
|
currentCursorStyle = style;
|
|
if (styleElement === null) {
|
|
styleElement = document.createElement("style");
|
|
const nonce2 = getNonce();
|
|
if (nonce2) {
|
|
styleElement.setAttribute("nonce", nonce2);
|
|
}
|
|
document.head.appendChild(styleElement);
|
|
}
|
|
if (prevRuleIndex >= 0) {
|
|
var _styleElement$sheet;
|
|
(_styleElement$sheet = styleElement.sheet) === null || _styleElement$sheet === void 0 ? void 0 : _styleElement$sheet.removeRule(prevRuleIndex);
|
|
}
|
|
prevRuleIndex = (_styleElement$sheet$i = (_styleElement$sheet2 = styleElement.sheet) === null || _styleElement$sheet2 === void 0 ? void 0 : _styleElement$sheet2.insertRule(`*{cursor: ${style} !important;}`)) !== null && _styleElement$sheet$i !== void 0 ? _styleElement$sheet$i : -1;
|
|
}
|
|
function isKeyDown(event) {
|
|
return event.type === "keydown";
|
|
}
|
|
function isPointerEvent(event) {
|
|
return event.type.startsWith("pointer");
|
|
}
|
|
function isMouseEvent(event) {
|
|
return event.type.startsWith("mouse");
|
|
}
|
|
function getResizeEventCoordinates(event) {
|
|
if (isPointerEvent(event)) {
|
|
if (event.isPrimary) {
|
|
return {
|
|
x: event.clientX,
|
|
y: event.clientY
|
|
};
|
|
}
|
|
} else if (isMouseEvent(event)) {
|
|
return {
|
|
x: event.clientX,
|
|
y: event.clientY
|
|
};
|
|
}
|
|
return {
|
|
x: Infinity,
|
|
y: Infinity
|
|
};
|
|
}
|
|
function getInputType() {
|
|
if (typeof matchMedia === "function") {
|
|
return matchMedia("(pointer:coarse)").matches ? "coarse" : "fine";
|
|
}
|
|
}
|
|
function intersects(rectOne, rectTwo, strict) {
|
|
if (strict) {
|
|
return rectOne.x < rectTwo.x + rectTwo.width && rectOne.x + rectOne.width > rectTwo.x && rectOne.y < rectTwo.y + rectTwo.height && rectOne.y + rectOne.height > rectTwo.y;
|
|
} else {
|
|
return rectOne.x <= rectTwo.x + rectTwo.width && rectOne.x + rectOne.width >= rectTwo.x && rectOne.y <= rectTwo.y + rectTwo.height && rectOne.y + rectOne.height >= rectTwo.y;
|
|
}
|
|
}
|
|
function compare(a, b) {
|
|
if (a === b) throw new Error("Cannot compare node with itself");
|
|
const ancestors = {
|
|
a: get_ancestors(a),
|
|
b: get_ancestors(b)
|
|
};
|
|
let common_ancestor;
|
|
while (ancestors.a.at(-1) === ancestors.b.at(-1)) {
|
|
a = ancestors.a.pop();
|
|
b = ancestors.b.pop();
|
|
common_ancestor = a;
|
|
}
|
|
assert(common_ancestor, "Stacking order can only be calculated for elements with a common ancestor");
|
|
const z_indexes = {
|
|
a: get_z_index(find_stacking_context(ancestors.a)),
|
|
b: get_z_index(find_stacking_context(ancestors.b))
|
|
};
|
|
if (z_indexes.a === z_indexes.b) {
|
|
const children = common_ancestor.childNodes;
|
|
const furthest_ancestors = {
|
|
a: ancestors.a.at(-1),
|
|
b: ancestors.b.at(-1)
|
|
};
|
|
let i = children.length;
|
|
while (i--) {
|
|
const child = children[i];
|
|
if (child === furthest_ancestors.a) return 1;
|
|
if (child === furthest_ancestors.b) return -1;
|
|
}
|
|
}
|
|
return Math.sign(z_indexes.a - z_indexes.b);
|
|
}
|
|
var props = /\b(?:position|zIndex|opacity|transform|webkitTransform|mixBlendMode|filter|webkitFilter|isolation)\b/;
|
|
function is_flex_item(node) {
|
|
var _get_parent;
|
|
const display = getComputedStyle((_get_parent = get_parent(node)) !== null && _get_parent !== void 0 ? _get_parent : node).display;
|
|
return display === "flex" || display === "inline-flex";
|
|
}
|
|
function creates_stacking_context(node) {
|
|
const style = getComputedStyle(node);
|
|
if (style.position === "fixed") return true;
|
|
if (style.zIndex !== "auto" && (style.position !== "static" || is_flex_item(node))) return true;
|
|
if (+style.opacity < 1) return true;
|
|
if ("transform" in style && style.transform !== "none") return true;
|
|
if ("webkitTransform" in style && style.webkitTransform !== "none") return true;
|
|
if ("mixBlendMode" in style && style.mixBlendMode !== "normal") return true;
|
|
if ("filter" in style && style.filter !== "none") return true;
|
|
if ("webkitFilter" in style && style.webkitFilter !== "none") return true;
|
|
if ("isolation" in style && style.isolation === "isolate") return true;
|
|
if (props.test(style.willChange)) return true;
|
|
if (style.webkitOverflowScrolling === "touch") return true;
|
|
return false;
|
|
}
|
|
function find_stacking_context(nodes) {
|
|
let i = nodes.length;
|
|
while (i--) {
|
|
const node = nodes[i];
|
|
assert(node, "Missing node");
|
|
if (creates_stacking_context(node)) return node;
|
|
}
|
|
return null;
|
|
}
|
|
function get_z_index(node) {
|
|
return node && Number(getComputedStyle(node).zIndex) || 0;
|
|
}
|
|
function get_ancestors(node) {
|
|
const ancestors = [];
|
|
while (node) {
|
|
ancestors.push(node);
|
|
node = get_parent(node);
|
|
}
|
|
return ancestors;
|
|
}
|
|
function get_parent(node) {
|
|
const {
|
|
parentNode
|
|
} = node;
|
|
if (parentNode && parentNode instanceof ShadowRoot) {
|
|
return parentNode.host;
|
|
}
|
|
return parentNode;
|
|
}
|
|
var EXCEEDED_HORIZONTAL_MIN = 1;
|
|
var EXCEEDED_HORIZONTAL_MAX = 2;
|
|
var EXCEEDED_VERTICAL_MIN = 4;
|
|
var EXCEEDED_VERTICAL_MAX = 8;
|
|
var isCoarsePointer = getInputType() === "coarse";
|
|
var intersectingHandles = [];
|
|
var isPointerDown = false;
|
|
var ownerDocumentCounts = /* @__PURE__ */ new Map();
|
|
var panelConstraintFlags = /* @__PURE__ */ new Map();
|
|
var registeredResizeHandlers = /* @__PURE__ */ new Set();
|
|
function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins, setResizeHandlerState) {
|
|
var _ownerDocumentCounts$;
|
|
const {
|
|
ownerDocument
|
|
} = element;
|
|
const data = {
|
|
direction,
|
|
element,
|
|
hitAreaMargins,
|
|
setResizeHandlerState
|
|
};
|
|
const count = (_ownerDocumentCounts$ = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$ !== void 0 ? _ownerDocumentCounts$ : 0;
|
|
ownerDocumentCounts.set(ownerDocument, count + 1);
|
|
registeredResizeHandlers.add(data);
|
|
updateListeners();
|
|
return function unregisterResizeHandle() {
|
|
var _ownerDocumentCounts$2;
|
|
panelConstraintFlags.delete(resizeHandleId);
|
|
registeredResizeHandlers.delete(data);
|
|
const count2 = (_ownerDocumentCounts$2 = ownerDocumentCounts.get(ownerDocument)) !== null && _ownerDocumentCounts$2 !== void 0 ? _ownerDocumentCounts$2 : 1;
|
|
ownerDocumentCounts.set(ownerDocument, count2 - 1);
|
|
updateListeners();
|
|
if (count2 === 1) {
|
|
ownerDocumentCounts.delete(ownerDocument);
|
|
}
|
|
if (intersectingHandles.includes(data)) {
|
|
const index = intersectingHandles.indexOf(data);
|
|
if (index >= 0) {
|
|
intersectingHandles.splice(index, 1);
|
|
}
|
|
updateCursor();
|
|
setResizeHandlerState("up", true, null);
|
|
}
|
|
};
|
|
}
|
|
function handlePointerDown(event) {
|
|
const {
|
|
target
|
|
} = event;
|
|
const {
|
|
x,
|
|
y
|
|
} = getResizeEventCoordinates(event);
|
|
isPointerDown = true;
|
|
recalculateIntersectingHandles({
|
|
target,
|
|
x,
|
|
y
|
|
});
|
|
updateListeners();
|
|
if (intersectingHandles.length > 0) {
|
|
updateResizeHandlerStates("down", event);
|
|
updateCursor();
|
|
event.preventDefault();
|
|
if (!isWithinResizeHandle(target)) {
|
|
event.stopImmediatePropagation();
|
|
}
|
|
}
|
|
}
|
|
function handlePointerMove(event) {
|
|
const {
|
|
x,
|
|
y
|
|
} = getResizeEventCoordinates(event);
|
|
if (isPointerDown && // Skip this check for "pointerleave" events, else Firefox triggers a false positive (see #514)
|
|
event.type !== "pointerleave" && event.buttons === 0) {
|
|
isPointerDown = false;
|
|
updateResizeHandlerStates("up", event);
|
|
}
|
|
if (!isPointerDown) {
|
|
const {
|
|
target
|
|
} = event;
|
|
recalculateIntersectingHandles({
|
|
target,
|
|
x,
|
|
y
|
|
});
|
|
}
|
|
updateResizeHandlerStates("move", event);
|
|
updateCursor();
|
|
if (intersectingHandles.length > 0) {
|
|
event.preventDefault();
|
|
}
|
|
}
|
|
function handlePointerUp(event) {
|
|
const {
|
|
target
|
|
} = event;
|
|
const {
|
|
x,
|
|
y
|
|
} = getResizeEventCoordinates(event);
|
|
panelConstraintFlags.clear();
|
|
isPointerDown = false;
|
|
if (intersectingHandles.length > 0) {
|
|
event.preventDefault();
|
|
if (!isWithinResizeHandle(target)) {
|
|
event.stopImmediatePropagation();
|
|
}
|
|
}
|
|
updateResizeHandlerStates("up", event);
|
|
recalculateIntersectingHandles({
|
|
target,
|
|
x,
|
|
y
|
|
});
|
|
updateCursor();
|
|
updateListeners();
|
|
}
|
|
function isWithinResizeHandle(element) {
|
|
let currentElement = element;
|
|
while (currentElement) {
|
|
if (currentElement.hasAttribute(DATA_ATTRIBUTES.resizeHandle)) {
|
|
return true;
|
|
}
|
|
currentElement = currentElement.parentElement;
|
|
}
|
|
return false;
|
|
}
|
|
function recalculateIntersectingHandles({
|
|
target,
|
|
x,
|
|
y
|
|
}) {
|
|
intersectingHandles.splice(0);
|
|
let targetElement = null;
|
|
if (target instanceof HTMLElement || target instanceof SVGElement) {
|
|
targetElement = target;
|
|
}
|
|
registeredResizeHandlers.forEach((data) => {
|
|
const {
|
|
element: dragHandleElement,
|
|
hitAreaMargins
|
|
} = data;
|
|
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
const {
|
|
bottom,
|
|
left,
|
|
right,
|
|
top
|
|
} = dragHandleRect;
|
|
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
if (eventIntersects) {
|
|
if (targetElement !== null && document.contains(targetElement) && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) && // Calculating stacking order has a cost, so we should avoid it if possible
|
|
// That is why we only check potentially intersecting handles,
|
|
// and why we skip if the event target is within the handle's DOM
|
|
compare(targetElement, dragHandleElement) > 0) {
|
|
let currentElement = targetElement;
|
|
let didIntersect = false;
|
|
while (currentElement) {
|
|
if (currentElement.contains(dragHandleElement)) {
|
|
break;
|
|
} else if (intersects(currentElement.getBoundingClientRect(), dragHandleRect, true)) {
|
|
didIntersect = true;
|
|
break;
|
|
}
|
|
currentElement = currentElement.parentElement;
|
|
}
|
|
if (didIntersect) {
|
|
return;
|
|
}
|
|
}
|
|
intersectingHandles.push(data);
|
|
}
|
|
});
|
|
}
|
|
function reportConstraintsViolation(resizeHandleId, flag) {
|
|
panelConstraintFlags.set(resizeHandleId, flag);
|
|
}
|
|
function updateCursor() {
|
|
let intersectsHorizontal = false;
|
|
let intersectsVertical = false;
|
|
intersectingHandles.forEach((data) => {
|
|
const {
|
|
direction
|
|
} = data;
|
|
if (direction === "horizontal") {
|
|
intersectsHorizontal = true;
|
|
} else {
|
|
intersectsVertical = true;
|
|
}
|
|
});
|
|
let constraintFlags = 0;
|
|
panelConstraintFlags.forEach((flag) => {
|
|
constraintFlags |= flag;
|
|
});
|
|
if (intersectsHorizontal && intersectsVertical) {
|
|
setGlobalCursorStyle("intersection", constraintFlags, isPointerDown);
|
|
} else if (intersectsHorizontal) {
|
|
setGlobalCursorStyle("horizontal", constraintFlags, isPointerDown);
|
|
} else if (intersectsVertical) {
|
|
setGlobalCursorStyle("vertical", constraintFlags, isPointerDown);
|
|
} else {
|
|
resetGlobalCursorStyle();
|
|
}
|
|
}
|
|
var listenersAbortController;
|
|
function updateListeners() {
|
|
var _listenersAbortContro;
|
|
(_listenersAbortContro = listenersAbortController) === null || _listenersAbortContro === void 0 ? void 0 : _listenersAbortContro.abort();
|
|
listenersAbortController = new AbortController();
|
|
const options = {
|
|
capture: true,
|
|
signal: listenersAbortController.signal
|
|
};
|
|
if (!registeredResizeHandlers.size) {
|
|
return;
|
|
}
|
|
if (isPointerDown) {
|
|
if (intersectingHandles.length > 0) {
|
|
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
const {
|
|
body
|
|
} = ownerDocument;
|
|
if (count > 0) {
|
|
body.addEventListener("contextmenu", handlePointerUp, options);
|
|
body.addEventListener("pointerleave", handlePointerMove, options);
|
|
body.addEventListener("pointermove", handlePointerMove, options);
|
|
}
|
|
});
|
|
}
|
|
ownerDocumentCounts.forEach((_, ownerDocument) => {
|
|
const {
|
|
body
|
|
} = ownerDocument;
|
|
body.addEventListener("pointerup", handlePointerUp, options);
|
|
body.addEventListener("pointercancel", handlePointerUp, options);
|
|
});
|
|
} else {
|
|
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
const {
|
|
body
|
|
} = ownerDocument;
|
|
if (count > 0) {
|
|
body.addEventListener("pointerdown", handlePointerDown, options);
|
|
body.addEventListener("pointermove", handlePointerMove, options);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
function updateResizeHandlerStates(action, event) {
|
|
registeredResizeHandlers.forEach((data) => {
|
|
const {
|
|
setResizeHandlerState
|
|
} = data;
|
|
const isActive = intersectingHandles.includes(data);
|
|
setResizeHandlerState(action, isActive, event);
|
|
});
|
|
}
|
|
function useForceUpdate() {
|
|
const [_, setCount] = (0, import_react.useState)(0);
|
|
return (0, import_react.useCallback)(() => setCount((prevCount) => prevCount + 1), []);
|
|
}
|
|
function assert(expectedCondition, message) {
|
|
if (!expectedCondition) {
|
|
console.error(message);
|
|
throw Error(message);
|
|
}
|
|
}
|
|
function fuzzyCompareNumbers(actual, expected, fractionDigits = PRECISION) {
|
|
if (actual.toFixed(fractionDigits) === expected.toFixed(fractionDigits)) {
|
|
return 0;
|
|
} else {
|
|
return actual > expected ? 1 : -1;
|
|
}
|
|
}
|
|
function fuzzyNumbersEqual$1(actual, expected, fractionDigits = PRECISION) {
|
|
return fuzzyCompareNumbers(actual, expected, fractionDigits) === 0;
|
|
}
|
|
function fuzzyNumbersEqual(actual, expected, fractionDigits) {
|
|
return fuzzyCompareNumbers(actual, expected, fractionDigits) === 0;
|
|
}
|
|
function fuzzyLayoutsEqual(actual, expected, fractionDigits) {
|
|
if (actual.length !== expected.length) {
|
|
return false;
|
|
}
|
|
for (let index = 0; index < actual.length; index++) {
|
|
const actualSize = actual[index];
|
|
const expectedSize = expected[index];
|
|
if (!fuzzyNumbersEqual(actualSize, expectedSize, fractionDigits)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function resizePanel({
|
|
panelConstraints: panelConstraintsArray,
|
|
panelIndex,
|
|
size
|
|
}) {
|
|
const panelConstraints = panelConstraintsArray[panelIndex];
|
|
assert(panelConstraints != null, `Panel constraints not found for index ${panelIndex}`);
|
|
let {
|
|
collapsedSize = 0,
|
|
collapsible,
|
|
maxSize = 100,
|
|
minSize = 0
|
|
} = panelConstraints;
|
|
if (fuzzyCompareNumbers(size, minSize) < 0) {
|
|
if (collapsible) {
|
|
const halfwayPoint = (collapsedSize + minSize) / 2;
|
|
if (fuzzyCompareNumbers(size, halfwayPoint) < 0) {
|
|
size = collapsedSize;
|
|
} else {
|
|
size = minSize;
|
|
}
|
|
} else {
|
|
size = minSize;
|
|
}
|
|
}
|
|
size = Math.min(maxSize, size);
|
|
size = parseFloat(size.toFixed(PRECISION));
|
|
return size;
|
|
}
|
|
function adjustLayoutByDelta({
|
|
delta,
|
|
initialLayout,
|
|
panelConstraints: panelConstraintsArray,
|
|
pivotIndices,
|
|
prevLayout,
|
|
trigger
|
|
}) {
|
|
if (fuzzyNumbersEqual(delta, 0)) {
|
|
return initialLayout;
|
|
}
|
|
const nextLayout = [...initialLayout];
|
|
const [firstPivotIndex, secondPivotIndex] = pivotIndices;
|
|
assert(firstPivotIndex != null, "Invalid first pivot index");
|
|
assert(secondPivotIndex != null, "Invalid second pivot index");
|
|
let deltaApplied = 0;
|
|
{
|
|
if (trigger === "keyboard") {
|
|
{
|
|
const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
const panelConstraints = panelConstraintsArray[index];
|
|
assert(panelConstraints, `Panel constraints not found for index ${index}`);
|
|
const {
|
|
collapsedSize = 0,
|
|
collapsible,
|
|
minSize = 0
|
|
} = panelConstraints;
|
|
if (collapsible) {
|
|
const prevSize = initialLayout[index];
|
|
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
|
|
const localDelta = minSize - prevSize;
|
|
if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
|
|
delta = delta < 0 ? 0 - localDelta : localDelta;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
{
|
|
const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
|
|
const panelConstraints = panelConstraintsArray[index];
|
|
assert(panelConstraints, `No panel constraints found for index ${index}`);
|
|
const {
|
|
collapsedSize = 0,
|
|
collapsible,
|
|
minSize = 0
|
|
} = panelConstraints;
|
|
if (collapsible) {
|
|
const prevSize = initialLayout[index];
|
|
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
if (fuzzyNumbersEqual(prevSize, minSize)) {
|
|
const localDelta = prevSize - collapsedSize;
|
|
if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0) {
|
|
delta = delta < 0 ? 0 - localDelta : localDelta;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
{
|
|
const increment = delta < 0 ? 1 : -1;
|
|
let index = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
let maxAvailableDelta = 0;
|
|
while (true) {
|
|
const prevSize = initialLayout[index];
|
|
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
const maxSafeSize = resizePanel({
|
|
panelConstraints: panelConstraintsArray,
|
|
panelIndex: index,
|
|
size: 100
|
|
});
|
|
const delta2 = maxSafeSize - prevSize;
|
|
maxAvailableDelta += delta2;
|
|
index += increment;
|
|
if (index < 0 || index >= panelConstraintsArray.length) {
|
|
break;
|
|
}
|
|
}
|
|
const minAbsDelta = Math.min(Math.abs(delta), Math.abs(maxAvailableDelta));
|
|
delta = delta < 0 ? 0 - minAbsDelta : minAbsDelta;
|
|
}
|
|
{
|
|
const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;
|
|
let index = pivotIndex;
|
|
while (index >= 0 && index < panelConstraintsArray.length) {
|
|
const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
|
|
const prevSize = initialLayout[index];
|
|
assert(prevSize != null, `Previous layout not found for panel index ${index}`);
|
|
const unsafeSize = prevSize - deltaRemaining;
|
|
const safeSize = resizePanel({
|
|
panelConstraints: panelConstraintsArray,
|
|
panelIndex: index,
|
|
size: unsafeSize
|
|
});
|
|
if (!fuzzyNumbersEqual(prevSize, safeSize)) {
|
|
deltaApplied += prevSize - safeSize;
|
|
nextLayout[index] = safeSize;
|
|
if (deltaApplied.toFixed(3).localeCompare(Math.abs(delta).toFixed(3), void 0, {
|
|
numeric: true
|
|
}) >= 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (delta < 0) {
|
|
index--;
|
|
} else {
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
if (fuzzyLayoutsEqual(prevLayout, nextLayout)) {
|
|
return prevLayout;
|
|
}
|
|
{
|
|
const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
const prevSize = initialLayout[pivotIndex];
|
|
assert(prevSize != null, `Previous layout not found for panel index ${pivotIndex}`);
|
|
const unsafeSize = prevSize + deltaApplied;
|
|
const safeSize = resizePanel({
|
|
panelConstraints: panelConstraintsArray,
|
|
panelIndex: pivotIndex,
|
|
size: unsafeSize
|
|
});
|
|
nextLayout[pivotIndex] = safeSize;
|
|
if (!fuzzyNumbersEqual(safeSize, unsafeSize)) {
|
|
let deltaRemaining = unsafeSize - safeSize;
|
|
const pivotIndex2 = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
let index = pivotIndex2;
|
|
while (index >= 0 && index < panelConstraintsArray.length) {
|
|
const prevSize2 = nextLayout[index];
|
|
assert(prevSize2 != null, `Previous layout not found for panel index ${index}`);
|
|
const unsafeSize2 = prevSize2 + deltaRemaining;
|
|
const safeSize2 = resizePanel({
|
|
panelConstraints: panelConstraintsArray,
|
|
panelIndex: index,
|
|
size: unsafeSize2
|
|
});
|
|
if (!fuzzyNumbersEqual(prevSize2, safeSize2)) {
|
|
deltaRemaining -= safeSize2 - prevSize2;
|
|
nextLayout[index] = safeSize2;
|
|
}
|
|
if (fuzzyNumbersEqual(deltaRemaining, 0)) {
|
|
break;
|
|
}
|
|
if (delta > 0) {
|
|
index--;
|
|
} else {
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const totalSize = nextLayout.reduce((total, size) => size + total, 0);
|
|
if (!fuzzyNumbersEqual(totalSize, 100)) {
|
|
return prevLayout;
|
|
}
|
|
return nextLayout;
|
|
}
|
|
function calculateAriaValues({
|
|
layout,
|
|
panelsArray,
|
|
pivotIndices
|
|
}) {
|
|
let currentMinSize = 0;
|
|
let currentMaxSize = 100;
|
|
let totalMinSize = 0;
|
|
let totalMaxSize = 0;
|
|
const firstIndex = pivotIndices[0];
|
|
assert(firstIndex != null, "No pivot index found");
|
|
panelsArray.forEach((panelData, index) => {
|
|
const {
|
|
constraints
|
|
} = panelData;
|
|
const {
|
|
maxSize = 100,
|
|
minSize = 0
|
|
} = constraints;
|
|
if (index === firstIndex) {
|
|
currentMinSize = minSize;
|
|
currentMaxSize = maxSize;
|
|
} else {
|
|
totalMinSize += minSize;
|
|
totalMaxSize += maxSize;
|
|
}
|
|
});
|
|
const valueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
const valueMin = Math.max(currentMinSize, 100 - totalMaxSize);
|
|
const valueNow = layout[firstIndex];
|
|
return {
|
|
valueMax,
|
|
valueMin,
|
|
valueNow
|
|
};
|
|
}
|
|
function getResizeHandleElementsForGroup(groupId, scope = document) {
|
|
return Array.from(scope.querySelectorAll(`[${DATA_ATTRIBUTES.resizeHandleId}][data-panel-group-id="${groupId}"]`));
|
|
}
|
|
function getResizeHandleElementIndex(groupId, id, scope = document) {
|
|
const handles = getResizeHandleElementsForGroup(groupId, scope);
|
|
const index = handles.findIndex((handle) => handle.getAttribute(DATA_ATTRIBUTES.resizeHandleId) === id);
|
|
return index !== null && index !== void 0 ? index : null;
|
|
}
|
|
function determinePivotIndices(groupId, dragHandleId, panelGroupElement) {
|
|
const index = getResizeHandleElementIndex(groupId, dragHandleId, panelGroupElement);
|
|
return index != null ? [index, index + 1] : [-1, -1];
|
|
}
|
|
function isHTMLElement(target) {
|
|
if (target instanceof HTMLElement) {
|
|
return true;
|
|
}
|
|
return typeof target === "object" && target !== null && "tagName" in target && "getAttribute" in target;
|
|
}
|
|
function getPanelGroupElement(id, rootElement = document) {
|
|
if (isHTMLElement(rootElement) && rootElement.dataset.panelGroupId == id) {
|
|
return rootElement;
|
|
}
|
|
const element = rootElement.querySelector(`[data-panel-group][data-panel-group-id="${id}"]`);
|
|
if (element) {
|
|
return element;
|
|
}
|
|
return null;
|
|
}
|
|
function getResizeHandleElement(id, scope = document) {
|
|
const element = scope.querySelector(`[${DATA_ATTRIBUTES.resizeHandleId}="${id}"]`);
|
|
if (element) {
|
|
return element;
|
|
}
|
|
return null;
|
|
}
|
|
function getResizeHandlePanelIds(groupId, handleId, panelsArray, scope = document) {
|
|
var _panelsArray$index$id, _panelsArray$index, _panelsArray$id, _panelsArray;
|
|
const handle = getResizeHandleElement(handleId, scope);
|
|
const handles = getResizeHandleElementsForGroup(groupId, scope);
|
|
const index = handle ? handles.indexOf(handle) : -1;
|
|
const idBefore = (_panelsArray$index$id = (_panelsArray$index = panelsArray[index]) === null || _panelsArray$index === void 0 ? void 0 : _panelsArray$index.id) !== null && _panelsArray$index$id !== void 0 ? _panelsArray$index$id : null;
|
|
const idAfter = (_panelsArray$id = (_panelsArray = panelsArray[index + 1]) === null || _panelsArray === void 0 ? void 0 : _panelsArray.id) !== null && _panelsArray$id !== void 0 ? _panelsArray$id : null;
|
|
return [idBefore, idAfter];
|
|
}
|
|
function useWindowSplitterPanelGroupBehavior({
|
|
committedValuesRef,
|
|
eagerValuesRef,
|
|
groupId,
|
|
layout,
|
|
panelDataArray,
|
|
panelGroupElement,
|
|
setLayout
|
|
}) {
|
|
const devWarningsRef = (0, import_react.useRef)({
|
|
didWarnAboutMissingResizeHandle: false
|
|
});
|
|
useIsomorphicLayoutEffect(() => {
|
|
if (!panelGroupElement) {
|
|
return;
|
|
}
|
|
const resizeHandleElements = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
for (let index = 0; index < panelDataArray.length - 1; index++) {
|
|
const {
|
|
valueMax,
|
|
valueMin,
|
|
valueNow
|
|
} = calculateAriaValues({
|
|
layout,
|
|
panelsArray: panelDataArray,
|
|
pivotIndices: [index, index + 1]
|
|
});
|
|
const resizeHandleElement = resizeHandleElements[index];
|
|
if (resizeHandleElement == null) {
|
|
{
|
|
const {
|
|
didWarnAboutMissingResizeHandle
|
|
} = devWarningsRef.current;
|
|
if (!didWarnAboutMissingResizeHandle) {
|
|
devWarningsRef.current.didWarnAboutMissingResizeHandle = true;
|
|
console.warn(`WARNING: Missing resize handle for PanelGroup "${groupId}"`);
|
|
}
|
|
}
|
|
} else {
|
|
const panelData = panelDataArray[index];
|
|
assert(panelData, `No panel data found for index "${index}"`);
|
|
resizeHandleElement.setAttribute("aria-controls", panelData.id);
|
|
resizeHandleElement.setAttribute("aria-valuemax", "" + Math.round(valueMax));
|
|
resizeHandleElement.setAttribute("aria-valuemin", "" + Math.round(valueMin));
|
|
resizeHandleElement.setAttribute("aria-valuenow", valueNow != null ? "" + Math.round(valueNow) : "");
|
|
}
|
|
}
|
|
return () => {
|
|
resizeHandleElements.forEach((resizeHandleElement, index) => {
|
|
resizeHandleElement.removeAttribute("aria-controls");
|
|
resizeHandleElement.removeAttribute("aria-valuemax");
|
|
resizeHandleElement.removeAttribute("aria-valuemin");
|
|
resizeHandleElement.removeAttribute("aria-valuenow");
|
|
});
|
|
};
|
|
}, [groupId, layout, panelDataArray, panelGroupElement]);
|
|
(0, import_react.useEffect)(() => {
|
|
if (!panelGroupElement) {
|
|
return;
|
|
}
|
|
const eagerValues = eagerValuesRef.current;
|
|
assert(eagerValues, `Eager values not found`);
|
|
const {
|
|
panelDataArray: panelDataArray2
|
|
} = eagerValues;
|
|
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
assert(handles, `No resize handles found for group id "${groupId}"`);
|
|
const cleanupFunctions = handles.map((handle) => {
|
|
const handleId = handle.getAttribute(DATA_ATTRIBUTES.resizeHandleId);
|
|
assert(handleId, `Resize handle element has no handle id attribute`);
|
|
const [idBefore, idAfter] = getResizeHandlePanelIds(groupId, handleId, panelDataArray2, panelGroupElement);
|
|
if (idBefore == null || idAfter == null) {
|
|
return () => {
|
|
};
|
|
}
|
|
const onKeyDown = (event) => {
|
|
if (event.defaultPrevented) {
|
|
return;
|
|
}
|
|
switch (event.key) {
|
|
case "Enter": {
|
|
event.preventDefault();
|
|
const index = panelDataArray2.findIndex((panelData) => panelData.id === idBefore);
|
|
if (index >= 0) {
|
|
const panelData = panelDataArray2[index];
|
|
assert(panelData, `No panel data found for index ${index}`);
|
|
const size = layout[index];
|
|
const {
|
|
collapsedSize = 0,
|
|
collapsible,
|
|
minSize = 0
|
|
} = panelData.constraints;
|
|
if (size != null && collapsible) {
|
|
const nextLayout = adjustLayoutByDelta({
|
|
delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
|
|
initialLayout: layout,
|
|
panelConstraints: panelDataArray2.map((panelData2) => panelData2.constraints),
|
|
pivotIndices: determinePivotIndices(groupId, handleId, panelGroupElement),
|
|
prevLayout: layout,
|
|
trigger: "keyboard"
|
|
});
|
|
if (layout !== nextLayout) {
|
|
setLayout(nextLayout);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
handle.addEventListener("keydown", onKeyDown);
|
|
return () => {
|
|
handle.removeEventListener("keydown", onKeyDown);
|
|
};
|
|
});
|
|
return () => {
|
|
cleanupFunctions.forEach((cleanupFunction) => cleanupFunction());
|
|
};
|
|
}, [panelGroupElement, committedValuesRef, eagerValuesRef, groupId, layout, panelDataArray, setLayout]);
|
|
}
|
|
function areEqual(arrayA, arrayB) {
|
|
if (arrayA.length !== arrayB.length) {
|
|
return false;
|
|
}
|
|
for (let index = 0; index < arrayA.length; index++) {
|
|
if (arrayA[index] !== arrayB[index]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function getResizeEventCursorPosition(direction, event) {
|
|
const isHorizontal = direction === "horizontal";
|
|
const {
|
|
x,
|
|
y
|
|
} = getResizeEventCoordinates(event);
|
|
return isHorizontal ? x : y;
|
|
}
|
|
function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
|
|
const isHorizontal = direction === "horizontal";
|
|
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElement);
|
|
assert(handleElement, `No resize handle element found for id "${dragHandleId}"`);
|
|
const groupId = handleElement.getAttribute(DATA_ATTRIBUTES.groupId);
|
|
assert(groupId, `Resize handle element has no group id attribute`);
|
|
let {
|
|
initialCursorPosition
|
|
} = initialDragState;
|
|
const cursorPosition = getResizeEventCursorPosition(direction, event);
|
|
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
assert(groupElement, `No group element found for id "${groupId}"`);
|
|
const groupRect = groupElement.getBoundingClientRect();
|
|
const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
|
|
const offsetPixels = cursorPosition - initialCursorPosition;
|
|
const offsetPercentage = offsetPixels / groupSizeInPixels * 100;
|
|
return offsetPercentage;
|
|
}
|
|
function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy, panelGroupElement) {
|
|
if (isKeyDown(event)) {
|
|
const isHorizontal = direction === "horizontal";
|
|
let delta = 0;
|
|
if (event.shiftKey) {
|
|
delta = 100;
|
|
} else if (keyboardResizeBy != null) {
|
|
delta = keyboardResizeBy;
|
|
} else {
|
|
delta = 10;
|
|
}
|
|
let movement = 0;
|
|
switch (event.key) {
|
|
case "ArrowDown":
|
|
movement = isHorizontal ? 0 : delta;
|
|
break;
|
|
case "ArrowLeft":
|
|
movement = isHorizontal ? -delta : 0;
|
|
break;
|
|
case "ArrowRight":
|
|
movement = isHorizontal ? delta : 0;
|
|
break;
|
|
case "ArrowUp":
|
|
movement = isHorizontal ? 0 : -delta;
|
|
break;
|
|
case "End":
|
|
movement = 100;
|
|
break;
|
|
case "Home":
|
|
movement = -100;
|
|
break;
|
|
}
|
|
return movement;
|
|
} else {
|
|
if (initialDragState == null) {
|
|
return 0;
|
|
}
|
|
return calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement);
|
|
}
|
|
}
|
|
function calculateUnsafeDefaultLayout({
|
|
panelDataArray
|
|
}) {
|
|
const layout = Array(panelDataArray.length);
|
|
const panelConstraintsArray = panelDataArray.map((panelData) => panelData.constraints);
|
|
let numPanelsWithSizes = 0;
|
|
let remainingSize = 100;
|
|
for (let index = 0; index < panelDataArray.length; index++) {
|
|
const panelConstraints = panelConstraintsArray[index];
|
|
assert(panelConstraints, `Panel constraints not found for index ${index}`);
|
|
const {
|
|
defaultSize
|
|
} = panelConstraints;
|
|
if (defaultSize != null) {
|
|
numPanelsWithSizes++;
|
|
layout[index] = defaultSize;
|
|
remainingSize -= defaultSize;
|
|
}
|
|
}
|
|
for (let index = 0; index < panelDataArray.length; index++) {
|
|
const panelConstraints = panelConstraintsArray[index];
|
|
assert(panelConstraints, `Panel constraints not found for index ${index}`);
|
|
const {
|
|
defaultSize
|
|
} = panelConstraints;
|
|
if (defaultSize != null) {
|
|
continue;
|
|
}
|
|
const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
|
|
const size = remainingSize / numRemainingPanels;
|
|
numPanelsWithSizes++;
|
|
layout[index] = size;
|
|
remainingSize -= size;
|
|
}
|
|
return layout;
|
|
}
|
|
function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
|
|
layout.forEach((size, index) => {
|
|
const panelData = panelsArray[index];
|
|
assert(panelData, `Panel data not found for index ${index}`);
|
|
const {
|
|
callbacks,
|
|
constraints,
|
|
id: panelId
|
|
} = panelData;
|
|
const {
|
|
collapsedSize = 0,
|
|
collapsible
|
|
} = constraints;
|
|
const lastNotifiedSize = panelIdToLastNotifiedSizeMap[panelId];
|
|
if (lastNotifiedSize == null || size !== lastNotifiedSize) {
|
|
panelIdToLastNotifiedSizeMap[panelId] = size;
|
|
const {
|
|
onCollapse,
|
|
onExpand,
|
|
onResize
|
|
} = callbacks;
|
|
if (onResize) {
|
|
onResize(size, lastNotifiedSize);
|
|
}
|
|
if (collapsible && (onCollapse || onExpand)) {
|
|
if (onExpand && (lastNotifiedSize == null || fuzzyNumbersEqual$1(lastNotifiedSize, collapsedSize)) && !fuzzyNumbersEqual$1(size, collapsedSize)) {
|
|
onExpand();
|
|
}
|
|
if (onCollapse && (lastNotifiedSize == null || !fuzzyNumbersEqual$1(lastNotifiedSize, collapsedSize)) && fuzzyNumbersEqual$1(size, collapsedSize)) {
|
|
onCollapse();
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function compareLayouts(a, b) {
|
|
if (a.length !== b.length) {
|
|
return false;
|
|
} else {
|
|
for (let index = 0; index < a.length; index++) {
|
|
if (a[index] != b[index]) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function computePanelFlexBoxStyle({
|
|
defaultSize,
|
|
dragState,
|
|
layout,
|
|
panelData,
|
|
panelIndex,
|
|
precision = 3
|
|
}) {
|
|
const size = layout[panelIndex];
|
|
let flexGrow;
|
|
if (size == null) {
|
|
flexGrow = defaultSize != void 0 ? defaultSize.toFixed(precision) : "1";
|
|
} else if (panelData.length === 1) {
|
|
flexGrow = "1";
|
|
} else {
|
|
flexGrow = size.toFixed(precision);
|
|
}
|
|
return {
|
|
flexBasis: 0,
|
|
flexGrow,
|
|
flexShrink: 1,
|
|
// Without this, Panel sizes may be unintentionally overridden by their content
|
|
overflow: "hidden",
|
|
// Disable pointer events inside of a panel during resize
|
|
// This avoid edge cases like nested iframes
|
|
pointerEvents: dragState !== null ? "none" : void 0
|
|
};
|
|
}
|
|
function debounce(callback, durationMs = 10) {
|
|
let timeoutId = null;
|
|
let callable = (...args) => {
|
|
if (timeoutId !== null) {
|
|
clearTimeout(timeoutId);
|
|
}
|
|
timeoutId = setTimeout(() => {
|
|
callback(...args);
|
|
}, durationMs);
|
|
};
|
|
return callable;
|
|
}
|
|
function initializeDefaultStorage(storageObject) {
|
|
try {
|
|
if (typeof localStorage !== "undefined") {
|
|
storageObject.getItem = (name) => {
|
|
return localStorage.getItem(name);
|
|
};
|
|
storageObject.setItem = (name, value) => {
|
|
localStorage.setItem(name, value);
|
|
};
|
|
} else {
|
|
throw new Error("localStorage not supported in this environment");
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
storageObject.getItem = () => null;
|
|
storageObject.setItem = () => {
|
|
};
|
|
}
|
|
}
|
|
function getPanelGroupKey(autoSaveId) {
|
|
return `react-resizable-panels:${autoSaveId}`;
|
|
}
|
|
function getPanelKey(panels) {
|
|
return panels.map((panel) => {
|
|
const {
|
|
constraints,
|
|
id,
|
|
idIsFromProps,
|
|
order
|
|
} = panel;
|
|
if (idIsFromProps) {
|
|
return id;
|
|
} else {
|
|
return order ? `${order}:${JSON.stringify(constraints)}` : JSON.stringify(constraints);
|
|
}
|
|
}).sort((a, b) => a.localeCompare(b)).join(",");
|
|
}
|
|
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
try {
|
|
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
const serialized = storage.getItem(panelGroupKey);
|
|
if (serialized) {
|
|
const parsed = JSON.parse(serialized);
|
|
if (typeof parsed === "object" && parsed != null) {
|
|
return parsed;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
}
|
|
return null;
|
|
}
|
|
function loadPanelGroupState(autoSaveId, panels, storage) {
|
|
var _loadSerializedPanelG, _state$panelKey;
|
|
const state = (_loadSerializedPanelG = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG !== void 0 ? _loadSerializedPanelG : {};
|
|
const panelKey = getPanelKey(panels);
|
|
return (_state$panelKey = state[panelKey]) !== null && _state$panelKey !== void 0 ? _state$panelKey : null;
|
|
}
|
|
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
var _loadSerializedPanelG2;
|
|
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
const panelKey = getPanelKey(panels);
|
|
const state = (_loadSerializedPanelG2 = loadSerializedPanelGroupState(autoSaveId, storage)) !== null && _loadSerializedPanelG2 !== void 0 ? _loadSerializedPanelG2 : {};
|
|
state[panelKey] = {
|
|
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
layout: sizes
|
|
};
|
|
try {
|
|
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
}
|
|
function validatePanelConstraints({
|
|
panelConstraints: panelConstraintsArray,
|
|
panelId,
|
|
panelIndex
|
|
}) {
|
|
{
|
|
const warnings = [];
|
|
const panelConstraints = panelConstraintsArray[panelIndex];
|
|
assert(panelConstraints, `No panel constraints found for index ${panelIndex}`);
|
|
const {
|
|
collapsedSize = 0,
|
|
collapsible = false,
|
|
defaultSize,
|
|
maxSize = 100,
|
|
minSize = 0
|
|
} = panelConstraints;
|
|
if (minSize > maxSize) {
|
|
warnings.push(`min size (${minSize}%) should not be greater than max size (${maxSize}%)`);
|
|
}
|
|
if (defaultSize != null) {
|
|
if (defaultSize < 0) {
|
|
warnings.push("default size should not be less than 0");
|
|
} else if (defaultSize < minSize && (!collapsible || defaultSize !== collapsedSize)) {
|
|
warnings.push("default size should not be less than min size");
|
|
}
|
|
if (defaultSize > 100) {
|
|
warnings.push("default size should not be greater than 100");
|
|
} else if (defaultSize > maxSize) {
|
|
warnings.push("default size should not be greater than max size");
|
|
}
|
|
}
|
|
if (collapsedSize > minSize) {
|
|
warnings.push("collapsed size should not be greater than min size");
|
|
}
|
|
if (warnings.length > 0) {
|
|
const name = panelId != null ? `Panel "${panelId}"` : "Panel";
|
|
console.warn(`${name} has an invalid configuration:
|
|
|
|
${warnings.join("\n")}`);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function validatePanelGroupLayout({
|
|
layout: prevLayout,
|
|
panelConstraints
|
|
}) {
|
|
const nextLayout = [...prevLayout];
|
|
const nextLayoutTotalSize = nextLayout.reduce((accumulated, current) => accumulated + current, 0);
|
|
if (nextLayout.length !== panelConstraints.length) {
|
|
throw Error(`Invalid ${panelConstraints.length} panel layout: ${nextLayout.map((size) => `${size}%`).join(", ")}`);
|
|
} else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100) && nextLayout.length > 0) {
|
|
{
|
|
console.warn(`WARNING: Invalid layout total size: ${nextLayout.map((size) => `${size}%`).join(", ")}. Layout normalization will be applied.`);
|
|
}
|
|
for (let index = 0; index < panelConstraints.length; index++) {
|
|
const unsafeSize = nextLayout[index];
|
|
assert(unsafeSize != null, `No layout data found for index ${index}`);
|
|
const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
|
|
nextLayout[index] = safeSize;
|
|
}
|
|
}
|
|
let remainingSize = 0;
|
|
for (let index = 0; index < panelConstraints.length; index++) {
|
|
const unsafeSize = nextLayout[index];
|
|
assert(unsafeSize != null, `No layout data found for index ${index}`);
|
|
const safeSize = resizePanel({
|
|
panelConstraints,
|
|
panelIndex: index,
|
|
size: unsafeSize
|
|
});
|
|
if (unsafeSize != safeSize) {
|
|
remainingSize += unsafeSize - safeSize;
|
|
nextLayout[index] = safeSize;
|
|
}
|
|
}
|
|
if (!fuzzyNumbersEqual(remainingSize, 0)) {
|
|
for (let index = 0; index < panelConstraints.length; index++) {
|
|
const prevSize = nextLayout[index];
|
|
assert(prevSize != null, `No layout data found for index ${index}`);
|
|
const unsafeSize = prevSize + remainingSize;
|
|
const safeSize = resizePanel({
|
|
panelConstraints,
|
|
panelIndex: index,
|
|
size: unsafeSize
|
|
});
|
|
if (prevSize !== safeSize) {
|
|
remainingSize -= safeSize - prevSize;
|
|
nextLayout[index] = safeSize;
|
|
if (fuzzyNumbersEqual(remainingSize, 0)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nextLayout;
|
|
}
|
|
var LOCAL_STORAGE_DEBOUNCE_INTERVAL = 100;
|
|
var defaultStorage = {
|
|
getItem: (name) => {
|
|
initializeDefaultStorage(defaultStorage);
|
|
return defaultStorage.getItem(name);
|
|
},
|
|
setItem: (name, value) => {
|
|
initializeDefaultStorage(defaultStorage);
|
|
defaultStorage.setItem(name, value);
|
|
}
|
|
};
|
|
var debounceMap = {};
|
|
function PanelGroupWithForwardedRef({
|
|
autoSaveId = null,
|
|
children,
|
|
className: classNameFromProps = "",
|
|
direction,
|
|
forwardedRef,
|
|
id: idFromProps = null,
|
|
onLayout = null,
|
|
keyboardResizeBy = null,
|
|
storage = defaultStorage,
|
|
style: styleFromProps,
|
|
tagName: Type = "div",
|
|
...rest
|
|
}) {
|
|
const groupId = useUniqueId(idFromProps);
|
|
const panelGroupElementRef = (0, import_react.useRef)(null);
|
|
const [dragState, setDragState] = (0, import_react.useState)(null);
|
|
const [layout, setLayout] = (0, import_react.useState)([]);
|
|
const forceUpdate = useForceUpdate();
|
|
const panelIdToLastNotifiedSizeMapRef = (0, import_react.useRef)({});
|
|
const panelSizeBeforeCollapseRef = (0, import_react.useRef)(/* @__PURE__ */ new Map());
|
|
const prevDeltaRef = (0, import_react.useRef)(0);
|
|
const committedValuesRef = (0, import_react.useRef)({
|
|
autoSaveId,
|
|
direction,
|
|
dragState,
|
|
id: groupId,
|
|
keyboardResizeBy,
|
|
onLayout,
|
|
storage
|
|
});
|
|
const eagerValuesRef = (0, import_react.useRef)({
|
|
layout,
|
|
panelDataArray: [],
|
|
panelDataArrayChanged: false
|
|
});
|
|
const devWarningsRef = (0, import_react.useRef)({
|
|
didLogIdAndOrderWarning: false,
|
|
didLogPanelConstraintsWarning: false,
|
|
prevPanelIds: []
|
|
});
|
|
(0, import_react.useImperativeHandle)(forwardedRef, () => ({
|
|
getId: () => committedValuesRef.current.id,
|
|
getLayout: () => {
|
|
const {
|
|
layout: layout2
|
|
} = eagerValuesRef.current;
|
|
return layout2;
|
|
},
|
|
setLayout: (unsafeLayout) => {
|
|
const {
|
|
onLayout: onLayout2
|
|
} = committedValuesRef.current;
|
|
const {
|
|
layout: prevLayout,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const safeLayout = validatePanelGroupLayout({
|
|
layout: unsafeLayout,
|
|
panelConstraints: panelDataArray.map((panelData) => panelData.constraints)
|
|
});
|
|
if (!areEqual(prevLayout, safeLayout)) {
|
|
setLayout(safeLayout);
|
|
eagerValuesRef.current.layout = safeLayout;
|
|
if (onLayout2) {
|
|
onLayout2(safeLayout);
|
|
}
|
|
callPanelCallbacks(panelDataArray, safeLayout, panelIdToLastNotifiedSizeMapRef.current);
|
|
}
|
|
}
|
|
}), []);
|
|
useIsomorphicLayoutEffect(() => {
|
|
committedValuesRef.current.autoSaveId = autoSaveId;
|
|
committedValuesRef.current.direction = direction;
|
|
committedValuesRef.current.dragState = dragState;
|
|
committedValuesRef.current.id = groupId;
|
|
committedValuesRef.current.onLayout = onLayout;
|
|
committedValuesRef.current.storage = storage;
|
|
});
|
|
useWindowSplitterPanelGroupBehavior({
|
|
committedValuesRef,
|
|
eagerValuesRef,
|
|
groupId,
|
|
layout,
|
|
panelDataArray: eagerValuesRef.current.panelDataArray,
|
|
setLayout,
|
|
panelGroupElement: panelGroupElementRef.current
|
|
});
|
|
(0, import_react.useEffect)(() => {
|
|
const {
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
if (autoSaveId) {
|
|
if (layout.length === 0 || layout.length !== panelDataArray.length) {
|
|
return;
|
|
}
|
|
let debouncedSave = debounceMap[autoSaveId];
|
|
if (debouncedSave == null) {
|
|
debouncedSave = debounce(savePanelGroupState, LOCAL_STORAGE_DEBOUNCE_INTERVAL);
|
|
debounceMap[autoSaveId] = debouncedSave;
|
|
}
|
|
const clonedPanelDataArray = [...panelDataArray];
|
|
const clonedPanelSizesBeforeCollapse = new Map(panelSizeBeforeCollapseRef.current);
|
|
debouncedSave(autoSaveId, clonedPanelDataArray, clonedPanelSizesBeforeCollapse, layout, storage);
|
|
}
|
|
}, [autoSaveId, layout, storage]);
|
|
(0, import_react.useEffect)(() => {
|
|
{
|
|
const {
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const {
|
|
didLogIdAndOrderWarning,
|
|
didLogPanelConstraintsWarning,
|
|
prevPanelIds
|
|
} = devWarningsRef.current;
|
|
if (!didLogIdAndOrderWarning) {
|
|
const panelIds = panelDataArray.map(({
|
|
id
|
|
}) => id);
|
|
devWarningsRef.current.prevPanelIds = panelIds;
|
|
const panelsHaveChanged = prevPanelIds.length > 0 && !areEqual(prevPanelIds, panelIds);
|
|
if (panelsHaveChanged) {
|
|
if (panelDataArray.find(({
|
|
idIsFromProps,
|
|
order
|
|
}) => !idIsFromProps || order == null)) {
|
|
devWarningsRef.current.didLogIdAndOrderWarning = true;
|
|
console.warn(`WARNING: Panel id and order props recommended when panels are dynamically rendered`);
|
|
}
|
|
}
|
|
}
|
|
if (!didLogPanelConstraintsWarning) {
|
|
const panelConstraints = panelDataArray.map((panelData) => panelData.constraints);
|
|
for (let panelIndex = 0; panelIndex < panelConstraints.length; panelIndex++) {
|
|
const panelData = panelDataArray[panelIndex];
|
|
assert(panelData, `Panel data not found for index ${panelIndex}`);
|
|
const isValid = validatePanelConstraints({
|
|
panelConstraints,
|
|
panelId: panelData.id,
|
|
panelIndex
|
|
});
|
|
if (!isValid) {
|
|
devWarningsRef.current.didLogPanelConstraintsWarning = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
const collapsePanel = (0, import_react.useCallback)((panelData) => {
|
|
const {
|
|
onLayout: onLayout2
|
|
} = committedValuesRef.current;
|
|
const {
|
|
layout: prevLayout,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
if (panelData.constraints.collapsible) {
|
|
const panelConstraintsArray = panelDataArray.map((panelData2) => panelData2.constraints);
|
|
const {
|
|
collapsedSize = 0,
|
|
panelSize,
|
|
pivotIndices
|
|
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
if (!fuzzyNumbersEqual$1(panelSize, collapsedSize)) {
|
|
panelSizeBeforeCollapseRef.current.set(panelData.id, panelSize);
|
|
const isLastPanel = findPanelDataIndex(panelDataArray, panelData) === panelDataArray.length - 1;
|
|
const delta = isLastPanel ? panelSize - collapsedSize : collapsedSize - panelSize;
|
|
const nextLayout = adjustLayoutByDelta({
|
|
delta,
|
|
initialLayout: prevLayout,
|
|
panelConstraints: panelConstraintsArray,
|
|
pivotIndices,
|
|
prevLayout,
|
|
trigger: "imperative-api"
|
|
});
|
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
setLayout(nextLayout);
|
|
eagerValuesRef.current.layout = nextLayout;
|
|
if (onLayout2) {
|
|
onLayout2(nextLayout);
|
|
}
|
|
callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
|
|
}
|
|
}
|
|
}
|
|
}, []);
|
|
const expandPanel = (0, import_react.useCallback)((panelData, minSizeOverride) => {
|
|
const {
|
|
onLayout: onLayout2
|
|
} = committedValuesRef.current;
|
|
const {
|
|
layout: prevLayout,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
if (panelData.constraints.collapsible) {
|
|
const panelConstraintsArray = panelDataArray.map((panelData2) => panelData2.constraints);
|
|
const {
|
|
collapsedSize = 0,
|
|
panelSize = 0,
|
|
minSize: minSizeFromProps = 0,
|
|
pivotIndices
|
|
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
const minSize = minSizeOverride !== null && minSizeOverride !== void 0 ? minSizeOverride : minSizeFromProps;
|
|
if (fuzzyNumbersEqual$1(panelSize, collapsedSize)) {
|
|
const prevPanelSize = panelSizeBeforeCollapseRef.current.get(panelData.id);
|
|
const baseSize = prevPanelSize != null && prevPanelSize >= minSize ? prevPanelSize : minSize;
|
|
const isLastPanel = findPanelDataIndex(panelDataArray, panelData) === panelDataArray.length - 1;
|
|
const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
|
|
const nextLayout = adjustLayoutByDelta({
|
|
delta,
|
|
initialLayout: prevLayout,
|
|
panelConstraints: panelConstraintsArray,
|
|
pivotIndices,
|
|
prevLayout,
|
|
trigger: "imperative-api"
|
|
});
|
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
setLayout(nextLayout);
|
|
eagerValuesRef.current.layout = nextLayout;
|
|
if (onLayout2) {
|
|
onLayout2(nextLayout);
|
|
}
|
|
callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
|
|
}
|
|
}
|
|
}
|
|
}, []);
|
|
const getPanelSize = (0, import_react.useCallback)((panelData) => {
|
|
const {
|
|
layout: layout2,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const {
|
|
panelSize
|
|
} = panelDataHelper(panelDataArray, panelData, layout2);
|
|
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
return panelSize;
|
|
}, []);
|
|
const getPanelStyle = (0, import_react.useCallback)((panelData, defaultSize) => {
|
|
const {
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const panelIndex = findPanelDataIndex(panelDataArray, panelData);
|
|
return computePanelFlexBoxStyle({
|
|
defaultSize,
|
|
dragState,
|
|
layout,
|
|
panelData: panelDataArray,
|
|
panelIndex
|
|
});
|
|
}, [dragState, layout]);
|
|
const isPanelCollapsed = (0, import_react.useCallback)((panelData) => {
|
|
const {
|
|
layout: layout2,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const {
|
|
collapsedSize = 0,
|
|
collapsible,
|
|
panelSize
|
|
} = panelDataHelper(panelDataArray, panelData, layout2);
|
|
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
return collapsible === true && fuzzyNumbersEqual$1(panelSize, collapsedSize);
|
|
}, []);
|
|
const isPanelExpanded = (0, import_react.useCallback)((panelData) => {
|
|
const {
|
|
layout: layout2,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const {
|
|
collapsedSize = 0,
|
|
collapsible,
|
|
panelSize
|
|
} = panelDataHelper(panelDataArray, panelData, layout2);
|
|
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
return !collapsible || fuzzyCompareNumbers(panelSize, collapsedSize) > 0;
|
|
}, []);
|
|
const registerPanel = (0, import_react.useCallback)((panelData) => {
|
|
const {
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
panelDataArray.push(panelData);
|
|
panelDataArray.sort((panelA, panelB) => {
|
|
const orderA = panelA.order;
|
|
const orderB = panelB.order;
|
|
if (orderA == null && orderB == null) {
|
|
return 0;
|
|
} else if (orderA == null) {
|
|
return -1;
|
|
} else if (orderB == null) {
|
|
return 1;
|
|
} else {
|
|
return orderA - orderB;
|
|
}
|
|
});
|
|
eagerValuesRef.current.panelDataArrayChanged = true;
|
|
forceUpdate();
|
|
}, [forceUpdate]);
|
|
useIsomorphicLayoutEffect(() => {
|
|
if (eagerValuesRef.current.panelDataArrayChanged) {
|
|
eagerValuesRef.current.panelDataArrayChanged = false;
|
|
const {
|
|
autoSaveId: autoSaveId2,
|
|
onLayout: onLayout2,
|
|
storage: storage2
|
|
} = committedValuesRef.current;
|
|
const {
|
|
layout: prevLayout,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
let unsafeLayout = null;
|
|
if (autoSaveId2) {
|
|
const state = loadPanelGroupState(autoSaveId2, panelDataArray, storage2);
|
|
if (state) {
|
|
panelSizeBeforeCollapseRef.current = new Map(Object.entries(state.expandToSizes));
|
|
unsafeLayout = state.layout;
|
|
}
|
|
}
|
|
if (unsafeLayout == null) {
|
|
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
panelDataArray
|
|
});
|
|
}
|
|
const nextLayout = validatePanelGroupLayout({
|
|
layout: unsafeLayout,
|
|
panelConstraints: panelDataArray.map((panelData) => panelData.constraints)
|
|
});
|
|
if (!areEqual(prevLayout, nextLayout)) {
|
|
setLayout(nextLayout);
|
|
eagerValuesRef.current.layout = nextLayout;
|
|
if (onLayout2) {
|
|
onLayout2(nextLayout);
|
|
}
|
|
callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
|
|
}
|
|
}
|
|
});
|
|
useIsomorphicLayoutEffect(() => {
|
|
const eagerValues = eagerValuesRef.current;
|
|
return () => {
|
|
eagerValues.layout = [];
|
|
};
|
|
}, []);
|
|
const registerResizeHandle2 = (0, import_react.useCallback)((dragHandleId) => {
|
|
let isRTL = false;
|
|
const panelGroupElement = panelGroupElementRef.current;
|
|
if (panelGroupElement) {
|
|
const style2 = window.getComputedStyle(panelGroupElement, null);
|
|
if (style2.getPropertyValue("direction") === "rtl") {
|
|
isRTL = true;
|
|
}
|
|
}
|
|
return function resizeHandler(event) {
|
|
event.preventDefault();
|
|
const panelGroupElement2 = panelGroupElementRef.current;
|
|
if (!panelGroupElement2) {
|
|
return () => null;
|
|
}
|
|
const {
|
|
direction: direction2,
|
|
dragState: dragState2,
|
|
id: groupId2,
|
|
keyboardResizeBy: keyboardResizeBy2,
|
|
onLayout: onLayout2
|
|
} = committedValuesRef.current;
|
|
const {
|
|
layout: prevLayout,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const {
|
|
initialLayout
|
|
} = dragState2 !== null && dragState2 !== void 0 ? dragState2 : {};
|
|
const pivotIndices = determinePivotIndices(groupId2, dragHandleId, panelGroupElement2);
|
|
let delta = calculateDeltaPercentage(event, dragHandleId, direction2, dragState2, keyboardResizeBy2, panelGroupElement2);
|
|
const isHorizontal = direction2 === "horizontal";
|
|
if (isHorizontal && isRTL) {
|
|
delta = -delta;
|
|
}
|
|
const panelConstraints = panelDataArray.map((panelData) => panelData.constraints);
|
|
const nextLayout = adjustLayoutByDelta({
|
|
delta,
|
|
initialLayout: initialLayout !== null && initialLayout !== void 0 ? initialLayout : prevLayout,
|
|
panelConstraints,
|
|
pivotIndices,
|
|
prevLayout,
|
|
trigger: isKeyDown(event) ? "keyboard" : "mouse-or-touch"
|
|
});
|
|
const layoutChanged = !compareLayouts(prevLayout, nextLayout);
|
|
if (isPointerEvent(event) || isMouseEvent(event)) {
|
|
if (prevDeltaRef.current != delta) {
|
|
prevDeltaRef.current = delta;
|
|
if (!layoutChanged && delta !== 0) {
|
|
if (isHorizontal) {
|
|
reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_HORIZONTAL_MIN : EXCEEDED_HORIZONTAL_MAX);
|
|
} else {
|
|
reportConstraintsViolation(dragHandleId, delta < 0 ? EXCEEDED_VERTICAL_MIN : EXCEEDED_VERTICAL_MAX);
|
|
}
|
|
} else {
|
|
reportConstraintsViolation(dragHandleId, 0);
|
|
}
|
|
}
|
|
}
|
|
if (layoutChanged) {
|
|
setLayout(nextLayout);
|
|
eagerValuesRef.current.layout = nextLayout;
|
|
if (onLayout2) {
|
|
onLayout2(nextLayout);
|
|
}
|
|
callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
|
|
}
|
|
};
|
|
}, []);
|
|
const resizePanel2 = (0, import_react.useCallback)((panelData, unsafePanelSize) => {
|
|
const {
|
|
onLayout: onLayout2
|
|
} = committedValuesRef.current;
|
|
const {
|
|
layout: prevLayout,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const panelConstraintsArray = panelDataArray.map((panelData2) => panelData2.constraints);
|
|
const {
|
|
panelSize,
|
|
pivotIndices
|
|
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
assert(panelSize != null, `Panel size not found for panel "${panelData.id}"`);
|
|
const isLastPanel = findPanelDataIndex(panelDataArray, panelData) === panelDataArray.length - 1;
|
|
const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
|
|
const nextLayout = adjustLayoutByDelta({
|
|
delta,
|
|
initialLayout: prevLayout,
|
|
panelConstraints: panelConstraintsArray,
|
|
pivotIndices,
|
|
prevLayout,
|
|
trigger: "imperative-api"
|
|
});
|
|
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
setLayout(nextLayout);
|
|
eagerValuesRef.current.layout = nextLayout;
|
|
if (onLayout2) {
|
|
onLayout2(nextLayout);
|
|
}
|
|
callPanelCallbacks(panelDataArray, nextLayout, panelIdToLastNotifiedSizeMapRef.current);
|
|
}
|
|
}, []);
|
|
const reevaluatePanelConstraints = (0, import_react.useCallback)((panelData, prevConstraints) => {
|
|
const {
|
|
layout: layout2,
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const {
|
|
collapsedSize: prevCollapsedSize = 0,
|
|
collapsible: prevCollapsible
|
|
} = prevConstraints;
|
|
const {
|
|
collapsedSize: nextCollapsedSize = 0,
|
|
collapsible: nextCollapsible,
|
|
maxSize: nextMaxSize = 100,
|
|
minSize: nextMinSize = 0
|
|
} = panelData.constraints;
|
|
const {
|
|
panelSize: prevPanelSize
|
|
} = panelDataHelper(panelDataArray, panelData, layout2);
|
|
if (prevPanelSize == null) {
|
|
return;
|
|
}
|
|
if (prevCollapsible && nextCollapsible && fuzzyNumbersEqual$1(prevPanelSize, prevCollapsedSize)) {
|
|
if (!fuzzyNumbersEqual$1(prevCollapsedSize, nextCollapsedSize)) {
|
|
resizePanel2(panelData, nextCollapsedSize);
|
|
}
|
|
} else if (prevPanelSize < nextMinSize) {
|
|
resizePanel2(panelData, nextMinSize);
|
|
} else if (prevPanelSize > nextMaxSize) {
|
|
resizePanel2(panelData, nextMaxSize);
|
|
}
|
|
}, [resizePanel2]);
|
|
const startDragging = (0, import_react.useCallback)((dragHandleId, event) => {
|
|
const {
|
|
direction: direction2
|
|
} = committedValuesRef.current;
|
|
const {
|
|
layout: layout2
|
|
} = eagerValuesRef.current;
|
|
if (!panelGroupElementRef.current) {
|
|
return;
|
|
}
|
|
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElementRef.current);
|
|
assert(handleElement, `Drag handle element not found for id "${dragHandleId}"`);
|
|
const initialCursorPosition = getResizeEventCursorPosition(direction2, event);
|
|
setDragState({
|
|
dragHandleId,
|
|
dragHandleRect: handleElement.getBoundingClientRect(),
|
|
initialCursorPosition,
|
|
initialLayout: layout2
|
|
});
|
|
}, []);
|
|
const stopDragging = (0, import_react.useCallback)(() => {
|
|
setDragState(null);
|
|
}, []);
|
|
const unregisterPanel = (0, import_react.useCallback)((panelData) => {
|
|
const {
|
|
panelDataArray
|
|
} = eagerValuesRef.current;
|
|
const index = findPanelDataIndex(panelDataArray, panelData);
|
|
if (index >= 0) {
|
|
panelDataArray.splice(index, 1);
|
|
delete panelIdToLastNotifiedSizeMapRef.current[panelData.id];
|
|
eagerValuesRef.current.panelDataArrayChanged = true;
|
|
forceUpdate();
|
|
}
|
|
}, [forceUpdate]);
|
|
const context = (0, import_react.useMemo)(() => ({
|
|
collapsePanel,
|
|
direction,
|
|
dragState,
|
|
expandPanel,
|
|
getPanelSize,
|
|
getPanelStyle,
|
|
groupId,
|
|
isPanelCollapsed,
|
|
isPanelExpanded,
|
|
reevaluatePanelConstraints,
|
|
registerPanel,
|
|
registerResizeHandle: registerResizeHandle2,
|
|
resizePanel: resizePanel2,
|
|
startDragging,
|
|
stopDragging,
|
|
unregisterPanel,
|
|
panelGroupElement: panelGroupElementRef.current
|
|
}), [collapsePanel, dragState, direction, expandPanel, getPanelSize, getPanelStyle, groupId, isPanelCollapsed, isPanelExpanded, reevaluatePanelConstraints, registerPanel, registerResizeHandle2, resizePanel2, startDragging, stopDragging, unregisterPanel]);
|
|
const style = {
|
|
display: "flex",
|
|
flexDirection: direction === "horizontal" ? "row" : "column",
|
|
height: "100%",
|
|
overflow: "hidden",
|
|
width: "100%"
|
|
};
|
|
return (0, import_react.createElement)(PanelGroupContext.Provider, {
|
|
value: context
|
|
}, (0, import_react.createElement)(Type, {
|
|
...rest,
|
|
children,
|
|
className: classNameFromProps,
|
|
id: idFromProps,
|
|
ref: panelGroupElementRef,
|
|
style: {
|
|
...style,
|
|
...styleFromProps
|
|
},
|
|
// CSS selectors
|
|
[DATA_ATTRIBUTES.group]: "",
|
|
[DATA_ATTRIBUTES.groupDirection]: direction,
|
|
[DATA_ATTRIBUTES.groupId]: groupId
|
|
}));
|
|
}
|
|
var PanelGroup = (0, import_react.forwardRef)((props2, ref) => (0, import_react.createElement)(PanelGroupWithForwardedRef, {
|
|
...props2,
|
|
forwardedRef: ref
|
|
}));
|
|
PanelGroupWithForwardedRef.displayName = "PanelGroup";
|
|
PanelGroup.displayName = "forwardRef(PanelGroup)";
|
|
function findPanelDataIndex(panelDataArray, panelData) {
|
|
return panelDataArray.findIndex((prevPanelData) => prevPanelData === panelData || prevPanelData.id === panelData.id);
|
|
}
|
|
function panelDataHelper(panelDataArray, panelData, layout) {
|
|
const panelIndex = findPanelDataIndex(panelDataArray, panelData);
|
|
const isLastPanel = panelIndex === panelDataArray.length - 1;
|
|
const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
|
|
const panelSize = layout[panelIndex];
|
|
return {
|
|
...panelData.constraints,
|
|
panelSize,
|
|
pivotIndices
|
|
};
|
|
}
|
|
function useWindowSplitterResizeHandlerBehavior({
|
|
disabled,
|
|
handleId,
|
|
resizeHandler,
|
|
panelGroupElement
|
|
}) {
|
|
(0, import_react.useEffect)(() => {
|
|
if (disabled || resizeHandler == null || panelGroupElement == null) {
|
|
return;
|
|
}
|
|
const handleElement = getResizeHandleElement(handleId, panelGroupElement);
|
|
if (handleElement == null) {
|
|
return;
|
|
}
|
|
const onKeyDown = (event) => {
|
|
if (event.defaultPrevented) {
|
|
return;
|
|
}
|
|
switch (event.key) {
|
|
case "ArrowDown":
|
|
case "ArrowLeft":
|
|
case "ArrowRight":
|
|
case "ArrowUp":
|
|
case "End":
|
|
case "Home": {
|
|
event.preventDefault();
|
|
resizeHandler(event);
|
|
break;
|
|
}
|
|
case "F6": {
|
|
event.preventDefault();
|
|
const groupId = handleElement.getAttribute(DATA_ATTRIBUTES.groupId);
|
|
assert(groupId, `No group element found for id "${groupId}"`);
|
|
const handles = getResizeHandleElementsForGroup(groupId, panelGroupElement);
|
|
const index = getResizeHandleElementIndex(groupId, handleId, panelGroupElement);
|
|
assert(index !== null, `No resize element found for id "${handleId}"`);
|
|
const nextIndex = event.shiftKey ? index > 0 ? index - 1 : handles.length - 1 : index + 1 < handles.length ? index + 1 : 0;
|
|
const nextHandle = handles[nextIndex];
|
|
nextHandle.focus();
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
handleElement.addEventListener("keydown", onKeyDown);
|
|
return () => {
|
|
handleElement.removeEventListener("keydown", onKeyDown);
|
|
};
|
|
}, [panelGroupElement, disabled, handleId, resizeHandler]);
|
|
}
|
|
function PanelResizeHandle({
|
|
children = null,
|
|
className: classNameFromProps = "",
|
|
disabled = false,
|
|
hitAreaMargins,
|
|
id: idFromProps,
|
|
onBlur,
|
|
onClick,
|
|
onDragging,
|
|
onFocus,
|
|
onPointerDown,
|
|
onPointerUp,
|
|
style: styleFromProps = {},
|
|
tabIndex = 0,
|
|
tagName: Type = "div",
|
|
...rest
|
|
}) {
|
|
var _hitAreaMargins$coars, _hitAreaMargins$fine;
|
|
const elementRef = (0, import_react.useRef)(null);
|
|
const callbacksRef = (0, import_react.useRef)({
|
|
onClick,
|
|
onDragging,
|
|
onPointerDown,
|
|
onPointerUp
|
|
});
|
|
(0, import_react.useEffect)(() => {
|
|
callbacksRef.current.onClick = onClick;
|
|
callbacksRef.current.onDragging = onDragging;
|
|
callbacksRef.current.onPointerDown = onPointerDown;
|
|
callbacksRef.current.onPointerUp = onPointerUp;
|
|
});
|
|
const panelGroupContext = (0, import_react.useContext)(PanelGroupContext);
|
|
if (panelGroupContext === null) {
|
|
throw Error(`PanelResizeHandle components must be rendered within a PanelGroup container`);
|
|
}
|
|
const {
|
|
direction,
|
|
groupId,
|
|
registerResizeHandle: registerResizeHandleWithParentGroup,
|
|
startDragging,
|
|
stopDragging,
|
|
panelGroupElement
|
|
} = panelGroupContext;
|
|
const resizeHandleId = useUniqueId(idFromProps);
|
|
const [state, setState] = (0, import_react.useState)("inactive");
|
|
const [isFocused, setIsFocused] = (0, import_react.useState)(false);
|
|
const [resizeHandler, setResizeHandler] = (0, import_react.useState)(null);
|
|
const committedValuesRef = (0, import_react.useRef)({
|
|
state
|
|
});
|
|
useIsomorphicLayoutEffect(() => {
|
|
committedValuesRef.current.state = state;
|
|
});
|
|
(0, import_react.useEffect)(() => {
|
|
if (disabled) {
|
|
setResizeHandler(null);
|
|
} else {
|
|
const resizeHandler2 = registerResizeHandleWithParentGroup(resizeHandleId);
|
|
setResizeHandler(() => resizeHandler2);
|
|
}
|
|
}, [disabled, resizeHandleId, registerResizeHandleWithParentGroup]);
|
|
const coarseHitAreaMargins = (_hitAreaMargins$coars = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.coarse) !== null && _hitAreaMargins$coars !== void 0 ? _hitAreaMargins$coars : 15;
|
|
const fineHitAreaMargins = (_hitAreaMargins$fine = hitAreaMargins === null || hitAreaMargins === void 0 ? void 0 : hitAreaMargins.fine) !== null && _hitAreaMargins$fine !== void 0 ? _hitAreaMargins$fine : 5;
|
|
(0, import_react.useEffect)(() => {
|
|
if (disabled || resizeHandler == null) {
|
|
return;
|
|
}
|
|
const element = elementRef.current;
|
|
assert(element, "Element ref not attached");
|
|
let didMove = false;
|
|
const setResizeHandlerState = (action, isActive, event) => {
|
|
if (!isActive) {
|
|
setState("inactive");
|
|
return;
|
|
}
|
|
switch (action) {
|
|
case "down": {
|
|
setState("drag");
|
|
didMove = false;
|
|
assert(event, 'Expected event to be defined for "down" action');
|
|
startDragging(resizeHandleId, event);
|
|
const {
|
|
onDragging: onDragging2,
|
|
onPointerDown: onPointerDown2
|
|
} = callbacksRef.current;
|
|
onDragging2 === null || onDragging2 === void 0 ? void 0 : onDragging2(true);
|
|
onPointerDown2 === null || onPointerDown2 === void 0 ? void 0 : onPointerDown2();
|
|
break;
|
|
}
|
|
case "move": {
|
|
const {
|
|
state: state2
|
|
} = committedValuesRef.current;
|
|
didMove = true;
|
|
if (state2 !== "drag") {
|
|
setState("hover");
|
|
}
|
|
assert(event, 'Expected event to be defined for "move" action');
|
|
resizeHandler(event);
|
|
break;
|
|
}
|
|
case "up": {
|
|
setState("hover");
|
|
stopDragging();
|
|
const {
|
|
onClick: onClick2,
|
|
onDragging: onDragging2,
|
|
onPointerUp: onPointerUp2
|
|
} = callbacksRef.current;
|
|
onDragging2 === null || onDragging2 === void 0 ? void 0 : onDragging2(false);
|
|
onPointerUp2 === null || onPointerUp2 === void 0 ? void 0 : onPointerUp2();
|
|
if (!didMove) {
|
|
onClick2 === null || onClick2 === void 0 ? void 0 : onClick2();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
return registerResizeHandle(resizeHandleId, element, direction, {
|
|
coarse: coarseHitAreaMargins,
|
|
fine: fineHitAreaMargins
|
|
}, setResizeHandlerState);
|
|
}, [coarseHitAreaMargins, direction, disabled, fineHitAreaMargins, registerResizeHandleWithParentGroup, resizeHandleId, resizeHandler, startDragging, stopDragging]);
|
|
useWindowSplitterResizeHandlerBehavior({
|
|
disabled,
|
|
handleId: resizeHandleId,
|
|
resizeHandler,
|
|
panelGroupElement
|
|
});
|
|
const style = {
|
|
touchAction: "none",
|
|
userSelect: "none"
|
|
};
|
|
return (0, import_react.createElement)(Type, {
|
|
...rest,
|
|
children,
|
|
className: classNameFromProps,
|
|
id: idFromProps,
|
|
onBlur: () => {
|
|
setIsFocused(false);
|
|
onBlur === null || onBlur === void 0 ? void 0 : onBlur();
|
|
},
|
|
onFocus: () => {
|
|
setIsFocused(true);
|
|
onFocus === null || onFocus === void 0 ? void 0 : onFocus();
|
|
},
|
|
ref: elementRef,
|
|
role: "separator",
|
|
style: {
|
|
...style,
|
|
...styleFromProps
|
|
},
|
|
tabIndex,
|
|
// CSS selectors
|
|
[DATA_ATTRIBUTES.groupDirection]: direction,
|
|
[DATA_ATTRIBUTES.groupId]: groupId,
|
|
[DATA_ATTRIBUTES.resizeHandle]: "",
|
|
[DATA_ATTRIBUTES.resizeHandleActive]: state === "drag" ? "pointer" : isFocused ? "keyboard" : void 0,
|
|
[DATA_ATTRIBUTES.resizeHandleEnabled]: !disabled,
|
|
[DATA_ATTRIBUTES.resizeHandleId]: resizeHandleId,
|
|
[DATA_ATTRIBUTES.resizeHandleState]: state
|
|
});
|
|
}
|
|
PanelResizeHandle.displayName = "PanelResizeHandle";
|
|
function usePanelGroupContext() {
|
|
const context = (0, import_react.useContext)(PanelGroupContext);
|
|
return {
|
|
direction: context === null || context === void 0 ? void 0 : context.direction,
|
|
groupId: context === null || context === void 0 ? void 0 : context.groupId
|
|
};
|
|
}
|
|
function getPanelElement(id, scope = document) {
|
|
const element = scope.querySelector(`[data-panel-id="${id}"]`);
|
|
if (element) {
|
|
return element;
|
|
}
|
|
return null;
|
|
}
|
|
function getPanelElementsForGroup(groupId, scope = document) {
|
|
return Array.from(scope.querySelectorAll(`[data-panel][data-panel-group-id="${groupId}"]`));
|
|
}
|
|
function getIntersectingRectangle(rectOne, rectTwo, strict) {
|
|
if (!intersects(rectOne, rectTwo, strict)) {
|
|
return {
|
|
x: 0,
|
|
y: 0,
|
|
width: 0,
|
|
height: 0
|
|
};
|
|
}
|
|
return {
|
|
x: Math.max(rectOne.x, rectTwo.x),
|
|
y: Math.max(rectOne.y, rectTwo.y),
|
|
width: Math.min(rectOne.x + rectOne.width, rectTwo.x + rectTwo.width) - Math.max(rectOne.x, rectTwo.x),
|
|
height: Math.min(rectOne.y + rectOne.height, rectTwo.y + rectTwo.height) - Math.max(rectOne.y, rectTwo.y)
|
|
};
|
|
}
|
|
export {
|
|
DATA_ATTRIBUTES,
|
|
Panel,
|
|
PanelGroup,
|
|
PanelResizeHandle,
|
|
assert,
|
|
customizeGlobalCursorStyles,
|
|
disableGlobalCursorStyles,
|
|
enableGlobalCursorStyles,
|
|
getIntersectingRectangle,
|
|
getPanelElement,
|
|
getPanelElementsForGroup,
|
|
getPanelGroupElement,
|
|
getResizeHandleElement,
|
|
getResizeHandleElementIndex,
|
|
getResizeHandleElementsForGroup,
|
|
getResizeHandlePanelIds,
|
|
intersects,
|
|
setNonce,
|
|
usePanelGroupContext
|
|
};
|
|
//# sourceMappingURL=react-resizable-panels.js.map
|