@mantine/core
Version:
React components library focused on usability, accessibility and developer experience
186 lines (185 loc) • 7.15 kB
JavaScript
"use client";
const require_use_props = require("../../core/MantineProvider/use-props/use-props.cjs");
const require_factory = require("../../core/factory/factory.cjs");
const require_Box = require("../../core/Box/Box.cjs");
const require_FloatingWindow_context = require("./FloatingWindow.context.cjs");
let react = require("react");
let _mantine_hooks = require("@mantine/hooks");
let react_jsx_runtime = require("react/jsx-runtime");
//#region packages/@mantine/core/src/components/FloatingWindow/FloatingWindowResizeHandle.tsx
const defaultProps = {};
const KEYBOARD_STEP = 10;
function clampDimension(value, min, max, viewportMax) {
let v = value;
if (min != null) v = Math.max(v, min);
if (max != null) v = Math.min(v, max);
if (viewportMax != null) v = Math.min(v, viewportMax);
return v;
}
function getViewportLimits(rect, constrainToViewport, constrainOffset) {
if (!constrainToViewport) return {
maxWidth: void 0,
maxHeight: void 0
};
const offset = constrainOffset ?? 0;
return {
maxWidth: window.innerWidth - rect.left - offset,
maxHeight: window.innerHeight - rect.top - offset
};
}
const FloatingWindowResizeHandle = require_factory.factory((_props) => {
const { children, ref, style, ...others } = require_use_props.useProps("FloatingWindowResizeHandle", defaultProps, _props);
const ctx = require_FloatingWindow_context.useFloatingWindowContext();
const handleRef = (0, react.useRef)(null);
const ctxRef = (0, react.useRef)(ctx);
ctxRef.current = ctx;
const valueNowRef = (0, react.useRef)(null);
const hasWidth = ctx.dimensions?.initialWidth != null || ctx.dimensions?.minWidth != null || ctx.dimensions?.maxWidth != null;
const hasHeight = ctx.dimensions?.initialHeight != null || ctx.dimensions?.minHeight != null || ctx.dimensions?.maxHeight != null;
(0, react.useEffect)(() => {
const handle = handleRef.current;
if (!handle) return;
const controller = new AbortController();
const { signal } = controller;
let isResizing = false;
let startX = 0;
let startY = 0;
let startWidth = 0;
let startHeight = 0;
const applySize = (width, height) => {
if (width === null && height === null) return;
const { dimensions, constrainToViewport, constrainOffset, onSizeChange } = ctxRef.current;
const root = ctxRef.current.rootRef.current;
if (!root) return;
const viewportLimits = getViewportLimits(root.getBoundingClientRect(), constrainToViewport, constrainOffset);
if (width !== null) {
const nextWidth = clampDimension(width, dimensions?.minWidth, dimensions?.maxWidth, viewportLimits.maxWidth);
root.style.width = `${nextWidth}px`;
}
if (height !== null) {
const nextHeight = clampDimension(height, dimensions?.minHeight, dimensions?.maxHeight, viewportLimits.maxHeight);
root.style.height = `${nextHeight}px`;
}
const resizedRect = root.getBoundingClientRect();
if (width !== null) {
valueNowRef.current = resizedRect.width;
handle.setAttribute("aria-valuenow", String(Math.round(resizedRect.width)));
}
onSizeChange?.({
width: resizedRect.width,
height: resizedRect.height
});
};
const onStart = (e) => {
if ("button" in e && e.button !== 0) return;
e.stopPropagation();
e.preventDefault();
if (!hasWidth && !hasHeight) return;
const root = ctxRef.current.rootRef.current;
if (!root) return;
const point = "touches" in e ? e.touches[0] : e;
startX = point.clientX;
startY = point.clientY;
const rect = root.getBoundingClientRect();
startWidth = rect.width;
startHeight = rect.height;
isResizing = true;
document.body.style.userSelect = "none";
document.body.style.webkitUserSelect = "none";
ctxRef.current.onResizeStart?.();
document.addEventListener("mousemove", onMove, { signal });
document.addEventListener("mouseup", onEnd, { signal });
document.addEventListener("touchmove", onMove, {
signal,
passive: false
});
document.addEventListener("touchend", onEnd, { signal });
document.addEventListener("touchcancel", onEnd, { signal });
};
const onMove = (e) => {
if (!isResizing) return;
e.preventDefault();
const point = "touches" in e ? e.touches[0] : e;
const deltaX = point.clientX - startX;
const deltaY = point.clientY - startY;
applySize(hasWidth ? startWidth + deltaX : null, hasHeight ? startHeight + deltaY : null);
};
const onEnd = () => {
if (!isResizing) return;
isResizing = false;
document.body.style.userSelect = "";
document.body.style.webkitUserSelect = "";
ctxRef.current.onResizeEnd?.();
};
const onKeyDown = (e) => {
const { dimensions } = ctxRef.current;
const root = ctxRef.current.rootRef.current;
if (!root) return;
const rect = root.getBoundingClientRect();
let newWidth = null;
let newHeight = null;
if (e.key === "ArrowRight" && hasWidth) newWidth = rect.width + KEYBOARD_STEP;
else if (e.key === "ArrowLeft" && hasWidth) newWidth = rect.width - KEYBOARD_STEP;
else if (e.key === "ArrowDown" && hasHeight) newHeight = rect.height + KEYBOARD_STEP;
else if (e.key === "ArrowUp" && hasHeight) newHeight = rect.height - KEYBOARD_STEP;
else if (e.key === "Home") {
if (hasWidth) newWidth = dimensions?.minWidth ?? rect.width;
if (hasHeight) newHeight = dimensions?.minHeight ?? rect.height;
} else if (e.key === "End") {
if (hasWidth) newWidth = dimensions?.maxWidth ?? rect.width;
if (hasHeight) newHeight = dimensions?.maxHeight ?? rect.height;
}
if (newWidth !== null || newHeight !== null) {
e.preventDefault();
applySize(newWidth, newHeight);
}
};
handle.addEventListener("mousedown", onStart, { signal });
handle.addEventListener("touchstart", onStart, {
signal,
passive: false
});
handle.addEventListener("keydown", onKeyDown, { signal });
return () => {
onEnd();
controller.abort();
};
}, [hasWidth, hasHeight]);
(0, react.useEffect)(() => {
const handle = handleRef.current;
if (!handle) return;
if (!hasWidth) {
valueNowRef.current = null;
handle.removeAttribute("aria-valuenow");
return;
}
if (valueNowRef.current !== null) return;
const initialWidth = ctx.dimensions?.initialWidth;
if (initialWidth == null) {
handle.removeAttribute("aria-valuenow");
return;
}
const width = clampDimension(initialWidth, ctx.dimensions?.minWidth, ctx.dimensions?.maxWidth, void 0);
handle.setAttribute("aria-valuenow", String(Math.round(width)));
}, [
hasWidth,
ctx.dimensions?.initialWidth,
ctx.dimensions?.minWidth,
ctx.dimensions?.maxWidth
]);
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Box.Box, {
ref: (0, _mantine_hooks.useMergedRef)(ref, handleRef),
role: "separator",
"aria-label": "Resize window",
"aria-valuemin": ctx.dimensions?.minWidth,
"aria-valuemax": ctx.dimensions?.maxWidth,
tabIndex: 0,
...others,
style: [{ touchAction: "none" }, style],
children
});
});
FloatingWindowResizeHandle.displayName = "@mantine/core/FloatingWindowResizeHandle";
//#endregion
exports.FloatingWindowResizeHandle = FloatingWindowResizeHandle;
//# sourceMappingURL=FloatingWindowResizeHandle.cjs.map