import type { AnchorHTMLAttributes, ButtonHTMLAttributes, ComponentType, ReactNode, Ref, } from "react"; import { cx, sortCx } from "@/utils/cx"; import { directionalIconClass } from "@/utils/directional-icon"; /** * Figma source: Board UI → Buttons (node 3656:13819). * * Variant matrix from Figma: * Type = Primary | Secondary | Ghost | Danger * Size = Medium | Small | Xs * State = Default | Hover | Active | Disabled (CSS pseudo) * OnlyIcon = false | true * * Sizing (1:1 with Figma): * * Medium Small Xs * container h=36, p=8, r=10 h=32, px=8 py=6, r=8 h=24, px=8, r=4 * gap 2px 2px 1.33px→1 * icon 20×20 18×18 14×14 * label wrapper px=4 px=2 px=2 * text style Body 1/Medium Body 1/Medium Caption 1/Semibold * icon-only square 36×36 (content-derived) 32×32 (forced size) 24×24 (forced size) * * `xs` is the smallest tier — first needed for the calendar template's * event-details modal ("Join" / edit-icon buttons, node 3920:10954), which * scales every dimension down by the same ~0.667 factor from Figma; the * table above rounds those to clean pixel values rather than reproducing * the fractional source numbers. * * Icons are rendered by the component itself via the `leadingIcon` / * `trailingIcon` props so the consumer can't pass the wrong size. Pass * a Remix Icon component reference (`RiAddLine`, not ``). * * For icon-only buttons: * ); } /** Anchor counterpart to Button for navigational actions. */ export function ButtonLink({ variant = "primary", size = "medium", iconOnly = false, leadingIcon: Leading, trailingIcon: Trailing, children, className, ref, ...props }: ButtonLinkProps) { return ( {Leading ? : null} {!iconOnly && children !== undefined && children !== null && ( {children} )} {!iconOnly && Trailing ? ( ) : null} ); } /** Style maps, exported for advanced composition and the dev Design Tuner. */ export const buttonStyles = styles;