UNPKG

@mantine/hooks

Version:

A collection of 50+ hooks for state and UI management

636 lines (635 loc) 27 kB
"use client"; import { useUncontrolled } from "../use-uncontrolled/use-uncontrolled.mjs"; import { useCallback, useEffect, useRef, useState } from "react"; //#region packages/@mantine/hooks/src/use-splitter/use-splitter.ts const PX_RE = /^(-?[\d.]+)px$/; const REM_RE = /^(-?[\d.]+)rem$/; const PERCENT_RE = /^(-?[\d.]+)%$/; function isFixedSize(size) { return typeof size === "string" && (PX_RE.test(size) || REM_RE.test(size)); } function sizeMagnitude(size) { return typeof size === "number" ? size : parseFloat(size); } function detectPixelMode(options) { return options.panels.some((panel) => isFixedSize(panel.defaultSize) || isFixedSize(panel.min) || isFixedSize(panel.max) || isFixedSize(panel.collapseThreshold)) || isFixedSize(options.step) || isFixedSize(options.shiftStep) || (options.sizes?.some(isFixedSize) ?? false); } function getRootFontSize() { if (typeof window === "undefined") return 16; const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize); return Number.isFinite(fontSize) && fontSize > 0 ? fontSize : 16; } function resolveSize(size, pixelMode, containerPx, rootFontSize) { if (!pixelMode) return sizeMagnitude(size); if (typeof size === "number") return size / 100 * containerPx; const percent = PERCENT_RE.exec(size); if (percent) return parseFloat(percent[1]) / 100 * containerPx; const rem = REM_RE.exec(size); if (rem) return parseFloat(rem[1]) * rootFontSize; const px = PX_RE.exec(size); if (px) return parseFloat(px[1]); return 0; } /** Down-scaling factor applied to fixed panes when their combined pixel size overflows the * container, so they shrink to fit (matching `resolveWorkingSizes`). Returns `1` when nothing * overflows or the layout is not in pixel mode. Encoders divide by this to invert the scaling and * persist the original absolute sizes instead of the shrunk-to-fit ones. */ function getFixedScale(sizes, pixelMode, containerPx, rootFontSize) { if (!pixelMode) return 1; let fixedTotal = 0; sizes.forEach((size) => { if (isFixedSize(size)) fixedTotal += resolveSize(size, true, containerPx, rootFontSize); }); return fixedTotal > containerPx && fixedTotal > 0 ? containerPx / fixedTotal : 1; } /** Resolves all sizes to pixels at once. Fixed panes get their absolute pixel size, flexible panes * share the leftover space by their weight ratio – matching how the layout is rendered with * `flex-grow`, so drag math operates on the same pixel sizes the user sees. */ function resolveWorkingSizes(sizes, pixelMode, containerPx, rootFontSize) { if (!pixelMode) return sizes.map((size) => sizeMagnitude(size)); let fixedTotal = 0; let flexibleWeight = 0; sizes.forEach((size) => { if (isFixedSize(size)) fixedTotal += resolveSize(size, true, containerPx, rootFontSize); else flexibleWeight += sizeMagnitude(size); }); const leftover = Math.max(0, containerPx - fixedTotal); const fixedScale = getFixedScale(sizes, pixelMode, containerPx, rootFontSize); return sizes.map((size) => { if (isFixedSize(size)) return resolveSize(size, true, containerPx, rootFontSize) * fixedScale; return flexibleWeight > 0 ? sizeMagnitude(size) / flexibleWeight * leftover : 0; }); } function encodeSize(value, original, pixelMode, containerPx, rootFontSize, fixedScale = 1) { if (!pixelMode) return typeof original === "string" && PERCENT_RE.test(original) ? `${value}%` : value; if (typeof original === "number") return containerPx > 0 ? value / containerPx * 100 : original; if (PERCENT_RE.test(original)) return `${containerPx > 0 ? value / containerPx * 100 : parseFloat(original)}%`; const absolute = fixedScale > 0 ? value / fixedScale : value; if (REM_RE.test(original)) return `${rootFontSize > 0 ? absolute / rootFontSize : 0}rem`; return `${absolute}px`; } /** Encodes working pixel sizes back to raw sizes after a resize, keeping the unit each pane was * declared in. Panes whose working size did not change keep their original raw value. When fixed * panes overflow the container they render down-scaled, so their working sizes are scaled back up to * absolute sizes (preserving their declared sizes). If the resize instead hands space to a flexible * pane the overflow clears and the layout leaves the down-scaled regime: every pane is then encoded * from its current working size – including untouched fixed panes (so they do not jump back to their * over-sized value) and untouched flexible panes (so a pane that was squeezed to `0` does not keep a * stale weight and steal the freed space on the next render). */ function encodeWorkingSizes(nextWorking, baseWorking, baseRaw, pixelMode, containerPx, rootFontSize) { const fixedScale = getFixedScale(baseRaw, pixelMode, containerPx, rootFontSize); let fixedWorkingSum = 0; nextWorking.forEach((value, i) => { if (isFixedSize(baseRaw[i])) fixedWorkingSum += value; }); const overflowCleared = fixedScale < 1 && fixedWorkingSum < containerPx - 1e-6; const encodeScale = overflowCleared ? 1 : fixedScale; return nextWorking.map((value, i) => overflowCleared || Math.abs(value - baseWorking[i]) > 1e-6 ? encodeSize(value, baseRaw[i], pixelMode, containerPx, rootFontSize, encodeScale) : baseRaw[i]); } function resolvePanel(panel, pixelMode, containerPx, rootFontSize) { return { defaultSize: resolveSize(panel.defaultSize, pixelMode, containerPx, rootFontSize), min: panel.min != null ? resolveSize(panel.min, pixelMode, containerPx, rootFontSize) : 0, max: panel.max != null ? resolveSize(panel.max, pixelMode, containerPx, rootFontSize) : pixelMode ? containerPx : 100, collapseThreshold: panel.collapseThreshold != null ? resolveSize(panel.collapseThreshold, pixelMode, containerPx, rootFontSize) : void 0, collapsible: panel.collapsible }; } function resolveStep(step, pixelMode, containerPx, rootFontSize) { return resolveSize(step, pixelMode, containerPx, rootFontSize); } function clamp(value, min, max) { return Math.min(Math.max(value, min), max); } function getMin(panel) { return panel.min ?? 0; } function getMax(panel) { return panel.max ?? Infinity; } function getCollapseThreshold(panel) { return panel.collapseThreshold ?? getMin(panel); } function createInitialInternalState() { return { isDragging: false, handleIndex: -1, startPointer: 0, containerSize: 0, rootFontSize: 16, pixelMode: false, startSizes: [], startRaw: [], preCollapseSizes: [] }; } function checkCollapse(sizes, panels, handleIndex, delta) { const beforeIdx = handleIndex; const afterIdx = handleIndex + 1; const beforePanel = panels[beforeIdx]; const afterPanel = panels[afterIdx]; const rawBefore = sizes[beforeIdx] + delta; const rawAfter = sizes[afterIdx] - delta; if (beforePanel.collapsible && rawBefore < getCollapseThreshold(beforePanel) && rawBefore < sizes[beforeIdx]) { const result = [...sizes]; result[afterIdx] += result[beforeIdx]; result[beforeIdx] = 0; return result; } if (afterPanel.collapsible && rawAfter < getCollapseThreshold(afterPanel) && rawAfter < sizes[afterIdx]) { const result = [...sizes]; result[beforeIdx] += result[afterIdx]; result[afterIdx] = 0; return result; } return null; } function applyAdjacentOnly(sizes, panels, handleIndex, delta) { const result = [...sizes]; const beforeIdx = handleIndex; const afterIdx = handleIndex + 1; const total = result[beforeIdx] + result[afterIdx]; const effectiveBeforeMax = Math.min(getMax(panels[beforeIdx]), total - getMin(panels[afterIdx])); const effectiveBeforeMin = Math.max(getMin(panels[beforeIdx]), total - getMax(panels[afterIdx])); const newBefore = clamp(result[beforeIdx] + delta, effectiveBeforeMin, effectiveBeforeMax); result[beforeIdx] = newBefore; result[afterIdx] = total - newBefore; return result; } function redistributeNearest(sizes, panels, handleIndex, delta) { const result = [...sizes]; if (delta > 0) { const growIdx = handleIndex; const maxGrow = getMax(panels[growIdx]) - result[growIdx]; const wantedGrow = Math.min(delta, maxGrow); let taken = 0; for (let i = handleIndex + 1; i < result.length && taken < wantedGrow; i += 1) { const canGive = result[i] - getMin(panels[i]); const take = Math.min(canGive, wantedGrow - taken); result[i] -= take; taken += take; } result[growIdx] += taken; } else if (delta < 0) { const growIdx = handleIndex + 1; const maxGrow = getMax(panels[growIdx]) - result[growIdx]; const wantedGrow = Math.min(Math.abs(delta), maxGrow); let taken = 0; for (let i = handleIndex; i >= 0 && taken < wantedGrow; i -= 1) { const canGive = result[i] - getMin(panels[i]); const take = Math.min(canGive, wantedGrow - taken); result[i] -= take; taken += take; } result[growIdx] += taken; } return result; } function redistributeEqual(sizes, panels, handleIndex, delta) { const result = [...sizes]; if (delta > 0) { const growIdx = handleIndex; const maxGrow = getMax(panels[growIdx]) - result[growIdx]; const wantedGrow = Math.min(delta, maxGrow); const donors = []; for (let i = handleIndex + 1; i < result.length; i += 1) if (result[i] > getMin(panels[i])) donors.push(i); let remaining = wantedGrow; while (remaining > .001 && donors.length > 0) { const perDonor = remaining / donors.length; const exhausted = []; for (let d = 0; d < donors.length; d += 1) { const idx = donors[d]; const canGive = result[idx] - getMin(panels[idx]); const take = Math.min(canGive, perDonor); result[idx] -= take; remaining -= take; if (canGive <= perDonor + .001) exhausted.push(d); } for (let i = exhausted.length - 1; i >= 0; i -= 1) donors.splice(exhausted[i], 1); if (exhausted.length === 0) break; } result[growIdx] += wantedGrow - remaining; } else if (delta < 0) { const growIdx = handleIndex + 1; const maxGrow = getMax(panels[growIdx]) - result[growIdx]; const wantedGrow = Math.min(Math.abs(delta), maxGrow); const donors = []; for (let i = handleIndex; i >= 0; i -= 1) if (result[i] > getMin(panels[i])) donors.push(i); let remaining = wantedGrow; while (remaining > .001 && donors.length > 0) { const perDonor = remaining / donors.length; const exhausted = []; for (let d = 0; d < donors.length; d += 1) { const idx = donors[d]; const canGive = result[idx] - getMin(panels[idx]); const take = Math.min(canGive, perDonor); result[idx] -= take; remaining -= take; if (canGive <= perDonor + .001) exhausted.push(d); } for (let i = exhausted.length - 1; i >= 0; i -= 1) donors.splice(exhausted[i], 1); if (exhausted.length === 0) break; } result[growIdx] += wantedGrow - remaining; } return result; } function applyConstraints(sizes, panels, handleIndex, delta, redistribute) { if (typeof redistribute === "function") return redistribute({ sizes: [...sizes], panels, handleIndex, delta }); if (redistribute === "nearest" || redistribute === "equal") { const result = (redistribute === "nearest" ? redistributeNearest : redistributeEqual)(sizes, panels, handleIndex, delta); const beforeIdx = handleIndex; const afterIdx = handleIndex + 1; const beforePanel = panels[beforeIdx]; const afterPanel = panels[afterIdx]; if (beforePanel.collapsible && result[beforeIdx] < getCollapseThreshold(beforePanel) && result[beforeIdx] < sizes[beforeIdx]) { const freed = result[beforeIdx]; result[afterIdx] += freed; result[beforeIdx] = 0; } else if (afterPanel.collapsible && result[afterIdx] < getCollapseThreshold(afterPanel) && result[afterIdx] < sizes[afterIdx]) { const freed = result[afterIdx]; result[beforeIdx] += freed; result[afterIdx] = 0; } return result; } const collapsed = checkCollapse(sizes, panels, handleIndex, delta); if (collapsed) return collapsed; return applyAdjacentOnly(sizes, panels, handleIndex, delta); } function useSplitter(options) { const { panels, orientation = "horizontal", sizes: controlledSizes, onSizeChange, onCollapseChange, redistribute, step = 1, shiftStep = 10, dir = "ltr", resetOnDoubleClick = true, enabled = true } = options; const pixelMode = detectPixelMode(options); const defaultSizes = panels.map((panel) => panel.defaultSize); const [currentSizes, setCurrentSizes] = useUncontrolled({ value: controlledSizes, defaultValue: defaultSizes, finalValue: defaultSizes, onChange: onSizeChange }); const [activeHandle, setActiveHandle] = useState(-1); const [containerSize, setContainerSize] = useState(0); const optionsRef = useRef(options); optionsRef.current = options; const internalStateRef = useRef(createInitialInternalState()); const containerRef = useRef(null); const containerSizeRef = useRef(0); const rootFontSizeRef = useRef(16); const documentControllerRef = useRef(null); const frameRef = useRef(0); const currentSizesRef = useRef(currentSizes); currentSizesRef.current = currentSizes; const preCollapseSizesRef = useRef(defaultSizes); const collapsed = currentSizes.map((size) => sizeMagnitude(size) === 0); const measureContainer = useCallback(() => { const node = containerRef.current; if (!node) return 0; const rect = node.getBoundingClientRect(); return (optionsRef.current.orientation ?? "horizontal") === "horizontal" ? rect.width : rect.height; }, []); const updateSizes = useCallback((newSizes) => { currentSizesRef.current = newSizes; setCurrentSizes(newSizes); }, [setCurrentSizes]); const collapsePanel = useCallback((panelIndex) => { if (!panels[panelIndex]?.collapsible) return; const raw = currentSizesRef.current; if (sizeMagnitude(raw[panelIndex]) === 0) return; const container = pixelMode ? containerSizeRef.current || measureContainer() : 0; const rootFontSize = rootFontSizeRef.current; const working = resolveWorkingSizes(raw, pixelMode, container, rootFontSize); preCollapseSizesRef.current = [...raw]; const freedSize = working[panelIndex]; working[panelIndex] = 0; const neighbor = panelIndex === 0 ? 1 : panelIndex - 1; working[neighbor] += freedSize; updateSizes(working.map((value, i) => encodeSize(value, raw[i], pixelMode, container, rootFontSize))); onCollapseChange?.(panelIndex, true); }, [ panels, pixelMode, measureContainer, updateSizes, onCollapseChange ]); const expandPanel = useCallback((panelIndex) => { if (!panels[panelIndex]?.collapsible) return; const raw = currentSizesRef.current; if (sizeMagnitude(raw[panelIndex]) !== 0) return; const container = pixelMode ? containerSizeRef.current || measureContainer() : 0; const rootFontSize = rootFontSizeRef.current; const working = resolveWorkingSizes(raw, pixelMode, container, rootFontSize); const preCollapse = preCollapseSizesRef.current; const restoreSize = resolveSize(preCollapse[panelIndex] != null && sizeMagnitude(preCollapse[panelIndex]) !== 0 ? preCollapse[panelIndex] : panels[panelIndex].defaultSize, pixelMode, container, rootFontSize); const neighbor = panelIndex === 0 ? 1 : panelIndex - 1; const neighborMin = panels[neighbor].min != null ? resolveSize(panels[neighbor].min, pixelMode, container, rootFontSize) : 0; const available = Math.max(0, working[neighbor] - neighborMin); const actualRestore = Math.min(restoreSize, available); if (actualRestore <= 0) return; working[panelIndex] = actualRestore; working[neighbor] -= actualRestore; updateSizes(working.map((value, i) => encodeSize(value, raw[i], pixelMode, container, rootFontSize))); onCollapseChange?.(panelIndex, false); }, [ panels, pixelMode, measureContainer, updateSizes, onCollapseChange ]); const toggleCollapsePanel = useCallback((panelIndex) => { if (sizeMagnitude(currentSizesRef.current[panelIndex]) === 0) expandPanel(panelIndex); else collapsePanel(panelIndex); }, [collapsePanel, expandPanel]); const emitCollapseTransitions = useCallback((prev, next, indices, preCollapseSnapshot) => { const onChange = optionsRef.current.onCollapseChange; for (const idx of indices) { const wasCollapsed = sizeMagnitude(prev[idx]) === 0; const nowCollapsed = next[idx] === 0; if (!wasCollapsed && nowCollapsed) { preCollapseSizesRef.current = [...preCollapseSnapshot]; onChange?.(idx, true); } else if (wasCollapsed && !nowCollapsed) onChange?.(idx, false); } }, []); const reset = useCallback((handleIndex) => { const raw = currentSizesRef.current; const beforeIdx = handleIndex; const afterIdx = handleIndex + 1; if (beforeIdx < 0 || afterIdx >= raw.length) return; const container = pixelMode ? containerSizeRef.current || measureContainer() : 0; const rootFontSize = rootFontSizeRef.current; const working = resolveWorkingSizes(raw, pixelMode, container, rootFontSize); const resolvedPanels = optionsRef.current.panels.map((panel) => resolvePanel(panel, pixelMode, container, rootFontSize)); const total = working[beforeIdx] + working[afterIdx]; const defBefore = resolvedPanels[beforeIdx].defaultSize; const defTotal = defBefore + resolvedPanels[afterIdx].defaultSize; const next = applyAdjacentOnly(working, resolvedPanels, beforeIdx, (defTotal === 0 ? total / 2 : total * (defBefore / defTotal)) - working[beforeIdx]); emitCollapseTransitions(raw, next, [beforeIdx, afterIdx], raw); updateSizes(encodeWorkingSizes(next, working, raw, pixelMode, container, rootFontSize)); }, [ emitCollapseTransitions, updateSizes, pixelMode, measureContainer ]); const containerRefCallback = useCallback((node) => { containerRef.current = node; }, []); useEffect(() => { if (!pixelMode || typeof ResizeObserver === "undefined") return; const node = containerRef.current; if (!node) return; let frame = 0; const update = () => { const rect = node.getBoundingClientRect(); const size = (optionsRef.current.orientation ?? "horizontal") === "horizontal" ? rect.width : rect.height; rootFontSizeRef.current = getRootFontSize(); containerSizeRef.current = size; setContainerSize((prev) => prev !== size ? size : prev); }; const observer = new ResizeObserver(() => { cancelAnimationFrame(frame); frame = requestAnimationFrame(update); }); observer.observe(node); update(); return () => { cancelAnimationFrame(frame); observer.disconnect(); }; }, [pixelMode, orientation]); const handleRefCallbacks = useRef(/* @__PURE__ */ new Map()); const handleElementControllers = useRef(/* @__PURE__ */ new Map()); const getHandleRefCallback = useCallback((handleIndex) => { if (handleRefCallbacks.current.has(handleIndex)) return handleRefCallbacks.current.get(handleIndex); const callback = (node) => { const existingController = handleElementControllers.current.get(handleIndex); if (existingController) { existingController.abort(); handleElementControllers.current.delete(handleIndex); } if (!node) return; const elementController = new AbortController(); handleElementControllers.current.set(handleIndex, elementController); const onPointerDown = (event) => { if (optionsRef.current.enabled === false) return; if (event.button !== 0) return; const container = containerRef.current; if (!container) return; const opts = optionsRef.current; const isHorizontal = (opts.orientation ?? "horizontal") === "horizontal"; const rect = container.getBoundingClientRect(); const containerSizePx = isHorizontal ? rect.width : rect.height; const pointerPos = isHorizontal ? event.clientX : event.clientY; const isPixelMode = detectPixelMode(opts); const rootFontSize = getRootFontSize(); const s = internalStateRef.current; s.isDragging = true; s.handleIndex = handleIndex; s.startPointer = pointerPos; s.containerSize = containerSizePx; s.rootFontSize = rootFontSize; s.pixelMode = isPixelMode; s.startRaw = [...currentSizesRef.current]; s.startSizes = resolveWorkingSizes(s.startRaw, isPixelMode, containerSizePx, rootFontSize); s.preCollapseSizes = [...preCollapseSizesRef.current]; setActiveHandle(handleIndex); document.body.style.userSelect = "none"; document.body.style.webkitUserSelect = "none"; document.body.style.cursor = isHorizontal ? "col-resize" : "row-resize"; opts.onResizeStart?.(handleIndex); documentControllerRef.current?.abort(); documentControllerRef.current = new AbortController(); const sig = documentControllerRef.current.signal; document.addEventListener("pointermove", onPointerMove, { signal: sig }); document.addEventListener("pointerup", onPointerUp, { signal: sig }); document.addEventListener("pointercancel", onPointerUp, { signal: sig }); }; const flushResize = (pointerEvent) => { const s = internalStateRef.current; if (!s.containerSize) return; const opts = optionsRef.current; const isHorizontal = (opts.orientation ?? "horizontal") === "horizontal"; const isRtl = isHorizontal && opts.dir === "rtl"; const pointerPos = isHorizontal ? pointerEvent.clientX : pointerEvent.clientY; const pixelDelta = (isRtl ? -1 : 1) * (pointerPos - s.startPointer); const delta = s.pixelMode ? pixelDelta : pixelDelta / s.containerSize * 100; const resolvedPanels = opts.panels.map((panel) => resolvePanel(panel, s.pixelMode, s.containerSize, s.rootFontSize)); const newSizes = applyConstraints(s.startSizes, resolvedPanels, s.handleIndex, delta, opts.redistribute); const prevSizes = currentSizesRef.current; emitCollapseTransitions(prevSizes, newSizes, [s.handleIndex, s.handleIndex + 1], s.startRaw); const encoded = encodeWorkingSizes(newSizes, s.startSizes, s.startRaw, s.pixelMode, s.containerSize, s.rootFontSize); currentSizesRef.current = encoded; setCurrentSizes(encoded); }; const onPointerMove = (event) => { if (!internalStateRef.current.isDragging) return; cancelAnimationFrame(frameRef.current); frameRef.current = requestAnimationFrame(() => { flushResize(event); }); }; const onPointerUp = (event) => { const s = internalStateRef.current; if (!s.isDragging) return; cancelAnimationFrame(frameRef.current); flushResize(event); s.isDragging = false; const finishedHandle = s.handleIndex; s.handleIndex = -1; setActiveHandle(-1); document.body.style.userSelect = ""; document.body.style.webkitUserSelect = ""; document.body.style.cursor = ""; documentControllerRef.current?.abort(); documentControllerRef.current = null; optionsRef.current.onResizeEnd?.(finishedHandle, [...currentSizesRef.current]); }; node.addEventListener("pointerdown", onPointerDown, { signal: elementController.signal }); }; handleRefCallbacks.current.set(handleIndex, callback); return callback; }, [setCurrentSizes]); const getHandleProps = useCallback((input) => { const { index } = input; const orient = orientation; const rootFontSize = rootFontSizeRef.current; const working = resolveWorkingSizes(currentSizes, pixelMode, containerSize, rootFontSize); const resolvedPanels = panels.map((panel) => resolvePanel(panel, pixelMode, containerSize, rootFontSize)); const beforeSize = working[index] ?? 0; const beforePanel = resolvedPanels[index]; return { ref: getHandleRefCallback(index), role: "separator", "aria-orientation": orient, "aria-valuenow": Math.round(beforeSize), "aria-valuemin": Math.round(getMin(beforePanel)), "aria-valuemax": Math.round(getMax(beforePanel)), tabIndex: 0, onKeyDown: (event) => { if (!enabled) return; const isHorizontal = orient === "horizontal"; const isRtl = dir === "rtl"; const container = pixelMode ? containerSizeRef.current || measureContainer() : 0; const liveRootFontSize = rootFontSizeRef.current; const liveWorking = resolveWorkingSizes(currentSizes, pixelMode, container, liveRootFontSize); const livePanels = panels.map((panel) => resolvePanel(panel, pixelMode, container, liveRootFontSize)); const liveBeforePanel = livePanels[index]; const liveAfterPanel = livePanels[index + 1]; let delta = 0; const currentStep = resolveStep(event.shiftKey ? shiftStep : step, pixelMode, container, liveRootFontSize); switch (event.key) { case "ArrowLeft": if (!isHorizontal) return; delta = isRtl ? currentStep : -currentStep; break; case "ArrowRight": if (!isHorizontal) return; delta = isRtl ? -currentStep : currentStep; break; case "ArrowUp": if (isHorizontal) return; delta = -currentStep; break; case "ArrowDown": if (isHorizontal) return; delta = currentStep; break; case "Home": delta = -(liveWorking[index] - getMin(liveBeforePanel)); break; case "End": delta = getMax(liveBeforePanel) - liveWorking[index]; break; case "Enter": { const beforeCollapsible = liveBeforePanel?.collapsible; const afterCollapsible = liveAfterPanel?.collapsible; if (beforeCollapsible && liveWorking[index] <= liveWorking[index + 1]) { toggleCollapsePanel(index); event.preventDefault(); return; } if (afterCollapsible) { toggleCollapsePanel(index + 1); event.preventDefault(); return; } if (beforeCollapsible) { toggleCollapsePanel(index); event.preventDefault(); return; } return; } default: return; } event.preventDefault(); if (delta !== 0) { const newSizes = applyConstraints(liveWorking, livePanels, index, delta, redistribute); emitCollapseTransitions(currentSizes, newSizes, [index, index + 1], currentSizes); updateSizes(encodeWorkingSizes(newSizes, liveWorking, currentSizes, pixelMode, container, liveRootFontSize)); } }, onDoubleClick: () => { if (!enabled || !resetOnDoubleClick) return; reset(index); }, "data-active": activeHandle === index || void 0, "data-orientation": orient }; }, [ orientation, currentSizes, panels, pixelMode, containerSize, enabled, dir, step, shiftStep, resetOnDoubleClick, activeHandle, redistribute, measureContainer, getHandleRefCallback, toggleCollapsePanel, updateSizes, emitCollapseTransitions, reset ]); useEffect(() => () => { documentControllerRef.current?.abort(); documentControllerRef.current = null; handleElementControllers.current.forEach((controller) => controller.abort()); handleElementControllers.current.clear(); cancelAnimationFrame(frameRef.current); if (internalStateRef.current.isDragging) { internalStateRef.current.isDragging = false; document.body.style.userSelect = ""; document.body.style.webkitUserSelect = ""; document.body.style.cursor = ""; } }, []); return { ref: containerRefCallback, sizes: currentSizes, pixelMode, collapsed, activeHandle, getHandleProps, setSizes: updateSizes, collapse: collapsePanel, expand: expandPanel, toggleCollapse: toggleCollapsePanel, reset }; } //#endregion export { useSplitter }; //# sourceMappingURL=use-splitter.mjs.map