Skip to content

Commit

Permalink
feat: Add Badge component (#1045)
Browse files Browse the repository at this point in the history
Co-authored-by: Vincent Smedinga <[email protected]>
Co-authored-by: Vincent Smedinga <[email protected]>
  • Loading branch information
3 people authored Jan 26, 2024
1 parent 9e48aec commit d346cdf
Show file tree
Hide file tree
Showing 21 changed files with 324 additions and 20 deletions.
3 changes: 2 additions & 1 deletion documentation/storybook.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ We write our documentation in Dutch.

## Best practices for controls

1. For props offering five options or less, use radio buttons rather than a dropdown. This makes it easier to compare the options. It saves the user a click to select each option and clearly shows all of them up front.
1. For props offering five options or less, use radio buttons rather than a select. This makes it easier to compare the options. It saves the user a click to select each option and clearly shows all of them up front.
2. Don’t use inline radios. Their options appear rather small, making them difficult to target with a pointing device.

More to follow.

Expand Down
10 changes: 10 additions & 0 deletions packages/css/src/components/badge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Badge

A prominently coloured box containing 1 or 2 words.
Guides the user in taking a specific action or describes its surrounding content.

## Design

The badge can contain a short text or a number.
The default background colour is dark green.
Suggestions on when to use the other colours will follow soon.
58 changes: 58 additions & 0 deletions packages/css/src/components/badge/badge.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2024 Gemeente Amsterdam
*/

.amsterdam-badge {
display: inline-block;
font-family: var(--amsterdam-badge-font-family);
font-size: var(--amsterdam-badge-spacious-font-size);
font-weight: var(--amsterdam-badge-font-weight);
line-height: var(--amsterdam-badge-spacious-line-height);
padding-inline: var(--amsterdam-badge-padding-inline);

.amsterdam-theme--compact & {
font-size: var(--amsterdam-badge-compact-font-size);
line-height: var(--amsterdam-badge-compact-line-height);
}
}

.amsterdam-badge--blue {
background-color: var(--amsterdam-badge-blue-background-color);
color: var(--amsterdam-badge-blue-color);
}

.amsterdam-badge--dark-blue {
background-color: var(--amsterdam-badge-dark-blue-background-color);
color: var(--amsterdam-badge-dark-blue-color);
}

.amsterdam-badge--dark-green {
background-color: var(--amsterdam-badge-dark-green-background-color);
color: var(--amsterdam-badge-dark-green-color);
}

.amsterdam-badge--green {
background-color: var(--amsterdam-badge-green-background-color);
color: var(--amsterdam-badge-green-color);
}

.amsterdam-badge--magenta {
background-color: var(--amsterdam-badge-magenta-background-color);
color: var(--amsterdam-badge-magenta-color);
}

.amsterdam-badge--orange {
background-color: var(--amsterdam-badge-orange-background-color);
color: var(--amsterdam-badge-orange-color);
}

.amsterdam-badge--purple {
background-color: var(--amsterdam-badge-purple-background-color);
color: var(--amsterdam-badge-purple-color);
}

.amsterdam-badge--yellow {
background-color: var(--amsterdam-badge-yellow-background-color);
color: var(--amsterdam-badge-yellow-color);
}
1 change: 1 addition & 0 deletions packages/css/src/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
@import "./badge/badge";
@import "./table/table";
@import "./mega-menu/mega-menu";
@import "./icon-button/icon-button";
Expand Down
67 changes: 67 additions & 0 deletions packages/react/src/Badge/Badge.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { render } from '@testing-library/react'
import { createRef } from 'react'
import { Badge, badgeColors } from './Badge'
import '@testing-library/jest-dom'

describe('Badge', () => {
it('renders', () => {
const { container } = render(<Badge label="test" />)

const component = container.querySelector(':only-child')

expect(component).toBeInTheDocument()
expect(component).toBeVisible()
})

it('renders a design system BEM class name', () => {
const { container } = render(<Badge label="test" />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass('amsterdam-badge')
})

it('renders an additional class name', () => {
const { container } = render(<Badge label="test" className="extra" />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass('amsterdam-badge extra')
})

it('supports ForwardRef in React', () => {
const ref = createRef<HTMLElement>()

const { container } = render(<Badge label="test" ref={ref} />)

const component = container.querySelector(':only-child')

expect(ref.current).toBe(component)
})

it('renders with a number label', () => {
const { container } = render(<Badge label={1} />)

const component = container.querySelector(':only-child')

expect(component).toHaveTextContent('1')
})

it('renders with default color', () => {
const { container } = render(<Badge label="test" />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass('amsterdam-badge--dark-green')
})

badgeColors.map((color) =>
it(`renders with ${color} color`, () => {
const { container } = render(<Badge label="test" color={color} />)

const component = container.querySelector(':only-child')

expect(component).toHaveClass(`amsterdam-badge--${color}`)
}),
)
})
36 changes: 36 additions & 0 deletions packages/react/src/Badge/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2024 Gemeente Amsterdam
*/

import clsx from 'clsx'
import { forwardRef } from 'react'
import type { ForwardedRef, HTMLAttributes } from 'react'

export const badgeColors = [
'blue',
'dark-blue',
'dark-green',
'green',
'magenta',
'orange',
'purple',
'yellow',
] as const

type BadgeColor = (typeof badgeColors)[number]

export type BadgeProps = {
color?: BadgeColor
label: string | number
} & HTMLAttributes<HTMLElement>

export const Badge = forwardRef(
({ label, className, color = 'dark-green', ...restProps }: BadgeProps, ref: ForwardedRef<HTMLElement>) => (
<span {...restProps} ref={ref} className={clsx('amsterdam-badge', `amsterdam-badge--${color}`, className)}>
{label}
</span>
),
)

Badge.displayName = 'Badge'
3 changes: 3 additions & 0 deletions packages/react/src/Badge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# React Badge component

[Badge documentation](../../../css/src/badge/README.md)
2 changes: 2 additions & 0 deletions packages/react/src/Badge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Badge } from './Badge'
export type { BadgeProps } from './Badge'
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
export * from './Badge'
export * from './Table'
export * from './MegaMenu'
export * from './IconButton'
Expand Down
49 changes: 49 additions & 0 deletions proprietary/tokens/src/components/amsterdam/badge.tokens.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"amsterdam": {
"badge": {
"font-family": { "value": "{amsterdam.typography.font-family}" },
"font-weight": { "value": "{amsterdam.typography.font-weight.bold}" },
"padding-inline": { "value": "0.5rem" },
"spacious": {
"font-size": { "value": "{amsterdam.typography.spacious.text-level.5.font-size}" },
"line-height": { "value": "{amsterdam.typography.spacious.text-level.5.line-height}" }
},
"compact": {
"font-size": { "value": "{amsterdam.typography.compact.text-level.5.font-size}" },
"line-height": { "value": "{amsterdam.typography.compact.text-level.5.line-height}" }
},
"blue": {
"background-color": { "value": "{amsterdam.color.blue}" },
"color": { "value": "{amsterdam.color.primary-black}" }
},
"dark-blue": {
"background-color": { "value": "{amsterdam.color.primary-blue}" },
"color": { "value": "{amsterdam.color.primary-white}" }
},
"dark-green": {
"background-color": { "value": "{amsterdam.color.dark-green}" },
"color": { "value": "{amsterdam.color.primary-white}" }
},
"green": {
"background-color": { "value": "{amsterdam.color.green}" },
"color": { "value": "{amsterdam.color.primary-black}" }
},
"magenta": {
"background-color": { "value": "{amsterdam.color.magenta}" },
"color": { "value": "{amsterdam.color.primary-white}" }
},
"orange": {
"background-color": { "value": "{amsterdam.color.orange}" },
"color": { "value": "{amsterdam.color.primary-black}" }
},
"purple": {
"background-color": { "value": "{amsterdam.color.purple}" },
"color": { "value": "{amsterdam.color.primary-white}" }
},
"yellow": {
"background-color": { "value": "{amsterdam.color.yellow}" },
"color": { "value": "{amsterdam.color.primary-black}" }
}
}
}
}
8 changes: 6 additions & 2 deletions storybook/storybook-react/src/Accordion/Accordion.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ const meta = {
},
},
headingLevel: {
control: { type: 'select' },
control: {
type: 'radio',
},
options: [1, 2, 3, 4],
},
section: {
control: { type: 'boolean' },
control: {
type: 'boolean',
},
},
},
} satisfies Meta<typeof Accordion>
Expand Down
15 changes: 15 additions & 0 deletions storybook/storybook-react/src/Badge/Badge.docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Controls, Markdown, Meta, Primary } from "@storybook/blocks";
import * as BadgeStories from "./Badge.stories.tsx";
import README from "../../../../packages/css/src/components/badge/README.md?raw";

<Meta of={BadgeStories} />

<Markdown>{README}</Markdown>

## Stories

### Default

<Primary />

<Controls />
30 changes: 30 additions & 0 deletions storybook/storybook-react/src/Badge/Badge.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2024 Gemeente Amsterdam
*/

import { Badge } from '@amsterdam/design-system-react'
import { Meta, StoryObj } from '@storybook/react'

const meta = {
title: 'Feedback/Badge',
component: Badge,
args: {
label: 'Tip',
},
argTypes: {
color: {
control: {
type: 'select',
},
options: ['blue', 'dark-blue', 'dark-green', 'green', 'magenta', 'orange', 'purple', 'yellow'],
selected: 'dark-green',
},
},
} satisfies Meta<typeof Badge>

export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {}
20 changes: 16 additions & 4 deletions storybook/storybook-react/src/Grid/Grid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ const argTypes = {

const gridArgTypes = {
compact: {
control: { type: 'boolean' },
control: {
type: 'boolean',
},
},
gapVertical: {
control: {
Expand All @@ -34,14 +36,24 @@ const gridArgTypes = {

const gridCellArgTypes = {
as: {
control: { type: 'inline-radio' },
control: {
type: 'radio',
},
options: ['article', 'div', 'section'],
},
span: {
control: { type: 'number', min: 1, max: 12 },
control: {
type: 'number',
min: 1,
max: 12,
},
},
start: {
control: { type: 'number', min: 1, max: 12 },
control: {
type: 'number',
min: 1,
max: 12,
},
},
}

Expand Down
2 changes: 1 addition & 1 deletion storybook/storybook-react/src/Header/Header.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const meta = {
argTypes: {
logoBrand: {
control: {
type: 'select',
type: 'radio',
},
options: ['amsterdam', 'ggd-amsterdam', 'stadsarchief', 'stadsbank-van-lening', 'vga-verzekeringen'],
},
Expand Down
12 changes: 9 additions & 3 deletions storybook/storybook-react/src/Icon/Icon.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ const meta = {
component: Icon,
argTypes: {
size: {
control: { type: 'select' },
control: {
type: 'radio',
},
options: ['level-3', 'level-4', 'level-5', 'level-6'],
},
square: {
control: { type: 'boolean' },
control: {
type: 'boolean',
},
},
svg: {
control: { type: 'select' },
control: {
type: 'select',
},
options: Object.keys(Icons),
mapping: Icons,
},
Expand Down
Loading

0 comments on commit d346cdf

Please sign in to comment.