Resizable

Layout

인접한 두 영역의 경계를 드래그해 크기를 조절하는 컨테이너.

Usage

목록과 상세, 편집기와 미리보기처럼 두 패널의 비율을 사용자가 조절할 때 사용한다.

import

import

import { Resizable } from '@mildang/design-system/Resizable';

Resizable 하나만 가져오면 Resizable.PanelGroup · Resizable.Panel · Resizable.Handle 를 그 아래에서 쓸 수 있다.

예제를 복사해 쓸 때 필요한 준비

@mildang/styled-system 은 이 저장소에서 Panda 가 생성하는 산출물이다. 저장소 안에서는 turbo run ship 이후 쓸 수 있고, 패키지 소비자는 자기 Panda 산출물이나 다른 레이아웃 수단으로 바꿔야 한다.

Anatomy

tsx

import { Resizable } from '@mildang/design-system/Resizable';

export default function Example() {
  return (
    <Resizable.PanelGroup>
      <Resizable.Panel />
      <Resizable.Handle />
    </Resizable.PanelGroup>
  );
}

부품

필수 여부

반복

위치

Resizable.PanelGroup

필수

Resizable.Panel

필수

여러 개 가능

Resizable.PanelGroup 안에 두 개 이상 배치한다.

Resizable.Handle

선택

여러 개 가능

Resizable.Panel 사이에 배치한다.

  • Resizable.PanelGroup 안에 두 개 이상의 Resizable.Panel을 배치한다.
  • 패널 사이에 Resizable.Handle을 배치하면 사용자가 경계를 드래그해 비율을 바꿀 수 있다.
  • 중첩 레이아웃은 Resizable.Panel 안에 다른 PanelGroup을 배치한다.

API Reference

Resizable.PanelGroup

패널과 리사이즈 핸들의 방향·크기 조정을 관리하는 그룹이다.

Prop

Type

Default

direction
필수

Direction & (import("@mildang/styled-system/types").ConditionalValue<"horizontal" | "vertical"> | undefined)

horizontal

className

string

지정 안 함

Resizable.Panel

사용자가 크기를 조절할 수 있는 콘텐츠 영역이다.

Prop

Type

Default

className

string

지정 안 함

Resizable.Handle

인접한 패널 사이의 크기를 드래그로 조절하는 경계다.

공개 Props 없음

패널 중첩

한 패널 안에 다른 방향의 PanelGroup을 넣어 목록·미리보기·상세처럼 세 영역을 조합한다.

중첩 패널

가로 패널 안에 세로 패널을 중첩해 목록·미리보기·상세를 조절하는 예시다.

import type { ResizablePanelGroupProps } from '@mildang/design-system/Resizable';

import { Resizable } from '@mildang/design-system/Resizable';
import { Text } from '@mildang/design-system/Text';
import { css } from '@mildang/styled-system/css';

const outerContentStyle = css({
  height: '400px',
  width: '500px',
  backgroundColor: 'neutral.surface.low',
  border: '1px solid',
  borderColor: 'neutral.border.low',
  borderRadius: '8',
  overflow: 'hidden',
});

const innerContentStyle = css({
  height: '100%',
  padding: '16px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
});

const STORY_DEFAULT_ARGS = { ...({}), ...({ direction: 'horizontal' }) } as ResizablePanelGroupProps;

const ResizableCombinedExampleRender = (args: ResizablePanelGroupProps) => (
    <div className={outerContentStyle}>
      <Resizable.PanelGroup {...args}>
        <Resizable.Panel defaultSize={50}>
          <div className={innerContentStyle}>
            <Text>One</Text>
          </div>
        </Resizable.Panel>
        <Resizable.Handle />
        <Resizable.Panel defaultSize={50}>
          <Resizable.PanelGroup direction="vertical">
            <Resizable.Panel defaultSize={25}>
              <div className={innerContentStyle}>
                <Text>Two</Text>
              </div>
            </Resizable.Panel>
            <Resizable.Handle />
            <Resizable.Panel defaultSize={75}>
              <div className={innerContentStyle}>
                <Text>Three</Text>
              </div>
            </Resizable.Panel>
          </Resizable.PanelGroup>
        </Resizable.Panel>
      </Resizable.PanelGroup>
    </div>
  );

export default function ResizableCombinedExample(props: Partial<ResizablePanelGroupProps>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ResizablePanelGroupProps;
  return ResizableCombinedExampleRender(mergedProps);
}

예제

Horizontal

import type { ResizablePanelGroupProps } from '@mildang/design-system/Resizable';

import { Resizable } from '@mildang/design-system/Resizable';
import { Text } from '@mildang/design-system/Text';
import { css } from '@mildang/styled-system/css';

const outerContentStyle = css({
  height: '400px',
  width: '500px',
  backgroundColor: 'neutral.surface.low',
  border: '1px solid',
  borderColor: 'neutral.border.low',
  borderRadius: '8',
  overflow: 'hidden',
});

const innerContentStyle = css({
  height: '100%',
  padding: '16px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
});

const STORY_DEFAULT_ARGS = { ...({}), ...({ direction: 'horizontal' }) } as ResizablePanelGroupProps;

const ResizableHorizontalExampleRender = (args: ResizablePanelGroupProps) => (
    <div className={outerContentStyle}>
      <Resizable.PanelGroup {...args}>
        <Resizable.Panel defaultSize={50} minSize={20} data-testid="panel-1">
          <div className={innerContentStyle}>
            <Text>Panel 1</Text>
          </div>
        </Resizable.Panel>
        <Resizable.Handle withHandle />
        <Resizable.Panel defaultSize={50} minSize={20} data-testid="panel-2">
          <div className={innerContentStyle}>
            <Text>Panel 2</Text>
          </div>
        </Resizable.Panel>
      </Resizable.PanelGroup>
    </div>
  );

export default function ResizableHorizontalExample(props: Partial<ResizablePanelGroupProps>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ResizablePanelGroupProps;
  return ResizableHorizontalExampleRender(mergedProps);
}

Vertical

import type { ResizablePanelGroupProps } from '@mildang/design-system/Resizable';

import { Resizable } from '@mildang/design-system/Resizable';
import { Text } from '@mildang/design-system/Text';
import { css } from '@mildang/styled-system/css';

const outerContentStyle = css({
  height: '400px',
  width: '500px',
  backgroundColor: 'neutral.surface.low',
  border: '1px solid',
  borderColor: 'neutral.border.low',
  borderRadius: '8',
  overflow: 'hidden',
});

const innerContentStyle = css({
  height: '100%',
  padding: '16px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
});

const STORY_DEFAULT_ARGS = { ...({}), ...({ direction: 'vertical' }) } as ResizablePanelGroupProps;

const ResizableVerticalExampleRender = (args: ResizablePanelGroupProps) => (
    <div className={outerContentStyle}>
      <Resizable.PanelGroup {...args}>
        <Resizable.Panel defaultSize={50} minSize={20} data-testid="panel-1">
          <div className={innerContentStyle}>
            <Text>Panel 1</Text>
          </div>
        </Resizable.Panel>
        <Resizable.Handle withHandle />
        <Resizable.Panel defaultSize={50} minSize={20} data-testid="panel-2">
          <div className={innerContentStyle}>
            <Text>Panel 2</Text>
          </div>
        </Resizable.Panel>
      </Resizable.PanelGroup>
    </div>
  );

export default function ResizableVerticalExample(props: Partial<ResizablePanelGroupProps>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ResizablePanelGroupProps;
  return ResizableVerticalExampleRender(mergedProps);
}

ThreePanels

import type { ResizablePanelGroupProps } from '@mildang/design-system/Resizable';

import { Resizable } from '@mildang/design-system/Resizable';
import { Text } from '@mildang/design-system/Text';
import { css } from '@mildang/styled-system/css';

const outerContentStyle = css({
  height: '400px',
  width: '500px',
  backgroundColor: 'neutral.surface.low',
  border: '1px solid',
  borderColor: 'neutral.border.low',
  borderRadius: '8',
  overflow: 'hidden',
});

const innerContentStyle = css({
  height: '100%',
  padding: '16px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
});

const STORY_DEFAULT_ARGS = { ...({}), ...({ direction: 'horizontal' }) } as ResizablePanelGroupProps;

const ResizableThreePanelsExampleRender = (args: ResizablePanelGroupProps) => (
    <div className={outerContentStyle}>
      <Resizable.PanelGroup {...args}>
        <Resizable.Panel defaultSize={25} minSize={15}>
          <div className={innerContentStyle}>
            <Text>Sidebar</Text>
          </div>
        </Resizable.Panel>
        <Resizable.Handle withHandle />
        <Resizable.Panel defaultSize={50} minSize={30}>
          <div className={innerContentStyle}>
            <Text>Main Content</Text>
          </div>
        </Resizable.Panel>
        <Resizable.Handle withHandle />
        <Resizable.Panel defaultSize={25} minSize={15}>
          <div className={innerContentStyle}>
            <Text>Details</Text>
          </div>
        </Resizable.Panel>
      </Resizable.PanelGroup>
    </div>
  );

export default function ResizableThreePanelsExample(props: Partial<ResizablePanelGroupProps>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ResizablePanelGroupProps;
  return ResizableThreePanelsExampleRender(mergedProps);
}

WithoutHandle

import type { ResizablePanelGroupProps } from '@mildang/design-system/Resizable';

import { Resizable } from '@mildang/design-system/Resizable';
import { Text } from '@mildang/design-system/Text';
import { css } from '@mildang/styled-system/css';

const outerContentStyle = css({
  height: '400px',
  width: '500px',
  backgroundColor: 'neutral.surface.low',
  border: '1px solid',
  borderColor: 'neutral.border.low',
  borderRadius: '8',
  overflow: 'hidden',
});

const innerContentStyle = css({
  height: '100%',
  padding: '16px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
});

const STORY_DEFAULT_ARGS = { ...({}), ...({ direction: 'horizontal' }) } as ResizablePanelGroupProps;

const ResizableWithoutHandleExampleRender = (args: ResizablePanelGroupProps) => (
    <div className={outerContentStyle}>
      <Resizable.PanelGroup {...args}>
        <Resizable.Panel defaultSize={50} minSize={20}>
          <div className={innerContentStyle}>
            <Text>Panel 1</Text>
          </div>
        </Resizable.Panel>
        <Resizable.Handle />
        <Resizable.Panel defaultSize={50} minSize={20}>
          <div className={innerContentStyle}>
            <Text>Panel 2</Text>
          </div>
        </Resizable.Panel>
      </Resizable.PanelGroup>
    </div>
  );

export default function ResizableWithoutHandleExample(props: Partial<ResizablePanelGroupProps>) {
  const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ResizablePanelGroupProps;
  return ResizableWithoutHandleExampleRender(mergedProps);
}