UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

186 lines (185 loc) 7.15 kB
"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