diff --git a/packages/css/src/components/hero-image/README.md b/packages/css/src/components/hero-image/README.md new file mode 100644 index 0000000000..bdc471e103 --- /dev/null +++ b/packages/css/src/components/hero-image/README.md @@ -0,0 +1,3 @@ +# Hero Image + +Een sfeerbepalende afbeelding die vaak over de volle breedte bovenaan een pagina wordt gebruikt. diff --git a/packages/css/src/components/hero-image/hero-image.scss b/packages/css/src/components/hero-image/hero-image.scss new file mode 100644 index 0000000000..35a2ad34d0 --- /dev/null +++ b/packages/css/src/components/hero-image/hero-image.scss @@ -0,0 +1,13 @@ +/** + * @license EUPL-1.2+ + * Copyright (c) 2023 Gemeente Amsterdam + */ + +.amsterdam-hero-image { + align-content: center; + aspect-ratio: var(--amsterdam-hero-image-aspect-ratio); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + display: grid; +} diff --git a/packages/css/src/components/index.scss b/packages/css/src/components/index.scss index f00d2555a5..43758f0eb1 100644 --- a/packages/css/src/components/index.scss +++ b/packages/css/src/components/index.scss @@ -4,6 +4,7 @@ */ /* Append here */ +@import "./hero-image/hero-image"; @import "./text-input/text-input"; @import "./search-field/search-field"; @import "./logo/logo"; diff --git a/packages/react/src/HeroImage/HeroImage.test.tsx b/packages/react/src/HeroImage/HeroImage.test.tsx new file mode 100644 index 0000000000..abfdb2639b --- /dev/null +++ b/packages/react/src/HeroImage/HeroImage.test.tsx @@ -0,0 +1,32 @@ +import { render } from '@testing-library/react' +import { createRef } from 'react' +import { HeroImage } from './HeroImage' +import '@testing-library/jest-dom' + +describe('Hero image', () => { + it('renders', () => { + const { container } = render() + const component = container.querySelector(':only-child') + expect(component).toBeInTheDocument() + expect(component).toBeVisible() + }) + + it('renders a design system BEM class name', () => { + const { container } = render() + const component = container.querySelector(':only-child') + expect(component).toHaveClass('amsterdam-hero-image') + }) + + it('renders an additional class name', () => { + const { container } = render() + const component = container.querySelector(':only-child') + expect(component).toHaveClass('amsterdam-hero-image extra') + }) + + it('supports ForwardRef in React', () => { + const ref = createRef() + const { container } = render() + const component = container.querySelector(':only-child') + expect(ref.current).toBe(component) + }) +}) diff --git a/packages/react/src/HeroImage/HeroImage.tsx b/packages/react/src/HeroImage/HeroImage.tsx new file mode 100644 index 0000000000..fb2d649991 --- /dev/null +++ b/packages/react/src/HeroImage/HeroImage.tsx @@ -0,0 +1,32 @@ +/** + * @license EUPL-1.2+ + * Copyright (c) 2023 Gemeente Amsterdam + */ + +import clsx from 'clsx' +import { ImgHTMLAttributes } from 'react' +import { forwardRef, HTMLAttributes, PropsWithChildren } from 'react' + +export interface HeroImageProps extends PropsWithChildren> { + as?: 'article' | 'aside' | 'div' | 'footer' | 'section' + src: ImgHTMLAttributes['src'] +} + +export const HeroImage = forwardRef( + ({ as = 'div', children, className, src, ...restProps }: HeroImageProps, ref) => { + const Component = as + + return ( + + {children} + + ) + }, +) + +HeroImage.displayName = 'HeroImage' diff --git a/packages/react/src/HeroImage/README.md b/packages/react/src/HeroImage/README.md new file mode 100644 index 0000000000..686aef95be --- /dev/null +++ b/packages/react/src/HeroImage/README.md @@ -0,0 +1,3 @@ +# React Hero-Image component + +[Hero-Image documentation](../../../css/src/hero-image/README.md) diff --git a/packages/react/src/HeroImage/index.ts b/packages/react/src/HeroImage/index.ts new file mode 100644 index 0000000000..67882b834f --- /dev/null +++ b/packages/react/src/HeroImage/index.ts @@ -0,0 +1,2 @@ +export { HeroImage } from './HeroImage' +export type { HeroImageProps } from './HeroImage' diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 4f31e99338..44eba0ae71 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -4,6 +4,7 @@ */ /* Append here */ +export * from './HeroImage' export * from './TextInput' export * from './SearchField' export * from './Logo' diff --git a/proprietary/tokens/src/components/amsterdam/hero-image.tokens.json b/proprietary/tokens/src/components/amsterdam/hero-image.tokens.json new file mode 100644 index 0000000000..9af603b0b8 --- /dev/null +++ b/proprietary/tokens/src/components/amsterdam/hero-image.tokens.json @@ -0,0 +1,7 @@ +{ + "amsterdam": { + "hero-image": { + "aspect-ratio": { "value": "{amsterdam.proportion.2x-wide}" } + } + } +} diff --git a/storybook/storybook-react/src/HeroImage/HeroImage.docs.mdx b/storybook/storybook-react/src/HeroImage/HeroImage.docs.mdx new file mode 100644 index 0000000000..7adb1a21b5 --- /dev/null +++ b/storybook/storybook-react/src/HeroImage/HeroImage.docs.mdx @@ -0,0 +1,25 @@ +import { Canvas, Markdown, Meta, Primary } from "@storybook/blocks"; +import * as HeroImageStories from "./HeroImage.stories.tsx"; +import README from "../../../../packages/css/src/components/hero-image/README.md?raw"; + + + +{README} + +## Voorbeelden + +### Basis + +De beeldverhouding van de afbeelding is 32:9. +Dat komt overeen met de `2x-wide` [aspect ratio](?path=/docs/react_layout-aspect-ratio--docs). + + + +### Met zoekveld + +De inhoud van een hero-afbeelding zal doorgaans in een grid staan. +De horizontale witruimte en maatvoering is dan verzorgd. + +In dit geval specificeert het zoekveld een maximale breedte en centreert het zichzelf binnen de cel van het grid. + + diff --git a/storybook/storybook-react/src/HeroImage/HeroImage.stories.tsx b/storybook/storybook-react/src/HeroImage/HeroImage.stories.tsx new file mode 100644 index 0000000000..671b6ec6dc --- /dev/null +++ b/storybook/storybook-react/src/HeroImage/HeroImage.stories.tsx @@ -0,0 +1,43 @@ +/** + * @license EUPL-1.2+ + * Copyright (c) 2023 Gemeente Amsterdam + */ + +import { Grid } from '@amsterdam/design-system-react' +import { SearchField } from '@amsterdam/design-system-react' +import { HeroImage } from '@amsterdam/design-system-react' +import { Meta, StoryObj } from '@storybook/react' + +const meta = { + title: 'Media/Hero Image', + component: HeroImage, + args: { + children: , + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = { + args: { + src: 'https://picsum.photos/1280/360?random=1', + }, +} + +export const WithSearchField: Story = { + args: { + src: 'https://picsum.photos/1280/360?random=2', + children: ( + + + + + + + + + ), + }, +}