From 3463bde333e39cbfd8c33cd5e7b744e11f66cacb Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Thu, 19 Sep 2024 13:56:32 -0400 Subject: [PATCH] IconButton: Add type=submit prop to allow submitting forms using the button (#2325) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary: This PR adds a new prop `type` to the `IconButton` component that allows the button to submit a form when clicked or pressed. This is useful when we want to use an IconButton to submit a form, for example, a search form. This is done as I noticed that the IconButton component is missing the `type` and was needed in the search page. The prop is currently set, but the type definition is missing. Issue: FEI-5728 ## Test plan: Docs: - Navigate to /?path=/docs/packages-iconbutton--docs#submitting%20forms - Verify that the docs make sense. Interactive example: - Navigate to /?path=/story/packages-iconbutton--submitting-forms - Verify that the submit action is recorded in the SB `Actions` tab. Screenshot 2024-09-19 at 10 14 56 AM Author: jandrade Reviewers: beaesguerra, jandrade Required Reviewers: Approved By: beaesguerra Checks: ✅ Chromatic - Get results on regular PRs (ubuntu-latest, 20.x), ✅ Check build sizes (ubuntu-latest, 20.x), ✅ Test (ubuntu-latest, 20.x, 2/2), ✅ Lint (ubuntu-latest, 20.x), ✅ Test (ubuntu-latest, 20.x, 1/2), ✅ Chromatic - Build on regular PRs / chromatic (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ⏭️ Chromatic - Skip on Release PR (changesets), ✅ Prime node_modules cache for primary configuration (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ gerald, ⏭️ dependabot Pull Request URL: https://github.com/Khan/wonder-blocks/pull/2325 --- .changeset/three-keys-add.md | 5 ++ .../icon-button.stories.tsx | 41 ++++++++++++++++ .../components/__tests__/icon-button.test.tsx | 47 +++++++++++++++++++ .../src/components/icon-button.tsx | 6 +++ 4 files changed, 99 insertions(+) create mode 100644 .changeset/three-keys-add.md diff --git a/.changeset/three-keys-add.md b/.changeset/three-keys-add.md new file mode 100644 index 000000000..1f69d7919 --- /dev/null +++ b/.changeset/three-keys-add.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/wonder-blocks-icon-button": minor +--- + +Add type=submit prop to allow submitting forms with the button diff --git a/__docs__/wonder-blocks-icon-button/icon-button.stories.tsx b/__docs__/wonder-blocks-icon-button/icon-button.stories.tsx index 7e1e004f2..806ec390b 100644 --- a/__docs__/wonder-blocks-icon-button/icon-button.stories.tsx +++ b/__docs__/wonder-blocks-icon-button/icon-button.stories.tsx @@ -21,6 +21,7 @@ import {color, spacing} from "@khanacademy/wonder-blocks-tokens"; import ComponentInfo from "../../.storybook/components/component-info"; import packageConfig from "../../packages/wonder-blocks-icon-button/package.json"; import IconButtonArgtypes from "./icon-button.argtypes"; +import TextField from "../../packages/wonder-blocks-form/src/components/text-field"; /** * An `IconButton` is a button whose contents are an SVG image. @@ -355,6 +356,45 @@ export const WithRouter: StoryComponentType = { ), }; +/** + * If the button is inside a form, you can use the `type="submit"` prop, so the + * form will be submitted on click or by pressing `Enter`. + */ +export const SubmittingForms: StoryComponentType = { + name: "Submitting forms", + render: () => ( +
{ + e.preventDefault(); + console.log("form submitted"); + action("form submitted")(e); + }} + > + + + Search:{" "} + {}} + /> + + + +
+ ), + parameters: { + chromatic: { + // We are testing the form submission, not UI changes. + disableSnapshot: true, + }, + }, +}; + const styles = StyleSheet.create({ dark: { backgroundColor: color.darkBlue, @@ -366,6 +406,7 @@ const styles = StyleSheet.create({ width: spacing.xxxLarge_64, }, row: { + display: "flex", flexDirection: "row", gap: spacing.medium_16, alignItems: "center", diff --git a/packages/wonder-blocks-icon-button/src/components/__tests__/icon-button.test.tsx b/packages/wonder-blocks-icon-button/src/components/__tests__/icon-button.test.tsx index 6145231b8..cc4f6d215 100644 --- a/packages/wonder-blocks-icon-button/src/components/__tests__/icon-button.test.tsx +++ b/packages/wonder-blocks-icon-button/src/components/__tests__/icon-button.test.tsx @@ -320,4 +320,51 @@ describe("IconButton", () => { expect(onClickMock).toHaveBeenCalledTimes(1); }); }); + + describe("type='submit'", () => { + it("should submit button within form via click", async () => { + // Arrange + const submitFnMock = jest.fn(); + render( +
+ + , + ); + + // Act + const button = await screen.findByRole("button"); + await userEvent.click(button); + + // Assert + expect(submitFnMock).toHaveBeenCalled(); + }); + + it("should submit button within form via keyboard", async () => { + // Arrange + const submitFnMock = jest.fn(); + render( +
+ + , + ); + + // Act + const button = await screen.findByRole("button"); + await userEvent.type(button, "{enter}"); + + // Assert + expect(submitFnMock).toHaveBeenCalled(); + }); + + it("should submit button doesn't break if it's not in a form", async () => { + // Arrange + render(); + + // Act + expect(async () => { + // Assert + await userEvent.click(await screen.findByRole("button")); + }).not.toThrow(); + }); + }); }); diff --git a/packages/wonder-blocks-icon-button/src/components/icon-button.tsx b/packages/wonder-blocks-icon-button/src/components/icon-button.tsx index 8b2ed1e13..e460bdabe 100644 --- a/packages/wonder-blocks-icon-button/src/components/icon-button.tsx +++ b/packages/wonder-blocks-icon-button/src/components/icon-button.tsx @@ -40,6 +40,10 @@ export type SharedProps = Partial> & { * Test ID used for e2e testing. */ testId?: string; + /** + * Used for icon buttons within
s. + */ + type?: "submit"; /** * Size of the icon button. * One of `xsmall` (16 icon, 20 target), `small` (24, 32), `medium` (24, 40), @@ -181,6 +185,7 @@ export const IconButton: React.ForwardRefExoticComponent< skipClientNav, tabIndex, target, + type, ...sharedProps } = props; @@ -219,6 +224,7 @@ export const IconButton: React.ForwardRefExoticComponent< tabIndex={tabIndex} onKeyDown={handleKeyDown} onKeyUp={handleKeyUp} + type={type} /> );