feat: release design system engine, studio and component contracts

This commit is contained in:
Clintchiz committed 2026-10-19 13:09:03 +05:30
1 parent ff1065fb27
commit 3943b946d6
693 files changed
+175546 -3894

No files matched your search

+82 -48
View File
@@ -90,7 +90,7 @@ test("generated component reference documents every bundled component and its pr
readFileSync(join(uiComponentsDir(), "..", "component-catalog.json"), "utf8"),
) as { components: Array<{ name: string }> };
expect(reference.count).toBe(uiComponentNames().length);
expect(reference.count).toBe(102);
expect(reference.count).toBe(104);
expect(reference.components.map((component) => component.name)).toEqual(
expect.arrayContaining(uiComponentNames()),
);
@@ -366,23 +366,17 @@ test("navbar closes sibling menus and menus close after an outside pointer press
],
});
const dom = mountHtml(html);
const menus = Array.from(dom.querySelectorAll(".wrn-navbar__dropdown")) as HTMLDetailsElement[];
const menus = Array.from(dom.querySelectorAll(".wrn-navbar__dropdown")) as HTMLElement[];
menus[0].open = true;
menus[0].dispatchEvent(
new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }),
);
menus[1].open = true;
menus[1].dispatchEvent(
new (dom.window as { Event: typeof Event }).Event("toggle", { bubbles: false }),
);
expect(menus[0].open).toBe(false);
expect(menus[1].open).toBe(true);
(menus[0].querySelector("[data-wrn-menu-toggle]") as HTMLButtonElement).click();
(menus[1].querySelector("[data-wrn-menu-toggle]") as HTMLButtonElement).click();
expect(menus[0].dataset.open).toBe("false");
expect(menus[1].dataset.open).toBe("true");
dom.document.body.dispatchEvent(
new (dom.window as { Event: typeof Event }).Event("pointerdown", { bubbles: true }),
);
expect(menus[1].open).toBe(false);
expect(menus[1].dataset.open).toBe("false");
});
test("navbar optionally opens menus on hover and renders full-width mode", async () => {
@@ -393,16 +387,16 @@ test("navbar optionally opens menus on hover and renders full-width mode", async
});
const dom = mountHtml(html);
const navbar = dom.querySelector("[data-wrn-navbar]");
const menu = dom.querySelector(".wrn-navbar__dropdown") as HTMLDetailsElement;
const menu = dom.querySelector(".wrn-navbar__dropdown") as HTMLElement;
expect(navbar?.classList.contains("wrn-navbar--width-full")).toBe(true);
expect(navbar?.getAttribute("data-open-on-hover")).toBe("true");
menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerenter"));
expect(menu.open).toBe(true);
expect(menu.dataset.open).toBe("true");
menu.dispatchEvent(new (dom.window as { Event: typeof Event }).Event("pointerleave"));
expect(menu.open).toBe(true);
expect(menu.dataset.open).toBe("true");
await new Promise((resolve) => setTimeout(resolve, 280));
expect(menu.open).toBe(false);
expect(menu.dataset.open).toBe("false");
});
test("navbar hover menu stays open while the pointer crosses into its panel", async () => {
@@ -411,7 +405,7 @@ test("navbar hover menu stays open while the pointer crosses into its panel", as
items: [{ label: "Services", children: [{ label: "Reports", href: "/reports" }] }],
});
const dom = mountHtml(html);
const menu = dom.querySelector(".wrn-navbar__dropdown") as HTMLDetailsElement;
const menu = dom.querySelector(".wrn-navbar__dropdown") as HTMLElement;
const panel = dom.querySelector(".wrn-navbar__panel") as HTMLElement;
const DomEvent = (dom.window as { Event: typeof Event }).Event;
@@ -420,7 +414,7 @@ test("navbar hover menu stays open while the pointer crosses into its panel", as
panel.dispatchEvent(new DomEvent("pointerenter", { bubbles: true }));
await new Promise((resolve) => setTimeout(resolve, 280));
expect(menu.open).toBe(true);
expect(menu.dataset.open).toBe("true");
});
test("preference switcher keeps only one popover open and closes outside", async () => {
@@ -429,18 +423,17 @@ test("preference switcher keeps only one popover open and closes outside", async
expect(source).toContain("window.wrnAccent?.set(value)");
expect(source).toContain("window.wrnTheme?.set(value)");
const dom = mountHtml(html);
const menus = Array.from(dom.querySelectorAll(".wrn-preferences__menu")) as HTMLDetailsElement[];
expect(dom.document.querySelector("details,summary")).toBeNull();
const menus = Array.from(dom.querySelectorAll(".wrn-preferences__menu")) as HTMLElement[];
const DomEvent = (dom.window as { Event: typeof Event }).Event;
menus[0].open = true;
menus[0].dispatchEvent(new DomEvent("toggle"));
menus[1].open = true;
menus[1].dispatchEvent(new DomEvent("toggle"));
expect(menus[0].open).toBe(false);
expect(menus[1].open).toBe(true);
(menus[0].querySelector("[data-wrn-menu-toggle]") as HTMLButtonElement).click();
(menus[1].querySelector("[data-wrn-menu-toggle]") as HTMLButtonElement).click();
expect(menus[0].dataset.open).toBe("false");
expect(menus[1].dataset.open).toBe("true");
dom.document.body.dispatchEvent(new DomEvent("pointerdown", { bubbles: true }));
expect(menus[1].open).toBe(false);
expect(menus[1].dataset.open).toBe("false");
});
test("sidebar renders compact grouped submenu navigation and a mobile drawer trigger", async () => {
@@ -1430,7 +1423,9 @@ test("basic fields suppress native popups and render package constraint messages
const selectSource = readFileSync(uiComponentPath("Select"), "utf8");
expect(selectSource).toContain("appearance: none");
expect(selectSource).toContain("background-color: var(--wrn-color-input-background, var(--wrn-color-surface))");
expect(selectSource).toContain(
"background-color: var(--wrn-color-input-background, var(--wrn-color-surface))",
);
expect(selectSource).toContain("wrn-next__select-indicator");
});
@@ -1672,7 +1667,9 @@ test("date picker renders a custom calendar trigger with accessible field state
expect(dom.querySelector("label")?.getAttribute("for")).toBe("start-date");
expect(dom.querySelector('button[aria-haspopup="dialog"]')).not.toBeNull();
expect(source).not.toContain('type="{type}"');
expect(dom.querySelectorAll(".wrn-next__date-selectors select")[0]?.querySelectorAll("option")).toHaveLength(12);
expect(
dom.querySelectorAll(".wrn-next__date-selectors select")[0]?.querySelectorAll("option"),
).toHaveLength(12);
expect(dom.querySelector(".wrn-next__field-help")?.textContent).toContain("local date");
const trigger = dom.querySelector('button[aria-haspopup="dialog"]') as HTMLButtonElement;
expect(dom.querySelector(".wrn-next--date-picker")?.getAttribute("data-expanded")).toBe("false");
@@ -3186,7 +3183,9 @@ test("announcement full-width surface does not create viewport scrollbar overflo
});
test("announcement status uses a compatible element and preserves live announcements", async () => {
const html = await renderComponent(readFileSync(uiComponentPath("AnnouncementBar"), "utf8"), { message: "Service update" });
const html = await renderComponent(readFileSync(uiComponentPath("AnnouncementBar"), "utf8"), {
message: "Service update",
});
const dom = mountHtml(html);
const status = dom.querySelector('[role="status"]')!;
expect(status.tagName).toBe("DIV");
@@ -3196,7 +3195,9 @@ test("announcement status uses a compatible element and preserves live announcem
test("feature grid supports arbitrary slotted articles without imposing list semantics", async () => {
const grid = await renderComponent(readFileSync(uiComponentPath("FeatureGrid"), "utf8"));
const card = await renderComponent(readFileSync(uiComponentPath("FeatureCard"), "utf8"), { title: "Feature" });
const card = await renderComponent(readFileSync(uiComponentPath("FeatureCard"), "utf8"), {
title: "Feature",
});
expect(mountHtml(grid).querySelector('[role="list"]')).toBeNull();
const dom = mountHtml(card);
expect(dom.querySelector('[role="listitem"]')).toBeNull();
@@ -3218,7 +3219,9 @@ test("mega menu trigger keeps an accessible name for an empty or missing label",
const dom = mountHtml(await renderComponent(source, { label, columns: [] }));
const trigger = dom.querySelector(".wrn-mega__trigger")!;
expect(trigger.getAttribute("aria-label")).toBe(label || "Menu");
expect(dom.querySelector(".wrn-mega__trigger-label")?.getAttribute("data-label")).toBe(label || "Menu");
expect(dom.querySelector(".wrn-mega__trigger-label")?.getAttribute("data-label")).toBe(
label || "Menu",
);
}
});
@@ -3839,27 +3842,24 @@ test("list selects items without hrefs as well as navigation items", async () =>
expect(events).toEqual([{ item: { label: "Run report" }, index: 0 }]);
});
test("chart renders accessible SVG bars and emits point and legend outputs", async () => {
test("chart renders a runtime canvas and forwards point and legend outputs", async () => {
const source = readFileSync(uiComponentPath("Chart"), "utf8");
const dom = mountHtml(
await renderComponent(source, {
items: [
{ label: "Alpha", value: 12 },
{ label: "Beta", value: 6 },
],
}),
);
const dom = mountHtml(await renderComponent(source, { items: [{ label: "Alpha", value: 12 }] }));
const root = dom.querySelector('[data-ui-component="Chart"]') as HTMLElement;
expect(root.getAttribute("data-wrnexus-runtime")).toBe("chartjs");
expect(root.querySelector("canvas")?.getAttribute("role")).toBe("img");
expect(JSON.parse(root.dataset.chartConfig!).items).toEqual([{ label: "Alpha", value: 12 }]);
const events: string[] = [];
for (const name of ["dataPointClick", "select", "legendToggle"]) {
for (const name of ["dataPointClick", "select", "legendToggle"])
root.addEventListener(name, () => events.push(name));
for (const name of ["chartpointclick", "chartselect", "chartlegendtoggle"]) {
root.dispatchEvent(
new (dom.window as { CustomEvent: typeof CustomEvent }).CustomEvent(name, {
detail: { item: 12, index: 0, datasetIndex: 0 },
bubbles: true,
}),
);
}
expect(root.querySelectorAll("svg path.wrn-chart__bar")).toHaveLength(2);
expect(root.querySelectorAll("button.wrn-chart__hit")).toHaveLength(2);
(root.querySelector("button.wrn-chart__hit") as HTMLElement).dispatchEvent(
new (dom.window as { Event: typeof Event }).Event("click", { bubbles: true }),
);
(root.querySelector(".wrn-chart__legend button") as HTMLButtonElement).click();
expect(events).toEqual(["dataPointClick", "select", "legendToggle"]);
});
@@ -3960,3 +3960,37 @@ test("a declared output is never emitted as a hand-built CustomEvent", () => {
expect([...new Set(offenders)]).toEqual([]);
});
test("Switch follows controlled checked props after a reset and remains usable uncontrolled", async () => {
const source = readFileSync(uiComponentPath("Switch"), "utf8");
const controlled = mountHtml(
await renderComponent(source, { name: "controlled-switch", checked: true }),
);
const input = controlled.querySelector("input") as HTMLInputElement;
expect(input.checked).toBe(true);
const root = controlled.querySelector(".wrn-next--choice-field")!.parentElement as HTMLElement & {
__wrnexusScopeApi: {
set(name: string, value: unknown): void;
get(name: string): unknown;
call(name: string): unknown;
};
};
expect(root.__wrnexusScopeApi).toBeDefined();
input.click();
expect(input.checked).toBe(false);
root.__wrnexusScopeApi.set("checked", false);
root.__wrnexusScopeApi.set("checked", true);
expect(input.checked).toBe(true);
root.__wrnexusScopeApi.set("checked", false);
expect(input.checked).toBe(false);
expect(input.getAttribute("aria-checked")).toBe("false");
const uncontrolled = mountHtml(await renderComponent(source, { name: "uncontrolled-switch" }));
const control = uncontrolled.querySelector("input") as HTMLInputElement;
control.checked = true;
control.dispatchEvent(
new (uncontrolled.window as { Event: typeof Event }).Event("change", { bubbles: true }),
);
expect(control.checked).toBe(true);
expect(control.getAttribute("aria-checked")).toBe("true");
});