diff --git a/apps/builder/app/shared/copy-paste.test.tsx b/apps/builder/app/shared/copy-paste.test.tsx
index 2e4f16af18db..4c816070851f 100644
--- a/apps/builder/app/shared/copy-paste.test.tsx
+++ b/apps/builder/app/shared/copy-paste.test.tsx
@@ -28,6 +28,7 @@ import {
} from "./instance-utils";
import { $project } from "./nano-states";
import { findAvailableVariables } from "./data-variables";
+import { camelCaseProperty } from "@webstudio-is/css-data";
$project.set({ id: "current_project" } as Project);
@@ -83,8 +84,14 @@ const insertStyles = ({
styleSourceId: string;
style: TemplateStyleDecl[];
}) => {
- for (const styleDecl of style) {
- const newStyleDecl = { breakpointId, styleSourceId, ...styleDecl };
+ for (const { state, property, value } of style) {
+ const newStyleDecl = {
+ breakpointId,
+ styleSourceId,
+ state,
+ property: camelCaseProperty(property),
+ value,
+ };
data.styles.set(getStyleDeclKey(newStyleDecl), newStyleDecl);
}
};
diff --git a/fixtures/react-router-docker/app/__generated__/index.css b/fixtures/react-router-docker/app/__generated__/index.css
index 2170b71f3d8f..d226704c7a4f 100644
--- a/fixtures/react-router-docker/app/__generated__/index.css
+++ b/fixtures/react-router-docker/app/__generated__/index.css
@@ -26,46 +26,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- h2.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h3.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h4.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h5.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h6.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
div.w-text {
box-sizing: border-box;
border-top-width: 1px;
diff --git a/fixtures/react-router-netlify/app/__generated__/index.css b/fixtures/react-router-netlify/app/__generated__/index.css
index 2170b71f3d8f..d226704c7a4f 100644
--- a/fixtures/react-router-netlify/app/__generated__/index.css
+++ b/fixtures/react-router-netlify/app/__generated__/index.css
@@ -26,46 +26,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- h2.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h3.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h4.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h5.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h6.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
div.w-text {
box-sizing: border-box;
border-top-width: 1px;
diff --git a/fixtures/react-router-vercel/app/__generated__/index.css b/fixtures/react-router-vercel/app/__generated__/index.css
index 2170b71f3d8f..d226704c7a4f 100644
--- a/fixtures/react-router-vercel/app/__generated__/index.css
+++ b/fixtures/react-router-vercel/app/__generated__/index.css
@@ -26,46 +26,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- h2.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h3.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h4.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h5.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h6.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
div.w-text {
box-sizing: border-box;
border-top-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 f94277d8c8e5..82f21c895eeb 100644
--- a/fixtures/ssg-netlify-by-project-id/app/__generated__/index.css
+++ b/fixtures/ssg-netlify-by-project-id/app/__generated__/index.css
@@ -26,44 +26,4 @@
border-left-width: 1px;
outline-width: 1px;
}
- h2.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h3.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h4.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h5.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h6.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
}
diff --git a/fixtures/ssg/app/__generated__/index.css b/fixtures/ssg/app/__generated__/index.css
index 2170b71f3d8f..d226704c7a4f 100644
--- a/fixtures/ssg/app/__generated__/index.css
+++ b/fixtures/ssg/app/__generated__/index.css
@@ -26,46 +26,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- h2.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h3.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h4.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h5.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h6.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
div.w-text {
box-sizing: border-box;
border-top-width: 1px;
diff --git a/fixtures/webstudio-cloudflare-template/app/__generated__/index.css b/fixtures/webstudio-cloudflare-template/app/__generated__/index.css
index 2170b71f3d8f..d226704c7a4f 100644
--- a/fixtures/webstudio-cloudflare-template/app/__generated__/index.css
+++ b/fixtures/webstudio-cloudflare-template/app/__generated__/index.css
@@ -26,46 +26,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- h2.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h3.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h4.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h5.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h6.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
div.w-text {
box-sizing: border-box;
border-top-width: 1px;
diff --git a/fixtures/webstudio-features/app/__generated__/index.css b/fixtures/webstudio-features/app/__generated__/index.css
index 91816fd03eb4..a4e795d25e5e 100644
--- a/fixtures/webstudio-features/app/__generated__/index.css
+++ b/fixtures/webstudio-features/app/__generated__/index.css
@@ -26,14 +26,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- h2.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
h3.w-heading {
box-sizing: border-box;
border-top-width: 1px;
@@ -42,30 +34,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- h4.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h5.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- h6.w-heading {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
div.w-box {
box-sizing: border-box;
border-top-width: 1px;
@@ -74,78 +42,6 @@
border-left-width: 1px;
outline-width: 1px;
}
- address.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- article.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- aside.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- figure.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- footer.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- header.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- main.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- nav.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
- section.w-box {
- box-sizing: border-box;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- outline-width: 1px;
- }
p.w-paragraph {
box-sizing: border-box;
border-top-width: 1px;
diff --git a/packages/sdk/src/css.test.tsx b/packages/sdk/src/css.test.tsx
index 56e3049f0019..1660b9242c63 100644
--- a/packages/sdk/src/css.test.tsx
+++ b/packages/sdk/src/css.test.tsx
@@ -1,5 +1,5 @@
import { expect, test } from "vitest";
-import { $, ws, css, renderData } from "@webstudio-is/template";
+import { $, ws, css, renderData, createProxy } from "@webstudio-is/template";
import { generateCss, type CssConfig } from "./css";
import type { Breakpoint } from "./schema/breakpoints";
import { rootComponent } from "./core-metas";
@@ -150,9 +150,12 @@ Map {
test("generate component presets with multiple tags", () => {
const { cssText, atomicCssText, classes, atomicClasses } = generateAllCss({
+ ...renderData(
+ <$.ListItem tag="div">
+ <$.ListItem tag="a">$.ListItem>
+ $.ListItem>
+ ),
assets: new Map(),
- instances: new Map(),
- props: new Map(),
breakpoints: new Map(),
styleSourceSelections: new Map([]),
styles: new Map(),
@@ -163,18 +166,12 @@ test("generate component presets with multiple tags", () => {
type: "container",
icon: "",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "block" },
- },
- ],
- a: [
- {
- property: "user-select",
- value: { type: "keyword", value: "none" },
- },
- ],
+ div: css`
+ display: block;
+ `,
+ a: css`
+ user-select: none;
+ `,
},
},
],
@@ -194,15 +191,27 @@ test("generate component presets with multiple tags", () => {
"
`);
expect(cssText).toEqual(atomicCssText);
- expect(classes).toMatchInlineSnapshot(`Map {}`);
+ expect(classes).toEqual(
+ new Map([
+ ["0", ["w-list-item"]],
+ ["1", ["w-list-item"]],
+ ])
+ );
expect(classes).toEqual(atomicClasses);
});
test("deduplicate component presets for similarly named components", () => {
+ const radix = createProxy("@webstudio/radix:");
+ const aria = createProxy("@webstudio/aria:");
const { cssText, atomicCssText, classes, atomicClasses } = generateAllCss({
+ ...renderData(
+ <$.ListItem>
+
+
+
+ $.ListItem>
+ ),
assets: new Map(),
- instances: new Map(),
- props: new Map(),
breakpoints: new Map(),
styleSourceSelections: new Map([]),
styles: new Map(),
@@ -213,12 +222,9 @@ test("deduplicate component presets for similarly named components", () => {
type: "container",
icon: "",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "block" },
- },
- ],
+ div: css`
+ display: block;
+ `,
},
},
],
@@ -228,12 +234,9 @@ test("deduplicate component presets for similarly named components", () => {
type: "container",
icon: "",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "flex" },
- },
- ],
+ div: css`
+ display: flex;
+ `,
},
},
],
@@ -243,12 +246,9 @@ test("deduplicate component presets for similarly named components", () => {
type: "container",
icon: "",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "grid" },
- },
- ],
+ div: css`
+ display: grid;
+ `,
},
},
],
@@ -270,7 +270,13 @@ test("deduplicate component presets for similarly named components", () => {
"
`);
expect(cssText).toEqual(atomicCssText);
- expect(classes).toMatchInlineSnapshot(`Map {}`);
+ expect(classes).toEqual(
+ new Map([
+ ["0", ["w-list-item"]],
+ ["1", ["w-list-item-1"]],
+ ["2", ["w-list-item-2"]],
+ ])
+ );
expect(classes).toEqual(atomicClasses);
});
@@ -298,12 +304,9 @@ test("expose preset classes to instances", () => {
type: "container",
icon: "",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "block" },
- },
- ],
+ div: css`
+ display: block;
+ `,
},
},
],
@@ -313,12 +316,9 @@ test("expose preset classes to instances", () => {
type: "container",
icon: "",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "flex" },
- },
- ],
+ div: css`
+ display: flex;
+ `,
},
},
],
@@ -395,12 +395,9 @@ test("generate classes with instance and meta label", () => {
icon: "",
label: "body meta label",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "block" },
- },
- ],
+ div: css`
+ display: block;
+ `,
},
},
],
@@ -411,12 +408,9 @@ test("generate classes with instance and meta label", () => {
icon: "",
label: "box meta label",
presetStyle: {
- div: [
- {
- property: "display",
- value: { type: "keyword", value: "flex" },
- },
- ],
+ div: css`
+ display: flex;
+ `,
},
},
],
@@ -494,12 +488,9 @@ test("generate :root preset and user styles", () => {
icon: "",
label: "Global Root",
presetStyle: {
- html: [
- {
- property: "display",
- value: { type: "keyword", value: "grid" },
- },
- ],
+ html: css`
+ display: grid;
+ `,
},
},
],
@@ -535,3 +526,69 @@ test("generate :root preset and user styles", () => {
`);
expect(atomicClasses).toEqual(new Map());
});
+
+test("generate presets only for used tags", () => {
+ const { cssText, classes } = generateCss({
+ ...renderData(
+ <$.Body ws:id="body">
+ {/* first tag in preset */}
+ <$.Box>$.Box>
+ {/* legacy tag property */}
+ <$.Box tag="span">$.Box>
+ {/* modern ws:tag property */}
+ <$.Box ws:tag="article">$.Box>
+ $.Body>
+ ),
+ atomic: false,
+ breakpoints: toMap([{ id: "base", label: "" }]),
+ styleSourceSelections: new Map(),
+ styles: new Map(),
+ componentMetas: new Map([
+ [
+ "Box",
+ {
+ type: "container",
+ icon: "",
+ presetStyle: {
+ div: css`
+ display: block;
+ `,
+ span: css`
+ display: block;
+ `,
+ article: css`
+ display: block;
+ `,
+ section: css`
+ display: block;
+ `,
+ main: css`
+ display: block;
+ `,
+ },
+ },
+ ],
+ ]),
+ assetBaseUrl: "",
+ });
+ expect(cssText).toMatchInlineSnapshot(`
+"@layer presets {
+ div.w-box {
+ display: block
+ }
+ span.w-box {
+ display: block
+ }
+ article.w-box {
+ display: block
+ }
+}
+"`);
+ expect(classes).toEqual(
+ new Map([
+ ["0", ["w-box"]],
+ ["1", ["w-box"]],
+ ["2", ["w-box"]],
+ ])
+ );
+});
diff --git a/packages/sdk/src/css.ts b/packages/sdk/src/css.ts
index 44e164c526db..d15ddd3ad6e5 100644
--- a/packages/sdk/src/css.ts
+++ b/packages/sdk/src/css.ts
@@ -98,7 +98,32 @@ export const generateCss = ({
presetSheet.addMediaRule("presets");
const presetClasses = new Map();
const scope = createScope([], normalizeClassName, "-");
+
+ const tagsByComponent = new Map>();
+ tagsByComponent.set(rootComponent, new Set(["html"]));
+ const tagByInstanceId = new Map();
+ for (const prop of props.values()) {
+ if (prop.type === "string" && prop.name === "tag") {
+ tagByInstanceId.set(prop.instanceId, prop.value);
+ }
+ }
+ for (const instance of instances.values()) {
+ const propTag = tagByInstanceId.get(instance.id);
+ const meta = componentMetas.get(instance.component);
+ const metaTag = Object.keys(meta?.presetStyle ?? {}).at(0);
+ let componentTags = tagsByComponent.get(instance.component);
+ if (componentTags === undefined) {
+ componentTags = new Set();
+ tagsByComponent.set(instance.component, componentTags);
+ }
+ const tag = instance.tag ?? propTag ?? metaTag;
+ if (tag) {
+ componentTags.add(tag);
+ }
+ }
+
for (const [component, meta] of componentMetas) {
+ const componentTags = tagsByComponent.get(component);
const [_namespace, componentName] = parseComponentName(component);
const className = `w-${scope.getName(component, meta.label ?? componentName)}`;
const presetStyle = Object.entries(meta.presetStyle ?? {});
@@ -106,12 +131,11 @@ 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
+ // ignore unused tags
+ if (!componentTags?.has(tag)) {
+ continue;
+ }
const selector =
component === rootComponent ? ":root" : `${tag}.${className}`;
const rule = presetSheet.addNestingRule(selector);
diff --git a/packages/template/src/css.ts b/packages/template/src/css.ts
index 5496a6583dbe..93858f475f61 100644
--- a/packages/template/src/css.ts
+++ b/packages/template/src/css.ts
@@ -1,9 +1,9 @@
-import { camelCaseProperty, parseCss } from "@webstudio-is/css-data";
-import type { StyleProperty, StyleValue } from "@webstudio-is/css-engine";
+import { parseCss } from "@webstudio-is/css-data";
+import type { CssProperty, StyleValue } from "@webstudio-is/css-engine";
export type TemplateStyleDecl = {
state?: string;
- property: StyleProperty;
+ property: CssProperty;
value: StyleValue;
};
@@ -14,7 +14,7 @@ export const css = (
const cssString = `.styles{ ${String.raw({ raw: strings }, ...values)} }`;
const styles: TemplateStyleDecl[] = [];
for (const { state, property, value } of parseCss(cssString)) {
- styles.push({ state, property: camelCaseProperty(property), value });
+ styles.push({ state, property: property, value });
}
return styles;
};
diff --git a/packages/template/src/jsx.ts b/packages/template/src/jsx.ts
index 718657ef5d10..b0d7f5f49eea 100644
--- a/packages/template/src/jsx.ts
+++ b/packages/template/src/jsx.ts
@@ -14,6 +14,7 @@ import type {
} from "@webstudio-is/sdk";
import { showAttribute } from "@webstudio-is/react-sdk";
import type { TemplateStyleDecl } from "./css";
+import { camelCaseProperty } from "@webstudio-is/css-data";
export class Variable {
name: string;
@@ -276,11 +277,13 @@ export const renderTemplate = (
values: [styleSourceId],
});
const localStyles = value as TemplateStyleDecl[];
- for (const styleDecl of localStyles) {
+ for (const { state, property, value } of localStyles) {
styles.push({
breakpointId: getBreakpointId(),
styleSourceId,
- ...styleDecl,
+ state,
+ property: camelCaseProperty(property),
+ value,
});
}
continue;