Skip to content

Commit

Permalink
Migrate Badge component to CSS modules
Browse files Browse the repository at this point in the history
  • Loading branch information
connor-baer committed Jun 26, 2023
1 parent d6eb5b8 commit 29d2b99
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 356 deletions.
46 changes: 46 additions & 0 deletions packages/circuit-ui/components/Badge/Badge.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
.base {
display: inline-block;
padding: 2px var(--cui-spacings-byte);
font-size: var(--cui-typography-body-two-font-size);
font-weight: var(--cui-font-weight-bold);
line-height: var(--cui-typography-body-two-line-height);
text-align: center;
letter-spacing: 0.25px;
border-radius: var(--cui-border-radius-pill);
}

.circle {
display: flex;
align-items: center;
justify-content: center;
width: var(--badge-width);
height: 24px;
padding: 2px 4px;
}

/* Variants */

.success {
color: var(--cui-fg-on-strong);
background-color: var(--cui-bg-success-strong);
}

.warning {
color: var(--cui-fg-on-strong);
background-color: var(--cui-bg-warning-strong);
}

.danger {
color: var(--cui-fg-on-strong);
background-color: var(--cui-bg-danger-strong);
}

.neutral {
color: var(--cui-fg-normal);
background-color: var(--cui-bg-highlight);
}

.promo {
color: var(--cui-fg-on-strong);
background-color: var(--cui-bg-promo-strong);
}
47 changes: 10 additions & 37 deletions packages/circuit-ui/components/Badge/Badge.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,47 +21,20 @@ import { render, axe } from '../../util/test-utils.js';
import { Badge } from './Badge.js';

describe('Badge', () => {
/**
* Style tests.
*/
it('should render with default styles', () => {
const { container } = render(<Badge />);
expect(container).toMatchSnapshot();
});

const variants = [
'neutral',
'success',
'warning',
'danger',
'promo',
] as const;

it.each(variants)('should render with %s styles', (variant) => {
const { container } = render(<Badge variant={variant} />);
expect(container).toMatchSnapshot();
});

it('should have the correct circle styles', () => {
const { container } = render(<Badge circle />);
expect(container).toMatchSnapshot();
it('should merge a custom class name with the default ones', () => {
const className = 'foo';
const { container } = render(<Badge className={className}>Badge</Badge>);
const badge = container.querySelector('div');
expect(badge?.className).toContain(className);
});

describe('business logic', () => {
/**
* Should accept a working ref
*/
it('should accept a working ref', () => {
const tref = createRef<HTMLDivElement>();
const { container } = render(<Badge ref={tref} />);
const div = container.querySelector('div');
expect(tref.current).toBe(div);
});
it('should forward a ref', () => {
const ref = createRef<HTMLDivElement>();
const { container } = render(<Badge ref={ref}>Badge</Badge>);
const badge = container.querySelector('div');
expect(ref.current).toBe(badge);
});

/**
* Accessibility tests.
*/
it('should meet accessibility guidelines', async () => {
const { container } = render(<Badge />);
const actual = await axe(container);
Expand Down
106 changes: 37 additions & 69 deletions packages/circuit-ui/components/Badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
* limitations under the License.
*/

import { Ref, HTMLAttributes } from 'react';
import { css } from '@emotion/react';
import { HTMLAttributes, forwardRef } from 'react';

import styled, { StyleProps } from '../../styles/styled.js';
import { typography } from '../../styles/style-mixins.js';
import type { AsPropType } from '../../types/prop-types.js';
import { clsx } from '../../styles/clsx.js';

import classes from './Badge.module.css';

export interface BadgeProps extends HTMLAttributes<HTMLDivElement> {
/**
Expand All @@ -29,85 +30,52 @@ export interface BadgeProps extends HTMLAttributes<HTMLDivElement> {
*/
circle?: boolean;
/**
* The ref to the HTML DOM element.
* Render the text using any HTML element.
*/
ref?: Ref<HTMLDivElement>;
as?: AsPropType;
}

const baseStyles = ({ theme }: StyleProps) => css`
border-radius: ${theme.borderRadius.pill};
display: inline-block;
padding: 2px ${theme.spacings.byte};
font-weight: ${theme.fontWeight.bold};
text-align: center;
letter-spacing: 0.25px;
`;

const variantStyles = ({ variant = 'neutral' }: BadgeProps) => {
switch (variant) {
case 'success': {
return css`
background-color: var(--cui-bg-success-strong);
color: var(--cui-fg-on-strong);
`;
}
case 'warning': {
return css`
background-color: var(--cui-bg-warning-strong);
color: var(--cui-fg-on-strong);
`;
}
case 'danger': {
return css`
background-color: var(--cui-bg-danger-strong);
color: var(--cui-fg-on-strong);
`;
}
case 'neutral': {
return css`
background-color: var(--cui-bg-highlight);
color: var(--cui-fg-normal);
`;
}
case 'promo': {
return css`
background-color: var(--cui-bg-promo-strong);
color: var(--cui-fg-on-strong);
`;
}
default: {
return null;
}
}
};

const isDynamicWidth = (children: BadgeProps['children']) => {
if (typeof children === 'string') {
return children.length > 2;
}
return false;
};

const circleStyles = ({ circle = false, children }: BadgeProps) =>
circle &&
css`
display: flex;
align-items: center;
justify-content: center;
padding: 2px 4px;
height: 24px;
width: ${isDynamicWidth(children) ? 'auto' : '24px'};
`;

/**
* A badge communicates the status of an element or the count of items
* related to an element.
*/
export const Badge = styled('div')<BadgeProps>(
typography('two'),
baseStyles,
variantStyles,
circleStyles,
export const Badge = forwardRef<HTMLDivElement, BadgeProps>(
(
{
as: Element = 'div',
className,
style = {},
variant = 'neutral',
circle,
children,
...props
},
ref,
) => {
const width = isDynamicWidth(children) ? 'auto' : '24px';
return (
<Element
{...props}
ref={ref}
className={clsx(
classes.base,
classes[variant],
circle && classes.circle,
className,
)}
style={{ ...style, '--badge-width': width }}
>
{children}
</Element>
);
},
);

Badge.displayName = 'Badge';
Loading

0 comments on commit 29d2b99

Please sign in to comment.