From 31b986817c6975b7be14caf789bfdffb6bc0d6a1 Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Thu, 4 Dec 2025 22:35:30 -0600 Subject: [PATCH 1/3] feat: expose onPreResize callback --- .changeset/funny-pianos-type.md | 5 +++++ README.md | 4 ++-- packages/react-flexy-panels/README.md | 4 ++-- .../components/FlexyPanelHandle/FlexyPanelHandle.tsx | 3 ++- .../types/FlexyPanelHandleProps.t.ts | 5 ++++- .../react-flexy-panels/src/hooks/usePanelDrag.ts | 12 +++++++++--- .../src/types/OnPreResizeFunction.t.ts | 4 ++++ packages/react-flexy-panels/src/types/index.ts | 1 + .../react-flexy-panels/src/utils/updatePanelSizes.ts | 11 +++++++++-- 9 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 .changeset/funny-pianos-type.md create mode 100644 packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts diff --git a/.changeset/funny-pianos-type.md b/.changeset/funny-pianos-type.md new file mode 100644 index 0000000..43ead54 --- /dev/null +++ b/.changeset/funny-pianos-type.md @@ -0,0 +1,5 @@ +--- +"react-flexy-panels": patch +--- + +feat: expose onPreResize prop on handle to allow any preprocess to be done before the panels are resized diff --git a/README.md b/README.md index b136a75..5fe34a2 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,11 @@ A flexible, resizable panel system for React applications version >= 18 with sup ## Features - ðŸŽĻ **Flexible Layouts** - Support for both horizontal and vertical panel arrangements +- 🎛ïļ **Customizable** - Support for pixel, percentage, and auto-sizing units +- 🎭 **Unstyled** - No default styles, giving you full control over appearance - 🔄 **Resizable Panels** - Drag handles to resize panels dynamically - ðŸ“Ķ **Tree-shakeable** - Optimized for minimal bundle size -- ðŸŽŊ **TypeScript** - Full TypeScript support with type definitions - ðŸŠķ **Lightweight** - Minimal dependencies, only React as a peer dependency -- 🎛ïļ **Customizable** - Support for pixel, percentage, and auto-sizing units ## Installation diff --git a/packages/react-flexy-panels/README.md b/packages/react-flexy-panels/README.md index b136a75..5fe34a2 100644 --- a/packages/react-flexy-panels/README.md +++ b/packages/react-flexy-panels/README.md @@ -7,11 +7,11 @@ A flexible, resizable panel system for React applications version >= 18 with sup ## Features - ðŸŽĻ **Flexible Layouts** - Support for both horizontal and vertical panel arrangements +- 🎛ïļ **Customizable** - Support for pixel, percentage, and auto-sizing units +- 🎭 **Unstyled** - No default styles, giving you full control over appearance - 🔄 **Resizable Panels** - Drag handles to resize panels dynamically - ðŸ“Ķ **Tree-shakeable** - Optimized for minimal bundle size -- ðŸŽŊ **TypeScript** - Full TypeScript support with type definitions - ðŸŠķ **Lightweight** - Minimal dependencies, only React as a peer dependency -- 🎛ïļ **Customizable** - Support for pixel, percentage, and auto-sizing units ## Installation diff --git a/packages/react-flexy-panels/src/components/FlexyPanelHandle/FlexyPanelHandle.tsx b/packages/react-flexy-panels/src/components/FlexyPanelHandle/FlexyPanelHandle.tsx index ee49c8b..9bfc2d5 100644 --- a/packages/react-flexy-panels/src/components/FlexyPanelHandle/FlexyPanelHandle.tsx +++ b/packages/react-flexy-panels/src/components/FlexyPanelHandle/FlexyPanelHandle.tsx @@ -7,7 +7,7 @@ import { FlexyPanelHandleProps } from "./types"; export const FlexyPanelHandle = forwardRef< HTMLDivElement, FlexyPanelHandleProps ->(({ onMouseDown, onTouchStart, ...props }, ref) => { +>(({ onMouseDown, onTouchStart, onPreResize, ...props }, ref) => { const id = useId(); const { direction } = useFlexyPanelsContext(); const { @@ -16,6 +16,7 @@ export const FlexyPanelHandle = forwardRef< } = usePanelDrag({ direction, handleId: id, + onPreResize, }); const handleMouseDown = useCallback( diff --git a/packages/react-flexy-panels/src/components/FlexyPanelHandle/types/FlexyPanelHandleProps.t.ts b/packages/react-flexy-panels/src/components/FlexyPanelHandle/types/FlexyPanelHandleProps.t.ts index 3ce5449..b865826 100644 --- a/packages/react-flexy-panels/src/components/FlexyPanelHandle/types/FlexyPanelHandleProps.t.ts +++ b/packages/react-flexy-panels/src/components/FlexyPanelHandle/types/FlexyPanelHandleProps.t.ts @@ -1,3 +1,6 @@ import { ComponentProps } from "react"; +import { OnPreResizeFunction } from "../../../types"; -export type FlexyPanelHandleProps = ComponentProps<"div">; \ No newline at end of file +export type FlexyPanelHandleProps = ComponentProps<"div"> & { + onPreResize?: OnPreResizeFunction; +}; diff --git a/packages/react-flexy-panels/src/hooks/usePanelDrag.ts b/packages/react-flexy-panels/src/hooks/usePanelDrag.ts index 8ee5b7d..1e1af9d 100644 --- a/packages/react-flexy-panels/src/hooks/usePanelDrag.ts +++ b/packages/react-flexy-panels/src/hooks/usePanelDrag.ts @@ -1,16 +1,21 @@ -import { Direction } from "../types"; +import { Direction, OnPreResizeFunction } from "../types"; import { findAdjacentPanels, updatePanelSizes } from "../utils"; import { useCallback, useEffect, useRef, useState } from "react"; type UsePanelDragOptions = { direction: Direction; handleId: string; + onPreResize?: OnPreResizeFunction; }; /** * Custom hook to handle panel dragging logic */ -export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { +export const usePanelDrag = ({ + direction, + handleId, + onPreResize, +}: UsePanelDragOptions) => { const [isDragging, setIsDragging] = useState(false); const dragStartRef = useRef(0); const handleElementRef = useRef(null); @@ -43,6 +48,7 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { dragDelta, direction, unappliedDragDelta: unappliedDragDeltaRef.current, + onPreResize, }); unappliedDragDeltaRef.current = @@ -50,7 +56,7 @@ export const usePanelDrag = ({ direction, handleId }: UsePanelDragOptions) => { dragStartRef.current = dragCurrent; }, - [direction, handleId] + [direction, handleId, onPreResize] ); const onDrag = useCallback( diff --git a/packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts b/packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts new file mode 100644 index 0000000..d148c59 --- /dev/null +++ b/packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts @@ -0,0 +1,4 @@ +export type OnPreResizeFunction = (sizes: { + panel1NewSize: number; + panel2NewSize: number; +}) => void; diff --git a/packages/react-flexy-panels/src/types/index.ts b/packages/react-flexy-panels/src/types/index.ts index 1246a8d..5f8ac3f 100644 --- a/packages/react-flexy-panels/src/types/index.ts +++ b/packages/react-flexy-panels/src/types/index.ts @@ -1 +1,2 @@ export * from "./Direction.t"; +export * from "./OnPreResizeFunction.t"; diff --git a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts index 1d688a3..e1c0435 100644 --- a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts +++ b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts @@ -1,4 +1,4 @@ -import { Direction } from "../types"; +import { Direction, OnPreResizeFunction } from "../types"; import { getPanelSizeByDirection } from "./getPanelSizeByDirection"; import { isSameSign } from "./isSameSign"; @@ -13,8 +13,9 @@ export function updatePanelSizes(props: { dragDelta: number; direction: Direction; unappliedDragDelta: number; + onPreResize?: OnPreResizeFunction; }): number { - const { panel1, panel2, direction, unappliedDragDelta } = props; + const { panel1, panel2, direction, unappliedDragDelta, onPreResize } = props; let dragDelta = props.dragDelta; if (dragDelta === 0) { @@ -92,6 +93,12 @@ export function updatePanelSizes(props: { panel2NewSize = Math.max(minPanelSize, panel2NewSize); } + // Call the onPreResize function to allow any custom logic to be applied before the panel sizes are updated + onPreResize?.({ + panel1NewSize, + panel2NewSize, + }); + // Handle different unit combinations if (panel1Unit === "auto" && panel2Unit === "auto") { panel1.style.flex = `0 1 ${panel1NewSize}px`; From fc780a76e61d1d9c16ebd41d51e3e2d2794e7e5b Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Fri, 5 Dec 2025 08:47:40 -0600 Subject: [PATCH 2/3] feat: allow resize abort onPreResize --- .changeset/lovely-suits-divide.md | 5 +++++ apps/docs/src/components/FlexyHandle.tsx | 5 +++-- apps/docs/src/pages/SandboxPage.tsx | 8 +++++++- .../react-flexy-panels/src/types/OnPreResizeFunction.t.ts | 6 +++++- packages/react-flexy-panels/src/utils/updatePanelSizes.ts | 5 ++++- 5 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 .changeset/lovely-suits-divide.md diff --git a/.changeset/lovely-suits-divide.md b/.changeset/lovely-suits-divide.md new file mode 100644 index 0000000..26b7937 --- /dev/null +++ b/.changeset/lovely-suits-divide.md @@ -0,0 +1,5 @@ +--- +"react-flexy-panels": patch +--- + +feat: allow resize abort onPreResize diff --git a/apps/docs/src/components/FlexyHandle.tsx b/apps/docs/src/components/FlexyHandle.tsx index 33f7cfb..0c78b2a 100644 --- a/apps/docs/src/components/FlexyHandle.tsx +++ b/apps/docs/src/components/FlexyHandle.tsx @@ -1,8 +1,8 @@ import { cn } from "@rlx-widgets/base"; import { GripVerticalIcon } from "lucide-react"; -import { FlexyPanelHandle } from "react-flexy-panels"; +import { FlexyPanelHandle, OnPreResizeFunction } from "react-flexy-panels"; -export const FlexyHandle = ({ withHandle }: { withHandle?: boolean }) => { +export const FlexyHandle = ({ withHandle, onPreResize }: { withHandle?: boolean, onPreResize?: OnPreResizeFunction }) => { return ( { "data-[direction=vertical]:h-px data-[direction=vertical]:after:left-0 data-[direction=vertical]:after:top-[calc(50%-0.5px)] data-[direction=vertical]:after:h-px data-[direction=vertical]:after:w-full data-[direction=vertical]:cursor-row-resize", "data-[direction=horizontal]:w-px data-[direction=horizontal]:after:inset-y-0 data-[direction=horizontal]:after:left-[calc(50%-0.5px)] data-[direction=horizontal]:after:w-px data-[direction=horizontal]:cursor-col-resize" )} + onPreResize={onPreResize} > {withHandle && (
{ const [panel2Open, setPanel2Open] = useState(true); + const onPreResize = (sizes: { + panel1NewSize: number; + panel2NewSize: number; + }) => { + return { abort: sizes.panel1NewSize > 300 }; + }; return (
@@ -16,7 +22,7 @@ export const SandboxPage = () => { {panel2Open && ( <> - +
Panel 2 diff --git a/packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts b/packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts index d148c59..e1b70b3 100644 --- a/packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts +++ b/packages/react-flexy-panels/src/types/OnPreResizeFunction.t.ts @@ -1,4 +1,8 @@ +export type OnPreResizeReturnOptions = { + abort?: boolean; +}; + export type OnPreResizeFunction = (sizes: { panel1NewSize: number; panel2NewSize: number; -}) => void; +}) => OnPreResizeReturnOptions | undefined | void; diff --git a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts index e1c0435..d3a2a7f 100644 --- a/packages/react-flexy-panels/src/utils/updatePanelSizes.ts +++ b/packages/react-flexy-panels/src/utils/updatePanelSizes.ts @@ -94,10 +94,13 @@ export function updatePanelSizes(props: { } // Call the onPreResize function to allow any custom logic to be applied before the panel sizes are updated - onPreResize?.({ + const onPreResizeResult = onPreResize?.({ panel1NewSize, panel2NewSize, }); + if (onPreResizeResult?.abort) { + return 0; + } // Handle different unit combinations if (panel1Unit === "auto" && panel2Unit === "auto") { From 0d857886eb6ff91cf45b7967612074c6d9e620f8 Mon Sep 17 00:00:00 2001 From: Guanghui Li Date: Fri, 5 Dec 2025 08:49:19 -0600 Subject: [PATCH 3/3] chore: remove previous changeset --- .changeset/funny-pianos-type.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/funny-pianos-type.md diff --git a/.changeset/funny-pianos-type.md b/.changeset/funny-pianos-type.md deleted file mode 100644 index 43ead54..0000000 --- a/.changeset/funny-pianos-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"react-flexy-panels": patch ---- - -feat: expose onPreResize prop on handle to allow any preprocess to be done before the panels are resized