Files
overleaf-cep/services/web/frontend/js/shared/components/ds/ds-button.tsx
Tim Down 763bede00a Merge pull request #29654 from overleaf/ac-ciam-confirm-email-storybook
[web] CIAM design for Email confirmation form

GitOrigin-RevId: 3e66c45fe20073eb0600b8243761dbe82d7dc6b2
2025-11-26 09:05:47 +00:00

91 lines
2.0 KiB
TypeScript

import { forwardRef, ReactNode } from 'react'
import { Button, ButtonProps, Spinner } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import classNames from 'classnames'
type DSButtonProps = Pick<
ButtonProps,
| 'children'
| 'disabled'
| 'href'
| 'id'
| 'target'
| 'rel'
| 'onClick'
| 'onMouseDown'
| 'onMouseOver'
| 'onMouseOut'
| 'onFocus'
| 'onBlur'
| 'size'
| 'active'
| 'type'
> & {
leadingIcon?: ReactNode
trailingIcon?: ReactNode
variant?: 'primary' | 'secondary' | 'tertiary' | 'danger'
isLoading?: boolean
loadingLabel?: string
}
const DSButton = forwardRef<HTMLButtonElement, DSButtonProps>(
(
{
children,
leadingIcon,
isLoading = false,
loadingLabel,
trailingIcon,
variant = 'primary',
size,
...props
},
ref
) => {
const { t } = useTranslation()
const buttonClassName = classNames('d-inline-grid btn-ds', {
'button-loading': isLoading,
})
const loadingSpinnerClassName =
size === 'lg' ? 'loading-spinner-large' : 'loading-spinner-small'
return (
<Button
className={buttonClassName}
variant={variant}
size={size}
{...props}
ref={ref}
disabled={isLoading || props.disabled}
data-ol-loading={isLoading}
role={undefined}
>
{isLoading && (
<span className="spinner-container">
<Spinner
size="sm"
animation="border"
aria-hidden="true"
className={loadingSpinnerClassName}
/>
<span className="visually-hidden">
{loadingLabel ?? t('loading')}
</span>
</span>
)}
<span className="button-content" aria-hidden={isLoading}>
{leadingIcon}
{children}
{trailingIcon}
</span>
</Button>
)
}
)
DSButton.displayName = 'DSButton'
export default DSButton