import React from 'react'; import cx from 'classnames'; import { Button as ButtonBaseComponent } from 'ariakit/button'; import { Icon as BaseIcon } from '../icon'; import css from './button.module.css'; export const BUTTON_SIZE = { SMALL: 'small', MEDIUM: 'medium', LARGE: 'large', } as const; export const BUTTON_KIND = { PRIMARY: 'primary', SECONDARY: 'secondary', DANGE: 'danger', WARNING: 'warning', INFO: 'info', SUCCES: 'success', } as const; export const BUTTON_GLYPHS = BaseIcon.ICONS; type Size = (typeof BUTTON_SIZE)[keyof typeof BUTTON_SIZE]; type Kind = (typeof BUTTON_KIND)[keyof typeof BUTTON_KIND]; interface ButtonProps { outline?: boolean; solid?: boolean; active?: boolean; kind?: Kind | 'default'; size?: Size; radius?: Size | 'circle' | 'none'; padding?: Size | 'none'; as?: T; Icon?: React.ElementType; glyph?: React.ComponentProps['glyph']; rightGlyph?: React.ComponentProps['glyph']; } const ButtonComponent = ( props: ButtonProps & Omit, keyof ButtonProps>, ) => { const { className = '', outline = false, solid = false, active = false, kind = 'default', size = 'medium', radius = '', padding = '', as: Component = ButtonBaseComponent, children = null, Icon = BaseIcon, glyph, rightGlyph, ...restProps } = props; // Set padding and radius when provided or when outline/solid variations are set const resolvedPadding = padding || ((outline || solid) && size); const resolvedRadius = radius || ((outline || solid) && size); const resolvedSize = Object.values(BUTTON_SIZE).includes(size) ? size : BUTTON_SIZE.MEDIUM; const rootClassName = cx( css.root, kind && css[kind], css[resolvedSize], outline && css.outline, outline && css[`outline--${kind}`], solid && css.solid, solid && css[`solid--${kind}`], resolvedPadding && css.padding, resolvedRadius && css[`radius--${resolvedRadius}`], active && css.active, active && outline && css[`active-outline-${kind}`], className, ); return ( {glyph && } {children && {children}} {rightGlyph && } ); }; // React.forwardRef collapses ButtonComponent's generic `as` parameter down to // its default ('button'), so cast back to a polymorphic signature to keep // `as`/its associated element props (e.g. `href` with `as="a"`) type-checked. export const Button = React.forwardRef(ButtonComponent) as ( props: ButtonProps & Omit, keyof ButtonProps> & React.RefAttributes, ) => React.ReactElement | null;