forked from CredenceOrg/Credence-Frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathButton.tsx
More file actions
90 lines (86 loc) · 2.44 KB
/
Copy pathButton.tsx
File metadata and controls
90 lines (86 loc) · 2.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { ButtonHTMLAttributes, forwardRef, ReactNode } from 'react'
import { TEST_IDS } from '../config/testIds'
import './Button.css'
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
/** Visual style variant */
variant?: 'primary' | 'secondary' | 'ghost' | 'danger'
/** Loading state - shows spinner and disables interaction */
isLoading?: boolean
/** Full width button */
fullWidth?: boolean
/** Button content */
children: ReactNode
}
/**
* Standardized button component with consistent variants and interactive states.
* Includes accessible focus styles and loading state support.
*/
const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
{
variant = 'primary',
isLoading = false,
fullWidth = false,
disabled,
children,
className = '',
type = 'button',
'data-testid': dataTestId,
...props
},
ref
) {
const isDisabled = disabled || isLoading
const finalTestId = dataTestId ?? (variant === 'primary' ? TEST_IDS.PRIMARY_CTA : undefined)
return (
<button
ref={ref}
type={type}
data-testid={finalTestId}
disabled={isDisabled}
className={[
'credence-button',
`credence-button--${variant}`,
fullWidth ? 'credence-button--full-width' : '',
className,
]
.filter(Boolean)
.join(' ')}
aria-busy={isLoading}
{...props}
>
{isLoading && (
<span className="credence-button__spinner" aria-hidden="true">
<svg
className="credence-button__spinner-icon"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<circle
className="credence-button__spinner-track"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="3"
/>
<circle
className="credence-button__spinner-head"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="3"
strokeLinecap="round"
/>
</svg>
</span>
)}
<span className="sr-only" aria-live="polite" aria-atomic="true">
{isLoading ? 'Sending…' : ''}
</span>
<span className={isLoading ? 'credence-button__content--loading' : ''}>{children}</span>
</button>
)
})
export default Button