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: Add Fieldset component #1081

Merged
merged 7 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
12 changes: 12 additions & 0 deletions packages/css/src/components/fieldset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Fieldset

A component to group related form inputs.

## Guidelines

- Use Fieldset when you need to show a relationship between multiple form inputs. For example, you may need to group a set of text inputs into a single fieldset when asking for an address.
- When grouping radio inputs, use `role="radiogroup"` on Fieldset to have this grouping explicitly announced as a radio group. Fieldset has a default role of `group`.

## Relevant WCAG Requirements

- [WCAG 1.3.5](https://www.w3.org/WAI/WCAG22/Understanding/identify-input-purpose.html): Fieldset labels the purpose of a group of inputs.
dlnr marked this conversation as resolved.
Show resolved Hide resolved
37 changes: 37 additions & 0 deletions packages/css/src/components/fieldset/fieldset.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2023 Gemeente Amsterdam
*/

@import "../../common/hyphenation";

@mixin reset {
VincentSmedinga marked this conversation as resolved.
Show resolved Hide resolved
border: none;
margin-inline: 0;
padding-block: 0;
padding-inline: 0;
}

.amsterdam-fieldset {
border: none;
margin-inline: 0;
padding-block: 0;
padding-inline: 0;
}

@mixin legend-reset {
padding-inline: 0;
-webkit-text-size-adjust: 100%;
}
dlnr marked this conversation as resolved.
Show resolved Hide resolved

.amsterdam-fieldset__legend {
color: var(--amsterdam-fieldset-legend-color);
font-family: var(--amsterdam-fieldset-legend-font-family);
font-size: var(--amsterdam-fieldset-legend-font-size);
font-weight: var(--amsterdam-fieldset-legend-font-weight);
line-height: var(--amsterdam-fieldset-legend-line-height);
margin-block-end: 1rem; /* Because of a bug in Chrome we can’t use display grid or flex for this gap */

@include hyphenation;
@include legend-reset;
}
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 "./fieldset/fieldset";
@import "./link-list/link-list";
@import "./badge/badge";
@import "./table/table";
Expand Down
49 changes: 49 additions & 0 deletions packages/react/src/Fieldset/Fieldset.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { render, screen } from '@testing-library/react'
import { createRef } from 'react'
import { Fieldset } from './Fieldset'
import '@testing-library/jest-dom'

describe('Fieldset', () => {
it('renders', () => {
render(<Fieldset legend="Test" />)

const component = screen.getByRole('group', { name: 'Test' })

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

it('renders a design system BEM class name', () => {
render(<Fieldset legend="Test" />)

const component = screen.getByRole('group', { name: 'Test' })

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

it('renders an additional class name', () => {
render(<Fieldset legend="Test" className="extra" />)

const component = screen.getByRole('group', { name: 'Test' })

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

it('renders the correct legend class name', () => {
const { container } = render(<Fieldset legend="Test" />)

const component = container.querySelector('legend')

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

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

render(<Fieldset legend="Test" ref={ref} />)

const component = screen.getByRole('group', { name: 'Test' })

expect(ref.current).toBe(component)
})
})
23 changes: 23 additions & 0 deletions packages/react/src/Fieldset/Fieldset.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 clsx from 'clsx'
import { forwardRef } from 'react'
import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react'

export type FieldsetProps = PropsWithChildren<HTMLAttributes<HTMLFieldSetElement>> & {
legend: string
}

export const Fieldset = forwardRef(
({ children, className, legend, ...restProps }: FieldsetProps, ref: ForwardedRef<HTMLFieldSetElement>) => (
<fieldset {...restProps} ref={ref} className={clsx('amsterdam-fieldset', className)}>
<legend className="amsterdam-fieldset__legend">{legend}</legend>
{children}
</fieldset>
),
)

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

[Fieldset documentation](../../../css/src/components/fieldset/README.md)
2 changes: 2 additions & 0 deletions packages/react/src/Fieldset/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Fieldset } from './Fieldset'
export type { FieldsetProps } from './Fieldset'
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 './Fieldset'
export * from './LinkList'
export * from './Badge'
export * from './Table'
Expand Down
13 changes: 13 additions & 0 deletions proprietary/tokens/src/components/amsterdam/fieldset.tokens.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"amsterdam": {
"fieldset": {
"legend": {
"color": { "value": "{amsterdam.color.primary-black}" },
"font-family": { "value": "{amsterdam.typography.font-family}" },
"font-size": { "value": "{amsterdam.typography.text-level.4.font-size}" },
"font-weight": { "value": "{amsterdam.typography.font-weight.bold}" },
"line-height": { "value": "{amsterdam.typography.text-level.4.line-height}" }
}
}
}
}
19 changes: 19 additions & 0 deletions storybook/storybook-react/src/Fieldset/Fieldset.docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Canvas, Controls, Markdown, Meta, Primary } from "@storybook/blocks";
import * as FieldsetStories from "./Fieldset.stories.tsx";
import README from "../../../../packages/css/src/components/fieldset/README.md?raw";

<Meta of={FieldsetStories} />

<Markdown>{README}</Markdown>

<Primary />

<Controls />

## Examples

### Checkbox group

Fieldset is used to group related form inputs, like checkboxes.

<Canvas of={FieldsetStories.CheckboxGroup} />
34 changes: 34 additions & 0 deletions storybook/storybook-react/src/Fieldset/Fieldset.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2023 Gemeente Amsterdam
*/

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

const meta = {
title: 'Forms/Fieldset',
component: Fieldset,
args: {
children: 'Body van de fieldset',
legend: 'Label van de fieldset',
},
} satisfies Meta<typeof Fieldset>

export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {}

export const CheckboxGroup: Story = {
args: {
children: [
<Checkbox key={1}>Horecabedrijf</Checkbox>,
<Checkbox key={2}>Ander soort bedrijf</Checkbox>,
<Checkbox key={3}>Evenement</Checkbox>,
<Checkbox key={4}>Iets anders</Checkbox>,
],
legend: 'Waar gaat uw melding over?',
},
}
Loading