Files
atomic-design-poc/src/app/shared/ui/stepper/stepper.component.ts
Edwin van den Houdt 7a582ae2fa Rijkshuisstijl restyle + wizard fixes
Chrome: two-tier Rijksoverheid header (white brand bar + lint-blue
breadcrumb bar, route-driven), dark multi-column footer, white page
surface. Session shown via a shared SESSION_PORT token (keeps shared/
free of the auth context).

Overview ("Mijn overzicht") rebuilt to the NL Design System #392 pattern:
side-nav + "Wat moet ik regelen" task list (derived) + "Mijn registratie"
cards. New shared components: card, task-list, side-nav; pure
tasksFromProfile (+spec).

Wizards: grey form panel, connected numbered stepper, form-field
"(verplicht)" markers + styled description/error, full-width inputs.
Propagated to login, detail, change-request, address-fields.

Bug fixes:
- wizard-shell: add FormsModule so NgForm intercepts submit (wizards now
  advance; no native GET leaking choices into the URL).
- wizard-shell: error-summary links focus the field instead of navigating
  (a fragment href resolved against <base href="/"> reloaded to "/" and
  bounced to login).
- wizard-shell: error-summary focus only on the rising edge, so typing
  while errors are shown no longer scrolls the page up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 13:21:54 +02:00

62 lines
2.9 KiB
TypeScript

import { Component, input } from '@angular/core';
/** Molecule: a horizontal step indicator for a multi-step flow. Visual progress
plus accessible semantics — an ordered list with `aria-current="step"` on the
active step and a visually-hidden "Stap X van Y" summary. Domain-free. */
@Component({
selector: 'app-stepper',
styles: [`
:host{display:block}
.sr-only{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.steps{display:flex;list-style:none;margin:0;padding:0}
.step{
flex:1 1 0;min-inline-size:0;position:relative;
display:flex;flex-direction:column;align-items:center;gap:var(--rhc-space-max-sm);
text-align:center;color:var(--rhc-color-foreground-subtle);
}
/* connector line to the previous step, drawn behind the circles */
.step::before{
content:'';position:absolute;z-index:0;
inset-block-start:calc(var(--rhc-space-max-4xl) / 2);
inset-inline-start:-50%;inline-size:100%;block-size:var(--rhc-border-width-md);
background:var(--rhc-color-cool-grey-300);
}
.step:first-child::before{display:none}
.step--done::before,.step--current::before{background:var(--rhc-color-lintblauw-500)}
.num{
position:relative;z-index:1;display:grid;place-items:center;
inline-size:var(--rhc-space-max-4xl);block-size:var(--rhc-space-max-4xl);
border-radius:var(--rhc-border-radius-round);
border:var(--rhc-border-width-md) solid var(--rhc-color-cool-grey-300);
background:var(--rhc-color-wit);
font-weight:var(--rhc-text-font-weight-bold);
}
.label{font-size:var(--rhc-text-font-size-sm);padding-inline:var(--rhc-space-max-sm)}
.step--done .num{background:var(--rhc-color-lintblauw-500);border-color:var(--rhc-color-lintblauw-500);color:var(--rhc-color-foreground-on-primary)}
.step--current{color:var(--rhc-color-foreground-default)}
.step--current .num{background:var(--rhc-color-lintblauw-700);border-color:var(--rhc-color-lintblauw-700);color:var(--rhc-color-foreground-on-primary)}
.step--current .label{font-weight:var(--rhc-text-font-weight-semi-bold)}
`],
template: `
<nav aria-label="Voortgang">
<p class="sr-only">Stap {{ current() + 1 }} van {{ steps().length }}: {{ steps()[current()] }}</p>
<ol class="steps">
@for (label of steps(); track label; let i = $index) {
<li
class="step"
[class.step--current]="i === current()"
[class.step--done]="i < current()"
[attr.aria-current]="i === current() ? 'step' : null">
<span class="num" aria-hidden="true">{{ i + 1 }}</span>
<span class="label">{{ label }}</span>
</li>
}
</ol>
</nav>
`,
})
export class StepperComponent {
steps = input.required<string[]>();
current = input.required<number>();
}