{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "resizable-panels",
  "title": "Resizable Panels",
  "description": "Two panels and a divider that can be dragged or driven from the keyboard.",
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/default/resizable-panels/resizable-panels.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\n\nexport type ResizablePanelsProps = Omit<\n  React.HTMLAttributes<HTMLDivElement>,\n  \"children\" | \"onChange\"\n> & {\n  first: React.ReactNode\n  second: React.ReactNode\n  direction?: \"horizontal\" | \"vertical\"\n  /** Percentage of the box given to the first panel. */\n  size?: number\n  defaultSize?: number\n  onSizeChange?: (size: number) => void\n  min?: number\n  max?: number\n  /** Percentage points an arrow key moves. */\n  step?: number\n  label?: string\n}\n\n/**\n * Two panels and something to drag between them. The divider is a real\n * separator with a value, so the split can be changed from the keyboard by\n * anyone who cannot drag it.\n */\nexport function ResizablePanels({\n  first,\n  second,\n  direction = \"horizontal\",\n  size,\n  defaultSize = 50,\n  onSizeChange,\n  min = 15,\n  max = 85,\n  step = 4,\n  label = \"Resize panels\",\n  className,\n  ...rootProps\n}: ResizablePanelsProps) {\n  const ref = React.useRef<HTMLDivElement>(null)\n  const [uncontrolled, setUncontrolled] = React.useState(defaultSize)\n  const current = Math.min(max, Math.max(min, size ?? uncontrolled))\n  const horizontal = direction === \"horizontal\"\n\n  const commit = (next: number) => {\n    const clamped = Math.min(max, Math.max(min, next))\n    if (size === undefined) setUncontrolled(clamped)\n    onSizeChange?.(clamped)\n  }\n\n  const fromPointer = (event: React.PointerEvent) => {\n    const box = ref.current?.getBoundingClientRect()\n    if (!box) return\n\n    const ratio = horizontal\n      ? (event.clientX - box.left) / box.width\n      : (event.clientY - box.top) / box.height\n\n    commit(ratio * 100)\n  }\n\n  return (\n    <div\n      ref={ref}\n      data-slot=\"resizable-panels\"\n      data-direction={direction}\n      className={cn(\"flex\", horizontal ? \"flex-row\" : \"flex-col\", className)}\n      {...rootProps}\n    >\n      <div\n        data-slot=\"resizable-panels-first\"\n        className=\"min-h-0 min-w-0 overflow-auto\"\n        style={{ flexBasis: `${current}%` }}\n      >\n        {first}\n      </div>\n\n      <div\n        role=\"separator\"\n        tabIndex={0}\n        aria-label={label}\n        aria-orientation={horizontal ? \"vertical\" : \"horizontal\"}\n        aria-valuenow={Math.round(current)}\n        aria-valuemin={min}\n        aria-valuemax={max}\n        data-slot=\"resizable-panels-divider\"\n        className={cn(\n          \"bg-border hover:bg-ring focus-visible:bg-ring group relative shrink-0 touch-none transition-colors focus-visible:outline-none motion-reduce:transition-none\",\n          horizontal ? \"w-px cursor-col-resize\" : \"h-px cursor-row-resize\"\n        )}\n        onPointerDown={(event) => {\n          event.currentTarget.setPointerCapture(event.pointerId)\n        }}\n        onPointerMove={(event) => {\n          if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n            fromPointer(event)\n          }\n        }}\n        onKeyDown={(event) => {\n          const back = horizontal ? \"ArrowLeft\" : \"ArrowUp\"\n          const forward = horizontal ? \"ArrowRight\" : \"ArrowDown\"\n\n          if (event.key === back) {\n            event.preventDefault()\n            commit(current - step)\n          }\n\n          if (event.key === forward) {\n            event.preventDefault()\n            commit(current + step)\n          }\n\n          if (event.key === \"Home\") {\n            event.preventDefault()\n            commit(min)\n          }\n\n          if (event.key === \"End\") {\n            event.preventDefault()\n            commit(max)\n          }\n        }}\n      >\n        {/* A one pixel line is impossible to hit, so the grab area is wider\n            than the line it moves. */}\n        <span\n          aria-hidden=\"true\"\n          className={cn(\n            \"absolute\",\n            horizontal\n              ? \"inset-y-0 -right-2 -left-2\"\n              : \"inset-x-0 -top-2 -bottom-2\"\n          )}\n        />\n      </div>\n\n      <div\n        data-slot=\"resizable-panels-second\"\n        className=\"min-h-0 min-w-0 flex-1 overflow-auto\"\n      >\n        {second}\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "layout",
    "panel",
    "resize"
  ],
  "type": "registry:ui"
}