/** * @fileoverview Saasflare Button — primary interactive component. * @module packages/ui/components/ui/button * @package ui * * 3-axis variant system: variant × intent × size. * Extends {@link SaasflareComponentProps} so `surface` and `animated` can be * supplied per-instance or inherited from . * * Precedence for resolved theme props: component prop > provider context > hardcoded default. * * Stateful concerns (loading, async pending) live in * {@link StatefulButton} — this file stays purely presentational. * * @example * import { Button } from "@saasflare/ui"; * * * * * * * * */ import * as React from "react"; import { type VariantProps } from "class-variance-authority"; import { type SaasflareComponentProps } from "../../providers"; declare const INTENTS: readonly ["primary", "neutral", "success", "warning", "danger", "info"]; /** Semantic color intent of a {@link Button} — emitted as `data-intent` and resolved to the `--intent` CSS tokens by the theme. */ type Intent = (typeof INTENTS)[number]; /** * Where the loading spinner renders relative to the label. * * @example * */ type SpinnerPlacement = "start" | "end"; /** * Button variant definitions using the 3-axis system. * * Axes: * variant — visual treatment: solid, soft, outline, ghost, link, glass, clay, shadow * intent — color intent via data-intent attribute + CSS tokens * size — dimensional: xs, sm, md, lg, xl, icon, icon-xs, icon-sm, icon-lg */ declare const buttonVariants: (props?: ({ variant?: "link" | "outline" | "glass" | "clay" | "soft" | "solid" | "ghost" | "shadow" | null | undefined; size?: "xs" | "sm" | "md" | "lg" | "xl" | "icon-xs" | "icon-sm" | "icon" | "icon-lg" | null | undefined; } & import("class-variance-authority/types").ClassProp) | undefined) => string; /** Motion event overrides that conflict with React HTML events */ type MotionConflicts = "onDrag" | "onDragStart" | "onDragEnd" | "onAnimationStart" | "onAnimationEnd"; /** * Props for the Saasflare Button component. * * Extends {@link SaasflareComponentProps} to accept `surface` and `animated` * overrides that are resolved against the context. */ interface ButtonProps extends Omit, MotionConflicts>, VariantProps, SaasflareComponentProps { /** * Render as child element (Radix Slot pattern). Mutually exclusive with the * presentational slot props below — when `asChild` is set they are ignored * (dev-only `console.warn`) since a Slot cannot own injected DOM children. */ asChild?: boolean; /** Semantic color intent */ intent?: Intent; /** Stretch to full width of container */ fullWidth?: boolean; /** * Node rendered before the label (e.g. a leading icon). Ignored when `asChild`. * Intended for non-interactive adornments; mark meaningful icons `aria-hidden` * yourself if they are decorative. */ startContent?: React.ReactNode; /** * Node rendered after the label (e.g. a trailing icon). Ignored when `asChild`. * Intended for non-interactive adornments. */ endContent?: React.ReactNode; /** * Presentational loading flag. Renders a hardcoded-regular `CircleNotch` * spinner, forces `disabled`, sets `aria-busy="true"`, and disables motion. * This is the DUMB flag you flip yourself; for promise/async orchestration * reach for {@link StatefulButton}. * * @default false */ isLoading?: boolean; /** * Spinner side while `isLoading`. Replaces `startContent` (start) or * `endContent` (end); the opposite slot still renders its content. No-op when * `isLoading` is false. * * @default "start" */ spinnerPlacement?: SpinnerPlacement; /** * Convenience: square icon button. Maps the resolved `size` to its paired * icon size token for the cva call only (`xs→icon-xs`, `sm→icon-sm`, * `md→icon`, `lg→icon-lg`, `xl→icon-lg`). If an `icon*` size is already * passed, that wins. Icon-only buttons require an accessible name — pass * `aria-label` (dev-only warn otherwise). Ignored when `asChild`. * * @default false */ isIconOnly?: boolean; } /** * Primary interactive button with motion and intent support. * * Resolves `surface` and `animated` via {@link useSaasflareProps} with the * precedence: component prop > context > hardcoded default. * * When no explicit `variant` is set and the resolved surface is `"glass"` or * `"clay"`, the button promotes itself to that matching variant. An explicit * `variant` prop always wins over the surface-based promotion. * * For loading / pending states use {@link StatefulButton}. * * @component * @layer ui * * @param {string} variant - Visual treatment: "solid" | "soft" | "outline" | "ghost" | "link" | "glass" | "clay" | "shadow" * @param {string} intent - Color intent: "primary" | "neutral" | "success" | "warning" | "danger" | "info" * @param {string} size - Button size: "xs" | "sm" | "md" | "lg" | "xl" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" * @param {string} surface - Surface style override: "flat" | "glass" | "clay" (inherits from provider when omitted) * @param {string} radius - Radius preset override: "sharp" | "soft" | "rounded" | "pill" (inherits from provider when omitted) * @param {string} iconWeight - Phosphor icon weight override: "regular" | "bold" | "fill" | "duotone" (inherits from provider when omitted) * @param {boolean} animated - Gate motion effects (inherits from provider when omitted) * @param {boolean} fullWidth - Stretches to container width * @param {boolean} asChild - Render as child element (Slot pattern) * * @example * // Solid primary (default) * * * @example * // Outline danger * * * @example * // Inherits surface from provider — auto-promotes to glass variant * * * @example * // Icon button * * * @example * // Leading + trailing icon slots * * * @example * // Presentational loading flag (dumb): you flip it yourself * * * * @example * // Square icon-only button — aria-label REQUIRED for an accessible name * * * @example * // Legacy API (deprecated but supported) * */ declare function Button({ className, variant: variantProp, size, intent: intentProp, asChild, fullWidth, startContent, endContent, isLoading, spinnerPlacement, isIconOnly, surface, iconWeight, radius, animated, disabled, children, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element; export { Button, buttonVariants, type ButtonProps, type Intent, type SpinnerPlacement };