diff --git a/fixtures/react-router-docker/app/__generated__/index.css b/fixtures/react-router-docker/app/__generated__/index.css index dd85fdf13b99..2170b71f3d8f 100644 --- a/fixtures/react-router-docker/app/__generated__/index.css +++ b/fixtures/react-router-docker/app/__generated__/index.css @@ -1,4 +1,4 @@ -@media all { +@layer presets { :root { display: grid; min-height: 100%; @@ -8,7 +8,7 @@ white-space: pre-wrap; white-space-collapse: preserve; } - :where(body.w-body) { + body.w-body { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -18,7 +18,7 @@ -moz-osx-font-smoothing: grayscale; margin: 0; } - :where(h1.w-heading) { + h1.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -26,7 +26,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h2.w-heading) { + h2.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -34,7 +34,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-heading) { + h3.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -42,7 +42,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h4.w-heading) { + h4.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -50,7 +50,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h5.w-heading) { + h5.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -58,7 +58,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h6.w-heading) { + h6.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -66,7 +66,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(div.w-text) { + div.w-text { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -75,7 +75,7 @@ outline-width: 1px; min-height: 1em; } - :where(a.w-link) { + a.w-link { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -84,7 +84,7 @@ outline-width: 1px; display: inline-block; } - :where(img.w-image) { + img.w-image { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; diff --git a/fixtures/react-router-netlify/app/__generated__/index.css b/fixtures/react-router-netlify/app/__generated__/index.css index dd85fdf13b99..2170b71f3d8f 100644 --- a/fixtures/react-router-netlify/app/__generated__/index.css +++ b/fixtures/react-router-netlify/app/__generated__/index.css @@ -1,4 +1,4 @@ -@media all { +@layer presets { :root { display: grid; min-height: 100%; @@ -8,7 +8,7 @@ white-space: pre-wrap; white-space-collapse: preserve; } - :where(body.w-body) { + body.w-body { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -18,7 +18,7 @@ -moz-osx-font-smoothing: grayscale; margin: 0; } - :where(h1.w-heading) { + h1.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -26,7 +26,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h2.w-heading) { + h2.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -34,7 +34,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-heading) { + h3.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -42,7 +42,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h4.w-heading) { + h4.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -50,7 +50,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h5.w-heading) { + h5.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -58,7 +58,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h6.w-heading) { + h6.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -66,7 +66,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(div.w-text) { + div.w-text { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -75,7 +75,7 @@ outline-width: 1px; min-height: 1em; } - :where(a.w-link) { + a.w-link { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -84,7 +84,7 @@ outline-width: 1px; display: inline-block; } - :where(img.w-image) { + img.w-image { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; diff --git a/fixtures/react-router-vercel/app/__generated__/index.css b/fixtures/react-router-vercel/app/__generated__/index.css index dd85fdf13b99..2170b71f3d8f 100644 --- a/fixtures/react-router-vercel/app/__generated__/index.css +++ b/fixtures/react-router-vercel/app/__generated__/index.css @@ -1,4 +1,4 @@ -@media all { +@layer presets { :root { display: grid; min-height: 100%; @@ -8,7 +8,7 @@ white-space: pre-wrap; white-space-collapse: preserve; } - :where(body.w-body) { + body.w-body { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -18,7 +18,7 @@ -moz-osx-font-smoothing: grayscale; margin: 0; } - :where(h1.w-heading) { + h1.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -26,7 +26,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h2.w-heading) { + h2.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -34,7 +34,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-heading) { + h3.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -42,7 +42,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h4.w-heading) { + h4.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -50,7 +50,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h5.w-heading) { + h5.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -58,7 +58,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h6.w-heading) { + h6.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -66,7 +66,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(div.w-text) { + div.w-text { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -75,7 +75,7 @@ outline-width: 1px; min-height: 1em; } - :where(a.w-link) { + a.w-link { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -84,7 +84,7 @@ outline-width: 1px; display: inline-block; } - :where(img.w-image) { + img.w-image { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; diff --git a/fixtures/ssg-netlify-by-project-id/app/__generated__/index.css b/fixtures/ssg-netlify-by-project-id/app/__generated__/index.css index 3b9a2ccc741a..f94277d8c8e5 100644 --- a/fixtures/ssg-netlify-by-project-id/app/__generated__/index.css +++ b/fixtures/ssg-netlify-by-project-id/app/__generated__/index.css @@ -1,4 +1,4 @@ -@media all { +@layer presets { :root { display: grid; min-height: 100%; @@ -8,7 +8,7 @@ white-space: pre-wrap; white-space-collapse: preserve; } - :where(body.w-body) { + body.w-body { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -18,7 +18,7 @@ -moz-osx-font-smoothing: grayscale; margin: 0; } - :where(h1.w-heading) { + h1.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -26,7 +26,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h2.w-heading) { + h2.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -34,7 +34,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-heading) { + h3.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -42,7 +42,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h4.w-heading) { + h4.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -50,7 +50,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h5.w-heading) { + h5.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -58,7 +58,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h6.w-heading) { + h6.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; diff --git a/fixtures/ssg/app/__generated__/index.css b/fixtures/ssg/app/__generated__/index.css index dd85fdf13b99..2170b71f3d8f 100644 --- a/fixtures/ssg/app/__generated__/index.css +++ b/fixtures/ssg/app/__generated__/index.css @@ -1,4 +1,4 @@ -@media all { +@layer presets { :root { display: grid; min-height: 100%; @@ -8,7 +8,7 @@ white-space: pre-wrap; white-space-collapse: preserve; } - :where(body.w-body) { + body.w-body { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -18,7 +18,7 @@ -moz-osx-font-smoothing: grayscale; margin: 0; } - :where(h1.w-heading) { + h1.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -26,7 +26,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h2.w-heading) { + h2.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -34,7 +34,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-heading) { + h3.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -42,7 +42,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h4.w-heading) { + h4.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -50,7 +50,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h5.w-heading) { + h5.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -58,7 +58,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h6.w-heading) { + h6.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -66,7 +66,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(div.w-text) { + div.w-text { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -75,7 +75,7 @@ outline-width: 1px; min-height: 1em; } - :where(a.w-link) { + a.w-link { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -84,7 +84,7 @@ outline-width: 1px; display: inline-block; } - :where(img.w-image) { + img.w-image { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; diff --git a/fixtures/webstudio-cloudflare-template/app/__generated__/index.css b/fixtures/webstudio-cloudflare-template/app/__generated__/index.css index dd85fdf13b99..2170b71f3d8f 100644 --- a/fixtures/webstudio-cloudflare-template/app/__generated__/index.css +++ b/fixtures/webstudio-cloudflare-template/app/__generated__/index.css @@ -1,4 +1,4 @@ -@media all { +@layer presets { :root { display: grid; min-height: 100%; @@ -8,7 +8,7 @@ white-space: pre-wrap; white-space-collapse: preserve; } - :where(body.w-body) { + body.w-body { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -18,7 +18,7 @@ -moz-osx-font-smoothing: grayscale; margin: 0; } - :where(h1.w-heading) { + h1.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -26,7 +26,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h2.w-heading) { + h2.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -34,7 +34,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-heading) { + h3.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -42,7 +42,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h4.w-heading) { + h4.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -50,7 +50,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h5.w-heading) { + h5.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -58,7 +58,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h6.w-heading) { + h6.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -66,7 +66,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(div.w-text) { + div.w-text { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -75,7 +75,7 @@ outline-width: 1px; min-height: 1em; } - :where(a.w-link) { + a.w-link { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -84,7 +84,7 @@ outline-width: 1px; display: inline-block; } - :where(img.w-image) { + img.w-image { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; diff --git a/fixtures/webstudio-features/app/__generated__/index.css b/fixtures/webstudio-features/app/__generated__/index.css index 844c0255bde4..64c7211b72ea 100644 --- a/fixtures/webstudio-features/app/__generated__/index.css +++ b/fixtures/webstudio-features/app/__generated__/index.css @@ -1,4 +1,4 @@ -@media all { +@layer presets { :root { display: grid; min-height: 100%; @@ -8,7 +8,7 @@ white-space: pre-wrap; white-space-collapse: preserve; } - :where(body.w-body) { + body.w-body { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -18,7 +18,7 @@ -moz-osx-font-smoothing: grayscale; margin: 0; } - :where(h1.w-heading) { + h1.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -26,7 +26,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h2.w-heading) { + h2.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -34,7 +34,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-heading) { + h3.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -42,7 +42,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h4.w-heading) { + h4.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -50,7 +50,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h5.w-heading) { + h5.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -58,7 +58,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h6.w-heading) { + h6.w-heading { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -66,7 +66,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(div.w-box) { + div.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -74,7 +74,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(address.w-box) { + address.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -82,7 +82,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(article.w-box) { + article.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -90,7 +90,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(aside.w-box) { + aside.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -98,7 +98,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(figure.w-box) { + figure.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -106,7 +106,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(footer.w-box) { + footer.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -114,7 +114,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(header.w-box) { + header.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -122,7 +122,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(main.w-box) { + main.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -130,7 +130,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(nav.w-box) { + nav.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -138,7 +138,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(section.w-box) { + section.w-box { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -146,7 +146,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(p.w-paragraph) { + p.w-paragraph { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -154,7 +154,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(img.w-image) { + img.w-image { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -165,7 +165,7 @@ display: block; height: auto; } - :where(a.w-link) { + a.w-link { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -174,7 +174,7 @@ outline-width: 1px; display: inline-block; } - :where(div.w-text) { + div.w-text { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -183,7 +183,7 @@ outline-width: 1px; min-height: 1em; } - :where(div.w-accordion) { + div.w-accordion { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -191,7 +191,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(div.w-item) { + div.w-item { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -199,7 +199,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(h3.w-item-header) { + h3.w-item-header { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -209,7 +209,7 @@ margin-top: 0px; margin-bottom: 0px; } - :where(button.w-item-trigger) { + button.w-item-trigger { font-family: inherit; font-size: 100%; line-height: 1.15; @@ -221,12 +221,12 @@ margin: 0; padding: 0px; } - :where(div.w-html-embed) { + div.w-html-embed { display: contents; white-space: normal; white-space-collapse: collapse; } - :where(div.w-item-content) { + div.w-item-content { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -234,7 +234,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(form.w-webhook-form) { + form.w-webhook-form { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -242,7 +242,7 @@ border-left-width: 1px; outline-width: 1px; } - :where(label.w-input-label) { + label.w-input-label { box-sizing: border-box; border-top-width: 1px; border-right-width: 1px; @@ -251,7 +251,7 @@ outline-width: 1px; display: block; } - :where(input.w-text-input) { + input.w-text-input { font-family: inherit; font-size: 100%; line-height: 1.15; @@ -267,7 +267,7 @@ display: block; margin: 0; } - :where(button.w-button) { + button.w-button { font-family: inherit; font-size: 100%; line-height: 1.15; diff --git a/packages/sdk/src/css.test.tsx b/packages/sdk/src/css.test.tsx index b43efe6a5d62..ce81a469cb15 100644 --- a/packages/sdk/src/css.test.tsx +++ b/packages/sdk/src/css.test.tsx @@ -182,11 +182,11 @@ test("generate component presets with multiple tags", () => { assetBaseUrl: "", }); expect(cssText).toMatchInlineSnapshot(` -"@media all { - :where(div.w-list-item) { +"@layer presets { + div.w-list-item { display: block } - :where(a.w-list-item) { + a.w-list-item { -webkit-user-select: none; user-select: none } @@ -256,14 +256,14 @@ test("deduplicate component presets for similarly named components", () => { assetBaseUrl: "", }); expect(cssText).toMatchInlineSnapshot(` -"@media all { - :where(div.w-list-item) { +"@layer presets { + div.w-list-item { display: block } - :where(div.w-list-item-1) { + div.w-list-item-1 { display: flex } - :where(div.w-list-item-2) { + div.w-list-item-2 { display: grid } } @@ -326,11 +326,11 @@ test("expose preset classes to instances", () => { assetBaseUrl: "", }); expect(atomicCssText).toMatchInlineSnapshot(` -"@media all { - :where(div.w-body) { +"@layer presets { + div.w-body { display: block } - :where(div.w-box) { + div.w-box { display: flex } } @@ -424,11 +424,11 @@ test("generate classes with instance and meta label", () => { assetBaseUrl: "", }); expect(cssText).toMatchInlineSnapshot(` -"@media all { - :where(div.w-body-meta-label) { +"@layer presets { + div.w-body-meta-label { display: block } - :where(div.w-box-meta-label) { + div.w-box-meta-label { display: flex } } @@ -507,7 +507,7 @@ test("generate :root preset and user styles", () => { assetBaseUrl: "", }); expect(cssText).toMatchInlineSnapshot(` -"@media all { +"@layer presets { :root { display: grid } @@ -521,7 +521,7 @@ test("generate :root preset and user styles", () => { `); expect(classes).toEqual(new Map()); expect(atomicCssText).toMatchInlineSnapshot(` -"@media all { +"@layer presets { :root { display: grid } diff --git a/packages/sdk/src/css.ts b/packages/sdk/src/css.ts index 2e7f71d579e5..44e164c526db 100644 --- a/packages/sdk/src/css.ts +++ b/packages/sdk/src/css.ts @@ -90,11 +90,12 @@ export const generateCss = ({ assetBaseUrl, atomic, }: CssConfig) => { - const globalSheet = createRegularStyleSheet({ name: "ssr" }); - const sheet = createRegularStyleSheet({ name: "ssr" }); + const fontSheet = createRegularStyleSheet({ name: "ssr" }); + const presetSheet = createRegularStyleSheet({ name: "ssr" }); + const userSheet = createRegularStyleSheet({ name: "ssr" }); - addFontRules({ sheet: globalSheet, assets, assetBaseUrl }); - globalSheet.addMediaRule("presets"); + addFontRules({ sheet: fontSheet, assets, assetBaseUrl }); + presetSheet.addMediaRule("presets"); const presetClasses = new Map(); const scope = createScope([], normalizeClassName, "-"); for (const [component, meta] of componentMetas) { @@ -105,14 +106,15 @@ export const generateCss = ({ // add preset class only when at least one style is defined presetClasses.set(component, className); } + // @todo reset specificity with css cascade layers instead of :where for (const [tag, styles] of presetStyle) { // use :where() to reset specificity of preset selector // and let user styles completely override it // ideally switch to @layer when better supported // render root preset styles without changes const selector = - component === rootComponent ? ":root" : `:where(${tag}.${className})`; - const rule = globalSheet.addNestingRule(selector); + component === rootComponent ? ":root" : `${tag}.${className}`; + const rule = presetSheet.addNestingRule(selector); for (const declaration of styles) { rule.setDeclaration({ breakpoint: "presets", @@ -125,16 +127,16 @@ export const generateCss = ({ } for (const breakpoint of breakpoints.values()) { - sheet.addMediaRule(breakpoint.id, breakpoint); + userSheet.addMediaRule(breakpoint.id, breakpoint); } const imageValueTransformer = createImageValueTransformer(assets, { assetBaseUrl, }); - sheet.setTransformer(imageValueTransformer); + userSheet.setTransformer(imageValueTransformer); for (const styleDecl of styles.values()) { - const rule = sheet.addMixinRule(styleDecl.styleSourceId); + const rule = userSheet.addMixinRule(styleDecl.styleSourceId); rule.setDeclaration({ breakpoint: styleDecl.breakpointId, selector: styleDecl.state ?? "", @@ -170,7 +172,7 @@ export const generateCss = ({ const { values } = selection; // special case for :root styles if (instanceId === ROOT_INSTANCE_ID) { - const rule = sheet.addNestingRule(`:root`); + const rule = userSheet.addNestingRule(`:root`); rule.applyMixins(values); // avoid storing in instanceByRule to prevent conversion into atomic styles continue; @@ -201,21 +203,34 @@ export const generateCss = ({ } classList.push(className); } - const rule = sheet.addNestingRule(`.${className}`, descendantSuffix); + const rule = userSheet.addNestingRule(`.${className}`, descendantSuffix); rule.applyMixins(values); instanceByRule.set(rule, instanceId); } + const fontCss = fontSheet.cssText; + // render presets inside of cascade layer to let user completely override all properties + // user agent (browser) styles work in the same way + // for example a { color: black } overrides a:visited as well + // @todo figure out proper API to work with layers when more use cases are known + const presetCss = presetSheet.cssText.replaceAll( + "@media all ", + "@layer presets " + ); + if (atomic) { - const { cssText } = generateAtomic(sheet, { + const { cssText } = generateAtomic(userSheet, { getKey: (rule) => instanceByRule.get(rule), transformValue: imageValueTransformer, classes, }); - return { cssText: `${globalSheet.cssText}\n${cssText}`, classes }; + return { + cssText: `${fontCss}${presetCss}\n${cssText}`, + classes, + }; } return { - cssText: `${globalSheet.cssText}\n${sheet.cssText}`, + cssText: `${fontCss}${presetCss}\n${userSheet.cssText}`, classes, }; };