Skip to content

Commit e5c80c5

Browse files
eirikbackerBarsnes
authored andcommitted
fix(Modal): block (#2583)
Fixes #2522 --------- Co-authored-by: Tobias Barsnes <tobias.barsnes@digdir.no>
1 parent ab5ae31 commit e5c80c5

File tree

11 files changed

+87
-135
lines changed

11 files changed

+87
-135
lines changed

.changeset/nine-cameras-peel.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@digdir/designsystemet-css": patch
3+
"@digdir/designsystemet-react": patch
4+
---
5+
6+
Modal: Remove `Modal.Header` and `Modal.Footer`, replace with `Modal.Block`

apps/_components/src/ColorModal/ColorModal.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@ export const ColorModal = ({
5959
maxWidth: '1050px',
6060
}}
6161
>
62-
<Modal.Header>
62+
<Modal.Block>
6363
{`${capitalizeFirstLetter(namespace)} ${capitalizeFirstLetter(getColorNameFromNumber(weight))}`}
64-
</Modal.Header>
65-
<div className={classes.modalContent}>
64+
</Modal.Block>
65+
<Modal.Block className={classes.modalContent}>
6666
<div className={classes.description}>
6767
{getColorDescription({
6868
weight,
@@ -120,7 +120,7 @@ export const ColorModal = ({
120120
</Accordion.Content>
121121
</Accordion.Item>
122122
</Accordion.Root> */}
123-
</div>
123+
</Modal.Block>
124124
</Modal>
125125
</Modal.Context>
126126
);

packages/css/modal.css

+12-14
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
--dsc-modal-divider: 1px solid var(--ds-color-neutral-border-subtle);
77
--dsc-modal-max-height: 80vh;
88
--dsc-modal-max-width: 40rem;
9-
--dsc-modal-padding-invert: calc(var(--dsc-modal-padding) * -1);
109
--dsc-modal-padding: var(--ds-spacing-6);
10+
--close-top-right: calc(var(--dsc-modal-padding) * -1 + var(--dsc-modal-close-margin));
1111

1212
background: var(--dsc-modal-background);
1313
border-radius: min(1rem, var(--ds-border-radius-lg));
@@ -31,6 +31,12 @@
3131
fade-in 300ms ease-in-out;
3232
}
3333

34+
&:has(> .ds-modal__block) {
35+
--close-top-right: var(--dsc-modal-close-margin);
36+
37+
padding: 0; /* Let Modal.Block own the padding */
38+
}
39+
3440
@media (max-width: 40rem) {
3541
min-width: 100%;
3642
max-width: 100%;
@@ -46,10 +52,8 @@
4652

4753
/* Close button */
4854
& > form[method='dialog']:first-child > button:only-child {
49-
--margin-top-right: calc(var(--dsc-modal-padding-invert) + var(--dsc-modal-close-margin));
50-
5155
float: right;
52-
margin: var(--margin-top-right) var(--margin-top-right) var(--dsc-modal-close-margin) var(--dsc-modal-close-margin);
56+
margin: var(--close-top-right) var(--close-top-right) var(--dsc-modal-close-margin) var(--dsc-modal-close-margin);
5357
color: inherit;
5458

5559
&::before {
@@ -63,18 +67,12 @@
6367
}
6468
}
6569

66-
.ds-modal__header {
67-
border-bottom: var(--dsc-modal-divider);
68-
margin-block: var(--dsc-modal-padding-invert) var(--dsc-modal-padding);
69-
margin-inline: var(--dsc-modal-padding-invert);
70+
.ds-modal__block {
7071
padding: var(--dsc-modal-padding);
71-
}
7272

73-
.ds-modal__footer {
74-
border-top: var(--dsc-modal-divider);
75-
margin-block: var(--dsc-modal-padding) var(--dsc-modal-padding-invert);
76-
margin-inline: var(--dsc-modal-padding-invert);
77-
padding: var(--dsc-modal-padding);
73+
& + & {
74+
border-top: var(--dsc-modal-divider);
75+
}
7876
}
7977

8078
/* Prevent scroll when open */

packages/react/src/components/Card/Card.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { Card } from '@digdir/designsystemet-react';
2626

2727
<br />
2828

29-
### Card.Block
29+
### Med `Block`
3030

3131
Bruk flere `Card.Block` hvis du vil dele opp kortet med skillelinjer eller legge inn utfallende bilder eller video.
3232
Merk at innhold kan ikke plasseres direkte i `Card` dersom du bruker `Card.Block`; da burde alt innholdet være inni en av av kortets `Card.Block`-seksjoner.

packages/react/src/components/Modal/ModaContent.tsx

-28
This file was deleted.

packages/react/src/components/Modal/Modal.mdx

+9-8
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ Les [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog)
2323
<Modal.Context>
2424
<Modal.Trigger>Open Modal</Modal.Trigger>
2525
<Modal>
26-
<Modal.Header>
26+
<Modal.Block>
2727
<Heading size="xs">Header</Heading>
28-
</Modal.Header>
29-
Content
30-
<Modal.Footer>Footer</Modal.Footer>
28+
</Modal.Block>
29+
<Modal.Block>Content</Modal.Block>
30+
<Modal.Block>Footer</Modal.Block>
3131
</Modal>
3232
</Modal.Context>
3333
```
@@ -57,9 +57,10 @@ Vi bruker `backdropClose={true}` proppen for å lukke modalen når brukeren klik
5757

5858
<Canvas of={ModalStories.BackdropClose} />
5959

60-
### Med `Header` og `Footer`
60+
### Med `Block`
6161

62-
Du kan legge til `Modal.Header` og `Modal.Footer` for å få på topp- og bunn-område med sikkelinje.
62+
Bruk flere `Modal.Block` hvis du vil dele opp modalen med skillelinjer til for eksempel topp- og bunn-område.
63+
Merk at innhold kan ikke plasseres direkte i `Modal` dersom du bruker `Modal.Block`; da burde alt innholdet være inni en av av modalens `Modal.Block`-seksjoner.
6364

6465
<Canvas of={ModalStories.WithHeaderAndFooter} />
6566

@@ -81,6 +82,6 @@ Bruk `overflow: visible` for å la innhold gå utenfor modalen.
8182

8283
<Canvas of={ModalStories.ModalWithCombobox} />
8384

84-
### `Modal.Header`
85+
### `Modal.Block`
8586

86-
<ArgTypes of={Modal.Header} />
87+
<ArgTypes of={Modal.Block} />

packages/react/src/components/Modal/Modal.stories.tsx

+44-39
Original file line numberDiff line numberDiff line change
@@ -80,32 +80,35 @@ export const WithHeaderAndFooter: StoryFn<typeof Modal> = () => (
8080
<Modal.Context>
8181
<Modal.Trigger>Open Modal</Modal.Trigger>
8282
<Modal>
83-
<Modal.Header>
83+
<Modal.Block>
8484
<Paragraph size='sm'>Her er det også divider</Paragraph>
8585
<Heading size='xs'>Vi kan legge divider under header</Heading>
86-
</Modal.Header>
87-
<Paragraph style={{ marginBottom: 'var(--ds-spacing-2)' }}>
88-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur
89-
sodales eros justo. Aenean non mi ipsum. Cras viverra elit nec vulputate
90-
mattis. Nunc placerat euismod pulvinar. Sed nec fringilla nulla, sit
91-
amet ultricies ante. Morbi egestas venenatis massa, eu interdum leo
92-
rutrum eu. Nulla varius, mi ac feugiat lacinia, magna eros ullamcorper
93-
arcu, vel tincidunt erat leo nec tortor. Sed ut dui arcu. Morbi commodo
94-
ipsum hendrerit est imperdiet imperdiet. Etiam sed maximus nisi. Quisque
95-
posuere posuere orci, non egestas risus facilisis a. Vivamus non tempus
96-
felis, in maximus lorem. Class aptent taciti sociosqu ad litora torquent
97-
per conubia nostra, per inceptos himenaeos.
98-
</Paragraph>
99-
<Paragraph>
100-
Etiam nec tincidunt est. Integer semper sodales efficitur. Pellentesque
101-
pellentesque varius leo id congue. Integer lacinia porttitor massa id
102-
euismod. Maecenas porta, magna nec interdum eleifend, risus magna
103-
condimentum neque, a gravida nisl risus a elit. Donec accumsan metus et
104-
lectus placerat varius. Donec tristique odio arcu. Donec cursus leo a
105-
dui auctor pulvinar. Sed in elit urna. Nunc vitae magna sed nibh
106-
elementum dignissim et ut massa.
107-
</Paragraph>
108-
<Modal.Footer>Og over footer</Modal.Footer>
86+
</Modal.Block>
87+
<Modal.Block>
88+
<Paragraph style={{ marginBottom: 'var(--ds-spacing-2)' }}>
89+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur
90+
sodales eros justo. Aenean non mi ipsum. Cras viverra elit nec
91+
vulputate mattis. Nunc placerat euismod pulvinar. Sed nec fringilla
92+
nulla, sit amet ultricies ante. Morbi egestas venenatis massa, eu
93+
interdum leo rutrum eu. Nulla varius, mi ac feugiat lacinia, magna
94+
eros ullamcorper arcu, vel tincidunt erat leo nec tortor. Sed ut dui
95+
arcu. Morbi commodo ipsum hendrerit est imperdiet imperdiet. Etiam sed
96+
maximus nisi. Quisque posuere posuere orci, non egestas risus
97+
facilisis a. Vivamus non tempus felis, in maximus lorem. Class aptent
98+
taciti sociosqu ad litora torquent per conubia nostra, per inceptos
99+
himenaeos.
100+
</Paragraph>
101+
<Paragraph>
102+
Etiam nec tincidunt est. Integer semper sodales efficitur.
103+
Pellentesque pellentesque varius leo id congue. Integer lacinia
104+
porttitor massa id euismod. Maecenas porta, magna nec interdum
105+
eleifend, risus magna condimentum neque, a gravida nisl risus a elit.
106+
Donec accumsan metus et lectus placerat varius. Donec tristique odio
107+
arcu. Donec cursus leo a dui auctor pulvinar. Sed in elit urna. Nunc
108+
vitae magna sed nibh elementum dignissim et ut massa.
109+
</Paragraph>
110+
</Modal.Block>
111+
<Modal.Block>Og over footer</Modal.Block>
109112
</Modal>
110113
</Modal.Context>
111114
);
@@ -175,28 +178,30 @@ export const ModalWithCombobox: StoryFn<typeof Modal> = () => {
175178
<Modal.Context>
176179
<Modal.Trigger>Open Modal</Modal.Trigger>
177180
<Modal style={{ overflow: 'visible' }} ref={modalRef}>
178-
<Modal.Header>
181+
<Modal.Block>
179182
<Heading size='xs'>Modal med combobox</Heading>
180-
</Modal.Header>
181-
<Combobox portal={false} label='Velg sted' autoFocus>
182-
<Combobox.Empty>Fant ingen treff</Combobox.Empty>
183-
<Combobox.Option value='leikanger'>Leikanger</Combobox.Option>
184-
<Combobox.Option value='oslo'>Oslo</Combobox.Option>
185-
<Combobox.Option value='bronnoysund'>Brønnøysund</Combobox.Option>
186-
<Combobox.Option value='stavanger'>Stavanger</Combobox.Option>
187-
<Combobox.Option value='trondheim'>Trondheim</Combobox.Option>
188-
<Combobox.Option value='tromso'>Tromsø</Combobox.Option>
189-
<Combobox.Option value='bergen'>Bergen</Combobox.Option>
190-
<Combobox.Option value='moirana'>Mo i Rana</Combobox.Option>
191-
</Combobox>
192-
<Modal.Footer>
183+
</Modal.Block>
184+
<Modal.Block>
185+
<Combobox portal={false} label='Velg sted' autoFocus>
186+
<Combobox.Empty>Fant ingen treff</Combobox.Empty>
187+
<Combobox.Option value='leikanger'>Leikanger</Combobox.Option>
188+
<Combobox.Option value='oslo'>Oslo</Combobox.Option>
189+
<Combobox.Option value='bronnoysund'>Brønnøysund</Combobox.Option>
190+
<Combobox.Option value='stavanger'>Stavanger</Combobox.Option>
191+
<Combobox.Option value='trondheim'>Trondheim</Combobox.Option>
192+
<Combobox.Option value='tromso'>Tromsø</Combobox.Option>
193+
<Combobox.Option value='bergen'>Bergen</Combobox.Option>
194+
<Combobox.Option value='moirana'>Mo i Rana</Combobox.Option>
195+
</Combobox>
196+
</Modal.Block>
197+
<Modal.Block>
193198
<Button
194199
variant='secondary'
195200
onClick={() => modalRef.current?.close()}
196201
>
197202
Avbryt
198203
</Button>
199-
</Modal.Footer>
204+
</Modal.Block>
200205
</Modal>
201206
</Modal.Context>
202207
</>

packages/react/src/components/Modal/Modal.test.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe('Modal', () => {
4040
const { user } = await render({
4141
children: (
4242
<>
43-
<Modal.Header>{HEADER_TITLE}</Modal.Header>
43+
<Modal.Block>{HEADER_TITLE}</Modal.Block>
4444
</>
4545
),
4646
});
@@ -99,7 +99,7 @@ describe('Modal', () => {
9999
open: true,
100100
children: (
101101
<>
102-
<Modal.Header>{HEADER_TITLE}</Modal.Header>
102+
<Modal.Block>{HEADER_TITLE}</Modal.Block>
103103
</>
104104
),
105105
});

packages/react/src/components/Modal/ModalFooter.tsx packages/react/src/components/Modal/ModalBlock.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@ import cl from 'clsx/lite';
33
import type { HTMLAttributes } from 'react';
44
import { forwardRef } from 'react';
55

6-
export type ModalFooterProps = {
6+
export type ModalBlockProps = {
77
/**
88
* Change the default rendered element for the one passed as a child, merging their props and behavior.
99
* @default false
1010
*/
1111
asChild?: boolean;
1212
} & HTMLAttributes<HTMLDivElement>;
1313

14-
export const ModalFooter = forwardRef<HTMLDivElement, ModalFooterProps>(
15-
function ModalFooter({ asChild, className, ...rest }, ref) {
14+
export const ModalBlock = forwardRef<HTMLDivElement, ModalBlockProps>(
15+
function ModalBlock({ asChild, className, ...rest }, ref) {
1616
const Component = asChild ? Slot : 'div';
1717

1818
return (
1919
<Component
20-
className={cl('ds-modal__footer', className)}
20+
className={cl('ds-modal__block', className)}
2121
ref={ref}
2222
{...rest}
2323
/>

packages/react/src/components/Modal/ModalHeader.tsx

-26
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
11
import { Modal as ModalParent } from './Modal';
2+
import { ModalBlock } from './ModalBlock';
23
import { ModalContext } from './ModalContext';
3-
import { ModalFooter } from './ModalFooter';
4-
import { ModalHeader } from './ModalHeader';
54
import { ModalTrigger } from './ModalTrigger';
65

76
const Modal = Object.assign(ModalParent, {
7+
Block: ModalBlock,
88
Context: ModalContext,
9-
Footer: ModalFooter,
10-
Header: ModalHeader,
119
Trigger: ModalTrigger,
1210
});
1311

12+
Modal.Block.displayName = 'Modal.Block';
1413
Modal.Context.displayName = 'Modal.Context';
15-
Modal.Footer.displayName = 'Modal.Footer';
16-
Modal.Header.displayName = 'Modal.Header';
1714
Modal.Trigger.displayName = 'Modal.Trigger';
1815

16+
export type { ModalBlockProps } from './ModalBlock';
1917
export type { ModalContextProps } from './ModalContext';
20-
export type { ModalFooterProps } from './ModalFooter';
21-
export type { ModalHeaderProps } from './ModalHeader';
2218
export type { ModalProps } from './Modal';
2319
export type { ModalTriggerProps } from './ModalTrigger';
24-
export { Modal, ModalContext, ModalFooter, ModalHeader, ModalTrigger };
20+
export { Modal, ModalBlock, ModalContext, ModalTrigger };

0 commit comments

Comments
 (0)