Merge pull request #29654 from overleaf/ac-ciam-confirm-email-storybook

[web] CIAM design for Email confirmation form

GitOrigin-RevId: 3e66c45fe20073eb0600b8243761dbe82d7dc6b2
This commit is contained in:
Tim Down
2025-11-25 11:25:39 +00:00
committed by Copybot
parent 0d9fa6c0a6
commit 763bede00a
18 changed files with 364 additions and 44 deletions
@@ -1,5 +1,7 @@
import { forwardRef, ReactNode } from 'react'
import { Button, ButtonProps } from 'react-bootstrap'
import { Button, ButtonProps, Spinner } from 'react-bootstrap'
import { useTranslation } from 'react-i18next'
import classNames from 'classnames'
type DSButtonProps = Pick<
ButtonProps,
@@ -22,6 +24,8 @@ type DSButtonProps = Pick<
leadingIcon?: ReactNode
trailingIcon?: ReactNode
variant?: 'primary' | 'secondary' | 'tertiary' | 'danger'
isLoading?: boolean
loadingLabel?: string
}
const DSButton = forwardRef<HTMLButtonElement, DSButtonProps>(
@@ -29,6 +33,8 @@ const DSButton = forwardRef<HTMLButtonElement, DSButtonProps>(
{
children,
leadingIcon,
isLoading = false,
loadingLabel,
trailingIcon,
variant = 'primary',
size,
@@ -36,16 +42,40 @@ const DSButton = forwardRef<HTMLButtonElement, DSButtonProps>(
},
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="d-inline-grid btn-ds"
className={buttonClassName}
variant={variant}
size={size}
{...props}
ref={ref}
disabled={isLoading || props.disabled}
data-ol-loading={isLoading}
role={undefined}
>
<span className="button-content">
{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}
@@ -7,7 +7,10 @@ type TextType = 'success' | 'error'
export type FormTextProps = MergeAndOverride<
BS5FormTextProps,
{ type?: TextType }
{
type?: TextType
marginless?: boolean
}
>
const typeClasses = {
@@ -31,10 +34,18 @@ function FormTextIcon({ type }: { type?: TextType }) {
}
}
function DSFormText({ type, children, className, ...rest }: FormTextProps) {
function DSFormText({
type,
marginless,
children,
className,
...rest
}: FormTextProps) {
return (
<Form.Text
className={classnames('form-text-ds', className, getFormTextClass(type))}
className={classnames('form-text-ds', className, getFormTextClass(type), {
marginless,
})}
{...rest}
>
<span className="form-text-inner-ds">
@@ -9,6 +9,7 @@ export type FormTextProps = MergeAndOverride<
BS5FormTextProps,
{
type?: TextType
marginless?: boolean
}
>
@@ -38,13 +39,14 @@ function FormTextIcon({ type }: { type?: TextType }) {
function FormText({
type = 'default',
marginless,
children,
className,
...rest
}: FormTextProps) {
return (
<Form.Text
className={classnames(className, getFormTextClass(type))}
className={classnames(className, getFormTextClass(type), { marginless })}
{...rest}
>
<span className="form-text-inner">