Skip to content

Commit

Permalink
feat!: Remove form from Dialog (#1582)
Browse files Browse the repository at this point in the history
Co-authored-by: Aram <[email protected]>
  • Loading branch information
dlnr and alimpens authored Sep 17, 2024
1 parent 824a2f9 commit 4fb6e53
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 40 deletions.
15 changes: 7 additions & 8 deletions packages/css/src/components/dialog/dialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
background-color: var(--ams-dialog-background-color);
border: var(--ams-dialog-border);
inline-size: var(--ams-dialog-inline-size);
max-block-size: var(--ams-dialog-max-block-size);
max-inline-size: var(--ams-dialog-max-inline-size);

@include reset-dialog;
Expand All @@ -24,16 +23,16 @@
}
}

.ams-dialog__form {
.ams-dialog__wrapper {
display: grid;
gap: var(--ams-dialog-form-gap);
padding-block: var(--ams-dialog-form-padding-block);
padding-inline: var(--ams-dialog-form-padding-inline);
gap: var(--ams-dialog-wrapper-gap);
grid-template-rows: auto 1fr auto;
max-block-size: var(--ams-dialog-wrapper-max-block-size);
padding-block: var(--ams-dialog-wrapper-padding-block);
padding-inline: var(--ams-dialog-wrapper-padding-inline);
}

.ams-dialog__article {
display: grid;
gap: var(--ams-space-md); /* Until we have a consistent way of spacing text elements */
.ams-dialog__content {
max-block-size: 100%; /* Safari */
overflow-y: auto;
overscroll-behavior-y: contain;
Expand Down
12 changes: 7 additions & 5 deletions packages/react/src/Dialog/Dialog.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,18 @@ describe('Dialog', () => {
expect(getByText('Test content')).toBeInTheDocument()
})

it('renders actions when provided', () => {
const { getByText } = render(<Dialog heading="Test heading" actions={<button>Click Me</button>} />)
it('renders footer when provided', () => {
const { getByText } = render(<Dialog heading="Test heading" footer={<button>Click Me</button>} />)

expect(getByText('Click Me')).toBeInTheDocument()
})

it('does not render actions when not provided', () => {
const { queryByText } = render(<Dialog heading="Test heading" />)
it('does not render footer when not provided', () => {
const { container } = render(<Dialog heading="Test heading" />)

expect(queryByText('Click Me')).not.toBeInTheDocument()
const component = container.querySelector('footer')

expect(component).not.toBeInTheDocument()
})

it('renders DialogClose button', () => {
Expand Down
12 changes: 6 additions & 6 deletions packages/react/src/Dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { IconButton } from '../IconButton'

export type DialogProps = {
/** The button(s) in the footer. Start with a primary button. */
actions?: ReactNode
footer?: ReactNode
/** The label for the button that dismisses the Dialog. */
closeButtonLabel?: string
/** The text for the Heading. */
Expand All @@ -23,18 +23,18 @@ const openDialog = (id: string) => (document.querySelector(id) as HTMLDialogElem

const DialogRoot = forwardRef(
(
{ actions, children, className, closeButtonLabel = 'Sluiten', heading, ...restProps }: DialogProps,
{ footer, children, className, closeButtonLabel = 'Sluiten', heading, ...restProps }: DialogProps,
ref: ForwardedRef<HTMLDialogElement>,
) => (
<dialog {...restProps} ref={ref} className={clsx('ams-dialog', className)}>
<form className="ams-dialog__form" method="dialog">
<div className="ams-dialog__wrapper">
<header className="ams-dialog__header">
<Heading size="level-4">{heading}</Heading>
<IconButton label={closeButtonLabel} onClick={closeDialog} size="level-4" type="button" />
</header>
<article className="ams-dialog__article">{children}</article>
{actions && <footer className="ams-dialog__footer">{actions}</footer>}
</form>
<div className="ams-dialog__content">{children}</div>
{footer && <footer className="ams-dialog__footer">{footer}</footer>}
</div>
</dialog>
),
)
Expand Down
4 changes: 2 additions & 2 deletions proprietary/tokens/src/components/ams/dialog.tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"background-color": { "value": "{ams.color.primary-white}" },
"border": { "value": "0" },
"inline-size": { "value": "calc(100% - 2 * {ams.space.grid.md})" },
"max-block-size": { "value": "calc(100% - 2 * {ams.space.grid.md})" },
"max-inline-size": { "value": "48rem" },
"form": {
"wrapper": {
"gap": { "value": "{ams.space.md}" },
"max-block-size": { "value": "calc(100dvh - 4 * {ams.space.grid.md})" },
"padding-block": { "value": "{ams.space.grid.md}" },
"padding-inline": { "value": "{ams.space.grid.lg}" }
},
Expand Down
13 changes: 12 additions & 1 deletion storybook/src/components/Dialog/Dialog.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,22 @@ import README from "../../../../packages/css/src/components/dialog/README.md?raw

## Examples

### Form in a Dialog

Set `method="dialog"` when using a form in Dialog.
This closes the Dialog when submitting the form.
Pass the submit Button to the `footer` prop,
and link it to the form by passing its `id` to the Buttons `form` attribute.
The Dialog returns the value of the submit Button, so you can check which Button was clicked.
For more information, see [Handling the return value from the dialog (MDN)](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog#handling_the_return_value_from_the_dialog).

<Canvas of={DialogStories.FormDialog} />

### With scrollbar

Content taller than the dialog itself will scroll.

<Canvas of={DialogStories.WithScrollbar} className="ams-dialog-story" />
<Canvas of={DialogStories.WithScrollbar} />

### Trigger Button

Expand Down
80 changes: 62 additions & 18 deletions storybook/src/components/Dialog/Dialog.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@ const meta = {
title: 'Components/Containers/Dialog',
component: Dialog,
args: {
actions: (
<>
<Button type="submit">Doorgaan</Button>
<Button onClick={Dialog.close} variant="tertiary">
Stoppen
</Button>
</>
footer: (
<Button onClick={Dialog.close} variant="primary">
Sluiten
</Button>
),
children: (
<Paragraph>
Expand All @@ -28,7 +25,7 @@ const meta = {
heading: 'Niet alle gegevens zijn opgeslagen',
},
argTypes: {
actions: {
footer: {
table: { disable: true },
},
},
Expand Down Expand Up @@ -65,35 +62,72 @@ export const Default: Story = {
},
}

export const FormDialog: Story = {
args: {
open: true,
footer: (
<>
<Button type="submit" form="dialog1" value="continue">
Doorgaan
</Button>
<Button onClick={Dialog.close} variant="tertiary">
Stoppen
</Button>
</>
),
children: (
<form method="dialog" id="dialog1">
<Paragraph>
Weet u zeker dat u door wilt gaan met het uitvoeren van deze actie? Dat verwijdert gegevens die nog niet
opgeslagen zijn.
</Paragraph>
</form>
),
},
decorators: [
(Story) => (
<div style={{ backgroundColor: '#0006', position: 'absolute', width: '100%', height: '100%' }}>
<Story />
</div>
),
],
parameters: {
docs: {
story: { height: '32em' },
},
layout: 'fullscreen',
},
}

export const WithScrollbar: Story = {
args: {
actions: <Button onClick={Dialog.close}>Sluiten</Button>,
footer: <Button onClick={Dialog.close}>Sluiten</Button>,
children: [
<Heading level={2} size="level-5" key={1}>
<Heading level={2} size="level-5" key={1} className="ams-mb--sm">
Algemeen
</Heading>,
<Paragraph key={2}>
<Paragraph key={2} className="ams-mb--sm">
De gemeente Amsterdam verwerkt bij de uitvoering van haar taken en verplichtingen persoonsgegevens. De manier
waarop de gemeente Amsterdam om gaat met persoonsgegevens is vastgelegd in het stedelijk kader verwerken
persoonsgegevens.
</Paragraph>,
<Paragraph key={3}>
<Paragraph key={3} className="ams-mb--sm">
Deze verklaring geeft aanvullende informatie over de omgang met persoonsgegevens door de gemeente Amsterdam en
over uw mogelijkheden tot het uitoefenen van uw rechten met betrekking tot persoonsgegevens.
</Paragraph>,
<Paragraph key={4}>
<Paragraph key={4} className="ams-mb--sm">
Meer specifieke informatie over privacy en de verwerking van persoonsgegevens door de gemeente Amsterdam kunt u
op de hoofdpagina vinden.
</Paragraph>,
<Paragraph key={5}>
<Paragraph key={5} className="ams-mb--sm">
Vanwege nieuwe wetgeving of andere ontwikkelingen, past de gemeente regelmatig haar processen aan. Dit kunnen
ook wijzigingen zijn in de wijze van het verwerken van persoonsgegevens. Wij raden u daarom aan om regelmatig
deze pagina te bekijken. Deze pagina wordt doorlopend geactualiseerd.
</Paragraph>,
<Heading level={2} size="level-5" key={6}>
<Heading level={2} size="level-5" key={6} className="ams-mb--sm">
Geldende wet- en regelgeving en reikwijdte
</Heading>,
<Paragraph key={7}>
<Paragraph key={7} className="ams-mb--sm">
Vanaf 25 mei 2018 is de Algemene verordening gegevensbescherming (Avg) van toepassing op alle verwerkingen van
persoonsgegevens. Deze Europese wetgeving heeft directe werking in Nederland. Voor die zaken die nationaal
geregeld moeten worden, is de Uitvoeringswet Avg in Nederland aanvullend van toepassing. Deze wetteksten kunt u
Expand Down Expand Up @@ -134,14 +168,24 @@ export const TriggerButton: Story = {

export const VerticalButtons: Story = {
args: {
actions: (
footer: (
<>
<Button type="submit">Lange teksten op deze knoppen</Button>
<Button type="submit" form="dialog2">
Lange teksten op deze knoppen
</Button>
<Button onClick={Dialog.close} variant="tertiary">
Om verticaal stapelen te demonstreren
</Button>
</>
),
children: (
<form method="dialog" id="dialog2">
<Paragraph>
Weet u zeker dat u door wilt gaan met het uitvoeren van deze actie? Dat verwijdert gegevens die nog niet
opgeslagen zijn.
</Paragraph>
</form>
),
open: true,
},
decorators: [
Expand Down

0 comments on commit 4fb6e53

Please sign in to comment.