Skip to content

Commit 779c237

Browse files
Jeffrey Lauwersclaude
andcommitted
feat(Backdrop): voeg Backdrop component toe (issue #113)
Vaste, volledig-scherm overlay voor Modal Dialog en Drawer. Bevat design tokens, HTML/CSS, React component met blur prop, Storybook stories en volledige documentatie. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 28c68c9 commit 779c237

17 files changed

Lines changed: 528 additions & 11 deletions

File tree

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pnpm --filter @dsn/design-tokens watch
6565
# Start Storybook in development mode
6666
pnpm dev
6767

68-
# Run tests (1125 tests across 54 test suites)
68+
# Run tests (1133 tests across 55 test suites)
6969
pnpm test
7070

7171
# Run tests in watch mode
@@ -187,11 +187,12 @@ All components are fully typed with TypeScript and include comprehensive JSDoc d
187187
| **Paragraph** | Yes | Yes | Yes |
188188
| **UnorderedList** | Yes | Yes | Yes |
189189

190-
**Display & Feedback Components (7)**
190+
**Display & Feedback Components (8)**
191191

192192
| Component | HTML/CSS | React | Web Component |
193193
| --------------- | -------- | ----- | ------------- |
194194
| **Alert** | Yes | Yes ||
195+
| **Backdrop** | Yes | Yes ||
195196
| **Card** | Yes | Yes ||
196197
| **Details** | Yes | Yes ||
197198
| **DotBadge** | Yes | Yes ||
@@ -372,7 +373,7 @@ Comprehensive documentation is available in the `/docs` folder:
372373

373374
- **Pre-commit hooks** via Husky + lint-staged (ESLint + Prettier)
374375
- **Type checking** across all packages (`pnpm type-check`)
375-
- **1125 tests** covering React components, Web Components, and utilities
376+
- **1133 tests** covering React components, Web Components, and utilities
376377
- **CI/CD** via GitHub Actions (lint, type-check, test, build)
377378

378379
## Tech Stack

docs/03-components.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,58 @@ Brengt consistente verticale ruimte aan tussen directe child-elementen via `flex
761761

762762
## Display & Feedback Components
763763

764-
**Status:** Complete (HTML/CSS, React) — 7 components total
764+
**Status:** Complete (HTML/CSS, React) — 8 components total
765+
766+
### Backdrop
767+
768+
**Status:** Complete (HTML/CSS, React)
769+
770+
**Location:** `packages/components-{html|react}/src/backdrop/` / `packages/components-react/src/Backdrop/`
771+
772+
**Tokens:** `tokens/components/backdrop.json` + `tokens/themes/start/colors-light.json` / `colors-dark.json`
773+
774+
**Features:**
775+
776+
- `position: fixed; inset: 0` — bedekt het volledige viewport
777+
- Semi-transparante overlay via `color-mix(in srgb, var(--dsn-backdrop-background-color) var(--dsn-backdrop-opacity), transparent)` — kleur en transparantie via losse tokens
778+
- `backdrop-filter: blur()` — valt gracefully weg bij browsers zonder support (~6%); fallback via `dsn-backdrop--no-blur` modifier of `blur={false}` prop
779+
- Altijd `aria-hidden="true"` — puur decoratief, geen ARIA-rol
780+
- `background-color` per thema apart gedefinieerd zodat overlay altijd donker is, ongeacht light/dark mode (patroon identiek aan box-shadow kleurtokens)
781+
- `blur` prop (boolean, default `true`) — togglet `dsn-backdrop--no-blur` modifier
782+
783+
**CSS klassen:**
784+
785+
| Klasse | Element | Beschrijving |
786+
| ----------------------- | ------- | ---------------------------------------------------------------------- |
787+
| `dsn-backdrop` | `<div>` | Vaste overlay over het volledige viewport; semi-transparante blur-laag |
788+
| `dsn-backdrop--no-blur` | `<div>` | Modifier — schakelt backdrop-filter uit (fallback) |
789+
790+
**Props (React):**
791+
792+
| Prop | Type | Default | Beschrijving |
793+
| ------ | --------------------------- | ------- | ---------------------------------------------------------------- |
794+
| `blur` | `boolean` | `true` | Schakelt blur-filter in/uit via `dsn-backdrop--no-blur` modifier |
795+
| `ref` | `React.Ref<HTMLDivElement>` || Doorgegeven via `React.forwardRef` |
796+
797+
**Gebruik:**
798+
799+
```html
800+
<!-- HTML/CSS — basis -->
801+
<div class="dsn-backdrop" aria-hidden="true"></div>
802+
803+
<!-- HTML/CSS — zonder blur (fallback) -->
804+
<div class="dsn-backdrop dsn-backdrop--no-blur" aria-hidden="true"></div>
805+
```
806+
807+
```tsx
808+
// React — conditioneel renderen vanuit parent
809+
{
810+
isOpen && <Backdrop />;
811+
}
812+
{
813+
isOpen && <Backdrop blur={false} />;
814+
}
815+
```
765816

766817
### Card
767818

docs/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Design System Documentation
22

3-
**Version:** 5.13.0
4-
**Last Updated:** March 23, 2026
3+
**Version:** 5.14.0
4+
**Last Updated:** March 25, 2026
55

66
Complete documentation voor het Design System Starter Kit.
77

@@ -91,8 +91,8 @@ Complete documentation voor het Design System Starter Kit.
9191

9292
- **Tokens per configuration:** ~1100 (400 semantic + 700 component)
9393
- **Configurations:** 8 (2 themes × 2 modes × 2 project types)
94-
- **Components:** 44 (4 layout + 9 content + 7 display/feedback + 25 form; HTML/CSS + React)
95-
- **Tests:** 1125 across 54 test suites
94+
- **Components:** 45 (4 layout + 9 content + 8 display/feedback + 25 form; HTML/CSS + React)
95+
- **Tests:** 1133 across 55 test suites
9696
- **Storybook stories:** 130+
9797

9898
---

docs/changelog.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@ All notable changes to this project are documented in this file.
66

77
---
88

9+
## Version 5.14.0 (March 25, 2026)
10+
11+
### Backdrop component (issue #113)
12+
13+
#### Added
14+
15+
- **Backdrop** component — vaste, volledig-scherm overlay die de achtergrondinhoud verhult achter een Modal Dialog of Drawer (PR #114)
16+
- `<div class="dsn-backdrop" aria-hidden="true">` — altijd decoratief, geen ARIA-rol
17+
- `dsn-backdrop--no-blur` modifier — schakelt `backdrop-filter: blur()` uit voor omgevingen zonder support
18+
- Component tokens: `--dsn-backdrop-background-color`, `--dsn-backdrop-opacity` (50%), `--dsn-backdrop-blur` (4px), `--dsn-backdrop-z-index` (400)
19+
- Kleurtoken `backdrop.background-color` in zowel `colors-light.json` als `colors-dark.json` — altijd donker ongeacht light/dark mode (zelfde patroon als box-shadow kleurtokens)
20+
- Semi-transparantie via `color-mix(in srgb, ...)` met expliciete fallback voor browsers zonder support
21+
- React `blur` prop (boolean, default `true`) — togglet `dsn-backdrop--no-blur` modifier
22+
- 8 React tests
23+
24+
---
25+
926
## Version 5.13.2 (March 23, 2026)
1027

1128
### Storybook story-structuur — consistentie (PR #111)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Backdrop Component
3+
* Vaste, volledig-scherm overlay die de achtergrondinhoud visueel verhult
4+
* wanneer een modaal UI-element open is (Modal Dialog, Drawer).
5+
*
6+
* Altijd aria-hidden="true" — puur decoratief, geen interactieve rol.
7+
* Conditioneel renderen vanuit de parent.
8+
*
9+
* Usage:
10+
* <div class="dsn-backdrop" aria-hidden="true"></div>
11+
*/
12+
13+
.dsn-backdrop {
14+
position: fixed;
15+
inset: 0;
16+
/* Fallback voor omgevingen zonder color-mix() support (~6%) */
17+
background-color: var(--dsn-backdrop-background-color);
18+
background-color: color-mix(
19+
in srgb,
20+
var(--dsn-backdrop-background-color) var(--dsn-backdrop-opacity),
21+
transparent
22+
);
23+
backdrop-filter: blur(var(--dsn-backdrop-blur));
24+
z-index: var(--dsn-backdrop-z-index);
25+
}
26+
27+
.dsn-backdrop--no-blur {
28+
backdrop-filter: none;
29+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import '../../../components-html/src/backdrop/backdrop.css';
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { render } from '@testing-library/react';
3+
import { Backdrop } from './Backdrop';
4+
5+
describe('Backdrop', () => {
6+
it('renders as a <div> element', () => {
7+
const { container } = render(<Backdrop />);
8+
expect(container.firstChild?.nodeName).toBe('DIV');
9+
});
10+
11+
it('always has base dsn-backdrop class', () => {
12+
const { container } = render(<Backdrop />);
13+
expect(container.firstChild).toHaveClass('dsn-backdrop');
14+
});
15+
16+
it('always has aria-hidden="true"', () => {
17+
const { container } = render(<Backdrop />);
18+
expect(container.firstChild).toHaveAttribute('aria-hidden', 'true');
19+
});
20+
21+
it('does not apply no-blur class when blur is true (default)', () => {
22+
const { container } = render(<Backdrop />);
23+
expect(container.firstChild).not.toHaveClass('dsn-backdrop--no-blur');
24+
});
25+
26+
it('applies no-blur class when blur is false', () => {
27+
const { container } = render(<Backdrop blur={false} />);
28+
expect(container.firstChild).toHaveClass('dsn-backdrop--no-blur');
29+
});
30+
31+
it('applies custom className', () => {
32+
const { container } = render(<Backdrop className="custom" />);
33+
expect(container.firstChild).toHaveClass('dsn-backdrop');
34+
expect(container.firstChild).toHaveClass('custom');
35+
});
36+
37+
it('forwards ref', () => {
38+
const ref = { current: null as HTMLDivElement | null };
39+
render(<Backdrop ref={ref} />);
40+
expect(ref.current).toBeInstanceOf(HTMLDivElement);
41+
});
42+
43+
it('spreads additional HTML attributes', () => {
44+
const { container } = render(<Backdrop data-testid="backdrop" />);
45+
expect(container.firstChild).toHaveAttribute('data-testid', 'backdrop');
46+
});
47+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from 'react';
2+
import { classNames } from '@dsn/core';
3+
import './Backdrop.css';
4+
5+
export interface BackdropProps extends React.HTMLAttributes<HTMLDivElement> {
6+
/**
7+
* Schakelt het blur-filter in of uit.
8+
* Gebruik `false` als fallback voor omgevingen zonder backdrop-filter support.
9+
* @default true
10+
*/
11+
blur?: boolean;
12+
}
13+
14+
/**
15+
* Backdrop component
16+
* Vaste, volledig-scherm overlay die de achtergrondinhoud visueel verhult
17+
* wanneer een modaal UI-element open is (Modal Dialog, Drawer).
18+
*
19+
* Altijd aria-hidden="true" — puur decoratief, geen interactieve rol.
20+
* Conditioneel renderen vanuit de parent.
21+
*
22+
* @example
23+
* ```tsx
24+
* {isOpen && <Backdrop />}
25+
* {isOpen && <Backdrop blur={false} />}
26+
* ```
27+
*/
28+
export const Backdrop = React.forwardRef<HTMLDivElement, BackdropProps>(
29+
({ className, blur = true, ...props }, ref) => {
30+
return (
31+
<div
32+
ref={ref}
33+
className={classNames(
34+
'dsn-backdrop',
35+
!blur && 'dsn-backdrop--no-blur',
36+
className
37+
)}
38+
aria-hidden="true"
39+
{...props}
40+
/>
41+
);
42+
}
43+
);
44+
45+
Backdrop.displayName = 'Backdrop';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { Backdrop } from './Backdrop';
2+
export type { BackdropProps } from './Backdrop';

packages/components-react/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export * from './RadioOption';
4848
export * from './OptionLabel';
4949

5050
// Display & Feedback Components
51+
export * from './Backdrop';
5152
export * from './DotBadge';
5253
export * from './StatusBadge';
5354
export * from './Alert';

0 commit comments

Comments
 (0)