Files
ragusaitweb/src/components/ui/Button.tsx
google-labs-jules[bot] 6d94ac7b93 🎨 Palette: Improve Button loading state accessibility
- Add `aria-busy` attribute to Button when loading.
- Refactor Button rendering to keep children in DOM (visually hidden) instead of unmounting.
- Fix layout shift regression by replicating flex properties in content wrapper.
- Move inline styles to CSS modules.
- Add tests for loading state accessibility.

Co-authored-by: ragusa-it <196988693+ragusa-it@users.noreply.github.com>
2026-01-27 01:42:19 +00:00

43 lines
1.2 KiB
TypeScript

import { type ReactNode, type ButtonHTMLAttributes } from 'react';
import { motion } from 'motion/react';
import styles from './Button.module.css';
interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onAnimationStart' | 'onDragStart' | 'onDragEnd' | 'onDrag'> {
variant?: 'primary' | 'secondary' | 'outline';
size?: 'sm' | 'md' | 'lg';
children: ReactNode;
isLoading?: boolean;
}
export function Button({
variant = 'primary',
size = 'md',
children,
isLoading,
className,
disabled,
type = 'button',
...props
}: ButtonProps) {
return (
<motion.button
type={type}
className={`${styles.button} ${styles[variant]} ${styles[size]} ${className || ''}`}
disabled={disabled || isLoading}
aria-busy={isLoading}
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
{...props}
>
<span className={`${styles.content} ${isLoading ? styles.contentHidden : ''}`}>
{children}
</span>
{isLoading && (
<span className={styles.loaderWrapper} aria-hidden="true">
<span className={styles.loader} />
</span>
)}
</motion.button>
);
}