import type { VariantProps } from 'class-variance-authority' import type { ReactNode } from 'react' import { Codicon } from '@/components/ui/codicon' import { cn } from '@/lib/utils' import type { buttonVariants } from './button'; import { Button } from './button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from './dropdown-menu' export interface SplitButtonAction { id: string label: string icon?: ReactNode } interface SplitButtonProps { actions: SplitButtonAction[] /** The id of the action the primary button runs (the user's current default). */ value: string /** Picking from the menu changes the default (so the next primary click repeats it). */ onValueChange: (id: string) => void /** Run an action by id (primary click or menu pick both call this). */ onTrigger: (id: string) => void disabled?: boolean className?: string /** Icon shown on the primary button only (e.g. a ✓ for Commit). */ primaryIcon?: ReactNode variant?: VariantProps['variant'] size?: VariantProps['size'] } /** * A primary action fused to a caret that opens alternates — VS Code's * Commit / Commit & Push pattern. The primary button runs `value`; picking a * menu item runs it AND makes it the new default, so the control adapts to how * the user works without a separate settings toggle. */ export function SplitButton({ actions, value, onValueChange, onTrigger, disabled, className, primaryIcon, variant = 'secondary', size = 'sm' }: SplitButtonProps) { const active = actions.find(action => action.id === value) ?? actions[0] if (!active) { return null } return (
{actions.map(action => ( { onValueChange(action.id) onTrigger(action.id) }} > {action.icon} {action.label} {action.id === value && } ))}
) }