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>
62 lines
2.9 KiB
TypeScript
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>();
|
|
}
|