{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "floating-toolbar",
  "type": "registry:component",
  "title": "Floating Toolbar",
  "description": "Compact action bar that floats above a selection — primary / ghost / destructive variants.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/floating-toolbar/floating-toolbar.tsx",
      "content": "\"use client\";\n\nimport {\n  type ComponentPropsWithoutRef,\n  forwardRef,\n  type ReactNode,\n} from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\n\n/**\n * One toolbar action.\n *\n * @public\n */\nexport type FloatingToolbarAction = {\n  /** Optional aria-label override (defaults to the visible label). */\n  ariaLabel?: string;\n  /** When `true`, renders dimmed and ignores clicks. */\n  disabled?: boolean;\n  /** Optional leading glyph. */\n  glyph?: ReactNode;\n  /** Stable identifier. */\n  id: string;\n  /** Visible label. */\n  label: ReactNode;\n  /** Click handler. */\n  onActivate: () => void;\n  /** Optional emphasis level. Defaults to `\"ghost\"`. */\n  variant?: \"destructive\" | \"ghost\" | \"primary\";\n};\n\nconst VARIANT_CLASSES: Record<\n  NonNullable<FloatingToolbarAction[\"variant\"]>,\n  string\n> = {\n  destructive:\n    \"border-red-300 bg-red-500/10 text-red-700 hover:bg-red-500/20 dark:text-red-300\",\n  ghost: \"border-border bg-background text-foreground hover:bg-accent\",\n  primary:\n    \"border-primary bg-primary text-primary-foreground hover:bg-primary/90\",\n};\n\n/**\n * Localizable strings.\n *\n * @public\n */\nexport type FloatingToolbarLabels = {\n  /** Aria-label for the toolbar. Defaults to `\"Selection actions\"`. */\n  region?: string;\n};\n\nconst DEFAULT_LABELS = {\n  region: \"Selection actions\",\n} as const satisfies Required<FloatingToolbarLabels>;\n\n/**\n * Props for {@link FloatingToolbar}.\n *\n * @public\n */\nexport type FloatingToolbarProps = {\n  /** Toolbar actions in render order. */\n  actions: FloatingToolbarAction[];\n  /** Localizable strings. */\n  labels?: FloatingToolbarLabels;\n  /** X coordinate in container px (left edge of the toolbar). */\n  x: number;\n  /** Y coordinate in container px (bottom edge of the toolbar — the bar floats above this point). */\n  y: number;\n} & Omit<ComponentPropsWithoutRef<\"div\">, \"style\">;\n\n/**\n * Compact action bar that floats above a selection. Pair with\n * {@link SelectionHalo} — surface the toolbar at the halo's top edge so\n * the user sees the available actions for the current selection.\n *\n * @example\n * ```tsx\n * <FloatingToolbar\n *   x={120}\n *   y={80}\n *   actions={[\n *     { id: \"rename\", label: \"Rename\", onActivate: rename, variant: \"primary\" },\n *     { id: \"duplicate\", label: \"Duplicate\", onActivate: duplicate },\n *     { id: \"delete\", label: \"Delete\", onActivate: remove, variant: \"destructive\" },\n *   ]}\n * />\n * ```\n *\n * @public\n */\nexport const FloatingToolbar = forwardRef<HTMLDivElement, FloatingToolbarProps>(\n  (props, ref) => {\n    const { actions, className, labels, x, y, ...rest } = props;\n    const resolvedLabels = { ...DEFAULT_LABELS, ...labels };\n    return (\n      <div\n        aria-label={resolvedLabels.region}\n        className={cn(\n          \"absolute z-30 flex -translate-y-full items-center gap-1 rounded-md border border-border bg-background/95 p-1 shadow-md backdrop-blur\",\n          className,\n        )}\n        data-floating-toolbar\n        ref={ref}\n        role=\"toolbar\"\n        style={{ left: `${x.toString()}px`, top: `${y.toString()}px` }}\n        {...rest}\n      >\n        {actions.map((action) => {\n          const variant = action.variant ?? \"ghost\";\n          const handleClick = (): void => {\n            action.onActivate();\n          };\n          return (\n            <button\n              aria-label={action.ariaLabel ?? undefined}\n              className={cn(\n                \"inline-flex h-7 items-center gap-1 rounded-md border px-2 text-xs font-medium transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n                VARIANT_CLASSES[variant],\n                action.disabled ? \"cursor-not-allowed opacity-50\" : \"\",\n              )}\n              data-action-id={action.id}\n              data-variant={variant}\n              disabled={action.disabled}\n              key={action.id}\n              onClick={handleClick}\n              type=\"button\"\n            >\n              {action.glyph ? (\n                <span aria-hidden=\"true\" className=\"inline-flex size-3\">\n                  {action.glyph}\n                </span>\n              ) : null}\n              <span>{action.label}</span>\n            </button>\n          );\n        })}\n      </div>\n    );\n  },\n);\nFloatingToolbar.displayName = \"FloatingToolbar\";\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
