/* Copyright 2026 Marimo. All rights reserved. */ import { ChevronRightIcon, MoreVerticalIcon, RefreshCwIcon, } from "lucide-react"; import React, { useCallback, useState } from "react"; import { Button } from "@/components/ui/button"; import { Tooltip } from "@/components/ui/tooltip"; import { cn } from "@/utils/cn"; /** * Animated chevron for tree expand/collapse. * Rotates 90° when `isExpanded` is true. */ export const TreeChevron: React.FC<{ isExpanded: boolean; className?: string; }> = ({ isExpanded, className }) => ( ); /** * Refresh button that briefly spins its icon when clicked. * Keeps spinning for at least 500ms, or until the onClick Promise resolves. */ export const RefreshIconButton: React.FC<{ onClick: (e: React.MouseEvent) => void | Promise; tooltip?: string; className?: string; iconClassName?: string; }> = ({ onClick, tooltip = "Refresh", className, iconClassName }) => { const [isSpinning, setIsSpinning] = useState(false); const handleClick = useCallback( async (e: React.MouseEvent) => { setIsSpinning(true); // Artificially spin for 500ms to show the user that the button is working. const minDelay = new Promise((r) => setTimeout(r, 500)); try { await Promise.all([onClick(e), minDelay]); } finally { setIsSpinning(false); } }, [onClick], ); const button = ( ); return {button}; }; /** * Three-dot menu trigger that fades in on row hover. * Must be inside a `group` container. * Forwards ref so it works with Radix `asChild`. */ export const MoreActionsButton = React.forwardRef< HTMLButtonElement, { onClick?: (e: React.MouseEvent) => void; className?: string; iconClassName?: string; } & Omit, "variant" | "size"> >(({ className, iconClassName, ...props }, ref) => ( )); MoreActionsButton.displayName = "MoreActionsButton"; /** Standard class string for icons inside dropdown menu items. */ export const MENU_ITEM_ICON_CLASS = "h-3.5 w-3.5 mr-2";