Skip to content

Commit

Permalink
feat(NumberIcon)!: introduce 2.0 component
Browse files Browse the repository at this point in the history
  • Loading branch information
booc0mtaco committed Mar 13, 2024
1 parent d5782cd commit 5d5c2d2
Show file tree
Hide file tree
Showing 3 changed files with 282 additions and 0 deletions.
92 changes: 92 additions & 0 deletions src/components/NumberIcon/NumberIcon-v2.module.css
Original file line number Diff line number Diff line change
@@ -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;
}
115 changes: 115 additions & 0 deletions src/components/NumberIcon/NumberIcon-v2.stories.tsx
Original file line number Diff line number Diff line change
@@ -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) => <div className="p-8">{Story()}</div>],
} as Meta<Args>;

type Args = React.ComponentProps<typeof NumberIcon>;
type Story = StoryObj<Args>;

export const Default: Story = {};

export const Sizes: Story = {
args: {
status: 'default',
},
render: (args) => {
return (
<>
<NumberIcon number={1} size="sm" {...args} />
<NumberIcon number={2} size="md" {...args} />
<NumberIcon number={3} size="lg" {...args} />
</>
);
},
decorators: [
(Story) => <div className="flex flex-wrap gap-1">{Story()}</div>,
],
};

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) => (
<div>
{[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, 32, 43, 54, 65, 76, 87, 98].map(
(number) => (
<NumberIcon
key={number}
{...args}
aria-label={`Step ${number}`}
number={number}
/>
),
)}
</div>
),
};

/**
* 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: () => (
<div className="flex flex-wrap gap-1">
<NumberIcon aria-label="Item 1" number={1} size="sm" />
<NumberIcon aria-label="Item 2" number={2} size="sm" />
<NumberIcon aria-label="Item 3" number={3} size="sm" />
<NumberIcon aria-label="Item 4" number={4} size="sm" />
<NumberIcon aria-label="Item 5" number={5} size="sm" />
<NumberIcon aria-label="Item 6" number={6} size="sm" />
</div>
),
};
75 changes: 75 additions & 0 deletions src/components/NumberIcon/NumberIcon-v2.tsx
Original file line number Diff line number Diff line change
@@ -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<Size, 'sm' | 'md' | 'lg'>;
/**
* 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 (
<Text
as="span"
className={componentClassName}
preset={['sm', 'md'].includes(size) ? 'caption-sm' : 'caption-lg'}
role="img"
tabIndex={isInteractive ? 0 : -1}
{...other}
>
{number}
</Text>
);
};

NumberIcon.displayName = 'NumberIcon';

0 comments on commit 5d5c2d2

Please sign in to comment.