Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/solid-facts-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-flexy-panels": minor
---

feat: enforce dragging on handle only
31 changes: 22 additions & 9 deletions packages/react-flexy-panels/src/hooks/usePanelDrag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => {
const [isDragging, setIsDragging] = useState(false);
const dragStartRef = useRef<number>(0);
const handleElementRef = useRef<HTMLElement | null>(null);
const unappliedDragDeltaRef = useRef<number>(0);

const updateDragPosition = useCallback(
(clientX: number, clientY: number) => {
Expand All @@ -36,12 +37,17 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => {
return;
}

updatePanelSizes({
const appliedDragDelta = updatePanelSizes({
panel1,
panel2,
dragDelta,
direction,
unappliedDragDelta: unappliedDragDeltaRef.current,
});

unappliedDragDeltaRef.current =
unappliedDragDeltaRef.current + (dragDelta - appliedDragDelta);

dragStartRef.current = dragCurrent;
},
[direction, handleId]
Expand Down Expand Up @@ -70,28 +76,35 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => {
[isDragging, updateDragPosition]
);

const handleMouseDown = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
// Cache handle element reference on drag start
const resetDraggingStates = useCallback(
(
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>
) => {
handleElementRef.current = e.currentTarget;
unappliedDragDeltaRef.current = 0;
setIsDragging(true);
},
[]
);

const handleMouseDown = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
resetDraggingStates(e);
dragStartRef.current = direction === "horizontal" ? e.clientX : e.clientY;
},
[direction]
[direction, resetDraggingStates]
);

const handleTouchStart = useCallback(
(e: React.TouchEvent<HTMLDivElement>) => {
if (e.touches.length > 0) {
// Cache handle element reference on drag start
handleElementRef.current = e.currentTarget;
setIsDragging(true);
resetDraggingStates(e);
const touch = e.touches[0];
dragStartRef.current =
direction === "horizontal" ? touch.clientX : touch.clientY;
}
},
[direction]
[direction, resetDraggingStates]
);

useEffect(() => {
Expand Down
13 changes: 13 additions & 0 deletions packages/react-flexy-panels/src/utils/getPanelSizeByDirection.ts
Original file line number Diff line number Diff line change
@@ -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;
};
4 changes: 3 additions & 1 deletion packages/react-flexy-panels/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from "./attachSetSizeFunction";
export * from "./findAdjacentPanels";
export * from "./panelSize";
export * from "./getPanelSizeByDirection";
export * from "./updatePanelSizes";
export * from "./isSameSign";
3 changes: 3 additions & 0 deletions packages/react-flexy-panels/src/utils/isSameSign.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const isSameSign = (a: number, b: number) => {
return (a === 0 && b === 0) || (a > 0 && b > 0) || (a < 0 && b < 0);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Direction } from "../types";
import { getPanelSizeByDirection } from "./getPanelSizeByDirection";
import { isSameSign } from "./isSameSign";

type PanelUnit = "px" | "%" | "auto";

Expand All @@ -10,32 +12,40 @@ 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;

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
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;
Expand All @@ -55,10 +65,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);

Expand Down Expand Up @@ -110,4 +117,9 @@ 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;

return appliedDragDelta1;
}