Skip to content
Open
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
12 changes: 7 additions & 5 deletions lib/Pane.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, HTMLAttributes, forwardRef, useRef, useEffect } from 'react';
import { ReactNode, HTMLAttributes, useRef, useEffect, RefObject } from 'react';
import { Slot } from '@radix-ui/react-slot';

import { useRootContext } from './RootContext';
Expand Down Expand Up @@ -101,8 +101,9 @@ export type ResplitPaneProps = Omit<
* </ResplitPane>
* ```
*/
export const ResplitPane = forwardRef<HTMLDivElement, ResplitPaneProps>(function Pane(
export const ResplitPane = function Pane(
{
ref,
children,
order,
minSize = PANE_DEFAULT_MIN_SIZE,
Expand All @@ -114,8 +115,9 @@ export const ResplitPane = forwardRef<HTMLDivElement, ResplitPaneProps>(function
onResizeStart,
onResizeEnd,
...rest
},
ref,
}: ResplitPaneProps & {
ref: RefObject<HTMLDivElement | null>;
}
) {
const Comp = asChild ? Slot : 'div';
const { id, registerPane } = useRootContext();
Expand Down Expand Up @@ -158,4 +160,4 @@ export const ResplitPane = forwardRef<HTMLDivElement, ResplitPaneProps>(function
{children}
</Comp>
);
});
};
27 changes: 17 additions & 10 deletions lib/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {
MutableRefObject,
HTMLAttributes,
ReactNode,
forwardRef,
useId,
useRef,
useState,
useCallback,
useMemo,
RefObject,
} from 'react';
import { Slot } from '@radix-ui/react-slot';

Expand Down Expand Up @@ -36,7 +35,7 @@ import type { ResplitSplitterOptions } from './Splitter';
*/
export interface PaneChild {
type: 'pane';
options: MutableRefObject<
options: RefObject<
ResplitPaneOptions & {
minSize: PxValue | FrValue;
collapsedSize: PxValue | FrValue;
Expand All @@ -53,7 +52,7 @@ export interface PaneChild {
*/
export interface SplitterChild {
type: 'splitter';
options: MutableRefObject<
options: RefObject<
ResplitSplitterOptions & {
size: PxValue;
}
Expand Down Expand Up @@ -115,9 +114,17 @@ export type ResplitRootProps = ResplitOptions &
* </ResplitRoot>
* ```
*/
export const ResplitRoot = forwardRef<HTMLDivElement, ResplitRootProps>(function Root(
{ direction = 'horizontal', children: reactChildren, style, asChild = false, ...rest },
forwardedRef,
export const ResplitRoot = function Root(
{
ref: forwardedRef,
direction = 'horizontal',
children: reactChildren,
style,
asChild = false,
...rest
}: ResplitRootProps & {
ref: RefObject<HTMLDivElement | null>;
}
) {
const id = useId();
const Comp = asChild ? Slot : 'div';
Expand Down Expand Up @@ -446,7 +453,7 @@ export const ResplitRoot = forwardRef<HTMLDivElement, ResplitRootProps>(function
);

const registerPane = useCallback(
(order: string, options: MutableRefObject<ResplitPaneOptions>) => {
(order: string, options: RefObject<ResplitPaneOptions>) => {
setChildren((children) => ({
...children,
[order]: {
Expand All @@ -459,7 +466,7 @@ export const ResplitRoot = forwardRef<HTMLDivElement, ResplitRootProps>(function
);

const registerSplitter = useCallback(
(order: string, options: MutableRefObject<ResplitSplitterOptions>) => {
(order: string, options: RefObject<ResplitSplitterOptions>) => {
setChildren((children) => ({
...children,
[order]: {
Expand Down Expand Up @@ -565,4 +572,4 @@ export const ResplitRoot = forwardRef<HTMLDivElement, ResplitRootProps>(function
</ResplitContext.Provider>
</RootContext.Provider>
);
});
};
22 changes: 15 additions & 7 deletions lib/Splitter.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactNode, HTMLAttributes, forwardRef, useRef, useEffect } from 'react';
import { ReactNode, HTMLAttributes, useRef, useEffect, RefObject } from 'react';
import { Slot } from '@radix-ui/react-slot';

import { useRootContext } from './RootContext';
Expand Down Expand Up @@ -56,9 +56,17 @@ export type ResplitSplitterProps = HTMLAttributes<HTMLDivElement> &
* <ResplitSplitter order={1} size={4} />
* ```
*/
export const ResplitSplitter = forwardRef<HTMLDivElement, ResplitSplitterProps>(function Splitter(
{ children, order, size = SPLITTER_DEFAULT_SIZE, asChild = false, ...rest },
ref,
export const ResplitSplitter = function Splitter(
{
ref,
children,
order,
size = SPLITTER_DEFAULT_SIZE,
asChild = false,
...rest
}: ResplitSplitterProps & {
ref: RefObject<HTMLDivElement | null>;
}
) {
const Comp = asChild ? Slot : 'div';
const { id, direction, registerSplitter, handleSplitterMouseDown, handleSplitterKeyDown } =
Expand All @@ -76,7 +84,7 @@ export const ResplitSplitter = forwardRef<HTMLDivElement, ResplitSplitterProps>(

return (
// eslint-disable-next-line jsx-a11y/role-supports-aria-props, jsx-a11y/no-noninteractive-element-interactions
<Comp
(<Comp
role="separator"
tabIndex={0}
aria-orientation={direction}
Expand All @@ -93,6 +101,6 @@ export const ResplitSplitter = forwardRef<HTMLDivElement, ResplitSplitterProps>(
{...rest}
>
{children}
</Comp>
</Comp>)
);
});
};
24 changes: 14 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-resplit",
"description": "Resizable split pane layouts for React applications",
"description": "Resizable split pane layouts for React@19 applications",
"keywords": [
"react",
"split",
Expand All @@ -20,7 +20,7 @@
},
"license": "MIT",
"type": "module",
"version": "1.3.2",
"version": "1.4.0",
"main": "./dist/resplit.umd.cjs",
"module": "./dist/resplit.es.js",
"types": "./dist/resplit.d.ts",
Expand Down Expand Up @@ -48,15 +48,15 @@
"size": "yarn build && size-limit"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
"react": ">=19",
"react-dom": ">=19"
},
"devDependencies": {
"@codesandbox/sandpack-react": "^1.18.2",
"@size-limit/preset-small-lib": "^8.1.2",
"@types/node": "^18.11.17",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@typescript-eslint/eslint-plugin": "^5.46.0",
"@typescript-eslint/parser": "^5.46.0",
"@vitejs/plugin-react": "^3.0.0",
Expand All @@ -71,15 +71,19 @@
"eslint-plugin-tsdoc": "^0.2.17",
"postcss": "^8.4.19",
"prettier": "^2.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"size-limit": "^8.1.2",
"tailwindcss": "^3.2.4",
"typescript": "^4.6.3",
"vite": "^4.0.5",
"vite-plugin-dts": "^1.7.1"
},
"dependencies": {
"@radix-ui/react-slot": "^1.0.2"
}
"@radix-ui/react-slot": "^1.2.0"
},
"directories": {
"lib": "lib"
},
"homepage": "https://github.com/KenanYusuf/react-resplit#readme"
}
29 changes: 23 additions & 6 deletions src/examples/CodeEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useRef, useState } from 'react';
import { Resplit, useResplitContext } from 'resplit';
import {
SandpackProvider,
Expand Down Expand Up @@ -74,6 +74,8 @@ const ProblemsPane = () => {
const { isPaneMinSize, setPaneSizes } = useResplitContext();
const [tab, setTab] = React.useState<'console' | 'problems'>('console');
const [isMinSize, setIsMinSize] = useState(false);
const paneRef = useRef<HTMLDivElement | null>(null);
const splitterRef = useRef<HTMLDivElement | null>(null);

const handleResize = () => {
if (isPaneMinSize(2)) {
Expand All @@ -85,7 +87,7 @@ const ProblemsPane = () => {

return (
<>
<Resplit.Splitter order={1} size="48px">
<Resplit.Splitter order={1} size="48px" ref={splitterRef}>
<PaneHeader>
<button
className={tab === 'console' ? 'underline' : ''}
Expand Down Expand Up @@ -131,6 +133,7 @@ const ProblemsPane = () => {

<Resplit.Pane
order={2}
ref={paneRef}
initialSize="0.3fr"
onResize={handleResize}
className="relative z-10 flex flex-col bg-zinc-800"
Expand All @@ -142,9 +145,12 @@ const ProblemsPane = () => {
};

const PreviewPane = () => {
const rootRef = useRef<HTMLDivElement | null>(null);
const paneRef = useRef<HTMLDivElement | null>(null);

return (
<Resplit.Root direction="vertical" className="h-full">
<Resplit.Pane order={0} initialSize="0.7fr" className="relative flex flex-col bg-zinc-800">
<Resplit.Root direction="vertical" className="h-full" ref={rootRef}>
<Resplit.Pane order={0} initialSize="0.7fr" className="relative flex flex-col bg-zinc-800" ref={paneRef}>
<PaneHeader>Preview</PaneHeader>
<SandpackPreview className="flex-1" />
</Resplit.Pane>
Expand All @@ -155,6 +161,13 @@ const PreviewPane = () => {
};

export const CodeEditorExample = () => {
const rootRef = useRef<HTMLDivElement | null>(null);
const splitterRef = useRef<HTMLDivElement | null>(null);
const secondSplitterRef = useRef<HTMLDivElement | null>(null);
const firstPaneRef = useRef<HTMLDivElement | null>(null);
const secondPaneRef = useRef<HTMLDivElement | null>(null);
const thirdPaneRef = useRef<HTMLDivElement | null>(null);

return (
<SandpackProvider
template="react-ts"
Expand Down Expand Up @@ -190,9 +203,10 @@ export const CodeEditorExample = () => {
</svg>
</button>
</div>
<Resplit.Root className="flex-1 font-mono text-sm">
<Resplit.Root className="flex-1 font-mono text-sm" ref={rootRef}>
<Resplit.Pane
order={0}
ref={firstPaneRef}
initialSize="0.15fr"
minSize="0.1fr"
collapsedSize="40px"
Expand All @@ -204,12 +218,14 @@ export const CodeEditorExample = () => {
</Resplit.Pane>
<Resplit.Splitter
order={1}
ref={splitterRef}
size="1px"
aria-labelledby="files-pane"
className={[SPLITTER_CLASSES, HORIZONTAL_SPLITTER_CLASSES].join(' ')}
/>
<Resplit.Pane
order={2}
ref={secondPaneRef}
initialSize="0.45fr"
minSize="0.1fr"
className="flex flex-col bg-zinc-800 overflow-hidden"
Expand All @@ -221,11 +237,12 @@ export const CodeEditorExample = () => {
</Resplit.Pane>
<Resplit.Splitter
order={3}
ref={secondSplitterRef}
size="1px"
aria-labelledby="code-pane"
className={[SPLITTER_CLASSES, HORIZONTAL_SPLITTER_CLASSES].join(' ')}
/>
<Resplit.Pane order={4} initialSize="0.4fr" minSize="0.1fr">
<Resplit.Pane order={4} initialSize="0.4fr" minSize="0.1fr" ref={thirdPaneRef}>
<PreviewPane />
</Resplit.Pane>
</Resplit.Root>
Expand Down
11 changes: 8 additions & 3 deletions src/examples/Context.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useState } from 'react';
import { useRef, useState } from 'react';
import { FrValue, Resplit, ResplitPaneProps, useResplitContext } from 'resplit';

export const SizeAwarePane = (props: ResplitPaneProps) => {
const { isPaneCollapsed, isPaneMinSize, setPaneSizes } = useResplitContext();
const [size, setSize] = useState('0.5fr');
const [isCollapsed, setIsCollapsed] = useState(false);
const [isMinSize, setIsMinSize] = useState(false);
const paneRef = useRef<HTMLDivElement | null>(null);

const handleResize = (newSize: FrValue) => {
setSize(newSize);
Expand All @@ -24,6 +25,7 @@ export const SizeAwarePane = (props: ResplitPaneProps) => {
initialSize="0.5fr"
minSize="0.3fr"
collapsedSize="0.2fr"
ref={paneRef}
collapsible
onResize={handleResize}
>
Expand All @@ -45,10 +47,13 @@ export const SizeAwarePane = (props: ResplitPaneProps) => {
};

export const ContextExample = () => {
const rootRef = useRef<HTMLDivElement | null>(null);
const splitterRef = useRef<HTMLDivElement | null>(null);

return (
<Resplit.Root className="h-full">
<Resplit.Root className="h-full" ref={rootRef}>
<SizeAwarePane order={0} />
<Resplit.Splitter order={1} size="10px" className="bg-neutral-600" />
<Resplit.Splitter order={1} size="10px" className="bg-neutral-600" ref={splitterRef} />
<SizeAwarePane order={2} />
</Resplit.Root>
);
Expand Down
14 changes: 10 additions & 4 deletions src/examples/ImageCompare.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useRef } from 'react';
import { Resplit } from 'resplit';

const PANE_CLASSES = 'relative w-full h-full';
Expand All @@ -20,19 +21,24 @@ const ChevronRight = () => (
);

export const ImageCompareExample = () => {
const rootRef = useRef<HTMLDivElement | null>(null);
const leftPaneRef = useRef<HTMLDivElement | null>(null);
const rightPaneRef = useRef<HTMLDivElement | null>(null);
const splitterRef = useRef<HTMLDivElement | null>(null);

return (
<div className="flex-1 flex flex-col items-center justify-center">
<Resplit.Root className="max-w-[720px] w-full aspect-[3/2]">
<Resplit.Pane order={0} initialSize="0.5fr" className={PANE_CLASSES}>
<Resplit.Root className="max-w-[720px] w-full aspect-[3/2]" ref={rootRef}>
<Resplit.Pane order={0} initialSize="0.5fr" className={PANE_CLASSES} ref={leftPaneRef}>
<img src={IMG_URL} alt="Sunflowers" className={[IMG_CLASSES, 'object-left'].join(' ')} />
</Resplit.Pane>
<Resplit.Splitter order={1} size="4px" className="relative w-full h-full bg-zinc-900">
<Resplit.Splitter order={1} size="4px" className="relative w-full h-full bg-zinc-900" ref={splitterRef}>
<div className="absolute z-10 top-1/2 left-1/2 transform -translate-y-1/2 -translate-x-1/2 flex items-center justify-center w-12 h-12 bg-zinc-900 rounded-full">
<ChevronLeft />
<ChevronRight />
</div>
</Resplit.Splitter>
<Resplit.Pane order={2} initialSize="0.5fr" className={PANE_CLASSES}>
<Resplit.Pane order={2} initialSize="0.5fr" className={PANE_CLASSES} ref={rightPaneRef}>
<img
src={IMG_URL}
alt="Sunflowers with grayscale filter applied"
Expand Down
Loading