{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "fab",
  "title": "Floating Action Button",
  "description": "The main-action button in plain, small, large and extended forms; the extended form collapses to its icon on scroll and keeps its name for screen readers.",
  "files": [
    {
      "path": "registry/tealmac/fab.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface FabProps extends Omit<\n  React.ComponentProps<\"button\">,\n  \"children\"\n> {\n  /** The icon. */\n  icon: React.ReactNode\n  /** The text. A plain FAB hides it visually but keeps it as the name. */\n  label: string\n  /** Show the label next to the icon (the extended FAB). */\n  extended?: boolean\n  /** Shrink an extended FAB to its icon, for example while scrolling down. */\n  collapsed?: boolean\n  size?: \"sm\" | \"md\" | \"lg\"\n  tone?: \"primary\" | \"secondary\" | \"surface\"\n  /** `fixed` pins it to the bottom end corner, above the home indicator. */\n  position?: \"fixed\" | \"static\"\n}\n\nconst SIZE = {\n  sm: \"h-10 min-w-10 text-sm [&_svg]:size-5\",\n  md: \"h-14 min-w-14 text-base [&_svg]:size-6\",\n  lg: \"h-24 min-w-24 text-lg [&_svg]:size-9\",\n}\nconst TONE = {\n  primary: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n  secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n  surface: \"bg-card text-foreground hover:bg-accent border\",\n}\n\n/**\n * The floating action button for the one main action of a screen. The extended\n * form shows the label; with `collapsed` it animates down to the icon and the\n * label stays as the accessible name.\n */\nexport const Fab = React.forwardRef<HTMLButtonElement, FabProps>(function Fab(\n  {\n    icon,\n    label,\n    extended = false,\n    collapsed = false,\n    size = \"md\",\n    tone = \"primary\",\n    position = \"static\",\n    className,\n    type = \"button\",\n    ...props\n  },\n  ref\n) {\n  const showLabel = extended && !collapsed\n  return (\n    <button\n      ref={ref}\n      type={type}\n      data-slot=\"fab\"\n      data-extended={extended || undefined}\n      data-collapsed={collapsed || undefined}\n      aria-label={showLabel ? undefined : label}\n      className={cn(\n        \"focus-visible:ring-ring inline-flex items-center justify-center rounded-2xl shadow-lg transition-[padding,background-color,box-shadow] duration-200 outline-none hover:shadow-xl focus-visible:ring-2 focus-visible:ring-offset-2 active:scale-95 motion-reduce:transition-none motion-reduce:active:scale-100\",\n        SIZE[size],\n        TONE[tone],\n        showLabel ? \"gap-2 px-5\" : \"p-0\",\n        size === \"lg\" && \"rounded-3xl\",\n        position === \"fixed\" &&\n          \"fixed end-4 bottom-[max(1rem,env(safe-area-inset-bottom))] z-40\",\n        className\n      )}\n      {...props}\n    >\n      {icon}\n      {showLabel && <span className=\"font-medium\">{label}</span>}\n    </button>\n  )\n})\n\n/**\n * Collapse an extended FAB while the content scrolls down and bring it back on\n * the way up. Pass the scrolling element, or nothing for the window.\n */\nexport function useCollapseOnScroll(\n  scrollRef?: React.RefObject<HTMLElement | null>,\n  threshold = 16\n) {\n  const [collapsed, setCollapsed] = React.useState(false)\n  React.useEffect(() => {\n    const target: HTMLElement | Window = scrollRef?.current ?? window\n    let last =\n      target === window ? window.scrollY : (target as HTMLElement).scrollTop\n    const onScroll = () => {\n      const y =\n        target === window ? window.scrollY : (target as HTMLElement).scrollTop\n      if (Math.abs(y - last) < threshold) return\n      setCollapsed(y > last && y > 0)\n      last = y\n    }\n    target.addEventListener(\"scroll\", onScroll, { passive: true })\n    return () => target.removeEventListener(\"scroll\", onScroll)\n  }, [scrollRef, threshold])\n  return collapsed\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}