refactor(ui): localize component styles

This commit is contained in:
2026-08-09 13:47:01 +05:30
parent b6bd5cfcb7
commit 54a93c1d14
37 changed files with 4508 additions and 3832 deletions
+24 -17
View File
@@ -10,6 +10,13 @@ import { renderThemeCss, resolveThemeConfig } from "../../styles/src/theme.ts";
// bundled for the browser.
import { uiComponentNames, uiComponentsDir, uiComponentPath, uiCss } from "../src/registry.ts";
function uiStyles(): string {
return [
uiCss(),
...uiComponentNames().map((name) => readFileSync(uiComponentPath(name), "utf8")),
].join("\n");
}
test("bundled UI assets are discoverable and readable", () => {
expect(uiComponentNames()).toContain("Button");
expect(uiComponentNames()).toContain("Accordion");
@@ -20,7 +27,7 @@ test("bundled UI assets are discoverable and readable", () => {
});
test("global UI CSS stays below its migration ratchet", () => {
expect(gzipSync(new TextEncoder().encode(uiCss())).length).toBeLessThanOrEqual(26_004);
expect(gzipSync(new TextEncoder().encode(uiCss())).length).toBeLessThanOrEqual(12_672);
});
test("generated component reference documents every bundled component and its props", () => {
@@ -420,7 +427,7 @@ test("footer renders header and link entries with the requested column count", a
});
test("component-system CSS includes responsive, theme-token, focus, and reduced-motion rules", () => {
const css = uiCss();
const css = uiStyles();
expect(css).toContain("@media (max-width: 768px)");
expect(css).toContain("@media (max-width: 480px)");
expect(css).toContain("@media (prefers-reduced-motion: reduce)");
@@ -448,7 +455,7 @@ test("component-system CSS includes responsive, theme-token, focus, and reduced-
* unchanged; only where they live moved.
*/
const navbarSource = readFileSync(uiComponentPath("Navbar"), "utf8");
expect(css).not.toContain(".wire-navbar");
expect(uiCss()).not.toContain(".wire-navbar");
expect(navbarSource).toMatch(
/\.wire-navbar__brand-copy strong\s*\{[^}]*font-size: 0\.9rem;[^}]*font-weight: 600;/s,
);
@@ -522,8 +529,8 @@ test("icon buttons expose their accessible label as a hover and focus tooltip",
const button = readFileSync(uiComponentPath("Button"), "utf8");
expect(button).toContain('class="wire-btn__tooltip"');
expect(button).toContain("{ariaLabel || label}");
expect(uiCss()).toContain(".wire-btn:hover > .wire-btn__tooltip");
expect(uiCss()).toContain(".wire-btn:focus-visible > .wire-btn__tooltip");
expect(uiStyles()).toContain(".wire-btn:hover > .wire-btn__tooltip");
expect(uiStyles()).toContain(".wire-btn:focus-visible > .wire-btn__tooltip");
});
test("button links navigate by default and only download when the native attribute is passed", () => {
@@ -593,7 +600,7 @@ test("button group supports vertical, responsive, detached, and toolbar layouts"
expect(group.getAttribute("data-attached")).toBe("false");
expect(group.querySelector('[class*="icon-[lucide--bold]"]')).not.toBeNull();
const css = uiCss();
const css = uiStyles();
expect(css).toContain('.wire-next--button-group[data-orientation="vertical"]');
expect(css).toContain('.wire-next--button-group[data-responsive="true"]');
expect(css).toContain('.wire-next--button-group[data-attached="false"]');
@@ -727,7 +734,7 @@ test("dismissible alert hides itself and emits dismiss details", async () => {
});
test("solid alert palettes preserve readable foregrounds and compact inline layout", () => {
const css = uiCss();
const css = uiStyles();
expect(css).toContain('.wire-next--alert[data-color="secondary"]');
expect(css).toContain("--wire-alert-color: #737373");
@@ -747,7 +754,7 @@ test("alert exposes configurable radius and elevation treatments", async () => {
});
const dom = mountHtml(html);
const root = dom.querySelector("[data-wrn-alert]") as HTMLElement;
const css = uiCss();
const css = uiStyles();
expect(root.dataset.radius).toBe("xl");
expect(root.dataset.shadow).toBe("lg");
@@ -798,7 +805,7 @@ test("avatar renders images, fallbacks, presence, badges, tooltips, and media co
const placeholderDom = mountHtml(await renderComponent(source, { size: "sm" }));
expect(placeholderDom.querySelector(".wire-next__avatar-placeholder")).not.toBeNull();
expect(source).not.toContain("items =");
expect(uiCss()).toContain('.wire-next__avatar-wrap[data-shape="rounded"]');
expect(uiStyles()).toContain('.wire-next__avatar-wrap[data-shape="rounded"]');
});
test("avatar group limits members and opens an accessible overflow menu", async () => {
@@ -841,7 +848,7 @@ test("avatar group limits members and opens an accessible overflow menu", async
"true",
);
expect(eventDetail).toEqual(expect.objectContaining({ open: true, hiddenCount: 2 }));
expect(uiCss()).toContain('.wire-next--avatar-group[data-layout="grid"]');
expect(uiStyles()).toContain('.wire-next--avatar-group[data-layout="grid"]');
});
test("badge supports rich content, anchored placement, animation, and dismissal", async () => {
@@ -880,7 +887,7 @@ test("badge supports rich content, anchored placement, animation, and dismissal"
expect(dom.querySelector("[data-wrn-badge]")?.getAttribute("data-show")).toBe("false");
expect(dismissed).toBe("Christina");
expect(source).not.toContain("items =");
expect(uiCss()).toContain("@keyframes wire-badge-ping");
expect(uiStyles()).toContain("@keyframes wire-badge-ping");
});
test("blockquote renders semantic quote and citation content", async () => {
@@ -930,7 +937,7 @@ test("blockquote supports bordered, right-aligned, non-italic, and slotted quote
expect(figure.querySelector(".wire-next__blockquote-mark")).toBeNull();
expect(source).toContain("<slot />");
const css = uiCss();
const css = uiStyles();
expect(css).toContain('.wire-next--blockquote[data-variant="bordered"]');
expect(css).toContain('.wire-next--blockquote[data-align="center"]');
expect(css).toContain("--wire-blockquote-font-size");
@@ -1031,7 +1038,7 @@ test("card supports overlays, horizontal media, groups, alerts, empty and scroll
"true",
);
const css = uiCss();
const css = uiStyles();
expect(css).toContain('.wire-next--card[data-layout="horizontal"]');
expect(css).toContain('.wire-next--card[data-hover="image"]');
expect(css).toContain(".wire-next__card-group");
@@ -1088,7 +1095,7 @@ test("chat bubble renders conversations, avatars, metadata, links, and public ev
expect(dom.querySelectorAll(".wire-next__chat-message")).toHaveLength(2);
expect(dom.querySelectorAll(".wire-next__chat-content li")).toHaveLength(2);
expect(dom.querySelector(".wire-next__chat-meta[data-tone='danger']")).not.toBeNull();
expect(uiCss()).toContain("color: var(--wire-color-primary-contrast, #fff)");
expect(uiStyles()).toContain("color: var(--wire-color-primary-contrast, #fff)");
(dom.querySelector(".wire-next__chat-content") as HTMLElement).click();
(dom.querySelector(".wire-next__chat-avatar") as HTMLButtonElement).click();
@@ -1127,7 +1134,7 @@ test("collapse toggles accessible panels and emits open, close, and toggle event
expect(trigger.getAttribute("aria-controls")).toBe("product-details");
expect(panel.dataset.open).toBe("true");
expect(panel.getAttribute("aria-hidden")).toBe("false");
expect(uiCss()).toContain("max-height: 40rem");
expect(uiStyles()).toContain("max-height: 40rem");
expect(trigger.textContent).toContain("Collapse");
trigger.click();
@@ -1546,7 +1553,7 @@ test("carousel supports RTL, multiple slides, dragging, snap, and thumbnail layo
expect(snapRoot.dataset.snap).toBe("true");
expect(snapRoot.dataset.draggable).toBe("false");
const css = uiCss();
const css = uiStyles();
expect(css).toContain('.wire-next--carousel[data-rtl="true"]');
expect(css).toContain('.wire-next--carousel[data-snap="true"]');
expect(css).toContain('.wire-next--carousel[data-thumbnails="vertical"]');
@@ -2276,7 +2283,7 @@ test("strong password scores input, supports custom special characters, and open
});
test("strong password completed requirements use a proper checkmark indicator", () => {
const css = uiCss();
const css = uiStyles();
expect(css).toContain(
'.wire-next__strong-password-requirements li[data-met="true"] > span::after',