import React, { forwardRef } from "react"; import { Loader } from "../loader"; import { AkselColor } from "../types"; import { Label } from "../typography"; import type { OverridableComponent } from "../utils-external"; import { omit } from "../utils-external"; import { cl, composeEventHandlers } from "../utils/helpers"; type legacyVariants = | "primary-neutral" | "secondary-neutral" | "tertiary-neutral" | "danger"; type HiddenVariant = legacyVariants & { __brand?: never }; export interface ButtonProps extends React.ButtonHTMLAttributes { /** * Button content. */ children?: React.ReactNode; /** * Changes design and interaction-visuals. * @default "primary" */ variant?: "primary" | "secondary" | "tertiary" | HiddenVariant; /** * Changes padding, height, and font-size. * @default "medium" */ size?: "medium" | "small" | "xsmall"; /** * **Avoid using if possible for accessibility purposes**. * * Prevent the user from interacting with the button: it cannot be pressed or focused. */ disabled?: boolean; /** * Replaces button content with a Loader component, keeps width. * @default false */ loading?: boolean; /** * Button Icon. */ icon?: React.ReactNode; /** * Icon position in Button. * @default "left" */ iconPosition?: "left" | "right"; /** * Overrides inherited color. * * We recommend only using `accent`, `neutral` and `danger`. * @see 🏷️ {@link AkselColor} * @see [📝 Documentation](https://aksel.nav.no/grunnleggende/styling/farger-tokens) */ "data-color"?: AkselColor; } /** * A button component * @see [📝 Documentation](https://aksel.nav.no/komponenter/core/button) * @see 🏷️ {@link ButtonProps} * @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support * @example * ```jsx * * ``` */ export const Button: OverridableComponent = forwardRef( ( { as: Component = "button", variant = "primary", className, children, size = "medium", loading = false, disabled, icon, iconPosition = "left", onKeyUp, "data-color": color, ...rest }, ref, ) => { const filterProps: React.ButtonHTMLAttributes = disabled || loading ? omit(rest, ["href"]) : rest; const handleKeyUp = (e: React.KeyboardEvent) => { if (e.key === " " && !disabled && !loading) { e.currentTarget.click(); } }; return ( {icon && iconPosition === "left" && ( {icon} )} {loading && } {children && ( )} {icon && iconPosition === "right" && ( {icon} )} ); }, ); function variantToColor( variant: ButtonProps["variant"], ): AkselColor | undefined { switch (variant) { case "primary-neutral": case "secondary-neutral": case "tertiary-neutral": return "neutral"; case "danger": return "danger"; default: return undefined; } } function variantToSimplifiedVariant( variant: ButtonProps["variant"], ): "primary" | "secondary" | "tertiary" { switch (variant) { case "primary": case "primary-neutral": case "danger": return "primary"; case "secondary": case "secondary-neutral": return "secondary"; case "tertiary": case "tertiary-neutral": return "tertiary"; default: return "primary"; } } export default Button;