{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "action-bar",
  "type": "registry:component",
  "title": "ActionBar",
  "description": "Reusable hover actions for message and response controls.",
  "dependencies": [],
  "registryDependencies": [
    "https://control-ui.dev/r/button.json",
    "https://control-ui.dev/r/core.json",
    "https://control-ui.dev/r/use-copy-to-clipboard.json"
  ],
  "files": [
    {
      "path": "src/registry/knob-contracts/action-bar-knobs.ts",
      "target": "@components/control-ui/knob-contracts/action-bar-knobs.ts",
      "type": "registry:component",
      "content": "// Generated from src/registry/sources/control-ui/recipes/action-bar.css by scripts/gen-knob-contracts.ts — run `bun run sync:knobs`.\nexport const actionBarKnobs = [] as const;\nexport type ActionBarKnobStyle = Partial<Record<(typeof actionBarKnobs)[number], string>>;\n"
    },
    {
      "path": "src/registry/sources/control-ui/action-bar.tsx",
      "target": "@components/control-ui/action-bar.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\nimport type { ComponentProps, CSSProperties, MouseEvent, ReactNode } from \"react\";\nimport { createContext, useContext } from \"react\";\nimport { useCopyToClipboard } from \"@/components/control-ui/hooks/use-copy-to-clipboard\";\nimport type { ActionBarKnobStyle } from \"@/components/control-ui/knob-contracts/action-bar-knobs\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport { Button } from \"@/components/control-ui/ui/button\";\n\nexport type ActionBarCopyValue = string | (() => string | Promise<string>);\n\nexport type ActionBarContextValue = {\n  copyValue?: ActionBarCopyValue;\n  editValue?: ActionBarCopyValue;\n  onCopy?: (value: string) => void;\n  onCopyError?: (error: unknown) => void;\n  onEdit?: (value: string) => void;\n  onEditError?: (error: unknown) => void;\n};\n\nexport type ActionBarProps = Omit<ComponentProps<\"div\">, \"style\"> & {\n  label?: string;\n  align?: \"start\" | \"end\";\n  context?: ActionBarContextValue;\n  copyValue?: ActionBarCopyValue;\n  editValue?: ActionBarCopyValue;\n  onCopy?: (value: string) => void;\n  onCopyError?: (error: unknown) => void;\n  onEdit?: (value: string) => void;\n  onEditError?: (error: unknown) => void;\n  style?: CSSProperties & ActionBarKnobStyle;\n};\n\nconst ActionBarContext = createContext<ActionBarContextValue>({});\n\nasync function resolveCopyValue(value?: ActionBarCopyValue) {\n  return typeof value === \"function\" ? await value() : value;\n}\n\nexport function ActionBar({\n  label = \"Message actions\",\n  align = \"start\",\n  className,\n  children,\n  context,\n  copyValue,\n  editValue,\n  onCopy,\n  onCopyError,\n  onEdit,\n  onEditError,\n  ...props\n}: ActionBarProps) {\n  const actionContext = {\n    ...context,\n    copyValue: copyValue ?? context?.copyValue,\n    editValue: editValue ?? context?.editValue,\n    onCopy: onCopy ?? context?.onCopy,\n    onCopyError: onCopyError ?? context?.onCopyError,\n    onEdit: onEdit ?? context?.onEdit,\n    onEditError: onEditError ?? context?.onEditError,\n  };\n\n  return (\n    <ActionBarContext.Provider value={actionContext}>\n      <div\n        data-control-ui=\"action-bar\"\n        data-control-family=\"action-bar\"\n        data-slot=\"root\"\n        role=\"toolbar\"\n        aria-label={label}\n        className={cn(\"mt-1 flex min-h-8 items-center gap-1\", align === \"end\" ? \"justify-end\" : \"justify-start\", className)}\n        {...props}\n      >\n        {children}\n      </div>\n    </ActionBarContext.Provider>\n  );\n}\n\nexport type ActionBarItemProps = ComponentProps<typeof Button> & {\n  icon?: ReactNode;\n};\n\nexport function ActionBarItem({ icon, children, className, ...props }: ActionBarItemProps) {\n  return (\n    <Button size=\"xs\" className={className} {...props}>\n      {icon}\n      {children}\n    </Button>\n  );\n}\n\nexport type ActionBarCopyProps = Omit<ActionBarItemProps, \"children\"> & {\n  value?: ActionBarCopyValue;\n  children?: ReactNode;\n  copiedChildren?: ReactNode;\n  resetDelay?: number;\n};\n\nexport function ActionBarCopy({\n  value,\n  children = \"Copy\",\n  copiedChildren = \"Copied\",\n  resetDelay = 1200,\n  disabled,\n  onClick,\n  ...props\n}: ActionBarCopyProps) {\n  const { copyValue: contextCopyValue, onCopy, onCopyError } = useContext(ActionBarContext);\n  const copyValue = value ?? contextCopyValue;\n  const { isCopied, copyToClipboard } = useCopyToClipboard({\n    copiedDuration: resetDelay,\n    onCopy,\n    onCopyError,\n  });\n\n  async function handleClick(event: MouseEvent<HTMLButtonElement>) {\n    onClick?.(event);\n    if (event.defaultPrevented) return;\n\n    const nextValue = await resolveCopyValue(copyValue);\n    if (!nextValue) return;\n\n    await copyToClipboard(nextValue);\n  }\n\n  return (\n    <ActionBarItem aria-live=\"polite\" disabled={disabled ?? !copyValue} onClick={handleClick} {...props}>\n      {isCopied ? copiedChildren : children}\n    </ActionBarItem>\n  );\n}\n\nexport type ActionBarEditProps = Omit<ActionBarItemProps, \"children\"> & {\n  value?: ActionBarCopyValue;\n  children?: ReactNode;\n};\n\nexport function ActionBarEdit({ value, children = \"Edit\", disabled, onClick, ...props }: ActionBarEditProps) {\n  const { copyValue, editValue: contextEditValue, onEdit, onEditError } = useContext(ActionBarContext);\n  const editValue = value ?? contextEditValue ?? copyValue;\n\n  async function handleClick(event: MouseEvent<HTMLButtonElement>) {\n    onClick?.(event);\n    if (event.defaultPrevented || !onEdit) return;\n\n    try {\n      const nextValue = await resolveCopyValue(editValue);\n      if (!nextValue) return;\n      onEdit(nextValue);\n    } catch (error) {\n      onEditError?.(error);\n    }\n  }\n\n  return (\n    <ActionBarItem disabled={disabled ?? (!editValue || !onEdit)} onClick={handleClick} {...props}>\n      {children}\n    </ActionBarItem>\n  );\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/recipes/action-bar.css",
      "target": "@components/control-ui/styles/recipes/action-bar.css",
      "type": "registry:file",
      "content": "@layer components {\n  :where([data-control-family=\"action-bar\"][data-slot=\"root\"]) {\n    opacity: 0;\n    transition: opacity var(--duration-base) var(--ease-standard);\n  }\n\n  @media (hover: hover) {\n    :where([data-control-family=\"chat-layout\"][data-slot=\"turn\"]:hover [data-control-family=\"action-bar\"][data-slot=\"root\"]) {\n      opacity: 1;\n    }\n  }\n\n  :where([data-control-family=\"chat-layout\"][data-slot=\"turn\"]:focus-within [data-control-family=\"action-bar\"][data-slot=\"root\"]) {\n    opacity: 1;\n  }\n}\n"
    }
  ],
  "css": {
    "@import \"../components/control-ui/styles/recipes/action-bar.css\"": {}
  },
  "meta": {}
}
