Skip to content

Commit c98c643

Browse files
Jeffrey Lauwersclaude
andcommitted
feat(Container): voeg Container layout component toe (#74)
Container biedt een visueel kader voor het groeperen van gerelateerde content via achtergrond, border en optionele box-shadow (elevated). - Design tokens: container.json met elevated variant via box-shadow.sm - Wireframe thema: ontbrekende box-shadow tokens (sm/md/lg: none) toegevoegd - HTML/CSS: dsn-container + dsn-container--elevated modifier - React: Container component met as, elevated props en forwardRef - Storybook: Default, Elevated, ElevatedWithContent, AllStates stories - Stack/Grid stories: placeholder Box vervangen door Container items Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent eae941c commit c98c643

File tree

13 files changed

+411
-59
lines changed

13 files changed

+411
-59
lines changed

packages/components-html/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"exports": {
88
".": "./dist/components.css",
99
"./button": "./src/button/button.css",
10+
"./container": "./src/container/container.css",
1011
"./icon": "./src/icon/icon.css",
1112
"./paragraph": "./src/paragraph/paragraph.css",
1213
"./heading": "./src/heading/heading.css",
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Container Component
3+
* Visuele groepering van gerelateerde content met achtergrond, border en optionele schaduw.
4+
*
5+
* Usage:
6+
* <!-- Standaard -->
7+
* <div class="dsn-container">
8+
* <p class="dsn-paragraph">Inhoud</p>
9+
* </div>
10+
*
11+
* <!-- Elevated (kaart-achtig, met schaduw) -->
12+
* <div class="dsn-container dsn-container--elevated">
13+
* <p class="dsn-paragraph">Inhoud</p>
14+
* </div>
15+
*
16+
* <!-- Semantisch element -->
17+
* <section class="dsn-container">
18+
* <h2 class="dsn-heading dsn-heading--2">Sectietitel</h2>
19+
* <p class="dsn-paragraph">Inhoud</p>
20+
* </section>
21+
*/
22+
23+
/* ===========================
24+
Base
25+
=========================== */
26+
.dsn-container {
27+
background-color: var(--dsn-container-background-color);
28+
border: var(--dsn-container-border-width) solid
29+
var(--dsn-container-border-color);
30+
border-radius: var(--dsn-container-border-radius);
31+
box-shadow: var(--dsn-container-box-shadow);
32+
color: var(--dsn-container-color);
33+
padding-block: var(--dsn-container-padding-block);
34+
padding-inline: var(--dsn-container-padding-inline);
35+
}
36+
37+
/* ===========================
38+
Elevated modifier — kaart-achtige schaduw
39+
=========================== */
40+
.dsn-container--elevated {
41+
box-shadow: var(--dsn-container-elevated-box-shadow);
42+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* Container component styles for React
3+
* Re-exports the base Container styles from components-html
4+
*/
5+
6+
@import '../../../components-html/src/container/container.css';
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React from 'react';
2+
import { classNames } from '@dsn/core';
3+
import './Container.css';
4+
5+
export type ContainerAs = 'div' | 'section' | 'article' | 'aside';
6+
7+
export interface ContainerProps extends React.HTMLAttributes<HTMLElement> {
8+
/**
9+
* HTML-element — ontkoppelt semantiek van visuele stijl
10+
* @default 'div'
11+
*/
12+
as?: ContainerAs;
13+
14+
/**
15+
* Voegt een lichte schaduw toe voor een zwevend, kaart-achtig effect
16+
* @default false
17+
*/
18+
elevated?: boolean;
19+
20+
children?: React.ReactNode;
21+
}
22+
23+
/**
24+
* Container component
25+
* Visuele groepering van gerelateerde content met achtergrond, border en optionele schaduw.
26+
*
27+
* @example
28+
* ```tsx
29+
* // Standaard
30+
* <Container>
31+
* <Paragraph>Inhoud</Paragraph>
32+
* </Container>
33+
*
34+
* // Elevated (kaart-achtig)
35+
* <Container elevated>
36+
* <Paragraph>Inhoud</Paragraph>
37+
* </Container>
38+
*
39+
* // Semantisch element
40+
* <Container as="section">
41+
* <Heading level={2}>Sectietitel</Heading>
42+
* <Paragraph>Inhoud</Paragraph>
43+
* </Container>
44+
* ```
45+
*/
46+
export const Container = React.forwardRef<HTMLElement, ContainerProps>(
47+
(
48+
{ as: As = 'div', className, elevated = false, children, ...props },
49+
ref
50+
) => {
51+
const classes = classNames(
52+
'dsn-container',
53+
elevated && 'dsn-container--elevated',
54+
className
55+
);
56+
57+
return (
58+
<As ref={ref as React.Ref<HTMLDivElement>} className={classes} {...props}>
59+
{children}
60+
</As>
61+
);
62+
}
63+
);
64+
65+
Container.displayName = 'Container';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { Container } from './Container';
2+
export type { ContainerProps, ContainerAs } from './Container';

packages/components-react/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
// Layout Components
9+
export * from './Container';
910
export * from './Grid';
1011
export * from './Stack';
1112

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"dsn": {
3+
"container": {
4+
"background-color": {
5+
"value": "{dsn.color.neutral.bg-elevated}",
6+
"type": "color",
7+
"comment": "Achtergrondkleur — bg-elevated voor visuele scheiding van de pagina"
8+
},
9+
"border-color": {
10+
"value": "{dsn.color.neutral.border-subtle}",
11+
"type": "color",
12+
"comment": "Subtiele border — minder prominent dan border-default"
13+
},
14+
"border-radius": {
15+
"value": "{dsn.border.radius.md}",
16+
"type": "dimension"
17+
},
18+
"border-width": {
19+
"value": "{dsn.border.width.thin}",
20+
"type": "dimension"
21+
},
22+
"box-shadow": {
23+
"value": "none",
24+
"comment": "Standaard geen schaduw — gebruik elevated variant voor een zwevend effect"
25+
},
26+
"color": {
27+
"value": "{dsn.color.neutral.color-document}",
28+
"type": "color",
29+
"comment": "Tekstkleur — altijd de volledige document-kleur voor leesbaarheid"
30+
},
31+
"padding-block": {
32+
"value": "{dsn.space.block.3xl}",
33+
"type": "dimension"
34+
},
35+
"padding-inline": {
36+
"value": "{dsn.space.inline.3xl}",
37+
"type": "dimension"
38+
},
39+
"elevated": {
40+
"box-shadow": {
41+
"value": "{dsn.box-shadow.sm}",
42+
"comment": "Lichte schaduw voor kaart-achtige containers (cards, panels)"
43+
}
44+
}
45+
}
46+
}
47+
}

packages/design-tokens/src/tokens/themes/wireframe/base.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,20 @@
516516
"value": "74em",
517517
"comment": "Extra large breakpoint - ~1184px. Reference only; use hardcoded values in CSS @media rules."
518518
}
519+
},
520+
"box-shadow": {
521+
"sm": {
522+
"value": "none",
523+
"comment": "Small elevation — flat in wireframe theme"
524+
},
525+
"md": {
526+
"value": "none",
527+
"comment": "Medium elevation — flat in wireframe theme"
528+
},
529+
"lg": {
530+
"value": "none",
531+
"comment": "Large elevation — flat in wireframe theme"
532+
}
519533
}
520534
}
521535
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Container
2+
3+
Visuele groepering van gerelateerde content met achtergrond, border en optionele schaduw.
4+
5+
## Doel
6+
7+
Container biedt een afgebakend kader voor content die visueel bij elkaar hoort. Het component combineert een `bg-elevated` achtergrond, een subtiele border en een optionele `box-shadow` tot een herkenbaar geheel. Container is puur visueel — het heeft geen eigen semantische rol en laat de keuze van het HTML-element aan de gebruiker over via de `as` prop.
8+
9+
<!-- VOORBEELD -->
10+
11+
## Use when
12+
13+
- Gerelateerde componenten visueel groeperen (formuliersecties, kaarten, panelen).
14+
- Een duidelijke grens nodig is tussen content en pagina-achtergrond.
15+
- Je een kaart-achtig element wilt met een lichte schaduw (`elevated`).
16+
- Layout componenten (Stack, Grid) een visueel kader geven in een pagina of demo.
17+
18+
## Don't use when
19+
20+
- Je alleen witruimte nodig hebt tussen secties — gebruik Stack of Grid met de juiste spacing tokens.
21+
- Het element navigatie, een formulier of andere semantisch geladen structuur is — geef dan de juiste HTML-semantiek aan de parent zelf mee.
22+
- Je een kleurrijke statusachtergrond wilt — gebruik Alert of Note.
23+
24+
## Best practices
25+
26+
### `as` prop
27+
28+
| Waarde | Wanneer |
29+
| ----------------- | --------------------------------------------------------- |
30+
| `'div'` (default) | Generieke groepering zonder extra semantische betekenis |
31+
| `'section'` | Benoemde inhoudssectie met een heading als label |
32+
| `'article'` | Zelfstandig herbruikbaar stuk content (kaart, nieuwsitem) |
33+
| `'aside'` | Tangentieel aanvullende content naast de hoofdinhoud |
34+
35+
### Elevated
36+
37+
Gebruik `elevated` alleen als de Container visueel boven de pagina zweeft — zoals een dropdown-panel, een card in een raster of een demo-wrapper in Storybook. Gebruik het niet voor alle containers, want schaduw werkt op contrast: hoe minder schaduwen, hoe meer impact.
38+
39+
### Nesting
40+
41+
Container kan andere layout-componenten bevatten (Stack, Grid). Container regelt de buitenkant (achtergrond, border, padding), Stack of Grid regelen de binnenste spacing.
42+
43+
## Design tokens
44+
45+
| Token | Beschrijving |
46+
| ------------------------------------- | ------------------------------------------ |
47+
| `--dsn-container-background-color` | Achtergrond — `neutral.bg-elevated` |
48+
| `--dsn-container-border-color` | Borderkleur — `neutral.border-subtle` |
49+
| `--dsn-container-border-radius` | Afronding — `border.radius.md` (8px) |
50+
| `--dsn-container-border-width` | Breedte — `border.width.thin` (1px) |
51+
| `--dsn-container-box-shadow` | Standaard geen schaduw (`none`) |
52+
| `--dsn-container-color` | Tekstkleur — `neutral.color-document` |
53+
| `--dsn-container-padding-block` | Verticale padding — `space.block.3xl` |
54+
| `--dsn-container-padding-inline` | Horizontale padding — `space.inline.3xl` |
55+
| `--dsn-container-elevated-box-shadow` | Schaduw elevated variant — `box-shadow.sm` |
56+
57+
## Accessibility
58+
59+
Container voegt geen ARIA-rollen of labels toe. Gebruik de `as` prop voor semantisch correcte HTML. Bij `as="section"` of `as="aside"` met een heading: voeg zelf `aria-labelledby` toe aan de Container en koppel het aan het `id` van de heading.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Meta, Story, Controls, Markdown } from '@storybook/blocks';
2+
import * as ContainerStories from './Container.stories';
3+
import docs from './Container.docs.md?raw';
4+
import { PreviewFrame, CodeTabs } from './components';
5+
6+
export const [intro, rest] = docs.split('<!-- VOORBEELD -->');
7+
8+
<Meta of={ContainerStories} />
9+
10+
<Markdown>{intro}</Markdown>
11+
12+
## Voorbeeld
13+
14+
<PreviewFrame>
15+
<Story of={ContainerStories.Default} />
16+
</PreviewFrame>
17+
18+
<CodeTabs
19+
of={ContainerStories.Default}
20+
html={`<div class="dsn-container">
21+
<p class="dsn-paragraph">Inhoud van de container.</p>
22+
</div>`}
23+
/>
24+
25+
<Controls of={ContainerStories.Default} />
26+
27+
<Markdown>{rest}</Markdown>

0 commit comments

Comments
 (0)