refactor(ui): localize component styles
This commit is contained in:
+24
-17
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user