metis-desk/packages/rdx-ui/src/components/form-progress.tsx
David 6b086e17f2 Add visual regression tests for UI components using Playwright
- Implemented a new test suite in `visual-audit-ui.test.py` to perform visual audits on the UI.
- Tests include checking row contrast, wizard geometry, focus behavior, and review headers across different screen sizes.
- Utilizes Playwright for browser automation and captures visual snapshots for comparison.
- Ensures that the tests run against a synthetic session state for accurate results.
2026-10-21 19:31:09 +02:00

71 lines
2.5 KiB
TypeScript

/** Indicador de pasos sin conocimiento del formulario o de sus datos. */
export function FormProgress({
step,
labels,
label,
progress,
completedLabel,
description,
}: {
step: number;
labels: readonly string[];
label: string;
progress: string;
completedLabel: string;
description: string;
}) {
return (
<div className="space-y-5">
<ol aria-label={label} className="flex gap-3 border-b border-border/60 pb-5">
{labels.map((title, index) => {
const current = step === index + 1;
const completed = step > index + 1;
return (
<li
aria-current={current ? "step" : undefined}
className="flex min-w-0 flex-1 flex-col items-start gap-2 sm:flex-row sm:items-center sm:gap-3"
key={title}
>
<span
aria-hidden="true"
className={`flex size-8 shrink-0 items-center justify-center rounded-full border text-sm font-semibold ${current ? "border-primary bg-primary text-primary-foreground" : completed ? "border-primary/30 bg-primary/10 text-primary" : "border-border bg-muted/50 text-muted-foreground"}`}
>
{completed ? "✓" : index + 1}
</span>
<span
className={`text-xs leading-snug sm:text-sm ${current ? "font-semibold text-foreground" : "text-muted-foreground"}`}
>
{title}
{completed && <span className="sr-only">{completedLabel}</span>}
</span>
</li>
);
})}
</ol>
<div className="space-y-2">
<div className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1 sr-only">
<h2 className="text-base font-semibold">{labels[step - 1]}</h2>
<p
aria-live="polite"
className="text-xs text-muted-foreground focus-visible:rounded-sm focus-visible:outline-2 focus-visible:outline-ring"
key={step}
ref={focusStep}
role="status"
tabIndex={-1}
>
{progress}
</p>
</div>
<p className="text-sm leading-relaxed text-muted-foreground">{description}</p>
</div>
</div>
);
}
function focusStep(element: HTMLParagraphElement | null) {
// Cada paso empieza arriba; enfocar el anuncio oculto no debe desplazar su indicador.
element?.closest("[data-slot=form-body]")?.scrollTo({ top: 0 });
element?.focus({ preventScroll: true });
}