feat: add loading state to FilledButton (#7650)

This commit is contained in:
David Luzar
2024-02-03 14:53:31 +01:00
committed by GitHub
parent d67eaa8710
commit a289c42830
8 changed files with 119 additions and 31 deletions

View File

@@ -1,7 +1,10 @@
import React, { forwardRef } from "react";
import React, { forwardRef, useState } from "react";
import clsx from "clsx";
import "./FilledButton.scss";
import { AbortError } from "../errors";
import Spinner from "./Spinner";
import { isPromiseLike } from "../utils";
export type ButtonVariant = "filled" | "outlined" | "icon";
export type ButtonColor = "primary" | "danger" | "warning" | "muted";
@@ -11,7 +14,7 @@ export type FilledButtonProps = {
label: string;
children?: React.ReactNode;
onClick?: () => void;
onClick?: (event: React.MouseEvent) => void;
variant?: ButtonVariant;
color?: ButtonColor;
@@ -19,14 +22,14 @@ export type FilledButtonProps = {
className?: string;
fullWidth?: boolean;
startIcon?: React.ReactNode;
icon?: React.ReactNode;
};
export const FilledButton = forwardRef<HTMLButtonElement, FilledButtonProps>(
(
{
children,
startIcon,
icon,
onClick,
label,
variant = "filled",
@@ -37,6 +40,27 @@ export const FilledButton = forwardRef<HTMLButtonElement, FilledButtonProps>(
},
ref,
) => {
const [isLoading, setIsLoading] = useState(false);
const _onClick = async (event: React.MouseEvent) => {
const ret = onClick?.(event);
if (isPromiseLike(ret)) {
try {
setIsLoading(true);
await ret;
} catch (error: any) {
if (!(error instanceof AbortError)) {
throw error;
} else {
console.warn(error);
}
} finally {
setIsLoading(false);
}
}
};
return (
<button
className={clsx(
@@ -47,17 +71,21 @@ export const FilledButton = forwardRef<HTMLButtonElement, FilledButtonProps>(
{ "ExcButton--fullWidth": fullWidth },
className,
)}
onClick={onClick}
onClick={_onClick}
type="button"
aria-label={label}
ref={ref}
disabled={isLoading}
>
{startIcon && (
<div className="ExcButton__icon" aria-hidden>
{startIcon}
</div>
)}
{variant !== "icon" && (children ?? label)}
<div className="ExcButton__contents">
{isLoading && <Spinner />}
{icon && (
<div className="ExcButton__icon" aria-hidden>
{icon}
</div>
)}
{variant !== "icon" && (children ?? label)}
</div>
</button>
);
},