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

Add initial image component #741

Merged
merged 8 commits into from
Nov 13, 2023
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Package versioning and publishing is done through Lerna, by the maintainers of t

## Adding a new component

Scaffold all necessary files for a new component at once through `npm plop`.
Scaffold all necessary files for a new component at once through `npx plop`.
Enter the name of your component when prompted.
This will create files for the design tokens, CSS and React components, and React Stories.

Expand Down
18 changes: 18 additions & 0 deletions packages/css/src/image/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Image

Toont een afbeelding.
alimpens marked this conversation as resolved.
Show resolved Hide resolved

## Richtlijnen

- Vergeet niet om een beschrijving van de afbeelding op te nemen in het `alt`-attribuut.
Dit zorgt ervoor dat gebruikers van schermlezers deze informatie ook tot zich kunnen nemen.
Daarnaast kan het helpen bij zoekmachineoptimalisatie.
- Alleen voor decoratieve afbeeldingen is zo’n beschrijving niet nodig. Gebruik in dit geval `alt=""`.
Denk aan afbeeldingen die weinig toevoegen aan de nabije tekst of afbeeldingen die louter bijdragen aan het ontwerp of de sfeer van de pagina (bron: [W3C Web Accessibility Initiative](https://www.w3.org/WAI/tutorials/images/decorative/)).
- Zorg ervoor dat de afbeelding een beeldverhouding heeft die ondersteund wordt door het [Aspect Ratio](?path=/docs/layout-aspect-ratio--docs) component.

## Relevante WCAG-eisen

- [WCAG 1.1.1](https://www.w3.org/TR/WCAG22/#non-text-content): niet-tekstuele content heeft een tekstueel alternatief
alimpens marked this conversation as resolved.
Show resolved Hide resolved
- [WCAG 1.4.5](https://www.w3.org/TR/WCAG22/#images-of-text): gebruik tekst in plaats van afbeeldingen van tekst
- [WCAG 1.4.9](https://www.w3.org/TR/WCAG22/#images-of-text-no-exception): gebruik afbeeldingen van tekst alleen als er geen alternatief is
16 changes: 16 additions & 0 deletions packages/css/src/image/image.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2023 Gemeente Amsterdam
*/

.amsterdam-image {
font-style: italic; /* [3] */
height: auto; /* [1] */
max-width: 100%; /* [1] */
vertical-align: middle; /* [2] */
}

// [1] Allow for fluid image sizing while maintaining aspect ratio governed by width/height attributes
// [2] Remove ‘phantom’ whitespace
// [3] Italicise alt text to visually offset it from surrounding copy
// Source: https://x.com/csswizardry/status/1717841334462005661
1 change: 1 addition & 0 deletions packages/css/src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
@import "./image/image";
@import "./pagination/pagination";
@import "./accordion/accordion";
@import "./alert/alert";
Expand Down
33 changes: 33 additions & 0 deletions packages/react/src/Image/Image.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { render } from '@testing-library/react'
import { createRef } from 'react'
import { Image } from './Image'
import '@testing-library/jest-dom'

describe('Image', () => {
it('renders', () => {
const { container } = render(<Image />)
const component = container.querySelector(':only-child')
expect(component).toBeInTheDocument()
expect(component).toBeVisible()
})

it('renders a design system BEM class name', () => {
const { container } = render(<Image />)
const component = container.querySelector(':only-child')
expect(component).toHaveClass('amsterdam-image')
})

it('renders an additional class name', () => {
const { container } = render(<Image className="extra" />)
const component = container.querySelector(':only-child')
expect(component).toHaveClass('extra')
expect(component).toHaveClass('amsterdam-image')
})

it('supports ForwardRef in React', () => {
const ref = createRef<HTMLImageElement>()
const { container } = render(<Image ref={ref} />)
const component = container.querySelector(':only-child')
expect(ref.current).toBe(component)
})
})
15 changes: 15 additions & 0 deletions packages/react/src/Image/Image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2023 Gemeente Amsterdam
*/

import clsx from 'clsx'
import { ForwardedRef, forwardRef, ImgHTMLAttributes } from 'react'

export interface ImageProps extends ImgHTMLAttributes<HTMLImageElement> {}

export const Image = forwardRef(({ className, ...restProps }: ImageProps, ref: ForwardedRef<HTMLImageElement>) => (
<img {...restProps} ref={ref} className={clsx('amsterdam-image', className)} />
dlnr marked this conversation as resolved.
Show resolved Hide resolved
))

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

[Image documentation](../../../css/src/image/README.md)
2 changes: 2 additions & 0 deletions packages/react/src/Image/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Image } from './Image'
export type { ImageProps } from './Image'
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 './Image'
export * from './Pagination'
export * from './Screen'
export * from './Switch'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright (c) 2023 Gemeente Amsterdam
*/

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

const meta = {
Expand Down Expand Up @@ -57,7 +57,7 @@ const StoryTemplate: Story = {
],
render: ({ ratio }) => (
<AspectRatio ratio={ratio} style={{ maxWidth: ratio ? storyConfig[ratio].maxWidth : '500px' }}>
<img alt="" src={ratio ? storyConfig[ratio].image : 'https://picsum.photos/800/800'} style={{ width: '100%' }} />
<Image alt="" src={ratio ? storyConfig[ratio].image : 'https://picsum.photos/800/800'} />
</AspectRatio>
),
}
Expand Down
4 changes: 2 additions & 2 deletions storybook/storybook-react/src/Card/Card.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Copyright (c) 2023 Gemeente Amsterdam
*/

import { AspectRatio, Card, Heading, Paragraph } from '@amsterdam/design-system-react'
import { AspectRatio, Card, Heading, Image, Paragraph } from '@amsterdam/design-system-react'
import { Meta, StoryObj } from '@storybook/react'

const meta = {
Expand Down Expand Up @@ -57,7 +57,7 @@ export const ImageCard: Story = {
args: {
children: [
<AspectRatio key={1} ratio="wide">
<img alt="" src="https://picsum.photos/440/352" />
<Image alt="" src="https://picsum.photos/440/352" />
</AspectRatio>,
<Card.HeadingGroup key={2} tagline="Dossier">
<Heading size="level-4">
Expand Down
5 changes: 2 additions & 3 deletions storybook/storybook-react/src/Grid/Grid.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
* Copyright (c) 2023 Gemeente Amsterdam
*/

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

const meta = {
Expand Down Expand Up @@ -40,7 +39,7 @@ export const Cells: Story = {
children: Array.from(Array(3).keys()).map((i) => (
<Grid.Cell key={i} span={4}>
<figure className="amsterdam-docs-figure">
<img alt="" src={`https://picsum.photos/1024/576?random=${i}`} />
<Image alt="" src={`https://picsum.photos/1024/576?random=${i}`} />
</figure>
</Grid.Cell>
)),
Expand Down
11 changes: 11 additions & 0 deletions storybook/storybook-react/src/Image/Image.docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Controls, Markdown, Meta, Primary } from "@storybook/blocks";
import * as ImageStories from "./Image.stories.tsx";
import README from "../../../../packages/css/src/image/README.md?raw";

<Meta of={ImageStories} />

<Markdown>{README}</Markdown>

<Primary />

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

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

const meta = {
title: 'Media/Image',
component: Image,
} satisfies Meta<typeof Image>

export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {
args: {
alt: '',
src: 'https://picsum.photos/1600/900',
},
}