From 255e5a558d26e47f338295a41219d2a1fdbc1935 Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Wed, 3 Dec 2025 17:48:00 -0600 Subject: [PATCH 1/6] chore: update file name --- packages/react-flexy-panels/src/utils/index.ts | 2 +- .../src/utils/{panelSize.ts => updatePanelSizes.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/react-flexy-panels/src/utils/{panelSize.ts => updatePanelSizes.ts} (100%) diff --git a/packages/react-flexy-panels/src/utils/index.ts b/packages/react-flexy-panels/src/utils/index.ts index 1561491..e029224 100644 --- a/packages/react-flexy-panels/src/utils/index.ts +++ b/packages/react-flexy-panels/src/utils/index.ts @@ -1,3 +1,3 @@ export * from "./attachSetSizeFunction"; export * from "./findAdjacentPanels"; -export * from "./panelSize"; +export * from "./updatePanelSizes"; diff --git a/packages/react-flexy-panels/src/utils/panelSize.ts b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts similarity index 100% rename from packages/react-flexy-panels/src/utils/panelSize.ts rename to packages/react-flexy-panels/src/utils/updatePanelSizes.ts From 97a44b217890c5c370e7a4b2ffca34bf6bb6d1e8 Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Wed, 3 Dec 2025 17:56:56 -0600 Subject: [PATCH 2/6] chore: refactor --- .../src/utils/getPanelSizeByDirection.ts | 13 +++++++++++++ packages/react-flexy-panels/src/utils/index.ts | 1 + .../src/utils/updatePanelSizes.ts | 15 ++++----------- 3 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 packages/react-flexy-panels/src/utils/getPanelSizeByDirection.ts diff --git a/packages/react-flexy-panels/src/utils/getPanelSizeByDirection.ts b/packages/react-flexy-panels/src/utils/getPanelSizeByDirection.ts new file mode 100644 index 0000000..654234e --- /dev/null +++ b/packages/react-flexy-panels/src/utils/getPanelSizeByDirection.ts @@ -0,0 +1,13 @@ +import { Direction } from "../types"; + +export const getPanelSizeByDirection = ({ + panel, + direction, +}: { + panel: HTMLElement; + direction: Direction; +}) => { + return direction === "horizontal" + ? panel.getBoundingClientRect().width + : panel.getBoundingClientRect().height; +}; diff --git a/packages/react-flexy-panels/src/utils/index.ts b/packages/react-flexy-panels/src/utils/index.ts index e029224..5793085 100644 --- a/packages/react-flexy-panels/src/utils/index.ts +++ b/packages/react-flexy-panels/src/utils/index.ts @@ -1,3 +1,4 @@ export * from "./attachSetSizeFunction"; export * from "./findAdjacentPanels"; +export * from "./getPanelSizeByDirection"; export * from "./updatePanelSizes"; diff --git a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts index 03b57f1..07ba1ed 100644 --- a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts +++ b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts @@ -1,4 +1,5 @@ import { Direction } from "../types"; +import { getPanelSizeByDirection } from "./getPanelSizeByDirection"; type PanelUnit = "px" | "%" | "auto"; @@ -16,21 +17,13 @@ export function updatePanelSizes(props: { const panel1Unit = (panel1.dataset.unit || "auto") as PanelUnit; const panel2Unit = (panel2.dataset.unit || "auto") as PanelUnit; - const panel1Size = - direction === "horizontal" - ? panel1.getBoundingClientRect().width - : panel1.getBoundingClientRect().height; - const panel2Size = - direction === "horizontal" - ? panel2.getBoundingClientRect().width - : panel2.getBoundingClientRect().height; + const panel1Size = getPanelSizeByDirection({ panel: panel1, direction }); + const panel2Size = getPanelSizeByDirection({ panel: panel2, direction }); // Get the parent container to check bounds const container = panel1.parentElement; const containerSize = container - ? direction === "horizontal" - ? container.getBoundingClientRect().width - : container.getBoundingClientRect().height + ? getPanelSizeByDirection({ panel: container, direction }) : null; // Calculate new sizes for the two panels being resized From 0ee1498286d05d3b436b2337fcfee77e2293590d Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Wed, 3 Dec 2025 18:07:58 -0600 Subject: [PATCH 3/6] chore: refactor --- packages/react-flexy-panels/src/utils/updatePanelSizes.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts index 07ba1ed..4dae0f6 100644 --- a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts +++ b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts @@ -48,10 +48,7 @@ export function updatePanelSizes(props: { // Calculate current sizes of all other panels const otherPanelsTotalSize = allPanels.reduce((sum, panel) => { - const size = - direction === "horizontal" - ? panel.getBoundingClientRect().width - : panel.getBoundingClientRect().height; + const size = getPanelSizeByDirection({ panel, direction }); return sum + size; }, 0); From a6a85ad5e383890886f811db759378831f3b9873 Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Wed, 3 Dec 2025 21:12:21 -0600 Subject: [PATCH 4/6] feat: drag on handle only and bug fix --- .../src/hooks/usePanelDrag.ts | 19 +++++- .../react-flexy-panels/src/utils/index.ts | 1 + .../src/utils/isSameSign.ts | 3 + .../src/utils/updatePanelSizes.ts | 58 +++++++++++++++++-- 4 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 packages/react-flexy-panels/src/utils/isSameSign.ts diff --git a/packages/react-flexy-panels/src/hooks/usePanelDrag.ts b/packages/react-flexy-panels/src/hooks/usePanelDrag.ts index fc578d2..ca50e14 100644 --- a/packages/react-flexy-panels/src/hooks/usePanelDrag.ts +++ b/packages/react-flexy-panels/src/hooks/usePanelDrag.ts @@ -14,6 +14,8 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { const [isDragging, setIsDragging] = useState(false); const dragStartRef = useRef(0); const handleElementRef = useRef(null); + const dragDeltaTotalRef = useRef(0); + const unappliedDragDeltaRef = useRef(0); const updateDragPosition = useCallback( (clientX: number, clientY: number) => { @@ -36,12 +38,25 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { return; } - updatePanelSizes({ + dragDeltaTotalRef.current += dragDelta; + + const appliedDragDelta = updatePanelSizes({ panel1, panel2, dragDelta, direction, + unappliedDragDelta: unappliedDragDeltaRef.current, }); + + unappliedDragDeltaRef.current = + unappliedDragDeltaRef.current + (dragDelta - appliedDragDelta); + + // if (Math.abs(unappliedDragDeltaRef.current) < 1) { + // unappliedDragDeltaRef.current = 0; + // } + + console.log({ dragDelta, unappliedDragDeltaTotal: unappliedDragDeltaRef.current }); + dragStartRef.current = dragCurrent; }, [direction, handleId] @@ -74,6 +89,7 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { (e: React.MouseEvent) => { // Cache handle element reference on drag start handleElementRef.current = e.currentTarget; + unappliedDragDeltaRef.current = 0; setIsDragging(true); dragStartRef.current = direction === "horizontal" ? e.clientX : e.clientY; }, @@ -85,6 +101,7 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { if (e.touches.length > 0) { // Cache handle element reference on drag start handleElementRef.current = e.currentTarget; + unappliedDragDeltaRef.current = 0; setIsDragging(true); const touch = e.touches[0]; dragStartRef.current = diff --git a/packages/react-flexy-panels/src/utils/index.ts b/packages/react-flexy-panels/src/utils/index.ts index 5793085..7f0d989 100644 --- a/packages/react-flexy-panels/src/utils/index.ts +++ b/packages/react-flexy-panels/src/utils/index.ts @@ -2,3 +2,4 @@ export * from "./attachSetSizeFunction"; export * from "./findAdjacentPanels"; export * from "./getPanelSizeByDirection"; export * from "./updatePanelSizes"; +export * from "./isSameSign"; \ No newline at end of file diff --git a/packages/react-flexy-panels/src/utils/isSameSign.ts b/packages/react-flexy-panels/src/utils/isSameSign.ts new file mode 100644 index 0000000..553b0d3 --- /dev/null +++ b/packages/react-flexy-panels/src/utils/isSameSign.ts @@ -0,0 +1,3 @@ +export const isSameSign = (a: number, b: number) => { + return (a === 0 && b === 0) || (a > 0 && b > 0) || (a < 0 && b < 0); +}; diff --git a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts index 4dae0f6..1e50e24 100644 --- a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts +++ b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts @@ -1,5 +1,6 @@ import { Direction } from "../types"; import { getPanelSizeByDirection } from "./getPanelSizeByDirection"; +import { isSameSign } from "./isSameSign"; type PanelUnit = "px" | "%" | "auto"; @@ -11,8 +12,24 @@ export function updatePanelSizes(props: { panel2: HTMLDivElement; dragDelta: number; direction: Direction; -}): void { - const { panel1, panel2, dragDelta, direction } = props; + unappliedDragDelta: number; +}): number { + const { panel1, panel2, direction, unappliedDragDelta } = props; + let dragDelta = props.dragDelta; + + if (dragDelta === 0) { + return 0; + } + + if (unappliedDragDelta !== 0 && dragDelta !== 0) { + if (!isSameSign(unappliedDragDelta, dragDelta)) { + if (Math.abs(unappliedDragDelta) > Math.abs(dragDelta)) { + return 0 ; + } else { + dragDelta += unappliedDragDelta; + } + } + } const panel1Unit = (panel1.dataset.unit || "auto") as PanelUnit; const panel2Unit = (panel2.dataset.unit || "auto") as PanelUnit; @@ -27,8 +44,8 @@ export function updatePanelSizes(props: { : null; // Calculate new sizes for the two panels being resized - let panel1NewSize = panel1Size + dragDelta; - let panel2NewSize = panel2Size - dragDelta; + let panel1NewSize = Math.abs(panel1Size + dragDelta); + let panel2NewSize = Math.abs(panel2Size - dragDelta); // Constrain sizes to container bounds const minPanelSize = 0; @@ -61,6 +78,21 @@ export function updatePanelSizes(props: { const panel1And2Total = panel1NewSize + panel2NewSize; if (panel1And2Total > 0 && availableSize > 0) { const scale = availableSize / panel1And2Total; + console.table({ + panel1Size, + panel2Size, + otherPanelsTotalSize, + totalSize, + containerSize, + availableSize, + dragDelta, + scale, + panel1NewSizeBeforeScale: panel1NewSize, + panel2NewSizeBeforeScale: panel2NewSize, + panel1And2Total, + panel1NewSizeAfterScale: panel1NewSize * scale, + panel2NewSizeAfterScale: panel2NewSize * scale, + }); panel1NewSize = panel1NewSize * scale; panel2NewSize = panel2NewSize * scale; } @@ -100,4 +132,22 @@ export function updatePanelSizes(props: { panel1.style.flex = `0 1 ${panel1NewSize}px`; panel2.style.flex = `0 1 ${panel2NewSize}px`; } + + const appliedDragDelta1 = + getPanelSizeByDirection({ panel: panel1, direction }) - panel1Size; + + const appliedDragDelta2 = + getPanelSizeByDirection({ panel: panel2, direction }) - panel2Size; + + let appliedDragDelta = Math.min( + Math.abs(appliedDragDelta1), + Math.abs(appliedDragDelta2) + ); + + if (appliedDragDelta1 !== 0) { + appliedDragDelta = + appliedDragDelta * (appliedDragDelta1 / Math.abs(appliedDragDelta1)); + } + + return appliedDragDelta1; } From dba39b363ab83ac87df6caadd3dc5dcff8d2694d Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Wed, 3 Dec 2025 21:25:42 -0600 Subject: [PATCH 5/6] chore: code cleanup --- .../src/hooks/usePanelDrag.ts | 32 ++++++++----------- .../src/utils/updatePanelSizes.ts | 30 +---------------- 2 files changed, 15 insertions(+), 47 deletions(-) diff --git a/packages/react-flexy-panels/src/hooks/usePanelDrag.ts b/packages/react-flexy-panels/src/hooks/usePanelDrag.ts index ca50e14..8ee5b7d 100644 --- a/packages/react-flexy-panels/src/hooks/usePanelDrag.ts +++ b/packages/react-flexy-panels/src/hooks/usePanelDrag.ts @@ -14,7 +14,6 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { const [isDragging, setIsDragging] = useState(false); const dragStartRef = useRef(0); const handleElementRef = useRef(null); - const dragDeltaTotalRef = useRef(0); const unappliedDragDeltaRef = useRef(0); const updateDragPosition = useCallback( @@ -38,8 +37,6 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { return; } - dragDeltaTotalRef.current += dragDelta; - const appliedDragDelta = updatePanelSizes({ panel1, panel2, @@ -51,12 +48,6 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { unappliedDragDeltaRef.current = unappliedDragDeltaRef.current + (dragDelta - appliedDragDelta); - // if (Math.abs(unappliedDragDeltaRef.current) < 1) { - // unappliedDragDeltaRef.current = 0; - // } - - console.log({ dragDelta, unappliedDragDeltaTotal: unappliedDragDeltaRef.current }); - dragStartRef.current = dragCurrent; }, [direction, handleId] @@ -85,30 +76,35 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { [isDragging, updateDragPosition] ); - const handleMouseDown = useCallback( - (e: React.MouseEvent) => { - // Cache handle element reference on drag start + const resetDraggingStates = useCallback( + ( + e: React.MouseEvent | React.TouchEvent + ) => { handleElementRef.current = e.currentTarget; unappliedDragDeltaRef.current = 0; setIsDragging(true); + }, + [] + ); + + const handleMouseDown = useCallback( + (e: React.MouseEvent) => { + resetDraggingStates(e); dragStartRef.current = direction === "horizontal" ? e.clientX : e.clientY; }, - [direction] + [direction, resetDraggingStates] ); const handleTouchStart = useCallback( (e: React.TouchEvent) => { if (e.touches.length > 0) { - // Cache handle element reference on drag start - handleElementRef.current = e.currentTarget; - unappliedDragDeltaRef.current = 0; - setIsDragging(true); + resetDraggingStates(e); const touch = e.touches[0]; dragStartRef.current = direction === "horizontal" ? touch.clientX : touch.clientY; } }, - [direction] + [direction, resetDraggingStates] ); useEffect(() => { diff --git a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts index 1e50e24..1d688a3 100644 --- a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts +++ b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts @@ -24,7 +24,7 @@ export function updatePanelSizes(props: { if (unappliedDragDelta !== 0 && dragDelta !== 0) { if (!isSameSign(unappliedDragDelta, dragDelta)) { if (Math.abs(unappliedDragDelta) > Math.abs(dragDelta)) { - return 0 ; + return 0; } else { dragDelta += unappliedDragDelta; } @@ -78,21 +78,6 @@ export function updatePanelSizes(props: { const panel1And2Total = panel1NewSize + panel2NewSize; if (panel1And2Total > 0 && availableSize > 0) { const scale = availableSize / panel1And2Total; - console.table({ - panel1Size, - panel2Size, - otherPanelsTotalSize, - totalSize, - containerSize, - availableSize, - dragDelta, - scale, - panel1NewSizeBeforeScale: panel1NewSize, - panel2NewSizeBeforeScale: panel2NewSize, - panel1And2Total, - panel1NewSizeAfterScale: panel1NewSize * scale, - panel2NewSizeAfterScale: panel2NewSize * scale, - }); panel1NewSize = panel1NewSize * scale; panel2NewSize = panel2NewSize * scale; } @@ -136,18 +121,5 @@ export function updatePanelSizes(props: { const appliedDragDelta1 = getPanelSizeByDirection({ panel: panel1, direction }) - panel1Size; - const appliedDragDelta2 = - getPanelSizeByDirection({ panel: panel2, direction }) - panel2Size; - - let appliedDragDelta = Math.min( - Math.abs(appliedDragDelta1), - Math.abs(appliedDragDelta2) - ); - - if (appliedDragDelta1 !== 0) { - appliedDragDelta = - appliedDragDelta * (appliedDragDelta1 / Math.abs(appliedDragDelta1)); - } - return appliedDragDelta1; } From cc0883c09788e8830dede0fe16efdf978b718009 Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Wed, 3 Dec 2025 21:29:53 -0600 Subject: [PATCH 6/6] chore: include changeset --- .changeset/solid-facts-flow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/solid-facts-flow.md diff --git a/.changeset/solid-facts-flow.md b/.changeset/solid-facts-flow.md new file mode 100644 index 0000000..440a75d --- /dev/null +++ b/.changeset/solid-facts-flow.md @@ -0,0 +1,5 @@ +--- +"react-flexy-panels": minor +--- + +feat: enforce dragging on handle only