Agents
ActionBar
Reusable hover actions for message and response controls.
Composition
The preferred shape for composing the installed agent from its exported parts.
Parts
Exported compound parts from the installed source.
ActionBar├── ActionBarItem├── ActionBarCopy└── ActionBarEditThis agent installs from the chat registry. Install the bundle with the command above, or inspect the source below.
npx shadcn@latest add http://127.0.0.1:3000/r/refined/chat.jsonUsage
import { ActionBar, ActionBarCopy, ActionBarEdit, ActionBarItem } from "@/components/refined-ui/action-bar";const messageText = "The assistant response you want to copy";export function Example({ onEdit }: { onEdit: (value: string) => void }) { return ( <ActionBar label="Response actions" copyValue={messageText} editValue={messageText} onEdit={onEdit}> <ActionBarCopy /> <ActionBarEdit /> <ActionBarItem>Share</ActionBarItem> <ActionBarItem>More</ActionBarItem> </ActionBar> );}Installed dependencies
Installed with this agent because the visible component depends on them; they are support files, not separate product surfaces.
Copy hook
src/registry/hooks/use-copy-to-clipboard.tsHookRaw code
Primary installed agent source
Component
src/registry/sources/refined/action-bar.tsx
"use client";import type { ComponentProps, MouseEvent, ReactNode } from "react";import { createContext, useContext } from "react";import { useCopyToClipboard } from "@/components/refined-ui/hooks/use-copy-to-clipboard";import { cn } from "@/components/refined-ui/lib/cn";import { skinSlot } from "@/components/refined-ui/skin";import { Button } from "@/components/refined-ui/ui/button";export type ActionBarCopyValue = string | (() => string | Promise<string>);export type ActionBarContextValue = { copyValue?: ActionBarCopyValue; editValue?: ActionBarCopyValue; onCopy?: (value: string) => void; onCopyError?: (error: unknown) => void; onEdit?: (value: string) => void; onEditError?: (error: unknown) => void;};export type ActionBarProps = ComponentProps<"div"> & { label?: string; align?: "start" | "end"; context?: ActionBarContextValue; copyValue?: ActionBarCopyValue; editValue?: ActionBarCopyValue; onCopy?: (value: string) => void; onCopyError?: (error: unknown) => void; onEdit?: (value: string) => void; onEditError?: (error: unknown) => void;};const ActionBarContext = createContext<ActionBarContextValue>({});async function resolveCopyValue(value?: ActionBarCopyValue) { return typeof value === "function" ? await value() : value;}export function ActionBar({ label = "Message actions", align = "start", className, children, context, copyValue, editValue, onCopy, onCopyError, onEdit, onEditError, ...props}: ActionBarProps) { const actionContext = { ...context, copyValue: copyValue ?? context?.copyValue, editValue: editValue ?? context?.editValue, onCopy: onCopy ?? context?.onCopy, onCopyError: onCopyError ?? context?.onCopyError, onEdit: onEdit ?? context?.onEdit, onEditError: onEditError ?? context?.onEditError, }; return ( <ActionBarContext.Provider value={actionContext}> <div data-ui="agent" data-component="action-bar" role="toolbar" aria-label={label} className={cn( "mt-1 flex min-h-8 items-center gap-1 opacity-0 transition-opacity duration-[var(--duration-base)] group-hover/turn:opacity-100 group-focus-within/turn:opacity-100", align === "end" ? "justify-end" : "justify-start", skinSlot("action-bar", {}), className, )} {...props} > {children} </div> </ActionBarContext.Provider> );}export type ActionBarItemProps = ComponentProps<typeof Button> & { icon?: ReactNode;};export function ActionBarItem({ icon, children, className, ...props }: ActionBarItemProps) { return ( <Button size="xs" className={className} {...props}> {icon} {children} </Button> );}export type ActionBarCopyProps = Omit<ActionBarItemProps, "children"> & { value?: ActionBarCopyValue; children?: ReactNode; copiedChildren?: ReactNode; resetDelay?: number;};export function ActionBarCopy({ value, children = "Copy", copiedChildren = "Copied", resetDelay = 1200, disabled, onClick, ...props}: ActionBarCopyProps) { const context = useContext(ActionBarContext); const copyValue = value ?? context.copyValue; const { isCopied, copyToClipboard } = useCopyToClipboard({ copiedDuration: resetDelay, onCopy: context.onCopy, onCopyError: context.onCopyError, }); async function handleClick(event: MouseEvent<HTMLButtonElement>) { onClick?.(event); if (event.defaultPrevented) return; const nextValue = await resolveCopyValue(copyValue); if (!nextValue) return; await copyToClipboard(nextValue); } return ( <ActionBarItem aria-live="polite" disabled={disabled ?? !copyValue} onClick={handleClick} {...props}> {isCopied ? copiedChildren : children} </ActionBarItem> );}export type ActionBarEditProps = Omit<ActionBarItemProps, "children"> & { value?: ActionBarCopyValue; children?: ReactNode;};export function ActionBarEdit({ value, children = "Edit", disabled, onClick, ...props }: ActionBarEditProps) { const context = useContext(ActionBarContext); const editValue = value ?? context.editValue ?? context.copyValue; async function handleClick(event: MouseEvent<HTMLButtonElement>) { onClick?.(event); if (event.defaultPrevented || !context.onEdit) return; try { const nextValue = await resolveCopyValue(editValue); if (!nextValue) return; context.onEdit(nextValue); } catch (error) { context.onEditError?.(error); } } return ( <ActionBarItem disabled={disabled ?? (!editValue || !context.onEdit)} onClick={handleClick} {...props}> {children} </ActionBarItem> );}Primitives
This agent composes these library primitives, installed under components/refined-ui/ui/*.