{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "speed-dial",
  "title": "Speed Dial",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-react/components/speed-dial/SpeedDial.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport type { LucideIcon } from 'lucide-react'\nimport { Plus } from 'lucide-react'\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'\nimport { Fab } from '@/components/ui/fab'\nimport { cn } from '@/lib/utils'\n\nexport interface SpeedDialAction {\n  icon: LucideIcon\n  label: string\n  handler?: () => void\n  disabled?: boolean\n  className?: string\n}\n\ntype Direction = 'up' | 'down' | 'left' | 'right'\ntype Trigger = 'click' | 'hover'\n\nexport interface SpeedDialProps {\n  actions: SpeedDialAction[]\n  /** Main FAB icon. */\n  icon?: LucideIcon\n  /** Accessible label for the main FAB. */\n  label?: string\n  direction?: Direction\n  trigger?: Trigger\n  /** Close the dial after an action is triggered. */\n  closeOnAction?: boolean\n  variant?: 'default' | 'secondary' | 'destructive' | 'outline'\n  position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' | 'bottom-center' | 'inline'\n  absolute?: boolean\n  disabled?: boolean\n  className?: string\n}\n\nconst sideMap: Record<Direction, 'top' | 'bottom' | 'left' | 'right'> = {\n  up: 'top',\n  down: 'bottom',\n  left: 'left',\n  right: 'right',\n}\n\nconst SpeedDial = React.forwardRef<HTMLButtonElement, SpeedDialProps>(\n  (\n    {\n      actions,\n      icon: Icon,\n      label,\n      direction = 'up',\n      trigger = 'click',\n      closeOnAction = true,\n      variant = 'default',\n      position = 'bottom-right',\n      absolute = false,\n      disabled = false,\n      className,\n    },\n    ref,\n  ) => {\n    const [open, setOpen] = React.useState(false)\n    const hoverTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null)\n\n    const clearHoverTimer = React.useCallback(() => {\n      if (hoverTimerRef.current) {\n        clearTimeout(hoverTimerRef.current)\n        hoverTimerRef.current = null\n      }\n    }, [])\n\n    const onTriggerEnter = React.useCallback(() => {\n      if (trigger !== 'hover') return\n      clearHoverTimer()\n      setOpen(true)\n    }, [trigger, clearHoverTimer])\n\n    const onTriggerLeave = React.useCallback(() => {\n      if (trigger !== 'hover') return\n      clearHoverTimer()\n      hoverTimerRef.current = setTimeout(() => setOpen(false), 150)\n    }, [trigger, clearHoverTimer])\n\n    const onContentEnter = React.useCallback(() => {\n      if (trigger !== 'hover') return\n      clearHoverTimer()\n    }, [trigger, clearHoverTimer])\n\n    const onContentLeave = React.useCallback(() => {\n      if (trigger !== 'hover') return\n      clearHoverTimer()\n      hoverTimerRef.current = setTimeout(() => setOpen(false), 150)\n    }, [trigger, clearHoverTimer])\n\n    React.useEffect(() => clearHoverTimer, [clearHoverTimer])\n\n    function runAction(action: SpeedDialAction) {\n      if (action.disabled) return\n      action.handler?.()\n      if (closeOnAction) setOpen(false)\n    }\n\n    const side = sideMap[direction]\n    const listClass =\n      direction === 'up' || direction === 'down'\n        ? 'flex flex-col items-center gap-3'\n        : 'flex flex-row items-center gap-3'\n\n    return (\n      <Popover open={open} onOpenChange={setOpen}>\n        <PopoverTrigger asChild>\n          <div\n            data-uipkge=\"\"\n            data-slot=\"speed-dial\"\n            className={cn(className)}\n            onMouseEnter={onTriggerEnter}\n            onMouseLeave={onTriggerLeave}\n          >\n            <Fab\n              ref={ref}\n              variant={variant}\n              position={position}\n              absolute={absolute}\n              disabled={disabled}\n              aria-label={label || 'Quick actions'}\n              className={cn('transition-transform duration-200', open && 'rotate-45')}\n              onClick={trigger === 'hover' ? (e) => e.stopPropagation() : undefined}\n            >\n              {Icon ? <Icon /> : <Plus />}\n            </Fab>\n          </div>\n        </PopoverTrigger>\n\n        <PopoverContent\n          side={side}\n          align=\"center\"\n          sideOffset={12}\n          className={cn('w-auto border-0 bg-transparent p-0 shadow-none', trigger === 'hover' && 'pointer-events-auto')}\n          onMouseEnter={onContentEnter}\n          onMouseLeave={onContentLeave}\n        >\n          <div className={listClass}>\n            {actions.map((action, i) => {\n              const ActionIcon = action.icon\n              return (\n                <button\n                  key={i}\n                  type=\"button\"\n                  data-slot=\"speed-dial-action\"\n                  disabled={action.disabled}\n                  aria-label={action.label}\n                  style={{ animationDelay: `${i * 40}ms` }}\n                  className={cn(\n                    \"group/speed-dial-item bg-background text-foreground hover:bg-accent hover:text-accent-foreground motion-safe:animate-in motion-safe:fade-in-0 motion-safe:zoom-in-95 focus-visible:ring-ring/50 inline-flex size-12 items-center justify-center rounded-full border shadow-md transition-colors outline-none focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5\",\n                    action.className,\n                  )}\n                  onClick={() => runAction(action)}\n                >\n                  <ActionIcon />\n                  <span className=\"sr-only\">{action.label}</span>\n                </button>\n              )\n            })}\n          </div>\n        </PopoverContent>\n      </Popover>\n    )\n  },\n)\nSpeedDial.displayName = 'SpeedDial'\n\nexport { SpeedDial }\n",
      "type": "registry:ui",
      "target": "~/components/ui/speed-dial/SpeedDial.tsx"
    },
    {
      "path": "packages/registry-react/components/speed-dial/index.ts",
      "content": "export { SpeedDial, type SpeedDialAction, type SpeedDialProps } from './SpeedDial'\n",
      "type": "registry:ui",
      "target": "~/components/ui/speed-dial/index.ts"
    }
  ],
  "dependencies": [
    "lucide-react",
    "@radix-ui/react-popover"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/fab.json",
    "https://uipkge.dev/r/react/popover.json"
  ],
  "description": "Expanding floating action button that reveals a list of secondary action buttons. Supports click or hover triggers, four expansion directions (up/down/left/right), staggered entrance animation, a configurable main FAB icon, and close-on-action. Built on the fab and popover primitives.",
  "categories": [
    "control",
    "navigation"
  ]
}