Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NumberIcon)!: introduce 2.0 component #1891

Merged
merged 2 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/components/NumberIcon/NumberIcon-v2.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@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-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;
}
114 changes: 114 additions & 0 deletions src/components/NumberIcon/NumberIcon-v2.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type { StoryObj, Meta } from '@storybook/react';
import React from 'react';

import { NumberIcon } from './NumberIcon-v2';

export default {
title: 'Components/V2/NumberIcon',
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={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', 'current-2.0', 'implementationExample'],
},
render: () => (
<div className="flex flex-wrap gap-1">
<NumberIcon aria-label="Item 1" number={1} size="md" />
<NumberIcon aria-label="Item 2" number={2} size="md" />
<NumberIcon aria-label="Item 3" number={3} size="md" />
<NumberIcon aria-label="Item 4" number={4} size="md" />
<NumberIcon aria-label="Item 5" number={5} size="md" />
<NumberIcon aria-label="Item 6" number={6} size="md" />
</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, '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';
1 change: 1 addition & 0 deletions src/components/NumberIcon/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { NumberIcon as default } from './NumberIcon';
export { NumberIcon as NumberIconV2 } from './NumberIcon-v2';
Loading