{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "fab",
  "title": "FAB",
  "description": "The floating action button in three sizes, plus the extended FAB, which requires a readable label.",
  "registryDependencies": [
    "https://guillermo-rebolledo.github.io/materialcn/r/button.json",
    "https://guillermo-rebolledo.github.io/materialcn/r/materialcn-theme.json",
    "https://guillermo-rebolledo.github.io/materialcn/r/utils.json"
  ],
  "files": [
    {
      "path": "src/components/ui/fab.tsx",
      "content": "import type { ComponentProps, ReactNode } from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"./button\"\n\n/**\n * Material 3 Expressive floating action button.\n *\n * Geometry comes from the kit's `FAB` / `Extended FAB` sets on the Buttons\n * page (the 40dp \"small\" FAB only survives on the deprecated internal canvas):\n *\n * | Size    | Box | Icon | Corner | Extended padding / gap / type   |\n * | ------- | --- | ---- | ------ | ------------------------------- |\n * | default | 56  | 24   | 16     | 16 / 8  / title-medium          |\n * | medium  | 80  | 28   | 20     | 26 / 12 / title-large (regular) |\n * | large   | 96  | 36   | 28     | 28 / 16 / headline-small        |\n *\n * Every color sits at elevation level 3 and rises to level 4 on hover. Unlike\n * the buttons, the kit's FAB keeps its corner radius while pressed, so the\n * active radius is written identically to cancel the inherited morph.\n */\ntype FABSize = \"default\" | \"medium\" | \"large\"\ntype FABColor =\n  | \"primary\"\n  | \"secondary\"\n  | \"tertiary\"\n  | \"primary-container\"\n  | \"secondary-container\"\n  | \"tertiary-container\"\ntype FABShape = \"round\" | \"square\"\n\ntype AccessibleName =\n  | { \"aria-label\": string; \"aria-labelledby\"?: string }\n  | { \"aria-label\"?: never; \"aria-labelledby\": string }\n\ntype FABProps = Omit<\n  ComponentProps<typeof Button>,\n  \"aria-label\" | \"aria-labelledby\" | \"shape\" | \"size\" | \"variant\"\n> &\n  AccessibleName & {\n    color?: FABColor\n    shape?: FABShape\n    size?: FABSize\n  }\n\nconst baseStyles = [\n  // `size=\"icon\"` carries no padding classes, so nothing from the Button size\n  // scale (notably `has-[>svg]:pl-*`) can survive tailwind-merge and push the\n  // icon off-centre. `p-0` is belt-and-braces for consumer overrides.\n  \"p-0 shadow-m3-3 hover:not-disabled:shadow-m3-4\",\n  \"disabled:bg-m3-on-surface/12 disabled:shadow-m3-0\",\n  \"motion-reduce:transition-none\",\n]\n\nconst sizeStyles: Record<FABSize, string> = {\n  default: \"size-14 [&_svg:not([class*='size-'])]:size-6\",\n  medium: \"size-20 [&_svg:not([class*='size-'])]:size-7\",\n  large: \"size-24 [&_svg:not([class*='size-'])]:size-9\",\n}\n\nconst shapeStyles: Record<FABShape, Record<FABSize, string>> = {\n  round: {\n    default: \"rounded-[28px] active:not-disabled:rounded-[28px]\",\n    medium: \"rounded-[40px] active:not-disabled:rounded-[40px]\",\n    large: \"rounded-[48px] active:not-disabled:rounded-[48px]\",\n  },\n  square: {\n    default: \"rounded-m3-lg active:not-disabled:rounded-m3-lg\",\n    medium: \"rounded-m3-lg-increased active:not-disabled:rounded-m3-lg-increased\",\n    large: \"rounded-m3-xl active:not-disabled:rounded-m3-xl\",\n  },\n}\n\nconst colorStyles: Record<FABColor, string> = {\n  primary: \"bg-m3-primary text-m3-on-primary\",\n  secondary: \"bg-m3-secondary text-m3-on-secondary\",\n  tertiary: \"bg-m3-tertiary text-m3-on-tertiary\",\n  \"primary-container\": \"bg-m3-primary-container text-m3-on-primary-container\",\n  \"secondary-container\": \"bg-m3-secondary-container text-m3-on-secondary-container\",\n  \"tertiary-container\": \"bg-m3-tertiary-container text-m3-on-tertiary-container\",\n}\n\nfunction FAB({\n  className,\n  color = \"primary-container\",\n  shape = \"square\",\n  size = \"default\",\n  ...props\n}: FABProps) {\n  return (\n    <Button\n      {...props}\n      size=\"icon\"\n      data-slot=\"fab\"\n      data-color={color}\n      data-fab-size={size}\n      className={cn(\n        baseStyles,\n        colorStyles[color],\n        sizeStyles[size],\n        shapeStyles[shape][size],\n        className,\n      )}\n    />\n  )\n}\n\ntype ExtendedFABProps = Omit<\n  ComponentProps<typeof Button>,\n  \"shape\" | \"size\" | \"variant\"\n> & {\n  color?: FABColor\n  label: string\n  shape?: FABShape\n  size?: FABSize\n  children?: ReactNode\n}\n\nconst extendedSizeStyles: Record<FABSize, string> = {\n  default: \"h-14 gap-2 px-4 has-[>svg]:pl-4 text-m3-title-md [&_svg:not([class*='size-'])]:size-6\",\n  medium:\n    \"h-20 gap-3 px-[26px] has-[>svg]:pl-[26px] text-m3-title-lg font-m3-regular [&_svg:not([class*='size-'])]:size-7\",\n  large:\n    \"h-24 gap-4 px-7 has-[>svg]:pl-7 text-m3-headline-sm font-m3-regular [&_svg:not([class*='size-'])]:size-9\",\n}\n\nfunction ExtendedFAB({\n  children,\n  className,\n  color = \"primary-container\",\n  label,\n  shape = \"square\",\n  size = \"default\",\n  ...props\n}: ExtendedFABProps) {\n  return (\n    <Button\n      {...props}\n      size=\"lg\"\n      data-slot=\"extended-fab\"\n      data-color={color}\n      data-fab-size={size}\n      className={cn(\n        \"shadow-m3-3 hover:not-disabled:shadow-m3-4 disabled:bg-m3-on-surface/12 disabled:shadow-m3-0 motion-reduce:transition-none\",\n        colorStyles[color],\n        extendedSizeStyles[size],\n        shapeStyles[shape][size],\n        className,\n      )}\n    >\n      {children}\n      <span>{label}</span>\n    </Button>\n  )\n}\n\nexport {\n  ExtendedFAB,\n  FAB,\n  type ExtendedFABProps,\n  type FABColor,\n  type FABProps,\n  type FABShape,\n  type FABSize,\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "actions"
  ],
  "type": "registry:ui"
}