Skip to content

Commit 1abb7a6

Browse files
committed
add Resizable
1 parent 1c42b41 commit 1abb7a6

6 files changed

Lines changed: 104 additions & 1 deletion

File tree

apps/playground/src/components/MainContent/MainContent.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { Resizable, Tabs } from '@douglasneuroinformatics/libui/components';
1+
import { Tabs } from '@douglasneuroinformatics/libui/components';
22
import { useMediaQuery } from '@douglasneuroinformatics/libui/hooks';
33

44
import { Editor } from '../Editor';
5+
import { Resizable } from '../Resizable';
56
import { Viewer } from '../Viewer';
67

78
export const MainContent = () => {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { Meta, StoryObj } from '@storybook/react-vite';
2+
3+
import { Resizable } from './Resizable';
4+
5+
type Story = StoryObj<typeof Resizable>;
6+
7+
export default { component: Resizable } as Meta<typeof Resizable>;
8+
9+
export const Default: Story = {
10+
args: {
11+
children: (
12+
<Resizable.PanelGroup className="max-w-md rounded-lg border" direction="horizontal">
13+
<Resizable.Panel defaultSize={50}>
14+
<div className="flex h-[200px] items-center justify-center p-6">
15+
<span className="font-semibold">One</span>
16+
</div>
17+
</Resizable.Panel>
18+
<Resizable.Handle />
19+
<Resizable.Panel defaultSize={50}>
20+
<Resizable.PanelGroup direction="vertical">
21+
<Resizable.Panel defaultSize={25}>
22+
<div className="flex h-full items-center justify-center p-6">
23+
<span className="font-semibold">Two</span>
24+
</div>
25+
</Resizable.Panel>
26+
<Resizable.Handle />
27+
<Resizable.Panel defaultSize={75}>
28+
<div className="flex h-full items-center justify-center p-6">
29+
<span className="font-semibold">Three</span>
30+
</div>
31+
</Resizable.Panel>
32+
</Resizable.PanelGroup>
33+
</Resizable.Panel>
34+
</Resizable.PanelGroup>
35+
)
36+
}
37+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as React from 'react';
2+
3+
import { Panel } from 'react-resizable-panels';
4+
import type { PanelProps } from 'react-resizable-panels';
5+
6+
import { ResizableHandle } from './ResizableHandle';
7+
import { ResizablePanelGroup } from './ResizablePanelGroup';
8+
9+
import type { ResizableHandleProps } from './ResizableHandle';
10+
import type { ResizablePanelGroupProps } from './ResizablePanelGroup';
11+
12+
type ResizableRootType = React.FC<{ children: React.ReactNode }>;
13+
type ResizableType = ResizableRootType & {
14+
Handle: React.FC<ResizableHandleProps>;
15+
Panel: React.FC<PanelProps>;
16+
PanelGroup: React.FC<ResizablePanelGroupProps>;
17+
};
18+
19+
// This is only for storybook and is unnecessary for real-world use
20+
const ResizableRoot: ResizableRootType = ({ children }) => <>{children}</>;
21+
22+
export const Resizable: ResizableType = Object.assign(ResizableRoot, {
23+
Handle: ResizableHandle,
24+
Panel,
25+
PanelGroup: ResizablePanelGroup
26+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as React from 'react';
2+
3+
import { cn } from '@douglasneuroinformatics/libui/utils';
4+
import { GripVertical } from 'lucide-react';
5+
import { PanelResizeHandle } from 'react-resizable-panels';
6+
7+
export type ResizableHandleProps = React.ComponentProps<typeof PanelResizeHandle> & {
8+
withHandle?: boolean;
9+
};
10+
11+
export const ResizableHandle = ({ className, withHandle, ...props }: ResizableHandleProps) => (
12+
<PanelResizeHandle
13+
className={cn(
14+
'bg-border focus-visible:ring-ring focus-visible:outline-hidden relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
15+
className
16+
)}
17+
{...props}
18+
>
19+
{withHandle && (
20+
<div className="bg-border rounded-xs z-10 flex h-4 w-3 items-center justify-center border">
21+
<GripVertical className="h-2.5 w-2.5" />
22+
</div>
23+
)}
24+
</PanelResizeHandle>
25+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as React from 'react';
2+
3+
import { cn } from '@douglasneuroinformatics/libui/utils';
4+
import { PanelGroup } from 'react-resizable-panels';
5+
6+
export type ResizablePanelGroupProps = React.ComponentProps<typeof PanelGroup>;
7+
8+
export const ResizablePanelGroup = ({ className, ...props }: ResizablePanelGroupProps) => (
9+
<PanelGroup
10+
className={cn('flex h-full w-full data-[panel-group-direction=vertical]:flex-col', className)}
11+
{...props}
12+
/>
13+
);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './Resizable';

0 commit comments

Comments
 (0)