{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "resizable-inset",
  "title": "Inset resizable",
  "description": "Styled resizable: the Inset set. 5 decorative resizable variations (SoftResizable, DeepResizable, GrooveResizable, FrameResizable, FloatResizable) on the ai2 token system, driven by CSS token transitions and sized sm to xl. Part of the free styled layer.",
  "dependencies": [],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/resizable-inset.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Inset resizable family: 5 self-contained split panels (NO panel library, NO\n   radix). The theme idea: the panes have an inner shadow (inset shadow) and a pill\n   handle floats over the seam. Each export holds an internal percentage (pct) state;\n   the pill handle is dragged with the pointer and adjusted with the arrow keys.\n   Deterministic (no Date.now / Math.random). The handle uses role=\"separator\" +\n   aria-orientation + aria-valuenow/min/max, tabIndex=0. Color comes ONLY from\n   semantic tokens; alpha via color-mix or the Tailwind /NN. There is no motion in\n   this family (only color transitions). */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\ntype Orientation = \"horizontal\" | \"vertical\"\n\nconst height: Record<StyledSize, string> = {\n  sm: \"h-40\",\n  md: \"h-56\",\n  lg: \"h-72\",\n  xl: \"h-96\",\n}\n\nconst MIN = 12\nconst MAX = 88\nconst clamp = (n: number) => Math.min(MAX, Math.max(MIN, n))\n\nconst focusRing =\n  \"outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n\n/* Ortak bolme mantigi: pct state + pointer/klavye tutamac handler'lari.\n   horizontal = sol/sag panel, dikey ayirici (yatay suruklenir).\n   vertical   = ust/alt panel, yatay ayirici (dikey suruklenir). */\nfunction useResizable(orientation: Orientation, initial = 50) {\n  const [pct, setPct] = React.useState(initial)\n  const containerRef = React.useRef<HTMLDivElement>(null)\n  const [dragging, setDragging] = React.useState(false)\n\n  const applyFromPoint = React.useCallback(\n    (clientX: number, clientY: number) => {\n      const el = containerRef.current\n      if (!el) return\n      const rect = el.getBoundingClientRect()\n      const raw =\n        orientation === \"horizontal\"\n          ? ((clientX - rect.left) / rect.width) * 100\n          : ((clientY - rect.top) / rect.height) * 100\n      setPct(clamp(raw))\n    },\n    [orientation]\n  )\n\n  const onPointerDown = React.useCallback(\n    (e: React.PointerEvent<HTMLDivElement>) => {\n      e.preventDefault()\n      e.currentTarget.setPointerCapture(e.pointerId)\n      setDragging(true)\n    },\n    []\n  )\n\n  const onPointerMove = React.useCallback(\n    (e: React.PointerEvent<HTMLDivElement>) => {\n      if (!e.currentTarget.hasPointerCapture(e.pointerId)) return\n      applyFromPoint(e.clientX, e.clientY)\n    },\n    [applyFromPoint]\n  )\n\n  const onPointerUp = React.useCallback(\n    (e: React.PointerEvent<HTMLDivElement>) => {\n      if (e.currentTarget.hasPointerCapture(e.pointerId))\n        e.currentTarget.releasePointerCapture(e.pointerId)\n      setDragging(false)\n    },\n    []\n  )\n\n  const onKeyDown = React.useCallback(\n    (e: React.KeyboardEvent<HTMLDivElement>) => {\n      const dec = orientation === \"horizontal\" ? \"ArrowLeft\" : \"ArrowUp\"\n      const inc = orientation === \"horizontal\" ? \"ArrowRight\" : \"ArrowDown\"\n      if (e.key === dec) {\n        e.preventDefault()\n        setPct((p) => clamp(p - (e.shiftKey ? 10 : 2)))\n      } else if (e.key === inc) {\n        e.preventDefault()\n        setPct((p) => clamp(p + (e.shiftKey ? 10 : 2)))\n      } else if (e.key === \"Home\") {\n        e.preventDefault()\n        setPct(MIN)\n      } else if (e.key === \"End\") {\n        e.preventDefault()\n        setPct(MAX)\n      }\n    },\n    [orientation]\n  )\n\n  const separatorProps = {\n    role: \"separator\" as const,\n    \"aria-orientation\": (orientation === \"horizontal\" ? \"vertical\" : \"horizontal\") as\n      | \"vertical\"\n      | \"horizontal\",\n    \"aria-valuenow\": Math.round(pct),\n    \"aria-valuemin\": MIN,\n    \"aria-valuemax\": MAX,\n    tabIndex: 0,\n    onPointerDown,\n    onPointerMove,\n    onPointerUp,\n    onKeyDown,\n  }\n\n  return { pct, containerRef, dragging, separatorProps }\n}\n\ninterface ResizableProps {\n  className?: string\n  size?: StyledSize\n  start?: React.ReactNode\n  end?: React.ReactNode\n}\n\n/* Ic golgeli bolme: token yuzey + inset shadow (varyanta gore) + ortalanmis etiket. */\nfunction InsetPane({\n  label,\n  tone = \"bg-surface-2\",\n  insetClass,\n  children,\n}: {\n  label?: string\n  tone?: string\n  insetClass: string\n  children?: React.ReactNode\n}) {\n  return (\n    <div\n      className={cn(\n        \"flex h-full w-full items-center justify-center overflow-hidden p-4 text-sm font-medium text-foreground\",\n        tone,\n        insetClass\n      )}\n    >\n      {children ?? <span className=\"text-muted-foreground\">{label}</span>}\n    </div>\n  )\n}\n\nconst shell =\n  \"flex w-full select-none overflow-hidden rounded-xl border border-border\"\n\n/* Shared inset divider: two panels with inner shadows plus a pill handle floating over them. insetClass carries the inner shadow depth of the panels, pillClass the pill shape and seamClass the colour of the thin seam underneath. The pill handle is grabbed through separatorProps. */\nfunction InsetSplit({\n  className,\n  size = \"md\",\n  start,\n  end,\n  insetClass,\n  pillClass,\n  seamClass = \"bg-border\",\n}: ResizableProps & { insetClass: string; pillClass: string; seamClass?: string }) {\n  const { pct, containerRef, dragging, separatorProps } = useResizable(\"horizontal\")\n  return (\n    <div data-slot=\"styled-resizable\" ref={containerRef} className={cn(shell, height[size], className)}>\n      <div style={{ width: `${pct}%` }} className=\"h-full\">\n        {start ?? <InsetPane label=\"Panel bir\" tone=\"bg-surface-2\" insetClass={insetClass} />}\n      </div>\n      <div className={cn(\"relative h-full w-px shrink-0\", seamClass)}>\n        <div\n          {...separatorProps}\n          className={cn(\n            \"absolute left-1/2 top-1/2 z-10 flex -translate-x-1/2 -translate-y-1/2 cursor-col-resize items-center justify-center border bg-background transition-colors\",\n            focusRing,\n            \"after:absolute after:inset-y-0 after:-inset-x-2 after:content-['']\",\n            pillClass,\n            dragging ? \"border-primary\" : \"border-border hover:border-primary/60\"\n          )}\n        >\n          <span\n            aria-hidden=\"true\"\n            className={cn(\n              \"h-4 w-0.5 rounded-full transition-colors\",\n              dragging ? \"bg-primary\" : \"bg-muted-foreground\"\n            )}\n          />\n        </div>\n      </div>\n      <div style={{ width: `${100 - pct}%` }} className=\"h-full\">\n        {end ?? <InsetPane label=\"Panel iki\" tone=\"bg-surface-3\" insetClass={insetClass} />}\n      </div>\n    </div>\n  )\n}\n\n/* SoftResizable: hafif ic golge + yuvarlak yuzen hap. */\nexport function SoftResizable(props: ResizableProps) {\n  return (\n    <InsetSplit\n      {...props}\n      insetClass=\"shadow-[inset_0_1px_6px_color-mix(in_oklab,var(--color-foreground)_8%,transparent)]\"\n      pillClass=\"h-10 w-5 rounded-full shadow-sm\"\n    />\n  )\n}\n\n/* DeepResizable: belirgin, derin ic golge + yuvarlak yuzen hap. */\nexport function DeepResizable(props: ResizableProps) {\n  return (\n    <InsetSplit\n      {...props}\n      insetClass=\"shadow-[inset_0_2px_12px_color-mix(in_oklab,var(--color-foreground)_20%,transparent)]\"\n      pillClass=\"h-10 w-5 rounded-full shadow-md\"\n    />\n  )\n}\n\n/* GrooveResizable: her iki panelde de oyuk hissi veren ic golge + koyu dikis + ince hap. */\nexport function GrooveResizable(props: ResizableProps) {\n  return (\n    <InsetSplit\n      {...props}\n      insetClass=\"shadow-[inset_0_0_10px_color-mix(in_oklab,var(--color-foreground)_14%,transparent)]\"\n      seamClass=\"bg-[color-mix(in_oklab,var(--color-foreground)_18%,transparent)]\"\n      pillClass=\"h-8 w-4 rounded-full shadow-sm\"\n    />\n  )\n}\n\n/* FrameResizable: ic golge + ic cerceve halkasi + kare koseli hap. */\nexport function FrameResizable(props: ResizableProps) {\n  return (\n    <InsetSplit\n      {...props}\n      insetClass=\"shadow-[inset_0_1px_6px_color-mix(in_oklab,var(--color-foreground)_10%,transparent)] ring-1 ring-inset ring-border/60\"\n      pillClass=\"h-9 w-6 rounded-md shadow-sm\"\n    />\n  )\n}\n\n/* FloatResizable: hafif ic golge + belirgin bicimde yukselen, gucluce yuzen hap. */\nexport function FloatResizable(props: ResizableProps) {\n  return (\n    <InsetSplit\n      {...props}\n      insetClass=\"shadow-[inset_0_1px_4px_color-mix(in_oklab,var(--color-foreground)_8%,transparent)]\"\n      seamClass=\"bg-transparent\"\n      pillClass=\"h-12 w-6 rounded-full shadow-lg\"\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/resizable-inset.tsx"
    }
  ],
  "categories": [
    "styled",
    "resizable"
  ],
  "type": "registry:component"
}