Skip to content

Commit

Permalink
Partially migrate imperative examples to new Panel and PanelGroup
Browse files Browse the repository at this point in the history
  • Loading branch information
bvaughn committed Oct 21, 2023
1 parent 15bb5c5 commit bc8f249
Show file tree
Hide file tree
Showing 8 changed files with 286 additions and 65 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { useMemo } from "react";
import { Panel, PanelGroup, PanelGroupStorage } from "react-resizable-panels";
import {
new_Panel as Panel,
new_PanelGroup as PanelGroup,
PanelGroupStorage,
} from "react-resizable-panels";
import { useNavigate } from "react-router-dom";

import ResizeHandle from "../../components/ResizeHandle";
import { new_ResizeHandle as ResizeHandle } from "../../components/ResizeHandle";

import Example from "./Example";
import styles from "./shared.module.css";
Expand Down Expand Up @@ -81,15 +85,23 @@ function Content() {
direction="horizontal"
storage={urlStorage}
>
<Panel className={styles.PanelRow} collapsible={true} minSize={10}>
<Panel
className={styles.PanelRow}
collapsible={true}
minSizePercentage={10}
>
<div className={styles.Centered}>left</div>
</Panel>
<ResizeHandle className={styles.ResizeHandle} />
<Panel className={styles.PanelRow} minSize={10}>
<Panel className={styles.PanelRow} minSizePercentage={10}>
<div className={styles.Centered}>middle</div>
</Panel>
<ResizeHandle className={styles.ResizeHandle} />
<Panel className={styles.PanelRow} collapsible={true} minSize={10}>
<Panel
className={styles.PanelRow}
collapsible={true}
minSizePercentage={10}
>
<div className={styles.Centered}>right</div>
</Panel>
</PanelGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ChangeEvent, FormEvent, RefObject, useRef, useState } from "react";
import {
ImperativePanelHandle,
Panel,
PanelGroup,
new_ImperativePanelHandle as ImperativePanelHandle,
new_Panel as Panel,
new_PanelGroup as PanelGroup,
} from "react-resizable-panels";
import Icon from "../../components/Icon";

import ResizeHandle from "../../components/ResizeHandle";
import { new_ResizeHandle as ResizeHandle } from "../../components/ResizeHandle";

import Example from "./Example";
import styles from "./ImperativePanelApi.module.css";
Expand Down Expand Up @@ -212,11 +212,11 @@ function Content({
<Panel
className={sharedStyles.PanelRow}
collapsible
defaultSize={sizes.left}
defaultSizePercentage={sizes.left}
id="left"
maxSize={30}
minSize={10}
onResize={(left: number) => onResize({ left })}
maxSizePercentage={30}
minSizePercentage={10}
onResize={({ sizePercentage: left }) => onResize({ left })}
order={1}
ref={leftPanelRef}
>
Expand All @@ -229,9 +229,9 @@ function Content({
className={sharedStyles.PanelRow}
collapsible={true}
id="middle"
maxSize={100}
minSize={10}
onResize={(middle: number) => onResize({ middle })}
maxSizePercentage={100}
minSizePercentage={10}
onResize={({ sizePercentage: middle }) => onResize({ middle })}
order={2}
ref={middlePanelRef}
>
Expand All @@ -243,11 +243,11 @@ function Content({
<Panel
className={sharedStyles.PanelRow}
collapsible
defaultSize={sizes.right}
defaultSizePercentage={sizes.right}
id="right"
maxSize={100}
minSize={10}
onResize={(right: number) => onResize({ right })}
maxSizePercentage={100}
minSizePercentage={10}
onResize={({ sizePercentage: right }) => onResize({ right })}
order={3}
ref={rightPanelRef}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import { RefObject, useRef, useState } from "react";
import { useRef, useState } from "react";
import type { new_ImperativePanelGroupHandle as ImperativePanelGroupHandle } from "react-resizable-panels";
import {
ImperativePanelHandle,
Panel,
PanelGroup,
new_Panel as Panel,
new_PanelGroup as PanelGroup,
} from "react-resizable-panels";

import ResizeHandle from "../../components/ResizeHandle";
import { new_ResizeHandle as ResizeHandle } from "../../components/ResizeHandle";

import Code from "../../components/Code";
import Example from "./Example";
import styles from "./ImperativePanelGroupApi.module.css";
import sharedStyles from "./shared.module.css";
import Code from "../../components/Code";
import { ImperativePanelGroupHandle } from "react-resizable-panels";

type Sizes = {
left: number;
middle: number;
right: number;
};

export default function ImperativePanelGroupApiRoute() {
return (
Expand Down Expand Up @@ -68,7 +61,7 @@ function Content() {
const resetLayout = () => {
const panelGroup = panelGroupRef.current;
if (panelGroup) {
panelGroup.setLayout([50, 50]);
panelGroup.setLayout([{ sizePercentage: 50 }, { sizePercentage: 50 }]);
}
};

Expand All @@ -87,13 +80,13 @@ function Content() {
onLayout={onLayout}
ref={panelGroupRef}
>
<Panel className={sharedStyles.PanelRow} minSize={10}>
<Panel className={sharedStyles.PanelRow} minSizePercentage={10}>
<div className={sharedStyles.Centered}>
left: {Math.round(sizes[0])}
</div>
</Panel>
<ResizeHandle className={sharedStyles.ResizeHandle} />
<Panel className={sharedStyles.PanelRow} minSize={10}>
<Panel className={sharedStyles.PanelRow} minSizePercentage={10}>
<div className={sharedStyles.Centered}>
right: {Math.round(sizes[1])}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ export default function PixelBasedLayouts() {
<span className={exampleStyles.Title}>Pixel based layouts</span>
</h1>
<p>
Resizable panels typically use percentage-based layout constraints, but
pixel units are also supported via the <code>units</code> prop. The
example below shows a horizontal panel group where the first panel is
limited to a range of 100-200 pixels.
Resizable panels can specific either <strong>percentage-based</strong>{" "}
or <strong>pixel-based</strong> layout constraints, although
percentage-based constraints are generally recommended for performance
purposes. The example below shows a horizontal panel group where the
first panel is limited to a range of 100-200 pixels.
</p>
<p className={sharedStyles.WarningBlock}>
<Icon className={sharedStyles.WarningIcon} type="warning" />
Pixel units should only be used when necessary because they require more
complex layout logic.
Pixel units should only be used when necessary because they require the
use of a <code>ResizerObserver</code>.
</p>
<div className={exampleStyles.ExampleContainer}>
<div className={sharedStyles.PanelGroupWrapper} data-short>
Expand Down Expand Up @@ -139,8 +140,8 @@ function Size({
}

const CODE_HOOK = `
<PanelGroup direction="horizontal" units="pixels">
<Panel minSize={100} maxSize={200} />
<PanelGroup direction="horizontal">
<Panel minSizePixels={100} maxSizePixels={200} />
<PanelResizeHandle />
<Panel />
<PanelResizeHandle />
Expand All @@ -149,11 +150,11 @@ const CODE_HOOK = `
`;

const CODE_HOOK_COLLAPSIBLE = `
<PanelGroup direction="horizontal" units="pixels">
<PanelGroup direction="horizontal">
<Panel />
<PanelResizeHandle />
<Panel />
<PanelResizeHandle />
<Panel collapsible={true} collapsedSize={75} minSize={100} maxSize={200} />
<Panel collapsible={true} collapsedSizePixels={75} minSizePixels={100} maxSizePixels={200} />
</PanelGroup>
`;
4 changes: 4 additions & 0 deletions packages/react-resizable-panels/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { PanelResizeHandle } from "./PanelResizeHandle";

// TEMP
import { Panel as new_Panel } from "./new/Panel";
import type { ImperativePanelHandle as new_ImperativePanelHandle } from "./new/Panel";
import { PanelGroup as new_PanelGroup } from "./new/PanelGroup";
import type { ImperativePanelGroupHandle as new_ImperativePanelGroupHandle } from "./new/PanelGroup";
import { PanelResizeHandle as new_PanelResizeHandle } from "./new/PanelResizeHandle";

import type { ImperativePanelHandle, PanelProps } from "./Panel";
Expand Down Expand Up @@ -43,6 +45,8 @@ export {
getAvailableGroupSizePixels,

// TEMP
new_ImperativePanelGroupHandle,
new_ImperativePanelHandle,
new_Panel,
new_PanelGroup,
new_PanelResizeHandle,
Expand Down
51 changes: 46 additions & 5 deletions packages/react-resizable-panels/src/new/PanelGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ import debounce from "../utils/debounce";
import {
CSSProperties,
ElementType,
ForwardedRef,
PropsWithChildren,
createElement,
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
useRef,
useState,
} from "../vendor/react";
import { PanelData } from "./Panel";
import { DragState, PanelGroupContext, ResizeEvent } from "./PanelGroupContext";
import { Direction } from "./types";
import { Direction, MixedSizes } from "./types";
import { adjustLayoutByDelta } from "./utils/adjustLayoutByDelta";
import { calculateDefaultLayout } from "./utils/calculateDefaultLayout";
import { calculateDeltaPercentage } from "./utils/calculateDeltaPercentage";
Expand All @@ -27,7 +30,7 @@ import { convertPercentageToPixels } from "./utils/convertPercentageToPixels";
import { determinePivotIndices } from "./utils/determinePivotIndices";
import { calculateAvailablePanelSizeInPixels } from "./utils/dom/calculateAvailablePanelSizeInPixels";
import { getResizeHandleElement } from "./utils/dom/getResizeHandleElement";
import { isMouseEvent, isTouchEvent } from "./utils/events";
import { isKeyDown, isMouseEvent, isTouchEvent } from "./utils/events";
import { getResizeEventCursorPosition } from "./utils/getResizeEventCursorPosition";
import { initializeDefaultStorage } from "./utils/initializeDefaultStorage";
import { loadPanelLayout, savePanelGroupLayout } from "./utils/serialization";
Expand All @@ -37,6 +40,12 @@ import { validatePanelGroupLayout } from "./utils/validatePanelGroupLayout";

// TODO Use ResizeObserver (but only if any Panels declare pixels units)

export type ImperativePanelGroupHandle = {
getId: () => string;
getLayout: () => MixedSizes[];
setLayout: (layout: Partial<MixedSizes>[]) => void;
};

export type PanelGroupStorage = {
getItem(name: string): string | null;
setItem(name: string, value: string): void;
Expand Down Expand Up @@ -73,17 +82,20 @@ const debounceMap: {
[key: string]: typeof savePanelGroupLayout;
} = {};

export function PanelGroup({
function PanelGroupWithForwardedRef({
autoSaveId,
children,
className: classNameFromProps = "",
direction,
forwardedRef,
id: idFromProps,
onLayout,
storage = defaultStorage,
style: styleFromProps,
tagName: Type = "div",
}: PanelGroupProps) {
}: PanelGroupProps & {
forwardedRef: ForwardedRef<ImperativePanelGroupHandle>;
}) {
const groupId = useUniqueId(idFromProps);

const [dragState, setDragState] = useState<DragState | null>(null);
Expand All @@ -106,6 +118,21 @@ export function PanelGroup({
panelDataArray,
});

useImperativeHandle(
forwardedRef,
() => ({
getId: () => groupId,
getLayout: () => {
// TODO
return [];
},
setLayout: (layout: Partial<MixedSizes>[]) => {
// TODO
},
}),
[groupId]
);

useIsomorphicLayoutEffect(() => {
committedValuesRef.current.direction = direction;
committedValuesRef.current.dragState = dragState;
Expand Down Expand Up @@ -196,12 +223,14 @@ export function PanelGroup({
layout,
panelConstraints: panelConstraintsArray,
pivotIndices,
trigger: "imperative-api",
});

if (!compareLayouts(layout, nextLayout)) {
setLayout(nextLayout);

// TODO Callbacks and stuff (put in helper function that takes prevLayout, nextLayout)
// onLayout()
}
}
}
Expand Down Expand Up @@ -236,6 +265,7 @@ export function PanelGroup({
layout,
panelConstraints: panelConstraintsArray,
pivotIndices,
trigger: "imperative-api",
});

if (!compareLayouts(layout, nextLayout)) {
Expand Down Expand Up @@ -370,12 +400,12 @@ export function PanelGroup({
);

const nextLayout = adjustLayoutByDelta({
collapsedPanelMode: "snap",
delta,
groupSizePixels,
layout: initialLayout ?? prevLayout,
panelConstraints,
pivotIndices,
trigger: isKeyDown(event) ? "keyboard" : "mouse-or-touch",
});

const layoutChanged = !compareLayouts(prevLayout, nextLayout);
Expand Down Expand Up @@ -434,6 +464,7 @@ export function PanelGroup({
layout,
panelConstraints: panelConstraintsArray,
pivotIndices,
trigger: "imperative-api",
});

if (!compareLayouts(layout, nextLayout)) {
Expand Down Expand Up @@ -549,6 +580,16 @@ export function PanelGroup({
);
}

export const PanelGroup = forwardRef<
ImperativePanelGroupHandle,
PanelGroupProps
>((props: PanelGroupProps, ref: ForwardedRef<ImperativePanelGroupHandle>) =>
createElement(PanelGroupWithForwardedRef, { ...props, forwardedRef: ref })
);

PanelGroupWithForwardedRef.displayName = "PanelGroup";
PanelGroup.displayName = "forwardRef(PanelGroup)";

function panelDataHelper(
groupId: string,
panelDataArray: PanelData[],
Expand Down
Loading

0 comments on commit bc8f249

Please sign in to comment.