import { Badge, Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@godxjp/ui/data-display"; import { Button, Text } from "@godxjp/ui/general"; import { Flex, PageContainer, ResizableHandle, ResizablePanel, ResizablePanelGroup, } from "@godxjp/ui/layout"; import { GripHorizontal, GripVertical, PanelLeftClose, PanelLeftOpen } from "lucide-react"; import * as React from "react"; import type { Layout, PanelImperativeHandle } from "react-resizable-panels"; /** * ResizablePanel · react-resizable-panels v4 compound primitive exported as * ResizablePanelGroup / ResizablePanel / ResizableHandle. Always compose: * ResizablePanelGroup wraps panels+handles; ResizableHandle sits between panels; * ResizablePanel holds content. Group orientation is set with orientation * ("horizontal" | "vertical"). minSize/maxSize prevent zero-collapse; collapsible * + collapsedSize enable collapse-to-zero; defaultLayout + onLayoutChanged persist * sizes. Composed only from real @godxjp/ui components. */ export default function Demo() { return ( ); } const frameStyle: React.CSSProperties = { border: "1px solid var(--color-border)", borderRadius: "var(--radius-md)", overflow: "hidden", }; /** orientation="horizontal" (default) · list + detail master/detail layout. */ function HorizontalCard() { return ( 水平分割 · リスト + 詳細 orientation="horizontal"(既定)。ResizableHandle をパネル間に配置。minSize でゼロ崩壊を防ぐ。ハンドルをダブルクリックすると defaultSize に戻る。
{/* No inner overflow: the panel is already the scroll container, and letting it own the scrolling is what earns the keyboard tab stop ResizablePanel now manages. */} 請求書リスト {[ { id: "INV-2024-001", label: "株式会社アルファ", status: "succeeded" }, { id: "INV-2024-002", label: "合同会社ベータ", status: "pending" }, { id: "INV-2024-003", label: "有限会社ガンマ", status: "scheduled" }, ].map((item) => ( {item.id} {item.label} ))} 詳細 INV-2024-001 株式会社アルファ 金額: ¥1,320,000(税込) 支払期日: 2024-02-28
); } /** orientation="vertical" · top/bottom split with a grip handle. */ function VerticalCard() { return ( 垂直分割 · エディタ + プレビュー orientation="vertical" で上下分割。コードエディタ + 出力プレビューやフォーム + 確認画面などの用途。ResizableHandle に children を渡すとグリップアイコンで掴みやすくなる。
仕訳エディタ 売掛金 / 売上高 借方 ¥880,000 仮受消費税 / 売上高 貸方 ¥880,000 プレビュー 仕訳内容のプレビューがここに表示されます。貸借が一致していることを確認してください。
); } /** * collapsible + collapsedSize · the sidebar collapses to zero and an imperative * panelRef toggle expands/collapses it. Seeded collapsed at rest so the * collapsed state is visible in a static screenshot. */ function CollapsibleCard() { const panelRef = React.useRef(null); const [collapsed, setCollapsed] = React.useState(true); const toggle = () => { const panel = panelRef.current; if (!panel) return; if (panel.isCollapsed()) { panel.expand(); setCollapsed(false); } else { panel.collapse(); setCollapsed(true); } }; return ( 折りたたみ · collapsible サイドバー collapsible + collapsedSize={0} でサイドバーをゼロまで折りたためる。panelRef の collapse()/expand() でトグル。minSize 未満までドラッグしても自動で折りたたまれる。 {collapsed ? "折りたたみ中" : "展開中"}
setCollapsed(size.asPercentage === 0)} > ナビゲーション {["売上", "仕入", "経費", "固定資産"].map((item) => ( {item} ))} メインコンテンツ サイドバーが折りたたまれると本文が全幅に広がる。
); } /** * defaultLayout + onLayoutChanged + a stable id · sizes persist across reloads. * In v4 a bare id does NOT persist; you must seed defaultLayout and capture * onLayoutChanged. Here the saved layout is held in state and echoed on screen. */ function PersistenceCard() { // Layout is a map of panel id -> flexGrow value (relative, not %). const [layout, setLayout] = React.useState({ "persisted-nav": 30, "persisted-content": 70, }); const total = Object.values(layout).reduce((sum, n) => sum + n, 0) || 1; const ratio = [layout["persisted-nav"], layout["persisted-content"]] .map((n) => `${Math.round(((n ?? 0) / total) * 100)}%`) .join(" / "); return ( 永続化 · defaultLayout + onLayoutChanged v4 では id 単体ではサイズは保存されない。defaultLayout で初期サイズを与え、onLayoutChanged を localStorage 等に保存して復元する。現在の比率: {ratio}。
勘定科目 この比率は保存されます。 仕訳一覧 ハンドルを動かすと上の比率表示が即時に更新される。
); } /** * disabled · read-only layout. Group disabled freezes all panels; an individual * Separator can be disabled, and disableDoubleClick suppresses double-click reset. */ function DisabledCard() { return ( 無効化 · disabled / disableDoubleClick ResizablePanelGroup に disabled を渡すとレイアウトを固定(読み取り専用)にできる。Separator 単位の disabled、ダブルクリックでのリセットを抑止する disableDoubleClick もある。下の例はハンドルがグレーアウトし操作できない。
確定済みレイアウト 承認後は配置を変更できません。 プレビュー 読み取り専用ビュー。
); } /** Three panes · multiple handles compose 3+ panes (IDE-style layout). */ function ThreePaneCard() { return ( 3ペイン · サイドバー + メイン + インスペクタ ResizableHandle を複数配置することで3ペイン以上に分割できる。IDE スタイルのコードエディタやダッシュボードビルダーに適している。
ナビゲーション {["売上", "仕入", "経費", "固定資産"].map((item) => ( {item} ))} メインコンテンツ 勘定科目ツリーや仕訳一覧 インスペクタ 選択項目の詳細・メタデータ
); }