{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "resizable",
  "title": "Resizable",
  "description": "A resizable component.",
  "dependencies": [
    "class-variance-authority",
    "react-resizable-panels"
  ],
  "files": [
    {
      "path": "registry/default/resizable/resizable.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport * as ResizablePrimitive from \"react-resizable-panels\";\n\nimport { cn } from \"@/lib/utils\";\n\n// Quiet period after the group last resized before layout changes ease again.\nconst SETTLE_DELAY = 150;\n\nfunction assignRef<T>(ref: React.Ref<T> | undefined, value: T): void {\n  if (typeof ref === \"function\") ref(value);\n  else if (ref) ref.current = value;\n}\n\nconst OrientationContext =\n  React.createContext<ResizablePrimitive.Orientation>(\"horizontal\");\n\nexport type ResizablePanelGroupProps = ResizablePrimitive.GroupProps;\n\nfunction ResizablePanelGroup({\n  className,\n  elementRef,\n  orientation = \"horizontal\",\n  style,\n  ...props\n}: ResizablePanelGroupProps) {\n  const localRef = React.useRef<HTMLDivElement | null>(null);\n  const ref = React.useCallback(\n    (node: HTMLDivElement | null) => {\n      localRef.current = node;\n      assignRef(elementRef, node);\n    },\n    [elementRef],\n  );\n\n  // Requested layout changes (collapse, reset, keyboard, setLayout) ease;\n  // forced ones (mount, window resize) must not, or panels trail behind.\n  // `data-settled` marks a group that has held its size, and is set on the\n  // DOM directly so React never reconciles it away.\n  React.useEffect(() => {\n    const node = localRef.current;\n    if (!node) return;\n\n    let timeout: number | undefined;\n    const observer = new ResizeObserver(() => {\n      delete node.dataset.settled;\n      window.clearTimeout(timeout);\n      timeout = window.setTimeout(() => {\n        node.dataset.settled = \"\";\n      }, SETTLE_DELAY);\n    });\n    observer.observe(node);\n\n    return () => {\n      window.clearTimeout(timeout);\n      observer.disconnect();\n    };\n  }, []);\n\n  return (\n    <OrientationContext.Provider value={orientation}>\n      <ResizablePrimitive.Group\n        data-slot=\"resizable-panel-group\"\n        data-orientation={orientation}\n        orientation={orientation}\n        elementRef={ref}\n        // The library's inline 100% height/width beats any class; clearing it\n        // lets `size-full` and a caller's `h-*` apply.\n        style={{ height: undefined, width: undefined, ...style }}\n        className={cn(\n          \"size-full\",\n          // Never during a drag, which must track the pointer 1:1. Written as\n          // a root :has() with a direct-child target: Tailwind's not-has +\n          // star variants restyle the whole page on any DOM change (TODO.md).\n          \"motion-safe:[&[data-settled]:not(:has(>[data-separator=active]))>[data-panel]]:[transition:flex-grow_var(--resizable-duration,320ms)_var(--ease-out-expo)]\",\n          className,\n        )}\n        {...props}\n      />\n    </OrientationContext.Provider>\n  );\n}\n\nexport type ResizablePanelProps = ResizablePrimitive.PanelProps;\n\n// `className` and `style` land on the inner scroll container. Its inline\n// `overflow: auto` is overridden to clip on the resize axis instead of growing\n// a scrollbar, while still scrolling on the other.\nfunction ResizablePanel({ style, ...props }: ResizablePanelProps) {\n  const orientation = React.useContext(OrientationContext);\n\n  return (\n    <ResizablePrimitive.Panel\n      data-slot=\"resizable-panel\"\n      style={{\n        overflow: orientation === \"horizontal\" ? \"hidden auto\" : \"auto hidden\",\n        ...style,\n      }}\n      {...props}\n    />\n  );\n}\n\n// States come from the library's `data-separator`, so hit-testing uses its\n// wide hit area rather than the painted 1px. `aria-orientation` is the line's\n// own axis: a horizontal group draws vertical lines.\nconst resizableHandleVariants = cva(\n  [\n    \"group/handle relative flex shrink-0 items-center justify-center outline-none\",\n    \"aria-[orientation=vertical]:w-px aria-[orientation=horizontal]:h-px\",\n  ],\n  {\n    variants: {\n      variant: {\n        line: \"bg-border\",\n        grip: \"bg-border\",\n        // Gutter between card-like panels; resize it with a `w-*` / `h-*` class.\n        gap: \"aria-[orientation=vertical]:w-2 aria-[orientation=horizontal]:h-2\",\n      },\n    },\n    defaultVariants: {\n      variant: \"line\",\n    },\n  },\n);\n\n// Shows after a short delay on hover, so sweeping past doesn't flicker, and at\n// once on press. `--reach` drives the scale so no state depends on class order.\n// A clicked handle keeps focus for arrow keys and reports `focus`, not `hover`,\n// so the bar stays up for it too.\nconst resizableIndicatorVariants = cva(\n  [\n    \"pointer-events-none absolute opacity-0\",\n    \"transition-[opacity,scale,background-color] duration-150 ease-out motion-reduce:transition-none\",\n    \"group-data-[separator=hover]/handle:opacity-100 group-data-[separator=hover]/handle:delay-100 group-data-[separator=hover]/handle:[--reach:1]\",\n    \"group-data-[separator=focus]/handle:opacity-100 group-data-[separator=focus]/handle:[--reach:1]\",\n    \"group-data-[separator=active]/handle:bg-primary group-data-[separator=active]/handle:opacity-100 group-data-[separator=active]/handle:[--reach:1]\",\n    \"group-focus-visible/handle:bg-primary group-focus-visible/handle:opacity-100 group-focus-visible/handle:[--reach:1]\",\n    \"group-data-[separator=disabled]/handle:hidden\",\n  ],\n  {\n    variants: {\n      variant: {\n        // Full-length bar growing out of the hairline.\n        line: [\n          \"bg-foreground/25 [--reach:0.34]\",\n          \"group-aria-[orientation=vertical]/handle:inset-y-0 group-aria-[orientation=vertical]/handle:w-[3px] group-aria-[orientation=vertical]/handle:scale-x-(--reach)\",\n          \"group-aria-[orientation=horizontal]/handle:inset-x-0 group-aria-[orientation=horizontal]/handle:h-[3px] group-aria-[orientation=horizontal]/handle:scale-y-(--reach)\",\n        ],\n        // A short pill floating in the gutter.\n        gap: [\n          \"bg-foreground/20 rounded-full [--reach:0.75] scale-(--reach)\",\n          \"group-aria-[orientation=vertical]/handle:h-8 group-aria-[orientation=vertical]/handle:w-1\",\n          \"group-aria-[orientation=horizontal]/handle:h-1 group-aria-[orientation=horizontal]/handle:w-8\",\n        ],\n      },\n    },\n  },\n);\n\n// A real border, not the surface rim, which vanishes against a dark page.\nconst resizableGripClassName = cn(\n  \"pointer-events-none relative shrink-0 rounded-full border\",\n  \"bg-surface-3 border-foreground/15 shadow-(--surface-shadow-3)\",\n  \"transition-[background-color,border-color] duration-150 ease-out motion-reduce:transition-none\",\n  \"group-aria-[orientation=vertical]/handle:h-6 group-aria-[orientation=vertical]/handle:w-2\",\n  \"group-aria-[orientation=horizontal]/handle:h-2 group-aria-[orientation=horizontal]/handle:w-6\",\n  \"group-data-[separator=active]/handle:bg-primary group-data-[separator=active]/handle:border-primary\",\n  \"group-focus-visible/handle:bg-primary group-focus-visible/handle:border-primary\",\n  \"group-data-[separator=disabled]/handle:opacity-60\",\n);\n\ntype ResizableHandleVariant = NonNullable<\n  VariantProps<typeof resizableHandleVariants>[\"variant\"]\n>;\n\nfunction ResizableHandleContent({\n  variant,\n  children,\n}: {\n  variant: ResizableHandleVariant;\n  children?: React.ReactNode;\n}) {\n  return (\n    <>\n      <span\n        data-slot=\"resizable-handle-indicator\"\n        aria-hidden\n        className={resizableIndicatorVariants({\n          variant: variant === \"gap\" ? \"gap\" : \"line\",\n        })}\n      />\n      {variant === \"grip\" && (\n        <span\n          data-slot=\"resizable-handle-grip\"\n          aria-hidden\n          className={resizableGripClassName}\n        />\n      )}\n      {children}\n    </>\n  );\n}\n\nexport type ResizableHandleProps = ResizablePrimitive.SeparatorProps &\n  VariantProps<typeof resizableHandleVariants>;\n\nfunction ResizableHandle({\n  variant,\n  className,\n  children,\n  ...props\n}: ResizableHandleProps) {\n  const resolvedVariant = variant ?? \"line\";\n\n  return (\n    <ResizablePrimitive.Separator\n      data-slot=\"resizable-handle\"\n      data-variant={resolvedVariant}\n      className={cn(\n        resizableHandleVariants({ variant: resolvedVariant }),\n        className,\n      )}\n      {...props}\n    >\n      <ResizableHandleContent variant={resolvedVariant}>\n        {children}\n      </ResizableHandleContent>\n    </ResizablePrimitive.Separator>\n  );\n}\n\nexport type ResizableGridProps = ResizablePrimitive.GridProps;\n\nfunction ResizableGrid({ className, style, ...props }: ResizableGridProps) {\n  return (\n    <ResizablePrimitive.Grid\n      data-slot=\"resizable-grid\"\n      // Same inline sizing as the group; see ResizablePanelGroup.\n      style={{ height: undefined, width: undefined, ...style }}\n      className={cn(\"size-full\", className)}\n      {...props}\n    />\n  );\n}\n\nexport type ResizableCellProps = ResizablePrimitive.CellProps;\n\n// Cells resize on both axes, so they clip on both. Inline, like the library's\n// `overflow: auto` it replaces.\nfunction ResizableCell({ style, ...props }: ResizableCellProps) {\n  return (\n    <ResizablePrimitive.Cell\n      data-slot=\"resizable-cell\"\n      style={{ overflow: \"hidden\", ...style }}\n      {...props}\n    />\n  );\n}\n\nexport type ResizableGridlineProps = ResizablePrimitive.GridlineProps &\n  VariantProps<typeof resizableHandleVariants>;\n\nfunction ResizableGridline({\n  variant,\n  className,\n  children,\n  elementRef,\n  ...props\n}: ResizableGridlineProps) {\n  const resolvedVariant = variant ?? \"line\";\n\n  // Gridline drops unknown props, so the data attributes go on via the ref.\n  const ref = React.useCallback(\n    (node: HTMLDivElement | null) => {\n      if (node) {\n        node.dataset.slot = \"resizable-gridline\";\n        node.dataset.variant = resolvedVariant;\n      }\n      assignRef(elementRef, node);\n    },\n    [elementRef, resolvedVariant],\n  );\n\n  return (\n    <ResizablePrimitive.Gridline\n      {...(props as ResizablePrimitive.GridlineProps)}\n      elementRef={ref}\n      className={cn(\n        resizableHandleVariants({ variant: resolvedVariant }),\n        // Gridlines are stretched by the grid, not the flex row.\n        \"aria-[orientation=horizontal]:w-auto aria-[orientation=vertical]:h-auto\",\n        className,\n      )}\n    >\n      <ResizableHandleContent variant={resolvedVariant}>\n        {children}\n      </ResizableHandleContent>\n    </ResizablePrimitive.Gridline>\n  );\n}\n\nexport {\n  ResizableCell,\n  ResizableGrid,\n  ResizableGridline,\n  ResizableHandle,\n  ResizablePanel,\n  ResizablePanelGroup,\n  resizableHandleVariants,\n};\n\nexport {\n  useDefaultGridLayout,\n  useDefaultLayout,\n  useGridRef,\n  useGroupRef,\n  usePanelRef,\n} from \"react-resizable-panels\";\n\nexport type {\n  GridImperativeHandle,\n  GridLayout,\n  GroupImperativeHandle,\n  Layout,\n  PanelImperativeHandle,\n  PanelSize,\n} from \"react-resizable-panels\";\n",
      "type": "registry:ui",
      "target": "components/ui/cubby-ui/resizable.tsx"
    }
  ],
  "type": "registry:ui"
}