npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aiquants/resize-panels

v1.5.1

Published

Reusable resizable panel components and utilities for React

Readme

@aiquants/resize-panels

React 向けのリサイズ可能なパネルレイアウトコンポーネント集です。~/components/elements/ResizablePanels で培ったロジックをパッケージ化し、任意のアプリケーションから再利用できるようにしました。

主な特徴

  • PanelGroupPanelPanelResizeHandle を中核に、リデューサーでレイアウトと DOM 計測を同期
  • calculateSnapThreshold とノイズ除去ロジックでリサイズ時の揺らぎを抑え、意図しない折りたたみを防止
  • 方向指定付き collapsible 設定と usePanelControls により、ドラッグ操作と UI 操作の両方で折りたたみ / 展開を制御
  • autoSaveId を指定するとローカルストレージにパネルサイズを自動保存し、再読み込み時に復元
  • showDebugInfo を使えば PanelDebugInfo とグローバルオーバーレイで計測結果や制約違反を可視化

インストール

ワークスペース内で利用する場合は pnpm を利用します。

pnpm add @aiquants/resize-panels

モノレポ内から参照する場合は package.json に次のように記載します。

{
    "dependencies": {
        "@aiquants/resize-panels": "workspace:*"
    }
}

クイックスタート

import { useId } from "react"
import { PanelGroup, Panel, PanelResizeHandle } from "@aiquants/resize-panels"

export const Example = () => {
    const baseId = useId()

    return (
        <PanelGroup id={`${baseId}-group`} direction="horizontal" className="h-96">
            <Panel id={`${baseId}-left`} defaultSize={{ value: 200, unit: "pixels" }} className="bg-slate-100">
                左パネル
            </Panel>
            <PanelResizeHandle id={`${baseId}-handle`} />
            <Panel id={`${baseId}-right`} defaultSize={{ value: 60, unit: "percentage" }} className="bg-slate-50">
                右パネル
            </Panel>
        </PanelGroup>
    )
}

折りたたみを有効にする

Panelcollapsible={{ from: "start" }}collapsible={{ from: "end" }} を指定すると、対応する PanelResizeHandle を端までドラッグしたタイミングで自動的に折りたたみ・展開が行われます。defaultCollapsed を併用すると初期状態を折りたたみ済みに設定できます。方向指定は必須で、各パネルがどちら側から折りたためるかを宣言します。両方向に対応したい場合は collapsible={{ from: "both" }} を使用します。

<PanelGroup direction="horizontal" className="h-96">
    <Panel id="sidebar" defaultSize={{ value: 240, unit: "pixels" }} collapsible={{ from: "end" }}>
        サイドバー
    </Panel>
    <PanelResizeHandle id="handle" />
    <Panel id="main" defaultSize={{ value: 60, unit: "percentage" }}>
        メインコンテンツ
    </Panel>
</PanelGroup>

UI から折りたたみ / 展開を切り替える

usePanelControls(panelId) フックを使うと、任意の UI から対象パネルを折りたたみ・展開・トグルできます。ボタンを配置するコンポーネントは PanelGroup の配下(コンテキスト内)に置いてください。折りたたみ後もボタンを表示したい場合は、別パネルやヘッダーなど常に可視な場所に設置します。API は方向を必須パラメーターとして受け取り、パネル構成に応じて呼び出し側で指定します。

import { PanelGroup, Panel, PanelResizeHandle, usePanelControls } from "@aiquants/resize-panels"

const PanelToggleButtons = ({ panelId, label }: { panelId: string; label: string }) => {
    const { panel, isCollapsed, collapse, expand, toggle, canCollapseFromStart, canCollapseFromEnd } = usePanelControls(panelId)
    const direction = panel?.collapsedByDirection ?? (canCollapseFromStart ? "start" : "end")

    return (
        <div className="flex items-center gap-2">
            <span>{label}</span>
            <button onClick={() => collapse(direction)} disabled={(!canCollapseFromStart && !canCollapseFromEnd) || isCollapsed}>
                折りたたむ
            </button>
            <button onClick={() => expand(direction)} disabled={!isCollapsed || (!canCollapseFromStart && !canCollapseFromEnd)}>
                展開する
            </button>
            <button onClick={() => toggle(direction)} disabled={!canCollapseFromStart && !canCollapseFromEnd}>
                {isCollapsed ? "展開に切り替え" : "折りたたみに切り替え"}
            </button>
        </div>
    )
}

export const Example = () => (
    <PanelGroup direction="horizontal" className="h-96">
        <Panel id="sidebar" defaultSize={{ value: 240, unit: "pixels" }} collapsible={{ from: "end" }}>
            <PanelToggleButtons panelId="sidebar" label="サイドバー" />
        </Panel>
        <PanelResizeHandle id="split" />
        <Panel id="main" defaultSize={{ value: 60, unit: "percentage" }}>
            <PanelToggleButtons panelId="details" label="詳細パネル" />
        </Panel>
        <PanelResizeHandle id="split-right" />
        <Panel id="details" defaultSize={{ value: 40, unit: "percentage" }} collapsible={{ from: "start" }}>
            詳細
        </Panel>
    </PanelGroup>
)

collapse(direction) は指定方向からパネルを非表示にし、expand(direction) はドラッグ操作と同じロジックで直前のサイズや推奨サイズを復元します。toggle(direction) を使うと現在の状態に応じて自動的に切り替わります。

コンポーネント API

PanelGroup の主なプロパティ

| プロパティ | 型 | 説明 | |-------------|----|------| | id | string | data-panel-group-id にも反映される識別子。複数グループを並べる場合は指定を推奨 | | direction | 'horizontal' \| 'vertical' | パネルの配置方向 | | className / style | string / React.CSSProperties | コンテナの見た目を調整するための追加スタイル | | children | React.ReactNode | グループ内の PanelPanelResizeHandle を並べるための子要素 | | showDebugInfo | boolean | PanelDebugInfo とグローバルオーバーレイを表示して計測結果と制約違反を可視化 | | onLayout | (sizes: number[]) => void | リサイズや初期化のたびに最新のピクセルサイズ配列を通知 | | autoSaveId | string | 指定すると localStorage にパネルサイズを保存・復元 |

Panel の主なプロパティ

| プロパティ | 型 | 説明 | |-------------|----|------| | id | string | パネル識別子。省略時はランダム生成だが、SSR との整合のため明示指定を推奨 | | defaultSize | { value: number; unit: 'pixels' \| 'percentage' } \| number | 初期サイズ。数値のみの場合はパーセンテージとして扱う | | minSize / maxSize | FlexibleSize | パネルの最小・最大サイズ制約。ピクセル・割合で指定可能 | | collapsible | { from: 'start' \| 'end' \| 'both' } | 折りたたみ方向の宣言。ドラッグや API 呼び出しで利用される必須設定 | | defaultCollapsed | boolean | 初期状態を折りたたみ済みにするかどうか | | pixelAdjustPriority | number | 余白調整時にピクセル基準パネルへ割り当てる優先度 | | className / style | string / React.CSSProperties | パネル本体の見た目をカスタマイズ |

PanelResizeHandle の主なプロパティ

| プロパティ | 型 | 説明 | |-------------|----|------| | id | string | ハンドル識別子。省略時はランダム生成 | | disabled | boolean | true にするとドラッグ操作を無効化 | | onDragging | (isDragging: boolean) => void | ドラッグ開始 / 終了ごとに呼び出されるコールバック | | className / style | string / React.CSSProperties | ハンドル見た目を追加カスタマイズ | | children | React.ReactNode | 独自のハンドルインジケーターを描画する場合に使用 |

フックとユーティリティ

  • useResizablePanels: PanelGroup 内部実装でも利用しているフック。カスタムコンテナを作る場合に役立ちます。
  • usePanelGroup: コンテキストを直接参照し、パネルリストやレイアウト情報を取得できます。
  • usePanelControls: 特定パネルに対する折りたたみ / 展開操作を提供します。
  • saveLayoutloadLayout: 任意のタイミングでレイアウトを永続化 / 復元できます。
  • getPanelElement, getPanelGroupElement, getResizeHandleElement: data-* 属性をもとに DOM 要素を取得します。

レイアウト保存と復元

PanelGroupautoSaveId を指定すると、ResizeObserver が安定した後のパネルサイズを 200ms デバウンス付きで localStorage に保存します。ページを再読み込みすると loadLayout(autoSaveId) の結果が自動的に反映され、ピクセル基準パネルと割合基準パネルの両方が復元されます。手動で制御したい場合は公開ユーティリティの saveLayout / loadLayout を直接呼び出してください。

デバッグと可視化

PanelGroupshowDebugInfo を有効にすると、各 PanelPanelDebugInfo が表示され、折りたたみ状態・計測サイズ・保持中の割合が即座に確認できます。同時にグローバルオーバーレイが開き、コンテナの実測サイズ、制約違反の有無、ハンドル厚み(PANEL_HANDLE_THICKNESS で定義された 8px)なども一覧できます。

スナップとノイズ対策の挙動

PanelResizeHandlePanel の両方で calculateSnapThreshold を利用し、コンテナサイズに応じたゼロスナップ閾値を共有しています。Panel コンポーネントでは ResizeObserver が一時的に極端な値を返した場合でも、noiseThreshold を用いたフィルタでチラつきを防ぎ、リデューサーが保持する状態と DOM 計測値の整合を保ちます。

スタイル

src/styles.css で Tailwind CSS レイヤーを読み込んでいます。グローバルに取り込み済みの環境では追加設定不要ですが、個別プロジェクトでユーティリティクラスを無効化したい場合はローカルの Tailwind 設定でオーバーライドしてください。

デモ

モノレポ内に簡易デモアプリを用意しています。

pnpm --filter '@aiquants/resize-panels-demo' dev

http://localhost:5175 にアクセスすると複数レイアウトを含むデモを確認できます。

ビルド

pnpm --filter '@aiquants/resize-panels' build

生成物は dist に出力されます。