From 38f0deaaca89b273c30a515a8f053d46f219e26d Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 10 Feb 2022 01:43:31 +0000 Subject: [PATCH 1/4] fix: Add FormCloseButton for project / workspace create forms --- .../Form/FormCloseButton.stories.tsx | 16 +++++ site/components/Form/FormCloseButton.test.tsx | 67 +++++++++++++++++++ site/components/Form/FormCloseButton.tsx | 56 ++++++++++++++++ site/components/Form/index.ts | 1 + site/components/Icons/Close.tsx | 8 +++ site/forms/CreateProjectForm.tsx | 10 ++- site/forms/CreateWorkspaceForm.tsx | 4 +- 7 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 site/components/Form/FormCloseButton.stories.tsx create mode 100644 site/components/Form/FormCloseButton.test.tsx create mode 100644 site/components/Form/FormCloseButton.tsx create mode 100644 site/components/Icons/Close.tsx diff --git a/site/components/Form/FormCloseButton.stories.tsx b/site/components/Form/FormCloseButton.stories.tsx new file mode 100644 index 0000000000000..6e011a2536d51 --- /dev/null +++ b/site/components/Form/FormCloseButton.stories.tsx @@ -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 = (args) => + +export const Example = Template.bind({}) +Example.args = {} diff --git a/site/components/Form/FormCloseButton.test.tsx b/site/components/Form/FormCloseButton.test.tsx new file mode 100644 index 0000000000000..193d3112c7efd --- /dev/null +++ b/site/components/Form/FormCloseButton.test.tsx @@ -0,0 +1,67 @@ +import { fireEvent, render, screen, waitFor } from "@testing-library/react" +import React from "react" +import { FormCloseButton, FormCloseButtonProps } from "./FormCloseButton" + +describe("FormCloseButton", () => { + it("renders", async () => { + // When + render( + { + return + }} + />, + ) + + // Then + await screen.findByText("ESC") + }) + + it("calls onClose when clicked", async () => { + // Given + const onClose = jest.fn() + + // When + render() + + // Then + const element = await screen.findByText("ESC") + fireEvent.click(element) + + expect(onClose).toBeCalledTimes(1) + }) + + it("calls onClose when escape is pressed", async () => { + // Given + const onClose = jest.fn() + + // When + render() + + // 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() + + // Then + const element = await screen.findByText("ESC") + + // When + fireEvent.keyDown(element, { key: "Enter", code: "Enter", charCode: 13 }) + + // Then + expect(onClose).toBeCalledTimes(0) + }) +}) diff --git a/site/components/Form/FormCloseButton.tsx b/site/components/Form/FormCloseButton.tsx new file mode 100644 index 0000000000000..44ced2df2c5c8 --- /dev/null +++ b/site/components/Form/FormCloseButton.tsx @@ -0,0 +1,56 @@ +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 = ({ 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 ( + + + + ESC + + + ) +} + +const useStyles = makeStyles((theme) => ({ + closeButton: { + position: "fixed", + top: theme.spacing(6), + 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%)", + }, +})) diff --git a/site/components/Form/index.ts b/site/components/Form/index.ts index 80ddbbac74b3b..08456432c7f74 100644 --- a/site/components/Form/index.ts +++ b/site/components/Form/index.ts @@ -1,3 +1,4 @@ +export * from "./FormCloseButton" export * from "./FormSection" export * from "./FormDropdownField" export * from "./FormTextField" diff --git a/site/components/Icons/Close.tsx b/site/components/Icons/Close.tsx new file mode 100644 index 0000000000000..ab9a44a898941 --- /dev/null +++ b/site/components/Icons/Close.tsx @@ -0,0 +1,8 @@ +import SvgIcon from "@material-ui/core/SvgIcon" +import React from "react" + +export const CloseIcon: typeof SvgIcon = (props) => ( + + + +) diff --git a/site/forms/CreateProjectForm.tsx b/site/forms/CreateProjectForm.tsx index 1a4558e9b2ef8..a930cf487e054 100644 --- a/site/forms/CreateProjectForm.tsx +++ b/site/forms/CreateProjectForm.tsx @@ -4,7 +4,14 @@ import { FormikContextType, useFormik } from "formik" import React from "react" import * as Yup from "yup" -import { DropdownItem, FormDropdownField, FormTextField, FormTitle, FormSection } from "../components/Form" +import { + DropdownItem, + FormDropdownField, + FormTextField, + FormTitle, + FormSection, + FormCloseButton, +} from "../components/Form" import { LoadingButton } from "../components/Button" import { Organization, Project, Provisioner, CreateProjectRequest } from "./../api" @@ -59,6 +66,7 @@ export const CreateProjectForm: React.FC = ({ return (
+ = ({ project, on } /> + + Date: Thu, 10 Feb 2022 01:46:29 +0000 Subject: [PATCH 2/4] Tweak styling --- site/components/Form/FormCloseButton.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/site/components/Form/FormCloseButton.tsx b/site/components/Form/FormCloseButton.tsx index 44ced2df2c5c8..a22f71e8c5b7d 100644 --- a/site/components/Form/FormCloseButton.tsx +++ b/site/components/Form/FormCloseButton.tsx @@ -38,7 +38,7 @@ export const FormCloseButton: React.FC = ({ onClose }) => const useStyles = makeStyles((theme) => ({ closeButton: { position: "fixed", - top: theme.spacing(6), + top: theme.spacing(3), right: theme.spacing(6), opacity: 0.5, color: theme.palette.text.primary, @@ -46,7 +46,6 @@ const useStyles = makeStyles((theme) => ({ opacity: 1, }, }, - label: { position: "absolute", left: "50%", From 19fb01b754fd05225c469c8b3c28f5bf5fcae0e0 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 10 Feb 2022 01:49:45 +0000 Subject: [PATCH 3/4] Clean up tests --- site/components/Form/FormCloseButton.test.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/site/components/Form/FormCloseButton.test.tsx b/site/components/Form/FormCloseButton.test.tsx index 193d3112c7efd..32a46d722f8ad 100644 --- a/site/components/Form/FormCloseButton.test.tsx +++ b/site/components/Form/FormCloseButton.test.tsx @@ -26,8 +26,11 @@ describe("FormCloseButton", () => { // Then const element = await screen.findByText("ESC") + + // When fireEvent.click(element) + // Then expect(onClose).toBeCalledTimes(1) }) From ed80c224d5bf42b58abdcae7054806f92b3465b6 Mon Sep 17 00:00:00 2001 From: Bryan Phelps Date: Thu, 10 Feb 2022 03:45:19 +0000 Subject: [PATCH 4/4] Fix lint issues --- site/components/Form/FormCloseButton.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/components/Form/FormCloseButton.test.tsx b/site/components/Form/FormCloseButton.test.tsx index 32a46d722f8ad..393f7bcc657f0 100644 --- a/site/components/Form/FormCloseButton.test.tsx +++ b/site/components/Form/FormCloseButton.test.tsx @@ -1,6 +1,6 @@ -import { fireEvent, render, screen, waitFor } from "@testing-library/react" +import { fireEvent, render, screen } from "@testing-library/react" import React from "react" -import { FormCloseButton, FormCloseButtonProps } from "./FormCloseButton" +import { FormCloseButton } from "./FormCloseButton" describe("FormCloseButton", () => { it("renders", async () => {