feat(ui): build the Stepper component

Replaces a scaffold that rendered bare anchors with ordered steps: complete,
current and upcoming status derived from the active index, horizontal or
vertical, optional icons, and indexed named slots (step-0, step-1, ...) for
authoring a step body by hand.

Also tightens the roving contract from the previous commit. A template writes
data-wrn-roving="" or data-wrn-roving-item="false" to mean not this time, but
a bare [attr] selector matches either, so a read-only stepper would still have
taken arrow-key focus. The container now requires a named axis, while a bare
item marker still counts as opted in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 16:44:12 +05:30
co-authored by Claude Opus 5
parent b67a5e43eb
commit 45ef035bae
5 changed files with 337 additions and 13 deletions
+15
View File
@@ -1030,3 +1030,18 @@ test("a hidden dialog does not trap Tab", () => {
outside.dispatchEvent(new win.KeyboardEvent("keydown", { key: "Tab", bubbles: true }));
expect(doc.activeElement!.id).toBe("outside");
});
test("an empty or false roving attribute opts the group out entirely", () => {
const win = mount(
`<div data-wrn-roving="">
<button data-wrn-roving-item="false" id="a">A</button>
<button data-wrn-roving-item="false" id="b">B</button>
</div>`,
);
const doc = win.document;
const a = doc.querySelector("#a") as unknown as HTMLElement;
expect(a.getAttribute("tabindex")).toBeNull();
a.focus();
a.dispatchEvent(new win.KeyboardEvent("keydown", { key: "ArrowRight", bubbles: true }));
expect(doc.activeElement!.id).toBe("a");
});