From be1805368331702da32ee1b6d0afcc4058d2cefd Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Wed, 15 Nov 2023 17:28:57 -0500 Subject: [PATCH 1/8] Add custom icon support in PhosphorIcon --- .changeset/dirty-eyes-rhyme.md | 5 ++ .changeset/fifty-cherries-draw.md | 5 ++ __docs__/wonder-blocks-icon/icons/article.svg | 3 + __docs__/wonder-blocks-icon/icons/course.svg | 4 + __docs__/wonder-blocks-icon/icons/crown.svg | 3 + .../icons/mastery-course-bold.svg | 3 + .../icons/mastery-course.svg | 3 + .../phosphor-icon.stories.tsx | 79 ++++++++++++++----- .../src/components/banner.tsx | 7 +- .../components/__tests__/custom-icon-mock.svg | 1 + .../__tests__/phosphor-icon.test.tsx | 14 ++++ .../__tests__/phosphor-icon.typestest.tsx | 6 +- .../src/components/phosphor-icon.tsx | 50 +----------- packages/wonder-blocks-icon/src/index.ts | 6 +- packages/wonder-blocks-icon/src/types.ts | 8 -- types/assets.d.ts | 1 + 16 files changed, 108 insertions(+), 90 deletions(-) create mode 100644 .changeset/dirty-eyes-rhyme.md create mode 100644 .changeset/fifty-cherries-draw.md create mode 100644 __docs__/wonder-blocks-icon/icons/article.svg create mode 100644 __docs__/wonder-blocks-icon/icons/course.svg create mode 100644 __docs__/wonder-blocks-icon/icons/crown.svg create mode 100644 __docs__/wonder-blocks-icon/icons/mastery-course-bold.svg create mode 100644 __docs__/wonder-blocks-icon/icons/mastery-course.svg create mode 100644 packages/wonder-blocks-icon/src/components/__tests__/custom-icon-mock.svg diff --git a/.changeset/dirty-eyes-rhyme.md b/.changeset/dirty-eyes-rhyme.md new file mode 100644 index 000000000..0a7ed9daa --- /dev/null +++ b/.changeset/dirty-eyes-rhyme.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/wonder-blocks-banner": patch +--- + +Modified Banner props to accept any icon weight in its type diff --git a/.changeset/fifty-cherries-draw.md b/.changeset/fifty-cherries-draw.md new file mode 100644 index 000000000..c7bb1e104 --- /dev/null +++ b/.changeset/fifty-cherries-draw.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/wonder-blocks-icon": major +--- + +Remove size/weight restriction from PhosphorIcon and remove some exported types from the package. diff --git a/__docs__/wonder-blocks-icon/icons/article.svg b/__docs__/wonder-blocks-icon/icons/article.svg new file mode 100644 index 000000000..8cda3562a --- /dev/null +++ b/__docs__/wonder-blocks-icon/icons/article.svg @@ -0,0 +1,3 @@ + + + diff --git a/__docs__/wonder-blocks-icon/icons/course.svg b/__docs__/wonder-blocks-icon/icons/course.svg new file mode 100644 index 000000000..41b307825 --- /dev/null +++ b/__docs__/wonder-blocks-icon/icons/course.svg @@ -0,0 +1,4 @@ + + + + diff --git a/__docs__/wonder-blocks-icon/icons/crown.svg b/__docs__/wonder-blocks-icon/icons/crown.svg new file mode 100644 index 000000000..63898f56b --- /dev/null +++ b/__docs__/wonder-blocks-icon/icons/crown.svg @@ -0,0 +1,3 @@ + + + diff --git a/__docs__/wonder-blocks-icon/icons/mastery-course-bold.svg b/__docs__/wonder-blocks-icon/icons/mastery-course-bold.svg new file mode 100644 index 000000000..242813cfe --- /dev/null +++ b/__docs__/wonder-blocks-icon/icons/mastery-course-bold.svg @@ -0,0 +1,3 @@ + + + diff --git a/__docs__/wonder-blocks-icon/icons/mastery-course.svg b/__docs__/wonder-blocks-icon/icons/mastery-course.svg new file mode 100644 index 000000000..c66971ed5 --- /dev/null +++ b/__docs__/wonder-blocks-icon/icons/mastery-course.svg @@ -0,0 +1,3 @@ + + + diff --git a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx index 8a861fe16..c67dd018a 100644 --- a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx +++ b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx @@ -2,9 +2,19 @@ import * as React from "react"; import {StyleSheet} from "aphrodite"; import type {Meta, StoryObj} from "@storybook/react"; +import articleIcon from "./icons/article.svg"; +import courseIcon from "./icons/course.svg"; +import crownIcon from "./icons/crown.svg"; +import masteryCourseIcon from "./icons/mastery-course.svg"; +import masteryCourseIconBold from "./icons/mastery-course-bold.svg"; + import Banner from "@khanacademy/wonder-blocks-banner"; import {addStyle, View} from "@khanacademy/wonder-blocks-core"; -import {Body, LabelMedium} from "@khanacademy/wonder-blocks-typography"; +import { + Body, + HeadingSmall, + LabelMedium, +} from "@khanacademy/wonder-blocks-typography"; import {PhosphorIcon} from "@khanacademy/wonder-blocks-icon"; import {tokens} from "@khanacademy/wonder-blocks-theming"; @@ -92,9 +102,12 @@ export const Default: StoryComponentType = { * available sizes are `"small"`, `"medium"`, `"large"`, and `"xlarge"`. * * __IMPORTANT NOTES:__ - * - `small` size icons only support `bold` and `fill` weights. - * - `medium` size icons only support `regular` and `fill` weights. - * - `large` and `xlarge` size icons support all weights. + * It's up to the consumer to make sure that the icon is legible at the + * specified size. For example, the `magnifyingGlassRegular` icon is not legible + * at the `"small"` size. + * - `small` size icons are recommended to use `bold` or `fill` weights. + * - `medium` size icons are recommended `regular` or `fill` weights. + * - `large` and `xlarge` size work well with all weights. */ export const Sizes: StoryComponentType = { render: () => { @@ -270,28 +283,52 @@ export const Inline: StoryComponentType = { }, }; -// TODO(WB-1611): Need to figure out how to use custom icons. /** * Icons can be customized by passing in a custom icon. * - * The icon should be an object with a size-related property (`small | medium | - * large | xlarge`) that is a string containing the path data for the icon. + * The icon should be an SVG file imported as a static asset. You can take a + * look at the source file of any of the following icons to see how they are + * generated. + * + * ```tsx + * // This SVG should have the following attributes: + * // - viewBox="0 0 256 256" + * // - fill="currentColor" + * // - A path (or paths) scaled up to fit in the 256x256 viewport. + * + * import crownIcon from "./icons/crown.svg"; + * + * ``` + * + * __NOTE:__ If you want to know how to create a custom icon, check out the + * [Exporting icon assets - + * Web](https://khanacademy.atlassian.net/wiki/x/SwD6gg#Web) section. */ -// export const CustomIcon: StoryComponentType = () => { -// const share: IconAsset = { -// medium: "M12.5 4.25C12.5 3.14543 13.3954 2.25 14.5 2.25C15.6046 2.25 16.5 3.14543 16.5 4.25C16.5 5.35457 15.6046 6.25 14.5 6.25C13.8117 6.25 13.2046 5.90228 12.8447 5.37291C12.8367 5.3589 12.8282 5.34502 12.8194 5.33126C12.8102 5.31696 12.8007 5.30297 12.7909 5.28929C12.6063 4.98641 12.5 4.63062 12.5 4.25ZM14.5 8.25C13.4511 8.25 12.4966 7.8463 11.7832 7.18581L7.79943 9.7458C7.92958 10.1403 8 10.5619 8 11C8 11.4381 7.92958 11.8597 7.79943 12.2542L11.7832 14.8142C12.4966 14.1537 13.4511 13.75 14.5 13.75C16.7091 13.75 18.5 15.5409 18.5 17.75C18.5 19.9591 16.7091 21.75 14.5 21.75C12.2909 21.75 10.5 19.9591 10.5 17.75C10.5 17.3119 10.5704 16.8903 10.7006 16.4958L6.71681 13.9358C6.00342 14.5963 5.04885 15 4 15C1.79086 15 0 13.2091 0 11C0 8.79086 1.79086 7 4 7C5.04885 7 6.00342 7.40369 6.71681 8.06417L10.7006 5.50416C10.5704 5.10969 10.5 4.68807 10.5 4.25C10.5 2.04086 12.2909 0.25 14.5 0.25C16.7091 0.25 18.5 2.04086 18.5 4.25C18.5 6.45914 16.7091 8.25 14.5 8.25ZM5.70939 12.0388C5.69949 12.0526 5.68988 12.0668 5.68058 12.0813C5.67164 12.0952 5.6631 12.1092 5.65493 12.1234C5.29508 12.6525 4.68812 13 4 13C2.89543 13 2 12.1046 2 11C2 9.8954 2.89543 9 4 9C4.68812 9 5.29507 9.3475 5.65493 9.8766C5.66309 9.8908 5.67164 9.9048 5.68058 9.9187C5.68988 9.9332 5.69949 9.9474 5.7094 9.9612C5.89379 10.264 6 10.6196 6 11C6 11.3804 5.89379 11.736 5.70939 12.0388ZM12.7909 16.7107C12.6063 17.0136 12.5 17.3694 12.5 17.75C12.5 18.8546 13.3954 19.75 14.5 19.75C15.6046 19.75 16.5 18.8546 16.5 17.75C16.5 16.6454 15.6046 15.75 14.5 15.75C13.8117 15.75 13.2046 16.0977 12.8447 16.6271C12.8367 16.6411 12.8282 16.655 12.8194 16.6687C12.8102 16.683 12.8007 16.697 12.7909 16.7107Z", -// }; +export const CustomIcons: StoryComponentType = { + render: () => { + const customIcoms = { + article: articleIcon, + course: courseIcon, + crown: crownIcon, + masteryCourse: masteryCourseIcon, + masteryCourseBold: masteryCourseIconBold, + }; -// return ( -// -// ); -// }; + return ( + + {Object.entries(customIcoms).map(([name, icon], index) => ( + + {name} + + + + + + ))} + + ); + }, +}; const styles = StyleSheet.create({ container: { diff --git a/packages/wonder-blocks-banner/src/components/banner.tsx b/packages/wonder-blocks-banner/src/components/banner.tsx index 5fc05521e..9801ec773 100644 --- a/packages/wonder-blocks-banner/src/components/banner.tsx +++ b/packages/wonder-blocks-banner/src/components/banner.tsx @@ -6,10 +6,7 @@ import xIcon from "@phosphor-icons/core/regular/x.svg"; import Button from "@khanacademy/wonder-blocks-button"; import Color from "@khanacademy/wonder-blocks-color"; import {View} from "@khanacademy/wonder-blocks-core"; -import { - PhosphorIcon, - PhosphorIconMedium, -} from "@khanacademy/wonder-blocks-icon"; +import {PhosphorIcon, PhosphorIconAsset} from "@khanacademy/wonder-blocks-icon"; import IconButton from "@khanacademy/wonder-blocks-icon-button"; import Link from "@khanacademy/wonder-blocks-link"; import Spacing from "@khanacademy/wonder-blocks-spacing"; @@ -77,7 +74,7 @@ type BannerLayout = type BannerValues = { color: string; - icon: PhosphorIconMedium; + icon: PhosphorIconAsset; role: "status" | "alert"; ariaLive?: "assertive" | "polite"; }; diff --git a/packages/wonder-blocks-icon/src/components/__tests__/custom-icon-mock.svg b/packages/wonder-blocks-icon/src/components/__tests__/custom-icon-mock.svg new file mode 100644 index 000000000..a5c74ae03 --- /dev/null +++ b/packages/wonder-blocks-icon/src/components/__tests__/custom-icon-mock.svg @@ -0,0 +1 @@ +this is a custom svg \ No newline at end of file diff --git a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx index c4f5e78d1..049894525 100644 --- a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx +++ b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx @@ -3,6 +3,8 @@ import {render, screen} from "@testing-library/react"; import Plus from "@phosphor-icons/core/regular/plus.svg"; import PlusBold from "@phosphor-icons/core/bold/plus-bold.svg"; +// mock out the custom icon +import customIcon from "./custom-icon-mock.svg"; import {PhosphorIcon} from "../phosphor-icon"; import * as utils from "../../util/icon-util"; @@ -120,4 +122,16 @@ describe("PhosphorIcon", () => { `mask-image: url(${Plus});`, ); }); + + it("allows importing an arbitrary SVG file (custom icon)", async () => { + // Arrange + + // Act + render(); + + // Assert + expect(screen.getByTestId("phosphor-icon")).toHaveStyle( + `mask-image: url(${customIcon});`, + ); + }); }); diff --git a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx index 79d4b812e..560b5daca 100644 --- a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx +++ b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx @@ -18,10 +18,8 @@ import {PhosphorIcon} from "../phosphor-icon"; // Valid: large + fill ; -// Invalid: small + regular -// @ts-expect-error - small icons only support `bold` and `fill` weights. +// Valid: small + regular ; -// Invalid: medium + bold -// @ts-expect-error - medium icons only support `regular` and `fill` weights. +// Valid: medium + bold ; diff --git a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx index f750a0261..5173170c6 100644 --- a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx +++ b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx @@ -4,17 +4,13 @@ import {StyleSheet} from "aphrodite"; import {addStyle, AriaProps, StyleType} from "@khanacademy/wonder-blocks-core"; import {viewportPixelsForSize} from "../util/icon-util"; -import { - PhosphorIconAsset, - PhosphorIconMedium, - PhosphorIconSmall, -} from "../types"; +import {PhosphorIconAsset} from "../types"; // We use a span instead of an img because we want to use the mask-image CSS // property. const StyledIcon = addStyle("span"); -type CommonProps = Pick & { +type Props = Pick & { /** * The color of the icon. Will default to `currentColor`, which means that * it will take on the CSS `color` value from the parent element. @@ -32,46 +28,9 @@ type CommonProps = Pick & { * Test ID used for e2e testing. */ testId?: string; -}; -type PropsForSmallIcon = CommonProps & { - /** - * The icon size (16px). - * - * __NOTE:__ small icons only support `bold` and `fill` weights. **Make sure - * you are not using a `regular` icon.** - */ - size?: "small"; - /** - * The icon to display. This is a reference to the icon asset - * (imported as a static SVG file). - * __NOTE:__ small icons only support `bold` and `fill` weights. - */ - icon: PhosphorIconSmall; -}; + size?: "small" | "medium" | "large" | "xlarge"; -type PropsForMediumIcon = CommonProps & { - /** - * The icon size (24px). Defaults to `medium`. - * - * __NOTE:__ medium icons only support `regular` and `fill` weights. **Make - * sure you are not using a `bold` icon.** - */ - size?: "medium"; - /** - * The icon to display. This is a reference to the icon asset - * (imported as a static SVG file). - * __NOTE:__ medium icons only support `regular` and `fill` weights. - */ - icon: PhosphorIconMedium; -}; - -type PropsForOtherSizes = CommonProps & { - /** - * large: The icon size (48px). - * xlarge: The icon size (96px). - */ - size?: "large" | "xlarge"; /** * The icon to display. This is a reference to the icon asset * (imported as a static SVG file). @@ -79,9 +38,6 @@ type PropsForOtherSizes = CommonProps & { icon: PhosphorIconAsset; }; -// Define icon size by icon weight -type Props = PropsForSmallIcon | PropsForMediumIcon | PropsForOtherSizes; - /** * A `PhosphorIcon` displays a small informational or decorative image as an * HTML element that renders a Phosphor Icon SVG available from the diff --git a/packages/wonder-blocks-icon/src/index.ts b/packages/wonder-blocks-icon/src/index.ts index 540ee5cbb..b72242bf0 100644 --- a/packages/wonder-blocks-icon/src/index.ts +++ b/packages/wonder-blocks-icon/src/index.ts @@ -3,10 +3,6 @@ import type {IconAsset, IconSize} from "./util/icon-assets"; export * as icons from "./util/icon-assets"; export {PhosphorIcon} from "./components/phosphor-icon"; -export type { - PhosphorIconAsset, - PhosphorIconMedium, - PhosphorIconSmall, -} from "./types"; +export type {PhosphorIconAsset} from "./types"; export type {IconAsset, IconSize}; export default Icon; diff --git a/packages/wonder-blocks-icon/src/types.ts b/packages/wonder-blocks-icon/src/types.ts index 3ceead408..a1fe2e194 100644 --- a/packages/wonder-blocks-icon/src/types.ts +++ b/packages/wonder-blocks-icon/src/types.ts @@ -2,11 +2,3 @@ * All the possible icon weights. */ export type PhosphorIconAsset = PhosphorRegular | PhosphorBold | PhosphorFill; -/** - * The different icon weights for small icons. - */ -export type PhosphorIconSmall = PhosphorBold | PhosphorFill; -/** - * The different icon weights for medium icons. - */ -export type PhosphorIconMedium = PhosphorRegular | PhosphorFill; diff --git a/types/assets.d.ts b/types/assets.d.ts index 0e1cde0e1..70fa229b8 100644 --- a/types/assets.d.ts +++ b/types/assets.d.ts @@ -5,6 +5,7 @@ */ declare module "*.jpg"; declare module "*.png"; +declare module "*.svg"; // Support specific SVG paths from @phosphor-icons/core. declare type PhosphorRegular = string & {weight: "PhosphorRegular"}; From 2634dca4027343171417fb1ff269cd022b951891 Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Wed, 15 Nov 2023 17:40:20 -0500 Subject: [PATCH 2/8] Fix type test --- .../src/components/__tests__/phosphor-icon.typestest.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx index 560b5daca..1a53b5e16 100644 --- a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx +++ b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.typestest.tsx @@ -3,10 +3,6 @@ import PlusCircleRegular from "@phosphor-icons/core/regular/plus-circle.svg"; import PlusCircleBold from "@phosphor-icons/core/bold/plus-circle-bold.svg"; import PlusCircleFill from "@phosphor-icons/core/fill/plus-circle-fill.svg"; -// @ts-expect-error - invalid icon weight (duotone) -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import VideoDuoTone from "@phosphor-icons/core/duotone/video-duotone.svg"; - import {PhosphorIcon} from "../phosphor-icon"; // Valid: small + bold From 54c17ed1d78878aeb1222942cc23f98179dcbfc7 Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Wed, 15 Nov 2023 19:17:08 -0500 Subject: [PATCH 3/8] Simplify SVG types --- types/assets.d.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/types/assets.d.ts b/types/assets.d.ts index 70fa229b8..20b03b089 100644 --- a/types/assets.d.ts +++ b/types/assets.d.ts @@ -6,22 +6,3 @@ declare module "*.jpg"; declare module "*.png"; declare module "*.svg"; - -// Support specific SVG paths from @phosphor-icons/core. -declare type PhosphorRegular = string & {weight: "PhosphorRegular"}; -declare module "@phosphor-icons/core/regular/*.svg" { - const icon: PhosphorRegular; - export default icon; -} - -declare type PhosphorBold = string & {weight: "PhosphorBold"}; -declare module "@phosphor-icons/core/bold/*-bold.svg" { - const icon: PhosphorBold; - export default icon; -} - -declare type PhosphorFill = string & {weight: "PhosphorFill"}; -declare module "@phosphor-icons/core/fill/*-fill.svg" { - const icon: PhosphorFill; - export default icon; -} From ad069a4a462b709882af1fc32955ebe8e96379fe Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Wed, 15 Nov 2023 19:35:11 -0500 Subject: [PATCH 4/8] Revert simplifying types and add 'string' as valid option --- .../src/components/phosphor-icon.tsx | 2 +- types/assets.d.ts | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx index 5173170c6..ed4ae4c5f 100644 --- a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx +++ b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx @@ -35,7 +35,7 @@ type Props = Pick & { * The icon to display. This is a reference to the icon asset * (imported as a static SVG file). */ - icon: PhosphorIconAsset; + icon: PhosphorIconAsset | string; }; /** diff --git a/types/assets.d.ts b/types/assets.d.ts index 20b03b089..d0fa8b4d5 100644 --- a/types/assets.d.ts +++ b/types/assets.d.ts @@ -5,4 +5,25 @@ */ declare module "*.jpg"; declare module "*.png"; + +// Support specific SVG paths from @phosphor-icons/core. +declare type PhosphorRegular = string & {weight: "PhosphorRegular"}; +declare module "@phosphor-icons/core/regular/*.svg" { + const icon: PhosphorRegular; + export default icon; +} + +declare type PhosphorBold = string & {weight: "PhosphorBold"}; +declare module "@phosphor-icons/core/bold/*-bold.svg" { + const icon: PhosphorBold; + export default icon; +} + +declare type PhosphorFill = string & {weight: "PhosphorFill"}; +declare module "@phosphor-icons/core/fill/*-fill.svg" { + const icon: PhosphorFill; + export default icon; +} + +// Fall back to generic SVG support. declare module "*.svg"; From 3fffa665fe095bb76d817c180fb9db9ceb1912aa Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Thu, 16 Nov 2023 13:15:11 -0500 Subject: [PATCH 5/8] Apply suggestions from code review Co-authored-by: Nisha Yerunkar --- __docs__/wonder-blocks-icon/phosphor-icon.stories.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx index c67dd018a..2b8a23267 100644 --- a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx +++ b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx @@ -105,9 +105,9 @@ export const Default: StoryComponentType = { * It's up to the consumer to make sure that the icon is legible at the * specified size. For example, the `magnifyingGlassRegular` icon is not legible * at the `"small"` size. - * - `small` size icons are recommended to use `bold` or `fill` weights. - * - `medium` size icons are recommended `regular` or `fill` weights. - * - `large` and `xlarge` size work well with all weights. + * - `small` size icons are recommended for use with `bold` or `fill` weights. + * - `medium` size icons are recommended for use with `regular` or `fill` weights. + * - `large` and `xlarge` size icons work well with all weights. */ export const Sizes: StoryComponentType = { render: () => { From 3dedbaa5850f0143703e62ed0e6f26b49d4f45b5 Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Thu, 16 Nov 2023 14:21:43 -0500 Subject: [PATCH 6/8] Improve docs, fix style prop --- .../phosphor-icon.argtypes.ts | 8 +++- .../phosphor-icon.stories.tsx | 7 ++- .../__tests__/phosphor-icon.test.tsx | 6 +-- .../src/components/phosphor-icon.tsx | 46 +++++++++++++++---- 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts b/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts index 2f801c700..45ea6aaa5 100644 --- a/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts +++ b/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts @@ -104,7 +104,11 @@ export const IconMappings = { export default { icon: { description: - "The icon to display. This is a reference to the icon asset (imported as a static SVG file). `small` size should use a `bold` icon, and `medium` size should use a `regular` icon.", + `The icon to display. This is a reference to the icon asset ` + + `(imported as a static SVG file).\n\n` + + `It supports the following types:\n` + + `- \`PhosphorIconAsset\`: a reference to a Phosphor SVG asset.\n` + + `- \`string\`: an import referencing an arbitrary SVG file.`, options: Object.keys(IconMappings), mapping: IconMappings, type: { @@ -114,7 +118,7 @@ export default { }, table: { type: { - summary: "string", + summary: "PhosphorIconAsset | string", }, }, }, diff --git a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx index 2b8a23267..b4f5872a2 100644 --- a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx +++ b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx @@ -274,7 +274,7 @@ export const Inline: StoryComponentType = { when it is inline. @@ -353,4 +353,9 @@ const styles = StyleSheet.create({ border: `${tokens.border.width.hairline}px solid ${tokens.color.offBlack}`, padding: tokens.spacing.medium_16, }, + inline: { + margin: tokens.spacing.xxxxSmall_2, + width: 50, + height: 50, + }, }); diff --git a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx index 049894525..319023ee8 100644 --- a/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx +++ b/packages/wonder-blocks-icon/src/components/__tests__/phosphor-icon.test.tsx @@ -93,7 +93,7 @@ describe("PhosphorIcon", () => { it("applies style prop", async () => { // Arrange const expectedStyle = { - display: "none", + width: 30, } as const; // Act @@ -106,9 +106,7 @@ describe("PhosphorIcon", () => { ); // Assert - expect(screen.getByTestId("phosphor-icon")).toHaveStyle( - "display: none;", - ); + expect(screen.getByTestId("phosphor-icon")).toHaveStyle("width: 30px"); }); it("includes SVG using the maskImage css attribute", async () => { diff --git a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx index ed4ae4c5f..02069ca7b 100644 --- a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx +++ b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx @@ -32,8 +32,12 @@ type Props = Pick & { size?: "small" | "medium" | "large" | "xlarge"; /** - * The icon to display. This is a reference to the icon asset - * (imported as a static SVG file). + * The icon to display. This is a reference to the icon asset (imported as a + * static SVG file). + * + * It supports the following types: + * - `PhosphorIconAsset`: a reference to a Phosphor SVG asset. + * - `string`: an import referencing an arbitrary SVG file. */ icon: PhosphorIconAsset | string; }; @@ -79,6 +83,7 @@ export const PhosphorIcon = React.forwardRef(function PhosphorIcon( const pixelSize = viewportPixelsForSize(size); const classNames = `${className ?? ""}`; + const iconStyles = _generateStyles(color, pixelSize); return ( = {}; + +/** + * Generates the visual styles for the icon. + */ +const _generateStyles = (color: string, size: number) => { + const iconStyle = `${color}-${size}`; + // The styles are cached to avoid creating a new object on every render. + if (styles[iconStyle]) { + return styles[iconStyle]; + } + + const newStyles: Record = { + icon: { + backgroundColor: color, + width: size, + height: size, + }, + }; + + dynamicStyles[iconStyle] = StyleSheet.create(newStyles); + return dynamicStyles[iconStyle]; +}; + const styles = StyleSheet.create({ svg: { display: "inline-block", verticalAlign: "text-bottom", flexShrink: 0, flexGrow: 0, + maskSize: "100%", + maskRepeat: "no-repeat", + maskPosition: "center", }, }); From 36b61b89d4ecfb134e7bbb01815e59b244830d7c Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Thu, 16 Nov 2023 14:23:58 -0500 Subject: [PATCH 7/8] Fix story --- __docs__/wonder-blocks-icon/phosphor-icon.stories.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx index b4f5872a2..b32e1370b 100644 --- a/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx +++ b/__docs__/wonder-blocks-icon/phosphor-icon.stories.tsx @@ -355,7 +355,5 @@ const styles = StyleSheet.create({ }, inline: { margin: tokens.spacing.xxxxSmall_2, - width: 50, - height: 50, }, }); From 2e33cfc1ca2f9e19567693417db044cc621fe2ea Mon Sep 17 00:00:00 2001 From: Juan Andrade Date: Wed, 22 Nov 2023 13:39:15 -0500 Subject: [PATCH 8/8] Add support to role --- .../wonder-blocks-icon/phosphor-icon.argtypes.ts | 13 +++++++++++++ .../src/components/phosphor-icon.tsx | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts b/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts index 45ea6aaa5..90bf0c6d4 100644 --- a/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts +++ b/__docs__/wonder-blocks-icon/phosphor-icon.argtypes.ts @@ -194,4 +194,17 @@ export default { }, }, }, + role: { + description: "The role of this icon.", + defaultValue: "img", + control: { + type: "text", + }, + table: { + category: "Accessibility", + type: { + summary: "string", + }, + }, + }, } satisfies Record; diff --git a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx index 02069ca7b..6d4a35f0d 100644 --- a/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx +++ b/packages/wonder-blocks-icon/src/components/phosphor-icon.tsx @@ -10,7 +10,7 @@ import {PhosphorIconAsset} from "../types"; // property. const StyledIcon = addStyle("span"); -type Props = Pick & { +type Props = Pick & { /** * The color of the icon. Will default to `currentColor`, which means that * it will take on the CSS `color` value from the parent element.