Skip to content

Commit

Permalink
Add :order prop to Panel
Browse files Browse the repository at this point in the history
  • Loading branch information
bvaughn committed Dec 23, 2022
1 parent cebd3a0 commit f9692d1
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 84 deletions.
7 changes: 0 additions & 7 deletions packages/react-resizable-panels-website/root.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,6 @@ code {
border-radius: 0.25em;
}

hr {
width: 100%;
height: 1px;
border: none;
background-color: #454950;
}

h2 {
font-weight: normal;
margin: 0.5rem 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default function HorizontalGroup({
reset vertical sizes
<div className={styles.VerticalDot} />
</button>
<hr />
<span className={styles.HorizontalDivider} />
<button
className={styles.Button}
onClick={() => clearSavedSizes(GROUP_ID, GROUP_ID_VERTICAL)}
Expand Down
141 changes: 85 additions & 56 deletions packages/react-resizable-panels-website/src/VerticalGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,101 @@ import styles from "./styles.module.css";
export const GROUP_ID = "vertical";

export function VerticalGroup() {
const [isPanelHidden, setIsPanelHidden] = useState(false);

const hidePanel = () => setIsPanelHidden(true);
const showPanel = () => setIsPanelHidden(false);
const [showTopPanel, setShowTopPanel] = useState(true);
const [showBottomPanel, setShowBottomPanel] = useState(true);

return (
<PanelGroup autoSaveId={GROUP_ID} direction="vertical">
<Panel
className={styles.PanelRow}
defaultSize={0.35}
id="top"
minSize={0.25}
>
<div
className={
isPanelHidden ? styles.VerticalFiller : styles.VerticalFillerTop
}
style={{ backgroundColor: "var(--color-vertical)" }}
>
<p className={styles.ParagraphOfText}>
This is a "<em>vertical</em>" <code>PanelGroup</code>.
</p>
<p className={styles.ParagraphOfText}>
It has a solid resize bar, similar to Chrome devtools or VS Code.
</p>
<p className={styles.ParagraphOfText}>
It uses the <code>minSize</code> prop to prevent it from shrinking
to less than 35% of the total height.
</p>

{isPanelHidden && (
<button
className={styles.ButtonBottom}
onClick={showPanel}
id="blah"
>
Show panel
</button>
)}
</div>
</Panel>
{isPanelHidden || (
<div
className={styles.VerticalFiller}
style={{ backgroundColor: "var(--color-vertical)" }}
>
<PanelGroup autoSaveId={GROUP_ID} direction="vertical">
{showTopPanel && (
<Panel
className={styles.PanelColumn}
defaultSize={0.35}
id="top"
minSize={0.2}
order={1}
>
<div className={styles.VerticalFiller}>
<p className={styles.ParagraphOfText}>
This is a "<em>vertical</em>" <code>PanelGroup</code>.
</p>
<p className={styles.ParagraphOfText}>
<button
className={styles.Button}
onClick={() => setShowTopPanel(false)}
>
Hide panel
</button>
</p>
</div>
<PanelResizeHandle panelBefore="top" panelAfter="middle">
<div className={styles.VerticalResizeBar} />
</PanelResizeHandle>
</Panel>
)}
<Panel
className={styles.PanelColumn}
defaultSize={0.65}
id="bottom"
defaultSize={0.35}
id="middle"
minSize={0.35}
order={2}
>
<PanelResizeHandle panelBefore="top" panelAfter="bottom">
<div className={styles.VerticalResizeBar} />
</PanelResizeHandle>
<div
className={styles.VerticalFillerBottom}
style={{ backgroundColor: "var(--color-vertical)" }}
>
<div className={styles.VerticalFiller}>
<p className={styles.ParagraphOfText}>
This panel's visibility can be toggled on or off.
This panel uses the <code>minSize</code> prop to prevent it from
shrinking to less than 35% of the total height.
</p>
<p className={styles.ParagraphOfText}>
<button className={styles.Button} onClick={hidePanel}>
Hide panel

{!showTopPanel && (
<button
className={styles.ButtonTop}
onClick={() => setShowTopPanel(true)}
>
Show top panel
</button>
</p>
)}

{!showBottomPanel && (
<button
className={styles.ButtonBottom}
onClick={() => setShowBottomPanel(true)}
>
Show bottom panel
</button>
)}
</div>
</Panel>
)}
</PanelGroup>
{showBottomPanel && (
<Panel
className={styles.PanelColumn}
defaultSize={0.65}
id="bottom"
minSize={0.2}
order={3}
>
<PanelResizeHandle panelBefore="middle" panelAfter="bottom">
<div className={styles.VerticalResizeBar} />
</PanelResizeHandle>
<div className={styles.VerticalFiller}>
<p className={styles.ParagraphOfText}>
This group uses a solid resize bar, similar to Chrome devtools
or VS Code.
</p>
<p className={styles.ParagraphOfText}>
<button
className={styles.Button}
onClick={() => setShowBottomPanel(false)}
>
Hide panel
</button>
</p>
</div>
</Panel>
)}
</PanelGroup>
</div>
);
}
33 changes: 19 additions & 14 deletions packages/react-resizable-panels-website/src/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@
.HorizontalFiller,
.HorizontalFillerLeft,
.HorizontalFillerRight,
.VerticalFiller,
.VerticalFillerBottom,
.VerticalFillerTop {
.VerticalFiller {
height: 100%;
width: 100%;
background-color: #192230;
display: flex;
flex-direction: column;
align-items: center;
Expand All @@ -31,14 +28,6 @@
.VerticalFiller {
border-radius: 0.5rem;
}
.VerticalFillerTop {
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
}
.VerticalFillerBottom {
border-bottom-left-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
}

.PanelRow {
display: flex;
Expand All @@ -62,7 +51,8 @@
}

.Button,
.ButtonBottom {
.ButtonBottom,
.ButtonTop {
color: #ffffff;
background: #2a3343;
border: 1px solid #18181a;
Expand All @@ -71,7 +61,8 @@
cursor: pointer;
}
.Button:hover,
.ButtonBottom:hover {
.ButtonBottom:hover,
.ButtonTop:hover {
background: #454950;
}

Expand Down Expand Up @@ -101,3 +92,17 @@
bottom: 1ch;
right: 1ch;
}
.ButtonTop {
position: absolute;
top: 1ch;
right: 1ch;
}

.HorizontalDivider {
display: block;
width: 100%;
height: 1px;
border: none;
background-color: #454950;
margin: 0.5rem 0;
}
3 changes: 3 additions & 0 deletions packages/react-resizable-panels/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## 0.0.4
* [#8](https://github.com/bvaughn/react-resizable-panels/issues/8): Added optional `order` prop to `Panel` to improve conditional rendering.

## 0.0.3
* [#3](https://github.com/bvaughn/react-resizable-panels/issues/3): `Panel`s can be conditionally rendered within a group. `PanelGroup` will persist separate layouts for each combination of visible panels.

Expand Down
1 change: 1 addition & 0 deletions packages/react-resizable-panels/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
| `defaultSize` | `?number` | Initial size of panel (relative to other panels within the group)
| `id` | `string` | Panel id (must be unique within the current group)
| `minSize` | `?number` | Minum allowable size of panel (0.0 - 1.0)
| `order` | `?number` | Order of panel within group; required for groups with conditionally rendered panels

### `PanelResizeHandle`
| prop | type | description
Expand Down
5 changes: 4 additions & 1 deletion packages/react-resizable-panels/src/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ export default function Panel({
defaultSize = 0.1,
id,
minSize = 0.1,
order = null,
}: {
children?: ReactNode;
className?: string;
defaultSize?: number;
id: string;
minSize?: number;
order?: number | null;
}) {
const context = useContext(PanelGroupContext);
if (context === null) {
Expand All @@ -40,14 +42,15 @@ export default function Panel({
defaultSize,
id,
minSize,
order,
};

registerPanel(id, panel);

return () => {
unregisterPanel(id);
};
}, [defaultSize, id, minSize, registerPanel, unregisterPanel]);
}, [defaultSize, id, minSize, order, registerPanel, unregisterPanel]);

const style = getPanelStyle(id);

Expand Down
15 changes: 10 additions & 5 deletions packages/react-resizable-panels/src/PanelGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export default function PanelGroup({
if (defaultSizes != null) {
setSizes(defaultSizes);
} else {
const panelsArray: PanelData[] = Array.from(panels.values());
const panelsArray = panelsMapToSortedArray(panels);
const totalWeight = panelsArray.reduce((weight, panel) => {
return weight + panel.defaultSize;
}, 0);
Expand Down Expand Up @@ -237,7 +237,7 @@ function adjustByDelta(
return prevSizes;
}

const panelsArray: PanelData[] = Array.from(panels.values());
const panelsArray = panelsMapToSortedArray(panels);

const nextSizes = prevSizes.concat();

Expand Down Expand Up @@ -295,7 +295,8 @@ function createLocalStorageKey(
autoSaveId: string,
panels: Map<string, PanelData>
): string {
const panelIds = Array.from(panels.keys()).sort();
const panelsArray = panelsMapToSortedArray(panels);
const panelIds = panelsArray.map((panel) => panel.id);

return `PanelGroup:sizes:${autoSaveId}${panelIds.join("|")}`;
}
Expand All @@ -308,7 +309,7 @@ function getOffset(
height: number,
width: number
): number {
const panelsArray: PanelData[] = Array.from(panels.values());
const panelsArray = panelsMapToSortedArray(panels);

let index = panelsArray.findIndex((panel) => panel.id === id);
if (index < 0) {
Expand Down Expand Up @@ -339,7 +340,7 @@ function getSize(
return totalSize;
}

const panelsArray: PanelData[] = Array.from(panels.values());
const panelsArray = panelsMapToSortedArray(panels);

const index = panelsArray.findIndex((panel) => panel.id === id);
const size = sizes[index];
Expand All @@ -349,3 +350,7 @@ function getSize(

return Math.round(size * totalSize);
}

function panelsMapToSortedArray(panels: Map<string, PanelData>): PanelData[] {
return Array.from(panels.values()).sort((a, b) => a.order - b.order);
}
1 change: 1 addition & 0 deletions packages/react-resizable-panels/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type PanelData = {
defaultSize: number;
id: string;
minSize: number;
order: number | null;
};

export type ResizeHandler = (event: MouseEvent) => void;

0 comments on commit f9692d1

Please sign in to comment.