import { pick } from "../../lib/emoji"; import { type ComponentPropsWithRef, useRef, useState } from "react"; import { MessageToolbarButton } from "./message-toolbar-button"; import { cn } from "../../lib/utils"; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "../../ui/dropdown-menu"; import { EmojiPicker } from "../../ui/emoji-picker"; import { Popover, PopoverPopup, PopoverPortal, PopoverPositioner, PopoverTrigger, } from "../../ui/popover"; import { IconCopy, IconDots, IconLinkMicro, IconPencil, IconReact, IconTrash } from "../../icons"; type MessageToolbarProps = Omit, "onSelect"> & { /** Which edge the overflow menu should align to. */ align?: "left" | "right"; /** Whether the active message belongs to the current user — controls edit/delete visibility. */ mine?: boolean; /** Whether the active message may be edited. Defaults to `mine`. */ canEdit?: boolean; /** Disable unavailable actions while retaining the existing toolbar and menu. */ actions?: Partial>; /** Called when the user picks a toolbar action. */ onAction: (action: MessageToolbarAction) => void; /** Reports picker/menu open state to the parent so it can keep the toolbar mounted. */ onOpenChange?: (open: boolean) => void; }; type MessageToolbarAction = | { type: "copy" } | { type: "delete" } | { type: "edit" } | { type: "permalink" } | { type: "react"; emoji: string }; /** * Compact message action strip shown in the timeline action row. */ function MessageToolbar( { align = "right", className, mine, canEdit = mine, actions, onAction, onOpenChange, ...props }: MessageToolbarProps, ) { let [open, setOpen] = useState(false); let [menu, setMenu] = useState(false); let [popup, setPopup] = useState(false); let button = useRef(null); function handleOpenChange(o: boolean) { setOpen(o); onOpenChange?.(o || menu); } function handleMenuChange(o: boolean) { setMenu(o); onOpenChange?.(open || o); } function showPicker() { setPopup(true); setMenu(false); setOpen(true); onOpenChange?.(true); } return (
} onClick={() => setPopup(false)} /> } /> { onAction({ type: "react", emoji: pick(e) }); handleOpenChange(false); }} /> { onAction({ type: "copy" }); }} aria-label="Copy" disabled={actions?.copy === false} className="hidden notouch:flex" icon={} /> { onAction({ type: "permalink" }); }} aria-label="Copy message link" disabled={actions?.permalink === false} className="hidden notouch:flex" icon={} /> } /> } /> Add reaction { onAction({ type: "copy" }); }} disabled={actions?.copy === false} > Copy { onAction({ type: "permalink" }); }} disabled={actions?.permalink === false} > Copy link {mine && canEdit && } {mine && ( <> {canEdit && ( <> { onAction({ type: "edit" }); }} disabled={actions?.edit === false} > Edit )} { onAction({ type: "delete" }); }} > Delete )}
); } export { MessageToolbar }; export type { MessageToolbarAction, MessageToolbarProps };