From 5d5c2d2f3ecd99c56c35ac337f0ae3582b22d1bb Mon Sep 17 00:00:00 2001 From: Andrew Holloway Date: Tue, 12 Mar 2024 21:30:23 -0500 Subject: [PATCH 1/2] feat(NumberIcon)!: introduce 2.0 component --- .../NumberIcon/NumberIcon-v2.module.css | 92 ++++++++++++++ .../NumberIcon/NumberIcon-v2.stories.tsx | 115 ++++++++++++++++++ src/components/NumberIcon/NumberIcon-v2.tsx | 75 ++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 src/components/NumberIcon/NumberIcon-v2.module.css create mode 100644 src/components/NumberIcon/NumberIcon-v2.stories.tsx create mode 100644 src/components/NumberIcon/NumberIcon-v2.tsx diff --git a/src/components/NumberIcon/NumberIcon-v2.module.css b/src/components/NumberIcon/NumberIcon-v2.module.css new file mode 100644 index 000000000..8b784ec10 --- /dev/null +++ b/src/components/NumberIcon/NumberIcon-v2.module.css @@ -0,0 +1,92 @@ +@import '../../design-tokens/mixins.css'; +/*------------------------------------*\ + # NUMBER ICON +\*------------------------------------*/ + +/** + * Number Icon displays a number enclosed in a circle. + * + * Centers the number text in the circle. + */ +.number-icon { + /* Line height set to 1 here since this should only ever be on 1 line and it evens out padding in circle. */ + line-height: 1; + display: flex; + justify-content: center; + align-items: center; + + /* The circle part of the icon, made with borders. */ + border: var(--eds-border-width-sm) solid; + border-color: inherit; + border-radius: var(--eds-border-radius-full); + + cursor: pointer; +} + +/** + * Size Variants. + */ +.number-icon--size-sm { + /* Line height set to 1 here since this should only ever be on 1 line and it evens out padding in circle. */ + line-height: 1; + height: 1rem; + width: 1rem; + min-width: 1rem; +} + +.number-icon--size-md { + height: 1.5rem; + width: 1.5rem; + min-width: 1.5rem; +} + +.number-icon--size-lg { + height: 2rem; + width: 2rem; + min-width: 2rem; +} + +/* Colors & Theme */ + +/** + * Interactive States + */ +.number-icon--status-default { + color: var(--eds-theme-color-text-utility-interactive-primary); + border-color: var(--eds-theme-color-border-utility-interactive); + background-color: var(--eds-theme-color-background-utility-interactive-no-emphasis); + + &:hover { + border-color: var(--eds-theme-color-border-utility-interactive-hover); + background-color: var(--eds-theme-color-background-utility-interactive-no-emphasis-hover); + } + + &:active { + border-color: var(--eds-theme-color-border-utility-interactive-active); + background-color: var(--eds-theme-color-background-utility-interactive-no-emphasis-active); + } +} + +.number-icon--status-completed { + color: var(--eds-theme-color-text-utility-inverse); + border-color: var(--eds-theme-color-background-utility-favorable-high-emphasis); + background-color: var(--eds-theme-color-background-utility-favorable-high-emphasis); + + &:hover { + border-color: var(--eds-theme-color-background-utility-favorable-high-emphasis-hover); + background-color: var(--eds-theme-color-background-utility-favorable-high-emphasis-hover); + } + + &:active { + border-color: var(--eds-theme-color-background-utility-favorable-high-emphasis-active); + background-color: var(--eds-theme-color-background-utility-favorable-high-emphasis-active); + } +} + +.number-icon--status-incomplete { + color: var(--eds-theme-color-text-utility-neutral-secondary); + border-color: var(--eds-theme-color-border-utility-neutral-medium-emphasis); + + border-style: dashed; + pointer-events: none; +} \ No newline at end of file diff --git a/src/components/NumberIcon/NumberIcon-v2.stories.tsx b/src/components/NumberIcon/NumberIcon-v2.stories.tsx new file mode 100644 index 000000000..400653ab7 --- /dev/null +++ b/src/components/NumberIcon/NumberIcon-v2.stories.tsx @@ -0,0 +1,115 @@ +import type { StoryObj, Meta } from '@storybook/react'; +import React from 'react'; + +import { NumberIcon } from './NumberIcon-v2'; + +export default { + title: 'Components/NumberIcon (v2)', + component: NumberIcon, + parameters: { + badges: ['intro-1.0', 'current-2.0'], + }, + args: { + 'aria-label': 'number icon example', + number: 1, + }, + decorators: [(Story) =>
{Story()}
], +} as Meta; + +type Args = React.ComponentProps; +type Story = StoryObj; + +export const Default: Story = {}; + +export const Sizes: Story = { + args: { + status: 'default', + }, + render: (args) => { + return ( + <> + + + + + ); + }, + decorators: [ + (Story) =>
{Story()}
, + ], +}; + +export const Completed: Story = { + args: { + ...Sizes.args, + status: 'completed', + }, + render: Sizes.render, + decorators: Sizes.decorators, +}; + +export const Incomplete: Story = { + args: { + ...Sizes.args, + status: 'incomplete', + }, + render: Sizes.render, + decorators: Sizes.decorators, +}; + +/** + * `NumberIcon` supports individual digits, with a maximum of two digits. By default, + * they are positioned as block-level elements. use `flex` or `display` to update positioning. + */ +export const DifferentNumbers: Story = { + /** + * Disables controls for args that have no affect on this story + */ + argTypes: { + number: { + table: { + disable: true, + }, + }, + 'aria-label': { + table: { + disable: true, + }, + }, + }, + render: (args) => ( +
+ {[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, 32, 43, 54, 65, 76, 87, 98].map( + (number) => ( + + ), + )} +
+ ), +}; + +/** + * This Implementation example shows how to use Number Icon to build a stepper-like component. + * + * - incomplete rows are aligned with each number icon to show progress + */ +export const NumberIconList: Story = { + parameters: { + badges: ['intro-1.0', 'implementationExample'], + }, + render: () => ( +
+ + + + + + +
+ ), +}; diff --git a/src/components/NumberIcon/NumberIcon-v2.tsx b/src/components/NumberIcon/NumberIcon-v2.tsx new file mode 100644 index 000000000..ecd5bf833 --- /dev/null +++ b/src/components/NumberIcon/NumberIcon-v2.tsx @@ -0,0 +1,75 @@ +import clsx from 'clsx'; +import React from 'react'; + +import type { Size } from '../../util/variant-types'; + +import Text from '../Text'; +import styles from './NumberIcon-v2.module.css'; + +export interface Props { + // Component API + /** + * (Required) Screen-reader text for the number icon. + */ + 'aria-label': string; + /** + * CSS class names that can be appended to the component. + */ + className?: string; + // Design API + /** + * Whether `NumberIcon` can be focused on, clicked, etc. + */ + isInteractive?: boolean; + /** + * Number to be shown as the icon. Maximum of two digits. + */ + number?: number; + /** + * The size of the icon. + * + * **Default is `"lg"`**. + */ + size?: Extract; + /** + * Indication of the status of the referenced item + */ + status?: 'completed' | 'incomplete' | 'default'; +} + +/** + * `import {NumberIcon} from "@chanzuckerberg/eds";` + * + * Treats a numeral as an icon by wrapping it in a container and adding color/spacing. + * + */ +export const NumberIcon = ({ + className, + isInteractive = false, + number, + status = 'default', + size = 'lg', + ...other +}: Props) => { + const componentClassName = clsx( + className, + styles['number-icon'], + size && styles[`number-icon--size-${size}`], + status && styles[`number-icon--status-${status}`], + ); + + return ( + + {number} + + ); +}; + +NumberIcon.displayName = 'NumberIcon'; From 1a472974c1108d523b080757f1e6511f3372d010 Mon Sep 17 00:00:00 2001 From: Andrew Holloway Date: Fri, 15 Mar 2024 11:18:20 -0500 Subject: [PATCH 2/2] feat(NumberIcon): remove sm size variant - also add export and nesting for V2 storybook --- .../NumberIcon/NumberIcon-v2.module.css | 8 -------- .../NumberIcon/NumberIcon-v2.stories.tsx | 17 ++++++++--------- src/components/NumberIcon/NumberIcon-v2.tsx | 2 +- src/components/NumberIcon/index.ts | 1 + 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/components/NumberIcon/NumberIcon-v2.module.css b/src/components/NumberIcon/NumberIcon-v2.module.css index 8b784ec10..4b1559188 100644 --- a/src/components/NumberIcon/NumberIcon-v2.module.css +++ b/src/components/NumberIcon/NumberIcon-v2.module.css @@ -26,14 +26,6 @@ /** * Size Variants. */ -.number-icon--size-sm { - /* Line height set to 1 here since this should only ever be on 1 line and it evens out padding in circle. */ - line-height: 1; - height: 1rem; - width: 1rem; - min-width: 1rem; -} - .number-icon--size-md { height: 1.5rem; width: 1.5rem; diff --git a/src/components/NumberIcon/NumberIcon-v2.stories.tsx b/src/components/NumberIcon/NumberIcon-v2.stories.tsx index 400653ab7..ddc4deba3 100644 --- a/src/components/NumberIcon/NumberIcon-v2.stories.tsx +++ b/src/components/NumberIcon/NumberIcon-v2.stories.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { NumberIcon } from './NumberIcon-v2'; export default { - title: 'Components/NumberIcon (v2)', + title: 'Components/V2/NumberIcon', component: NumberIcon, parameters: { badges: ['intro-1.0', 'current-2.0'], @@ -28,7 +28,6 @@ export const Sizes: Story = { render: (args) => { return ( <> - @@ -100,16 +99,16 @@ export const DifferentNumbers: Story = { */ export const NumberIconList: Story = { parameters: { - badges: ['intro-1.0', 'implementationExample'], + badges: ['intro-1.0', 'current-2.0', 'implementationExample'], }, render: () => (
- - - - - - + + + + + +
), }; diff --git a/src/components/NumberIcon/NumberIcon-v2.tsx b/src/components/NumberIcon/NumberIcon-v2.tsx index ecd5bf833..a08d35289 100644 --- a/src/components/NumberIcon/NumberIcon-v2.tsx +++ b/src/components/NumberIcon/NumberIcon-v2.tsx @@ -30,7 +30,7 @@ export interface Props { * * **Default is `"lg"`**. */ - size?: Extract; + size?: Extract; /** * Indication of the status of the referenced item */ diff --git a/src/components/NumberIcon/index.ts b/src/components/NumberIcon/index.ts index 27abe5f81..096c360ce 100644 --- a/src/components/NumberIcon/index.ts +++ b/src/components/NumberIcon/index.ts @@ -1 +1,2 @@ export { NumberIcon as default } from './NumberIcon'; +export { NumberIcon as NumberIconV2 } from './NumberIcon-v2';