73 lines
1.6 KiB
TypeScript
73 lines
1.6 KiB
TypeScript
'use client';
|
|
|
|
import { HTMLProps, useEffect, useRef } from 'react';
|
|
import { useFormStatus } from 'react-dom';
|
|
import Spinner, { SpinnerColor } from './Spinner';
|
|
import { clsx } from 'clsx/lite';
|
|
import { toastSuccess } from '@/toast';
|
|
|
|
interface Props extends HTMLProps<HTMLButtonElement> {
|
|
icon?: JSX.Element
|
|
styleAsLink?: boolean
|
|
spinnerColor?: SpinnerColor
|
|
onFormSubmitToastMessage?: string
|
|
}
|
|
|
|
export default function SubmitButtonWithStatus({
|
|
icon,
|
|
styleAsLink,
|
|
spinnerColor,
|
|
onFormSubmitToastMessage,
|
|
children,
|
|
disabled,
|
|
className,
|
|
type: _type,
|
|
...buttonProps
|
|
}: Props) {
|
|
|
|
const { pending } = useFormStatus();
|
|
const pendingPrevious = useRef(pending);
|
|
|
|
useEffect(() => {
|
|
if (
|
|
pendingPrevious.current &&
|
|
!pending &&
|
|
onFormSubmitToastMessage
|
|
) {
|
|
toastSuccess(onFormSubmitToastMessage);
|
|
}
|
|
pendingPrevious.current = pending;
|
|
}, [pending, onFormSubmitToastMessage]);
|
|
|
|
return (
|
|
<button
|
|
type="submit"
|
|
disabled={disabled}
|
|
className={clsx(
|
|
className,
|
|
'inline-flex items-center gap-2',
|
|
styleAsLink && 'link',
|
|
)}
|
|
{...buttonProps}
|
|
>
|
|
{(icon || pending) &&
|
|
<span className={clsx(
|
|
'h-4',
|
|
'min-w-[1rem]',
|
|
'inline-flex justify-center sm:justify-normal',
|
|
'-mx-0.5',
|
|
'translate-y-[1px]',
|
|
)}>
|
|
{pending
|
|
? <Spinner size={14} color={spinnerColor} />
|
|
: icon}
|
|
</span>}
|
|
{children && <span className={clsx(
|
|
icon !== undefined && 'hidden sm:inline-block',
|
|
)}>
|
|
{children}
|
|
</span>}
|
|
</button>
|
|
);
|
|
};
|