-
Notifications
You must be signed in to change notification settings - Fork 582
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: Forms - Add 'escape' button / key handler in forms (#240)
In v1, we had a quick and easy way to leave creation forms - an escape button (and key handler) in the top right corner. This was especially helpful in cases where the form was long enough that the 'Cancel' button was off-screen. This ports over that component into v2 and hooks up into our two existing forms: <img width="977" alt="Screen Shot 2022-02-09 at 5 48 03 PM" src="https://user-images.githubusercontent.com/88213859/153321503-af957f2b-d674-4ebf-9ac5-97939cb9153f.png"> In addition, this adds test cases + a storybook story for it.
- Loading branch information
1 parent
a86f2ee
commit 35291d3
Showing
7 changed files
with
162 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Story } from "@storybook/react" | ||
import React from "react" | ||
import { FormCloseButton, FormCloseButtonProps } from "./FormCloseButton" | ||
|
||
export default { | ||
title: "Form/FormCloseButton", | ||
component: FormCloseButton, | ||
argTypes: { | ||
onClose: { action: "onClose" }, | ||
}, | ||
} | ||
|
||
const Template: Story<FormCloseButtonProps> = (args) => <FormCloseButton {...args} /> | ||
|
||
export const Example = Template.bind({}) | ||
Example.args = {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { fireEvent, render, screen } from "@testing-library/react" | ||
import React from "react" | ||
import { FormCloseButton } from "./FormCloseButton" | ||
|
||
describe("FormCloseButton", () => { | ||
it("renders", async () => { | ||
// When | ||
render( | ||
<FormCloseButton | ||
onClose={() => { | ||
return | ||
}} | ||
/>, | ||
) | ||
|
||
// Then | ||
await screen.findByText("ESC") | ||
}) | ||
|
||
it("calls onClose when clicked", async () => { | ||
// Given | ||
const onClose = jest.fn() | ||
|
||
// When | ||
render(<FormCloseButton onClose={onClose} />) | ||
|
||
// Then | ||
const element = await screen.findByText("ESC") | ||
|
||
// When | ||
fireEvent.click(element) | ||
|
||
// Then | ||
expect(onClose).toBeCalledTimes(1) | ||
}) | ||
|
||
it("calls onClose when escape is pressed", async () => { | ||
// Given | ||
const onClose = jest.fn() | ||
|
||
// When | ||
render(<FormCloseButton onClose={onClose} />) | ||
|
||
// Then | ||
const element = await screen.findByText("ESC") | ||
|
||
// When | ||
fireEvent.keyDown(element, { key: "Escape", code: "Esc", charCode: 27 }) | ||
|
||
// Then | ||
expect(onClose).toBeCalledTimes(1) | ||
}) | ||
|
||
it("doesn't call onClose if another key is pressed", async () => { | ||
// Given | ||
const onClose = jest.fn() | ||
|
||
// When | ||
render(<FormCloseButton onClose={onClose} />) | ||
|
||
// Then | ||
const element = await screen.findByText("ESC") | ||
|
||
// When | ||
fireEvent.keyDown(element, { key: "Enter", code: "Enter", charCode: 13 }) | ||
|
||
// Then | ||
expect(onClose).toBeCalledTimes(0) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import IconButton from "@material-ui/core/IconButton" | ||
import { makeStyles } from "@material-ui/core/styles" | ||
import Typography from "@material-ui/core/Typography" | ||
import React, { useEffect } from "react" | ||
import { CloseIcon } from "../Icons/Close" | ||
|
||
export interface FormCloseButtonProps { | ||
onClose: () => void | ||
} | ||
|
||
export const FormCloseButton: React.FC<FormCloseButtonProps> = ({ onClose }) => { | ||
const styles = useStyles() | ||
|
||
useEffect(() => { | ||
const handleKeyPress = (event: KeyboardEvent) => { | ||
if (event.key === "Escape") { | ||
onClose() | ||
} | ||
} | ||
|
||
document.body.addEventListener("keydown", handleKeyPress, false) | ||
|
||
return () => { | ||
document.body.removeEventListener("keydown", handleKeyPress, false) | ||
} | ||
}, []) | ||
|
||
return ( | ||
<IconButton className={styles.closeButton} onClick={onClose} size="medium"> | ||
<CloseIcon /> | ||
<Typography variant="caption" className={styles.label}> | ||
ESC | ||
</Typography> | ||
</IconButton> | ||
) | ||
} | ||
|
||
const useStyles = makeStyles((theme) => ({ | ||
closeButton: { | ||
position: "fixed", | ||
top: theme.spacing(3), | ||
right: theme.spacing(6), | ||
opacity: 0.5, | ||
color: theme.palette.text.primary, | ||
"&:hover": { | ||
opacity: 1, | ||
}, | ||
}, | ||
label: { | ||
position: "absolute", | ||
left: "50%", | ||
top: "100%", | ||
transform: "translate(-50%, 50%)", | ||
}, | ||
})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import SvgIcon from "@material-ui/core/SvgIcon" | ||
import React from "react" | ||
|
||
export const CloseIcon: typeof SvgIcon = (props) => ( | ||
<SvgIcon {...props} viewBox="0 0 31 31"> | ||
<path d="M29.5 1.5l-28 28M29.5 29.5l-28-28" stroke="currentcolor" strokeMiterlimit="10" strokeLinecap="square" /> | ||
</SvgIcon> | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters