Skip to content

Commit

Permalink
WB-1612: IconButton: Add PhosphorIcon support (#2067)
Browse files Browse the repository at this point in the history
## Summary:
- Changes the `icon` prop to accept a `PhosphorIcon` instead of an
`IconAsset`.
- Updates the `IconButton` stories and unit tests to verify the new
  `PhosphorIcon` support.
- Updates existing WB packages to use the new `IconButton` API (Banner,
  Modal, Popover, SearchField).

**NOTE:** The plan is to replace all `IconButton` instances in webapp after this PR is landed.

Issue: WB-1612

## Test plan:

Verify that the `IconButton` stories and unit tests are passing. Also verify the
visual changes in Chromatic.


https://github.com/Khan/wonder-blocks/assets/843075/5a5c8ba1-3858-42c0-8791-085cf819ffda

Author: jandrade

Reviewers: jandrade, jeresig

Required Reviewers:

Approved By: jeresig

Checks: ✅ Chromatic - Get results on non-draft regular PRs (ubuntu-latest, 16.x), ✅ codecov/project, ✅ Test (ubuntu-latest, 16.x, 2/2), ✅ Check build sizes (ubuntu-latest, 16.x), ✅ Test (ubuntu-latest, 16.x, 1/2), ✅ Lint (ubuntu-latest, 16.x), ✅ Chromatic - Build on non-draft regular PRs / chromatic (ubuntu-latest, 16.x), ✅ Prime node_modules cache for primary configuration (ubuntu-latest, 16.x), ⏭  Chromatic - Skip on Release PR (changesets), ✅ Publish npm snapshot (ubuntu-latest, 16.x), ⏭  dependabot, ✅ gerald, ✅ Check for .changeset entries for all changed files (ubuntu-latest, 16.x)

Pull Request URL: #2067
  • Loading branch information
jandrade authored Sep 29, 2023
1 parent c1e0483 commit cc6b195
Show file tree
Hide file tree
Showing 24 changed files with 1,155 additions and 1,186 deletions.
8 changes: 8 additions & 0 deletions .changeset/strange-spiders-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@khanacademy/wonder-blocks-search-field": patch
"@khanacademy/wonder-blocks-popover": patch
"@khanacademy/wonder-blocks-banner": patch
"@khanacademy/wonder-blocks-modal": patch
---

Switch internal `IconButton` instances to use phosphor.
5 changes: 5 additions & 0 deletions .changeset/tasty-deers-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@khanacademy/wonder-blocks-icon-button": major
---

Change `icon` type to use `PhosphorIcon` (instead of `Icon`).
6 changes: 3 additions & 3 deletions __docs__/wonder-blocks-icon-button/icon-button.argtypes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {icons} from "@khanacademy/wonder-blocks-icon";
import {IconMappings} from "../wonder-blocks-icon/phosphor-icon.argtypes";

export default {
color: {
Expand Down Expand Up @@ -26,8 +26,8 @@ export default {
control: {
type: "select",
},
description: "Icon to use.",
options: icons,
description: "A Phosphor icon asset (imported as a static SVG file).",
options: IconMappings,
},
kind: {
control: {
Expand Down
131 changes: 79 additions & 52 deletions __docs__/wonder-blocks-icon-button/icon-button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,61 @@ import {StyleSheet} from "aphrodite";
import {action} from "@storybook/addon-actions";
import type {Meta, StoryObj} from "@storybook/react";

import caretLeft from "@phosphor-icons/core/regular/caret-left.svg";
import caretRight from "@phosphor-icons/core/regular/caret-right.svg";
import info from "@phosphor-icons/core/regular/info.svg";
import magnifyingGlass from "@phosphor-icons/core/regular/magnifying-glass.svg";
import magnifyingGlassBold from "@phosphor-icons/core/bold/magnifying-glass-bold.svg";

import Color from "@khanacademy/wonder-blocks-color";
import {View} from "@khanacademy/wonder-blocks-core";
import {icons} from "@khanacademy/wonder-blocks-icon";
import {LabelMedium} from "@khanacademy/wonder-blocks-typography";
import {Strut} from "@khanacademy/wonder-blocks-layout";
import Spacing from "@khanacademy/wonder-blocks-spacing";
import IconButton from "@khanacademy/wonder-blocks-icon-button";

import ComponentInfo from "../../.storybook/components/component-info";
import packageConfig from "../../packages/wonder-blocks-icon-button/package.json";
import IconButtonArgtypes from "./icon-button.argtypes";

/**
* An `IconButton` is a button whose contents are an SVG image.
*
* To use, supply an `onClick` function, a Phosphor icon asset (see the
* `Icon>PhosphorIcon` section) and an `aria-label` to describe the button
* functionality. Optionally specify href (URL), clientSideNav, color (Wonder
* Blocks Blue or Red), kind ("primary", "secondary", or "tertiary"), light
* (whether the IconButton will be rendered on a dark background), disabled ,
* test ID, and custom styling.
*
* The size of an `IconButton` is based on how the `size` prop is defined (see
* `Sizes` below for more details). The focus ring which is displayed on hover
* and focus is much larger but does not affect its size. This matches the
* behavior of Button.
*
* IconButtons require a certain amount of space between them to ensure the
* focus rings don't overlap. The minimum amount of spacing is 16px, but you
* should refer to the mocks provided by design. Using a Strut in between
* IconButtons is the preferred way to for adding this spacing.
*
* Many layouts require alignment of visual left (or right) side of an
* `IconButton`. This requires a little bit of pixel nudging since each icon as
* a different amount of internal padding.
*
* See the Toolbar documentation for examples of `IconButton` use that follow
* the best practices described above.
*
* ```js
* import magnifyingGlassIcon from "@phosphor-icons/core/regular/magnifying-glass.svg";
* import IconButton from "@khanacademy/wonder-blocks-icon-button";
*
* <IconButton
* icon={magnifyingGlassIcon}
* aria-label="An Icon"
* onClick={(e) => console.log("Hello, world!")}
* size="medium"
* />
* ```
*/
export default {
title: "IconButton",
component: IconButton,
Expand All @@ -32,9 +75,13 @@ export default {

type StoryComponentType = StoryObj<typeof IconButton>;

/**
* Minimal icon button. The only props specified in this example are `icon` and
* `onClick`.
*/
export const Default: StoryComponentType = {
args: {
icon: icons.search,
icon: magnifyingGlass,
color: "default",
disabled: false,
kind: "primary",
Expand All @@ -47,61 +94,41 @@ export const Default: StoryComponentType = {
},
};

export const Basic: StoryComponentType = () => {
return (
<IconButton icon={icons.search} onClick={() => console.log("Click!")} />
);
};

Basic.parameters = {
docs: {
description: {
story: `Minimal icon button. The only props specified in
this example are \`icon\` and \`onClick\`.`,
},
},
};

/**
* Icon buttons can be one of three sizes: `xsmall` (16px icon with a 24px touch target),
* `small` (24px icon with a 32px touch target), and `medium` (24px icon with a 40px touch target).
* The default size is `medium`.
* IconButtons can be used with any icon from the `@phosphor-icons/core`
* package. The `icon` prop takes an SVG asset from the package.
*
* In this example you can see the different sizes of the icon button:
* - `xsmall` (16px icon with a 24px touch target).
* - `small` (24px icon with a 32px touch target).
* - `medium` (24px icon with a 40px touch target).
*/
export const Sizes: StoryComponentType = (() => {
return (
<View style={{flexDirection: "column"}}>
export const Sizes: StoryComponentType = {
...Default,
args: {
icon: magnifyingGlass,
},
render: (args) => (
<View style={{gap: Spacing.medium_16}}>
<View style={styles.row}>
<LabelMedium style={styles.label}>xsmall</LabelMedium>
<IconButton
icon={icons.search}
{...args}
icon={magnifyingGlassBold}
size="xsmall"
aria-label="search"
onClick={(e) => console.log("Click!")}
/>
</View>
<Strut size={Spacing.large_24} />
<View style={styles.row}>
<LabelMedium style={styles.label}>small</LabelMedium>
<IconButton
icon={icons.search}
size="small"
aria-label="search"
onClick={(e) => console.log("Click!")}
/>
<IconButton {...args} size="small" />
</View>
<Strut size={Spacing.large_24} />
<View style={styles.row}>
<LabelMedium style={styles.label}>medium</LabelMedium>
<IconButton
icon={icons.search}
size="medium"
aria-label="search"
onClick={(e) => console.log("Click!")}
/>
<IconButton {...args} size="medium" />
</View>
</View>
);
}) as StoryComponentType;
),
};

/**
* In this example, we have primary, secondary, tertiary,
Expand All @@ -112,25 +139,25 @@ export const Variants: StoryComponentType = {
return (
<View style={styles.row}>
<IconButton
icon={icons.search}
icon={magnifyingGlass}
aria-label="search"
onClick={(e) => console.log("Click!")}
/>
<IconButton
icon={icons.search}
icon={magnifyingGlass}
aria-label="search"
kind="secondary"
onClick={(e) => console.log("Click!")}
/>
<IconButton
icon={icons.search}
icon={magnifyingGlass}
aria-label="search"
kind="tertiary"
onClick={(e) => console.log("Click!")}
/>
<IconButton
disabled={true}
icon={icons.search}
icon={magnifyingGlass}
aria-label="search"
onClick={(e) => console.log("Click!")}
/>
Expand All @@ -148,7 +175,7 @@ export const Light: StoryComponentType = {
return (
<View style={styles.dark}>
<IconButton
icon={icons.search}
icon={magnifyingGlass}
aria-label="search"
light={true}
onClick={(e) => console.log("Click!")}
Expand All @@ -167,7 +194,7 @@ export const DisabledLight: StoryComponentType = {
<View style={styles.dark}>
<IconButton
disabled={true}
icon={icons.search}
icon={magnifyingGlass}
aria-label="search"
light={true}
onClick={(e) => console.log("Click!")}
Expand All @@ -187,7 +214,7 @@ export const UsingHref: StoryComponentType = {
render: () => {
return (
<IconButton
icon={icons.info}
icon={info}
aria-label="More information"
href="/"
target="_blank"
Expand All @@ -206,12 +233,12 @@ export const WithAriaLabel: StoryComponentType = {
return (
<View style={styles.arrowsWrapper}>
<IconButton
icon={icons.caretLeft}
icon={caretLeft}
onClick={(e) => console.log("Click!")}
aria-label="Previous page"
/>
<IconButton
icon={icons.caretRight}
icon={caretRight}
onClick={(e) => console.log("Click!")}
aria-label="Next page"
/>
Expand Down
Loading

0 comments on commit cc6b195

Please sign in to comment.