mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
@@ -0,0 +1,26 @@
|
||||
import { Story } from "@storybook/react"
|
||||
import React from "react"
|
||||
import { LoadingButton, LoadingButtonProps } from "./LoadingButton"
|
||||
|
||||
export default {
|
||||
title: "components/LoadingButton",
|
||||
component: LoadingButton,
|
||||
argTypes: {
|
||||
loading: { control: { type: "boolean" } },
|
||||
children: { control: "text", defaultValue: "Create workspace" },
|
||||
},
|
||||
}
|
||||
|
||||
const Template: Story<LoadingButtonProps> = (args) => <LoadingButton {...args} />
|
||||
|
||||
export const Loading = Template.bind({})
|
||||
Loading.args = {
|
||||
variant: "contained",
|
||||
loading: true,
|
||||
}
|
||||
|
||||
export const NotLoading = Template.bind({})
|
||||
NotLoading.args = {
|
||||
variant: "contained",
|
||||
loading: false,
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { render, screen } from "@testing-library/react"
|
||||
import React from "react"
|
||||
import { LoadingButton } from "./LoadingButton"
|
||||
|
||||
describe("LoadingButton", () => {
|
||||
it("renders", async () => {
|
||||
// When
|
||||
render(<LoadingButton>Sign In</LoadingButton>)
|
||||
|
||||
// Then
|
||||
const element = await screen.findByText("Sign In")
|
||||
expect(element).toBeDefined()
|
||||
})
|
||||
|
||||
it("shows spinner if loading is set to true", async () => {
|
||||
// When
|
||||
render(<LoadingButton loading>Sign in</LoadingButton>)
|
||||
|
||||
// Then
|
||||
const spinnerElement = await screen.findByRole("progressbar")
|
||||
expect(spinnerElement).toBeDefined()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,45 @@
|
||||
import Button, { ButtonProps } from "@material-ui/core/Button"
|
||||
import CircularProgress from "@material-ui/core/CircularProgress"
|
||||
import { makeStyles } from "@material-ui/core/styles"
|
||||
import * as React from "react"
|
||||
|
||||
export interface LoadingButtonProps extends ButtonProps {
|
||||
/** Whether or not to disable the button and show a spinner */
|
||||
loading?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* LoadingButton is a small wrapper around Material-UI's button to show a loading spinner
|
||||
*
|
||||
* In Material-UI 5+ - this is built-in, but since we're on an earlier version,
|
||||
* we have to roll our own.
|
||||
*/
|
||||
export const LoadingButton: React.FC<LoadingButtonProps> = ({ loading = false, children, ...rest }) => {
|
||||
const styles = useStyles()
|
||||
const hidden = loading ? { opacity: 0 } : undefined
|
||||
|
||||
return (
|
||||
<Button {...rest} disabled={rest.disabled || loading}>
|
||||
<span style={hidden}>{children}</span>
|
||||
{loading && (
|
||||
<div className={styles.loader}>
|
||||
<CircularProgress size={18} className={styles.spinner} />
|
||||
</div>
|
||||
)}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
loader: {
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
height: 18,
|
||||
width: 18,
|
||||
},
|
||||
spinner: {
|
||||
color: theme.palette.text.disabled,
|
||||
},
|
||||
}))
|
||||
Reference in New Issue
Block a user