feat: use classes for preset styles (#3794)

Closes https://github.com/webstudio-is/webstudio/issues/3787

Replaced [data-ws-component=...] selector with classes in generated
styles. This will unlock cleaner html output in the future.
This commit is contained in:
Bogdan Chadkin authored and GitHub committed 2024-07-26 10:45:29 +02:00
1 parent 7f1af26ad8
commit f73680027f
37 files changed
+654 -269

No files matched your search

+16 -2
View File
@@ -11,7 +11,6 @@ import {
collapsedAttribute,
idAttribute,
addGlobalRules,
addPresetRules,
createImageValueTransformer,
descendantComponent,
type Params,
@@ -324,7 +323,22 @@ export const GlobalStyles = ({ params }: { params: Params }) => {
useLayoutEffect(() => {
presetSheet.clear();
addPresetRules(presetSheet, metas);
presetSheet.addMediaRule("presets");
for (const [component, meta] of metas) {
for (const [tag, styles] of Object.entries(meta.presetStyle ?? {})) {
const rule = presetSheet.addNestingRule(
`${tag}:where([data-ws-component="${component}"])`
);
for (const declaration of styles) {
rule.setDeclaration({
breakpoint: "presets",
selector: declaration.state ?? "",
property: declaration.property,
value: declaration.value,
});
}
}
}
presetSheet.render();
}, [metas]);
+10 -2
View File
@@ -20,8 +20,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="n_VBMr7klpx25buS0NV7R" data-ws-component="Body">
<Heading data-ws-id="wthNByqb3RPmheb-56VYI" data-ws-component="Heading">
<Body
data-ws-id="n_VBMr7klpx25buS0NV7R"
data-ws-component="Body"
className="w-body"
>
<Heading
data-ws-id="wthNByqb3RPmheb-56VYI"
data-ws-component="Heading"
className="w-heading"
>
{"Another page"}
</Heading>
</Body>
+8 -3
View File
@@ -29,15 +29,19 @@ const Page = ({}: { system: any }) => {
<Body
data-ws-id="MMimeobf_zi4ZkRGXapju"
data-ws-component="Body"
className="c1jaw2zx cbipm55 ctniqj4 ctgx88l"
className="w-body c1jaw2zx cbipm55 ctniqj4 ctgx88l"
>
<Heading data-ws-id="MYDt0guk1-vzc7yzqyN6A" data-ws-component="Heading">
<Heading
data-ws-id="MYDt0guk1-vzc7yzqyN6A"
data-ws-component="Heading"
className="w-heading"
>
{"Simple Project to test CLI"}
</Heading>
<Text
data-ws-id="BMJfjOzunWs8XkQgvvx1e"
data-ws-component="Text"
className="cn3rfux"
className="w-text cn3rfux"
>
{"Please don't change directly in the fixture"}
</Text>
@@ -45,6 +49,7 @@ const Page = ({}: { system: any }) => {
data-ws-id="pjkZo5EiBqaeUXBcyHf_O"
data-ws-component="Link"
href={"/another-page"}
className="w-link"
>
{"Test another page link"}
</Link>
+9 -9
View File
@@ -4,7 +4,7 @@ html {
min-height: 100%;
}
@media all {
body:where([data-ws-component="Body"]) {
:where(body.w-body) {
font-family: Arial, Roboto, sans-serif;
font-size: 16px;
line-height: 1.2;
@@ -17,7 +17,7 @@ html {
-moz-osx-font-smoothing: grayscale;
margin: 0;
}
h1:where([data-ws-component="Heading"]) {
:where(h1.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -25,7 +25,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h2:where([data-ws-component="Heading"]) {
:where(h2.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -33,7 +33,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h3:where([data-ws-component="Heading"]) {
:where(h3.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -41,7 +41,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h4:where([data-ws-component="Heading"]) {
:where(h4.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -49,7 +49,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h5:where([data-ws-component="Heading"]) {
:where(h5.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -57,7 +57,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h6:where([data-ws-component="Heading"]) {
:where(h6.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -65,7 +65,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
div:where([data-ws-component="Text"]) {
:where(div.w-text) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -74,7 +74,7 @@ html {
outline-width: 1px;
min-height: 1em;
}
a:where([data-ws-component="Link"]) {
:where(a.w-link) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -18,8 +18,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="n_VBMr7klpx25buS0NV7R" data-ws-component="Body">
<Heading data-ws-id="wthNByqb3RPmheb-56VYI" data-ws-component="Heading">
<Body
data-ws-id="n_VBMr7klpx25buS0NV7R"
data-ws-component="Body"
className="w-body"
>
<Heading
data-ws-id="wthNByqb3RPmheb-56VYI"
data-ws-component="Heading"
className="w-heading"
>
{"Another page"}
</Heading>
</Body>
@@ -31,15 +31,19 @@ const Page = ({}: { system: any }) => {
<Body
data-ws-id="MMimeobf_zi4ZkRGXapju"
data-ws-component="Body"
className="c1jaw2zx cbipm55 ctniqj4 ctgx88l"
className="w-body c1jaw2zx cbipm55 ctniqj4 ctgx88l"
>
<Heading data-ws-id="MYDt0guk1-vzc7yzqyN6A" data-ws-component="Heading">
<Heading
data-ws-id="MYDt0guk1-vzc7yzqyN6A"
data-ws-component="Heading"
className="w-heading"
>
{"Simple Project to test CLI"}
</Heading>
<Text
data-ws-id="BMJfjOzunWs8XkQgvvx1e"
data-ws-component="Text"
className="cn3rfux"
className="w-text cn3rfux"
>
{"Please don't change directly in the fixture"}
</Text>
@@ -47,6 +51,7 @@ const Page = ({}: { system: any }) => {
data-ws-id="pjkZo5EiBqaeUXBcyHf_O"
data-ws-component="Link"
href={"/another-page"}
className="w-link"
>
{"Test another page link"}
</Link>
@@ -4,7 +4,7 @@ html {
min-height: 100%;
}
@media all {
body:where([data-ws-component="Body"]) {
:where(body.w-body) {
font-family: Arial, Roboto, sans-serif;
font-size: 16px;
line-height: 1.2;
@@ -17,7 +17,7 @@ html {
-moz-osx-font-smoothing: grayscale;
margin: 0;
}
h1:where([data-ws-component="Heading"]) {
:where(h1.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -25,7 +25,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h2:where([data-ws-component="Heading"]) {
:where(h2.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -33,7 +33,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h3:where([data-ws-component="Heading"]) {
:where(h3.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -41,7 +41,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h4:where([data-ws-component="Heading"]) {
:where(h4.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -49,7 +49,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h5:where([data-ws-component="Heading"]) {
:where(h5.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -57,7 +57,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h6:where([data-ws-component="Heading"]) {
:where(h6.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -65,7 +65,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
div:where([data-ws-component="Text"]) {
:where(div.w-text) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -74,7 +74,7 @@ html {
outline-width: 1px;
min-height: 1em;
}
a:where([data-ws-component="Link"]) {
:where(a.w-link) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -37,15 +37,20 @@ const Page = ({}: { system: any }) => {
<Body
data-ws-id="LW98_-srDnnagkR10lsk4"
data-ws-component="Body"
className="cjrgi00"
className="w-body cjrgi00"
>
<Heading data-ws-id="SHXddDLFWST_sy44UfGQO" data-ws-component="Heading">
<Heading
data-ws-id="SHXddDLFWST_sy44UfGQO"
data-ws-component="Heading"
className="w-heading"
>
{"Script Test"}
</Heading>
<Link
data-ws-id="8MXByradrqVRiGSyHI0aH"
data-ws-component="Link"
href={"/"}
className="w-link"
>
{"Go Home"}
</Link>
@@ -55,6 +60,7 @@ const Page = ({}: { system: any }) => {
code={
"<br>\n<script>console.log('SCRIPT TEST SSR')</script>\n<script>console.log('SCRIPT TEST SSR 2')</script>\nSCRIPTS ARE HERE 2<br>"
}
className="w-html-embed"
/>
<HtmlEmbed
data-ws-id="evFyHvPu9rGzKojoj723b"
@@ -63,6 +69,7 @@ const Page = ({}: { system: any }) => {
"<script>console.log('SCRIPTS TEST Client')</script>\n<script>console.log('SCRIPTS TEST 2 Client')</script>\nSCRIPTS ARE HERE <br>"
}
clientOnly={true}
className="w-html-embed"
/>
</Body>
);
@@ -30,7 +30,11 @@ const Body = (props: any) => props.children;
const Page = ({ system: system }: { system: any }) => {
let sitemapxml = useResource("sitemapxml_1");
return (
<Body data-ws-id="rve0BYRbzAkSCr3Lq-wzi" data-ws-component="Body">
<Body
data-ws-id="rve0BYRbzAkSCr3Lq-wzi"
data-ws-component="Body"
className="w-body"
>
<XmlNode
data-ws-id="cgaMXxOMMAh4H-u-MB3_0"
data-ws-component="XmlNode"
@@ -28,8 +28,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="jDb2FuSK2-azIZxkH5XNv" data-ws-component="Body">
<Heading data-ws-id="D7kQxgXxrjei-MS_KzUa2" data-ws-component="Heading">
<Body
data-ws-id="jDb2FuSK2-azIZxkH5XNv"
data-ws-component="Body"
className="w-body"
>
<Heading
data-ws-id="D7kQxgXxrjei-MS_KzUa2"
data-ws-component="Heading"
className="w-heading"
>
{"Привет Мир"}
</Heading>
</Body>
@@ -92,19 +92,19 @@ const Page = ({}: { system: any }) => {
<Body
data-ws-id="ibXgMoi9_ipHx1gVrvii0"
data-ws-component="Body"
className="cjrgi00"
className="w-body cjrgi00"
>
<Heading
data-ws-id="7pwqBSgrfuuOfk1JblWcL"
data-ws-component="Heading"
className="ce7mxws cd0g70b c1ku1ozg c1kbs9xq c1m6kmmg crjoqt7 c1n5sjmn c1hqh3e6 cwdggon c4o64du"
className="w-heading ce7mxws cd0g70b c1ku1ozg c1kbs9xq c1m6kmmg crjoqt7 c1n5sjmn c1hqh3e6 cwdggon c4o64du"
>
{"DO NOT TOUCH THIS PROJECT, IT'S USED FOR FIXTURES"}
</Heading>
<Box
data-ws-id="GMg3Wi9tJBFMtKcwbIK6z"
data-ws-component="Box"
className="cxb89wn c12qr5j7 c111rqf8 cp8i2p0 cwfevk3"
className="w-box cxb89wn c12qr5j7 c111rqf8 cp8i2p0 cwfevk3"
>
<Image
data-ws-id="Mfd_mI-VJtT4r7gICAvXi"
@@ -114,15 +114,19 @@ const Page = ({}: { system: any }) => {
}
width={1024}
height={1024}
className="ccgiojm cv4f3rn cer5re4 c9lz7ss"
className="w-image ccgiojm cv4f3rn cer5re4 c9lz7ss"
/>
<Box
data-ws-id="COafOppxs73Ne4O0Geik0"
data-ws-component="Box"
className="ccgiojm cv4f3rn cer5re4 c9lz7ss"
className="w-box ccgiojm cv4f3rn cer5re4 c9lz7ss"
/>
</Box>
<Heading data-ws-id="jWb8SRMYG_XPWqCYvGZjo" data-ws-component="Heading">
<Heading
data-ws-id="jWb8SRMYG_XPWqCYvGZjo"
data-ws-component="Heading"
className="w-heading"
>
{"Below Image"}
</Heading>
<HtmlEmbed
@@ -132,6 +136,7 @@ const Page = ({}: { system: any }) => {
"<script>console.log('PAGE MAIN Client')</script>\n<script>console.log('PAGE MAIN 2 Client')</script>\nSCRIPTS ARE HERE <br>"
}
clientOnly={true}
className="w-html-embed"
/>
<HtmlEmbed
data-ws-id="ffuOk2adQRwdmAPbN0C02"
@@ -139,11 +144,13 @@ const Page = ({}: { system: any }) => {
code={
"<script>console.log('PAGE MAIN SSR')</script>\n<script>console.log('PAGE MAIN 2 SSR')</script>\nSCRIPTS ARE HERE <br>"
}
className="w-html-embed"
/>
<Link
data-ws-id="QzTSoZnbGD6luZ5xcv893"
data-ws-component="Link"
href={"/script-test"}
className="w-link"
>
{"Goto Scr"}
</Link>
@@ -152,7 +159,7 @@ const Page = ({}: { system: any }) => {
data-ws-component="Vimeo"
url={"https://player.vimeo.com/video/831343124"}
showPreview={true}
className="c17osjft c5kxibo c8mrdqb"
className="w-vimeo c17osjft c5kxibo c8mrdqb"
>
<VimeoPreviewImage
data-ws-id="wxd8Wul8dl2yPRFFedNn6"
@@ -160,12 +167,12 @@ const Page = ({}: { system: any }) => {
alt={"Vimeo video preview image"}
sizes={"100vw"}
src={"/custom-folder/home_wsKvRSqvkajPPBeycZ-C8.svg"}
className="c13adha2 c19kjzjn c8mrdqb chv0hit c1vw7ut7 c64vnj4 cow7xo6 cddunt6 cqjhyu2"
className="w-vimeo-preview-image c13adha2 c19kjzjn c8mrdqb chv0hit c1vw7ut7 c64vnj4 cow7xo6 cddunt6 cqjhyu2"
/>
<VimeoSpinner
data-ws-id="o8sAMUoaOraWYZClEfRgl"
data-ws-component="VimeoSpinner"
className="c13adha2 c1ifzo79 c1ljqvnn c10zke2u cplzsl2 c1ardg8l ces5mo3"
className="w-vimeo-spinner c13adha2 c1ifzo79 c1ljqvnn c10zke2u cplzsl2 c1ardg8l ces5mo3"
>
<HtmlEmbed
data-ws-id="BeQ7sgDlUizFvf4aHqOsh"
@@ -174,19 +181,20 @@ const Page = ({}: { system: any }) => {
'<svg xmlns="http://www.w3.org/2000/svg" id="e2CRglijn891" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" viewBox="0 0 128 128" fill="currentColor" width="100%" height="100%" style="display: block;"><style>@keyframes e2CRglijn892_tr__tr{0%{transform:translate(64px,64px) rotate(90deg);animation-timing-function:cubic-bezier(.42,0,.58,1)}50%{transform:translate(64px,64px) rotate(810deg);animation-timing-function:cubic-bezier(.42,0,.58,1)}to{transform:translate(64px,64px) rotate(1530deg)}}@keyframes e2CRglijn892_s_p{0%,to{stroke:#39fbbb}25%{stroke:#4a4efa}50%{stroke:#e63cfe}75%{stroke:#ffae3c}}@keyframes e2CRglijn892_s_do{0%{stroke-dashoffset:251.89}2.5%,52.5%{stroke-dashoffset:263.88;animation-timing-function:cubic-bezier(.42,0,.58,1)}25%,75%{stroke-dashoffset:131.945}to{stroke-dashoffset:251.885909}}#e2CRglijn892_tr{animation:e2CRglijn892_tr__tr 3000ms linear infinite normal forwards}#e2CRglijn892{animation-name:e2CRglijn892_s_p,e2CRglijn892_s_do;animation-duration:3000ms;animation-fill-mode:forwards;animation-timing-function:linear;animation-direction:normal;animation-iteration-count:infinite}</style><g id="e2CRglijn892_tr" transform="translate(64,64) rotate(90)"><circle id="e2CRglijn892" r="42" fill="none" stroke="#39fbbb" stroke-dasharray="263.89" stroke-dashoffset="251.89" stroke-linecap="round" stroke-width="16" transform="scale(-1,1) translate(0,0)"/></g></svg>'
}
executeScriptOnCanvas={false}
className="w-html-embed"
/>
</VimeoSpinner>
<VimeoPlayButton
data-ws-id="9hBBPGSf7hB30ZkSHKjNd"
data-ws-component="VimeoPlayButton"
aria-label={"Play button"}
className="c13adha2 c1t88ri8 ca7kf99 c1ifzo79 c1ljqvnn c1bld9op ctly9e6 cxb89wn cwcnvqs cvchf4 c1y7dyx c1bnrgjg c1joowif c120xed6 c2eug5n cvwgylz c1f0qcby c1syyj1x cil01r8 c11087u4 coba2o7 c82nx6d"
className="w-vimeo-play-button c13adha2 c1t88ri8 ca7kf99 c1ifzo79 c1ljqvnn c1bld9op ctly9e6 cxb89wn cwcnvqs cvchf4 c1y7dyx c1bnrgjg c1joowif c120xed6 c2eug5n cvwgylz c1f0qcby c1syyj1x cil01r8 c11087u4 coba2o7 c82nx6d"
>
<Box
data-ws-id="D__QElBIIQtamhJN3a4FI"
data-ws-component="Box"
aria-hidden={"true"}
className="c1cccshn c1eyznz"
className="w-box c1cccshn c1eyznz"
>
<HtmlEmbed
data-ws-id="iEc6hab-WardXZc5P9wJu"
@@ -194,6 +202,7 @@ const Page = ({}: { system: any }) => {
code={
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" fill="currentColor" width="100%" height="100%" style="display: block;"><path d="M4.766 5.765c0-.725 0-1.088.178-1.288a.93.93 0 0 1 .648-.294c.294-.015.65.186 1.359.588l9.234 5.235c.586.332.88.498.982.708.09.183.09.389 0 .572-.102.21-.396.376-.982.708l-9.234 5.235c-.71.402-1.065.603-1.359.588a.93.93 0 0 1-.648-.294c-.178-.2-.178-.563-.178-1.288V5.765Z"/></svg>'
}
className="w-html-embed"
/>
</Box>
</VimeoPlayButton>
+24 -24
View File
@@ -12,7 +12,7 @@ html {
min-height: 100%;
}
@media all {
body:where([data-ws-component="Body"]) {
:where(body.w-body) {
font-family: Arial, Roboto, sans-serif;
font-size: 16px;
line-height: 1.2;
@@ -25,7 +25,7 @@ html {
-moz-osx-font-smoothing: grayscale;
margin: 0;
}
h1:where([data-ws-component="Heading"]) {
:where(h1.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -33,7 +33,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h2:where([data-ws-component="Heading"]) {
:where(h2.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -41,7 +41,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h3:where([data-ws-component="Heading"]) {
:where(h3.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -49,7 +49,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h4:where([data-ws-component="Heading"]) {
:where(h4.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -57,7 +57,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h5:where([data-ws-component="Heading"]) {
:where(h5.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -65,7 +65,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h6:where([data-ws-component="Heading"]) {
:where(h6.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -73,7 +73,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
a:where([data-ws-component="Link"]) {
:where(a.w-link) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -83,7 +83,7 @@ html {
min-height: 1em;
display: inline-block;
}
div:where([data-ws-component="Vimeo"]) {
:where(div.w-vimeo) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -91,7 +91,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
img:where([data-ws-component="VimeoPreviewImage"]) {
:where(img.w-vimeo-preview-image) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -102,7 +102,7 @@ html {
display: block;
height: auto;
}
button:where([data-ws-component="VimeoPlayButton"]) {
:where(button.w-vimeo-play-button) {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
@@ -118,7 +118,7 @@ html {
text-transform: none;
margin: 0;
}
div:where([data-ws-component="Box"]) {
:where(div.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -126,7 +126,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
address:where([data-ws-component="Box"]) {
:where(address.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -134,7 +134,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
article:where([data-ws-component="Box"]) {
:where(article.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -142,7 +142,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
aside:where([data-ws-component="Box"]) {
:where(aside.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -150,7 +150,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
figure:where([data-ws-component="Box"]) {
:where(figure.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -158,7 +158,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
footer:where([data-ws-component="Box"]) {
:where(footer.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -166,7 +166,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
header:where([data-ws-component="Box"]) {
:where(header.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -174,7 +174,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
main:where([data-ws-component="Box"]) {
:where(main.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -182,7 +182,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
nav:where([data-ws-component="Box"]) {
:where(nav.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -190,7 +190,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
section:where([data-ws-component="Box"]) {
:where(section.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -198,10 +198,10 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
div:where([data-ws-component="HtmlEmbed"]) {
:where(div.w-html-embed) {
display: contents;
}
div:where([data-ws-component="VimeoSpinner"]) {
:where(div.w-vimeo-spinner) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -209,7 +209,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
img:where([data-ws-component="Image"]) {
:where(img.w-image) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -18,8 +18,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="n_VBMr7klpx25buS0NV7R" data-ws-component="Body">
<Heading data-ws-id="wthNByqb3RPmheb-56VYI" data-ws-component="Heading">
<Body
data-ws-id="n_VBMr7klpx25buS0NV7R"
data-ws-component="Body"
className="w-body"
>
<Heading
data-ws-id="wthNByqb3RPmheb-56VYI"
data-ws-component="Heading"
className="w-heading"
>
{"Another page"}
</Heading>
</Body>
@@ -31,15 +31,19 @@ const Page = ({}: { system: any }) => {
<Body
data-ws-id="MMimeobf_zi4ZkRGXapju"
data-ws-component="Body"
className="c1jaw2zx cbipm55 ctniqj4 ctgx88l"
className="w-body c1jaw2zx cbipm55 ctniqj4 ctgx88l"
>
<Heading data-ws-id="MYDt0guk1-vzc7yzqyN6A" data-ws-component="Heading">
<Heading
data-ws-id="MYDt0guk1-vzc7yzqyN6A"
data-ws-component="Heading"
className="w-heading"
>
{"Simple Project to test CLI"}
</Heading>
<Text
data-ws-id="BMJfjOzunWs8XkQgvvx1e"
data-ws-component="Text"
className="cn3rfux"
className="w-text cn3rfux"
>
{"Please don't change directly in the fixture"}
</Text>
@@ -47,6 +51,7 @@ const Page = ({}: { system: any }) => {
data-ws-id="pjkZo5EiBqaeUXBcyHf_O"
data-ws-component="Link"
href={"/another-page"}
className="w-link"
>
{"Test another page link"}
</Link>
@@ -4,7 +4,7 @@ html {
min-height: 100%;
}
@media all {
body:where([data-ws-component="Body"]) {
:where(body.w-body) {
font-family: Arial, Roboto, sans-serif;
font-size: 16px;
line-height: 1.2;
@@ -17,7 +17,7 @@ html {
-moz-osx-font-smoothing: grayscale;
margin: 0;
}
h1:where([data-ws-component="Heading"]) {
:where(h1.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -25,7 +25,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h2:where([data-ws-component="Heading"]) {
:where(h2.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -33,7 +33,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h3:where([data-ws-component="Heading"]) {
:where(h3.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -41,7 +41,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h4:where([data-ws-component="Heading"]) {
:where(h4.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -49,7 +49,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h5:where([data-ws-component="Heading"]) {
:where(h5.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -57,7 +57,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h6:where([data-ws-component="Heading"]) {
:where(h6.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -65,7 +65,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
div:where([data-ws-component="Text"]) {
:where(div.w-text) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -74,7 +74,7 @@ html {
outline-width: 1px;
min-height: 1em;
}
a:where([data-ws-component="Link"]) {
:where(a.w-link) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -18,8 +18,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="n_VBMr7klpx25buS0NV7R" data-ws-component="Body">
<Heading data-ws-id="wthNByqb3RPmheb-56VYI" data-ws-component="Heading">
<Body
data-ws-id="n_VBMr7klpx25buS0NV7R"
data-ws-component="Body"
className="w-body"
>
<Heading
data-ws-id="wthNByqb3RPmheb-56VYI"
data-ws-component="Heading"
className="w-heading"
>
{"Another page"}
</Heading>
</Body>
@@ -31,15 +31,19 @@ const Page = ({}: { system: any }) => {
<Body
data-ws-id="MMimeobf_zi4ZkRGXapju"
data-ws-component="Body"
className="c1jaw2zx cbipm55 ctniqj4 ctgx88l"
className="w-body c1jaw2zx cbipm55 ctniqj4 ctgx88l"
>
<Heading data-ws-id="MYDt0guk1-vzc7yzqyN6A" data-ws-component="Heading">
<Heading
data-ws-id="MYDt0guk1-vzc7yzqyN6A"
data-ws-component="Heading"
className="w-heading"
>
{"Simple Project to test CLI"}
</Heading>
<Text
data-ws-id="BMJfjOzunWs8XkQgvvx1e"
data-ws-component="Text"
className="cn3rfux"
className="w-text cn3rfux"
>
{"Please don't change directly in the fixture"}
</Text>
@@ -47,6 +51,7 @@ const Page = ({}: { system: any }) => {
data-ws-id="pjkZo5EiBqaeUXBcyHf_O"
data-ws-component="Link"
href={"/another-page"}
className="w-link"
>
{"Test another page link"}
</Link>
@@ -4,7 +4,7 @@ html {
min-height: 100%;
}
@media all {
body:where([data-ws-component="Body"]) {
:where(body.w-body) {
font-family: Arial, Roboto, sans-serif;
font-size: 16px;
line-height: 1.2;
@@ -17,7 +17,7 @@ html {
-moz-osx-font-smoothing: grayscale;
margin: 0;
}
h1:where([data-ws-component="Heading"]) {
:where(h1.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -25,7 +25,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h2:where([data-ws-component="Heading"]) {
:where(h2.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -33,7 +33,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h3:where([data-ws-component="Heading"]) {
:where(h3.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -41,7 +41,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h4:where([data-ws-component="Heading"]) {
:where(h4.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -49,7 +49,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h5:where([data-ws-component="Heading"]) {
:where(h5.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -57,7 +57,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h6:where([data-ws-component="Heading"]) {
:where(h6.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -65,7 +65,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
div:where([data-ws-component="Text"]) {
:where(div.w-text) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -74,7 +74,7 @@ html {
outline-width: 1px;
min-height: 1em;
}
a:where([data-ws-component="Link"]) {
:where(a.w-link) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -28,12 +28,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="EDEfpMPRqDejthtwkH7ws" data-ws-component="Body">
<Body
data-ws-id="EDEfpMPRqDejthtwkH7ws"
data-ws-component="Body"
className="w-body"
>
<Image
data-ws-id="AdXSAYCx4QDo5QN6nLoGs"
data-ws-component="Image"
src={"/assets/small-avif-kitty_FnabJsioMWpBtXZSGf4DR.webp"}
className="c1czoo99"
className="w-image c1czoo99"
/>
</Body>
);
@@ -39,7 +39,11 @@ const Page = ({}: { system: any }) => {
let [formState, set$formState] = useState<any>("initial");
let [formState_1, set$formState_1] = useState<any>("initial");
return (
<Body data-ws-id="a-4nDFkaWy4px1fn38XWJ" data-ws-component="Body">
<Body
data-ws-id="a-4nDFkaWy4px1fn38XWJ"
data-ws-component="Body"
className="w-body"
>
<Form
data-ws-id="-1RvizaBcVpHsjvnYxn1c"
data-ws-component="Form"
@@ -48,47 +52,72 @@ const Page = ({}: { system: any }) => {
formState = state;
set$formState(formState);
}}
className="w-form"
>
{(formState === "initial" || formState === "error") && (
<Box data-ws-id="qhnVrmYGlyrMZi3UzqSQA" data-ws-component="Box">
<Box
data-ws-id="qhnVrmYGlyrMZi3UzqSQA"
data-ws-component="Box"
className="w-box"
>
<Heading
data-ws-id="YdHHf4u3jrdbRIWpB_VfH"
data-ws-component="Heading"
tag={"h3"}
className="w-heading"
>
{"Default form"}
</Heading>
<Label data-ws-id="A0RNI1WVwOGGDbwYnoZia" data-ws-component="Label">
<Label
data-ws-id="A0RNI1WVwOGGDbwYnoZia"
data-ws-component="Label"
className="w-label"
>
{"Name"}
</Label>
<Input
data-ws-id="e035xi9fcwYtrn9La49Eh"
data-ws-component="Input"
name={"name"}
className="w-input"
/>
<Label data-ws-id="LImtuVzw5R9yQsG4faiGV" data-ws-component="Label">
<Label
data-ws-id="LImtuVzw5R9yQsG4faiGV"
data-ws-component="Label"
className="w-label"
>
{"Email"}
</Label>
<Input
data-ws-id="dcHjdeW_HXPkyQlx3ZiL7"
data-ws-component="Input"
name={"email"}
className="w-input"
/>
<Button
data-ws-id="ZAtG6JgK4sbTnOAZlp2rU"
data-ws-component="Button"
className="w-button"
>
{"Submit"}
</Button>
</Box>
)}
{formState === "success" && (
<Box data-ws-id="966cjxuqP_T99N27-mqWE" data-ws-component="Box">
<Box
data-ws-id="966cjxuqP_T99N27-mqWE"
data-ws-component="Box"
className="w-box"
>
{"Thank you for getting in touch!"}
</Box>
)}
{formState === "error" && (
<Box data-ws-id="SYG5hhOz31xFJUN_v9zq6" data-ws-component="Box">
<Box
data-ws-id="SYG5hhOz31xFJUN_v9zq6"
data-ws-component="Box"
className="w-box"
>
{"Sorry, something went wrong."}
</Box>
)}
@@ -103,47 +132,72 @@ const Page = ({}: { system: any }) => {
}}
method={"get"}
action={"/custom"}
className="w-form"
>
{(formState_1 === "initial" || formState_1 === "error") && (
<Box data-ws-id="a5YPRc19IJyhTrjjasA_R" data-ws-component="Box">
<Box
data-ws-id="a5YPRc19IJyhTrjjasA_R"
data-ws-component="Box"
className="w-box"
>
<Heading
data-ws-id="y4pceTmziuBRIDgUBQNLD"
data-ws-component="Heading"
tag={"h3"}
className="w-heading"
>
{"Form with custom action and method"}
</Heading>
<Label data-ws-id="_gLjS0enBOV8KW9Ykz_es" data-ws-component="Label">
<Label
data-ws-id="_gLjS0enBOV8KW9Ykz_es"
data-ws-component="Label"
className="w-label"
>
{"Name"}
</Label>
<Input
data-ws-id="ydR5B_9uMS4PXFS76TmBh"
data-ws-component="Input"
name={"name"}
className="w-input"
/>
<Label data-ws-id="8RU1FyL2QRyqhNUKELGrb" data-ws-component="Label">
<Label
data-ws-id="8RU1FyL2QRyqhNUKELGrb"
data-ws-component="Label"
className="w-label"
>
{"Email"}
</Label>
<Input
data-ws-id="TsqGP49hjgEW41ReCwrpZ"
data-ws-component="Input"
name={"email"}
className="w-input"
/>
<Button
data-ws-id="5GWjwVdapuGdn443GIKDW"
data-ws-component="Button"
className="w-button"
>
{"Submit"}
</Button>
</Box>
)}
{formState_1 === "success" && (
<Box data-ws-id="Gw-ta0R4FNFAGBTVRWKep" data-ws-component="Box">
<Box
data-ws-id="Gw-ta0R4FNFAGBTVRWKep"
data-ws-component="Box"
className="w-box"
>
{"Thank you for getting in touch!"}
</Box>
)}
{formState_1 === "error" && (
<Box data-ws-id="ewk_WKpu4syHLPABMmvUz" data-ws-component="Box">
<Box
data-ws-id="ewk_WKpu4syHLPABMmvUz"
data-ws-component="Box"
className="w-box"
>
{"Sorry, something went wrong."}
</Box>
)}
@@ -28,11 +28,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="O-ljaGZQ0iRNTlEshMkgE" data-ws-component="Body">
<Body
data-ws-id="O-ljaGZQ0iRNTlEshMkgE"
data-ws-component="Body"
className="w-body"
>
<Heading
data-ws-id="qmxnOlSxUGpuhuonVArWJ"
data-ws-component="Heading"
id={"my-heading"}
className="w-heading"
>
{"Heading you can edit"}
</Heading>
@@ -28,8 +28,16 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
return (
<Body data-ws-id="L0ZXd5F9xk9Rsl9ORzIkJ" data-ws-component="Body">
<Heading data-ws-id="VFPjLwt6Caq4l9PPJSiyI" data-ws-component="Heading">
<Body
data-ws-id="L0ZXd5F9xk9Rsl9ORzIkJ"
data-ws-component="Body"
className="w-body"
>
<Heading
data-ws-id="VFPjLwt6Caq4l9PPJSiyI"
data-ws-component="Heading"
className="w-heading"
>
{"Nested page"}
</Heading>
</Body>
@@ -40,7 +40,11 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
let [accordionValue, set$accordionValue] = useState<any>("0");
return (
<Body data-ws-id="uKWGyE9JY3cPwY-xI9vk6" data-ws-component="Body">
<Body
data-ws-id="uKWGyE9JY3cPwY-xI9vk6"
data-ws-component="Body"
className="w-body"
>
<Accordion
data-ws-id="AM9fD6dv2Ftc3Xjcsd7Uc"
data-ws-component="@webstudio-is/sdk-components-react-radix:Accordion"
@@ -50,30 +54,35 @@ const Page = ({}: { system: any }) => {
accordionValue = value;
set$accordionValue(accordionValue);
}}
className="w-accordion"
>
<AccordionItem
data-ws-id="zJ927zk9txwUbYycKB7QA"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionItem"
data-ws-index="0"
className="c2onvcp"
className="w-accordion-item c2onvcp"
>
<AccordionHeader
data-ws-id="sMxg7xT1hwYt05hbOvoPL"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionHeader"
className="c13v7j50"
className="w-accordion-header c13v7j50"
>
<AccordionTrigger
data-ws-id="qQSA4NoyKC88O68mBiQe2"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionTrigger"
className="c13v7j50 c1qxdkbn chhejm9 c13bviim cpjvam0 c1tw5o2 cqw88jp c44srea c14kxsax cg783j6 c1ad236a c1s4llbc"
className="w-accordion-trigger c13v7j50 c1qxdkbn chhejm9 c13bviim cpjvam0 c1tw5o2 cqw88jp c44srea c14kxsax cg783j6 c1ad236a c1s4llbc"
>
<Text data-ws-id="q-DVI4YTNrQ1LizmEyJHI" data-ws-component="Text">
<Text
data-ws-id="q-DVI4YTNrQ1LizmEyJHI"
data-ws-component="Text"
className="w-text"
>
{"Is it accessible?"}
</Text>
<Box
data-ws-id="RSk81lLj2IGXgchTuXF7V"
data-ws-component="Box"
className="c14hansb c6d2sb5 cwwiftc c16vb2zi c1hl6g8z c1xm49r0 c1vri55v"
className="w-box c14hansb c6d2sb5 cwwiftc c16vb2zi c1hl6g8z c1xm49r0 c1vri55v"
>
<HtmlEmbed
data-ws-id="d0sd_G-kHirxgjq6s6Uq1"
@@ -81,6 +90,7 @@ const Page = ({}: { system: any }) => {
code={
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" width="100%" height="100%" style="display: block;"><path d="M4.04 6.284a.65.65 0 0 1 .92.001L8 9.335l3.04-3.05a.65.65 0 1 1 .921.918l-3.5 3.512a.65.65 0 0 1-.921 0L4.039 7.203a.65.65 0 0 1 .001-.92Z"/></svg>'
}
className="w-html-embed"
/>
</Box>
</AccordionTrigger>
@@ -88,7 +98,7 @@ const Page = ({}: { system: any }) => {
<AccordionContent
data-ws-id="IUftdfjK-ilSzfOTdIx1u"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionContent"
className="c1mxwmum c1j0j9ep c1gl2i2 c44srea"
className="w-accordion-content c1mxwmum c1j0j9ep c1gl2i2 c44srea"
>
{"Yes. It adheres to the WAI-ARIA design pattern."}
</AccordionContent>
@@ -97,25 +107,29 @@ const Page = ({}: { system: any }) => {
data-ws-id="C838wkvIcA1BQu30Xu2G8"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionItem"
data-ws-index="1"
className="c2onvcp"
className="w-accordion-item c2onvcp"
>
<AccordionHeader
data-ws-id="fYUOB_brm6s0Ky68lzMfU"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionHeader"
className="c13v7j50"
className="w-accordion-header c13v7j50"
>
<AccordionTrigger
data-ws-id="dfd4gonev_AX6BpuCsxjb"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionTrigger"
className="c13v7j50 c1qxdkbn chhejm9 c13bviim cpjvam0 c1tw5o2 cqw88jp c44srea c14kxsax cg783j6 c1ad236a c1s4llbc"
className="w-accordion-trigger c13v7j50 c1qxdkbn chhejm9 c13bviim cpjvam0 c1tw5o2 cqw88jp c44srea c14kxsax cg783j6 c1ad236a c1s4llbc"
>
<Text data-ws-id="lZ7sI6Kw_0VZkURriKscB" data-ws-component="Text">
<Text
data-ws-id="lZ7sI6Kw_0VZkURriKscB"
data-ws-component="Text"
className="w-text"
>
{"Is it styled?"}
</Text>
<Box
data-ws-id="wRw75kuvFzl5NWD8IGJoI"
data-ws-component="Box"
className="c14hansb c6d2sb5 cwwiftc c16vb2zi c1hl6g8z c1xm49r0 c1vri55v"
className="w-box c14hansb c6d2sb5 cwwiftc c16vb2zi c1hl6g8z c1xm49r0 c1vri55v"
>
<HtmlEmbed
data-ws-id="StPslEr81nfBISqBE2R-Y"
@@ -123,6 +137,7 @@ const Page = ({}: { system: any }) => {
code={
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" width="100%" height="100%" style="display: block;"><path d="M4.04 6.284a.65.65 0 0 1 .92.001L8 9.335l3.04-3.05a.65.65 0 1 1 .921.918l-3.5 3.512a.65.65 0 0 1-.921 0L4.039 7.203a.65.65 0 0 1 .001-.92Z"/></svg>'
}
className="w-html-embed"
/>
</Box>
</AccordionTrigger>
@@ -130,7 +145,7 @@ const Page = ({}: { system: any }) => {
<AccordionContent
data-ws-id="wNRVuu0L5E8TVufKdswp1"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionContent"
className="c1mxwmum c1j0j9ep c1gl2i2 c44srea"
className="w-accordion-content c1mxwmum c1j0j9ep c1gl2i2 c44srea"
>
{
"Yes. It comes with default styles that matches the other components' aesthetic."
@@ -141,25 +156,29 @@ const Page = ({}: { system: any }) => {
data-ws-id="65djoTmSBGemZ2L5izQ5M"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionItem"
data-ws-index="2"
className="c2onvcp"
className="w-accordion-item c2onvcp"
>
<AccordionHeader
data-ws-id="UJYfe6kH7HqhH0YYeJwe7"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionHeader"
className="c13v7j50"
className="w-accordion-header c13v7j50"
>
<AccordionTrigger
data-ws-id="600nGddaNxGGdsuGgpxJR"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionTrigger"
className="c13v7j50 c1qxdkbn chhejm9 c13bviim cpjvam0 c1tw5o2 cqw88jp c44srea c14kxsax cg783j6 c1ad236a c1s4llbc"
className="w-accordion-trigger c13v7j50 c1qxdkbn chhejm9 c13bviim cpjvam0 c1tw5o2 cqw88jp c44srea c14kxsax cg783j6 c1ad236a c1s4llbc"
>
<Text data-ws-id="1iNKIMG91n83PzJnEdxq9" data-ws-component="Text">
<Text
data-ws-id="1iNKIMG91n83PzJnEdxq9"
data-ws-component="Text"
className="w-text"
>
{"Is it animated?"}
</Text>
<Box
data-ws-id="Ta70VqUb_fGJXBT_zsnxQ"
data-ws-component="Box"
className="c14hansb c6d2sb5 cwwiftc c16vb2zi c1hl6g8z c1xm49r0 c1vri55v"
className="w-box c14hansb c6d2sb5 cwwiftc c16vb2zi c1hl6g8z c1xm49r0 c1vri55v"
>
<HtmlEmbed
data-ws-id="sO80m5u4f87jVGG91t6u8"
@@ -167,6 +186,7 @@ const Page = ({}: { system: any }) => {
code={
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" width="100%" height="100%" style="display: block;"><path d="M4.04 6.284a.65.65 0 0 1 .92.001L8 9.335l3.04-3.05a.65.65 0 1 1 .921.918l-3.5 3.512a.65.65 0 0 1-.921 0L4.039 7.203a.65.65 0 0 1 .001-.92Z"/></svg>'
}
className="w-html-embed"
/>
</Box>
</AccordionTrigger>
@@ -174,7 +194,7 @@ const Page = ({}: { system: any }) => {
<AccordionContent
data-ws-id="mOVPnIrlt6IwVAzI_i2Fc"
data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionContent"
className="c1mxwmum c1j0j9ep c1gl2i2 c44srea"
className="w-accordion-content c1mxwmum c1j0j9ep c1gl2i2 c44srea"
>
{
"Yes. It's animated by default, but you can disable it if you prefer."
@@ -32,14 +32,23 @@ export const pageBackgroundImageAssets: ImageAsset[] = [];
const Page = ({}: { system: any }) => {
let list = useResource("list_1");
return (
<Body data-ws-id="AWY2qZfpbykoiWELeJhse" data-ws-component="Body">
<Body
data-ws-id="AWY2qZfpbykoiWELeJhse"
data-ws-component="Body"
className="w-body"
>
{list?.data?.map((collectionItem: any, index: number) => (
<Fragment key={index}>
<Box data-ws-id="-F-b3eIEZ8WKW_F-Aw8nN" data-ws-component="Box">
<Box
data-ws-id="-F-b3eIEZ8WKW_F-Aw8nN"
data-ws-component="Box"
className="w-box"
>
<HtmlEmbed
data-ws-id="05oK4Ks0ocFv3w8MJOcNR"
data-ws-component="HtmlEmbed"
code={collectionItem?.name}
className="w-html-embed"
/>
</Box>
</Fragment>
+18 -9
View File
@@ -64,34 +64,36 @@ const Page = ({}: { system: any }) => {
<Body
data-ws-id="On9cvWCxr5rdZtY9O1Bv0"
data-ws-component="Body"
className="cielobv"
className="w-body cielobv"
>
<Heading
data-ws-id="nVMWvMsaLCcb0o1wuNQgg"
data-ws-component="Heading"
className="ceva767"
className="w-heading ceva767"
>
{"DO NOT TOUCH THIS PROJECT, IT'S USED FOR FIXTURES"}
</Heading>
<Box
data-ws-id="f0kF-WmL7DQg7MSyRvqY1"
data-ws-component="Box"
className="c13v7j50 cqkqnmd cv6wa71"
className="w-box c13v7j50 cqkqnmd cv6wa71"
>
<Box
data-ws-id="5XDbqPrZDeCwq4YJ3CHsc"
data-ws-component="Box"
className="c1t3ybra c1qxdkbn c1ogzcge cv3kvac"
className="w-box c1t3ybra c1qxdkbn c1ogzcge cv3kvac"
>
<Heading
data-ws-id="oLXYe1UQiVMhVnZGvJSMr"
data-ws-component="Heading"
className="w-heading"
>
{"Heading"}
</Heading>
<Paragraph
data-ws-id="p34JHWcU6UNrd9FVnY80Q"
data-ws-component="Paragraph"
className="w-paragraph"
>
{
"a little kitten painted in black and white gouache with a thick brush"
@@ -101,6 +103,7 @@ const Page = ({}: { system: any }) => {
data-ws-id="l9AI_pShC-BH4ibxK6kNT"
data-ws-component="Link"
href={"https://github.com/"}
className="w-link"
>
{"Click here to adore more kittens"}
</Link>
@@ -108,6 +111,7 @@ const Page = ({}: { system: any }) => {
data-ws-id="D8wLZzLWQfxH9uaKsn-0L"
data-ws-component="Text"
tag={"span"}
className="w-text"
>
{" or "}
</Text>
@@ -115,15 +119,20 @@ const Page = ({}: { system: any }) => {
data-ws-id="8AXawjUE3fJoOH_1qOAoq"
data-ws-component="Link"
href={"/assets/small-avif-kitty_FnabJsioMWpBtXZSGf4DR.webp"}
className="w-link"
>
{"go download this little kitten"}
</Link>
<Box data-ws-id="82HYqzxZeahPxSDFNWem5" data-ws-component="Box" />
<Box
data-ws-id="82HYqzxZeahPxSDFNWem5"
data-ws-component="Box"
className="w-box"
/>
<Link
data-ws-id="9I4GRU1sev48hREkQcKQ-"
data-ws-component="Link"
href={"/_route_with_symbols_"}
className="ch2exr5"
className="w-link ch2exr5"
>
{"Symbols in path"}
</Link>
@@ -131,7 +140,7 @@ const Page = ({}: { system: any }) => {
data-ws-id="81ejLVXyFEV1SxiJrWhyw"
data-ws-component="Link"
href={"/heading-with-id#my-heading"}
className="ch2exr5"
className="w-link ch2exr5"
>
{"Link to instance"}
</Link>
@@ -139,7 +148,7 @@ const Page = ({}: { system: any }) => {
<Box
data-ws-id="qPnkiFGDj8dITWb1kmpGl"
data-ws-component="Box"
className="c1t3ybra c1qxdkbn c1ogzcge cv3kvac"
className="w-box c1t3ybra c1qxdkbn c1ogzcge cv3kvac"
>
<Image
data-ws-id="pX1ovPI7NdC0HRjkw6Kpw"
@@ -147,7 +156,7 @@ const Page = ({}: { system: any }) => {
src={
"/assets/_937084ed-a798-49fe-8664-df93a2af605e_uiBk3o6UWdqolyakMvQJ9.jpeg"
}
className="c1czoo99"
className="w-image c1czoo99"
/>
</Box>
</Box>
+31 -41
View File
@@ -4,7 +4,7 @@ html {
min-height: 100%;
}
@media all {
body:where([data-ws-component="Body"]) {
:where(body.w-body) {
font-family: Arial, Roboto, sans-serif;
font-size: 16px;
line-height: 1.2;
@@ -17,7 +17,7 @@ html {
-moz-osx-font-smoothing: grayscale;
margin: 0;
}
h1:where([data-ws-component="Heading"]) {
:where(h1.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -25,7 +25,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h2:where([data-ws-component="Heading"]) {
:where(h2.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -33,7 +33,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h3:where([data-ws-component="Heading"]) {
:where(h3.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -41,7 +41,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h4:where([data-ws-component="Heading"]) {
:where(h4.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -49,7 +49,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h5:where([data-ws-component="Heading"]) {
:where(h5.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -57,7 +57,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h6:where([data-ws-component="Heading"]) {
:where(h6.w-heading) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -65,7 +65,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
div:where([data-ws-component="Box"]) {
:where(div.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -73,7 +73,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
address:where([data-ws-component="Box"]) {
:where(address.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -81,7 +81,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
article:where([data-ws-component="Box"]) {
:where(article.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -89,7 +89,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
aside:where([data-ws-component="Box"]) {
:where(aside.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -97,7 +97,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
figure:where([data-ws-component="Box"]) {
:where(figure.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -105,7 +105,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
footer:where([data-ws-component="Box"]) {
:where(footer.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -113,7 +113,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
header:where([data-ws-component="Box"]) {
:where(header.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -121,7 +121,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
main:where([data-ws-component="Box"]) {
:where(main.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -129,7 +129,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
nav:where([data-ws-component="Box"]) {
:where(nav.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -137,7 +137,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
section:where([data-ws-component="Box"]) {
:where(section.w-box) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -145,7 +145,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
p:where([data-ws-component="Paragraph"]) {
:where(p.w-paragraph) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -153,7 +153,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
img:where([data-ws-component="Image"]) {
:where(img.w-image) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -164,7 +164,7 @@ html {
display: block;
height: auto;
}
a:where([data-ws-component="Link"]) {
:where(a.w-link) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -174,7 +174,7 @@ html {
min-height: 1em;
display: inline-block;
}
div:where([data-ws-component="Text"]) {
:where(div.w-text) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -183,9 +183,7 @@ html {
outline-width: 1px;
min-height: 1em;
}
div:where(
[data-ws-component="@webstudio-is/sdk-components-react-radix:Accordion"]
) {
:where(div.w-accordion) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -193,9 +191,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
div:where(
[data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionItem"]
) {
:where(div.w-accordion-item) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -203,9 +199,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
h3:where(
[data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionHeader"]
) {
:where(h3.w-accordion-header) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -215,9 +209,7 @@ html {
margin-top: 0px;
margin-bottom: 0px;
}
button:where(
[data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionTrigger"]
) {
:where(button.w-accordion-trigger) {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
@@ -229,12 +221,10 @@ html {
margin: 0;
padding: 0px;
}
div:where([data-ws-component="HtmlEmbed"]) {
:where(div.w-html-embed) {
display: contents;
}
div:where(
[data-ws-component="@webstudio-is/sdk-components-react-radix:AccordionContent"]
) {
:where(div.w-accordion-content) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -242,7 +232,7 @@ html {
border-left-width: 1px;
outline-width: 1px;
}
form:where([data-ws-component="Form"]) {
:where(form.w-form) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -251,7 +241,7 @@ html {
outline-width: 1px;
min-height: 20px;
}
label:where([data-ws-component="Label"]) {
:where(label.w-label) {
box-sizing: border-box;
border-top-width: 1px;
border-right-width: 1px;
@@ -260,7 +250,7 @@ html {
outline-width: 1px;
display: block;
}
input:where([data-ws-component="Input"]) {
:where(input.w-input) {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
@@ -276,7 +266,7 @@ html {
display: block;
margin: 0;
}
button:where([data-ws-component="Button"]) {
:where(button.w-button) {
font-family: inherit;
font-size: 100%;
line-height: 1.15;
+2 -2
View File
@@ -483,7 +483,7 @@ export const prebuild = async (options: {
const assets = new Map(siteData.assets.map((asset) => [asset.id, asset]));
const { cssText, classesMap } = generateCss({
const { cssText, classes } = generateCss({
instances: new Map(siteData.build.instances),
props: new Map(siteData.build.props),
assets,
@@ -596,7 +596,7 @@ export const prebuild = async (options: {
instances,
props,
dataSources,
classesMap,
classesMap: classes,
indexesWithinAncestors: getIndexesWithinAncestors(
projectMetas,
instances,
+5 -5
View File
@@ -67,10 +67,10 @@ test("added classes", () => {
value: { type: "keyword", value: "block" },
});
const instances = new Map([[rule, "instanceId"]]);
const { classesMap } = generateAtomic(sheet, {
const { classes } = generateAtomic(sheet, {
getKey: (rule) => instances.get(rule) ?? "",
});
expect(classesMap.get("instanceId")).toEqual(["ccqp4le"]);
expect(classes.get("instanceId")).toEqual(["ccqp4le"]);
});
test("rule with multiple properties", () => {
@@ -129,7 +129,7 @@ test("share atomic rules", () => {
[rule1, "1"],
[rule2, "2"],
]);
const { cssText, classesMap } = generateAtomic(sheet, {
const { cssText, classes } = generateAtomic(sheet, {
getKey: (rule) => instances.get(rule) ?? "",
});
expect(cssText).toMatchInlineSnapshot(`
@@ -142,8 +142,8 @@ test("share atomic rules", () => {
}
}"
`);
expect(classesMap.get("1")).toEqual(["ccqp4le", "cen0ymu"]);
expect(classesMap.get("2")).toEqual(["ccqp4le"]);
expect(classes.get("1")).toEqual(["ccqp4le", "cen0ymu"]);
expect(classes.get("2")).toEqual(["ccqp4le"]);
});
test("distinct similar declarations from different breakpoints", () => {
+5 -4
View File
@@ -6,21 +6,22 @@ import { toValue, type TransformValue } from "./to-value";
type Options = {
getKey: (rule: NestingRule) => string;
transformValue?: TransformValue;
classes?: Map<string, string[]>;
};
export const generateAtomic = (sheet: StyleSheet, options: Options) => {
const { getKey, transformValue } = options;
const atomicRules = new Map<string, NestingRule>();
const classesMap = new Map<string, string[]>();
const classes = options.classes ?? new Map<string, string[]>();
for (const rule of sheet.nestingRules.values()) {
const descendantSuffix = rule.getDescendantSuffix();
const groupKey = getKey(rule);
// a few rules can be in the same group
// when rule have descendant suffix
let classList = classesMap.get(groupKey);
let classList = classes.get(groupKey);
if (classList === undefined) {
classList = [];
classesMap.set(groupKey, classList);
classes.set(groupKey, classList);
}
// convert each declaration into separate rule
for (const declaration of rule.getMergedDeclarations()) {
@@ -51,5 +52,5 @@ export const generateAtomic = (sheet: StyleSheet, options: Options) => {
nestingRules: Array.from(atomicRules.values()),
transformValue,
});
return { cssText, classesMap };
return { cssText, classes };
};
+187 -17
View File
@@ -2,24 +2,25 @@ import { expect, test } from "@jest/globals";
import type { Breakpoint } from "@webstudio-is/sdk";
import { generateCss, type CssConfig } from "./css";
import { descendantComponent } from "../core-components";
import { $, renderJsx } from "@webstudio-is/sdk/testing";
const toMap = <T extends { id: string }>(list: T[]) =>
new Map(list.map((item) => [item.id, item] as const));
const generateAllCss = (config: Omit<CssConfig, "atomic">) => {
const { cssText } = generateCss({
const { cssText, classes } = generateCss({
...config,
atomic: false,
});
const { cssText: atomicCssText, classesMap } = generateCss({
const { cssText: atomicCssText, classes: atomicClasses } = generateCss({
...config,
atomic: true,
});
return { cssText, atomicCssText, classesMap };
return { cssText, atomicCssText, classes, atomicClasses };
};
test("generate css for one instance with two tokens", () => {
const { cssText, atomicCssText, classesMap } = generateAllCss({
const { cssText, atomicCssText, atomicClasses } = generateAllCss({
assets: new Map(),
instances: new Map(),
props: new Map(),
@@ -67,7 +68,7 @@ test("generate css for one instance with two tokens", () => {
}
}"
`);
expect(classesMap).toMatchInlineSnapshot(`
expect(atomicClasses).toMatchInlineSnapshot(`
Map {
"box" => [
"cawkhls",
@@ -77,7 +78,7 @@ Map {
});
test("generate descendant selector", () => {
const { cssText, atomicCssText, classesMap } = generateAllCss({
const { cssText, atomicCssText, atomicClasses } = generateAllCss({
assets: new Map(),
instances: toMap([
{
@@ -165,7 +166,7 @@ test("generate descendant selector", () => {
}
}"
`);
expect(classesMap).toMatchInlineSnapshot(`
expect(atomicClasses).toMatchInlineSnapshot(`
Map {
"root" => [
"c17hlgoh",
@@ -177,8 +178,8 @@ Map {
`);
});
test("generate component presets", () => {
const { cssText, atomicCssText, classesMap } = generateAllCss({
test("generate component presets with multiple tags", () => {
const { cssText, atomicCssText, classes, atomicClasses } = generateAllCss({
assets: new Map(),
instances: new Map(),
props: new Map(),
@@ -187,7 +188,7 @@ test("generate component presets", () => {
styles: new Map(),
componentMetas: new Map([
[
"Box",
"ListItem",
{
type: "container",
icon: "",
@@ -213,28 +214,197 @@ test("generate component presets", () => {
expect(cssText).toMatchInlineSnapshot(`
"html {margin: 0; display: grid; min-height: 100%}
@media all {
div:where([data-ws-component="Box"]) {
:where(div.w-list-item) {
display: block
}
a:where([data-ws-component="Box"]) {
:where(a.w-list-item) {
-webkit-user-select: none;
user-select: none
}
}
"
`);
expect(cssText).toEqual(atomicCssText);
expect(classes).toMatchInlineSnapshot(`Map {}`);
expect(classes).toEqual(atomicClasses);
});
test("deduplicate component presets for similarly named components", () => {
const { cssText, atomicCssText, classes, atomicClasses } = generateAllCss({
assets: new Map(),
instances: new Map(),
props: new Map(),
breakpoints: new Map(),
styleSourceSelections: new Map([]),
styles: new Map(),
componentMetas: new Map([
[
"ListItem",
{
type: "container",
icon: "",
presetStyle: {
div: [
{
property: "display",
value: { type: "keyword", value: "block" },
},
],
},
},
],
[
"@webstudio/radix:ListItem",
{
type: "container",
icon: "",
presetStyle: {
div: [
{
property: "display",
value: { type: "keyword", value: "flex" },
},
],
},
},
],
[
"@webstudio/aria:ListItem",
{
type: "container",
icon: "",
presetStyle: {
div: [
{
property: "display",
value: { type: "keyword", value: "grid" },
},
],
},
},
],
]),
assetBaseUrl: "",
});
expect(cssText).toMatchInlineSnapshot(`
"html {margin: 0; display: grid; min-height: 100%}
@media all {
:where(div.w-list-item) {
display: block
}
:where(div.w-list-item-1) {
display: flex
}
:where(div.w-list-item-2) {
display: grid
}
}
"
`);
expect(cssText).toEqual(atomicCssText);
expect(classes).toMatchInlineSnapshot(`Map {}`);
expect(classes).toEqual(atomicClasses);
});
test("expose preset classes to instances", () => {
const { atomicCssText, classes, atomicClasses } = generateAllCss({
assets: new Map(),
...renderJsx(
<$.Body ws:id="body">
<$.Box ws:id="box"></$.Box>
</$.Body>
),
breakpoints: new Map(),
styleSourceSelections: new Map([
["body", { instanceId: "body", values: ["localBody"] }],
["box", { instanceId: "box", values: ["localBox"] }],
]),
styles: new Map([
[
"localBody:base:color",
{
styleSourceId: "localBody",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "blue" },
},
],
[
"localBox:base:color::hover",
{
styleSourceId: "localBox",
breakpointId: "base",
property: "color",
value: { type: "keyword", value: "red" },
},
],
]),
componentMetas: new Map([
[
"Body",
{
type: "container",
icon: "",
presetStyle: {
div: [
{
property: "display",
value: { type: "keyword", value: "block" },
},
],
},
},
],
[
"Box",
{
type: "container",
icon: "",
presetStyle: {
div: [
{
property: "display",
value: { type: "keyword", value: "flex" },
},
],
},
},
],
]),
assetBaseUrl: "",
});
expect(atomicCssText).toMatchInlineSnapshot(`
"html {margin: 0; display: grid; min-height: 100%}
@media all {
div:where([data-ws-component="Box"]) {
:where(div.w-body) {
display: block
}
a:where([data-ws-component="Box"]) {
-webkit-user-select: none;
user-select: none
:where(div.w-box) {
display: flex
}
}
"
`);
expect(classesMap).toMatchInlineSnapshot(`Map {}`);
expect(classes).toMatchInlineSnapshot(`
Map {
"body" => [
"w-body",
],
"box" => [
"w-box",
],
}
`);
expect(atomicClasses).toMatchInlineSnapshot(`
Map {
"body" => [
"w-body",
"c17hlgoh",
],
"box" => [
"w-box",
"cawkhls",
],
}
`);
});
+64 -27
View File
@@ -4,19 +4,22 @@ import {
type NestingRule,
type TransformValue,
} from "@webstudio-is/css-engine";
import type {
Assets,
Breakpoints,
Instance,
Instances,
Props,
StyleSourceSelections,
Styles,
import {
createScope,
parseComponentName,
type Assets,
type Breakpoints,
type Instance,
type Instances,
type Props,
type StyleSourceSelections,
type Styles,
} from "@webstudio-is/sdk";
import type { WsComponentMeta } from "../components/component-meta";
import { idAttribute } from "../props";
import { descendantComponent } from "../core-components";
import { addGlobalRules, addPresetRules } from "./global-rules";
import { addGlobalRules } from "./global-rules";
import { kebabCase } from "change-case";
export type CssConfig = {
assets: Assets;
@@ -56,6 +59,8 @@ export const createImageValueTransformer =
}
};
const normalizeClassName = (name: string) => kebabCase(name);
export const generateCss = ({
assets,
instances,
@@ -69,25 +74,35 @@ export const generateCss = ({
}: CssConfig) => {
const globalSheet = createRegularStyleSheet({ name: "ssr" });
const sheet = createRegularStyleSheet({ name: "ssr" });
const parentIdByInstanceId = new Map<Instance["id"], Instance["id"]>();
for (const instance of instances.values()) {
for (const child of instance.children) {
if (child.type === "id") {
parentIdByInstanceId.set(child.value, instance.id);
addGlobalRules(globalSheet, { assets, assetBaseUrl });
globalSheet.addMediaRule("presets");
const presetClasses = new Map<Instance["component"], string>();
const scope = createScope([], normalizeClassName, "-");
for (const [component, meta] of componentMetas) {
const [_namespace, componentName] = parseComponentName(component);
const className = `w-${scope.getName(component, componentName)}`;
const presetStyle = Object.entries(meta.presetStyle ?? {});
if (presetStyle.length > 0) {
// add preset class only when at least one style is defined
presetClasses.set(component, className);
}
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
const rule = globalSheet.addNestingRule(`:where(${tag}.${className})`);
for (const declaration of styles) {
rule.setDeclaration({
breakpoint: "presets",
selector: declaration.state ?? "",
property: declaration.property,
value: declaration.value,
});
}
}
}
const descendantSelectorByInstanceId = new Map<Instance["id"], string>();
for (const prop of props.values()) {
if (prop.name === "selector" && prop.type === "string") {
descendantSelectorByInstanceId.set(prop.instanceId, prop.value);
}
}
addGlobalRules(globalSheet, { assets, assetBaseUrl });
addPresetRules(globalSheet, componentMetas);
for (const breakpoint of breakpoints.values()) {
sheet.addMediaRule(breakpoint.id, breakpoint);
}
@@ -107,6 +122,27 @@ export const generateCss = ({
});
}
const classes = new Map<Instance["id"], string[]>();
const parentIdByInstanceId = new Map<Instance["id"], Instance["id"]>();
for (const instance of instances.values()) {
const presetClass = presetClasses.get(instance.component);
if (presetClass) {
classes.set(instance.id, [presetClass]);
}
for (const child of instance.children) {
if (child.type === "id") {
parentIdByInstanceId.set(child.value, instance.id);
}
}
}
const descendantSelectorByInstanceId = new Map<Instance["id"], string>();
for (const prop of props.values()) {
if (prop.name === "selector" && prop.type === "string") {
descendantSelectorByInstanceId.set(prop.instanceId, prop.value);
}
}
const instanceByRule = new Map<NestingRule, Instance["id"]>();
for (const selection of styleSourceSelections.values()) {
let { instanceId } = selection;
@@ -131,14 +167,15 @@ export const generateCss = ({
}
if (atomic) {
const { cssText, classesMap } = generateAtomic(sheet, {
const { cssText } = generateAtomic(sheet, {
getKey: (rule) => instanceByRule.get(rule) ?? "",
transformValue: imageValueTransformer,
classes,
});
return { cssText: `${globalSheet.cssText}\n${cssText}`, classesMap };
return { cssText: `${globalSheet.cssText}\n${cssText}`, classes };
}
return {
cssText: `${globalSheet.cssText}\n${sheet.cssText}`,
classesMap: new Map<string, Array<string>>(),
classes,
};
};
@@ -1,7 +1,6 @@
import type { StyleSheetRegular } from "@webstudio-is/css-engine";
import type { Assets, FontAsset } from "@webstudio-is/sdk";
import { getFontFaces } from "@webstudio-is/fonts";
import type { WsComponentMeta } from "../components/component-meta";
export const addGlobalRules = (
sheet: StyleSheetRegular,
@@ -25,25 +24,3 @@ export const addGlobalRules = (
sheet.addFontFaceRule(fontFace);
}
};
export const addPresetRules = (
sheet: StyleSheetRegular,
metas: Map<string, WsComponentMeta>
) => {
sheet.addMediaRule("presets");
for (const [component, meta] of metas) {
for (const [tag, styles] of Object.entries(meta.presetStyle ?? {})) {
const rule = sheet.addNestingRule(
`${tag}:where([data-ws-component="${component}"])`
);
for (const declaration of styles) {
rule.setDeclaration({
breakpoint: "presets",
selector: declaration.state ?? "",
property: declaration.property,
value: declaration.value,
});
}
}
}
};
+2 -2
View File
@@ -146,7 +146,7 @@ export const generateStories = async () => {
usedMetas.set(instance.component, meta);
}
}
const { cssText, classesMap } = generateCss({
const { cssText, classes } = generateCss({
instances,
props,
assets: new Map(),
@@ -175,7 +175,7 @@ export const generateStories = async () => {
});
content += `\n`;
content += generateWebstudioComponent({
classesMap,
classesMap: classes,
scope,
name: `Component`,
rootInstanceId,
@@ -1,6 +1,7 @@
import type { PropMeta } from "@webstudio-is/react-sdk";
export const props: Record<string, PropMeta> = {
className: { required: false, control: "text", type: "string" },
clientOnly: { required: false, control: "boolean", type: "boolean" },
code: { required: true, control: "text", type: "string" },
executeScriptOnCanvas: {
@@ -129,6 +129,7 @@ type ChildProps = {
innerRef: ForwardedRef<HTMLDivElement>;
// code can be actually undefined when prop is not provided
code?: string;
className?: string;
};
const Placeholder = (props: ChildProps) => {
@@ -214,6 +215,7 @@ type HtmlEmbedProps = {
code: string;
executeScriptOnCanvas?: boolean;
clientOnly?: boolean;
className?: string;
// avoid builder passing it to dom
children?: never;
};
@@ -45,5 +45,5 @@ export const propsMeta: WsComponentPropsMeta = {
type: "string",
},
},
initialProps: ["clientOnly", "executeScriptOnCanvas"],
initialProps: ["className", "clientOnly", "executeScriptOnCanvas"],
};
+7 -3
View File
@@ -8,7 +8,7 @@ export type Scope = {
};
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#identifiers
const normalizeName = (name: string) => {
const normalizeJsName = (name: string) => {
// only letters, digits, underscores and dollar signs allowed in names
// delete everything else
name = name.replaceAll(/[^\w$]/g, "");
@@ -30,7 +30,11 @@ const normalizeName = (name: string) => {
* occupiedIdentifiers parameter prevents collision with hardcoded
* identifiers.
*/
export const createScope = (occupiedIdentifiers: string[] = []): Scope => {
export const createScope = (
occupiedIdentifiers: string[] = [],
normalizeName = normalizeJsName,
separator = "_"
): Scope => {
const freeIndexByPreferredName = new Map<string, number>();
const scopedNameByIdMap = new Map<string, string>();
for (const identifier of occupiedIdentifiers) {
@@ -47,7 +51,7 @@ export const createScope = (occupiedIdentifiers: string[] = []): Scope => {
freeIndexByPreferredName.set(preferredName, (index ?? 0) + 1);
let scopedName = preferredName;
if (index !== undefined) {
scopedName = `${preferredName}_${index}`;
scopedName = `${preferredName}${separator}${index}`;
}
scopedNameByIdMap.set(id, scopedName);
return scopedName;