{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "resizable",
  "type": "registry:ui",
  "title": "Resizable",
  "description": "Accessible resizable panel groups and split layouts with keyboard support.",
  "dependencies": [
    "react-resizable-panels@^4.12.2"
  ],
  "registryDependencies": [
    "https://control-ui.dev/r/core.json"
  ],
  "files": [
    {
      "path": "src/registry/knob-contracts/resizable-knobs.ts",
      "target": "@components/control-ui/knob-contracts/resizable-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/resizable.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const resizableKnobs = [\n  \"--cui-resizable-group-background\",\n  \"--cui-resizable-group-radius\",\n  \"--cui-resizable-group-border-color\",\n  \"--cui-resizable-handle-color\",\n  \"--cui-resizable-handle-hover-background\",\n  \"--cui-resizable-handle-active-background\",\n  \"--cui-resizable-grip-radius\",\n  \"--cui-resizable-grip-background\",\n  \"--cui-resizable-grip-foreground\",\n] as const;\nexport type ResizableKnobStyle = Partial<Record<(typeof resizableKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/resizable.css",
      "target": "@components/control-ui/styles/recipes/resizable.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"resizable\"][data-slot=\"panel-group\"]) {\n    --cui-resizable-group-background: var(--card);\n    --cui-resizable-group-radius: var(--radius-panel);\n    --cui-resizable-group-border-color: var(--border);\n    --cui-resizable-handle-color: var(--foreground);\n    --cui-resizable-handle-hover-background: oklch(from var(--foreground) l c h / 0.25);\n    --cui-resizable-handle-active-background: oklch(from var(--foreground) l c h / 0.4);\n    --cui-resizable-grip-radius: var(--radius-control);\n    --cui-resizable-grip-background: var(--card);\n    --cui-resizable-grip-foreground: var(--muted-foreground);\n    background-color: var(--cui-resizable-group-background);\n    color: var(--card-foreground);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"panel-group\"][data-variant=\"framed\"]) {\n    border: 1px solid var(--cui-resizable-group-border-color);\n    border-radius: var(--cui-resizable-group-radius);\n    box-shadow: var(--shadow-sm);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"panel-group\"][data-variant=\"nested\"]) {\n    --cui-resizable-group-background: transparent;\n    --cui-resizable-group-radius: 0px;\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"]) {\n    --_resizable-gradient-color: var(--cui-resizable-handle-color);\n    transition-property: background-color, box-shadow, opacity;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n    outline-style: none;\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"solid\"]) {\n    background-color: var(--border);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"solid\"][data-separator=\"hover\"]),\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"solid\"][data-separator=\"focus\"]) {\n    background-color: var(--cui-resizable-handle-hover-background);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"solid\"][data-separator=\"active\"]) {\n    background-color: var(--cui-resizable-handle-active-background);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-separator=\"focus\"]) {\n    box-shadow: 0 0 0 2px oklch(from var(--foreground) l c h / 0.2);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-separator=\"disabled\"]) {\n    opacity: 0.5;\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"hover\"])::before {\n    position: absolute;\n    inset: 0;\n    content: \"\";\n    opacity: 0;\n    transition-property: opacity;\n    transition-duration: var(--duration-base);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"hover\"][data-axis=\"vertical\"])::before {\n    background-image: linear-gradient(to bottom, var(--_resizable-gradient-color), oklch(from var(--_resizable-gradient-color) l c h / 0));\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"hover\"][data-axis=\"horizontal\"])::before {\n    background-image: linear-gradient(to right, var(--_resizable-gradient-color), oklch(from var(--_resizable-gradient-color) l c h / 0));\n  }\n\n  :where(\n    [data-control-family=\"resizable\"][data-slot=\"handle\"][data-variant=\"hover\"]:is(\n      [data-separator=\"hover\"],\n      [data-separator=\"focus\"],\n      [data-separator=\"active\"]\n    )\n  )::before {\n    opacity: 1;\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle-grip\"]) {\n    border: 1px solid var(--border);\n    border-radius: var(--cui-resizable-grip-radius);\n    background-color: var(--cui-resizable-grip-background);\n    color: var(--cui-resizable-grip-foreground);\n    box-shadow: var(--shadow-sm);\n    opacity: 1;\n    transition-property: opacity;\n    transition-duration: var(--duration-fast);\n    transition-timing-function: var(--ease-standard);\n  }\n\n  :where([data-control-family=\"resizable\"][data-slot=\"handle-grip\"][data-variant=\"hover\"]) {\n    opacity: 0;\n  }\n\n  :where(\n    [data-control-family=\"resizable\"][data-slot=\"handle\"]:is([data-separator=\"hover\"], [data-separator=\"focus\"], [data-separator=\"active\"])\n      > [data-slot=\"handle-grip\"][data-variant=\"hover\"]\n  ) {\n    opacity: 1;\n  }\n}\n\n@property --cui-resizable-group-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-resizable-group-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-resizable-group-border-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-resizable-handle-color {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-resizable-handle-hover-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-resizable-handle-active-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-resizable-grip-radius {\n  syntax: \"<length-percentage>\";\n  inherits: true;\n  initial-value: 0px;\n}\n\n@property --cui-resizable-grip-background {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n\n@property --cui-resizable-grip-foreground {\n  syntax: \"<color>\";\n  inherits: true;\n  initial-value: transparent;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/ui/resizable.tsx",
      "target": "@components/control-ui/ui/resizable.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport type { ComponentProps, CSSProperties, Ref } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport { Group, Panel, Separator } from \"react-resizable-panels\";\nimport type { ResizableKnobStyle } from \"@/components/control-ui/knob-contracts/resizable-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\n\nexport type ResizableLayout = { [panelId: string]: number };\n\nexport type ResizablePanelGroupVariant = \"framed\" | \"nested\";\n\nexport type ResizableHandleVariant = \"solid\" | \"hover\";\n\nexport type ResizablePanelGroupProps = Omit<ComponentProps<\"div\">, \"style\"> & {\n  orientation?: \"horizontal\" | \"vertical\";\n  variant?: ResizablePanelGroupVariant;\n  defaultLayout?: ResizableLayout;\n  disableCursor?: boolean;\n  disabled?: boolean;\n  onLayoutChange?: (layout: ResizableLayout) => void;\n  onLayoutChanged?: (layout: ResizableLayout, meta: { isUserInteraction: boolean }) => void;\n  style?: CSSProperties & ResizableKnobStyle;\n};\n\nexport type ResizablePanelSize = { asPercentage: number; inPixels: number };\n\nexport interface ResizablePanelHandle {\n  collapse: () => void;\n  expand: () => void;\n  getSize: () => ResizablePanelSize;\n  isCollapsed: () => boolean;\n  resize: (size: number | string) => void;\n}\n\nexport type ResizablePanelProps = Omit<ComponentProps<\"div\">, \"onResize\"> & {\n  defaultSize?: number | string;\n  minSize?: number | string;\n  maxSize?: number | string;\n  collapsible?: boolean;\n  collapsedSize?: number | string;\n  groupResizeBehavior?: \"preserve-relative-size\" | \"preserve-pixel-size\";\n  disabled?: boolean;\n  panelRef?: Ref<ResizablePanelHandle>;\n  onResize?: (size: ResizablePanelSize, id: string | number | undefined, prevSize: ResizablePanelSize | undefined) => void;\n} & { style?: CSSProperties & ResizableKnobStyle };\n\nexport type ResizableHandleProps = Omit<ComponentProps<\"div\">, \"role\" | \"tabIndex\" | \"style\"> & {\n  variant?: ResizableHandleVariant;\n  withHandle?: boolean;\n  disabled?: boolean;\n  disableDoubleClick?: boolean;\n  style?: CSSProperties & ResizableKnobStyle;\n};\n\ntype Orientation = \"horizontal\" | \"vertical\";\nconst OrientationContext = createContext<Orientation>(\"horizontal\");\n\nexport function ResizablePanelGroup({\n  className,\n  orientation = \"horizontal\",\n  variant = \"framed\",\n  children,\n  ...props\n}: ResizablePanelGroupProps) {\n  return (\n    <OrientationContext.Provider value={orientation}>\n      <Group\n        data-control-ui=\"resizable\"\n        data-control-family=\"resizable\"\n        data-slot=\"panel-group\"\n        data-surface=\"panel\"\n        data-variant={variant}\n        orientation={orientation}\n        className={cn(\"flex h-full w-full\", className)}\n        {...props}\n      >\n        {children}\n      </Group>\n    </OrientationContext.Provider>\n  );\n}\n\nexport function ResizablePanel({ className, ...props }: ResizablePanelProps) {\n  return <Panel data-control-ui=\"resizable\" data-control-family=\"resizable\" data-slot=\"panel\" className={className} {...props} />;\n}\n\nexport function ResizableHandle({ className, variant = \"solid\", withHandle, children, ...props }: ResizableHandleProps) {\n  const orientation = useContext(OrientationContext);\n  const axis = orientation === \"horizontal\" ? \"vertical\" : \"horizontal\";\n  return (\n    <Separator\n      data-control-ui=\"resizable\"\n      data-control-family=\"resizable\"\n      data-slot=\"handle\"\n      data-variant={variant}\n      data-axis={axis}\n      className={cn(\"relative flex items-center justify-center\", axis === \"vertical\" ? \"w-px\" : \"h-px\", className)}\n      {...props}\n    >\n      {withHandle ? (\n        <span\n          data-control-ui=\"resizable\"\n          data-control-family=\"resizable\"\n          data-slot=\"handle-grip\"\n          data-variant={variant}\n          data-axis={axis}\n          className={cn(\n            \"absolute top-1/2 left-1/2 z-10 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center\",\n            axis === \"vertical\" ? \"h-5 w-3.5\" : \"h-3.5 w-5\",\n          )}\n        >\n          <GripIcon className={axis === \"horizontal\" ? \"rotate-90\" : undefined} />\n        </span>\n      ) : null}\n      {children}\n    </Separator>\n  );\n}\n\nfunction GripIcon({ className }: { className?: string }) {\n  return (\n    <svg viewBox=\"0 0 4 16\" width=\"4\" height=\"16\" fill=\"currentColor\" aria-hidden=\"true\" className={className}>\n      <circle cx=\"2\" cy=\"3\" r=\"1\" />\n      <circle cx=\"2\" cy=\"8\" r=\"1\" />\n      <circle cx=\"2\" cy=\"13\" r=\"1\" />\n    </svg>\n  );\n}\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/resizable.css\"": {}
  },
  "meta": {}
}
